@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
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
<p align="center">
|
|
2
|
+
<img src="./public/logo.png" alt="useful-react-hooks" height="40px">
|
|
3
|
+
</p>
|
|
4
|
+
|
|
5
|
+
<p align="center" style="font-size: 1.2rem; font-weight: bold;">
|
|
6
|
+
Modern React and Next.js hooks, unopinionated and focused on developer experience.
|
|
7
|
+
</p>
|
|
8
|
+
|
|
9
|
+
### **Release: Monday, February 9 2025**
|
|
10
|
+
|
|
11
|
+
## **Installation**
|
|
12
|
+
|
|
13
|
+
You can install the package with the following command:
|
|
14
|
+
|
|
15
|
+
Using `npm`:
|
|
16
|
+
|
|
17
|
+
```bash
|
|
18
|
+
npm install @vibehooks/react
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
Using `pnpm`:
|
|
22
|
+
|
|
23
|
+
```bash
|
|
24
|
+
pnpm add @vibehooks/react
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
That package is fully typed with TypeScript and comes with all the types you need.
|
|
28
|
+
You can use the types just by importing them from the package like this:
|
|
29
|
+
|
|
30
|
+
```ts
|
|
31
|
+
import { useToggle, type UseToggleReturn } from '@vibehooks/react';
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
## **Contributing**
|
|
35
|
+
|
|
36
|
+
Contributions are always welcome!
|
|
37
|
+
|
|
38
|
+
See [`Contributing`](https://github.com/SebastianUrdaneguiBisalaya/vibehooks?tab=contributing-ov-file) for ways to get started.
|
|
39
|
+
|
|
40
|
+
If you do not want create your custom hook, you can also contribute to the package by mentioning the name and purpose of the hook you would like to see in this package in the [issues](https://github.com/SebastianUrdaneguiBisalaya/vibehooks/issues) section.
|
|
41
|
+
|
|
42
|
+
## **API Docs**
|
|
43
|
+
|
|
44
|
+
| **Hook** | **Description** |
|
|
45
|
+
| --------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------ |
|
|
46
|
+
| [**useAsyncState**](https://github.com/SebastianUrdaneguiBisalaya/vibehooks/blob/main/src/useAsyncState.ts) | A robust React hook for managing asynchronous operations and remote data fetching with integrated state tracking and retry logic. |
|
|
47
|
+
| [**useAudio**](https://github.com/SebastianUrdaneguiBisalaya/vibehooks/blob/main/src/useAudio.ts) | A React hook providing a declarative and unopinionated interface to manage the HTML5 Audio API lifecycle. |
|
|
48
|
+
| [**useAutoScroll**](https://github.com/SebastianUrdaneguiBisalaya/vibehooks/blob/main/src/useAutoScroll.ts) | A custom hook that automatically manages scrolling to the bottom of a container while respecting manual user navigation. |
|
|
49
|
+
| [**useBarcode**](https://github.com/SebastianUrdaneguiBisalaya/vibehooks/blob/main/src/useBarcode.ts) | A React hook that provides a high-level interface for detecting barcodes and QR codes in real-time using the browser's Barcode Detection API. |
|
|
50
|
+
| [**useBatteryStatus**](https://github.com/SebastianUrdaneguiBisalaya/vibehooks/blob/main/src/useBatteryStatus.ts) | A hardware-integration hook that provides real-time access to the system's battery levels, charging state, and timing estimates. |
|
|
51
|
+
| [**useBodyScrollFreeze**](https://github.com/SebastianUrdaneguiBisalaya/vibehooks/blob/main/src/useBodyScrollFreeze.ts) | An imperative hook to disable body scrolling on specific axes while maintaining the user's current scroll position. |
|
|
52
|
+
| [**useCookies**](https://github.com/SebastianUrdaneguiBisalaya/vibehooks/blob/main/src/useCookies.ts) | A React hook that provides an unopinionated interface for managing browser cookies with standard configuration options. |
|
|
53
|
+
| [**useCameraCapture**](https://github.com/SebastianUrdaneguiBisalaya/vibehooks/blob/main/src/useCameraCapture.ts) | A hook that manages camera access and simplifies capturing still images from a live video stream via a canvas element. |
|
|
54
|
+
| [**useCopyToClipboard**](https://github.com/SebastianUrdaneguiBisalaya/vibehooks/blob/main/src/useCopyToClipboard.ts) | A hook to copy text to the system clipboard using the modern Clipboard API. |
|
|
55
|
+
| [**useCountDown**](https://github.com/SebastianUrdaneguiBisalaya/vibehooks/blob/main/src/useCountDown.ts) | High-precision React hook for managing synchronized countdown timers with manual lifecycle controls and drift-correction. |
|
|
56
|
+
| [**useDebouncedState**](https://github.com/SebastianUrdaneguiBisalaya/vibehooks/blob/main/src/useDebouncedState.ts) | A state management hook that tracks immediate value changes while providing a delayed update for performance-heavy operations. |
|
|
57
|
+
| [**useExternalNotifications**](https://github.com/SebastianUrdaneguiBisalaya/vibehooks/blob/main/src/useExternalNotifications.ts) | Manages and synchronizes system notifications across multiple contexts using a global external store. |
|
|
58
|
+
| [**useGeolocation**](https://github.com/SebastianUrdaneguiBisalaya/vibehooks/blob/main/src/useGeolocation.ts) | A comprehensive, SSR-safe hook for interfacing with the Geolocation API and Permissions API to track device coordinates and access status. |
|
|
59
|
+
| [**useHoverIntent**](https://github.com/SebastianUrdaneguiBisalaya/vibehooks/blob/main/src/useHoverIntent.ts) | A detection hook that distinguishes between accidental mouse-overs and intentional user hovers. |
|
|
60
|
+
| [**useFile**](https://github.com/SebastianUrdaneguiBisalaya/vibehooks/blob/main/src/useFile.ts) | Manages file selection state and provides input-ready props for uploads and drag-and-drop. |
|
|
61
|
+
| [**useFullscreen**](https://github.com/SebastianUrdaneguiBisalaya/vibehooks/blob/main/src/useFullScreen.ts) | A declarative interface for managing the browser Fullscreen API on a specific DOM element. |
|
|
62
|
+
| [**useIdle**](https://github.com/SebastianUrdaneguiBisalaya/vibehooks/blob/main/src/useIdle.ts) | An SSR-safe hook to monitor user inactivity by tracking browser interaction events and exposing real-time idle status based on a custom timeout. |
|
|
63
|
+
| [**useIndexedDB**](https://github.com/SebastianUrdaneguiBisalaya/vibehooks/blob/main/src/useIndexedDB.ts) | A React hook that abstracts the boilerplate of the IndexedDB API, facilitating database connections and transaction management. |
|
|
64
|
+
| [**useIntersectionObserver**](https://github.com/SebastianUrdaneguiBisalaya/vibehooks/blob/main/src/useIntersectionObserver.ts) | A hook that monitors the visibility and intersection of a DOM element within a viewport. |
|
|
65
|
+
| [**useIntervalSafe**](https://github.com/SebastianUrdaneguiBisalaya/vibehooks/blob/main/src/useIntervalSafe.ts) | A declarative and robust React hook for managing **setInterval** lifecycles with execution limits and manual controls. |
|
|
66
|
+
| [**useIsClient**](https://github.com/SebastianUrdaneguiBisalaya/vibehooks/blob/main/src/useIsClient.ts) | Returns true if the code is running in the browser and false if it is running on the server. |
|
|
67
|
+
| [**useIsDesktop**](https://github.com/SebastianUrdaneguiBisalaya/vibehooks/blob/main/src/useIsDesktop.ts) | Determines if the current viewport width meets or exceeds a specified desktop breakpoint. |
|
|
68
|
+
| [**useIsFirstRender**](https://github.com/SebastianUrdaneguiBisalaya/vibehooks/blob/main/src/useIsFirstRender.ts) | Tracks whether the current render cycle is the initial mount of the component. |
|
|
69
|
+
| [**useList**](https://github.com/SebastianUrdaneguiBisalaya/vibehooks/blob/main/src/useList.ts) | A stateful array management hook providing memoized utility functions for CRUD operations on lists. |
|
|
70
|
+
| [**useLocalStorage**](https://github.com/SebastianUrdaneguiBisalaya/vibehooks/blob/main/src/useLocalStorage.ts) | A typed React hook for interacting with the Web Storage API, providing automatic JSON serialization and fallback support. |
|
|
71
|
+
| [**useLocaleNotifications**](https://github.com/SebastianUrdaneguiBisalaya/vibehooks/blob/main/src/useLocalNotifications.ts) | Provides a direct interface to trigger browser system notifications within a component. |
|
|
72
|
+
| [**useNetworkInformation**](https://github.com/SebastianUrdaneguiBisalaya/vibehooks/blob/main/src/useNetworkInformation.ts) | A performance-aware hook that provides real-time network telemetry and user connectivity preferences to adapt application behavior. |
|
|
73
|
+
| [**usePageVisibility**](https://github.com/SebastianUrdaneguiBisalaya/vibehooks/blob/main/src/usePageVisibility.ts) | Provides the current visibility state of the document using the Page Visibility API. |
|
|
74
|
+
| [**usePermissions**](https://github.com/SebastianUrdaneguiBisalaya/vibehooks/blob/main/src/usePermissions.ts) | A reactive hook that observes and synchronizes browser permission statuses in real-time. |
|
|
75
|
+
| [**usePictureInPicture**](https://github.com/SebastianUrdaneguiBisalaya/vibehooks/blob/main/src/usePictureInPicture.ts) | A specialized hook to manage the Picture-in-Picture (PiP) Web API for floating video playback. |
|
|
76
|
+
| [**usePopover**](https://github.com/SebastianUrdaneguiBisalaya/vibehooks/blob/main/src/usePopover.ts) | A lifecycle management hook for popover UI elements that handles visibility and "click-outside" logic. |
|
|
77
|
+
| [**usePreferredTheme**](https://github.com/SebastianUrdaneguiBisalaya/vibehooks/blob/main/src/usePreferredTheme.ts) | Resolves the effective theme by reconciling system preferences and manual user selection. |
|
|
78
|
+
| [**usePreferredLanguage**](https://github.com/SebastianUrdaneguiBisalaya/vibehooks/blob/main/src/usePreferredLanguage.ts) | Manages and resolves the application language based on system settings and user overrides. |
|
|
79
|
+
| [**usePreviousDistinct**](https://github.com/SebastianUrdaneguiBisalaya/vibehooks/blob/main/src/usePreviousDistinct.ts) | A utility hook that captures the last distinct value of a variable, filtering out redundant consecutive updates. |
|
|
80
|
+
| [**useResettableState**](https://github.com/SebastianUrdaneguiBisalaya/vibehooks/blob/main/src/useResettableState.ts) | Extends standard state management with a memoized reset mechanism to revert to the initial value. |
|
|
81
|
+
| [**useScreenOrientation**](https://github.com/SebastianUrdaneguiBisalaya/vibehooks/blob/main/src/useScreenOrientation.ts) | A React hook that provides real-time access to the device's screen orientation state and control methods via the Screen Orientation API. |
|
|
82
|
+
| [**useScreenSize**](https://github.com/SebastianUrdaneguiBisalaya/vibehooks/blob/main/src/useScreenSize.ts) | Returns the current inner dimensions of the browser window. |
|
|
83
|
+
| [**useScreenWakeLock**](https://github.com/SebastianUrdaneguiBisalaya/vibehooks/blob/main/src/useScreenWakeLock.ts) | A React hook that provides unopinionated access to the Screen Wake Lock API to prevent devices from dimming or locking the screen. |
|
|
84
|
+
| [**useServerSentEvent**](https://github.com/SebastianUrdaneguiBisalaya/vibehooks/blob/main/src/useServerSentEvent.ts) | A React hook that provides unopinionated access to the EventSource Web API for receiving real-time server-side updates. |
|
|
85
|
+
| [**useShoppingCart**](https://github.com/SebastianUrdaneguiBisalaya/vibehooks/blob/main/src/useShoppingCart.ts) | A generic, domain-agnostic hook for managing complex shopping cart logic and calculations. |
|
|
86
|
+
| [**useSmartVideo**](https://github.com/SebastianUrdaneguiBisalaya/vibehooks/blob/main/src/useSmartVideo.ts) | An advanced video hook that combines intersection logic with playback control for automated "smart" behavior. |
|
|
87
|
+
| [**useSpeech**](https://github.com/SebastianUrdaneguiBisalaya/vibehooks/blob/main/src/useSpeech.ts) | Provides unopinionated, high-level access to the Web Speech API for speech-to-text recognition. |
|
|
88
|
+
| [**useSummarizer**](https://github.com/SebastianUrdaneguiBisalaya/vibehooks/blob/main/src/useSummarizer.ts) | Provides low-level access to the browser's built-in AI Summarizer API. |
|
|
89
|
+
| [**useTaskQueue**](https://github.com/SebastianUrdaneguiBisalaya/vibehooks/blob/main/src/useTaskQueue.ts) | A React hook for managing and executing a sequential queue of asynchronous tasks with automatic concurrency control. |
|
|
90
|
+
| [**useTimeout**](https://github.com/SebastianUrdaneguiBisalaya/vibehooks/blob/main/src/useTimeout.ts) | A declarative React hook for managing the lifecycle of single-execution timers with manual controls and SSR safety. |
|
|
91
|
+
| [**useThrottledCallback**](https://github.com/SebastianUrdaneguiBisalaya/vibehooks/blob/main/src/useThrottledCallback.ts) | A performance-optimization hook that limits the execution frequency of a callback to one per specified time window. |
|
|
92
|
+
| [**useTraceUpdates**](https://github.com/SebastianUrdaneguiBisalaya/vibehooks/blob/main/src/useTraceUpdates.ts) | Logs property changes to the console whenever the component updates. |
|
|
93
|
+
| [**useTranslator**](https://github.com/SebastianUrdaneguiBisalaya/vibehooks/blob/main/src/useTranslator.ts) | Enables AI-powered text translation directly within the browser via the Translator API. |
|
|
94
|
+
| [**useToggle**](https://github.com/SebastianUrdaneguiBisalaya/vibehooks/blob/main/src/useToggle.ts) | A lightweight, unopinionated hook to manage boolean state toggling with memoized handlers. |
|
|
95
|
+
| [**useUserActivation**](https://github.com/SebastianUrdaneguiBisalaya/vibehooks/blob/main/src/useUserActivation.ts) | A React hook that tracks the browser's User Activation state to determine if a user has interacted with the page. |
|
|
96
|
+
| [**useVibration**](https://github.com/SebastianUrdaneguiBisalaya/vibehooks/blob/main/src/useVibration.ts) | A React hook that provides an SSR-safe interface to interact with the device's physical vibration hardware. |
|
|
97
|
+
| [**useWebsocket**](https://github.com/SebastianUrdaneguiBisalaya/vibehooks/blob/main/src/useWebsocket.ts) | A comprehensive React hook for managing WebSocket connections with built-in auto-reconnection logic, message history, and SSR safety. |
|
|
98
|
+
|
|
99
|
+
## License
|
|
100
|
+
|
|
101
|
+
[MIT](https://github.com/SebastianUrdaneguiBisalaya/vibehooks?tab=MIT-1-ov-file)
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
import { useAudio } from "./useAudio.js";
|
|
2
|
+
import { useAsyncState } from "./useAsyncState.js";
|
|
3
|
+
import { useAutoScroll } from "./useAutoScroll.js";
|
|
4
|
+
import { useBarcode } from "./useBarcode.js";
|
|
5
|
+
import { useBatteryStatus } from "./useBatteryStatus.js";
|
|
6
|
+
import { useBodyScrollFreeze } from "./useBodyScrollFreeze.js";
|
|
7
|
+
import { useCameraCapture } from "./useCameraCapture.js";
|
|
8
|
+
import { useCookies } from "./useCookies.js";
|
|
9
|
+
import { useCopyToClipboard } from "./useCopyToClipboard.js";
|
|
10
|
+
import { useCountDown } from "./useCountDown.js";
|
|
11
|
+
import { useDebouncedState } from "./useDebouncedState.js";
|
|
12
|
+
import { useExternalNotifications } from "./useExternalNotifications.js";
|
|
13
|
+
import { useGeolocation } from "./useGeolocation.js";
|
|
14
|
+
import { useHoverIntent } from "./useHoverIntent.js";
|
|
15
|
+
import { useFile } from "./useFile.js";
|
|
16
|
+
import { useFullscreen } from "./useFullScreen.js";
|
|
17
|
+
import { useIdle } from "./useIdle.js";
|
|
18
|
+
import { useIndexedDB } from "./useIndexedDB.js";
|
|
19
|
+
import { useIntersectionObserver } from "./useIntersectionObserver.js";
|
|
20
|
+
import { useIntervalSafe } from "./useIntervalSafe.js";
|
|
21
|
+
import { useIsClient } from "./useIsClient.js";
|
|
22
|
+
import { useIsDesktop } from "./useIsDesktop.js";
|
|
23
|
+
import { useIsFirstRender } from "./useIsFirstRender.js";
|
|
24
|
+
import { useList } from "./useList.js";
|
|
25
|
+
import { useLocalStorage } from "./useLocalStorage.js";
|
|
26
|
+
import { useLocalNotifications } from "./useLocalNotifications.js";
|
|
27
|
+
import { useNetworkInformation } from "./useNetworkInformation.js";
|
|
28
|
+
import { usePageVisibility } from "./usePageVisibility.js";
|
|
29
|
+
import { usePermissions } from "./usePermissions.js";
|
|
30
|
+
import { usePictureInPicture } from "./usePictureInPicture.js";
|
|
31
|
+
import { usePopover } from "./usePopover.js";
|
|
32
|
+
import { usePreferredTheme } from "./usePreferredTheme.js";
|
|
33
|
+
import { usePreferredLanguage } from "./usePreferredLanguage.js";
|
|
34
|
+
import { usePreviousDistinct } from "./usePreviousDistinct.js";
|
|
35
|
+
import { useResettableState } from "./useResettableState.js";
|
|
36
|
+
import { useScreenOrientation } from "./useScreenOrientation.js";
|
|
37
|
+
import { useScreenSize } from "./useScreenSize.js";
|
|
38
|
+
import { useScreenWakeLock } from "./useScreenWakeLock.js";
|
|
39
|
+
import { useServerSentEvent } from "./useServerSentEvent.js";
|
|
40
|
+
import { useShoppingCart } from "./useShoppingCart.js";
|
|
41
|
+
import { useSmartVideo } from "./useSmartVideo.js";
|
|
42
|
+
import { useSpeech } from "./useSpeech.js";
|
|
43
|
+
import { useSummarizer } from "./useSummarizer.js";
|
|
44
|
+
import { useTaskQueue } from "./useTaskQueue.js";
|
|
45
|
+
import { useTimeout } from "./useTimeout.js";
|
|
46
|
+
import { useThrottledCallback } from "./useThrottledCallback.js";
|
|
47
|
+
import { useTraceUpdates } from "./useTraceUpdates.js";
|
|
48
|
+
import { useTranslator } from "./useTranslator.js";
|
|
49
|
+
import { useToggle } from "./useToggle.js";
|
|
50
|
+
import { useOnline } from "./useOnline.js";
|
|
51
|
+
import { useUserActivation } from "./useUserActivation.js";
|
|
52
|
+
import { useVibration } from "./useVibration.js";
|
|
53
|
+
import { useWebsocket } from "./useWebsocket.js";
|
|
54
|
+
export { useAsyncState, useAudio, useAutoScroll, useBarcode, useBatteryStatus, useBodyScrollFreeze, useCameraCapture, useCookies, useCopyToClipboard, useCountDown, useDebouncedState, useExternalNotifications, useFile, useFullscreen, useGeolocation, useHoverIntent, useIdle, useIndexedDB, useIntersectionObserver, useIntervalSafe, useIsClient, useIsDesktop, useIsFirstRender, useList, useLocalNotifications, useLocalStorage, useNetworkInformation, useOnline, usePageVisibility, usePermissions, usePictureInPicture, usePopover, usePreferredLanguage, usePreferredTheme, usePreviousDistinct, useResettableState, useScreenOrientation, useScreenSize, useScreenWakeLock, useServerSentEvent, useShoppingCart, useSmartVideo, useSpeech, useSummarizer, useTaskQueue, useThrottledCallback, useTimeout, useToggle, useTraceUpdates, useTranslator, useUserActivation, useVibration, useWebsocket };
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
import { useAudio } from "./useAudio.js";
|
|
2
|
+
import { useAsyncState } from "./useAsyncState.js";
|
|
3
|
+
import { useAutoScroll } from "./useAutoScroll.js";
|
|
4
|
+
import { useBarcode } from "./useBarcode.js";
|
|
5
|
+
import { useBatteryStatus } from "./useBatteryStatus.js";
|
|
6
|
+
import { useBodyScrollFreeze } from "./useBodyScrollFreeze.js";
|
|
7
|
+
import { useCameraCapture } from "./useCameraCapture.js";
|
|
8
|
+
import { useCookies } from "./useCookies.js";
|
|
9
|
+
import { useCopyToClipboard } from "./useCopyToClipboard.js";
|
|
10
|
+
import { useCountDown } from "./useCountDown.js";
|
|
11
|
+
import { useDebouncedState } from "./useDebouncedState.js";
|
|
12
|
+
import { useExternalNotifications } from "./useExternalNotifications.js";
|
|
13
|
+
import { useGeolocation } from "./useGeolocation.js";
|
|
14
|
+
import { useHoverIntent } from "./useHoverIntent.js";
|
|
15
|
+
import { useFile } from "./useFile.js";
|
|
16
|
+
import { useFullscreen } from "./useFullScreen.js";
|
|
17
|
+
import { useIdle } from "./useIdle.js";
|
|
18
|
+
import { useIndexedDB } from "./useIndexedDB.js";
|
|
19
|
+
import { useIntersectionObserver } from "./useIntersectionObserver.js";
|
|
20
|
+
import { useIntervalSafe } from "./useIntervalSafe.js";
|
|
21
|
+
import { useIsClient } from "./useIsClient.js";
|
|
22
|
+
import { useScreenSize } from "./useScreenSize.js";
|
|
23
|
+
import { useIsDesktop } from "./useIsDesktop.js";
|
|
24
|
+
import { useIsFirstRender } from "./useIsFirstRender.js";
|
|
25
|
+
import { useList } from "./useList.js";
|
|
26
|
+
import { useLocalStorage } from "./useLocalStorage.js";
|
|
27
|
+
import { useLocalNotifications } from "./useLocalNotifications.js";
|
|
28
|
+
import { useNetworkInformation } from "./useNetworkInformation.js";
|
|
29
|
+
import { usePageVisibility } from "./usePageVisibility.js";
|
|
30
|
+
import { usePermissions } from "./usePermissions.js";
|
|
31
|
+
import { usePictureInPicture } from "./usePictureInPicture.js";
|
|
32
|
+
import { usePopover } from "./usePopover.js";
|
|
33
|
+
import { usePreferredTheme } from "./usePreferredTheme.js";
|
|
34
|
+
import { usePreferredLanguage } from "./usePreferredLanguage.js";
|
|
35
|
+
import { usePreviousDistinct } from "./usePreviousDistinct.js";
|
|
36
|
+
import { useResettableState } from "./useResettableState.js";
|
|
37
|
+
import { useScreenOrientation } from "./useScreenOrientation.js";
|
|
38
|
+
import { useScreenWakeLock } from "./useScreenWakeLock.js";
|
|
39
|
+
import { useServerSentEvent } from "./useServerSentEvent.js";
|
|
40
|
+
import { useShoppingCart } from "./useShoppingCart.js";
|
|
41
|
+
import { useSmartVideo } from "./useSmartVideo.js";
|
|
42
|
+
import { useSpeech } from "./useSpeech.js";
|
|
43
|
+
import { useSummarizer } from "./useSummarizer.js";
|
|
44
|
+
import { useTaskQueue } from "./useTaskQueue.js";
|
|
45
|
+
import { useTimeout } from "./useTimeout.js";
|
|
46
|
+
import { useThrottledCallback } from "./useThrottledCallback.js";
|
|
47
|
+
import { useTraceUpdates } from "./useTraceUpdates.js";
|
|
48
|
+
import { useTranslator } from "./useTranslator.js";
|
|
49
|
+
import { useToggle } from "./useToggle.js";
|
|
50
|
+
import { useOnline } from "./useOnline.js";
|
|
51
|
+
import { useUserActivation } from "./useUserActivation.js";
|
|
52
|
+
import { useVibration } from "./useVibration.js";
|
|
53
|
+
import { useWebsocket } from "./useWebsocket.js";
|
|
54
|
+
|
|
55
|
+
export { useAsyncState, useAudio, useAutoScroll, useBarcode, useBatteryStatus, useBodyScrollFreeze, useCameraCapture, useCookies, useCopyToClipboard, useCountDown, useDebouncedState, useExternalNotifications, useFile, useFullscreen, useGeolocation, useHoverIntent, useIdle, useIndexedDB, useIntersectionObserver, useIntervalSafe, useIsClient, useIsDesktop, useIsFirstRender, useList, useLocalNotifications, useLocalStorage, useNetworkInformation, useOnline, usePageVisibility, usePermissions, usePictureInPicture, usePopover, usePreferredLanguage, usePreferredTheme, usePreviousDistinct, useResettableState, useScreenOrientation, useScreenSize, useScreenWakeLock, useServerSentEvent, useShoppingCart, useSmartVideo, useSpeech, useSummarizer, useTaskQueue, useThrottledCallback, useTimeout, useToggle, useTraceUpdates, useTranslator, useUserActivation, useVibration, useWebsocket };
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
//#region src/useAsyncState.d.ts
|
|
2
|
+
type AsyncState<T> = {
|
|
3
|
+
data: T | null;
|
|
4
|
+
error: Error | null;
|
|
5
|
+
isError: boolean;
|
|
6
|
+
isIdle: boolean;
|
|
7
|
+
isLoading: boolean;
|
|
8
|
+
isSuccess: boolean;
|
|
9
|
+
};
|
|
10
|
+
type FetchConfig = RequestInit & {
|
|
11
|
+
onError?: (error: Error) => void;
|
|
12
|
+
onSuccess?: (data: unknown) => void;
|
|
13
|
+
params?: Record<string, string | number | boolean>;
|
|
14
|
+
retries?: number;
|
|
15
|
+
retryDelay?: number;
|
|
16
|
+
timeout?: number;
|
|
17
|
+
};
|
|
18
|
+
type UseAsyncStateReturn<T> = AsyncState<T> & {
|
|
19
|
+
execute: (url: string, config?: FetchConfig) => Promise<T | null>;
|
|
20
|
+
mutate: (data: T) => void;
|
|
21
|
+
reset: () => void;
|
|
22
|
+
retry: () => Promise<T | null>;
|
|
23
|
+
};
|
|
24
|
+
interface UseAsyncStateOptions<T> {
|
|
25
|
+
initialData?: T | null;
|
|
26
|
+
onError?: (error: Error) => void;
|
|
27
|
+
onSuccess?: (data: T) => void;
|
|
28
|
+
}
|
|
29
|
+
/**
|
|
30
|
+
* `useAsyncState` is a comprehensive hook for managing asynchronous fetch operations with built-in state management.
|
|
31
|
+
* This hook eliminates the need to manually manage loading state, errors, retries, and data handling for fetch requests.
|
|
32
|
+
*
|
|
33
|
+
* @example
|
|
34
|
+
* ```tsx
|
|
35
|
+
* function UserProfile() {
|
|
36
|
+
* const { data, isLoading, isError, error, execute } = useAsyncState<User>();
|
|
37
|
+
*
|
|
38
|
+
* React.useEffect(() => {
|
|
39
|
+
* execute('https://api.example.com/user/123');
|
|
40
|
+
* }, []);
|
|
41
|
+
*
|
|
42
|
+
* if (isLoading) return <div>Loading...</div>;
|
|
43
|
+
* if (isError) return <div>Error: {error?.message}</div>;
|
|
44
|
+
* if (!data) return null;
|
|
45
|
+
*
|
|
46
|
+
* return <div>Welcome, {data.name}!</div>;
|
|
47
|
+
* }
|
|
48
|
+
* ```
|
|
49
|
+
*/
|
|
50
|
+
declare function useAsyncState<T>(options?: UseAsyncStateOptions<T>): UseAsyncStateReturn<T>;
|
|
51
|
+
//#endregion
|
|
52
|
+
export { useAsyncState };
|
|
@@ -0,0 +1,173 @@
|
|
|
1
|
+
import * as React from "react";
|
|
2
|
+
|
|
3
|
+
//#region src/useAsyncState.ts
|
|
4
|
+
var FetchError = class extends Error {
|
|
5
|
+
constructor(message, status, statusText, response) {
|
|
6
|
+
super(message);
|
|
7
|
+
this.status = status;
|
|
8
|
+
this.statusText = statusText;
|
|
9
|
+
this.response = response;
|
|
10
|
+
this.name = "FetchError";
|
|
11
|
+
}
|
|
12
|
+
};
|
|
13
|
+
/**
|
|
14
|
+
* `useAsyncState` is a comprehensive hook for managing asynchronous fetch operations with built-in state management.
|
|
15
|
+
* This hook eliminates the need to manually manage loading state, errors, retries, and data handling for fetch requests.
|
|
16
|
+
*
|
|
17
|
+
* @example
|
|
18
|
+
* ```tsx
|
|
19
|
+
* function UserProfile() {
|
|
20
|
+
* const { data, isLoading, isError, error, execute } = useAsyncState<User>();
|
|
21
|
+
*
|
|
22
|
+
* React.useEffect(() => {
|
|
23
|
+
* execute('https://api.example.com/user/123');
|
|
24
|
+
* }, []);
|
|
25
|
+
*
|
|
26
|
+
* if (isLoading) return <div>Loading...</div>;
|
|
27
|
+
* if (isError) return <div>Error: {error?.message}</div>;
|
|
28
|
+
* if (!data) return null;
|
|
29
|
+
*
|
|
30
|
+
* return <div>Welcome, {data.name}!</div>;
|
|
31
|
+
* }
|
|
32
|
+
* ```
|
|
33
|
+
*/
|
|
34
|
+
function useAsyncState(options) {
|
|
35
|
+
const { initialData = null, onError, onSuccess } = options || {};
|
|
36
|
+
const [state, setState] = React.useState({
|
|
37
|
+
data: initialData,
|
|
38
|
+
error: null,
|
|
39
|
+
isError: false,
|
|
40
|
+
isIdle: true,
|
|
41
|
+
isLoading: false,
|
|
42
|
+
isSuccess: false
|
|
43
|
+
});
|
|
44
|
+
const lastRequestRef = React.useRef(null);
|
|
45
|
+
const abortControllerRef = React.useRef(null);
|
|
46
|
+
const buildUrl = React.useCallback((url, params) => {
|
|
47
|
+
if (!params || Object.keys(params).length === 0) return url;
|
|
48
|
+
const urlObj = new URL(url);
|
|
49
|
+
Object.entries(params).forEach(([key, value]) => {
|
|
50
|
+
urlObj.searchParams.append(key, value.toString());
|
|
51
|
+
});
|
|
52
|
+
return urlObj.toString();
|
|
53
|
+
}, []);
|
|
54
|
+
const performFetch = React.useCallback(async (url, config, attemptNumber = 1) => {
|
|
55
|
+
const { onError: configOnError, onSuccess: configOnSuccess, params, retries = 0, retryDelay = 1e3, timeout = 3e4, ...fetchConfig } = config || {};
|
|
56
|
+
abortControllerRef.current = new AbortController();
|
|
57
|
+
const { signal } = abortControllerRef.current;
|
|
58
|
+
const fullUrl = buildUrl(url, params);
|
|
59
|
+
const timeoutPromise = new Promise((_, reject) => {
|
|
60
|
+
setTimeout(() => {
|
|
61
|
+
abortControllerRef.current?.abort();
|
|
62
|
+
reject(new FetchError("Request timeout", void 0, "Timeout"));
|
|
63
|
+
}, timeout);
|
|
64
|
+
});
|
|
65
|
+
try {
|
|
66
|
+
const response = await Promise.race([fetch(fullUrl, {
|
|
67
|
+
...fetchConfig,
|
|
68
|
+
signal
|
|
69
|
+
}), timeoutPromise]);
|
|
70
|
+
if (!response.ok) throw new FetchError(await response.text().catch(() => response.statusText) || `HTTP Error ${response.status}`, response.status, response.statusText, response);
|
|
71
|
+
const contentType = response.headers.get("Content-Type");
|
|
72
|
+
let data;
|
|
73
|
+
if (contentType?.includes("application/json")) data = await response.json();
|
|
74
|
+
else if (contentType?.includes("text/")) data = await response.text();
|
|
75
|
+
else data = await response.blob();
|
|
76
|
+
configOnSuccess?.(data);
|
|
77
|
+
onSuccess?.(data);
|
|
78
|
+
return data;
|
|
79
|
+
} catch (err) {
|
|
80
|
+
const error = err instanceof Error ? err : new Error(String(err));
|
|
81
|
+
if (attemptNumber <= retries && error.name !== "AbortError") {
|
|
82
|
+
await new Promise((resolve) => setTimeout(resolve, retryDelay));
|
|
83
|
+
return performFetch(url, config, attemptNumber + 1);
|
|
84
|
+
}
|
|
85
|
+
configOnError?.(error);
|
|
86
|
+
onError?.(error);
|
|
87
|
+
throw error;
|
|
88
|
+
}
|
|
89
|
+
}, [
|
|
90
|
+
buildUrl,
|
|
91
|
+
onSuccess,
|
|
92
|
+
onError
|
|
93
|
+
]);
|
|
94
|
+
const execute = React.useCallback(async (url, config) => {
|
|
95
|
+
abortControllerRef.current?.abort();
|
|
96
|
+
lastRequestRef.current = {
|
|
97
|
+
config,
|
|
98
|
+
url
|
|
99
|
+
};
|
|
100
|
+
setState((prev) => ({
|
|
101
|
+
...prev,
|
|
102
|
+
error: null,
|
|
103
|
+
isError: false,
|
|
104
|
+
isIdle: false,
|
|
105
|
+
isLoading: true,
|
|
106
|
+
isSuccess: false
|
|
107
|
+
}));
|
|
108
|
+
try {
|
|
109
|
+
const data = await performFetch(url, config);
|
|
110
|
+
setState({
|
|
111
|
+
data,
|
|
112
|
+
error: null,
|
|
113
|
+
isError: false,
|
|
114
|
+
isIdle: false,
|
|
115
|
+
isLoading: false,
|
|
116
|
+
isSuccess: true
|
|
117
|
+
});
|
|
118
|
+
return data;
|
|
119
|
+
} catch (err) {
|
|
120
|
+
const error = err instanceof Error ? err : new Error(String(err));
|
|
121
|
+
if (error.name !== "AbortError") return null;
|
|
122
|
+
setState((prev) => ({
|
|
123
|
+
...prev,
|
|
124
|
+
error,
|
|
125
|
+
isError: true,
|
|
126
|
+
isLoading: false,
|
|
127
|
+
isSuccess: false
|
|
128
|
+
}));
|
|
129
|
+
return null;
|
|
130
|
+
}
|
|
131
|
+
}, [performFetch]);
|
|
132
|
+
const reset = React.useCallback(() => {
|
|
133
|
+
abortControllerRef.current?.abort();
|
|
134
|
+
lastRequestRef.current = null;
|
|
135
|
+
setState({
|
|
136
|
+
data: initialData,
|
|
137
|
+
error: null,
|
|
138
|
+
isError: false,
|
|
139
|
+
isIdle: true,
|
|
140
|
+
isLoading: false,
|
|
141
|
+
isSuccess: false
|
|
142
|
+
});
|
|
143
|
+
}, [initialData]);
|
|
144
|
+
const mutate = React.useCallback((newData) => {
|
|
145
|
+
setState((prev) => ({
|
|
146
|
+
...prev,
|
|
147
|
+
data: newData
|
|
148
|
+
}));
|
|
149
|
+
}, []);
|
|
150
|
+
const retry = React.useCallback(async () => {
|
|
151
|
+
if (!lastRequestRef.current) {
|
|
152
|
+
console.warn("No previous request to retry.");
|
|
153
|
+
return null;
|
|
154
|
+
}
|
|
155
|
+
const { config, url } = lastRequestRef.current;
|
|
156
|
+
return execute(url, config);
|
|
157
|
+
}, [execute]);
|
|
158
|
+
React.useEffect(() => {
|
|
159
|
+
return () => {
|
|
160
|
+
abortControllerRef.current?.abort();
|
|
161
|
+
};
|
|
162
|
+
}, []);
|
|
163
|
+
return {
|
|
164
|
+
...state,
|
|
165
|
+
execute,
|
|
166
|
+
mutate,
|
|
167
|
+
reset,
|
|
168
|
+
retry
|
|
169
|
+
};
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
//#endregion
|
|
173
|
+
export { useAsyncState };
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
//#region src/useAudio.d.ts
|
|
2
|
+
type AudioStatus = 'idle' | 'loading' | 'playing' | 'paused' | 'ended' | 'error';
|
|
3
|
+
interface UseAudioOptions {
|
|
4
|
+
loop?: boolean;
|
|
5
|
+
src?: string;
|
|
6
|
+
volume?: number;
|
|
7
|
+
}
|
|
8
|
+
interface UseAudioReturn {
|
|
9
|
+
audio: HTMLAudioElement | null;
|
|
10
|
+
error: Error | null;
|
|
11
|
+
pause: () => void;
|
|
12
|
+
play: () => Promise<void>;
|
|
13
|
+
status: AudioStatus;
|
|
14
|
+
}
|
|
15
|
+
/**
|
|
16
|
+
* `useAudio` is a React hook that provides unopinionated access to the HTML5 Audio API.
|
|
17
|
+
*
|
|
18
|
+
* @example
|
|
19
|
+
* ```tsx
|
|
20
|
+
* const audio = useAudio({ src: '/sound.mp3' });
|
|
21
|
+
* audio.play();
|
|
22
|
+
* ```
|
|
23
|
+
*/
|
|
24
|
+
declare function useAudio(options?: UseAudioOptions): UseAudioReturn;
|
|
25
|
+
//#endregion
|
|
26
|
+
export { useAudio };
|
package/dist/useAudio.js
ADDED
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
import * as React from "react";
|
|
2
|
+
|
|
3
|
+
//#region src/useAudio.ts
|
|
4
|
+
/**
|
|
5
|
+
* `useAudio` is a React hook that provides unopinionated access to the HTML5 Audio API.
|
|
6
|
+
*
|
|
7
|
+
* @example
|
|
8
|
+
* ```tsx
|
|
9
|
+
* const audio = useAudio({ src: '/sound.mp3' });
|
|
10
|
+
* audio.play();
|
|
11
|
+
* ```
|
|
12
|
+
*/
|
|
13
|
+
function useAudio(options = {}) {
|
|
14
|
+
const audioRef = React.useRef(null);
|
|
15
|
+
const mountedRef = React.useRef(false);
|
|
16
|
+
const [status, setStatus] = React.useState("idle");
|
|
17
|
+
const [error, setError] = React.useState(null);
|
|
18
|
+
const play = React.useCallback(async () => {
|
|
19
|
+
if (!audioRef.current) return;
|
|
20
|
+
try {
|
|
21
|
+
await audioRef.current.play();
|
|
22
|
+
setStatus("playing");
|
|
23
|
+
} catch (error$1) {
|
|
24
|
+
setError(error$1);
|
|
25
|
+
setStatus("error");
|
|
26
|
+
}
|
|
27
|
+
}, []);
|
|
28
|
+
const pause = React.useCallback(() => {
|
|
29
|
+
audioRef.current?.pause();
|
|
30
|
+
setStatus("paused");
|
|
31
|
+
}, []);
|
|
32
|
+
React.useEffect(() => {
|
|
33
|
+
mountedRef.current = true;
|
|
34
|
+
const audio = new Audio(options.src ?? "");
|
|
35
|
+
audio.loop = options.loop ?? false;
|
|
36
|
+
audio.volume = options.volume ?? 1;
|
|
37
|
+
audio.onended = () => mountedRef.current && setStatus("ended");
|
|
38
|
+
audio.onerror = () => {
|
|
39
|
+
if (!mountedRef.current) return;
|
|
40
|
+
setError(/* @__PURE__ */ new Error("Audio error"));
|
|
41
|
+
setStatus("error");
|
|
42
|
+
};
|
|
43
|
+
audioRef.current = audio;
|
|
44
|
+
return () => {
|
|
45
|
+
mountedRef.current = false;
|
|
46
|
+
audio.pause();
|
|
47
|
+
audioRef.current = null;
|
|
48
|
+
};
|
|
49
|
+
}, [
|
|
50
|
+
options.src,
|
|
51
|
+
options.loop,
|
|
52
|
+
options.volume
|
|
53
|
+
]);
|
|
54
|
+
return {
|
|
55
|
+
audio: audioRef.current,
|
|
56
|
+
error,
|
|
57
|
+
pause,
|
|
58
|
+
play,
|
|
59
|
+
status
|
|
60
|
+
};
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
//#endregion
|
|
64
|
+
export { useAudio };
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
import * as React from "react";
|
|
2
|
+
|
|
3
|
+
//#region src/useAutoScroll.d.ts
|
|
4
|
+
interface UseAutoScrollOptions {
|
|
5
|
+
behavior?: 'auto' | 'smooth';
|
|
6
|
+
enabled?: boolean;
|
|
7
|
+
threshold?: number;
|
|
8
|
+
}
|
|
9
|
+
/**
|
|
10
|
+
* `useAutoScroll` is a custom hook for automatically scrolling to the bottom of a container element.
|
|
11
|
+
* It keeps the scroll at the bottom of the container while new content is generated, but only if the user is near the bottom. If the user scrolls up to read previous content, auto-scrolling is automatically disabled so as not to interrupt their reading.
|
|
12
|
+
*
|
|
13
|
+
* @example
|
|
14
|
+
* ```tsx
|
|
15
|
+
* function ChatInterface() {
|
|
16
|
+
* const { ref, isAtBottom, scrollToBottom } = useAutoScroll({
|
|
17
|
+
* threshold: 50,
|
|
18
|
+
* behavior: 'smooth'
|
|
19
|
+
* });
|
|
20
|
+
*
|
|
21
|
+
* return (
|
|
22
|
+
* <div>
|
|
23
|
+
* <div ref={ref} className="chat-container">
|
|
24
|
+
* {messages.map(msg => (
|
|
25
|
+
* <Message key={msg.id} content={msg.content} />
|
|
26
|
+
* ))}
|
|
27
|
+
* </div>
|
|
28
|
+
* {!isAtBottom && (
|
|
29
|
+
* <button onClick={scrollToBottom}>
|
|
30
|
+
* Ir al final ↓
|
|
31
|
+
* </button>
|
|
32
|
+
* )}
|
|
33
|
+
* </div>
|
|
34
|
+
* );
|
|
35
|
+
* }
|
|
36
|
+
* ```
|
|
37
|
+
*/
|
|
38
|
+
declare function useAutoScroll(options?: UseAutoScrollOptions): {
|
|
39
|
+
autoScrollEnabled: boolean;
|
|
40
|
+
disableAutoScroll: () => void;
|
|
41
|
+
enableAutoScroll: () => void;
|
|
42
|
+
isAtBottom: boolean;
|
|
43
|
+
ref: React.RefObject<HTMLDivElement | null>;
|
|
44
|
+
scrollToBottom: (forceSmooth?: boolean) => void;
|
|
45
|
+
};
|
|
46
|
+
//#endregion
|
|
47
|
+
export { useAutoScroll };
|