@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.
- package/LICENSE +21 -0
- package/README.md +101 -0
- package/dist/index.d.ts +54 -0
- package/dist/index.js +55 -0
- package/dist/useAsyncState.d.ts +52 -0
- package/dist/useAsyncState.js +173 -0
- package/dist/useAudio.d.ts +26 -0
- package/dist/useAudio.js +64 -0
- package/dist/useAutoScroll.d.ts +47 -0
- package/dist/useAutoScroll.js +122 -0
- package/dist/useBarcode.d.ts +77 -0
- package/dist/useBarcode.js +140 -0
- package/dist/useBatteryStatus.d.ts +53 -0
- package/dist/useBatteryStatus.js +67 -0
- package/dist/useBodyScrollFreeze.d.ts +36 -0
- package/dist/useBodyScrollFreeze.js +74 -0
- package/dist/useCameraCapture.d.ts +76 -0
- package/dist/useCameraCapture.js +116 -0
- package/dist/useCookies.d.ts +42 -0
- package/dist/useCookies.js +61 -0
- package/dist/useCopyToClipboard.d.ts +22 -0
- package/dist/useCopyToClipboard.js +31 -0
- package/dist/useCountDown.d.ts +80 -0
- package/dist/useCountDown.js +106 -0
- package/dist/useDebouncedState.d.ts +47 -0
- package/dist/useDebouncedState.js +47 -0
- package/dist/useExternalNotifications.d.ts +36 -0
- package/dist/useExternalNotifications.js +100 -0
- package/dist/useFile.d.ts +74 -0
- package/dist/useFile.js +74 -0
- package/dist/useFullScreen.d.ts +20 -0
- package/dist/useFullScreen.js +43 -0
- package/dist/useGeolocation.d.ts +47 -0
- package/dist/useGeolocation.js +68 -0
- package/dist/useHoverIntent.d.ts +45 -0
- package/dist/useHoverIntent.js +81 -0
- package/dist/useIdle.d.ts +47 -0
- package/dist/useIdle.js +59 -0
- package/dist/useIndexedDB.d.ts +60 -0
- package/dist/useIndexedDB.js +75 -0
- package/dist/useIntersectionObserver.d.ts +45 -0
- package/dist/useIntersectionObserver.js +70 -0
- package/dist/useIntervalSafe.d.ts +72 -0
- package/dist/useIntervalSafe.js +85 -0
- package/dist/useIsClient.d.ts +12 -0
- package/dist/useIsClient.js +21 -0
- package/dist/useIsDesktop.d.ts +12 -0
- package/dist/useIsDesktop.js +23 -0
- package/dist/useIsFirstRender.d.ts +12 -0
- package/dist/useIsFirstRender.js +21 -0
- package/dist/useList.d.ts +19 -0
- package/dist/useList.js +44 -0
- package/dist/useLocalNotifications.d.ts +23 -0
- package/dist/useLocalNotifications.js +50 -0
- package/dist/useLocalStorage.d.ts +45 -0
- package/dist/useLocalStorage.js +71 -0
- package/dist/useNetworkInformation.d.ts +138 -0
- package/dist/useNetworkInformation.js +76 -0
- package/dist/useOnline.d.ts +17 -0
- package/dist/useOnline.js +29 -0
- package/dist/usePageVisibility.d.ts +32 -0
- package/dist/usePageVisibility.js +65 -0
- package/dist/usePermissions.d.ts +28 -0
- package/dist/usePermissions.js +70 -0
- package/dist/usePictureInPicture.d.ts +47 -0
- package/dist/usePictureInPicture.js +60 -0
- package/dist/usePopover.d.ts +54 -0
- package/dist/usePopover.js +67 -0
- package/dist/usePreferredLanguage.d.ts +55 -0
- package/dist/usePreferredLanguage.js +127 -0
- package/dist/usePreferredTheme.d.ts +67 -0
- package/dist/usePreferredTheme.js +133 -0
- package/dist/usePreviousDistinct.d.ts +12 -0
- package/dist/usePreviousDistinct.js +23 -0
- package/dist/useResettableState.d.ts +15 -0
- package/dist/useResettableState.js +25 -0
- package/dist/useScreenOrientation.d.ts +48 -0
- package/dist/useScreenOrientation.js +51 -0
- package/dist/useScreenSize.d.ts +16 -0
- package/dist/useScreenSize.js +34 -0
- package/dist/useScreenWakeLock.d.ts +37 -0
- package/dist/useScreenWakeLock.js +48 -0
- package/dist/useServerSentEvent.d.ts +57 -0
- package/dist/useServerSentEvent.js +78 -0
- package/dist/useShoppingCart.d.ts +54 -0
- package/dist/useShoppingCart.js +122 -0
- package/dist/useSmartVideo.d.ts +35 -0
- package/dist/useSmartVideo.js +76 -0
- package/dist/useSpeech.d.ts +74 -0
- package/dist/useSpeech.js +156 -0
- package/dist/useSummarizer.d.ts +92 -0
- package/dist/useSummarizer.js +83 -0
- package/dist/useTaskQueue.d.ts +25 -0
- package/dist/useTaskQueue.js +51 -0
- package/dist/useThrottledCallback.d.ts +32 -0
- package/dist/useThrottledCallback.js +42 -0
- package/dist/useTimeout.d.ts +58 -0
- package/dist/useTimeout.js +70 -0
- package/dist/useToggle.d.ts +30 -0
- package/dist/useToggle.js +23 -0
- package/dist/useTraceUpdates.d.ts +22 -0
- package/dist/useTraceUpdates.js +38 -0
- package/dist/useTranslator.d.ts +110 -0
- package/dist/useTranslator.js +119 -0
- package/dist/useUserActivation.d.ts +40 -0
- package/dist/useUserActivation.js +63 -0
- package/dist/useVibration.d.ts +55 -0
- package/dist/useVibration.js +50 -0
- package/dist/useWebsocket.d.ts +80 -0
- package/dist/useWebsocket.js +125 -0
- 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 };
|
package/dist/useList.js
ADDED
|
@@ -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 };
|