@vibehooks/react 0.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 (111) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +101 -0
  3. package/dist/index.d.ts +54 -0
  4. package/dist/index.js +55 -0
  5. package/dist/useAsyncState.d.ts +52 -0
  6. package/dist/useAsyncState.js +173 -0
  7. package/dist/useAudio.d.ts +26 -0
  8. package/dist/useAudio.js +64 -0
  9. package/dist/useAutoScroll.d.ts +47 -0
  10. package/dist/useAutoScroll.js +122 -0
  11. package/dist/useBarcode.d.ts +77 -0
  12. package/dist/useBarcode.js +140 -0
  13. package/dist/useBatteryStatus.d.ts +53 -0
  14. package/dist/useBatteryStatus.js +67 -0
  15. package/dist/useBodyScrollFreeze.d.ts +36 -0
  16. package/dist/useBodyScrollFreeze.js +74 -0
  17. package/dist/useCameraCapture.d.ts +76 -0
  18. package/dist/useCameraCapture.js +116 -0
  19. package/dist/useCookies.d.ts +42 -0
  20. package/dist/useCookies.js +61 -0
  21. package/dist/useCopyToClipboard.d.ts +22 -0
  22. package/dist/useCopyToClipboard.js +31 -0
  23. package/dist/useCountDown.d.ts +80 -0
  24. package/dist/useCountDown.js +106 -0
  25. package/dist/useDebouncedState.d.ts +47 -0
  26. package/dist/useDebouncedState.js +47 -0
  27. package/dist/useExternalNotifications.d.ts +36 -0
  28. package/dist/useExternalNotifications.js +100 -0
  29. package/dist/useFile.d.ts +74 -0
  30. package/dist/useFile.js +74 -0
  31. package/dist/useFullScreen.d.ts +20 -0
  32. package/dist/useFullScreen.js +43 -0
  33. package/dist/useGeolocation.d.ts +47 -0
  34. package/dist/useGeolocation.js +68 -0
  35. package/dist/useHoverIntent.d.ts +45 -0
  36. package/dist/useHoverIntent.js +81 -0
  37. package/dist/useIdle.d.ts +47 -0
  38. package/dist/useIdle.js +59 -0
  39. package/dist/useIndexedDB.d.ts +60 -0
  40. package/dist/useIndexedDB.js +75 -0
  41. package/dist/useIntersectionObserver.d.ts +45 -0
  42. package/dist/useIntersectionObserver.js +70 -0
  43. package/dist/useIntervalSafe.d.ts +72 -0
  44. package/dist/useIntervalSafe.js +85 -0
  45. package/dist/useIsClient.d.ts +12 -0
  46. package/dist/useIsClient.js +21 -0
  47. package/dist/useIsDesktop.d.ts +12 -0
  48. package/dist/useIsDesktop.js +23 -0
  49. package/dist/useIsFirstRender.d.ts +12 -0
  50. package/dist/useIsFirstRender.js +21 -0
  51. package/dist/useList.d.ts +19 -0
  52. package/dist/useList.js +44 -0
  53. package/dist/useLocalNotifications.d.ts +23 -0
  54. package/dist/useLocalNotifications.js +50 -0
  55. package/dist/useLocalStorage.d.ts +45 -0
  56. package/dist/useLocalStorage.js +71 -0
  57. package/dist/useNetworkInformation.d.ts +138 -0
  58. package/dist/useNetworkInformation.js +76 -0
  59. package/dist/useOnline.d.ts +17 -0
  60. package/dist/useOnline.js +29 -0
  61. package/dist/usePageVisibility.d.ts +32 -0
  62. package/dist/usePageVisibility.js +65 -0
  63. package/dist/usePermissions.d.ts +28 -0
  64. package/dist/usePermissions.js +70 -0
  65. package/dist/usePictureInPicture.d.ts +47 -0
  66. package/dist/usePictureInPicture.js +60 -0
  67. package/dist/usePopover.d.ts +54 -0
  68. package/dist/usePopover.js +67 -0
  69. package/dist/usePreferredLanguage.d.ts +55 -0
  70. package/dist/usePreferredLanguage.js +127 -0
  71. package/dist/usePreferredTheme.d.ts +67 -0
  72. package/dist/usePreferredTheme.js +133 -0
  73. package/dist/usePreviousDistinct.d.ts +12 -0
  74. package/dist/usePreviousDistinct.js +23 -0
  75. package/dist/useResettableState.d.ts +15 -0
  76. package/dist/useResettableState.js +25 -0
  77. package/dist/useScreenOrientation.d.ts +48 -0
  78. package/dist/useScreenOrientation.js +51 -0
  79. package/dist/useScreenSize.d.ts +16 -0
  80. package/dist/useScreenSize.js +34 -0
  81. package/dist/useScreenWakeLock.d.ts +37 -0
  82. package/dist/useScreenWakeLock.js +48 -0
  83. package/dist/useServerSentEvent.d.ts +57 -0
  84. package/dist/useServerSentEvent.js +78 -0
  85. package/dist/useShoppingCart.d.ts +54 -0
  86. package/dist/useShoppingCart.js +122 -0
  87. package/dist/useSmartVideo.d.ts +35 -0
  88. package/dist/useSmartVideo.js +76 -0
  89. package/dist/useSpeech.d.ts +74 -0
  90. package/dist/useSpeech.js +156 -0
  91. package/dist/useSummarizer.d.ts +92 -0
  92. package/dist/useSummarizer.js +83 -0
  93. package/dist/useTaskQueue.d.ts +25 -0
  94. package/dist/useTaskQueue.js +51 -0
  95. package/dist/useThrottledCallback.d.ts +32 -0
  96. package/dist/useThrottledCallback.js +42 -0
  97. package/dist/useTimeout.d.ts +58 -0
  98. package/dist/useTimeout.js +70 -0
  99. package/dist/useToggle.d.ts +30 -0
  100. package/dist/useToggle.js +23 -0
  101. package/dist/useTraceUpdates.d.ts +22 -0
  102. package/dist/useTraceUpdates.js +38 -0
  103. package/dist/useTranslator.d.ts +110 -0
  104. package/dist/useTranslator.js +119 -0
  105. package/dist/useUserActivation.d.ts +40 -0
  106. package/dist/useUserActivation.js +63 -0
  107. package/dist/useVibration.d.ts +55 -0
  108. package/dist/useVibration.js +50 -0
  109. package/dist/useWebsocket.d.ts +80 -0
  110. package/dist/useWebsocket.js +125 -0
  111. package/package.json +70 -0
