Skip to content

Commit 7301f6d

Browse files
committed
Add test, CI config and updates to component
1 parent c906cd0 commit 7301f6d

File tree

8 files changed

+390
-46
lines changed

8 files changed

+390
-46
lines changed

.babelrc

+3
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
{
2+
"presets": ["./tools/babel-preset.js"]
3+
}

.circleci/config.yml

+45
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
# Javascript Node CircleCI 2.0 configuration file
2+
#
3+
# Check https://circleci.com/docs/2.0/language-javascript/ for more details
4+
#
5+
version: 2
6+
jobs:
7+
build:
8+
docker:
9+
# specify the version you desire here
10+
- image: circleci/node:7.10
11+
12+
# Specify service dependencies here if necessary
13+
# CircleCI maintains a library of pre-built images
14+
# documented at https://circleci.com/docs/2.0/circleci-images/
15+
# - image: circleci/mongo:3.4.4
16+
17+
working_directory: ~/repo
18+
19+
steps:
20+
- checkout
21+
22+
# Download and cache dependencies
23+
- restore_cache:
24+
keys:
25+
- v1-dependencies-{{ checksum "package.json" }}
26+
# fallback to using the latest cache if no exact match is found
27+
- v1-dependencies-
28+
29+
- run: yarn install
30+
31+
- save_cache:
32+
paths:
33+
- node_modules
34+
key: v1-dependencies-{{ checksum "package.json" }}
35+
36+
- run: ./node_modules/.bin/greenkeeper-lockfile-update
37+
- run: yarn build
38+
39+
# run tests!
40+
- run: yarn test
41+
42+
# send code coverage info to coveralls
43+
- run: cat ./coverage/lcov.info | ./node_modules/coveralls/bin/coveralls.js
44+
45+
- run: ./node_modules/.bin/greenkeeper-lockfile-upload

.gitignore

+1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
.DS_Store
2+
coverage
23
es
34
node_modules
45
umd

.npmignore

+3
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,7 @@
1+
coverage
12
tools
3+
src/.babelrc
4+
src/index.test.js
25
rollup.config.js
36
*.sublime-project
47
*.sublime-workspace

README.md

