@oscarpalmer/timer 0.12.0 → 0.13.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 +14 -0
- package/dist/timer.cjs +76 -70
- package/dist/timer.iife.js +1 -2
- package/dist/timer.js +85 -69
- package/package.json +8 -14
- package/src/index.d.ts +29 -1
- package/src/index.js +193 -0
- package/dist/timer.cjs.map +0 -7
- package/dist/timer.iife.js.map +0 -7
- package/dist/timer.js.map +0 -7
- package/src/index.ts +0 -197
package/README.md
CHANGED
|
@@ -60,6 +60,20 @@ Both the nice helper methods and the class syntax create similar objects – `Wa
|
|
|
60
60
|
|`stop()`|Stops the timer|
|
|
61
61
|
|`restart()`|Restarts the timer|
|
|
62
62
|
|
|
63
|
+
## Callbacks
|
|
64
|
+
|
|
65
|
+
When you create a repeated timer, you can also provide a fourth parameter to act as a callback to run when the timer stops, as below:
|
|
66
|
+
|
|
67
|
+
```typescript
|
|
68
|
+
function after(finished: boolean) {
|
|
69
|
+
// Let's do something fun!
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
repeat(() => {}, 0, 10, after);
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
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.
|
|
76
|
+
|
|
63
77
|
## License
|
|
64
78
|
|
|
65
79
|
[MIT licensed](LICENSE), natch :wink:
|
package/dist/timer.cjs
CHANGED
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
"use strict";
|
|
2
1
|
var __defProp = Object.defineProperty;
|
|
3
2
|
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
4
3
|
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
@@ -22,7 +21,7 @@ var __publicField = (obj, key, value) => {
|
|
|
22
21
|
return value;
|
|
23
22
|
};
|
|
24
23
|
|
|
25
|
-
// src/index.
|
|
24
|
+
// src/index.js
|
|
26
25
|
var src_exports = {};
|
|
27
26
|
__export(src_exports, {
|
|
28
27
|
Repeated: () => Repeated,
|
|
@@ -32,111 +31,115 @@ __export(src_exports, {
|
|
|
32
31
|
});
|
|
33
32
|
module.exports = __toCommonJS(src_exports);
|
|
34
33
|
var milliseconds = Math.round(1e3 / 60);
|
|
35
|
-
var request = requestAnimationFrame
|
|
36
|
-
|
|
37
|
-
return (_a = setTimeout == null ? void 0 : setTimeout(() => {
|
|
34
|
+
var request = globalThis.requestAnimationFrame ?? function(callback) {
|
|
35
|
+
return setTimeout?.(() => {
|
|
38
36
|
callback(Date.now());
|
|
39
|
-
}, milliseconds)
|
|
37
|
+
}, milliseconds);
|
|
40
38
|
};
|
|
39
|
+
function run(timed) {
|
|
40
|
+
timed.state.active = true;
|
|
41
|
+
timed.state.finished = false;
|
|
42
|
+
const isRepeated = timed instanceof Repeated;
|
|
43
|
+
let count = 0;
|
|
44
|
+
let start;
|
|
45
|
+
function step(timestamp) {
|
|
46
|
+
if (!timed.state.active) {
|
|
47
|
+
return;
|
|
48
|
+
}
|
|
49
|
+
start ?? (start = timestamp);
|
|
50
|
+
const elapsed = timestamp - start;
|
|
51
|
+
const elapsedMinimum = elapsed - milliseconds;
|
|
52
|
+
const elapsedMaximum = elapsed + milliseconds;
|
|
53
|
+
if (elapsedMinimum < timed.configuration.time && timed.configuration.time < elapsedMaximum) {
|
|
54
|
+
if (timed.state.active) {
|
|
55
|
+
timed.callbacks.default(isRepeated ? count : void 0);
|
|
56
|
+
}
|
|
57
|
+
count += 1;
|
|
58
|
+
if (isRepeated && count < timed.configuration.count) {
|
|
59
|
+
start = void 0;
|
|
60
|
+
} else {
|
|
61
|
+
timed.state.finished = true;
|
|
62
|
+
timed.stop();
|
|
63
|
+
return;
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
timed.state.frame = request(step);
|
|
67
|
+
}
|
|
68
|
+
timed.state.frame = request(step);
|
|
69
|
+
}
|
|
41
70
|
var Timed = class {
|
|
71
|
+
/**
|
|
72
|
+
* @param {Function} callback
|
|
73
|
+
* @param {number} time
|
|
74
|
+
* @param {number} count
|
|
75
|
+
* @param {Function?} afterCallback
|
|
76
|
+
*/
|
|
42
77
|
constructor(callback, time, count, afterCallback) {
|
|
78
|
+
/**
|
|
79
|
+
* @readonly
|
|
80
|
+
* @type {{after?: Function; default: Function}}
|
|
81
|
+
*/
|
|
43
82
|
__publicField(this, "callbacks");
|
|
83
|
+
/**
|
|
84
|
+
* @readonly
|
|
85
|
+
* @type {{count: number; time: number}}
|
|
86
|
+
*/
|
|
44
87
|
__publicField(this, "configuration");
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
88
|
+
/**
|
|
89
|
+
* @readonly
|
|
90
|
+
* @type {{active: boolean; finished: boolean; frame?: DOMHighResTimeStamp}}
|
|
91
|
+
*/
|
|
92
|
+
__publicField(this, "state");
|
|
49
93
|
const isRepeated = this instanceof Repeated;
|
|
50
94
|
const type = isRepeated ? "repeated" : "waited";
|
|
51
95
|
if (typeof callback !== "function") {
|
|
52
|
-
throw new
|
|
96
|
+
throw new TypeError(`A ${type} timer must have a callback function`);
|
|
53
97
|
}
|
|
54
98
|
if (typeof time !== "number" || time < 0) {
|
|
55
|
-
throw new
|
|
99
|
+
throw new TypeError(`A ${type} timer must have a non-negative number as its time`);
|
|
56
100
|
}
|
|
57
101
|
if (isRepeated && (typeof count !== "number" || count < 2)) {
|
|
58
|
-
throw new
|
|
102
|
+
throw new TypeError("A repeated timer must have a number above 1 as its repeat count");
|
|
59
103
|
}
|
|
60
|
-
if (isRepeated && afterCallback
|
|
61
|
-
throw new
|
|
104
|
+
if (isRepeated && afterCallback !== void 0 && typeof afterCallback !== "function") {
|
|
105
|
+
throw new TypeError("A repeated timer's after-callback must be a function");
|
|
62
106
|
}
|
|
63
107
|
this.configuration = { count, time };
|
|
64
108
|
this.callbacks = {
|
|
65
109
|
after: afterCallback,
|
|
66
110
|
default: callback
|
|
67
111
|
};
|
|
112
|
+
this.state = {
|
|
113
|
+
active: false,
|
|
114
|
+
finished: false,
|
|
115
|
+
frame: null
|
|
116
|
+
};
|
|
68
117
|
}
|
|
69
|
-
/**
|
|
70
|
-
* Is the timer active?
|
|
71
|
-
*/
|
|
118
|
+
/** */
|
|
72
119
|
get active() {
|
|
73
120
|
return this.state.active;
|
|
74
121
|
}
|
|
75
|
-
/**
|
|
76
|
-
* Has the timer finished?
|
|
77
|
-
*/
|
|
78
122
|
get finished() {
|
|
79
|
-
return !this.
|
|
80
|
-
}
|
|
81
|
-
static run(timed) {
|
|
82
|
-
timed.state.active = true;
|
|
83
|
-
timed.state.finished = false;
|
|
84
|
-
const isRepeated = timed instanceof Repeated;
|
|
85
|
-
let count = 0;
|
|
86
|
-
let start;
|
|
87
|
-
function step(timestamp) {
|
|
88
|
-
if (!timed.state.active) {
|
|
89
|
-
return;
|
|
90
|
-
}
|
|
91
|
-
start != null ? start : start = timestamp;
|
|
92
|
-
const elapsed = timestamp - start;
|
|
93
|
-
const elapsedMinimum = elapsed - milliseconds;
|
|
94
|
-
const elapsedMaximum = elapsed + milliseconds;
|
|
95
|
-
if (elapsedMinimum < timed.configuration.time && timed.configuration.time < elapsedMaximum) {
|
|
96
|
-
if (timed.state.active) {
|
|
97
|
-
timed.callbacks.default(isRepeated ? count : void 0);
|
|
98
|
-
}
|
|
99
|
-
count += 1;
|
|
100
|
-
if (isRepeated && count < timed.configuration.count) {
|
|
101
|
-
start = void 0;
|
|
102
|
-
} else {
|
|
103
|
-
timed.state.finished = true;
|
|
104
|
-
timed.stop();
|
|
105
|
-
return;
|
|
106
|
-
}
|
|
107
|
-
}
|
|
108
|
-
timed.state.frame = request(step);
|
|
109
|
-
}
|
|
110
|
-
timed.state.frame = request(step);
|
|
123
|
+
return !this.active && this.state.finished;
|
|
111
124
|
}
|
|
112
|
-
/**
|
|
113
|
-
* Restart timer
|
|
114
|
-
*/
|
|
115
125
|
restart() {
|
|
116
126
|
this.stop();
|
|
117
|
-
|
|
127
|
+
run(this);
|
|
118
128
|
return this;
|
|
119
129
|
}
|
|
120
|
-
/**
|
|
121
|
-
* Start timer
|
|
122
|
-
*/
|
|
123
130
|
start() {
|
|
124
131
|
if (!this.state.active) {
|
|
125
|
-
|
|
132
|
+
run(this);
|
|
126
133
|
}
|
|
127
134
|
return this;
|
|
128
135
|
}
|
|
129
|
-
/**
|
|
130
|
-
* Stop timer
|
|
131
|
-
*/
|
|
132
136
|
stop() {
|
|
133
|
-
var _a, _b, _c;
|
|
134
137
|
this.state.active = false;
|
|
135
|
-
if (
|
|
138
|
+
if (this.state.frame === void 0) {
|
|
136
139
|
return this;
|
|
137
140
|
}
|
|
138
|
-
(
|
|
139
|
-
|
|
141
|
+
(globalThis.cancelAnimationFrame ?? clearTimeout)?.(this.state.frame);
|
|
142
|
+
this.callbacks.after?.(this.finished);
|
|
140
143
|
this.state.frame = void 0;
|
|
141
144
|
return this;
|
|
142
145
|
}
|
|
@@ -144,8 +147,12 @@ var Timed = class {
|
|
|
144
147
|
var Repeated = class extends Timed {
|
|
145
148
|
};
|
|
146
149
|
var Waited = class extends Timed {
|
|
150
|
+
/**
|
|
151
|
+
* @param {Function} callback
|
|
152
|
+
* @param {number} time
|
|
153
|
+
*/
|
|
147
154
|
constructor(callback, time) {
|
|
148
|
-
super(callback, time, 1);
|
|
155
|
+
super(callback, time, 1, null);
|
|
149
156
|
}
|
|
150
157
|
};
|
|
151
158
|
function repeat(callback, time, count, afterCallback) {
|
|
@@ -154,4 +161,3 @@ function repeat(callback, time, count, afterCallback) {
|
|
|
154
161
|
function wait(callback, time) {
|
|
155
162
|
return new Waited(callback, time).start();
|
|
156
163
|
}
|
|
157
|
-
//# sourceMappingURL=timer.cjs.map
|
package/dist/timer.iife.js
CHANGED
|
@@ -1,2 +1 @@
|
|
|
1
|
-
|
|
2
|
-
//# sourceMappingURL=timer.iife.js.map
|
|
1
|
+
var Timer=(()=>{var u=Object.defineProperty;var w=Object.getOwnPropertyDescriptor;var b=Object.getOwnPropertyNames;var g=Object.prototype.hasOwnProperty;var y=(t,e,s)=>e in t?u(t,e,{enumerable:!0,configurable:!0,writable:!0,value:s}):t[e]=s;var x=(t,e)=>{for(var s in e)u(t,s,{get:e[s],enumerable:!0})},T=(t,e,s,n)=>{if(e&&typeof e=="object"||typeof e=="function")for(let a of b(e))!g.call(t,a)&&a!==s&&u(t,a,{get:()=>e[a],enumerable:!(n=w(e,a))||n.enumerable});return t};var A=t=>T(u({},"__esModule",{value:!0}),t);var f=(t,e,s)=>(y(t,typeof e!="symbol"?e+"":e,s),s);var M={};x(M,{Repeated:()=>r,Waited:()=>h,repeat:()=>E,wait:()=>k});var l=Math.round(16.666666666666668),p=globalThis.requestAnimationFrame??function(t){return setTimeout?.(()=>{t(Date.now())},l)};function d(t){t.state.active=!0,t.state.finished=!1;let e=t instanceof r,s=0,n;function a(i){if(!t.state.active)return;n??(n=i);let o=i-n,m=o-l,v=o+l;if(m<t.configuration.time&&t.configuration.time<v)if(t.state.active&&t.callbacks.default(e?s:void 0),s+=1,e&&s<t.configuration.count)n=void 0;else{t.state.finished=!0,t.stop();return}t.state.frame=p(a)}t.state.frame=p(a)}var c=class{constructor(e,s,n,a){f(this,"callbacks");f(this,"configuration");f(this,"state");let i=this instanceof r,o=i?"repeated":"waited";if(typeof e!="function")throw new TypeError(`A ${o} timer must have a callback function`);if(typeof s!="number"||s<0)throw new TypeError(`A ${o} timer must have a non-negative number as its time`);if(i&&(typeof n!="number"||n<2))throw new TypeError("A repeated timer must have a number above 1 as its repeat count");if(i&&a!==void 0&&typeof a!="function")throw new TypeError("A repeated timer's after-callback must be a function");this.configuration={count:n,time:s},this.callbacks={after:a,default:e},this.state={active:!1,finished:!1,frame:null}}get active(){return this.state.active}get finished(){return!this.active&&this.state.finished}restart(){return this.stop(),d(this),this}start(){return this.state.active||d(this),this}stop(){return this.state.active=!1,this.state.frame===void 0?this:((globalThis.cancelAnimationFrame??clearTimeout)?.(this.state.frame),this.callbacks.after?.(this.finished),this.state.frame=void 0,this)}},r=class extends c{},h=class extends c{constructor(e,s){super(e,s,1,null)}};function E(t,e,s,n){return new r(t,e,s,n).start()}function k(t,e){return new h(t,e).start()}return A(M);})();
|
package/dist/timer.js
CHANGED
|
@@ -1,107 +1,120 @@
|
|
|
1
|
-
|
|
1
|
+
var __defProp = Object.defineProperty;
|
|
2
|
+
var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
|
|
3
|
+
var __publicField = (obj, key, value) => {
|
|
4
|
+
__defNormalProp(obj, typeof key !== "symbol" ? key + "" : key, value);
|
|
5
|
+
return value;
|
|
6
|
+
};
|
|
7
|
+
|
|
8
|
+
// src/index.js
|
|
2
9
|
var milliseconds = Math.round(1e3 / 60);
|
|
3
|
-
var request = requestAnimationFrame ?? function(callback) {
|
|
10
|
+
var request = globalThis.requestAnimationFrame ?? function(callback) {
|
|
4
11
|
return setTimeout?.(() => {
|
|
5
12
|
callback(Date.now());
|
|
6
|
-
}, milliseconds)
|
|
13
|
+
}, milliseconds);
|
|
7
14
|
};
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
15
|
+
function run(timed) {
|
|
16
|
+
timed.state.active = true;
|
|
17
|
+
timed.state.finished = false;
|
|
18
|
+
const isRepeated = timed instanceof Repeated;
|
|
19
|
+
let count = 0;
|
|
20
|
+
let start;
|
|
21
|
+
function step(timestamp) {
|
|
22
|
+
if (!timed.state.active) {
|
|
23
|
+
return;
|
|
24
|
+
}
|
|
25
|
+
start ?? (start = timestamp);
|
|
26
|
+
const elapsed = timestamp - start;
|
|
27
|
+
const elapsedMinimum = elapsed - milliseconds;
|
|
28
|
+
const elapsedMaximum = elapsed + milliseconds;
|
|
29
|
+
if (elapsedMinimum < timed.configuration.time && timed.configuration.time < elapsedMaximum) {
|
|
30
|
+
if (timed.state.active) {
|
|
31
|
+
timed.callbacks.default(isRepeated ? count : void 0);
|
|
32
|
+
}
|
|
33
|
+
count += 1;
|
|
34
|
+
if (isRepeated && count < timed.configuration.count) {
|
|
35
|
+
start = void 0;
|
|
36
|
+
} else {
|
|
37
|
+
timed.state.finished = true;
|
|
38
|
+
timed.stop();
|
|
39
|
+
return;
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
timed.state.frame = request(step);
|
|
20
43
|
}
|
|
44
|
+
timed.state.frame = request(step);
|
|
45
|
+
}
|
|
46
|
+
var Timed = class {
|
|
21
47
|
/**
|
|
22
|
-
*
|
|
48
|
+
* @param {Function} callback
|
|
49
|
+
* @param {number} time
|
|
50
|
+
* @param {number} count
|
|
51
|
+
* @param {Function?} afterCallback
|
|
23
52
|
*/
|
|
24
|
-
get finished() {
|
|
25
|
-
return !this.state.active && this.state.finished;
|
|
26
|
-
}
|
|
27
53
|
constructor(callback, time, count, afterCallback) {
|
|
54
|
+
/**
|
|
55
|
+
* @readonly
|
|
56
|
+
* @type {{after?: Function; default: Function}}
|
|
57
|
+
*/
|
|
58
|
+
__publicField(this, "callbacks");
|
|
59
|
+
/**
|
|
60
|
+
* @readonly
|
|
61
|
+
* @type {{count: number; time: number}}
|
|
62
|
+
*/
|
|
63
|
+
__publicField(this, "configuration");
|
|
64
|
+
/**
|
|
65
|
+
* @readonly
|
|
66
|
+
* @type {{active: boolean; finished: boolean; frame?: DOMHighResTimeStamp}}
|
|
67
|
+
*/
|
|
68
|
+
__publicField(this, "state");
|
|
28
69
|
const isRepeated = this instanceof Repeated;
|
|
29
70
|
const type = isRepeated ? "repeated" : "waited";
|
|
30
71
|
if (typeof callback !== "function") {
|
|
31
|
-
throw new
|
|
72
|
+
throw new TypeError(`A ${type} timer must have a callback function`);
|
|
32
73
|
}
|
|
33
74
|
if (typeof time !== "number" || time < 0) {
|
|
34
|
-
throw new
|
|
75
|
+
throw new TypeError(`A ${type} timer must have a non-negative number as its time`);
|
|
35
76
|
}
|
|
36
77
|
if (isRepeated && (typeof count !== "number" || count < 2)) {
|
|
37
|
-
throw new
|
|
78
|
+
throw new TypeError("A repeated timer must have a number above 1 as its repeat count");
|
|
38
79
|
}
|
|
39
|
-
if (isRepeated && afterCallback
|
|
40
|
-
throw new
|
|
80
|
+
if (isRepeated && afterCallback !== void 0 && typeof afterCallback !== "function") {
|
|
81
|
+
throw new TypeError("A repeated timer's after-callback must be a function");
|
|
41
82
|
}
|
|
42
83
|
this.configuration = { count, time };
|
|
43
84
|
this.callbacks = {
|
|
44
85
|
after: afterCallback,
|
|
45
86
|
default: callback
|
|
46
87
|
};
|
|
88
|
+
this.state = {
|
|
89
|
+
active: false,
|
|
90
|
+
finished: false,
|
|
91
|
+
frame: null
|
|
92
|
+
};
|
|
47
93
|
}
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
function step(timestamp) {
|
|
55
|
-
if (!timed.state.active) {
|
|
56
|
-
return;
|
|
57
|
-
}
|
|
58
|
-
start ??= timestamp;
|
|
59
|
-
const elapsed = timestamp - start;
|
|
60
|
-
const elapsedMinimum = elapsed - milliseconds;
|
|
61
|
-
const elapsedMaximum = elapsed + milliseconds;
|
|
62
|
-
if (elapsedMinimum < timed.configuration.time && timed.configuration.time < elapsedMaximum) {
|
|
63
|
-
if (timed.state.active) {
|
|
64
|
-
timed.callbacks.default(isRepeated ? count : void 0);
|
|
65
|
-
}
|
|
66
|
-
count += 1;
|
|
67
|
-
if (isRepeated && count < timed.configuration.count) {
|
|
68
|
-
start = void 0;
|
|
69
|
-
} else {
|
|
70
|
-
timed.state.finished = true;
|
|
71
|
-
timed.stop();
|
|
72
|
-
return;
|
|
73
|
-
}
|
|
74
|
-
}
|
|
75
|
-
timed.state.frame = request(step);
|
|
76
|
-
}
|
|
77
|
-
timed.state.frame = request(step);
|
|
94
|
+
/** */
|
|
95
|
+
get active() {
|
|
96
|
+
return this.state.active;
|
|
97
|
+
}
|
|
98
|
+
get finished() {
|
|
99
|
+
return !this.active && this.state.finished;
|
|
78
100
|
}
|
|
79
|
-
/**
|
|
80
|
-
* Restart timer
|
|
81
|
-
*/
|
|
82
101
|
restart() {
|
|
83
102
|
this.stop();
|
|
84
|
-
|
|
103
|
+
run(this);
|
|
85
104
|
return this;
|
|
86
105
|
}
|
|
87
|
-
/**
|
|
88
|
-
* Start timer
|
|
89
|
-
*/
|
|
90
106
|
start() {
|
|
91
107
|
if (!this.state.active) {
|
|
92
|
-
|
|
108
|
+
run(this);
|
|
93
109
|
}
|
|
94
110
|
return this;
|
|
95
111
|
}
|
|
96
|
-
/**
|
|
97
|
-
* Stop timer
|
|
98
|
-
*/
|
|
99
112
|
stop() {
|
|
100
113
|
this.state.active = false;
|
|
101
|
-
if (
|
|
114
|
+
if (this.state.frame === void 0) {
|
|
102
115
|
return this;
|
|
103
116
|
}
|
|
104
|
-
(cancelAnimationFrame ?? clearTimeout)?.(this.state.frame);
|
|
117
|
+
(globalThis.cancelAnimationFrame ?? clearTimeout)?.(this.state.frame);
|
|
105
118
|
this.callbacks.after?.(this.finished);
|
|
106
119
|
this.state.frame = void 0;
|
|
107
120
|
return this;
|
|
@@ -110,8 +123,12 @@ var Timed = class {
|
|
|
110
123
|
var Repeated = class extends Timed {
|
|
111
124
|
};
|
|
112
125
|
var Waited = class extends Timed {
|
|
126
|
+
/**
|
|
127
|
+
* @param {Function} callback
|
|
128
|
+
* @param {number} time
|
|
129
|
+
*/
|
|
113
130
|
constructor(callback, time) {
|
|
114
|
-
super(callback, time, 1);
|
|
131
|
+
super(callback, time, 1, null);
|
|
115
132
|
}
|
|
116
133
|
};
|
|
117
134
|
function repeat(callback, time, count, afterCallback) {
|
|
@@ -126,4 +143,3 @@ export {
|
|
|
126
143
|
repeat,
|
|
127
144
|
wait
|
|
128
145
|
};
|
|
129
|
-
//# sourceMappingURL=timer.js.map
|
package/package.json
CHANGED
|
@@ -6,15 +6,9 @@
|
|
|
6
6
|
"browser": "dist/timer.iife.js",
|
|
7
7
|
"description": "A better solution for timeout- and interval-based timers.",
|
|
8
8
|
"devDependencies": {
|
|
9
|
-
"@tsconfig/recommended": "^1.0",
|
|
10
|
-
"@types/node": "^18.15",
|
|
11
|
-
"@typescript-eslint/eslint-plugin": "^5.57",
|
|
12
|
-
"@typescript-eslint/parser": "^5.57",
|
|
13
9
|
"esbuild": "^0.17",
|
|
14
|
-
"
|
|
15
|
-
"
|
|
16
|
-
"eslint-config-xo-typescript": "^0.57",
|
|
17
|
-
"typescript": "^5.0"
|
|
10
|
+
"typescript": "^5.0",
|
|
11
|
+
"xo": "^0.54"
|
|
18
12
|
},
|
|
19
13
|
"exports": {
|
|
20
14
|
".": {
|
|
@@ -43,14 +37,14 @@
|
|
|
43
37
|
"url": "git+https://github.com/oscarpalmer/timer.git"
|
|
44
38
|
},
|
|
45
39
|
"scripts": {
|
|
46
|
-
"build": "npm run build:cjs; npm run build:esm; npm run build:iife",
|
|
47
|
-
"build:cjs": "esbuild ./src/index.
|
|
48
|
-
"build:esm": "esbuild ./src/index.
|
|
49
|
-
"build:iife": "esbuild ./src/index.
|
|
50
|
-
"
|
|
40
|
+
"build": "npm run build:cjs; npm run build:esm; npm run build:iife; npm run types",
|
|
41
|
+
"build:cjs": "esbuild ./src/index.js --bundle --format=cjs --outfile=./dist/timer.cjs --target=es2020",
|
|
42
|
+
"build:esm": "esbuild ./src/index.js --bundle --format=esm --outfile=./dist/timer.js --target=es2020",
|
|
43
|
+
"build:iife": "esbuild ./src/index.js --bundle --minify --format=iife --global-name=Timer --outfile=./dist/timer.iife.js --target=es2020",
|
|
44
|
+
"types": "./node_modules/.bin/tsc ./src/index.js --allowJs --declaration --emitDeclarationOnly --removeComments"
|
|
51
45
|
},
|
|
52
46
|
"type": "module",
|
|
53
47
|
"types": "src/index.d.ts",
|
|
54
48
|
"unpkg": "dist/timer.iife.js",
|
|
55
|
-
"version": "0.
|
|
49
|
+
"version": "0.13.0"
|
|
56
50
|
}
|
package/src/index.d.ts
CHANGED
|
@@ -1 +1,29 @@
|
|
|
1
|
-
export
|
|
1
|
+
export function repeat(callback: Function, time: number, count: number, afterCallback: Function | null): Repeated;
|
|
2
|
+
export function wait(callback: Function, time: number): Waited;
|
|
3
|
+
export class Repeated extends Timed {
|
|
4
|
+
}
|
|
5
|
+
export class Waited extends Timed {
|
|
6
|
+
constructor(callback: Function, time: number);
|
|
7
|
+
}
|
|
8
|
+
declare class Timed {
|
|
9
|
+
constructor(callback: Function, time: number, count: number, afterCallback: Function | null);
|
|
10
|
+
readonly callbacks: {
|
|
11
|
+
after?: Function;
|
|
12
|
+
default: Function;
|
|
13
|
+
};
|
|
14
|
+
readonly configuration: {
|
|
15
|
+
count: number;
|
|
16
|
+
time: number;
|
|
17
|
+
};
|
|
18
|
+
readonly state: {
|
|
19
|
+
active: boolean;
|
|
20
|
+
finished: boolean;
|
|
21
|
+
frame?: DOMHighResTimeStamp;
|
|
22
|
+
};
|
|
23
|
+
get active(): boolean;
|
|
24
|
+
get finished(): boolean;
|
|
25
|
+
restart(): Timed;
|
|
26
|
+
start(): Timed;
|
|
27
|
+
stop(): Timed;
|
|
28
|
+
}
|
|
29
|
+
export {};
|
package/src/index.js
ADDED
|
@@ -0,0 +1,193 @@
|
|
|
1
|
+
const milliseconds = Math.round(1000 / 60);
|
|
2
|
+
|
|
3
|
+
const request = globalThis.requestAnimationFrame ?? function (callback) {
|
|
4
|
+
return setTimeout?.(() => {
|
|
5
|
+
callback(Date.now());
|
|
6
|
+
}, milliseconds);
|
|
7
|
+
};
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* @param {Timed} timed
|
|
11
|
+
*/
|
|
12
|
+
function run(timed) {
|
|
13
|
+
timed.state.active = true;
|
|
14
|
+
timed.state.finished = false;
|
|
15
|
+
|
|
16
|
+
const isRepeated = timed instanceof Repeated;
|
|
17
|
+
|
|
18
|
+
let count = 0;
|
|
19
|
+
|
|
20
|
+
let start;
|
|
21
|
+
|
|
22
|
+
function step(timestamp) {
|
|
23
|
+
if (!timed.state.active) {
|
|
24
|
+
return;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
start ??= timestamp;
|
|
28
|
+
|
|
29
|
+
const elapsed = timestamp - start;
|
|
30
|
+
|
|
31
|
+
const elapsedMinimum = elapsed - milliseconds;
|
|
32
|
+
const elapsedMaximum = elapsed + milliseconds;
|
|
33
|
+
|
|
34
|
+
if (elapsedMinimum < timed.configuration.time && timed.configuration.time < elapsedMaximum) {
|
|
35
|
+
if (timed.state.active) {
|
|
36
|
+
timed.callbacks.default(isRepeated ? count : undefined);
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
count += 1;
|
|
40
|
+
|
|
41
|
+
if (isRepeated && count < timed.configuration.count) {
|
|
42
|
+
start = undefined;
|
|
43
|
+
} else {
|
|
44
|
+
timed.state.finished = true;
|
|
45
|
+
|
|
46
|
+
timed.stop();
|
|
47
|
+
|
|
48
|
+
return;
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
timed.state.frame = request(step);
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
timed.state.frame = request(step);
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
class Timed {
|
|
59
|
+
/**
|
|
60
|
+
* @readonly
|
|
61
|
+
* @type {{after?: Function; default: Function}}
|
|
62
|
+
*/
|
|
63
|
+
callbacks;
|
|
64
|
+
|
|
65
|
+
/**
|
|
66
|
+
* @readonly
|
|
67
|
+
* @type {{count: number; time: number}}
|
|
68
|
+
*/
|
|
69
|
+
configuration;
|
|
70
|
+
|
|
71
|
+
/**
|
|
72
|
+
* @readonly
|
|
73
|
+
* @type {{active: boolean; finished: boolean; frame?: DOMHighResTimeStamp}}
|
|
74
|
+
*/
|
|
75
|
+
state;
|
|
76
|
+
|
|
77
|
+
/** */
|
|
78
|
+
|
|
79
|
+
get active() {
|
|
80
|
+
return this.state.active;
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
get finished() {
|
|
84
|
+
return !this.active && this.state.finished;
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
/**
|
|
88
|
+
* @param {Function} callback
|
|
89
|
+
* @param {number} time
|
|
90
|
+
* @param {number} count
|
|
91
|
+
* @param {Function?} afterCallback
|
|
92
|
+
*/
|
|
93
|
+
constructor(callback, time, count, afterCallback) {
|
|
94
|
+
const isRepeated = this instanceof Repeated;
|
|
95
|
+
|
|
96
|
+
const type = isRepeated
|
|
97
|
+
? 'repeated'
|
|
98
|
+
: 'waited';
|
|
99
|
+
|
|
100
|
+
if (typeof callback !== 'function') {
|
|
101
|
+
throw new TypeError(`A ${type} timer must have a callback function`);
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
if (typeof time !== 'number' || time < 0) {
|
|
105
|
+
throw new TypeError(`A ${type} timer must have a non-negative number as its time`);
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
if (isRepeated && (typeof count !== 'number' || count < 2)) {
|
|
109
|
+
throw new TypeError('A repeated timer must have a number above 1 as its repeat count');
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
if (isRepeated && afterCallback !== undefined && typeof afterCallback !== 'function') {
|
|
113
|
+
throw new TypeError('A repeated timer\'s after-callback must be a function');
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
this.configuration = {count, time};
|
|
117
|
+
|
|
118
|
+
this.callbacks = {
|
|
119
|
+
after: afterCallback,
|
|
120
|
+
default: callback,
|
|
121
|
+
};
|
|
122
|
+
|
|
123
|
+
this.state = {
|
|
124
|
+
active: false,
|
|
125
|
+
finished: false,
|
|
126
|
+
frame: null,
|
|
127
|
+
};
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
restart() {
|
|
131
|
+
this.stop();
|
|
132
|
+
|
|
133
|
+
run(this);
|
|
134
|
+
|
|
135
|
+
return this;
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
start() {
|
|
139
|
+
if (!this.state.active) {
|
|
140
|
+
run(this);
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
return this;
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
stop() {
|
|
147
|
+
this.state.active = false;
|
|
148
|
+
|
|
149
|
+
if (this.state.frame === undefined) {
|
|
150
|
+
return this;
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
(globalThis.cancelAnimationFrame ?? clearTimeout)?.(this.state.frame);
|
|
154
|
+
|
|
155
|
+
this.callbacks.after?.(this.finished);
|
|
156
|
+
|
|
157
|
+
this.state.frame = undefined;
|
|
158
|
+
|
|
159
|
+
return this;
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
export class Repeated extends Timed {}
|
|
164
|
+
|
|
165
|
+
export class Waited extends Timed {
|
|
166
|
+
/**
|
|
167
|
+
* @param {Function} callback
|
|
168
|
+
* @param {number} time
|
|
169
|
+
*/
|
|
170
|
+
constructor(callback, time) {
|
|
171
|
+
super(callback, time, 1, null);
|
|
172
|
+
}
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
/**
|
|
176
|
+
* @param {Function} callback
|
|
177
|
+
* @param {number} time
|
|
178
|
+
* @param {number} count
|
|
179
|
+
* @param {Function?} afterCallback
|
|
180
|
+
* @return {Repeated} A repeated timer
|
|
181
|
+
*/
|
|
182
|
+
export function repeat(callback, time, count, afterCallback) {
|
|
183
|
+
return (new Repeated(callback, time, count, afterCallback)).start();
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
/**
|
|
187
|
+
* @param {Function} callback
|
|
188
|
+
* @param {number} time
|
|
189
|
+
* @return {Waited} A waited timer
|
|
190
|
+
*/
|
|
191
|
+
export function wait(callback, time) {
|
|
192
|
+
return (new Waited(callback, time)).start();
|
|
193
|
+
}
|
package/dist/timer.cjs.map
DELETED
|
@@ -1,7 +0,0 @@
|
|
|
1
|
-
{
|
|
2
|
-
"version": 3,
|
|
3
|
-
"sources": ["../src/index.ts"],
|
|
4
|
-
"sourcesContent": ["type AfterCallback = (finished: boolean) => void;\ntype RepeatedCallback = (index: number) => void;\ntype WaitedCallback = () => void;\n\ntype Callbacks<Callback> = {\n\tafter?: AfterCallback;\n\tdefault: Callback;\n};\n\ntype Configuration = {\n\tcount: number;\n\ttime: number;\n};\n\ntype State = {\n\tactive: boolean;\n\tfinished: boolean;\n\tframe?: number;\n};\n\nconst milliseconds = Math.round(1000 / 60);\n\nconst request = requestAnimationFrame ?? function (callback: FrameRequestCallback): number {\n\treturn (setTimeout?.(() => {\n\t\tcallback(Date.now());\n\t}, milliseconds) ?? -1) as unknown as number;\n};\n\nabstract class Timed<Callback> {\n\treadonly callbacks!: Callbacks<Callback>;\n\treadonly configuration!: Configuration;\n\n\treadonly state: State = {\n\t\tactive: false,\n\t\tfinished: false,\n\t};\n\n\t/**\n\t * Is the timer active?\n\t */\n\tget active(): boolean {\n\t\treturn this.state.active;\n\t}\n\n\t/**\n\t * Has the timer finished?\n\t */\n get finished(): boolean {\n\t\treturn !this.state.active && this.state.finished;\n\t}\n\n\tconstructor(callback: Callback, time: number,\tcount: number, afterCallback?: AfterCallback) {\n\t\tconst isRepeated = this instanceof Repeated;\n\n\t\tconst type = isRepeated\n\t\t? 'repeated'\n\t\t: 'waited';\n\n\t\tif (typeof callback !== 'function') {\n\t\t\tthrow new Error(`A ${type} timer must have a callback function`);\n\t\t}\n\n\t\tif (typeof time !== 'number' || time < 0) {\n\t\t\tthrow new Error(`A ${type} timer must have a non-negative number as its time`);\n\t\t}\n\n\t\tif (isRepeated && (typeof count !== 'number' || count < 2)) {\n\t\t\tthrow new Error('A repeated timer must have a number above 1 as its repeat count');\n\t\t}\n\n\t\tif (isRepeated && afterCallback != null && typeof afterCallback !== 'function') {\n\t\t\tthrow new Error('A repeated timer\\'s after-callback must be a function');\n\t\t}\n\n\t\tthis.configuration = {count, time};\n\n\t\tthis.callbacks = {\n\t\t\tafter: afterCallback,\n\t\t\tdefault: callback,\n\t\t};\n\t}\n\n\tprivate static run(timed: Timed<(index: number | undefined) => void>): void {\n\t\ttimed.state.active = true;\n\t\ttimed.state.finished = false;\n\n\t\tconst isRepeated = timed instanceof Repeated;\n\n\t\tlet count = 0;\n\n\t\tlet start: DOMHighResTimeStamp | undefined;\n\n\t\tfunction step(timestamp: DOMHighResTimeStamp): void {\n\t\t\tif (!timed.state.active) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tstart ??= timestamp;\n\n\t\t\tconst elapsed = timestamp - start;\n\n\t\t\tconst elapsedMinimum = elapsed - milliseconds;\n\t\t\tconst elapsedMaximum = elapsed + milliseconds;\n\n\t\t\tif (elapsedMinimum < timed.configuration.time && timed.configuration.time < elapsedMaximum) {\n\t\t\t\tif (timed.state.active) {\n\t\t\t\t\ttimed.callbacks.default(isRepeated ? count : undefined);\n\t\t\t\t}\n\n\t\t\t\tcount += 1;\n\n\t\t\t\tif (isRepeated && count < timed.configuration.count) {\n\t\t\t\t\tstart = undefined;\n\t\t\t\t} else {\n\t\t\t\t\ttimed.state.finished = true;\n\n\t\t\t\t\ttimed.stop();\n\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\ttimed.state.frame = request(step);\n\t\t}\n\n\t\ttimed.state.frame = request(step);\n\t}\n\n\t/**\n\t * Restart timer\n\t */\n\trestart(): this {\n\t\tthis.stop();\n\n\t\tTimed.run(this as never);\n\n\t\treturn this;\n\t}\n\n\t/**\n\t * Start timer\n\t */\n\tstart(): this {\n\t\tif (!this.state.active) {\n\t\t\tTimed.run(this as never);\n\t\t}\n\n\t\treturn this;\n\t}\n\n\t/**\n\t * Stop timer\n\t */\n\tstop(): this {\n\t\tthis.state.active = false;\n\n\t\tif (typeof this.state.frame === 'undefined') {\n\t\t\treturn this;\n\t\t}\n\n\t\t(cancelAnimationFrame ?? clearTimeout)?.(this.state.frame);\n\n\t\tthis.callbacks.after?.(this.finished);\n\n\t\tthis.state.frame = undefined;\n\n\t\treturn this;\n\t}\n}\n\n/**\n * A repeated timer\n */\nexport class Repeated extends Timed<RepeatedCallback> {}\n\n/**\n * A waited timer\n */\nexport class Waited extends Timed<WaitedCallback> {\n\tconstructor(callback: WaitedCallback, time: number) {\n\t\tsuper(callback, time, 1);\n\t}\n}\n\n/**\n * Create and start a new repeated timer\n */\nexport function repeat(callback: RepeatedCallback, time: number, count: number, afterCallback?: AfterCallback): Repeated {\n\treturn (new Repeated(callback, time, count, afterCallback)).start();\n}\n\n/**\n * Create and start a new waited timer\n */\nexport function wait(callback: WaitedCallback, time: number): Waited {\n\treturn (new Waited(callback, time)).start();\n}\n"],
|
|
5
|
-
"mappings": "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",
|
|
6
|
-
"names": []
|
|
7
|
-
}
|
package/dist/timer.iife.js.map
DELETED
|
@@ -1,7 +0,0 @@
|
|
|
1
|
-
{
|
|
2
|
-
"version": 3,
|
|
3
|
-
"sources": ["../src/index.ts"],
|
|
4
|
-
"sourcesContent": ["type AfterCallback = (finished: boolean) => void;\ntype RepeatedCallback = (index: number) => void;\ntype WaitedCallback = () => void;\n\ntype Callbacks<Callback> = {\n\tafter?: AfterCallback;\n\tdefault: Callback;\n};\n\ntype Configuration = {\n\tcount: number;\n\ttime: number;\n};\n\ntype State = {\n\tactive: boolean;\n\tfinished: boolean;\n\tframe?: number;\n};\n\nconst milliseconds = Math.round(1000 / 60);\n\nconst request = requestAnimationFrame ?? function (callback: FrameRequestCallback): number {\n\treturn (setTimeout?.(() => {\n\t\tcallback(Date.now());\n\t}, milliseconds) ?? -1) as unknown as number;\n};\n\nabstract class Timed<Callback> {\n\treadonly callbacks!: Callbacks<Callback>;\n\treadonly configuration!: Configuration;\n\n\treadonly state: State = {\n\t\tactive: false,\n\t\tfinished: false,\n\t};\n\n\t/**\n\t * Is the timer active?\n\t */\n\tget active(): boolean {\n\t\treturn this.state.active;\n\t}\n\n\t/**\n\t * Has the timer finished?\n\t */\n get finished(): boolean {\n\t\treturn !this.state.active && this.state.finished;\n\t}\n\n\tconstructor(callback: Callback, time: number,\tcount: number, afterCallback?: AfterCallback) {\n\t\tconst isRepeated = this instanceof Repeated;\n\n\t\tconst type = isRepeated\n\t\t? 'repeated'\n\t\t: 'waited';\n\n\t\tif (typeof callback !== 'function') {\n\t\t\tthrow new Error(`A ${type} timer must have a callback function`);\n\t\t}\n\n\t\tif (typeof time !== 'number' || time < 0) {\n\t\t\tthrow new Error(`A ${type} timer must have a non-negative number as its time`);\n\t\t}\n\n\t\tif (isRepeated && (typeof count !== 'number' || count < 2)) {\n\t\t\tthrow new Error('A repeated timer must have a number above 1 as its repeat count');\n\t\t}\n\n\t\tif (isRepeated && afterCallback != null && typeof afterCallback !== 'function') {\n\t\t\tthrow new Error('A repeated timer\\'s after-callback must be a function');\n\t\t}\n\n\t\tthis.configuration = {count, time};\n\n\t\tthis.callbacks = {\n\t\t\tafter: afterCallback,\n\t\t\tdefault: callback,\n\t\t};\n\t}\n\n\tprivate static run(timed: Timed<(index: number | undefined) => void>): void {\n\t\ttimed.state.active = true;\n\t\ttimed.state.finished = false;\n\n\t\tconst isRepeated = timed instanceof Repeated;\n\n\t\tlet count = 0;\n\n\t\tlet start: DOMHighResTimeStamp | undefined;\n\n\t\tfunction step(timestamp: DOMHighResTimeStamp): void {\n\t\t\tif (!timed.state.active) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tstart ??= timestamp;\n\n\t\t\tconst elapsed = timestamp - start;\n\n\t\t\tconst elapsedMinimum = elapsed - milliseconds;\n\t\t\tconst elapsedMaximum = elapsed + milliseconds;\n\n\t\t\tif (elapsedMinimum < timed.configuration.time && timed.configuration.time < elapsedMaximum) {\n\t\t\t\tif (timed.state.active) {\n\t\t\t\t\ttimed.callbacks.default(isRepeated ? count : undefined);\n\t\t\t\t}\n\n\t\t\t\tcount += 1;\n\n\t\t\t\tif (isRepeated && count < timed.configuration.count) {\n\t\t\t\t\tstart = undefined;\n\t\t\t\t} else {\n\t\t\t\t\ttimed.state.finished = true;\n\n\t\t\t\t\ttimed.stop();\n\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\ttimed.state.frame = request(step);\n\t\t}\n\n\t\ttimed.state.frame = request(step);\n\t}\n\n\t/**\n\t * Restart timer\n\t */\n\trestart(): this {\n\t\tthis.stop();\n\n\t\tTimed.run(this as never);\n\n\t\treturn this;\n\t}\n\n\t/**\n\t * Start timer\n\t */\n\tstart(): this {\n\t\tif (!this.state.active) {\n\t\t\tTimed.run(this as never);\n\t\t}\n\n\t\treturn this;\n\t}\n\n\t/**\n\t * Stop timer\n\t */\n\tstop(): this {\n\t\tthis.state.active = false;\n\n\t\tif (typeof this.state.frame === 'undefined') {\n\t\t\treturn this;\n\t\t}\n\n\t\t(cancelAnimationFrame ?? clearTimeout)?.(this.state.frame);\n\n\t\tthis.callbacks.after?.(this.finished);\n\n\t\tthis.state.frame = undefined;\n\n\t\treturn this;\n\t}\n}\n\n/**\n * A repeated timer\n */\nexport class Repeated extends Timed<RepeatedCallback> {}\n\n/**\n * A waited timer\n */\nexport class Waited extends Timed<WaitedCallback> {\n\tconstructor(callback: WaitedCallback, time: number) {\n\t\tsuper(callback, time, 1);\n\t}\n}\n\n/**\n * Create and start a new repeated timer\n */\nexport function repeat(callback: RepeatedCallback, time: number, count: number, afterCallback?: AfterCallback): Repeated {\n\treturn (new Repeated(callback, time, count, afterCallback)).start();\n}\n\n/**\n * Create and start a new waited timer\n */\nexport function wait(callback: WaitedCallback, time: number): Waited {\n\treturn (new Waited(callback, time)).start();\n}\n"],
|
|
5
|
-
"mappings": "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",
|
|
6
|
-
"names": ["src_exports", "__export", "Repeated", "Waited", "repeat", "wait", "milliseconds", "request", "callback", "_a", "Timed", "time", "count", "afterCallback", "__publicField", "isRepeated", "Repeated", "type", "timed", "start", "step", "timestamp", "elapsed", "elapsedMinimum", "elapsedMaximum", "_b", "_c", "Waited", "repeat", "wait"]
|
|
7
|
-
}
|
package/dist/timer.js.map
DELETED
|
@@ -1,7 +0,0 @@
|
|
|
1
|
-
{
|
|
2
|
-
"version": 3,
|
|
3
|
-
"sources": ["../src/index.ts"],
|
|
4
|
-
"sourcesContent": ["type AfterCallback = (finished: boolean) => void;\ntype RepeatedCallback = (index: number) => void;\ntype WaitedCallback = () => void;\n\ntype Callbacks<Callback> = {\n\tafter?: AfterCallback;\n\tdefault: Callback;\n};\n\ntype Configuration = {\n\tcount: number;\n\ttime: number;\n};\n\ntype State = {\n\tactive: boolean;\n\tfinished: boolean;\n\tframe?: number;\n};\n\nconst milliseconds = Math.round(1000 / 60);\n\nconst request = requestAnimationFrame ?? function (callback: FrameRequestCallback): number {\n\treturn (setTimeout?.(() => {\n\t\tcallback(Date.now());\n\t}, milliseconds) ?? -1) as unknown as number;\n};\n\nabstract class Timed<Callback> {\n\treadonly callbacks!: Callbacks<Callback>;\n\treadonly configuration!: Configuration;\n\n\treadonly state: State = {\n\t\tactive: false,\n\t\tfinished: false,\n\t};\n\n\t/**\n\t * Is the timer active?\n\t */\n\tget active(): boolean {\n\t\treturn this.state.active;\n\t}\n\n\t/**\n\t * Has the timer finished?\n\t */\n get finished(): boolean {\n\t\treturn !this.state.active && this.state.finished;\n\t}\n\n\tconstructor(callback: Callback, time: number,\tcount: number, afterCallback?: AfterCallback) {\n\t\tconst isRepeated = this instanceof Repeated;\n\n\t\tconst type = isRepeated\n\t\t? 'repeated'\n\t\t: 'waited';\n\n\t\tif (typeof callback !== 'function') {\n\t\t\tthrow new Error(`A ${type} timer must have a callback function`);\n\t\t}\n\n\t\tif (typeof time !== 'number' || time < 0) {\n\t\t\tthrow new Error(`A ${type} timer must have a non-negative number as its time`);\n\t\t}\n\n\t\tif (isRepeated && (typeof count !== 'number' || count < 2)) {\n\t\t\tthrow new Error('A repeated timer must have a number above 1 as its repeat count');\n\t\t}\n\n\t\tif (isRepeated && afterCallback != null && typeof afterCallback !== 'function') {\n\t\t\tthrow new Error('A repeated timer\\'s after-callback must be a function');\n\t\t}\n\n\t\tthis.configuration = {count, time};\n\n\t\tthis.callbacks = {\n\t\t\tafter: afterCallback,\n\t\t\tdefault: callback,\n\t\t};\n\t}\n\n\tprivate static run(timed: Timed<(index: number | undefined) => void>): void {\n\t\ttimed.state.active = true;\n\t\ttimed.state.finished = false;\n\n\t\tconst isRepeated = timed instanceof Repeated;\n\n\t\tlet count = 0;\n\n\t\tlet start: DOMHighResTimeStamp | undefined;\n\n\t\tfunction step(timestamp: DOMHighResTimeStamp): void {\n\t\t\tif (!timed.state.active) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tstart ??= timestamp;\n\n\t\t\tconst elapsed = timestamp - start;\n\n\t\t\tconst elapsedMinimum = elapsed - milliseconds;\n\t\t\tconst elapsedMaximum = elapsed + milliseconds;\n\n\t\t\tif (elapsedMinimum < timed.configuration.time && timed.configuration.time < elapsedMaximum) {\n\t\t\t\tif (timed.state.active) {\n\t\t\t\t\ttimed.callbacks.default(isRepeated ? count : undefined);\n\t\t\t\t}\n\n\t\t\t\tcount += 1;\n\n\t\t\t\tif (isRepeated && count < timed.configuration.count) {\n\t\t\t\t\tstart = undefined;\n\t\t\t\t} else {\n\t\t\t\t\ttimed.state.finished = true;\n\n\t\t\t\t\ttimed.stop();\n\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\ttimed.state.frame = request(step);\n\t\t}\n\n\t\ttimed.state.frame = request(step);\n\t}\n\n\t/**\n\t * Restart timer\n\t */\n\trestart(): this {\n\t\tthis.stop();\n\n\t\tTimed.run(this as never);\n\n\t\treturn this;\n\t}\n\n\t/**\n\t * Start timer\n\t */\n\tstart(): this {\n\t\tif (!this.state.active) {\n\t\t\tTimed.run(this as never);\n\t\t}\n\n\t\treturn this;\n\t}\n\n\t/**\n\t * Stop timer\n\t */\n\tstop(): this {\n\t\tthis.state.active = false;\n\n\t\tif (typeof this.state.frame === 'undefined') {\n\t\t\treturn this;\n\t\t}\n\n\t\t(cancelAnimationFrame ?? clearTimeout)?.(this.state.frame);\n\n\t\tthis.callbacks.after?.(this.finished);\n\n\t\tthis.state.frame = undefined;\n\n\t\treturn this;\n\t}\n}\n\n/**\n * A repeated timer\n */\nexport class Repeated extends Timed<RepeatedCallback> {}\n\n/**\n * A waited timer\n */\nexport class Waited extends Timed<WaitedCallback> {\n\tconstructor(callback: WaitedCallback, time: number) {\n\t\tsuper(callback, time, 1);\n\t}\n}\n\n/**\n * Create and start a new repeated timer\n */\nexport function repeat(callback: RepeatedCallback, time: number, count: number, afterCallback?: AfterCallback): Repeated {\n\treturn (new Repeated(callback, time, count, afterCallback)).start();\n}\n\n/**\n * Create and start a new waited timer\n */\nexport function wait(callback: WaitedCallback, time: number): Waited {\n\treturn (new Waited(callback, time)).start();\n}\n"],
|
|
5
|
-
"mappings": "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",
|
|
6
|
-
"names": []
|
|
7
|
-
}
|
package/src/index.ts
DELETED
|
@@ -1,197 +0,0 @@
|
|
|
1
|
-
type AfterCallback = (finished: boolean) => void;
|
|
2
|
-
type RepeatedCallback = (index: number) => void;
|
|
3
|
-
type WaitedCallback = () => void;
|
|
4
|
-
|
|
5
|
-
type Callbacks<Callback> = {
|
|
6
|
-
after?: AfterCallback;
|
|
7
|
-
default: Callback;
|
|
8
|
-
};
|
|
9
|
-
|
|
10
|
-
type Configuration = {
|
|
11
|
-
count: number;
|
|
12
|
-
time: number;
|
|
13
|
-
};
|
|
14
|
-
|
|
15
|
-
type State = {
|
|
16
|
-
active: boolean;
|
|
17
|
-
finished: boolean;
|
|
18
|
-
frame?: number;
|
|
19
|
-
};
|
|
20
|
-
|
|
21
|
-
const milliseconds = Math.round(1000 / 60);
|
|
22
|
-
|
|
23
|
-
const request = requestAnimationFrame ?? function (callback: FrameRequestCallback): number {
|
|
24
|
-
return (setTimeout?.(() => {
|
|
25
|
-
callback(Date.now());
|
|
26
|
-
}, milliseconds) ?? -1) as unknown as number;
|
|
27
|
-
};
|
|
28
|
-
|
|
29
|
-
abstract class Timed<Callback> {
|
|
30
|
-
readonly callbacks!: Callbacks<Callback>;
|
|
31
|
-
readonly configuration!: Configuration;
|
|
32
|
-
|
|
33
|
-
readonly state: State = {
|
|
34
|
-
active: false,
|
|
35
|
-
finished: false,
|
|
36
|
-
};
|
|
37
|
-
|
|
38
|
-
/**
|
|
39
|
-
* Is the timer active?
|
|
40
|
-
*/
|
|
41
|
-
get active(): boolean {
|
|
42
|
-
return this.state.active;
|
|
43
|
-
}
|
|
44
|
-
|
|
45
|
-
/**
|
|
46
|
-
* Has the timer finished?
|
|
47
|
-
*/
|
|
48
|
-
get finished(): boolean {
|
|
49
|
-
return !this.state.active && this.state.finished;
|
|
50
|
-
}
|
|
51
|
-
|
|
52
|
-
constructor(callback: Callback, time: number, count: number, afterCallback?: AfterCallback) {
|
|
53
|
-
const isRepeated = this instanceof Repeated;
|
|
54
|
-
|
|
55
|
-
const type = isRepeated
|
|
56
|
-
? 'repeated'
|
|
57
|
-
: 'waited';
|
|
58
|
-
|
|
59
|
-
if (typeof callback !== 'function') {
|
|
60
|
-
throw new Error(`A ${type} timer must have a callback function`);
|
|
61
|
-
}
|
|
62
|
-
|
|
63
|
-
if (typeof time !== 'number' || time < 0) {
|
|
64
|
-
throw new Error(`A ${type} timer must have a non-negative number as its time`);
|
|
65
|
-
}
|
|
66
|
-
|
|
67
|
-
if (isRepeated && (typeof count !== 'number' || count < 2)) {
|
|
68
|
-
throw new Error('A repeated timer must have a number above 1 as its repeat count');
|
|
69
|
-
}
|
|
70
|
-
|
|
71
|
-
if (isRepeated && afterCallback != null && typeof afterCallback !== 'function') {
|
|
72
|
-
throw new Error('A repeated timer\'s after-callback must be a function');
|
|
73
|
-
}
|
|
74
|
-
|
|
75
|
-
this.configuration = {count, time};
|
|
76
|
-
|
|
77
|
-
this.callbacks = {
|
|
78
|
-
after: afterCallback,
|
|
79
|
-
default: callback,
|
|
80
|
-
};
|
|
81
|
-
}
|
|
82
|
-
|
|
83
|
-
private static run(timed: Timed<(index: number | undefined) => void>): void {
|
|
84
|
-
timed.state.active = true;
|
|
85
|
-
timed.state.finished = false;
|
|
86
|
-
|
|
87
|
-
const isRepeated = timed instanceof Repeated;
|
|
88
|
-
|
|
89
|
-
let count = 0;
|
|
90
|
-
|
|
91
|
-
let start: DOMHighResTimeStamp | undefined;
|
|
92
|
-
|
|
93
|
-
function step(timestamp: DOMHighResTimeStamp): void {
|
|
94
|
-
if (!timed.state.active) {
|
|
95
|
-
return;
|
|
96
|
-
}
|
|
97
|
-
|
|
98
|
-
start ??= timestamp;
|
|
99
|
-
|
|
100
|
-
const elapsed = timestamp - start;
|
|
101
|
-
|
|
102
|
-
const elapsedMinimum = elapsed - milliseconds;
|
|
103
|
-
const elapsedMaximum = elapsed + milliseconds;
|
|
104
|
-
|
|
105
|
-
if (elapsedMinimum < timed.configuration.time && timed.configuration.time < elapsedMaximum) {
|
|
106
|
-
if (timed.state.active) {
|
|
107
|
-
timed.callbacks.default(isRepeated ? count : undefined);
|
|
108
|
-
}
|
|
109
|
-
|
|
110
|
-
count += 1;
|
|
111
|
-
|
|
112
|
-
if (isRepeated && count < timed.configuration.count) {
|
|
113
|
-
start = undefined;
|
|
114
|
-
} else {
|
|
115
|
-
timed.state.finished = true;
|
|
116
|
-
|
|
117
|
-
timed.stop();
|
|
118
|
-
|
|
119
|
-
return;
|
|
120
|
-
}
|
|
121
|
-
}
|
|
122
|
-
|
|
123
|
-
timed.state.frame = request(step);
|
|
124
|
-
}
|
|
125
|
-
|
|
126
|
-
timed.state.frame = request(step);
|
|
127
|
-
}
|
|
128
|
-
|
|
129
|
-
/**
|
|
130
|
-
* Restart timer
|
|
131
|
-
*/
|
|
132
|
-
restart(): this {
|
|
133
|
-
this.stop();
|
|
134
|
-
|
|
135
|
-
Timed.run(this as never);
|
|
136
|
-
|
|
137
|
-
return this;
|
|
138
|
-
}
|
|
139
|
-
|
|
140
|
-
/**
|
|
141
|
-
* Start timer
|
|
142
|
-
*/
|
|
143
|
-
start(): this {
|
|
144
|
-
if (!this.state.active) {
|
|
145
|
-
Timed.run(this as never);
|
|
146
|
-
}
|
|
147
|
-
|
|
148
|
-
return this;
|
|
149
|
-
}
|
|
150
|
-
|
|
151
|
-
/**
|
|
152
|
-
* Stop timer
|
|
153
|
-
*/
|
|
154
|
-
stop(): this {
|
|
155
|
-
this.state.active = false;
|
|
156
|
-
|
|
157
|
-
if (typeof this.state.frame === 'undefined') {
|
|
158
|
-
return this;
|
|
159
|
-
}
|
|
160
|
-
|
|
161
|
-
(cancelAnimationFrame ?? clearTimeout)?.(this.state.frame);
|
|
162
|
-
|
|
163
|
-
this.callbacks.after?.(this.finished);
|
|
164
|
-
|
|
165
|
-
this.state.frame = undefined;
|
|
166
|
-
|
|
167
|
-
return this;
|
|
168
|
-
}
|
|
169
|
-
}
|
|
170
|
-
|
|
171
|
-
/**
|
|
172
|
-
* A repeated timer
|
|
173
|
-
*/
|
|
174
|
-
export class Repeated extends Timed<RepeatedCallback> {}
|
|
175
|
-
|
|
176
|
-
/**
|
|
177
|
-
* A waited timer
|
|
178
|
-
*/
|
|
179
|
-
export class Waited extends Timed<WaitedCallback> {
|
|
180
|
-
constructor(callback: WaitedCallback, time: number) {
|
|
181
|
-
super(callback, time, 1);
|
|
182
|
-
}
|
|
183
|
-
}
|
|
184
|
-
|
|
185
|
-
/**
|
|
186
|
-
* Create and start a new repeated timer
|
|
187
|
-
*/
|
|
188
|
-
export function repeat(callback: RepeatedCallback, time: number, count: number, afterCallback?: AfterCallback): Repeated {
|
|
189
|
-
return (new Repeated(callback, time, count, afterCallback)).start();
|
|
190
|
-
}
|
|
191
|
-
|
|
192
|
-
/**
|
|
193
|
-
* Create and start a new waited timer
|
|
194
|
-
*/
|
|
195
|
-
export function wait(callback: WaitedCallback, time: number): Waited {
|
|
196
|
-
return (new Waited(callback, time)).start();
|
|
197
|
-
}
|