react-simplikit 0.0.48 → 0.0.50

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 (63) hide show
  1. package/dist/components/ImpressionArea/index.cjs +7 -4
  2. package/dist/components/ImpressionArea/index.d.cts +1 -1
  3. package/dist/components/Separated/index.cjs +1 -1
  4. package/dist/hooks/useCallbackOncePerRender/index.cjs +6 -3
  5. package/dist/hooks/useCounter/index.cjs +12 -14
  6. package/dist/hooks/useDebounce/index.cjs +14 -8
  7. package/dist/hooks/useDebouncedCallback/index.cjs +7 -4
  8. package/dist/hooks/useDoubleClick/index.cjs +6 -3
  9. package/dist/hooks/useImpressionRef/index.cjs +7 -4
  10. package/dist/hooks/useIntersectionObserver/index.cjs +6 -3
  11. package/dist/hooks/useInterval/index.cjs +24 -15
  12. package/dist/hooks/useIsClient/index.cjs +40 -0
  13. package/dist/hooks/useIsClient/index.d.cts +40 -0
  14. package/dist/hooks/useList/index.cjs +104 -0
  15. package/dist/hooks/useList/index.d.cts +50 -0
  16. package/dist/hooks/useLoading/index.cjs +9 -6
  17. package/dist/hooks/useLongPress/index.cjs +6 -3
  18. package/dist/hooks/useOutsideClickEffect/index.cjs +6 -3
  19. package/dist/hooks/usePreservedCallback/index.cjs +6 -3
  20. package/dist/hooks/usePrevious/index.d.cts +3 -3
  21. package/dist/hooks/useRefEffect/index.cjs +6 -3
  22. package/dist/hooks/useRefEffect/index.d.cts +3 -3
  23. package/dist/hooks/useSet/index.cjs +105 -0
  24. package/dist/hooks/useSet/index.d.cts +39 -0
  25. package/dist/hooks/useThrottle/index.cjs +6 -3
  26. package/dist/hooks/useThrottledCallback/index.cjs +172 -0
  27. package/dist/hooks/useThrottledCallback/index.d.cts +30 -0
  28. package/dist/hooks/useTimeout/index.cjs +8 -5
  29. package/dist/hooks/useTimeout/index.d.cts +1 -1
  30. package/dist/index.cjs +264 -110
  31. package/dist/index.d.cts +4 -0
  32. package/esm/components/ImpressionArea/index.d.ts +1 -1
  33. package/esm/components/ImpressionArea/index.js +7 -4
  34. package/esm/components/Separated/index.js +1 -1
  35. package/esm/hooks/useCallbackOncePerRender/index.js +6 -3
  36. package/esm/hooks/useCounter/index.js +12 -14
  37. package/esm/hooks/useDebounce/index.js +14 -8
  38. package/esm/hooks/useDebouncedCallback/index.js +7 -4
  39. package/esm/hooks/useDoubleClick/index.js +6 -3
  40. package/esm/hooks/useImpressionRef/index.js +7 -4
  41. package/esm/hooks/useIntersectionObserver/index.js +6 -3
  42. package/esm/hooks/useInterval/index.js +24 -15
  43. package/esm/hooks/useIsClient/index.d.ts +40 -0
  44. package/esm/hooks/useIsClient/index.js +14 -0
  45. package/esm/hooks/useList/index.d.ts +50 -0
  46. package/esm/hooks/useList/index.js +78 -0
  47. package/esm/hooks/useLoading/index.js +9 -6
  48. package/esm/hooks/useLongPress/index.js +6 -3
  49. package/esm/hooks/useOutsideClickEffect/index.js +6 -3
  50. package/esm/hooks/usePreservedCallback/index.js +6 -3
  51. package/esm/hooks/usePrevious/index.d.ts +3 -3
  52. package/esm/hooks/useRefEffect/index.d.ts +3 -3
  53. package/esm/hooks/useRefEffect/index.js +6 -3
  54. package/esm/hooks/useSet/index.d.ts +39 -0
  55. package/esm/hooks/useSet/index.js +79 -0
  56. package/esm/hooks/useThrottle/index.js +6 -3
  57. package/esm/hooks/useThrottledCallback/index.d.ts +30 -0
  58. package/esm/hooks/useThrottledCallback/index.js +146 -0
  59. package/esm/hooks/useTimeout/index.d.ts +1 -1
  60. package/esm/hooks/useTimeout/index.js +8 -5
  61. package/esm/index.d.ts +4 -0
  62. package/esm/index.js +234 -84
  63. package/package.json +1 -1
