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.
Files changed (117) hide show
  1. package/CHANGELOG.md +23 -0
  2. package/README.md +6 -33
  3. package/dist/hooks/useAsyncEffect/useAsyncEffect.cjs +2 -2
  4. package/dist/hooks/useAsyncEffect/useAsyncEffect.d.cts +2 -2
  5. package/dist/hooks/useAsyncEffect/useAsyncEffect.d.mts +2 -2
  6. package/dist/hooks/useAsyncEffect/useAsyncEffect.mjs +2 -2
  7. package/dist/{mobile/hooks → hooks}/useAvoidKeyboard/useAvoidKeyboard.cjs +1 -1
  8. package/dist/{mobile/hooks → hooks}/useAvoidKeyboard/useAvoidKeyboard.d.cts +1 -1
  9. package/dist/{mobile/hooks → hooks}/useAvoidKeyboard/useAvoidKeyboard.d.mts +1 -1
  10. package/dist/{mobile/hooks → hooks}/useAvoidKeyboard/useAvoidKeyboard.mjs +1 -1
  11. package/dist/{mobile/hooks → hooks}/useBodyScrollLock/useBodyScrollLock.cjs +1 -1
  12. package/dist/{mobile/hooks → hooks}/useBodyScrollLock/useBodyScrollLock.d.cts +1 -1
  13. package/dist/{mobile/hooks → hooks}/useBodyScrollLock/useBodyScrollLock.d.mts +1 -1
  14. package/dist/{mobile/hooks → hooks}/useBodyScrollLock/useBodyScrollLock.mjs +1 -1
  15. package/dist/hooks/useBooleanState/useBooleanState.cjs +3 -3
  16. package/dist/hooks/useBooleanState/useBooleanState.d.cts +3 -2
  17. package/dist/hooks/useBooleanState/useBooleanState.d.mts +3 -2
  18. package/dist/hooks/useBooleanState/useBooleanState.mjs +3 -3
  19. package/dist/hooks/useDebounce/debounce.cjs +1 -0
  20. package/dist/hooks/useDebounce/debounce.mjs +1 -0
  21. package/dist/hooks/useDebounce/useDebounce.cjs +1 -1
  22. package/dist/hooks/useDebounce/useDebounce.mjs +1 -1
  23. package/dist/hooks/useDebouncedCallback/useDebouncedCallback.cjs +9 -32
  24. package/dist/hooks/useDebouncedCallback/useDebouncedCallback.mjs +10 -33
  25. package/dist/hooks/useDebouncedValue/useDebouncedValue.cjs +64 -0
  26. package/dist/hooks/useDebouncedValue/useDebouncedValue.d.cts +49 -0
  27. package/dist/hooks/useDebouncedValue/useDebouncedValue.d.mts +49 -0
  28. package/dist/hooks/useDebouncedValue/useDebouncedValue.mjs +64 -0
  29. package/dist/hooks/useImpressionRef/useImpressionRef.cjs +19 -3
  30. package/dist/hooks/useImpressionRef/useImpressionRef.mjs +20 -4
  31. package/dist/hooks/useInputState/useInputState.cjs +1 -1
  32. package/dist/hooks/useInputState/useInputState.d.cts +3 -2
  33. package/dist/hooks/useInputState/useInputState.d.mts +3 -2
  34. package/dist/hooks/useInputState/useInputState.mjs +1 -1
  35. package/dist/hooks/useIntersectionObserver/useIntersectionObserver.cjs +8 -3
  36. package/dist/hooks/useIntersectionObserver/useIntersectionObserver.mjs +8 -3
  37. package/dist/{mobile/hooks → hooks}/useKeyboardHeight/useKeyboardHeight.cjs +1 -1
  38. package/dist/{mobile/hooks → hooks}/useKeyboardHeight/useKeyboardHeight.d.cts +1 -1
  39. package/dist/{mobile/hooks → hooks}/useKeyboardHeight/useKeyboardHeight.d.mts +1 -1
  40. package/dist/{mobile/hooks → hooks}/useKeyboardHeight/useKeyboardHeight.mjs +1 -1
  41. package/dist/hooks/useLongPress/useLongPress.cjs +3 -0
  42. package/dist/hooks/useLongPress/useLongPress.mjs +4 -1
  43. package/dist/{mobile/hooks → hooks}/useNetworkStatus/useNetworkStatus.cjs +1 -1
  44. package/dist/{mobile/hooks → hooks}/useNetworkStatus/useNetworkStatus.d.cts +1 -1
  45. package/dist/{mobile/hooks → hooks}/useNetworkStatus/useNetworkStatus.d.mts +1 -1
  46. package/dist/{mobile/hooks → hooks}/useNetworkStatus/useNetworkStatus.mjs +1 -1
  47. package/dist/{mobile/hooks → hooks}/usePageVisibility/usePageVisibility.cjs +1 -1
  48. package/dist/{mobile/hooks → hooks}/usePageVisibility/usePageVisibility.d.cts +1 -1
  49. package/dist/{mobile/hooks → hooks}/usePageVisibility/usePageVisibility.d.mts +1 -1
  50. package/dist/{mobile/hooks → hooks}/usePageVisibility/usePageVisibility.mjs +1 -1
  51. package/dist/hooks/useRefEffect/useRefEffect.cjs +6 -4
  52. package/dist/hooks/useRefEffect/useRefEffect.mjs +7 -5
  53. package/dist/{mobile/hooks → hooks}/useSafeAreaInset/useSafeAreaInset.cjs +1 -1
  54. package/dist/{mobile/hooks → hooks}/useSafeAreaInset/useSafeAreaInset.d.cts +1 -1
  55. package/dist/{mobile/hooks → hooks}/useSafeAreaInset/useSafeAreaInset.d.mts +1 -1
  56. package/dist/{mobile/hooks → hooks}/useSafeAreaInset/useSafeAreaInset.mjs +1 -1
  57. package/dist/{mobile/hooks → hooks}/useScrollDirection/useScrollDirection.cjs +1 -1
  58. package/dist/{mobile/hooks → hooks}/useScrollDirection/useScrollDirection.d.cts +1 -1
  59. package/dist/{mobile/hooks → hooks}/useScrollDirection/useScrollDirection.d.mts +1 -1
  60. package/dist/{mobile/hooks → hooks}/useScrollDirection/useScrollDirection.mjs +1 -1
  61. package/dist/hooks/useStorageState/useStorageState.cjs +1 -1
  62. package/dist/hooks/useStorageState/useStorageState.mjs +1 -1
  63. package/dist/hooks/useThrottle/throttle.cjs +22 -5
  64. package/dist/hooks/useThrottle/throttle.mjs +22 -5
  65. package/dist/hooks/useThrottledCallback/useThrottledCallback.cjs +7 -29
  66. package/dist/hooks/useThrottledCallback/useThrottledCallback.mjs +8 -30
  67. package/dist/hooks/useThrottledValue/useThrottledValue.cjs +66 -0
  68. package/dist/hooks/useThrottledValue/useThrottledValue.d.cts +48 -0
  69. package/dist/hooks/useThrottledValue/useThrottledValue.d.mts +48 -0
  70. package/dist/hooks/useThrottledValue/useThrottledValue.mjs +66 -0
  71. package/dist/{mobile/hooks → hooks}/useVisualViewport/useVisualViewport.cjs +1 -1
  72. package/dist/{mobile/hooks → hooks}/useVisualViewport/useVisualViewport.d.cts +1 -1
  73. package/dist/{mobile/hooks → hooks}/useVisualViewport/useVisualViewport.d.mts +1 -1
  74. package/dist/{mobile/hooks → hooks}/useVisualViewport/useVisualViewport.mjs +1 -1
  75. package/dist/index.cjs +23 -19
  76. package/dist/index.d.cts +21 -19
  77. package/dist/index.d.mts +21 -19
  78. package/dist/index.mjs +22 -20
  79. package/dist/{mobile/utils → utils}/disableBodyScrollLock/disableBodyScrollLock.cjs +1 -1
  80. package/dist/{mobile/utils → utils}/disableBodyScrollLock/disableBodyScrollLock.d.cts +1 -1
  81. package/dist/{mobile/utils → utils}/disableBodyScrollLock/disableBodyScrollLock.d.mts +1 -1
  82. package/dist/{mobile/utils → utils}/disableBodyScrollLock/disableBodyScrollLock.mjs +1 -1
  83. package/dist/{mobile/utils → utils}/enableBodyScrollLock/enableBodyScrollLock.cjs +1 -1
  84. package/dist/{mobile/utils → utils}/enableBodyScrollLock/enableBodyScrollLock.d.cts +1 -1
  85. package/dist/{mobile/utils → utils}/enableBodyScrollLock/enableBodyScrollLock.d.mts +1 -1
  86. package/dist/{mobile/utils → utils}/enableBodyScrollLock/enableBodyScrollLock.mjs +1 -1
  87. package/dist/{mobile/utils → utils}/getKeyboardHeight/getKeyboardHeight.cjs +1 -1
  88. package/dist/{mobile/utils → utils}/getKeyboardHeight/getKeyboardHeight.d.cts +1 -1
  89. package/dist/{mobile/utils → utils}/getKeyboardHeight/getKeyboardHeight.d.mts +1 -1
  90. package/dist/{mobile/utils → utils}/getKeyboardHeight/getKeyboardHeight.mjs +1 -1
  91. package/dist/{mobile/utils → utils}/getSafeAreaInset/getSafeAreaInset.cjs +1 -1
  92. package/dist/{mobile/utils → utils}/getSafeAreaInset/getSafeAreaInset.d.cts +1 -1
  93. package/dist/{mobile/utils → utils}/getSafeAreaInset/getSafeAreaInset.d.mts +1 -1
  94. package/dist/{mobile/utils → utils}/getSafeAreaInset/getSafeAreaInset.mjs +1 -1
  95. package/dist/{mobile/utils → utils}/isAndroid/isAndroid.cjs +1 -1
  96. package/dist/{mobile/utils → utils}/isAndroid/isAndroid.d.cts +1 -1
  97. package/dist/{mobile/utils → utils}/isAndroid/isAndroid.d.mts +1 -1
  98. package/dist/{mobile/utils → utils}/isAndroid/isAndroid.mjs +1 -1
  99. package/dist/{mobile/utils → utils}/isIOS/isIOS.cjs +1 -1
  100. package/dist/{mobile/utils → utils}/isIOS/isIOS.d.cts +1 -1
  101. package/dist/{mobile/utils → utils}/isIOS/isIOS.d.mts +1 -1
  102. package/dist/{mobile/utils → utils}/isIOS/isIOS.mjs +1 -1
  103. package/dist/{mobile/utils → utils}/isKeyboardVisible/isKeyboardVisible.cjs +1 -1
  104. package/dist/{mobile/utils → utils}/isKeyboardVisible/isKeyboardVisible.d.cts +1 -1
  105. package/dist/{mobile/utils → utils}/isKeyboardVisible/isKeyboardVisible.d.mts +1 -1
  106. package/dist/{mobile/utils → utils}/isKeyboardVisible/isKeyboardVisible.mjs +1 -1
  107. package/dist/{mobile/utils → utils}/isServer/isServer.cjs +1 -1
  108. package/dist/{mobile/utils → utils}/isServer/isServer.d.cts +1 -1
  109. package/dist/{mobile/utils → utils}/isServer/isServer.d.mts +1 -1
  110. package/dist/{mobile/utils → utils}/isServer/isServer.mjs +1 -1
  111. package/dist/{mobile/utils → utils}/subscribeKeyboardHeight/subscribeKeyboardHeight.cjs +1 -1
  112. package/dist/{mobile/utils → utils}/subscribeKeyboardHeight/subscribeKeyboardHeight.d.cts +1 -1
  113. package/dist/{mobile/utils → utils}/subscribeKeyboardHeight/subscribeKeyboardHeight.d.mts +1 -1
  114. package/dist/{mobile/utils → utils}/subscribeKeyboardHeight/subscribeKeyboardHeight.mjs +1 -1
  115. package/package.json +2 -2
  116. /package/dist/{mobile/hooks → hooks}/useAvoidKeyboard/index.d.cts +0 -0
  117. /package/dist/{mobile/hooks → hooks}/useAvoidKeyboard/index.d.mts +0 -0
