@timekeeper-countdown/react 0.1.3 → 0.2.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 +15 -0
- package/dist/index.cjs +1 -0
- package/dist/index.d.cts +27 -0
- package/dist/index.js +1 -1
- package/package.json +14 -3
package/README.md
CHANGED
|
@@ -182,6 +182,21 @@ it('counts down when the fake clock advances', async () => {
|
|
|
182
182
|
|
|
183
183
|
The hook handles cleanup automatically, so tests do not need to destroy the engine manually.
|
|
184
184
|
|
|
185
|
+
### Available Testing Utilities
|
|
186
|
+
|
|
187
|
+
The core package ships several helpers under `@timekeeper-countdown/core/testing-utils`:
|
|
188
|
+
|
|
189
|
+
- `createFakeTimeProvider(options?)` — controllable clock with `advance()`, `set()`, `reset()`, and `getTime()`.
|
|
190
|
+
- `toTimeProvider(fake)` — adapts a fake clock to the `TimeProvider` interface.
|
|
191
|
+
- `buildSnapshot(options?)` — fabricates `CountdownSnapshot` objects for unit tests without running an engine.
|
|
192
|
+
- `buildSnapshotSequence(options?)` — generates an array of snapshots simulating a countdown progression.
|
|
193
|
+
- `assertSnapshotState(snapshot, expected, message?)` — throws if the snapshot is not in the expected `TimerState`.
|
|
194
|
+
- `assertSnapshotCompleted(snapshot, message?)` — throws if the countdown is not completed.
|
|
195
|
+
- `assertRemainingSeconds(snapshot, expected, tolerance?, message?)` — throws if remaining seconds differ beyond tolerance.
|
|
196
|
+
- `TimerState` — re-exported for convenience (`IDLE`, `RUNNING`, `PAUSED`, `STOPPED`).
|
|
197
|
+
|
|
198
|
+
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.
|
|
199
|
+
|
|
185
200
|
---
|
|
186
201
|
|
|
187
202
|
## Multiple Timers
|
package/dist/index.cjs
ADDED
|
@@ -0,0 +1 @@
|
|
|
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.d.cts
ADDED
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import { CountdownEngineOptions, CountdownSnapshot, TimerState } from '@timekeeper-countdown/core';
|
|
2
|
+
|
|
3
|
+
interface UseCountdownOptions extends Omit<CountdownEngineOptions, 'onSnapshot' | 'onStateChange' | 'onError'> {
|
|
4
|
+
autoStart?: boolean;
|
|
5
|
+
onSnapshot?: CountdownEngineOptions['onSnapshot'];
|
|
6
|
+
onStateChange?: CountdownEngineOptions['onStateChange'];
|
|
7
|
+
onError?: CountdownEngineOptions['onError'];
|
|
8
|
+
}
|
|
9
|
+
interface UseCountdownControls {
|
|
10
|
+
start: () => boolean;
|
|
11
|
+
pause: () => boolean;
|
|
12
|
+
resume: () => boolean;
|
|
13
|
+
reset: (nextInitialSeconds?: number) => boolean;
|
|
14
|
+
stop: () => boolean;
|
|
15
|
+
setSeconds: (value: number) => void;
|
|
16
|
+
}
|
|
17
|
+
interface UseCountdownResult extends UseCountdownControls {
|
|
18
|
+
snapshot: CountdownSnapshot;
|
|
19
|
+
state: TimerState;
|
|
20
|
+
totalSeconds: number;
|
|
21
|
+
parts: CountdownSnapshot['parts'];
|
|
22
|
+
isRunning: boolean;
|
|
23
|
+
isCompleted: boolean;
|
|
24
|
+
}
|
|
25
|
+
declare function useCountdown(initialSeconds: number, options?: UseCountdownOptions): UseCountdownResult;
|
|
26
|
+
|
|
27
|
+
export { type UseCountdownControls, type UseCountdownOptions, type UseCountdownResult, useCountdown };
|
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.2.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",
|
|
@@ -9,7 +19,8 @@
|
|
|
9
19
|
"exports": {
|
|
10
20
|
".": {
|
|
11
21
|
"types": "./dist/index.d.ts",
|
|
12
|
-
"import": "./dist/index.js"
|
|
22
|
+
"import": "./dist/index.js",
|
|
23
|
+
"require": "./dist/index.cjs"
|
|
13
24
|
}
|
|
14
25
|
},
|
|
15
26
|
"files": [
|
|
@@ -33,7 +44,7 @@
|
|
|
33
44
|
"react": ">=17.0.0"
|
|
34
45
|
},
|
|
35
46
|
"dependencies": {
|
|
36
|
-
"@timekeeper-countdown/core": "^0.
|
|
47
|
+
"@timekeeper-countdown/core": "^0.2.0"
|
|
37
48
|
},
|
|
38
49
|
"devDependencies": {
|
|
39
50
|
"@testing-library/jest-dom": "^6.4.2",
|