+7-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,10 @@
1-
# react-timer-wrapper
1+
# ⏳ react-timer-wrapper
2+
3+
[![npm version](https://badge.fury.io/js/react-timer-wrapper.svg)](https://badge.fury.io/js/clean-react-props)
4+
[![npm](https://img.shields.io/npm/l/express.svg)](LICENSE)
5+
[![Coverage Status](https://coveralls.io/repos/github/ryanhefner/react-timer-wrapper/badge.svg?branch=master)](https://coveralls.io/github/ryanhefner/react-timer-wrapper?branch=master)
6+
[![CircleCI](https://circleci.com/gh/ryanhefner/react-timer-wrapper.svg?style=shield)](https://circleci.com/gh/ryanhefner/react-timer-wrapper)
7+
[![Greenkeeper badge](https://badges.greenkeeper.io/ryanhefner/react-timer-wrapper.svg)](https://greenkeeper.io/)
28

39
Composable React Timer component that passes status props to children, in addition
410
to some basic callbacks. Can be used at a countdown timer ⏲ or as stopwatch ⏱ to track

src/index.js

+63-43
Original file line numberDiff line numberDiff line change
@@ -8,15 +8,34 @@ class TimerWrapper extends Component {
88

99
this.state = {
1010
duration: props.duration,
11-
startTime: props.active ? Date.now() : null,
11+
startTime: props.active ? Date.now() - props.time : null,
1212
time: props.time,
1313
};
1414

1515
this.tick = this.tick.bind(this);
1616
}
1717

1818
componentDidMount() {
19-
if (this.props.active) {
19+
const {
20+
duration,
21+
startTime,
22+
time,
23+
} = this.state;
24+
25+
const {
26+
active,
27+
onStart,
28+
} = this.props;
29+
30+
if (active) {
31+
const progress = Math.max(0, Math.min(1, time / duration));
32+
33+
onStart({
34+
duration,
35+
progress: this.getProgress(time),
36+
time,
37+
});
38+
2039
this.animationFrame = requestAnimationFrame(this.tick);
2140
}
2241
}
@@ -37,8 +56,6 @@ class TimerWrapper extends Component {
3756
}
3857

3958
if (active !== this.props.active) {
40-
let progress;
41-
4259
switch (active) {
4360
case true:
4461
const nextTime = duration !== null && this.state.time >= duration
@@ -50,13 +67,9 @@ class TimerWrapper extends Component {
5067
time: nextTime,
5168
});
5269

53-
progress = duration !== null
54-
? Math.max(0, Math.min(1, nextTime / duration))
55-
: null;
56-
5770
onStart({
5871
duration,
59-
progress,
72+
progress: this.getProgress(nextTime),
6073
time: nextTime,
6174
});
6275

@@ -66,10 +79,9 @@ class TimerWrapper extends Component {
6679
case false:
6780
cancelAnimationFrame(this.animationFrame);
6881

69-
progress = Math.max(0, Math.min(1, this.state.time / duration));
7082
onStop({
7183
duration,
72-
progress,
84+
progress: this.getProgress(this.state.time),
7385
time: this.state.time,
7486
});
7587
break;
@@ -81,6 +93,18 @@ class TimerWrapper extends Component {
8193
cancelAnimationFrame(this.animationFrame);
8294
}
8395

96+
getProgress(time) {
97+
const {
98+
duration,
99+
} = this.state;
100+
101+
if (!duration) {
102+
return null;
103+
}
104+
105+
return Math.max(0, Math.min(1, time / duration));
106+
}
107+
84108
tick() {
85109
const {
86110
duration,
@@ -95,47 +119,43 @@ class TimerWrapper extends Component {
95119
startTime,
96120
} = this.state;
97121

98-
99-
const diff = Date.now() - startTime;
100-
let nextTime = this.props.time + diff;
101-
102-
const progress = Math.max(0, Math.min(1, (nextTime / duration)));
122+
let nextTime = Date.now() - startTime;
103123

104124
onTimeUpdate({
105125
duration,
106-
progress,
126+
progress: this.getProgress(nextTime),
107127
time: nextTime,
108128
});
109129

110130
this.setState({
111131
time: nextTime,
112-
});
113-
114-
if (duration !== null && this.state.time >= duration) {
115-
onFinish({
116-
duration,
117-
progress,
118-
time: nextTime,
119-
});
120-
121-
if (!loop) {
122-
cancelAnimationFrame(this.animationFrame);
123-
return;
132+
}, () => {
133+
if (duration !== null && nextTime >= duration) {
134+
onFinish({
135+
duration,
136+
progress: this.getProgress(nextTime),
137+
time: nextTime,
138+
});
139+
140+
if (!loop) {
141+
cancelAnimationFrame(this.animationFrame);
142+
return;
143+
}
144+
145+
nextTime = 0;
146+
onStart({
147+
duration,
148+
progress: 0,
149+
time: nextTime,
150+
});
151+
152+
this.setState({
153+
startTime: Date.now(),
154+
});
124155
}
125156

126-
nextTime = 0;
127-
onStart({
128-
duration,
129-
progress: 0,
130-
time: nextTime,
131-
});
132-
133-
this.setState({
134-
startTime: Date.now(),
135-
});
136-
}
137-
138-
this.animationFrame = requestAnimationFrame(this.tick);
157+
this.animationFrame = requestAnimationFrame(this.tick);
158+
});
139159
}
140160

141161
render() {
@@ -172,7 +192,7 @@ class TimerWrapper extends Component {
172192
TimerWrapper.propTypes = {
173193
active: PropTypes.bool,
174194
component: PropTypes.oneOfType([
175-
PropTypes.element,
195+
PropTypes.func,
176196
PropTypes.string,
177197
]),
178198
duration: PropTypes.number,

0 commit comments

Comments
 (0)