@timekeeper-countdown/react 0.1.4 → 0.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +18 -6
- package/dist/index.cjs +1 -1
- package/dist/index.js +1 -1
- package/package.json +19 -4
package/README.md
CHANGED
|
@@ -100,6 +100,7 @@ interface UseCountdownResult {
|
|
|
100
100
|
```
|
|
101
101
|
|
|
102
102
|
- All control methods mirror the engine and return `false` for invalid transitions.
|
|
103
|
+
- `setSeconds(value)` and `reset(value)` validate their argument and **throw** on an invalid value (negative, non-integer, `NaN`, or `Infinity`), matching the engine.
|
|
103
104
|
- `snapshot` is stable per render; derive memoised values with `useMemo` if needed.
|
|
104
105
|
- `totalSeconds`, `parts`, `isRunning`, and `isCompleted` are re-exposed for convenience.
|
|
105
106
|
|
|
@@ -182,6 +183,21 @@ it('counts down when the fake clock advances', async () => {
|
|
|
182
183
|
|
|
183
184
|
The hook handles cleanup automatically, so tests do not need to destroy the engine manually.
|
|
184
185
|
|
|
186
|
+
### Available Testing Utilities
|
|
187
|
+
|
|
188
|
+
The core package ships several helpers under `@timekeeper-countdown/core/testing-utils`:
|
|
189
|
+
|
|
190
|
+
- `createFakeTimeProvider(options?)` — controllable clock with `advance()`, `set()`, `reset()`, and `getTime()`.
|
|
191
|
+
- `toTimeProvider(fake)` — adapts a fake clock to the `TimeProvider` interface.
|
|
192
|
+
- `buildSnapshot(options?)` — fabricates `CountdownSnapshot` objects for unit tests without running an engine.
|
|
193
|
+
- `buildSnapshotSequence(options?)` — generates an array of snapshots simulating a countdown progression.
|
|
194
|
+
- `assertSnapshotState(snapshot, expected, message?)` — throws if the snapshot is not in the expected `TimerState`.
|
|
195
|
+
- `assertSnapshotCompleted(snapshot, message?)` — throws if the countdown is not completed.
|
|
196
|
+
- `assertRemainingSeconds(snapshot, expected, tolerance?, message?)` — throws if remaining seconds differ beyond tolerance.
|
|
197
|
+
- `TimerState` — re-exported for convenience (`IDLE`, `RUNNING`, `PAUSED`, `STOPPED`).
|
|
198
|
+
|
|
199
|
+
See the [core README](https://github.com/eagle-head/timekeeper-countdown/tree/main/packages/core#testing-utilities) or [API Reference](https://eagle-head.github.io/timekeeper-countdown/api-reference) for full signatures and examples.
|
|
200
|
+
|
|
185
201
|
---
|
|
186
202
|
|
|
187
203
|
## Multiple Timers
|
|
@@ -221,13 +237,9 @@ function MultiStageTimer() {
|
|
|
221
237
|
|
|
222
238
|
## Contributing
|
|
223
239
|
|
|
224
|
-
|
|
240
|
+
We welcome contributions! Please read our [Contributing Guide](https://github.com/eagle-head/timekeeper-countdown/blob/main/CONTRIBUTING.md) to get started.
|
|
225
241
|
|
|
226
|
-
|
|
227
|
-
npm run lint --workspaces
|
|
228
|
-
npm run test --workspaces
|
|
229
|
-
npm run typecheck --workspaces
|
|
230
|
-
```
|
|
242
|
+
By participating in this project, you agree to abide by our [Code of Conduct](https://github.com/eagle-head/timekeeper-countdown/blob/main/CODE_OF_CONDUCT.md).
|
|
231
243
|
|
|
232
244
|
---
|
|
233
245
|
|
package/dist/index.cjs
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
'use strict';var react=require('react'),core=require('@timekeeper-countdown/core');
|
|
1
|
+
'use strict';var react=require('react'),core=require('@timekeeper-countdown/core');function D(a,h={}){let{autoStart:C=false,tickIntervalMs:c,timeProvider:S,onSnapshot:p,onStateChange:i,onError:d}=h,u=react.useRef({onSnapshot:p,onStateChange:i,onError:d}),l=react.useRef(null),[r,g]=react.useState(()=>core.buildSnapshot(a,a,core.TimerState.IDLE));react.useEffect(()=>{u.current={onSnapshot:p,onStateChange:i,onError:d};},[d,p,i]);let w=react.useMemo(()=>({tickIntervalMs:c,timeProvider:S}),[c,S]);react.useEffect(()=>{let n=true,o=core.CountdownEngine(a,{...w,onSnapshot:e=>{n&&g(e),u.current.onSnapshot?.(e);},onStateChange:(e,y)=>{u.current.onStateChange?.(e,y);},onError:e=>{u.current.onError?.(e);}});return l.current=o,g(o.getSnapshot()),C&&o.start(),()=>{n=false,o.destroy(),l.current=null;}},[C,w,a]);let t=react.useCallback((n,o)=>{let e=l.current;return e?n(e):o},[]),E=react.useCallback(()=>t(n=>n.start(),false),[t]),b=react.useCallback(()=>t(n=>n.pause(),false),[t]),O=react.useCallback(()=>t(n=>n.resume(),false),[t]),R=react.useCallback(()=>t(n=>n.stop(),false),[t]),U=react.useCallback(n=>{t(o=>o.setSeconds(n),void 0);},[t]),x=react.useCallback(n=>t(o=>o.reset(n),false),[t]);return {snapshot:r,state:r.state,totalSeconds:r.totalSeconds,parts:r.parts,isRunning:r.isRunning,isCompleted:r.isCompleted,start:E,pause:b,resume:O,reset:x,stop:R,setSeconds:U}}exports.useCountdown=D;
|
package/dist/index.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
import {useRef,useState,useEffect,useMemo,useCallback}from'react';import {CountdownEngine}from'@timekeeper-countdown/core';
|
|
1
|
+
import {useRef,useState,useEffect,useMemo,useCallback}from'react';import {buildSnapshot,TimerState,CountdownEngine}from'@timekeeper-countdown/core';function D(a,h={}){let{autoStart:C=false,tickIntervalMs:c,timeProvider:S,onSnapshot:p,onStateChange:i,onError:d}=h,u=useRef({onSnapshot:p,onStateChange:i,onError:d}),l=useRef(null),[r,g]=useState(()=>buildSnapshot(a,a,TimerState.IDLE));useEffect(()=>{u.current={onSnapshot:p,onStateChange:i,onError:d};},[d,p,i]);let w=useMemo(()=>({tickIntervalMs:c,timeProvider:S}),[c,S]);useEffect(()=>{let n=true,o=CountdownEngine(a,{...w,onSnapshot:e=>{n&&g(e),u.current.onSnapshot?.(e);},onStateChange:(e,y)=>{u.current.onStateChange?.(e,y);},onError:e=>{u.current.onError?.(e);}});return l.current=o,g(o.getSnapshot()),C&&o.start(),()=>{n=false,o.destroy(),l.current=null;}},[C,w,a]);let t=useCallback((n,o)=>{let e=l.current;return e?n(e):o},[]),E=useCallback(()=>t(n=>n.start(),false),[t]),b=useCallback(()=>t(n=>n.pause(),false),[t]),O=useCallback(()=>t(n=>n.resume(),false),[t]),R=useCallback(()=>t(n=>n.stop(),false),[t]),U=useCallback(n=>{t(o=>o.setSeconds(n),void 0);},[t]),x=useCallback(n=>t(o=>o.reset(n),false),[t]);return {snapshot:r,state:r.state,totalSeconds:r.totalSeconds,parts:r.parts,isRunning:r.isRunning,isCompleted:r.isCompleted,start:E,pause:b,resume:O,reset:x,stop:R,setSeconds:U}}export{D as useCountdown};
|
package/package.json
CHANGED
|
@@ -1,7 +1,17 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@timekeeper-countdown/react",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.3.0",
|
|
4
4
|
"description": "React adapter for the Timekeeper Countdown engine",
|
|
5
|
+
"author": "Eduardo Kohn",
|
|
6
|
+
"license": "MIT",
|
|
7
|
+
"repository": {
|
|
8
|
+
"type": "git",
|
|
9
|
+
"url": "git+https://github.com/eagle-head/timekeeper-countdown.git"
|
|
10
|
+
},
|
|
11
|
+
"homepage": "https://eagle-head.github.io/timekeeper-countdown/",
|
|
12
|
+
"bugs": {
|
|
13
|
+
"url": "https://github.com/eagle-head/timekeeper-countdown/issues"
|
|
14
|
+
},
|
|
5
15
|
"type": "module",
|
|
6
16
|
"main": "./dist/index.js",
|
|
7
17
|
"module": "./dist/index.js",
|
|
@@ -23,6 +33,7 @@
|
|
|
23
33
|
"test": "vitest run",
|
|
24
34
|
"test:ui": "vitest --ui",
|
|
25
35
|
"test:coverage": "vitest run --coverage",
|
|
36
|
+
"test:mutation": "stryker run",
|
|
26
37
|
"typecheck": "tsc --noEmit",
|
|
27
38
|
"lint": "eslint .",
|
|
28
39
|
"lint:fix": "eslint . --fix",
|
|
@@ -34,11 +45,12 @@
|
|
|
34
45
|
"react": ">=17.0.0"
|
|
35
46
|
},
|
|
36
47
|
"dependencies": {
|
|
37
|
-
"@timekeeper-countdown/core": "^0.
|
|
48
|
+
"@timekeeper-countdown/core": "^0.3.0"
|
|
38
49
|
},
|
|
39
50
|
"devDependencies": {
|
|
40
|
-
"@testing-library/
|
|
41
|
-
"@testing-library/
|
|
51
|
+
"@testing-library/dom": "^10.4.1",
|
|
52
|
+
"@testing-library/jest-dom": "^6.9.1",
|
|
53
|
+
"@testing-library/react": "^16.3.2",
|
|
42
54
|
"@types/react": "^18.2.55",
|
|
43
55
|
"@types/react-dom": "^18.2.19",
|
|
44
56
|
"react": "^18.3.1",
|
|
@@ -52,6 +64,9 @@
|
|
|
52
64
|
"typescript"
|
|
53
65
|
],
|
|
54
66
|
"sideEffects": false,
|
|
67
|
+
"engines": {
|
|
68
|
+
"node": ">=22"
|
|
69
|
+
},
|
|
55
70
|
"publishConfig": {
|
|
56
71
|
"registry": "https://registry.npmjs.org",
|
|
57
72
|
"access": "public"
|