@sohanemon/utils 4.0.22 → 4.0.23
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/hooks/action.d.ts +20 -0
- package/dist/hooks/action.js +84 -0
- package/dist/hooks/async.d.ts +17 -0
- package/dist/hooks/async.js +44 -0
- package/dist/hooks/index.d.ts +3 -19
- package/dist/hooks/index.js +2 -43
- package/package.json +1 -1
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
type ActionType<Input, Result> = (input: Input) => Promise<Result>;
|
|
2
|
+
interface UseActionOptions<_Input, Result> {
|
|
3
|
+
onSuccess?: (data: Result) => void;
|
|
4
|
+
onError?: (error: Error) => void;
|
|
5
|
+
onSettled?: () => void;
|
|
6
|
+
}
|
|
7
|
+
export declare const useAction: <Input, Result>(action: ActionType<Input, Result>, options?: UseActionOptions<Input, Result>) => {
|
|
8
|
+
execute: (input: Input) => void;
|
|
9
|
+
executeAsync: (input: Input) => Promise<Result>;
|
|
10
|
+
reset: () => void;
|
|
11
|
+
useExecute: (input: Input) => void;
|
|
12
|
+
data: Result;
|
|
13
|
+
error: Error;
|
|
14
|
+
input: Input;
|
|
15
|
+
isIdle: boolean;
|
|
16
|
+
isLoading: boolean;
|
|
17
|
+
isSuccess: boolean;
|
|
18
|
+
isError: boolean;
|
|
19
|
+
};
|
|
20
|
+
export {};
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
import * as React from 'react';
|
|
2
|
+
import { useIsomorphicEffect } from '.';
|
|
3
|
+
export const useAction = (action, options) => {
|
|
4
|
+
const [status, setStatus] = React.useState('idle');
|
|
5
|
+
const [data, setData] = React.useState(null);
|
|
6
|
+
const [error, setError] = React.useState(null);
|
|
7
|
+
const [clientInput, setClientInput] = React.useState(undefined);
|
|
8
|
+
const [isTransitioning, startTransition] = React.useTransition();
|
|
9
|
+
// Derived state booleans
|
|
10
|
+
const isIdle = status === 'idle';
|
|
11
|
+
const isLoading = status === 'loading' || isTransitioning;
|
|
12
|
+
const isSuccess = status === 'success';
|
|
13
|
+
const isError = status === 'error';
|
|
14
|
+
const handleSuccess = React.useCallback((result) => {
|
|
15
|
+
setData(result);
|
|
16
|
+
setStatus('success');
|
|
17
|
+
options?.onSuccess?.(result); // Call onSuccess if provided
|
|
18
|
+
options?.onSettled?.(); // Call onSettled if provided
|
|
19
|
+
}, [options]);
|
|
20
|
+
const handleError = React.useCallback((err) => {
|
|
21
|
+
setError(err);
|
|
22
|
+
setStatus('error');
|
|
23
|
+
options?.onError?.(err); // Call onError if provided
|
|
24
|
+
options?.onSettled?.(); // Call onSettled if provided
|
|
25
|
+
}, [options]);
|
|
26
|
+
// Executes the action with the provided input, updating state accordingly
|
|
27
|
+
const execute = React.useCallback((input) => {
|
|
28
|
+
setClientInput(input);
|
|
29
|
+
setStatus('loading');
|
|
30
|
+
setError(null);
|
|
31
|
+
startTransition(() => {
|
|
32
|
+
action(input).then(handleSuccess).catch(handleError);
|
|
33
|
+
});
|
|
34
|
+
}, [action, handleSuccess, handleError]);
|
|
35
|
+
// Asynchronous version of execute for promise-based consumption
|
|
36
|
+
const executeAsync = React.useCallback((input) => {
|
|
37
|
+
return new Promise((resolve, reject) => {
|
|
38
|
+
setClientInput(input);
|
|
39
|
+
setStatus('loading');
|
|
40
|
+
setError(null);
|
|
41
|
+
startTransition(() => {
|
|
42
|
+
action(input)
|
|
43
|
+
.then((res) => {
|
|
44
|
+
handleSuccess(res);
|
|
45
|
+
resolve(res);
|
|
46
|
+
})
|
|
47
|
+
.catch((err) => {
|
|
48
|
+
handleError(err);
|
|
49
|
+
reject(err);
|
|
50
|
+
});
|
|
51
|
+
});
|
|
52
|
+
});
|
|
53
|
+
}, [action, handleSuccess, handleError]);
|
|
54
|
+
// Resets the hook's state to its initial "idle" status
|
|
55
|
+
const reset = React.useCallback(() => {
|
|
56
|
+
setStatus('idle');
|
|
57
|
+
setData(null);
|
|
58
|
+
setError(null);
|
|
59
|
+
setClientInput(undefined);
|
|
60
|
+
}, []);
|
|
61
|
+
// Hook to execute the action automatically on mount
|
|
62
|
+
const useExecute = (input) => {
|
|
63
|
+
useIsomorphicEffect(() => {
|
|
64
|
+
execute(input);
|
|
65
|
+
}, []);
|
|
66
|
+
};
|
|
67
|
+
return {
|
|
68
|
+
// Methods to trigger action
|
|
69
|
+
execute,
|
|
70
|
+
executeAsync,
|
|
71
|
+
reset,
|
|
72
|
+
// Hook for auto execution on mount
|
|
73
|
+
useExecute,
|
|
74
|
+
// Data and error objects
|
|
75
|
+
data,
|
|
76
|
+
error,
|
|
77
|
+
input: clientInput,
|
|
78
|
+
// Status booleans
|
|
79
|
+
isIdle,
|
|
80
|
+
isLoading,
|
|
81
|
+
isSuccess,
|
|
82
|
+
isError,
|
|
83
|
+
};
|
|
84
|
+
};
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
interface UseAsyncOptions<T extends (...args: any) => any> {
|
|
2
|
+
initialArgs?: Parameters<T>[0];
|
|
3
|
+
callback?: {
|
|
4
|
+
onSuccess?: (result: T) => void;
|
|
5
|
+
onError?: (error: Error) => void;
|
|
6
|
+
onExecute?: () => void;
|
|
7
|
+
onSettle?: () => void;
|
|
8
|
+
};
|
|
9
|
+
mode?: 'onLoad' | 'onTrigger';
|
|
10
|
+
}
|
|
11
|
+
export declare const useAsync: <T extends (...args: any) => any>(fn: T, opts?: UseAsyncOptions<T>) => {
|
|
12
|
+
execute: (args: Parameters<T>[0]) => Promise<void>;
|
|
13
|
+
isLoading: boolean;
|
|
14
|
+
result: Awaited<ReturnType<T>>;
|
|
15
|
+
error: Error;
|
|
16
|
+
};
|
|
17
|
+
export {};
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import { useState, useTransition, useCallback } from 'react';
|
|
2
|
+
import { useIsomorphicEffect } from '.';
|
|
3
|
+
export const useAsync = (fn, opts = {}) => {
|
|
4
|
+
const { initialArgs, callback = {}, mode = 'onTrigger' } = opts;
|
|
5
|
+
const { onSuccess, onError, onExecute, onSettle } = callback;
|
|
6
|
+
const [isLoading, setIsLoading] = useState(false);
|
|
7
|
+
const [result, setValue] = useState(null);
|
|
8
|
+
const [error, setError] = useState(null);
|
|
9
|
+
const [isPending, startTransition] = useTransition();
|
|
10
|
+
const execute = useCallback(async (args) => {
|
|
11
|
+
setIsLoading(true);
|
|
12
|
+
setValue(null);
|
|
13
|
+
setError(null);
|
|
14
|
+
onExecute?.();
|
|
15
|
+
try {
|
|
16
|
+
startTransition(() => {
|
|
17
|
+
(async () => {
|
|
18
|
+
const response = await fn(args);
|
|
19
|
+
setValue(response);
|
|
20
|
+
onSuccess?.(response);
|
|
21
|
+
})();
|
|
22
|
+
});
|
|
23
|
+
}
|
|
24
|
+
catch (error) {
|
|
25
|
+
setError(error);
|
|
26
|
+
onError?.(error);
|
|
27
|
+
}
|
|
28
|
+
finally {
|
|
29
|
+
setIsLoading(false);
|
|
30
|
+
onSettle?.();
|
|
31
|
+
}
|
|
32
|
+
}, [fn, onExecute, onSuccess, onError, onSettle]);
|
|
33
|
+
useIsomorphicEffect(() => {
|
|
34
|
+
if (mode === 'onLoad') {
|
|
35
|
+
execute(initialArgs);
|
|
36
|
+
}
|
|
37
|
+
}, []);
|
|
38
|
+
return {
|
|
39
|
+
execute,
|
|
40
|
+
isLoading: isLoading || isPending,
|
|
41
|
+
result,
|
|
42
|
+
error,
|
|
43
|
+
};
|
|
44
|
+
};
|
package/dist/hooks/index.d.ts
CHANGED
|
@@ -1,32 +1,16 @@
|
|
|
1
|
-
import { type Dispatch, type EffectCallback, type SetStateAction,
|
|
1
|
+
import { type Dispatch, type EffectCallback, type SetStateAction, useLayoutEffect } from 'react';
|
|
2
|
+
export * from './action';
|
|
2
3
|
export declare const useClickOutside: (callback?: () => void) => import("react").MutableRefObject<HTMLDivElement>;
|
|
3
4
|
export declare function useMediaQuery(tailwindBreakpoint: 'sm' | 'md' | 'lg' | 'xl' | '2xl' | `(${string})`): boolean;
|
|
4
5
|
export declare function useEffectOnce(effect: EffectCallback): void;
|
|
5
6
|
export declare function useUpdateEffect(effect: EffectCallback, deps: any[]): void;
|
|
6
7
|
export declare function useDebounce<T>(state: T, delay?: number): T;
|
|
7
|
-
export declare const useIsomorphicEffect: typeof
|
|
8
|
+
export declare const useIsomorphicEffect: typeof useLayoutEffect;
|
|
8
9
|
export declare function useTimeout(callback: () => void, delay?: number | null): void;
|
|
9
10
|
export declare function useWindowEvent<K extends string = keyof WindowEventMap>(type: K, listener: K extends keyof WindowEventMap ? (this: Window, ev: WindowEventMap[K]) => void : (this: Window, ev: CustomEvent) => void, options?: boolean | AddEventListenerOptions): void;
|
|
10
11
|
type LocalStorageValue<T> = [T, Dispatch<SetStateAction<T>>];
|
|
11
12
|
export declare const useLocalStorage: <T extends Record<string, any>>(key: string, defaultValue: T) => LocalStorageValue<T>;
|
|
12
13
|
export declare const useUrlParams: <T extends string | number | boolean>(key: string, defaultValue: T) => [T, (value: T) => void];
|
|
13
|
-
interface UseAsyncOptions<T extends (...args: any) => any> {
|
|
14
|
-
initialArgs?: Parameters<T>[0];
|
|
15
|
-
callback?: {
|
|
16
|
-
onSuccess?: (result: T) => void;
|
|
17
|
-
onError?: (error: Error) => void;
|
|
18
|
-
onExecute?: () => void;
|
|
19
|
-
onSettle?: () => void;
|
|
20
|
-
};
|
|
21
|
-
mode?: 'onLoad' | 'onTrigger';
|
|
22
|
-
}
|
|
23
|
-
export declare const useAsync: <T extends (...args: any) => any>(fn: T, opts?: UseAsyncOptions<T>) => {
|
|
24
|
-
execute: (args: Parameters<T>[0]) => Promise<void>;
|
|
25
|
-
isLoading: boolean;
|
|
26
|
-
result: Awaited<ReturnType<T>>;
|
|
27
|
-
error: Error;
|
|
28
|
-
};
|
|
29
14
|
export declare const useQuerySelector: <T extends Element>(selector: string) => T | null;
|
|
30
15
|
export declare function useIsClient(): boolean;
|
|
31
16
|
export declare function useLockScroll(): void;
|
|
32
|
-
export {};
|
package/dist/hooks/index.js
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
'use client';
|
|
2
|
-
import { useEffect, useLayoutEffect, useMemo,
|
|
2
|
+
import { useEffect, useLayoutEffect, useMemo, useRef, useState, } from 'react';
|
|
3
|
+
export * from './action';
|
|
3
4
|
export const useClickOutside = (callback = () => alert('clicked outside')) => {
|
|
4
5
|
const ref = useRef(null);
|
|
5
6
|
const listener = (e) => {
|
|
@@ -147,48 +148,6 @@ export const useUrlParams = (key, defaultValue) => {
|
|
|
147
148
|
};
|
|
148
149
|
return [value, updateValue];
|
|
149
150
|
};
|
|
150
|
-
export const useAsync = (fn, opts = {}) => {
|
|
151
|
-
const { initialArgs, callback = {}, mode = 'onTrigger' } = opts;
|
|
152
|
-
const { onSuccess, onError, onExecute, onSettle } = callback;
|
|
153
|
-
const [isLoading, setIsLoading] = useState(false);
|
|
154
|
-
const [result, setValue] = useState(null);
|
|
155
|
-
const [error, setError] = useState(null);
|
|
156
|
-
const [isPending, startTransition] = useTransition();
|
|
157
|
-
const execute = useCallback(async (args) => {
|
|
158
|
-
setIsLoading(true);
|
|
159
|
-
setValue(null);
|
|
160
|
-
setError(null);
|
|
161
|
-
onExecute?.();
|
|
162
|
-
try {
|
|
163
|
-
startTransition(() => {
|
|
164
|
-
(async () => {
|
|
165
|
-
const response = await fn(args);
|
|
166
|
-
setValue(response);
|
|
167
|
-
onSuccess?.(response);
|
|
168
|
-
})();
|
|
169
|
-
});
|
|
170
|
-
}
|
|
171
|
-
catch (error) {
|
|
172
|
-
setError(error);
|
|
173
|
-
onError?.(error);
|
|
174
|
-
}
|
|
175
|
-
finally {
|
|
176
|
-
setIsLoading(false);
|
|
177
|
-
onSettle?.();
|
|
178
|
-
}
|
|
179
|
-
}, [fn, onExecute, onSuccess, onError, onSettle]);
|
|
180
|
-
useIsomorphicEffect(() => {
|
|
181
|
-
if (mode === 'onLoad') {
|
|
182
|
-
execute(initialArgs);
|
|
183
|
-
}
|
|
184
|
-
}, []);
|
|
185
|
-
return {
|
|
186
|
-
execute,
|
|
187
|
-
isLoading: isLoading || isPending,
|
|
188
|
-
result,
|
|
189
|
-
error,
|
|
190
|
-
};
|
|
191
|
-
};
|
|
192
151
|
export const useQuerySelector = (selector) => {
|
|
193
152
|
const [element, setElement] = useState(null);
|
|
194
153
|
const elementRef = useRef(null);
|