@versini/ui-hooks 5.3.2 → 6.0.1

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 (45) hide show
  1. package/README.md +35 -9
  2. package/dist/__tests__/__mocks__/ResizeObserver.d.ts +21 -0
  3. package/dist/__tests__/useClickOutside.test.d.ts +1 -0
  4. package/dist/__tests__/useHaptic.test.d.ts +1 -0
  5. package/dist/__tests__/useHotkeys.test.d.ts +1 -0
  6. package/dist/__tests__/useInterval.test.d.ts +1 -0
  7. package/dist/__tests__/useIsMounted.test.d.ts +1 -0
  8. package/dist/__tests__/useLocalStorage.test.d.ts +1 -0
  9. package/dist/__tests__/useMergeRefs.test.d.ts +1 -0
  10. package/dist/__tests__/useResizeObserver.test.d.ts +1 -0
  11. package/dist/__tests__/useUncontrolled.test.d.ts +1 -0
  12. package/dist/__tests__/useUniqueId.test.d.ts +1 -0
  13. package/dist/__tests__/useViewportSize.test.d.ts +1 -0
  14. package/dist/__tests__/utilities.test.d.ts +1 -0
  15. package/dist/useClickOutside/useClickOutside.d.ts +17 -0
  16. package/dist/useClickOutside/useClickOutside.js +68 -0
  17. package/dist/useHaptic/useHaptic.d.ts +24 -0
  18. package/dist/useHaptic/useHaptic.js +200 -0
  19. package/dist/useHotkeys/useHotkeys.d.ts +10 -0
  20. package/dist/useHotkeys/useHotkeys.js +65 -0
  21. package/dist/useHotkeys/utilities.d.ts +19 -0
  22. package/dist/useHotkeys/utilities.js +87 -0
  23. package/dist/useInViewport/useInViewport.d.ts +10 -0
  24. package/dist/useInViewport/useInViewport.js +52 -0
  25. package/dist/useInterval/useInterval.d.ts +21 -0
  26. package/dist/useInterval/useInterval.js +75 -0
  27. package/dist/useIsMounted/useIsMounted.d.ts +13 -0
  28. package/dist/useIsMounted/useIsMounted.js +46 -0
  29. package/dist/useLocalStorage/useLocalStorage.d.ts +82 -0
  30. package/dist/useLocalStorage/useLocalStorage.js +236 -0
  31. package/dist/useMergeRefs/useMergeRefs.d.ts +20 -0
  32. package/dist/useMergeRefs/useMergeRefs.js +62 -0
  33. package/dist/useResizeObserver/useResizeObserver.d.ts +17 -0
  34. package/dist/useResizeObserver/useResizeObserver.js +94 -0
  35. package/dist/useUncontrolled/useUncontrolled.d.ts +14 -0
  36. package/dist/useUncontrolled/useUncontrolled.js +76 -0
  37. package/dist/useUniqueId/useUniqueId.d.ts +36 -0
  38. package/dist/useUniqueId/useUniqueId.js +41 -0
  39. package/dist/useViewportSize/useViewportSize.d.ts +13 -0
  40. package/dist/useViewportSize/useViewportSize.js +60 -0
  41. package/dist/useVisualViewportSize/useVisualViewportSize.d.ts +14 -0
  42. package/dist/useVisualViewportSize/useVisualViewportSize.js +70 -0
  43. package/package.json +56 -4
  44. package/dist/index.d.ts +0 -316
  45. package/dist/index.js +0 -958
