@crup/react-timer-hook 0.0.1-alpha.8 → 0.0.1
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 +140 -22
- package/dist/chunk-OYRPLLEV.js +1 -0
- package/dist/chunk-XXJAJJJ6.js +1 -0
- package/dist/diagnostics.cjs +1 -0
- package/dist/diagnostics.d.cts +9 -0
- package/dist/diagnostics.d.ts +9 -0
- package/dist/diagnostics.js +1 -0
- package/dist/duration.cjs +1 -0
- package/dist/duration.d.cts +5 -0
- package/dist/duration.d.ts +5 -0
- package/dist/duration.js +1 -0
- package/dist/group.cjs +1 -0
- package/dist/group.d.cts +6 -0
- package/dist/group.d.ts +6 -0
- package/dist/group.js +1 -0
- package/dist/index.cjs +1 -1
- package/dist/index.d.cts +3 -126
- package/dist/index.d.ts +3 -126
- package/dist/index.js +1 -1
- package/dist/schedules.cjs +1 -0
- package/dist/schedules.d.cts +6 -0
- package/dist/schedules.d.ts +6 -0
- package/dist/schedules.js +1 -0
- package/dist/types-D-Vzr-PF.d.cts +133 -0
- package/dist/types-D-Vzr-PF.d.ts +133 -0
- package/package.json +47 -6
package/README.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# @crup/react-timer-hook
|
|
2
2
|
|
|
3
|
-
> React
|
|
3
|
+
> A lightweight React hooks library for building timers, stopwatches, and real-time clocks with minimal boilerplate.
|
|
4
4
|
|
|
5
5
|
[](https://www.npmjs.com/package/@crup/react-timer-hook?activeTab=versions)
|
|
6
6
|
[](https://www.npmjs.com/package/@crup/react-timer-hook)
|
|
@@ -15,16 +15,17 @@
|
|
|
15
15
|
|
|
16
16
|
## Why this exists
|
|
17
17
|
|
|
18
|
-
|
|
18
|
+
Timers get messy when a product needs pause and resume, countdowns tied to server time, async work, or a screen full of independent rows.
|
|
19
19
|
|
|
20
|
-
`@crup/react-timer-hook` keeps the
|
|
20
|
+
`@crup/react-timer-hook` keeps the default import small and lets you add only the pieces your screen needs:
|
|
21
21
|
|
|
22
|
-
- ⏱️ `useTimer()` for one lifecycle: stopwatch, countdown, clock,
|
|
23
|
-
-
|
|
24
|
-
-
|
|
25
|
-
-
|
|
26
|
-
-
|
|
27
|
-
-
|
|
22
|
+
- ⏱️ `useTimer()` from the root package for one lifecycle: stopwatch, countdown, clock, or custom flow.
|
|
23
|
+
- 🔋 Add schedules, timer groups, duration helpers, and diagnostics only when a screen needs them.
|
|
24
|
+
- 🧭 `useTimerGroup()` from `/group` for many keyed lifecycles with one shared scheduler.
|
|
25
|
+
- 📡 `useScheduledTimer()` from `/schedules` for polling and timing context.
|
|
26
|
+
- 🧩 `durationParts()` from `/duration` for common display math.
|
|
27
|
+
- 🧪 Tested against rerenders, React Strict Mode, async callbacks, cleanup, and multi-timer screens.
|
|
28
|
+
- 🤖 AI-ready docs are available through hosted `llms.txt`, `llms-full.txt`, and an optional MCP docs helper.
|
|
28
29
|
|
|
29
30
|
## Install
|
|
30
31
|
|
|
@@ -35,17 +36,43 @@ npm install @crup/react-timer-hook@alpha
|
|
|
35
36
|
pnpm add @crup/react-timer-hook@alpha
|
|
36
37
|
```
|
|
37
38
|
|
|
39
|
+
Runtime requirements: Node 18+ and React 18+.
|
|
40
|
+
|
|
38
41
|
```tsx
|
|
39
|
-
import {
|
|
42
|
+
import { useTimer } from '@crup/react-timer-hook';
|
|
43
|
+
import { durationParts } from '@crup/react-timer-hook/duration';
|
|
44
|
+
import { useTimerGroup } from '@crup/react-timer-hook/group';
|
|
45
|
+
import { useScheduledTimer } from '@crup/react-timer-hook/schedules';
|
|
40
46
|
```
|
|
41
47
|
|
|
42
48
|
## Live recipes
|
|
43
49
|
|
|
44
50
|
Each recipe has a live playground and a focused code sample:
|
|
45
51
|
|
|
46
|
-
- Basic: [wall clock](https://crup.github.io/react-timer-hook/recipes/basic/wall-clock/), [stopwatch](https://crup.github.io/react-timer-hook/recipes/basic/stopwatch/), [absolute countdown](https://crup.github.io/react-timer-hook/recipes/basic/absolute-countdown/), [pausable countdown](https://crup.github.io/react-timer-hook/recipes/basic/pausable-countdown/), [manual controls](https://crup.github.io/react-timer-hook/recipes/basic/manual-controls/)
|
|
47
|
-
- Intermediate: [once-only onEnd](https://crup.github.io/react-timer-hook/recipes/intermediate/once-only-on-end/), [polling schedule](https://crup.github.io/react-timer-hook/recipes/intermediate/polling-schedule/), [poll and cancel](https://crup.github.io/react-timer-hook/recipes/intermediate/poll-and-cancel/), [backend event stop](https://crup.github.io/react-timer-hook/recipes/intermediate/backend-event-stop/), [
|
|
48
|
-
- Advanced: [many display countdowns](https://crup.github.io/react-timer-hook/recipes/advanced/many-display-countdowns/), [timer group](https://crup.github.io/react-timer-hook/recipes/advanced/timer-group/), [group controls](https://crup.github.io/react-timer-hook/recipes/advanced/group-controls/), [per-item polling](https://crup.github.io/react-timer-hook/recipes/advanced/per-item-polling/), [dynamic items](https://crup.github.io/react-timer-hook/recipes/advanced/dynamic-items/)
|
|
52
|
+
- Basic: [wall clock](https://crup.github.io/react-timer-hook/recipes/basic/wall-clock/), [stopwatch](https://crup.github.io/react-timer-hook/recipes/basic/stopwatch/), [absolute countdown](https://crup.github.io/react-timer-hook/recipes/basic/absolute-countdown/), [pausable countdown](https://crup.github.io/react-timer-hook/recipes/basic/pausable-countdown/), [OTP resend cooldown](https://crup.github.io/react-timer-hook/recipes/basic/otp-resend/), [manual controls](https://crup.github.io/react-timer-hook/recipes/basic/manual-controls/)
|
|
53
|
+
- Intermediate: [once-only onEnd](https://crup.github.io/react-timer-hook/recipes/intermediate/once-only-on-end/), [polling schedule](https://crup.github.io/react-timer-hook/recipes/intermediate/polling-schedule/), [autosave heartbeat](https://crup.github.io/react-timer-hook/recipes/intermediate/autosave-heartbeat/), [poll and cancel](https://crup.github.io/react-timer-hook/recipes/intermediate/poll-and-cancel/), [backend event stop](https://crup.github.io/react-timer-hook/recipes/intermediate/backend-event-stop/), [diagnostics](https://crup.github.io/react-timer-hook/recipes/intermediate/debug-logs/)
|
|
54
|
+
- Advanced: [many display countdowns](https://crup.github.io/react-timer-hook/recipes/advanced/many-display-countdowns/), [timer group](https://crup.github.io/react-timer-hook/recipes/advanced/timer-group/), [group controls](https://crup.github.io/react-timer-hook/recipes/advanced/group-controls/), [checkout holds](https://crup.github.io/react-timer-hook/recipes/advanced/checkout-holds/), [per-item polling](https://crup.github.io/react-timer-hook/recipes/advanced/per-item-polling/), [dynamic items](https://crup.github.io/react-timer-hook/recipes/advanced/dynamic-items/), [toast auto-dismiss](https://crup.github.io/react-timer-hook/recipes/advanced/toast-auto-dismiss/)
|
|
55
|
+
|
|
56
|
+
## Use cases
|
|
57
|
+
|
|
58
|
+
| Product case | Use | Import | Recipe |
|
|
59
|
+
| --- | --- | --- | --- |
|
|
60
|
+
| Stopwatch, call timer, workout timer | Core | `@crup/react-timer-hook` | [Stopwatch](https://crup.github.io/react-timer-hook/recipes/basic/stopwatch/) |
|
|
61
|
+
| Wall clock or "last updated" display | Core | `@crup/react-timer-hook` | [Wall clock](https://crup.github.io/react-timer-hook/recipes/basic/wall-clock/) |
|
|
62
|
+
| Auction, reservation, or job deadline | Core | `@crup/react-timer-hook` | [Absolute countdown](https://crup.github.io/react-timer-hook/recipes/basic/absolute-countdown/) |
|
|
63
|
+
| Focus timer or checkout hold that pauses | Core + duration | `@crup/react-timer-hook` + `/duration` | [Pausable countdown](https://crup.github.io/react-timer-hook/recipes/basic/pausable-countdown/) |
|
|
64
|
+
| OTP resend or retry cooldown | Core + duration | `@crup/react-timer-hook` + `/duration` | [OTP resend cooldown](https://crup.github.io/react-timer-hook/recipes/basic/otp-resend/) |
|
|
65
|
+
| Backend status polling | Schedules | `@crup/react-timer-hook/schedules` | [Polling schedule](https://crup.github.io/react-timer-hook/recipes/intermediate/polling-schedule/) |
|
|
66
|
+
| Draft autosave or presence heartbeat | Schedules | `@crup/react-timer-hook/schedules` | [Autosave heartbeat](https://crup.github.io/react-timer-hook/recipes/intermediate/autosave-heartbeat/) |
|
|
67
|
+
| Polling that can close early | Schedules | `@crup/react-timer-hook/schedules` | [Poll and cancel](https://crup.github.io/react-timer-hook/recipes/intermediate/poll-and-cancel/) |
|
|
68
|
+
| Auction list with independent row controls | Timer group | `@crup/react-timer-hook/group` | [Timer group](https://crup.github.io/react-timer-hook/recipes/advanced/timer-group/) |
|
|
69
|
+
| Checkout holds with independent controls | Timer group | `@crup/react-timer-hook/group` | [Checkout holds](https://crup.github.io/react-timer-hook/recipes/advanced/checkout-holds/) |
|
|
70
|
+
| Upload/job dashboard with per-row polling | Timer group + schedules | `@crup/react-timer-hook/group` | [Per-item polling](https://crup.github.io/react-timer-hook/recipes/advanced/per-item-polling/) |
|
|
71
|
+
| Toast expiry or runtime item timers | Timer group | `@crup/react-timer-hook/group` | [Toast auto-dismiss](https://crup.github.io/react-timer-hook/recipes/advanced/toast-auto-dismiss/) |
|
|
72
|
+
|
|
73
|
+
See the full use-case guide: https://crup.github.io/react-timer-hook/use-cases/
|
|
74
|
+
|
|
75
|
+
Design assumptions and runtime limits: https://crup.github.io/react-timer-hook/project/caveats/
|
|
49
76
|
|
|
50
77
|
## Quick examples
|
|
51
78
|
|
|
@@ -99,7 +126,9 @@ export function AuctionTimer({ auctionId, expiresAt }: {
|
|
|
99
126
|
Schedules run while the timer is active. Slow async work is skipped by default with `overlap: 'skip'`.
|
|
100
127
|
|
|
101
128
|
```tsx
|
|
102
|
-
|
|
129
|
+
import { useScheduledTimer } from '@crup/react-timer-hook/schedules';
|
|
130
|
+
|
|
131
|
+
const timer = useScheduledTimer({
|
|
103
132
|
autoStart: true,
|
|
104
133
|
updateIntervalMs: 1000,
|
|
105
134
|
endWhen: snapshot => snapshot.now >= expiresAt,
|
|
@@ -108,7 +137,8 @@ const timer = useTimer({
|
|
|
108
137
|
id: 'auction-poll',
|
|
109
138
|
everyMs: 5000,
|
|
110
139
|
overlap: 'skip',
|
|
111
|
-
callback: async (_snapshot, controls) => {
|
|
140
|
+
callback: async (_snapshot, controls, context) => {
|
|
141
|
+
console.log(`auction poll fired ${context.firedAt - context.scheduledAt}ms late`);
|
|
112
142
|
const auction = await api.getAuction(auctionId);
|
|
113
143
|
if (auction.status === 'sold') controls.cancel('sold');
|
|
114
144
|
},
|
|
@@ -122,6 +152,8 @@ const timer = useTimer({
|
|
|
122
152
|
Use `useTimerGroup()` when every row needs its own pause, resume, cancel, restart, schedules, or `onEnd`.
|
|
123
153
|
|
|
124
154
|
```tsx
|
|
155
|
+
import { useTimerGroup } from '@crup/react-timer-hook/group';
|
|
156
|
+
|
|
125
157
|
const timers = useTimerGroup({
|
|
126
158
|
updateIntervalMs: 1000,
|
|
127
159
|
items: auctions.map(auction => ({
|
|
@@ -133,15 +165,100 @@ const timers = useTimerGroup({
|
|
|
133
165
|
});
|
|
134
166
|
```
|
|
135
167
|
|
|
168
|
+
## API reference
|
|
169
|
+
|
|
170
|
+
### `useTimer()` settings
|
|
171
|
+
|
|
172
|
+
| Key | Type | Required | Description |
|
|
173
|
+
| --- | --- | --- | --- |
|
|
174
|
+
| `autoStart` | `boolean` | No | Starts the lifecycle after mount. Defaults to `false`. |
|
|
175
|
+
| `updateIntervalMs` | `number` | No | Render/update cadence in milliseconds. Defaults to `1000`. This does not define elapsed time; elapsed time is calculated from timestamps. Use a smaller value like `100` or `20` when the UI needs finer updates. |
|
|
176
|
+
| `endWhen` | `(snapshot) => boolean` | No | Ends the lifecycle when it returns `true`. Use this for countdowns, timeouts, and custom stop conditions. |
|
|
177
|
+
| `onEnd` | `(snapshot, controls) => void \| Promise<void>` | No | Called once per generation when `endWhen` ends the lifecycle. `restart()` creates a new generation. |
|
|
178
|
+
| `onError` | `(error, snapshot, controls) => void` | No | Handles sync throws and async rejections from `onEnd`. Also used as the fallback for schedule callback failures when a schedule does not define `onError`. |
|
|
179
|
+
|
|
180
|
+
### `useScheduledTimer()` settings
|
|
181
|
+
|
|
182
|
+
Import from `@crup/react-timer-hook/schedules` when you need polling or scheduled side effects.
|
|
183
|
+
|
|
184
|
+
| Key | Type | Required | Description |
|
|
185
|
+
| --- | --- | --- | --- |
|
|
186
|
+
| `autoStart` | `boolean` | No | Starts the lifecycle after mount. Defaults to `false`. |
|
|
187
|
+
| `updateIntervalMs` | `number` | No | Render/update cadence in milliseconds. Defaults to `1000`. Scheduled callbacks can run on their own cadence. |
|
|
188
|
+
| `endWhen` | `(snapshot) => boolean` | No | Ends the lifecycle when it returns `true`. |
|
|
189
|
+
| `onEnd` | `(snapshot, controls) => void \| Promise<void>` | No | Called once per generation when `endWhen` ends the lifecycle. |
|
|
190
|
+
| `onError` | `(error, snapshot, controls) => void` | No | Handles sync throws and async rejections from `onEnd`. |
|
|
191
|
+
| `schedules` | `TimerSchedule[]` | No | Scheduled side effects that run while the timer is active. Async overlap defaults to `skip`. |
|
|
192
|
+
| `diagnostics` | `TimerDiagnostics` | No | Optional lifecycle and schedule events. No logs are emitted unless you pass a logger. |
|
|
193
|
+
|
|
194
|
+
### `TimerSchedule`
|
|
195
|
+
|
|
196
|
+
| Key | Type | Required | Description |
|
|
197
|
+
| --- | --- | --- | --- |
|
|
198
|
+
| `id` | `string` | No | Stable identifier used in diagnostics events and schedule context. Falls back to the array index. |
|
|
199
|
+
| `everyMs` | `number` | Yes | Schedule cadence in milliseconds. Must be positive and finite. |
|
|
200
|
+
| `leading` | `boolean` | No | Runs the schedule immediately when the timer starts or resumes into a new generation. Defaults to `false`. |
|
|
201
|
+
| `overlap` | `'skip' \| 'allow'` | No | Controls async overlap. Defaults to `skip`, so a pending callback prevents another run. |
|
|
202
|
+
| `callback` | `(snapshot, controls, context) => void \| Promise<void>` | Yes | Scheduled side effect. Receives timing context with `scheduledAt`, `firedAt`, `nextRunAt`, `overdueCount`, and `effectiveEveryMs`. |
|
|
203
|
+
| `onError` | `(error, snapshot, controls, context) => void` | No | Handles sync throws and async rejections from that schedule's `callback`. Falls back to the timer or item `onError` when omitted. |
|
|
204
|
+
|
|
205
|
+
### `useTimerGroup()` settings
|
|
206
|
+
|
|
207
|
+
Import from `@crup/react-timer-hook/group` when many keyed items need independent lifecycle control.
|
|
208
|
+
|
|
209
|
+
| Key | Type | Required | Description |
|
|
210
|
+
| --- | --- | --- | --- |
|
|
211
|
+
| `updateIntervalMs` | `number` | No | Shared scheduler cadence for the group. Defaults to `1000`. |
|
|
212
|
+
| `items` | `TimerGroupItem[]` | No | Initial/synced timer item definitions. Each item has its own lifecycle state. |
|
|
213
|
+
| `diagnostics` | `TimerDiagnostics` | No | Optional lifecycle and schedule events for group timers. |
|
|
214
|
+
|
|
215
|
+
### `TimerGroupItem`
|
|
216
|
+
|
|
217
|
+
| Key | Type | Required | Description |
|
|
218
|
+
| --- | --- | --- | --- |
|
|
219
|
+
| `id` | `string` | Yes | Stable key for the item. Duplicate IDs throw. |
|
|
220
|
+
| `autoStart` | `boolean` | No | Starts the item automatically when it is added or synced. Defaults to `false`. |
|
|
221
|
+
| `endWhen` | `(snapshot) => boolean` | No | Ends that item when it returns `true`. |
|
|
222
|
+
| `onEnd` | `(snapshot, controls) => void \| Promise<void>` | No | Called once per item generation when that item ends naturally. |
|
|
223
|
+
| `onError` | `(error, snapshot, controls) => void` | No | Handles sync throws and async rejections from that item's `onEnd`. Also used as the fallback for that item's schedule callback failures. |
|
|
224
|
+
| `schedules` | `TimerSchedule[]` | No | Per-item schedules with the same contract as `useScheduledTimer()`. |
|
|
225
|
+
|
|
226
|
+
### Values and controls
|
|
227
|
+
|
|
228
|
+
| Key | Type | Description |
|
|
229
|
+
| --- | --- | --- |
|
|
230
|
+
| `status` | `'idle' \| 'running' \| 'paused' \| 'ended' \| 'cancelled'` | Current lifecycle state. |
|
|
231
|
+
| `now` | `number` | Wall-clock timestamp from `Date.now()`. Use for clocks and absolute deadlines. |
|
|
232
|
+
| `tick` | `number` | Number of render/update ticks produced in the current generation. |
|
|
233
|
+
| `startedAt` | `number \| null` | Wall-clock timestamp when the current generation started. |
|
|
234
|
+
| `pausedAt` | `number \| null` | Wall-clock timestamp for the current pause, or `null`. |
|
|
235
|
+
| `endedAt` | `number \| null` | Wall-clock timestamp when `endWhen` ended the lifecycle. |
|
|
236
|
+
| `cancelledAt` | `number \| null` | Wall-clock timestamp when `cancel()` ended the lifecycle early. |
|
|
237
|
+
| `cancelReason` | `string \| null` | Optional reason passed to `cancel(reason)`. |
|
|
238
|
+
| `elapsedMilliseconds` | `number` | Active elapsed duration calculated from monotonic time, excluding paused time. |
|
|
239
|
+
| `isIdle` | `boolean` | Convenience flag for `status === 'idle'`. |
|
|
240
|
+
| `isRunning` | `boolean` | Convenience flag for `status === 'running'`. |
|
|
241
|
+
| `isPaused` | `boolean` | Convenience flag for `status === 'paused'`. |
|
|
242
|
+
| `isEnded` | `boolean` | Convenience flag for `status === 'ended'`. |
|
|
243
|
+
| `isCancelled` | `boolean` | Convenience flag for `status === 'cancelled'`. |
|
|
244
|
+
| `start()` | `function` | Starts an idle timer. No-op if it is already started. |
|
|
245
|
+
| `pause()` | `function` | Pauses a running timer. |
|
|
246
|
+
| `resume()` | `function` | Resumes a paused timer from the paused elapsed value. |
|
|
247
|
+
| `reset(options?)` | `function` | Resets to idle and zero elapsed time. Pass `{ autoStart: true }` to reset directly into running. |
|
|
248
|
+
| `restart()` | `function` | Starts a new running generation from zero elapsed time. |
|
|
249
|
+
| `cancel(reason?)` | `function` | Terminal early stop. Does not call `onEnd`. |
|
|
250
|
+
|
|
136
251
|
## Bundle size
|
|
137
252
|
|
|
138
|
-
|
|
253
|
+
The default import stays small. Add the other pieces only when that screen needs them.
|
|
139
254
|
|
|
140
|
-
|
|
|
141
|
-
| --- | ---: | ---: | ---: |
|
|
142
|
-
|
|
|
143
|
-
|
|
|
144
|
-
|
|
|
255
|
+
| Piece | Import | Best for | Raw | Gzip | Brotli |
|
|
256
|
+
| --- | --- | --- | ---: | ---: | ---: |
|
|
257
|
+
| ⏱️ Core | `@crup/react-timer-hook` | Stopwatch, countdown, clock, custom lifecycle | 4.44 kB | 1.52 kB | 1.40 kB |
|
|
258
|
+
| 🧭 Timer group | `@crup/react-timer-hook/group` | Many independent row/item timers | 10.93 kB | 3.83 kB | 3.50 kB |
|
|
259
|
+
| 📡 Schedules | `@crup/react-timer-hook/schedules` | Polling, cadence callbacks, overdue timing context | 8.62 kB | 3.02 kB | 2.78 kB |
|
|
260
|
+
| 🧩 Duration | `@crup/react-timer-hook/duration` | `days`, `hours`, `minutes`, `seconds`, `milliseconds` | 318 B | 224 B | 192 B |
|
|
261
|
+
| 🔎 Diagnostics | `@crup/react-timer-hook/diagnostics` | Optional lifecycle and schedule event logging | 105 B | 115 B | 90 B |
|
|
145
262
|
|
|
146
263
|
CI writes a size summary to the GitHub Actions UI and posts bundle-size reports on pull requests.
|
|
147
264
|
|
|
@@ -180,5 +297,6 @@ Issues, recipes, docs improvements, and focused bug reports are welcome.
|
|
|
180
297
|
- Read the docs: https://crup.github.io/react-timer-hook/
|
|
181
298
|
- Open an issue: https://github.com/crup/react-timer-hook/issues
|
|
182
299
|
- See the contributing guide: ./CONTRIBUTING.md
|
|
300
|
+
- Release policy: https://crup.github.io/react-timer-hook/project/release-channels/
|
|
183
301
|
|
|
184
|
-
The package targets Node
|
|
302
|
+
The package targets Node 18+ and React 18+.
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{c as C,d as y,e as T,l as b}from"./chunk-XXJAJJJ6.js";function E(e){return e?typeof e=="function"?{enabled:!0,includeTicks:!1,logger:e}:{enabled:e.enabled!==!1,includeTicks:e.includeTicks??!1,label:e.label,logger:e.logger}:{enabled:!1,includeTicks:!1}}function M(e,n){let t=E(e);!t.enabled||!t.logger||n.type==="timer:tick"&&!t.includeTicks||t.logger({...n,label:n.label??t.label})}function R(e,n){return{generation:n,tick:e.tick,now:e.now,elapsedMilliseconds:e.elapsedMilliseconds,status:e.status}}function k(){return{lastRunAt:null,pendingCount:0,leadingGeneration:null,signature:""}}function G({schedules:e=[],states:n,snapshot:t,generation:i,controls:r,activation:o=!1,isLive:s,onError:a,onEvent:m}){let u=new Set;e.forEach((l,h)=>{let c=f(l,h);u.add(c);let d=n.get(c);if(d||(d=k(),d.signature=g(l,h),n.set(c,d)),o&&l.leading&&d.leadingGeneration!==i){d.leadingGeneration=i,x(l,c,d,t,i,r,v(l,c,t.now,t.now,0),s,a,m);return}d.lastRunAt===null&&(d.lastRunAt=t.now);let p=Math.floor((t.now-d.lastRunAt)/l.everyMs);if(p>=1){let D=d.lastRunAt+p*l.everyMs;x(l,c,d,t,i,r,v(l,c,D,t.now,p-1),s,a,m)}});for(let l of n.keys())u.has(l)||n.delete(l)}function P(e,n,t,i){let r=i;return e?.forEach((o,s)=>{let a=f(o,s),u=n.get(a)?.lastRunAt??t;r=Math.min(r,Math.max(1,u+o.everyMs-t))}),r}function O(e,n,t,i){let r=new Set;e?.forEach((o,s)=>{let a=f(o,s),m=g(o,s);r.add(a);let u=n.get(a);if(u)u.signature!==m&&(u.lastRunAt=i?t:null,u.leadingGeneration=null,u.signature=m);else{let l=k();l.lastRunAt=i?t:null,l.signature=m,n.set(a,l)}});for(let o of n.keys())r.has(o)||n.delete(o)}function N(e){return JSON.stringify((e??[]).map((n,t)=>g(n,t)))}function H(e){let n=new Set;e?.forEach((t,i)=>{C(t.everyMs,"schedule.everyMs");let r=f(t,i);if(n.has(r))throw new Error(`Duplicate schedule id "${r}"`);n.add(r)})}function v(e,n,t,i,r){return{scheduleId:e.id??n,scheduledAt:t,firedAt:i,nextRunAt:t+e.everyMs,overdueCount:r,effectiveEveryMs:e.everyMs}}function x(e,n,t,i,r,o,s,a,m,u){if(t.pendingCount>0&&(e.overlap??"skip")==="skip"){t.lastRunAt=s.scheduledAt,S(a,r,u,{type:"schedule:skip",context:s,reason:"overlap"});return}t.lastRunAt=s.scheduledAt,t.pendingCount+=1,S(a,r,u,{type:"schedule:start",context:s}),Promise.resolve().then(()=>e.callback(i,o,s)).then(()=>S(a,r,u,{type:"schedule:end",context:s}),l=>{if(a(r))try{e.onError?e.onError(l,i,o,s):m?.(l,i,o,s)}finally{u?.({type:"schedule:error",context:s,error:l})}}).finally(()=>{a(r)&&(t.pendingCount=Math.max(0,t.pendingCount-1))})}function f(e,n){return e.id??String(n)}function g(e,n){return JSON.stringify([e.id??n,e.everyMs,e.leading??!1,e.overlap??"skip"])}function S(e,n,t,i){e(n)&&t?.(i)}function W(e,n){return{state:y(n),definition:e,endCalledGeneration:null}}function F(e){e.endCalledGeneration=null}function $(e,n){return T(e.state,n)}function j(e,n,t,i){let r=T(e.state,n);if(!e.definition.endWhen?.(r)||!b(e.state,n))return null;let o=T(e.state,n);return I(e,o,t,i),o}function I(e,n,t,i){let r=e.state.generation;if(e.endCalledGeneration!==r){e.endCalledGeneration=r;try{let o=e.definition.onEnd?.(n,t);o&&i&&Promise.resolve(o).catch(s=>i?.(s,n,r))}catch(o){if(i){i(o,n,r);return}throw o}}}export{M as a,R as b,G as c,P as d,O as e,N as f,H as g,W as h,F as i,$ as j,j as k};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
function o(n,e){return{start:()=>{e()&&n.start()},pause:()=>{e()&&n.pause()},resume:()=>{e()&&n.resume()},reset:t=>{e()&&n.reset(t)},restart:()=>{e()&&n.restart()},cancel:t=>{e()&&n.cancel(t)}}}function u(){let n=Date.now(),e=typeof performance<"u"&&typeof performance.now=="function"?performance.now():n;return{wallNow:n,monotonicNow:e}}function i(n,e){if(!Number.isFinite(n)||n<=0)throw new RangeError(`${e} must be a finite number greater than 0`)}function c(n){return{status:"idle",generation:0,tick:0,startedAt:null,pausedAt:null,endedAt:null,cancelledAt:null,cancelReason:null,baseElapsedMilliseconds:0,activeStartedAtMonotonic:null,now:n.wallNow}}function r(n,e){return n.status!=="running"||n.activeStartedAtMonotonic===null?n.baseElapsedMilliseconds:Math.max(0,n.baseElapsedMilliseconds+e.monotonicNow-n.activeStartedAtMonotonic)}function s(n,e){let t=r(n,e);return{status:n.status,now:e.wallNow,tick:n.tick,startedAt:n.startedAt,pausedAt:n.pausedAt,endedAt:n.endedAt,cancelledAt:n.cancelledAt,cancelReason:n.cancelReason,elapsedMilliseconds:t,isIdle:n.status==="idle",isRunning:n.status==="running",isPaused:n.status==="paused",isEnded:n.status==="ended",isCancelled:n.status==="cancelled"}}function m(n,e){return n.status!=="idle"?!1:(n.status="running",n.startedAt=e.wallNow,n.pausedAt=null,n.endedAt=null,n.cancelledAt=null,n.cancelReason=null,n.activeStartedAtMonotonic=e.monotonicNow,n.now=e.wallNow,!0)}function p(n,e){return n.status!=="running"?!1:(n.baseElapsedMilliseconds=r(n,e),n.activeStartedAtMonotonic=null,n.status="paused",n.pausedAt=e.wallNow,n.now=e.wallNow,!0)}function w(n,e){return n.status!=="paused"?!1:(n.status="running",n.pausedAt=null,n.activeStartedAtMonotonic=e.monotonicNow,n.now=e.wallNow,!0)}function l(n,e,t={}){return n.generation+=1,n.tick=0,n.status=t.autoStart?"running":"idle",n.startedAt=t.autoStart?e.wallNow:null,n.pausedAt=null,n.endedAt=null,n.cancelledAt=null,n.cancelReason=null,n.baseElapsedMilliseconds=0,n.activeStartedAtMonotonic=t.autoStart?e.monotonicNow:null,n.now=e.wallNow,!0}function f(n,e){return l(n,e,{autoStart:!0})}function S(n,e,t){return n.status!=="running"&&n.status!=="paused"?!1:(n.baseElapsedMilliseconds=r(n,e),n.activeStartedAtMonotonic=null,n.status="cancelled",n.cancelledAt=e.wallNow,n.cancelReason=t??null,n.now=e.wallNow,!0)}function A(n,e){return n.status!=="running"?!1:(n.baseElapsedMilliseconds=r(n,e),n.activeStartedAtMonotonic=null,n.status="ended",n.endedAt=e.wallNow,n.now=e.wallNow,!0)}function b(n,e){return n.status!=="running"?!1:(n.tick+=1,n.now=e.wallNow,!0)}export{o as a,u as b,i as c,c as d,s as e,m as f,p as g,w as h,l as i,f as j,S as k,A as l,b as m};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
"use strict";var t=Object.defineProperty;var r=Object.getOwnPropertyDescriptor;var g=Object.getOwnPropertyNames;var c=Object.prototype.hasOwnProperty;var m=(e,i)=>{for(var s in i)t(e,s,{get:i[s],enumerable:!0})},a=(e,i,s,n)=>{if(i&&typeof i=="object"||typeof i=="function")for(let o of g(i))!c.call(e,o)&&o!==s&&t(e,o,{get:()=>i[o],enumerable:!(n=r(i,o))||n.enumerable});return e};var T=e=>a(t({},"__esModule",{value:!0}),e);var l={};m(l,{consoleTimerDiagnostics:()=>D});module.exports=T(l);function D(e={}){return{...e,logger:i=>console.debug("[timer]",i)}}0&&(module.exports={consoleTimerDiagnostics});
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { i as TimerDiagnostics } from './types-D-Vzr-PF.cjs';
|
|
2
|
+
export { j as TimerDiagnosticsEvent, k as TimerDiagnosticsLogger } from './types-D-Vzr-PF.cjs';
|
|
3
|
+
|
|
4
|
+
declare function consoleTimerDiagnostics(options?: {
|
|
5
|
+
includeTicks?: boolean;
|
|
6
|
+
label?: string;
|
|
7
|
+
}): TimerDiagnostics;
|
|
8
|
+
|
|
9
|
+
export { TimerDiagnostics, consoleTimerDiagnostics };
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { i as TimerDiagnostics } from './types-D-Vzr-PF.js';
|
|
2
|
+
export { j as TimerDiagnosticsEvent, k as TimerDiagnosticsLogger } from './types-D-Vzr-PF.js';
|
|
3
|
+
|
|
4
|
+
declare function consoleTimerDiagnostics(options?: {
|
|
5
|
+
includeTicks?: boolean;
|
|
6
|
+
label?: string;
|
|
7
|
+
}): TimerDiagnostics;
|
|
8
|
+
|
|
9
|
+
export { TimerDiagnostics, consoleTimerDiagnostics };
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
function o(i={}){return{...i,logger:e=>console.debug("[timer]",e)}}export{o as consoleTimerDiagnostics};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
"use strict";var a=Object.defineProperty;var f=Object.getOwnPropertyDescriptor;var D=Object.getOwnPropertyNames;var N=Object.prototype.hasOwnProperty;var l=(o,t)=>{for(var s in t)a(o,s,{get:t[s],enumerable:!0})},E=(o,t,s,n)=>{if(t&&typeof t=="object"||typeof t=="function")for(let r of D(t))!N.call(o,r)&&r!==s&&a(o,r,{get:()=>t[r],enumerable:!(n=f(t,r))||n.enumerable});return o};var O=o=>E(a({},"__esModule",{value:!0}),o);var h={};l(h,{durationParts:()=>i});module.exports=O(h);function i(o){let t=Math.max(0,Math.trunc(Number.isFinite(o)?o:0)),s=Math.floor(t/864e5),n=t%864e5,r=Math.floor(n/36e5),e=n%36e5,u=Math.floor(e/6e4),c=e%6e4,M=Math.floor(c/1e3);return{totalMilliseconds:t,totalSeconds:Math.floor(t/1e3),milliseconds:c%1e3,seconds:M,minutes:u,hours:r,days:s}}0&&(module.exports={durationParts});
|
package/dist/duration.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
function u(o){let t=Math.max(0,Math.trunc(Number.isFinite(o)?o:0)),a=Math.floor(t/864e5),r=t%864e5,e=Math.floor(r/36e5),s=r%36e5,c=Math.floor(s/6e4),n=s%6e4,i=Math.floor(n/1e3);return{totalMilliseconds:t,totalSeconds:Math.floor(t/1e3),milliseconds:n%1e3,seconds:i,minutes:c,hours:e,days:a}}export{u as durationParts};
|
package/dist/group.cjs
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
"use strict";var B=Object.defineProperty;var Ee=Object.getOwnPropertyDescriptor;var Ge=Object.getOwnPropertyNames;var Re=Object.prototype.hasOwnProperty;var Me=(e,t)=>{for(var o in t)B(e,o,{get:t[o],enumerable:!0})},Ne=(e,t,o,i)=>{if(t&&typeof t=="object"||typeof t=="function")for(let l of Ge(t))!Re.call(e,l)&&l!==o&&B(e,l,{get:()=>t[l],enumerable:!(i=Ee(t,l))||i.enumerable});return e};var De=e=>Ne(B({},"__esModule",{value:!0}),e);var ze={};Me(ze,{useTimerGroup:()=>we});module.exports=De(ze);var x=require("react");function T(){let e=Date.now(),t=typeof performance<"u"&&typeof performance.now=="function"?performance.now():e;return{wallNow:e,monotonicNow:t}}function N(e,t){if(!Number.isFinite(e)||e<=0)throw new RangeError(`${t} must be a finite number greater than 0`)}function Q(e,t){return{start:()=>{t()&&e.start()},pause:()=>{t()&&e.pause()},resume:()=>{t()&&e.resume()},reset:o=>{t()&&e.reset(o)},restart:()=>{t()&&e.restart()},cancel:o=>{t()&&e.cancel(o)}}}function Oe(e){return e?typeof e=="function"?{enabled:!0,includeTicks:!1,logger:e}:{enabled:e.enabled!==!1,includeTicks:e.includeTicks??!1,label:e.label,logger:e.logger}:{enabled:!1,includeTicks:!1}}function D(e,t){let o=Oe(e);!o.enabled||!o.logger||t.type==="timer:tick"&&!o.includeTicks||o.logger({...t,label:t.label??o.label})}function O(e,t){return{generation:t,tick:e.tick,now:e.now,elapsedMilliseconds:e.elapsedMilliseconds,status:e.status}}function ie(){return{lastRunAt:null,pendingCount:0,leadingGeneration:null,signature:""}}function se({schedules:e=[],states:t,snapshot:o,generation:i,controls:l,activation:c=!1,isLive:d,onError:p,onEvent:h}){let m=new Set;e.forEach((u,A)=>{let f=P(u,A);m.add(f);let y=t.get(f);if(y||(y=ie(),y.signature=X(u,A),t.set(f,y)),c&&u.leading&&y.leadingGeneration!==i){y.leadingGeneration=i,oe(u,f,y,o,i,l,re(u,f,o.now,o.now,0),d,p,h);return}y.lastRunAt===null&&(y.lastRunAt=o.now);let G=Math.floor((o.now-y.lastRunAt)/u.everyMs);if(G>=1){let M=y.lastRunAt+G*u.everyMs;oe(u,f,y,o,i,l,re(u,f,M,o.now,G-1),d,p,h)}});for(let u of t.keys())m.has(u)||t.delete(u)}function le(e,t,o,i){let l=i;return e?.forEach((c,d)=>{let p=P(c,d),m=t.get(p)?.lastRunAt??o;l=Math.min(l,Math.max(1,m+c.everyMs-o))}),l}function ae(e,t,o,i){let l=new Set;e?.forEach((c,d)=>{let p=P(c,d),h=X(c,d);l.add(p);let m=t.get(p);if(m)m.signature!==h&&(m.lastRunAt=i?o:null,m.leadingGeneration=null,m.signature=h);else{let u=ie();u.lastRunAt=i?o:null,u.signature=h,t.set(p,u)}});for(let c of t.keys())l.has(c)||t.delete(c)}function ue(e){return JSON.stringify((e??[]).map((t,o)=>X(t,o)))}function ce(e){let t=new Set;e?.forEach((o,i)=>{N(o.everyMs,"schedule.everyMs");let l=P(o,i);if(t.has(l))throw new Error(`Duplicate schedule id "${l}"`);t.add(l)})}function re(e,t,o,i,l){return{scheduleId:e.id??t,scheduledAt:o,firedAt:i,nextRunAt:o+e.everyMs,overdueCount:l,effectiveEveryMs:e.everyMs}}function oe(e,t,o,i,l,c,d,p,h,m){if(o.pendingCount>0&&(e.overlap??"skip")==="skip"){o.lastRunAt=d.scheduledAt,V(p,l,m,{type:"schedule:skip",context:d,reason:"overlap"});return}o.lastRunAt=d.scheduledAt,o.pendingCount+=1,V(p,l,m,{type:"schedule:start",context:d}),Promise.resolve().then(()=>e.callback(i,c,d)).then(()=>V(p,l,m,{type:"schedule:end",context:d}),u=>{if(p(l))try{e.onError?e.onError(u,i,c,d):h?.(u,i,c,d)}finally{m?.({type:"schedule:error",context:d,error:u})}}).finally(()=>{p(l)&&(o.pendingCount=Math.max(0,o.pendingCount-1))})}function P(e,t){return e.id??String(t)}function X(e,t){return JSON.stringify([e.id??t,e.everyMs,e.leading??!1,e.overlap??"skip"])}function V(e,t,o,i){e(t)&&o?.(i)}function de(e){return{status:"idle",generation:0,tick:0,startedAt:null,pausedAt:null,endedAt:null,cancelledAt:null,cancelReason:null,baseElapsedMilliseconds:0,activeStartedAtMonotonic:null,now:e.wallNow}}function U(e,t){return e.status!=="running"||e.activeStartedAtMonotonic===null?e.baseElapsedMilliseconds:Math.max(0,e.baseElapsedMilliseconds+t.monotonicNow-e.activeStartedAtMonotonic)}function z(e,t){let o=U(e,t);return{status:e.status,now:t.wallNow,tick:e.tick,startedAt:e.startedAt,pausedAt:e.pausedAt,endedAt:e.endedAt,cancelledAt:e.cancelledAt,cancelReason:e.cancelReason,elapsedMilliseconds:o,isIdle:e.status==="idle",isRunning:e.status==="running",isPaused:e.status==="paused",isEnded:e.status==="ended",isCancelled:e.status==="cancelled"}}function F(e,t){return e.status!=="idle"?!1:(e.status="running",e.startedAt=t.wallNow,e.pausedAt=null,e.endedAt=null,e.cancelledAt=null,e.cancelReason=null,e.activeStartedAtMonotonic=t.monotonicNow,e.now=t.wallNow,!0)}function me(e,t){return e.status!=="running"?!1:(e.baseElapsedMilliseconds=U(e,t),e.activeStartedAtMonotonic=null,e.status="paused",e.pausedAt=t.wallNow,e.now=t.wallNow,!0)}function pe(e,t){return e.status!=="paused"?!1:(e.status="running",e.pausedAt=null,e.activeStartedAtMonotonic=t.monotonicNow,e.now=t.wallNow,!0)}function Y(e,t,o={}){return e.generation+=1,e.tick=0,e.status=o.autoStart?"running":"idle",e.startedAt=o.autoStart?t.wallNow:null,e.pausedAt=null,e.endedAt=null,e.cancelledAt=null,e.cancelReason=null,e.baseElapsedMilliseconds=0,e.activeStartedAtMonotonic=o.autoStart?t.monotonicNow:null,e.now=t.wallNow,!0}function fe(e,t){return Y(e,t,{autoStart:!0})}function Te(e,t,o){return e.status!=="running"&&e.status!=="paused"?!1:(e.baseElapsedMilliseconds=U(e,t),e.activeStartedAtMonotonic=null,e.status="cancelled",e.cancelledAt=t.wallNow,e.cancelReason=o??null,e.now=t.wallNow,!0)}function Se(e,t){return e.status!=="running"?!1:(e.baseElapsedMilliseconds=U(e,t),e.activeStartedAtMonotonic=null,e.status="ended",e.endedAt=t.wallNow,e.now=t.wallNow,!0)}function ge(e,t){return e.status!=="running"?!1:(e.tick+=1,e.now=t.wallNow,!0)}function he(e,t){return{state:de(t),definition:e,endCalledGeneration:null}}function Z(e){e.endCalledGeneration=null}function C(e,t){return z(e.state,t)}function ye(e,t,o,i){let l=z(e.state,t);if(!e.definition.endWhen?.(l)||!Se(e.state,t))return null;let c=z(e.state,t);return Pe(e,c,o,i),c}function Pe(e,t,o,i){let l=e.state.generation;if(e.endCalledGeneration!==l){e.endCalledGeneration=l;try{let c=e.definition.onEnd?.(t,o);c&&i&&Promise.resolve(c).catch(d=>i?.(d,t,l))}catch(c){if(i){i(c,t,l);return}throw c}}}function we(e={}){let t=(0,x.useRef)(null);return t.current===null&&(t.current=Ue(e)),t.current.setOptions(e),(0,x.useEffect)(()=>{t.current?.commitOptions()}),(0,x.useEffect)(()=>{let i=t.current;return()=>i.destroy()},[]),{...(0,x.useSyncExternalStore)(t.current.subscribe,t.current.getSnapshot,t.current.getServerSnapshot),get:t.current.getTimer,...t.current.controls}}function Ue(e){let t=e;L(t);let o=new Set,i=new Map,l=T(),c=_(i,l.wallNow),d=c,p=null,h=$(t),m=!0,u=(n=T())=>{l=n,c=_(i,n.wallNow),o.forEach(r=>r())},A=()=>{p!==null&&(clearTimeout(p),p=null)},f=(n,r,s,a={})=>{D(t.diagnostics,{type:n,scope:"timer-group",timerId:r?.id,...O(s,r?.state.generation??0),...a})},y=n=>(r,s,a)=>{let S=Q(M(n.id),()=>i.get(n.id)===n&&n.state.generation===a);n.definition.onError?.(r,s,S),D(t.diagnostics,{type:"callback:error",scope:"timer-group",timerId:n.id,error:r,...O(s,a)})},G=(n,r,s)=>a=>{D(t.diagnostics,{type:a.type,scope:"timer-group",timerId:n.id,...a.context,..."reason"in a?{reason:a.reason}:{},..."error"in a?{error:a.error}:{},...O(r,s)})},M=n=>({start:()=>H(n),pause:()=>J(n),resume:()=>K(n),reset:r=>W(n,r),restart:()=>q(n),cancel:r=>j(n,r)}),v=(n,r=T(),s=!1)=>{if(n.state.status!=="running")return!1;let a=n.state.generation,S=Q(M(n.id),()=>i.get(n.id)===n&&n.state.generation===a),b=ye(n,r,S,y(n));if(b)return f("timer:end",n,b),!0;let g=C(n,r);return se({schedules:n.definition.schedules,states:n.schedules,snapshot:g,generation:n.state.generation,controls:S,activation:s,isLive:I=>i.get(n.id)===n&&n.state.generation===I,onError:(I,k,E)=>n.definition.onError?.(I,k,E),onEvent:G(n,g,n.state.generation)}),!1},w=(n=!0)=>{A();let r=Array.from(i.values()).filter(S=>S.state.status==="running");if(r.length===0)return;let s=T(),a=t.updateIntervalMs??1e3;for(let S of r)a=Math.min(a,le(S.definition.schedules,S.schedules,s.wallNow,a));n&&f("scheduler:start",r[0],C(r[0],s)),p=setTimeout(()=>{let S=T();for(let b of i.values()){if(b.state.status!=="running")continue;ge(b.state,S);let g=C(b,S);f("timer:tick",b,g),v(b,S)}u(S),w()},a)},te=n=>{let r=i.get(n.id);if(r)return r.definition=n,R(r,T().wallNow),{item:r,added:!1};let s=T(),a={...he(n,s),id:n.id,schedules:new Map};return i.set(n.id,a),R(a,s.wallNow),{item:a,added:!0}},ne=(n={})=>{let r=n.notify??!0,s=n.process??!0,a=n.reschedule??!0,S=n.autoStart??!0;L(t);let b=new Set,g=!1,I=T();if(t.items){for(let k of t.items){b.add(k.id);let{item:E,added:Ae}=te(k);g=g||Ae,S&&k.autoStart&&E.state.status==="idle"&&F(E.state,I)&&(g=!0,s&&(g=v(E,I,!0)||g)),s&&(g=v(E,I)||g)}for(let k of i.keys())b.has(k)||(i.delete(k),g=!0)}g&&(r?u(I):(l=I,c=_(i,I.wallNow))),(g||a)&&w(r)},be=n=>{if(ee([n]),i.has(n.id))throw new Error(`Timer item "${n.id}" already exists`);let{item:r}=te(n),s=T();n.autoStart&&F(r.state,s)&&v(r,s,!0),h=$(t),u(s),w()},Ce=(n,r)=>{let s=i.get(n);if(!s)return;let a={...s.definition,...r,id:n};ee([a]),s.definition=a,R(s,T().wallNow),v(s),h=$(t),u(),w()},Ie=n=>{i.delete(n)&&(u(),w())},ve=()=>{i.clear(),A(),u()},H=n=>{let r=i.get(n);if(!r)return;let s=T();F(r.state,s)&&(f("timer:start",r,C(r,s)),v(r,s,!0),u(s),w())},J=n=>{let r=i.get(n);if(!r)return;let s=T();me(r.state,s)&&(f("timer:pause",r,C(r,s)),u(s),w())},K=n=>{let r=i.get(n);if(!r)return;let s=T();pe(r.state,s)&&(f("timer:resume",r,C(r,s)),v(r,s,!0),u(s),w())},W=(n,r={})=>{let s=i.get(n);if(!s)return;let a=T();Y(s.state,a,r),s.schedules.clear(),R(s,a.wallNow),Z(s),f("timer:reset",s,C(s,a)),v(s,a,r.autoStart),u(a),w()},q=n=>{let r=i.get(n);if(!r)return;let s=T();fe(r.state,s),r.schedules.clear(),R(r,s.wallNow),Z(r),f("timer:restart",r,C(r,s)),v(r,s,!0),u(s),w()},j=(n,r)=>{let s=i.get(n);if(!s)return;let a=T();Te(s.state,a,r)&&(f("timer:cancel",s,C(s,a),{reason:r}),u(a),w())},ke=n=>{let r=i.get(n);return r?C(r,l):void 0},xe={add:be,update:Ce,remove:Ie,clear:ve,start:H,pause:J,resume:K,reset:W,restart:q,cancel:j,startAll:()=>Array.from(i.keys()).forEach(H),pauseAll:()=>Array.from(i.keys()).forEach(J),resumeAll:()=>Array.from(i.keys()).forEach(K),resetAll:n=>Array.from(i.keys()).forEach(r=>W(r,n)),restartAll:()=>Array.from(i.keys()).forEach(q),cancelAll:n=>Array.from(i.keys()).forEach(r=>j(r,n))};return ne({notify:!1,process:!1,reschedule:!1,autoStart:!1}),{commitOptions:()=>{m&&(m=!1,ne({notify:!0,process:!0,reschedule:!0,autoStart:!0}))},controls:xe,destroy:A,getSnapshot:()=>c,getServerSnapshot:()=>d,getTimer:ke,setOptions:n=>{L(n);let r=$(n);m=m||n.items!==t.items||r!==h,t=n,h=r},subscribe:n=>(o.add(n),()=>o.delete(n))}}function _(e,t){return{now:t,size:e.size,ids:Array.from(e.keys())}}function R(e,t){ae(e.definition.schedules,e.schedules,t,e.state.status==="running")}function $(e){return JSON.stringify([e.updateIntervalMs??1e3,...(e.items??[]).map(t=>{let o=ue(t.schedules);return[t.id,t.autoStart??!1,o??""]})])}function L(e){N(e.updateIntervalMs??1e3,"updateIntervalMs"),ee(e.items)}function ee(e){let t=new Set;e?.forEach(o=>{if(!o.id)throw new Error("Timer item id is required");if(t.has(o.id))throw new Error(`Duplicate timer item id "${o.id}"`);t.add(o.id),ce(o.schedules)})}0&&(module.exports={useTimerGroup});
|
package/dist/group.d.cts
ADDED
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import { d as UseTimerGroupOptions, e as TimerGroupResult } from './types-D-Vzr-PF.cjs';
|
|
2
|
+
export { f as TimerGroupItem, g as TimerGroupItemControls } from './types-D-Vzr-PF.cjs';
|
|
3
|
+
|
|
4
|
+
declare function useTimerGroup(options?: UseTimerGroupOptions): TimerGroupResult;
|
|
5
|
+
|
|
6
|
+
export { TimerGroupResult, UseTimerGroupOptions, useTimerGroup };
|
package/dist/group.d.ts
ADDED
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import { d as UseTimerGroupOptions, e as TimerGroupResult } from './types-D-Vzr-PF.js';
|
|
2
|
+
export { f as TimerGroupItem, g as TimerGroupItemControls } from './types-D-Vzr-PF.js';
|
|
3
|
+
|
|
4
|
+
declare function useTimerGroup(options?: UseTimerGroupOptions): TimerGroupResult;
|
|
5
|
+
|
|
6
|
+
export { TimerGroupResult, UseTimerGroupOptions, useTimerGroup };
|
package/dist/group.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{a as A,b as N,c as Z,d as _,e as ee,f as te,g as re,h as se,i as L,j as f,k as oe}from"./chunk-OYRPLLEV.js";import{a as D,b as a,c as H,f as b,g as K,h as Q,i as V,j as W,k as X,m as Y}from"./chunk-XXJAJJJ6.js";import{useEffect as ne,useRef as he,useSyncExternalStore as Se}from"react";function Te(i={}){let o=he(null);return o.current===null&&(o.current=ye(i)),o.current.setOptions(i),ne(()=>{o.current?.commitOptions()}),ne(()=>{let n=o.current;return()=>n.destroy()},[]),{...Se(o.current.subscribe,o.current.getSnapshot,o.current.getServerSnapshot),get:o.current.getTimer,...o.current.controls}}function ye(i){let o=i;q(o);let l=new Set,n=new Map,G=a(),w=$(n,G.wallNow),ie=w,k=null,v=R(o),E=!0,m=(e=a())=>{G=e,w=$(n,e.wallNow),l.forEach(t=>t())},C=()=>{k!==null&&(clearTimeout(k),k=null)},h=(e,t,r,s={})=>{A(o.diagnostics,{type:e,scope:"timer-group",timerId:t?.id,...N(r,t?.state.generation??0),...s})},ae=e=>(t,r,s)=>{let u=D(J(e.id),()=>n.get(e.id)===e&&e.state.generation===s);e.definition.onError?.(t,r,u),A(o.diagnostics,{type:"callback:error",scope:"timer-group",timerId:e.id,error:t,...N(r,s)})},ue=(e,t,r)=>s=>{A(o.diagnostics,{type:s.type,scope:"timer-group",timerId:e.id,...s.context,..."reason"in s?{reason:s.reason}:{},..."error"in s?{error:s.error}:{},...N(t,r)})},J=e=>({start:()=>O(e),pause:()=>M(e),resume:()=>P(e),reset:t=>x(e,t),restart:()=>U(e),cancel:t=>z(e,t)}),S=(e,t=a(),r=!1)=>{if(e.state.status!=="running")return!1;let s=e.state.generation,u=D(J(e.id),()=>n.get(e.id)===e&&e.state.generation===s),p=oe(e,t,u,ae(e));if(p)return h("timer:end",e,p),!0;let c=f(e,t);return Z({schedules:e.definition.schedules,states:e.schedules,snapshot:c,generation:e.state.generation,controls:u,activation:r,isLive:g=>n.get(e.id)===e&&e.state.generation===g,onError:(g,T,y)=>e.definition.onError?.(g,T,y),onEvent:ue(e,c,e.state.generation)}),!1},d=(e=!0)=>{C();let t=Array.from(n.values()).filter(u=>u.state.status==="running");if(t.length===0)return;let r=a(),s=o.updateIntervalMs??1e3;for(let u of t)s=Math.min(s,_(u.definition.schedules,u.schedules,r.wallNow,s));e&&h("scheduler:start",t[0],f(t[0],r)),k=setTimeout(()=>{let u=a();for(let p of n.values()){if(p.state.status!=="running")continue;Y(p.state,u);let c=f(p,u);h("timer:tick",p,c),S(p,u)}m(u),d()},s)},j=e=>{let t=n.get(e.id);if(t)return t.definition=e,I(t,a().wallNow),{item:t,added:!1};let r=a(),s={...se(e,r),id:e.id,schedules:new Map};return n.set(e.id,s),I(s,r.wallNow),{item:s,added:!0}},B=(e={})=>{let t=e.notify??!0,r=e.process??!0,s=e.reschedule??!0,u=e.autoStart??!0;q(o);let p=new Set,c=!1,g=a();if(o.items){for(let T of o.items){p.add(T.id);let{item:y,added:ge}=j(T);c=c||ge,u&&T.autoStart&&y.state.status==="idle"&&b(y.state,g)&&(c=!0,r&&(c=S(y,g,!0)||c)),r&&(c=S(y,g)||c)}for(let T of n.keys())p.has(T)||(n.delete(T),c=!0)}c&&(t?m(g):(G=g,w=$(n,g.wallNow))),(c||s)&&d(t)},ce=e=>{if(F([e]),n.has(e.id))throw new Error(`Timer item "${e.id}" already exists`);let{item:t}=j(e),r=a();e.autoStart&&b(t.state,r)&&S(t,r,!0),v=R(o),m(r),d()},le=(e,t)=>{let r=n.get(e);if(!r)return;let s={...r.definition,...t,id:e};F([s]),r.definition=s,I(r,a().wallNow),S(r),v=R(o),m(),d()},me=e=>{n.delete(e)&&(m(),d())},de=()=>{n.clear(),C(),m()},O=e=>{let t=n.get(e);if(!t)return;let r=a();b(t.state,r)&&(h("timer:start",t,f(t,r)),S(t,r,!0),m(r),d())},M=e=>{let t=n.get(e);if(!t)return;let r=a();K(t.state,r)&&(h("timer:pause",t,f(t,r)),m(r),d())},P=e=>{let t=n.get(e);if(!t)return;let r=a();Q(t.state,r)&&(h("timer:resume",t,f(t,r)),S(t,r,!0),m(r),d())},x=(e,t={})=>{let r=n.get(e);if(!r)return;let s=a();V(r.state,s,t),r.schedules.clear(),I(r,s.wallNow),L(r),h("timer:reset",r,f(r,s)),S(r,s,t.autoStart),m(s),d()},U=e=>{let t=n.get(e);if(!t)return;let r=a();W(t.state,r),t.schedules.clear(),I(t,r.wallNow),L(t),h("timer:restart",t,f(t,r)),S(t,r,!0),m(r),d()},z=(e,t)=>{let r=n.get(e);if(!r)return;let s=a();X(r.state,s,t)&&(h("timer:cancel",r,f(r,s),{reason:t}),m(s),d())},pe=e=>{let t=n.get(e);return t?f(t,G):void 0},fe={add:ce,update:le,remove:me,clear:de,start:O,pause:M,resume:P,reset:x,restart:U,cancel:z,startAll:()=>Array.from(n.keys()).forEach(O),pauseAll:()=>Array.from(n.keys()).forEach(M),resumeAll:()=>Array.from(n.keys()).forEach(P),resetAll:e=>Array.from(n.keys()).forEach(t=>x(t,e)),restartAll:()=>Array.from(n.keys()).forEach(U),cancelAll:e=>Array.from(n.keys()).forEach(t=>z(t,e))};return B({notify:!1,process:!1,reschedule:!1,autoStart:!1}),{commitOptions:()=>{E&&(E=!1,B({notify:!0,process:!0,reschedule:!0,autoStart:!0}))},controls:fe,destroy:C,getSnapshot:()=>w,getServerSnapshot:()=>ie,getTimer:pe,setOptions:e=>{q(e);let t=R(e);E=E||e.items!==o.items||t!==v,o=e,v=t},subscribe:e=>(l.add(e),()=>l.delete(e))}}function $(i,o){return{now:o,size:i.size,ids:Array.from(i.keys())}}function I(i,o){ee(i.definition.schedules,i.schedules,o,i.state.status==="running")}function R(i){return JSON.stringify([i.updateIntervalMs??1e3,...(i.items??[]).map(o=>{let l=te(o.schedules);return[o.id,o.autoStart??!1,l??""]})])}function q(i){H(i.updateIntervalMs??1e3,"updateIntervalMs"),F(i.items)}function F(i){let o=new Set;i?.forEach(l=>{if(!l.id)throw new Error("Timer item id is required");if(o.has(l.id))throw new Error(`Duplicate timer item id "${l.id}"`);o.add(l.id),re(l.schedules)})}export{Te as useTimerGroup};
|
package/dist/index.cjs
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
"use strict";var ne=Object.defineProperty;var ie=Object.getOwnPropertyDescriptor;var le=Object.getOwnPropertyNames;var ce=Object.prototype.hasOwnProperty;var de=(e,o)=>{for(var a in o)ne(e,a,{get:o[a],enumerable:!0})},me=(e,o,a,u)=>{if(o&&typeof o=="object"||typeof o=="function")for(let I of le(o))!ce.call(e,I)&&I!==a&&ne(e,I,{get:()=>o[I],enumerable:!(u=ie(o,I))||u.enumerable});return e};var fe=e=>me(ne({},"__esModule",{value:!0}),e);var Te={};de(Te,{durationParts:()=>ue,useTimer:()=>se,useTimerGroup:()=>ae});module.exports=fe(Te);function ue(e){let o=Math.max(0,Math.trunc(Number.isFinite(e)?e:0)),a=Math.floor(o/864e5),u=o%864e5,I=Math.floor(u/36e5),y=u%36e5,T=Math.floor(y/6e4),w=y%6e4,M=Math.floor(w/1e3);return{totalMilliseconds:o,totalSeconds:Math.floor(o/1e3),milliseconds:w%1e3,seconds:M,minutes:T,hours:I,days:a}}var m=require("react");function pe(e){return e?e===!0?{enabled:!0,includeTicks:!1,logger:console.debug}:typeof e=="function"?{enabled:!0,includeTicks:!1,logger:e}:{enabled:e.enabled!==!1,includeTicks:e.includeTicks??!1,label:e.label,logger:e.logger??console.debug}:{enabled:!1,includeTicks:!1}}function v(e,o){let a=pe(e);!a.enabled||!a.logger||o.type==="timer:tick"&&!a.includeTicks||a.logger({...o,label:o.label??a.label})}function R(e,o){return{generation:o,tick:e.tick,now:e.now,elapsedMilliseconds:e.elapsedMilliseconds,status:e.status}}function f(){let e=Date.now(),o=typeof performance<"u"&&typeof performance.now=="function"?performance.now():e;return{wallNow:e,monotonicNow:o}}function L(e,o){if(!Number.isFinite(e)||e<=0)throw new RangeError(`${o} must be a finite number greater than 0`)}function Q(e){return{status:"idle",generation:0,tick:0,startedAt:null,pausedAt:null,endedAt:null,cancelledAt:null,cancelReason:null,baseElapsedMilliseconds:0,activeStartedAtMonotonic:null,now:e.wallNow}}function V(e,o){return e.status!=="running"||e.activeStartedAtMonotonic===null?e.baseElapsedMilliseconds:Math.max(0,e.baseElapsedMilliseconds+o.monotonicNow-e.activeStartedAtMonotonic)}function p(e,o){let a=V(e,o);return{status:e.status,now:o.wallNow,tick:e.tick,startedAt:e.startedAt,pausedAt:e.pausedAt,endedAt:e.endedAt,cancelledAt:e.cancelledAt,cancelReason:e.cancelReason,elapsedMilliseconds:a,isIdle:e.status==="idle",isRunning:e.status==="running",isPaused:e.status==="paused",isEnded:e.status==="ended",isCancelled:e.status==="cancelled"}}function Y(e,o){return e.status!=="idle"?!1:(e.status="running",e.startedAt=o.wallNow,e.pausedAt=null,e.endedAt=null,e.cancelledAt=null,e.cancelReason=null,e.activeStartedAtMonotonic=o.monotonicNow,e.now=o.wallNow,!0)}function X(e,o){return e.status!=="running"?!1:(e.baseElapsedMilliseconds=V(e,o),e.activeStartedAtMonotonic=null,e.status="paused",e.pausedAt=o.wallNow,e.now=o.wallNow,!0)}function Z(e,o){return e.status!=="paused"?!1:(e.status="running",e.pausedAt=null,e.activeStartedAtMonotonic=o.monotonicNow,e.now=o.wallNow,!0)}function B(e,o,a={}){return e.generation+=1,e.tick=0,e.status=a.autoStart?"running":"idle",e.startedAt=a.autoStart?o.wallNow:null,e.pausedAt=null,e.endedAt=null,e.cancelledAt=null,e.cancelReason=null,e.baseElapsedMilliseconds=0,e.activeStartedAtMonotonic=a.autoStart?o.monotonicNow:null,e.now=o.wallNow,!0}function _(e,o){return B(e,o,{autoStart:!0})}function ee(e,o,a){return e.status==="ended"||e.status==="cancelled"?!1:(e.baseElapsedMilliseconds=V(e,o),e.activeStartedAtMonotonic=null,e.status="cancelled",e.cancelledAt=o.wallNow,e.cancelReason=a??null,e.now=o.wallNow,!0)}function te(e,o){return e.status!=="running"?!1:(e.baseElapsedMilliseconds=V(e,o),e.activeStartedAtMonotonic=null,e.status="ended",e.endedAt=o.wallNow,e.now=o.wallNow,!0)}function re(e,o){return e.status!=="running"?!1:(e.tick+=1,e.now=o.wallNow,!0)}function se(e={}){let o=e.updateIntervalMs??1e3;L(o,"updateIntervalMs"),ge(e.schedules);let a=(0,m.useRef)(e);a.current=e;let u=(0,m.useRef)(null);u.current===null&&(u.current=Q(f()));let I=(0,m.useRef)(!1),y=(0,m.useRef)(null),T=(0,m.useRef)(new Map),w=(0,m.useRef)(null),[,M]=(0,m.useReducer)(s=>s+1,0),l=(0,m.useCallback)(()=>{y.current!==null&&(clearTimeout(y.current),y.current=null)},[]),N=(0,m.useCallback)((s=f())=>p(u.current,s),[]),S=(0,m.useCallback)((s,c,g={})=>{v(a.current.debug,{type:s,scope:"timer",...R(c,u.current.generation),...g})},[]),D=(0,m.useRef)(null),z=(0,m.useCallback)(s=>{let c=u.current.generation;if(w.current!==c){w.current=c;try{a.current.onEnd?.(s,D.current)}catch(g){v(a.current.debug,{type:"callback:error",scope:"timer",...R(s,c),error:g})}}},[]),A=(0,m.useCallback)((s,c,g,k,G)=>{if(g.pending&&(s.overlap??"skip")==="skip"){v(a.current.debug,{type:"schedule:skip",scope:"timer",scheduleId:s.id??c,reason:"overlap",...R(k,G)});return}g.lastRunAt=k.now,g.pending=!0,v(a.current.debug,{type:"schedule:start",scope:"timer",scheduleId:s.id??c,...R(k,G)}),Promise.resolve().then(()=>s.callback(k,D.current)).then(()=>{v(a.current.debug,{type:"schedule:end",scope:"timer",scheduleId:s.id??c,...R(k,G)})},t=>{v(a.current.debug,{type:"schedule:error",scope:"timer",scheduleId:s.id??c,error:t,...R(k,G)})}).finally(()=>{u.current?.generation===G&&(g.pending=!1)})},[]),P=(0,m.useCallback)((s,c,g=!1)=>{let k=a.current.schedules??[],G=new Set;k.forEach((t,r)=>{let n=t.id??String(r);G.add(n);let i=T.current.get(n);if(i||(i={lastRunAt:null,pending:!1,leadingGeneration:null},T.current.set(n,i)),g&&t.leading&&i.leadingGeneration!==c){i.leadingGeneration=c,A(t,n,i,s,c);return}if(i.lastRunAt===null){i.lastRunAt=s.now;return}s.now-i.lastRunAt>=t.everyMs&&A(t,n,i,s,c)});for(let t of T.current.keys())G.has(t)||T.current.delete(t)},[A]),E=(0,m.useCallback)((s=f(),c=!1)=>{let g=u.current;if(g.status!=="running")return;let k=p(g,s),G=g.generation;if(a.current.endWhen?.(k)){if(te(g,s)){let t=p(g,s);S("timer:end",t),l(),z(t),M()}return}P(k,G,c)},[z,l,S,P]),K=(0,m.useCallback)(()=>{let s=f();if(!Y(u.current,s))return;let c=p(u.current,s);S("timer:start",c),E(s,!0),M()},[S,E]),W=(0,m.useCallback)(()=>{let s=f();if(!X(u.current,s))return;l();let c=p(u.current,s);S("timer:pause",c),M()},[l,S]),j=(0,m.useCallback)(()=>{let s=f();if(!Z(u.current,s))return;let c=p(u.current,s);S("timer:resume",c),E(s,!0),M()},[S,E]),q=(0,m.useCallback)((s={})=>{let c=f();l(),B(u.current,c,s),T.current.clear(),w.current=null;let g=p(u.current,c);S("timer:reset",g),s.autoStart&&E(c,!0),M()},[l,S,E]),O=(0,m.useCallback)(()=>{let s=f();l(),_(u.current,s),T.current.clear(),w.current=null;let c=p(u.current,s);S("timer:restart",c),E(s,!0),M()},[l,S,E]),U=(0,m.useCallback)(s=>{let c=f();if(!ee(u.current,c,s))return;l();let g=p(u.current,c);S("timer:cancel",g,{reason:s}),M()},[l,S]);D.current=(0,m.useMemo)(()=>({start:K,pause:W,resume:j,reset:q,restart:O,cancel:U}),[U,W,q,O,j,K]),(0,m.useEffect)(()=>(I.current=!0,a.current.autoStart&&u.current.status==="idle"&&D.current.start(),()=>{I.current=!1,l()}),[l]);let x=N(),$=u.current.generation,F=x.status;return(0,m.useEffect)(()=>{if(!I.current||F!=="running"){l();return}return l(),S("scheduler:start",N()),y.current=setTimeout(()=>{if(!I.current||u.current.generation!==$||u.current.status!=="running")return;let s=f();re(u.current,s);let c=p(u.current,s);S("timer:tick",c),E(s),M()},a.current.updateIntervalMs??1e3),()=>{y.current!==null&&S("scheduler:stop",N()),l()}},[l,S,$,N,E,x.tick,F]),{...x,...D.current}}function ge(e){e?.forEach(o=>L(o.everyMs,"schedule.everyMs"))}var d=require("react");function ae(e={}){let o=e.updateIntervalMs??1e3;L(o,"updateIntervalMs"),oe(e.items);let a=(0,d.useRef)(e);a.current=e;let u=(0,d.useRef)(new Map),I=(0,d.useRef)(!1),y=(0,d.useRef)(null),[,T]=(0,d.useReducer)(t=>t+1,0),w=(0,d.useCallback)(()=>{y.current!==null&&(clearTimeout(y.current),y.current=null)},[]),M=(0,d.useCallback)((t,r=f())=>p(t.state,r),[]),l=(0,d.useCallback)((t,r,n,i={})=>{v(a.current.debug,{type:t,scope:"timer-group",timerId:r?.id,...R(n,r?.state.generation??0),...i})},[]),N=(0,d.useCallback)(t=>({start:()=>O(t),pause:()=>U(t),resume:()=>x(t),reset:r=>$(t,r),restart:()=>F(t),cancel:r=>s(t,r)}),[]),S=(0,d.useCallback)((t,r)=>{let n=t.state.generation;if(t.endCalledGeneration!==n){t.endCalledGeneration=n;try{t.definition.onEnd?.(r,N(t.id))}catch(i){v(a.current.debug,{type:"callback:error",scope:"timer-group",timerId:t.id,error:i,...R(r,n)})}}},[N]),D=(0,d.useCallback)((t,r,n,i,h,b)=>{if(i.pending&&(r.overlap??"skip")==="skip"){v(a.current.debug,{type:"schedule:skip",scope:"timer-group",timerId:t.id,scheduleId:r.id??n,reason:"overlap",...R(h,b)});return}i.lastRunAt=h.now,i.pending=!0,v(a.current.debug,{type:"schedule:start",scope:"timer-group",timerId:t.id,scheduleId:r.id??n,...R(h,b)}),Promise.resolve().then(()=>r.callback(h,N(t.id))).then(()=>{v(a.current.debug,{type:"schedule:end",scope:"timer-group",timerId:t.id,scheduleId:r.id??n,...R(h,b)})},J=>{v(a.current.debug,{type:"schedule:error",scope:"timer-group",timerId:t.id,scheduleId:r.id??n,error:J,...R(h,b)})}).finally(()=>{u.current.get(t.id)?.state.generation===b&&(i.pending=!1)})},[N]),z=(0,d.useCallback)((t,r,n=!1)=>{let i=t.definition.schedules??[],h=new Set;i.forEach((b,J)=>{let H=b.id??String(J);h.add(H);let C=t.schedules.get(H);if(C||(C={lastRunAt:null,pending:!1,leadingGeneration:null},t.schedules.set(H,C)),n&&b.leading&&C.leadingGeneration!==t.state.generation){C.leadingGeneration=t.state.generation,D(t,b,H,C,r,t.state.generation);return}if(C.lastRunAt===null){C.lastRunAt=t.state.startedAt??r.now,r.now-C.lastRunAt>=b.everyMs&&D(t,b,H,C,r,t.state.generation);return}r.now-C.lastRunAt>=b.everyMs&&D(t,b,H,C,r,t.state.generation)});for(let b of t.schedules.keys())h.has(b)||t.schedules.delete(b)},[D]),A=(0,d.useCallback)((t,r=f(),n=!1)=>{if(t.state.status!=="running")return;let i=p(t.state,r);if(t.definition.endWhen?.(i)){if(te(t.state,r)){let h=p(t.state,r);l("timer:end",t,h),S(t,h)}return}z(t,i,n)},[S,l,z]),P=(0,d.useCallback)(t=>{let r=u.current.get(t.id);if(r)return r.definition=t,{item:r,added:!1};let n={id:t.id,state:Q(f()),definition:t,schedules:new Map,endCalledGeneration:null};return u.current.set(t.id,n),t.autoStart&&Y(n.state,f()),{item:n,added:!0}},[]),E=(0,d.useCallback)(()=>{let t=a.current.items??[],r=new Set,n=!1;t.forEach(i=>{r.add(i.id);let{item:h,added:b}=P(i);n=n||b,i.autoStart&&h.state.status==="idle"&&(n=Y(h.state,f())||n)});for(let i of u.current.keys())r.has(i)||(u.current.delete(i),n=!0);return n},[P]);(0,d.useEffect)(()=>{E()&&T()},[E,e.items]);let K=(0,d.useCallback)(t=>{if(oe([t]),u.current.has(t.id))throw new Error(`Timer item "${t.id}" already exists`);P(t),T()},[P]),W=(0,d.useCallback)((t,r)=>{let n=u.current.get(t);if(!n)return;let i={...n.definition,...r,id:t};oe([i]),n.definition=i,T()},[]),j=(0,d.useCallback)(t=>{u.current.delete(t),T()},[]),q=(0,d.useCallback)(()=>{u.current.clear(),w(),T()},[w]),O=(0,d.useCallback)(t=>{let r=u.current.get(t);if(!r)return;let n=f();Y(r.state,n)&&(l("timer:start",r,p(r.state,n)),A(r,n,!0),T())},[l,A]),U=(0,d.useCallback)(t=>{let r=u.current.get(t);if(!r)return;let n=f();X(r.state,n)&&(l("timer:pause",r,p(r.state,n)),T())},[l]),x=(0,d.useCallback)(t=>{let r=u.current.get(t);if(!r)return;let n=f();Z(r.state,n)&&(l("timer:resume",r,p(r.state,n)),A(r,n,!0),T())},[l,A]),$=(0,d.useCallback)((t,r={})=>{let n=u.current.get(t);if(!n)return;let i=f();B(n.state,i,r),n.schedules.clear(),n.endCalledGeneration=null,l("timer:reset",n,p(n.state,i)),r.autoStart&&A(n,i,!0),T()},[l,A]),F=(0,d.useCallback)(t=>{let r=u.current.get(t);if(!r)return;let n=f();_(r.state,n),r.schedules.clear(),r.endCalledGeneration=null,l("timer:restart",r,p(r.state,n)),A(r,n,!0),T()},[l,A]),s=(0,d.useCallback)((t,r)=>{let n=u.current.get(t);if(!n)return;let i=f();ee(n.state,i,r)&&(l("timer:cancel",n,p(n.state,i),{reason:r}),T())},[l]),g=Array.from(u.current.keys()).map(t=>`${t}:${u.current.get(t).state.status}:${u.current.get(t).state.generation}:${u.current.get(t).state.tick}`).join("|");(0,d.useEffect)(()=>{I.current=!0;let t=Array.from(u.current.values()).filter(n=>n.state.status==="running");if(t.length===0){w();return}w();let r=t[0];return l("scheduler:start",r,p(r.state,f())),y.current=setTimeout(()=>{if(!I.current)return;let n=f();for(let i of u.current.values()){if(i.state.status!=="running")continue;re(i.state,n);let h=p(i.state,n);l("timer:tick",i,h),A(i,n)}T()},a.current.updateIntervalMs??1e3),()=>{y.current!==null&&l("scheduler:stop",r,p(r.state,f())),w(),I.current=!1}},[g,w,l,A]);let k=(0,d.useCallback)(t=>{let r=u.current.get(t);if(r)return M(r)},[M]),G=f().wallNow;return(0,d.useMemo)(()=>({now:G,size:u.current.size,ids:Array.from(u.current.keys()),get:k,add:K,update:W,remove:j,clear:q,start:O,pause:U,resume:x,reset:$,restart:F,cancel:s,startAll:()=>Array.from(u.current.keys()).forEach(O),pauseAll:()=>Array.from(u.current.keys()).forEach(U),resumeAll:()=>Array.from(u.current.keys()).forEach(x),resetAll:t=>Array.from(u.current.keys()).forEach(r=>$(r,t)),restartAll:()=>Array.from(u.current.keys()).forEach(F),cancelAll:t=>Array.from(u.current.keys()).forEach(r=>s(r,t))}),[K,s,q,k,G,U,j,$,F,x,O,W])}function oe(e){let o=new Set;e?.forEach(a=>{if(o.has(a.id))throw new Error(`Duplicate timer item id "${a.id}"`);o.add(a.id),a.schedules?.forEach(u=>L(u.everyMs,"schedule.everyMs"))})}0&&(module.exports={durationParts,useTimer,useTimerGroup});
|
|
1
|
+
"use strict";var g=Object.defineProperty;var D=Object.getOwnPropertyDescriptor;var G=Object.getOwnPropertyNames;var $=Object.prototype.hasOwnProperty;var j=(e,t)=>{for(var o in t)g(e,o,{get:t[o],enumerable:!0})},q=(e,t,o,r)=>{if(t&&typeof t=="object"||typeof t=="function")for(let i of G(t))!$.call(e,i)&&i!==o&&g(e,i,{get:()=>t[i],enumerable:!(r=D(t,i))||r.enumerable});return e};var z=e=>q(g({},"__esModule",{value:!0}),e);var H={};j(H,{useTimer:()=>U});module.exports=z(H);var d=require("react");function R(e,t){return{start:()=>{t()&&e.start()},pause:()=>{t()&&e.pause()},resume:()=>{t()&&e.resume()},reset:o=>{t()&&e.reset(o)},restart:()=>{t()&&e.restart()},cancel:o=>{t()&&e.cancel(o)}}}function l(){let e=Date.now(),t=typeof performance<"u"&&typeof performance.now=="function"?performance.now():e;return{wallNow:e,monotonicNow:t}}function A(e,t){if(!Number.isFinite(e)||e<=0)throw new RangeError(`${t} must be a finite number greater than 0`)}function y(e){return{status:"idle",generation:0,tick:0,startedAt:null,pausedAt:null,endedAt:null,cancelledAt:null,cancelReason:null,baseElapsedMilliseconds:0,activeStartedAtMonotonic:null,now:e.wallNow}}function b(e,t){return e.status!=="running"||e.activeStartedAtMonotonic===null?e.baseElapsedMilliseconds:Math.max(0,e.baseElapsedMilliseconds+t.monotonicNow-e.activeStartedAtMonotonic)}function f(e,t){let o=b(e,t);return{status:e.status,now:t.wallNow,tick:e.tick,startedAt:e.startedAt,pausedAt:e.pausedAt,endedAt:e.endedAt,cancelledAt:e.cancelledAt,cancelReason:e.cancelReason,elapsedMilliseconds:o,isIdle:e.status==="idle",isRunning:e.status==="running",isPaused:e.status==="paused",isEnded:e.status==="ended",isCancelled:e.status==="cancelled"}}function N(e,t){return e.status!=="idle"?!1:(e.status="running",e.startedAt=t.wallNow,e.pausedAt=null,e.endedAt=null,e.cancelledAt=null,e.cancelReason=null,e.activeStartedAtMonotonic=t.monotonicNow,e.now=t.wallNow,!0)}function I(e,t){return e.status!=="running"?!1:(e.baseElapsedMilliseconds=b(e,t),e.activeStartedAtMonotonic=null,e.status="paused",e.pausedAt=t.wallNow,e.now=t.wallNow,!0)}function k(e,t){return e.status!=="paused"?!1:(e.status="running",e.pausedAt=null,e.activeStartedAtMonotonic=t.monotonicNow,e.now=t.wallNow,!0)}function C(e,t,o={}){return e.generation+=1,e.tick=0,e.status=o.autoStart?"running":"idle",e.startedAt=o.autoStart?t.wallNow:null,e.pausedAt=null,e.endedAt=null,e.cancelledAt=null,e.cancelReason=null,e.baseElapsedMilliseconds=0,e.activeStartedAtMonotonic=o.autoStart?t.monotonicNow:null,e.now=t.wallNow,!0}function E(e,t){return C(e,t,{autoStart:!0})}function x(e,t,o){return e.status!=="running"&&e.status!=="paused"?!1:(e.baseElapsedMilliseconds=b(e,t),e.activeStartedAtMonotonic=null,e.status="cancelled",e.cancelledAt=t.wallNow,e.cancelReason=o??null,e.now=t.wallNow,!0)}function O(e,t){return e.status!=="running"?!1:(e.baseElapsedMilliseconds=b(e,t),e.activeStartedAtMonotonic=null,e.status="ended",e.endedAt=t.wallNow,e.now=t.wallNow,!0)}function P(e,t){return e.status!=="running"?!1:(e.tick+=1,e.now=t.wallNow,!0)}function U(e={}){let t=(0,d.useRef)(null);return t.current===null&&(t.current=B(e)),t.current.setOptions(e),(0,d.useEffect)(()=>{t.current?.commitOptions()}),(0,d.useEffect)(()=>{let r=t.current;return e.autoStart&&r.controls.start(),()=>r.destroy()},[]),{...(0,d.useSyncExternalStore)(t.current.subscribe,t.current.getSnapshot,t.current.getServerSnapshot),...t.current.controls}}function B(e){let t=e;A(t.updateIntervalMs??1e3,"updateIntervalMs");let o=new Set,r=y(l()),i=f(r,l()),F=i,S=null,T=null,w=!1,s=(n=l())=>{i=f(r,n),o.forEach(a=>a())},u=()=>{S!==null&&(clearTimeout(S),S=null)},W=n=>{if(T===r.generation)return;T=r.generation;let a=r.generation,M=R(h,()=>r.generation===a),v=p=>{if(t.onError){t.onError(p,n,M);return}setTimeout(()=>{throw p},0)};try{Promise.resolve(t.onEnd?.(n,M)).catch(p=>{v(p)})}catch(p){v(p)}},m=n=>{let a=f(r,n);return!t.endWhen?.(a)||!O(r,n)?!1:(u(),s(n),W(f(r,n)),!0)},c=()=>{u(),r.status==="running"&&(S=setTimeout(()=>{if(r.status!=="running")return;let n=l();P(r,n),!m(n)&&(s(n),c())},t.updateIntervalMs??1e3))},h={start:()=>{let n=l();if(!N(r,n)){r.status==="running"&&c();return}s(n),m(n)||c()},pause:()=>{let n=l();I(r,n)&&(u(),s(n))},resume:()=>{let n=l();k(r,n)&&(s(n),m(n)||c())},reset:(n={})=>{let a=l();u(),C(r,a,n),T=null,s(a),n.autoStart&&!m(a)&&c()},restart:()=>{let n=l();u(),E(r,n),T=null,s(n),m(n)||c()},cancel:n=>{let a=l();x(r,a,n)&&(u(),s(a))}};return{commitOptions:()=>{if(w&&(w=!1,r.status==="running")){let n=l();m(n)||c()}},controls:h,destroy:u,getSnapshot:()=>i,getServerSnapshot:()=>F,setOptions:n=>{A(n.updateIntervalMs??1e3,"updateIntervalMs"),w=w||(n.updateIntervalMs??1e3)!==(t.updateIntervalMs??1e3)||n.endWhen!==t.endWhen,t=n},subscribe:n=>(o.add(n),()=>o.delete(n))}}0&&(module.exports={useTimer});
|
package/dist/index.d.cts
CHANGED
|
@@ -1,129 +1,6 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
totalMilliseconds: number;
|
|
4
|
-
totalSeconds: number;
|
|
5
|
-
milliseconds: number;
|
|
6
|
-
seconds: number;
|
|
7
|
-
minutes: number;
|
|
8
|
-
hours: number;
|
|
9
|
-
days: number;
|
|
10
|
-
};
|
|
11
|
-
type TimerSnapshot = {
|
|
12
|
-
status: TimerStatus;
|
|
13
|
-
now: number;
|
|
14
|
-
tick: number;
|
|
15
|
-
startedAt: number | null;
|
|
16
|
-
pausedAt: number | null;
|
|
17
|
-
endedAt: number | null;
|
|
18
|
-
cancelledAt: number | null;
|
|
19
|
-
cancelReason: string | null;
|
|
20
|
-
elapsedMilliseconds: number;
|
|
21
|
-
isIdle: boolean;
|
|
22
|
-
isRunning: boolean;
|
|
23
|
-
isPaused: boolean;
|
|
24
|
-
isEnded: boolean;
|
|
25
|
-
isCancelled: boolean;
|
|
26
|
-
};
|
|
27
|
-
type TimerControls = {
|
|
28
|
-
start(): void;
|
|
29
|
-
pause(): void;
|
|
30
|
-
resume(): void;
|
|
31
|
-
reset(options?: {
|
|
32
|
-
autoStart?: boolean;
|
|
33
|
-
}): void;
|
|
34
|
-
restart(): void;
|
|
35
|
-
cancel(reason?: string): void;
|
|
36
|
-
};
|
|
37
|
-
type TimerEndPredicate = (snapshot: TimerSnapshot) => boolean;
|
|
38
|
-
type TimerSchedule = {
|
|
39
|
-
id?: string;
|
|
40
|
-
everyMs: number;
|
|
41
|
-
leading?: boolean;
|
|
42
|
-
overlap?: 'skip' | 'allow';
|
|
43
|
-
callback: (snapshot: TimerSnapshot, controls: TimerControls) => void | Promise<void>;
|
|
44
|
-
};
|
|
45
|
-
type TimerDebug = boolean | TimerDebugLogger | {
|
|
46
|
-
enabled?: boolean;
|
|
47
|
-
logger?: TimerDebugLogger;
|
|
48
|
-
includeTicks?: boolean;
|
|
49
|
-
label?: string;
|
|
50
|
-
};
|
|
51
|
-
type TimerDebugLogger = (event: TimerDebugEvent) => void;
|
|
52
|
-
type TimerDebugEvent = {
|
|
53
|
-
type: 'timer:start' | 'timer:pause' | 'timer:resume' | 'timer:reset' | 'timer:restart' | 'timer:cancel' | 'timer:end' | 'timer:tick' | 'scheduler:start' | 'scheduler:stop' | 'schedule:start' | 'schedule:skip' | 'schedule:end' | 'schedule:error' | 'callback:error';
|
|
54
|
-
scope: 'timer' | 'timer-group';
|
|
55
|
-
label?: string;
|
|
56
|
-
timerId?: string;
|
|
57
|
-
scheduleId?: string;
|
|
58
|
-
generation: number;
|
|
59
|
-
tick: number;
|
|
60
|
-
now: number;
|
|
61
|
-
elapsedMilliseconds: number;
|
|
62
|
-
status: TimerStatus;
|
|
63
|
-
reason?: string;
|
|
64
|
-
error?: unknown;
|
|
65
|
-
};
|
|
66
|
-
type UseTimerOptions = {
|
|
67
|
-
autoStart?: boolean;
|
|
68
|
-
updateIntervalMs?: number;
|
|
69
|
-
endWhen?: TimerEndPredicate;
|
|
70
|
-
onEnd?: (snapshot: TimerSnapshot, controls: TimerControls) => void | Promise<void>;
|
|
71
|
-
schedules?: TimerSchedule[];
|
|
72
|
-
debug?: TimerDebug;
|
|
73
|
-
};
|
|
74
|
-
type TimerGroupItemControls = {
|
|
75
|
-
start(): void;
|
|
76
|
-
pause(): void;
|
|
77
|
-
resume(): void;
|
|
78
|
-
reset(options?: {
|
|
79
|
-
autoStart?: boolean;
|
|
80
|
-
}): void;
|
|
81
|
-
restart(): void;
|
|
82
|
-
cancel(reason?: string): void;
|
|
83
|
-
};
|
|
84
|
-
type TimerGroupItem = {
|
|
85
|
-
id: string;
|
|
86
|
-
autoStart?: boolean;
|
|
87
|
-
endWhen?: TimerEndPredicate;
|
|
88
|
-
onEnd?: (snapshot: TimerSnapshot, controls: TimerGroupItemControls) => void | Promise<void>;
|
|
89
|
-
schedules?: TimerSchedule[];
|
|
90
|
-
};
|
|
91
|
-
type UseTimerGroupOptions = {
|
|
92
|
-
updateIntervalMs?: number;
|
|
93
|
-
items?: TimerGroupItem[];
|
|
94
|
-
debug?: TimerDebug;
|
|
95
|
-
};
|
|
96
|
-
type TimerGroupResult = {
|
|
97
|
-
now: number;
|
|
98
|
-
size: number;
|
|
99
|
-
ids: string[];
|
|
100
|
-
get(id: string): TimerSnapshot | undefined;
|
|
101
|
-
add(item: TimerGroupItem): void;
|
|
102
|
-
update(id: string, item: Partial<Omit<TimerGroupItem, 'id'>>): void;
|
|
103
|
-
remove(id: string): void;
|
|
104
|
-
clear(): void;
|
|
105
|
-
start(id: string): void;
|
|
106
|
-
pause(id: string): void;
|
|
107
|
-
resume(id: string): void;
|
|
108
|
-
reset(id: string, options?: {
|
|
109
|
-
autoStart?: boolean;
|
|
110
|
-
}): void;
|
|
111
|
-
restart(id: string): void;
|
|
112
|
-
cancel(id: string, reason?: string): void;
|
|
113
|
-
startAll(): void;
|
|
114
|
-
pauseAll(): void;
|
|
115
|
-
resumeAll(): void;
|
|
116
|
-
resetAll(options?: {
|
|
117
|
-
autoStart?: boolean;
|
|
118
|
-
}): void;
|
|
119
|
-
restartAll(): void;
|
|
120
|
-
cancelAll(reason?: string): void;
|
|
121
|
-
};
|
|
122
|
-
|
|
123
|
-
declare function durationParts(milliseconds: number): DurationParts;
|
|
1
|
+
import { U as UseTimerOptions, T as TimerSnapshot, a as TimerControls } from './types-D-Vzr-PF.cjs';
|
|
2
|
+
export { b as TimerEndPredicate, c as TimerStatus } from './types-D-Vzr-PF.cjs';
|
|
124
3
|
|
|
125
4
|
declare function useTimer(options?: UseTimerOptions): TimerSnapshot & TimerControls;
|
|
126
5
|
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
export { type DurationParts, type TimerControls, type TimerDebug, type TimerDebugEvent, type TimerDebugLogger, type TimerEndPredicate, type TimerGroupItem, type TimerGroupItemControls, type TimerGroupResult, type TimerSchedule, type TimerSnapshot, type TimerStatus, type UseTimerGroupOptions, type UseTimerOptions, durationParts, useTimer, useTimerGroup };
|
|
6
|
+
export { TimerControls, TimerSnapshot, UseTimerOptions, useTimer };
|
package/dist/index.d.ts
CHANGED
|
@@ -1,129 +1,6 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
totalMilliseconds: number;
|
|
4
|
-
totalSeconds: number;
|
|
5
|
-
milliseconds: number;
|
|
6
|
-
seconds: number;
|
|
7
|
-
minutes: number;
|
|
8
|
-
hours: number;
|
|
9
|
-
days: number;
|
|
10
|
-
};
|
|
11
|
-
type TimerSnapshot = {
|
|
12
|
-
status: TimerStatus;
|
|
13
|
-
now: number;
|
|
14
|
-
tick: number;
|
|
15
|
-
startedAt: number | null;
|
|
16
|
-
pausedAt: number | null;
|
|
17
|
-
endedAt: number | null;
|
|
18
|
-
cancelledAt: number | null;
|
|
19
|
-
cancelReason: string | null;
|
|
20
|
-
elapsedMilliseconds: number;
|
|
21
|
-
isIdle: boolean;
|
|
22
|
-
isRunning: boolean;
|
|
23
|
-
isPaused: boolean;
|
|
24
|
-
isEnded: boolean;
|
|
25
|
-
isCancelled: boolean;
|
|
26
|
-
};
|
|
27
|
-
type TimerControls = {
|
|
28
|
-
start(): void;
|
|
29
|
-
pause(): void;
|
|
30
|
-
resume(): void;
|
|
31
|
-
reset(options?: {
|
|
32
|
-
autoStart?: boolean;
|
|
33
|
-
}): void;
|
|
34
|
-
restart(): void;
|
|
35
|
-
cancel(reason?: string): void;
|
|
36
|
-
};
|
|
37
|
-
type TimerEndPredicate = (snapshot: TimerSnapshot) => boolean;
|
|
38
|
-
type TimerSchedule = {
|
|
39
|
-
id?: string;
|
|
40
|
-
everyMs: number;
|
|
41
|
-
leading?: boolean;
|
|
42
|
-
overlap?: 'skip' | 'allow';
|
|
43
|
-
callback: (snapshot: TimerSnapshot, controls: TimerControls) => void | Promise<void>;
|
|
44
|
-
};
|
|
45
|
-
type TimerDebug = boolean | TimerDebugLogger | {
|
|
46
|
-
enabled?: boolean;
|
|
47
|
-
logger?: TimerDebugLogger;
|
|
48
|
-
includeTicks?: boolean;
|
|
49
|
-
label?: string;
|
|
50
|
-
};
|
|
51
|
-
type TimerDebugLogger = (event: TimerDebugEvent) => void;
|
|
52
|
-
type TimerDebugEvent = {
|
|
53
|
-
type: 'timer:start' | 'timer:pause' | 'timer:resume' | 'timer:reset' | 'timer:restart' | 'timer:cancel' | 'timer:end' | 'timer:tick' | 'scheduler:start' | 'scheduler:stop' | 'schedule:start' | 'schedule:skip' | 'schedule:end' | 'schedule:error' | 'callback:error';
|
|
54
|
-
scope: 'timer' | 'timer-group';
|
|
55
|
-
label?: string;
|
|
56
|
-
timerId?: string;
|
|
57
|
-
scheduleId?: string;
|
|
58
|
-
generation: number;
|
|
59
|
-
tick: number;
|
|
60
|
-
now: number;
|
|
61
|
-
elapsedMilliseconds: number;
|
|
62
|
-
status: TimerStatus;
|
|
63
|
-
reason?: string;
|
|
64
|
-
error?: unknown;
|
|
65
|
-
};
|
|
66
|
-
type UseTimerOptions = {
|
|
67
|
-
autoStart?: boolean;
|
|
68
|
-
updateIntervalMs?: number;
|
|
69
|
-
endWhen?: TimerEndPredicate;
|
|
70
|
-
onEnd?: (snapshot: TimerSnapshot, controls: TimerControls) => void | Promise<void>;
|
|
71
|
-
schedules?: TimerSchedule[];
|
|
72
|
-
debug?: TimerDebug;
|
|
73
|
-
};
|
|
74
|
-
type TimerGroupItemControls = {
|
|
75
|
-
start(): void;
|
|
76
|
-
pause(): void;
|
|
77
|
-
resume(): void;
|
|
78
|
-
reset(options?: {
|
|
79
|
-
autoStart?: boolean;
|
|
80
|
-
}): void;
|
|
81
|
-
restart(): void;
|
|
82
|
-
cancel(reason?: string): void;
|
|
83
|
-
};
|
|
84
|
-
type TimerGroupItem = {
|
|
85
|
-
id: string;
|
|
86
|
-
autoStart?: boolean;
|
|
87
|
-
endWhen?: TimerEndPredicate;
|
|
88
|
-
onEnd?: (snapshot: TimerSnapshot, controls: TimerGroupItemControls) => void | Promise<void>;
|
|
89
|
-
schedules?: TimerSchedule[];
|
|
90
|
-
};
|
|
91
|
-
type UseTimerGroupOptions = {
|
|
92
|
-
updateIntervalMs?: number;
|
|
93
|
-
items?: TimerGroupItem[];
|
|
94
|
-
debug?: TimerDebug;
|
|
95
|
-
};
|
|
96
|
-
type TimerGroupResult = {
|
|
97
|
-
now: number;
|
|
98
|
-
size: number;
|
|
99
|
-
ids: string[];
|
|
100
|
-
get(id: string): TimerSnapshot | undefined;
|
|
101
|
-
add(item: TimerGroupItem): void;
|
|
102
|
-
update(id: string, item: Partial<Omit<TimerGroupItem, 'id'>>): void;
|
|
103
|
-
remove(id: string): void;
|
|
104
|
-
clear(): void;
|
|
105
|
-
start(id: string): void;
|
|
106
|
-
pause(id: string): void;
|
|
107
|
-
resume(id: string): void;
|
|
108
|
-
reset(id: string, options?: {
|
|
109
|
-
autoStart?: boolean;
|
|
110
|
-
}): void;
|
|
111
|
-
restart(id: string): void;
|
|
112
|
-
cancel(id: string, reason?: string): void;
|
|
113
|
-
startAll(): void;
|
|
114
|
-
pauseAll(): void;
|
|
115
|
-
resumeAll(): void;
|
|
116
|
-
resetAll(options?: {
|
|
117
|
-
autoStart?: boolean;
|
|
118
|
-
}): void;
|
|
119
|
-
restartAll(): void;
|
|
120
|
-
cancelAll(reason?: string): void;
|
|
121
|
-
};
|
|
122
|
-
|
|
123
|
-
declare function durationParts(milliseconds: number): DurationParts;
|
|
1
|
+
import { U as UseTimerOptions, T as TimerSnapshot, a as TimerControls } from './types-D-Vzr-PF.js';
|
|
2
|
+
export { b as TimerEndPredicate, c as TimerStatus } from './types-D-Vzr-PF.js';
|
|
124
3
|
|
|
125
4
|
declare function useTimer(options?: UseTimerOptions): TimerSnapshot & TimerControls;
|
|
126
5
|
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
export { type DurationParts, type TimerControls, type TimerDebug, type TimerDebugEvent, type TimerDebugLogger, type TimerEndPredicate, type TimerGroupItem, type TimerGroupItemControls, type TimerGroupResult, type TimerSchedule, type TimerSnapshot, type TimerStatus, type UseTimerGroupOptions, type UseTimerOptions, durationParts, useTimer, useTimerGroup };
|
|
6
|
+
export { TimerControls, TimerSnapshot, UseTimerOptions, useTimer };
|
package/dist/index.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
function ie(e){let u=Math.max(0,Math.trunc(Number.isFinite(e)?e:0)),i=Math.floor(u/864e5),o=u%864e5,C=Math.floor(o/36e5),h=o%36e5,p=Math.floor(h/6e4),I=h%6e4,v=Math.floor(I/1e3);return{totalMilliseconds:u,totalSeconds:Math.floor(u/1e3),milliseconds:I%1e3,seconds:v,minutes:p,hours:C,days:i}}import{useCallback as E,useEffect as se,useMemo as ce,useReducer as de,useRef as H}from"react";function le(e){return e?e===!0?{enabled:!0,includeTicks:!1,logger:console.debug}:typeof e=="function"?{enabled:!0,includeTicks:!1,logger:e}:{enabled:e.enabled!==!1,includeTicks:e.includeTicks??!1,label:e.label,logger:e.logger??console.debug}:{enabled:!1,includeTicks:!1}}function A(e,u){let i=le(e);!i.enabled||!i.logger||u.type==="timer:tick"&&!i.includeTicks||i.logger({...u,label:u.label??i.label})}function k(e,u){return{generation:u,tick:e.tick,now:e.now,elapsedMilliseconds:e.elapsedMilliseconds,status:e.status}}function d(){let e=Date.now(),u=typeof performance<"u"&&typeof performance.now=="function"?performance.now():e;return{wallNow:e,monotonicNow:u}}function Y(e,u){if(!Number.isFinite(e)||e<=0)throw new RangeError(`${u} must be a finite number greater than 0`)}function V(e){return{status:"idle",generation:0,tick:0,startedAt:null,pausedAt:null,endedAt:null,cancelledAt:null,cancelReason:null,baseElapsedMilliseconds:0,activeStartedAtMonotonic:null,now:e.wallNow}}function X(e,u){return e.status!=="running"||e.activeStartedAtMonotonic===null?e.baseElapsedMilliseconds:Math.max(0,e.baseElapsedMilliseconds+u.monotonicNow-e.activeStartedAtMonotonic)}function m(e,u){let i=X(e,u);return{status:e.status,now:u.wallNow,tick:e.tick,startedAt:e.startedAt,pausedAt:e.pausedAt,endedAt:e.endedAt,cancelledAt:e.cancelledAt,cancelReason:e.cancelReason,elapsedMilliseconds:i,isIdle:e.status==="idle",isRunning:e.status==="running",isPaused:e.status==="paused",isEnded:e.status==="ended",isCancelled:e.status==="cancelled"}}function z(e,u){return e.status!=="idle"?!1:(e.status="running",e.startedAt=u.wallNow,e.pausedAt=null,e.endedAt=null,e.cancelledAt=null,e.cancelReason=null,e.activeStartedAtMonotonic=u.monotonicNow,e.now=u.wallNow,!0)}function Z(e,u){return e.status!=="running"?!1:(e.baseElapsedMilliseconds=X(e,u),e.activeStartedAtMonotonic=null,e.status="paused",e.pausedAt=u.wallNow,e.now=u.wallNow,!0)}function _(e,u){return e.status!=="paused"?!1:(e.status="running",e.pausedAt=null,e.activeStartedAtMonotonic=u.monotonicNow,e.now=u.wallNow,!0)}function J(e,u,i={}){return e.generation+=1,e.tick=0,e.status=i.autoStart?"running":"idle",e.startedAt=i.autoStart?u.wallNow:null,e.pausedAt=null,e.endedAt=null,e.cancelledAt=null,e.cancelReason=null,e.baseElapsedMilliseconds=0,e.activeStartedAtMonotonic=i.autoStart?u.monotonicNow:null,e.now=u.wallNow,!0}function ee(e,u){return J(e,u,{autoStart:!0})}function te(e,u,i){return e.status==="ended"||e.status==="cancelled"?!1:(e.baseElapsedMilliseconds=X(e,u),e.activeStartedAtMonotonic=null,e.status="cancelled",e.cancelledAt=u.wallNow,e.cancelReason=i??null,e.now=u.wallNow,!0)}function re(e,u){return e.status!=="running"?!1:(e.baseElapsedMilliseconds=X(e,u),e.activeStartedAtMonotonic=null,e.status="ended",e.endedAt=u.wallNow,e.now=u.wallNow,!0)}function ne(e,u){return e.status!=="running"?!1:(e.tick+=1,e.now=u.wallNow,!0)}function me(e={}){let u=e.updateIntervalMs??1e3;Y(u,"updateIntervalMs"),fe(e.schedules);let i=H(e);i.current=e;let o=H(null);o.current===null&&(o.current=V(d()));let C=H(!1),h=H(null),p=H(new Map),I=H(null),[,v]=de(s=>s+1,0),l=E(()=>{h.current!==null&&(clearTimeout(h.current),h.current=null)},[]),N=E((s=d())=>m(o.current,s),[]),g=E((s,c,f={})=>{A(i.current.debug,{type:s,scope:"timer",...k(c,o.current.generation),...f})},[]),D=H(null),K=E(s=>{let c=o.current.generation;if(I.current!==c){I.current=c;try{i.current.onEnd?.(s,D.current)}catch(f){A(i.current.debug,{type:"callback:error",scope:"timer",...k(s,c),error:f})}}},[]),y=E((s,c,f,w,M)=>{if(f.pending&&(s.overlap??"skip")==="skip"){A(i.current.debug,{type:"schedule:skip",scope:"timer",scheduleId:s.id??c,reason:"overlap",...k(w,M)});return}f.lastRunAt=w.now,f.pending=!0,A(i.current.debug,{type:"schedule:start",scope:"timer",scheduleId:s.id??c,...k(w,M)}),Promise.resolve().then(()=>s.callback(w,D.current)).then(()=>{A(i.current.debug,{type:"schedule:end",scope:"timer",scheduleId:s.id??c,...k(w,M)})},t=>{A(i.current.debug,{type:"schedule:error",scope:"timer",scheduleId:s.id??c,error:t,...k(w,M)})}).finally(()=>{o.current?.generation===M&&(f.pending=!1)})},[]),P=E((s,c,f=!1)=>{let w=i.current.schedules??[],M=new Set;w.forEach((t,r)=>{let n=t.id??String(r);M.add(n);let a=p.current.get(n);if(a||(a={lastRunAt:null,pending:!1,leadingGeneration:null},p.current.set(n,a)),f&&t.leading&&a.leadingGeneration!==c){a.leadingGeneration=c,y(t,n,a,s,c);return}if(a.lastRunAt===null){a.lastRunAt=s.now;return}s.now-a.lastRunAt>=t.everyMs&&y(t,n,a,s,c)});for(let t of p.current.keys())M.has(t)||p.current.delete(t)},[y]),R=E((s=d(),c=!1)=>{let f=o.current;if(f.status!=="running")return;let w=m(f,s),M=f.generation;if(i.current.endWhen?.(w)){if(re(f,s)){let t=m(f,s);g("timer:end",t),l(),K(t),v()}return}P(w,M,c)},[K,l,g,P]),W=E(()=>{let s=d();if(!z(o.current,s))return;let c=m(o.current,s);g("timer:start",c),R(s,!0),v()},[g,R]),j=E(()=>{let s=d();if(!Z(o.current,s))return;l();let c=m(o.current,s);g("timer:pause",c),v()},[l,g]),q=E(()=>{let s=d();if(!_(o.current,s))return;let c=m(o.current,s);g("timer:resume",c),R(s,!0),v()},[g,R]),B=E((s={})=>{let c=d();l(),J(o.current,c,s),p.current.clear(),I.current=null;let f=m(o.current,c);g("timer:reset",f),s.autoStart&&R(c,!0),v()},[l,g,R]),O=E(()=>{let s=d();l(),ee(o.current,s),p.current.clear(),I.current=null;let c=m(o.current,s);g("timer:restart",c),R(s,!0),v()},[l,g,R]),U=E(s=>{let c=d();if(!te(o.current,c,s))return;l();let f=m(o.current,c);g("timer:cancel",f,{reason:s}),v()},[l,g]);D.current=ce(()=>({start:W,pause:j,resume:q,reset:B,restart:O,cancel:U}),[U,j,B,O,q,W]),se(()=>(C.current=!0,i.current.autoStart&&o.current.status==="idle"&&D.current.start(),()=>{C.current=!1,l()}),[l]);let x=N(),$=o.current.generation,F=x.status;return se(()=>{if(!C.current||F!=="running"){l();return}return l(),g("scheduler:start",N()),h.current=setTimeout(()=>{if(!C.current||o.current.generation!==$||o.current.status!=="running")return;let s=d();ne(o.current,s);let c=m(o.current,s);g("timer:tick",c),R(s),v()},i.current.updateIntervalMs??1e3),()=>{h.current!==null&&g("scheduler:stop",N()),l()}},[l,g,$,N,R,x.tick,F]),{...x,...D.current}}function fe(e){e?.forEach(u=>Y(u.everyMs,"schedule.everyMs"))}import{useCallback as T,useEffect as ae,useMemo as pe,useReducer as ge,useRef as oe}from"react";function Te(e={}){let u=e.updateIntervalMs??1e3;Y(u,"updateIntervalMs"),ue(e.items);let i=oe(e);i.current=e;let o=oe(new Map),C=oe(!1),h=oe(null),[,p]=ge(t=>t+1,0),I=T(()=>{h.current!==null&&(clearTimeout(h.current),h.current=null)},[]),v=T((t,r=d())=>m(t.state,r),[]),l=T((t,r,n,a={})=>{A(i.current.debug,{type:t,scope:"timer-group",timerId:r?.id,...k(n,r?.state.generation??0),...a})},[]),N=T(t=>({start:()=>O(t),pause:()=>U(t),resume:()=>x(t),reset:r=>$(t,r),restart:()=>F(t),cancel:r=>s(t,r)}),[]),g=T((t,r)=>{let n=t.state.generation;if(t.endCalledGeneration!==n){t.endCalledGeneration=n;try{t.definition.onEnd?.(r,N(t.id))}catch(a){A(i.current.debug,{type:"callback:error",scope:"timer-group",timerId:t.id,error:a,...k(r,n)})}}},[N]),D=T((t,r,n,a,b,S)=>{if(a.pending&&(r.overlap??"skip")==="skip"){A(i.current.debug,{type:"schedule:skip",scope:"timer-group",timerId:t.id,scheduleId:r.id??n,reason:"overlap",...k(b,S)});return}a.lastRunAt=b.now,a.pending=!0,A(i.current.debug,{type:"schedule:start",scope:"timer-group",timerId:t.id,scheduleId:r.id??n,...k(b,S)}),Promise.resolve().then(()=>r.callback(b,N(t.id))).then(()=>{A(i.current.debug,{type:"schedule:end",scope:"timer-group",timerId:t.id,scheduleId:r.id??n,...k(b,S)})},Q=>{A(i.current.debug,{type:"schedule:error",scope:"timer-group",timerId:t.id,scheduleId:r.id??n,error:Q,...k(b,S)})}).finally(()=>{o.current.get(t.id)?.state.generation===S&&(a.pending=!1)})},[N]),K=T((t,r,n=!1)=>{let a=t.definition.schedules??[],b=new Set;a.forEach((S,Q)=>{let L=S.id??String(Q);b.add(L);let G=t.schedules.get(L);if(G||(G={lastRunAt:null,pending:!1,leadingGeneration:null},t.schedules.set(L,G)),n&&S.leading&&G.leadingGeneration!==t.state.generation){G.leadingGeneration=t.state.generation,D(t,S,L,G,r,t.state.generation);return}if(G.lastRunAt===null){G.lastRunAt=t.state.startedAt??r.now,r.now-G.lastRunAt>=S.everyMs&&D(t,S,L,G,r,t.state.generation);return}r.now-G.lastRunAt>=S.everyMs&&D(t,S,L,G,r,t.state.generation)});for(let S of t.schedules.keys())b.has(S)||t.schedules.delete(S)},[D]),y=T((t,r=d(),n=!1)=>{if(t.state.status!=="running")return;let a=m(t.state,r);if(t.definition.endWhen?.(a)){if(re(t.state,r)){let b=m(t.state,r);l("timer:end",t,b),g(t,b)}return}K(t,a,n)},[g,l,K]),P=T(t=>{let r=o.current.get(t.id);if(r)return r.definition=t,{item:r,added:!1};let n={id:t.id,state:V(d()),definition:t,schedules:new Map,endCalledGeneration:null};return o.current.set(t.id,n),t.autoStart&&z(n.state,d()),{item:n,added:!0}},[]),R=T(()=>{let t=i.current.items??[],r=new Set,n=!1;t.forEach(a=>{r.add(a.id);let{item:b,added:S}=P(a);n=n||S,a.autoStart&&b.state.status==="idle"&&(n=z(b.state,d())||n)});for(let a of o.current.keys())r.has(a)||(o.current.delete(a),n=!0);return n},[P]);ae(()=>{R()&&p()},[R,e.items]);let W=T(t=>{if(ue([t]),o.current.has(t.id))throw new Error(`Timer item "${t.id}" already exists`);P(t),p()},[P]),j=T((t,r)=>{let n=o.current.get(t);if(!n)return;let a={...n.definition,...r,id:t};ue([a]),n.definition=a,p()},[]),q=T(t=>{o.current.delete(t),p()},[]),B=T(()=>{o.current.clear(),I(),p()},[I]),O=T(t=>{let r=o.current.get(t);if(!r)return;let n=d();z(r.state,n)&&(l("timer:start",r,m(r.state,n)),y(r,n,!0),p())},[l,y]),U=T(t=>{let r=o.current.get(t);if(!r)return;let n=d();Z(r.state,n)&&(l("timer:pause",r,m(r.state,n)),p())},[l]),x=T(t=>{let r=o.current.get(t);if(!r)return;let n=d();_(r.state,n)&&(l("timer:resume",r,m(r.state,n)),y(r,n,!0),p())},[l,y]),$=T((t,r={})=>{let n=o.current.get(t);if(!n)return;let a=d();J(n.state,a,r),n.schedules.clear(),n.endCalledGeneration=null,l("timer:reset",n,m(n.state,a)),r.autoStart&&y(n,a,!0),p()},[l,y]),F=T(t=>{let r=o.current.get(t);if(!r)return;let n=d();ee(r.state,n),r.schedules.clear(),r.endCalledGeneration=null,l("timer:restart",r,m(r.state,n)),y(r,n,!0),p()},[l,y]),s=T((t,r)=>{let n=o.current.get(t);if(!n)return;let a=d();te(n.state,a,r)&&(l("timer:cancel",n,m(n.state,a),{reason:r}),p())},[l]),f=Array.from(o.current.keys()).map(t=>`${t}:${o.current.get(t).state.status}:${o.current.get(t).state.generation}:${o.current.get(t).state.tick}`).join("|");ae(()=>{C.current=!0;let t=Array.from(o.current.values()).filter(n=>n.state.status==="running");if(t.length===0){I();return}I();let r=t[0];return l("scheduler:start",r,m(r.state,d())),h.current=setTimeout(()=>{if(!C.current)return;let n=d();for(let a of o.current.values()){if(a.state.status!=="running")continue;ne(a.state,n);let b=m(a.state,n);l("timer:tick",a,b),y(a,n)}p()},i.current.updateIntervalMs??1e3),()=>{h.current!==null&&l("scheduler:stop",r,m(r.state,d())),I(),C.current=!1}},[f,I,l,y]);let w=T(t=>{let r=o.current.get(t);if(r)return v(r)},[v]),M=d().wallNow;return pe(()=>({now:M,size:o.current.size,ids:Array.from(o.current.keys()),get:w,add:W,update:j,remove:q,clear:B,start:O,pause:U,resume:x,reset:$,restart:F,cancel:s,startAll:()=>Array.from(o.current.keys()).forEach(O),pauseAll:()=>Array.from(o.current.keys()).forEach(U),resumeAll:()=>Array.from(o.current.keys()).forEach(x),resetAll:t=>Array.from(o.current.keys()).forEach(r=>$(r,t)),restartAll:()=>Array.from(o.current.keys()).forEach(F),cancelAll:t=>Array.from(o.current.keys()).forEach(r=>s(r,t))}),[W,s,B,w,M,U,q,$,F,x,O,j])}function ue(e){let u=new Set;e?.forEach(i=>{if(u.has(i.id))throw new Error(`Duplicate timer item id "${i.id}"`);u.add(i.id),i.schedules?.forEach(o=>Y(o.everyMs,"schedule.everyMs"))})}export{ie as durationParts,me as useTimer,Te as useTimerGroup};
|
|
1
|
+
import{a as C,b as o,c as h,d as k,e as m,f as I,g as b,h as E,i as O,j as M,k as U,l as R,m as w}from"./chunk-XXJAJJJ6.js";import{useEffect as P,useRef as F,useSyncExternalStore as G}from"react";function N(l={}){let r=F(null);return r.current===null&&(r.current=j(l)),r.current.setOptions(l),P(()=>{r.current?.commitOptions()}),P(()=>{let e=r.current;return l.autoStart&&e.controls.start(),()=>e.destroy()},[]),{...G(r.current.subscribe,r.current.getSnapshot,r.current.getServerSnapshot),...r.current.controls}}function j(l){let r=l;h(r.updateIntervalMs??1e3,"updateIntervalMs");let p=new Set,e=k(o()),d=m(e,o()),W=d,f=null,T=null,S=!1,s=(t=o())=>{d=m(e,t),p.forEach(n=>n())},i=()=>{f!==null&&(clearTimeout(f),f=null)},x=t=>{if(T===e.generation)return;T=e.generation;let n=e.generation,g=C(v,()=>e.generation===n),y=u=>{if(r.onError){r.onError(u,t,g);return}setTimeout(()=>{throw u},0)};try{Promise.resolve(r.onEnd?.(t,g)).catch(u=>{y(u)})}catch(u){y(u)}},c=t=>{let n=m(e,t);return!r.endWhen?.(n)||!R(e,t)?!1:(i(),s(t),x(m(e,t)),!0)},a=()=>{i(),e.status==="running"&&(f=setTimeout(()=>{if(e.status!=="running")return;let t=o();w(e,t),!c(t)&&(s(t),a())},r.updateIntervalMs??1e3))},v={start:()=>{let t=o();if(!I(e,t)){e.status==="running"&&a();return}s(t),c(t)||a()},pause:()=>{let t=o();b(e,t)&&(i(),s(t))},resume:()=>{let t=o();E(e,t)&&(s(t),c(t)||a())},reset:(t={})=>{let n=o();i(),O(e,n,t),T=null,s(n),t.autoStart&&!c(n)&&a()},restart:()=>{let t=o();i(),M(e,t),T=null,s(t),c(t)||a()},cancel:t=>{let n=o();U(e,n,t)&&(i(),s(n))}};return{commitOptions:()=>{if(S&&(S=!1,e.status==="running")){let t=o();c(t)||a()}},controls:v,destroy:i,getSnapshot:()=>d,getServerSnapshot:()=>W,setOptions:t=>{h(t.updateIntervalMs??1e3,"updateIntervalMs"),S=S||(t.updateIntervalMs??1e3)!==(r.updateIntervalMs??1e3)||t.endWhen!==r.endWhen,r=t},subscribe:t=>(p.add(t),()=>p.delete(t))}}export{N as useTimer};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
"use strict";var N=Object.defineProperty;var ae=Object.getOwnPropertyDescriptor;var ue=Object.getOwnPropertyNames;var ce=Object.prototype.hasOwnProperty;var de=(e,t)=>{for(var r in t)N(e,r,{get:t[r],enumerable:!0})},me=(e,t,r,n)=>{if(t&&typeof t=="object"||typeof t=="function")for(let i of ue(t))!ce.call(e,i)&&i!==r&&N(e,i,{get:()=>t[i],enumerable:!(n=ae(t,i))||n.enumerable});return e};var pe=e=>me(N({},"__esModule",{value:!0}),e);var ge={};de(ge,{useScheduledTimer:()=>ie});module.exports=pe(ge);var y=require("react");function f(){let e=Date.now(),t=typeof performance<"u"&&typeof performance.now=="function"?performance.now():e;return{wallNow:e,monotonicNow:t}}function x(e,t){if(!Number.isFinite(e)||e<=0)throw new RangeError(`${t} must be a finite number greater than 0`)}function O(e,t){return{start:()=>{t()&&e.start()},pause:()=>{t()&&e.pause()},resume:()=>{t()&&e.resume()},reset:r=>{t()&&e.reset(r)},restart:()=>{t()&&e.restart()},cancel:r=>{t()&&e.cancel(r)}}}function fe(e){return e?typeof e=="function"?{enabled:!0,includeTicks:!1,logger:e}:{enabled:e.enabled!==!1,includeTicks:e.includeTicks??!1,label:e.label,logger:e.logger}:{enabled:!1,includeTicks:!1}}function k(e,t){let r=fe(e);!r.enabled||!r.logger||t.type==="timer:tick"&&!r.includeTicks||r.logger({...t,label:t.label??r.label})}function A(e,t){return{generation:t,tick:e.tick,now:e.now,elapsedMilliseconds:e.elapsedMilliseconds,status:e.status}}function j(){return{lastRunAt:null,pendingCount:0,leadingGeneration:null,signature:""}}function q({schedules:e=[],states:t,snapshot:r,generation:n,controls:i,activation:s=!1,isLive:u,onError:m,onEvent:T}){let d=new Set;e.forEach((l,h)=>{let p=E(l,h);d.add(p);let S=t.get(p);if(S||(S=j(),S.signature=U(l,h),t.set(p,S)),s&&l.leading&&S.leadingGeneration!==n){S.leadingGeneration=n,$(l,p,S,r,n,i,J(l,p,r.now,r.now,0),u,m,T);return}S.lastRunAt===null&&(S.lastRunAt=r.now);let v=Math.floor((r.now-S.lastRunAt)/l.everyMs);if(v>=1){let C=S.lastRunAt+v*l.everyMs;$(l,p,S,r,n,i,J(l,p,C,r.now,v-1),u,m,T)}});for(let l of t.keys())d.has(l)||t.delete(l)}function z(e,t,r,n){let i=n;return e?.forEach((s,u)=>{let m=E(s,u),d=t.get(m)?.lastRunAt??r;i=Math.min(i,Math.max(1,d+s.everyMs-r))}),i}function B(e,t,r,n){let i=new Set;e?.forEach((s,u)=>{let m=E(s,u),T=U(s,u);i.add(m);let d=t.get(m);if(d)d.signature!==T&&(d.lastRunAt=n?r:null,d.leadingGeneration=null,d.signature=T);else{let l=j();l.lastRunAt=n?r:null,l.signature=T,t.set(m,l)}});for(let s of t.keys())i.has(s)||t.delete(s)}function G(e){return JSON.stringify((e??[]).map((t,r)=>U(t,r)))}function Q(e){let t=new Set;e?.forEach((r,n)=>{x(r.everyMs,"schedule.everyMs");let i=E(r,n);if(t.has(i))throw new Error(`Duplicate schedule id "${i}"`);t.add(i)})}function J(e,t,r,n,i){return{scheduleId:e.id??t,scheduledAt:r,firedAt:n,nextRunAt:r+e.everyMs,overdueCount:i,effectiveEveryMs:e.everyMs}}function $(e,t,r,n,i,s,u,m,T,d){if(r.pendingCount>0&&(e.overlap??"skip")==="skip"){r.lastRunAt=u.scheduledAt,P(m,i,d,{type:"schedule:skip",context:u,reason:"overlap"});return}r.lastRunAt=u.scheduledAt,r.pendingCount+=1,P(m,i,d,{type:"schedule:start",context:u}),Promise.resolve().then(()=>e.callback(n,s,u)).then(()=>P(m,i,d,{type:"schedule:end",context:u}),l=>{if(m(i))try{e.onError?e.onError(l,n,s,u):T?.(l,n,s,u)}finally{d?.({type:"schedule:error",context:u,error:l})}}).finally(()=>{m(i)&&(r.pendingCount=Math.max(0,r.pendingCount-1))})}function E(e,t){return e.id??String(t)}function U(e,t){return JSON.stringify([e.id??t,e.everyMs,e.leading??!1,e.overlap??"skip"])}function P(e,t,r,n){e(t)&&r?.(n)}function V(e){return{status:"idle",generation:0,tick:0,startedAt:null,pausedAt:null,endedAt:null,cancelledAt:null,cancelReason:null,baseElapsedMilliseconds:0,activeStartedAtMonotonic:null,now:e.wallNow}}function M(e,t){return e.status!=="running"||e.activeStartedAtMonotonic===null?e.baseElapsedMilliseconds:Math.max(0,e.baseElapsedMilliseconds+t.monotonicNow-e.activeStartedAtMonotonic)}function I(e,t){let r=M(e,t);return{status:e.status,now:t.wallNow,tick:e.tick,startedAt:e.startedAt,pausedAt:e.pausedAt,endedAt:e.endedAt,cancelledAt:e.cancelledAt,cancelReason:e.cancelReason,elapsedMilliseconds:r,isIdle:e.status==="idle",isRunning:e.status==="running",isPaused:e.status==="paused",isEnded:e.status==="ended",isCancelled:e.status==="cancelled"}}function X(e,t){return e.status!=="idle"?!1:(e.status="running",e.startedAt=t.wallNow,e.pausedAt=null,e.endedAt=null,e.cancelledAt=null,e.cancelReason=null,e.activeStartedAtMonotonic=t.monotonicNow,e.now=t.wallNow,!0)}function Y(e,t){return e.status!=="running"?!1:(e.baseElapsedMilliseconds=M(e,t),e.activeStartedAtMonotonic=null,e.status="paused",e.pausedAt=t.wallNow,e.now=t.wallNow,!0)}function Z(e,t){return e.status!=="paused"?!1:(e.status="running",e.pausedAt=null,e.activeStartedAtMonotonic=t.monotonicNow,e.now=t.wallNow,!0)}function F(e,t,r={}){return e.generation+=1,e.tick=0,e.status=r.autoStart?"running":"idle",e.startedAt=r.autoStart?t.wallNow:null,e.pausedAt=null,e.endedAt=null,e.cancelledAt=null,e.cancelReason=null,e.baseElapsedMilliseconds=0,e.activeStartedAtMonotonic=r.autoStart?t.monotonicNow:null,e.now=t.wallNow,!0}function _(e,t){return F(e,t,{autoStart:!0})}function L(e,t,r){return e.status!=="running"&&e.status!=="paused"?!1:(e.baseElapsedMilliseconds=M(e,t),e.activeStartedAtMonotonic=null,e.status="cancelled",e.cancelledAt=t.wallNow,e.cancelReason=r??null,e.now=t.wallNow,!0)}function ee(e,t){return e.status!=="running"?!1:(e.baseElapsedMilliseconds=M(e,t),e.activeStartedAtMonotonic=null,e.status="ended",e.endedAt=t.wallNow,e.now=t.wallNow,!0)}function te(e,t){return e.status!=="running"?!1:(e.tick+=1,e.now=t.wallNow,!0)}function ne(e,t){return{state:V(t),definition:e,endCalledGeneration:null}}function W(e){e.endCalledGeneration=null}function g(e,t){return I(e.state,t)}function re(e,t,r,n){let i=I(e.state,t);if(!e.definition.endWhen?.(i)||!ee(e.state,t))return null;let s=I(e.state,t);return Se(e,s,r,n),s}function Se(e,t,r,n){let i=e.state.generation;if(e.endCalledGeneration!==i){e.endCalledGeneration=i;try{let s=e.definition.onEnd?.(t,r);s&&n&&Promise.resolve(s).catch(u=>n?.(u,t,i))}catch(s){if(n){n(s,t,i);return}throw s}}}function ie(e={}){let t=(0,y.useRef)(null);return t.current===null&&(t.current=Te(e)),t.current.setOptions(e),(0,y.useEffect)(()=>{t.current?.commitOptions()}),(0,y.useEffect)(()=>{let n=t.current;return e.autoStart&&n.controls.start(),()=>n.destroy()},[]),{...(0,y.useSyncExternalStore)(t.current.subscribe,t.current.getSnapshot,t.current.getServerSnapshot),...t.current.controls}}function Te(e){let t=e;oe(t);let r=new Set,n=ne(t,f()),i=new Map,s=g(n,f()),u=s,m=null,T=G(t.schedules),d=!1,l=(o=f())=>{s=g(n,o),r.forEach(a=>a())},h=()=>{m!==null&&(clearTimeout(m),m=null)},p=(o,a,c={})=>{k(t.diagnostics,{type:o,scope:"timer",...A(a,n.state.generation),...c})},S=(o,a,c)=>{let w=O(R,()=>n.state.generation===c);t.onError?.(o,a,w),k(t.diagnostics,{type:"callback:error",scope:"timer",error:o,...A(a,c)})},v=(o,a)=>c=>{k(t.diagnostics,{type:c.type,scope:"timer",...c.context,..."reason"in c?{reason:c.reason}:{},..."error"in c?{error:c.error}:{},...A(o,a)})},C=(o=f(),a=!1)=>{if(n.state.status!=="running")return!1;let c=n.state.generation,w=O(R,()=>n.state.generation===c),H=re(n,o,w,S);if(H)return h(),p("timer:end",H),l(o),!0;let K=g(n,o);return q({schedules:t.schedules,states:i,snapshot:K,generation:n.state.generation,controls:w,activation:a,isLive:D=>n.state.generation===D,onError:(D,le,se)=>t.onError?.(D,le,se),onEvent:v(K,n.state.generation)}),!1},b=(o=!0)=>{if(h(),n.state.status!=="running")return;let a=z(t.schedules,i,f().wallNow,t.updateIntervalMs??1e3);o&&p("scheduler:start",g(n,f())),m=setTimeout(()=>{if(n.state.status!=="running")return;let c=f();te(n.state,c);let w=g(n,c);p("timer:tick",w),C(c)||(l(c),b())},a)},R={start:()=>{let o=f();if(!X(n.state,o)){n.state.status==="running"&&b();return}p("timer:start",g(n,o)),C(o,!0),l(o),b()},pause:()=>{let o=f();Y(n.state,o)&&(h(),p("timer:pause",g(n,o)),l(o))},resume:()=>{let o=f();Z(n.state,o)&&(p("timer:resume",g(n,o)),C(o,!0),l(o),b())},reset:(o={})=>{let a=f();h(),F(n.state,a,o),i.clear(),W(n),p("timer:reset",g(n,a)),C(a,o.autoStart),l(a),b()},restart:()=>{let o=f();h(),_(n.state,o),i.clear(),W(n),p("timer:restart",g(n,o)),C(o,!0),l(o),b()},cancel:o=>{let a=f();L(n.state,a,o)&&(h(),p("timer:cancel",g(n,a),{reason:o}),l(a))}};return{commitOptions:()=>{if(d&&(d=!1,B(t.schedules,i,f().wallNow,n.state.status==="running"),n.state.status==="running")){let o=f();C(o)||b(!1)}},controls:R,destroy:h,getSnapshot:()=>s,getServerSnapshot:()=>u,setOptions:o=>{oe(o);let a=G(o.schedules),c=a!==T;d=d||c||(o.updateIntervalMs??1e3)!==(t.updateIntervalMs??1e3)||o.endWhen!==t.endWhen,t=o,n.definition=o,c&&(T=a)},subscribe:o=>(r.add(o),()=>r.delete(o))}}function oe(e){x(e.updateIntervalMs??1e3,"updateIntervalMs"),Q(e.schedules)}0&&(module.exports={useScheduledTimer});
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import { h as UseScheduledTimerOptions, T as TimerSnapshot, a as TimerControls } from './types-D-Vzr-PF.cjs';
|
|
2
|
+
export { i as TimerDiagnostics, j as TimerDiagnosticsEvent, k as TimerDiagnosticsLogger, l as TimerSchedule, m as TimerScheduleContext } from './types-D-Vzr-PF.cjs';
|
|
3
|
+
|
|
4
|
+
declare function useScheduledTimer(options?: UseScheduledTimerOptions): TimerSnapshot & TimerControls;
|
|
5
|
+
|
|
6
|
+
export { UseScheduledTimerOptions, useScheduledTimer };
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import { h as UseScheduledTimerOptions, T as TimerSnapshot, a as TimerControls } from './types-D-Vzr-PF.js';
|
|
2
|
+
export { i as TimerDiagnostics, j as TimerDiagnosticsEvent, k as TimerDiagnosticsLogger, l as TimerSchedule, m as TimerScheduleContext } from './types-D-Vzr-PF.js';
|
|
3
|
+
|
|
4
|
+
declare function useScheduledTimer(options?: UseScheduledTimerOptions): TimerSnapshot & TimerControls;
|
|
5
|
+
|
|
6
|
+
export { UseScheduledTimerOptions, useScheduledTimer };
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{a as g,b as y,c as F,d as G,e as j,f as C,g as q,h as z,i as I,j as i,k as A}from"./chunk-OYRPLLEV.js";import{a as E,b as o,c as U,f as M,g as N,h as P,i as x,j as R,k as L,m as W}from"./chunk-XXJAJJJ6.js";import{useEffect as B,useRef as Y,useSyncExternalStore as Z}from"react";function _(c={}){let r=Y(null);return r.current===null&&(r.current=$(c)),r.current.setOptions(c),B(()=>{r.current?.commitOptions()}),B(()=>{let t=r.current;return c.autoStart&&t.controls.start(),()=>t.destroy()},[]),{...Z(r.current.subscribe,r.current.getSnapshot,r.current.getServerSnapshot),...r.current.controls}}function $(c){let r=c;H(r);let h=new Set,t=z(r,o()),S=new Map,v=i(t,o()),J=v,f=null,O=C(r.schedules),T=!1,u=(e=o())=>{v=i(t,e),h.forEach(s=>s())},l=()=>{f!==null&&(clearTimeout(f),f=null)},a=(e,s,n={})=>{g(r.diagnostics,{type:e,scope:"timer",...y(s,t.state.generation),...n})},K=(e,s,n)=>{let p=E(b,()=>t.state.generation===n);r.onError?.(e,s,p),g(r.diagnostics,{type:"callback:error",scope:"timer",error:e,...y(s,n)})},Q=(e,s)=>n=>{g(r.diagnostics,{type:n.type,scope:"timer",...n.context,..."reason"in n?{reason:n.reason}:{},..."error"in n?{error:n.error}:{},...y(e,s)})},d=(e=o(),s=!1)=>{if(t.state.status!=="running")return!1;let n=t.state.generation,p=E(b,()=>t.state.generation===n),D=A(t,e,p,K);if(D)return l(),a("timer:end",D),u(e),!0;let w=i(t,e);return F({schedules:r.schedules,states:S,snapshot:w,generation:t.state.generation,controls:p,activation:s,isLive:k=>t.state.generation===k,onError:(k,V,X)=>r.onError?.(k,V,X),onEvent:Q(w,t.state.generation)}),!1},m=(e=!0)=>{if(l(),t.state.status!=="running")return;let s=G(r.schedules,S,o().wallNow,r.updateIntervalMs??1e3);e&&a("scheduler:start",i(t,o())),f=setTimeout(()=>{if(t.state.status!=="running")return;let n=o();W(t.state,n);let p=i(t,n);a("timer:tick",p),d(n)||(u(n),m())},s)},b={start:()=>{let e=o();if(!M(t.state,e)){t.state.status==="running"&&m();return}a("timer:start",i(t,e)),d(e,!0),u(e),m()},pause:()=>{let e=o();N(t.state,e)&&(l(),a("timer:pause",i(t,e)),u(e))},resume:()=>{let e=o();P(t.state,e)&&(a("timer:resume",i(t,e)),d(e,!0),u(e),m())},reset:(e={})=>{let s=o();l(),x(t.state,s,e),S.clear(),I(t),a("timer:reset",i(t,s)),d(s,e.autoStart),u(s),m()},restart:()=>{let e=o();l(),R(t.state,e),S.clear(),I(t),a("timer:restart",i(t,e)),d(e,!0),u(e),m()},cancel:e=>{let s=o();L(t.state,s,e)&&(l(),a("timer:cancel",i(t,s),{reason:e}),u(s))}};return{commitOptions:()=>{if(T&&(T=!1,j(r.schedules,S,o().wallNow,t.state.status==="running"),t.state.status==="running")){let e=o();d(e)||m(!1)}},controls:b,destroy:l,getSnapshot:()=>v,getServerSnapshot:()=>J,setOptions:e=>{H(e);let s=C(e.schedules),n=s!==O;T=T||n||(e.updateIntervalMs??1e3)!==(r.updateIntervalMs??1e3)||e.endWhen!==r.endWhen,r=e,t.definition=e,n&&(O=s)},subscribe:e=>(h.add(e),()=>h.delete(e))}}function H(c){U(c.updateIntervalMs??1e3,"updateIntervalMs"),q(c.schedules)}export{_ as useScheduledTimer};
|
|
@@ -0,0 +1,133 @@
|
|
|
1
|
+
type TimerStatus = 'idle' | 'running' | 'paused' | 'ended' | 'cancelled';
|
|
2
|
+
type DurationParts = {
|
|
3
|
+
totalMilliseconds: number;
|
|
4
|
+
totalSeconds: number;
|
|
5
|
+
milliseconds: number;
|
|
6
|
+
seconds: number;
|
|
7
|
+
minutes: number;
|
|
8
|
+
hours: number;
|
|
9
|
+
days: number;
|
|
10
|
+
};
|
|
11
|
+
type TimerSnapshot = {
|
|
12
|
+
status: TimerStatus;
|
|
13
|
+
now: number;
|
|
14
|
+
tick: number;
|
|
15
|
+
startedAt: number | null;
|
|
16
|
+
pausedAt: number | null;
|
|
17
|
+
endedAt: number | null;
|
|
18
|
+
cancelledAt: number | null;
|
|
19
|
+
cancelReason: string | null;
|
|
20
|
+
elapsedMilliseconds: number;
|
|
21
|
+
isIdle: boolean;
|
|
22
|
+
isRunning: boolean;
|
|
23
|
+
isPaused: boolean;
|
|
24
|
+
isEnded: boolean;
|
|
25
|
+
isCancelled: boolean;
|
|
26
|
+
};
|
|
27
|
+
type TimerLifecycleControls = {
|
|
28
|
+
start(): void;
|
|
29
|
+
pause(): void;
|
|
30
|
+
resume(): void;
|
|
31
|
+
reset(options?: {
|
|
32
|
+
autoStart?: boolean;
|
|
33
|
+
}): void;
|
|
34
|
+
restart(): void;
|
|
35
|
+
cancel(reason?: string): void;
|
|
36
|
+
};
|
|
37
|
+
type TimerControls = TimerLifecycleControls;
|
|
38
|
+
type TimerEndPredicate = (snapshot: TimerSnapshot) => boolean;
|
|
39
|
+
type TimerScheduleContext = {
|
|
40
|
+
scheduleId: string;
|
|
41
|
+
scheduledAt: number;
|
|
42
|
+
firedAt: number;
|
|
43
|
+
nextRunAt: number;
|
|
44
|
+
overdueCount: number;
|
|
45
|
+
effectiveEveryMs: number;
|
|
46
|
+
};
|
|
47
|
+
type TimerSchedule = {
|
|
48
|
+
id?: string;
|
|
49
|
+
everyMs: number;
|
|
50
|
+
leading?: boolean;
|
|
51
|
+
overlap?: 'skip' | 'allow';
|
|
52
|
+
callback: (snapshot: TimerSnapshot, controls: TimerControls, context: TimerScheduleContext) => void | Promise<void>;
|
|
53
|
+
onError?: (error: unknown, snapshot: TimerSnapshot, controls: TimerControls, context: TimerScheduleContext) => void;
|
|
54
|
+
};
|
|
55
|
+
type TimerDiagnostics = TimerDiagnosticsLogger | {
|
|
56
|
+
enabled?: boolean;
|
|
57
|
+
logger: TimerDiagnosticsLogger;
|
|
58
|
+
includeTicks?: boolean;
|
|
59
|
+
label?: string;
|
|
60
|
+
};
|
|
61
|
+
type TimerDiagnosticsLogger = (event: TimerDiagnosticsEvent) => void;
|
|
62
|
+
type TimerDiagnosticsEvent = {
|
|
63
|
+
type: 'timer:start' | 'timer:pause' | 'timer:resume' | 'timer:reset' | 'timer:restart' | 'timer:cancel' | 'timer:end' | 'timer:tick' | 'scheduler:start' | 'schedule:start' | 'schedule:skip' | 'schedule:end' | 'schedule:error' | 'callback:error';
|
|
64
|
+
scope: 'timer' | 'timer-group';
|
|
65
|
+
label?: string;
|
|
66
|
+
timerId?: string;
|
|
67
|
+
scheduleId?: string;
|
|
68
|
+
generation: number;
|
|
69
|
+
tick: number;
|
|
70
|
+
now: number;
|
|
71
|
+
elapsedMilliseconds: number;
|
|
72
|
+
status: TimerStatus;
|
|
73
|
+
reason?: string;
|
|
74
|
+
error?: unknown;
|
|
75
|
+
scheduledAt?: number;
|
|
76
|
+
firedAt?: number;
|
|
77
|
+
nextRunAt?: number;
|
|
78
|
+
overdueCount?: number;
|
|
79
|
+
effectiveEveryMs?: number;
|
|
80
|
+
};
|
|
81
|
+
type UseTimerOptions = {
|
|
82
|
+
autoStart?: boolean;
|
|
83
|
+
updateIntervalMs?: number;
|
|
84
|
+
endWhen?: TimerEndPredicate;
|
|
85
|
+
onEnd?: (snapshot: TimerSnapshot, controls: TimerControls) => void | Promise<void>;
|
|
86
|
+
onError?: (error: unknown, snapshot: TimerSnapshot, controls: TimerControls) => void;
|
|
87
|
+
};
|
|
88
|
+
type UseScheduledTimerOptions = UseTimerOptions & {
|
|
89
|
+
schedules?: TimerSchedule[];
|
|
90
|
+
diagnostics?: TimerDiagnostics;
|
|
91
|
+
};
|
|
92
|
+
type TimerGroupItemControls = TimerLifecycleControls;
|
|
93
|
+
type TimerGroupItem = {
|
|
94
|
+
id: string;
|
|
95
|
+
autoStart?: boolean;
|
|
96
|
+
endWhen?: TimerEndPredicate;
|
|
97
|
+
onEnd?: (snapshot: TimerSnapshot, controls: TimerGroupItemControls) => void | Promise<void>;
|
|
98
|
+
onError?: (error: unknown, snapshot: TimerSnapshot, controls: TimerGroupItemControls) => void;
|
|
99
|
+
schedules?: TimerSchedule[];
|
|
100
|
+
};
|
|
101
|
+
type UseTimerGroupOptions = {
|
|
102
|
+
updateIntervalMs?: number;
|
|
103
|
+
items?: TimerGroupItem[];
|
|
104
|
+
diagnostics?: TimerDiagnostics;
|
|
105
|
+
};
|
|
106
|
+
type TimerGroupResult = {
|
|
107
|
+
now: number;
|
|
108
|
+
size: number;
|
|
109
|
+
ids: string[];
|
|
110
|
+
get(id: string): TimerSnapshot | undefined;
|
|
111
|
+
add(item: TimerGroupItem): void;
|
|
112
|
+
update(id: string, item: Partial<Omit<TimerGroupItem, 'id'>>): void;
|
|
113
|
+
remove(id: string): void;
|
|
114
|
+
clear(): void;
|
|
115
|
+
start(id: string): void;
|
|
116
|
+
pause(id: string): void;
|
|
117
|
+
resume(id: string): void;
|
|
118
|
+
reset(id: string, options?: {
|
|
119
|
+
autoStart?: boolean;
|
|
120
|
+
}): void;
|
|
121
|
+
restart(id: string): void;
|
|
122
|
+
cancel(id: string, reason?: string): void;
|
|
123
|
+
startAll(): void;
|
|
124
|
+
pauseAll(): void;
|
|
125
|
+
resumeAll(): void;
|
|
126
|
+
resetAll(options?: {
|
|
127
|
+
autoStart?: boolean;
|
|
128
|
+
}): void;
|
|
129
|
+
restartAll(): void;
|
|
130
|
+
cancelAll(reason?: string): void;
|
|
131
|
+
};
|
|
132
|
+
|
|
133
|
+
export type { DurationParts as D, TimerSnapshot as T, UseTimerOptions as U, TimerControls as a, TimerEndPredicate as b, TimerStatus as c, UseTimerGroupOptions as d, TimerGroupResult as e, TimerGroupItem as f, TimerGroupItemControls as g, UseScheduledTimerOptions as h, TimerDiagnostics as i, TimerDiagnosticsEvent as j, TimerDiagnosticsLogger as k, TimerSchedule as l, TimerScheduleContext as m };
|
|
@@ -0,0 +1,133 @@
|
|
|
1
|
+
type TimerStatus = 'idle' | 'running' | 'paused' | 'ended' | 'cancelled';
|
|
2
|
+
type DurationParts = {
|
|
3
|
+
totalMilliseconds: number;
|
|
4
|
+
totalSeconds: number;
|
|
5
|
+
milliseconds: number;
|
|
6
|
+
seconds: number;
|
|
7
|
+
minutes: number;
|
|
8
|
+
hours: number;
|
|
9
|
+
days: number;
|
|
10
|
+
};
|
|
11
|
+
type TimerSnapshot = {
|
|
12
|
+
status: TimerStatus;
|
|
13
|
+
now: number;
|
|
14
|
+
tick: number;
|
|
15
|
+
startedAt: number | null;
|
|
16
|
+
pausedAt: number | null;
|
|
17
|
+
endedAt: number | null;
|
|
18
|
+
cancelledAt: number | null;
|
|
19
|
+
cancelReason: string | null;
|
|
20
|
+
elapsedMilliseconds: number;
|
|
21
|
+
isIdle: boolean;
|
|
22
|
+
isRunning: boolean;
|
|
23
|
+
isPaused: boolean;
|
|
24
|
+
isEnded: boolean;
|
|
25
|
+
isCancelled: boolean;
|
|
26
|
+
};
|
|
27
|
+
type TimerLifecycleControls = {
|
|
28
|
+
start(): void;
|
|
29
|
+
pause(): void;
|
|
30
|
+
resume(): void;
|
|
31
|
+
reset(options?: {
|
|
32
|
+
autoStart?: boolean;
|
|
33
|
+
}): void;
|
|
34
|
+
restart(): void;
|
|
35
|
+
cancel(reason?: string): void;
|
|
36
|
+
};
|
|
37
|
+
type TimerControls = TimerLifecycleControls;
|
|
38
|
+
type TimerEndPredicate = (snapshot: TimerSnapshot) => boolean;
|
|
39
|
+
type TimerScheduleContext = {
|
|
40
|
+
scheduleId: string;
|
|
41
|
+
scheduledAt: number;
|
|
42
|
+
firedAt: number;
|
|
43
|
+
nextRunAt: number;
|
|
44
|
+
overdueCount: number;
|
|
45
|
+
effectiveEveryMs: number;
|
|
46
|
+
};
|
|
47
|
+
type TimerSchedule = {
|
|
48
|
+
id?: string;
|
|
49
|
+
everyMs: number;
|
|
50
|
+
leading?: boolean;
|
|
51
|
+
overlap?: 'skip' | 'allow';
|
|
52
|
+
callback: (snapshot: TimerSnapshot, controls: TimerControls, context: TimerScheduleContext) => void | Promise<void>;
|
|
53
|
+
onError?: (error: unknown, snapshot: TimerSnapshot, controls: TimerControls, context: TimerScheduleContext) => void;
|
|
54
|
+
};
|
|
55
|
+
type TimerDiagnostics = TimerDiagnosticsLogger | {
|
|
56
|
+
enabled?: boolean;
|
|
57
|
+
logger: TimerDiagnosticsLogger;
|
|
58
|
+
includeTicks?: boolean;
|
|
59
|
+
label?: string;
|
|
60
|
+
};
|
|
61
|
+
type TimerDiagnosticsLogger = (event: TimerDiagnosticsEvent) => void;
|
|
62
|
+
type TimerDiagnosticsEvent = {
|
|
63
|
+
type: 'timer:start' | 'timer:pause' | 'timer:resume' | 'timer:reset' | 'timer:restart' | 'timer:cancel' | 'timer:end' | 'timer:tick' | 'scheduler:start' | 'schedule:start' | 'schedule:skip' | 'schedule:end' | 'schedule:error' | 'callback:error';
|
|
64
|
+
scope: 'timer' | 'timer-group';
|
|
65
|
+
label?: string;
|
|
66
|
+
timerId?: string;
|
|
67
|
+
scheduleId?: string;
|
|
68
|
+
generation: number;
|
|
69
|
+
tick: number;
|
|
70
|
+
now: number;
|
|
71
|
+
elapsedMilliseconds: number;
|
|
72
|
+
status: TimerStatus;
|
|
73
|
+
reason?: string;
|
|
74
|
+
error?: unknown;
|
|
75
|
+
scheduledAt?: number;
|
|
76
|
+
firedAt?: number;
|
|
77
|
+
nextRunAt?: number;
|
|
78
|
+
overdueCount?: number;
|
|
79
|
+
effectiveEveryMs?: number;
|
|
80
|
+
};
|
|
81
|
+
type UseTimerOptions = {
|
|
82
|
+
autoStart?: boolean;
|
|
83
|
+
updateIntervalMs?: number;
|
|
84
|
+
endWhen?: TimerEndPredicate;
|
|
85
|
+
onEnd?: (snapshot: TimerSnapshot, controls: TimerControls) => void | Promise<void>;
|
|
86
|
+
onError?: (error: unknown, snapshot: TimerSnapshot, controls: TimerControls) => void;
|
|
87
|
+
};
|
|
88
|
+
type UseScheduledTimerOptions = UseTimerOptions & {
|
|
89
|
+
schedules?: TimerSchedule[];
|
|
90
|
+
diagnostics?: TimerDiagnostics;
|
|
91
|
+
};
|
|
92
|
+
type TimerGroupItemControls = TimerLifecycleControls;
|
|
93
|
+
type TimerGroupItem = {
|
|
94
|
+
id: string;
|
|
95
|
+
autoStart?: boolean;
|
|
96
|
+
endWhen?: TimerEndPredicate;
|
|
97
|
+
onEnd?: (snapshot: TimerSnapshot, controls: TimerGroupItemControls) => void | Promise<void>;
|
|
98
|
+
onError?: (error: unknown, snapshot: TimerSnapshot, controls: TimerGroupItemControls) => void;
|
|
99
|
+
schedules?: TimerSchedule[];
|
|
100
|
+
};
|
|
101
|
+
type UseTimerGroupOptions = {
|
|
102
|
+
updateIntervalMs?: number;
|
|
103
|
+
items?: TimerGroupItem[];
|
|
104
|
+
diagnostics?: TimerDiagnostics;
|
|
105
|
+
};
|
|
106
|
+
type TimerGroupResult = {
|
|
107
|
+
now: number;
|
|
108
|
+
size: number;
|
|
109
|
+
ids: string[];
|
|
110
|
+
get(id: string): TimerSnapshot | undefined;
|
|
111
|
+
add(item: TimerGroupItem): void;
|
|
112
|
+
update(id: string, item: Partial<Omit<TimerGroupItem, 'id'>>): void;
|
|
113
|
+
remove(id: string): void;
|
|
114
|
+
clear(): void;
|
|
115
|
+
start(id: string): void;
|
|
116
|
+
pause(id: string): void;
|
|
117
|
+
resume(id: string): void;
|
|
118
|
+
reset(id: string, options?: {
|
|
119
|
+
autoStart?: boolean;
|
|
120
|
+
}): void;
|
|
121
|
+
restart(id: string): void;
|
|
122
|
+
cancel(id: string, reason?: string): void;
|
|
123
|
+
startAll(): void;
|
|
124
|
+
pauseAll(): void;
|
|
125
|
+
resumeAll(): void;
|
|
126
|
+
resetAll(options?: {
|
|
127
|
+
autoStart?: boolean;
|
|
128
|
+
}): void;
|
|
129
|
+
restartAll(): void;
|
|
130
|
+
cancelAll(reason?: string): void;
|
|
131
|
+
};
|
|
132
|
+
|
|
133
|
+
export type { DurationParts as D, TimerSnapshot as T, UseTimerOptions as U, TimerControls as a, TimerEndPredicate as b, TimerStatus as c, UseTimerGroupOptions as d, TimerGroupResult as e, TimerGroupItem as f, TimerGroupItemControls as g, UseScheduledTimerOptions as h, TimerDiagnostics as i, TimerDiagnosticsEvent as j, TimerDiagnosticsLogger as k, TimerSchedule as l, TimerScheduleContext as m };
|
package/package.json
CHANGED
|
@@ -1,7 +1,15 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@crup/react-timer-hook",
|
|
3
|
-
"version": "0.0.1
|
|
4
|
-
"description": "
|
|
3
|
+
"version": "0.0.1",
|
|
4
|
+
"description": "A lightweight React hooks library for building timers, stopwatches, and real-time clocks with minimal boilerplate.",
|
|
5
|
+
"homepage": "https://crup.github.io/react-timer-hook/",
|
|
6
|
+
"repository": {
|
|
7
|
+
"type": "git",
|
|
8
|
+
"url": "git+https://github.com/crup/react-timer-hook.git"
|
|
9
|
+
},
|
|
10
|
+
"bugs": {
|
|
11
|
+
"url": "https://github.com/crup/react-timer-hook/issues"
|
|
12
|
+
},
|
|
5
13
|
"main": "./dist/index.cjs",
|
|
6
14
|
"module": "./dist/index.js",
|
|
7
15
|
"types": "./dist/index.d.ts",
|
|
@@ -10,6 +18,26 @@
|
|
|
10
18
|
"types": "./dist/index.d.ts",
|
|
11
19
|
"import": "./dist/index.js",
|
|
12
20
|
"require": "./dist/index.cjs"
|
|
21
|
+
},
|
|
22
|
+
"./group": {
|
|
23
|
+
"types": "./dist/group.d.ts",
|
|
24
|
+
"import": "./dist/group.js",
|
|
25
|
+
"require": "./dist/group.cjs"
|
|
26
|
+
},
|
|
27
|
+
"./duration": {
|
|
28
|
+
"types": "./dist/duration.d.ts",
|
|
29
|
+
"import": "./dist/duration.js",
|
|
30
|
+
"require": "./dist/duration.cjs"
|
|
31
|
+
},
|
|
32
|
+
"./schedules": {
|
|
33
|
+
"types": "./dist/schedules.d.ts",
|
|
34
|
+
"import": "./dist/schedules.js",
|
|
35
|
+
"require": "./dist/schedules.cjs"
|
|
36
|
+
},
|
|
37
|
+
"./diagnostics": {
|
|
38
|
+
"types": "./dist/diagnostics.d.ts",
|
|
39
|
+
"import": "./dist/diagnostics.js",
|
|
40
|
+
"require": "./dist/diagnostics.cjs"
|
|
13
41
|
}
|
|
14
42
|
},
|
|
15
43
|
"files": [
|
|
@@ -19,20 +47,33 @@
|
|
|
19
47
|
],
|
|
20
48
|
"sideEffects": false,
|
|
21
49
|
"publishConfig": {
|
|
22
|
-
"access": "public"
|
|
23
|
-
"tag": "alpha"
|
|
50
|
+
"access": "public"
|
|
24
51
|
},
|
|
25
52
|
"engines": {
|
|
26
|
-
"node": ">=
|
|
53
|
+
"node": ">=18.0.0"
|
|
27
54
|
},
|
|
28
55
|
"keywords": [
|
|
29
56
|
"react",
|
|
30
57
|
"hook",
|
|
58
|
+
"hooks",
|
|
31
59
|
"timer",
|
|
60
|
+
"react-timer",
|
|
61
|
+
"react-timer-hook",
|
|
62
|
+
"timer-hook",
|
|
32
63
|
"stopwatch",
|
|
64
|
+
"react-stopwatch",
|
|
65
|
+
"stopwatch-hook",
|
|
33
66
|
"time",
|
|
34
67
|
"countdown",
|
|
68
|
+
"countdown-timer",
|
|
69
|
+
"react-countdown",
|
|
70
|
+
"clock",
|
|
71
|
+
"real-time",
|
|
35
72
|
"scheduler",
|
|
73
|
+
"polling",
|
|
74
|
+
"duration",
|
|
75
|
+
"timer-group",
|
|
76
|
+
"typescript",
|
|
36
77
|
"react-hooks"
|
|
37
78
|
],
|
|
38
79
|
"author": "Rajender Joshi <connect@rajender.pro>",
|
|
@@ -67,7 +108,7 @@
|
|
|
67
108
|
"ai:context": "node scripts/ai-context.mjs",
|
|
68
109
|
"build": "tsup",
|
|
69
110
|
"changeset": "changeset",
|
|
70
|
-
"docs:build": "
|
|
111
|
+
"docs:build": "node scripts/build-docs.mjs",
|
|
71
112
|
"docs:dev": "NO_UPDATE_NOTIFIER=1 docusaurus start docs-site",
|
|
72
113
|
"docs:preview": "NO_UPDATE_NOTIFIER=1 docusaurus serve docs-site/build",
|
|
73
114
|
"mcp:docs": "node mcp/server.mjs",
|