@reactuses/core 6.1.10 → 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 +70 -17
- package/dist/index.mjs +70 -17
- package/package.json +1 -1
package/dist/index.cjs
CHANGED
|
@@ -113,10 +113,57 @@ const useDeepCompareEffect = (effect, deps)=>{
|
|
|
113
113
|
useCustomCompareEffect(effect, deps, lodashEs.isEqual);
|
|
114
114
|
};
|
|
115
115
|
|
|
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
|
+
|
|
116
160
|
function useEventListenerImpl(eventName, handler, element, options = defaultOptions$1) {
|
|
117
161
|
const savedHandler = useLatest(handler);
|
|
118
|
-
const
|
|
162
|
+
const { key: elementKey, ref: elementRef } = useStableTarget(element, defaultWindow);
|
|
119
163
|
useDeepCompareEffect(()=>{
|
|
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,7 +177,7 @@ function useEventListenerImpl(eventName, handler, element, options = defaultOpti
|
|
|
130
177
|
};
|
|
131
178
|
}, [
|
|
132
179
|
eventName,
|
|
133
|
-
|
|
180
|
+
elementKey,
|
|
134
181
|
options
|
|
135
182
|
]);
|
|
136
183
|
}
|
|
@@ -1099,13 +1146,14 @@ const useDropZone = (target, onDrop)=>{
|
|
|
1099
1146
|
const useResizeObserver = (target, callback, options = defaultOptions$1)=>{
|
|
1100
1147
|
const savedCallback = useLatest(callback);
|
|
1101
1148
|
const observerRef = React.useRef();
|
|
1149
|
+
const { key: targetKey, ref: targetRef } = useStableTarget(target);
|
|
1102
1150
|
const stop = React.useCallback(()=>{
|
|
1103
1151
|
if (observerRef.current) {
|
|
1104
1152
|
observerRef.current.disconnect();
|
|
1105
1153
|
}
|
|
1106
1154
|
}, []);
|
|
1107
1155
|
useDeepCompareEffect(()=>{
|
|
1108
|
-
const element = getTargetElement(
|
|
1156
|
+
const element = getTargetElement(targetRef.current);
|
|
1109
1157
|
if (!element) {
|
|
1110
1158
|
return;
|
|
1111
1159
|
}
|
|
@@ -1113,9 +1161,7 @@ const useResizeObserver = (target, callback, options = defaultOptions$1)=>{
|
|
|
1113
1161
|
observerRef.current.observe(element, options);
|
|
1114
1162
|
return stop;
|
|
1115
1163
|
}, [
|
|
1116
|
-
|
|
1117
|
-
stop,
|
|
1118
|
-
target,
|
|
1164
|
+
targetKey,
|
|
1119
1165
|
options
|
|
1120
1166
|
]);
|
|
1121
1167
|
return stop;
|
|
@@ -1226,13 +1272,14 @@ const useElementSize = (target, options = defaultOptions$1)=>{
|
|
|
1226
1272
|
const useIntersectionObserver = (target, callback, options = defaultOptions$1)=>{
|
|
1227
1273
|
const savedCallback = useLatest(callback);
|
|
1228
1274
|
const observerRef = React.useRef();
|
|
1275
|
+
const { key: targetKey, ref: targetRef } = useStableTarget(target);
|
|
1229
1276
|
const stop = React.useCallback(()=>{
|
|
1230
1277
|
if (observerRef.current) {
|
|
1231
1278
|
observerRef.current.disconnect();
|
|
1232
1279
|
}
|
|
1233
1280
|
}, []);
|
|
1234
1281
|
useDeepCompareEffect(()=>{
|
|
1235
|
-
const element = getTargetElement(
|
|
1282
|
+
const element = getTargetElement(targetRef.current);
|
|
1236
1283
|
if (!element) {
|
|
1237
1284
|
return;
|
|
1238
1285
|
}
|
|
@@ -1240,6 +1287,7 @@ const useIntersectionObserver = (target, callback, options = defaultOptions$1)=>
|
|
|
1240
1287
|
observerRef.current.observe(element);
|
|
1241
1288
|
return stop;
|
|
1242
1289
|
}, [
|
|
1290
|
+
targetKey,
|
|
1243
1291
|
options
|
|
1244
1292
|
]);
|
|
1245
1293
|
return stop;
|
|
@@ -2345,13 +2393,14 @@ const useMousePressed = (target, options = defaultOptions$1)=>{
|
|
|
2345
2393
|
const useMutationObserver = (callback, target, options = defaultOptions$1)=>{
|
|
2346
2394
|
const callbackRef = useLatest(callback);
|
|
2347
2395
|
const observerRef = React.useRef();
|
|
2396
|
+
const { key: targetKey, ref: targetRef } = useStableTarget(target);
|
|
2348
2397
|
const stop = React.useCallback(()=>{
|
|
2349
2398
|
if (observerRef.current) {
|
|
2350
2399
|
observerRef.current.disconnect();
|
|
2351
2400
|
}
|
|
2352
2401
|
}, []);
|
|
2353
2402
|
useDeepCompareEffect(()=>{
|
|
2354
|
-
const element = getTargetElement(
|
|
2403
|
+
const element = getTargetElement(targetRef.current);
|
|
2355
2404
|
if (!element) {
|
|
2356
2405
|
return;
|
|
2357
2406
|
}
|
|
@@ -2359,6 +2408,7 @@ const useMutationObserver = (callback, target, options = defaultOptions$1)=>{
|
|
|
2359
2408
|
observerRef.current.observe(element, options);
|
|
2360
2409
|
return stop;
|
|
2361
2410
|
}, [
|
|
2411
|
+
targetKey,
|
|
2362
2412
|
options
|
|
2363
2413
|
]);
|
|
2364
2414
|
return stop;
|
|
@@ -3173,21 +3223,25 @@ const useSetState = (initialState)=>{
|
|
|
3173
3223
|
|
|
3174
3224
|
function useSticky(targetElement, { axis = 'y', nav = 0 }, scrollElement) {
|
|
3175
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);
|
|
3176
3230
|
const { run: scrollHandler } = useThrottleFn(()=>{
|
|
3177
|
-
const element = getTargetElement(
|
|
3231
|
+
const element = getTargetElement(targetRef.current);
|
|
3178
3232
|
if (!element) {
|
|
3179
3233
|
return;
|
|
3180
3234
|
}
|
|
3181
3235
|
const rect = element.getBoundingClientRect();
|
|
3182
|
-
if (
|
|
3183
|
-
setSticky((rect == null ? void 0 : rect.top) <=
|
|
3236
|
+
if (axisRef.current === 'y') {
|
|
3237
|
+
setSticky((rect == null ? void 0 : rect.top) <= navRef.current);
|
|
3184
3238
|
} else {
|
|
3185
|
-
setSticky((rect == null ? void 0 : rect.left) <=
|
|
3239
|
+
setSticky((rect == null ? void 0 : rect.left) <= navRef.current);
|
|
3186
3240
|
}
|
|
3187
3241
|
}, 50);
|
|
3188
3242
|
React.useEffect(()=>{
|
|
3189
|
-
const element = getTargetElement(
|
|
3190
|
-
const scrollParent = getTargetElement(
|
|
3243
|
+
const element = getTargetElement(targetRef.current);
|
|
3244
|
+
const scrollParent = getTargetElement(scrollRef.current) || getScrollParent(axisRef.current, element);
|
|
3191
3245
|
if (!element || !scrollParent) {
|
|
3192
3246
|
return;
|
|
3193
3247
|
}
|
|
@@ -3197,9 +3251,8 @@ function useSticky(targetElement, { axis = 'y', nav = 0 }, scrollElement) {
|
|
|
3197
3251
|
scrollParent.removeEventListener('scroll', scrollHandler);
|
|
3198
3252
|
};
|
|
3199
3253
|
}, [
|
|
3200
|
-
|
|
3201
|
-
|
|
3202
|
-
scrollElement,
|
|
3254
|
+
targetKey,
|
|
3255
|
+
scrollKey,
|
|
3203
3256
|
scrollHandler
|
|
3204
3257
|
]);
|
|
3205
3258
|
return [
|
package/dist/index.mjs
CHANGED
|
@@ -105,10 +105,57 @@ const useDeepCompareEffect = (effect, deps)=>{
|
|
|
105
105
|
useCustomCompareEffect(effect, deps, isEqual);
|
|
106
106
|
};
|
|
107
107
|
|
|
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
|
+
|
|
108
152
|
function useEventListenerImpl(eventName, handler, element, options = defaultOptions$1) {
|
|
109
153
|
const savedHandler = useLatest(handler);
|
|
110
|
-
const
|
|
154
|
+
const { key: elementKey, ref: elementRef } = useStableTarget(element, defaultWindow);
|
|
111
155
|
useDeepCompareEffect(()=>{
|
|
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,7 +169,7 @@ function useEventListenerImpl(eventName, handler, element, options = defaultOpti
|
|
|
122
169
|
};
|
|
123
170
|
}, [
|
|
124
171
|
eventName,
|
|
125
|
-
|
|
172
|
+
elementKey,
|
|
126
173
|
options
|
|
127
174
|
]);
|
|
128
175
|
}
|
|
@@ -1091,13 +1138,14 @@ const useDropZone = (target, onDrop)=>{
|
|
|
1091
1138
|
const useResizeObserver = (target, callback, options = defaultOptions$1)=>{
|
|
1092
1139
|
const savedCallback = useLatest(callback);
|
|
1093
1140
|
const observerRef = useRef();
|
|
1141
|
+
const { key: targetKey, ref: targetRef } = useStableTarget(target);
|
|
1094
1142
|
const stop = useCallback(()=>{
|
|
1095
1143
|
if (observerRef.current) {
|
|
1096
1144
|
observerRef.current.disconnect();
|
|
1097
1145
|
}
|
|
1098
1146
|
}, []);
|
|
1099
1147
|
useDeepCompareEffect(()=>{
|
|
1100
|
-
const element = getTargetElement(
|
|
1148
|
+
const element = getTargetElement(targetRef.current);
|
|
1101
1149
|
if (!element) {
|
|
1102
1150
|
return;
|
|
1103
1151
|
}
|
|
@@ -1105,9 +1153,7 @@ const useResizeObserver = (target, callback, options = defaultOptions$1)=>{
|
|
|
1105
1153
|
observerRef.current.observe(element, options);
|
|
1106
1154
|
return stop;
|
|
1107
1155
|
}, [
|
|
1108
|
-
|
|
1109
|
-
stop,
|
|
1110
|
-
target,
|
|
1156
|
+
targetKey,
|
|
1111
1157
|
options
|
|
1112
1158
|
]);
|
|
1113
1159
|
return stop;
|
|
@@ -1218,13 +1264,14 @@ const useElementSize = (target, options = defaultOptions$1)=>{
|
|
|
1218
1264
|
const useIntersectionObserver = (target, callback, options = defaultOptions$1)=>{
|
|
1219
1265
|
const savedCallback = useLatest(callback);
|
|
1220
1266
|
const observerRef = useRef();
|
|
1267
|
+
const { key: targetKey, ref: targetRef } = useStableTarget(target);
|
|
1221
1268
|
const stop = useCallback(()=>{
|
|
1222
1269
|
if (observerRef.current) {
|
|
1223
1270
|
observerRef.current.disconnect();
|
|
1224
1271
|
}
|
|
1225
1272
|
}, []);
|
|
1226
1273
|
useDeepCompareEffect(()=>{
|
|
1227
|
-
const element = getTargetElement(
|
|
1274
|
+
const element = getTargetElement(targetRef.current);
|
|
1228
1275
|
if (!element) {
|
|
1229
1276
|
return;
|
|
1230
1277
|
}
|
|
@@ -1232,6 +1279,7 @@ const useIntersectionObserver = (target, callback, options = defaultOptions$1)=>
|
|
|
1232
1279
|
observerRef.current.observe(element);
|
|
1233
1280
|
return stop;
|
|
1234
1281
|
}, [
|
|
1282
|
+
targetKey,
|
|
1235
1283
|
options
|
|
1236
1284
|
]);
|
|
1237
1285
|
return stop;
|
|
@@ -2337,13 +2385,14 @@ const useMousePressed = (target, options = defaultOptions$1)=>{
|
|
|
2337
2385
|
const useMutationObserver = (callback, target, options = defaultOptions$1)=>{
|
|
2338
2386
|
const callbackRef = useLatest(callback);
|
|
2339
2387
|
const observerRef = useRef();
|
|
2388
|
+
const { key: targetKey, ref: targetRef } = useStableTarget(target);
|
|
2340
2389
|
const stop = useCallback(()=>{
|
|
2341
2390
|
if (observerRef.current) {
|
|
2342
2391
|
observerRef.current.disconnect();
|
|
2343
2392
|
}
|
|
2344
2393
|
}, []);
|
|
2345
2394
|
useDeepCompareEffect(()=>{
|
|
2346
|
-
const element = getTargetElement(
|
|
2395
|
+
const element = getTargetElement(targetRef.current);
|
|
2347
2396
|
if (!element) {
|
|
2348
2397
|
return;
|
|
2349
2398
|
}
|
|
@@ -2351,6 +2400,7 @@ const useMutationObserver = (callback, target, options = defaultOptions$1)=>{
|
|
|
2351
2400
|
observerRef.current.observe(element, options);
|
|
2352
2401
|
return stop;
|
|
2353
2402
|
}, [
|
|
2403
|
+
targetKey,
|
|
2354
2404
|
options
|
|
2355
2405
|
]);
|
|
2356
2406
|
return stop;
|
|
@@ -3165,21 +3215,25 @@ const useSetState = (initialState)=>{
|
|
|
3165
3215
|
|
|
3166
3216
|
function useSticky(targetElement, { axis = 'y', nav = 0 }, scrollElement) {
|
|
3167
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);
|
|
3168
3222
|
const { run: scrollHandler } = useThrottleFn(()=>{
|
|
3169
|
-
const element = getTargetElement(
|
|
3223
|
+
const element = getTargetElement(targetRef.current);
|
|
3170
3224
|
if (!element) {
|
|
3171
3225
|
return;
|
|
3172
3226
|
}
|
|
3173
3227
|
const rect = element.getBoundingClientRect();
|
|
3174
|
-
if (
|
|
3175
|
-
setSticky((rect == null ? void 0 : rect.top) <=
|
|
3228
|
+
if (axisRef.current === 'y') {
|
|
3229
|
+
setSticky((rect == null ? void 0 : rect.top) <= navRef.current);
|
|
3176
3230
|
} else {
|
|
3177
|
-
setSticky((rect == null ? void 0 : rect.left) <=
|
|
3231
|
+
setSticky((rect == null ? void 0 : rect.left) <= navRef.current);
|
|
3178
3232
|
}
|
|
3179
3233
|
}, 50);
|
|
3180
3234
|
useEffect(()=>{
|
|
3181
|
-
const element = getTargetElement(
|
|
3182
|
-
const scrollParent = getTargetElement(
|
|
3235
|
+
const element = getTargetElement(targetRef.current);
|
|
3236
|
+
const scrollParent = getTargetElement(scrollRef.current) || getScrollParent(axisRef.current, element);
|
|
3183
3237
|
if (!element || !scrollParent) {
|
|
3184
3238
|
return;
|
|
3185
3239
|
}
|
|
@@ -3189,9 +3243,8 @@ function useSticky(targetElement, { axis = 'y', nav = 0 }, scrollElement) {
|
|
|
3189
3243
|
scrollParent.removeEventListener('scroll', scrollHandler);
|
|
3190
3244
|
};
|
|
3191
3245
|
}, [
|
|
3192
|
-
|
|
3193
|
-
|
|
3194
|
-
scrollElement,
|
|
3246
|
+
targetKey,
|
|
3247
|
+
scrollKey,
|
|
3195
3248
|
scrollHandler
|
|
3196
3249
|
]);
|
|
3197
3250
|
return [
|