@cripty2001/utils 0.0.143 → 0.0.145
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/react-whispr.d.ts +50 -6
- package/dist/react-whispr.js +59 -7
- package/package.json +2 -2
package/dist/react-whispr.d.ts
CHANGED
|
@@ -30,8 +30,9 @@ export declare function useWhispr<T>(data: T | Whispr<T>): Whispr<T>;
|
|
|
30
30
|
* Subscribe a callback to a Whispr inside a react component, properly handling unsubscription on unmount.
|
|
31
31
|
* @param w The whispr to subscribe to
|
|
32
32
|
* @param cb The callback to call on value change
|
|
33
|
+
* @param unsafe If true, the callback will be allowed to throw errors, that will then bubble up
|
|
33
34
|
*/
|
|
34
|
-
export declare function useOnWhispr<T>(w: Whispr<T>, cb: (value: T) => void): void;
|
|
35
|
+
export declare function useOnWhispr<T>(w: Whispr<T>, unsafe: boolean | undefined, cb: (value: T) => void): void;
|
|
35
36
|
/**
|
|
36
37
|
* Return a reactive current timestamp (ms), updated at the given interval.
|
|
37
38
|
* @returns The current timestamp
|
|
@@ -52,18 +53,61 @@ export declare function useDebounced<T>(value: T): T;
|
|
|
52
53
|
*/
|
|
53
54
|
export declare function useSynced<T extends any>(def: T, value: T | undefined, setValue: ((value: T) => void) | undefined): [T, React.Dispatch<React.SetStateAction<T>>];
|
|
54
55
|
/**
|
|
56
|
+
* Wraps an async function into a reactable data structure that tracks loading state, progress, and results.
|
|
55
57
|
*
|
|
56
|
-
*
|
|
58
|
+
* **Error Handling:** This function does NOT throw errors. Instead, errors are stored in the returned dispatcher's state.
|
|
59
|
+
* Check the dispatcher's `data` property to access the error state. The dispatcher's promise resolves successfully
|
|
60
|
+
* even when errors occur - errors are captured and stored in the reactive state for UI consumption.
|
|
57
61
|
*
|
|
58
|
-
* @param f The async function to call. It should return a promise that resolves to the data. It is not reactive
|
|
62
|
+
* @param f The async function to call. It should return a promise that resolves to the data. It is not reactive.
|
|
59
63
|
* @param data The data to give to f. It must be stable, as anything in the dependency array of the useEffect and similars in the react ecosystem. If null, this function will act like an useEffect with an empty dependency array.
|
|
60
|
-
* @param debouce Debounce time in ms. Default to 200ms. The async function will not be called if this time has not passed since the useAsync first invocation or value change. If another change happens during the wait, the first function call is never executed
|
|
61
|
-
* @returns
|
|
64
|
+
* @param debouce Debounce time in ms. Default to 200ms. The async function will not be called if this time has not passed since the useAsync first invocation or value change. If another change happens during the wait, the first function call is never executed.
|
|
65
|
+
* @returns A Dispatcher object containing:
|
|
66
|
+
* - `data`: A Whispr<DispatcherStatePayload<O>> that contains the loading state, progress, and either the result data or error
|
|
67
|
+
* - `filtered`: A Whispr<O | null> that contains the result data when successful, or null when loading or on error
|
|
62
68
|
*
|
|
63
69
|
* @type I Input for the async function.
|
|
64
|
-
* @type O Output for the async function
|
|
70
|
+
* @type O Output for the async function.
|
|
71
|
+
*
|
|
72
|
+
* @example
|
|
73
|
+
* const dispatcher = useAsync(async (userId) => {
|
|
74
|
+
* const response = await fetch(`/api/users/${userId}`);
|
|
75
|
+
* return response.json();
|
|
76
|
+
* }, userId);
|
|
77
|
+
*
|
|
78
|
+
* const state = useWhisprValue(dispatcher.data);
|
|
79
|
+
* // state can be: { loading: true, progress: 0 } | { loading: false, ok: true, data: T } | { loading: false, ok: false, error: Error }
|
|
80
|
+
*
|
|
81
|
+
* if (!state.loading && !state.ok) {
|
|
82
|
+
* console.error('Error:', state.error);
|
|
83
|
+
* }
|
|
65
84
|
*/
|
|
66
85
|
export declare function useAsync<I, O>(f: (input: I, setProgress: (p: number) => void, signal: AbortSignal) => Promise<O>, data: I, debouce?: number): Dispatcher<I, O>;
|
|
86
|
+
/**
|
|
87
|
+
* Async version of useEffect with debouncing. Executes an async function as a side effect when data changes.
|
|
88
|
+
*
|
|
89
|
+
* **Error Handling:** This function THROWS errors. Unlike `useAsync`, errors are not stored in state but are thrown
|
|
90
|
+
* as promise rejections. Use this when you want errors to propagate (e.g., to error boundaries or try/catch blocks).
|
|
91
|
+
*
|
|
92
|
+
* @param f The async function to execute. It should return a promise. It is not reactive.
|
|
93
|
+
* @param data The data that triggers the effect. It must be stable, as anything in the dependency array of useEffect.
|
|
94
|
+
* If null, this function will act like useEffect with an empty dependency array.
|
|
95
|
+
* @param debounce Debounce time in ms. Default to 200ms. The async function will not be called if this time has not
|
|
96
|
+
* passed since the last data change. If another change happens during the wait, the first function call is aborted.
|
|
97
|
+
*
|
|
98
|
+
* @remarks This function returns void - it is purely for side effects, similar to useEffect.
|
|
99
|
+
* @remarks Errors thrown by the async function will cause the promise to reject. If you need to handle errors
|
|
100
|
+
* in the UI without throwing, use `useAsync` instead.
|
|
101
|
+
*
|
|
102
|
+
* @example
|
|
103
|
+
* useAsyncEffect(async (userId, setProgress, signal) => {
|
|
104
|
+
* const response = await fetch(`/api/users/${userId}`, { signal });
|
|
105
|
+
* if (!response.ok) throw new Error('Failed to fetch');
|
|
106
|
+
* const data = await response.json();
|
|
107
|
+
* // Do something with data
|
|
108
|
+
* }, userId, 300);
|
|
109
|
+
*/
|
|
110
|
+
export declare function useAsyncEffect<I>(f: (input: I, setProgress: (p: number) => void, signal: AbortSignal) => Promise<void>, data: I, debounce?: number): void;
|
|
67
111
|
/**
|
|
68
112
|
* Format a timestamp into a relative time string (e.g. "5 minutes ago", "in 2 hours"), using the browser locale.
|
|
69
113
|
* The refreshed time is reactive.
|
package/dist/react-whispr.js
CHANGED
|
@@ -7,6 +7,7 @@ exports.useCurrentTimestamp = useCurrentTimestamp;
|
|
|
7
7
|
exports.useDebounced = useDebounced;
|
|
8
8
|
exports.useSynced = useSynced;
|
|
9
9
|
exports.useAsync = useAsync;
|
|
10
|
+
exports.useAsyncEffect = useAsyncEffect;
|
|
10
11
|
exports.useRelTime = useRelTime;
|
|
11
12
|
exports.useSearcher = useSearcher;
|
|
12
13
|
exports.useSafeRef = useSafeRef;
|
|
@@ -65,10 +66,11 @@ function useWhispr(data) {
|
|
|
65
66
|
* Subscribe a callback to a Whispr inside a react component, properly handling unsubscription on unmount.
|
|
66
67
|
* @param w The whispr to subscribe to
|
|
67
68
|
* @param cb The callback to call on value change
|
|
69
|
+
* @param unsafe If true, the callback will be allowed to throw errors, that will then bubble up
|
|
68
70
|
*/
|
|
69
|
-
function useOnWhispr(w, cb) {
|
|
71
|
+
function useOnWhispr(w, unsafe = false, cb) {
|
|
70
72
|
(0, react_1.useEffect)(() => {
|
|
71
|
-
const unsub = w.subscribe(cb);
|
|
73
|
+
const unsub = w.subscribe(cb, undefined, unsafe);
|
|
72
74
|
return () => unsub();
|
|
73
75
|
}, [w, cb]);
|
|
74
76
|
}
|
|
@@ -136,16 +138,34 @@ function useSynced(def, value, setValue) {
|
|
|
136
138
|
return [v, syncedSetter];
|
|
137
139
|
}
|
|
138
140
|
/**
|
|
141
|
+
* Wraps an async function into a reactable data structure that tracks loading state, progress, and results.
|
|
139
142
|
*
|
|
140
|
-
*
|
|
143
|
+
* **Error Handling:** This function does NOT throw errors. Instead, errors are stored in the returned dispatcher's state.
|
|
144
|
+
* Check the dispatcher's `data` property to access the error state. The dispatcher's promise resolves successfully
|
|
145
|
+
* even when errors occur - errors are captured and stored in the reactive state for UI consumption.
|
|
141
146
|
*
|
|
142
|
-
* @param f The async function to call. It should return a promise that resolves to the data. It is not reactive
|
|
147
|
+
* @param f The async function to call. It should return a promise that resolves to the data. It is not reactive.
|
|
143
148
|
* @param data The data to give to f. It must be stable, as anything in the dependency array of the useEffect and similars in the react ecosystem. If null, this function will act like an useEffect with an empty dependency array.
|
|
144
|
-
* @param debouce Debounce time in ms. Default to 200ms. The async function will not be called if this time has not passed since the useAsync first invocation or value change. If another change happens during the wait, the first function call is never executed
|
|
145
|
-
* @returns
|
|
149
|
+
* @param debouce Debounce time in ms. Default to 200ms. The async function will not be called if this time has not passed since the useAsync first invocation or value change. If another change happens during the wait, the first function call is never executed.
|
|
150
|
+
* @returns A Dispatcher object containing:
|
|
151
|
+
* - `data`: A Whispr<DispatcherStatePayload<O>> that contains the loading state, progress, and either the result data or error
|
|
152
|
+
* - `filtered`: A Whispr<O | null> that contains the result data when successful, or null when loading or on error
|
|
146
153
|
*
|
|
147
154
|
* @type I Input for the async function.
|
|
148
|
-
* @type O Output for the async function
|
|
155
|
+
* @type O Output for the async function.
|
|
156
|
+
*
|
|
157
|
+
* @example
|
|
158
|
+
* const dispatcher = useAsync(async (userId) => {
|
|
159
|
+
* const response = await fetch(`/api/users/${userId}`);
|
|
160
|
+
* return response.json();
|
|
161
|
+
* }, userId);
|
|
162
|
+
*
|
|
163
|
+
* const state = useWhisprValue(dispatcher.data);
|
|
164
|
+
* // state can be: { loading: true, progress: 0 } | { loading: false, ok: true, data: T } | { loading: false, ok: false, error: Error }
|
|
165
|
+
*
|
|
166
|
+
* if (!state.loading && !state.ok) {
|
|
167
|
+
* console.error('Error:', state.error);
|
|
168
|
+
* }
|
|
149
169
|
*/
|
|
150
170
|
function useAsync(f, data, debouce = 200) {
|
|
151
171
|
// Initing reactive input
|
|
@@ -160,6 +180,38 @@ function useAsync(f, data, debouce = 200) {
|
|
|
160
180
|
// Returning dispatcher
|
|
161
181
|
return dispatcher;
|
|
162
182
|
}
|
|
183
|
+
/**
|
|
184
|
+
* Async version of useEffect with debouncing. Executes an async function as a side effect when data changes.
|
|
185
|
+
*
|
|
186
|
+
* **Error Handling:** This function THROWS errors. Unlike `useAsync`, errors are not stored in state but are thrown
|
|
187
|
+
* as promise rejections. Use this when you want errors to propagate (e.g., to error boundaries or try/catch blocks).
|
|
188
|
+
*
|
|
189
|
+
* @param f The async function to execute. It should return a promise. It is not reactive.
|
|
190
|
+
* @param data The data that triggers the effect. It must be stable, as anything in the dependency array of useEffect.
|
|
191
|
+
* If null, this function will act like useEffect with an empty dependency array.
|
|
192
|
+
* @param debounce Debounce time in ms. Default to 200ms. The async function will not be called if this time has not
|
|
193
|
+
* passed since the last data change. If another change happens during the wait, the first function call is aborted.
|
|
194
|
+
*
|
|
195
|
+
* @remarks This function returns void - it is purely for side effects, similar to useEffect.
|
|
196
|
+
* @remarks Errors thrown by the async function will cause the promise to reject. If you need to handle errors
|
|
197
|
+
* in the UI without throwing, use `useAsync` instead.
|
|
198
|
+
*
|
|
199
|
+
* @example
|
|
200
|
+
* useAsyncEffect(async (userId, setProgress, signal) => {
|
|
201
|
+
* const response = await fetch(`/api/users/${userId}`, { signal });
|
|
202
|
+
* if (!response.ok) throw new Error('Failed to fetch');
|
|
203
|
+
* const data = await response.json();
|
|
204
|
+
* // Do something with data
|
|
205
|
+
* }, userId, 300);
|
|
206
|
+
*/
|
|
207
|
+
function useAsyncEffect(f, data, debounce = 200) {
|
|
208
|
+
const dispatcher = useAsync(f, data, debounce);
|
|
209
|
+
useOnWhispr(dispatcher.data, true, (data) => {
|
|
210
|
+
if (!data.loading && !data.ok) {
|
|
211
|
+
throw data.error;
|
|
212
|
+
}
|
|
213
|
+
});
|
|
214
|
+
}
|
|
163
215
|
/**
|
|
164
216
|
* Format a timestamp into a relative time string (e.g. "5 minutes ago", "in 2 hours"), using the browser locale.
|
|
165
217
|
* The refreshed time is reactive.
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@cripty2001/utils",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.145",
|
|
4
4
|
"description": "Internal Set of utils. If you need them use them, otherwise go to the next package ;)",
|
|
5
5
|
"homepage": "https://github.com/cripty2001/utils#readme",
|
|
6
6
|
"bugs": {
|
|
@@ -22,7 +22,7 @@
|
|
|
22
22
|
"dist"
|
|
23
23
|
],
|
|
24
24
|
"dependencies": {
|
|
25
|
-
"@cripty2001/whispr": "^0.2.
|
|
25
|
+
"@cripty2001/whispr": "^0.2.3",
|
|
26
26
|
"lodash": "^4.17.21"
|
|
27
27
|
},
|
|
28
28
|
"devDependencies": {
|