@oscarpalmer/timer 0.21.1 → 0.22.1

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.
@@ -0,0 +1,9 @@
1
+ // src/constants.ts
2
+ var activeTimers = new Set;
3
+ var hiddenTimers = new Set;
4
+ var milliseconds = 1000 / 60;
5
+ export {
6
+ milliseconds,
7
+ hiddenTimers,
8
+ activeTimers
9
+ };
@@ -0,0 +1,9 @@
1
+ // src/constants.ts
2
+ var activeTimers = new Set;
3
+ var hiddenTimers = new Set;
4
+ var milliseconds = 1000 / 60;
5
+ export {
6
+ milliseconds,
7
+ hiddenTimers,
8
+ activeTimers
9
+ };
@@ -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
+ }
@@ -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.js ADDED
@@ -0,0 +1,292 @@
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/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/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
+ };
File without changes
package/dist/timer.js CHANGED
@@ -1,21 +1,8 @@
1
- // node_modules/@oscarpalmer/atoms/dist/js/function.mjs
2
- function noop() {
3
- }
4
-
5
1
  // src/constants.ts
6
2
  var activeTimers = new Set;
7
3
  var hiddenTimers = new Set;
8
4
  var milliseconds = 1000 / 60;
9
5
 
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
6
  // src/functions.ts
20
7
  function getOptions(options, isRepeated) {
21
8
  return {
@@ -174,119 +161,10 @@ class TimerTrace extends Error {
174
161
  this.name = "TimerTrace";
175
162
  }
176
163
  }
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
164
  export {
284
- when,
285
165
  wait,
166
+ timer,
286
167
  repeat,
287
- isWhen,
288
- isWaited,
289
- isTimer,
290
- isRepeated,
291
- delay
168
+ Timer,
169
+ BasicTimer
292
170
  };
package/dist/timer.mjs CHANGED
@@ -1,40 +1,79 @@
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
- });
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
- when,
33
- wait2 as wait,
74
+ wait,
75
+ timer,
34
76
  repeat,
35
- isWhen,
36
- isWaited,
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
@@ -20,36 +20,35 @@
20
20
  "bun": "./src/index.ts",
21
21
  "import": {
22
22
  "types": "./types/index.d.ts",
23
- "default": "./dist/timer.mjs"
23
+ "default": "./dist/index.mjs"
24
24
  },
25
25
  "require": {
26
26
  "types": "./types/index.d.cts",
27
- "default": "./dist/timer.js"
27
+ "default": "./dist/index.js"
28
28
  }
29
29
  }
30
30
  },
31
31
  "files": ["dist", "src", "types"],
32
32
  "keywords": ["timer", "setTimeout", "setInterval", "requestAnimationFrame"],
33
33
  "license": "MIT",
34
- "main": "dist/timer.js",
35
- "module": "dist/timer.mjs",
34
+ "main": "dist/index.js",
35
+ "module": "dist/index.mjs",
36
36
  "name": "@oscarpalmer/timer",
37
37
  "repository": {
38
38
  "type": "git",
39
39
  "url": "git+https://github.com/oscarpalmer/timer.git"
40
40
  },
41
41
  "scripts": {
42
- "build": "bun run clean && bun run build:cjs && bun run build:esm && bun run types",
43
- "build:cjs": "bun build ./src/index.ts --outfile ./dist/timer.js",
44
- "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",
45
44
  "clean": "rm -rf ./dist && rm -rf ./types && rm -f ./tsconfig.tsbuildinfo",
46
45
  "test": "bun test",
47
46
  "types": "bun run types:cjs && bun run types:esm",
48
47
  "types:cjs": "bunx dts-bundle-generator --out-file ./types/index.d.cts --external-inlines '@oscarpalmer/atoms' --no-check --silent ./src/index.ts",
49
48
  "types:esm": "bunx tsc -p ./tsconfig.json",
50
- "watch": "bun build ./src/index.ts --outfile ./dist/timer.js --watch"
49
+ "watch": "bun build ./src/index.ts --outfile ./dist/index.js --watch"
51
50
  },
52
51
  "type": "module",
53
52
  "types": "types/index.d.cts",
54
- "version": "0.21.1"
53
+ "version": "0.22.1"
55
54
  }