@oscarpalmer/timer 0.19.0 → 0.21.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/README.md +28 -33
- package/dist/timer.js +290 -160
- package/dist/timer.mjs +40 -0
- package/package.json +33 -51
- package/src/constants.ts +16 -0
- package/src/functions.ts +151 -0
- package/src/global.ts +14 -0
- package/src/index.ts +26 -219
- package/src/is.ts +35 -0
- package/src/models.ts +76 -0
- package/src/timer.ts +186 -0
- package/src/when.ts +111 -0
- package/types/constants.d.ts +13 -0
- package/types/functions.d.ts +5 -0
- package/types/global.d.ts +5 -0
- package/types/index.d.cts +184 -0
- package/types/index.d.ts +6 -70
- package/types/is.d.ts +18 -0
- package/types/models.d.ts +62 -0
- package/types/timer.d.ts +72 -0
- package/types/when.d.ts +28 -0
- package/dist/timer.iife.js +0 -162
package/README.md
CHANGED
|
@@ -8,8 +8,6 @@ A better solution for timeout- and interval-based timers.
|
|
|
8
8
|
|
|
9
9
|
Timer is available on _npm_ as [`@oscarpalmer/timer`](https://www.npmjs.com/package/@oscarpalmer/timer) to be bundled with your awesome projects.
|
|
10
10
|
|
|
11
|
-
If you don't need to bundle things, you can use the CDN-version and include a script in your proejcts right away, thanks to [jsDelivr](https://www.jsdelivr.com/package/npm/@oscarpalmer/timer) and [UNPKG](https://unpkg.com/@oscarpalmer/timer).
|
|
12
|
-
|
|
13
11
|
## Getting started
|
|
14
12
|
|
|
15
13
|
This is fairly lightweight package, so hopefully you'll be up and running in seconds :blush:
|
|
@@ -21,65 +19,62 @@ The timers can be called with nice helper methods, which also auto-starts the ti
|
|
|
21
19
|
```typescript
|
|
22
20
|
import {repeat, wait} from '@oscarpalmer/timer';
|
|
23
21
|
|
|
24
|
-
|
|
25
|
-
|
|
22
|
+
const waited = wait(waitedCallback);
|
|
23
|
+
const repeated = repeat(repeatedCallback, 10);
|
|
26
24
|
```
|
|
27
25
|
|
|
28
|
-
Or they can be created using
|
|
26
|
+
Or they can be created using the `new`-keyword, but without being auto-started:
|
|
29
27
|
|
|
30
28
|
```typescript
|
|
31
|
-
import {
|
|
29
|
+
import {Timer} from '@oscarpalmer/timer';
|
|
32
30
|
|
|
33
|
-
waited = new
|
|
34
|
-
repeated = new
|
|
31
|
+
const waited = new Timer(waitedCallback);
|
|
32
|
+
const repeated = new Timer(repeatedCallback, 10);
|
|
35
33
|
```
|
|
36
34
|
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
If you're using Timer by including the file suffixed with `.iife.js` – or one of the CDN-versions mentioned above – you won't have to import any of the classes or methods.
|
|
35
|
+
## Parameters
|
|
40
36
|
|
|
41
|
-
|
|
37
|
+
When creating a _Timer_, either with the new `new`-keyword or using the functions, you can configure the timer with a few parameters:
|
|
42
38
|
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
waited = new Timer.Waited(callback, time);
|
|
50
|
-
repeated = new Timer.Repeated(callback, time, count);
|
|
51
|
-
```
|
|
39
|
+
|Parameter|Description|
|
|
40
|
+
|--------:|:----------|
|
|
41
|
+
|`callback`|Callback function to be invoked for each run that are __required__ for all timers.<br>For more information on callbacks, please read [the callbacks section](#callbacks).|
|
|
42
|
+
|`count`|How many times the timer should run.<br>If no value is provided, it will default to `1` when using the `new`-keyword and the `wait`-method, but throws an error for the `repeat`-method.|
|
|
43
|
+
|`time`|How many milliseconds between each invokations of the provided callback.<br>Defaults to `0`, which is not really _0_ milliseconds, but close enough :wink:|
|
|
44
|
+
|`after`|A callback to run after the timer finishes, both when cancelled and completed.<br>If _count_ is greater than `1` and _after_ __is not__ `undefined`, a function is expected.|
|
|
52
45
|
|
|
53
|
-
## Methods
|
|
46
|
+
## Methods and properties
|
|
54
47
|
|
|
55
|
-
|
|
48
|
+
An instance of _Timer_ also has a few helpful methods and properties:
|
|
56
49
|
|
|
57
|
-
|
|
|
58
|
-
|
|
59
|
-
|`
|
|
60
|
-
|`
|
|
61
|
-
|`
|
|
50
|
+
|Name|Type|Description|
|
|
51
|
+
|---:|----|:----------|
|
|
52
|
+
|`active`|_Property_|A `boolean` value to check if the timer is running|
|
|
53
|
+
|`finished`|_Property_|A `boolean` value to check if the timer was able to finish|
|
|
54
|
+
|`start()`|_Method_|Starts the timer.<br>Necessary when creating a timer using the class syntax _(e.g. `new Waited...`)_, but helpful when the timer needs to be started at other times, as well.|
|
|
55
|
+
|`stop()`|_Method_|Stops the timer|
|
|
56
|
+
|`restart()`|_Method_|Restarts the timer|
|
|
62
57
|
|
|
63
58
|
## Callbacks
|
|
64
59
|
|
|
65
|
-
Callbacks for waited
|
|
60
|
+
Callbacks for both waited and repeated timers receive one parameter:
|
|
66
61
|
|
|
67
62
|
```typescript
|
|
68
|
-
|
|
63
|
+
function callback(index) {
|
|
69
64
|
// 'index' is the current step
|
|
70
65
|
// starts at 0, goes up to a maximum of count - 1
|
|
71
66
|
// for this example: 0 → 9
|
|
72
|
-
}
|
|
67
|
+
};
|
|
73
68
|
```
|
|
74
69
|
|
|
75
|
-
When you create a repeated timer, you can also provide a
|
|
70
|
+
When you create a repeated timer, you can also provide a callback to run when the timer stops, as below:
|
|
76
71
|
|
|
77
72
|
```typescript
|
|
78
73
|
function after(finished: boolean) {
|
|
79
74
|
// Let's do something fun!
|
|
80
75
|
}
|
|
81
76
|
|
|
82
|
-
repeat(() => {},
|
|
77
|
+
repeat(() => {}, 10, after);
|
|
83
78
|
```
|
|
84
79
|
|
|
85
80
|
The `finished`-parameter for the `after`-function can be used to determine if the timer was stopped manually, or if it was able to finish its work.
|
package/dist/timer.js
CHANGED
|
@@ -1,162 +1,292 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
* @param {boolean} finished Did the timer finish?
|
|
4
|
-
* @returns {void}
|
|
5
|
-
*/
|
|
6
|
-
/**
|
|
7
|
-
* @callback RepeatedCallback
|
|
8
|
-
* @param {number} index The index of the current iteration
|
|
9
|
-
* @returns {void}
|
|
10
|
-
*/
|
|
11
|
-
const callbacks = new WeakMap();
|
|
12
|
-
const configuration = new WeakMap();
|
|
13
|
-
const state = new WeakMap();
|
|
14
|
-
const milliseconds = Math.round(1000 / 60);
|
|
15
|
-
function run(timed) {
|
|
16
|
-
const timedConfiguration = configuration.get(timed);
|
|
17
|
-
const timedCallbacks = callbacks.get(timed);
|
|
18
|
-
const timedState = state.get(timed);
|
|
19
|
-
timedState.active = true;
|
|
20
|
-
timedState.finished = false;
|
|
21
|
-
const isRepeated = timed instanceof Repeated;
|
|
22
|
-
let index = 0;
|
|
23
|
-
let start;
|
|
24
|
-
function step(timestamp) {
|
|
25
|
-
if (!timedState.active) {
|
|
26
|
-
return;
|
|
27
|
-
}
|
|
28
|
-
start ?? (start = timestamp);
|
|
29
|
-
const elapsed = timestamp - start;
|
|
30
|
-
const elapsedMinimum = elapsed - milliseconds;
|
|
31
|
-
const elapsedMaximum = elapsed + milliseconds;
|
|
32
|
-
if (
|
|
33
|
-
elapsedMinimum < timedConfiguration.time &&
|
|
34
|
-
timedConfiguration.time < elapsedMaximum
|
|
35
|
-
) {
|
|
36
|
-
if (timedState.active) {
|
|
37
|
-
timedCallbacks.default(isRepeated ? index : undefined);
|
|
38
|
-
}
|
|
39
|
-
index += 1;
|
|
40
|
-
if (isRepeated && index < timedConfiguration.count) {
|
|
41
|
-
start = undefined;
|
|
42
|
-
} else {
|
|
43
|
-
timedState.finished = true;
|
|
44
|
-
timed.stop();
|
|
45
|
-
return;
|
|
46
|
-
}
|
|
47
|
-
}
|
|
48
|
-
timedState.frame = globalThis.requestAnimationFrame(step);
|
|
49
|
-
}
|
|
50
|
-
timedState.frame = globalThis.requestAnimationFrame(step);
|
|
51
|
-
}
|
|
52
|
-
class Timed {
|
|
53
|
-
get active() {
|
|
54
|
-
return state.get(this)?.active ?? false;
|
|
55
|
-
}
|
|
56
|
-
get finished() {
|
|
57
|
-
return !this.active && (state.get(this)?.finished ?? false);
|
|
58
|
-
}
|
|
59
|
-
/**
|
|
60
|
-
* @param {Callback} callback
|
|
61
|
-
* @param {number} time
|
|
62
|
-
* @param {number} count
|
|
63
|
-
* @param {AfterCallback=} afterCallback
|
|
64
|
-
*/
|
|
65
|
-
constructor(callback, time, count, afterCallback) {
|
|
66
|
-
const isRepeated = this instanceof Repeated;
|
|
67
|
-
const type = isRepeated ? 'repeated' : 'waited';
|
|
68
|
-
if (typeof callback !== 'function') {
|
|
69
|
-
throw new TypeError(`A ${type} timer must have a callback function`);
|
|
70
|
-
}
|
|
71
|
-
if (typeof time !== 'number' || time < 0) {
|
|
72
|
-
throw new TypeError(
|
|
73
|
-
`A ${type} timer must have a non-negative number as its time`,
|
|
74
|
-
);
|
|
75
|
-
}
|
|
76
|
-
if (isRepeated && (typeof count !== 'number' || count < 2)) {
|
|
77
|
-
throw new TypeError(
|
|
78
|
-
'A repeated timer must have a number above 1 as its repeat count',
|
|
79
|
-
);
|
|
80
|
-
}
|
|
81
|
-
if (
|
|
82
|
-
isRepeated &&
|
|
83
|
-
afterCallback !== undefined &&
|
|
84
|
-
typeof afterCallback !== 'function'
|
|
85
|
-
) {
|
|
86
|
-
throw new TypeError(
|
|
87
|
-
"A repeated timer's after-callback must be a function",
|
|
88
|
-
);
|
|
89
|
-
}
|
|
90
|
-
callbacks.set(this, {
|
|
91
|
-
after: afterCallback,
|
|
92
|
-
default: callback,
|
|
93
|
-
});
|
|
94
|
-
configuration.set(this, {count, time});
|
|
95
|
-
state.set(this, {
|
|
96
|
-
active: false,
|
|
97
|
-
finished: false,
|
|
98
|
-
});
|
|
99
|
-
}
|
|
100
|
-
restart() {
|
|
101
|
-
this.stop();
|
|
102
|
-
run(this);
|
|
103
|
-
return this;
|
|
104
|
-
}
|
|
105
|
-
start() {
|
|
106
|
-
if (!this.active) {
|
|
107
|
-
run(this);
|
|
108
|
-
}
|
|
109
|
-
return this;
|
|
110
|
-
}
|
|
111
|
-
stop() {
|
|
112
|
-
const timedCallbacks = callbacks.get(this);
|
|
113
|
-
const timedState = state.get(this);
|
|
114
|
-
timedState.active = false;
|
|
115
|
-
if (timedState.frame === undefined) {
|
|
116
|
-
return this;
|
|
117
|
-
}
|
|
118
|
-
globalThis.cancelAnimationFrame(timedState.frame);
|
|
119
|
-
timedCallbacks.after?.(this.finished);
|
|
120
|
-
timedState.frame = undefined;
|
|
121
|
-
return this;
|
|
122
|
-
}
|
|
123
|
-
}
|
|
124
|
-
/**
|
|
125
|
-
* A timer that waits and runs repeatedly
|
|
126
|
-
*/
|
|
127
|
-
class Repeated extends Timed {}
|
|
128
|
-
/**
|
|
129
|
-
* A timer that waits and runs once
|
|
130
|
-
*/
|
|
131
|
-
class Waited extends Timed {
|
|
132
|
-
/**
|
|
133
|
-
* Creates a new waited timer
|
|
134
|
-
* @param {() => void} callback
|
|
135
|
-
* @param {number} time
|
|
136
|
-
*/
|
|
137
|
-
constructor(callback, time) {
|
|
138
|
-
super(callback, time, 1);
|
|
139
|
-
}
|
|
140
|
-
}
|
|
141
|
-
/**
|
|
142
|
-
* Creates and starts a new repeated timer
|
|
143
|
-
* @param {RepeatedCallback} callback
|
|
144
|
-
* @param {number} time
|
|
145
|
-
* @param {number} count
|
|
146
|
-
* @param {AfterCallback=} afterCallback
|
|
147
|
-
* @return {Repeated}
|
|
148
|
-
*/
|
|
149
|
-
function repeat(callback, time, count, afterCallback) {
|
|
150
|
-
return new Repeated(callback, time, count, afterCallback).start();
|
|
151
|
-
}
|
|
152
|
-
/**
|
|
153
|
-
* Creates and starts a new waited timer
|
|
154
|
-
* @param {() => void} callback
|
|
155
|
-
* @param {number} time
|
|
156
|
-
* @return {Waited}
|
|
157
|
-
*/
|
|
158
|
-
function wait(callback, time) {
|
|
159
|
-
return new Waited(callback, time).start();
|
|
1
|
+
// node_modules/@oscarpalmer/atoms/dist/js/function.mjs
|
|
2
|
+
function noop() {
|
|
160
3
|
}
|
|
161
4
|
|
|
162
|
-
|
|
5
|
+
// src/constants.ts
|
|
6
|
+
var activeTimers = new Set;
|
|
7
|
+
var hiddenTimers = new Set;
|
|
8
|
+
var milliseconds = 1000 / 60;
|
|
9
|
+
|
|
10
|
+
// src/global.ts
|
|
11
|
+
if (globalThis._oscarpalmer_timers == null) {
|
|
12
|
+
Object.defineProperty(globalThis, "_oscarpalmer_timers", {
|
|
13
|
+
get() {
|
|
14
|
+
return globalThis._oscarpalmer_timer_debug ? [...activeTimers] : [];
|
|
15
|
+
}
|
|
16
|
+
});
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
// src/functions.ts
|
|
20
|
+
function getOptions(options, isRepeated) {
|
|
21
|
+
return {
|
|
22
|
+
afterCallback: options.afterCallback,
|
|
23
|
+
count: getValueOrDefault(options.count, isRepeated ? Number.POSITIVE_INFINITY : 1),
|
|
24
|
+
errorCallback: options.errorCallback,
|
|
25
|
+
interval: getValueOrDefault(options.interval, milliseconds, milliseconds),
|
|
26
|
+
timeout: getValueOrDefault(options.timeout, isRepeated ? Number.POSITIVE_INFINITY : 30000)
|
|
27
|
+
};
|
|
28
|
+
}
|
|
29
|
+
function getValueOrDefault(value, defaultValue, minimum) {
|
|
30
|
+
return typeof value === "number" && value > (minimum ?? 0) ? value : defaultValue;
|
|
31
|
+
}
|
|
32
|
+
function work(type, timer, state, options) {
|
|
33
|
+
if (["continue", "start"].includes(type) && state.active || ["pause", "stop"].includes(type) && !state.active) {
|
|
34
|
+
return timer;
|
|
35
|
+
}
|
|
36
|
+
const { count, interval, timeout } = options;
|
|
37
|
+
const { isRepeated, minimum } = state;
|
|
38
|
+
if (["pause", "restart", "stop"].includes(type)) {
|
|
39
|
+
const isStop = type === "stop";
|
|
40
|
+
activeTimers.delete(timer);
|
|
41
|
+
cancelAnimationFrame(state.frame);
|
|
42
|
+
if (isStop) {
|
|
43
|
+
options.afterCallback?.(false);
|
|
44
|
+
}
|
|
45
|
+
state.active = false;
|
|
46
|
+
state.frame = undefined;
|
|
47
|
+
state.paused = !isStop;
|
|
48
|
+
if (isStop) {
|
|
49
|
+
state.elapsed = undefined;
|
|
50
|
+
state.index = undefined;
|
|
51
|
+
}
|
|
52
|
+
return type === "restart" ? work("start", timer, state, options) : timer;
|
|
53
|
+
}
|
|
54
|
+
state.active = true;
|
|
55
|
+
state.paused = false;
|
|
56
|
+
const elapsed = type === "continue" ? +(state.elapsed ?? 0) : 0;
|
|
57
|
+
let index = type === "continue" ? +(state.index ?? 0) : 0;
|
|
58
|
+
state.elapsed = elapsed;
|
|
59
|
+
state.index = index;
|
|
60
|
+
const total = (count === Number.POSITIVE_INFINITY ? Number.POSITIVE_INFINITY : (count - index) * (interval > 0 ? interval : milliseconds)) - elapsed;
|
|
61
|
+
let current;
|
|
62
|
+
let start;
|
|
63
|
+
function finish(finished, error) {
|
|
64
|
+
activeTimers.delete(timer);
|
|
65
|
+
state.active = false;
|
|
66
|
+
state.elapsed = undefined;
|
|
67
|
+
state.frame = undefined;
|
|
68
|
+
state.index = undefined;
|
|
69
|
+
if (error) {
|
|
70
|
+
options.errorCallback?.();
|
|
71
|
+
}
|
|
72
|
+
options.afterCallback?.(finished);
|
|
73
|
+
}
|
|
74
|
+
function step(timestamp) {
|
|
75
|
+
if (!state.active) {
|
|
76
|
+
return;
|
|
77
|
+
}
|
|
78
|
+
current ??= timestamp;
|
|
79
|
+
start ??= timestamp;
|
|
80
|
+
const time = timestamp - current;
|
|
81
|
+
state.elapsed = elapsed + (current - start);
|
|
82
|
+
const finished = time - elapsed >= total;
|
|
83
|
+
if (timestamp - start >= timeout - elapsed) {
|
|
84
|
+
finish(finished, !finished);
|
|
85
|
+
return;
|
|
86
|
+
}
|
|
87
|
+
if (finished || time >= minimum) {
|
|
88
|
+
if (state.active) {
|
|
89
|
+
state.callback(isRepeated ? index : undefined);
|
|
90
|
+
}
|
|
91
|
+
index += 1;
|
|
92
|
+
state.index = index;
|
|
93
|
+
if (!finished && index < count) {
|
|
94
|
+
current = null;
|
|
95
|
+
} else {
|
|
96
|
+
finish(true, false);
|
|
97
|
+
return;
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
state.frame = requestAnimationFrame(step);
|
|
101
|
+
}
|
|
102
|
+
activeTimers.add(timer);
|
|
103
|
+
state.frame = requestAnimationFrame(step);
|
|
104
|
+
return timer;
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
// src/timer.ts
|
|
108
|
+
function repeat(callback, options) {
|
|
109
|
+
return timer("repeat", callback, options ?? {}, true);
|
|
110
|
+
}
|
|
111
|
+
function timer(type, callback, partial, start) {
|
|
112
|
+
const isRepeated = type === "repeat";
|
|
113
|
+
const options = getOptions(partial, isRepeated);
|
|
114
|
+
const instance = new Timer(type, {
|
|
115
|
+
callback,
|
|
116
|
+
isRepeated,
|
|
117
|
+
active: false,
|
|
118
|
+
minimum: options.interval - options.interval % milliseconds / 2,
|
|
119
|
+
paused: false,
|
|
120
|
+
trace: new TimerTrace
|
|
121
|
+
}, options);
|
|
122
|
+
if (start) {
|
|
123
|
+
instance.start();
|
|
124
|
+
}
|
|
125
|
+
return instance;
|
|
126
|
+
}
|
|
127
|
+
function wait(callback, options) {
|
|
128
|
+
return timer("wait", callback, options == null || typeof options === "number" ? {
|
|
129
|
+
interval: options
|
|
130
|
+
} : options, true);
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
class BasicTimer {
|
|
134
|
+
constructor(type, state) {
|
|
135
|
+
this.$timer = type;
|
|
136
|
+
this.state = state;
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
class Timer extends BasicTimer {
|
|
141
|
+
get active() {
|
|
142
|
+
return this.state.active;
|
|
143
|
+
}
|
|
144
|
+
get paused() {
|
|
145
|
+
return this.state.paused;
|
|
146
|
+
}
|
|
147
|
+
get trace() {
|
|
148
|
+
return globalThis._oscarpalmer_timer_debug ? this.state.trace : undefined;
|
|
149
|
+
}
|
|
150
|
+
constructor(type, state, options) {
|
|
151
|
+
super(type, state);
|
|
152
|
+
this.options = options;
|
|
153
|
+
}
|
|
154
|
+
continue() {
|
|
155
|
+
return work("continue", this, this.state, this.options);
|
|
156
|
+
}
|
|
157
|
+
pause() {
|
|
158
|
+
return work("pause", this, this.state, this.options);
|
|
159
|
+
}
|
|
160
|
+
restart() {
|
|
161
|
+
return work("restart", this, this.state, this.options);
|
|
162
|
+
}
|
|
163
|
+
start() {
|
|
164
|
+
return work("start", this, this.state, this.options);
|
|
165
|
+
}
|
|
166
|
+
stop() {
|
|
167
|
+
return work("stop", this, this.state, this.options);
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
class TimerTrace extends Error {
|
|
172
|
+
constructor() {
|
|
173
|
+
super();
|
|
174
|
+
this.name = "TimerTrace";
|
|
175
|
+
}
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
// src/index.ts
|
|
179
|
+
function delay(time, timeout) {
|
|
180
|
+
return new Promise((resolve, reject) => {
|
|
181
|
+
wait(resolve ?? noop, {
|
|
182
|
+
timeout,
|
|
183
|
+
errorCallback: reject ?? noop,
|
|
184
|
+
interval: time
|
|
185
|
+
});
|
|
186
|
+
});
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
// src/is.ts
|
|
190
|
+
function is(pattern, value) {
|
|
191
|
+
return pattern.test(value?.$timer);
|
|
192
|
+
}
|
|
193
|
+
function isRepeated(value) {
|
|
194
|
+
return is(/^repeat$/, value);
|
|
195
|
+
}
|
|
196
|
+
function isTimer(value) {
|
|
197
|
+
return is(/^repeat|wait$/, value);
|
|
198
|
+
}
|
|
199
|
+
function isWaited(value) {
|
|
200
|
+
return is(/^wait$/, value);
|
|
201
|
+
}
|
|
202
|
+
function isWhen(value) {
|
|
203
|
+
return is(/^when$/, value) && typeof value.then === "function";
|
|
204
|
+
}
|
|
205
|
+
// src/when.ts
|
|
206
|
+
function when(condition, options) {
|
|
207
|
+
const repeated = timer("repeat", () => {
|
|
208
|
+
if (condition()) {
|
|
209
|
+
repeated.stop();
|
|
210
|
+
state.resolver?.();
|
|
211
|
+
}
|
|
212
|
+
}, {
|
|
213
|
+
afterCallback() {
|
|
214
|
+
if (!repeated.paused) {
|
|
215
|
+
if (condition()) {
|
|
216
|
+
state.resolver?.();
|
|
217
|
+
} else {
|
|
218
|
+
state.rejecter?.();
|
|
219
|
+
}
|
|
220
|
+
}
|
|
221
|
+
},
|
|
222
|
+
errorCallback() {
|
|
223
|
+
state.rejecter?.();
|
|
224
|
+
},
|
|
225
|
+
count: options?.count,
|
|
226
|
+
interval: options?.interval,
|
|
227
|
+
timeout: options?.timeout
|
|
228
|
+
}, false);
|
|
229
|
+
const state = {};
|
|
230
|
+
state.promise = new Promise((resolve, reject) => {
|
|
231
|
+
state.resolver = resolve;
|
|
232
|
+
state.rejecter = reject;
|
|
233
|
+
});
|
|
234
|
+
state.timer = repeated;
|
|
235
|
+
return new When(state);
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
class When extends BasicTimer {
|
|
239
|
+
get active() {
|
|
240
|
+
return this.state.timer.active;
|
|
241
|
+
}
|
|
242
|
+
get paused() {
|
|
243
|
+
return this.state.timer.paused;
|
|
244
|
+
}
|
|
245
|
+
constructor(state) {
|
|
246
|
+
super("when", state);
|
|
247
|
+
}
|
|
248
|
+
continue() {
|
|
249
|
+
this.state.timer.continue();
|
|
250
|
+
return this;
|
|
251
|
+
}
|
|
252
|
+
pause() {
|
|
253
|
+
this.state.timer.pause();
|
|
254
|
+
return this;
|
|
255
|
+
}
|
|
256
|
+
stop() {
|
|
257
|
+
if (this.state.timer.active) {
|
|
258
|
+
this.state.timer.stop();
|
|
259
|
+
this.state.rejecter?.();
|
|
260
|
+
}
|
|
261
|
+
return this;
|
|
262
|
+
}
|
|
263
|
+
then(resolve, reject) {
|
|
264
|
+
this.state.timer.start();
|
|
265
|
+
return this.state.promise.then(resolve ?? noop, reject ?? noop);
|
|
266
|
+
}
|
|
267
|
+
}
|
|
268
|
+
|
|
269
|
+
// src/index.ts
|
|
270
|
+
document.addEventListener("visibilitychange", () => {
|
|
271
|
+
if (document.hidden) {
|
|
272
|
+
for (const timer4 of activeTimers) {
|
|
273
|
+
hiddenTimers.add(timer4);
|
|
274
|
+
timer4.pause();
|
|
275
|
+
}
|
|
276
|
+
} else {
|
|
277
|
+
for (const timer4 of hiddenTimers) {
|
|
278
|
+
timer4.continue();
|
|
279
|
+
}
|
|
280
|
+
hiddenTimers.clear();
|
|
281
|
+
}
|
|
282
|
+
});
|
|
283
|
+
export {
|
|
284
|
+
when,
|
|
285
|
+
wait,
|
|
286
|
+
repeat,
|
|
287
|
+
isWhen,
|
|
288
|
+
isWaited,
|
|
289
|
+
isTimer,
|
|
290
|
+
isRepeated,
|
|
291
|
+
delay
|
|
292
|
+
};
|
package/dist/timer.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/package.json
CHANGED
|
@@ -3,66 +3,48 @@
|
|
|
3
3
|
"name": "Oscar Palmér",
|
|
4
4
|
"url": "https://oscarpalmer.se"
|
|
5
5
|
},
|
|
6
|
-
"
|
|
6
|
+
"dependencies": {
|
|
7
|
+
"@oscarpalmer/atoms": "0.69.0"
|
|
8
|
+
},
|
|
7
9
|
"description": "A better solution for timeout- and interval-based timers.",
|
|
8
10
|
"devDependencies": {
|
|
9
|
-
"@
|
|
10
|
-
"@
|
|
11
|
-
"bun": "^1.
|
|
12
|
-
"
|
|
13
|
-
"
|
|
14
|
-
"typescript": "^5.
|
|
15
|
-
|
|
11
|
+
"@biomejs/biome": "^1.8.3",
|
|
12
|
+
"@happy-dom/global-registrator": "^14.12.3",
|
|
13
|
+
"@types/bun": "^1.1.6",
|
|
14
|
+
"bun": "^1.1.21",
|
|
15
|
+
"dts-bundle-generator": "9.5.1",
|
|
16
|
+
"typescript": "^5.5.4"
|
|
17
|
+
},
|
|
18
|
+
"exports": {
|
|
19
|
+
".": {
|
|
20
|
+
"types": "./types/index.d.cts",
|
|
21
|
+
"bun": "./src/index.ts",
|
|
22
|
+
"import": "./dist/timer.mjs",
|
|
23
|
+
"require": "./dist/timer.js"
|
|
24
|
+
}
|
|
16
25
|
},
|
|
17
|
-
"files": [
|
|
18
|
-
|
|
19
|
-
"src",
|
|
20
|
-
"types"
|
|
21
|
-
],
|
|
22
|
-
"jsdelivr": "dist/timer.iife.js",
|
|
23
|
-
"keywords": [
|
|
24
|
-
"timer",
|
|
25
|
-
"setTimeout",
|
|
26
|
-
"setInterval",
|
|
27
|
-
"requestAnimationFrame"
|
|
28
|
-
],
|
|
26
|
+
"files": ["dist", "src", "types"],
|
|
27
|
+
"keywords": ["timer", "setTimeout", "setInterval", "requestAnimationFrame"],
|
|
29
28
|
"license": "MIT",
|
|
30
|
-
"main": "dist/timer.
|
|
31
|
-
"module": "dist/timer.
|
|
29
|
+
"main": "dist/timer.js",
|
|
30
|
+
"module": "dist/timer.mjs",
|
|
32
31
|
"name": "@oscarpalmer/timer",
|
|
33
|
-
"prettier": {
|
|
34
|
-
"arrowParens": "avoid",
|
|
35
|
-
"bracketSpacing": false,
|
|
36
|
-
"singleQuote": true,
|
|
37
|
-
"switchIndent": true,
|
|
38
|
-
"trailingComma": "all",
|
|
39
|
-
"useTabs": true
|
|
40
|
-
},
|
|
41
32
|
"repository": {
|
|
42
33
|
"type": "git",
|
|
43
34
|
"url": "git+https://github.com/oscarpalmer/timer.git"
|
|
44
35
|
},
|
|
45
36
|
"scripts": {
|
|
46
|
-
"build": "
|
|
47
|
-
"build:
|
|
48
|
-
"build:
|
|
49
|
-
"
|
|
50
|
-
"
|
|
51
|
-
"
|
|
52
|
-
"
|
|
37
|
+
"build": "bun run clean && bun run build:cjs && bun run build:esm && bun run types",
|
|
38
|
+
"build:cjs": "bun build ./src/index.ts --outfile ./dist/timer.js",
|
|
39
|
+
"build:esm": "bun build ./src/index.ts --external '*' --outfile ./dist/timer.mjs",
|
|
40
|
+
"clean": "rm -rf ./dist && rm -rf ./types && rm -f ./tsconfig.tsbuildinfo",
|
|
41
|
+
"test": "bun test",
|
|
42
|
+
"types": "bun run types:cjs && bun run types:esm",
|
|
43
|
+
"types:cjs": "bunx dts-bundle-generator --out-file ./types/index.d.cts --external-inlines '@oscarpalmer/atoms' --no-check --silent ./src/index.ts",
|
|
44
|
+
"types:esm": "bunx tsc -p ./tsconfig.json",
|
|
45
|
+
"watch": "bun build ./src/index.ts --outfile ./dist/timer.js --watch"
|
|
53
46
|
},
|
|
54
47
|
"type": "module",
|
|
55
|
-
"types": "
|
|
56
|
-
"
|
|
57
|
-
|
|
58
|
-
"xo": {
|
|
59
|
-
"envs": [
|
|
60
|
-
"browser"
|
|
61
|
-
],
|
|
62
|
-
"prettier": true,
|
|
63
|
-
"rules": {
|
|
64
|
-
"import/extensions": "off",
|
|
65
|
-
"import/no-cycle": "off"
|
|
66
|
-
}
|
|
67
|
-
}
|
|
68
|
-
}
|
|
48
|
+
"types": "types/index.d.cts",
|
|
49
|
+
"version": "0.21.0"
|
|
50
|
+
}
|