@reactuses/core 6.1.9 → 6.1.11
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/index.cjs +85 -30
- package/dist/index.d.cts +7 -6
- package/dist/index.d.mts +7 -6
- package/dist/index.d.ts +7 -6
- package/dist/index.mjs +85 -30
- package/package.json +1 -1
package/dist/index.cjs
CHANGED
|
@@ -23,7 +23,7 @@ function isString(val) {
|
|
|
23
23
|
const isDev = process.env.NODE_ENV === 'development' || process.env.NODE_ENV === 'test';
|
|
24
24
|
const isBrowser = typeof window !== 'undefined';
|
|
25
25
|
const isNavigator = typeof navigator !== 'undefined';
|
|
26
|
-
function noop() {}
|
|
26
|
+
function noop$1() {}
|
|
27
27
|
const isIOS = isBrowser && ((_window = window) == null ? void 0 : (_window_navigator = _window.navigator) == null ? void 0 : _window_navigator.userAgent) && /iP(?:ad|hone|od)/.test(window.navigator.userAgent);
|
|
28
28
|
|
|
29
29
|
const useIsomorphicLayoutEffect = isBrowser ? React.useLayoutEffect : React.useEffect;
|
|
@@ -113,10 +113,57 @@ const useDeepCompareEffect = (effect, deps)=>{
|
|
|
113
113
|
useCustomCompareEffect(effect, deps, lodashEs.isEqual);
|
|
114
114
|
};
|
|
115
115
|
|
|
116
|
-
|
|
116
|
+
/**
|
|
117
|
+
* Creates a stable identifier for a BasicTarget that can be safely used in effect dependencies.
|
|
118
|
+
*
|
|
119
|
+
* This hook solves the problem where passing unstable function references like `() => document`
|
|
120
|
+
* would cause infinite re-renders when used directly in effect dependency arrays.
|
|
121
|
+
*
|
|
122
|
+
* @param target - The target element (ref, function, or direct element)
|
|
123
|
+
* @param defaultElement - Default element to use if target is undefined
|
|
124
|
+
* @returns A stable reference that only changes when the actual target element changes
|
|
125
|
+
*
|
|
126
|
+
* @example
|
|
127
|
+
* ```tsx
|
|
128
|
+
* // For ref objects: returns the ref itself (stable)
|
|
129
|
+
* const ref = useRef<HTMLDivElement>(null)
|
|
130
|
+
* const key = useStableTarget(ref) // key === ref (stable)
|
|
131
|
+
*
|
|
132
|
+
* // For functions: returns the resolved actual element
|
|
133
|
+
* const key = useStableTarget(() => document) // key === document (stable)
|
|
134
|
+
*
|
|
135
|
+
* // For direct elements: returns the element itself
|
|
136
|
+
* const key = useStableTarget(divElement) // key === divElement (stable)
|
|
137
|
+
* ```
|
|
138
|
+
*/ function useStableTarget(target, defaultElement) {
|
|
139
|
+
const targetRef = React.useRef(target);
|
|
140
|
+
targetRef.current = target;
|
|
141
|
+
// Calculate stable key without memoization
|
|
142
|
+
// For ref objects: return the ref itself (always stable)
|
|
143
|
+
// For functions/direct elements: resolve to the actual element
|
|
144
|
+
let stableKey;
|
|
145
|
+
if (!target) {
|
|
146
|
+
stableKey = defaultElement != null ? defaultElement : null;
|
|
147
|
+
} else if (typeof target === 'object' && 'current' in target) {
|
|
148
|
+
// Ref object - use the ref itself as the stable key
|
|
149
|
+
stableKey = target;
|
|
150
|
+
} else {
|
|
151
|
+
// Function or direct element - resolve to actual element
|
|
152
|
+
stableKey = getTargetElement(target, defaultElement);
|
|
153
|
+
}
|
|
154
|
+
return {
|
|
155
|
+
/** The stable key that can be safely used in effect dependencies */ key: stableKey,
|
|
156
|
+
/** A ref containing the current target (useful for accessing in effects) */ ref: targetRef
|
|
157
|
+
};
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
function useEventListenerImpl(eventName, handler, element, options = defaultOptions$1) {
|
|
117
161
|
const savedHandler = useLatest(handler);
|
|
162
|
+
const { key: elementKey, ref: elementRef } = useStableTarget(element, defaultWindow);
|
|
118
163
|
useDeepCompareEffect(()=>{
|
|
119
|
-
|
|
164
|
+
// Call getTargetElement inside effect to support ref-based targets
|
|
165
|
+
// (ref.current is null during render, only available in commit phase)
|
|
166
|
+
const targetElement = getTargetElement(elementRef.current, defaultWindow);
|
|
120
167
|
if (!(targetElement && targetElement.addEventListener)) {
|
|
121
168
|
return;
|
|
122
169
|
}
|
|
@@ -130,10 +177,12 @@ function useEventListener(eventName, handler, element, options = defaultOptions$
|
|
|
130
177
|
};
|
|
131
178
|
}, [
|
|
132
179
|
eventName,
|
|
133
|
-
|
|
180
|
+
elementKey,
|
|
134
181
|
options
|
|
135
182
|
]);
|
|
136
183
|
}
|
|
184
|
+
function noop() {}
|
|
185
|
+
const useEventListener = isBrowser ? useEventListenerImpl : noop;
|
|
137
186
|
|
|
138
187
|
const useMount = (fn)=>{
|
|
139
188
|
if (isDev) {
|
|
@@ -203,7 +252,7 @@ function _async_to_generator$7(fn) {
|
|
|
203
252
|
});
|
|
204
253
|
};
|
|
205
254
|
}
|
|
206
|
-
const useAsyncEffect = (effect, cleanup = noop, deps)=>{
|
|
255
|
+
const useAsyncEffect = (effect, cleanup = noop$1, deps)=>{
|
|
207
256
|
const mounted = useMountedState();
|
|
208
257
|
React.useEffect(()=>{
|
|
209
258
|
const execute = ()=>_async_to_generator$7(function*() {
|
|
@@ -1097,13 +1146,14 @@ const useDropZone = (target, onDrop)=>{
|
|
|
1097
1146
|
const useResizeObserver = (target, callback, options = defaultOptions$1)=>{
|
|
1098
1147
|
const savedCallback = useLatest(callback);
|
|
1099
1148
|
const observerRef = React.useRef();
|
|
1149
|
+
const { key: targetKey, ref: targetRef } = useStableTarget(target);
|
|
1100
1150
|
const stop = React.useCallback(()=>{
|
|
1101
1151
|
if (observerRef.current) {
|
|
1102
1152
|
observerRef.current.disconnect();
|
|
1103
1153
|
}
|
|
1104
1154
|
}, []);
|
|
1105
1155
|
useDeepCompareEffect(()=>{
|
|
1106
|
-
const element = getTargetElement(
|
|
1156
|
+
const element = getTargetElement(targetRef.current);
|
|
1107
1157
|
if (!element) {
|
|
1108
1158
|
return;
|
|
1109
1159
|
}
|
|
@@ -1111,9 +1161,7 @@ const useResizeObserver = (target, callback, options = defaultOptions$1)=>{
|
|
|
1111
1161
|
observerRef.current.observe(element, options);
|
|
1112
1162
|
return stop;
|
|
1113
1163
|
}, [
|
|
1114
|
-
|
|
1115
|
-
stop,
|
|
1116
|
-
target,
|
|
1164
|
+
targetKey,
|
|
1117
1165
|
options
|
|
1118
1166
|
]);
|
|
1119
1167
|
return stop;
|
|
@@ -1224,13 +1272,14 @@ const useElementSize = (target, options = defaultOptions$1)=>{
|
|
|
1224
1272
|
const useIntersectionObserver = (target, callback, options = defaultOptions$1)=>{
|
|
1225
1273
|
const savedCallback = useLatest(callback);
|
|
1226
1274
|
const observerRef = React.useRef();
|
|
1275
|
+
const { key: targetKey, ref: targetRef } = useStableTarget(target);
|
|
1227
1276
|
const stop = React.useCallback(()=>{
|
|
1228
1277
|
if (observerRef.current) {
|
|
1229
1278
|
observerRef.current.disconnect();
|
|
1230
1279
|
}
|
|
1231
1280
|
}, []);
|
|
1232
1281
|
useDeepCompareEffect(()=>{
|
|
1233
|
-
const element = getTargetElement(
|
|
1282
|
+
const element = getTargetElement(targetRef.current);
|
|
1234
1283
|
if (!element) {
|
|
1235
1284
|
return;
|
|
1236
1285
|
}
|
|
@@ -1238,6 +1287,7 @@ const useIntersectionObserver = (target, callback, options = defaultOptions$1)=>
|
|
|
1238
1287
|
observerRef.current.observe(element);
|
|
1239
1288
|
return stop;
|
|
1240
1289
|
}, [
|
|
1290
|
+
targetKey,
|
|
1241
1291
|
options
|
|
1242
1292
|
]);
|
|
1243
1293
|
return stop;
|
|
@@ -1774,7 +1824,7 @@ const defaultListerOptions = {
|
|
|
1774
1824
|
passive: true
|
|
1775
1825
|
};
|
|
1776
1826
|
const useScroll = (target, options = defaultOptions$1)=>{
|
|
1777
|
-
const { throttle = 0, idle = 200, onStop = noop, onScroll = noop, offset = {
|
|
1827
|
+
const { throttle = 0, idle = 200, onStop = noop$1, onScroll = noop$1, offset = {
|
|
1778
1828
|
left: 0,
|
|
1779
1829
|
right: 0,
|
|
1780
1830
|
top: 0,
|
|
@@ -2112,7 +2162,7 @@ const useMediaDevices = (options = {})=>{
|
|
|
2112
2162
|
label
|
|
2113
2163
|
}))
|
|
2114
2164
|
});
|
|
2115
|
-
}).catch(noop);
|
|
2165
|
+
}).catch(noop$1);
|
|
2116
2166
|
}, []);
|
|
2117
2167
|
const ensurePermissions = React.useCallback(()=>_async_to_generator$3(function*() {
|
|
2118
2168
|
if (!isSupported) {
|
|
@@ -2343,13 +2393,14 @@ const useMousePressed = (target, options = defaultOptions$1)=>{
|
|
|
2343
2393
|
const useMutationObserver = (callback, target, options = defaultOptions$1)=>{
|
|
2344
2394
|
const callbackRef = useLatest(callback);
|
|
2345
2395
|
const observerRef = React.useRef();
|
|
2396
|
+
const { key: targetKey, ref: targetRef } = useStableTarget(target);
|
|
2346
2397
|
const stop = React.useCallback(()=>{
|
|
2347
2398
|
if (observerRef.current) {
|
|
2348
2399
|
observerRef.current.disconnect();
|
|
2349
2400
|
}
|
|
2350
2401
|
}, []);
|
|
2351
2402
|
useDeepCompareEffect(()=>{
|
|
2352
|
-
const element = getTargetElement(
|
|
2403
|
+
const element = getTargetElement(targetRef.current);
|
|
2353
2404
|
if (!element) {
|
|
2354
2405
|
return;
|
|
2355
2406
|
}
|
|
@@ -2357,6 +2408,7 @@ const useMutationObserver = (callback, target, options = defaultOptions$1)=>{
|
|
|
2357
2408
|
observerRef.current.observe(element, options);
|
|
2358
2409
|
return stop;
|
|
2359
2410
|
}, [
|
|
2411
|
+
targetKey,
|
|
2360
2412
|
options
|
|
2361
2413
|
]);
|
|
2362
2414
|
return stop;
|
|
@@ -2515,13 +2567,13 @@ function usePageLeave() {
|
|
|
2515
2567
|
const from = event.relatedTarget || event.toElement;
|
|
2516
2568
|
setIsLeft(!from);
|
|
2517
2569
|
};
|
|
2518
|
-
useEventListener('mouseout', handler,
|
|
2570
|
+
useEventListener('mouseout', handler, defaultWindow, {
|
|
2519
2571
|
passive: true
|
|
2520
2572
|
});
|
|
2521
|
-
useEventListener('mouseleave', handler,
|
|
2573
|
+
useEventListener('mouseleave', handler, defaultDocument, {
|
|
2522
2574
|
passive: true
|
|
2523
2575
|
});
|
|
2524
|
-
useEventListener('mouseenter', handler,
|
|
2576
|
+
useEventListener('mouseenter', handler, defaultDocument, {
|
|
2525
2577
|
passive: true
|
|
2526
2578
|
});
|
|
2527
2579
|
return isLeft;
|
|
@@ -2549,7 +2601,7 @@ const usePermission = (permissionDesc)=>{
|
|
|
2549
2601
|
permissionStatus = status;
|
|
2550
2602
|
on(permissionStatus, 'change', onChange);
|
|
2551
2603
|
onChange();
|
|
2552
|
-
}).catch(noop);
|
|
2604
|
+
}).catch(noop$1);
|
|
2553
2605
|
return ()=>{
|
|
2554
2606
|
permissionStatus && off(permissionStatus, 'change', onChange);
|
|
2555
2607
|
mounted = false;
|
|
@@ -2687,7 +2739,7 @@ const useScratch = (target, options = {})=>{
|
|
|
2687
2739
|
isScratching: true
|
|
2688
2740
|
});
|
|
2689
2741
|
refState.current = newState;
|
|
2690
|
-
(optionsRef.current.onScratch || noop)(newState);
|
|
2742
|
+
(optionsRef.current.onScratch || noop$1)(newState);
|
|
2691
2743
|
return newState;
|
|
2692
2744
|
});
|
|
2693
2745
|
});
|
|
@@ -2701,7 +2753,7 @@ const useScratch = (target, options = {})=>{
|
|
|
2701
2753
|
isScratching: false
|
|
2702
2754
|
});
|
|
2703
2755
|
refState.current = endState;
|
|
2704
|
-
(optionsRef.current.onScratchEnd || noop)(endState);
|
|
2756
|
+
(optionsRef.current.onScratchEnd || noop$1)(endState);
|
|
2705
2757
|
setState(endState);
|
|
2706
2758
|
};
|
|
2707
2759
|
const startScratching = (docX, docY)=>{
|
|
@@ -2734,7 +2786,7 @@ const useScratch = (target, options = {})=>{
|
|
|
2734
2786
|
posY: elY
|
|
2735
2787
|
};
|
|
2736
2788
|
refState.current = newState;
|
|
2737
|
-
(optionsRef.current.onScratchStart || noop)(newState);
|
|
2789
|
+
(optionsRef.current.onScratchStart || noop$1)(newState);
|
|
2738
2790
|
setState(newState);
|
|
2739
2791
|
};
|
|
2740
2792
|
useEventListener('mousedown', (event)=>{
|
|
@@ -2761,7 +2813,7 @@ const useScratch = (target, options = {})=>{
|
|
|
2761
2813
|
return state;
|
|
2762
2814
|
};
|
|
2763
2815
|
|
|
2764
|
-
const useScriptTag = (src, onLoaded = noop, options = defaultOptions$1)=>{
|
|
2816
|
+
const useScriptTag = (src, onLoaded = noop$1, options = defaultOptions$1)=>{
|
|
2765
2817
|
const { immediate = true, manual = false, type = 'text/javascript', async = true, crossOrigin, referrerPolicy, noModule, defer, attrs = {} } = options;
|
|
2766
2818
|
const scriptTag = React.useRef(null);
|
|
2767
2819
|
const _promise = React.useRef(null);
|
|
@@ -3171,21 +3223,25 @@ const useSetState = (initialState)=>{
|
|
|
3171
3223
|
|
|
3172
3224
|
function useSticky(targetElement, { axis = 'y', nav = 0 }, scrollElement) {
|
|
3173
3225
|
const [isSticky, setSticky] = React.useState(false);
|
|
3226
|
+
const { key: targetKey, ref: targetRef } = useStableTarget(targetElement);
|
|
3227
|
+
const { key: scrollKey, ref: scrollRef } = useStableTarget(scrollElement);
|
|
3228
|
+
const axisRef = useLatest(axis);
|
|
3229
|
+
const navRef = useLatest(nav);
|
|
3174
3230
|
const { run: scrollHandler } = useThrottleFn(()=>{
|
|
3175
|
-
const element = getTargetElement(
|
|
3231
|
+
const element = getTargetElement(targetRef.current);
|
|
3176
3232
|
if (!element) {
|
|
3177
3233
|
return;
|
|
3178
3234
|
}
|
|
3179
3235
|
const rect = element.getBoundingClientRect();
|
|
3180
|
-
if (
|
|
3181
|
-
setSticky((rect == null ? void 0 : rect.top) <=
|
|
3236
|
+
if (axisRef.current === 'y') {
|
|
3237
|
+
setSticky((rect == null ? void 0 : rect.top) <= navRef.current);
|
|
3182
3238
|
} else {
|
|
3183
|
-
setSticky((rect == null ? void 0 : rect.left) <=
|
|
3239
|
+
setSticky((rect == null ? void 0 : rect.left) <= navRef.current);
|
|
3184
3240
|
}
|
|
3185
3241
|
}, 50);
|
|
3186
3242
|
React.useEffect(()=>{
|
|
3187
|
-
const element = getTargetElement(
|
|
3188
|
-
const scrollParent = getTargetElement(
|
|
3243
|
+
const element = getTargetElement(targetRef.current);
|
|
3244
|
+
const scrollParent = getTargetElement(scrollRef.current) || getScrollParent(axisRef.current, element);
|
|
3189
3245
|
if (!element || !scrollParent) {
|
|
3190
3246
|
return;
|
|
3191
3247
|
}
|
|
@@ -3195,9 +3251,8 @@ function useSticky(targetElement, { axis = 'y', nav = 0 }, scrollElement) {
|
|
|
3195
3251
|
scrollParent.removeEventListener('scroll', scrollHandler);
|
|
3196
3252
|
};
|
|
3197
3253
|
}, [
|
|
3198
|
-
|
|
3199
|
-
|
|
3200
|
-
scrollElement,
|
|
3254
|
+
targetKey,
|
|
3255
|
+
scrollKey,
|
|
3201
3256
|
scrollHandler
|
|
3202
3257
|
]);
|
|
3203
3258
|
return [
|
package/dist/index.d.cts
CHANGED
|
@@ -888,12 +888,13 @@ interface UseEventEmitterReturn<T, U = void> {
|
|
|
888
888
|
declare function useEventEmitter<T, U = void>(): readonly [UseEventEmitterEvent<T, U>, (arg1: T, arg2: U) => void, () => void];
|
|
889
889
|
|
|
890
890
|
type Target = BasicTarget<HTMLElement | Element | Window | Document | EventTarget>;
|
|
891
|
-
declare function
|
|
892
|
-
declare function
|
|
893
|
-
declare function
|
|
894
|
-
declare function
|
|
895
|
-
declare function
|
|
896
|
-
declare function
|
|
891
|
+
declare function useEventListenerImpl<K extends keyof WindowEventMap>(eventName: K, handler: (event: WindowEventMap[K]) => void, element?: Window, options?: boolean | AddEventListenerOptions): void;
|
|
892
|
+
declare function useEventListenerImpl<K extends keyof DocumentEventMap>(eventName: K, handler: (event: DocumentEventMap[K]) => void, element: Document, options?: boolean | AddEventListenerOptions): void;
|
|
893
|
+
declare function useEventListenerImpl<K extends keyof HTMLElementEventMap, T extends HTMLElement = HTMLDivElement>(eventName: K, handler: (event: HTMLElementEventMap[K]) => void, element: T, options?: boolean | AddEventListenerOptions): void;
|
|
894
|
+
declare function useEventListenerImpl<K extends keyof ElementEventMap>(eventName: K, handler: (event: ElementEventMap[K]) => void, element: Element, options?: boolean | AddEventListenerOptions): void;
|
|
895
|
+
declare function useEventListenerImpl<K = Event>(eventName: string, handler: (event: K) => void, element: EventTarget | null | undefined, options?: boolean | AddEventListenerOptions): void;
|
|
896
|
+
declare function useEventListenerImpl(eventName: string, handler: (...p: any) => void, element?: Target, options?: boolean | AddEventListenerOptions): void;
|
|
897
|
+
declare const useEventListener: typeof useEventListenerImpl;
|
|
897
898
|
|
|
898
899
|
/**
|
|
899
900
|
* @title useEyeDropper
|
package/dist/index.d.mts
CHANGED
|
@@ -888,12 +888,13 @@ interface UseEventEmitterReturn<T, U = void> {
|
|
|
888
888
|
declare function useEventEmitter<T, U = void>(): readonly [UseEventEmitterEvent<T, U>, (arg1: T, arg2: U) => void, () => void];
|
|
889
889
|
|
|
890
890
|
type Target = BasicTarget<HTMLElement | Element | Window | Document | EventTarget>;
|
|
891
|
-
declare function
|
|
892
|
-
declare function
|
|
893
|
-
declare function
|
|
894
|
-
declare function
|
|
895
|
-
declare function
|
|
896
|
-
declare function
|
|
891
|
+
declare function useEventListenerImpl<K extends keyof WindowEventMap>(eventName: K, handler: (event: WindowEventMap[K]) => void, element?: Window, options?: boolean | AddEventListenerOptions): void;
|
|
892
|
+
declare function useEventListenerImpl<K extends keyof DocumentEventMap>(eventName: K, handler: (event: DocumentEventMap[K]) => void, element: Document, options?: boolean | AddEventListenerOptions): void;
|
|
893
|
+
declare function useEventListenerImpl<K extends keyof HTMLElementEventMap, T extends HTMLElement = HTMLDivElement>(eventName: K, handler: (event: HTMLElementEventMap[K]) => void, element: T, options?: boolean | AddEventListenerOptions): void;
|
|
894
|
+
declare function useEventListenerImpl<K extends keyof ElementEventMap>(eventName: K, handler: (event: ElementEventMap[K]) => void, element: Element, options?: boolean | AddEventListenerOptions): void;
|
|
895
|
+
declare function useEventListenerImpl<K = Event>(eventName: string, handler: (event: K) => void, element: EventTarget | null | undefined, options?: boolean | AddEventListenerOptions): void;
|
|
896
|
+
declare function useEventListenerImpl(eventName: string, handler: (...p: any) => void, element?: Target, options?: boolean | AddEventListenerOptions): void;
|
|
897
|
+
declare const useEventListener: typeof useEventListenerImpl;
|
|
897
898
|
|
|
898
899
|
/**
|
|
899
900
|
* @title useEyeDropper
|
package/dist/index.d.ts
CHANGED
|
@@ -888,12 +888,13 @@ interface UseEventEmitterReturn<T, U = void> {
|
|
|
888
888
|
declare function useEventEmitter<T, U = void>(): readonly [UseEventEmitterEvent<T, U>, (arg1: T, arg2: U) => void, () => void];
|
|
889
889
|
|
|
890
890
|
type Target = BasicTarget<HTMLElement | Element | Window | Document | EventTarget>;
|
|
891
|
-
declare function
|
|
892
|
-
declare function
|
|
893
|
-
declare function
|
|
894
|
-
declare function
|
|
895
|
-
declare function
|
|
896
|
-
declare function
|
|
891
|
+
declare function useEventListenerImpl<K extends keyof WindowEventMap>(eventName: K, handler: (event: WindowEventMap[K]) => void, element?: Window, options?: boolean | AddEventListenerOptions): void;
|
|
892
|
+
declare function useEventListenerImpl<K extends keyof DocumentEventMap>(eventName: K, handler: (event: DocumentEventMap[K]) => void, element: Document, options?: boolean | AddEventListenerOptions): void;
|
|
893
|
+
declare function useEventListenerImpl<K extends keyof HTMLElementEventMap, T extends HTMLElement = HTMLDivElement>(eventName: K, handler: (event: HTMLElementEventMap[K]) => void, element: T, options?: boolean | AddEventListenerOptions): void;
|
|
894
|
+
declare function useEventListenerImpl<K extends keyof ElementEventMap>(eventName: K, handler: (event: ElementEventMap[K]) => void, element: Element, options?: boolean | AddEventListenerOptions): void;
|
|
895
|
+
declare function useEventListenerImpl<K = Event>(eventName: string, handler: (event: K) => void, element: EventTarget | null | undefined, options?: boolean | AddEventListenerOptions): void;
|
|
896
|
+
declare function useEventListenerImpl(eventName: string, handler: (...p: any) => void, element?: Target, options?: boolean | AddEventListenerOptions): void;
|
|
897
|
+
declare const useEventListener: typeof useEventListenerImpl;
|
|
897
898
|
|
|
898
899
|
/**
|
|
899
900
|
* @title useEyeDropper
|
package/dist/index.mjs
CHANGED
|
@@ -15,7 +15,7 @@ function isString(val) {
|
|
|
15
15
|
const isDev = process.env.NODE_ENV === 'development' || process.env.NODE_ENV === 'test';
|
|
16
16
|
const isBrowser = typeof window !== 'undefined';
|
|
17
17
|
const isNavigator = typeof navigator !== 'undefined';
|
|
18
|
-
function noop() {}
|
|
18
|
+
function noop$1() {}
|
|
19
19
|
const isIOS = isBrowser && ((_window = window) == null ? void 0 : (_window_navigator = _window.navigator) == null ? void 0 : _window_navigator.userAgent) && /iP(?:ad|hone|od)/.test(window.navigator.userAgent);
|
|
20
20
|
|
|
21
21
|
const useIsomorphicLayoutEffect = isBrowser ? useLayoutEffect : useEffect;
|
|
@@ -105,10 +105,57 @@ const useDeepCompareEffect = (effect, deps)=>{
|
|
|
105
105
|
useCustomCompareEffect(effect, deps, isEqual);
|
|
106
106
|
};
|
|
107
107
|
|
|
108
|
-
|
|
108
|
+
/**
|
|
109
|
+
* Creates a stable identifier for a BasicTarget that can be safely used in effect dependencies.
|
|
110
|
+
*
|
|
111
|
+
* This hook solves the problem where passing unstable function references like `() => document`
|
|
112
|
+
* would cause infinite re-renders when used directly in effect dependency arrays.
|
|
113
|
+
*
|
|
114
|
+
* @param target - The target element (ref, function, or direct element)
|
|
115
|
+
* @param defaultElement - Default element to use if target is undefined
|
|
116
|
+
* @returns A stable reference that only changes when the actual target element changes
|
|
117
|
+
*
|
|
118
|
+
* @example
|
|
119
|
+
* ```tsx
|
|
120
|
+
* // For ref objects: returns the ref itself (stable)
|
|
121
|
+
* const ref = useRef<HTMLDivElement>(null)
|
|
122
|
+
* const key = useStableTarget(ref) // key === ref (stable)
|
|
123
|
+
*
|
|
124
|
+
* // For functions: returns the resolved actual element
|
|
125
|
+
* const key = useStableTarget(() => document) // key === document (stable)
|
|
126
|
+
*
|
|
127
|
+
* // For direct elements: returns the element itself
|
|
128
|
+
* const key = useStableTarget(divElement) // key === divElement (stable)
|
|
129
|
+
* ```
|
|
130
|
+
*/ function useStableTarget(target, defaultElement) {
|
|
131
|
+
const targetRef = useRef(target);
|
|
132
|
+
targetRef.current = target;
|
|
133
|
+
// Calculate stable key without memoization
|
|
134
|
+
// For ref objects: return the ref itself (always stable)
|
|
135
|
+
// For functions/direct elements: resolve to the actual element
|
|
136
|
+
let stableKey;
|
|
137
|
+
if (!target) {
|
|
138
|
+
stableKey = defaultElement != null ? defaultElement : null;
|
|
139
|
+
} else if (typeof target === 'object' && 'current' in target) {
|
|
140
|
+
// Ref object - use the ref itself as the stable key
|
|
141
|
+
stableKey = target;
|
|
142
|
+
} else {
|
|
143
|
+
// Function or direct element - resolve to actual element
|
|
144
|
+
stableKey = getTargetElement(target, defaultElement);
|
|
145
|
+
}
|
|
146
|
+
return {
|
|
147
|
+
/** The stable key that can be safely used in effect dependencies */ key: stableKey,
|
|
148
|
+
/** A ref containing the current target (useful for accessing in effects) */ ref: targetRef
|
|
149
|
+
};
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
function useEventListenerImpl(eventName, handler, element, options = defaultOptions$1) {
|
|
109
153
|
const savedHandler = useLatest(handler);
|
|
154
|
+
const { key: elementKey, ref: elementRef } = useStableTarget(element, defaultWindow);
|
|
110
155
|
useDeepCompareEffect(()=>{
|
|
111
|
-
|
|
156
|
+
// Call getTargetElement inside effect to support ref-based targets
|
|
157
|
+
// (ref.current is null during render, only available in commit phase)
|
|
158
|
+
const targetElement = getTargetElement(elementRef.current, defaultWindow);
|
|
112
159
|
if (!(targetElement && targetElement.addEventListener)) {
|
|
113
160
|
return;
|
|
114
161
|
}
|
|
@@ -122,10 +169,12 @@ function useEventListener(eventName, handler, element, options = defaultOptions$
|
|
|
122
169
|
};
|
|
123
170
|
}, [
|
|
124
171
|
eventName,
|
|
125
|
-
|
|
172
|
+
elementKey,
|
|
126
173
|
options
|
|
127
174
|
]);
|
|
128
175
|
}
|
|
176
|
+
function noop() {}
|
|
177
|
+
const useEventListener = isBrowser ? useEventListenerImpl : noop;
|
|
129
178
|
|
|
130
179
|
const useMount = (fn)=>{
|
|
131
180
|
if (isDev) {
|
|
@@ -195,7 +244,7 @@ function _async_to_generator$7(fn) {
|
|
|
195
244
|
});
|
|
196
245
|
};
|
|
197
246
|
}
|
|
198
|
-
const useAsyncEffect = (effect, cleanup = noop, deps)=>{
|
|
247
|
+
const useAsyncEffect = (effect, cleanup = noop$1, deps)=>{
|
|
199
248
|
const mounted = useMountedState();
|
|
200
249
|
useEffect(()=>{
|
|
201
250
|
const execute = ()=>_async_to_generator$7(function*() {
|
|
@@ -1089,13 +1138,14 @@ const useDropZone = (target, onDrop)=>{
|
|
|
1089
1138
|
const useResizeObserver = (target, callback, options = defaultOptions$1)=>{
|
|
1090
1139
|
const savedCallback = useLatest(callback);
|
|
1091
1140
|
const observerRef = useRef();
|
|
1141
|
+
const { key: targetKey, ref: targetRef } = useStableTarget(target);
|
|
1092
1142
|
const stop = useCallback(()=>{
|
|
1093
1143
|
if (observerRef.current) {
|
|
1094
1144
|
observerRef.current.disconnect();
|
|
1095
1145
|
}
|
|
1096
1146
|
}, []);
|
|
1097
1147
|
useDeepCompareEffect(()=>{
|
|
1098
|
-
const element = getTargetElement(
|
|
1148
|
+
const element = getTargetElement(targetRef.current);
|
|
1099
1149
|
if (!element) {
|
|
1100
1150
|
return;
|
|
1101
1151
|
}
|
|
@@ -1103,9 +1153,7 @@ const useResizeObserver = (target, callback, options = defaultOptions$1)=>{
|
|
|
1103
1153
|
observerRef.current.observe(element, options);
|
|
1104
1154
|
return stop;
|
|
1105
1155
|
}, [
|
|
1106
|
-
|
|
1107
|
-
stop,
|
|
1108
|
-
target,
|
|
1156
|
+
targetKey,
|
|
1109
1157
|
options
|
|
1110
1158
|
]);
|
|
1111
1159
|
return stop;
|
|
@@ -1216,13 +1264,14 @@ const useElementSize = (target, options = defaultOptions$1)=>{
|
|
|
1216
1264
|
const useIntersectionObserver = (target, callback, options = defaultOptions$1)=>{
|
|
1217
1265
|
const savedCallback = useLatest(callback);
|
|
1218
1266
|
const observerRef = useRef();
|
|
1267
|
+
const { key: targetKey, ref: targetRef } = useStableTarget(target);
|
|
1219
1268
|
const stop = useCallback(()=>{
|
|
1220
1269
|
if (observerRef.current) {
|
|
1221
1270
|
observerRef.current.disconnect();
|
|
1222
1271
|
}
|
|
1223
1272
|
}, []);
|
|
1224
1273
|
useDeepCompareEffect(()=>{
|
|
1225
|
-
const element = getTargetElement(
|
|
1274
|
+
const element = getTargetElement(targetRef.current);
|
|
1226
1275
|
if (!element) {
|
|
1227
1276
|
return;
|
|
1228
1277
|
}
|
|
@@ -1230,6 +1279,7 @@ const useIntersectionObserver = (target, callback, options = defaultOptions$1)=>
|
|
|
1230
1279
|
observerRef.current.observe(element);
|
|
1231
1280
|
return stop;
|
|
1232
1281
|
}, [
|
|
1282
|
+
targetKey,
|
|
1233
1283
|
options
|
|
1234
1284
|
]);
|
|
1235
1285
|
return stop;
|
|
@@ -1766,7 +1816,7 @@ const defaultListerOptions = {
|
|
|
1766
1816
|
passive: true
|
|
1767
1817
|
};
|
|
1768
1818
|
const useScroll = (target, options = defaultOptions$1)=>{
|
|
1769
|
-
const { throttle = 0, idle = 200, onStop = noop, onScroll = noop, offset = {
|
|
1819
|
+
const { throttle = 0, idle = 200, onStop = noop$1, onScroll = noop$1, offset = {
|
|
1770
1820
|
left: 0,
|
|
1771
1821
|
right: 0,
|
|
1772
1822
|
top: 0,
|
|
@@ -2104,7 +2154,7 @@ const useMediaDevices = (options = {})=>{
|
|
|
2104
2154
|
label
|
|
2105
2155
|
}))
|
|
2106
2156
|
});
|
|
2107
|
-
}).catch(noop);
|
|
2157
|
+
}).catch(noop$1);
|
|
2108
2158
|
}, []);
|
|
2109
2159
|
const ensurePermissions = useCallback(()=>_async_to_generator$3(function*() {
|
|
2110
2160
|
if (!isSupported) {
|
|
@@ -2335,13 +2385,14 @@ const useMousePressed = (target, options = defaultOptions$1)=>{
|
|
|
2335
2385
|
const useMutationObserver = (callback, target, options = defaultOptions$1)=>{
|
|
2336
2386
|
const callbackRef = useLatest(callback);
|
|
2337
2387
|
const observerRef = useRef();
|
|
2388
|
+
const { key: targetKey, ref: targetRef } = useStableTarget(target);
|
|
2338
2389
|
const stop = useCallback(()=>{
|
|
2339
2390
|
if (observerRef.current) {
|
|
2340
2391
|
observerRef.current.disconnect();
|
|
2341
2392
|
}
|
|
2342
2393
|
}, []);
|
|
2343
2394
|
useDeepCompareEffect(()=>{
|
|
2344
|
-
const element = getTargetElement(
|
|
2395
|
+
const element = getTargetElement(targetRef.current);
|
|
2345
2396
|
if (!element) {
|
|
2346
2397
|
return;
|
|
2347
2398
|
}
|
|
@@ -2349,6 +2400,7 @@ const useMutationObserver = (callback, target, options = defaultOptions$1)=>{
|
|
|
2349
2400
|
observerRef.current.observe(element, options);
|
|
2350
2401
|
return stop;
|
|
2351
2402
|
}, [
|
|
2403
|
+
targetKey,
|
|
2352
2404
|
options
|
|
2353
2405
|
]);
|
|
2354
2406
|
return stop;
|
|
@@ -2507,13 +2559,13 @@ function usePageLeave() {
|
|
|
2507
2559
|
const from = event.relatedTarget || event.toElement;
|
|
2508
2560
|
setIsLeft(!from);
|
|
2509
2561
|
};
|
|
2510
|
-
useEventListener('mouseout', handler,
|
|
2562
|
+
useEventListener('mouseout', handler, defaultWindow, {
|
|
2511
2563
|
passive: true
|
|
2512
2564
|
});
|
|
2513
|
-
useEventListener('mouseleave', handler,
|
|
2565
|
+
useEventListener('mouseleave', handler, defaultDocument, {
|
|
2514
2566
|
passive: true
|
|
2515
2567
|
});
|
|
2516
|
-
useEventListener('mouseenter', handler,
|
|
2568
|
+
useEventListener('mouseenter', handler, defaultDocument, {
|
|
2517
2569
|
passive: true
|
|
2518
2570
|
});
|
|
2519
2571
|
return isLeft;
|
|
@@ -2541,7 +2593,7 @@ const usePermission = (permissionDesc)=>{
|
|
|
2541
2593
|
permissionStatus = status;
|
|
2542
2594
|
on(permissionStatus, 'change', onChange);
|
|
2543
2595
|
onChange();
|
|
2544
|
-
}).catch(noop);
|
|
2596
|
+
}).catch(noop$1);
|
|
2545
2597
|
return ()=>{
|
|
2546
2598
|
permissionStatus && off(permissionStatus, 'change', onChange);
|
|
2547
2599
|
mounted = false;
|
|
@@ -2679,7 +2731,7 @@ const useScratch = (target, options = {})=>{
|
|
|
2679
2731
|
isScratching: true
|
|
2680
2732
|
});
|
|
2681
2733
|
refState.current = newState;
|
|
2682
|
-
(optionsRef.current.onScratch || noop)(newState);
|
|
2734
|
+
(optionsRef.current.onScratch || noop$1)(newState);
|
|
2683
2735
|
return newState;
|
|
2684
2736
|
});
|
|
2685
2737
|
});
|
|
@@ -2693,7 +2745,7 @@ const useScratch = (target, options = {})=>{
|
|
|
2693
2745
|
isScratching: false
|
|
2694
2746
|
});
|
|
2695
2747
|
refState.current = endState;
|
|
2696
|
-
(optionsRef.current.onScratchEnd || noop)(endState);
|
|
2748
|
+
(optionsRef.current.onScratchEnd || noop$1)(endState);
|
|
2697
2749
|
setState(endState);
|
|
2698
2750
|
};
|
|
2699
2751
|
const startScratching = (docX, docY)=>{
|
|
@@ -2726,7 +2778,7 @@ const useScratch = (target, options = {})=>{
|
|
|
2726
2778
|
posY: elY
|
|
2727
2779
|
};
|
|
2728
2780
|
refState.current = newState;
|
|
2729
|
-
(optionsRef.current.onScratchStart || noop)(newState);
|
|
2781
|
+
(optionsRef.current.onScratchStart || noop$1)(newState);
|
|
2730
2782
|
setState(newState);
|
|
2731
2783
|
};
|
|
2732
2784
|
useEventListener('mousedown', (event)=>{
|
|
@@ -2753,7 +2805,7 @@ const useScratch = (target, options = {})=>{
|
|
|
2753
2805
|
return state;
|
|
2754
2806
|
};
|
|
2755
2807
|
|
|
2756
|
-
const useScriptTag = (src, onLoaded = noop, options = defaultOptions$1)=>{
|
|
2808
|
+
const useScriptTag = (src, onLoaded = noop$1, options = defaultOptions$1)=>{
|
|
2757
2809
|
const { immediate = true, manual = false, type = 'text/javascript', async = true, crossOrigin, referrerPolicy, noModule, defer, attrs = {} } = options;
|
|
2758
2810
|
const scriptTag = useRef(null);
|
|
2759
2811
|
const _promise = useRef(null);
|
|
@@ -3163,21 +3215,25 @@ const useSetState = (initialState)=>{
|
|
|
3163
3215
|
|
|
3164
3216
|
function useSticky(targetElement, { axis = 'y', nav = 0 }, scrollElement) {
|
|
3165
3217
|
const [isSticky, setSticky] = useState(false);
|
|
3218
|
+
const { key: targetKey, ref: targetRef } = useStableTarget(targetElement);
|
|
3219
|
+
const { key: scrollKey, ref: scrollRef } = useStableTarget(scrollElement);
|
|
3220
|
+
const axisRef = useLatest(axis);
|
|
3221
|
+
const navRef = useLatest(nav);
|
|
3166
3222
|
const { run: scrollHandler } = useThrottleFn(()=>{
|
|
3167
|
-
const element = getTargetElement(
|
|
3223
|
+
const element = getTargetElement(targetRef.current);
|
|
3168
3224
|
if (!element) {
|
|
3169
3225
|
return;
|
|
3170
3226
|
}
|
|
3171
3227
|
const rect = element.getBoundingClientRect();
|
|
3172
|
-
if (
|
|
3173
|
-
setSticky((rect == null ? void 0 : rect.top) <=
|
|
3228
|
+
if (axisRef.current === 'y') {
|
|
3229
|
+
setSticky((rect == null ? void 0 : rect.top) <= navRef.current);
|
|
3174
3230
|
} else {
|
|
3175
|
-
setSticky((rect == null ? void 0 : rect.left) <=
|
|
3231
|
+
setSticky((rect == null ? void 0 : rect.left) <= navRef.current);
|
|
3176
3232
|
}
|
|
3177
3233
|
}, 50);
|
|
3178
3234
|
useEffect(()=>{
|
|
3179
|
-
const element = getTargetElement(
|
|
3180
|
-
const scrollParent = getTargetElement(
|
|
3235
|
+
const element = getTargetElement(targetRef.current);
|
|
3236
|
+
const scrollParent = getTargetElement(scrollRef.current) || getScrollParent(axisRef.current, element);
|
|
3181
3237
|
if (!element || !scrollParent) {
|
|
3182
3238
|
return;
|
|
3183
3239
|
}
|
|
@@ -3187,9 +3243,8 @@ function useSticky(targetElement, { axis = 'y', nav = 0 }, scrollElement) {
|
|
|
3187
3243
|
scrollParent.removeEventListener('scroll', scrollHandler);
|
|
3188
3244
|
};
|
|
3189
3245
|
}, [
|
|
3190
|
-
|
|
3191
|
-
|
|
3192
|
-
scrollElement,
|
|
3246
|
+
targetKey,
|
|
3247
|
+
scrollKey,
|
|
3193
3248
|
scrollHandler
|
|
3194
3249
|
]);
|
|
3195
3250
|
return [
|