@oscarpalmer/timer 0.21.0 → 0.22.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.js +9 -0
- package/dist/constants.mjs +9 -0
- package/dist/functions.js +97 -0
- package/dist/functions.mjs +93 -0
- package/dist/global.js +13 -0
- package/dist/global.mjs +9 -0
- package/dist/index.mjs +40 -0
- package/dist/is.js +22 -0
- package/dist/is.mjs +22 -0
- package/dist/models.mjs +0 -0
- package/dist/timer.mjs +75 -36
- package/dist/when.js +226 -0
- package/dist/when.mjs +69 -0
- package/package.json +13 -9
- /package/dist/{timer.js → index.js} +0 -0
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
// src/constants.ts
|
|
2
|
+
var activeTimers = new Set;
|
|
3
|
+
var hiddenTimers = new Set;
|
|
4
|
+
var milliseconds = 1000 / 60;
|
|
5
|
+
|
|
6
|
+
// src/functions.ts
|
|
7
|
+
function getOptions(options, isRepeated) {
|
|
8
|
+
return {
|
|
9
|
+
afterCallback: options.afterCallback,
|
|
10
|
+
count: getValueOrDefault(options.count, isRepeated ? Number.POSITIVE_INFINITY : 1),
|
|
11
|
+
errorCallback: options.errorCallback,
|
|
12
|
+
interval: getValueOrDefault(options.interval, milliseconds, milliseconds),
|
|
13
|
+
timeout: getValueOrDefault(options.timeout, isRepeated ? Number.POSITIVE_INFINITY : 30000)
|
|
14
|
+
};
|
|
15
|
+
}
|
|
16
|
+
function getValueOrDefault(value, defaultValue, minimum) {
|
|
17
|
+
return typeof value === "number" && value > (minimum ?? 0) ? value : defaultValue;
|
|
18
|
+
}
|
|
19
|
+
function work(type, timer, state, options) {
|
|
20
|
+
if (["continue", "start"].includes(type) && state.active || ["pause", "stop"].includes(type) && !state.active) {
|
|
21
|
+
return timer;
|
|
22
|
+
}
|
|
23
|
+
const { count, interval, timeout } = options;
|
|
24
|
+
const { isRepeated, minimum } = state;
|
|
25
|
+
if (["pause", "restart", "stop"].includes(type)) {
|
|
26
|
+
const isStop = type === "stop";
|
|
27
|
+
activeTimers.delete(timer);
|
|
28
|
+
cancelAnimationFrame(state.frame);
|
|
29
|
+
if (isStop) {
|
|
30
|
+
options.afterCallback?.(false);
|
|
31
|
+
}
|
|
32
|
+
state.active = false;
|
|
33
|
+
state.frame = undefined;
|
|
34
|
+
state.paused = !isStop;
|
|
35
|
+
if (isStop) {
|
|
36
|
+
state.elapsed = undefined;
|
|
37
|
+
state.index = undefined;
|
|
38
|
+
}
|
|
39
|
+
return type === "restart" ? work("start", timer, state, options) : timer;
|
|
40
|
+
}
|
|
41
|
+
state.active = true;
|
|
42
|
+
state.paused = false;
|
|
43
|
+
const elapsed = type === "continue" ? +(state.elapsed ?? 0) : 0;
|
|
44
|
+
let index = type === "continue" ? +(state.index ?? 0) : 0;
|
|
45
|
+
state.elapsed = elapsed;
|
|
46
|
+
state.index = index;
|
|
47
|
+
const total = (count === Number.POSITIVE_INFINITY ? Number.POSITIVE_INFINITY : (count - index) * (interval > 0 ? interval : milliseconds)) - elapsed;
|
|
48
|
+
let current;
|
|
49
|
+
let start;
|
|
50
|
+
function finish(finished, error) {
|
|
51
|
+
activeTimers.delete(timer);
|
|
52
|
+
state.active = false;
|
|
53
|
+
state.elapsed = undefined;
|
|
54
|
+
state.frame = undefined;
|
|
55
|
+
state.index = undefined;
|
|
56
|
+
if (error) {
|
|
57
|
+
options.errorCallback?.();
|
|
58
|
+
}
|
|
59
|
+
options.afterCallback?.(finished);
|
|
60
|
+
}
|
|
61
|
+
function step(timestamp) {
|
|
62
|
+
if (!state.active) {
|
|
63
|
+
return;
|
|
64
|
+
}
|
|
65
|
+
current ??= timestamp;
|
|
66
|
+
start ??= timestamp;
|
|
67
|
+
const time = timestamp - current;
|
|
68
|
+
state.elapsed = elapsed + (current - start);
|
|
69
|
+
const finished = time - elapsed >= total;
|
|
70
|
+
if (timestamp - start >= timeout - elapsed) {
|
|
71
|
+
finish(finished, !finished);
|
|
72
|
+
return;
|
|
73
|
+
}
|
|
74
|
+
if (finished || time >= minimum) {
|
|
75
|
+
if (state.active) {
|
|
76
|
+
state.callback(isRepeated ? index : undefined);
|
|
77
|
+
}
|
|
78
|
+
index += 1;
|
|
79
|
+
state.index = index;
|
|
80
|
+
if (!finished && index < count) {
|
|
81
|
+
current = null;
|
|
82
|
+
} else {
|
|
83
|
+
finish(true, false);
|
|
84
|
+
return;
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
state.frame = requestAnimationFrame(step);
|
|
88
|
+
}
|
|
89
|
+
activeTimers.add(timer);
|
|
90
|
+
state.frame = requestAnimationFrame(step);
|
|
91
|
+
return timer;
|
|
92
|
+
}
|
|
93
|
+
export {
|
|
94
|
+
work,
|
|
95
|
+
getValueOrDefault,
|
|
96
|
+
getOptions
|
|
97
|
+
};
|
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
// src/functions.ts
|
|
2
|
+
import {activeTimers, milliseconds} from "./constants";
|
|
3
|
+
function getOptions(options, isRepeated) {
|
|
4
|
+
return {
|
|
5
|
+
afterCallback: options.afterCallback,
|
|
6
|
+
count: getValueOrDefault(options.count, isRepeated ? Number.POSITIVE_INFINITY : 1),
|
|
7
|
+
errorCallback: options.errorCallback,
|
|
8
|
+
interval: getValueOrDefault(options.interval, milliseconds, milliseconds),
|
|
9
|
+
timeout: getValueOrDefault(options.timeout, isRepeated ? Number.POSITIVE_INFINITY : 30000)
|
|
10
|
+
};
|
|
11
|
+
}
|
|
12
|
+
function getValueOrDefault(value, defaultValue, minimum) {
|
|
13
|
+
return typeof value === "number" && value > (minimum ?? 0) ? value : defaultValue;
|
|
14
|
+
}
|
|
15
|
+
function work(type, timer, state, options) {
|
|
16
|
+
if (["continue", "start"].includes(type) && state.active || ["pause", "stop"].includes(type) && !state.active) {
|
|
17
|
+
return timer;
|
|
18
|
+
}
|
|
19
|
+
const { count, interval, timeout } = options;
|
|
20
|
+
const { isRepeated, minimum } = state;
|
|
21
|
+
if (["pause", "restart", "stop"].includes(type)) {
|
|
22
|
+
const isStop = type === "stop";
|
|
23
|
+
activeTimers.delete(timer);
|
|
24
|
+
cancelAnimationFrame(state.frame);
|
|
25
|
+
if (isStop) {
|
|
26
|
+
options.afterCallback?.(false);
|
|
27
|
+
}
|
|
28
|
+
state.active = false;
|
|
29
|
+
state.frame = undefined;
|
|
30
|
+
state.paused = !isStop;
|
|
31
|
+
if (isStop) {
|
|
32
|
+
state.elapsed = undefined;
|
|
33
|
+
state.index = undefined;
|
|
34
|
+
}
|
|
35
|
+
return type === "restart" ? work("start", timer, state, options) : timer;
|
|
36
|
+
}
|
|
37
|
+
state.active = true;
|
|
38
|
+
state.paused = false;
|
|
39
|
+
const elapsed = type === "continue" ? +(state.elapsed ?? 0) : 0;
|
|
40
|
+
let index = type === "continue" ? +(state.index ?? 0) : 0;
|
|
41
|
+
state.elapsed = elapsed;
|
|
42
|
+
state.index = index;
|
|
43
|
+
const total = (count === Number.POSITIVE_INFINITY ? Number.POSITIVE_INFINITY : (count - index) * (interval > 0 ? interval : milliseconds)) - elapsed;
|
|
44
|
+
let current;
|
|
45
|
+
let start;
|
|
46
|
+
function finish(finished, error) {
|
|
47
|
+
activeTimers.delete(timer);
|
|
48
|
+
state.active = false;
|
|
49
|
+
state.elapsed = undefined;
|
|
50
|
+
state.frame = undefined;
|
|
51
|
+
state.index = undefined;
|
|
52
|
+
if (error) {
|
|
53
|
+
options.errorCallback?.();
|
|
54
|
+
}
|
|
55
|
+
options.afterCallback?.(finished);
|
|
56
|
+
}
|
|
57
|
+
function step(timestamp) {
|
|
58
|
+
if (!state.active) {
|
|
59
|
+
return;
|
|
60
|
+
}
|
|
61
|
+
current ??= timestamp;
|
|
62
|
+
start ??= timestamp;
|
|
63
|
+
const time = timestamp - current;
|
|
64
|
+
state.elapsed = elapsed + (current - start);
|
|
65
|
+
const finished = time - elapsed >= total;
|
|
66
|
+
if (timestamp - start >= timeout - elapsed) {
|
|
67
|
+
finish(finished, !finished);
|
|
68
|
+
return;
|
|
69
|
+
}
|
|
70
|
+
if (finished || time >= minimum) {
|
|
71
|
+
if (state.active) {
|
|
72
|
+
state.callback(isRepeated ? index : undefined);
|
|
73
|
+
}
|
|
74
|
+
index += 1;
|
|
75
|
+
state.index = index;
|
|
76
|
+
if (!finished && index < count) {
|
|
77
|
+
current = null;
|
|
78
|
+
} else {
|
|
79
|
+
finish(true, false);
|
|
80
|
+
return;
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
state.frame = requestAnimationFrame(step);
|
|
84
|
+
}
|
|
85
|
+
activeTimers.add(timer);
|
|
86
|
+
state.frame = requestAnimationFrame(step);
|
|
87
|
+
return timer;
|
|
88
|
+
}
|
|
89
|
+
export {
|
|
90
|
+
work,
|
|
91
|
+
getValueOrDefault,
|
|
92
|
+
getOptions
|
|
93
|
+
};
|
package/dist/global.js
ADDED
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
// src/constants.ts
|
|
2
|
+
var activeTimers = new Set;
|
|
3
|
+
var hiddenTimers = new Set;
|
|
4
|
+
var milliseconds = 1000 / 60;
|
|
5
|
+
|
|
6
|
+
// src/global.ts
|
|
7
|
+
if (globalThis._oscarpalmer_timers == null) {
|
|
8
|
+
Object.defineProperty(globalThis, "_oscarpalmer_timers", {
|
|
9
|
+
get() {
|
|
10
|
+
return globalThis._oscarpalmer_timer_debug ? [...activeTimers] : [];
|
|
11
|
+
}
|
|
12
|
+
});
|
|
13
|
+
}
|
package/dist/global.mjs
ADDED
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
// src/global.ts
|
|
2
|
+
import {activeTimers} from "./constants";
|
|
3
|
+
if (globalThis._oscarpalmer_timers == null) {
|
|
4
|
+
Object.defineProperty(globalThis, "_oscarpalmer_timers", {
|
|
5
|
+
get() {
|
|
6
|
+
return globalThis._oscarpalmer_timer_debug ? [...activeTimers] : [];
|
|
7
|
+
}
|
|
8
|
+
});
|
|
9
|
+
}
|
package/dist/index.mjs
ADDED
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
// src/index.ts
|
|
2
|
+
import {noop} from "@oscarpalmer/atoms/function";
|
|
3
|
+
import {activeTimers, hiddenTimers} from "./constants";
|
|
4
|
+
import"./global";
|
|
5
|
+
import {wait} from "./timer";
|
|
6
|
+
function delay(time, timeout) {
|
|
7
|
+
return new Promise((resolve, reject) => {
|
|
8
|
+
wait(resolve ?? noop, {
|
|
9
|
+
timeout,
|
|
10
|
+
errorCallback: reject ?? noop,
|
|
11
|
+
interval: time
|
|
12
|
+
});
|
|
13
|
+
});
|
|
14
|
+
}
|
|
15
|
+
import {isRepeated, isTimer, isWaited, isWhen} from "./is";
|
|
16
|
+
import {repeat, wait as wait2} from "./timer";
|
|
17
|
+
import {when} from "./when";
|
|
18
|
+
document.addEventListener("visibilitychange", () => {
|
|
19
|
+
if (document.hidden) {
|
|
20
|
+
for (const timer2 of activeTimers) {
|
|
21
|
+
hiddenTimers.add(timer2);
|
|
22
|
+
timer2.pause();
|
|
23
|
+
}
|
|
24
|
+
} else {
|
|
25
|
+
for (const timer2 of hiddenTimers) {
|
|
26
|
+
timer2.continue();
|
|
27
|
+
}
|
|
28
|
+
hiddenTimers.clear();
|
|
29
|
+
}
|
|
30
|
+
});
|
|
31
|
+
export {
|
|
32
|
+
when,
|
|
33
|
+
wait2 as wait,
|
|
34
|
+
repeat,
|
|
35
|
+
isWhen,
|
|
36
|
+
isWaited,
|
|
37
|
+
isTimer,
|
|
38
|
+
isRepeated,
|
|
39
|
+
delay
|
|
40
|
+
};
|
package/dist/is.js
ADDED
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
// src/is.ts
|
|
2
|
+
function is(pattern, value) {
|
|
3
|
+
return pattern.test(value?.$timer);
|
|
4
|
+
}
|
|
5
|
+
function isRepeated(value) {
|
|
6
|
+
return is(/^repeat$/, value);
|
|
7
|
+
}
|
|
8
|
+
function isTimer(value) {
|
|
9
|
+
return is(/^repeat|wait$/, value);
|
|
10
|
+
}
|
|
11
|
+
function isWaited(value) {
|
|
12
|
+
return is(/^wait$/, value);
|
|
13
|
+
}
|
|
14
|
+
function isWhen(value) {
|
|
15
|
+
return is(/^when$/, value) && typeof value.then === "function";
|
|
16
|
+
}
|
|
17
|
+
export {
|
|
18
|
+
isWhen,
|
|
19
|
+
isWaited,
|
|
20
|
+
isTimer,
|
|
21
|
+
isRepeated
|
|
22
|
+
};
|
package/dist/is.mjs
ADDED
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
// src/is.ts
|
|
2
|
+
function is(pattern, value) {
|
|
3
|
+
return pattern.test(value?.$timer);
|
|
4
|
+
}
|
|
5
|
+
function isRepeated(value) {
|
|
6
|
+
return is(/^repeat$/, value);
|
|
7
|
+
}
|
|
8
|
+
function isTimer(value) {
|
|
9
|
+
return is(/^repeat|wait$/, value);
|
|
10
|
+
}
|
|
11
|
+
function isWaited(value) {
|
|
12
|
+
return is(/^wait$/, value);
|
|
13
|
+
}
|
|
14
|
+
function isWhen(value) {
|
|
15
|
+
return is(/^when$/, value) && typeof value.then === "function";
|
|
16
|
+
}
|
|
17
|
+
export {
|
|
18
|
+
isWhen,
|
|
19
|
+
isWaited,
|
|
20
|
+
isTimer,
|
|
21
|
+
isRepeated
|
|
22
|
+
};
|
package/dist/models.mjs
ADDED
|
File without changes
|
package/dist/timer.mjs
CHANGED
|
@@ -1,40 +1,79 @@
|
|
|
1
|
-
// src/
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
1
|
+
// src/timer.ts
|
|
2
|
+
import {milliseconds} from "./constants";
|
|
3
|
+
import {getOptions, work} from "./functions";
|
|
4
|
+
function repeat(callback, options) {
|
|
5
|
+
return timer("repeat", callback, options ?? {}, true);
|
|
6
|
+
}
|
|
7
|
+
function timer(type, callback, partial, start) {
|
|
8
|
+
const isRepeated = type === "repeat";
|
|
9
|
+
const options = getOptions(partial, isRepeated);
|
|
10
|
+
const instance = new Timer(type, {
|
|
11
|
+
callback,
|
|
12
|
+
isRepeated,
|
|
13
|
+
active: false,
|
|
14
|
+
minimum: options.interval - options.interval % milliseconds / 2,
|
|
15
|
+
paused: false,
|
|
16
|
+
trace: new TimerTrace
|
|
17
|
+
}, options);
|
|
18
|
+
if (start) {
|
|
19
|
+
instance.start();
|
|
20
|
+
}
|
|
21
|
+
return instance;
|
|
22
|
+
}
|
|
23
|
+
function wait(callback, options) {
|
|
24
|
+
return timer("wait", callback, options == null || typeof options === "number" ? {
|
|
25
|
+
interval: options
|
|
26
|
+
} : options, true);
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
class BasicTimer {
|
|
30
|
+
constructor(type, state) {
|
|
31
|
+
this.$timer = type;
|
|
32
|
+
this.state = state;
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
class Timer extends BasicTimer {
|
|
37
|
+
get active() {
|
|
38
|
+
return this.state.active;
|
|
39
|
+
}
|
|
40
|
+
get paused() {
|
|
41
|
+
return this.state.paused;
|
|
42
|
+
}
|
|
43
|
+
get trace() {
|
|
44
|
+
return globalThis._oscarpalmer_timer_debug ? this.state.trace : undefined;
|
|
45
|
+
}
|
|
46
|
+
constructor(type, state, options) {
|
|
47
|
+
super(type, state);
|
|
48
|
+
this.options = options;
|
|
49
|
+
}
|
|
50
|
+
continue() {
|
|
51
|
+
return work("continue", this, this.state, this.options);
|
|
52
|
+
}
|
|
53
|
+
pause() {
|
|
54
|
+
return work("pause", this, this.state, this.options);
|
|
55
|
+
}
|
|
56
|
+
restart() {
|
|
57
|
+
return work("restart", this, this.state, this.options);
|
|
58
|
+
}
|
|
59
|
+
start() {
|
|
60
|
+
return work("start", this, this.state, this.options);
|
|
61
|
+
}
|
|
62
|
+
stop() {
|
|
63
|
+
return work("stop", this, this.state, this.options);
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
class TimerTrace extends Error {
|
|
68
|
+
constructor() {
|
|
69
|
+
super();
|
|
70
|
+
this.name = "TimerTrace";
|
|
71
|
+
}
|
|
14
72
|
}
|
|
15
|
-
import {isRepeated, isTimer, isWaited, isWhen} from "./is";
|
|
16
|
-
import {repeat, wait as wait2} from "./timer";
|
|
17
|
-
import {when} from "./when";
|
|
18
|
-
document.addEventListener("visibilitychange", () => {
|
|
19
|
-
if (document.hidden) {
|
|
20
|
-
for (const timer2 of activeTimers) {
|
|
21
|
-
hiddenTimers.add(timer2);
|
|
22
|
-
timer2.pause();
|
|
23
|
-
}
|
|
24
|
-
} else {
|
|
25
|
-
for (const timer2 of hiddenTimers) {
|
|
26
|
-
timer2.continue();
|
|
27
|
-
}
|
|
28
|
-
hiddenTimers.clear();
|
|
29
|
-
}
|
|
30
|
-
});
|
|
31
73
|
export {
|
|
32
|
-
|
|
33
|
-
|
|
74
|
+
wait,
|
|
75
|
+
timer,
|
|
34
76
|
repeat,
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
isTimer,
|
|
38
|
-
isRepeated,
|
|
39
|
-
delay
|
|
77
|
+
Timer,
|
|
78
|
+
BasicTimer
|
|
40
79
|
};
|
package/dist/when.js
ADDED
|
@@ -0,0 +1,226 @@
|
|
|
1
|
+
// node_modules/@oscarpalmer/atoms/dist/js/function.mjs
|
|
2
|
+
function noop() {
|
|
3
|
+
}
|
|
4
|
+
|
|
5
|
+
// src/constants.ts
|
|
6
|
+
var activeTimers = new Set;
|
|
7
|
+
var hiddenTimers = new Set;
|
|
8
|
+
var milliseconds = 1000 / 60;
|
|
9
|
+
|
|
10
|
+
// src/functions.ts
|
|
11
|
+
function getOptions(options, isRepeated) {
|
|
12
|
+
return {
|
|
13
|
+
afterCallback: options.afterCallback,
|
|
14
|
+
count: getValueOrDefault(options.count, isRepeated ? Number.POSITIVE_INFINITY : 1),
|
|
15
|
+
errorCallback: options.errorCallback,
|
|
16
|
+
interval: getValueOrDefault(options.interval, milliseconds, milliseconds),
|
|
17
|
+
timeout: getValueOrDefault(options.timeout, isRepeated ? Number.POSITIVE_INFINITY : 30000)
|
|
18
|
+
};
|
|
19
|
+
}
|
|
20
|
+
function getValueOrDefault(value, defaultValue, minimum) {
|
|
21
|
+
return typeof value === "number" && value > (minimum ?? 0) ? value : defaultValue;
|
|
22
|
+
}
|
|
23
|
+
function work(type, timer, state, options) {
|
|
24
|
+
if (["continue", "start"].includes(type) && state.active || ["pause", "stop"].includes(type) && !state.active) {
|
|
25
|
+
return timer;
|
|
26
|
+
}
|
|
27
|
+
const { count, interval, timeout } = options;
|
|
28
|
+
const { isRepeated, minimum } = state;
|
|
29
|
+
if (["pause", "restart", "stop"].includes(type)) {
|
|
30
|
+
const isStop = type === "stop";
|
|
31
|
+
activeTimers.delete(timer);
|
|
32
|
+
cancelAnimationFrame(state.frame);
|
|
33
|
+
if (isStop) {
|
|
34
|
+
options.afterCallback?.(false);
|
|
35
|
+
}
|
|
36
|
+
state.active = false;
|
|
37
|
+
state.frame = undefined;
|
|
38
|
+
state.paused = !isStop;
|
|
39
|
+
if (isStop) {
|
|
40
|
+
state.elapsed = undefined;
|
|
41
|
+
state.index = undefined;
|
|
42
|
+
}
|
|
43
|
+
return type === "restart" ? work("start", timer, state, options) : timer;
|
|
44
|
+
}
|
|
45
|
+
state.active = true;
|
|
46
|
+
state.paused = false;
|
|
47
|
+
const elapsed = type === "continue" ? +(state.elapsed ?? 0) : 0;
|
|
48
|
+
let index = type === "continue" ? +(state.index ?? 0) : 0;
|
|
49
|
+
state.elapsed = elapsed;
|
|
50
|
+
state.index = index;
|
|
51
|
+
const total = (count === Number.POSITIVE_INFINITY ? Number.POSITIVE_INFINITY : (count - index) * (interval > 0 ? interval : milliseconds)) - elapsed;
|
|
52
|
+
let current;
|
|
53
|
+
let start;
|
|
54
|
+
function finish(finished, error) {
|
|
55
|
+
activeTimers.delete(timer);
|
|
56
|
+
state.active = false;
|
|
57
|
+
state.elapsed = undefined;
|
|
58
|
+
state.frame = undefined;
|
|
59
|
+
state.index = undefined;
|
|
60
|
+
if (error) {
|
|
61
|
+
options.errorCallback?.();
|
|
62
|
+
}
|
|
63
|
+
options.afterCallback?.(finished);
|
|
64
|
+
}
|
|
65
|
+
function step(timestamp) {
|
|
66
|
+
if (!state.active) {
|
|
67
|
+
return;
|
|
68
|
+
}
|
|
69
|
+
current ??= timestamp;
|
|
70
|
+
start ??= timestamp;
|
|
71
|
+
const time = timestamp - current;
|
|
72
|
+
state.elapsed = elapsed + (current - start);
|
|
73
|
+
const finished = time - elapsed >= total;
|
|
74
|
+
if (timestamp - start >= timeout - elapsed) {
|
|
75
|
+
finish(finished, !finished);
|
|
76
|
+
return;
|
|
77
|
+
}
|
|
78
|
+
if (finished || time >= minimum) {
|
|
79
|
+
if (state.active) {
|
|
80
|
+
state.callback(isRepeated ? index : undefined);
|
|
81
|
+
}
|
|
82
|
+
index += 1;
|
|
83
|
+
state.index = index;
|
|
84
|
+
if (!finished && index < count) {
|
|
85
|
+
current = null;
|
|
86
|
+
} else {
|
|
87
|
+
finish(true, false);
|
|
88
|
+
return;
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
state.frame = requestAnimationFrame(step);
|
|
92
|
+
}
|
|
93
|
+
activeTimers.add(timer);
|
|
94
|
+
state.frame = requestAnimationFrame(step);
|
|
95
|
+
return timer;
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
// src/timer.ts
|
|
99
|
+
function timer(type, callback, partial, start) {
|
|
100
|
+
const isRepeated = type === "repeat";
|
|
101
|
+
const options = getOptions(partial, isRepeated);
|
|
102
|
+
const instance = new Timer(type, {
|
|
103
|
+
callback,
|
|
104
|
+
isRepeated,
|
|
105
|
+
active: false,
|
|
106
|
+
minimum: options.interval - options.interval % milliseconds / 2,
|
|
107
|
+
paused: false,
|
|
108
|
+
trace: new TimerTrace
|
|
109
|
+
}, options);
|
|
110
|
+
if (start) {
|
|
111
|
+
instance.start();
|
|
112
|
+
}
|
|
113
|
+
return instance;
|
|
114
|
+
}
|
|
115
|
+
class BasicTimer {
|
|
116
|
+
constructor(type, state) {
|
|
117
|
+
this.$timer = type;
|
|
118
|
+
this.state = state;
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
class Timer extends BasicTimer {
|
|
123
|
+
get active() {
|
|
124
|
+
return this.state.active;
|
|
125
|
+
}
|
|
126
|
+
get paused() {
|
|
127
|
+
return this.state.paused;
|
|
128
|
+
}
|
|
129
|
+
get trace() {
|
|
130
|
+
return globalThis._oscarpalmer_timer_debug ? this.state.trace : undefined;
|
|
131
|
+
}
|
|
132
|
+
constructor(type, state, options) {
|
|
133
|
+
super(type, state);
|
|
134
|
+
this.options = options;
|
|
135
|
+
}
|
|
136
|
+
continue() {
|
|
137
|
+
return work("continue", this, this.state, this.options);
|
|
138
|
+
}
|
|
139
|
+
pause() {
|
|
140
|
+
return work("pause", this, this.state, this.options);
|
|
141
|
+
}
|
|
142
|
+
restart() {
|
|
143
|
+
return work("restart", this, this.state, this.options);
|
|
144
|
+
}
|
|
145
|
+
start() {
|
|
146
|
+
return work("start", this, this.state, this.options);
|
|
147
|
+
}
|
|
148
|
+
stop() {
|
|
149
|
+
return work("stop", this, this.state, this.options);
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
class TimerTrace extends Error {
|
|
154
|
+
constructor() {
|
|
155
|
+
super();
|
|
156
|
+
this.name = "TimerTrace";
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
// src/when.ts
|
|
161
|
+
function when(condition, options) {
|
|
162
|
+
const repeated = timer("repeat", () => {
|
|
163
|
+
if (condition()) {
|
|
164
|
+
repeated.stop();
|
|
165
|
+
state.resolver?.();
|
|
166
|
+
}
|
|
167
|
+
}, {
|
|
168
|
+
afterCallback() {
|
|
169
|
+
if (!repeated.paused) {
|
|
170
|
+
if (condition()) {
|
|
171
|
+
state.resolver?.();
|
|
172
|
+
} else {
|
|
173
|
+
state.rejecter?.();
|
|
174
|
+
}
|
|
175
|
+
}
|
|
176
|
+
},
|
|
177
|
+
errorCallback() {
|
|
178
|
+
state.rejecter?.();
|
|
179
|
+
},
|
|
180
|
+
count: options?.count,
|
|
181
|
+
interval: options?.interval,
|
|
182
|
+
timeout: options?.timeout
|
|
183
|
+
}, false);
|
|
184
|
+
const state = {};
|
|
185
|
+
state.promise = new Promise((resolve, reject) => {
|
|
186
|
+
state.resolver = resolve;
|
|
187
|
+
state.rejecter = reject;
|
|
188
|
+
});
|
|
189
|
+
state.timer = repeated;
|
|
190
|
+
return new When(state);
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
class When extends BasicTimer {
|
|
194
|
+
get active() {
|
|
195
|
+
return this.state.timer.active;
|
|
196
|
+
}
|
|
197
|
+
get paused() {
|
|
198
|
+
return this.state.timer.paused;
|
|
199
|
+
}
|
|
200
|
+
constructor(state) {
|
|
201
|
+
super("when", state);
|
|
202
|
+
}
|
|
203
|
+
continue() {
|
|
204
|
+
this.state.timer.continue();
|
|
205
|
+
return this;
|
|
206
|
+
}
|
|
207
|
+
pause() {
|
|
208
|
+
this.state.timer.pause();
|
|
209
|
+
return this;
|
|
210
|
+
}
|
|
211
|
+
stop() {
|
|
212
|
+
if (this.state.timer.active) {
|
|
213
|
+
this.state.timer.stop();
|
|
214
|
+
this.state.rejecter?.();
|
|
215
|
+
}
|
|
216
|
+
return this;
|
|
217
|
+
}
|
|
218
|
+
then(resolve, reject) {
|
|
219
|
+
this.state.timer.start();
|
|
220
|
+
return this.state.promise.then(resolve ?? noop, reject ?? noop);
|
|
221
|
+
}
|
|
222
|
+
}
|
|
223
|
+
export {
|
|
224
|
+
when,
|
|
225
|
+
When
|
|
226
|
+
};
|
package/dist/when.mjs
ADDED
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
// src/when.ts
|
|
2
|
+
import {noop} from "@oscarpalmer/atoms/function";
|
|
3
|
+
import {BasicTimer, timer as timer2} from "./timer";
|
|
4
|
+
function when(condition, options) {
|
|
5
|
+
const repeated = timer2("repeat", () => {
|
|
6
|
+
if (condition()) {
|
|
7
|
+
repeated.stop();
|
|
8
|
+
state.resolver?.();
|
|
9
|
+
}
|
|
10
|
+
}, {
|
|
11
|
+
afterCallback() {
|
|
12
|
+
if (!repeated.paused) {
|
|
13
|
+
if (condition()) {
|
|
14
|
+
state.resolver?.();
|
|
15
|
+
} else {
|
|
16
|
+
state.rejecter?.();
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
},
|
|
20
|
+
errorCallback() {
|
|
21
|
+
state.rejecter?.();
|
|
22
|
+
},
|
|
23
|
+
count: options?.count,
|
|
24
|
+
interval: options?.interval,
|
|
25
|
+
timeout: options?.timeout
|
|
26
|
+
}, false);
|
|
27
|
+
const state = {};
|
|
28
|
+
state.promise = new Promise((resolve, reject) => {
|
|
29
|
+
state.resolver = resolve;
|
|
30
|
+
state.rejecter = reject;
|
|
31
|
+
});
|
|
32
|
+
state.timer = repeated;
|
|
33
|
+
return new When(state);
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
class When extends BasicTimer {
|
|
37
|
+
get active() {
|
|
38
|
+
return this.state.timer.active;
|
|
39
|
+
}
|
|
40
|
+
get paused() {
|
|
41
|
+
return this.state.timer.paused;
|
|
42
|
+
}
|
|
43
|
+
constructor(state) {
|
|
44
|
+
super("when", state);
|
|
45
|
+
}
|
|
46
|
+
continue() {
|
|
47
|
+
this.state.timer.continue();
|
|
48
|
+
return this;
|
|
49
|
+
}
|
|
50
|
+
pause() {
|
|
51
|
+
this.state.timer.pause();
|
|
52
|
+
return this;
|
|
53
|
+
}
|
|
54
|
+
stop() {
|
|
55
|
+
if (this.state.timer.active) {
|
|
56
|
+
this.state.timer.stop();
|
|
57
|
+
this.state.rejecter?.();
|
|
58
|
+
}
|
|
59
|
+
return this;
|
|
60
|
+
}
|
|
61
|
+
then(resolve, reject) {
|
|
62
|
+
this.state.timer.start();
|
|
63
|
+
return this.state.promise.then(resolve ?? noop, reject ?? noop);
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
export {
|
|
67
|
+
when,
|
|
68
|
+
When
|
|
69
|
+
};
|
package/package.json
CHANGED
|
@@ -17,26 +17,30 @@
|
|
|
17
17
|
},
|
|
18
18
|
"exports": {
|
|
19
19
|
".": {
|
|
20
|
-
"types": "./types/index.d.cts",
|
|
21
20
|
"bun": "./src/index.ts",
|
|
22
|
-
"import":
|
|
23
|
-
|
|
21
|
+
"import": {
|
|
22
|
+
"types": "./types/index.d.ts",
|
|
23
|
+
"default": "./dist/timer.mjs"
|
|
24
|
+
},
|
|
25
|
+
"require": {
|
|
26
|
+
"types": "./types/index.d.cts",
|
|
27
|
+
"default": "./dist/index.js"
|
|
28
|
+
}
|
|
24
29
|
}
|
|
25
30
|
},
|
|
26
31
|
"files": ["dist", "src", "types"],
|
|
27
32
|
"keywords": ["timer", "setTimeout", "setInterval", "requestAnimationFrame"],
|
|
28
33
|
"license": "MIT",
|
|
29
|
-
"main": "dist/
|
|
30
|
-
"module": "dist/
|
|
34
|
+
"main": "dist/index.js",
|
|
35
|
+
"module": "dist/index.mjs",
|
|
31
36
|
"name": "@oscarpalmer/timer",
|
|
32
37
|
"repository": {
|
|
33
38
|
"type": "git",
|
|
34
39
|
"url": "git+https://github.com/oscarpalmer/timer.git"
|
|
35
40
|
},
|
|
36
41
|
"scripts": {
|
|
37
|
-
"build": "bun run clean && bun run build:
|
|
38
|
-
"build:
|
|
39
|
-
"build:esm": "bun build ./src/index.ts --external '*' --outfile ./dist/timer.mjs",
|
|
42
|
+
"build": "bun run clean && bun run build:js && bun run types",
|
|
43
|
+
"build:js": "bunx bun ./.bun.ts && bunx bun ./.bun.ts --mjs",
|
|
40
44
|
"clean": "rm -rf ./dist && rm -rf ./types && rm -f ./tsconfig.tsbuildinfo",
|
|
41
45
|
"test": "bun test",
|
|
42
46
|
"types": "bun run types:cjs && bun run types:esm",
|
|
@@ -46,5 +50,5 @@
|
|
|
46
50
|
},
|
|
47
51
|
"type": "module",
|
|
48
52
|
"types": "types/index.d.cts",
|
|
49
|
-
"version": "0.
|
|
53
|
+
"version": "0.22.0"
|
|
50
54
|
}
|
|
File without changes
|