package/CHANGELOG.md CHANGED
@@ -1,5 +1,28 @@
1
1
  # react-simplikit
2
2
 
3
+ ## 0.3.0
4
+
5
+ ### Minor Changes
6
+
7
+ - [#471](https://github.com/toss/react-simplikit/pull/471) [`edddd4b`](https://github.com/toss/react-simplikit/commit/edddd4bdc2b4e86158e1d59fdcd71f9d4f084ec3) Thanks [@hyesungoh](https://github.com/hyesungoh)! - Add `useDebouncedValue` and `useThrottledValue`. Both take a value the caller owns and return a delayed copy of it: `useDebouncedValue(value, wait, { leading?, trailing? })` follows the value `wait` milliseconds after the last change, and `useThrottledValue(value, wait, { leading?, trailing? })` follows it at most once per `wait` milliseconds. They pair with the existing `useDebouncedCallback` and `useThrottledCallback`, which wrap a setter instead of a value.
8
+
9
+ - [#479](https://github.com/toss/react-simplikit/pull/479) [`72ed16e`](https://github.com/toss/react-simplikit/commit/72ed16e9bccabaa5b06ca408885b4440461574ad) Thanks [@Antoliny0919](https://github.com/Antoliny0919)! - Add lazy initializer support to useBooleanState.
10
+
11
+ - [#469](https://github.com/toss/react-simplikit/pull/469) [`cc8b69e`](https://github.com/toss/react-simplikit/commit/cc8b69e466b1ad11089bc5aca32c898c5c7204ea) Thanks [@DongEun02](https://github.com/DongEun02)! - Add lazy initializer support to useInputState.
12
+
13
+ ### Patch Changes
14
+
15
+ - [#483](https://github.com/toss/react-simplikit/pull/483) [`6605918`](https://github.com/toss/react-simplikit/commit/66059185a194537b1b73224254683302324b9271) Thanks [@chungyo](https://github.com/chungyo)! - Use the updated callback when useRefEffect dependencies change during DOM ref attachment.
16
+
17
+ - [#482](https://github.com/toss/react-simplikit/pull/482) [`163ac5c`](https://github.com/toss/react-simplikit/commit/163ac5cc8418458d3c4c53624332ce6cb2d11109) Thanks [@chungyo](https://github.com/chungyo)! - Fix `useStorageState` retaining stale state when another tab clears localStorage.
18
+
19
+ - [#470](https://github.com/toss/react-simplikit/pull/470) [`52ed163`](https://github.com/toss/react-simplikit/commit/52ed163a7273faad99d1cf5fa7877b2a8a1c2e5f) Thanks [@hyesungoh](https://github.com/hyesungoh)! - `useThrottle` with `edges: ['trailing']` now invokes once per `wait` while calls keep coming in, instead of waiting for the calls to stop. `useThrottledCallback` and `useDebouncedCallback` now keep a single throttle or debounce across calls: `useThrottledCallback` forwards a stream of distinct values at most once per `timeThreshold` instead of every time, and `useDebouncedCallback` with `leading: true` forwards the first value of a burst once instead of every value immediately. Sharing one instance has two further consequences. A call carrying the same value as the last forwarded one is still skipped, but it now occupies a window, so a different value arriving inside that window waits for the window to close. And changing `timeThreshold`, `edges`, `leading` or `trailing` while a value is pending discards that pending value instead of forwarding it. `useImpressionRef` and `ImpressionArea` inherit the `useDebouncedCallback` change: an impression that ends within `timeThreshold` of its start now reports `onImpressionEnd` on the trailing edge rather than immediately, and an end still pending when the element unmounts is emitted during cleanup instead of being dropped.
20
+
21
+ - [#467](https://github.com/toss/react-simplikit/pull/467) [`92cbb34`](https://github.com/toss/react-simplikit/commit/92cbb349454a1b54f60db3edd1037240677984e4) Thanks [@constantly-dev](https://github.com/constantly-dev)! - `useIntersectionObserver` no longer recreates the underlying `IntersectionObserver` on every render when an inline `options` object is passed. It now recreates it only when `root`, `rootMargin`, or `threshold` actually change.
22
+
23
+ - [#473](https://github.com/toss/react-simplikit/pull/473) [`6f6361c`](https://github.com/toss/react-simplikit/commit/6f6361c38a5a951a813df8d033d60f6e7754a6d5) Thanks [@JetProc](https://github.com/JetProc)! - Cancel pending useLongPress timers when the component unmounts, preventing
24
+ onLongPress from firing after unmount.
25
+
3
26
  ## 0.2.0
4
27
 
5
28
  ### Minor Changes
package/README.md CHANGED
@@ -57,46 +57,19 @@ The debounced function exposes `.cancel()`, and pending calls are cancelled auto
57
57
 
58
58
  ## What's Included
59
59
 
60
- ### Hooks
61
-
62
- | Hook | Description |
63
- | ------------------------- | ----------------------------------------------------- |
64
- | `useBooleanState` | Manage boolean state with handlers |
65
- | `useDebounce` | Debounce a callback function |
66
- | `useDebouncedCallback` | Debounce an `onChange` callback via an options object |
67
- | `useInterval` | Set up intervals declaratively |
68
- | `useIntersectionObserver` | Observe element visibility |
69
- | `usePreservedCallback` | Stable callback reference |
70
- | `usePreservedReference` | Stable object reference |
71
- | ... | [See all hooks](https://react-simplikit.slash.page) |
72
-
73
- ### Components
74
-
75
- | Component | Description |
76
- | ---------------- | --------------------------------- |
77
- | `SwitchCase` | Declarative switch-case rendering |
78
- | `Separated` | Render items with separators |
79
- | `ImpressionArea` | Track element impressions |
80
-
81
- ### Utilities
82
-
83
- | Utility | Description |
84
- | -------------- | --------------------------------------------------- |
85
- | `buildContext` | Define React Context with less boilerplate |
86
- | `mergeProps` | Merge props, composing `className`, `style`, events |
87
- | `mergeRefs` | Combine multiple refs into a single ref |
60
+ - **Hooks** — state and logic (`useToggle`, `useDebounce`, `useList`, …), browser events (`useIntersectionObserver`, `useOutsideClickEffect`, …) and mobile web (`useAvoidKeyboard`, `useSafeAreaInset`, `useVisualViewport`, …)
61
+ - **Components** — `SwitchCase`, `Separated`, `ImpressionArea`
62
+ - **Utils** — `buildContext`, `mergeProps`, `mergeRefs`, and mobile web helpers such as `isIOS` and `getKeyboardHeight`
63
+
64
+ The full list with a one-line description each is on the [reference page](https://react-simplikit.slash.page/reference.html).
88
65
 
89
66
  ## Documentation
90
67
 
91
68
  Visit [react-simplikit.slash.page](https://react-simplikit.slash.page) for full documentation.
92
69
 
93
- ## Related Packages
94
-
95
- - [Mobile web utilities](https://react-simplikit.slash.page/mobile/intro.html) - included in `react-simplikit`
96
-
97
70
  ## Contributing
98
71
 
99
- We welcome contributions! Please see our [Contributing Guide](https://github.com/toss/react-simplikit/blob/main/CONTRIBUTING.md).
72
+ We welcome contributions! Please see our [Contributing Guide](https://github.com/toss/react-simplikit/blob/main/.github/CONTRIBUTING.md).
100
73
 
101
74
  ## License
102
75
 
@@ -6,10 +6,10 @@ let react = require("react");
6
6
  * `useAsyncEffect` is a React hook for handling asynchronous side effects in React components.
7
7
  * It follows the same cleanup pattern as `useEffect` while ensuring async operations are handled safely.
8
8
  *
9
- * @param {() => Promise<void | (() => void)>} [effect] - An asynchronous function executed in the `useEffect` pattern.
9
+ * @param {() => Promise<void | (() => void)>} effect - An asynchronous function executed in the `useEffect` pattern.
10
10
  * This function can optionally return a cleanup function.
11
11
  * @param {DependencyList} [deps] - A dependency array.
12
- * The effect will re-run whenever any value in this array changes. If omitted, it runs only once when the component mounts.
12
+ * The effect will re-run whenever any value in this array changes. If omitted, it runs after every render of the component.
13
13
  *
14
14
  * @example
15
15
  * useAsyncEffect(async () => {
@@ -6,10 +6,10 @@ import { DependencyList } from "react";
6
6
  * `useAsyncEffect` is a React hook for handling asynchronous side effects in React components.
7
7
  * It follows the same cleanup pattern as `useEffect` while ensuring async operations are handled safely.
8
8
  *
9
- * @param {() => Promise<void | (() => void)>} [effect] - An asynchronous function executed in the `useEffect` pattern.
9
+ * @param {() => Promise<void | (() => void)>} effect - An asynchronous function executed in the `useEffect` pattern.
10
10
  * This function can optionally return a cleanup function.
11
11
  * @param {DependencyList} [deps] - A dependency array.
12
- * The effect will re-run whenever any value in this array changes. If omitted, it runs only once when the component mounts.
12
+ * The effect will re-run whenever any value in this array changes. If omitted, it runs after every render of the component.
13
13
  *
14
14
  * @example
15
15
  * useAsyncEffect(async () => {
@@ -6,10 +6,10 @@ import { DependencyList } from "react";
6
6
  * `useAsyncEffect` is a React hook for handling asynchronous side effects in React components.
7
7
  * It follows the same cleanup pattern as `useEffect` while ensuring async operations are handled safely.
8
8
  *
9
- * @param {() => Promise<void | (() => void)>} [effect] - An asynchronous function executed in the `useEffect` pattern.
9
+ * @param {() => Promise<void | (() => void)>} effect - An asynchronous function executed in the `useEffect` pattern.
10
10
  * This function can optionally return a cleanup function.
11
11
  * @param {DependencyList} [deps] - A dependency array.
12
- * The effect will re-run whenever any value in this array changes. If omitted, it runs only once when the component mounts.
12
+ * The effect will re-run whenever any value in this array changes. If omitted, it runs after every render of the component.
13
13
  *
14
14
  * @example
15
15
  * useAsyncEffect(async () => {
@@ -6,10 +6,10 @@ import { useEffect } from "react";
6
6
  * `useAsyncEffect` is a React hook for handling asynchronous side effects in React components.
7
7
  * It follows the same cleanup pattern as `useEffect` while ensuring async operations are handled safely.
8
8
  *
9
- * @param {() => Promise<void | (() => void)>} [effect] - An asynchronous function executed in the `useEffect` pattern.
9
+ * @param {() => Promise<void | (() => void)>} effect - An asynchronous function executed in the `useEffect` pattern.
10
10
  * This function can optionally return a cleanup function.
11
11
  * @param {DependencyList} [deps] - A dependency array.
12
- * The effect will re-run whenever any value in this array changes. If omitted, it runs only once when the component mounts.
12
+ * The effect will re-run whenever any value in this array changes. If omitted, it runs after every render of the component.
13
13
  *
14
14
  * @example
15
15
  * useAsyncEffect(async () => {
@@ -1,7 +1,7 @@
1
1
  "use client";
2
2
  const require_useKeyboardHeight = require("../useKeyboardHeight/useKeyboardHeight.cjs");
3
3
  let react = require("react");
4
- //#region src/mobile/hooks/useAvoidKeyboard/useAvoidKeyboard.ts
4
+ //#region src/hooks/useAvoidKeyboard/useAvoidKeyboard.ts
5
5
  /**
6
6
  * @description
7
7
  * `useAvoidKeyboard` is a React hook that helps fixed-bottom elements avoid the on-screen keyboard.
@@ -1,6 +1,6 @@
1
1
 
2
2
  import { CSSProperties } from "react";
3
- //#region src/mobile/hooks/useAvoidKeyboard/useAvoidKeyboard.d.ts
3
+ //#region src/hooks/useAvoidKeyboard/useAvoidKeyboard.d.ts
4
4
  type UseAvoidKeyboardOptions = {
5
5
  /**
6
6
  * Base bottom offset in pixels when keyboard is hidden.
@@ -1,6 +1,6 @@
1
1
 
2
2
  import { CSSProperties } from "react";
3
- //#region src/mobile/hooks/useAvoidKeyboard/useAvoidKeyboard.d.ts
3
+ //#region src/hooks/useAvoidKeyboard/useAvoidKeyboard.d.ts
4
4
  type UseAvoidKeyboardOptions = {
5
5
  /**
6
6
  * Base bottom offset in pixels when keyboard is hidden.
@@ -1,7 +1,7 @@
1
1
  "use client";
2
2
  import { useKeyboardHeight } from "../useKeyboardHeight/useKeyboardHeight.mjs";
3
3
  import { useMemo } from "react";
4
- //#region src/mobile/hooks/useAvoidKeyboard/useAvoidKeyboard.ts
4
+ //#region src/hooks/useAvoidKeyboard/useAvoidKeyboard.ts
5
5
  /**
6
6
  * @description
7
7
  * `useAvoidKeyboard` is a React hook that helps fixed-bottom elements avoid the on-screen keyboard.
@@ -2,7 +2,7 @@
2
2
  const require_disableBodyScrollLock = require("../../utils/disableBodyScrollLock/disableBodyScrollLock.cjs");
3
3
  const require_enableBodyScrollLock = require("../../utils/enableBodyScrollLock/enableBodyScrollLock.cjs");
4
4
  let react = require("react");
5
- //#region src/mobile/hooks/useBodyScrollLock/useBodyScrollLock.ts
5
+ //#region src/hooks/useBodyScrollLock/useBodyScrollLock.ts
6
6
  /**
7
7
  * @description
8
8
  * `useBodyScrollLock` is a React hook that locks body scroll while the component is mounted.
@@ -1,5 +1,5 @@
1
1
 
2
- //#region src/mobile/hooks/useBodyScrollLock/useBodyScrollLock.d.ts
2
+ //#region src/hooks/useBodyScrollLock/useBodyScrollLock.d.ts
3
3
  /**
4
4
  * @description
5
5
  * `useBodyScrollLock` is a React hook that locks body scroll while the component is mounted.
@@ -1,5 +1,5 @@
1
1
 
2
- //#region src/mobile/hooks/useBodyScrollLock/useBodyScrollLock.d.ts
2
+ //#region src/hooks/useBodyScrollLock/useBodyScrollLock.d.ts
3
3
  /**
4
4
  * @description
5
5
  * `useBodyScrollLock` is a React hook that locks body scroll while the component is mounted.
@@ -2,7 +2,7 @@
2
2
  import { disableBodyScrollLock } from "../../utils/disableBodyScrollLock/disableBodyScrollLock.mjs";
3
3
  import { enableBodyScrollLock } from "../../utils/enableBodyScrollLock/enableBodyScrollLock.mjs";
4
4
  import { useEffect } from "react";
5
- //#region src/mobile/hooks/useBodyScrollLock/useBodyScrollLock.ts
5
+ //#region src/hooks/useBodyScrollLock/useBodyScrollLock.ts
6
6
  /**
7
7
  * @description
8
8
  * `useBodyScrollLock` is a React hook that locks body scroll while the component is mounted.
@@ -6,7 +6,7 @@ let react = require("react");
6
6
  * `useBooleanState` is a React hook that simplifies managing a boolean state.
7
7
  * It provides functions to set the state to `true`, set it to `false`, and toggle its value.
8
8
  *
9
- * @param {boolean} [defaultValue=false] - The initial value of the state. Defaults to `false`.
9
+ * @param {boolean | (() => boolean)} [initialValue=false] - The initial value of the state. Defaults to `false`.
10
10
  *
11
11
  * @returns {readonly [state: boolean, setTrue: () => void, setFalse: () => void, toggle: () => void]} A tuple containing:
12
12
  * - state `boolean` - The current state value;
@@ -17,8 +17,8 @@ let react = require("react");
17
17
  * @example
18
18
  * const [open, openBottomSheet, closeBottomSheet, toggleBottomSheet] = useBooleanState(false);
19
19
  */
20
- function useBooleanState(defaultValue = false) {
21
- const [bool, setBool] = (0, react.useState)(defaultValue);
20
+ function useBooleanState(initialValue = false) {
21
+ const [bool, setBool] = (0, react.useState)(initialValue);
22
22
  return [
23
23
  bool,
24
24
  (0, react.useCallback)(() => {
@@ -1,11 +1,12 @@
1
1
 
2
2
  //#region src/hooks/useBooleanState/useBooleanState.d.ts
3
+ type InitialValue = boolean | (() => boolean);
3
4
  /**
4
5
  * @description
5
6
  * `useBooleanState` is a React hook that simplifies managing a boolean state.
6
7
  * It provides functions to set the state to `true`, set it to `false`, and toggle its value.
7
8
  *
8
- * @param {boolean} [defaultValue=false] - The initial value of the state. Defaults to `false`.
9
+ * @param {boolean | (() => boolean)} [initialValue=false] - The initial value of the state. Defaults to `false`.
9
10
  *
10
11
  * @returns {readonly [state: boolean, setTrue: () => void, setFalse: () => void, toggle: () => void]} A tuple containing:
11
12
  * - state `boolean` - The current state value;
@@ -16,6 +17,6 @@
16
17
  * @example
17
18
  * const [open, openBottomSheet, closeBottomSheet, toggleBottomSheet] = useBooleanState(false);
18
19
  */
19
- declare function useBooleanState(defaultValue?: boolean): readonly [boolean, () => void, () => void, () => void];
20
+ declare function useBooleanState(initialValue?: InitialValue): readonly [boolean, () => void, () => void, () => void];
20
21
  //#endregion
21
22
  export { useBooleanState };
@@ -1,11 +1,12 @@
1
1
 
2
2
  //#region src/hooks/useBooleanState/useBooleanState.d.ts
3
+ type InitialValue = boolean | (() => boolean);
3
4
  /**
4
5
  * @description
5
6
  * `useBooleanState` is a React hook that simplifies managing a boolean state.
6
7
  * It provides functions to set the state to `true`, set it to `false`, and toggle its value.
7
8
  *
8
- * @param {boolean} [defaultValue=false] - The initial value of the state. Defaults to `false`.
9
+ * @param {boolean | (() => boolean)} [initialValue=false] - The initial value of the state. Defaults to `false`.
9
10
  *
10
11
  * @returns {readonly [state: boolean, setTrue: () => void, setFalse: () => void, toggle: () => void]} A tuple containing:
11
12
  * - state `boolean` - The current state value;
@@ -16,6 +17,6 @@
16
17
  * @example
17
18
  * const [open, openBottomSheet, closeBottomSheet, toggleBottomSheet] = useBooleanState(false);
18
19
  */
19
- declare function useBooleanState(defaultValue?: boolean): readonly [boolean, () => void, () => void, () => void];
20
+ declare function useBooleanState(initialValue?: InitialValue): readonly [boolean, () => void, () => void, () => void];
20
21
  //#endregion
21
22
  export { useBooleanState };
@@ -6,7 +6,7 @@ import { useCallback, useState } from "react";
6
6
  * `useBooleanState` is a React hook that simplifies managing a boolean state.
7
7
  * It provides functions to set the state to `true`, set it to `false`, and toggle its value.
8
8
  *
9
- * @param {boolean} [defaultValue=false] - The initial value of the state. Defaults to `false`.
9
+ * @param {boolean | (() => boolean)} [initialValue=false] - The initial value of the state. Defaults to `false`.
10
10
  *
11
11
  * @returns {readonly [state: boolean, setTrue: () => void, setFalse: () => void, toggle: () => void]} A tuple containing:
12
12
  * - state `boolean` - The current state value;
@@ -17,8 +17,8 @@ import { useCallback, useState } from "react";
17
17
  * @example
18
18
  * const [open, openBottomSheet, closeBottomSheet, toggleBottomSheet] = useBooleanState(false);
19
19
  */
20
- function useBooleanState(defaultValue = false) {
21
- const [bool, setBool] = useState(defaultValue);
20
+ function useBooleanState(initialValue = false) {
21
+ const [bool, setBool] = useState(initialValue);
22
22
  return [
23
23
  bool,
24
24
  useCallback(() => {
@@ -42,6 +42,7 @@ function debounce(func, debounceMs, { edges = ["leading", "trailing"] } = {}) {
42
42
  schedule();
43
43
  if (leading && isFirstCall) invoke();
44
44
  };
45
+ debounced.schedule = schedule;
45
46
  debounced.cancel = cancel;
46
47
  return debounced;
47
48
  }
@@ -42,6 +42,7 @@ function debounce(func, debounceMs, { edges = ["leading", "trailing"] } = {}) {
42
42
  schedule();
43
43
  if (leading && isFirstCall) invoke();
44
44
  };
45
+ debounced.schedule = schedule;
45
46
  debounced.cancel = cancel;
46
47
  return debounced;
47
48
  }
@@ -1,6 +1,6 @@
1
1
  "use client";
2
- const require_debounce = require("./debounce.cjs");
3
2
  const require_usePreservedCallback = require("../usePreservedCallback/usePreservedCallback.cjs");
3
+ const require_debounce = require("./debounce.cjs");
4
4
  let react = require("react");
5
5
  //#region src/hooks/useDebounce/useDebounce.ts
6
6
  /**
@@ -1,6 +1,6 @@
1
1
  "use client";
2
- import { debounce } from "./debounce.mjs";
3
2
  import { usePreservedCallback } from "../usePreservedCallback/usePreservedCallback.mjs";
3
+ import { debounce } from "./debounce.mjs";
4
4
  import { useEffect, useMemo } from "react";
5
5
  //#region src/hooks/useDebounce/useDebounce.ts
6
6
  /**
@@ -1,6 +1,5 @@
1
1
  "use client";
2
- const require_debounce = require("../useDebounce/debounce.cjs");
3
- const require_usePreservedCallback = require("../usePreservedCallback/usePreservedCallback.cjs");
2
+ const require_useDebounce = require("../useDebounce/useDebounce.cjs");
4
3
  let react = require("react");
5
4
  //#region src/hooks/useDebouncedCallback/useDebouncedCallback.ts
6
5
  /**
@@ -44,37 +43,15 @@ const NOT_INVOKED = Symbol("NOT_INVOKED");
44
43
  * }
45
44
  */
46
45
  function useDebouncedCallback({ onChange, timeThreshold, leading = false, trailing = true }) {
47
- const handleChange = require_usePreservedCallback.usePreservedCallback(onChange);
48
- const ref = (0, react.useRef)({
49
- value: NOT_INVOKED,
50
- clearPreviousDebounce: () => {}
46
+ const lastForwardedRef = (0, react.useRef)(NOT_INVOKED);
47
+ return require_useDebounce.useDebounce((nextValue) => {
48
+ if (nextValue === lastForwardedRef.current) return;
49
+ onChange(nextValue);
50
+ lastForwardedRef.current = nextValue;
51
+ }, timeThreshold, {
52
+ leading,
53
+ trailing
51
54
  });
52
- (0, react.useEffect)(function clearDebouncedOnUnmount() {
53
- const current = ref.current;
54
- return () => {
55
- current.clearPreviousDebounce();
56
- };
57
- }, []);
58
- const edges = (0, react.useMemo)(() => {
59
- const _edges = [];
60
- if (leading) _edges.push("leading");
61
- if (trailing) _edges.push("trailing");
62
- return _edges;
63
- }, [leading, trailing]);
64
- return (0, react.useCallback)((nextValue) => {
65
- ref.current.clearPreviousDebounce();
66
- if (nextValue === ref.current.value) return;
67
- const debounced = require_debounce.debounce(() => {
68
- handleChange(nextValue);
69
- ref.current.value = nextValue;
70
- }, timeThreshold, { edges });
71
- debounced();
72
- ref.current.clearPreviousDebounce = debounced.cancel;
73
- }, [
74
- handleChange,
75
- timeThreshold,
76
- edges
77
- ]);
78
55
  }
79
56
  //#endregion
80
57
  exports.useDebouncedCallback = useDebouncedCallback;
@@ -1,7 +1,6 @@
1
1
  "use client";
2
- import { debounce } from "../useDebounce/debounce.mjs";
3
- import { usePreservedCallback } from "../usePreservedCallback/usePreservedCallback.mjs";
4
- import { useCallback, useEffect, useMemo, useRef } from "react";
2
+ import { useDebounce } from "../useDebounce/useDebounce.mjs";
3
+ import { useRef } from "react";
5
4
  //#region src/hooks/useDebouncedCallback/useDebouncedCallback.ts
6
5
  /**
7
6
  * Marks that no value has been forwarded to `onChange` yet.
@@ -44,37 +43,15 @@ const NOT_INVOKED = Symbol("NOT_INVOKED");
44
43
  * }
45
44
  */
46
45
  function useDebouncedCallback({ onChange, timeThreshold, leading = false, trailing = true }) {
47
- const handleChange = usePreservedCallback(onChange);
48
- const ref = useRef({
49
- value: NOT_INVOKED,
50
- clearPreviousDebounce: () => {}
46
+ const lastForwardedRef = useRef(NOT_INVOKED);
47
+ return useDebounce((nextValue) => {
48
+ if (nextValue === lastForwardedRef.current) return;
49
+ onChange(nextValue);
50
+ lastForwardedRef.current = nextValue;
51
+ }, timeThreshold, {
52
+ leading,
53
+ trailing
51
54
  });
52
- useEffect(function clearDebouncedOnUnmount() {
53
- const current = ref.current;
54
- return () => {
55
- current.clearPreviousDebounce();
56
- };
57
- }, []);
58
- const edges = useMemo(() => {
59
- const _edges = [];
60
- if (leading) _edges.push("leading");
61
- if (trailing) _edges.push("trailing");
62
- return _edges;
63
- }, [leading, trailing]);
64
- return useCallback((nextValue) => {
65
- ref.current.clearPreviousDebounce();
66
- if (nextValue === ref.current.value) return;
67
- const debounced = debounce(() => {
68
- handleChange(nextValue);
69
- ref.current.value = nextValue;
70
- }, timeThreshold, { edges });
71
- debounced();
72
- ref.current.clearPreviousDebounce = debounced.cancel;
73
- }, [
74
- handleChange,
75
- timeThreshold,
76
- edges
77
- ]);
78
55
  }
79
56
  //#endregion
80
57
  export { useDebouncedCallback };
@@ -0,0 +1,64 @@
1
+ "use client";
2
+ const require_useDebounce = require("../useDebounce/useDebounce.cjs");
3
+ let react = require("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] = (0, react.useState)(() => value);
47
+ const debounced = require_useDebounce.useDebounce((next) => setDebouncedValue(() => next), wait, {
48
+ leading,
49
+ trailing
50
+ });
51
+ const lastForwardedRef = (0, react.useRef)(value);
52
+ (0, react.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
+ exports.useDebouncedValue = useDebouncedValue;
@@ -0,0 +1,49 @@
1
+
2
+ //#region src/hooks/useDebouncedValue/useDebouncedValue.d.ts
3
+ type DebounceOptions = {
4
+ leading?: boolean;
5
+ trailing?: boolean;
6
+ };
7
+ /**
8
+ * @description
9
+ * `useDebouncedValue` is a React hook that returns a debounced copy of the given value.
10
+ * The caller keeps owning the state; the hook only delays how quickly the returned value follows it.
11
+ * The returned value updates `wait` milliseconds after the last change, which is useful for
12
+ * deriving a search query or a validation input from fast-changing state.
13
+ *
14
+ * On the first render and on the server the value is returned as is. A change is never scheduled
15
+ * on mount, so with `leading: true` the first change after mount is applied immediately.
16
+ * If both `leading` and `trailing` are `false`, the returned value never updates.
17
+ *
18
+ * The value is compared by reference. Passing a new object or array on every render keeps
19
+ * the returned value updating every `wait` milliseconds; stabilize the reference first, for
20
+ * example with `usePreservedReference`.
21
+ *
22
+ * @template T - The type of the value.
23
+ * @param {T} value - The value to debounce.
24
+ * @param {number} wait - The number of milliseconds to wait after the last change before updating.
25
+ * @param {DebounceOptions} [options] - Configuration options for debounce behavior.
26
+ * @param {boolean} [options.leading=false] - If `true`, the first change after an idle period is applied immediately.
27
+ * @param {boolean} [options.trailing=true] - If `true`, the last change is applied after `wait` milliseconds.
28
+ *
29
+ * @returns {T} The debounced value.
30
+ *
31
+ * @example
32
+ * import { useDebouncedValue } from 'react-simplikit';
33
+ * import { useState } from 'react';
34
+ *
35
+ * function SearchInput() {
36
+ * const [query, setQuery] = useState('');
37
+ * const debouncedQuery = useDebouncedValue(query, 300);
38
+ *
39
+ * return (
40
+ * <>
41
+ * <input value={query} onChange={e => setQuery(e.target.value)} />
42
+ * <SearchResults query={debouncedQuery} />
43
+ * </>
44
+ * );
45
+ * }
46
+ */
47
+ declare function useDebouncedValue<T>(value: T, wait: number, { leading, trailing }?: DebounceOptions): T;
48
+ //#endregion
49
+ export { useDebouncedValue };
@@ -0,0 +1,49 @@
1
+
2
+ //#region src/hooks/useDebouncedValue/useDebouncedValue.d.ts
3
+ type DebounceOptions = {
4
+ leading?: boolean;
5
+ trailing?: boolean;
6
+ };
7
+ /**
8
+ * @description
9
+ * `useDebouncedValue` is a React hook that returns a debounced copy of the given value.
10
+ * The caller keeps owning the state; the hook only delays how quickly the returned value follows it.
11
+ * The returned value updates `wait` milliseconds after the last change, which is useful for
12
+ * deriving a search query or a validation input from fast-changing state.
13
+ *
14
+ * On the first render and on the server the value is returned as is. A change is never scheduled
15
+ * on mount, so with `leading: true` the first change after mount is applied immediately.
16
+ * If both `leading` and `trailing` are `false`, the returned value never updates.
17
+ *
18
+ * The value is compared by reference. Passing a new object or array on every render keeps
19
+ * the returned value updating every `wait` milliseconds; stabilize the reference first, for
20
+ * example with `usePreservedReference`.
21
+ *
22
+ * @template T - The type of the value.
23
+ * @param {T} value - The value to debounce.
24
+ * @param {number} wait - The number of milliseconds to wait after the last change before updating.
25
+ * @param {DebounceOptions} [options] - Configuration options for debounce behavior.
26
+ * @param {boolean} [options.leading=false] - If `true`, the first change after an idle period is applied immediately.
27
+ * @param {boolean} [options.trailing=true] - If `true`, the last change is applied after `wait` milliseconds.
28
+ *
29
+ * @returns {T} The debounced value.
30
+ *
31
+ * @example
32
+ * import { useDebouncedValue } from 'react-simplikit';
33
+ * import { useState } from 'react';
34
+ *
35
+ * function SearchInput() {
36
+ * const [query, setQuery] = useState('');
37
+ * const debouncedQuery = useDebouncedValue(query, 300);
38
+ *
39
+ * return (
40
+ * <>
41
+ * <input value={query} onChange={e => setQuery(e.target.value)} />
42
+ * <SearchResults query={debouncedQuery} />
43
+ * </>
44
+ * );
45
+ * }
46
+ */
47
+ declare function useDebouncedValue<T>(value: T, wait: number, { leading, trailing }?: DebounceOptions): T;
48
+ //#endregion
49
+ export { useDebouncedValue };