@zayne-labs/toolkit-react 0.11.19 → 0.11.21
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/esm/hooks/createCustomContext.d.ts +21 -0
- package/dist/esm/hooks/createCustomContext.js +25 -0
- package/dist/esm/hooks/createCustomContext.js.map +1 -0
- package/dist/esm/hooks/effects/useAfterMountEffect.d.ts +7 -0
- package/dist/esm/hooks/effects/useAfterMountEffect.js +19 -0
- package/dist/esm/hooks/effects/useAfterMountEffect.js.map +1 -0
- package/dist/esm/hooks/effects/useAsyncEffect.d.ts +5 -0
- package/dist/esm/hooks/effects/useAsyncEffect.js +20 -0
- package/dist/esm/hooks/effects/useAsyncEffect.js.map +1 -0
- package/dist/esm/hooks/effects/useEffectOnce.d.ts +5 -0
- package/dist/esm/hooks/effects/useEffectOnce.js +17 -0
- package/dist/esm/hooks/effects/useEffectOnce.js.map +1 -0
- package/dist/esm/hooks/effects/useLifeCycle.d.ts +13 -0
- package/dist/esm/hooks/effects/useLifeCycle.js +16 -0
- package/dist/esm/hooks/effects/useLifeCycle.js.map +1 -0
- package/dist/esm/hooks/effects/useMountEffect.d.ts +5 -0
- package/dist/esm/hooks/effects/useMountEffect.js +10 -0
- package/dist/esm/hooks/effects/useMountEffect.js.map +1 -0
- package/dist/esm/hooks/effects/useUnMountEffect.d.ts +7 -0
- package/dist/esm/hooks/effects/useUnMountEffect.js +8 -0
- package/dist/esm/hooks/effects/useUnMountEffect.js.map +1 -0
- package/dist/esm/hooks/index.d.ts +27 -2
- package/dist/esm/hooks/index.js +27 -2
- package/dist/esm/hooks/useAnimateElementRefs.d.ts +19 -0
- package/dist/esm/hooks/useAnimateElementRefs.js +54 -0
- package/dist/esm/hooks/useAnimateElementRefs.js.map +1 -0
- package/dist/esm/hooks/useAnimationInterval.d.ts +15 -0
- package/dist/esm/hooks/useAnimationInterval.js +27 -0
- package/dist/esm/hooks/useAnimationInterval.js.map +1 -0
- package/dist/esm/hooks/useCallbackRef.d.ts +13 -0
- package/dist/esm/hooks/useCallbackRef.js +19 -0
- package/dist/esm/hooks/useCallbackRef.js.map +1 -0
- package/dist/esm/hooks/useClickOutside.d.ts +14 -0
- package/dist/esm/hooks/useClickOutside.js +25 -0
- package/dist/esm/hooks/useClickOutside.js.map +1 -0
- package/dist/esm/hooks/useComposeRefs.d.ts +8 -0
- package/dist/esm/hooks/useComposeRefs.js +11 -0
- package/dist/esm/hooks/useComposeRefs.js.map +1 -0
- package/dist/esm/hooks/useConstant.d.ts +6 -0
- package/dist/esm/hooks/useConstant.js +17 -0
- package/dist/esm/hooks/useConstant.js.map +1 -0
- package/dist/esm/hooks/useControllable.d.ts +55 -0
- package/dist/esm/hooks/useControllable.js +79 -0
- package/dist/esm/hooks/useControllable.js.map +1 -0
- package/dist/esm/hooks/useCopyToClipboard.d.ts +15 -0
- package/dist/esm/hooks/useCopyToClipboard.js +49 -0
- package/dist/esm/hooks/useCopyToClipboard.js.map +1 -0
- package/dist/esm/hooks/useDebounce.d.ts +23 -0
- package/dist/esm/hooks/useDebounce.js +32 -0
- package/dist/esm/hooks/useDebounce.js.map +1 -0
- package/dist/esm/hooks/useDisclosure.d.ts +14 -0
- package/dist/esm/hooks/useDisclosure.js +42 -0
- package/dist/esm/hooks/useDisclosure.js.map +1 -0
- package/dist/esm/hooks/useIsHydrated.d.ts +28 -0
- package/dist/esm/hooks/useIsHydrated.js +39 -0
- package/dist/esm/hooks/useIsHydrated.js.map +1 -0
- package/dist/esm/hooks/useLocationState.d.ts +17 -0
- package/dist/esm/hooks/useLocationState.js +24 -0
- package/dist/esm/hooks/useLocationState.js.map +1 -0
- package/dist/esm/hooks/useScrollObserver.d.ts +11 -0
- package/dist/esm/hooks/useScrollObserver.js +44 -0
- package/dist/esm/hooks/useScrollObserver.js.map +1 -0
- package/dist/esm/hooks/useSearch.d.ts +12 -0
- package/dist/esm/hooks/useSearch.js +40 -0
- package/dist/esm/hooks/useSearch.js.map +1 -0
- package/dist/esm/hooks/useSearchParams.d.ts +12 -0
- package/dist/esm/hooks/useSearchParams.js +36 -0
- package/dist/esm/hooks/useSearchParams.js.map +1 -0
- package/dist/esm/hooks/useShallowCompare.d.ts +8 -0
- package/dist/esm/hooks/useShallowCompare.js +26 -0
- package/dist/esm/hooks/useShallowCompare.js.map +1 -0
- package/dist/esm/hooks/useStorageState.d.ts +20 -0
- package/dist/esm/hooks/useStorageState.js +54 -0
- package/dist/esm/hooks/useStorageState.js.map +1 -0
- package/dist/esm/hooks/useStore.d.ts +8 -0
- package/dist/esm/hooks/useStore.js +13 -0
- package/dist/esm/hooks/useStore.js.map +1 -0
- package/dist/esm/hooks/useThrottle.d.ts +15 -0
- package/dist/esm/hooks/useThrottle.js +27 -0
- package/dist/esm/hooks/useThrottle.js.map +1 -0
- package/dist/esm/hooks/useToggle.d.ts +6 -0
- package/dist/esm/hooks/useToggle.js +18 -0
- package/dist/esm/hooks/useToggle.js.map +1 -0
- package/dist/esm/utils/composeEventHandlers.d.ts +8 -0
- package/dist/esm/utils/composeEventHandlers.js +36 -0
- package/dist/esm/utils/composeEventHandlers.js.map +1 -0
- package/dist/esm/utils/composeRefs.d.ts +17 -0
- package/dist/esm/utils/composeRefs.js +28 -0
- package/dist/esm/utils/composeRefs.js.map +1 -0
- package/dist/esm/utils/getSlot/getSlot.d.ts +60 -0
- package/dist/esm/utils/getSlot/getSlot.js +78 -0
- package/dist/esm/utils/getSlot/getSlot.js.map +1 -0
- package/dist/esm/utils/getSlotMap/getSlotMap.d.ts +86 -0
- package/dist/esm/utils/getSlotMap/getSlotMap.js +87 -0
- package/dist/esm/utils/getSlotMap/getSlotMap.js.map +1 -0
- package/dist/esm/utils/index.d.ts +8 -1
- package/dist/esm/utils/index.js +6 -1
- package/dist/esm/utils/mergeProps.d.ts +20 -0
- package/dist/esm/utils/mergeProps.js +31 -0
- package/dist/esm/utils/mergeProps.js.map +1 -0
- package/dist/esm/utils/mergeTwoProps.d.ts +5 -0
- package/dist/esm/utils/mergeTwoProps.js +42 -0
- package/dist/esm/utils/mergeTwoProps.js.map +1 -0
- package/dist/esm/utils/types/common.d.ts +43 -0
- package/dist/esm/utils/types/polymorphism.d.ts +13 -0
- package/dist/esm/zustand/createReactZustandStore.js +8 -0
- package/dist/esm/zustand/createReactZustandStore.js.map +1 -0
- package/dist/esm/zustand/createZustandContext.d.ts +13 -0
- package/dist/esm/zustand/createZustandContext.js +21 -0
- package/dist/esm/zustand/createZustandContext.js.map +1 -0
- package/dist/esm/zustand/createZustandStoreWithCombine.d.ts +12 -0
- package/dist/esm/zustand/createZustandStoreWithCombine.js +14 -0
- package/dist/esm/zustand/createZustandStoreWithCombine.js.map +1 -0
- package/dist/esm/zustand/createZustandStoreWithSubscribe.d.ts +17 -0
- package/dist/esm/zustand/createZustandStoreWithSubscribe.js +16 -0
- package/dist/esm/zustand/createZustandStoreWithSubscribe.js.map +1 -0
- package/dist/esm/zustand/index.d.ts +4 -38
- package/dist/esm/zustand/index.js +4 -42
- package/dist/esm/zustand/types.d.ts +20 -0
- package/package.json +11 -16
- package/dist/esm/hooks-iZivekUZ.js +0 -635
- package/dist/esm/hooks-iZivekUZ.js.map +0 -1
- package/dist/esm/index-DlScRgBk.d.ts +0 -228
- package/dist/esm/index-ouFKofvj.d.ts +0 -293
- package/dist/esm/utils-Bvs8tFDM.js +0 -279
- package/dist/esm/utils-Bvs8tFDM.js.map +0 -1
- package/dist/esm/zustand/index.js.map +0 -1
|
@@ -1,635 +0,0 @@
|
|
|
1
|
-
import { composeRefs } from "./utils-Bvs8tFDM.js";
|
|
2
|
-
import { createContext, use, useCallback, useDebugValue, useEffect, useInsertionEffect, useMemo, useRef, useState, useSyncExternalStore } from "react";
|
|
3
|
-
import { copyToClipboard, createExternalStorageStore, createLocationStore, createScrollObserver, createSearchParams, debounce, lockScroll, on, onClickOutside, setAnimationInterval, shallowCompare, throttleByFrame, throttleBySetTimeout, throttleByTime, toArray } from "@zayne-labs/toolkit-core";
|
|
4
|
-
import { isArray, isBoolean, isFunction, isPlainObject } from "@zayne-labs/toolkit-type-helpers";
|
|
5
|
-
|
|
6
|
-
//#region src/hooks/createCustomContext.ts
|
|
7
|
-
const createCustomContext = (options = {}) => {
|
|
8
|
-
const { defaultValue = null, errorMessage, extension, hookName = "useUnnamedContext", providerName = "UnnamedContextProvider", name = providerName.endsWith("Provider") ? providerName.slice(0, -8) : "UnnamedContext", strict = true } = options;
|
|
9
|
-
const Context = createContext(defaultValue);
|
|
10
|
-
Context.displayName = name;
|
|
11
|
-
const useCustomContext = () => {
|
|
12
|
-
const contextValue = use(Context);
|
|
13
|
-
const extendedContextValue = extension?.(contextValue) ?? contextValue;
|
|
14
|
-
if (strict && extendedContextValue === null) throw new ContextError(errorMessage ?? getErrorMessage(hookName, providerName));
|
|
15
|
-
return extendedContextValue;
|
|
16
|
-
};
|
|
17
|
-
return [Context, useCustomContext];
|
|
18
|
-
};
|
|
19
|
-
var ContextError = class extends Error {
|
|
20
|
-
name = "ContextError";
|
|
21
|
-
};
|
|
22
|
-
const getErrorMessage = (hook, provider) => {
|
|
23
|
-
return `${hook} returned "null". Did you forget to wrap the necessary components within ${provider}?`;
|
|
24
|
-
};
|
|
25
|
-
|
|
26
|
-
//#endregion
|
|
27
|
-
//#region src/hooks/useCallbackRef.ts
|
|
28
|
-
/**
|
|
29
|
-
* Returns a stable function that always points to the latest version of the callback function.
|
|
30
|
-
* @param callbackFn - The function to reference
|
|
31
|
-
* @returns a stable function that always points to the latest version of the callback function
|
|
32
|
-
*/
|
|
33
|
-
const useCallbackRef = (callbackFn) => {
|
|
34
|
-
const callbackRef = useRef(callbackFn);
|
|
35
|
-
useInsertionEffect(() => {
|
|
36
|
-
callbackRef.current = callbackFn;
|
|
37
|
-
}, [callbackFn]);
|
|
38
|
-
return useCallback((...params) => callbackRef.current?.(...params), []);
|
|
39
|
-
};
|
|
40
|
-
|
|
41
|
-
//#endregion
|
|
42
|
-
//#region src/hooks/effects/useAfterMountEffect.ts
|
|
43
|
-
const useAfterMountEffect = (callBackFn, deps) => {
|
|
44
|
-
const isFirstMount = useRef(true);
|
|
45
|
-
const stableCallback = useCallbackRef(callBackFn);
|
|
46
|
-
useEffect(() => {
|
|
47
|
-
if (isFirstMount.current) {
|
|
48
|
-
isFirstMount.current = false;
|
|
49
|
-
return;
|
|
50
|
-
}
|
|
51
|
-
stableCallback();
|
|
52
|
-
}, deps);
|
|
53
|
-
};
|
|
54
|
-
|
|
55
|
-
//#endregion
|
|
56
|
-
//#region src/hooks/effects/useAsyncEffect.ts
|
|
57
|
-
function useAsyncEffect(effect, deps) {
|
|
58
|
-
const stableEffectCallback = useCallbackRef(effect);
|
|
59
|
-
const [destroy, setDestroy] = useState();
|
|
60
|
-
useEffect(() => {
|
|
61
|
-
const e = stableEffectCallback();
|
|
62
|
-
async function execute() {
|
|
63
|
-
setDestroy(await e);
|
|
64
|
-
}
|
|
65
|
-
execute();
|
|
66
|
-
return () => void destroy?.();
|
|
67
|
-
}, deps);
|
|
68
|
-
}
|
|
69
|
-
|
|
70
|
-
//#endregion
|
|
71
|
-
//#region src/hooks/effects/useEffectOnce.ts
|
|
72
|
-
const useEffectOnce = (callBackFn) => {
|
|
73
|
-
const stableCallback = useCallbackRef(callBackFn);
|
|
74
|
-
const effectGuardRef = useRef(false);
|
|
75
|
-
useEffect(() => {
|
|
76
|
-
if (effectGuardRef.current) return;
|
|
77
|
-
effectGuardRef.current = true;
|
|
78
|
-
return stableCallback();
|
|
79
|
-
}, []);
|
|
80
|
-
};
|
|
81
|
-
|
|
82
|
-
//#endregion
|
|
83
|
-
//#region src/hooks/effects/useLifeCycle.ts
|
|
84
|
-
const useLifeCycle = ({ onMount, onUnmount }) => {
|
|
85
|
-
const stableOnMount = useCallbackRef(onMount);
|
|
86
|
-
const stableOnUnmount = useCallbackRef(onUnmount);
|
|
87
|
-
useEffect(() => {
|
|
88
|
-
stableOnMount();
|
|
89
|
-
return stableOnUnmount;
|
|
90
|
-
}, []);
|
|
91
|
-
};
|
|
92
|
-
|
|
93
|
-
//#endregion
|
|
94
|
-
//#region src/hooks/effects/useMountEffect.ts
|
|
95
|
-
const useMountEffect = (callBackFn) => {
|
|
96
|
-
useLifeCycle({ onMount: callBackFn });
|
|
97
|
-
};
|
|
98
|
-
|
|
99
|
-
//#endregion
|
|
100
|
-
//#region src/hooks/effects/useUnMountEffect.ts
|
|
101
|
-
const useUnmountEffect = (cleanUpFn) => useLifeCycle({ onUnmount: cleanUpFn });
|
|
102
|
-
|
|
103
|
-
//#endregion
|
|
104
|
-
//#region src/hooks/useAnimateElementRefs.ts
|
|
105
|
-
const removeClass = (target, className) => () => target.classList.remove(className);
|
|
106
|
-
/**
|
|
107
|
-
* This is a custom React hook that adds and removes animation classes to specified HTML elements.
|
|
108
|
-
* @param elementsInfoArray - An array of objects that contain information about the animation class and the target HTML element.
|
|
109
|
-
* @returns - An object containing the refs of the animated elements and a function to handle the initiation and removal animation.
|
|
110
|
-
*/
|
|
111
|
-
const useAnimateElementRefs = (elementsInfoArray) => {
|
|
112
|
-
const elementsRef = useRef({});
|
|
113
|
-
const addAnimationClasses = useCallbackRef(() => {
|
|
114
|
-
if (!isArray(elementsInfoArray)) {
|
|
115
|
-
console.error("elementsInfo is not an Array");
|
|
116
|
-
return;
|
|
117
|
-
}
|
|
118
|
-
for (const { animationClass, targetElement } of elementsInfoArray) {
|
|
119
|
-
if (!elementsRef.current[targetElement]) {
|
|
120
|
-
console.error("ElementError", `"${targetElement}" element does not exist`);
|
|
121
|
-
return;
|
|
122
|
-
}
|
|
123
|
-
elementsRef.current[targetElement].classList.add(animationClass);
|
|
124
|
-
}
|
|
125
|
-
});
|
|
126
|
-
const removeAnimationClasses = useCallbackRef(() => {
|
|
127
|
-
if (!isArray(elementsInfoArray)) {
|
|
128
|
-
console.error("elementsInfo is not an Array");
|
|
129
|
-
return;
|
|
130
|
-
}
|
|
131
|
-
for (const { animationClass, targetElement } of elementsInfoArray) {
|
|
132
|
-
if (!elementsRef.current[targetElement]) {
|
|
133
|
-
console.error("ElementError", `"${targetElement}" element does not exist`);
|
|
134
|
-
return;
|
|
135
|
-
}
|
|
136
|
-
on("transitionend", elementsRef.current[targetElement], removeClass(elementsRef.current[targetElement], animationClass));
|
|
137
|
-
on("animationend", elementsRef.current[targetElement], removeClass(elementsRef.current[targetElement], animationClass));
|
|
138
|
-
}
|
|
139
|
-
});
|
|
140
|
-
const handleElementsAnimation = useCallback(() => {
|
|
141
|
-
addAnimationClasses();
|
|
142
|
-
removeAnimationClasses();
|
|
143
|
-
}, [addAnimationClasses, removeAnimationClasses]);
|
|
144
|
-
return {
|
|
145
|
-
animatedElements: elementsRef.current,
|
|
146
|
-
handleElementsAnimation
|
|
147
|
-
};
|
|
148
|
-
};
|
|
149
|
-
|
|
150
|
-
//#endregion
|
|
151
|
-
//#region src/hooks/useAnimationInterval.ts
|
|
152
|
-
const useAnimationInterval = (options) => {
|
|
153
|
-
const { intervalDuration, onAnimation, once } = options;
|
|
154
|
-
const latestCallback = useCallbackRef(onAnimation);
|
|
155
|
-
const { start, stop } = useMemo(() => setAnimationInterval(latestCallback, intervalDuration, { once }), [
|
|
156
|
-
intervalDuration,
|
|
157
|
-
latestCallback,
|
|
158
|
-
once
|
|
159
|
-
]);
|
|
160
|
-
useEffect(() => {
|
|
161
|
-
if (intervalDuration === null) return;
|
|
162
|
-
start();
|
|
163
|
-
return stop;
|
|
164
|
-
}, [intervalDuration]);
|
|
165
|
-
return {
|
|
166
|
-
start,
|
|
167
|
-
stop
|
|
168
|
-
};
|
|
169
|
-
};
|
|
170
|
-
|
|
171
|
-
//#endregion
|
|
172
|
-
//#region src/hooks/useClickOutside.ts
|
|
173
|
-
const useClickOutside = (options) => {
|
|
174
|
-
const innerRef = useRef(null);
|
|
175
|
-
const { enabled = true, onClick, ref: refOrRefArray = innerRef } = options;
|
|
176
|
-
const savedOnClick = useCallbackRef(onClick);
|
|
177
|
-
useEffect(() => {
|
|
178
|
-
if (!enabled) return;
|
|
179
|
-
const elementArray = toArray(refOrRefArray).map((ref) => ref.current);
|
|
180
|
-
const cleanup = onClickOutside(elementArray, savedOnClick);
|
|
181
|
-
return () => cleanup();
|
|
182
|
-
}, [
|
|
183
|
-
enabled,
|
|
184
|
-
refOrRefArray,
|
|
185
|
-
savedOnClick
|
|
186
|
-
]);
|
|
187
|
-
return { ref: innerRef };
|
|
188
|
-
};
|
|
189
|
-
|
|
190
|
-
//#endregion
|
|
191
|
-
//#region src/hooks/useComposeRefs.ts
|
|
192
|
-
const useComposeRefs = (...refs) => {
|
|
193
|
-
return useMemo(() => composeRefs(...refs), refs);
|
|
194
|
-
};
|
|
195
|
-
|
|
196
|
-
//#endregion
|
|
197
|
-
//#region src/hooks/useConstant.ts
|
|
198
|
-
const useConstant = (initFn) => {
|
|
199
|
-
const resultRef = useRef(null);
|
|
200
|
-
if (resultRef.current === null) resultRef.current = initFn();
|
|
201
|
-
return resultRef.current;
|
|
202
|
-
};
|
|
203
|
-
const useLazyRef = (initFn) => {
|
|
204
|
-
const resultRef = useRef(null);
|
|
205
|
-
if (resultRef.current === null) resultRef.current = initFn();
|
|
206
|
-
return resultRef;
|
|
207
|
-
};
|
|
208
|
-
|
|
209
|
-
//#endregion
|
|
210
|
-
//#region src/hooks/useControllable.ts
|
|
211
|
-
/**
|
|
212
|
-
* @description Given a prop value and state value, the useControllableProp hook is used to determine whether a component is controlled or uncontrolled, and also returns the computed value.
|
|
213
|
-
*/
|
|
214
|
-
const useControllableProp = (options) => {
|
|
215
|
-
const { prop, state } = options;
|
|
216
|
-
const isControlled = prop !== void 0;
|
|
217
|
-
const value = isControlled ? prop : state;
|
|
218
|
-
return useMemo(() => [isControlled, value], [isControlled, value]);
|
|
219
|
-
};
|
|
220
|
-
/**
|
|
221
|
-
* @description React hook to manage state that can be either controlled or uncontrolled.
|
|
222
|
-
* - When `options.value` is provided, the hook operates in controlled mode.
|
|
223
|
-
* In this mode, `value` always equals `options.value` and `setValue` will
|
|
224
|
-
* invoke `options.onChange(next)` without mutating internal state.
|
|
225
|
-
* - When `options.value` is not provided, the hook operates in uncontrolled
|
|
226
|
-
* mode, initializing internal state from `options.defaultValue` and updating
|
|
227
|
-
* it via `setValue`.
|
|
228
|
-
* - All updates are gated by `options.equalityFn(prev, next)` which defaults
|
|
229
|
-
* to `Object.is`.
|
|
230
|
-
*
|
|
231
|
-
* @param options - Configuration options for the hook.
|
|
232
|
-
* @param options.value - Controlled value. If defined, the state is controlled.
|
|
233
|
-
* @param options.defaultValue - Initial value for the uncontrolled state. Can be a
|
|
234
|
-
* function for lazy initialization or a direct value.
|
|
235
|
-
* @param options.onChange - Callback fired when a new value is requested. In
|
|
236
|
-
* controlled mode, this is invoked instead of updating internal state. In
|
|
237
|
-
* uncontrolled mode, it is called after the internal state updates.
|
|
238
|
-
* @param options.equalityFn - Predicate that decides whether to commit an
|
|
239
|
-
* update given `prevState` and `nextValue`. If the values are equal, the update
|
|
240
|
-
* is skipped. Defaults to `Object.is`.
|
|
241
|
-
* @returns A tuple `[value, setValue]` just like React.useState.
|
|
242
|
-
*
|
|
243
|
-
* @example
|
|
244
|
-
* // Uncontrolled usage
|
|
245
|
-
* const [value, setValue] = useControllableState({ defaultValue: 0 });
|
|
246
|
-
*
|
|
247
|
-
* @example
|
|
248
|
-
* // Controlled usage
|
|
249
|
-
* const [value, setValue] = useControllableState({
|
|
250
|
-
* value: props.value,
|
|
251
|
-
* onChange: props.onChange,
|
|
252
|
-
* });
|
|
253
|
-
*/
|
|
254
|
-
const useControllableState = (options) => {
|
|
255
|
-
const { defaultValue, equalityFn = Object.is, onChange: onChangeProp, value: valueProp } = options;
|
|
256
|
-
const savedOnchangeProp = useCallbackRef(onChangeProp);
|
|
257
|
-
const savedEqualityFn = useCallbackRef(equalityFn);
|
|
258
|
-
const [unControlledState, setUncontrolledState] = useState(defaultValue);
|
|
259
|
-
const isControlled = valueProp !== void 0;
|
|
260
|
-
const currentValue = isControlled ? valueProp : unControlledState;
|
|
261
|
-
const setValue = useCallback((newValue) => {
|
|
262
|
-
const nextValue = isFunction(newValue) ? newValue(currentValue) : newValue;
|
|
263
|
-
if (savedEqualityFn(currentValue, nextValue)) return;
|
|
264
|
-
if (isControlled) {
|
|
265
|
-
savedOnchangeProp(nextValue);
|
|
266
|
-
return;
|
|
267
|
-
}
|
|
268
|
-
setUncontrolledState(nextValue);
|
|
269
|
-
savedOnchangeProp(nextValue);
|
|
270
|
-
}, [
|
|
271
|
-
isControlled,
|
|
272
|
-
savedOnchangeProp,
|
|
273
|
-
savedEqualityFn,
|
|
274
|
-
currentValue
|
|
275
|
-
]);
|
|
276
|
-
return [currentValue, setValue];
|
|
277
|
-
};
|
|
278
|
-
|
|
279
|
-
//#endregion
|
|
280
|
-
//#region src/hooks/useToggle.ts
|
|
281
|
-
const useToggle = (initialValue = false) => {
|
|
282
|
-
const [value, setValue] = useState(initialValue);
|
|
283
|
-
const toggleValue = useCallback((newValue) => {
|
|
284
|
-
if (typeof newValue === "boolean") {
|
|
285
|
-
setValue(newValue);
|
|
286
|
-
return;
|
|
287
|
-
}
|
|
288
|
-
setValue((prev) => !prev);
|
|
289
|
-
}, []);
|
|
290
|
-
return [value, toggleValue];
|
|
291
|
-
};
|
|
292
|
-
|
|
293
|
-
//#endregion
|
|
294
|
-
//#region src/hooks/useCopyToClipboard.ts
|
|
295
|
-
const useCopyToClipboard = (options = {}) => {
|
|
296
|
-
const { mimeType, onCopied, onError, onSuccess, timeout = 1500 } = options;
|
|
297
|
-
const [value, setValue] = useState("");
|
|
298
|
-
const [hasCopied, toggleHasCopied] = useToggle(false);
|
|
299
|
-
const timeoutRef = useRef(null);
|
|
300
|
-
const savedOnError = useCallbackRef(onError);
|
|
301
|
-
const savedOnSuccess = useCallbackRef(onSuccess);
|
|
302
|
-
const savedOnCopied = useCallbackRef(onCopied);
|
|
303
|
-
const handleHasCopied = useCallback(() => {
|
|
304
|
-
toggleHasCopied(true);
|
|
305
|
-
timeoutRef.current && clearTimeout(timeoutRef.current);
|
|
306
|
-
timeoutRef.current = setTimeout(() => {
|
|
307
|
-
toggleHasCopied(false);
|
|
308
|
-
}, timeout);
|
|
309
|
-
}, [toggleHasCopied, timeout]);
|
|
310
|
-
return {
|
|
311
|
-
handleCopy: useCallback((valueToCopy) => {
|
|
312
|
-
setValue(valueToCopy);
|
|
313
|
-
copyToClipboard(valueToCopy, {
|
|
314
|
-
mimeType,
|
|
315
|
-
onCopied: () => {
|
|
316
|
-
savedOnCopied();
|
|
317
|
-
handleHasCopied();
|
|
318
|
-
},
|
|
319
|
-
onError: savedOnError,
|
|
320
|
-
onSuccess: savedOnSuccess
|
|
321
|
-
});
|
|
322
|
-
}, [
|
|
323
|
-
handleHasCopied,
|
|
324
|
-
mimeType,
|
|
325
|
-
savedOnCopied,
|
|
326
|
-
savedOnError,
|
|
327
|
-
savedOnSuccess
|
|
328
|
-
]),
|
|
329
|
-
hasCopied,
|
|
330
|
-
setValue,
|
|
331
|
-
value
|
|
332
|
-
};
|
|
333
|
-
};
|
|
334
|
-
|
|
335
|
-
//#endregion
|
|
336
|
-
//#region src/hooks/useDebounce.ts
|
|
337
|
-
const useDebouncedFn = (callBackFn, delay) => {
|
|
338
|
-
const latestCallback = useCallbackRef(callBackFn);
|
|
339
|
-
const debouncedFn = useMemo(() => debounce(latestCallback, delay), [delay, latestCallback]);
|
|
340
|
-
useUnmountEffect(() => {
|
|
341
|
-
debouncedFn.cancel();
|
|
342
|
-
debouncedFn.cancelMaxWait();
|
|
343
|
-
});
|
|
344
|
-
return debouncedFn;
|
|
345
|
-
};
|
|
346
|
-
const useDebouncedState = (defaultValue, delay) => {
|
|
347
|
-
const [value, setValue] = useState(defaultValue);
|
|
348
|
-
const setDebouncedValue = useMemo(() => debounce(setValue, delay), [delay]);
|
|
349
|
-
useUnmountEffect(() => {
|
|
350
|
-
setDebouncedValue.cancel();
|
|
351
|
-
setDebouncedValue.cancelMaxWait();
|
|
352
|
-
});
|
|
353
|
-
return [
|
|
354
|
-
value,
|
|
355
|
-
setDebouncedValue,
|
|
356
|
-
setValue
|
|
357
|
-
];
|
|
358
|
-
};
|
|
359
|
-
|
|
360
|
-
//#endregion
|
|
361
|
-
//#region src/hooks/useDisclosure.ts
|
|
362
|
-
const useDisclosure = (options = {}) => {
|
|
363
|
-
const { hasScrollControl = false, initialState = false } = options;
|
|
364
|
-
const [isOpen, toggleIsOpen] = useToggle(initialState);
|
|
365
|
-
const onOpen = useCallbackRef(() => {
|
|
366
|
-
toggleIsOpen(true);
|
|
367
|
-
hasScrollControl && lockScroll({ lock: true });
|
|
368
|
-
});
|
|
369
|
-
const onClose = useCallbackRef(() => {
|
|
370
|
-
toggleIsOpen(false);
|
|
371
|
-
hasScrollControl && lockScroll({ lock: false });
|
|
372
|
-
});
|
|
373
|
-
const onToggle = useCallbackRef((value) => {
|
|
374
|
-
if (isBoolean(value)) {
|
|
375
|
-
toggleIsOpen(value);
|
|
376
|
-
hasScrollControl && lockScroll({ lock: value });
|
|
377
|
-
return;
|
|
378
|
-
}
|
|
379
|
-
isOpen ? onClose() : onOpen();
|
|
380
|
-
});
|
|
381
|
-
return useMemo(() => ({
|
|
382
|
-
isOpen,
|
|
383
|
-
onClose,
|
|
384
|
-
onOpen,
|
|
385
|
-
onToggle
|
|
386
|
-
}), [
|
|
387
|
-
isOpen,
|
|
388
|
-
onClose,
|
|
389
|
-
onOpen,
|
|
390
|
-
onToggle
|
|
391
|
-
]);
|
|
392
|
-
};
|
|
393
|
-
|
|
394
|
-
//#endregion
|
|
395
|
-
//#region src/hooks/useIsHydrated.ts
|
|
396
|
-
const noop = () => {};
|
|
397
|
-
const noopStore = {
|
|
398
|
-
getServerSnapshot: () => true,
|
|
399
|
-
getSnapshot: () => false,
|
|
400
|
-
subscribe: () => noop
|
|
401
|
-
};
|
|
402
|
-
/**
|
|
403
|
-
* @description Return a boolean indicating if the JS has been hydrated already.
|
|
404
|
-
* When doing Server-Side Rendering, the result will always be false.
|
|
405
|
-
* When doing Client-Side Rendering, the result will always be false on the
|
|
406
|
-
* first render and true from then on. Even if a new component renders it will
|
|
407
|
-
* always start with true.
|
|
408
|
-
*
|
|
409
|
-
* @see https://github.com/sergiodxa/remix-utils/blob/main/src/react/use-hydrated.ts
|
|
410
|
-
*
|
|
411
|
-
* @see https://github.com/sergiodxa/remix-utils/blob/main/src/react/use-hydrated.ts
|
|
412
|
-
*
|
|
413
|
-
* @example
|
|
414
|
-
* **Example: Disable a button that needs JS to work.**
|
|
415
|
-
* ```tsx
|
|
416
|
-
* const isHydrated = useIsHydrated();
|
|
417
|
-
*
|
|
418
|
-
* return (
|
|
419
|
-
* <button type="button" disabled={!isHydrated} onClick={doSomethingCustom}>
|
|
420
|
-
* Click me
|
|
421
|
-
* </button>
|
|
422
|
-
* );
|
|
423
|
-
* ```
|
|
424
|
-
*/
|
|
425
|
-
const useIsHydrated = () => {
|
|
426
|
-
return useSyncExternalStore(noopStore.subscribe, noopStore.getSnapshot, noopStore.getServerSnapshot);
|
|
427
|
-
};
|
|
428
|
-
|
|
429
|
-
//#endregion
|
|
430
|
-
//#region src/hooks/useStore.ts
|
|
431
|
-
const identity = (value) => value;
|
|
432
|
-
const useStore = (store, selector = identity) => {
|
|
433
|
-
const slice = useSyncExternalStore(store.subscribe, useCallback(() => selector(store.getState()), [store, selector]), useCallback(() => selector(store.getInitialState()), [store, selector]));
|
|
434
|
-
useDebugValue(slice);
|
|
435
|
-
return slice;
|
|
436
|
-
};
|
|
437
|
-
|
|
438
|
-
//#endregion
|
|
439
|
-
//#region src/hooks/useLocationState.ts
|
|
440
|
-
const createUseLocationState = (options) => {
|
|
441
|
-
const locationStore = createLocationStore(options);
|
|
442
|
-
const useLocationState$1 = (selector) => {
|
|
443
|
-
return [useStore(locationStore, selector), locationStore];
|
|
444
|
-
};
|
|
445
|
-
Object.assign(useLocationState$1, locationStore);
|
|
446
|
-
return useLocationState$1;
|
|
447
|
-
};
|
|
448
|
-
const useLocationState = (selector, options = {}) => {
|
|
449
|
-
const { equalityFn } = options;
|
|
450
|
-
const savedEqualityFn = useCallbackRef(equalityFn);
|
|
451
|
-
const locationStore = useMemo(() => createLocationStore({ equalityFn: savedEqualityFn }), [savedEqualityFn]);
|
|
452
|
-
return [useStore(locationStore, selector), locationStore];
|
|
453
|
-
};
|
|
454
|
-
|
|
455
|
-
//#endregion
|
|
456
|
-
//#region src/hooks/useScrollObserver.ts
|
|
457
|
-
const useScrollObserver = (options = {}) => {
|
|
458
|
-
const { onIntersection, root, rootMargin = "10px 0px 0px 0px", threshold } = options;
|
|
459
|
-
const [isScrolled, setIsScrolled] = useState(false);
|
|
460
|
-
const savedOnIntersection = useCallbackRef(onIntersection);
|
|
461
|
-
const { handleObservation } = useMemo(() => {
|
|
462
|
-
return createScrollObserver({
|
|
463
|
-
onIntersection: (entry, observer) => {
|
|
464
|
-
const newIsScrolledState = !entry.isIntersecting;
|
|
465
|
-
setIsScrolled(newIsScrolledState);
|
|
466
|
-
entry.target.dataset.scrolled = String(newIsScrolledState);
|
|
467
|
-
savedOnIntersection(entry, observer);
|
|
468
|
-
},
|
|
469
|
-
root,
|
|
470
|
-
rootMargin,
|
|
471
|
-
threshold
|
|
472
|
-
});
|
|
473
|
-
}, [
|
|
474
|
-
root,
|
|
475
|
-
rootMargin,
|
|
476
|
-
savedOnIntersection,
|
|
477
|
-
threshold
|
|
478
|
-
]);
|
|
479
|
-
const observedElementRef = useCallbackRef((element) => {
|
|
480
|
-
const cleanupFn = handleObservation(element);
|
|
481
|
-
if (!element) {
|
|
482
|
-
cleanupFn?.();
|
|
483
|
-
return;
|
|
484
|
-
}
|
|
485
|
-
return cleanupFn;
|
|
486
|
-
});
|
|
487
|
-
return {
|
|
488
|
-
isScrolled,
|
|
489
|
-
observedElementRef
|
|
490
|
-
};
|
|
491
|
-
};
|
|
492
|
-
|
|
493
|
-
//#endregion
|
|
494
|
-
//#region src/hooks/useSearch.ts
|
|
495
|
-
const isSerializable = (item) => typeof item === "string" || typeof item === "number" || typeof item === "boolean";
|
|
496
|
-
const checkObjectPropsForQuery = (item, query) => {
|
|
497
|
-
for (const value of Object.values(item)) if (isSerializable(value) && value.toString().toLowerCase().includes(query)) return true;
|
|
498
|
-
return false;
|
|
499
|
-
};
|
|
500
|
-
const useSearch = (initialData, delay) => {
|
|
501
|
-
const [searchQuery, setSearchQuery] = useState("");
|
|
502
|
-
const [filteredData, setFilteredData] = useState(initialData);
|
|
503
|
-
const [isLoading, setIsLoading] = useState(false);
|
|
504
|
-
const handleDebouncedSearch = useDebouncedFn(() => {
|
|
505
|
-
const query = searchQuery.toLowerCase();
|
|
506
|
-
const filteredResults = initialData.filter((item) => {
|
|
507
|
-
if (isSerializable(item)) return item.toString().toLowerCase().includes(query);
|
|
508
|
-
if (isPlainObject(item)) return checkObjectPropsForQuery(item, query);
|
|
509
|
-
return false;
|
|
510
|
-
});
|
|
511
|
-
setFilteredData(filteredResults);
|
|
512
|
-
setIsLoading(false);
|
|
513
|
-
}, delay);
|
|
514
|
-
useAfterMountEffect(() => {
|
|
515
|
-
setIsLoading(true);
|
|
516
|
-
handleDebouncedSearch();
|
|
517
|
-
}, [searchQuery]);
|
|
518
|
-
return {
|
|
519
|
-
data: filteredData,
|
|
520
|
-
isLoading,
|
|
521
|
-
query: searchQuery,
|
|
522
|
-
setQuery: setSearchQuery
|
|
523
|
-
};
|
|
524
|
-
};
|
|
525
|
-
|
|
526
|
-
//#endregion
|
|
527
|
-
//#region src/hooks/useSearchParams.ts
|
|
528
|
-
const useSearchParams = (options) => {
|
|
529
|
-
const { action = "push",...restOfOptions } = options ?? {};
|
|
530
|
-
const [searchParams, actions] = useLocationState((state) => state.search, restOfOptions);
|
|
531
|
-
const setSearchParams = (newQueryParams) => {
|
|
532
|
-
const params = isFunction(newQueryParams) ? newQueryParams(searchParams) : newQueryParams;
|
|
533
|
-
const nextSearchParams = createSearchParams(params);
|
|
534
|
-
actions[action]({ search: nextSearchParams });
|
|
535
|
-
};
|
|
536
|
-
setSearchParams.triggerPopstateEvent = actions.triggerPopstateEvent;
|
|
537
|
-
return [searchParams, setSearchParams];
|
|
538
|
-
};
|
|
539
|
-
const useSearchParamsObject = (options) => {
|
|
540
|
-
const [searchParams, setSearchParams] = useSearchParams(options);
|
|
541
|
-
const searchParamsObject = Object.fromEntries(searchParams);
|
|
542
|
-
const setSearchParamsObject = (newQueryParams) => {
|
|
543
|
-
const params = isFunction(newQueryParams) ? newQueryParams(searchParamsObject) : newQueryParams;
|
|
544
|
-
setSearchParams(params);
|
|
545
|
-
};
|
|
546
|
-
setSearchParamsObject.triggerPopstateEvent = setSearchParams.triggerPopstateEvent;
|
|
547
|
-
return [searchParamsObject, setSearchParamsObject];
|
|
548
|
-
};
|
|
549
|
-
|
|
550
|
-
//#endregion
|
|
551
|
-
//#region src/hooks/useShallowCompare.ts
|
|
552
|
-
const useShallowCompSelector = (selector) => {
|
|
553
|
-
const prevStateRef = useRef(void 0);
|
|
554
|
-
return useCallbackRef((state) => {
|
|
555
|
-
const nextState = selector?.(state);
|
|
556
|
-
if (!nextState) return prevStateRef.current;
|
|
557
|
-
if (shallowCompare(prevStateRef.current, nextState)) return prevStateRef.current;
|
|
558
|
-
return prevStateRef.current = nextState;
|
|
559
|
-
});
|
|
560
|
-
};
|
|
561
|
-
const useShallowCompValue = (value) => {
|
|
562
|
-
const prevValueRef = useRef(value);
|
|
563
|
-
if (shallowCompare(prevValueRef.current, value)) return prevValueRef.current;
|
|
564
|
-
return prevValueRef.current = value;
|
|
565
|
-
};
|
|
566
|
-
|
|
567
|
-
//#endregion
|
|
568
|
-
//#region src/hooks/useStorageState.ts
|
|
569
|
-
/**
|
|
570
|
-
* @description Creates a custom hook that returns a storage state and actions to modify it. You can use this if you need shared options.
|
|
571
|
-
* @note You must use this if you want to be able to prevent syncing state across tabs.
|
|
572
|
-
*/
|
|
573
|
-
const createUseStorageState = (baseOptions) => {
|
|
574
|
-
const externalStore = createExternalStorageStore(baseOptions);
|
|
575
|
-
const useStorageState$1 = (selector) => {
|
|
576
|
-
return [useStore(externalStore, selector), externalStore];
|
|
577
|
-
};
|
|
578
|
-
Object.assign(useStorageState$1, externalStore);
|
|
579
|
-
return useStorageState$1;
|
|
580
|
-
};
|
|
581
|
-
const useStorageState = (key, initialValue, options) => {
|
|
582
|
-
const { equalityFn, logger, parser, partialize, select, serializer, storageArea, syncStateAcrossTabs } = options ?? {};
|
|
583
|
-
const savedEquality = useCallbackRef(equalityFn);
|
|
584
|
-
const savedLogger = useCallbackRef(logger);
|
|
585
|
-
const savedParser = useCallbackRef(parser);
|
|
586
|
-
const savedPartialize = useCallbackRef(partialize);
|
|
587
|
-
const savedSerializer = useCallbackRef(serializer);
|
|
588
|
-
const externalStore = useMemo(() => {
|
|
589
|
-
return createExternalStorageStore({
|
|
590
|
-
equalityFn: savedEquality,
|
|
591
|
-
initialValue,
|
|
592
|
-
key,
|
|
593
|
-
logger: savedLogger,
|
|
594
|
-
parser: savedParser,
|
|
595
|
-
partialize: savedPartialize,
|
|
596
|
-
serializer: savedSerializer,
|
|
597
|
-
storageArea,
|
|
598
|
-
syncStateAcrossTabs
|
|
599
|
-
});
|
|
600
|
-
}, [
|
|
601
|
-
initialValue,
|
|
602
|
-
key,
|
|
603
|
-
savedEquality,
|
|
604
|
-
savedLogger,
|
|
605
|
-
savedParser,
|
|
606
|
-
savedPartialize,
|
|
607
|
-
savedSerializer,
|
|
608
|
-
storageArea,
|
|
609
|
-
syncStateAcrossTabs
|
|
610
|
-
]);
|
|
611
|
-
return [useStore(externalStore, select), externalStore];
|
|
612
|
-
};
|
|
613
|
-
|
|
614
|
-
//#endregion
|
|
615
|
-
//#region src/hooks/useThrottle.ts
|
|
616
|
-
const useThrottleBySetTimeout = (callbackFn, delay) => {
|
|
617
|
-
const latestCallback = useCallbackRef(callbackFn);
|
|
618
|
-
const throttledCallback = useMemo(() => throttleBySetTimeout(latestCallback, delay), [delay, latestCallback]);
|
|
619
|
-
useUnmountEffect(() => throttledCallback.cancelTimeout());
|
|
620
|
-
return throttledCallback;
|
|
621
|
-
};
|
|
622
|
-
const useThrottleByTimer = (callbackFn, delay) => {
|
|
623
|
-
const latestCallback = useCallbackRef(callbackFn);
|
|
624
|
-
return useMemo(() => throttleByTime(latestCallback, delay), [delay, latestCallback]);
|
|
625
|
-
};
|
|
626
|
-
const useThrottleByFrame = (callbackFn) => {
|
|
627
|
-
const latestCallback = useCallbackRef(callbackFn);
|
|
628
|
-
const throttledCallback = useConstant(() => throttleByFrame(latestCallback));
|
|
629
|
-
useUnmountEffect(() => throttledCallback.cancelAnimation());
|
|
630
|
-
return throttledCallback;
|
|
631
|
-
};
|
|
632
|
-
|
|
633
|
-
//#endregion
|
|
634
|
-
export { ContextError, createCustomContext, createUseLocationState, createUseStorageState, getErrorMessage, useAfterMountEffect, useAnimateElementRefs, useAnimationInterval, useAsyncEffect, useCallbackRef, useClickOutside, useComposeRefs, useConstant, useControllableProp, useControllableState, useCopyToClipboard, useDebouncedFn, useDebouncedState, useDisclosure, useEffectOnce, useIsHydrated, useLazyRef, useLifeCycle, useLocationState, useMountEffect, useScrollObserver, useSearch, useSearchParams, useSearchParamsObject, useShallowCompSelector, useShallowCompValue, useStorageState, useStore, useThrottleByFrame, useThrottleBySetTimeout, useThrottleByTimer, useToggle, useUnmountEffect };
|
|
635
|
-
//# sourceMappingURL=hooks-iZivekUZ.js.map
|