@@ -0,0 +1,45 @@
1
+ import * as React from "react";
2
+
3
+ //#region src/useIntersectionObserver.d.ts
4
+ type IntersectionObserverOptions = IntersectionObserverInit & {
5
+ /**
6
+ * If true, the observer disconnects after the first intersection.
7
+ */
8
+ once?: boolean;
9
+ /**
10
+ * Callback that executes every time the IntersectionObserverEntry changes.
11
+ */
12
+ onChange?: (entry: IntersectionObserverEntry) => void;
13
+ };
14
+ interface IntersectionObserverReturn<T extends Element> {
15
+ /**
16
+ * Last IntersectionObserverEntry.
17
+ */
18
+ entry: IntersectionObserverEntry | null;
19
+ /**
20
+ * Indicates if the element is visible in the viewport.
21
+ */
22
+ isVisible: boolean;
23
+ /**
24
+ * Ref will be assigned to the element that is being observed.
25
+ */
26
+ ref: React.RefObject<T | null>;
27
+ }
28
+ /**
29
+ * `useIntersectionObserver` observers the visibility of an element using the native IntersectionObserver API.
30
+ * Returns a typed `ref` that must be assigned to the element you want to observe.
31
+ *
32
+ * @example
33
+ * ```tsx
34
+ * const { ref, isVisible } = useIntersectionObserver<HTMLDivElement>({
35
+ * threshold: 0.5,
36
+ * once: true,
37
+ * });
38
+ *
39
+ * return <div ref={ref}>{isVisible}</div>;
40
+ * ```
41
+ * @see https://developer.mozilla.org/en-US/docs/Web/API/Intersection_Observer_API
42
+ */
43
+ declare function useIntersectionObserver<T extends Element = HTMLElement>(options?: IntersectionObserverOptions, externalRef?: React.RefObject<T | null>): IntersectionObserverReturn<T>;
44
+ //#endregion
45
+ export { useIntersectionObserver };
@@ -0,0 +1,70 @@
1
+ import * as React from "react";
2
+
3
+ //#region src/useIntersectionObserver.ts
4
+ /**
5
+ * `useIntersectionObserver` observers the visibility of an element using the native IntersectionObserver API.
6
+ * Returns a typed `ref` that must be assigned to the element you want to observe.
7
+ *
8
+ * @example
9
+ * ```tsx
10
+ * const { ref, isVisible } = useIntersectionObserver<HTMLDivElement>({
11
+ * threshold: 0.5,
12
+ * once: true,
13
+ * });
14
+ *
15
+ * return <div ref={ref}>{isVisible}</div>;
16
+ * ```
17
+ * @see https://developer.mozilla.org/en-US/docs/Web/API/Intersection_Observer_API
18
+ */
19
+ function useIntersectionObserver(options, externalRef) {
20
+ const internalRef = React.useRef(null);
21
+ const ref = externalRef ?? internalRef;
22
+ const [entry, setEntry] = React.useState(null);
23
+ const [isVisible, setIsVisible] = React.useState(false);
24
+ const callbackRef = React.useRef(options?.onChange);
25
+ callbackRef.current = options?.onChange;
26
+ const observerOptions = React.useMemo(() => {
27
+ return {
28
+ root: options?.root,
29
+ rootMargin: options?.rootMargin,
30
+ threshold: options?.threshold
31
+ };
32
+ }, [
33
+ options?.root,
34
+ options?.rootMargin,
35
+ options?.threshold
36
+ ]);
37
+ const once = options?.once;
38
+ const onceRef = React.useRef(false);
39
+ React.useEffect(() => {
40
+ if (typeof window === "undefined") return;
41
+ const element = ref.current;
42
+ if (!element) return;
43
+ const observer = new IntersectionObserver((entries, observer$1) => {
44
+ const firstEntry = entries[0];
45
+ if (!firstEntry) return;
46
+ setEntry(firstEntry);
47
+ setIsVisible(firstEntry.isIntersecting);
48
+ callbackRef.current?.(firstEntry);
49
+ if (once && firstEntry.isIntersecting && !onceRef.current) {
50
+ onceRef.current = true;
51
+ observer$1.unobserve(element);
52
+ observer$1.disconnect();
53
+ }
54
+ }, observerOptions);
55
+ observer.observe(element);
56
+ return () => observer.disconnect();
57
+ }, [
58
+ observerOptions,
59
+ ref,
60
+ once
61
+ ]);
62
+ return {
63
+ entry,
64
+ isVisible,
65
+ ref
66
+ };
67
+ }
68
+
69
+ //#endregion
70
+ export { useIntersectionObserver };
@@ -0,0 +1,72 @@
1
+ //#region src/useIntervalSafe.d.ts
2
+ interface UseIntervalOptions {
3
+ /**
4
+ * Delay in milliseconds between each interval execution.
5
+ * If null or undefined, the interval won't be set.
6
+ */
7
+ delay: number | null;
8
+ /**
9
+ * Maximum number of times to execute the callback.
10
+ * If undefined, runs indefinitely until cancelled.
11
+ */
12
+ maxExecutions?: number;
13
+ /**
14
+ * Whether the interval should start immediately on mount.
15
+ * @default true
16
+ */
17
+ startOnMount?: boolean;
18
+ }
19
+ interface UseIntervalReturn {
20
+ /**
21
+ * Cancel the running interval.
22
+ */
23
+ cancel: () => void;
24
+ /**
25
+ * Number of times the callback has been executed.
26
+ */
27
+ executionCount: number;
28
+ /**
29
+ * Whether the interval is currently active.
30
+ */
31
+ isActive: boolean;
32
+ /**
33
+ * Reset the interval (cancel and start again, resetting execution count).
34
+ */
35
+ reset: () => void;
36
+ /**
37
+ * Start or restart the interval.
38
+ */
39
+ start: () => void;
40
+ }
41
+ /**
42
+ * `useInterval` is a custom hook for managing intervals in a declarative way. It's server safe and unopinionated about when/how to trigger the interval.
43
+ *
44
+ * @example
45
+ * ```tsx
46
+ * // Auto-start interval
47
+ * const interval = useInterval(() => {
48
+ * console.log('Executed every 1 second');
49
+ * }, { delay: 1000 });
50
+ *
51
+ * // Manual control with execution limit
52
+ * const interval = useInterval(
53
+ * () => fetchData(),
54
+ * {
55
+ * delay: 5000,
56
+ * startOnMount: false,
57
+ * maxExecutions: 10
58
+ * }
59
+ * );
60
+ *
61
+ * <button onClick={interval.start}>Start Polling</button>
62
+ * <button onClick={interval.cancel}>Stop</button>
63
+ * <span>Polled {interval.executionCount} times</span>
64
+ * ```
65
+ */
66
+ declare function useIntervalSafe(callback: () => void, {
67
+ delay,
68
+ maxExecutions,
69
+ startOnMount
70
+ }: UseIntervalOptions): UseIntervalReturn;
71
+ //#endregion
72
+ export { useIntervalSafe };
@@ -0,0 +1,85 @@
1
+ import * as React from "react";
2
+
3
+ //#region src/useIntervalSafe.ts
4
+ /**
5
+ * `useInterval` is a custom hook for managing intervals in a declarative way. It's server safe and unopinionated about when/how to trigger the interval.
6
+ *
7
+ * @example
8
+ * ```tsx
9
+ * // Auto-start interval
10
+ * const interval = useInterval(() => {
11
+ * console.log('Executed every 1 second');
12
+ * }, { delay: 1000 });
13
+ *
14
+ * // Manual control with execution limit
15
+ * const interval = useInterval(
16
+ * () => fetchData(),
17
+ * {
18
+ * delay: 5000,
19
+ * startOnMount: false,
20
+ * maxExecutions: 10
21
+ * }
22
+ * );
23
+ *
24
+ * <button onClick={interval.start}>Start Polling</button>
25
+ * <button onClick={interval.cancel}>Stop</button>
26
+ * <span>Polled {interval.executionCount} times</span>
27
+ * ```
28
+ */
29
+ function useIntervalSafe(callback, { delay, maxExecutions, startOnMount = true }) {
30
+ const intervalRef = React.useRef(null);
31
+ const callbackRef = React.useRef(callback);
32
+ const executionsRef = React.useRef(0);
33
+ const [isActive, setIsActive] = React.useState(false);
34
+ const [executions, setExecutions] = React.useState(0);
35
+ React.useEffect(() => {
36
+ callbackRef.current = callback;
37
+ }, [callback]);
38
+ const cancel = React.useCallback(() => {
39
+ if (intervalRef.current) {
40
+ clearInterval(intervalRef.current);
41
+ intervalRef.current = null;
42
+ }
43
+ setIsActive(false);
44
+ }, []);
45
+ const tick = React.useCallback(() => {
46
+ if (maxExecutions !== void 0 && executionsRef.current >= maxExecutions) {
47
+ cancel();
48
+ return;
49
+ }
50
+ callbackRef.current();
51
+ executionsRef.current += 1;
52
+ setExecutions(executionsRef.current);
53
+ if (maxExecutions !== void 0 && executionsRef.current >= maxExecutions) cancel();
54
+ }, [cancel, maxExecutions]);
55
+ const start = React.useCallback(() => {
56
+ if (delay == null || intervalRef.current) return;
57
+ executionsRef.current = 0;
58
+ setExecutions(0);
59
+ setIsActive(true);
60
+ intervalRef.current = setInterval(tick, delay);
61
+ }, [
62
+ delay,
63
+ maxExecutions,
64
+ tick
65
+ ]);
66
+ const reset = React.useCallback(() => {
67
+ cancel();
68
+ start();
69
+ }, [cancel, start]);
70
+ React.useEffect(() => {
71
+ if (!startOnMount) return;
72
+ start();
73
+ return cancel;
74
+ }, [startOnMount]);
75
+ return {
76
+ cancel,
77
+ executionCount: executions,
78
+ isActive,
79
+ reset,
80
+ start
81
+ };
82
+ }
83
+
84
+ //#endregion
85
+ export { useIntervalSafe };
@@ -0,0 +1,12 @@
1
+ //#region src/useIsClient.d.ts
2
+ /**
3
+ * `useIsClient` returns true if the code is running in the browser. Otherwise, it returns false if the code is running on the server.
4
+ *
5
+ * @example
6
+ * ```tsx
7
+ * const isClient = useIsClient();
8
+ * ```
9
+ */
10
+ declare function useIsClient(): boolean;
11
+ //#endregion
12
+ export { useIsClient };
@@ -0,0 +1,21 @@
1
+ import * as React from "react";
2
+
3
+ //#region src/useIsClient.ts
4
+ /**
5
+ * `useIsClient` returns true if the code is running in the browser. Otherwise, it returns false if the code is running on the server.
6
+ *
7
+ * @example
8
+ * ```tsx
9
+ * const isClient = useIsClient();
10
+ * ```
11
+ */
12
+ function useIsClient() {
13
+ const [isClient, setIsClient] = React.useState(false);
14
+ React.useEffect(() => {
15
+ setIsClient(true);
16
+ }, []);
17
+ return isClient;
18
+ }
19
+
20
+ //#endregion
21
+ export { useIsClient };
@@ -0,0 +1,12 @@
1
+ //#region src/useIsDesktop.d.ts
2
+ /**
3
+ * `useIsDesktop` returns true if the screen size is greater than or equal to the given width.
4
+ *
5
+ * @example
6
+ * ```tsx
7
+ * const isDesktop = useIsDesktop(1000);
8
+ * ```
9
+ */
10
+ declare function useIsDesktop(width?: number): boolean;
11
+ //#endregion
12
+ export { useIsDesktop };
@@ -0,0 +1,23 @@
1
+ import { useScreenSize } from "./useScreenSize.js";
2
+ import * as React from "react";
3
+
4
+ //#region src/useIsDesktop.ts
5
+ /**
6
+ * `useIsDesktop` returns true if the screen size is greater than or equal to the given width.
7
+ *
8
+ * @example
9
+ * ```tsx
10
+ * const isDesktop = useIsDesktop(1000);
11
+ * ```
12
+ */
13
+ function useIsDesktop(width = 0) {
14
+ const screenSize = useScreenSize();
15
+ const [isDesktop, setIsDesktop] = React.useState(false);
16
+ React.useEffect(() => {
17
+ setIsDesktop(screenSize.width >= width);
18
+ }, [screenSize.width, width]);
19
+ return isDesktop;
20
+ }
21
+
22
+ //#endregion
23
+ export { useIsDesktop };
@@ -0,0 +1,12 @@
1
+ //#region src/useIsFirstRender.d.ts
2
+ /**
3
+ * `useIsFirstRender` returns true if the component is the first render.
4
+ *
5
+ * @example
6
+ * ```tsx
7
+ * const isFirstRender = useIsFirstRender();
8
+ * ```
9
+ */
10
+ declare function useIsFirstRender(): boolean;
11
+ //#endregion
12
+ export { useIsFirstRender };
@@ -0,0 +1,21 @@
1
+ import * as React from "react";
2
+
3
+ //#region src/useIsFirstRender.ts
4
+ /**
5
+ * `useIsFirstRender` returns true if the component is the first render.
6
+ *
7
+ * @example
8
+ * ```tsx
9
+ * const isFirstRender = useIsFirstRender();
10
+ * ```
11
+ */
12
+ function useIsFirstRender() {
13
+ const [isFirst, setIsFirst] = React.useState(true);
14
+ React.useEffect(() => {
15
+ setIsFirst(false);
16
+ }, []);
17
+ return isFirst;
18
+ }
19
+
20
+ //#endregion
21
+ export { useIsFirstRender };
@@ -0,0 +1,19 @@
1
+ //#region src/useList.d.ts
2
+ interface ListReturn<T> {
3
+ insert: (idx: number, item: T) => void;
4
+ items: T[];
5
+ push: (item: T) => void;
6
+ remove: (idx: number) => void;
7
+ update: (idx: number, item: T) => void;
8
+ }
9
+ /**
10
+ * `useList` is a custom hook that allows you to create, update, and delete items in a list.
11
+ *
12
+ * @example
13
+ * ```tsx
14
+ * const { items, insert, push, remove, update } = useList<string>(['item1', 'item2']);
15
+ * ```
16
+ */
17
+ declare function useList<T>(defaultValue?: T[]): ListReturn<T>;
18
+ //#endregion
19
+ export { useList };
@@ -0,0 +1,44 @@
1
+ import * as React from "react";
2
+
3
+ //#region src/useList.ts
4
+ /**
5
+ * `useList` is a custom hook that allows you to create, update, and delete items in a list.
6
+ *
7
+ * @example
8
+ * ```tsx
9
+ * const { items, insert, push, remove, update } = useList<string>(['item1', 'item2']);
10
+ * ```
11
+ */
12
+ function useList(defaultValue = []) {
13
+ const [items, setItems] = React.useState(defaultValue || []);
14
+ return {
15
+ insert: React.useCallback((idx, item) => {
16
+ setItems((prevItems) => {
17
+ const copy = [...prevItems];
18
+ copy.splice(idx, 0, item);
19
+ return copy;
20
+ });
21
+ }, []),
22
+ items,
23
+ push: React.useCallback((item) => {
24
+ setItems((prevItems) => [...prevItems, item]);
25
+ }, []),
26
+ remove: React.useCallback((idx) => {
27
+ setItems((prevItems) => {
28
+ const copy = [...prevItems];
29
+ copy.splice(idx, 1);
30
+ return copy;
31
+ });
32
+ }, []),
33
+ update: React.useCallback((idx, item) => {
34
+ setItems((prevItems) => {
35
+ const copy = [...prevItems];
36
+ copy[idx] = item;
37
+ return copy;
38
+ });
39
+ }, [])
40
+ };
41
+ }
42
+
43
+ //#endregion
44
+ export { useList };
@@ -0,0 +1,23 @@
1
+ //#region src/useLocalNotifications.d.ts
2
+ interface UseLocalNotificationReturn {
3
+ isSupported: boolean;
4
+ notify: (options: UseNotificationOptions) => void;
5
+ permission: NotificationPermission;
6
+ requestPermission: () => Promise<NotificationPermission>;
7
+ }
8
+ interface UseNotificationOptions extends NotificationOptions {
9
+ title: string;
10
+ }
11
+ /**
12
+ * `useLocalNotifications` is React hook for managing local notifications in the browser.
13
+ *
14
+ * @example
15
+ * ```tsx
16
+ * const { notify, requestPermission, permission } = useNotifications();
17
+ * notify({ title: 'Hello', body: 'World' });
18
+ * ```
19
+ * @see https://developer.mozilla.org/en-US/docs/Web/API/Notification
20
+ */
21
+ declare function useLocalNotifications(): UseLocalNotificationReturn;
22
+ //#endregion
23
+ export { useLocalNotifications };
@@ -0,0 +1,50 @@
1
+ import * as React from "react";
2
+
3
+ //#region src/useLocalNotifications.ts
4
+ /**
5
+ * `useLocalNotifications` is React hook for managing local notifications in the browser.
6
+ *
7
+ * @example
8
+ * ```tsx
9
+ * const { notify, requestPermission, permission } = useNotifications();
10
+ * notify({ title: 'Hello', body: 'World' });
11
+ * ```
12
+ * @see https://developer.mozilla.org/en-US/docs/Web/API/Notification
13
+ */
14
+ function useLocalNotifications() {
15
+ const [permission, setPermission] = React.useState(typeof window !== "undefined" && "Notification" in window ? Notification.permission : "default");
16
+ const isSupported = typeof window !== "undefined" && "Notification" in window;
17
+ const requestPermission = React.useCallback(async () => {
18
+ if (!isSupported) return "denied";
19
+ const result = await Notification.requestPermission();
20
+ setPermission(result);
21
+ return result;
22
+ }, [isSupported]);
23
+ return {
24
+ isSupported,
25
+ notify: React.useCallback(({ badge, body, data, dir, icon, lang, requireInteraction, silent, tag, title }) => {
26
+ if (!isSupported) return;
27
+ if (permission !== "granted") {
28
+ console.warn("Notifications are not allowed.");
29
+ return;
30
+ }
31
+ const options = {
32
+ ...badge !== void 0 && { badge },
33
+ ...body !== void 0 && { body },
34
+ ...data !== void 0 && { data },
35
+ ...dir !== void 0 && { dir },
36
+ ...icon !== void 0 && { icon },
37
+ ...lang !== void 0 && { lang },
38
+ ...requireInteraction !== void 0 && { requireInteraction },
39
+ ...silent !== void 0 && { silent },
40
+ ...tag !== void 0 && { tag }
41
+ };
42
+ new Notification(title, options);
43
+ }, [permission, isSupported]),
44
+ permission,
45
+ requestPermission
46
+ };
47
+ }
48
+
49
+ //#endregion
50
+ export { useLocalNotifications };
@@ -0,0 +1,45 @@
1
+ //#region src/useLocalStorage.d.ts
2
+ interface UseLocalStorageOptions<T> {
3
+ /**
4
+ * Fallback value returned when the key does not exist or parsing fails.
5
+ */
6
+ fallback: T;
7
+ }
8
+ interface UseLocalStorageReturn<T> {
9
+ /**
10
+ * Removes the key from localStorage.
11
+ */
12
+ remove(): void;
13
+ /**
14
+ * Serializes and stores a value in localStorage.
15
+ */
16
+ set(value: T): void;
17
+ /**
18
+ * Updates the stored value using a functional updater.
19
+ */
20
+ update(updater: (prev: T | null) => T): void;
21
+ /**
22
+ * The current value of the key.
23
+ */
24
+ value: T;
25
+ }
26
+ /**
27
+ * `useLocalStorage` is a React hook that provides a typed, unopinionated API for interacting with `window.localStorage`.
28
+ *
29
+ * @example
30
+ * ```tsx
31
+ * const storage = useLocalStorage<User>('user', {
32
+ * fallback: null,
33
+ * });
34
+ *
35
+ * const saveUser = () => {
36
+ * storage.set({ id: '1', name: 'Sebas' });
37
+ * };
38
+ *
39
+ * const user = storage.get();
40
+ * ```
41
+ * @see https://developer.mozilla.org/es/docs/Web/API/Window/localStorage
42
+ */
43
+ declare function useLocalStorage<T>(key: string, options: UseLocalStorageOptions<T>): UseLocalStorageReturn<T>;
44
+ //#endregion
45
+ export { useLocalStorage };
@@ -0,0 +1,71 @@
1
+ import * as React from "react";
2
+
3
+ //#region src/useLocalStorage.ts
4
+ const listeners = /* @__PURE__ */ new Set();
5
+ const cache = /* @__PURE__ */ new Map();
6
+ function emit() {
7
+ listeners.forEach((listener) => listener());
8
+ }
9
+ function subscribe(listener) {
10
+ listeners.add(listener);
11
+ return () => {
12
+ listeners.delete(listener);
13
+ };
14
+ }
15
+ function readFromStorage(key, fallback) {
16
+ if (typeof window === "undefined") return fallback;
17
+ try {
18
+ const raw = window.localStorage.getItem(key);
19
+ return raw === null ? fallback : JSON.parse(raw);
20
+ } catch {
21
+ return fallback;
22
+ }
23
+ }
24
+ /**
25
+ * `useLocalStorage` is a React hook that provides a typed, unopinionated API for interacting with `window.localStorage`.
26
+ *
27
+ * @example
28
+ * ```tsx
29
+ * const storage = useLocalStorage<User>('user', {
30
+ * fallback: null,
31
+ * });
32
+ *
33
+ * const saveUser = () => {
34
+ * storage.set({ id: '1', name: 'Sebas' });
35
+ * };
36
+ *
37
+ * const user = storage.get();
38
+ * ```
39
+ * @see https://developer.mozilla.org/es/docs/Web/API/Window/localStorage
40
+ */
41
+ function useLocalStorage(key, options) {
42
+ const { fallback } = options;
43
+ const getSnapshot = React.useCallback(() => {
44
+ if (!cache.has(key)) cache.set(key, readFromStorage(key, fallback));
45
+ return cache.get(key);
46
+ }, [key, fallback]);
47
+ const value = React.useSyncExternalStore(subscribe, getSnapshot, () => fallback);
48
+ const set = React.useCallback((next) => {
49
+ if (typeof window === "undefined") return;
50
+ cache.set(key, next);
51
+ window.localStorage.setItem(key, JSON.stringify(next));
52
+ emit();
53
+ }, [key]);
54
+ const update = React.useCallback((updater) => {
55
+ set(updater(value));
56
+ }, [value, set]);
57
+ return {
58
+ remove: React.useCallback(() => {
59
+ if (typeof window === "undefined") return;
60
+ cache.delete(key);
61
+ window.localStorage.removeItem(key);
62
+ emit();
63
+ }, [key]),
64
+ set,
65
+ update,
66
+ value
67
+ };
68
+ }
69
+
70
+ //#endregion
71
+ export { useLocalStorage };