@oscarpalmer/timer 0.10.0 → 0.12.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
@@ -32,9 +32,6 @@ __export(src_exports, {
32
32
  });
33
33
  module.exports = __toCommonJS(src_exports);
34
34
  var milliseconds = Math.round(1e3 / 60);
35
- var cancel = cancelAnimationFrame != null ? cancelAnimationFrame : function(id) {
36
- clearTimeout == null ? void 0 : clearTimeout(id);
37
- };
38
35
  var request = requestAnimationFrame != null ? requestAnimationFrame : function(callback) {
39
36
  var _a;
40
37
  return (_a = setTimeout == null ? void 0 : setTimeout(() => {
@@ -42,12 +39,13 @@ var request = requestAnimationFrame != null ? requestAnimationFrame : function(c
42
39
  }, milliseconds)) != null ? _a : -1;
43
40
  };
44
41
  var Timed = class {
45
- constructor(callback, time, count) {
46
- __publicField(this, "callback");
47
- __publicField(this, "count");
48
- __publicField(this, "frame");
49
- __publicField(this, "running", false);
50
- __publicField(this, "time");
42
+ constructor(callback, time, count, afterCallback) {
43
+ __publicField(this, "callbacks");
44
+ __publicField(this, "configuration");
45
+ __publicField(this, "state", {
46
+ active: false,
47
+ finished: false
48
+ });
51
49
  const isRepeated = this instanceof Repeated;
52
50
  const type = isRepeated ? "repeated" : "waited";
53
51
  if (typeof callback !== "function") {
@@ -59,60 +57,87 @@ var Timed = class {
59
57
  if (isRepeated && (typeof count !== "number" || count < 2)) {
60
58
  throw new Error("A repeated timer must have a number above 1 as its repeat count");
61
59
  }
62
- this.callback = callback;
63
- this.count = count;
64
- this.time = time;
60
+ if (isRepeated && afterCallback != null && typeof afterCallback !== "function") {
61
+ throw new Error("A repeated timer's after-callback must be a function");
62
+ }
63
+ this.configuration = { count, time };
64
+ this.callbacks = {
65
+ after: afterCallback,
66
+ default: callback
67
+ };
65
68
  }
69
+ /**
70
+ * Is the timer active?
71
+ */
66
72
  get active() {
67
- return this.running;
73
+ return this.state.active;
74
+ }
75
+ /**
76
+ * Has the timer finished?
77
+ */
78
+ get finished() {
79
+ return !this.state.active && this.state.finished;
68
80
  }
69
81
  static run(timed) {
70
- timed.running = true;
82
+ timed.state.active = true;
83
+ timed.state.finished = false;
84
+ const isRepeated = timed instanceof Repeated;
71
85
  let count = 0;
72
86
  let start;
73
87
  function step(timestamp) {
74
- if (!timed.running) {
88
+ if (!timed.state.active) {
75
89
  return;
76
90
  }
77
91
  start != null ? start : start = timestamp;
78
92
  const elapsed = timestamp - start;
79
93
  const elapsedMinimum = elapsed - milliseconds;
80
94
  const elapsedMaximum = elapsed + milliseconds;
81
- if (elapsedMinimum < timed.time && timed.time < elapsedMaximum) {
82
- if (timed.running) {
83
- timed.callback(timed instanceof Repeated ? count : void 0);
95
+ if (elapsedMinimum < timed.configuration.time && timed.configuration.time < elapsedMaximum) {
96
+ if (timed.state.active) {
97
+ timed.callbacks.default(isRepeated ? count : void 0);
84
98
  }
85
99
  count += 1;
86
- if (timed instanceof Repeated && count < timed.count) {
100
+ if (isRepeated && count < timed.configuration.count) {
87
101
  start = void 0;
88
102
  } else {
103
+ timed.state.finished = true;
89
104
  timed.stop();
90
105
  return;
91
106
  }
92
107
  }
93
- timed.frame = request(step);
108
+ timed.state.frame = request(step);
94
109
  }
95
- timed.frame = request(step);
110
+ timed.state.frame = request(step);
96
111
  }
112
+ /**
113
+ * Restart timer
114
+ */
97
115
  restart() {
98
116
  this.stop();
99
117
  Timed.run(this);
100
118
  return this;
101
119
  }
120
+ /**
121
+ * Start timer
122
+ */
102
123
  start() {
103
- if (this.running) {
104
- return this;
124
+ if (!this.state.active) {
125
+ Timed.run(this);
105
126
  }
106
- Timed.run(this);
107
127
  return this;
108
128
  }
129
+ /**
130
+ * Stop timer
131
+ */
109
132
  stop() {
110
- this.running = false;
111
- if (typeof this.frame === "undefined") {
133
+ var _a, _b, _c;
134
+ this.state.active = false;
135
+ if (typeof this.state.frame === "undefined") {
112
136
  return this;
113
137
  }
114
- cancel(this.frame);
115
- this.frame = void 0;
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);
140
+ this.state.frame = void 0;
116
141
  return this;
117
142
  }
118
143
  };
@@ -123,8 +148,8 @@ var Waited = class extends Timed {
123
148
  super(callback, time, 1);
124
149
  }
125
150
  };
126
- function repeat(callback, time, count) {
127
- return new Repeated(callback, time, count).start();
151
+ function repeat(callback, time, count, afterCallback) {
152
+ return new Repeated(callback, time, count, afterCallback).start();
128
153
  }
129
154
  function wait(callback, time) {
130
155
  return new Waited(callback, time).start();
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../src/index.ts"],
4
- "sourcesContent": ["type RepeatedCallback = (index: number) => void;\ntype WaitedCallback = () => void;\n\nconst milliseconds = Math.round(1000 / 60);\n\nconst cancel = cancelAnimationFrame ?? function (id: number): void {\n\tclearTimeout?.(id);\n};\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\tprivate readonly callback: Callback;\n\tprivate readonly count: number;\n\tprivate frame: number | undefined;\n\tprivate running = false;\n\tprivate readonly time: number;\n\n\t/**\n\t * Is the timer active?\n\t */\n\tget active(): boolean {\n\t\treturn this.running;\n\t}\n\n\tconstructor(callback: Callback, time: number,\tcount: number) {\n\t\tconst isRepeated = this instanceof Repeated;\n\t\tconst type = isRepeated ? 'repeated' : '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\tthis.callback = callback;\n\t\tthis.count = count;\n\t\tthis.time = time;\n\t}\n\n\tprivate static run(timed: Timed<(index: number | undefined) => void>): void {\n\t\ttimed.running = true;\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.running) {\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.time && timed.time < elapsedMaximum) {\n\t\t\t\tif (timed.running) {\n\t\t\t\t\ttimed.callback(timed instanceof Repeated ? count : undefined);\n\t\t\t\t}\n\n\t\t\t\tcount += 1;\n\n\t\t\t\tif ((timed instanceof Repeated) && count < timed.count) {\n\t\t\t\t\tstart = undefined;\n\t\t\t\t} else {\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.frame = request(step);\n\t\t}\n\n\t\ttimed.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.running) {\n\t\t\treturn this;\n\t\t}\n\n\t\tTimed.run(this as never);\n\n\t\treturn this;\n\t}\n\n\t/**\n\t * Stop timer\n\t */\n\tstop(): this {\n\t\tthis.running = false;\n\n\t\tif (typeof this.frame === 'undefined') {\n\t\t\treturn this;\n\t\t}\n\n\t\tcancel(this.frame);\n\n\t\tthis.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): Repeated {\n\treturn (new Repeated(callback, time, count)).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;AAGA,IAAM,eAAe,KAAK,MAAM,MAAO,EAAE;AAEzC,IAAM,SAAS,sDAAwB,SAAU,IAAkB;AAClE,+CAAe;AAChB;AAEA,IAAM,UAAU,wDAAyB,SAAU,UAAwC;AAT3F;AAUC,UAAQ,8CAAa,MAAM;AAC1B,aAAS,KAAK,IAAI,CAAC;AAAA,EACpB,GAAG,kBAFK,YAEY;AACrB;AAEA,IAAe,QAAf,MAA+B;AAAA,EAc9B,YAAY,UAAoB,MAAc,OAAe;AAb7D,wBAAiB;AACjB,wBAAiB;AACjB,wBAAQ;AACR,wBAAQ,WAAU;AAClB,wBAAiB;AAUhB,UAAM,aAAa,gBAAgB;AACnC,UAAM,OAAO,aAAa,aAAa;AAEvC,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,SAAK,WAAW;AAChB,SAAK,QAAQ;AACb,SAAK,OAAO;AAAA,EACb;AAAA,EAvBA,IAAI,SAAkB;AACrB,WAAO,KAAK;AAAA,EACb;AAAA,EAuBA,OAAe,IAAI,OAAyD;AAC3E,UAAM,UAAU;AAEhB,QAAI,QAAQ;AAEZ,QAAI;AAEJ,aAAS,KAAK,WAAsC;AACnD,UAAI,CAAC,MAAM,SAAS;AACnB;AAAA,MACD;AAEA,sCAAU;AAEV,YAAM,UAAU,YAAY;AAE5B,YAAM,iBAAiB,UAAU;AACjC,YAAM,iBAAiB,UAAU;AAEjC,UAAI,iBAAiB,MAAM,QAAQ,MAAM,OAAO,gBAAgB;AAC/D,YAAI,MAAM,SAAS;AAClB,gBAAM,SAAS,iBAAiB,WAAW,QAAQ,MAAS;AAAA,QAC7D;AAEA,iBAAS;AAET,YAAK,iBAAiB,YAAa,QAAQ,MAAM,OAAO;AACvD,kBAAQ;AAAA,QACT,OAAO;AACN,gBAAM,KAAK;AAEX;AAAA,QACD;AAAA,MACD;AAEA,YAAM,QAAQ,QAAQ,IAAI;AAAA,IAC3B;AAEA,UAAM,QAAQ,QAAQ,IAAI;AAAA,EAC3B;AAAA,EAKA,UAAgB;AACf,SAAK,KAAK;AAEV,UAAM,IAAI,IAAa;AAEvB,WAAO;AAAA,EACR;AAAA,EAKA,QAAc;AACb,QAAI,KAAK,SAAS;AACjB,aAAO;AAAA,IACR;AAEA,UAAM,IAAI,IAAa;AAEvB,WAAO;AAAA,EACR;AAAA,EAKA,OAAa;AACZ,SAAK,UAAU;AAEf,QAAI,OAAO,KAAK,UAAU,aAAa;AACtC,aAAO;AAAA,IACR;AAEA,WAAO,KAAK,KAAK;AAEjB,SAAK,QAAQ;AAEb,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,OAAyB;AACzF,SAAQ,IAAI,SAAS,UAAU,MAAM,KAAK,EAAG,MAAM;AACpD;AAKO,SAAS,KAAK,UAA0B,MAAsB;AACpE,SAAQ,IAAI,OAAO,UAAU,IAAI,EAAG,MAAM;AAC3C;",
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
6
  "names": []
7
7
  }
@@ -1,2 +1,2 @@
1
- "use strict";var Timer=(()=>{var c=Object.defineProperty;var h=Object.getOwnPropertyDescriptor;var v=Object.getOwnPropertyNames;var k=Object.prototype.hasOwnProperty;var w=(n,e,t)=>e in n?c(n,e,{enumerable:!0,configurable:!0,writable:!0,value:t}):n[e]=t;var g=(n,e)=>{for(var t in e)c(n,t,{get:e[t],enumerable:!0})},C=(n,e,t,r)=>{if(e&&typeof e=="object"||typeof e=="function")for(let a of v(e))!k.call(n,a)&&a!==t&&c(n,a,{get:()=>e[a],enumerable:!(r=h(e,a))||r.enumerable});return n};var y=n=>C(c({},"__esModule",{value:!0}),n);var u=(n,e,t)=>(w(n,typeof e!="symbol"?e+"":e,t),t);var M={};g(M,{Repeated:()=>i,Waited:()=>l,repeat:()=>R,wait:()=>A});var f=Math.round(16.666666666666668),x=cancelAnimationFrame!=null?cancelAnimationFrame:function(n){clearTimeout==null||clearTimeout(n)},m=requestAnimationFrame!=null?requestAnimationFrame:function(n){var e;return(e=setTimeout==null?void 0:setTimeout(()=>{n(Date.now())},f))!=null?e:-1},s=class{constructor(e,t,r){u(this,"callback");u(this,"count");u(this,"frame");u(this,"running",!1);u(this,"time");let a=this instanceof i,o=a?"repeated":"waited";if(typeof e!="function")throw new Error(`A ${o} timer must have a callback function`);if(typeof t!="number"||t<0)throw new Error(`A ${o} timer must have a non-negative number as its time`);if(a&&(typeof r!="number"||r<2))throw new Error("A repeated timer must have a number above 1 as its repeat count");this.callback=e,this.count=r,this.time=t}get active(){return this.running}static run(e){e.running=!0;let t=0,r;function a(o){if(!e.running)return;r!=null||(r=o);let b=o-r,p=b-f,d=b+f;if(p<e.time&&e.time<d)if(e.running&&e.callback(e instanceof i?t:void 0),t+=1,e instanceof i&&t<e.count)r=void 0;else{e.stop();return}e.frame=m(a)}e.frame=m(a)}restart(){return this.stop(),s.run(this),this}start(){return this.running?this:(s.run(this),this)}stop(){return this.running=!1,typeof this.frame=="undefined"?this:(x(this.frame),this.frame=void 0,this)}},i=class extends s{},l=class extends s{constructor(e,t){super(e,t,1)}};function R(n,e,t){return new i(n,e,t).start()}function A(n,e){return new l(n,e).start()}return y(M);})();
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
2
  //# sourceMappingURL=timer.iife.js.map
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../src/index.ts"],
4
- "sourcesContent": ["type RepeatedCallback = (index: number) => void;\ntype WaitedCallback = () => void;\n\nconst milliseconds = Math.round(1000 / 60);\n\nconst cancel = cancelAnimationFrame ?? function (id: number): void {\n\tclearTimeout?.(id);\n};\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\tprivate readonly callback: Callback;\n\tprivate readonly count: number;\n\tprivate frame: number | undefined;\n\tprivate running = false;\n\tprivate readonly time: number;\n\n\t/**\n\t * Is the timer active?\n\t */\n\tget active(): boolean {\n\t\treturn this.running;\n\t}\n\n\tconstructor(callback: Callback, time: number,\tcount: number) {\n\t\tconst isRepeated = this instanceof Repeated;\n\t\tconst type = isRepeated ? 'repeated' : '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\tthis.callback = callback;\n\t\tthis.count = count;\n\t\tthis.time = time;\n\t}\n\n\tprivate static run(timed: Timed<(index: number | undefined) => void>): void {\n\t\ttimed.running = true;\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.running) {\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.time && timed.time < elapsedMaximum) {\n\t\t\t\tif (timed.running) {\n\t\t\t\t\ttimed.callback(timed instanceof Repeated ? count : undefined);\n\t\t\t\t}\n\n\t\t\t\tcount += 1;\n\n\t\t\t\tif ((timed instanceof Repeated) && count < timed.count) {\n\t\t\t\t\tstart = undefined;\n\t\t\t\t} else {\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.frame = request(step);\n\t\t}\n\n\t\ttimed.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.running) {\n\t\t\treturn this;\n\t\t}\n\n\t\tTimed.run(this as never);\n\n\t\treturn this;\n\t}\n\n\t/**\n\t * Stop timer\n\t */\n\tstop(): this {\n\t\tthis.running = false;\n\n\t\tif (typeof this.frame === 'undefined') {\n\t\t\treturn this;\n\t\t}\n\n\t\tcancel(this.frame);\n\n\t\tthis.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): Repeated {\n\treturn (new Repeated(callback, time, count)).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": "qkBAAA,IAAAA,EAAA,GAAAC,EAAAD,EAAA,cAAAE,EAAA,WAAAC,EAAA,WAAAC,EAAA,SAAAC,IAGA,IAAMC,EAAe,KAAK,MAAM,kBAAS,EAEnCC,EAAS,gDAAwB,SAAUC,EAAkB,CAClE,iCAAeA,EAChB,EAEMC,EAAU,kDAAyB,SAAUC,EAAwC,CAT3F,IAAAC,EAUC,OAAQA,EAAA,mCAAa,IAAM,CAC1BD,EAAS,KAAK,IAAI,CAAC,CACpB,EAAGJ,KAFK,KAAAK,EAEY,EACrB,EAEeC,EAAf,KAA+B,CAc9B,YAAYF,EAAoBG,EAAcC,EAAe,CAb7DC,EAAA,KAAiB,YACjBA,EAAA,KAAiB,SACjBA,EAAA,KAAQ,SACRA,EAAA,KAAQ,UAAU,IAClBA,EAAA,KAAiB,QAUhB,IAAMC,EAAa,gBAAgBC,EAC7BC,EAAOF,EAAa,WAAa,SAEvC,GAAI,OAAON,GAAa,WACvB,MAAM,IAAI,MAAM,KAAKQ,uCAA0C,EAGhE,GAAI,OAAOL,GAAS,UAAYA,EAAO,EACtC,MAAM,IAAI,MAAM,KAAKK,qDAAwD,EAG9E,GAAIF,IAAe,OAAOF,GAAU,UAAYA,EAAQ,GACvD,MAAM,IAAI,MAAM,iEAAiE,EAGlF,KAAK,SAAWJ,EAChB,KAAK,MAAQI,EACb,KAAK,KAAOD,CACb,CAvBA,IAAI,QAAkB,CACrB,OAAO,KAAK,OACb,CAuBA,OAAe,IAAIM,EAAyD,CAC3EA,EAAM,QAAU,GAEhB,IAAIL,EAAQ,EAERM,EAEJ,SAASC,EAAKC,EAAsC,CACnD,GAAI,CAACH,EAAM,QACV,OAGDC,GAAA,OAAAA,EAAUE,GAEV,IAAMC,EAAUD,EAAYF,EAEtBI,EAAiBD,EAAUjB,EAC3BmB,EAAiBF,EAAUjB,EAEjC,GAAIkB,EAAiBL,EAAM,MAAQA,EAAM,KAAOM,EAO/C,GANIN,EAAM,SACTA,EAAM,SAASA,aAAiBF,EAAWH,EAAQ,MAAS,EAG7DA,GAAS,EAEJK,aAAiBF,GAAaH,EAAQK,EAAM,MAChDC,EAAQ,WACF,CACND,EAAM,KAAK,EAEX,MACD,CAGDA,EAAM,MAAQV,EAAQY,CAAI,CAC3B,CAEAF,EAAM,MAAQV,EAAQY,CAAI,CAC3B,CAKA,SAAgB,CACf,YAAK,KAAK,EAEVT,EAAM,IAAI,IAAa,EAEhB,IACR,CAKA,OAAc,CACb,OAAI,KAAK,QACD,MAGRA,EAAM,IAAI,IAAa,EAEhB,KACR,CAKA,MAAa,CAGZ,OAFA,KAAK,QAAU,GAEX,OAAO,KAAK,OAAU,YAClB,MAGRL,EAAO,KAAK,KAAK,EAEjB,KAAK,MAAQ,OAEN,KACR,CACD,EAKaU,EAAN,cAAuBL,CAAwB,CAAC,EAK1Cc,EAAN,cAAqBd,CAAsB,CACjD,YAAYF,EAA0BG,EAAc,CACnD,MAAMH,EAAUG,EAAM,CAAC,CACxB,CACD,EAKO,SAASc,EAAOjB,EAA4BG,EAAcC,EAAyB,CACzF,OAAQ,IAAIG,EAASP,EAAUG,EAAMC,CAAK,EAAG,MAAM,CACpD,CAKO,SAASc,EAAKlB,EAA0BG,EAAsB,CACpE,OAAQ,IAAIa,EAAOhB,EAAUG,CAAI,EAAG,MAAM,CAC3C",
6
- "names": ["src_exports", "__export", "Repeated", "Waited", "repeat", "wait", "milliseconds", "cancel", "id", "request", "callback", "_a", "Timed", "time", "count", "__publicField", "isRepeated", "Repeated", "type", "timed", "start", "step", "timestamp", "elapsed", "elapsedMinimum", "elapsedMaximum", "Waited", "repeat", "wait"]
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
7
  }
package/dist/timer.js CHANGED
@@ -1,23 +1,30 @@
1
1
  // src/index.ts
2
2
  var milliseconds = Math.round(1e3 / 60);
3
- var cancel = cancelAnimationFrame ?? function(id) {
4
- clearTimeout?.(id);
5
- };
6
3
  var request = requestAnimationFrame ?? function(callback) {
7
4
  return setTimeout?.(() => {
8
5
  callback(Date.now());
9
6
  }, milliseconds) ?? -1;
10
7
  };
11
8
  var Timed = class {
12
- callback;
13
- count;
14
- frame;
15
- running = false;
16
- time;
9
+ callbacks;
10
+ configuration;
11
+ state = {
12
+ active: false,
13
+ finished: false
14
+ };
15
+ /**
16
+ * Is the timer active?
17
+ */
17
18
  get active() {
18
- return this.running;
19
+ return this.state.active;
20
+ }
21
+ /**
22
+ * Has the timer finished?
23
+ */
24
+ get finished() {
25
+ return !this.state.active && this.state.finished;
19
26
  }
20
- constructor(callback, time, count) {
27
+ constructor(callback, time, count, afterCallback) {
21
28
  const isRepeated = this instanceof Repeated;
22
29
  const type = isRepeated ? "repeated" : "waited";
23
30
  if (typeof callback !== "function") {
@@ -29,57 +36,74 @@ var Timed = class {
29
36
  if (isRepeated && (typeof count !== "number" || count < 2)) {
30
37
  throw new Error("A repeated timer must have a number above 1 as its repeat count");
31
38
  }
32
- this.callback = callback;
33
- this.count = count;
34
- this.time = time;
39
+ if (isRepeated && afterCallback != null && typeof afterCallback !== "function") {
40
+ throw new Error("A repeated timer's after-callback must be a function");
41
+ }
42
+ this.configuration = { count, time };
43
+ this.callbacks = {
44
+ after: afterCallback,
45
+ default: callback
46
+ };
35
47
  }
36
48
  static run(timed) {
37
- timed.running = true;
49
+ timed.state.active = true;
50
+ timed.state.finished = false;
51
+ const isRepeated = timed instanceof Repeated;
38
52
  let count = 0;
39
53
  let start;
40
54
  function step(timestamp) {
41
- if (!timed.running) {
55
+ if (!timed.state.active) {
42
56
  return;
43
57
  }
44
58
  start ??= timestamp;
45
59
  const elapsed = timestamp - start;
46
60
  const elapsedMinimum = elapsed - milliseconds;
47
61
  const elapsedMaximum = elapsed + milliseconds;
48
- if (elapsedMinimum < timed.time && timed.time < elapsedMaximum) {
49
- if (timed.running) {
50
- timed.callback(timed instanceof Repeated ? count : void 0);
62
+ if (elapsedMinimum < timed.configuration.time && timed.configuration.time < elapsedMaximum) {
63
+ if (timed.state.active) {
64
+ timed.callbacks.default(isRepeated ? count : void 0);
51
65
  }
52
66
  count += 1;
53
- if (timed instanceof Repeated && count < timed.count) {
67
+ if (isRepeated && count < timed.configuration.count) {
54
68
  start = void 0;
55
69
  } else {
70
+ timed.state.finished = true;
56
71
  timed.stop();
57
72
  return;
58
73
  }
59
74
  }
60
- timed.frame = request(step);
75
+ timed.state.frame = request(step);
61
76
  }
62
- timed.frame = request(step);
77
+ timed.state.frame = request(step);
63
78
  }
79
+ /**
80
+ * Restart timer
81
+ */
64
82
  restart() {
65
83
  this.stop();
66
84
  Timed.run(this);
67
85
  return this;
68
86
  }
87
+ /**
88
+ * Start timer
89
+ */
69
90
  start() {
70
- if (this.running) {
71
- return this;
91
+ if (!this.state.active) {
92
+ Timed.run(this);
72
93
  }
73
- Timed.run(this);
74
94
  return this;
75
95
  }
96
+ /**
97
+ * Stop timer
98
+ */
76
99
  stop() {
77
- this.running = false;
78
- if (typeof this.frame === "undefined") {
100
+ this.state.active = false;
101
+ if (typeof this.state.frame === "undefined") {
79
102
  return this;
80
103
  }
81
- cancel(this.frame);
82
- this.frame = void 0;
104
+ (cancelAnimationFrame ?? clearTimeout)?.(this.state.frame);
105
+ this.callbacks.after?.(this.finished);
106
+ this.state.frame = void 0;
83
107
  return this;
84
108
  }
85
109
  };
@@ -90,8 +114,8 @@ var Waited = class extends Timed {
90
114
  super(callback, time, 1);
91
115
  }
92
116
  };
93
- function repeat(callback, time, count) {
94
- return new Repeated(callback, time, count).start();
117
+ function repeat(callback, time, count, afterCallback) {
118
+ return new Repeated(callback, time, count, afterCallback).start();
95
119
  }
96
120
  function wait(callback, time) {
97
121
  return new Waited(callback, time).start();
package/dist/timer.js.map CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../src/index.ts"],
4
- "sourcesContent": ["type RepeatedCallback = (index: number) => void;\ntype WaitedCallback = () => void;\n\nconst milliseconds = Math.round(1000 / 60);\n\nconst cancel = cancelAnimationFrame ?? function (id: number): void {\n\tclearTimeout?.(id);\n};\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\tprivate readonly callback: Callback;\n\tprivate readonly count: number;\n\tprivate frame: number | undefined;\n\tprivate running = false;\n\tprivate readonly time: number;\n\n\t/**\n\t * Is the timer active?\n\t */\n\tget active(): boolean {\n\t\treturn this.running;\n\t}\n\n\tconstructor(callback: Callback, time: number,\tcount: number) {\n\t\tconst isRepeated = this instanceof Repeated;\n\t\tconst type = isRepeated ? 'repeated' : '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\tthis.callback = callback;\n\t\tthis.count = count;\n\t\tthis.time = time;\n\t}\n\n\tprivate static run(timed: Timed<(index: number | undefined) => void>): void {\n\t\ttimed.running = true;\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.running) {\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.time && timed.time < elapsedMaximum) {\n\t\t\t\tif (timed.running) {\n\t\t\t\t\ttimed.callback(timed instanceof Repeated ? count : undefined);\n\t\t\t\t}\n\n\t\t\t\tcount += 1;\n\n\t\t\t\tif ((timed instanceof Repeated) && count < timed.count) {\n\t\t\t\t\tstart = undefined;\n\t\t\t\t} else {\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.frame = request(step);\n\t\t}\n\n\t\ttimed.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.running) {\n\t\t\treturn this;\n\t\t}\n\n\t\tTimed.run(this as never);\n\n\t\treturn this;\n\t}\n\n\t/**\n\t * Stop timer\n\t */\n\tstop(): this {\n\t\tthis.running = false;\n\n\t\tif (typeof this.frame === 'undefined') {\n\t\t\treturn this;\n\t\t}\n\n\t\tcancel(this.frame);\n\n\t\tthis.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): Repeated {\n\treturn (new Repeated(callback, time, count)).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": ";AAGA,IAAM,eAAe,KAAK,MAAM,MAAO,EAAE;AAEzC,IAAM,SAAS,wBAAwB,SAAU,IAAkB;AAClE,iBAAe,EAAE;AAClB;AAEA,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,EACb;AAAA,EACA;AAAA,EACT;AAAA,EACA,UAAU;AAAA,EACD;AAAA,EAKjB,IAAI,SAAkB;AACrB,WAAO,KAAK;AAAA,EACb;AAAA,EAEA,YAAY,UAAoB,MAAc,OAAe;AAC5D,UAAM,aAAa,gBAAgB;AACnC,UAAM,OAAO,aAAa,aAAa;AAEvC,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,SAAK,WAAW;AAChB,SAAK,QAAQ;AACb,SAAK,OAAO;AAAA,EACb;AAAA,EAEA,OAAe,IAAI,OAAyD;AAC3E,UAAM,UAAU;AAEhB,QAAI,QAAQ;AAEZ,QAAI;AAEJ,aAAS,KAAK,WAAsC;AACnD,UAAI,CAAC,MAAM,SAAS;AACnB;AAAA,MACD;AAEA,gBAAU;AAEV,YAAM,UAAU,YAAY;AAE5B,YAAM,iBAAiB,UAAU;AACjC,YAAM,iBAAiB,UAAU;AAEjC,UAAI,iBAAiB,MAAM,QAAQ,MAAM,OAAO,gBAAgB;AAC/D,YAAI,MAAM,SAAS;AAClB,gBAAM,SAAS,iBAAiB,WAAW,QAAQ,MAAS;AAAA,QAC7D;AAEA,iBAAS;AAET,YAAK,iBAAiB,YAAa,QAAQ,MAAM,OAAO;AACvD,kBAAQ;AAAA,QACT,OAAO;AACN,gBAAM,KAAK;AAEX;AAAA,QACD;AAAA,MACD;AAEA,YAAM,QAAQ,QAAQ,IAAI;AAAA,IAC3B;AAEA,UAAM,QAAQ,QAAQ,IAAI;AAAA,EAC3B;AAAA,EAKA,UAAgB;AACf,SAAK,KAAK;AAEV,UAAM,IAAI,IAAa;AAEvB,WAAO;AAAA,EACR;AAAA,EAKA,QAAc;AACb,QAAI,KAAK,SAAS;AACjB,aAAO;AAAA,IACR;AAEA,UAAM,IAAI,IAAa;AAEvB,WAAO;AAAA,EACR;AAAA,EAKA,OAAa;AACZ,SAAK,UAAU;AAEf,QAAI,OAAO,KAAK,UAAU,aAAa;AACtC,aAAO;AAAA,IACR;AAEA,WAAO,KAAK,KAAK;AAEjB,SAAK,QAAQ;AAEb,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,OAAyB;AACzF,SAAQ,IAAI,SAAS,UAAU,MAAM,KAAK,EAAG,MAAM;AACpD;AAKO,SAAS,KAAK,UAA0B,MAAsB;AACpE,SAAQ,IAAI,OAAO,UAAU,IAAI,EAAG,MAAM;AAC3C;",
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
6
  "names": []
7
7
  }
package/package.json CHANGED
@@ -6,15 +6,15 @@
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.0",
10
- "@types/node": "^18.7.0",
11
- "@typescript-eslint/eslint-plugin": "^5.38.0",
12
- "@typescript-eslint/parser": "^5.38.0",
13
- "esbuild": "^0.15.0",
14
- "eslint": "^8.23.0",
15
- "eslint-config-xo": "^0.42.0",
16
- "eslint-config-xo-typescript": "^0.53.0",
17
- "typescript": "^4.8.0"
9
+ "@tsconfig/recommended": "^1.0",
10
+ "@types/node": "^18.15",
11
+ "@typescript-eslint/eslint-plugin": "^5.57",
12
+ "@typescript-eslint/parser": "^5.57",
13
+ "esbuild": "^0.17",
14
+ "eslint": "^8.38",
15
+ "eslint-config-xo": "^0.43",
16
+ "eslint-config-xo-typescript": "^0.57",
17
+ "typescript": "^5.0"
18
18
  },
19
19
  "exports": {
20
20
  ".": {
@@ -52,5 +52,5 @@
52
52
  "type": "module",
53
53
  "types": "src/index.d.ts",
54
54
  "unpkg": "dist/timer.iife.js",
55
- "version": "0.10.0"
55
+ "version": "0.12.0"
56
56
  }
package/src/index.ts CHANGED
@@ -1,12 +1,25 @@
1
+ type AfterCallback = (finished: boolean) => void;
1
2
  type RepeatedCallback = (index: number) => void;
2
3
  type WaitedCallback = () => void;
3
4
 
4
- const milliseconds = Math.round(1000 / 60);
5
+ type Callbacks<Callback> = {
6
+ after?: AfterCallback;
7
+ default: Callback;
8
+ };
9
+
10
+ type Configuration = {
11
+ count: number;
12
+ time: number;
13
+ };
5
14
 
6
- const cancel = cancelAnimationFrame ?? function (id: number): void {
7
- clearTimeout?.(id);
15
+ type State = {
16
+ active: boolean;
17
+ finished: boolean;
18
+ frame?: number;
8
19
  };
9
20
 
21
+ const milliseconds = Math.round(1000 / 60);
22
+
10
23
  const request = requestAnimationFrame ?? function (callback: FrameRequestCallback): number {
11
24
  return (setTimeout?.(() => {
12
25
  callback(Date.now());
@@ -14,22 +27,34 @@ const request = requestAnimationFrame ?? function (callback: FrameRequestCallbac
14
27
  };
15
28
 
16
29
  abstract class Timed<Callback> {
17
- private readonly callback: Callback;
18
- private readonly count: number;
19
- private frame: number | undefined;
20
- private running = false;
21
- private readonly time: number;
30
+ readonly callbacks!: Callbacks<Callback>;
31
+ readonly configuration!: Configuration;
32
+
33
+ readonly state: State = {
34
+ active: false,
35
+ finished: false,
36
+ };
22
37
 
23
38
  /**
24
39
  * Is the timer active?
25
40
  */
26
41
  get active(): boolean {
27
- return this.running;
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;
28
50
  }
29
51
 
30
- constructor(callback: Callback, time: number, count: number) {
52
+ constructor(callback: Callback, time: number, count: number, afterCallback?: AfterCallback) {
31
53
  const isRepeated = this instanceof Repeated;
32
- const type = isRepeated ? 'repeated' : 'waited';
54
+
55
+ const type = isRepeated
56
+ ? 'repeated'
57
+ : 'waited';
33
58
 
34
59
  if (typeof callback !== 'function') {
35
60
  throw new Error(`A ${type} timer must have a callback function`);
@@ -43,20 +68,30 @@ abstract class Timed<Callback> {
43
68
  throw new Error('A repeated timer must have a number above 1 as its repeat count');
44
69
  }
45
70
 
46
- this.callback = callback;
47
- this.count = count;
48
- this.time = time;
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
+ };
49
81
  }
50
82
 
51
83
  private static run(timed: Timed<(index: number | undefined) => void>): void {
52
- timed.running = true;
84
+ timed.state.active = true;
85
+ timed.state.finished = false;
86
+
87
+ const isRepeated = timed instanceof Repeated;
53
88
 
54
89
  let count = 0;
55
90
 
56
91
  let start: DOMHighResTimeStamp | undefined;
57
92
 
58
93
  function step(timestamp: DOMHighResTimeStamp): void {
59
- if (!timed.running) {
94
+ if (!timed.state.active) {
60
95
  return;
61
96
  }
62
97
 
@@ -67,26 +102,28 @@ abstract class Timed<Callback> {
67
102
  const elapsedMinimum = elapsed - milliseconds;
68
103
  const elapsedMaximum = elapsed + milliseconds;
69
104
 
70
- if (elapsedMinimum < timed.time && timed.time < elapsedMaximum) {
71
- if (timed.running) {
72
- timed.callback(timed instanceof Repeated ? count : undefined);
105
+ if (elapsedMinimum < timed.configuration.time && timed.configuration.time < elapsedMaximum) {
106
+ if (timed.state.active) {
107
+ timed.callbacks.default(isRepeated ? count : undefined);
73
108
  }
74
109
 
75
110
  count += 1;
76
111
 
77
- if ((timed instanceof Repeated) && count < timed.count) {
112
+ if (isRepeated && count < timed.configuration.count) {
78
113
  start = undefined;
79
114
  } else {
115
+ timed.state.finished = true;
116
+
80
117
  timed.stop();
81
118
 
82
119
  return;
83
120
  }
84
121
  }
85
122
 
86
- timed.frame = request(step);
123
+ timed.state.frame = request(step);
87
124
  }
88
125
 
89
- timed.frame = request(step);
126
+ timed.state.frame = request(step);
90
127
  }
91
128
 
92
129
  /**
@@ -104,12 +141,10 @@ abstract class Timed<Callback> {
104
141
  * Start timer
105
142
  */
106
143
  start(): this {
107
- if (this.running) {
108
- return this;
144
+ if (!this.state.active) {
145
+ Timed.run(this as never);
109
146
  }
110
147
 
111
- Timed.run(this as never);
112
-
113
148
  return this;
114
149
  }
115
150
 
@@ -117,15 +152,17 @@ abstract class Timed<Callback> {
117
152
  * Stop timer
118
153
  */
119
154
  stop(): this {
120
- this.running = false;
155
+ this.state.active = false;
121
156
 
122
- if (typeof this.frame === 'undefined') {
157
+ if (typeof this.state.frame === 'undefined') {
123
158
  return this;
124
159
  }
125
160
 
126
- cancel(this.frame);
161
+ (cancelAnimationFrame ?? clearTimeout)?.(this.state.frame);
162
+
163
+ this.callbacks.after?.(this.finished);
127
164
 
128
- this.frame = undefined;
165
+ this.state.frame = undefined;
129
166
 
130
167
  return this;
131
168
  }
@@ -148,8 +185,8 @@ export class Waited extends Timed<WaitedCallback> {
148
185
  /**
149
186
  * Create and start a new repeated timer
150
187
  */
151
- export function repeat(callback: RepeatedCallback, time: number, count: number): Repeated {
152
- return (new Repeated(callback, time, count)).start();
188
+ export function repeat(callback: RepeatedCallback, time: number, count: number, afterCallback?: AfterCallback): Repeated {
189
+ return (new Repeated(callback, time, count, afterCallback)).start();
153
190
  }
154
191
 
155
192
  /**