@useless-engineer/utils 0.1.1 → 0.1.2
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 +8 -9
- package/dist/index.cjs +57 -2
- package/dist/index.d.cts +24 -1
- package/dist/index.d.ts +24 -1
- package/dist/index.js +55 -3
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -91,7 +91,7 @@ const padding = isIOS ? 20 : 16;
|
|
|
91
91
|
### Core
|
|
92
92
|
|
|
93
93
|
<details>
|
|
94
|
-
<summary><code>debounce(fn, delay)</code>
|
|
94
|
+
<summary><code>debounce(fn, delay)</code> <img alt="live" src="https://img.shields.io/badge/-live-22c55e?style=flat-square"> <img alt="async" src="https://img.shields.io/badge/-async-6366f1?style=flat-square"></summary>
|
|
95
95
|
|
|
96
96
|
<br>
|
|
97
97
|
|
|
@@ -117,7 +117,7 @@ save.cancel();
|
|
|
117
117
|
</details>
|
|
118
118
|
|
|
119
119
|
<details>
|
|
120
|
-
<summary><code>throttle(fn, interval, options?)</code>
|
|
120
|
+
<summary><code>throttle(fn, interval, options?)</code> <img alt="live" src="https://img.shields.io/badge/-live-22c55e?style=flat-square"> <img alt="async" src="https://img.shields.io/badge/-async-6366f1?style=flat-square"></summary>
|
|
121
121
|
|
|
122
122
|
<br>
|
|
123
123
|
|
|
@@ -158,7 +158,7 @@ Returns a function with `.cancel()`.
|
|
|
158
158
|
### React Native
|
|
159
159
|
|
|
160
160
|
<details>
|
|
161
|
-
<summary><code>isIOS</code> / <code>isAndroid</code>
|
|
161
|
+
<summary><code>isIOS</code> / <code>isAndroid</code> <img alt="live" src="https://img.shields.io/badge/-live-22c55e?style=flat-square"> <img alt="react native" src="https://img.shields.io/badge/-react%20native-61DAFB?style=flat-square&logoColor=black"></summary>
|
|
162
162
|
|
|
163
163
|
<br>
|
|
164
164
|
|
|
@@ -178,12 +178,11 @@ const behavior = isIOS ? "padding" : "height";
|
|
|
178
178
|
|
|
179
179
|
Released one or two at a time, each matching a post that's already live.
|
|
180
180
|
|
|
181
|
-
| Next up | Entry | Origin
|
|
182
|
-
| ------------------------------------------------------------------------------------------------------------------------ | ------------ |
|
|
183
|
-
|  `
|
|
184
|
-
|  `
|
|
185
|
-
|  `
|
|
186
|
-
|  `useInterval`, `useCountdown`, `useIsMounted` | react | Stale closures and unmounted updates |
|
|
181
|
+
| Next up | Entry | Origin |
|
|
182
|
+
| ------------------------------------------------------------------------------------------------------------------------ | ------------ | ------------------------------------ |
|
|
183
|
+
| `safeParseJSON`, `safeStringify`, `deepClone` | core | JSON and shallow-copy gotchas |
|
|
184
|
+
|  `getAccessibilityProps`, `createShadow` | react-native | Accessibility and iOS-only shadows |
|
|
185
|
+
|  `useInterval`, `useCountdown`, `useIsMounted` | react | Stale closures and unmounted updates |
|
|
187
186
|
|
|
188
187
|
---
|
|
189
188
|
|
package/dist/index.cjs
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
3
|
// src/async/debounce.ts
|
|
4
|
-
function debounce(fn,
|
|
4
|
+
function debounce(fn, delay2) {
|
|
5
5
|
let timer;
|
|
6
6
|
const debounced = (...args) => {
|
|
7
7
|
if (timer !== void 0) clearTimeout(timer);
|
|
8
8
|
timer = setTimeout(() => {
|
|
9
9
|
timer = void 0;
|
|
10
10
|
fn(...args);
|
|
11
|
-
},
|
|
11
|
+
}, delay2);
|
|
12
12
|
};
|
|
13
13
|
debounced.cancel = () => {
|
|
14
14
|
if (timer !== void 0) clearTimeout(timer);
|
|
@@ -56,5 +56,60 @@ function throttle(fn, interval, { leading = true, trailing = true } = {}) {
|
|
|
56
56
|
return throttled;
|
|
57
57
|
}
|
|
58
58
|
|
|
59
|
+
// src/async/delay.ts
|
|
60
|
+
function delay(ms, { signal } = {}) {
|
|
61
|
+
if (typeof ms !== "number" || !Number.isFinite(ms) || ms < 0) {
|
|
62
|
+
return Promise.reject(
|
|
63
|
+
new RangeError(`delay: expected a finite, non-negative number of ms, got ${String(ms)}`)
|
|
64
|
+
);
|
|
65
|
+
}
|
|
66
|
+
if (signal?.aborted) return Promise.reject(signal.reason);
|
|
67
|
+
return new Promise((resolve, reject) => {
|
|
68
|
+
const onAbort = () => {
|
|
69
|
+
clearTimeout(timer);
|
|
70
|
+
reject(signal.reason);
|
|
71
|
+
};
|
|
72
|
+
const timer = setTimeout(() => {
|
|
73
|
+
signal?.removeEventListener("abort", onAbort);
|
|
74
|
+
resolve();
|
|
75
|
+
}, ms);
|
|
76
|
+
signal?.addEventListener("abort", onAbort, { once: true });
|
|
77
|
+
});
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
// src/async/withTimeout.ts
|
|
81
|
+
var TimeoutError = class extends Error {
|
|
82
|
+
constructor(message = "Operation timed out") {
|
|
83
|
+
super(message);
|
|
84
|
+
this.name = "TimeoutError";
|
|
85
|
+
}
|
|
86
|
+
};
|
|
87
|
+
function withTimeout(promise, ms, message) {
|
|
88
|
+
if (typeof ms !== "number" || !Number.isFinite(ms) || ms < 0) {
|
|
89
|
+
return Promise.reject(
|
|
90
|
+
new RangeError(`withTimeout: expected a finite, non-negative number of ms, got ${String(ms)}`)
|
|
91
|
+
);
|
|
92
|
+
}
|
|
93
|
+
return new Promise((resolve, reject) => {
|
|
94
|
+
const timer = setTimeout(
|
|
95
|
+
() => reject(new TimeoutError(message ?? `Timed out after ${ms}ms`)),
|
|
96
|
+
ms
|
|
97
|
+
);
|
|
98
|
+
Promise.resolve(promise).then(
|
|
99
|
+
(value) => {
|
|
100
|
+
clearTimeout(timer);
|
|
101
|
+
resolve(value);
|
|
102
|
+
},
|
|
103
|
+
(error) => {
|
|
104
|
+
clearTimeout(timer);
|
|
105
|
+
reject(error);
|
|
106
|
+
}
|
|
107
|
+
);
|
|
108
|
+
});
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
exports.TimeoutError = TimeoutError;
|
|
59
112
|
exports.debounce = debounce;
|
|
113
|
+
exports.delay = delay;
|
|
60
114
|
exports.throttle = throttle;
|
|
115
|
+
exports.withTimeout = withTimeout;
|
package/dist/index.d.cts
CHANGED
|
@@ -26,4 +26,27 @@ interface Throttled<A extends unknown[]> {
|
|
|
26
26
|
*/
|
|
27
27
|
declare function throttle<A extends unknown[]>(fn: (...args: A) => void, interval: number, { leading, trailing }?: ThrottleOptions): Throttled<A>;
|
|
28
28
|
|
|
29
|
-
|
|
29
|
+
interface DelayOptions {
|
|
30
|
+
/** Abort to stop waiting early. The promise rejects with `signal.reason`. */
|
|
31
|
+
signal?: AbortSignal;
|
|
32
|
+
}
|
|
33
|
+
/**
|
|
34
|
+
* Resolves after `ms` milliseconds.
|
|
35
|
+
*
|
|
36
|
+
* Unlike a bare `setTimeout`, it rejects bad input (NaN, negative, Infinity)
|
|
37
|
+
* instead of silently firing immediately, and it can be cancelled.
|
|
38
|
+
*/
|
|
39
|
+
declare function delay(ms: number, { signal }?: DelayOptions): Promise<void>;
|
|
40
|
+
|
|
41
|
+
declare class TimeoutError extends Error {
|
|
42
|
+
constructor(message?: string);
|
|
43
|
+
}
|
|
44
|
+
/**
|
|
45
|
+
* Rejects with `TimeoutError` if `promise` hasn't settled within `ms`.
|
|
46
|
+
*
|
|
47
|
+
* Note: this stops *waiting*, it does not stop the underlying work.
|
|
48
|
+
* To cancel a request too, pass an AbortSignal to it as well.
|
|
49
|
+
*/
|
|
50
|
+
declare function withTimeout<T>(promise: PromiseLike<T>, ms: number, message?: string): Promise<T>;
|
|
51
|
+
|
|
52
|
+
export { type Debounced, type DelayOptions, type ThrottleOptions, type Throttled, TimeoutError, debounce, delay, throttle, withTimeout };
|
package/dist/index.d.ts
CHANGED
|
@@ -26,4 +26,27 @@ interface Throttled<A extends unknown[]> {
|
|
|
26
26
|
*/
|
|
27
27
|
declare function throttle<A extends unknown[]>(fn: (...args: A) => void, interval: number, { leading, trailing }?: ThrottleOptions): Throttled<A>;
|
|
28
28
|
|
|
29
|
-
|
|
29
|
+
interface DelayOptions {
|
|
30
|
+
/** Abort to stop waiting early. The promise rejects with `signal.reason`. */
|
|
31
|
+
signal?: AbortSignal;
|
|
32
|
+
}
|
|
33
|
+
/**
|
|
34
|
+
* Resolves after `ms` milliseconds.
|
|
35
|
+
*
|
|
36
|
+
* Unlike a bare `setTimeout`, it rejects bad input (NaN, negative, Infinity)
|
|
37
|
+
* instead of silently firing immediately, and it can be cancelled.
|
|
38
|
+
*/
|
|
39
|
+
declare function delay(ms: number, { signal }?: DelayOptions): Promise<void>;
|
|
40
|
+
|
|
41
|
+
declare class TimeoutError extends Error {
|
|
42
|
+
constructor(message?: string);
|
|
43
|
+
}
|
|
44
|
+
/**
|
|
45
|
+
* Rejects with `TimeoutError` if `promise` hasn't settled within `ms`.
|
|
46
|
+
*
|
|
47
|
+
* Note: this stops *waiting*, it does not stop the underlying work.
|
|
48
|
+
* To cancel a request too, pass an AbortSignal to it as well.
|
|
49
|
+
*/
|
|
50
|
+
declare function withTimeout<T>(promise: PromiseLike<T>, ms: number, message?: string): Promise<T>;
|
|
51
|
+
|
|
52
|
+
export { type Debounced, type DelayOptions, type ThrottleOptions, type Throttled, TimeoutError, debounce, delay, throttle, withTimeout };
|
package/dist/index.js
CHANGED
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
// src/async/debounce.ts
|
|
2
|
-
function debounce(fn,
|
|
2
|
+
function debounce(fn, delay2) {
|
|
3
3
|
let timer;
|
|
4
4
|
const debounced = (...args) => {
|
|
5
5
|
if (timer !== void 0) clearTimeout(timer);
|
|
6
6
|
timer = setTimeout(() => {
|
|
7
7
|
timer = void 0;
|
|
8
8
|
fn(...args);
|
|
9
|
-
},
|
|
9
|
+
}, delay2);
|
|
10
10
|
};
|
|
11
11
|
debounced.cancel = () => {
|
|
12
12
|
if (timer !== void 0) clearTimeout(timer);
|
|
@@ -54,4 +54,56 @@ function throttle(fn, interval, { leading = true, trailing = true } = {}) {
|
|
|
54
54
|
return throttled;
|
|
55
55
|
}
|
|
56
56
|
|
|
57
|
-
|
|
57
|
+
// src/async/delay.ts
|
|
58
|
+
function delay(ms, { signal } = {}) {
|
|
59
|
+
if (typeof ms !== "number" || !Number.isFinite(ms) || ms < 0) {
|
|
60
|
+
return Promise.reject(
|
|
61
|
+
new RangeError(`delay: expected a finite, non-negative number of ms, got ${String(ms)}`)
|
|
62
|
+
);
|
|
63
|
+
}
|
|
64
|
+
if (signal?.aborted) return Promise.reject(signal.reason);
|
|
65
|
+
return new Promise((resolve, reject) => {
|
|
66
|
+
const onAbort = () => {
|
|
67
|
+
clearTimeout(timer);
|
|
68
|
+
reject(signal.reason);
|
|
69
|
+
};
|
|
70
|
+
const timer = setTimeout(() => {
|
|
71
|
+
signal?.removeEventListener("abort", onAbort);
|
|
72
|
+
resolve();
|
|
73
|
+
}, ms);
|
|
74
|
+
signal?.addEventListener("abort", onAbort, { once: true });
|
|
75
|
+
});
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
// src/async/withTimeout.ts
|
|
79
|
+
var TimeoutError = class extends Error {
|
|
80
|
+
constructor(message = "Operation timed out") {
|
|
81
|
+
super(message);
|
|
82
|
+
this.name = "TimeoutError";
|
|
83
|
+
}
|
|
84
|
+
};
|
|
85
|
+
function withTimeout(promise, ms, message) {
|
|
86
|
+
if (typeof ms !== "number" || !Number.isFinite(ms) || ms < 0) {
|
|
87
|
+
return Promise.reject(
|
|
88
|
+
new RangeError(`withTimeout: expected a finite, non-negative number of ms, got ${String(ms)}`)
|
|
89
|
+
);
|
|
90
|
+
}
|
|
91
|
+
return new Promise((resolve, reject) => {
|
|
92
|
+
const timer = setTimeout(
|
|
93
|
+
() => reject(new TimeoutError(message ?? `Timed out after ${ms}ms`)),
|
|
94
|
+
ms
|
|
95
|
+
);
|
|
96
|
+
Promise.resolve(promise).then(
|
|
97
|
+
(value) => {
|
|
98
|
+
clearTimeout(timer);
|
|
99
|
+
resolve(value);
|
|
100
|
+
},
|
|
101
|
+
(error) => {
|
|
102
|
+
clearTimeout(timer);
|
|
103
|
+
reject(error);
|
|
104
|
+
}
|
|
105
|
+
);
|
|
106
|
+
});
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
export { TimeoutError, debounce, delay, throttle, withTimeout };
|