@@ -66,9 +66,12 @@ function debounce(func, debounceMs, { edges = ["leading", "trailing"] } = {}) {
66
66
  import { useCallback, useEffect, useRef } from "react";
67
67
  function usePreservedCallback(callback) {
68
68
  const callbackRef = useRef(callback);
69
- useEffect(() => {
70
- callbackRef.current = callback;
71
- }, [callback]);
69
+ useEffect(
70
+ function syncCallbackRef() {
71
+ callbackRef.current = callback;
72
+ },
73
+ [callback]
74
+ );
72
75
  return useCallback((...args) => {
73
76
  return callbackRef.current(...args);
74
77
  }, []);
@@ -84,7 +87,7 @@ function useDebouncedCallback({
84
87
  const handleChange = usePreservedCallback(onChange);
85
88
  const ref = useRef2({ value: false, clearPreviousDebounce: () => {
86
89
  } });
87
- useEffect2(() => {
90
+ useEffect2(function clearDebouncedOnUnmount() {
88
91
  const current = ref.current;
89
92
  return () => {
90
93
  current.clearPreviousDebounce();
@@ -8,7 +8,7 @@ function Separated({ children, by: separator }) {
8
8
  return /* @__PURE__ */ jsx(Fragment2, { children: childrenArray.map((child, i, { length }) => /* @__PURE__ */ jsxs(Fragment, { children: [
9
9
  child,
10
10
  i + 1 !== length && separator
11
- ] }, i)) });
11
+ ] }, child.key ?? i)) });
12
12
  }
13
13
  export {
14
14
  Separated
@@ -7,9 +7,12 @@ import { useEffect as useEffect2, useRef as useRef2 } from "react";
7
7
  import { useCallback, useEffect, useRef } from "react";
8
8
  function usePreservedCallback(callback) {
9
9
  const callbackRef = useRef(callback);
10
- useEffect(() => {
11
- callbackRef.current = callback;
12
- }, [callback]);
10
+ useEffect(
11
+ function syncCallbackRef() {
12
+ callbackRef.current = callback;
13
+ },
14
+ [callback]
15
+ );
13
16
  return useCallback((...args) => {
14
17
  return callbackRef.current(...args);
15
18
  }, []);
@@ -2,27 +2,25 @@
2
2
 
3
3
  // src/hooks/useCounter/useCounter.ts
4
4
  import { useCallback, useState } from "react";
5
+ var validateValue = (value, { min, max }) => {
6
+ if (min !== void 0 && value < min) {
7
+ return min;
8
+ }
9
+ if (max !== void 0 && value > max) {
10
+ return max;
11
+ }
12
+ return value;
13
+ };
5
14
  function useCounter(initialValue = 0, { min, max, step = 1 } = {}) {
6
- const validateValue = (value) => {
7
- let validatedValue = value;
8
- if (min !== void 0 && validatedValue < min) {
9
- validatedValue = min;
10
- }
11
- if (max !== void 0 && validatedValue > max) {
12
- validatedValue = max;
13
- }
14
- return validatedValue;
15
- };
16
- const [count, setCountState] = useState(() => validateValue(initialValue));
17
- const validateValueMemoized = useCallback(validateValue, [min, max]);
15
+ const [count, setCountState] = useState(() => validateValue(initialValue, { min, max }));
18
16
  const setCount = useCallback(
19
17
  (value) => {
20
18
  setCountState((prev) => {
21
19
  const nextValue = typeof value === "function" ? value(prev) : value;
22
- return validateValueMemoized(nextValue);
20
+ return validateValue(nextValue, { min, max });
23
21
  });
24
22
  },
25
- [validateValueMemoized]
23
+ [min, max]
26
24
  );
27
25
  const increment = useCallback(() => {
28
26
  setCount((prev) => prev + step);
@@ -8,9 +8,12 @@ import { useMemo } from "react";
8
8
  import { useCallback, useEffect, useRef } from "react";
9
9
  function usePreservedCallback(callback) {
10
10
  const callbackRef = useRef(callback);
11
- useEffect(() => {
12
- callbackRef.current = callback;
13
- }, [callback]);
11
+ useEffect(
12
+ function syncCallbackRef() {
13
+ callbackRef.current = callback;
14
+ },
15
+ [callback]
16
+ );
14
17
  return useCallback((...args) => {
15
18
  return callbackRef.current(...args);
16
19
  }, []);
@@ -86,11 +89,14 @@ function useDebounce(callback, wait, options = {}) {
86
89
  const debounced = useMemo(() => {
87
90
  return debounce(preservedCallback, wait, { edges });
88
91
  }, [preservedCallback, wait, edges]);
89
- useEffect2(() => {
90
- return () => {
91
- debounced.cancel();
92
- };
93
- }, [debounced]);
92
+ useEffect2(
93
+ function cancelDebouncedOnUnmount() {
94
+ return () => {
95
+ debounced.cancel();
96
+ };
97
+ },
98
+ [debounced]
99
+ );
94
100
  return debounced;
95
101
  }
96
102
  export {
@@ -60,9 +60,12 @@ function debounce(func, debounceMs, { edges = ["leading", "trailing"] } = {}) {
60
60
  import { useCallback, useEffect, useRef } from "react";
61
61
  function usePreservedCallback(callback) {
62
62
  const callbackRef = useRef(callback);
63
- useEffect(() => {
64
- callbackRef.current = callback;
65
- }, [callback]);
63
+ useEffect(
64
+ function syncCallbackRef() {
65
+ callbackRef.current = callback;
66
+ },
67
+ [callback]
68
+ );
66
69
  return useCallback((...args) => {
67
70
  return callbackRef.current(...args);
68
71
  }, []);
@@ -78,7 +81,7 @@ function useDebouncedCallback({
78
81
  const handleChange = usePreservedCallback(onChange);
79
82
  const ref = useRef2({ value: false, clearPreviousDebounce: () => {
80
83
  } });
81
- useEffect2(() => {
84
+ useEffect2(function clearDebouncedOnUnmount() {
82
85
  const current = ref.current;
83
86
  return () => {
84
87
  current.clearPreviousDebounce();
@@ -7,9 +7,12 @@ import { useCallback as useCallback2, useEffect as useEffect2, useRef as useRef2
7
7
  import { useCallback, useEffect, useRef } from "react";
8
8
  function usePreservedCallback(callback) {
9
9
  const callbackRef = useRef(callback);
10
- useEffect(() => {
11
- callbackRef.current = callback;
12
- }, [callback]);
10
+ useEffect(
11
+ function syncCallbackRef() {
12
+ callbackRef.current = callback;
13
+ },
14
+ [callback]
15
+ );
13
16
  return useCallback((...args) => {
14
17
  return callbackRef.current(...args);
15
18
  }, []);
@@ -63,9 +63,12 @@ function debounce(func, debounceMs, { edges = ["leading", "trailing"] } = {}) {
63
63
  import { useCallback, useEffect, useRef } from "react";
64
64
  function usePreservedCallback(callback) {
65
65
  const callbackRef = useRef(callback);
66
- useEffect(() => {
67
- callbackRef.current = callback;
68
- }, [callback]);
66
+ useEffect(
67
+ function syncCallbackRef() {
68
+ callbackRef.current = callback;
69
+ },
70
+ [callback]
71
+ );
69
72
  return useCallback((...args) => {
70
73
  return callbackRef.current(...args);
71
74
  }, []);
@@ -81,7 +84,7 @@ function useDebouncedCallback({
81
84
  const handleChange = usePreservedCallback(onChange);
82
85
  const ref = useRef2({ value: false, clearPreviousDebounce: () => {
83
86
  } });
84
- useEffect2(() => {
87
+ useEffect2(function clearDebouncedOnUnmount() {
85
88
  const current = ref.current;
86
89
  return () => {
87
90
  current.clearPreviousDebounce();
@@ -7,9 +7,12 @@ import { useMemo } from "react";
7
7
  import { useCallback, useEffect, useRef } from "react";
8
8
  function usePreservedCallback(callback) {
9
9
  const callbackRef = useRef(callback);
10
- useEffect(() => {
11
- callbackRef.current = callback;
12
- }, [callback]);
10
+ useEffect(
11
+ function syncCallbackRef() {
12
+ callbackRef.current = callback;
13
+ },
14
+ [callback]
15
+ );
13
16
  return useCallback((...args) => {
14
17
  return callbackRef.current(...args);
15
18
  }, []);
@@ -7,9 +7,12 @@ import { useEffect as useEffect2 } from "react";
7
7
  import { useCallback, useEffect, useRef } from "react";
8
8
  function usePreservedCallback(callback) {
9
9
  const callbackRef = useRef(callback);
10
- useEffect(() => {
11
- callbackRef.current = callback;
12
- }, [callback]);
10
+ useEffect(
11
+ function syncCallbackRef() {
12
+ callbackRef.current = callback;
13
+ },
14
+ [callback]
15
+ );
13
16
  return useCallback((...args) => {
14
17
  return callbackRef.current(...args);
15
18
  }, []);
@@ -21,18 +24,24 @@ function useInterval(callback, options) {
21
24
  const immediate = typeof options === "number" ? false : options.immediate;
22
25
  const enabled = typeof options === "number" ? true : options.enabled ?? true;
23
26
  const preservedCallback = usePreservedCallback(callback);
24
- useEffect2(() => {
25
- if (immediate === true && enabled) {
26
- preservedCallback();
27
- }
28
- }, [immediate, preservedCallback, enabled]);
29
- useEffect2(() => {
30
- if (!enabled) {
31
- return;
32
- }
33
- const id = window.setInterval(preservedCallback, delay);
34
- return () => window.clearInterval(id);
35
- }, [delay, preservedCallback, enabled]);
27
+ useEffect2(
28
+ function runImmediateCallback() {
29
+ if (immediate === true && enabled) {
30
+ preservedCallback();
31
+ }
32
+ },
33
+ [immediate, preservedCallback, enabled]
34
+ );
35
+ useEffect2(
36
+ function startInterval() {
37
+ if (!enabled) {
38
+ return;
39
+ }
40
+ const id = setInterval(preservedCallback, delay);
41
+ return () => clearInterval(id);
42
+ },
43
+ [delay, preservedCallback, enabled]
44
+ );
36
45
  }
37
46
  export {
38
47
  useInterval
@@ -0,0 +1,40 @@
1
+ /**
2
+ * @description
3
+ * `useIsClient` is a React hook that returns `true` only in the client-side environment.
4
+ * It is primarily used to differentiate between client-side and server-side rendering (SSR).
5
+ * The state is set to `true` only after the component is mounted in the client-side environment.
6
+ *
7
+ * @returns {boolean} Returns `true` in a client-side environment, and `false` otherwise.
8
+ *
9
+ * @example
10
+ * function ClientSideContent() {
11
+ * const isClient = useIsClient();
12
+ *
13
+ * if (!isClient) {
14
+ * return <div>Loading...</div>; // Rendered on the server side
15
+ * }
16
+ *
17
+ * return <div>Client-side rendered content</div>; // Rendered on the client side
18
+ * }
19
+ *
20
+ * @example
21
+ * function ClientOnlyMap() {
22
+ * const isClient = useIsClient();
23
+ *
24
+ * if (!isClient) return null;
25
+ *
26
+ * return <div id="map" />;
27
+ * }
28
+ *
29
+ * @example
30
+ * function ClientTheme() {
31
+ * const isClient = useIsClient();
32
+ *
33
+ * const theme = isClient ? localStorage.getItem('theme') : 'light';
34
+ *
35
+ * return <div>Current theme: {theme}</div>;
36
+ * }
37
+ */
38
+ declare function useIsClient(): boolean;
39
+
40
+ export { useIsClient };
@@ -0,0 +1,14 @@
1
+ "use client";
2
+
3
+ // src/hooks/useIsClient/useIsClient.ts
4
+ import { useEffect, useState } from "react";
5
+ function useIsClient() {
6
+ const [isClient, setIsClient] = useState(false);
7
+ useEffect(function syncClientState() {
8
+ setIsClient(true);
9
+ }, []);
10
+ return isClient;
11
+ }
12
+ export {
13
+ useIsClient
14
+ };
@@ -0,0 +1,50 @@
1
+ type ListActions<T> = {
2
+ push: (value: T) => void;
3
+ insertAt: (index: number, value: T) => void;
4
+ updateAt: (index: number, value: T) => void;
5
+ removeAt: (index: number) => void;
6
+ setAll: (values: T[]) => void;
7
+ reset: () => void;
8
+ };
9
+ type UseListReturn<T> = [ReadonlyArray<T>, ListActions<T>];
10
+ /**
11
+ * @description
12
+ * A React hook that manages an array as state.
13
+ * Provides efficient state management and stable action functions.
14
+ *
15
+ * @param {T[]} initialState - Initial array state
16
+ *
17
+ * @returns {UseListReturn<T>} A tuple containing the array state and actions to manipulate it
18
+ * - `push` - Appends a value to the end of the list
19
+ * - `insertAt` - Inserts a value at the specified index
20
+ * - `updateAt` - Updates the value at the specified index
21
+ * - `removeAt` - Removes the value at the specified index
22
+ * - `setAll` - Replaces the entire list with a new array
23
+ * - `reset` - Resets the list to its initial state
24
+ *
25
+ * @example
26
+ * ```tsx
27
+ * const [list, actions] = useList<string>(['apple', 'banana']);
28
+ *
29
+ * // Add an item
30
+ * actions.push('cherry');
31
+ *
32
+ * // Insert at index
33
+ * actions.insertAt(1, 'grape');
34
+ *
35
+ * // Update at index
36
+ * actions.updateAt(0, 'orange');
37
+ *
38
+ * // Remove at index
39
+ * actions.removeAt(2);
40
+ *
41
+ * // Replace all
42
+ * actions.setAll(['kiwi', 'mango']);
43
+ *
44
+ * // Reset to initial state
45
+ * actions.reset();
46
+ * ```
47
+ */
48
+ declare function useList<T>(initialState?: T[]): UseListReturn<T>;
49
+
50
+ export { useList };
@@ -0,0 +1,78 @@
1
+ "use client";
2
+
3
+ // src/hooks/useList/useList.ts
4
+ import { useMemo as useMemo2, useState } from "react";
5
+
6
+ // src/hooks/usePreservedCallback/usePreservedCallback.ts
7
+ import { useCallback, useEffect, useRef } from "react";
8
+ function usePreservedCallback(callback) {
9
+ const callbackRef = useRef(callback);
10
+ useEffect(
11
+ function syncCallbackRef() {
12
+ callbackRef.current = callback;
13
+ },
14
+ [callback]
15
+ );
16
+ return useCallback((...args) => {
17
+ return callbackRef.current(...args);
18
+ }, []);
19
+ }
20
+
21
+ // src/hooks/usePreservedReference/usePreservedReference.ts
22
+ import { useMemo, useRef as useRef2 } from "react";
23
+ function usePreservedReference(value, areValuesEqual = areDeeplyEqual) {
24
+ const ref = useRef2(value);
25
+ return useMemo(() => {
26
+ if (!areValuesEqual(ref.current, value)) {
27
+ ref.current = value;
28
+ }
29
+ return ref.current;
30
+ }, [areValuesEqual, value]);
31
+ }
32
+ function areDeeplyEqual(x, y) {
33
+ return JSON.stringify(x) === JSON.stringify(y);
34
+ }
35
+
36
+ // src/hooks/useList/useList.ts
37
+ function useList(initialState = []) {
38
+ const [list, setList] = useState(initialState);
39
+ const preservedInitialState = usePreservedReference(initialState);
40
+ const push = usePreservedCallback((value) => {
41
+ setList((prev) => [...prev, value]);
42
+ });
43
+ const insertAt = usePreservedCallback((index, value) => {
44
+ setList((prev) => {
45
+ const next = [...prev];
46
+ next.splice(index, 0, value);
47
+ return next;
48
+ });
49
+ });
50
+ const updateAt = usePreservedCallback((index, value) => {
51
+ setList((prev) => {
52
+ const next = [...prev];
53
+ next[index] = value;
54
+ return next;
55
+ });
56
+ });
57
+ const removeAt = usePreservedCallback((index) => {
58
+ setList((prev) => {
59
+ const next = [...prev];
60
+ next.splice(index, 1);
61
+ return next;
62
+ });
63
+ });
64
+ const setAll = usePreservedCallback((values) => {
65
+ setList(values);
66
+ });
67
+ const reset = usePreservedCallback(() => {
68
+ setList(preservedInitialState);
69
+ });
70
+ const actions = useMemo2(
71
+ () => ({ push, insertAt, updateAt, removeAt, setAll, reset }),
72
+ [push, insertAt, updateAt, removeAt, setAll, reset]
73
+ );
74
+ return [list, actions];
75
+ }
76
+ export {
77
+ useList
78
+ };
@@ -23,12 +23,15 @@ function useLoading() {
23
23
  }
24
24
  function useIsMountedRef() {
25
25
  const ref = useRef({ isMounted: true }).current;
26
- useEffect(() => {
27
- ref.isMounted = true;
28
- return () => {
29
- ref.isMounted = false;
30
- };
31
- }, [ref]);
26
+ useEffect(
27
+ function trackMountedState() {
28
+ ref.isMounted = true;
29
+ return () => {
30
+ ref.isMounted = false;
31
+ };
32
+ },
33
+ [ref]
34
+ );
32
35
  return ref;
33
36
  }
34
37
  export {
@@ -7,9 +7,12 @@ import { useCallback as useCallback2, useRef as useRef2 } from "react";
7
7
  import { useCallback, useEffect, useRef } from "react";
8
8
  function usePreservedCallback(callback) {
9
9
  const callbackRef = useRef(callback);
10
- useEffect(() => {
11
- callbackRef.current = callback;
12
- }, [callback]);
10
+ useEffect(
11
+ function syncCallbackRef() {
12
+ callbackRef.current = callback;
13
+ },
14
+ [callback]
15
+ );
13
16
  return useCallback((...args) => {
14
17
  return callbackRef.current(...args);
15
18
  }, []);
@@ -7,9 +7,12 @@ import { useEffect as useEffect2, useRef as useRef2 } from "react";
7
7
  import { useCallback, useEffect, useRef } from "react";
8
8
  function usePreservedCallback(callback) {
9
9
  const callbackRef = useRef(callback);
10
- useEffect(() => {
11
- callbackRef.current = callback;
12
- }, [callback]);
10
+ useEffect(
11
+ function syncCallbackRef() {
12
+ callbackRef.current = callback;
13
+ },
14
+ [callback]
15
+ );
13
16
  return useCallback((...args) => {
14
17
  return callbackRef.current(...args);
15
18
  }, []);
@@ -4,9 +4,12 @@
4
4
  import { useCallback, useEffect, useRef } from "react";
5
5
  function usePreservedCallback(callback) {
6
6
  const callbackRef = useRef(callback);
7
- useEffect(() => {
8
- callbackRef.current = callback;
9
- }, [callback]);
7
+ useEffect(
8
+ function syncCallbackRef() {
9
+ callbackRef.current = callback;
10
+ },
11
+ [callback]
12
+ );
10
13
  return useCallback((...args) => {
11
14
  return callbackRef.current(...args);
12
15
  }, []);
@@ -1,15 +1,15 @@
1
1
  /**
2
2
  * @description
3
3
  * `usePrevious` is a React hook that returns the previous value of the input state.
4
- * It preserves the previous value unchanged when re-render occur without state changes.
4
+ * It preserves the previous value unchanged when re-renders occur without state changes.
5
5
  * If the state is an object or requires custom change detection, a `compare` function can be provided.
6
6
  * By default, state changes are detected using `prev === next`.
7
7
  *
8
8
  * @template T - The type of the state.
9
9
  * @param {T} state - The state whose previous value is to be tracked.
10
- * @param {(prev: T | undefined, next: T) => boolean} [compare] - An optional comparison function to determine if the state has changed.
10
+ * @param {(prev: T, next: T) => boolean} [compare] - An optional comparison function to determine if the state has changed.
11
11
  *
12
- * @returns {T | undefined} The previous value of the state.
12
+ * @returns {T} The previous value of the state.
13
13
  *
14
14
  * @example
15
15
  * const [count, setCount] = useState(0);
@@ -6,10 +6,10 @@ type CleanupCallback = () => void;
6
6
  * `useRefEffect` is a React hook that helps you set a reference to a specific DOM element and execute a callback whenever the element changes.
7
7
  * This hook calls a cleanup function whenever the element changes to prevent memory leaks.
8
8
  *
9
- * @param {(element: Element) => CleanupCallback | void} callback - A callback function that is executed when the element is set. This function can return a cleanup function.
9
+ * @param {(element: RefElement) => CleanupCallback | void} callback - A callback function that is executed when the element is set. This function can return a cleanup function.
10
10
  * @param {DependencyList} deps - An array of dependencies that define when the callback should be re-executed. The `callback` is re-executed whenever the `deps` change.
11
11
  *
12
- * @returns {(element: Element | null) => void} A function to set the element. Pass this function to the `ref` attribute, and the `callback` will be called whenever the element changes.
12
+ * @returns {(element: RefElement | null) => void} A function to set the element. Pass this function to the `ref` attribute, and the `callback` will be called whenever the element changes.
13
13
  *
14
14
  * @example
15
15
  * import { useRefEffect } from 'react-simplikit';
@@ -26,6 +26,6 @@ type CleanupCallback = () => void;
26
26
  * return <div ref={ref}>Basic Example</div>;
27
27
  * }
28
28
  */
29
- declare function useRefEffect<Element extends HTMLElement = HTMLElement>(callback: (element: Element) => CleanupCallback | void, deps: DependencyList): (element: Element | null) => void;
29
+ declare function useRefEffect<RefElement extends HTMLElement = HTMLElement>(callback: (element: RefElement) => CleanupCallback | void, deps: DependencyList): (element: RefElement | null) => void;
30
30
 
31
31
  export { useRefEffect };
@@ -7,9 +7,12 @@ import { useCallback as useCallback2, useRef as useRef2 } from "react";
7
7
  import { useCallback, useEffect, useRef } from "react";
8
8
  function usePreservedCallback(callback) {
9
9
  const callbackRef = useRef(callback);
10
- useEffect(() => {
11
- callbackRef.current = callback;
12
- }, [callback]);
10
+ useEffect(
11
+ function syncCallbackRef() {
12
+ callbackRef.current = callback;
13
+ },
14
+ [callback]
15
+ );
13
16
  return useCallback((...args) => {
14
17
  return callbackRef.current(...args);
15
18
  }, []);
@@ -0,0 +1,39 @@
1
+ type SetOrValues<T> = Set<T> | T[];
2
+ type SetActions<T> = {
3
+ add: (value: T) => void;
4
+ remove: (value: T) => void;
5
+ toggle: (value: T) => void;
6
+ setAll: (values: SetOrValues<T>) => void;
7
+ reset: () => void;
8
+ };
9
+ type UseSetReturn<T> = [Omit<Set<T>, 'add' | 'clear' | 'delete'>, SetActions<T>];
10
+ /**
11
+ * @description
12
+ * A React hook that manages a Set as state.
13
+ * Provides efficient state management and stable action functions.
14
+ *
15
+ * @param {SetOrValues<T>} initialState - Initial Set state (Set object or array of values)
16
+ * @returns {UseSetReturn<T>} A tuple containing the Set state and actions to manipulate it
17
+ *
18
+ * @example
19
+ * ```tsx
20
+ * import { useSet } from 'react-simplikit';
21
+ *
22
+ * function TagSelector() {
23
+ * const [selectedTags, { add, remove, toggle }] = useSet<string>(['react']);
24
+ *
25
+ * return (
26
+ * <div>
27
+ * {['react', 'vue', 'svelte'].map(tag => (
28
+ * <button key={tag} onClick={() => toggle(tag)}>
29
+ * {selectedTags.has(tag) ? '✓' : ''} {tag}
30
+ * </button>
31
+ * ))}
32
+ * </div>
33
+ * );
34
+ * }
35
+ * ```
36
+ */
37
+ declare function useSet<T>(initialState?: SetOrValues<T>): UseSetReturn<T>;
38
+
39
+ export { useSet };