@oscarpalmer/timer 0.37.0 → 0.38.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.
@@ -1,532 +0,0 @@
1
- function calculate$1() {
2
- return new Promise(resolve => {
3
- const values = [];
4
- let last;
5
- function step(now) {
6
- if (last != null) {
7
- values.push(now - last);
8
- }
9
- last = now;
10
- if (values.length >= 10) {
11
- const median = values
12
- .sort()
13
- .slice(2, -2)
14
- .reduce((first, second) => first + second, 0) /
15
- (values.length - 4);
16
- resolve(median);
17
- }
18
- else {
19
- requestAnimationFrame(step);
20
- }
21
- }
22
- requestAnimationFrame(step);
23
- });
24
- }
25
- //
26
- const defaultTimeout = 30_000;
27
- /**
28
- * A set of all active timers
29
- */
30
- const activeTimers = new Set();
31
- /**
32
- * Buffer value to use when evaluating if a specific time is within a certain range
33
- */
34
- const intervalBuffer = 5;
35
- /**
36
- * Message to show when a when-timer is destroyed
37
- */
38
- const destroyedMessage = 'Timer has already been destroyed';
39
- /**
40
- * A set of timers that were paused due to the document being hidden
41
- */
42
- const hiddenTimers = new Set();
43
- /**
44
- * Message to show when a when-timer is started
45
- */
46
- const startedMessage = 'Timer has already been started';
47
- const TYPE_REPEAT = 'repeat';
48
- const TYPE_WAIT = 'wait';
49
- const TYPE_WHEN = 'when';
50
- const WORK_CONTINUE = 'continue';
51
- const WORK_PAUSE = 'pause';
52
- const WORK_RESTART = 'restart';
53
- const WORK_START = 'start';
54
- const WORK_STOP = 'stop';
55
- //
56
- /**
57
- * A calculated average of the refresh rate of the display _(in milliseconds)_
58
- */
59
- let milliseconds = 1000 / 60;
60
- calculate$1().then(value => {
61
- milliseconds = value;
62
- });
63
-
64
- if (globalThis._oscarpalmer_timers == null) {
65
- Object.defineProperty(globalThis, '_oscarpalmer_timers', {
66
- get() {
67
- return globalThis._oscarpalmer_timer_debug ? [...activeTimers] : [];
68
- },
69
- });
70
- }
71
- /* istanbul ignore next */
72
- document.addEventListener('visibilitychange', () => {
73
- const from = document.hidden ? activeTimers : hiddenTimers;
74
- const method = document.hidden ? WORK_PAUSE : WORK_CONTINUE;
75
- const to = document.hidden ? hiddenTimers : activeTimers;
76
- for (const timer of from) {
77
- timer[method]();
78
- to.add(timer);
79
- }
80
- from.clear();
81
- });
82
-
83
- function calculate() {
84
- return new Promise((resolve) => {
85
- const values = [];
86
- let last;
87
- function step(now) {
88
- if (last != null) values.push(now - last);
89
- last = now;
90
- if (values.length >= 10) {
91
- const median = values.sort().slice(2, -2).reduce((first, second) => first + second, 0) / (values.length - 4);
92
- resolve(median);
93
- } else requestAnimationFrame(step);
94
- }
95
- requestAnimationFrame(step);
96
- });
97
- }
98
- function noop() {}
99
- calculate().then((value) => {
100
- });
101
-
102
- function getCallback(value) {
103
- return typeof value === 'function' ? value : noop;
104
- }
105
- function getValidTimeout(value) {
106
- return typeof value === 'number' && value > 0 ? value : defaultTimeout;
107
- }
108
- function getValidNumber(value, defaultValue) {
109
- const actualDefault = defaultValue ?? 0;
110
- return typeof value === 'number' && value > actualDefault
111
- ? value
112
- : actualDefault;
113
- }
114
-
115
- /**
116
- * Create a delayed promise that resolves after a certain amount of time _(in milliseconds; defaults to screen refresh rate)_
117
- */
118
- function delay(time) {
119
- return new Promise(resolve => {
120
- const interval = getValidNumber(time, milliseconds);
121
- let start;
122
- function step(now) {
123
- start ??= now;
124
- if (interval === milliseconds ||
125
- now - start >= interval - intervalBuffer) {
126
- resolve();
127
- }
128
- else {
129
- requestAnimationFrame(step);
130
- }
131
- }
132
- requestAnimationFrame(step);
133
- });
134
- }
135
-
136
- function is(names, value) {
137
- return names.includes(value?.$timer);
138
- }
139
- /**
140
- * Is the value a repeating timer?
141
- */
142
- function isRepeated(value) {
143
- return is([TYPE_REPEAT], value);
144
- }
145
- /**
146
- * Is the value a timer?
147
- */
148
- function isTimer(value) {
149
- return is([TYPE_REPEAT, TYPE_WAIT], value);
150
- }
151
- /**
152
- * Is the value a waiting timer?
153
- */
154
- function isWaited(value) {
155
- return is([TYPE_WAIT], value);
156
- }
157
- /**
158
- * Is the value a conditional timer?
159
- */
160
- function isWhen(value) {
161
- return is([TYPE_WHEN], value) && typeof value.then === 'function';
162
- }
163
-
164
- class TimerTrace extends Error {
165
- constructor() {
166
- super();
167
- this.name = 'TimerTrace';
168
- }
169
- }
170
-
171
- function finish(timer, state, options, success) {
172
- cancelAnimationFrame(state.frame);
173
- activeTimers.delete(timer.instance);
174
- state.active = false;
175
- state.elapsed = 0;
176
- state.frame = undefined;
177
- if (timer.type === TYPE_WAIT) {
178
- state.callback();
179
- }
180
- else {
181
- options.onAfter?.(success);
182
- }
183
- }
184
- function ignore(type, state) {
185
- if (state.destroyed) {
186
- return type !== WORK_STOP;
187
- }
188
- if (state.paused) {
189
- return type === WORK_PAUSE || type === WORK_START;
190
- }
191
- return state.active && type === WORK_START;
192
- }
193
- function pause(timer, state) {
194
- cancelAnimationFrame(state.frame);
195
- state.frame = undefined;
196
- return timer.instance;
197
- }
198
- function run(timer, state, options) {
199
- let last;
200
- return function step(now) {
201
- if (!state.active) {
202
- return;
203
- }
204
- last ??= now;
205
- const difference = now - last;
206
- state.elapsed += difference;
207
- state.total += difference;
208
- last = now;
209
- if (options.timeout > 0 && state.total >= options.timeout) {
210
- options.onError?.();
211
- finish(timer, state, options, false);
212
- return;
213
- }
214
- if (options.interval === milliseconds ||
215
- state.elapsed >= options.interval - intervalBuffer) {
216
- if (options.count > -1) {
217
- state.callback(state.index);
218
- }
219
- state.elapsed = 0;
220
- state.index += 1;
221
- if (options.count === -1 ||
222
- (options.count > 0 && state.index >= options.count)) {
223
- finish(timer, state, options, true);
224
- return;
225
- }
226
- }
227
- state.frame = requestAnimationFrame(step);
228
- };
229
- }
230
- function setState(type, state) {
231
- const pausable = type === WORK_CONTINUE || type === WORK_PAUSE;
232
- state.elapsed = pausable ? state.elapsed : 0;
233
- state.index = pausable ? state.index : 0;
234
- state.total = pausable ? state.total : 0;
235
- }
236
- function stop(timer, state, options) {
237
- cancelAnimationFrame(state.frame);
238
- activeTimers.delete(timer.instance);
239
- options.onAfter?.(false);
240
- state.active = !stop;
241
- state.frame = undefined;
242
- state.paused = false;
243
- return timer.instance;
244
- }
245
- function work(type, timer, state, options) {
246
- if (ignore(type, state)) {
247
- return timer.instance;
248
- }
249
- setState(type, state);
250
- if (type === WORK_STOP) {
251
- return stop(timer, state, options);
252
- }
253
- if (type === WORK_PAUSE || type === WORK_RESTART) {
254
- cancelAnimationFrame(state.frame);
255
- state.frame = undefined;
256
- }
257
- state.active = true;
258
- state.paused = type === WORK_PAUSE;
259
- if (state.paused) {
260
- return pause(timer, state);
261
- }
262
- activeTimers.add(timer.instance);
263
- const runner = run(timer, state, options);
264
- state.frame = requestAnimationFrame(runner);
265
- return timer.instance;
266
- }
267
-
268
- class Timer {
269
- options;
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)
294
- ? this.state.trace
295
- : undefined;
296
- }
297
- constructor(type, state, options, start) {
298
- this.options = options;
299
- this.$timer = type;
300
- this.state = {
301
- ...state,
302
- active: false,
303
- destroyed: false,
304
- elapsed: 0,
305
- frame: undefined,
306
- index: 0,
307
- paused: false,
308
- total: 0,
309
- };
310
- if (start) {
311
- this.start();
312
- }
313
- }
314
- /**
315
- * Continue running the timer _(if it's paused)_
316
- */
317
- continue() {
318
- return this.#work(WORK_CONTINUE);
319
- }
320
- /**
321
- * Destroy the timer
322
- */
323
- destroy() {
324
- this.state.destroyed = true;
325
- this.options.onAfter = noop;
326
- this.options.onError = noop;
327
- this.state.callback = noop;
328
- if (!globalThis._oscarpalmer_timer_debug) {
329
- this.state.trace = undefined;
330
- }
331
- stop({
332
- instance: this,
333
- type: this.$timer,
334
- }, this.state, this.options);
335
- }
336
- /**
337
- * Pause the timer _(if it's running)_
338
- */
339
- pause() {
340
- return this.#work(WORK_PAUSE);
341
- }
342
- /**
343
- * Restart the timer _(or start it, if it's not running)_
344
- */
345
- restart() {
346
- return this.#work(WORK_RESTART);
347
- }
348
- /**
349
- * Start the timer _(if it's not running)_
350
- */
351
- start() {
352
- return this.#work(WORK_START);
353
- }
354
- /**
355
- * Stop the timer _(if it's running)_
356
- */
357
- stop() {
358
- return this.#work(WORK_STOP);
359
- }
360
- #work(type) {
361
- return work(type, {
362
- instance: this,
363
- type: this.$timer,
364
- }, this.state, this.options);
365
- }
366
- }
367
-
368
- /**
369
- * Create a repeating timer
370
- */
371
- function repeat(callback, options) {
372
- return new Timer(TYPE_REPEAT, {
373
- callback: getCallback(callback),
374
- trace: new TimerTrace().stack,
375
- }, {
376
- onAfter: getCallback(options?.onAfter),
377
- onError: getCallback(options?.onTimeout),
378
- count: getValidNumber(options?.count),
379
- interval: getValidNumber(options?.interval, milliseconds),
380
- timeout: getValidNumber(options?.timeout),
381
- }, true);
382
- }
383
-
384
- /**
385
- * Create a waiting timer
386
- * @param callback Callback to run when the timer has finished
387
- * @param time How long to wait for _(in milliseconds; defaults to screen refresh rate)_
388
- */
389
- function wait(callback, time) {
390
- return new Timer(TYPE_WAIT, {
391
- callback: getCallback(callback),
392
- trace: new TimerTrace().stack,
393
- }, {
394
- onAfter: undefined,
395
- onError: undefined,
396
- count: -1,
397
- interval: getValidNumber(time, milliseconds),
398
- timeout: 0,
399
- }, true);
400
- }
401
-
402
- class When {
403
- $timer = TYPE_WHEN;
404
- state = {
405
- promise: undefined,
406
- rejecter: undefined,
407
- resolver: undefined,
408
- started: false,
409
- timer: undefined,
410
- };
411
- /**
412
- * Is the timer active?
413
- */
414
- get active() {
415
- return this.state.timer?.active ?? false;
416
- }
417
- /**
418
- * Is the timer destroyed?
419
- */
420
- get destroyed() {
421
- return this.state.timer == null;
422
- }
423
- /**
424
- * Is the timer paused?
425
- */
426
- get paused() {
427
- return this.state.timer?.paused ?? false;
428
- }
429
- /**
430
- * Get the timer's origin _(if debugging is enabled)_
431
- */
432
- get trace() {
433
- return (globalThis._oscarpalmer_timer_debug ?? false)
434
- ? this.state.timer?.trace
435
- : undefined;
436
- }
437
- constructor(condition, options) {
438
- const { state } = this;
439
- state.promise = new Promise((resolve, reject) => {
440
- state.resolver = resolve;
441
- state.rejecter = reject;
442
- });
443
- let result = false;
444
- this.state.timer = new Timer(TYPE_WHEN, {
445
- callback() {
446
- try {
447
- if (condition()) {
448
- result = true;
449
- state.timer.stop();
450
- }
451
- }
452
- catch {
453
- state.timer.stop();
454
- }
455
- },
456
- trace: new TimerTrace().stack,
457
- }, {
458
- onAfter: () => {
459
- if (result) {
460
- state.resolver?.();
461
- }
462
- else {
463
- state.rejecter?.();
464
- }
465
- this.destroy();
466
- },
467
- onError: () => {
468
- state.rejecter?.();
469
- this.destroy();
470
- },
471
- count: getValidNumber(options?.count),
472
- interval: getValidNumber(options?.interval, milliseconds),
473
- timeout: getValidTimeout(options?.timeout),
474
- }, false);
475
- }
476
- /**
477
- * Continues the timer _(if it was paused)_
478
- */
479
- continue() {
480
- this.state.timer?.continue();
481
- return this;
482
- }
483
- /**
484
- * Destroys the timer _(and stops it,if it was running)_
485
- */
486
- destroy() {
487
- const { state } = this;
488
- state.timer?.destroy();
489
- state.promise = undefined;
490
- state.resolver = noop;
491
- state.rejecter = noop;
492
- state.timer = undefined;
493
- }
494
- /**
495
- * Pauses the timer _(if it was running)_
496
- */
497
- pause() {
498
- this.state.timer?.pause();
499
- return this;
500
- }
501
- /**
502
- * Stops the timer _(if it was running)_
503
- */
504
- stop() {
505
- this.state.timer?.stop();
506
- return this;
507
- }
508
- /**
509
- * Starts the timer and returns a promise that resolves when the condition is met
510
- */
511
- // biome-ignore lint/suspicious/noThenProperty: returning a promise-like object, so it's ok ;)
512
- then(resolve, reject) {
513
- const { state } = this;
514
- if (state.timer == null) {
515
- throw new Error(destroyedMessage);
516
- }
517
- if (state.started) {
518
- throw new Error(startedMessage);
519
- }
520
- state.started = true;
521
- state.timer.start();
522
- return state.promise.then(resolve ?? noop, reject ?? noop);
523
- }
524
- }
525
- /**
526
- * Create a conditional timer
527
- */
528
- function when(condition, options) {
529
- return new When(condition, options);
530
- }
531
-
532
- export { delay, isRepeated, isTimer, isWaited, isWhen, repeat, wait, when };
package/dist/wait.cjs DELETED
@@ -1,18 +0,0 @@
1
- const require_constants = require("./constants.cjs");
2
- const require_get = require("./get.cjs");
3
- require("./global.cjs");
4
- const require_models = require("./models.cjs");
5
- const require_timer = require("./timer.cjs");
6
- function wait(callback, time) {
7
- return new require_timer.Timer(require_constants.TYPE_WAIT, {
8
- callback: require_get.getCallback(callback),
9
- trace: new require_models.TimerTrace().stack
10
- }, {
11
- onAfter: void 0,
12
- onError: void 0,
13
- count: -1,
14
- interval: require_get.getValidNumber(time, require_constants.milliseconds),
15
- timeout: 0
16
- }, true);
17
- }
18
- exports.wait = wait;
package/dist/when.cjs DELETED
@@ -1,96 +0,0 @@
1
- const require_rolldown_runtime = require("./rolldown_runtime.cjs");
2
- const require_constants = require("./constants.cjs");
3
- const require_get = require("./get.cjs");
4
- require("./global.cjs");
5
- const require_models = require("./models.cjs");
6
- const require_timer = require("./timer.cjs");
7
- let __oscarpalmer_atoms_function = require("@oscarpalmer/atoms/function");
8
- __oscarpalmer_atoms_function = require_rolldown_runtime.__toESM(__oscarpalmer_atoms_function);
9
- var When = class {
10
- $timer = require_constants.TYPE_WHEN;
11
- state = {
12
- promise: void 0,
13
- rejecter: void 0,
14
- resolver: void 0,
15
- started: false,
16
- timer: void 0
17
- };
18
- get active() {
19
- return this.state.timer?.active ?? false;
20
- }
21
- get destroyed() {
22
- return this.state.timer == null;
23
- }
24
- get paused() {
25
- return this.state.timer?.paused ?? false;
26
- }
27
- get trace() {
28
- return globalThis._oscarpalmer_timer_debug ?? false ? this.state.timer?.trace : void 0;
29
- }
30
- constructor(condition, options) {
31
- const { state } = this;
32
- state.promise = new Promise((resolve, reject) => {
33
- state.resolver = resolve;
34
- state.rejecter = reject;
35
- });
36
- let result = false;
37
- this.state.timer = new require_timer.Timer(require_constants.TYPE_WHEN, {
38
- callback() {
39
- try {
40
- if (condition()) {
41
- result = true;
42
- state.timer.stop();
43
- }
44
- } catch {
45
- state.timer.stop();
46
- }
47
- },
48
- trace: new require_models.TimerTrace().stack
49
- }, {
50
- onAfter: () => {
51
- if (result) state.resolver?.();
52
- else state.rejecter?.();
53
- this.destroy();
54
- },
55
- onError: () => {
56
- state.rejecter?.();
57
- this.destroy();
58
- },
59
- count: require_get.getValidNumber(options?.count),
60
- interval: require_get.getValidNumber(options?.interval, require_constants.milliseconds),
61
- timeout: require_get.getValidTimeout(options?.timeout)
62
- }, false);
63
- }
64
- continue() {
65
- this.state.timer?.continue();
66
- return this;
67
- }
68
- destroy() {
69
- const { state } = this;
70
- state.timer?.destroy();
71
- state.promise = void 0;
72
- state.resolver = __oscarpalmer_atoms_function.noop;
73
- state.rejecter = __oscarpalmer_atoms_function.noop;
74
- state.timer = void 0;
75
- }
76
- pause() {
77
- this.state.timer?.pause();
78
- return this;
79
- }
80
- stop() {
81
- this.state.timer?.stop();
82
- return this;
83
- }
84
- then(resolve, reject) {
85
- const { state } = this;
86
- if (state.timer == null) throw new Error(require_constants.destroyedMessage);
87
- if (state.started) throw new Error(require_constants.startedMessage);
88
- state.started = true;
89
- state.timer.start();
90
- return state.promise.then(resolve ?? __oscarpalmer_atoms_function.noop, reject ?? __oscarpalmer_atoms_function.noop);
91
- }
92
- };
93
- function when(condition, options) {
94
- return new When(condition, options);
95
- }
96
- exports.when = when;