@oscarpalmer/timer 0.12.1 → 0.14.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/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.ts
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 != null ? requestAnimationFrame : function(callback) {
36
- var _a;
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)) != null ? _a : -1;
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 index = 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 ? index : void 0);
56
+ }
57
+ index += 1;
58
+ if (isRepeated && index < 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 {RepeatedCallback} callback
73
+ * @param {number} time
74
+ * @param {number} count
75
+ * @param {AfterCallback|undefined} afterCallback
76
+ */
42
77
  constructor(callback, time, count, afterCallback) {
78
+ /**
79
+ * @readonly
80
+ * @type {{after: AfterCallback | undefined; default: RepeatedCallback}}
81
+ */
43
82
  __publicField(this, "callbacks");
83
+ /**
84
+ * @readonly
85
+ * @type {{count: number; time: number}}
86
+ */
44
87
  __publicField(this, "configuration");
45
- __publicField(this, "state", {
46
- active: false,
47
- finished: false
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 Error(`A ${type} timer must have a callback function`);
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 Error(`A ${type} timer must have a non-negative number as its time`);
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 Error("A repeated timer must have a number above 1 as its repeat count");
102
+ throw new TypeError("A repeated timer must have a number above 1 as its repeat count");
59
103
  }
60
- if (isRepeated && afterCallback != null && typeof afterCallback !== "function") {
61
- throw new Error("A repeated timer's after-callback must be a function");
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.state.active && this.state.finished;
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
- Timed.run(this);
127
+ run(this);
118
128
  return this;
119
129
  }
120
- /**
121
- * Start timer
122
- */
123
130
  start() {
124
131
  if (!this.state.active) {
125
- Timed.run(this);
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 (typeof this.state.frame === "undefined") {
138
+ if (this.state.frame === void 0) {
136
139
  return this;
137
140
  }
138
- (_a = cancelAnimationFrame != null ? cancelAnimationFrame : clearTimeout) == null ? void 0 : _a(this.state.frame);
139
- (_c = (_b = this.callbacks).after) == null ? void 0 : _c.call(_b, this.finished);
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
@@ -1,2 +1 @@
1
- "use strict";var Timer=(()=>{var c=Object.defineProperty;var v=Object.getOwnPropertyDescriptor;var k=Object.getOwnPropertyNames;var C=Object.prototype.hasOwnProperty;var y=(a,e,t)=>e in a?c(a,e,{enumerable:!0,configurable:!0,writable:!0,value:t}):a[e]=t;var w=(a,e)=>{for(var t in e)c(a,t,{get:e[t],enumerable:!0})},g=(a,e,t,n)=>{if(e&&typeof e=="object"||typeof e=="function")for(let i of k(e))!C.call(a,i)&&i!==t&&c(a,i,{get:()=>e[i],enumerable:!(n=v(e,i))||n.enumerable});return a};var A=a=>g(c({},"__esModule",{value:!0}),a);var l=(a,e,t)=>(y(a,typeof e!="symbol"?e+"":e,t),t);var M={};w(M,{Repeated:()=>o,Waited:()=>f,repeat:()=>x,wait:()=>R});var b=Math.round(16.666666666666668),d=requestAnimationFrame!=null?requestAnimationFrame:function(a){var e;return(e=setTimeout==null?void 0:setTimeout(()=>{a(Date.now())},b))!=null?e:-1},r=class{constructor(e,t,n,i){l(this,"callbacks");l(this,"configuration");l(this,"state",{active:!1,finished:!1});let s=this instanceof o,u=s?"repeated":"waited";if(typeof e!="function")throw new Error(`A ${u} timer must have a callback function`);if(typeof t!="number"||t<0)throw new Error(`A ${u} timer must have a non-negative number as its time`);if(s&&(typeof n!="number"||n<2))throw new Error("A repeated timer must have a number above 1 as its repeat count");if(s&&i!=null&&typeof i!="function")throw new Error("A repeated timer's after-callback must be a function");this.configuration={count:n,time:t},this.callbacks={after:i,default:e}}get active(){return this.state.active}get finished(){return!this.state.active&&this.state.finished}static run(e){e.state.active=!0,e.state.finished=!1;let t=e instanceof o,n=0,i;function s(u){if(!e.state.active)return;i!=null||(i=u);let h=u-i,p=h-b,m=h+b;if(p<e.configuration.time&&e.configuration.time<m)if(e.state.active&&e.callbacks.default(t?n:void 0),n+=1,t&&n<e.configuration.count)i=void 0;else{e.state.finished=!0,e.stop();return}e.state.frame=d(s)}e.state.frame=d(s)}restart(){return this.stop(),r.run(this),this}start(){return this.state.active||r.run(this),this}stop(){var e,t,n;return this.state.active=!1,typeof this.state.frame=="undefined"?this:((e=cancelAnimationFrame!=null?cancelAnimationFrame:clearTimeout)==null||e(this.state.frame),(n=(t=this.callbacks).after)==null||n.call(t,this.finished),this.state.frame=void 0,this)}},o=class extends r{},f=class extends r{constructor(e,t){super(e,t,1)}};function x(a,e,t,n){return new o(a,e,t,n).start()}function R(a,e){return new f(a,e).start()}return A(M);})();
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
- // src/index.ts
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) ?? -1;
13
+ }, milliseconds);
7
14
  };
8
- var Timed = class {
9
- callbacks;
10
- configuration;
11
- state = {
12
- active: false,
13
- finished: false
14
- };
15
- /**
16
- * Is the timer active?
17
- */
18
- get active() {
19
- return this.state.active;
15
+ function run(timed) {
16
+ timed.state.active = true;
17
+ timed.state.finished = false;
18
+ const isRepeated = timed instanceof Repeated;
19
+ let index = 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 ? index : void 0);
32
+ }
33
+ index += 1;
34
+ if (isRepeated && index < 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
- * Has the timer finished?
48
+ * @param {RepeatedCallback} callback
49
+ * @param {number} time
50
+ * @param {number} count
51
+ * @param {AfterCallback|undefined} 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: AfterCallback | undefined; default: RepeatedCallback}}
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 Error(`A ${type} timer must have a callback function`);
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 Error(`A ${type} timer must have a non-negative number as its time`);
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 Error("A repeated timer must have a number above 1 as its repeat count");
78
+ throw new TypeError("A repeated timer must have a number above 1 as its repeat count");
38
79
  }
39
- if (isRepeated && afterCallback != null && typeof afterCallback !== "function") {
40
- throw new Error("A repeated timer's after-callback must be a function");
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
- static run(timed) {
49
- timed.state.active = true;
50
- timed.state.finished = false;
51
- const isRepeated = timed instanceof Repeated;
52
- let count = 0;
53
- let start;
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
- Timed.run(this);
103
+ run(this);
85
104
  return this;
86
105
  }
87
- /**
88
- * Start timer
89
- */
90
106
  start() {
91
107
  if (!this.state.active) {
92
- Timed.run(this);
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 (typeof this.state.frame === "undefined") {
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
- "eslint": "^8.38",
15
- "eslint-config-xo": "^0.43",
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.ts --bundle --sourcemap --format=cjs --outfile=./dist/timer.cjs --target=es2017",
48
- "build:esm": "esbuild ./src/index.ts --bundle --sourcemap --format=esm --outfile=./dist/timer.js --target=esnext",
49
- "build:iife": "esbuild ./src/index.ts --bundle --minify --sourcemap --format=iife --global-name=Timer --outfile=./dist/timer.iife.js --target=es2017",
50
- "watch": "esbuild ./src/index.ts --bundle --watch --format=esm --outfile=./dist/timer.js --platform=browser --target=esnext"
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.12.1"
49
+ "version": "0.14.0"
56
50
  }
package/src/index.d.ts CHANGED
@@ -1 +1,31 @@
1
- export * from './index';
1
+ export function repeat(callback: RepeatedCallback, time: number, count: number, afterCallback: AfterCallback | undefined): 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
+ export type AfterCallback = (finished: boolean) => void;
9
+ export type RepeatedCallback = (index: number) => void;
10
+ declare class Timed {
11
+ constructor(callback: RepeatedCallback, time: number, count: number, afterCallback: AfterCallback | undefined);
12
+ readonly callbacks: {
13
+ after: AfterCallback | undefined;
14
+ default: RepeatedCallback;
15
+ };
16
+ readonly configuration: {
17
+ count: number;
18
+ time: number;
19
+ };
20
+ readonly state: {
21
+ active: boolean;
22
+ finished: boolean;
23
+ frame?: DOMHighResTimeStamp;
24
+ };
25
+ get active(): boolean;
26
+ get finished(): boolean;
27
+ restart(): Timed;
28
+ start(): Timed;
29
+ stop(): Timed;
30
+ }
31
+ export {};
package/src/index.js ADDED
@@ -0,0 +1,205 @@
1
+ /**
2
+ * @callback AfterCallback
3
+ * @param {boolean} finished
4
+ * @returns {void}
5
+ */
6
+
7
+ /**
8
+ * @callback RepeatedCallback
9
+ * @param {number} index
10
+ * @returns {void}
11
+ */
12
+
13
+ const milliseconds = Math.round(1000 / 60);
14
+
15
+ const request = globalThis.requestAnimationFrame ?? function (callback) {
16
+ return setTimeout?.(() => {
17
+ callback(Date.now());
18
+ }, milliseconds);
19
+ };
20
+
21
+ /**
22
+ * @param {Timed} timed
23
+ */
24
+ function run(timed) {
25
+ timed.state.active = true;
26
+ timed.state.finished = false;
27
+
28
+ const isRepeated = timed instanceof Repeated;
29
+
30
+ let index = 0;
31
+
32
+ let start;
33
+
34
+ function step(timestamp) {
35
+ if (!timed.state.active) {
36
+ return;
37
+ }
38
+
39
+ start ??= timestamp;
40
+
41
+ const elapsed = timestamp - start;
42
+
43
+ const elapsedMinimum = elapsed - milliseconds;
44
+ const elapsedMaximum = elapsed + milliseconds;
45
+
46
+ if (elapsedMinimum < timed.configuration.time && timed.configuration.time < elapsedMaximum) {
47
+ if (timed.state.active) {
48
+ timed.callbacks.default(isRepeated ? index : undefined);
49
+ }
50
+
51
+ index += 1;
52
+
53
+ if (isRepeated && index < timed.configuration.count) {
54
+ start = undefined;
55
+ } else {
56
+ timed.state.finished = true;
57
+
58
+ timed.stop();
59
+
60
+ return;
61
+ }
62
+ }
63
+
64
+ timed.state.frame = request(step);
65
+ }
66
+
67
+ timed.state.frame = request(step);
68
+ }
69
+
70
+ class Timed {
71
+ /**
72
+ * @readonly
73
+ * @type {{after: AfterCallback | undefined; default: RepeatedCallback}}
74
+ */
75
+ callbacks;
76
+
77
+ /**
78
+ * @readonly
79
+ * @type {{count: number; time: number}}
80
+ */
81
+ configuration;
82
+
83
+ /**
84
+ * @readonly
85
+ * @type {{active: boolean; finished: boolean; frame?: DOMHighResTimeStamp}}
86
+ */
87
+ state;
88
+
89
+ /** */
90
+
91
+ get active() {
92
+ return this.state.active;
93
+ }
94
+
95
+ get finished() {
96
+ return !this.active && this.state.finished;
97
+ }
98
+
99
+ /**
100
+ * @param {RepeatedCallback} callback
101
+ * @param {number} time
102
+ * @param {number} count
103
+ * @param {AfterCallback|undefined} afterCallback
104
+ */
105
+ constructor(callback, time, count, afterCallback) {
106
+ const isRepeated = this instanceof Repeated;
107
+
108
+ const type = isRepeated
109
+ ? 'repeated'
110
+ : 'waited';
111
+
112
+ if (typeof callback !== 'function') {
113
+ throw new TypeError(`A ${type} timer must have a callback function`);
114
+ }
115
+
116
+ if (typeof time !== 'number' || time < 0) {
117
+ throw new TypeError(`A ${type} timer must have a non-negative number as its time`);
118
+ }
119
+
120
+ if (isRepeated && (typeof count !== 'number' || count < 2)) {
121
+ throw new TypeError('A repeated timer must have a number above 1 as its repeat count');
122
+ }
123
+
124
+ if (isRepeated && afterCallback !== undefined && typeof afterCallback !== 'function') {
125
+ throw new TypeError('A repeated timer\'s after-callback must be a function');
126
+ }
127
+
128
+ this.configuration = {count, time};
129
+
130
+ this.callbacks = {
131
+ after: afterCallback,
132
+ default: callback,
133
+ };
134
+
135
+ this.state = {
136
+ active: false,
137
+ finished: false,
138
+ frame: null,
139
+ };
140
+ }
141
+
142
+ restart() {
143
+ this.stop();
144
+
145
+ run(this);
146
+
147
+ return this;
148
+ }
149
+
150
+ start() {
151
+ if (!this.state.active) {
152
+ run(this);
153
+ }
154
+
155
+ return this;
156
+ }
157
+
158
+ stop() {
159
+ this.state.active = false;
160
+
161
+ if (this.state.frame === undefined) {
162
+ return this;
163
+ }
164
+
165
+ (globalThis.cancelAnimationFrame ?? clearTimeout)?.(this.state.frame);
166
+
167
+ this.callbacks.after?.(this.finished);
168
+
169
+ this.state.frame = undefined;
170
+
171
+ return this;
172
+ }
173
+ }
174
+
175
+ export class Repeated extends Timed {}
176
+
177
+ export class Waited extends Timed {
178
+ /**
179
+ * @param {Function} callback
180
+ * @param {number} time
181
+ */
182
+ constructor(callback, time) {
183
+ super(callback, time, 1, null);
184
+ }
185
+ }
186
+
187
+ /**
188
+ * @param {RepeatedCallback} callback
189
+ * @param {number} time
190
+ * @param {number} count
191
+ * @param {AfterCallback|undefined} afterCallback
192
+ * @return {Repeated} A repeated timer
193
+ */
194
+ export function repeat(callback, time, count, afterCallback) {
195
+ return (new Repeated(callback, time, count, afterCallback)).start();
196
+ }
197
+
198
+ /**
199
+ * @param {Function} callback
200
+ * @param {number} time
201
+ * @return {Waited} A waited timer
202
+ */
203
+ export function wait(callback, time) {
204
+ return (new Waited(callback, time)).start();
205
+ }
@@ -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": ";;;;;;;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAoBA,IAAM,eAAe,KAAK,MAAM,MAAO,EAAE;AAEzC,IAAM,UAAU,wDAAyB,SAAU,UAAwC;AAtB3F;AAuBC,UAAQ,8CAAa,MAAM;AAC1B,aAAS,KAAK,IAAI,CAAC;AAAA,EACpB,GAAG,kBAFK,YAEY;AACrB;AAEA,IAAe,QAAf,MAA+B;AAAA,EAuB9B,YAAY,UAAoB,MAAc,OAAe,eAA+B;AAtB5F,wBAAS;AACT,wBAAS;AAET,wBAAS,SAAe;AAAA,MACvB,QAAQ;AAAA,MACR,UAAU;AAAA,IACX;AAiBC,UAAM,aAAa,gBAAgB;AAEnC,UAAM,OAAO,aACX,aACA;AAEF,QAAI,OAAO,aAAa,YAAY;AACnC,YAAM,IAAI,MAAM,KAAK,0CAA0C;AAAA,IAChE;AAEA,QAAI,OAAO,SAAS,YAAY,OAAO,GAAG;AACzC,YAAM,IAAI,MAAM,KAAK,wDAAwD;AAAA,IAC9E;AAEA,QAAI,eAAe,OAAO,UAAU,YAAY,QAAQ,IAAI;AAC3D,YAAM,IAAI,MAAM,iEAAiE;AAAA,IAClF;AAEA,QAAI,cAAc,iBAAiB,QAAQ,OAAO,kBAAkB,YAAY;AAC/E,YAAM,IAAI,MAAM,sDAAuD;AAAA,IACxE;AAEA,SAAK,gBAAgB,EAAC,OAAO,KAAI;AAEjC,SAAK,YAAY;AAAA,MAChB,OAAO;AAAA,MACP,SAAS;AAAA,IACV;AAAA,EACD;AAAA;AAAA;AAAA;AAAA,EAxCA,IAAI,SAAkB;AACrB,WAAO,KAAK,MAAM;AAAA,EACnB;AAAA;AAAA;AAAA;AAAA,EAKC,IAAI,WAAoB;AACxB,WAAO,CAAC,KAAK,MAAM,UAAU,KAAK,MAAM;AAAA,EACzC;AAAA,EAiCA,OAAe,IAAI,OAAyD;AAC3E,UAAM,MAAM,SAAS;AACrB,UAAM,MAAM,WAAW;AAEvB,UAAM,aAAa,iBAAiB;AAEpC,QAAI,QAAQ;AAEZ,QAAI;AAEJ,aAAS,KAAK,WAAsC;AACnD,UAAI,CAAC,MAAM,MAAM,QAAQ;AACxB;AAAA,MACD;AAEA,sCAAU;AAEV,YAAM,UAAU,YAAY;AAE5B,YAAM,iBAAiB,UAAU;AACjC,YAAM,iBAAiB,UAAU;AAEjC,UAAI,iBAAiB,MAAM,cAAc,QAAQ,MAAM,cAAc,OAAO,gBAAgB;AAC3F,YAAI,MAAM,MAAM,QAAQ;AACvB,gBAAM,UAAU,QAAQ,aAAa,QAAQ,MAAS;AAAA,QACvD;AAEA,iBAAS;AAET,YAAI,cAAc,QAAQ,MAAM,cAAc,OAAO;AACpD,kBAAQ;AAAA,QACT,OAAO;AACN,gBAAM,MAAM,WAAW;AAEvB,gBAAM,KAAK;AAEX;AAAA,QACD;AAAA,MACD;AAEA,YAAM,MAAM,QAAQ,QAAQ,IAAI;AAAA,IACjC;AAEA,UAAM,MAAM,QAAQ,QAAQ,IAAI;AAAA,EACjC;AAAA;AAAA;AAAA;AAAA,EAKA,UAAgB;AACf,SAAK,KAAK;AAEV,UAAM,IAAI,IAAa;AAEvB,WAAO;AAAA,EACR;AAAA;AAAA;AAAA;AAAA,EAKA,QAAc;AACb,QAAI,CAAC,KAAK,MAAM,QAAQ;AACvB,YAAM,IAAI,IAAa;AAAA,IACxB;AAEA,WAAO;AAAA,EACR;AAAA;AAAA;AAAA;AAAA,EAKA,OAAa;AAzJd;AA0JE,SAAK,MAAM,SAAS;AAEpB,QAAI,OAAO,KAAK,MAAM,UAAU,aAAa;AAC5C,aAAO;AAAA,IACR;AAEA,KAAC,2DAAwB,iBAAxB,mBAAwC,KAAK,MAAM;AAEpD,qBAAK,WAAU,UAAf,4BAAuB,KAAK;AAE5B,SAAK,MAAM,QAAQ;AAEnB,WAAO;AAAA,EACR;AACD;AAKO,IAAM,WAAN,cAAuB,MAAwB;AAAC;AAKhD,IAAM,SAAN,cAAqB,MAAsB;AAAA,EACjD,YAAY,UAA0B,MAAc;AACnD,UAAM,UAAU,MAAM,CAAC;AAAA,EACxB;AACD;AAKO,SAAS,OAAO,UAA4B,MAAc,OAAe,eAAyC;AACxH,SAAQ,IAAI,SAAS,UAAU,MAAM,OAAO,aAAa,EAAG,MAAM;AACnE;AAKO,SAAS,KAAK,UAA0B,MAAsB;AACpE,SAAQ,IAAI,OAAO,UAAU,IAAI,EAAG,MAAM;AAC3C;",
6
- "names": []
7
- }
@@ -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": ";AAoBA,IAAM,eAAe,KAAK,MAAM,MAAO,EAAE;AAEzC,IAAM,UAAU,yBAAyB,SAAU,UAAwC;AAC1F,SAAQ,aAAa,MAAM;AAC1B,aAAS,KAAK,IAAI,CAAC;AAAA,EACpB,GAAG,YAAY,KAAK;AACrB;AAEA,IAAe,QAAf,MAA+B;AAAA,EACrB;AAAA,EACA;AAAA,EAEA,QAAe;AAAA,IACvB,QAAQ;AAAA,IACR,UAAU;AAAA,EACX;AAAA;AAAA;AAAA;AAAA,EAKA,IAAI,SAAkB;AACrB,WAAO,KAAK,MAAM;AAAA,EACnB;AAAA;AAAA;AAAA;AAAA,EAKC,IAAI,WAAoB;AACxB,WAAO,CAAC,KAAK,MAAM,UAAU,KAAK,MAAM;AAAA,EACzC;AAAA,EAEA,YAAY,UAAoB,MAAc,OAAe,eAA+B;AAC3F,UAAM,aAAa,gBAAgB;AAEnC,UAAM,OAAO,aACX,aACA;AAEF,QAAI,OAAO,aAAa,YAAY;AACnC,YAAM,IAAI,MAAM,KAAK,0CAA0C;AAAA,IAChE;AAEA,QAAI,OAAO,SAAS,YAAY,OAAO,GAAG;AACzC,YAAM,IAAI,MAAM,KAAK,wDAAwD;AAAA,IAC9E;AAEA,QAAI,eAAe,OAAO,UAAU,YAAY,QAAQ,IAAI;AAC3D,YAAM,IAAI,MAAM,iEAAiE;AAAA,IAClF;AAEA,QAAI,cAAc,iBAAiB,QAAQ,OAAO,kBAAkB,YAAY;AAC/E,YAAM,IAAI,MAAM,sDAAuD;AAAA,IACxE;AAEA,SAAK,gBAAgB,EAAC,OAAO,KAAI;AAEjC,SAAK,YAAY;AAAA,MAChB,OAAO;AAAA,MACP,SAAS;AAAA,IACV;AAAA,EACD;AAAA,EAEA,OAAe,IAAI,OAAyD;AAC3E,UAAM,MAAM,SAAS;AACrB,UAAM,MAAM,WAAW;AAEvB,UAAM,aAAa,iBAAiB;AAEpC,QAAI,QAAQ;AAEZ,QAAI;AAEJ,aAAS,KAAK,WAAsC;AACnD,UAAI,CAAC,MAAM,MAAM,QAAQ;AACxB;AAAA,MACD;AAEA,gBAAU;AAEV,YAAM,UAAU,YAAY;AAE5B,YAAM,iBAAiB,UAAU;AACjC,YAAM,iBAAiB,UAAU;AAEjC,UAAI,iBAAiB,MAAM,cAAc,QAAQ,MAAM,cAAc,OAAO,gBAAgB;AAC3F,YAAI,MAAM,MAAM,QAAQ;AACvB,gBAAM,UAAU,QAAQ,aAAa,QAAQ,MAAS;AAAA,QACvD;AAEA,iBAAS;AAET,YAAI,cAAc,QAAQ,MAAM,cAAc,OAAO;AACpD,kBAAQ;AAAA,QACT,OAAO;AACN,gBAAM,MAAM,WAAW;AAEvB,gBAAM,KAAK;AAEX;AAAA,QACD;AAAA,MACD;AAEA,YAAM,MAAM,QAAQ,QAAQ,IAAI;AAAA,IACjC;AAEA,UAAM,MAAM,QAAQ,QAAQ,IAAI;AAAA,EACjC;AAAA;AAAA;AAAA;AAAA,EAKA,UAAgB;AACf,SAAK,KAAK;AAEV,UAAM,IAAI,IAAa;AAEvB,WAAO;AAAA,EACR;AAAA;AAAA;AAAA;AAAA,EAKA,QAAc;AACb,QAAI,CAAC,KAAK,MAAM,QAAQ;AACvB,YAAM,IAAI,IAAa;AAAA,IACxB;AAEA,WAAO;AAAA,EACR;AAAA;AAAA;AAAA;AAAA,EAKA,OAAa;AACZ,SAAK,MAAM,SAAS;AAEpB,QAAI,OAAO,KAAK,MAAM,UAAU,aAAa;AAC5C,aAAO;AAAA,IACR;AAEA,KAAC,wBAAwB,gBAAgB,KAAK,MAAM,KAAK;AAEzD,SAAK,UAAU,QAAQ,KAAK,QAAQ;AAEpC,SAAK,MAAM,QAAQ;AAEnB,WAAO;AAAA,EACR;AACD;AAKO,IAAM,WAAN,cAAuB,MAAwB;AAAC;AAKhD,IAAM,SAAN,cAAqB,MAAsB;AAAA,EACjD,YAAY,UAA0B,MAAc;AACnD,UAAM,UAAU,MAAM,CAAC;AAAA,EACxB;AACD;AAKO,SAAS,OAAO,UAA4B,MAAc,OAAe,eAAyC;AACxH,SAAQ,IAAI,SAAS,UAAU,MAAM,OAAO,aAAa,EAAG,MAAM;AACnE;AAKO,SAAS,KAAK,UAA0B,MAAsB;AACpE,SAAQ,IAAI,OAAO,UAAU,IAAI,EAAG,MAAM;AAC3C;",
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
- }