@brandup/ui-helpers 2.0.2 → 2.0.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +17 -3
- package/dist/cjs/helpers/func.js +54 -26
- package/dist/cjs/helpers/func.js.map +1 -1
- package/dist/cjs/polyfill.js +44 -0
- package/dist/cjs/polyfill.js.map +1 -0
- package/dist/mjs/helpers/func.js +54 -27
- package/dist/mjs/helpers/func.js.map +1 -1
- package/dist/mjs/polyfill.js +42 -0
- package/dist/mjs/polyfill.js.map +1 -0
- package/dist/polyfill.d.ts +2 -0
- package/dist/types.d.ts +27 -6
- package/package.json +10 -2
package/README.md
CHANGED
|
@@ -129,6 +129,9 @@ const data = await FuncHelper.minWaitAsync(() => loadData(), 1000);
|
|
|
129
129
|
|
|
130
130
|
// Reject with TimeoutError if the request takes longer than 5000ms
|
|
131
131
|
const result = await FuncHelper.timeout(fetch("/api"), 5000);
|
|
132
|
+
|
|
133
|
+
// Make the wait abortable without stopping the underlying work
|
|
134
|
+
const value = await FuncHelper.abortable(longRunning(), abortController.signal);
|
|
132
135
|
```
|
|
133
136
|
|
|
134
137
|
Detect a timeout by checking the error type:
|
|
@@ -146,7 +149,18 @@ try {
|
|
|
146
149
|
```
|
|
147
150
|
|
|
148
151
|
- `minWait(func, minTime?)` — wraps a callback so it runs no sooner than `minTime` ms after wrapping.
|
|
149
|
-
- `minWaitAsync(func, minTime?, abort?)` — awaits an async operation, padding so it settles no sooner than `minTime` ms.
|
|
150
|
-
- `delay(
|
|
151
|
-
- `timeout(promise,
|
|
152
|
+
- `minWaitAsync(func, minTime?, abort?)` — awaits an async operation, padding so it settles no sooner than `minTime` ms. An already-aborted signal rejects immediately, before `func` runs.
|
|
153
|
+
- `delay(ms, abort?)` — a promise resolved after `ms` ms; rejects on abort. Throws synchronously if `ms` is negative (`0` is allowed).
|
|
154
|
+
- `timeout(promise, ms, abort?)` — races `promise` against `ms` ms; rejects with a `TimeoutError` on timeout, or with the signal's reason on abort. Throws synchronously if `ms ≤ 0`. The underlying `promise` is not cancelled — only the wait ends.
|
|
155
|
+
- `abortable(promise, abort?)` — makes *waiting* for `promise` abortable: rejects with the signal's reason on abort. Does not stop the underlying work; without a signal the promise is awaited as-is.
|
|
152
156
|
- `TimeoutError` — error class thrown by `timeout` when the time limit is exceeded.
|
|
157
|
+
|
|
158
|
+
## Polyfills
|
|
159
|
+
|
|
160
|
+
An opt-in, side-effect-only entry point fills in `AbortSignal` APIs that older runtimes may lack — `AbortSignal.prototype.throwIfAborted`, `AbortSignal.timeout` and `AbortSignal.any`. Import it once, as early as possible (e.g. in your entry module):
|
|
161
|
+
|
|
162
|
+
```TypeScript
|
|
163
|
+
import "@brandup/ui-helpers/polyfill";
|
|
164
|
+
```
|
|
165
|
+
|
|
166
|
+
Each implementation installs only when missing, so native behaviour is preserved where available. Types ship with the TypeScript `ESNext` lib; this module provides just the runtime. It is excluded from tree-shaking (`sideEffects`), so a bare import is never dropped by the bundler.
|
package/dist/cjs/helpers/func.js
CHANGED
|
@@ -31,13 +31,17 @@ const minWait = (func, minTime) => {
|
|
|
31
31
|
* Useful for keeping spinners/loading states visible for a minimum duration. If `minTime`
|
|
32
32
|
* is omitted or falsy, `func` is awaited and its result returned without padding.
|
|
33
33
|
*
|
|
34
|
+
* An already-aborted signal rejects immediately, before `func` runs; aborting later cancels
|
|
35
|
+
* the padding delay (but not `func` itself, which can't be cancelled here).
|
|
36
|
+
*
|
|
34
37
|
* @typeParam TResult Result type produced by `func`.
|
|
35
38
|
* @param func Factory returning the promise to await.
|
|
36
39
|
* @param minTime Minimum total duration in milliseconds.
|
|
37
|
-
* @param abort Optional signal used to cancel the
|
|
40
|
+
* @param abort Optional signal used to cancel the wait.
|
|
38
41
|
* @returns The result produced by `func`.
|
|
39
42
|
*/
|
|
40
43
|
async function minWaitAsync(func, minTime, abort) {
|
|
44
|
+
abort?.throwIfAborted();
|
|
41
45
|
if (!minTime)
|
|
42
46
|
return func();
|
|
43
47
|
const beginTime = Date.now();
|
|
@@ -51,6 +55,8 @@ async function minWaitAsync(func, minTime, abort) {
|
|
|
51
55
|
const getRightTime = (start, minTime) => {
|
|
52
56
|
const finishTime = Date.now();
|
|
53
57
|
const w = minTime - (finishTime - start);
|
|
58
|
+
// Skip padding when the leftover is within 10% of `minTime`: the wait is already
|
|
59
|
+
// "close enough", and a sub-tick delay would only add jitter without a visible effect.
|
|
54
60
|
return w > minTime * 0.1 ? w : 0;
|
|
55
61
|
};
|
|
56
62
|
/**
|
|
@@ -59,21 +65,26 @@ const getRightTime = (start, minTime) => {
|
|
|
59
65
|
* If an already-aborted signal is supplied the promise rejects immediately; otherwise
|
|
60
66
|
* aborting before the delay elapses clears the timer and rejects with the abort reason.
|
|
61
67
|
*
|
|
62
|
-
* @param
|
|
68
|
+
* @param ms Delay in milliseconds; must not be negative. Values above 2147483647 (~24.8 days)
|
|
69
|
+
* overflow the timer and fire on the next tick — a `setTimeout` limitation.
|
|
63
70
|
* @param abort Optional signal used to cancel the delay.
|
|
64
71
|
* @returns A promise that resolves when the delay elapses.
|
|
72
|
+
* @throws {Error} When `ms` is negative.
|
|
65
73
|
*/
|
|
66
|
-
function delay(
|
|
74
|
+
function delay(ms, abort) {
|
|
75
|
+
if (ms < 0)
|
|
76
|
+
throw new Error("Invalid delay value.");
|
|
67
77
|
return new Promise((resolve, reject) => {
|
|
68
78
|
abort?.throwIfAborted();
|
|
69
79
|
const onAbort = () => {
|
|
70
80
|
clearTimeout(timer);
|
|
71
|
-
|
|
81
|
+
// `onAbort` only runs once the listener has fired, which means `abort` exists.
|
|
82
|
+
reject(abort.reason);
|
|
72
83
|
};
|
|
73
84
|
const timer = setTimeout(() => {
|
|
74
85
|
abort?.removeEventListener("abort", onAbort);
|
|
75
86
|
resolve();
|
|
76
|
-
},
|
|
87
|
+
}, ms);
|
|
77
88
|
abort?.addEventListener("abort", onAbort, { once: true });
|
|
78
89
|
});
|
|
79
90
|
}
|
|
@@ -86,32 +97,48 @@ function delay(time, abort) {
|
|
|
86
97
|
*
|
|
87
98
|
* @typeParam T Resolved value type of the wrapped promise.
|
|
88
99
|
* @param promise Promise to guard with a timeout.
|
|
89
|
-
* @param
|
|
100
|
+
* @param ms Timeout in milliseconds; must be greater than `0`. Values above 2147483647
|
|
101
|
+
* (~24.8 days) overflow the timer and fire on the next tick — a `setTimeout` limitation.
|
|
90
102
|
* @param abort Optional signal used to cancel the wait.
|
|
91
103
|
* @returns A promise mirroring `promise` unless the timeout or abort fires first.
|
|
92
|
-
* @throws {Error} When `
|
|
104
|
+
* @throws {Error} When `ms` is not greater than `0`.
|
|
93
105
|
*/
|
|
94
|
-
function timeout(promise,
|
|
95
|
-
if (
|
|
106
|
+
function timeout(promise, ms, abort) {
|
|
107
|
+
if (ms <= 0)
|
|
96
108
|
throw new Error("Invalid timeout value.");
|
|
109
|
+
// Own controller so the `delay` timer can be torn down once the race is decided,
|
|
110
|
+
// independently of the caller's `abort`.
|
|
111
|
+
const timer = new AbortController();
|
|
112
|
+
// Wins the race only by timing out (rejects with TimeoutError). If the timer is cancelled
|
|
113
|
+
// instead — the guarded work settled, or the caller aborted — `delay` rejects, and we turn
|
|
114
|
+
// that into a never-settling promise so `expire` simply stands aside: the race never produces
|
|
115
|
+
// a stray rejection that nobody is listening for.
|
|
116
|
+
const expire = delay(ms, timer.signal).then(() => Promise.reject(new TimeoutError()), () => new Promise(() => { }));
|
|
117
|
+
return abortable(Promise.race([promise, expire]), abort)
|
|
118
|
+
.finally(() => timer.abort());
|
|
119
|
+
}
|
|
120
|
+
/**
|
|
121
|
+
* Makes *waiting* for a promise abortable: rejects with the signal's reason on abort.
|
|
122
|
+
* Does not stop the underlying work the promise performs.
|
|
123
|
+
*
|
|
124
|
+
* If no signal is supplied the promise is awaited as-is. An already-aborted signal rejects
|
|
125
|
+
* immediately; otherwise the abort listener is removed once the promise settles.
|
|
126
|
+
*
|
|
127
|
+
* @typeParam T Resolved value type of the wrapped promise.
|
|
128
|
+
* @param promise Promise (or thenable) whose wait should become abortable.
|
|
129
|
+
* @param abort Optional signal used to cancel the wait.
|
|
130
|
+
* @returns A promise mirroring `promise` unless the abort fires first.
|
|
131
|
+
*/
|
|
132
|
+
function abortable(promise, abort) {
|
|
133
|
+
if (!abort)
|
|
134
|
+
return Promise.resolve(promise);
|
|
135
|
+
if (abort.aborted)
|
|
136
|
+
return Promise.reject(abort.reason);
|
|
97
137
|
return new Promise((resolve, reject) => {
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
};
|
|
103
|
-
const timer = setTimeout(() => {
|
|
104
|
-
abort?.removeEventListener("abort", onAbort);
|
|
105
|
-
reject(new TimeoutError());
|
|
106
|
-
}, timeout);
|
|
107
|
-
abort?.addEventListener("abort", onAbort, { once: true });
|
|
108
|
-
promise
|
|
109
|
-
.then(result => resolve(result))
|
|
110
|
-
.catch(reason => reject(reason))
|
|
111
|
-
.finally(() => {
|
|
112
|
-
clearTimeout(timer);
|
|
113
|
-
abort?.removeEventListener("abort", onAbort);
|
|
114
|
-
});
|
|
138
|
+
const onAbort = () => reject(abort.reason);
|
|
139
|
+
abort.addEventListener("abort", onAbort, { once: true });
|
|
140
|
+
const cleanup = () => abort.removeEventListener("abort", onAbort);
|
|
141
|
+
Promise.resolve(promise).then(v => { cleanup(); resolve(v); }, e => { cleanup(); reject(e); });
|
|
115
142
|
});
|
|
116
143
|
}
|
|
117
144
|
/** Thrown by {@link timeout} when the time limit is exceeded. */
|
|
@@ -123,6 +150,7 @@ class TimeoutError extends Error {
|
|
|
123
150
|
}
|
|
124
151
|
|
|
125
152
|
exports.TimeoutError = TimeoutError;
|
|
153
|
+
exports.abortable = abortable;
|
|
126
154
|
exports.delay = delay;
|
|
127
155
|
exports.minWait = minWait;
|
|
128
156
|
exports.minWaitAsync = minWaitAsync;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"func.js","sources":["../../../../source/helpers/func.ts"],"sourcesContent":[null],"names":[],"mappings":";;AAAA;;;;;;;;;;AAUG;AACH,MAAM,OAAO,GAAG,CAAC,IAA8B,EAAE,OAAgB,KAAI;AACpE,IAAA,IAAI,CAAC,OAAO;AACX,QAAA,OAAO,IAAI;AAEZ,IAAA,MAAM,SAAS,GAAG,IAAI,CAAC,GAAG,EAAE;AAE5B,IAAA,MAAM,GAAG,GAAG,CAAC,GAAG,IAAW,KAAI;QAC9B,MAAM,SAAS,GAAG,YAAY,CAAC,SAAS,EAAE,OAAO,CAAC;AAClD,QAAA,IAAI,SAAS;AACZ,YAAA,UAAU,CAAC,MAAM,IAAI,CAAC,GAAG,IAAI,CAAC,EAAE,SAAS,CAAC;;AAE1C,YAAA,IAAI,CAAC,GAAG,IAAI,CAAC;AACf,IAAA,CAAC;AAED,IAAA,OAAO,GAAG;AACX;AAEA
|
|
1
|
+
{"version":3,"file":"func.js","sources":["../../../../source/helpers/func.ts"],"sourcesContent":[null],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Runtime polyfills for `AbortSignal`, installed only when the host lacks them:
|
|
5
|
+
* `AbortSignal.prototype.throwIfAborted`, `AbortSignal.timeout` and `AbortSignal.any`.
|
|
6
|
+
*
|
|
7
|
+
* Import for its side effect — there are no exports:
|
|
8
|
+
*
|
|
9
|
+
* ```TypeScript
|
|
10
|
+
* import "@brandup/ui-helpers/polyfill";
|
|
11
|
+
* ```
|
|
12
|
+
*
|
|
13
|
+
* Types already ship with the TypeScript `ESNext` lib; this module only fills in the
|
|
14
|
+
* implementations missing in older runtimes, matching the standard behaviour.
|
|
15
|
+
*/
|
|
16
|
+
if (typeof AbortSignal.prototype.throwIfAborted !== "function") {
|
|
17
|
+
AbortSignal.prototype.throwIfAborted = function () {
|
|
18
|
+
if (this.aborted)
|
|
19
|
+
throw this.reason;
|
|
20
|
+
};
|
|
21
|
+
}
|
|
22
|
+
if (typeof AbortSignal.timeout !== "function") {
|
|
23
|
+
AbortSignal.timeout = (milliseconds) => {
|
|
24
|
+
const controller = new AbortController();
|
|
25
|
+
setTimeout(() => controller.abort(new DOMException("The operation timed out.", "TimeoutError")), milliseconds);
|
|
26
|
+
return controller.signal;
|
|
27
|
+
};
|
|
28
|
+
}
|
|
29
|
+
if (typeof AbortSignal.any !== "function") {
|
|
30
|
+
AbortSignal.any = (signals) => {
|
|
31
|
+
const controller = new AbortController();
|
|
32
|
+
for (const signal of signals) {
|
|
33
|
+
// If one is already aborted, the combined signal aborts immediately with its reason.
|
|
34
|
+
if (signal.aborted) {
|
|
35
|
+
controller.abort(signal.reason);
|
|
36
|
+
break;
|
|
37
|
+
}
|
|
38
|
+
// Tying each listener to the combined signal removes them all once it aborts — no leak.
|
|
39
|
+
signal.addEventListener("abort", () => controller.abort(signal.reason), { signal: controller.signal });
|
|
40
|
+
}
|
|
41
|
+
return controller.signal;
|
|
42
|
+
};
|
|
43
|
+
}
|
|
44
|
+
//# sourceMappingURL=polyfill.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"polyfill.js","sources":["../../../source/polyfill.ts"],"sourcesContent":[null],"names":[],"mappings":";;AAAA;;;;;;;;;;;;AAYG;AAEH,IAAI,OAAO,WAAW,CAAC,SAAS,CAAC,cAAc,KAAK,UAAU,EAAE;AAC/D,IAAA,WAAW,CAAC,SAAS,CAAC,cAAc,GAAG,YAAA;QACtC,IAAI,IAAI,CAAC,OAAO;YACf,MAAM,IAAI,CAAC,MAAM;AACnB,IAAA,CAAC;AACF;AAEA,IAAI,OAAO,WAAW,CAAC,OAAO,KAAK,UAAU,EAAE;AAC9C,IAAA,WAAW,CAAC,OAAO,GAAG,CAAC,YAAoB,KAAiB;AAC3D,QAAA,MAAM,UAAU,GAAG,IAAI,eAAe,EAAE;AACxC,QAAA,UAAU,CAAC,MAAM,UAAU,CAAC,KAAK,CAAC,IAAI,YAAY,CAAC,0BAA0B,EAAE,cAAc,CAAC,CAAC,EAAE,YAAY,CAAC;QAC9G,OAAO,UAAU,CAAC,MAAM;AACzB,IAAA,CAAC;AACF;AAEA,IAAI,OAAO,WAAW,CAAC,GAAG,KAAK,UAAU,EAAE;AAC1C,IAAA,WAAW,CAAC,GAAG,GAAG,CAAC,OAAsB,KAAiB;AACzD,QAAA,MAAM,UAAU,GAAG,IAAI,eAAe,EAAE;AAExC,QAAA,KAAK,MAAM,MAAM,IAAI,OAAO,EAAE;;AAE7B,YAAA,IAAI,MAAM,CAAC,OAAO,EAAE;AACnB,gBAAA,UAAU,CAAC,KAAK,CAAC,MAAM,CAAC,MAAM,CAAC;gBAC/B;YACD;;YAGA,MAAM,CAAC,gBAAgB,CAAC,OAAO,EAAE,MAAM,UAAU,CAAC,KAAK,CAAC,MAAM,CAAC,MAAM,CAAC,EAAE,EAAE,MAAM,EAAE,UAAU,CAAC,MAAM,EAAE,CAAC;QACvG;QAEA,OAAO,UAAU,CAAC,MAAM;AACzB,IAAA,CAAC;AACF;;"}
|
package/dist/mjs/helpers/func.js
CHANGED
|
@@ -29,13 +29,17 @@ const minWait = (func, minTime) => {
|
|
|
29
29
|
* Useful for keeping spinners/loading states visible for a minimum duration. If `minTime`
|
|
30
30
|
* is omitted or falsy, `func` is awaited and its result returned without padding.
|
|
31
31
|
*
|
|
32
|
+
* An already-aborted signal rejects immediately, before `func` runs; aborting later cancels
|
|
33
|
+
* the padding delay (but not `func` itself, which can't be cancelled here).
|
|
34
|
+
*
|
|
32
35
|
* @typeParam TResult Result type produced by `func`.
|
|
33
36
|
* @param func Factory returning the promise to await.
|
|
34
37
|
* @param minTime Minimum total duration in milliseconds.
|
|
35
|
-
* @param abort Optional signal used to cancel the
|
|
38
|
+
* @param abort Optional signal used to cancel the wait.
|
|
36
39
|
* @returns The result produced by `func`.
|
|
37
40
|
*/
|
|
38
41
|
async function minWaitAsync(func, minTime, abort) {
|
|
42
|
+
abort?.throwIfAborted();
|
|
39
43
|
if (!minTime)
|
|
40
44
|
return func();
|
|
41
45
|
const beginTime = Date.now();
|
|
@@ -49,6 +53,8 @@ async function minWaitAsync(func, minTime, abort) {
|
|
|
49
53
|
const getRightTime = (start, minTime) => {
|
|
50
54
|
const finishTime = Date.now();
|
|
51
55
|
const w = minTime - (finishTime - start);
|
|
56
|
+
// Skip padding when the leftover is within 10% of `minTime`: the wait is already
|
|
57
|
+
// "close enough", and a sub-tick delay would only add jitter without a visible effect.
|
|
52
58
|
return w > minTime * 0.1 ? w : 0;
|
|
53
59
|
};
|
|
54
60
|
/**
|
|
@@ -57,21 +63,26 @@ const getRightTime = (start, minTime) => {
|
|
|
57
63
|
* If an already-aborted signal is supplied the promise rejects immediately; otherwise
|
|
58
64
|
* aborting before the delay elapses clears the timer and rejects with the abort reason.
|
|
59
65
|
*
|
|
60
|
-
* @param
|
|
66
|
+
* @param ms Delay in milliseconds; must not be negative. Values above 2147483647 (~24.8 days)
|
|
67
|
+
* overflow the timer and fire on the next tick — a `setTimeout` limitation.
|
|
61
68
|
* @param abort Optional signal used to cancel the delay.
|
|
62
69
|
* @returns A promise that resolves when the delay elapses.
|
|
70
|
+
* @throws {Error} When `ms` is negative.
|
|
63
71
|
*/
|
|
64
|
-
function delay(
|
|
72
|
+
function delay(ms, abort) {
|
|
73
|
+
if (ms < 0)
|
|
74
|
+
throw new Error("Invalid delay value.");
|
|
65
75
|
return new Promise((resolve, reject) => {
|
|
66
76
|
abort?.throwIfAborted();
|
|
67
77
|
const onAbort = () => {
|
|
68
78
|
clearTimeout(timer);
|
|
69
|
-
|
|
79
|
+
// `onAbort` only runs once the listener has fired, which means `abort` exists.
|
|
80
|
+
reject(abort.reason);
|
|
70
81
|
};
|
|
71
82
|
const timer = setTimeout(() => {
|
|
72
83
|
abort?.removeEventListener("abort", onAbort);
|
|
73
84
|
resolve();
|
|
74
|
-
},
|
|
85
|
+
}, ms);
|
|
75
86
|
abort?.addEventListener("abort", onAbort, { once: true });
|
|
76
87
|
});
|
|
77
88
|
}
|
|
@@ -84,32 +95,48 @@ function delay(time, abort) {
|
|
|
84
95
|
*
|
|
85
96
|
* @typeParam T Resolved value type of the wrapped promise.
|
|
86
97
|
* @param promise Promise to guard with a timeout.
|
|
87
|
-
* @param
|
|
98
|
+
* @param ms Timeout in milliseconds; must be greater than `0`. Values above 2147483647
|
|
99
|
+
* (~24.8 days) overflow the timer and fire on the next tick — a `setTimeout` limitation.
|
|
88
100
|
* @param abort Optional signal used to cancel the wait.
|
|
89
101
|
* @returns A promise mirroring `promise` unless the timeout or abort fires first.
|
|
90
|
-
* @throws {Error} When `
|
|
102
|
+
* @throws {Error} When `ms` is not greater than `0`.
|
|
91
103
|
*/
|
|
92
|
-
function timeout(promise,
|
|
93
|
-
if (
|
|
104
|
+
function timeout(promise, ms, abort) {
|
|
105
|
+
if (ms <= 0)
|
|
94
106
|
throw new Error("Invalid timeout value.");
|
|
107
|
+
// Own controller so the `delay` timer can be torn down once the race is decided,
|
|
108
|
+
// independently of the caller's `abort`.
|
|
109
|
+
const timer = new AbortController();
|
|
110
|
+
// Wins the race only by timing out (rejects with TimeoutError). If the timer is cancelled
|
|
111
|
+
// instead — the guarded work settled, or the caller aborted — `delay` rejects, and we turn
|
|
112
|
+
// that into a never-settling promise so `expire` simply stands aside: the race never produces
|
|
113
|
+
// a stray rejection that nobody is listening for.
|
|
114
|
+
const expire = delay(ms, timer.signal).then(() => Promise.reject(new TimeoutError()), () => new Promise(() => { }));
|
|
115
|
+
return abortable(Promise.race([promise, expire]), abort)
|
|
116
|
+
.finally(() => timer.abort());
|
|
117
|
+
}
|
|
118
|
+
/**
|
|
119
|
+
* Makes *waiting* for a promise abortable: rejects with the signal's reason on abort.
|
|
120
|
+
* Does not stop the underlying work the promise performs.
|
|
121
|
+
*
|
|
122
|
+
* If no signal is supplied the promise is awaited as-is. An already-aborted signal rejects
|
|
123
|
+
* immediately; otherwise the abort listener is removed once the promise settles.
|
|
124
|
+
*
|
|
125
|
+
* @typeParam T Resolved value type of the wrapped promise.
|
|
126
|
+
* @param promise Promise (or thenable) whose wait should become abortable.
|
|
127
|
+
* @param abort Optional signal used to cancel the wait.
|
|
128
|
+
* @returns A promise mirroring `promise` unless the abort fires first.
|
|
129
|
+
*/
|
|
130
|
+
function abortable(promise, abort) {
|
|
131
|
+
if (!abort)
|
|
132
|
+
return Promise.resolve(promise);
|
|
133
|
+
if (abort.aborted)
|
|
134
|
+
return Promise.reject(abort.reason);
|
|
95
135
|
return new Promise((resolve, reject) => {
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
};
|
|
101
|
-
const timer = setTimeout(() => {
|
|
102
|
-
abort?.removeEventListener("abort", onAbort);
|
|
103
|
-
reject(new TimeoutError());
|
|
104
|
-
}, timeout);
|
|
105
|
-
abort?.addEventListener("abort", onAbort, { once: true });
|
|
106
|
-
promise
|
|
107
|
-
.then(result => resolve(result))
|
|
108
|
-
.catch(reason => reject(reason))
|
|
109
|
-
.finally(() => {
|
|
110
|
-
clearTimeout(timer);
|
|
111
|
-
abort?.removeEventListener("abort", onAbort);
|
|
112
|
-
});
|
|
136
|
+
const onAbort = () => reject(abort.reason);
|
|
137
|
+
abort.addEventListener("abort", onAbort, { once: true });
|
|
138
|
+
const cleanup = () => abort.removeEventListener("abort", onAbort);
|
|
139
|
+
Promise.resolve(promise).then(v => { cleanup(); resolve(v); }, e => { cleanup(); reject(e); });
|
|
113
140
|
});
|
|
114
141
|
}
|
|
115
142
|
/** Thrown by {@link timeout} when the time limit is exceeded. */
|
|
@@ -120,5 +147,5 @@ class TimeoutError extends Error {
|
|
|
120
147
|
}
|
|
121
148
|
}
|
|
122
149
|
|
|
123
|
-
export { TimeoutError, delay, minWait, minWaitAsync, timeout };
|
|
150
|
+
export { TimeoutError, abortable, delay, minWait, minWaitAsync, timeout };
|
|
124
151
|
//# sourceMappingURL=func.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"func.js","sources":["../../../../source/helpers/func.ts"],"sourcesContent":[null],"names":[],"mappings":"AAAA;;;;;;;;;;AAUG;AACH,MAAM,OAAO,GAAG,CAAC,IAA8B,EAAE,OAAgB,KAAI;AACpE,IAAA,IAAI,CAAC,OAAO;AACX,QAAA,OAAO,IAAI;AAEZ,IAAA,MAAM,SAAS,GAAG,IAAI,CAAC,GAAG,EAAE;AAE5B,IAAA,MAAM,GAAG,GAAG,CAAC,GAAG,IAAW,KAAI;QAC9B,MAAM,SAAS,GAAG,YAAY,CAAC,SAAS,EAAE,OAAO,CAAC;AAClD,QAAA,IAAI,SAAS;AACZ,YAAA,UAAU,CAAC,MAAM,IAAI,CAAC,GAAG,IAAI,CAAC,EAAE,SAAS,CAAC;;AAE1C,YAAA,IAAI,CAAC,GAAG,IAAI,CAAC;AACf,IAAA,CAAC;AAED,IAAA,OAAO,GAAG;AACX;AAEA
|
|
1
|
+
{"version":3,"file":"func.js","sources":["../../../../source/helpers/func.ts"],"sourcesContent":[null],"names":[],"mappings":"AAAA;;;;;;;;;;AAUG;AACH,MAAM,OAAO,GAAG,CAAC,IAA8B,EAAE,OAAgB,KAAI;AACpE,IAAA,IAAI,CAAC,OAAO;AACX,QAAA,OAAO,IAAI;AAEZ,IAAA,MAAM,SAAS,GAAG,IAAI,CAAC,GAAG,EAAE;AAE5B,IAAA,MAAM,GAAG,GAAG,CAAC,GAAG,IAAW,KAAI;QAC9B,MAAM,SAAS,GAAG,YAAY,CAAC,SAAS,EAAE,OAAO,CAAC;AAClD,QAAA,IAAI,SAAS;AACZ,YAAA,UAAU,CAAC,MAAM,IAAI,CAAC,GAAG,IAAI,CAAC,EAAE,SAAS,CAAC;;AAE1C,YAAA,IAAI,CAAC,GAAG,IAAI,CAAC;AACf,IAAA,CAAC;AAED,IAAA,OAAO,GAAG;AACX;AAEA;;;;;;;;;;;;;;;AAeG;AACH,eAAe,YAAY,CAAoB,IAA4B,EAAE,OAAgB,EAAE,KAAmB,EAAA;IACjH,KAAK,EAAE,cAAc,EAAE;AAEvB,IAAA,IAAI,CAAC,OAAO;QACX,OAAO,IAAI,EAAE;AAEd,IAAA,MAAM,SAAS,GAAG,IAAI,CAAC,GAAG,EAAE;AAC5B,IAAA,MAAM,MAAM,GAAG,MAAM,IAAI,EAAE;IAE3B,MAAM,SAAS,GAAG,YAAY,CAAC,SAAS,EAAE,OAAO,CAAC;AAClD,IAAA,IAAI,SAAS;AACZ,QAAA,MAAM,KAAK,CAAC,SAAS,EAAE,KAAK,CAAC;AAE9B,IAAA,OAAO,MAAM;AACd;AAEA;AACA,MAAM,YAAY,GAAG,CAAC,KAAa,EAAE,OAAe,KAAI;AACvD,IAAA,MAAM,UAAU,GAAG,IAAI,CAAC,GAAG,EAAE;IAC7B,MAAM,CAAC,GAAG,OAAO,IAAI,UAAU,GAAG,KAAK,CAAC;;;AAIxC,IAAA,OAAO,CAAC,GAAG,OAAO,GAAG,GAAG,GAAG,CAAC,GAAG,CAAC;AACjC,CAAC;AAED;;;;;;;;;;;AAWG;AACH,SAAS,KAAK,CAAC,EAAU,EAAE,KAAmB,EAAA;IAC7C,IAAI,EAAE,GAAG,CAAC;AACT,QAAA,MAAM,IAAI,KAAK,CAAC,sBAAsB,CAAC;IAExC,OAAO,IAAI,OAAO,CAAO,CAAC,OAAO,EAAE,MAAM,KAAI;QAC5C,KAAK,EAAE,cAAc,EAAE;QAEvB,MAAM,OAAO,GAAG,MAAK;YACpB,YAAY,CAAC,KAAK,CAAC;;AAEnB,YAAA,MAAM,CAAC,KAAM,CAAC,MAAM,CAAC;AACtB,QAAA,CAAC;AAED,QAAA,MAAM,KAAK,GAAG,UAAU,CAAC,MAAK;AAC7B,YAAA,KAAK,EAAE,mBAAmB,CAAC,OAAO,EAAE,OAAO,CAAC;AAC5C,YAAA,OAAO,EAAE;QACV,CAAC,EAAE,EAAE,CAAC;AAEN,QAAA,KAAK,EAAE,gBAAgB,CAAC,OAAO,EAAE,OAAO,EAAE,EAAE,IAAI,EAAE,IAAI,EAAE,CAAC;AAC1D,IAAA,CAAC,CAAC;AACH;AAEA;;;;;;;;;;;;;;AAcG;AACH,SAAS,OAAO,CAAc,OAAmB,EAAE,EAAU,EAAE,KAAmB,EAAA;IACjF,IAAI,EAAE,IAAI,CAAC;AACV,QAAA,MAAM,IAAI,KAAK,CAAC,wBAAwB,CAAC;;;AAI1C,IAAA,MAAM,KAAK,GAAG,IAAI,eAAe,EAAE;;;;;AAMnC,IAAA,MAAM,MAAM,GAAG,KAAK,CAAC,EAAE,EAAE,KAAK,CAAC,MAAM,CAAC,CAAC,IAAI,CAC1C,MAAM,OAAO,CAAC,MAAM,CAAI,IAAI,YAAY,EAAE,CAAC,EAC3C,MAAM,IAAI,OAAO,CAAI,QAA0D,CAAC,CAAC,CACjF;AAED,IAAA,OAAO,SAAS,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,OAAO,EAAE,MAAM,CAAC,CAAC,EAAE,KAAK;SACrD,OAAO,CAAC,MAAM,KAAK,CAAC,KAAK,EAAE,CAAC;AAC/B;AAEA;;;;;;;;;;;AAWG;AACH,SAAS,SAAS,CAAI,OAAuB,EAAE,KAAmB,EAAA;AACjE,IAAA,IAAI,CAAC,KAAK;AACT,QAAA,OAAO,OAAO,CAAC,OAAO,CAAC,OAAO,CAAC;IAEhC,IAAI,KAAK,CAAC,OAAO;QAChB,OAAO,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,MAAM,CAAC;IAEpC,OAAO,IAAI,OAAO,CAAI,CAAC,OAAO,EAAE,MAAM,KAAI;QACzC,MAAM,OAAO,GAAG,MAAM,MAAM,CAAC,KAAK,CAAC,MAAM,CAAC;AAC1C,QAAA,KAAK,CAAC,gBAAgB,CAAC,OAAO,EAAE,OAAO,EAAE,EAAE,IAAI,EAAE,IAAI,EAAE,CAAC;AAExD,QAAA,MAAM,OAAO,GAAG,MAAM,KAAK,CAAC,mBAAmB,CAAC,OAAO,EAAE,OAAO,CAAC;AACjE,QAAA,OAAO,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC,IAAI,CAC5B,CAAC,MAAM,OAAO,EAAE,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,EAC/B,CAAC,IAAG,EAAG,OAAO,EAAE,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAC9B;AACF,IAAA,CAAC,CAAC;AACH;AAEA;AACM,MAAO,YAAa,SAAQ,KAAK,CAAA;AACtC,IAAA,WAAA,GAAA;QACC,KAAK,CAAC,SAAS,CAAC;AAChB,QAAA,IAAI,CAAC,IAAI,GAAG,cAAc;IAC3B;AACA;;;;"}
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Runtime polyfills for `AbortSignal`, installed only when the host lacks them:
|
|
3
|
+
* `AbortSignal.prototype.throwIfAborted`, `AbortSignal.timeout` and `AbortSignal.any`.
|
|
4
|
+
*
|
|
5
|
+
* Import for its side effect — there are no exports:
|
|
6
|
+
*
|
|
7
|
+
* ```TypeScript
|
|
8
|
+
* import "@brandup/ui-helpers/polyfill";
|
|
9
|
+
* ```
|
|
10
|
+
*
|
|
11
|
+
* Types already ship with the TypeScript `ESNext` lib; this module only fills in the
|
|
12
|
+
* implementations missing in older runtimes, matching the standard behaviour.
|
|
13
|
+
*/
|
|
14
|
+
if (typeof AbortSignal.prototype.throwIfAborted !== "function") {
|
|
15
|
+
AbortSignal.prototype.throwIfAborted = function () {
|
|
16
|
+
if (this.aborted)
|
|
17
|
+
throw this.reason;
|
|
18
|
+
};
|
|
19
|
+
}
|
|
20
|
+
if (typeof AbortSignal.timeout !== "function") {
|
|
21
|
+
AbortSignal.timeout = (milliseconds) => {
|
|
22
|
+
const controller = new AbortController();
|
|
23
|
+
setTimeout(() => controller.abort(new DOMException("The operation timed out.", "TimeoutError")), milliseconds);
|
|
24
|
+
return controller.signal;
|
|
25
|
+
};
|
|
26
|
+
}
|
|
27
|
+
if (typeof AbortSignal.any !== "function") {
|
|
28
|
+
AbortSignal.any = (signals) => {
|
|
29
|
+
const controller = new AbortController();
|
|
30
|
+
for (const signal of signals) {
|
|
31
|
+
// If one is already aborted, the combined signal aborts immediately with its reason.
|
|
32
|
+
if (signal.aborted) {
|
|
33
|
+
controller.abort(signal.reason);
|
|
34
|
+
break;
|
|
35
|
+
}
|
|
36
|
+
// Tying each listener to the combined signal removes them all once it aborts — no leak.
|
|
37
|
+
signal.addEventListener("abort", () => controller.abort(signal.reason), { signal: controller.signal });
|
|
38
|
+
}
|
|
39
|
+
return controller.signal;
|
|
40
|
+
};
|
|
41
|
+
}
|
|
42
|
+
//# sourceMappingURL=polyfill.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"polyfill.js","sources":["../../../source/polyfill.ts"],"sourcesContent":[null],"names":[],"mappings":"AAAA;;;;;;;;;;;;AAYG;AAEH,IAAI,OAAO,WAAW,CAAC,SAAS,CAAC,cAAc,KAAK,UAAU,EAAE;AAC/D,IAAA,WAAW,CAAC,SAAS,CAAC,cAAc,GAAG,YAAA;QACtC,IAAI,IAAI,CAAC,OAAO;YACf,MAAM,IAAI,CAAC,MAAM;AACnB,IAAA,CAAC;AACF;AAEA,IAAI,OAAO,WAAW,CAAC,OAAO,KAAK,UAAU,EAAE;AAC9C,IAAA,WAAW,CAAC,OAAO,GAAG,CAAC,YAAoB,KAAiB;AAC3D,QAAA,MAAM,UAAU,GAAG,IAAI,eAAe,EAAE;AACxC,QAAA,UAAU,CAAC,MAAM,UAAU,CAAC,KAAK,CAAC,IAAI,YAAY,CAAC,0BAA0B,EAAE,cAAc,CAAC,CAAC,EAAE,YAAY,CAAC;QAC9G,OAAO,UAAU,CAAC,MAAM;AACzB,IAAA,CAAC;AACF;AAEA,IAAI,OAAO,WAAW,CAAC,GAAG,KAAK,UAAU,EAAE;AAC1C,IAAA,WAAW,CAAC,GAAG,GAAG,CAAC,OAAsB,KAAiB;AACzD,QAAA,MAAM,UAAU,GAAG,IAAI,eAAe,EAAE;AAExC,QAAA,KAAK,MAAM,MAAM,IAAI,OAAO,EAAE;;AAE7B,YAAA,IAAI,MAAM,CAAC,OAAO,EAAE;AACnB,gBAAA,UAAU,CAAC,KAAK,CAAC,MAAM,CAAC,MAAM,CAAC;gBAC/B;YACD;;YAGA,MAAM,CAAC,gBAAgB,CAAC,OAAO,EAAE,MAAM,UAAU,CAAC,KAAK,CAAC,MAAM,CAAC,MAAM,CAAC,EAAE,EAAE,MAAM,EAAE,UAAU,CAAC,MAAM,EAAE,CAAC;QACvG;QAEA,OAAO,UAAU,CAAC,MAAM;AACzB,IAAA,CAAC;AACF"}
|
package/dist/types.d.ts
CHANGED
|
@@ -74,10 +74,13 @@ declare const minWait: (func: (...args: any[]) => void, minTime?: number) => (..
|
|
|
74
74
|
* Useful for keeping spinners/loading states visible for a minimum duration. If `minTime`
|
|
75
75
|
* is omitted or falsy, `func` is awaited and its result returned without padding.
|
|
76
76
|
*
|
|
77
|
+
* An already-aborted signal rejects immediately, before `func` runs; aborting later cancels
|
|
78
|
+
* the padding delay (but not `func` itself, which can't be cancelled here).
|
|
79
|
+
*
|
|
77
80
|
* @typeParam TResult Result type produced by `func`.
|
|
78
81
|
* @param func Factory returning the promise to await.
|
|
79
82
|
* @param minTime Minimum total duration in milliseconds.
|
|
80
|
-
* @param abort Optional signal used to cancel the
|
|
83
|
+
* @param abort Optional signal used to cancel the wait.
|
|
81
84
|
* @returns The result produced by `func`.
|
|
82
85
|
*/
|
|
83
86
|
declare function minWaitAsync<TResult = unknown>(func: () => Promise<TResult>, minTime?: number, abort?: AbortSignal): Promise<TResult>;
|
|
@@ -87,11 +90,13 @@ declare function minWaitAsync<TResult = unknown>(func: () => Promise<TResult>, m
|
|
|
87
90
|
* If an already-aborted signal is supplied the promise rejects immediately; otherwise
|
|
88
91
|
* aborting before the delay elapses clears the timer and rejects with the abort reason.
|
|
89
92
|
*
|
|
90
|
-
* @param
|
|
93
|
+
* @param ms Delay in milliseconds; must not be negative. Values above 2147483647 (~24.8 days)
|
|
94
|
+
* overflow the timer and fire on the next tick — a `setTimeout` limitation.
|
|
91
95
|
* @param abort Optional signal used to cancel the delay.
|
|
92
96
|
* @returns A promise that resolves when the delay elapses.
|
|
97
|
+
* @throws {Error} When `ms` is negative.
|
|
93
98
|
*/
|
|
94
|
-
declare function delay(
|
|
99
|
+
declare function delay(ms: number, abort?: AbortSignal): Promise<void>;
|
|
95
100
|
/**
|
|
96
101
|
* Races a promise against a timeout.
|
|
97
102
|
*
|
|
@@ -101,12 +106,26 @@ declare function delay(time: number, abort?: AbortSignal): Promise<void>;
|
|
|
101
106
|
*
|
|
102
107
|
* @typeParam T Resolved value type of the wrapped promise.
|
|
103
108
|
* @param promise Promise to guard with a timeout.
|
|
104
|
-
* @param
|
|
109
|
+
* @param ms Timeout in milliseconds; must be greater than `0`. Values above 2147483647
|
|
110
|
+
* (~24.8 days) overflow the timer and fire on the next tick — a `setTimeout` limitation.
|
|
105
111
|
* @param abort Optional signal used to cancel the wait.
|
|
106
112
|
* @returns A promise mirroring `promise` unless the timeout or abort fires first.
|
|
107
|
-
* @throws {Error} When `
|
|
113
|
+
* @throws {Error} When `ms` is not greater than `0`.
|
|
114
|
+
*/
|
|
115
|
+
declare function timeout<T = unknown>(promise: Promise<T>, ms: number, abort?: AbortSignal): Promise<T>;
|
|
116
|
+
/**
|
|
117
|
+
* Makes *waiting* for a promise abortable: rejects with the signal's reason on abort.
|
|
118
|
+
* Does not stop the underlying work the promise performs.
|
|
119
|
+
*
|
|
120
|
+
* If no signal is supplied the promise is awaited as-is. An already-aborted signal rejects
|
|
121
|
+
* immediately; otherwise the abort listener is removed once the promise settles.
|
|
122
|
+
*
|
|
123
|
+
* @typeParam T Resolved value type of the wrapped promise.
|
|
124
|
+
* @param promise Promise (or thenable) whose wait should become abortable.
|
|
125
|
+
* @param abort Optional signal used to cancel the wait.
|
|
126
|
+
* @returns A promise mirroring `promise` unless the abort fires first.
|
|
108
127
|
*/
|
|
109
|
-
declare function
|
|
128
|
+
declare function abortable<T>(promise: PromiseLike<T>, abort?: AbortSignal): Promise<T>;
|
|
110
129
|
/** Thrown by {@link timeout} when the time limit is exceeded. */
|
|
111
130
|
declare class TimeoutError extends Error {
|
|
112
131
|
constructor();
|
|
@@ -114,6 +133,7 @@ declare class TimeoutError extends Error {
|
|
|
114
133
|
|
|
115
134
|
type func_TimeoutError = TimeoutError;
|
|
116
135
|
declare const func_TimeoutError: typeof TimeoutError;
|
|
136
|
+
declare const func_abortable: typeof abortable;
|
|
117
137
|
declare const func_delay: typeof delay;
|
|
118
138
|
declare const func_minWait: typeof minWait;
|
|
119
139
|
declare const func_minWaitAsync: typeof minWaitAsync;
|
|
@@ -121,6 +141,7 @@ declare const func_timeout: typeof timeout;
|
|
|
121
141
|
declare namespace func {
|
|
122
142
|
export {
|
|
123
143
|
func_TimeoutError as TimeoutError,
|
|
144
|
+
func_abortable as abortable,
|
|
124
145
|
func_delay as delay,
|
|
125
146
|
func_minWait as minWait,
|
|
126
147
|
func_minWaitAsync as minWaitAsync,
|
package/package.json
CHANGED
|
@@ -22,16 +22,24 @@
|
|
|
22
22
|
"email": "it@brandup.online"
|
|
23
23
|
},
|
|
24
24
|
"license": "Apache-2.0",
|
|
25
|
-
"version": "2.0.
|
|
25
|
+
"version": "2.0.4",
|
|
26
26
|
"main": "dist/cjs/index.js",
|
|
27
27
|
"module": "dist/mjs/index.js",
|
|
28
28
|
"types": "dist/types.d.ts",
|
|
29
|
-
"sideEffects":
|
|
29
|
+
"sideEffects": [
|
|
30
|
+
"./dist/cjs/polyfill.js",
|
|
31
|
+
"./dist/mjs/polyfill.js"
|
|
32
|
+
],
|
|
30
33
|
"exports": {
|
|
31
34
|
".": {
|
|
32
35
|
"types": "./dist/types.d.ts",
|
|
33
36
|
"import": "./dist/mjs/index.js",
|
|
34
37
|
"require": "./dist/cjs/index.js"
|
|
38
|
+
},
|
|
39
|
+
"./polyfill": {
|
|
40
|
+
"types": "./dist/polyfill.d.ts",
|
|
41
|
+
"import": "./dist/mjs/polyfill.js",
|
|
42
|
+
"require": "./dist/cjs/polyfill.js"
|
|
35
43
|
}
|
|
36
44
|
},
|
|
37
45
|
"files": [
|