@oscarpalmer/timer 0.42.0 → 0.44.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.mjs CHANGED
@@ -46,42 +46,50 @@ function getInterval(value) {
46
46
  return typeof value === "number" && value > 0 ? value : 0;
47
47
  }
48
48
  function getTimer(type, callback, time) {
49
- const interval = getInterval(time);
50
- function run(now) {
49
+ function run() {
50
+ const now = performance.now();
51
51
  start ??= now;
52
52
  if (interval === 0 || now - start >= interval - OFFSET) {
53
- if (throttle) start = now;
53
+ start = throttle ? now : void 0;
54
54
  callback(...args);
55
- } else frame = requestAnimationFrame(run);
55
+ } else id = startTimer(run);
56
56
  }
57
+ const interval = getInterval(time);
57
58
  const throttle = type === TIMER_THROTTLE;
58
59
  let args;
59
- let frame;
60
+ let id;
60
61
  let start;
61
62
  const timer = (...parameters) => {
62
63
  timer.cancel();
63
64
  args = parameters;
64
- frame = requestAnimationFrame(run);
65
+ if (throttle) run();
66
+ else id = startTimer(run);
65
67
  };
66
68
  timer.cancel = () => {
67
- cancelAnimationFrame(frame);
69
+ clearTimer(id);
68
70
  };
69
71
  return timer;
70
72
  }
71
73
  const OFFSET = 5;
72
74
  const TIMER_THROTTLE = "throttle";
73
75
  const TIMER_WAIT = "wait";
76
+ // istanbul ignore next
77
+ const clearTimer = typeof cancelAnimationFrame === "function" ? cancelAnimationFrame : clearTimeout;
78
+ // istanbul ignore next
79
+ const startTimer = typeof requestAnimationFrame === "function" ? requestAnimationFrame : setTimeout;
74
80
  //#endregion
75
81
  //#region node_modules/@oscarpalmer/atoms/dist/promise/models.mjs
76
82
  const PROMISE_ABORT_EVENT = "abort";
77
83
  const PROMISE_ABORT_OPTIONS = { once: true };
78
84
  //#endregion
