@versini/ui-hooks 5.2.0 → 5.3.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.
package/dist/index.d.ts CHANGED
@@ -18,13 +18,21 @@ declare type ObserverRect = Omit<DOMRectReadOnly, "toJSON">;
18
18
 
19
19
  export declare function shouldFireEvent(event: KeyboardEvent, tagsToIgnore: string[], triggerOnContentEditable?: boolean): boolean;
20
20
 
21
+ /**
22
+ * Configuration properties for the useLocalStorage hook.
23
+ *
24
+ * @template T - The type of the value stored in localStorage
25
+ *
26
+ */
21
27
  export declare interface StorageProperties<T> {
22
28
  /**
23
- * Storage key.
29
+ * The localStorage key under which the value will be stored. Must be unique
30
+ * within your application to avoid conflicts.
24
31
  */
25
32
  key: string;
26
33
  /**
27
- * Default value that will be set if value is not found in storage.
34
+ * Optional default value that will be set in localStorage if no value exists.
35
+ * This value will be used on initial mount and when resetValue() is called.
28
36
  */
29
37
  initialValue?: T;
30
38
  }
@@ -47,6 +55,39 @@ export declare interface StorageProperties<T> {
47
55
  */
48
56
  export declare function useClickOutside<T extends HTMLElement = any>(handler: () => void, events?: string[] | null, nodes?: (HTMLElement | null)[]): RefObject<T | null>;
49
57
 
58
+ /**
59
+ * Custom hook for trapping focus within a container element. Implements W3C
60
+ * WAI-ARIA dialog focus management patterns:
61
+ * - Tab/Shift+Tab cycles through focusable elements within the container
62
+ * - Focus is trapped and cannot escape to elements outside
63
+ * - Initial focus is set based on the initialFocus option
64
+ *
65
+ * @see https://www.w3.org/WAI/ARIA/apg/patterns/dialog-modal/
66
+ *
67
+ */
68
+ export declare function useFocusTrap({ enabled, initialFocus, }: UseFocusTrapOptions): UseFocusTrapReturn;
69
+
70
+ declare interface UseFocusTrapOptions {
71
+ /**
72
+ * Whether the focus trap is active.
73
+ */
74
+ enabled: boolean;
75
+ /**
76
+ * Which element to initially focus when the trap activates. Can be a number
77
+ * (tabbable index, 0 = first), a ref to an element, or -1 to disable initial
78
+ * focus.
79
+ * @default 0
80
+ */
81
+ initialFocus?: number | React.RefObject<HTMLElement | null>;
82
+ }
83
+
84
+ declare interface UseFocusTrapReturn {
85
+ /**
86
+ * Ref to attach to the container element that should trap focus.
87
+ */
88
+ containerRef: React.RefObject<HTMLDivElement | null>;
89
+ }
90
+
50
91
  /**
51
92
  * Custom hook providing imperative haptic feedback for mobile devices. Uses
52
93
  * navigator.vibrate when available, falls back to iOS switch element trick for
@@ -122,18 +163,67 @@ export declare function useInViewport<T extends HTMLElement = any>(): {
122
163
  export declare function useIsMounted(): () => boolean;
123
164
 
124
165
  /**
166
+ * A React hook for managing state synchronized with localStorage. Uses React
167
+ * 19's useSyncExternalStore for optimal concurrent rendering support and
168
+ * automatic synchronization across components. Changes are automatically
169
+ * persisted to localStorage and synchronized across all components using the
170
+ * same key, including across browser tabs.
171
+ *
172
+ * Features:
173
+ * - Automatic serialization/deserialization with JSON
174
+ * - Type-safe with TypeScript generics
175
+ * - Supports functional updates (similar to setState)
176
+ * - Synchronized across components and browser tabs
177
+ * - Handles edge cases (null, undefined, errors)
178
+ * - Compatible with React 19+ concurrent features
179
+ *
180
+ * @template T - The type of the value stored in localStorage
181
+ * @param {StorageProperties<T>} config - Configuration object with key and optional initialValue
182
+ * @returns {[T | null, (value: T | ((current: T) => T)) => void, () => void, () => void]} A tuple containing:
183
+ * - [0] current value from localStorage (or null if not set)
184
+ * - [1] setValue function to update the stored value (supports direct value or function updater)
185
+ * - [2] resetValue function to restore the initialValue
186
+ * - [3] removeValue function to remove the value from localStorage
125
187
  *
126
188
  * @example
189
+ * ```js
190
+ * // Basic usage with a string value
127
191
  * import { useLocalStorage } from '@versini/ui-hooks';
128
- * const [value, setValue, resetValue, removeValue] = useLocalStorage({
192
+ * const [model, setModel, resetModel, removeModel] = useLocalStorage({
129
193
  * key: 'gpt-model',
130
194
  * initialValue: 'gpt-3',
131
195
  * });
132
196
  *
133
- * setValue('gpt-4'); ==> "gpt-4"
134
- * setValue((current) => (current === 'gpt-3' ? 'gpt-4' : 'gpt-3'));
135
- * resetValue(); ==> "gpt-3"
136
- * removeValue(); ==> null
197
+ * // Direct update
198
+ * setModel('gpt-4'); // Stores "gpt-4"
199
+ *
200
+ * // Functional update (receives current value)
201
+ * setModel((current) => (current === 'gpt-3' ? 'gpt-4' : 'gpt-3'));
202
+ *
203
+ * // Reset to initial value
204
+ * resetModel(); // Restores "gpt-3"
205
+ *
206
+ * // Remove from localStorage
207
+ * removeModel(); // Sets value to null and removes from storage
208
+ * ```
209
+ *
210
+ * @example
211
+ * ```js
212
+ * // Usage with complex objects
213
+ * interface UserPreferences {
214
+ * theme: 'light' | 'dark';
215
+ * fontSize: number;
216
+ * }
217
+ *
218
+ * const [prefs, setPrefs] = useLocalStorage<UserPreferences>({
219
+ * key: 'user-preferences',
220
+ * initialValue: { theme: 'light', fontSize: 14 }
221
+ * });
222
+ *
223
+ * // Update specific property
224
+ * setPrefs(current => ({ ...current, theme: 'dark' }));
225
+ * ```
226
+ *
137
227
  */
138
228
  export declare function useLocalStorage<T>({ key, initialValue, }: StorageProperties<T>): any[];
139
229
 
package/dist/index.js CHANGED
@@ -1,13 +1,13 @@
1
1
  /*!
2
- @versini/ui-hooks v5.2.0
2
+ @versini/ui-hooks v5.3.1
3
3
  © 2025 gizmette.com
4
4
  */
5
5
  try {
6
6
  if (!window.__VERSINI_UI_HOOKS__) {
7
7
  window.__VERSINI_UI_HOOKS__ = {
8
- version: "5.2.0",
9
- buildTime: "11/04/2025 03:42 PM EST",
10
- homepage: "https://github.com/aversini/ui-components",
8
+ version: "5.3.1",
9
+ buildTime: "12/15/2025 06:38 PM EST",
10
+ homepage: "https://www.npmjs.com/package/@versini/ui-hooks",
11
11
  license: "MIT",
12
12
  };
13
13
  }
@@ -65,6 +65,160 @@ const DEFAULT_EVENTS = [
65
65
  return ref;
66
66
  }
67
67
 
68
+ ;// CONCATENATED MODULE: ./src/hooks/useFocusTrap.ts
69
+
70
+ /**
71
+ * Selector for all focusable elements within a container. Based on W3C WAI-ARIA
72
+ * practices for dialog focus management.
73
+ */ const FOCUSABLE_SELECTOR = [
74
+ 'a[href]:not([disabled]):not([tabindex="-1"])',
75
+ 'button:not([disabled]):not([tabindex="-1"])',
76
+ 'textarea:not([disabled]):not([tabindex="-1"])',
77
+ 'input:not([disabled]):not([tabindex="-1"])',
78
+ 'select:not([disabled]):not([tabindex="-1"])',
79
+ '[tabindex]:not([tabindex="-1"]):not([disabled])',
80
+ 'audio[controls]:not([tabindex="-1"])',
81
+ 'video[controls]:not([tabindex="-1"])',
82
+ 'details:not([tabindex="-1"])'
83
+ ].join(", ");
84
+ /**
85
+ * Custom hook for trapping focus within a container element. Implements W3C
86
+ * WAI-ARIA dialog focus management patterns:
87
+ * - Tab/Shift+Tab cycles through focusable elements within the container
88
+ * - Focus is trapped and cannot escape to elements outside
89
+ * - Initial focus is set based on the initialFocus option
90
+ *
91
+ * @see https://www.w3.org/WAI/ARIA/apg/patterns/dialog-modal/
92
+ *
93
+ */ function useFocusTrap({ enabled, initialFocus = 0 }) {
94
+ const containerRef = useRef(null);
95
+ const previouslyFocusedRef = useRef(null);
96
+ /**
97
+ * Get all focusable elements within the container.
98
+ */ const getFocusableElements = useCallback(()=>{
99
+ /* c8 ignore next 3 - defensive check, containerRef is always set when enabled */ if (!containerRef.current) {
100
+ return [];
101
+ }
102
+ const elements = containerRef.current.querySelectorAll(FOCUSABLE_SELECTOR);
103
+ return Array.from(elements).filter((el)=>el.offsetParent !== null);
104
+ }, []);
105
+ /**
106
+ * Focus a specific element by index, or the element referenced by a ref.
107
+ */ const focusElement = useCallback((target)=>{
108
+ if (typeof target === "number") {
109
+ if (target === -1) {
110
+ // -1 means don't focus anything.
111
+ return;
112
+ }
113
+ const focusableElements = getFocusableElements();
114
+ if (focusableElements.length > 0) {
115
+ const index = Math.min(target, focusableElements.length - 1);
116
+ focusableElements[index]?.focus();
117
+ }
118
+ } else if (target?.current) {
119
+ target.current.focus();
120
+ }
121
+ }, [
122
+ getFocusableElements
123
+ ]);
124
+ /**
125
+ * Handle keyboard events for focus trapping. Tab cycles forward, Shift+Tab
126
+ * cycles backward.
127
+ */ const handleKeyDown = useCallback((event)=>{
128
+ if (event.key !== "Tab" || !containerRef.current) {
129
+ return;
130
+ }
131
+ const activeElement = document.activeElement;
132
+ // If focus is in a nested dialog or menu, let that element handle Tab.
133
+ if (activeElement && !containerRef.current.contains(activeElement) && activeElement.closest('[role="dialog"], [role="menu"]')) {
134
+ return;
135
+ }
136
+ const focusableElements = getFocusableElements();
137
+ if (focusableElements.length === 0) {
138
+ event.preventDefault();
139
+ return;
140
+ }
141
+ const firstElement = focusableElements[0];
142
+ const lastElement = focusableElements[focusableElements.length - 1];
143
+ // Shift+Tab from first element -> go to last.
144
+ if (event.shiftKey && activeElement === firstElement) {
145
+ event.preventDefault();
146
+ lastElement?.focus();
147
+ return;
148
+ }
149
+ // Tab from last element -> go to first.
150
+ if (!event.shiftKey && activeElement === lastElement) {
151
+ event.preventDefault();
152
+ firstElement?.focus();
153
+ return;
154
+ }
155
+ /* c8 ignore next 9 - defensive check for focus escaping, hard to trigger in tests */ // If focus is outside the container, bring it back.
156
+ if (!containerRef.current.contains(activeElement)) {
157
+ event.preventDefault();
158
+ if (event.shiftKey) {
159
+ lastElement?.focus();
160
+ } else {
161
+ firstElement?.focus();
162
+ }
163
+ }
164
+ }, [
165
+ getFocusableElements
166
+ ]);
167
+ /**
168
+ * Handle focus events to ensure focus stays within the container. This catches
169
+ * focus that escapes via mouse clicks or other means.
170
+ */ const handleFocusIn = useCallback((event)=>{
171
+ if (!containerRef.current || containerRef.current.contains(event.target)) {
172
+ return;
173
+ }
174
+ // Allow focus to go to nested dialogs (child panels) or menus (dropdown menus).
175
+ const target = event.target;
176
+ if (target?.closest('[role="dialog"], [role="menu"]')) {
177
+ return;
178
+ }
179
+ // Focus escaped the container, bring it back.
180
+ const focusableElements = getFocusableElements();
181
+ if (focusableElements.length > 0) {
182
+ focusableElements[0]?.focus();
183
+ }
184
+ }, [
185
+ getFocusableElements
186
+ ]);
187
+ // Set up focus trap when enabled.
188
+ useEffect(()=>{
189
+ if (!enabled) {
190
+ return;
191
+ }
192
+ // Store the currently focused element to restore later.
193
+ previouslyFocusedRef.current = document.activeElement;
194
+ // Set initial focus after a small delay to ensure the DOM is ready.
195
+ const focusTimer = setTimeout(()=>{
196
+ focusElement(initialFocus);
197
+ }, 0);
198
+ // Add event listeners for focus trapping.
199
+ document.addEventListener("keydown", handleKeyDown);
200
+ document.addEventListener("focusin", handleFocusIn);
201
+ return ()=>{
202
+ clearTimeout(focusTimer);
203
+ document.removeEventListener("keydown", handleKeyDown);
204
+ document.removeEventListener("focusin", handleFocusIn);
205
+ // Restore focus to the previously focused element if it's still in the DOM.
206
+ if (previouslyFocusedRef.current?.isConnected) {
207
+ previouslyFocusedRef.current.focus();
208
+ }
209
+ };
210
+ }, [
211
+ enabled,
212
+ initialFocus,
213
+ focusElement,
214
+ handleKeyDown,
215
+ handleFocusIn
216
+ ]);
217
+ return {
218
+ containerRef
219
+ };
220
+ }
221
+
68
222
  ;// CONCATENATED MODULE: ./src/hooks/useHaptic.ts
69
223
 
70
224
  const HAPTIC_DURATION_MS = 50;
@@ -460,83 +614,211 @@ function useHotkeys(hotkeys, tagsToIgnore = [
460
614
 
461
615
  ;// CONCATENATED MODULE: ./src/hooks/useLocalStorage.ts
462
616
 
463
- function dispatchStorageEvent(key, newValue) {
617
+ /**
618
+ * Dispatches a custom storage event to notify other parts of the application
619
+ * about localStorage changes. This is necessary because the native storage
620
+ * event only fires in other tabs/windows, not in the current one. By manually
621
+ * dispatching the event, we ensure that all components using the same key stay
622
+ * synchronized.
623
+ *
624
+ * @param key - The localStorage key that was modified
625
+ * @param newValue - The new value (stringified) or null if the item was removed
626
+ *
627
+ */ function dispatchStorageEvent(key, newValue) {
464
628
  window.dispatchEvent(new StorageEvent("storage", {
465
629
  key,
466
630
  newValue
467
631
  }));
468
632
  }
469
- const setLocalStorageItem = (key, value)=>{
470
- const stringifiedValue = JSON.stringify(typeof value === "function" ? value() : value);
633
+ /**
634
+ * Sets an item in localStorage and dispatches a storage event. Handles both
635
+ * direct values and function updaters (similar to React's setState). Values are
636
+ * automatically serialized to JSON before storage.
637
+ *
638
+ * @param key - The localStorage key to set
639
+ * @param value - The value to store, or a function that returns the value to store
640
+ *
641
+ */ const setLocalStorageItem = (key, value)=>{
642
+ /**
643
+ * If value is a function, call it to get the actual value (supports functional
644
+ * updates).
645
+ */ const stringifiedValue = JSON.stringify(typeof value === "function" ? value() : value);
471
646
  window.localStorage.setItem(key, stringifiedValue);
647
+ // Dispatch event to notify other components in the same window/tab.
472
648
  dispatchStorageEvent(key, stringifiedValue);
473
649
  };
474
- const removeLocalStorageItem = (key)=>{
650
+ /**
651
+ * Removes an item from localStorage and dispatches a storage event with null
652
+ * value. This ensures all components using this key are notified of the
653
+ * removal.
654
+ *
655
+ * @param key - The localStorage key to remove
656
+ *
657
+ */ const removeLocalStorageItem = (key)=>{
475
658
  window.localStorage.removeItem(key);
659
+ // Dispatch event with null to signal removal.
476
660
  dispatchStorageEvent(key, null);
477
661
  };
478
- const getLocalStorageItem = (key)=>{
662
+ /**
663
+ * Retrieves an item from localStorage. Returns the raw stringified value or
664
+ * null if the key doesn't exist.
665
+ *
666
+ * @param key - The localStorage key to retrieve
667
+ * @returns The stored string value or null if not found
668
+ *
669
+ */ const getLocalStorageItem = (key)=>{
479
670
  return window.localStorage.getItem(key);
480
671
  };
481
- const useLocalStorageSubscribe = (callback)=>{
672
+ /**
673
+ * Creates a subscription to localStorage changes for use with React's
674
+ * useSyncExternalStore. This function is called by React to set up and tear
675
+ * down event listeners. It listens to both native storage events (from other
676
+ * tabs) and custom dispatched events (from this tab).
677
+ *
678
+ * @param callback - The callback function to invoke when storage changes occur
679
+ * @returns A cleanup function that removes the event listener
680
+ *
681
+ */ const useLocalStorageSubscribe = (callback)=>{
482
682
  window.addEventListener("storage", callback);
683
+ // Return cleanup function for React to call on unmount.
483
684
  return ()=>window.removeEventListener("storage", callback);
484
685
  };
485
686
  /**
687
+ * A React hook for managing state synchronized with localStorage. Uses React
688
+ * 19's useSyncExternalStore for optimal concurrent rendering support and
689
+ * automatic synchronization across components. Changes are automatically
690
+ * persisted to localStorage and synchronized across all components using the
691
+ * same key, including across browser tabs.
692
+ *
693
+ * Features:
694
+ * - Automatic serialization/deserialization with JSON
695
+ * - Type-safe with TypeScript generics
696
+ * - Supports functional updates (similar to setState)
697
+ * - Synchronized across components and browser tabs
698
+ * - Handles edge cases (null, undefined, errors)
699
+ * - Compatible with React 19+ concurrent features
700
+ *
701
+ * @template T - The type of the value stored in localStorage
702
+ * @param {StorageProperties<T>} config - Configuration object with key and optional initialValue
703
+ * @returns {[T | null, (value: T | ((current: T) => T)) => void, () => void, () => void]} A tuple containing:
704
+ * - [0] current value from localStorage (or null if not set)
705
+ * - [1] setValue function to update the stored value (supports direct value or function updater)
706
+ * - [2] resetValue function to restore the initialValue
707
+ * - [3] removeValue function to remove the value from localStorage
486
708
  *
487
709
  * @example
710
+ * ```js
711
+ * // Basic usage with a string value
488
712
  * import { useLocalStorage } from '@versini/ui-hooks';
489
- * const [value, setValue, resetValue, removeValue] = useLocalStorage({
713
+ * const [model, setModel, resetModel, removeModel] = useLocalStorage({
490
714
  * key: 'gpt-model',
491
715
  * initialValue: 'gpt-3',
492
716
  * });
493
717
  *
494
- * setValue('gpt-4'); ==> "gpt-4"
495
- * setValue((current) => (current === 'gpt-3' ? 'gpt-4' : 'gpt-3'));
496
- * resetValue(); ==> "gpt-3"
497
- * removeValue(); ==> null
718
+ * // Direct update
719
+ * setModel('gpt-4'); // Stores "gpt-4"
720
+ *
721
+ * // Functional update (receives current value)
722
+ * setModel((current) => (current === 'gpt-3' ? 'gpt-4' : 'gpt-3'));
723
+ *
724
+ * // Reset to initial value
725
+ * resetModel(); // Restores "gpt-3"
726
+ *
727
+ * // Remove from localStorage
728
+ * removeModel(); // Sets value to null and removes from storage
729
+ * ```
730
+ *
731
+ * @example
732
+ * ```js
733
+ * // Usage with complex objects
734
+ * interface UserPreferences {
735
+ * theme: 'light' | 'dark';
736
+ * fontSize: number;
737
+ * }
738
+ *
739
+ * const [prefs, setPrefs] = useLocalStorage<UserPreferences>({
740
+ * key: 'user-preferences',
741
+ * initialValue: { theme: 'light', fontSize: 14 }
742
+ * });
743
+ *
744
+ * // Update specific property
745
+ * setPrefs(current => ({ ...current, theme: 'dark' }));
746
+ * ```
747
+ *
498
748
  */ function useLocalStorage({ key, initialValue }) {
499
- const getSnapshot = ()=>getLocalStorageItem(key);
500
- const store = useSyncExternalStore(useLocalStorageSubscribe, getSnapshot);
501
- const setValue = useCallback((v)=>{
749
+ /**
750
+ * Snapshot function for useSyncExternalStore - returns current localStorage
751
+ * value.
752
+ */ const getSnapshot = ()=>getLocalStorageItem(key);
753
+ /**
754
+ * Use React's useSyncExternalStore to subscribe to localStorage changes. This
755
+ * ensures proper integration with React 19+ concurrent rendering and provides
756
+ * automatic re-rendering when the stored value changes (either from this
757
+ * component, other components, or other browser tabs).
758
+ */ const store = useSyncExternalStore(useLocalStorageSubscribe, getSnapshot);
759
+ /**
760
+ * Updates the stored value in localStorage. Accepts either a direct value or a
761
+ * function that receives the current value. Setting to null or undefined will
762
+ * remove the item from localStorage.
763
+ */ const setValue = useCallback((v)=>{
502
764
  try {
765
+ // Support both direct values and functional updates.
503
766
  const nextState = typeof v === "function" ? v(JSON.parse(store)) : v;
767
+ // Remove from storage if value is null or undefined.
504
768
  if (nextState === undefined || nextState === null) {
505
769
  removeLocalStorageItem(key);
506
770
  } else {
507
771
  setLocalStorageItem(key, nextState);
508
772
  }
509
- /* v8 ignore next 3 */ } catch (e) {
773
+ /* v8 ignore next 4 */ } catch (e) {
774
+ // Log parsing or storage errors without breaking the application.
510
775
  console.warn(e);
511
776
  }
512
777
  }, [
513
778
  key,
514
779
  store
515
780
  ]);
516
- const resetValue = useCallback(()=>{
781
+ /**
782
+ * Resets the stored value back to the initialValue provided in the
783
+ * configuration. If no initialValue was provided, this will remove the item
784
+ * from localStorage.
785
+ */ const resetValue = useCallback(()=>{
517
786
  setValue(initialValue);
518
787
  }, [
519
788
  initialValue,
520
789
  setValue
521
790
  ]);
522
- const removeValue = useCallback(()=>{
791
+ /**
792
+ * Removes the value from localStorage entirely. After calling this, the hook
793
+ * will return null until a new value is set.
794
+ */ const removeValue = useCallback(()=>{
523
795
  setValue(null);
524
796
  }, [
525
797
  setValue
526
798
  ]);
527
- useEffect(()=>{
799
+ /**
800
+ * Initialize localStorage with the initialValue on first mount if the key
801
+ * doesn't exist. This effect only runs once when the component mounts and
802
+ * ensures that the initialValue is persisted to localStorage if no value is
803
+ * currently stored.
804
+ */ useEffect(()=>{
528
805
  try {
806
+ // Only set initialValue if key doesn't exist and initialValue is defined.
529
807
  if (getLocalStorageItem(key) === null && typeof initialValue !== "undefined") {
530
808
  setLocalStorageItem(key, initialValue);
531
809
  }
532
- /* v8 ignore next 3 */ } catch (e) {
810
+ /* v8 ignore next 4 */ } catch (e) {
811
+ // Log initialization errors without breaking the application.
533
812
  console.warn(e);
534
813
  }
535
814
  }, [
536
815
  key,
537
816
  initialValue
538
817
  ]);
539
- return [
818
+ /**
819
+ * Return tuple: [currentValue, setValue, resetValue, removeValue] Parse the
820
+ * stored JSON string back to its original type, or return null if empty.
821
+ */ return [
540
822
  store ? JSON.parse(store) : null,
541
823
  setValue,
542
824
  resetValue,
@@ -827,4 +1109,5 @@ function useWindowEvent(type, listener) {
827
1109
 
828
1110
 
829
1111
 
830
- export { getHotkeyHandler, shouldFireEvent, useClickOutside, useHaptic, useHotkeys, useInViewport, useInterval, useIsMounted, useLocalStorage, useMergeRefs, useResizeObserver, useUncontrolled, useUniqueId, useViewportSize, useVisualViewportSize };
1112
+
1113
+ export { getHotkeyHandler, shouldFireEvent, useClickOutside, useFocusTrap, useHaptic, useHotkeys, useInViewport, useInterval, useIsMounted, useLocalStorage, useMergeRefs, useResizeObserver, useUncontrolled, useUniqueId, useViewportSize, useVisualViewportSize };
package/package.json CHANGED
@@ -1,12 +1,12 @@
1
1
  {
2
2
  "name": "@versini/ui-hooks",
3
- "version": "5.2.0",
3
+ "version": "5.3.1",
4
4
  "license": "MIT",
5
5
  "author": "Arno Versini",
6
6
  "publishConfig": {
7
7
  "access": "public"
8
8
  },
9
- "homepage": "https://github.com/aversini/ui-components",
9
+ "homepage": "https://www.npmjs.com/package/@versini/ui-hooks",
10
10
  "repository": {
11
11
  "type": "git",
12
12
  "url": "git@github.com:aversini/ui-components.git"
@@ -36,5 +36,5 @@
36
36
  "test:watch": "vitest",
37
37
  "test": "vitest run"
38
38
  },
39
- "gitHead": "7484ad443b77ef31e52ae3a7d88b8129bc6cdf1d"
39
+ "gitHead": "e525a00f1bf7288dffb5c49451e075cedc22aaa0"
40
40
  }