react-simplikit 0.2.0 → 0.3.0
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/CHANGELOG.md +23 -0
- package/README.md +6 -33
- package/dist/hooks/useAsyncEffect/useAsyncEffect.cjs +2 -2
- package/dist/hooks/useAsyncEffect/useAsyncEffect.d.cts +2 -2
- package/dist/hooks/useAsyncEffect/useAsyncEffect.d.mts +2 -2
- package/dist/hooks/useAsyncEffect/useAsyncEffect.mjs +2 -2
- package/dist/{mobile/hooks → hooks}/useAvoidKeyboard/useAvoidKeyboard.cjs +1 -1
- package/dist/{mobile/hooks → hooks}/useAvoidKeyboard/useAvoidKeyboard.d.cts +1 -1
- package/dist/{mobile/hooks → hooks}/useAvoidKeyboard/useAvoidKeyboard.d.mts +1 -1
- package/dist/{mobile/hooks → hooks}/useAvoidKeyboard/useAvoidKeyboard.mjs +1 -1
- package/dist/{mobile/hooks → hooks}/useBodyScrollLock/useBodyScrollLock.cjs +1 -1
- package/dist/{mobile/hooks → hooks}/useBodyScrollLock/useBodyScrollLock.d.cts +1 -1
- package/dist/{mobile/hooks → hooks}/useBodyScrollLock/useBodyScrollLock.d.mts +1 -1
- package/dist/{mobile/hooks → hooks}/useBodyScrollLock/useBodyScrollLock.mjs +1 -1
- package/dist/hooks/useBooleanState/useBooleanState.cjs +3 -3
- package/dist/hooks/useBooleanState/useBooleanState.d.cts +3 -2
- package/dist/hooks/useBooleanState/useBooleanState.d.mts +3 -2
- package/dist/hooks/useBooleanState/useBooleanState.mjs +3 -3
- package/dist/hooks/useDebounce/debounce.cjs +1 -0
- package/dist/hooks/useDebounce/debounce.mjs +1 -0
- package/dist/hooks/useDebounce/useDebounce.cjs +1 -1
- package/dist/hooks/useDebounce/useDebounce.mjs +1 -1
- package/dist/hooks/useDebouncedCallback/useDebouncedCallback.cjs +9 -32
- package/dist/hooks/useDebouncedCallback/useDebouncedCallback.mjs +10 -33
- package/dist/hooks/useDebouncedValue/useDebouncedValue.cjs +64 -0
- package/dist/hooks/useDebouncedValue/useDebouncedValue.d.cts +49 -0
- package/dist/hooks/useDebouncedValue/useDebouncedValue.d.mts +49 -0
- package/dist/hooks/useDebouncedValue/useDebouncedValue.mjs +64 -0
- package/dist/hooks/useImpressionRef/useImpressionRef.cjs +19 -3
- package/dist/hooks/useImpressionRef/useImpressionRef.mjs +20 -4
- package/dist/hooks/useInputState/useInputState.cjs +1 -1
- package/dist/hooks/useInputState/useInputState.d.cts +3 -2
- package/dist/hooks/useInputState/useInputState.d.mts +3 -2
- package/dist/hooks/useInputState/useInputState.mjs +1 -1
- package/dist/hooks/useIntersectionObserver/useIntersectionObserver.cjs +8 -3
- package/dist/hooks/useIntersectionObserver/useIntersectionObserver.mjs +8 -3
- package/dist/{mobile/hooks → hooks}/useKeyboardHeight/useKeyboardHeight.cjs +1 -1
- package/dist/{mobile/hooks → hooks}/useKeyboardHeight/useKeyboardHeight.d.cts +1 -1
- package/dist/{mobile/hooks → hooks}/useKeyboardHeight/useKeyboardHeight.d.mts +1 -1
- package/dist/{mobile/hooks → hooks}/useKeyboardHeight/useKeyboardHeight.mjs +1 -1
- package/dist/hooks/useLongPress/useLongPress.cjs +3 -0
- package/dist/hooks/useLongPress/useLongPress.mjs +4 -1
- package/dist/{mobile/hooks → hooks}/useNetworkStatus/useNetworkStatus.cjs +1 -1
- package/dist/{mobile/hooks → hooks}/useNetworkStatus/useNetworkStatus.d.cts +1 -1
- package/dist/{mobile/hooks → hooks}/useNetworkStatus/useNetworkStatus.d.mts +1 -1
- package/dist/{mobile/hooks → hooks}/useNetworkStatus/useNetworkStatus.mjs +1 -1
- package/dist/{mobile/hooks → hooks}/usePageVisibility/usePageVisibility.cjs +1 -1
- package/dist/{mobile/hooks → hooks}/usePageVisibility/usePageVisibility.d.cts +1 -1
- package/dist/{mobile/hooks → hooks}/usePageVisibility/usePageVisibility.d.mts +1 -1
- package/dist/{mobile/hooks → hooks}/usePageVisibility/usePageVisibility.mjs +1 -1
- package/dist/hooks/useRefEffect/useRefEffect.cjs +6 -4
- package/dist/hooks/useRefEffect/useRefEffect.mjs +7 -5
- package/dist/{mobile/hooks → hooks}/useSafeAreaInset/useSafeAreaInset.cjs +1 -1
- package/dist/{mobile/hooks → hooks}/useSafeAreaInset/useSafeAreaInset.d.cts +1 -1
- package/dist/{mobile/hooks → hooks}/useSafeAreaInset/useSafeAreaInset.d.mts +1 -1
- package/dist/{mobile/hooks → hooks}/useSafeAreaInset/useSafeAreaInset.mjs +1 -1
- package/dist/{mobile/hooks → hooks}/useScrollDirection/useScrollDirection.cjs +1 -1
- package/dist/{mobile/hooks → hooks}/useScrollDirection/useScrollDirection.d.cts +1 -1
- package/dist/{mobile/hooks → hooks}/useScrollDirection/useScrollDirection.d.mts +1 -1
- package/dist/{mobile/hooks → hooks}/useScrollDirection/useScrollDirection.mjs +1 -1
- package/dist/hooks/useStorageState/useStorageState.cjs +1 -1
- package/dist/hooks/useStorageState/useStorageState.mjs +1 -1
- package/dist/hooks/useThrottle/throttle.cjs +22 -5
- package/dist/hooks/useThrottle/throttle.mjs +22 -5
- package/dist/hooks/useThrottledCallback/useThrottledCallback.cjs +7 -29
- package/dist/hooks/useThrottledCallback/useThrottledCallback.mjs +8 -30
- package/dist/hooks/useThrottledValue/useThrottledValue.cjs +66 -0
- package/dist/hooks/useThrottledValue/useThrottledValue.d.cts +48 -0
- package/dist/hooks/useThrottledValue/useThrottledValue.d.mts +48 -0
- package/dist/hooks/useThrottledValue/useThrottledValue.mjs +66 -0
- package/dist/{mobile/hooks → hooks}/useVisualViewport/useVisualViewport.cjs +1 -1
- package/dist/{mobile/hooks → hooks}/useVisualViewport/useVisualViewport.d.cts +1 -1
- package/dist/{mobile/hooks → hooks}/useVisualViewport/useVisualViewport.d.mts +1 -1
- package/dist/{mobile/hooks → hooks}/useVisualViewport/useVisualViewport.mjs +1 -1
- package/dist/index.cjs +23 -19
- package/dist/index.d.cts +21 -19
- package/dist/index.d.mts +21 -19
- package/dist/index.mjs +22 -20
- package/dist/{mobile/utils → utils}/disableBodyScrollLock/disableBodyScrollLock.cjs +1 -1
- package/dist/{mobile/utils → utils}/disableBodyScrollLock/disableBodyScrollLock.d.cts +1 -1
- package/dist/{mobile/utils → utils}/disableBodyScrollLock/disableBodyScrollLock.d.mts +1 -1
- package/dist/{mobile/utils → utils}/disableBodyScrollLock/disableBodyScrollLock.mjs +1 -1
- package/dist/{mobile/utils → utils}/enableBodyScrollLock/enableBodyScrollLock.cjs +1 -1
- package/dist/{mobile/utils → utils}/enableBodyScrollLock/enableBodyScrollLock.d.cts +1 -1
- package/dist/{mobile/utils → utils}/enableBodyScrollLock/enableBodyScrollLock.d.mts +1 -1
- package/dist/{mobile/utils → utils}/enableBodyScrollLock/enableBodyScrollLock.mjs +1 -1
- package/dist/{mobile/utils → utils}/getKeyboardHeight/getKeyboardHeight.cjs +1 -1
- package/dist/{mobile/utils → utils}/getKeyboardHeight/getKeyboardHeight.d.cts +1 -1
- package/dist/{mobile/utils → utils}/getKeyboardHeight/getKeyboardHeight.d.mts +1 -1
- package/dist/{mobile/utils → utils}/getKeyboardHeight/getKeyboardHeight.mjs +1 -1
- package/dist/{mobile/utils → utils}/getSafeAreaInset/getSafeAreaInset.cjs +1 -1
- package/dist/{mobile/utils → utils}/getSafeAreaInset/getSafeAreaInset.d.cts +1 -1
- package/dist/{mobile/utils → utils}/getSafeAreaInset/getSafeAreaInset.d.mts +1 -1
- package/dist/{mobile/utils → utils}/getSafeAreaInset/getSafeAreaInset.mjs +1 -1
- package/dist/{mobile/utils → utils}/isAndroid/isAndroid.cjs +1 -1
- package/dist/{mobile/utils → utils}/isAndroid/isAndroid.d.cts +1 -1
- package/dist/{mobile/utils → utils}/isAndroid/isAndroid.d.mts +1 -1
- package/dist/{mobile/utils → utils}/isAndroid/isAndroid.mjs +1 -1
- package/dist/{mobile/utils → utils}/isIOS/isIOS.cjs +1 -1
- package/dist/{mobile/utils → utils}/isIOS/isIOS.d.cts +1 -1
- package/dist/{mobile/utils → utils}/isIOS/isIOS.d.mts +1 -1
- package/dist/{mobile/utils → utils}/isIOS/isIOS.mjs +1 -1
- package/dist/{mobile/utils → utils}/isKeyboardVisible/isKeyboardVisible.cjs +1 -1
- package/dist/{mobile/utils → utils}/isKeyboardVisible/isKeyboardVisible.d.cts +1 -1
- package/dist/{mobile/utils → utils}/isKeyboardVisible/isKeyboardVisible.d.mts +1 -1
- package/dist/{mobile/utils → utils}/isKeyboardVisible/isKeyboardVisible.mjs +1 -1
- package/dist/{mobile/utils → utils}/isServer/isServer.cjs +1 -1
- package/dist/{mobile/utils → utils}/isServer/isServer.d.cts +1 -1
- package/dist/{mobile/utils → utils}/isServer/isServer.d.mts +1 -1
- package/dist/{mobile/utils → utils}/isServer/isServer.mjs +1 -1
- package/dist/{mobile/utils → utils}/subscribeKeyboardHeight/subscribeKeyboardHeight.cjs +1 -1
- package/dist/{mobile/utils → utils}/subscribeKeyboardHeight/subscribeKeyboardHeight.d.cts +1 -1
- package/dist/{mobile/utils → utils}/subscribeKeyboardHeight/subscribeKeyboardHeight.d.mts +1 -1
- package/dist/{mobile/utils → utils}/subscribeKeyboardHeight/subscribeKeyboardHeight.mjs +1 -1
- package/package.json +2 -2
- /package/dist/{mobile/hooks → hooks}/useAvoidKeyboard/index.d.cts +0 -0
- /package/dist/{mobile/hooks → hooks}/useAvoidKeyboard/index.d.mts +0 -0
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { useDebounce } from "../useDebounce/useDebounce.mjs";
|
|
3
|
+
import { useEffect, useRef, useState } from "react";
|
|
4
|
+
//#region src/hooks/useDebouncedValue/useDebouncedValue.ts
|
|
5
|
+
/**
|
|
6
|
+
* @description
|
|
7
|
+
* `useDebouncedValue` is a React hook that returns a debounced copy of the given value.
|
|
8
|
+
* The caller keeps owning the state; the hook only delays how quickly the returned value follows it.
|
|
9
|
+
* The returned value updates `wait` milliseconds after the last change, which is useful for
|
|
10
|
+
* deriving a search query or a validation input from fast-changing state.
|
|
11
|
+
*
|
|
12
|
+
* On the first render and on the server the value is returned as is. A change is never scheduled
|
|
13
|
+
* on mount, so with `leading: true` the first change after mount is applied immediately.
|
|
14
|
+
* If both `leading` and `trailing` are `false`, the returned value never updates.
|
|
15
|
+
*
|
|
16
|
+
* The value is compared by reference. Passing a new object or array on every render keeps
|
|
17
|
+
* the returned value updating every `wait` milliseconds; stabilize the reference first, for
|
|
18
|
+
* example with `usePreservedReference`.
|
|
19
|
+
*
|
|
20
|
+
* @template T - The type of the value.
|
|
21
|
+
* @param {T} value - The value to debounce.
|
|
22
|
+
* @param {number} wait - The number of milliseconds to wait after the last change before updating.
|
|
23
|
+
* @param {DebounceOptions} [options] - Configuration options for debounce behavior.
|
|
24
|
+
* @param {boolean} [options.leading=false] - If `true`, the first change after an idle period is applied immediately.
|
|
25
|
+
* @param {boolean} [options.trailing=true] - If `true`, the last change is applied after `wait` milliseconds.
|
|
26
|
+
*
|
|
27
|
+
* @returns {T} The debounced value.
|
|
28
|
+
*
|
|
29
|
+
* @example
|
|
30
|
+
* import { useDebouncedValue } from 'react-simplikit';
|
|
31
|
+
* import { useState } from 'react';
|
|
32
|
+
*
|
|
33
|
+
* function SearchInput() {
|
|
34
|
+
* const [query, setQuery] = useState('');
|
|
35
|
+
* const debouncedQuery = useDebouncedValue(query, 300);
|
|
36
|
+
*
|
|
37
|
+
* return (
|
|
38
|
+
* <>
|
|
39
|
+
* <input value={query} onChange={e => setQuery(e.target.value)} />
|
|
40
|
+
* <SearchResults query={debouncedQuery} />
|
|
41
|
+
* </>
|
|
42
|
+
* );
|
|
43
|
+
* }
|
|
44
|
+
*/
|
|
45
|
+
function useDebouncedValue(value, wait, { leading = false, trailing = true } = {}) {
|
|
46
|
+
const [debouncedValue, setDebouncedValue] = useState(() => value);
|
|
47
|
+
const debounced = useDebounce((next) => setDebouncedValue(() => next), wait, {
|
|
48
|
+
leading,
|
|
49
|
+
trailing
|
|
50
|
+
});
|
|
51
|
+
const lastForwardedRef = useRef(value);
|
|
52
|
+
useEffect(function forwardChangedValue() {
|
|
53
|
+
if (Object.is(lastForwardedRef.current, value) && Object.is(value, debouncedValue)) return;
|
|
54
|
+
lastForwardedRef.current = value;
|
|
55
|
+
debounced(value);
|
|
56
|
+
}, [
|
|
57
|
+
value,
|
|
58
|
+
debouncedValue,
|
|
59
|
+
debounced
|
|
60
|
+
]);
|
|
61
|
+
return debouncedValue;
|
|
62
|
+
}
|
|
63
|
+
//#endregion
|
|
64
|
+
export { useDebouncedValue };
|
|
@@ -37,6 +37,7 @@ function useImpressionRef({ onImpressionStart = () => {}, onImpressionEnd = () =
|
|
|
37
37
|
const impressionStartHandler = require_usePreservedCallback.usePreservedCallback(onImpressionStart);
|
|
38
38
|
const impressionEndHandler = require_usePreservedCallback.usePreservedCallback(onImpressionEnd);
|
|
39
39
|
const isIntersectingRef = (0, react.useRef)(false);
|
|
40
|
+
const requestedImpressionRef = (0, react.useRef)(false);
|
|
40
41
|
const hasImpressionStartedRef = (0, react.useRef)(false);
|
|
41
42
|
const impressionEventHandler = require_useDebouncedCallback.useDebouncedCallback({
|
|
42
43
|
timeThreshold,
|
|
@@ -46,20 +47,35 @@ function useImpressionRef({ onImpressionStart = () => {}, onImpressionEnd = () =
|
|
|
46
47
|
impressionStartHandler();
|
|
47
48
|
return;
|
|
48
49
|
}
|
|
49
|
-
if (hasImpressionStartedRef.current)
|
|
50
|
+
if (hasImpressionStartedRef.current) {
|
|
51
|
+
hasImpressionStartedRef.current = false;
|
|
52
|
+
impressionEndHandler();
|
|
53
|
+
}
|
|
50
54
|
},
|
|
51
55
|
leading: true
|
|
52
56
|
});
|
|
57
|
+
const requestImpressionChange = (impressed) => {
|
|
58
|
+
requestedImpressionRef.current = impressed;
|
|
59
|
+
impressionEventHandler(impressed);
|
|
60
|
+
};
|
|
61
|
+
(0, react.useEffect)(function emitPendingImpressionEndOnUnmount() {
|
|
62
|
+
return () => {
|
|
63
|
+
if (hasImpressionStartedRef.current && !requestedImpressionRef.current) {
|
|
64
|
+
hasImpressionStartedRef.current = false;
|
|
65
|
+
impressionEndHandler();
|
|
66
|
+
}
|
|
67
|
+
};
|
|
68
|
+
}, [impressionEndHandler]);
|
|
53
69
|
require_useVisibilityEvent.useVisibilityEvent((documentVisible) => {
|
|
54
70
|
if (!isIntersectingRef.current) return;
|
|
55
|
-
|
|
71
|
+
requestImpressionChange(documentVisible === "visible");
|
|
56
72
|
});
|
|
57
73
|
return require_useIntersectionObserver.useIntersectionObserver((entry) => {
|
|
58
74
|
if (document.visibilityState === "hidden") return;
|
|
59
75
|
const currentRatio = entry.intersectionRatio;
|
|
60
76
|
const isIntersecting = areaThreshold === 0 ? entry.isIntersecting : currentRatio >= areaThreshold;
|
|
61
77
|
isIntersectingRef.current = isIntersecting;
|
|
62
|
-
|
|
78
|
+
requestImpressionChange(isIntersecting);
|
|
63
79
|
}, {
|
|
64
80
|
rootMargin,
|
|
65
81
|
threshold: areaThreshold
|
|
@@ -3,7 +3,7 @@ import { usePreservedCallback } from "../usePreservedCallback/usePreservedCallba
|
|
|
3
3
|
import { useDebouncedCallback } from "../useDebouncedCallback/useDebouncedCallback.mjs";
|
|
4
4
|
import { useIntersectionObserver } from "../useIntersectionObserver/useIntersectionObserver.mjs";
|
|
5
5
|
import { useVisibilityEvent } from "../useVisibilityEvent/useVisibilityEvent.mjs";
|
|
6
|
-
import { useRef } from "react";
|
|
6
|
+
import { useEffect, useRef } from "react";
|
|
7
7
|
//#region src/hooks/useImpressionRef/useImpressionRef.ts
|
|
8
8
|
/**
|
|
9
9
|
* @description
|
|
@@ -37,6 +37,7 @@ function useImpressionRef({ onImpressionStart = () => {}, onImpressionEnd = () =
|
|
|
37
37
|
const impressionStartHandler = usePreservedCallback(onImpressionStart);
|
|
38
38
|
const impressionEndHandler = usePreservedCallback(onImpressionEnd);
|
|
39
39
|
const isIntersectingRef = useRef(false);
|
|
40
|
+
const requestedImpressionRef = useRef(false);
|
|
40
41
|
const hasImpressionStartedRef = useRef(false);
|
|
41
42
|
const impressionEventHandler = useDebouncedCallback({
|
|
42
43
|
timeThreshold,
|
|
@@ -46,20 +47,35 @@ function useImpressionRef({ onImpressionStart = () => {}, onImpressionEnd = () =
|
|
|
46
47
|
impressionStartHandler();
|
|
47
48
|
return;
|
|
48
49
|
}
|
|
49
|
-
if (hasImpressionStartedRef.current)
|
|
50
|
+
if (hasImpressionStartedRef.current) {
|
|
51
|
+
hasImpressionStartedRef.current = false;
|
|
52
|
+
impressionEndHandler();
|
|
53
|
+
}
|
|
50
54
|
},
|
|
51
55
|
leading: true
|
|
52
56
|
});
|
|
57
|
+
const requestImpressionChange = (impressed) => {
|
|
58
|
+
requestedImpressionRef.current = impressed;
|
|
59
|
+
impressionEventHandler(impressed);
|
|
60
|
+
};
|
|
61
|
+
useEffect(function emitPendingImpressionEndOnUnmount() {
|
|
62
|
+
return () => {
|
|
63
|
+
if (hasImpressionStartedRef.current && !requestedImpressionRef.current) {
|
|
64
|
+
hasImpressionStartedRef.current = false;
|
|
65
|
+
impressionEndHandler();
|
|
66
|
+
}
|
|
67
|
+
};
|
|
68
|
+
}, [impressionEndHandler]);
|
|
53
69
|
useVisibilityEvent((documentVisible) => {
|
|
54
70
|
if (!isIntersectingRef.current) return;
|
|
55
|
-
|
|
71
|
+
requestImpressionChange(documentVisible === "visible");
|
|
56
72
|
});
|
|
57
73
|
return useIntersectionObserver((entry) => {
|
|
58
74
|
if (document.visibilityState === "hidden") return;
|
|
59
75
|
const currentRatio = entry.intersectionRatio;
|
|
60
76
|
const isIntersecting = areaThreshold === 0 ? entry.isIntersecting : currentRatio >= areaThreshold;
|
|
61
77
|
isIntersectingRef.current = isIntersecting;
|
|
62
|
-
|
|
78
|
+
requestImpressionChange(isIntersecting);
|
|
63
79
|
}, {
|
|
64
80
|
rootMargin,
|
|
65
81
|
threshold: areaThreshold
|
|
@@ -6,7 +6,7 @@ let react = require("react");
|
|
|
6
6
|
* `useInputState` is a React hook that manages an input state with optional value transformation.
|
|
7
7
|
* The returned `onChange` handler works with both `<input>` and `<textarea>` elements.
|
|
8
8
|
*
|
|
9
|
-
* @param {string} [initialValue=""] - The initial value of the input. Defaults to an empty string (`""`).
|
|
9
|
+
* @param {string | (() => string)} [initialValue=""] - The initial value of the input. Defaults to an empty string (`""`).
|
|
10
10
|
* @param {(value: string) => string} [transformValue=(v: string) => v] - A function to transform the input value.
|
|
11
11
|
* Defaults to an identity function that returns the input unchanged.
|
|
12
12
|
*
|
|
@@ -2,12 +2,13 @@
|
|
|
2
2
|
import { ChangeEventHandler } from "react";
|
|
3
3
|
//#region src/hooks/useInputState/useInputState.d.ts
|
|
4
4
|
type InputLikeElement = HTMLInputElement | HTMLTextAreaElement;
|
|
5
|
+
type InitialValue = string | (() => string);
|
|
5
6
|
/**
|
|
6
7
|
* @description
|
|
7
8
|
* `useInputState` is a React hook that manages an input state with optional value transformation.
|
|
8
9
|
* The returned `onChange` handler works with both `<input>` and `<textarea>` elements.
|
|
9
10
|
*
|
|
10
|
-
* @param {string} [initialValue=""] - The initial value of the input. Defaults to an empty string (`""`).
|
|
11
|
+
* @param {string | (() => string)} [initialValue=""] - The initial value of the input. Defaults to an empty string (`""`).
|
|
11
12
|
* @param {(value: string) => string} [transformValue=(v: string) => v] - A function to transform the input value.
|
|
12
13
|
* Defaults to an identity function that returns the input unchanged.
|
|
13
14
|
*
|
|
@@ -26,6 +27,6 @@ type InputLikeElement = HTMLInputElement | HTMLTextAreaElement;
|
|
|
26
27
|
* );
|
|
27
28
|
* }
|
|
28
29
|
*/
|
|
29
|
-
declare function useInputState(initialValue?:
|
|
30
|
+
declare function useInputState(initialValue?: InitialValue, transformValue?: (value: string) => string): readonly [string, ChangeEventHandler<InputLikeElement>];
|
|
30
31
|
//#endregion
|
|
31
32
|
export { useInputState };
|
|
@@ -2,12 +2,13 @@
|
|
|
2
2
|
import { ChangeEventHandler } from "react";
|
|
3
3
|
//#region src/hooks/useInputState/useInputState.d.ts
|
|
4
4
|
type InputLikeElement = HTMLInputElement | HTMLTextAreaElement;
|
|
5
|
+
type InitialValue = string | (() => string);
|
|
5
6
|
/**
|
|
6
7
|
* @description
|
|
7
8
|
* `useInputState` is a React hook that manages an input state with optional value transformation.
|
|
8
9
|
* The returned `onChange` handler works with both `<input>` and `<textarea>` elements.
|
|
9
10
|
*
|
|
10
|
-
* @param {string} [initialValue=""] - The initial value of the input. Defaults to an empty string (`""`).
|
|
11
|
+
* @param {string | (() => string)} [initialValue=""] - The initial value of the input. Defaults to an empty string (`""`).
|
|
11
12
|
* @param {(value: string) => string} [transformValue=(v: string) => v] - A function to transform the input value.
|
|
12
13
|
* Defaults to an identity function that returns the input unchanged.
|
|
13
14
|
*
|
|
@@ -26,6 +27,6 @@ type InputLikeElement = HTMLInputElement | HTMLTextAreaElement;
|
|
|
26
27
|
* );
|
|
27
28
|
* }
|
|
28
29
|
*/
|
|
29
|
-
declare function useInputState(initialValue?:
|
|
30
|
+
declare function useInputState(initialValue?: InitialValue, transformValue?: (value: string) => string): readonly [string, ChangeEventHandler<InputLikeElement>];
|
|
30
31
|
//#endregion
|
|
31
32
|
export { useInputState };
|
|
@@ -6,7 +6,7 @@ import { useCallback, useState } from "react";
|
|
|
6
6
|
* `useInputState` is a React hook that manages an input state with optional value transformation.
|
|
7
7
|
* The returned `onChange` handler works with both `<input>` and `<textarea>` elements.
|
|
8
8
|
*
|
|
9
|
-
* @param {string} [initialValue=""] - The initial value of the input. Defaults to an empty string (`""`).
|
|
9
|
+
* @param {string | (() => string)} [initialValue=""] - The initial value of the input. Defaults to an empty string (`""`).
|
|
10
10
|
* @param {(value: string) => string} [transformValue=(v: string) => v] - A function to transform the input value.
|
|
11
11
|
* Defaults to an identity function that returns the input unchanged.
|
|
12
12
|
*
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
"use client";
|
|
2
2
|
const require_usePreservedCallback = require("../usePreservedCallback/usePreservedCallback.cjs");
|
|
3
|
+
const require_usePreservedReference = require("../usePreservedReference/usePreservedReference.cjs");
|
|
3
4
|
const require_useRefEffect = require("../useRefEffect/useRefEffect.cjs");
|
|
4
5
|
let react = require("react");
|
|
5
6
|
//#region src/hooks/useIntersectionObserver/useIntersectionObserver.ts
|
|
@@ -37,18 +38,22 @@ let react = require("react");
|
|
|
37
38
|
*/
|
|
38
39
|
function useIntersectionObserver(callback, options) {
|
|
39
40
|
const preservedCallback = require_usePreservedCallback.usePreservedCallback(callback);
|
|
41
|
+
const preservedOptions = require_usePreservedReference.usePreservedReference(options, areIntersectionOptionsEqual);
|
|
40
42
|
const observer = (0, react.useMemo)(() => {
|
|
41
43
|
if (typeof IntersectionObserver === "undefined") return;
|
|
42
44
|
return new IntersectionObserver(([entry]) => {
|
|
43
45
|
preservedCallback(entry);
|
|
44
|
-
},
|
|
45
|
-
}, [preservedCallback,
|
|
46
|
+
}, preservedOptions);
|
|
47
|
+
}, [preservedCallback, preservedOptions]);
|
|
46
48
|
return require_useRefEffect.useRefEffect((element) => {
|
|
47
49
|
observer?.observe(element);
|
|
48
50
|
return () => {
|
|
49
51
|
observer?.unobserve(element);
|
|
50
52
|
};
|
|
51
|
-
}, [preservedCallback,
|
|
53
|
+
}, [preservedCallback, preservedOptions]);
|
|
54
|
+
}
|
|
55
|
+
function areIntersectionOptionsEqual(a, b) {
|
|
56
|
+
return a.root === b.root && a.rootMargin === b.rootMargin && JSON.stringify(a.threshold) === JSON.stringify(b.threshold);
|
|
52
57
|
}
|
|
53
58
|
//#endregion
|
|
54
59
|
exports.useIntersectionObserver = useIntersectionObserver;
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
"use client";
|
|
2
2
|
import { usePreservedCallback } from "../usePreservedCallback/usePreservedCallback.mjs";
|
|
3
|
+
import { usePreservedReference } from "../usePreservedReference/usePreservedReference.mjs";
|
|
3
4
|
import { useRefEffect } from "../useRefEffect/useRefEffect.mjs";
|
|
4
5
|
import { useMemo } from "react";
|
|
5
6
|
//#region src/hooks/useIntersectionObserver/useIntersectionObserver.ts
|
|
@@ -37,18 +38,22 @@ import { useMemo } from "react";
|
|
|
37
38
|
*/
|
|
38
39
|
function useIntersectionObserver(callback, options) {
|
|
39
40
|
const preservedCallback = usePreservedCallback(callback);
|
|
41
|
+
const preservedOptions = usePreservedReference(options, areIntersectionOptionsEqual);
|
|
40
42
|
const observer = useMemo(() => {
|
|
41
43
|
if (typeof IntersectionObserver === "undefined") return;
|
|
42
44
|
return new IntersectionObserver(([entry]) => {
|
|
43
45
|
preservedCallback(entry);
|
|
44
|
-
},
|
|
45
|
-
}, [preservedCallback,
|
|
46
|
+
}, preservedOptions);
|
|
47
|
+
}, [preservedCallback, preservedOptions]);
|
|
46
48
|
return useRefEffect((element) => {
|
|
47
49
|
observer?.observe(element);
|
|
48
50
|
return () => {
|
|
49
51
|
observer?.unobserve(element);
|
|
50
52
|
};
|
|
51
|
-
}, [preservedCallback,
|
|
53
|
+
}, [preservedCallback, preservedOptions]);
|
|
54
|
+
}
|
|
55
|
+
function areIntersectionOptionsEqual(a, b) {
|
|
56
|
+
return a.root === b.root && a.rootMargin === b.rootMargin && JSON.stringify(a.threshold) === JSON.stringify(b.threshold);
|
|
52
57
|
}
|
|
53
58
|
//#endregion
|
|
54
59
|
export { useIntersectionObserver };
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
"use client";
|
|
2
2
|
const require_subscribeKeyboardHeight = require("../../utils/subscribeKeyboardHeight/subscribeKeyboardHeight.cjs");
|
|
3
3
|
let react = require("react");
|
|
4
|
-
//#region src/
|
|
4
|
+
//#region src/hooks/useKeyboardHeight/useKeyboardHeight.ts
|
|
5
5
|
/**
|
|
6
6
|
* @description
|
|
7
7
|
* `useKeyboardHeight` is a React hook that tracks the on-screen keyboard height.
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
"use client";
|
|
2
2
|
import { subscribeKeyboardHeight } from "../../utils/subscribeKeyboardHeight/subscribeKeyboardHeight.mjs";
|
|
3
3
|
import { useEffect, useState } from "react";
|
|
4
|
-
//#region src/
|
|
4
|
+
//#region src/hooks/useKeyboardHeight/useKeyboardHeight.ts
|
|
5
5
|
/**
|
|
6
6
|
* @description
|
|
7
7
|
* `useKeyboardHeight` is a React hook that tracks the on-screen keyboard height.
|
|
@@ -85,6 +85,9 @@ function useLongPress(onLongPress, { delay = 500, moveThreshold, onClick, onLong
|
|
|
85
85
|
timeoutRef.current = null;
|
|
86
86
|
}
|
|
87
87
|
}, []);
|
|
88
|
+
(0, react.useEffect)(function cleanupLongPressOnUnmount() {
|
|
89
|
+
return cancelLongPress;
|
|
90
|
+
}, [cancelLongPress]);
|
|
88
91
|
const handlePressStart = (0, react.useCallback)((event) => {
|
|
89
92
|
cancelLongPress();
|
|
90
93
|
const position = getClientPosition(event);
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"use client";
|
|
2
2
|
import { usePreservedCallback } from "../usePreservedCallback/usePreservedCallback.mjs";
|
|
3
|
-
import { useCallback, useRef } from "react";
|
|
3
|
+
import { useCallback, useEffect, useRef } from "react";
|
|
4
4
|
//#region src/hooks/useLongPress/useLongPress.ts
|
|
5
5
|
/**
|
|
6
6
|
* @description
|
|
@@ -85,6 +85,9 @@ function useLongPress(onLongPress, { delay = 500, moveThreshold, onClick, onLong
|
|
|
85
85
|
timeoutRef.current = null;
|
|
86
86
|
}
|
|
87
87
|
}, []);
|
|
88
|
+
useEffect(function cleanupLongPressOnUnmount() {
|
|
89
|
+
return cancelLongPress;
|
|
90
|
+
}, [cancelLongPress]);
|
|
88
91
|
const handlePressStart = useCallback((event) => {
|
|
89
92
|
cancelLongPress();
|
|
90
93
|
const position = getClientPosition(event);
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
"use client";
|
|
2
2
|
const require_isServer = require("../../utils/isServer/isServer.cjs");
|
|
3
3
|
let react = require("react");
|
|
4
|
-
//#region src/
|
|
4
|
+
//#region src/hooks/useNetworkStatus/useNetworkStatus.ts
|
|
5
5
|
/**
|
|
6
6
|
* @description
|
|
7
7
|
* `useNetworkStatus` is a React hook that provides access to the Network Information API.
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
"use client";
|
|
2
2
|
import { isServer } from "../../utils/isServer/isServer.mjs";
|
|
3
3
|
import { useEffect, useState } from "react";
|
|
4
|
-
//#region src/
|
|
4
|
+
//#region src/hooks/useNetworkStatus/useNetworkStatus.ts
|
|
5
5
|
/**
|
|
6
6
|
* @description
|
|
7
7
|
* `useNetworkStatus` is a React hook that provides access to the Network Information API.
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
"use client";
|
|
2
2
|
const require_isServer = require("../../utils/isServer/isServer.cjs");
|
|
3
3
|
let react = require("react");
|
|
4
|
-
//#region src/
|
|
4
|
+
//#region src/hooks/usePageVisibility/usePageVisibility.ts
|
|
5
5
|
/**
|
|
6
6
|
* @description
|
|
7
7
|
* `usePageVisibility` is a React hook that detects page visibility changes.
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
|
|
2
|
-
//#region src/
|
|
2
|
+
//#region src/hooks/usePageVisibility/usePageVisibility.d.ts
|
|
3
3
|
/**
|
|
4
4
|
* Page visibility state derived from browser's DocumentVisibilityState.
|
|
5
5
|
* Excludes 'prerender' as it is deprecated and not used in modern browsers.
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
|
|
2
|
-
//#region src/
|
|
2
|
+
//#region src/hooks/usePageVisibility/usePageVisibility.d.ts
|
|
3
3
|
/**
|
|
4
4
|
* Page visibility state derived from browser's DocumentVisibilityState.
|
|
5
5
|
* Excludes 'prerender' as it is deprecated and not used in modern browsers.
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
"use client";
|
|
2
2
|
import { isServer } from "../../utils/isServer/isServer.mjs";
|
|
3
3
|
import { useEffect, useState } from "react";
|
|
4
|
-
//#region src/
|
|
4
|
+
//#region src/hooks/usePageVisibility/usePageVisibility.ts
|
|
5
5
|
/**
|
|
6
6
|
* @description
|
|
7
7
|
* `usePageVisibility` is a React hook that detects page visibility changes.
|
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
"use client";
|
|
2
|
-
const require_usePreservedCallback = require("../usePreservedCallback/usePreservedCallback.cjs");
|
|
3
2
|
let react = require("react");
|
|
4
3
|
//#region src/hooks/useRefEffect/useRefEffect.ts
|
|
5
4
|
/**
|
|
@@ -29,15 +28,18 @@ let react = require("react");
|
|
|
29
28
|
*/
|
|
30
29
|
function useRefEffect(callback, deps) {
|
|
31
30
|
"use no memo";
|
|
32
|
-
const
|
|
31
|
+
const callbackRef = (0, react.useMemo)(() => ({ current: callback }), deps);
|
|
32
|
+
(0, react.useEffect)(function syncCallbackRef() {
|
|
33
|
+
callbackRef.current = callback;
|
|
34
|
+
}, [callback, callbackRef]);
|
|
33
35
|
const cleanupCallbackRef = (0, react.useRef)(() => {});
|
|
34
36
|
return (0, react.useCallback)((element) => {
|
|
35
37
|
cleanupCallbackRef.current();
|
|
36
38
|
cleanupCallbackRef.current = () => {};
|
|
37
39
|
if (element == null) return;
|
|
38
|
-
const cleanup =
|
|
40
|
+
const cleanup = callbackRef.current(element);
|
|
39
41
|
if (typeof cleanup === "function") cleanupCallbackRef.current = cleanup;
|
|
40
|
-
}, [
|
|
42
|
+
}, [callbackRef]);
|
|
41
43
|
}
|
|
42
44
|
//#endregion
|
|
43
45
|
exports.useRefEffect = useRefEffect;
|
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
"use client";
|
|
2
|
-
import {
|
|
3
|
-
import { useCallback, useRef } from "react";
|
|
2
|
+
import { useCallback, useEffect, useMemo, useRef } from "react";
|
|
4
3
|
//#region src/hooks/useRefEffect/useRefEffect.ts
|
|
5
4
|
/**
|
|
6
5
|
* @description
|
|
@@ -29,15 +28,18 @@ import { useCallback, useRef } from "react";
|
|
|
29
28
|
*/
|
|
30
29
|
function useRefEffect(callback, deps) {
|
|
31
30
|
"use no memo";
|
|
32
|
-
const
|
|
31
|
+
const callbackRef = useMemo(() => ({ current: callback }), deps);
|
|
32
|
+
useEffect(function syncCallbackRef() {
|
|
33
|
+
callbackRef.current = callback;
|
|
34
|
+
}, [callback, callbackRef]);
|
|
33
35
|
const cleanupCallbackRef = useRef(() => {});
|
|
34
36
|
return useCallback((element) => {
|
|
35
37
|
cleanupCallbackRef.current();
|
|
36
38
|
cleanupCallbackRef.current = () => {};
|
|
37
39
|
if (element == null) return;
|
|
38
|
-
const cleanup =
|
|
40
|
+
const cleanup = callbackRef.current(element);
|
|
39
41
|
if (typeof cleanup === "function") cleanupCallbackRef.current = cleanup;
|
|
40
|
-
}, [
|
|
42
|
+
}, [callbackRef]);
|
|
41
43
|
}
|
|
42
44
|
//#endregion
|
|
43
45
|
export { useRefEffect };
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
const require_isServer = require("../../utils/isServer/isServer.cjs");
|
|
3
3
|
const require_getSafeAreaInset = require("../../utils/getSafeAreaInset/getSafeAreaInset.cjs");
|
|
4
4
|
let react = require("react");
|
|
5
|
-
//#region src/
|
|
5
|
+
//#region src/hooks/useSafeAreaInset/useSafeAreaInset.ts
|
|
6
6
|
/**
|
|
7
7
|
* @description
|
|
8
8
|
* `useSafeAreaInset` is a React hook that tracks safe area inset changes.
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
|
|
2
2
|
import { SafeAreaInset } from "../../utils/getSafeAreaInset/getSafeAreaInset.cjs";
|
|
3
|
-
//#region src/
|
|
3
|
+
//#region src/hooks/useSafeAreaInset/useSafeAreaInset.d.ts
|
|
4
4
|
/**
|
|
5
5
|
* @description
|
|
6
6
|
* `useSafeAreaInset` is a React hook that tracks safe area inset changes.
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
|
|
2
2
|
import { SafeAreaInset } from "../../utils/getSafeAreaInset/getSafeAreaInset.mjs";
|
|
3
|
-
//#region src/
|
|
3
|
+
//#region src/hooks/useSafeAreaInset/useSafeAreaInset.d.ts
|
|
4
4
|
/**
|
|
5
5
|
* @description
|
|
6
6
|
* `useSafeAreaInset` is a React hook that tracks safe area inset changes.
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
import { isServer } from "../../utils/isServer/isServer.mjs";
|
|
3
3
|
import { getSafeAreaInset } from "../../utils/getSafeAreaInset/getSafeAreaInset.mjs";
|
|
4
4
|
import { startTransition, useCallback, useEffect, useState } from "react";
|
|
5
|
-
//#region src/
|
|
5
|
+
//#region src/hooks/useSafeAreaInset/useSafeAreaInset.ts
|
|
6
6
|
/**
|
|
7
7
|
* @description
|
|
8
8
|
* `useSafeAreaInset` is a React hook that tracks safe area inset changes.
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
"use client";
|
|
2
2
|
const require_isServer = require("../../utils/isServer/isServer.cjs");
|
|
3
3
|
let react = require("react");
|
|
4
|
-
//#region src/
|
|
4
|
+
//#region src/hooks/useScrollDirection/useScrollDirection.ts
|
|
5
5
|
/**
|
|
6
6
|
* @description
|
|
7
7
|
* `useScrollDirection` is a React hook that detects scroll direction.
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
"use client";
|
|
2
2
|
import { isServer } from "../../utils/isServer/isServer.mjs";
|
|
3
3
|
import { useCallback, useEffect, useRef, useState } from "react";
|
|
4
|
-
//#region src/
|
|
4
|
+
//#region src/hooks/useScrollDirection/useScrollDirection.ts
|
|
5
5
|
/**
|
|
6
6
|
* @description
|
|
7
7
|
* `useScrollDirection` is a React hook that detects scroll direction.
|
|
@@ -46,7 +46,7 @@ function useStorageState(key, { storage = require_storage.safeLocalStorage, defa
|
|
|
46
46
|
const storageState = (0, react.useSyncExternalStore)((onStoreChange) => {
|
|
47
47
|
listeners.add(onStoreChange);
|
|
48
48
|
const handler = (event) => {
|
|
49
|
-
if (event.key === key) onStoreChange();
|
|
49
|
+
if (event.key == null || event.key === key) onStoreChange();
|
|
50
50
|
};
|
|
51
51
|
window.addEventListener("storage", handler);
|
|
52
52
|
return () => {
|
|
@@ -46,7 +46,7 @@ function useStorageState(key, { storage = safeLocalStorage, defaultValue, ...opt
|
|
|
46
46
|
const storageState = useSyncExternalStore((onStoreChange) => {
|
|
47
47
|
listeners.add(onStoreChange);
|
|
48
48
|
const handler = (event) => {
|
|
49
|
-
if (event.key === key) onStoreChange();
|
|
49
|
+
if (event.key == null || event.key === key) onStoreChange();
|
|
50
50
|
};
|
|
51
51
|
window.addEventListener("storage", handler);
|
|
52
52
|
return () => {
|
|
@@ -2,17 +2,34 @@
|
|
|
2
2
|
const require_debounce = require("../useDebounce/debounce.cjs");
|
|
3
3
|
//#region src/hooks/useThrottle/throttle.ts
|
|
4
4
|
function throttle(func, throttleMs, { edges = ["leading", "trailing"] } = {}) {
|
|
5
|
+
const leading = edges.includes("leading");
|
|
6
|
+
const trailing = edges.includes("trailing");
|
|
5
7
|
let pendingAt = null;
|
|
6
|
-
|
|
8
|
+
let isPending = false;
|
|
9
|
+
const debounced = require_debounce.debounce(function(...args) {
|
|
10
|
+
pendingAt = Date.now();
|
|
11
|
+
isPending = false;
|
|
12
|
+
func.apply(this, args);
|
|
13
|
+
}, throttleMs, { edges });
|
|
7
14
|
const throttled = function(...args) {
|
|
8
|
-
if (pendingAt
|
|
9
|
-
|
|
15
|
+
if (pendingAt === null) pendingAt = Date.now();
|
|
16
|
+
const windowElapsed = Date.now() - pendingAt >= throttleMs;
|
|
17
|
+
if (windowElapsed && (leading || trailing && isPending)) {
|
|
10
18
|
pendingAt = Date.now();
|
|
19
|
+
isPending = false;
|
|
20
|
+
func.apply(this, args);
|
|
11
21
|
debounced.cancel();
|
|
22
|
+
debounced.schedule();
|
|
23
|
+
return;
|
|
12
24
|
}
|
|
13
|
-
|
|
25
|
+
if (windowElapsed) pendingAt = Date.now();
|
|
26
|
+
isPending = true;
|
|
27
|
+
debounced.apply(this, args);
|
|
28
|
+
};
|
|
29
|
+
throttled.cancel = () => {
|
|
30
|
+
isPending = false;
|
|
31
|
+
debounced.cancel();
|
|
14
32
|
};
|
|
15
|
-
throttled.cancel = debounced.cancel;
|
|
16
33
|
return throttled;
|
|
17
34
|
}
|
|
18
35
|
//#endregion
|