79
- //#region node_modules/@oscarpalmer/atoms/dist/promise/helpers.mjs
80
- function getNumberOrDefault(value) {
81
- return typeof value === "number" && value > 0 ? value : 0;
85
+ //#region node_modules/@oscarpalmer/atoms/dist/internal/number.mjs
86
+ function getNumberOrDefault(value, defaultValue, minimum) {
87
+ return typeof value === "number" && !Number.isNaN(value) && value >= (minimum ?? 0) ? Math.floor(value) : defaultValue;
82
88
  }
89
+ //#endregion
90
+ //#region node_modules/@oscarpalmer/atoms/dist/promise/helpers.mjs
83
91
  function getPromiseOptions(input) {
84
- if (typeof input === "number") return { time: getNumberOrDefault(input) };
92
+ if (typeof input === "number") return { time: getNumberOrDefault(input, 0) };
85
93
  if (input instanceof AbortSignal) return {
86
94
  signal: input,
87
95
  time: 0
@@ -89,7 +97,7 @@ function getPromiseOptions(input) {
89
97
  const options = typeof input === "object" && input !== null ? input : {};
90
98
  return {
91
99
  signal: options.signal instanceof AbortSignal ? options.signal : void 0,
92
- time: getNumberOrDefault(options.time)
100
+ time: getNumberOrDefault(options.time, 0)
93
101
  };
94
102
  }
95
103
  //#endregion
@@ -155,7 +163,7 @@ function isWaited(value) {
155
163
  * @returns `true` if the value is a conditional timer
156
164
  */
157
165
  function isWhen(value) {
158
- return is(["when"], value) && typeof value.then === "function";
166
+ return is(["when"], value) && typeof value.start === "function";
159
167
  }
160
168
  //#endregion
161
169
  //#region node_modules/@oscarpalmer/atoms/dist/internal/function/misc.mjs
@@ -191,7 +199,7 @@ function finish(timer, state, options, success) {
191
199
  state.active = false;
192
200
  state.elapsed = 0;
193
201
  state.frame = void 0;
194
- if (timer.type === "wait") state.callback();
202
+ if (timer.name === "wait") state.callback();
195
203
  else options.onAfter?.(success);
196
204
  }
197
205
  function ignore(type, state) {
@@ -266,108 +274,78 @@ function work(type, timer, state, options) {
266
274
  }
267
275
  //#endregion
268
276
  //#region src/timer.ts
269
- var Timer = class {
270
- state;
271
- /**
272
- * Is the timer active?
273
- */
274
- get active() {
275
- return this.state.active;
276
- }
277
- /**
278
- * Is the timer destroyed?
279
- */
280
- get destroyed() {
281
- return this.state.destroyed;
282
- }
283
- /**
284
- * Is the timer paused?
285
- */
286
- get paused() {
287
- return this.state.paused;
288
- }
289
- /**
290
- * Get the timer's origin _(if debugging is enabled)_
291
- */
292
- get trace() {
293
- return globalThis._oscarpalmer_timer_debug ?? false ? this.state.trace : void 0;
294
- }
295
- constructor(type, state, options, start) {
296
- this.options = options;
297
- Object.defineProperty(this, "$timer", { value: type });
298
- this.state = {
299
- ...state,
300
- active: false,
301
- destroyed: false,
302
- elapsed: 0,
303
- frame: void 0,
304
- index: 0,
305
- paused: false,
306
- total: 0
307
- };
308
- if (start) this.start();
309
- }
310
- /**
311
- * Continue running the timer _(if it's paused)_
312
- */
313
- continue() {
314
- return this.#work(WORK_CONTINUE);
315
- }
316
- /**
317
- * Destroy the timer
318
- */
319
- destroy() {
320
- this.state.destroyed = true;
321
- this.options.onAfter = noop;
322
- this.options.onError = noop;
323
- this.state.callback = noop;
324
- if (!globalThis._oscarpalmer_timer_debug) this.state.trace = void 0;
325
- stop({
326
- instance: this,
327
- type: this.$timer
328
- }, this.state, this.options);
329
- }
330
- /**
331
- * Pause the timer _(if it's running)_
332
- */
333
- pause() {
334
- return this.#work(WORK_PAUSE);
335
- }
336
- /**
337
- * Restart the timer _(or start it, if it's not running)_
338
- */
339
- restart() {
340
- return this.#work(WORK_RESTART);
341
- }
342
- /**
343
- * Start the timer _(if it's not running)_
344
- */
345
- start() {
346
- return this.#work(WORK_START);
347
- }
348
- /**
349
- * Stop the timer _(if it's running)_
350
- */
351
- stop() {
352
- return this.#work(WORK_STOP);
353
- }
354
- #work(type) {
277
+ function createTimer(name, pick, options, start) {
278
+ function worker(type) {
355
279
  return work(type, {
356
- instance: this,
357
- type: this.$timer
358
- }, this.state, this.options);
280
+ name,
281
+ instance
282
+ }, state, options);
359
283
  }
360
- };
284
+ const state = {
285
+ ...pick,
286
+ active: false,
287
+ destroyed: false,
288
+ elapsed: 0,
289
+ frame: void 0,
290
+ index: 0,
291
+ paused: false,
292
+ total: 0
293
+ };
294
+ const instance = {
295
+ continue: () => worker(WORK_CONTINUE),
296
+ destroy: () => destroyTimer(name, instance, state, options),
297
+ pause: () => worker(WORK_PAUSE),
298
+ restart: () => worker(WORK_RESTART),
299
+ start: () => worker(WORK_START),
300
+ stop: () => worker(WORK_STOP)
301
+ };
302
+ Object.defineProperties(instance, {
303
+ $timer: {
304
+ enumerable: false,
305
+ value: name
306
+ },
307
+ active: {
308
+ enumerable: true,
309
+ get: () => state.active
310
+ },
311
+ destroyed: {
312
+ enumerable: true,
313
+ get: () => state.destroyed
314
+ },
315
+ paused: {
316
+ enumerable: true,
317
+ get: () => state.paused
318
+ },
319
+ trace: {
320
+ enumerable: true,
321
+ get: () => globalThis._oscarpalmer_timer_debug ?? false ? state.trace : void 0
322
+ }
323
+ });
324
+ if (start) instance.start();
325
+ return Object.freeze(instance);
326
+ }
327
+ function destroyTimer(name, instance, state, options) {
328
+ state.destroyed = true;
329
+ options.onAfter = noop;
330
+ options.onError = noop;
331
+ state.callback = noop;
332
+ if (!globalThis._oscarpalmer_timer_debug) state.trace = void 0;
333
+ stop({
334
+ instance,
335
+ name
336
+ }, state, options);
337
+ }
361
338
  //#endregion
362
339
  //#region src/repeat.ts
363
340
  /**
364
341
  * Create a repeating timer
342
+ *
365
343
  * @param callback Callback to run on each interval
366
344
  * @param options Timer options
367
345
  * @returns Timer instance
368
346
  */
369
347
  function repeat(callback, options) {
370
- return new Timer(TYPE_REPEAT, {
348
+ return createTimer(TYPE_REPEAT, {
371
349
  callback: getCallback(callback),
372
350
  trace: new TimerTrace().stack
373
351
  }, {
@@ -382,11 +360,12 @@ function repeat(callback, options) {
382
360
  //#region src/wait.ts
383
361
  /**
384
362
  * Create a waiting timer
363
+ *
385
364
  * @param callback Callback to run when the timer has finished
386
365
  * @param time How long to wait for _(in milliseconds; defaults to screen refresh rate)_
387
366
  */
388
367
  function wait(callback, time) {
389
- return new Timer(TYPE_WAIT, {
368
+ return createTimer(TYPE_WAIT, {
390
369
  callback: getCallback(callback),
391
370
  trace: new TimerTrace().stack
392
371
  }, {
@@ -399,130 +378,43 @@ function wait(callback, time) {
399
378
  }
400
379
  //#endregion
401
380
  //#region src/when.ts
402
- var When = class {
403
- state = {
404
- promise: void 0,
405
- rejecter: void 0,
406
- resolver: void 0,
407
- started: false,
408
- timer: void 0
409
- };
410
- /**
411
- * Is the timer active?
412
- */
413
- get active() {
414
- return this.state.timer?.active ?? false;
415
- }
416
- /**
417
- * Is the timer destroyed?
418
- */
419
- get destroyed() {
420
- return this.state.timer == null;
421
- }
422
- /**
423
- * Is the timer paused?
424
- */
425
- get paused() {
426
- return this.state.timer?.paused ?? false;
427
- }
428
- /**
429
- * Get the timer's origin _(if debugging is enabled)_
430
- */
431
- get trace() {
432
- return globalThis._oscarpalmer_timer_debug ?? false ? this.state.timer?.trace : void 0;
433
- }
434
- constructor(condition, options) {
435
- Object.defineProperty(this, "$timer", { value: TYPE_WHEN });
436
- const { state } = this;
437
- state.promise = new Promise((resolve, reject) => {
438
- state.resolver = resolve;
439
- state.rejecter = reject;
440
- });
441
- let result = false;
442
- this.state.timer = new Timer(TYPE_WHEN, {
443
- callback() {
444
- try {
445
- if (condition()) {
446
- result = true;
447
- state.timer.stop();
448
- }
449
- } catch {
450
- state.timer.stop();
451
- }
452
- },
453
- trace: new TimerTrace().stack
454
- }, {
455
- onAfter: () => {
456
- if (result) state.resolver?.();
457
- else state.rejecter?.();
458
- this.destroy();
459
- },
460
- onError: () => {
461
- state.rejecter?.();
462
- this.destroy();
463
- },
464
- count: getValidNumber(options?.count),
465
- interval: getValidNumber(options?.interval),
466
- timeout: getValidTimeout(options?.timeout)
467
- }, false);
468
- }
469
- /**
470
- * Continues the timer _(if it was paused)_
471
- */
472
- continue() {
473
- this.state.timer?.continue();
474
- return this;
475
- }
476
- /**
477
- * Destroys the timer _(and stops it,if it was running)_
478
- */
479
- destroy() {
480
- const { state } = this;
481
- state.timer?.destroy();
482
- state.promise = void 0;
483
- state.resolver = noop;
484
- state.rejecter = noop;
485
- state.timer = void 0;
486
- }
487
- /**
488
- * Pauses the timer _(if it was running)_
489
- */
490
- pause() {
491
- this.state.timer?.pause();
492
- return this;
493
- }
494
- /**
495
- * Start the timer
496
- * @param resolve Optional resolve callback
497
- * @param reject Optional reject callback
498
- * @returns Promise that resolves when the condition is met
499
- */
500
- start(resolve, reject) {
501
- const { state } = this;
502
- if (state.timer == null) throw new Error(MESSAGE_DESTROYED);
503
- if (state.started) throw new Error(MESSAGE_STARTED);
504
- state.started = true;
505
- state.timer.start();
506
- return state.promise.then(resolve ?? noop, reject ?? noop);
507
- }
508
- /**
509
- * Stops the timer _(if it was running)_
510
- */
511
- stop() {
512
- this.state.timer?.stop();
513
- return this;
514
- }
515
- /**
516
- * Start the timer
517
- * @deprecated Use `start()` instead
518
- * @param resolve Optional resolve callback
519
- * @param reject Optional reject callback
520
- * @returns Promise that resolves when the condition is met
521
- */
522
- then(resolve, reject) {
523
- return this.start(resolve, reject);
381
+ function destroyWhen(state) {
382
+ state.timer?.destroy();
383
+ state.promise = void 0;
384
+ state.resolver = noop;
385
+ state.rejecter = noop;
386
+ state.timer = void 0;
387
+ }
388
+ function onAfter(instance, state) {
389
+ if (state.result) state.resolver?.();
390
+ else state.rejecter?.();
391
+ instance.destroy();
392
+ }
393
+ function onCallback(condition, state) {
394
+ try {
395
+ if (condition()) {
396
+ state.result = true;
397
+ state.timer.stop();
398
+ }
399
+ } catch {
400
+ state.timer.stop();
524
401
  }
525
- };
402
+ }
403
+ function onError(instance, state) {
404
+ state.rejecter?.();
405
+ instance.destroy();
406
+ }
407
+ function onWhen(type, instance, state) {
408
+ state.timer?.[type]?.();
409
+ return instance;
410
+ }
411
+ function startWhen(state, resolve) {
412
+ if (state.timer == null) throw new Error(MESSAGE_DESTROYED);
413
+ if (state.started) throw new Error(MESSAGE_STARTED);
414
+ state.started = true;
415
+ state.timer.start();
416
+ return state.promise.then(resolve);
417
+ }
526
418
  /**
527
419
  * Create a conditional timer
528
420
  * @param condition Condition to check
@@ -530,7 +422,57 @@ var When = class {
530
422
  * @returns Timer instance
531
423
  */
532
424
  function when(condition, options) {
533
- return new When(condition, options);
425
+ const state = {
426
+ promise: void 0,
427
+ result: false,
428
+ started: false,
429
+ timer: void 0
430
+ };
431
+ let instance;
432
+ state.promise = new Promise((resolve, reject) => {
433
+ state.resolver = resolve;
434
+ state.rejecter = reject;
435
+ });
436
+ state.timer = createTimer(TYPE_WHEN, {
437
+ callback: () => onCallback(condition, state),
438
+ trace: new TimerTrace().stack
439
+ }, {
440
+ onAfter: () => onAfter(instance, state),
441
+ onError: () => onError(instance, state),
442
+ count: getValidNumber(options?.count),
443
+ interval: getValidNumber(options?.interval),
444
+ timeout: getValidTimeout(options?.timeout)
445
+ }, false);
446
+ instance = {
447
+ continue: () => onWhen(WORK_CONTINUE, instance, state),
448
+ destroy: () => destroyWhen(state),
449
+ pause: () => onWhen("pause", instance, state),
450
+ start: (resolve) => startWhen(state, resolve),
451
+ stop: () => onWhen("stop", instance, state)
452
+ };
453
+ Object.defineProperties(instance, {
454
+ $timer: {
455
+ enumerable: false,
456
+ value: TYPE_WHEN
457
+ },
458
+ active: {
459
+ enumerable: true,
460
+ get: () => state.timer?.active ?? false
461
+ },
462
+ destroyed: {
463
+ enumerable: true,
464
+ get: () => state.timer == null
465
+ },
466
+ paused: {
467
+ enumerable: true,
468
+ get: () => state.timer?.paused ?? false
469
+ },
470
+ trace: {
471
+ enumerable: true,
472
+ get: () => globalThis._oscarpalmer_timer_debug ?? false ? state.timer?.trace : void 0
473
+ }
474
+ });
475
+ return Object.freeze(instance);
534
476
  }
535
477
  //#endregion
536
478
  export { delay, isRepeated, isTimer, isWaited, isWhen, repeat, wait, when };
package/dist/is.d.mts CHANGED
@@ -1,6 +1,4 @@
1
- import { Timer } from "./timer.mjs";
2
- import { When } from "./when.mjs";
3
-
1
+ import { Timer, When } from "./models.mjs";
4
2
  //#region src/is.d.ts
5
3
  /**
6
4
  * Is the value a repeating timer?
package/dist/is.mjs CHANGED
@@ -33,7 +33,7 @@ function isWaited(value) {
33
33
  * @returns `true` if the value is a conditional timer
34
34
  */
35
35
  function isWhen(value) {
36
- return is(["when"], value) && typeof value.then === "function";
36
+ return is(["when"], value) && typeof value.start === "function";
37
37
  }
38
38
  //#endregion
39
39
  export { isRepeated, isTimer, isWaited, isWhen };
package/dist/models.d.mts CHANGED
@@ -1,5 +1,3 @@
1
- import { Timer } from "./timer.mjs";
2
-
3
1
  //#region src/models.d.ts
4
2
  /**
5
3
  * Options for a repeating timer
@@ -26,6 +24,49 @@ type RepeatOptions = {
26
24
  */
27
25
  timeout: number;
28
26
  };
27
+ type Timer = {
28
+ /**
29
+ * Is the timer active?
30
+ */
31
+ get active(): boolean;
32
+ /**
33
+ * Is the timer destroyed?
34
+ */
35
+ get destroyed(): boolean;
36
+ /**
37
+ * Is the timer paused?
38
+ */
39
+ get paused(): boolean;
40
+ /**
41
+ * Get the timer's origin _(if debugging is enabled)_
42
+ */
43
+ get trace(): string | undefined;
44
+ /**
45
+ * Continue running the timer _(if it's paused)_
46
+ */
47
+ continue(): Timer;
48
+ /**
49
+ * Destroy the timer
50
+ */
51
+ destroy(): void;
52
+ /**
53
+ * Pause the timer _(if it's running)_
54
+ */
55
+ pause(): Timer;
56
+ /**
57
+ * Restart the timer _(or start it, if it's not running)_
58
+ */
59
+ restart(): Timer;
60
+ /**
61
+ * Start the timer _(if it's not running)_
62
+ */
63
+ start(): Timer;
64
+ /**
65
+ * Stop the timer _(if it's running)_
66
+ */
67
+ stop(): Timer;
68
+ };
69
+ type TimerName = 'repeat' | 'wait' | 'when';
29
70
  type TimerOptions = {
30
71
  onAfter: ((finished: boolean) => void) | undefined;
31
72
  onError: (() => void) | undefined;
@@ -47,7 +88,47 @@ type TimerState = {
47
88
  declare class TimerTrace extends Error {
48
89
  constructor();
49
90
  }
50
- type TimerType = 'repeat' | 'wait' | 'when';
91
+ type When = {
92
+ /**
93
+ * Is the timer active?
94
+ */
95
+ get active(): boolean;
96
+ /**
97
+ * Is the timer destroyed?
98
+ */
99
+ get destroyed(): boolean;
100
+ /**
101
+ * Is the timer paused?
102
+ */
103
+ get paused(): boolean;
104
+ /**
105
+ * Get the timer's origin _(if debugging is enabled)_
106
+ */
107
+ get trace(): string | undefined;
108
+ /**
109
+ * Continues the timer _(if it was paused)_
110
+ */
111
+ continue(): When;
112
+ /**
113
+ * Destroys the timer _(and stops it,if it was running)_
114
+ */
115
+ destroy(): void;
116
+ /**
117
+ * Pauses the timer _(if it was running)_
118
+ */
119
+ pause(): When;
120
+ /**
121
+ * Start the timer
122
+ *
123
+ * @param resolve Optional resolve callback
124
+ * @returns Promise that resolves when the condition is met
125
+ */
126
+ start(resolve?: (() => void) | null): Promise<void>;
127
+ /**
128
+ * Stops the timer _(if it was running)_
129
+ */
130
+ stop(): When;
131
+ };
51
132
  /**
52
133
  * Options for a conditional timer
53
134
  */
@@ -69,14 +150,15 @@ type WhenState = {
69
150
  promise: Promise<void>;
70
151
  rejecter?: () => void;
71
152
  resolver?: () => void;
153
+ result: boolean;
72
154
  started: boolean;
73
155
  timer: Timer;
74
156
  };
75
157
  type WorkHandler = (type: WorkHandlerType, timer: WorkHandlerTimer, state: TimerState, options: TimerOptions) => Timer;
76
158
  type WorkHandlerTimer = {
77
159
  instance: Timer;
78
- type: TimerType;
160
+ name: TimerName;
79
161
  };
80
162
  type WorkHandlerType = 'continue' | 'pause' | 'restart' | 'start' | 'stop';
81
163
  //#endregion
82
- export { RepeatOptions, TimerOptions, TimerState, TimerTrace, TimerType, WhenOptions, WhenState, WorkHandler, WorkHandlerTimer, WorkHandlerType };
164
+ export { RepeatOptions, Timer, TimerName, TimerOptions, TimerState, TimerTrace, When, WhenOptions, WhenState, WorkHandler, WorkHandlerTimer, WorkHandlerType };
package/dist/repeat.d.mts CHANGED
@@ -1,12 +1,13 @@
1
- import { Timer } from "./timer.mjs";
2
- import { RepeatOptions } from "./models.mjs";
1
+ import { RepeatOptions, Timer } from "./models.mjs";
2
+ import "./global.mjs";
3
3
  //#region src/repeat.d.ts
4
4
  /**
5
5
  * Create a repeating timer
6
+ *
6
7
  * @param callback Callback to run on each interval
7
8
  * @param options Timer options
8
9
  * @returns Timer instance
9
10
  */
10
11
  declare function repeat(callback: (index: number) => void, options?: Partial<RepeatOptions>): Timer;
11
12
  //#endregion
12
- export { type RepeatOptions, type Timer, repeat };
13
+ export { repeat };
package/dist/repeat.mjs CHANGED
@@ -2,16 +2,17 @@ import { TYPE_REPEAT } from "./constants.mjs";
2
2
  import { getCallback, getValidNumber } from "./get.mjs";
3
3
  import "./global.mjs";
4
4
  import { TimerTrace } from "./models.mjs";
5
- import { Timer } from "./timer.mjs";
5
+ import { createTimer } from "./timer.mjs";
6
6
  //#region src/repeat.ts
7
7
  /**
8
8
  * Create a repeating timer
9
+ *
9
10
  * @param callback Callback to run on each interval
10
11
  * @param options Timer options
11
12
  * @returns Timer instance
12
13
  */
13
14
  function repeat(callback, options) {
14
- return new Timer(TYPE_REPEAT, {
15
+ return createTimer(TYPE_REPEAT, {
15
16
  callback: getCallback(callback),
16
17
  trace: new TimerTrace().stack
17
18
  }, {