@oscarpalmer/timer 0.43.0 → 0.45.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/constants.d.mts +6 -19
- package/dist/constants.mjs +5 -13
- package/dist/global.d.mts +4 -2
- package/dist/global.mjs +5 -14
- package/dist/index.d.mts +52 -95
- package/dist/index.mjs +232 -411
- package/dist/is.d.mts +1 -3
- package/dist/misc.d.mts +10 -0
- package/dist/misc.mjs +34 -0
- package/dist/models.d.mts +110 -7
- package/dist/repeat.d.mts +3 -3
- package/dist/repeat.mjs +3 -3
- package/dist/timer.d.mts +3 -50
- package/dist/timer.mjs +50 -94
- package/dist/wait.d.mts +3 -2
- package/dist/wait.mjs +3 -3
- package/dist/when.d.mts +3 -46
- package/dist/when.mjs +77 -117
- package/dist/work.d.mts +3 -5
- package/dist/work.mjs +26 -31
- package/package.json +8 -8
- package/src/constants.ts +8 -19
- package/src/global.ts +12 -22
- package/src/index.ts +4 -5
- package/src/is.ts +1 -2
- package/src/misc.ts +49 -0
- package/src/models.ts +129 -6
- package/src/repeat.ts +4 -6
- package/src/timer.ts +60 -130
- package/src/wait.ts +4 -6
- package/src/when.ts +98 -153
- package/src/work.ts +33 -57
- package/dist/delay.d.mts +0 -3
- package/dist/delay.mjs +0 -2
- package/dist/get.d.mts +0 -8
- package/dist/get.mjs +0 -15
- package/src/delay.ts +0 -2
- package/src/get.ts +0 -17
package/dist/index.mjs
CHANGED
|
@@ -1,21 +1,13 @@
|
|
|
1
1
|
//#region src/constants.ts
|
|
2
2
|
const DEFAULT_TIMEOUT = 3e4;
|
|
3
3
|
/**
|
|
4
|
-
* Message to show when a when-timer is destroyed
|
|
5
|
-
*/
|
|
6
|
-
const MESSAGE_DESTROYED = "Timer has already been destroyed";
|
|
7
|
-
/**
|
|
8
4
|
* Message to show when a when-timer is started
|
|
9
5
|
*/
|
|
10
6
|
const MESSAGE_STARTED = "Timer has already been started";
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
*/
|
|
14
|
-
|
|
15
|
-
/**
|
|
16
|
-
* A set of timers that were paused due to the document being hidden
|
|
17
|
-
*/
|
|
18
|
-
const TIMERS_HIDDEN = /* @__PURE__ */ new Set();
|
|
7
|
+
const STATES = {
|
|
8
|
+
active: /* @__PURE__ */ new Set(),
|
|
9
|
+
hidden: /* @__PURE__ */ new Set()
|
|
10
|
+
};
|
|
19
11
|
const TYPE_REPEAT = "repeat";
|
|
20
12
|
const TYPE_WAIT = "wait";
|
|
21
13
|
const TYPE_WHEN = "when";
|
|
@@ -25,194 +17,27 @@ const WORK_RESTART = "restart";
|
|
|
25
17
|
const WORK_START = "start";
|
|
26
18
|
const WORK_STOP = "stop";
|
|
27
19
|
//#endregion
|
|
28
|
-
//#region src/global.ts
|
|
29
|
-
if (globalThis._oscarpalmer_timers == null) Object.defineProperty(globalThis, "_oscarpalmer_timers", { get() {
|
|
30
|
-
return globalThis._oscarpalmer_timer_debug ? [...TIMERS_ACTIVE] : [];
|
|
31
|
-
} });
|
|
32
|
-
/* istanbul ignore next */
|
|
33
|
-
document.addEventListener("visibilitychange", () => {
|
|
34
|
-
const from = document.hidden ? TIMERS_ACTIVE : TIMERS_HIDDEN;
|
|
35
|
-
const method = document.hidden ? WORK_PAUSE : WORK_CONTINUE;
|
|
36
|
-
const to = document.hidden ? TIMERS_HIDDEN : TIMERS_ACTIVE;
|
|
37
|
-
for (const timer of from) {
|
|
38
|
-
timer[method]();
|
|
39
|
-
to.add(timer);
|
|
40
|
-
}
|
|
41
|
-
from.clear();
|
|
42
|
-
});
|
|
43
|
-
//#endregion
|
|
44
|
-
//#region node_modules/@oscarpalmer/atoms/dist/internal/function/timer.mjs
|
|
45
|
-
function getInterval(value) {
|
|
46
|
-
return typeof value === "number" && value > 0 ? value : 0;
|
|
47
|
-
}
|
|
48
|
-
function getTimer(type, callback, time) {
|
|
49
|
-
function run() {
|
|
50
|
-
const now = performance.now();
|
|
51
|
-
start ??= now;
|
|
52
|
-
if (interval === 0 || now - start >= interval - OFFSET) {
|
|
53
|
-
start = throttle ? now : void 0;
|
|
54
|
-
callback(...args);
|
|
55
|
-
} else id = startTimer(run);
|
|
56
|
-
}
|
|
57
|
-
const interval = getInterval(time);
|
|
58
|
-
const throttle = type === TIMER_THROTTLE;
|
|
59
|
-
let args;
|
|
60
|
-
let id;
|
|
61
|
-
let start;
|
|
62
|
-
const timer = (...parameters) => {
|
|
63
|
-
timer.cancel();
|
|
64
|
-
args = parameters;
|
|
65
|
-
if (throttle) run();
|
|
66
|
-
else id = startTimer(run);
|
|
67
|
-
};
|
|
68
|
-
timer.cancel = () => {
|
|
69
|
-
clearTimer(id);
|
|
70
|
-
};
|
|
71
|
-
return timer;
|
|
72
|
-
}
|
|
73
|
-
const OFFSET = 5;
|
|
74
|
-
const TIMER_THROTTLE = "throttle";
|
|
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;
|
|
80
|
-
//#endregion
|
|
81
|
-
//#region node_modules/@oscarpalmer/atoms/dist/promise/models.mjs
|
|
82
|
-
const PROMISE_ABORT_EVENT = "abort";
|
|
83
|
-
const PROMISE_ABORT_OPTIONS = { once: true };
|
|
84
|
-
//#endregion
|
|
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;
|
|
88
|
-
}
|
|
89
|
-
//#endregion
|
|
90
|
-
//#region node_modules/@oscarpalmer/atoms/dist/promise/helpers.mjs
|
|
91
|
-
function getPromiseOptions(input) {
|
|
92
|
-
if (typeof input === "number") return { time: getNumberOrDefault(input, 0) };
|
|
93
|
-
if (input instanceof AbortSignal) return {
|
|
94
|
-
signal: input,
|
|
95
|
-
time: 0
|
|
96
|
-
};
|
|
97
|
-
const options = typeof input === "object" && input !== null ? input : {};
|
|
98
|
-
return {
|
|
99
|
-
signal: options.signal instanceof AbortSignal ? options.signal : void 0,
|
|
100
|
-
time: getNumberOrDefault(options.time, 0)
|
|
101
|
-
};
|
|
102
|
-
}
|
|
103
|
-
//#endregion
|
|
104
|
-
//#region node_modules/@oscarpalmer/atoms/dist/promise/misc.mjs
|
|
105
|
-
function settlePromise(aborter, settler, value, signal) {
|
|
106
|
-
signal?.removeEventListener(PROMISE_ABORT_EVENT, aborter);
|
|
107
|
-
settler(value);
|
|
108
|
-
}
|
|
109
|
-
//#endregion
|
|
110
|
-
//#region node_modules/@oscarpalmer/atoms/dist/promise/delay.mjs
|
|
111
|
-
function delay(options) {
|
|
112
|
-
const { signal, time } = getPromiseOptions(options);
|
|
113
|
-
if (signal?.aborted ?? false) return Promise.reject(signal.reason);
|
|
114
|
-
function abort() {
|
|
115
|
-
timer.cancel();
|
|
116
|
-
rejector(signal.reason);
|
|
117
|
-
}
|
|
118
|
-
const timer = getTimer(TIMER_WAIT, () => {
|
|
119
|
-
settlePromise(abort, resolver, void 0, signal);
|
|
120
|
-
}, time);
|
|
121
|
-
signal?.addEventListener(PROMISE_ABORT_EVENT, abort, PROMISE_ABORT_OPTIONS);
|
|
122
|
-
let rejector;
|
|
123
|
-
let resolver;
|
|
124
|
-
return new Promise((resolve, reject) => {
|
|
125
|
-
rejector = reject;
|
|
126
|
-
resolver = resolve;
|
|
127
|
-
if (time === 0) settlePromise(abort, resolve, void 0, signal);
|
|
128
|
-
else timer();
|
|
129
|
-
});
|
|
130
|
-
}
|
|
131
|
-
//#endregion
|
|
132
|
-
//#region src/is.ts
|
|
133
|
-
function is(names, value) {
|
|
134
|
-
return names.includes(value?.$timer);
|
|
135
|
-
}
|
|
136
|
-
/**
|
|
137
|
-
* Is the value a repeating timer?
|
|
138
|
-
* @param value Value to check
|
|
139
|
-
* @returns `true` if the value is a repeating timer
|
|
140
|
-
*/
|
|
141
|
-
function isRepeated(value) {
|
|
142
|
-
return is([TYPE_REPEAT], value);
|
|
143
|
-
}
|
|
144
|
-
/**
|
|
145
|
-
* Is the value a timer?
|
|
146
|
-
* @param value Value to check
|
|
147
|
-
* @returns `true` if the value is a timer
|
|
148
|
-
*/
|
|
149
|
-
function isTimer(value) {
|
|
150
|
-
return is([TYPE_REPEAT, TYPE_WAIT], value);
|
|
151
|
-
}
|
|
152
|
-
/**
|
|
153
|
-
* Is the value a waiting timer?
|
|
154
|
-
* @param value Value to check
|
|
155
|
-
* @returns `true` if the value is a waiting timer
|
|
156
|
-
*/
|
|
157
|
-
function isWaited(value) {
|
|
158
|
-
return is([TYPE_WAIT], value);
|
|
159
|
-
}
|
|
160
|
-
/**
|
|
161
|
-
* Is the value a conditional timer?
|
|
162
|
-
* @param value Value to check
|
|
163
|
-
* @returns `true` if the value is a conditional timer
|
|
164
|
-
*/
|
|
165
|
-
function isWhen(value) {
|
|
166
|
-
return is(["when"], value) && typeof value.start === "function";
|
|
167
|
-
}
|
|
168
|
-
//#endregion
|
|
169
20
|
//#region node_modules/@oscarpalmer/atoms/dist/internal/function/misc.mjs
|
|
170
21
|
/**
|
|
171
22
|
* A function that does nothing, which can be useful, I guess…
|
|
172
23
|
*/
|
|
173
24
|
function noop() {}
|
|
174
25
|
//#endregion
|
|
175
|
-
//#region src/get.ts
|
|
176
|
-
function getCallback(value) {
|
|
177
|
-
return typeof value === "function" ? value : noop;
|
|
178
|
-
}
|
|
179
|
-
function getValidTimeout(value) {
|
|
180
|
-
return typeof value === "number" && value > 0 ? value : DEFAULT_TIMEOUT;
|
|
181
|
-
}
|
|
182
|
-
function getValidNumber(value, defaultValue) {
|
|
183
|
-
const actualDefault = defaultValue ?? 0;
|
|
184
|
-
return typeof value === "number" && value > actualDefault ? value : actualDefault;
|
|
185
|
-
}
|
|
186
|
-
//#endregion
|
|
187
|
-
//#region src/models.ts
|
|
188
|
-
var TimerTrace = class extends Error {
|
|
189
|
-
constructor() {
|
|
190
|
-
super();
|
|
191
|
-
this.name = "TimerTrace";
|
|
192
|
-
}
|
|
193
|
-
};
|
|
194
|
-
//#endregion
|
|
195
26
|
//#region src/work.ts
|
|
196
|
-
function finish(
|
|
27
|
+
function finish(state, success) {
|
|
28
|
+
updateStates(state);
|
|
197
29
|
cancelAnimationFrame(state.frame);
|
|
198
|
-
TIMERS_ACTIVE.delete(timer.instance);
|
|
199
30
|
state.active = false;
|
|
200
31
|
state.elapsed = 0;
|
|
201
32
|
state.frame = void 0;
|
|
202
|
-
if (
|
|
203
|
-
else options.onAfter?.(success);
|
|
33
|
+
if (state.name === "wait") state.callback();
|
|
34
|
+
else state.options.onAfter?.(success);
|
|
204
35
|
}
|
|
205
36
|
function ignore(type, state) {
|
|
206
|
-
if (state.destroyed) return type !== WORK_STOP;
|
|
207
37
|
if (state.paused) return type === "pause" || type === "start";
|
|
208
38
|
return state.active && type === "start";
|
|
209
39
|
}
|
|
210
|
-
function
|
|
211
|
-
cancelAnimationFrame(state.frame);
|
|
212
|
-
state.frame = void 0;
|
|
213
|
-
return timer.instance;
|
|
214
|
-
}
|
|
215
|
-
function run(timer, state, options) {
|
|
40
|
+
function run(state) {
|
|
216
41
|
let last;
|
|
217
42
|
let start;
|
|
218
43
|
return function step(now) {
|
|
@@ -223,18 +48,18 @@ function run(timer, state, options) {
|
|
|
223
48
|
state.elapsed += difference;
|
|
224
49
|
state.total += difference;
|
|
225
50
|
last = now;
|
|
226
|
-
if (options.timeout > 0 && state.total >= options.timeout) {
|
|
227
|
-
options.onError?.();
|
|
228
|
-
finish(
|
|
51
|
+
if (state.options.timeout > 0 && state.total >= state.options.timeout) {
|
|
52
|
+
state.options.onError?.();
|
|
53
|
+
finish(state, false);
|
|
229
54
|
return;
|
|
230
55
|
}
|
|
231
|
-
if (options.interval === 0 || state.elapsed >= options.interval - 5) {
|
|
232
|
-
if (options.count > -1) state.callback(state.index);
|
|
56
|
+
if (state.options.interval === 0 || state.elapsed >= state.options.interval - 5) {
|
|
57
|
+
if (state.options.count > -1) state.callback(state.index);
|
|
233
58
|
start = now;
|
|
234
59
|
state.elapsed = 0;
|
|
235
60
|
state.index += 1;
|
|
236
|
-
if (options.count === -1 || options.count > 0 && state.index >= options.count) {
|
|
237
|
-
finish(
|
|
61
|
+
if (state.options.count === -1 || state.options.count > 0 && state.index >= state.options.count) {
|
|
62
|
+
finish(state, true);
|
|
238
63
|
return;
|
|
239
64
|
}
|
|
240
65
|
}
|
|
@@ -247,127 +72,163 @@ function setState(type, state) {
|
|
|
247
72
|
state.index = pausable ? state.index : 0;
|
|
248
73
|
state.total = pausable ? state.total : 0;
|
|
249
74
|
}
|
|
250
|
-
function stop(
|
|
75
|
+
function stop(state) {
|
|
76
|
+
updateStates(state);
|
|
251
77
|
cancelAnimationFrame(state.frame);
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
state.active = !stop;
|
|
78
|
+
state.options.onAfter?.(false);
|
|
79
|
+
state.active = false;
|
|
255
80
|
state.frame = void 0;
|
|
256
81
|
state.paused = false;
|
|
257
|
-
return timer
|
|
82
|
+
return state.timer;
|
|
258
83
|
}
|
|
259
|
-
function work(type,
|
|
260
|
-
if (ignore(type, state)) return timer
|
|
84
|
+
function work(type, state, hide) {
|
|
85
|
+
if (ignore(type, state)) return state.timer;
|
|
261
86
|
setState(type, state);
|
|
262
|
-
if (type === "stop") return stop(
|
|
87
|
+
if (type === "stop") return stop(state);
|
|
263
88
|
if (type === "pause" || type === "restart") {
|
|
264
89
|
cancelAnimationFrame(state.frame);
|
|
265
90
|
state.frame = void 0;
|
|
266
91
|
}
|
|
267
92
|
state.active = true;
|
|
268
93
|
state.paused = type === WORK_PAUSE;
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
const runner = run(
|
|
94
|
+
updateStates(state, state.paused ? hide ?? false ? "hidden" : void 0 : "active");
|
|
95
|
+
if (state.paused) return state.timer;
|
|
96
|
+
const runner = run(state);
|
|
272
97
|
state.frame = requestAnimationFrame(runner);
|
|
273
|
-
return timer
|
|
98
|
+
return state.timer;
|
|
274
99
|
}
|
|
275
100
|
//#endregion
|
|
276
|
-
//#region src/
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
*/
|
|
295
|
-
get paused() {
|
|
296
|
-
return this.state.paused;
|
|
297
|
-
}
|
|
298
|
-
/**
|
|
299
|
-
* Get the timer's origin _(if debugging is enabled)_
|
|
300
|
-
*/
|
|
301
|
-
get trace() {
|
|
302
|
-
return globalThis._oscarpalmer_timer_debug ?? false ? this.state.trace : void 0;
|
|
303
|
-
}
|
|
304
|
-
constructor(type, state, options, start) {
|
|
305
|
-
this.options = options;
|
|
306
|
-
Object.defineProperty(this, "$timer", { value: type });
|
|
307
|
-
this.state = {
|
|
308
|
-
...state,
|
|
309
|
-
active: false,
|
|
310
|
-
destroyed: false,
|
|
311
|
-
elapsed: 0,
|
|
312
|
-
frame: void 0,
|
|
313
|
-
index: 0,
|
|
314
|
-
paused: false,
|
|
315
|
-
total: 0
|
|
316
|
-
};
|
|
317
|
-
if (start) this.start();
|
|
318
|
-
}
|
|
319
|
-
/**
|
|
320
|
-
* Continue running the timer _(if it's paused)_
|
|
321
|
-
*/
|
|
322
|
-
continue() {
|
|
323
|
-
return this.#work(WORK_CONTINUE);
|
|
324
|
-
}
|
|
325
|
-
/**
|
|
326
|
-
* Destroy the timer
|
|
327
|
-
*/
|
|
328
|
-
destroy() {
|
|
329
|
-
this.state.destroyed = true;
|
|
330
|
-
this.options.onAfter = noop;
|
|
331
|
-
this.options.onError = noop;
|
|
332
|
-
this.state.callback = noop;
|
|
333
|
-
if (!globalThis._oscarpalmer_timer_debug) this.state.trace = void 0;
|
|
334
|
-
stop({
|
|
335
|
-
instance: this,
|
|
336
|
-
type: this.$timer
|
|
337
|
-
}, this.state, this.options);
|
|
338
|
-
}
|
|
339
|
-
/**
|
|
340
|
-
* Pause the timer _(if it's running)_
|
|
341
|
-
*/
|
|
342
|
-
pause() {
|
|
343
|
-
return this.#work(WORK_PAUSE);
|
|
344
|
-
}
|
|
345
|
-
/**
|
|
346
|
-
* Restart the timer _(or start it, if it's not running)_
|
|
347
|
-
*/
|
|
348
|
-
restart() {
|
|
349
|
-
return this.#work(WORK_RESTART);
|
|
350
|
-
}
|
|
351
|
-
/**
|
|
352
|
-
* Start the timer _(if it's not running)_
|
|
353
|
-
*/
|
|
354
|
-
start() {
|
|
355
|
-
return this.#work(WORK_START);
|
|
356
|
-
}
|
|
357
|
-
/**
|
|
358
|
-
* Stop the timer _(if it's running)_
|
|
359
|
-
*/
|
|
360
|
-
stop() {
|
|
361
|
-
return this.#work(WORK_STOP);
|
|
101
|
+
//#region src/misc.ts
|
|
102
|
+
function getCallback(value) {
|
|
103
|
+
return typeof value === "function" ? value : noop;
|
|
104
|
+
}
|
|
105
|
+
function getValidNumber(value, defaultValue) {
|
|
106
|
+
const actualDefault = defaultValue ?? 0;
|
|
107
|
+
return typeof value === "number" && value > actualDefault ? value : actualDefault;
|
|
108
|
+
}
|
|
109
|
+
function getValidTimeout(value) {
|
|
110
|
+
return typeof value === "number" && value > 0 ? value : DEFAULT_TIMEOUT;
|
|
111
|
+
}
|
|
112
|
+
/* istanbul ignore next */
|
|
113
|
+
function onVisibilityChange() {
|
|
114
|
+
const from = document.hidden ? STATES.active : STATES.hidden;
|
|
115
|
+
const type = document.hidden ? WORK_PAUSE : WORK_CONTINUE;
|
|
116
|
+
for (const stored of from) {
|
|
117
|
+
const state = stored instanceof WeakRef ? stored.deref() : stored;
|
|
118
|
+
if (state != null) work(type, state, true);
|
|
362
119
|
}
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
120
|
+
}
|
|
121
|
+
function updateStates(state, key) {
|
|
122
|
+
STATES.active.delete(state);
|
|
123
|
+
const hidden = [...STATES.hidden].find((stored) => stored.deref() === state);
|
|
124
|
+
/* istanbul ignore next */
|
|
125
|
+
if (hidden != null) STATES.hidden.delete(hidden);
|
|
126
|
+
if (key != null)
|
|
127
|
+
/* istanbul ignore next */
|
|
128
|
+
STATES[key].add(key === "hidden" ? new WeakRef(state) : state);
|
|
129
|
+
}
|
|
130
|
+
//#endregion
|
|
131
|
+
//#region src/global.ts
|
|
132
|
+
Object.defineProperty(globalThis, "_oscarpalmer_timers", { get() {
|
|
133
|
+
return globalThis._oscarpalmer_timer_debug ? [...STATES.active].map((state) => state.timer) : [];
|
|
134
|
+
} });
|
|
135
|
+
document.addEventListener("visibilitychange", onVisibilityChange);
|
|
136
|
+
//#endregion
|
|
137
|
+
//#region src/is.ts
|
|
138
|
+
function is(names, value) {
|
|
139
|
+
return names.includes(value?.$timer);
|
|
140
|
+
}
|
|
141
|
+
/**
|
|
142
|
+
* Is the value a repeating timer?
|
|
143
|
+
* @param value Value to check
|
|
144
|
+
* @returns `true` if the value is a repeating timer
|
|
145
|
+
*/
|
|
146
|
+
function isRepeated(value) {
|
|
147
|
+
return is([TYPE_REPEAT], value);
|
|
148
|
+
}
|
|
149
|
+
/**
|
|
150
|
+
* Is the value a timer?
|
|
151
|
+
* @param value Value to check
|
|
152
|
+
* @returns `true` if the value is a timer
|
|
153
|
+
*/
|
|
154
|
+
function isTimer(value) {
|
|
155
|
+
return is([TYPE_REPEAT, TYPE_WAIT], value);
|
|
156
|
+
}
|
|
157
|
+
/**
|
|
158
|
+
* Is the value a waiting timer?
|
|
159
|
+
* @param value Value to check
|
|
160
|
+
* @returns `true` if the value is a waiting timer
|
|
161
|
+
*/
|
|
162
|
+
function isWaited(value) {
|
|
163
|
+
return is([TYPE_WAIT], value);
|
|
164
|
+
}
|
|
165
|
+
/**
|
|
166
|
+
* Is the value a conditional timer?
|
|
167
|
+
* @param value Value to check
|
|
168
|
+
* @returns `true` if the value is a conditional timer
|
|
169
|
+
*/
|
|
170
|
+
function isWhen(value) {
|
|
171
|
+
return is(["when"], value) && typeof value.start === "function";
|
|
172
|
+
}
|
|
173
|
+
//#endregion
|
|
174
|
+
//#region src/models.ts
|
|
175
|
+
var TimerTrace = class extends Error {
|
|
176
|
+
constructor() {
|
|
177
|
+
super();
|
|
178
|
+
this.name = "TimerTrace";
|
|
368
179
|
}
|
|
369
180
|
};
|
|
370
181
|
//#endregion
|
|
182
|
+
//#region src/timer.ts
|
|
183
|
+
function createTimer(name, pick, options, start) {
|
|
184
|
+
const state = {
|
|
185
|
+
...pick,
|
|
186
|
+
name,
|
|
187
|
+
options,
|
|
188
|
+
active: false,
|
|
189
|
+
destroyed: false,
|
|
190
|
+
elapsed: 0,
|
|
191
|
+
frame: void 0,
|
|
192
|
+
index: 0,
|
|
193
|
+
paused: false,
|
|
194
|
+
timer: void 0,
|
|
195
|
+
total: 0
|
|
196
|
+
};
|
|
197
|
+
const instance = {
|
|
198
|
+
continue: () => work(WORK_CONTINUE, state),
|
|
199
|
+
destroy: noop,
|
|
200
|
+
pause: () => work(WORK_PAUSE, state),
|
|
201
|
+
restart: () => work(WORK_RESTART, state),
|
|
202
|
+
start: () => work(WORK_START, state),
|
|
203
|
+
stop: () => work(WORK_STOP, state)
|
|
204
|
+
};
|
|
205
|
+
Object.defineProperties(instance, {
|
|
206
|
+
$timer: {
|
|
207
|
+
enumerable: false,
|
|
208
|
+
value: name
|
|
209
|
+
},
|
|
210
|
+
active: {
|
|
211
|
+
enumerable: true,
|
|
212
|
+
get: () => state.active
|
|
213
|
+
},
|
|
214
|
+
destroyed: {
|
|
215
|
+
enumerable: true,
|
|
216
|
+
value: false
|
|
217
|
+
},
|
|
218
|
+
paused: {
|
|
219
|
+
enumerable: true,
|
|
220
|
+
get: () => state.paused
|
|
221
|
+
},
|
|
222
|
+
trace: {
|
|
223
|
+
enumerable: true,
|
|
224
|
+
get: () => globalThis._oscarpalmer_timer_debug ?? false ? state.trace : void 0
|
|
225
|
+
}
|
|
226
|
+
});
|
|
227
|
+
state.timer = Object.freeze(instance);
|
|
228
|
+
if (start) state.timer.start();
|
|
229
|
+
return state.timer;
|
|
230
|
+
}
|
|
231
|
+
//#endregion
|
|
371
232
|
//#region src/repeat.ts
|
|
372
233
|
/**
|
|
373
234
|
* Create a repeating timer
|
|
@@ -377,7 +238,7 @@ var Timer = class {
|
|
|
377
238
|
* @returns Timer instance
|
|
378
239
|
*/
|
|
379
240
|
function repeat(callback, options) {
|
|
380
|
-
return
|
|
241
|
+
return createTimer(TYPE_REPEAT, {
|
|
381
242
|
callback: getCallback(callback),
|
|
382
243
|
trace: new TimerTrace().stack
|
|
383
244
|
}, {
|
|
@@ -397,7 +258,7 @@ function repeat(callback, options) {
|
|
|
397
258
|
* @param time How long to wait for _(in milliseconds; defaults to screen refresh rate)_
|
|
398
259
|
*/
|
|
399
260
|
function wait(callback, time) {
|
|
400
|
-
return
|
|
261
|
+
return createTimer(TYPE_WAIT, {
|
|
401
262
|
callback: getCallback(callback),
|
|
402
263
|
trace: new TimerTrace().stack
|
|
403
264
|
}, {
|
|
@@ -410,120 +271,30 @@ function wait(callback, time) {
|
|
|
410
271
|
}
|
|
411
272
|
//#endregion
|
|
412
273
|
//#region src/when.ts
|
|
413
|
-
|
|
414
|
-
state
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
return this.state.timer?.active ?? false;
|
|
426
|
-
}
|
|
427
|
-
/**
|
|
428
|
-
* Is the timer destroyed?
|
|
429
|
-
*/
|
|
430
|
-
get destroyed() {
|
|
431
|
-
return this.state.timer == null;
|
|
432
|
-
}
|
|
433
|
-
/**
|
|
434
|
-
* Is the timer paused?
|
|
435
|
-
*/
|
|
436
|
-
get paused() {
|
|
437
|
-
return this.state.timer?.paused ?? false;
|
|
438
|
-
}
|
|
439
|
-
/**
|
|
440
|
-
* Get the timer's origin _(if debugging is enabled)_
|
|
441
|
-
*/
|
|
442
|
-
get trace() {
|
|
443
|
-
return globalThis._oscarpalmer_timer_debug ?? false ? this.state.timer?.trace : void 0;
|
|
444
|
-
}
|
|
445
|
-
constructor(condition, options) {
|
|
446
|
-
Object.defineProperty(this, "$timer", { value: TYPE_WHEN });
|
|
447
|
-
const { state } = this;
|
|
448
|
-
state.promise = new Promise((resolve, reject) => {
|
|
449
|
-
state.resolver = resolve;
|
|
450
|
-
state.rejecter = reject;
|
|
451
|
-
});
|
|
452
|
-
let result = false;
|
|
453
|
-
this.state.timer = new Timer(TYPE_WHEN, {
|
|
454
|
-
callback() {
|
|
455
|
-
try {
|
|
456
|
-
if (condition()) {
|
|
457
|
-
result = true;
|
|
458
|
-
state.timer.stop();
|
|
459
|
-
}
|
|
460
|
-
} catch {
|
|
461
|
-
state.timer.stop();
|
|
462
|
-
}
|
|
463
|
-
},
|
|
464
|
-
trace: new TimerTrace().stack
|
|
465
|
-
}, {
|
|
466
|
-
onAfter: () => {
|
|
467
|
-
if (result) state.resolver?.();
|
|
468
|
-
else state.rejecter?.();
|
|
469
|
-
this.destroy();
|
|
470
|
-
},
|
|
471
|
-
onError: () => {
|
|
472
|
-
state.rejecter?.();
|
|
473
|
-
this.destroy();
|
|
474
|
-
},
|
|
475
|
-
count: getValidNumber(options?.count),
|
|
476
|
-
interval: getValidNumber(options?.interval),
|
|
477
|
-
timeout: getValidTimeout(options?.timeout)
|
|
478
|
-
}, false);
|
|
479
|
-
}
|
|
480
|
-
/**
|
|
481
|
-
* Continues the timer _(if it was paused)_
|
|
482
|
-
*/
|
|
483
|
-
continue() {
|
|
484
|
-
this.state.timer?.continue();
|
|
485
|
-
return this;
|
|
486
|
-
}
|
|
487
|
-
/**
|
|
488
|
-
* Destroys the timer _(and stops it,if it was running)_
|
|
489
|
-
*/
|
|
490
|
-
destroy() {
|
|
491
|
-
const { state } = this;
|
|
492
|
-
state.timer?.destroy();
|
|
493
|
-
state.promise = void 0;
|
|
494
|
-
state.resolver = noop;
|
|
495
|
-
state.rejecter = noop;
|
|
496
|
-
state.timer = void 0;
|
|
497
|
-
}
|
|
498
|
-
/**
|
|
499
|
-
* Pauses the timer _(if it was running)_
|
|
500
|
-
*/
|
|
501
|
-
pause() {
|
|
502
|
-
this.state.timer?.pause();
|
|
503
|
-
return this;
|
|
504
|
-
}
|
|
505
|
-
/**
|
|
506
|
-
* Start the timer
|
|
507
|
-
*
|
|
508
|
-
* @param resolve Optional resolve callback
|
|
509
|
-
* @returns Promise that resolves when the condition is met
|
|
510
|
-
*/
|
|
511
|
-
start(resolve) {
|
|
512
|
-
const { state } = this;
|
|
513
|
-
if (state.timer == null) throw new Error(MESSAGE_DESTROYED);
|
|
514
|
-
if (state.started) throw new Error(MESSAGE_STARTED);
|
|
515
|
-
state.started = true;
|
|
516
|
-
state.timer.start();
|
|
517
|
-
return state.promise.then(resolve);
|
|
518
|
-
}
|
|
519
|
-
/**
|
|
520
|
-
* Stops the timer _(if it was running)_
|
|
521
|
-
*/
|
|
522
|
-
stop() {
|
|
523
|
-
this.state.timer?.stop();
|
|
524
|
-
return this;
|
|
274
|
+
function onAfter(state) {
|
|
275
|
+
if (state.result) state.resolver?.();
|
|
276
|
+
else state.rejecter?.();
|
|
277
|
+
}
|
|
278
|
+
function onCallback(condition, state) {
|
|
279
|
+
try {
|
|
280
|
+
if (condition()) {
|
|
281
|
+
state.result = true;
|
|
282
|
+
state.timer.stop();
|
|
283
|
+
}
|
|
284
|
+
} catch {
|
|
285
|
+
state.timer.stop();
|
|
525
286
|
}
|
|
526
|
-
}
|
|
287
|
+
}
|
|
288
|
+
function onWhen(type, instance, state) {
|
|
289
|
+
state.timer?.[type]?.();
|
|
290
|
+
return instance;
|
|
291
|
+
}
|
|
292
|
+
function startWhen(state, resolve) {
|
|
293
|
+
if (state.started) throw new Error(MESSAGE_STARTED);
|
|
294
|
+
state.started = true;
|
|
295
|
+
state.timer.start();
|
|
296
|
+
return state.promise.then(resolve);
|
|
297
|
+
}
|
|
527
298
|
/**
|
|
528
299
|
* Create a conditional timer
|
|
529
300
|
* @param condition Condition to check
|
|
@@ -531,7 +302,57 @@ var When = class {
|
|
|
531
302
|
* @returns Timer instance
|
|
532
303
|
*/
|
|
533
304
|
function when(condition, options) {
|
|
534
|
-
|
|
305
|
+
const state = {
|
|
306
|
+
promise: void 0,
|
|
307
|
+
result: false,
|
|
308
|
+
started: false,
|
|
309
|
+
timer: void 0
|
|
310
|
+
};
|
|
311
|
+
let instance;
|
|
312
|
+
state.promise = new Promise((resolve, reject) => {
|
|
313
|
+
state.resolver = resolve;
|
|
314
|
+
state.rejecter = reject;
|
|
315
|
+
});
|
|
316
|
+
state.timer = createTimer(TYPE_WHEN, {
|
|
317
|
+
callback: () => onCallback(condition, state),
|
|
318
|
+
trace: new TimerTrace().stack
|
|
319
|
+
}, {
|
|
320
|
+
onAfter: () => onAfter(state),
|
|
321
|
+
onError: () => state.rejecter?.(),
|
|
322
|
+
count: getValidNumber(options?.count),
|
|
323
|
+
interval: getValidNumber(options?.interval),
|
|
324
|
+
timeout: getValidTimeout(options?.timeout)
|
|
325
|
+
}, false);
|
|
326
|
+
instance = {
|
|
327
|
+
continue: () => onWhen(WORK_CONTINUE, instance, state),
|
|
328
|
+
destroy: noop,
|
|
329
|
+
pause: () => onWhen(WORK_PAUSE, instance, state),
|
|
330
|
+
start: (resolve) => startWhen(state, resolve),
|
|
331
|
+
stop: () => onWhen(WORK_STOP, instance, state)
|
|
332
|
+
};
|
|
333
|
+
Object.defineProperties(instance, {
|
|
334
|
+
$timer: {
|
|
335
|
+
enumerable: false,
|
|
336
|
+
value: TYPE_WHEN
|
|
337
|
+
},
|
|
338
|
+
active: {
|
|
339
|
+
enumerable: true,
|
|
340
|
+
get: () => state.timer.active
|
|
341
|
+
},
|
|
342
|
+
destroyed: {
|
|
343
|
+
enumerable: true,
|
|
344
|
+
value: false
|
|
345
|
+
},
|
|
346
|
+
paused: {
|
|
347
|
+
enumerable: true,
|
|
348
|
+
get: () => state.timer.paused
|
|
349
|
+
},
|
|
350
|
+
trace: {
|
|
351
|
+
enumerable: true,
|
|
352
|
+
get: () => globalThis._oscarpalmer_timer_debug ?? false ? state.timer?.trace : void 0
|
|
353
|
+
}
|
|
354
|
+
});
|
|
355
|
+
return Object.freeze(instance);
|
|
535
356
|
}
|
|
536
357
|
//#endregion
|
|
537
|
-
export {
|
|
358
|
+
export { isRepeated, isTimer, isWaited, isWhen, repeat, wait, when };
|