@@ -0,0 +1,52 @@
1
+ /*!
2
+ @versini/ui-hooks v6.0.1
3
+ © 2025 gizmette.com
4
+ */
5
+ try {
6
+ if (!window.__VERSINI_UI_HOOKS__) {
7
+ window.__VERSINI_UI_HOOKS__ = {
8
+ version: "6.0.1",
9
+ buildTime: "12/24/2025 09:19 AM EST",
10
+ homepage: "https://www.npmjs.com/package/@versini/ui-hooks",
11
+ license: "MIT",
12
+ };
13
+ }
14
+ } catch (error) {
15
+ // nothing to declare officer
16
+ }
17
+
18
+ import { useCallback, useRef, useState } from "react";
19
+
20
+ ;// CONCATENATED MODULE: external "react"
21
+
22
+ ;// CONCATENATED MODULE: ./src/hooks/useInViewport/useInViewport.ts
23
+
24
+ /**
25
+ * Hook that checks if an element is visible in the viewport.
26
+ * @returns
27
+ * ref: React ref object to attach to the element you want to monitor.
28
+ * inViewport: Boolean indicating if the element is in the viewport.
29
+ */ /* v8 ignore start */ function useInViewport() {
30
+ const observer = useRef(null);
31
+ const [inViewport, setInViewport] = useState(false);
32
+ const ref = useCallback((node)=>{
33
+ if (typeof IntersectionObserver !== "undefined") {
34
+ if (node && !observer.current) {
35
+ observer.current = new IntersectionObserver((entries)=>setInViewport(entries.some((entry)=>entry.isIntersecting)));
36
+ } else {
37
+ observer.current?.disconnect();
38
+ }
39
+ if (node) {
40
+ observer.current?.observe(node);
41
+ } else {
42
+ setInViewport(false);
43
+ }
44
+ }
45
+ }, []);
46
+ return {
47
+ ref,
48
+ inViewport
49
+ };
50
+ } /* v8 ignore stop */
51
+
52
+ export { useInViewport };
@@ -0,0 +1,21 @@
1
+ /**
2
+ * Custom hook to call a function within a given interval.
3
+ *
4
+ * @param fn Callback function to be executed at each interval
5
+ * @param interval Interval time in milliseconds
6
+ * @returns An object containing start, stop, and active state
7
+ *
8
+ * @example
9
+ * const { start, stop, active } = useInterval(() => {
10
+ * console.log("Interval executed");
11
+ * }, 1000);
12
+ * start(); // To start the interval
13
+ * stop(); // To stop the interval
14
+ * console.log(active); // To check if the interval is active
15
+ *
16
+ */
17
+ export declare function useInterval(fn: () => void, interval: number): {
18
+ start: () => void;
19
+ stop: () => void;
20
+ active: boolean;
21
+ };
@@ -0,0 +1,75 @@
1
+ /*!
2
+ @versini/ui-hooks v6.0.1
3
+ © 2025 gizmette.com
4
+ */
5
+ try {
6
+ if (!window.__VERSINI_UI_HOOKS__) {
7
+ window.__VERSINI_UI_HOOKS__ = {
8
+ version: "6.0.1",
9
+ buildTime: "12/24/2025 09:19 AM EST",
10
+ homepage: "https://www.npmjs.com/package/@versini/ui-hooks",
11
+ license: "MIT",
12
+ };
13
+ }
14
+ } catch (error) {
15
+ // nothing to declare officer
16
+ }
17
+
18
+ import { useCallback, useEffect, useRef, useState } from "react";
19
+
20
+ ;// CONCATENATED MODULE: external "react"
21
+
22
+ ;// CONCATENATED MODULE: ./src/hooks/useInterval/useInterval.ts
23
+
24
+ /**
25
+ * Custom hook to call a function within a given interval.
26
+ *
27
+ * @param fn Callback function to be executed at each interval
28
+ * @param interval Interval time in milliseconds
29
+ * @returns An object containing start, stop, and active state
30
+ *
31
+ * @example
32
+ * const { start, stop, active } = useInterval(() => {
33
+ * console.log("Interval executed");
34
+ * }, 1000);
35
+ * start(); // To start the interval
36
+ * stop(); // To stop the interval
37
+ * console.log(active); // To check if the interval is active
38
+ *
39
+ */ function useInterval(fn, interval) {
40
+ const [active, setActive] = useState(false);
41
+ const intervalRef = useRef(null);
42
+ const fnRef = useRef(null);
43
+ const start = useCallback(()=>{
44
+ setActive((old)=>{
45
+ /* v8 ignore start - interval reactivation edge case */ if (!old && (!intervalRef.current || intervalRef.current === -1)) {
46
+ intervalRef.current = window.setInterval(fnRef.current, interval);
47
+ }
48
+ /* v8 ignore stop */ return true;
49
+ });
50
+ }, [
51
+ interval
52
+ ]);
53
+ const stop = useCallback(()=>{
54
+ setActive(false);
55
+ window.clearInterval(intervalRef.current || -1);
56
+ intervalRef.current = -1;
57
+ }, []);
58
+ useEffect(()=>{
59
+ fnRef.current = fn;
60
+ active && start();
61
+ return stop;
62
+ }, [
63
+ fn,
64
+ active,
65
+ start,
66
+ stop
67
+ ]);
68
+ return {
69
+ start,
70
+ stop,
71
+ active
72
+ };
73
+ }
74
+
75
+ export { useInterval };
@@ -0,0 +1,13 @@
1
+ /**
2
+ * Custom hook that returns a function indicating whether the component
3
+ * is mounted or not.
4
+ *
5
+ * @returns A function that returns a boolean value indicating whether
6
+ * the component is mounted.
7
+ *
8
+ * @example
9
+ * const isMounted = useIsMounted();
10
+ * console.log(isMounted()); // true
11
+ *
12
+ */
13
+ export declare function useIsMounted(): () => boolean;
@@ -0,0 +1,46 @@
1
+ /*!
2
+ @versini/ui-hooks v6.0.1
3
+ © 2025 gizmette.com
4
+ */
5
+ try {
6
+ if (!window.__VERSINI_UI_HOOKS__) {
7
+ window.__VERSINI_UI_HOOKS__ = {
8
+ version: "6.0.1",
9
+ buildTime: "12/24/2025 09:19 AM EST",
10
+ homepage: "https://www.npmjs.com/package/@versini/ui-hooks",
11
+ license: "MIT",
12
+ };
13
+ }
14
+ } catch (error) {
15
+ // nothing to declare officer
16
+ }
17
+
18
+ import { useCallback, useEffect, useRef } from "react";
19
+
20
+ ;// CONCATENATED MODULE: external "react"
21
+
22
+ ;// CONCATENATED MODULE: ./src/hooks/useIsMounted/useIsMounted.ts
23
+
24
+ /**
25
+ * Custom hook that returns a function indicating whether the component
26
+ * is mounted or not.
27
+ *
28
+ * @returns A function that returns a boolean value indicating whether
29
+ * the component is mounted.
30
+ *
31
+ * @example
32
+ * const isMounted = useIsMounted();
33
+ * console.log(isMounted()); // true
34
+ *
35
+ */ function useIsMounted() {
36
+ const isMounted = useRef(false);
37
+ useEffect(()=>{
38
+ isMounted.current = true;
39
+ return ()=>{
40
+ isMounted.current = false;
41
+ };
42
+ }, []);
43
+ return useCallback(()=>isMounted.current, []);
44
+ }
45
+
46
+ export { useIsMounted };
@@ -0,0 +1,82 @@
1
+ /**
2
+ * Configuration properties for the useLocalStorage hook.
3
+ *
4
+ * @template T - The type of the value stored in localStorage
5
+ *
6
+ */
7
+ export interface StorageProperties<T> {
8
+ /**
9
+ * The localStorage key under which the value will be stored. Must be unique
10
+ * within your application to avoid conflicts.
11
+ */
12
+ key: string;
13
+ /**
14
+ * Optional default value that will be set in localStorage if no value exists.
15
+ * This value will be used on initial mount and when resetValue() is called.
16
+ */
17
+ initialValue?: T;
18
+ }
19
+ /**
20
+ * A React hook for managing state synchronized with localStorage. Uses React
21
+ * 19's useSyncExternalStore for optimal concurrent rendering support and
22
+ * automatic synchronization across components. Changes are automatically
23
+ * persisted to localStorage and synchronized across all components using the
24
+ * same key, including across browser tabs.
25
+ *
26
+ * Features:
27
+ * - Automatic serialization/deserialization with JSON
28
+ * - Type-safe with TypeScript generics
29
+ * - Supports functional updates (similar to setState)
30
+ * - Synchronized across components and browser tabs
31
+ * - Handles edge cases (null, undefined, errors)
32
+ * - Compatible with React 19+ concurrent features
33
+ *
34
+ * @template T - The type of the value stored in localStorage
35
+ * @param {StorageProperties<T>} config - Configuration object with key and optional initialValue
36
+ * @returns {[T | null, (value: T | ((current: T) => T)) => void, () => void, () => void]} A tuple containing:
37
+ * - [0] current value from localStorage (or null if not set)
38
+ * - [1] setValue function to update the stored value (supports direct value or function updater)
39
+ * - [2] resetValue function to restore the initialValue
40
+ * - [3] removeValue function to remove the value from localStorage
41
+ *
42
+ * @example
43
+ * ```js
44
+ * // Basic usage with a string value
45
+ * import { useLocalStorage } from '@versini/ui-hooks';
46
+ * const [model, setModel, resetModel, removeModel] = useLocalStorage({
47
+ * key: 'gpt-model',
48
+ * initialValue: 'gpt-3',
49
+ * });
50
+ *
51
+ * // Direct update
52
+ * setModel('gpt-4'); // Stores "gpt-4"
53
+ *
54
+ * // Functional update (receives current value)
55
+ * setModel((current) => (current === 'gpt-3' ? 'gpt-4' : 'gpt-3'));
56
+ *
57
+ * // Reset to initial value
58
+ * resetModel(); // Restores "gpt-3"
59
+ *
60
+ * // Remove from localStorage
61
+ * removeModel(); // Sets value to null and removes from storage
62
+ * ```
63
+ *
64
+ * @example
65
+ * ```js
66
+ * // Usage with complex objects
67
+ * interface UserPreferences {
68
+ * theme: 'light' | 'dark';
69
+ * fontSize: number;
70
+ * }
71
+ *
72
+ * const [prefs, setPrefs] = useLocalStorage<UserPreferences>({
73
+ * key: 'user-preferences',
74
+ * initialValue: { theme: 'light', fontSize: 14 }
75
+ * });
76
+ *
77
+ * // Update specific property
78
+ * setPrefs(current => ({ ...current, theme: 'dark' }));
79
+ * ```
80
+ *
81
+ */
82
+ export declare function useLocalStorage<T>({ key, initialValue, }: StorageProperties<T>): any[];
@@ -0,0 +1,236 @@
1
+ /*!
2
+ @versini/ui-hooks v6.0.1
3
+ © 2025 gizmette.com
4
+ */
5
+ try {
6
+ if (!window.__VERSINI_UI_HOOKS__) {
7
+ window.__VERSINI_UI_HOOKS__ = {
8
+ version: "6.0.1",
9
+ buildTime: "12/24/2025 09:19 AM EST",
10
+ homepage: "https://www.npmjs.com/package/@versini/ui-hooks",
11
+ license: "MIT",
12
+ };
13
+ }
14
+ } catch (error) {
15
+ // nothing to declare officer
16
+ }
17
+
18
+ import { useCallback, useEffect, useSyncExternalStore } from "react";
19
+
20
+ ;// CONCATENATED MODULE: external "react"
21
+
22
+ ;// CONCATENATED MODULE: ./src/hooks/useLocalStorage/useLocalStorage.ts
23
+
24
+ /**
25
+ * Dispatches a custom storage event to notify other parts of the application
26
+ * about localStorage changes. This is necessary because the native storage
27
+ * event only fires in other tabs/windows, not in the current one. By manually
28
+ * dispatching the event, we ensure that all components using the same key stay
29
+ * synchronized.
30
+ *
31
+ * @param key - The localStorage key that was modified
32
+ * @param newValue - The new value (stringified) or null if the item was removed
33
+ *
34
+ */ function dispatchStorageEvent(key, newValue) {
35
+ window.dispatchEvent(new StorageEvent("storage", {
36
+ key,
37
+ newValue
38
+ }));
39
+ }
40
+ /**
41
+ * Sets an item in localStorage and dispatches a storage event. Handles both
42
+ * direct values and function updaters (similar to React's setState). Values are
43
+ * automatically serialized to JSON before storage.
44
+ *
45
+ * @param key - The localStorage key to set
46
+ * @param value - The value to store, or a function that returns the value to store
47
+ *
48
+ */ const setLocalStorageItem = (key, value)=>{
49
+ /**
50
+ * If value is a function, call it to get the actual value (supports functional
51
+ * updates).
52
+ */ const stringifiedValue = JSON.stringify(typeof value === "function" ? value() : value);
53
+ window.localStorage.setItem(key, stringifiedValue);
54
+ // Dispatch event to notify other components in the same window/tab.
55
+ dispatchStorageEvent(key, stringifiedValue);
56
+ };
57
+ /**
58
+ * Removes an item from localStorage and dispatches a storage event with null
59
+ * value. This ensures all components using this key are notified of the
60
+ * removal.
61
+ *
62
+ * @param key - The localStorage key to remove
63
+ *
64
+ */ const removeLocalStorageItem = (key)=>{
65
+ window.localStorage.removeItem(key);
66
+ // Dispatch event with null to signal removal.
67
+ dispatchStorageEvent(key, null);
68
+ };
69
+ /**
70
+ * Retrieves an item from localStorage. Returns the raw stringified value or
71
+ * null if the key doesn't exist.
72
+ *
73
+ * @param key - The localStorage key to retrieve
74
+ * @returns The stored string value or null if not found
75
+ *
76
+ */ const getLocalStorageItem = (key)=>{
77
+ return window.localStorage.getItem(key);
78
+ };
79
+ /**
80
+ * Creates a subscription to localStorage changes for use with React's
81
+ * useSyncExternalStore. This function is called by React to set up and tear
82
+ * down event listeners. It listens to both native storage events (from other
83
+ * tabs) and custom dispatched events (from this tab).
84
+ *
85
+ * @param callback - The callback function to invoke when storage changes occur
86
+ * @returns A cleanup function that removes the event listener
87
+ *
88
+ */ const useLocalStorageSubscribe = (callback)=>{
89
+ window.addEventListener("storage", callback);
90
+ // Return cleanup function for React to call on unmount.
91
+ return ()=>window.removeEventListener("storage", callback);
92
+ };
93
+ /**
94
+ * A React hook for managing state synchronized with localStorage. Uses React
95
+ * 19's useSyncExternalStore for optimal concurrent rendering support and
96
+ * automatic synchronization across components. Changes are automatically
97
+ * persisted to localStorage and synchronized across all components using the
98
+ * same key, including across browser tabs.
99
+ *
100
+ * Features:
101
+ * - Automatic serialization/deserialization with JSON
102
+ * - Type-safe with TypeScript generics
103
+ * - Supports functional updates (similar to setState)
104
+ * - Synchronized across components and browser tabs
105
+ * - Handles edge cases (null, undefined, errors)
106
+ * - Compatible with React 19+ concurrent features
107
+ *
108
+ * @template T - The type of the value stored in localStorage
109
+ * @param {StorageProperties<T>} config - Configuration object with key and optional initialValue
110
+ * @returns {[T | null, (value: T | ((current: T) => T)) => void, () => void, () => void]} A tuple containing:
111
+ * - [0] current value from localStorage (or null if not set)
112
+ * - [1] setValue function to update the stored value (supports direct value or function updater)
113
+ * - [2] resetValue function to restore the initialValue
114
+ * - [3] removeValue function to remove the value from localStorage
115
+ *
116
+ * @example
117
+ * ```js
118
+ * // Basic usage with a string value
119
+ * import { useLocalStorage } from '@versini/ui-hooks';
120
+ * const [model, setModel, resetModel, removeModel] = useLocalStorage({
121
+ * key: 'gpt-model',
122
+ * initialValue: 'gpt-3',
123
+ * });
124
+ *
125
+ * // Direct update
126
+ * setModel('gpt-4'); // Stores "gpt-4"
127
+ *
128
+ * // Functional update (receives current value)
129
+ * setModel((current) => (current === 'gpt-3' ? 'gpt-4' : 'gpt-3'));
130
+ *
131
+ * // Reset to initial value
132
+ * resetModel(); // Restores "gpt-3"
133
+ *
134
+ * // Remove from localStorage
135
+ * removeModel(); // Sets value to null and removes from storage
136
+ * ```
137
+ *
138
+ * @example
139
+ * ```js
140
+ * // Usage with complex objects
141
+ * interface UserPreferences {
142
+ * theme: 'light' | 'dark';
143
+ * fontSize: number;
144
+ * }
145
+ *
146
+ * const [prefs, setPrefs] = useLocalStorage<UserPreferences>({
147
+ * key: 'user-preferences',
148
+ * initialValue: { theme: 'light', fontSize: 14 }
149
+ * });
150
+ *
151
+ * // Update specific property
152
+ * setPrefs(current => ({ ...current, theme: 'dark' }));
153
+ * ```
154
+ *
155
+ */ function useLocalStorage({ key, initialValue }) {
156
+ /**
157
+ * Snapshot function for useSyncExternalStore - returns current localStorage
158
+ * value.
159
+ */ const getSnapshot = ()=>getLocalStorageItem(key);
160
+ /**
161
+ * Use React's useSyncExternalStore to subscribe to localStorage changes. This
162
+ * ensures proper integration with React 19+ concurrent rendering and provides
163
+ * automatic re-rendering when the stored value changes (either from this
164
+ * component, other components, or other browser tabs).
165
+ */ const store = useSyncExternalStore(useLocalStorageSubscribe, getSnapshot);
166
+ /**
167
+ * Updates the stored value in localStorage. Accepts either a direct value or a
168
+ * function that receives the current value. Setting to null or undefined will
169
+ * remove the item from localStorage.
170
+ */ const setValue = useCallback((v)=>{
171
+ try {
172
+ // Support both direct values and functional updates.
173
+ const nextState = typeof v === "function" ? v(JSON.parse(store)) : v;
174
+ // Remove from storage if value is null or undefined.
175
+ if (nextState === undefined || nextState === null) {
176
+ removeLocalStorageItem(key);
177
+ } else {
178
+ setLocalStorageItem(key, nextState);
179
+ }
180
+ /* v8 ignore start */ } catch (e) {
181
+ // Log parsing or storage errors without breaking the application.
182
+ console.warn(e);
183
+ }
184
+ /* v8 ignore stop */ }, [
185
+ key,
186
+ store
187
+ ]);
188
+ /**
189
+ * Resets the stored value back to the initialValue provided in the
190
+ * configuration. If no initialValue was provided, this will remove the item
191
+ * from localStorage.
192
+ */ const resetValue = useCallback(()=>{
193
+ setValue(initialValue);
194
+ }, [
195
+ initialValue,
196
+ setValue
197
+ ]);
198
+ /**
199
+ * Removes the value from localStorage entirely. After calling this, the hook
200
+ * will return null until a new value is set.
201
+ */ const removeValue = useCallback(()=>{
202
+ setValue(null);
203
+ }, [
204
+ setValue
205
+ ]);
206
+ /**
207
+ * Initialize localStorage with the initialValue on first mount if the key
208
+ * doesn't exist. This effect only runs once when the component mounts and
209
+ * ensures that the initialValue is persisted to localStorage if no value is
210
+ * currently stored.
211
+ */ useEffect(()=>{
212
+ try {
213
+ // Only set initialValue if key doesn't exist and initialValue is defined.
214
+ if (getLocalStorageItem(key) === null && typeof initialValue !== "undefined") {
215
+ setLocalStorageItem(key, initialValue);
216
+ }
217
+ /* v8 ignore start */ } catch (e) {
218
+ // Log initialization errors without breaking the application.
219
+ console.warn(e);
220
+ }
221
+ /* v8 ignore stop */ }, [
222
+ key,
223
+ initialValue
224
+ ]);
225
+ /**
226
+ * Return tuple: [currentValue, setValue, resetValue, removeValue] Parse the
227
+ * stored JSON string back to its original type, or return null if empty.
228
+ */ return [
229
+ store ? JSON.parse(store) : null,
230
+ setValue,
231
+ resetValue,
232
+ removeValue
233
+ ];
234
+ }
235
+
236
+ export { useLocalStorage };
@@ -0,0 +1,20 @@
1
+ /**
2
+ * React utility to merge refs.
3
+ *
4
+ * When developing low level UI components, it is common to have to use a local
5
+ * ref but also support an external one using React.forwardRef. Natively, React
6
+ * does not offer a way to set two refs inside the ref property.
7
+ *
8
+ * @param Array of refs (object, function, etc.)
9
+ *
10
+ * @example
11
+ *
12
+ * const Example = React.forwardRef(function Example(props, ref) {
13
+ * const localRef = React.useRef();
14
+ * const mergedRefs = useMergeRefs([localRef, ref]);
15
+ *
16
+ * return <div ref={mergedRefs} />;
17
+ * });
18
+ *
19
+ */
20
+ export declare function useMergeRefs<T = any>(refs: Array<React.MutableRefObject<T> | React.LegacyRef<T> | undefined | null>): React.RefCallback<T>;
@@ -0,0 +1,62 @@
1
+ /*!
2
+ @versini/ui-hooks v6.0.1
3
+ © 2025 gizmette.com
4
+ */
5
+ try {
6
+ if (!window.__VERSINI_UI_HOOKS__) {
7
+ window.__VERSINI_UI_HOOKS__ = {
8
+ version: "6.0.1",
9
+ buildTime: "12/24/2025 09:19 AM EST",
10
+ homepage: "https://www.npmjs.com/package/@versini/ui-hooks",
11
+ license: "MIT",
12
+ };
13
+ }
14
+ } catch (error) {
15
+ // nothing to declare officer
16
+ }
17
+
18
+ import { useMemo } from "react";
19
+
20
+ ;// CONCATENATED MODULE: external "react"
21
+
22
+ ;// CONCATENATED MODULE: ./src/hooks/useMergeRefs/useMergeRefs.ts
23
+ /**
24
+ * React utility to merge refs.
25
+ *
26
+ * When developing low level UI components, it is common to have to use a local
27
+ * ref but also support an external one using React.forwardRef. Natively, React
28
+ * does not offer a way to set two refs inside the ref property.
29
+ *
30
+ * @param Array of refs (object, function, etc.)
31
+ *
32
+ * @example
33
+ *
34
+ * const Example = React.forwardRef(function Example(props, ref) {
35
+ * const localRef = React.useRef();
36
+ * const mergedRefs = useMergeRefs([localRef, ref]);
37
+ *
38
+ * return <div ref={mergedRefs} />;
39
+ * });
40
+ *
41
+ */
42
+ function useMergeRefs(refs) {
43
+ // biome-ignore lint/correctness/useExhaustiveDependencies: refs array is used as dependency but spread for proper comparison
44
+ return useMemo(()=>{
45
+ /* v8 ignore start - all refs null edge case */ if (refs.every((ref)=>ref == null)) {
46
+ return ()=>{};
47
+ }
48
+ /* v8 ignore stop */ /* v8 ignore start - ref assignment handling */ return (value)=>{
49
+ refs.forEach((ref)=>{
50
+ if (typeof ref === "function") {
51
+ ref(value);
52
+ } else if (ref != null) {
53
+ ref.current = value;
54
+ }
55
+ });
56
+ };
57
+ /* v8 ignore stop */ }, [
58
+ ...refs
59
+ ]);
60
+ }
61
+
62
+ export { useMergeRefs };
@@ -0,0 +1,17 @@
1
+ type ObserverRect = Omit<DOMRectReadOnly, "toJSON">;
2
+ /**
3
+ * A custom hook that uses the ResizeObserver API to track the size changes of a DOM element.
4
+ *
5
+ * @template T - The type of the DOM element being observed.
6
+ * @param {ResizeObserverOptions} [options] - The options to configure the ResizeObserver.
7
+ * @returns {[React.RefObject<T>, ObserverRect]} - A tuple containing the ref object and
8
+ * the observed rectangle.
9
+ * @example
10
+ *
11
+ * const [rightElementRef, rect] = useResizeObserver<HTMLDivElement>();
12
+ * <div ref={componentRef}>
13
+ * Observed: <code>{JSON.stringify(rect)}</code>
14
+ * </div>
15
+ */
16
+ export declare function useResizeObserver<T extends HTMLElement = any>(options?: ResizeObserverOptions): readonly [import("react").RefObject<T | null>, ObserverRect];
17
+ export {};