├── .github └── workflows │ └── deploy.yml ├── .gitignore ├── README.md ├── docs ├── .gitignore ├── README.md ├── babel.config.js ├── docs │ ├── hooks │ │ ├── useBattery.md │ │ ├── useClickOutside.md │ │ ├── useClipboard.md │ │ ├── useCookie.md │ │ ├── useDebounce.md │ │ ├── useDebouncedCallback.md │ │ ├── useDeviceOrientation.md │ │ ├── useDimensions.md │ │ ├── useEventListener.md │ │ ├── useFavicon.md │ │ ├── useFetch.md │ │ ├── useFocusBlur.md │ │ ├── useGeolocation.md │ │ ├── useHistory.md │ │ ├── useHover.md │ │ ├── useIdle.md │ │ ├── useIntersectionObserver.md │ │ ├── useKeyCombo.md │ │ ├── useKeyPress.md │ │ ├── useLocalStorage.md │ │ ├── useLongPress.md │ │ ├── useMediaQuery.md │ │ ├── useMouse.md │ │ ├── useMutationObserver.md │ │ ├── useNotification.md │ │ ├── useOnlineStatus.md │ │ ├── usePreferredLanguage.md │ │ ├── usePrevious.md │ │ ├── useRandomColor.md │ │ ├── useScript.md │ │ ├── useScrollIntoPosition.md │ │ ├── useScrollLock.md │ │ ├── useScrollPosition.md │ │ ├── useSessionStorage.md │ │ ├── useSound.md │ │ ├── useStopwatch.md │ │ ├── useSystemTheme.md │ │ ├── useTitle.md │ │ ├── useTouch.md │ │ ├── useTouchSwipe.md │ │ ├── useUpdateEffect.md │ │ ├── useVibration.md │ │ ├── useWindowFocus.md │ │ ├── useWindowScrollIntoPosition.md │ │ ├── useWindowScrollPosition.md │ │ ├── useWindowSize.md │ │ └── useWindowTouchSwipe.md │ └── intro.md ├── docusaurus.config.ts ├── package-lock.json ├── package.json ├── sidebars.ts ├── src │ ├── components │ │ └── HomepageFeatures │ │ │ ├── index.tsx │ │ │ └── styles.module.css │ ├── css │ │ └── custom.css │ ├── pages │ │ ├── index.module.css │ │ └── index.tsx │ └── theme │ │ ├── ReactLiveScope │ │ └── index.js │ │ └── Root.js ├── static │ ├── .nojekyll │ ├── bg.svg │ ├── img │ │ └── favicon.ico │ └── test-sound.mp3 └── tsconfig.json ├── package-lock.json ├── package.json ├── rollup.config.mjs ├── src ├── hooks │ ├── useBattery.ts │ ├── useClickOutside.ts │ ├── useClipboard.ts │ ├── useCookie.ts │ ├── useDebounce.ts │ ├── useDebouncedCallback.ts │ ├── useDeviceOrientation.ts │ ├── useDimensions.ts │ ├── useEventListener.ts │ ├── useFavicon.ts │ ├── useFetch.ts │ ├── useFocusBlur.ts │ ├── useGeoLocation.ts │ ├── useHistory.ts │ ├── useHover.ts │ ├── useIdle.ts │ ├── useIntersectionObserver.ts │ ├── useKeyCombo.ts │ ├── useKeyPress.ts │ ├── useLocalStorage.ts │ ├── useLongPress.ts │ ├── useMediaQuery.ts │ ├── useMouse.ts │ ├── useMutationObserver.ts │ ├── useNotification.ts │ ├── useOnlineStatus.ts │ ├── usePreferredLanguage.ts │ ├── usePrevious.ts │ ├── useRandomColor.ts │ ├── useScript.ts │ ├── useScrollIntoPosition.ts │ ├── useScrollLock.ts │ ├── useScrollPosition.ts │ ├── useSessionStorage.ts │ ├── useSound.ts │ ├── useStopWatch.ts │ ├── useSystemTheme.ts │ ├── useTitle.ts │ ├── useTouch.ts │ ├── useTouchSwipe.ts │ ├── useUpdateEffect.ts │ ├── useVibration.ts │ ├── useWindowFocus.ts │ ├── useWindowScrollIntoPosition.ts │ ├── useWindowScrollPosition.ts │ ├── useWindowSize.ts │ └── useWindowTouchSwipe.ts ├── index.ts └── utils │ └── index.ts └── tsconfig.json /.github/workflows/deploy.yml: -------------------------------------------------------------------------------- 1 | name: Deploy Docusaurus site to GitHub Pages 2 | 3 | on: 4 | push: 5 | branches: 6 | - master # Adjust if your default branch is different 7 | 8 | jobs: 9 | build: 10 | runs-on: ubuntu-latest 11 | 12 | steps: 13 | - name: Checkout code 14 | uses: actions/checkout@v2 15 | 16 | - name: Set up Node.js 17 | uses: actions/setup-node@v2 18 | with: 19 | node-version: '18' # Ensure Node.js version is 18 or higher 20 | 21 | - name: Install dependencies 22 | run: npm install 23 | working-directory: ./docs 24 | 25 | - name: Build Docusaurus site 26 | run: npm run build 27 | working-directory: ./docs 28 | env: 29 | ALGOLIA_APP_ID: ${{ secrets.ALGOLIA_APP_ID }} 30 | ALGOLIA_API_KEY: ${{ secrets.ALGOLIA_API_KEY }} 31 | ALGOLIA_INDEX_NAME: ${{ secrets.ALGOLIA_INDEX_NAME }} 32 | 33 | - name: Deploy to GitHub Pages 34 | uses: peaceiris/actions-gh-pages@v3 35 | with: 36 | personal_token: ${{ secrets.ACTIONS_DEPLOY_ACCESS_TOKEN }} 37 | publish_dir: ./docs/build 38 | external_repository: jpranays/react-fast-hooks # Ensure this is your repo name 39 | force_orphan: true 40 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Node modules 2 | /node_modules 3 | 4 | # Build output 5 | /dist 6 | 7 | # Rollup cache 8 | /.rollup.cache 9 | 10 | # TypeScript build artifacts 11 | *.tsbuildinfo 12 | *.d.ts 13 | 14 | # Rollup plugin outputs (if needed) 15 | *.cjs.js 16 | *.esm.js 17 | 18 | # Log files 19 | npm-debug.log* 20 | yarn-debug.log* 21 | yarn-error.log* 22 | 23 | # OS-specific files 24 | .DS_Store 25 | Thumbs.db 26 | 27 | # Environment variables 28 | .env 29 | .env.local 30 | .env.development 31 | .env.test 32 | .env.production 33 | 34 | # IDE/Editor specific files 35 | .vscode/ 36 | .idea/ 37 | *.suo 38 | *.ntvs* 39 | *.njsproj 40 | *.sln 41 | 42 | # Jest coverage 43 | /coverage 44 | 45 | # Source maps 46 | /**/*.map 47 | 48 | # local test 49 | /local-test -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 |

5 | react-fast-hooks 6 |

7 |

8 | 9 | 10 | Install Size 11 | NPM Downloads 12 | License 13 | NPM Bundle Size 14 | Types 15 | Tree Shaking 16 | Build Passing 17 | DOCS 18 | maintained - yes 19 | Hosted with GH Pages 20 | Made with GH Actions 21 | Synk Security - monitored 22 | jsDelivr - 1.1.1 23 | 24 | 25 | 26 |

27 |
28 | 29 |

These hooks aim to simplify state management, side effects, and other common functionalities in React applications, improving both productivity and code quality.

30 | 31 | ## Features 32 | 33 | 🚀 **Lightweight and Fast** 34 | 35 | - Designed to be minimal in size, ensuring your application remains performant and fast. 36 | 37 | 🌐 **SSR-Friendly** 38 | 39 | - Built with Server-Side Rendering (SSR) compatibility, making it perfect for Next.js. 40 | 41 | 📝 **Typed with TypeScript** 42 | 43 | - Full TypeScript support, including comprehensive type definitions. 44 | 45 | 🌲 **Tree Shaking Support** 46 | 47 | - Optimized for tree shaking, ensuring only the code you use is included in your final bundle. 48 | 49 | 🌍 **Cross-Browser Compatibility** 50 | 51 | - Ensures consistent behavior across all major browsers. 52 | 53 | 🔧 **Ease of Use** 54 | 55 | - Designed with simplicity and ease of integration in mind. 56 | 57 | ## Installation 58 | 59 | ```bash 60 | npm install react-fast-hooks 61 | ``` 62 | 63 | ## Documentation 64 | 65 | For more detailed documentation and live code editor visit the [website](https://jpranays.github.io/react-fast-hooks/). 66 | 67 | ## Hooks Available 68 | 69 | - [useBattery](https://jpranays.github.io/react-fast-hooks/docs/hooks/useBattery) - A hook to get the battery status of the device. 70 | - [useClickOutside](https://jpranays.github.io/react-fast-hooks/docs/hooks/useClickOutside) - A hook to detect clicks outside a specified element. 71 | - [useClipboard](https://jpranays.github.io/react-fast-hooks/docs/hooks/useClipboard) - A hook to copy text to the clipboard. 72 | - [useCookie](https://jpranays.github.io/react-fast-hooks/docs/hooks/useCookie) - A hook to manage browser cookies. 73 | - [useDebounce](https://jpranays.github.io/react-fast-hooks/docs/hooks/useDebounce) - A hook to debounce a value. 74 | - [useDebouncedCallback](https://jpranays.github.io/react-fast-hooks/docs/hooks/useDebouncedCallback) - A hook to debounce a callback. 75 | - [useDeviceOrientation](https://jpranays.github.io/react-fast-hooks/docs/hooks/useDeviceOrientation) - A hook to get the device orientation. 76 | - [useDimensions](https://jpranays.github.io/react-fast-hooks/docs/hooks/useDimensions) - A hook to get the dimensions of an element. 77 | - [useEventListener](https://jpranays.github.io/react-fast-hooks/docs/hooks/useEventListener) - A hook to add an event listener to a target. 78 | - [useFavicon](https://jpranays.github.io/react-fast-hooks/docs/hooks/useFavicon) - A hook to change the favicon of the page. 79 | - [useFetch](https://jpranays.github.io/react-fast-hooks/docs/hooks/useFetch) - A hook to fetch data. 80 | - [useFocusBlur](https://jpranays.github.io/react-fast-hooks/docs/hooks/useFocusBlur) - A hook to detect focus and blur events. 81 | - [useGeolocation](https://jpranays.github.io/react-fast-hooks/docs/hooks/useGeolocation) - A hook to get the geolocation of the device. 82 | - [useHistory](https://jpranays.github.io/react-fast-hooks/docs/hooks/useHistory) - A hook to manage the browser history. 83 | - [useHover](https://jpranays.github.io/react-fast-hooks/docs/hooks/useHover) - A hook to detect hover events. 84 | - [useIdle](https://jpranays.github.io/react-fast-hooks/docs/hooks/useIdle) - A hook to detect when the user is idle. 85 | - [useIntersectionObserver](https://jpranays.github.io/react-fast-hooks/docs/hooks/useIntersectionObserver) - A hook to observe an element's intersection with the viewport. 86 | - [useKeyCombo](https://jpranays.github.io/react-fast-hooks/docs/hooks/useKeyCombo) - A hook to detect key combinations. 87 | - [useKeyPress](https://jpranays.github.io/react-fast-hooks/docs/hooks/useKeyPress) - A hook to detect key presses. 88 | - [useLocalStorage](https://jpranays.github.io/react-fast-hooks/docs/hooks/useLocalStorage) - A hook to manage local storage. 89 | - [useLongPress](https://jpranays.github.io/react-fast-hooks/docs/hooks/useLongPress) - A hook to detect long presses. 90 | - [useMediaQuery](https://jpranays.github.io/react-fast-hooks/docs/hooks/useMediaQuery) - A hook to detect media queries. 91 | - [useMouse](https://jpranays.github.io/react-fast-hooks/docs/hooks/useMouse) - A hook to get the mouse position. 92 | - [useMutationObserver](https://jpranays.github.io/react-fast-hooks/docs/hooks/useMutationObserver) - A hook to observe mutations on an element. 93 | - [useNotification](https://jpranays.github.io/react-fast-hooks/docs/hooks/useNotification) - A hook to show notifications. 94 | - [useOnlineStatus](https://jpranays.github.io/react-fast-hooks/docs/hooks/useOnlineStatus) - A hook to detect online status. 95 | - [usePreferredLanguage](https://jpranays.github.io/react-fast-hooks/docs/hooks/usePreferredLanguage) - A hook to get the preferred language of the user. 96 | - [usePrevious](https://jpranays.github.io/react-fast-hooks/docs/hooks/usePrevious) - A hook to get the previous value of a state. 97 | - [useRandomColor](https://jpranays.github.io/react-fast-hooks/docs/hooks/useRandomColor) - A hook to generate a random color. 98 | - [useScript](https://jpranays.github.io/react-fast-hooks/docs/hooks/useScript) - A hook to load an external script. 99 | - [useScrollIntoPosition](https://jpranays.github.io/react-fast-hooks/docs/hooks/useScrollIntoPosition) - A hook to scroll an element into view. 100 | - [useScrollLock](https://jpranays.github.io/react-fast-hooks/docs/hooks/useScrollLock) - A hook to lock scrolling. 101 | - [useScrollPosition](https://jpranays.github.io/react-fast-hooks/docs/hooks/useScrollPosition) - A hook to get the scroll position. 102 | - [useSessionStorage](https://jpranays.github.io/react-fast-hooks/docs/hooks/useSessionStorage) - A hook to manage session storage. 103 | - [useSound](https://jpranays.github.io/react-fast-hooks/docs/hooks/useSound) - A hook to play sounds. 104 | - [useStopwatch](https://jpranays.github.io/react-fast-hooks/docs/hooks/useStopwatch) - A hook to create a stopwatch. 105 | - [useSystemTheme](https://jpranays.github.io/react-fast-hooks/docs/hooks/useSystemTheme) - A hook to get the system theme. 106 | - [useTitle](https://jpranays.github.io/react-fast-hooks/docs/hooks/useTitle) - A hook to set the document title. 107 | - [useTouch](https://jpranays.github.io/react-fast-hooks/docs/hooks/useTouch) - A hook to detect touch events. 108 | - [useTouchSwipe](https://jpranays.github.io/react-fast-hooks/docs/hooks/useTouchSwipe) - A hook to detect touch swipe events. 109 | - [useUpdateEffect](https://jpranays.github.io/react-fast-hooks/docs/hooks/useUpdateEffect) - A hook to run an effect only on updates. 110 | - [useVibration](https://jpranays.github.io/react-fast-hooks/docs/hooks/useVibration) - A hook to vibrate the device. 111 | - [useWindowFocus](https://jpranays.github.io/react-fast-hooks/docs/hooks/useWindowFocus) - A hook to detect window focus. 112 | - [useWindowScrollIntoPosition](https://jpranays.github.io/react-fast-hooks/docs/hooks/useWindowScrollIntoPosition) - A hook to scroll the window to a position. 113 | - [useWindowScrollPosition](https://jpranays.github.io/react-fast-hooks/docs/hooks/useWindowScrollPosition) - A hook to get the window scroll position. 114 | - [useWindowSize](https://jpranays.github.io/react-fast-hooks/docs/hooks/useWindowSize) - A hook to get the window size. 115 | - [useWindowTouchSwipe](https://jpranays.github.io/react-fast-hooks/docs/hooks/useWindowTouchSwipe) - A hook to detect window touch swipe events. 116 | 117 | ## Contributing 118 | 119 | Contribution guidelines [coming soon](). 120 | -------------------------------------------------------------------------------- /docs/.gitignore: -------------------------------------------------------------------------------- 1 | # Dependencies 2 | /node_modules 3 | 4 | # Production 5 | /build 6 | 7 | # Generated files 8 | .docusaurus 9 | .cache-loader 10 | 11 | # Misc 12 | .DS_Store 13 | .env.local 14 | .env.development.local 15 | .env.test.local 16 | .env.production.local 17 | 18 | npm-debug.log* 19 | yarn-debug.log* 20 | yarn-error.log* 21 | -------------------------------------------------------------------------------- /docs/README.md: -------------------------------------------------------------------------------- 1 | # Website 2 | 3 | This website is built using [Docusaurus](https://docusaurus.io/), a modern static website generator. 4 | 5 | ### Installation 6 | 7 | ``` 8 | $ yarn 9 | ``` 10 | 11 | ### Local Development 12 | 13 | ``` 14 | $ yarn start 15 | ``` 16 | 17 | This command starts a local development server and opens up a browser window. Most changes are reflected live without having to restart the server. 18 | 19 | ### Build 20 | 21 | ``` 22 | $ yarn build 23 | ``` 24 | 25 | This command generates static content into the `build` directory and can be served using any static contents hosting service. 26 | 27 | ### Deployment 28 | 29 | Using SSH: 30 | 31 | ``` 32 | $ USE_SSH=true yarn deploy 33 | ``` 34 | 35 | Not using SSH: 36 | 37 | ``` 38 | $ GIT_USER= yarn deploy 39 | ``` 40 | 41 | If you are using GitHub pages for hosting, this command is a convenient way to build the website and push to the `gh-pages` branch. 42 | -------------------------------------------------------------------------------- /docs/babel.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | presets: [require.resolve('@docusaurus/core/lib/babel/preset')], 3 | }; 4 | -------------------------------------------------------------------------------- /docs/docs/hooks/useBattery.md: -------------------------------------------------------------------------------- 1 | --- 2 | id: useBattery 3 | title: useBattery 4 | sidebar_label: useBattery 5 | --- 6 | 7 | Hook to get the current battery status of the device. 8 | 9 | ### Usage 10 | 11 | ```jsx live 12 | function App() { 13 | const batteryState = useBattery(); 14 | 15 | return ( 16 |
17 | {batteryState.loading ? ( 18 |

Loading battery status...

19 | ) : !batteryState.supported ? ( 20 |

Battery API not supported on this device.

21 | ) : ( 22 |
23 |

Battery Level: {batteryState.level * 100}%

24 |

Charging: {batteryState.charging ? "Yes" : "No"}

25 |

Charging Time: {batteryState.chargingTime} seconds

26 |

Discharging Time: {batteryState.dischargingTime} seconds

27 |
28 | )} 29 |
30 | ); 31 | } 32 | ``` 33 | 34 | ### API 35 | 36 | Returns : `BatteryState` 37 | 38 | An object containing the following properties: 39 | 40 | - `supported` : A boolean indicating if the Battery API is supported. 41 | - `loading` : A boolean indicating if the battery status is currently loading. 42 | - `level` : A number or null indicating the current battery level (0 to 1). 43 | - `charging` : A boolean or null indicating whether the battery is currently charging. 44 | - `chargingTime` : A number or null indicating the time remaining until the battery is fully charged (in seconds). 45 | - `dischargingTime` : A number or null indicating the time remaining until the battery is fully discharged (in seconds). 46 | -------------------------------------------------------------------------------- /docs/docs/hooks/useClickOutside.md: -------------------------------------------------------------------------------- 1 | --- 2 | id: useClickOutside 3 | title: useClickOutside 4 | sidebar_label: useClickOutside 5 | --- 6 | 7 | Hook to detect clicks outside of a specified element. 8 | 9 | ### Usage 10 | 11 | ```jsx live 12 | function App() { 13 | const [isOpen, setIsOpen] = useState(true); 14 | const ref = useRef(null); 15 | 16 | useClickOutside(ref, () => { 17 | console.log("Clicked outside the element"); 18 | }); 19 | 20 | return ( 21 |
22 |
23 |

Click outside this element and check the console.

24 |
25 |
26 | ); 27 | } 28 | ``` 29 | 30 | ### API 31 | 32 | Parameter 33 | 34 | - `ref` : `elementRef` - The ref to the element to track clicks outside of. 35 | - `callback` : `(e:MouseEvent) => void` - The callback function to execute when a click is detected outside the element. 36 | -------------------------------------------------------------------------------- /docs/docs/hooks/useClipboard.md: -------------------------------------------------------------------------------- 1 | --- 2 | id: useClipboard 3 | title: useClipboard 4 | sidebar_label: useClipboard 5 | --- 6 | 7 | Hook to copy text to the clipboard. 8 | 9 | ### Usage 10 | 11 | ```jsx live 12 | function App() { 13 | const { copy, isCopied } = useClipboard(); 14 | 15 | return ( 16 |
17 | 20 |
21 | ); 22 | } 23 | ``` 24 | 25 | ### API 26 | 27 | Returns : `Object` 28 | 29 | An object containing the following properties: 30 | 31 | - `copy` : A function to copy the provided text to the clipboard. 32 | - `isCopied` : A boolean state that is set to true when the text is successfully copied and resets to false after 2 seconds. 33 | -------------------------------------------------------------------------------- /docs/docs/hooks/useCookie.md: -------------------------------------------------------------------------------- 1 | --- 2 | id: useCookie 3 | title: useCookie 4 | sidebar_label: useCookie 5 | --- 6 | 7 | Hook to manage browser cookies. 8 | 9 | ### Usage 10 | 11 | ```jsx live 12 | function App() { 13 | const { value, setCookie, removeCookie, hasCookie } = useCookie("myCookie"); 14 | 15 | return ( 16 |
17 |

Cookie Value: {value}

18 | 21 | 22 |

Has Cookie: {hasCookie() ? "Yes" : "No"}

23 |
24 | ); 25 | } 26 | ``` 27 | 28 | ### API 29 | 30 | Parameters: 31 | 32 | - `key` : `string` - The key of the cookie to manage. 33 | 34 | Returns: An object containing the following properties: 35 | 36 | - `value`: `string | undefined` - The value of the cookie. 37 | - `setCookie`: `(value: string, options?: CookieOptions) => void` - A function to set a cookie. 38 | - `removeCookie`: `() => void` - A function to remove the cookie. 39 | - `hasCookie`: `() => boolean` - A function to check if the cookie exists. 40 | 41 | CookieOptions: 42 | 43 | - `expires` : `number | Date` - The expiration time of the cookie. It can be in seconds or a Date object. 44 | - `path` : `string` - The path for which the cookie is valid. 45 | - `domain` : `string` - The domain for which the cookie is valid. 46 | - `secure` : `boolean` - Whether the cookie should be secure. 47 | - `sameSite` : `"Lax" | "Strict" | "None"` - The SameSite attribute of the cookie. 48 | -------------------------------------------------------------------------------- /docs/docs/hooks/useDebounce.md: -------------------------------------------------------------------------------- 1 | --- 2 | id: useDebounce 3 | title: useDebounce 4 | sidebar_label: useDebounce 5 | --- 6 | 7 | Hook to debounce a value. 8 | 9 | ### Usage 10 | 11 | ```jsx live 12 | function App() { 13 | const [text, setText] = useState(""); 14 | const debouncedText = useDebounce(text, 500); 15 | 16 | return ( 17 |
18 | setText(e.target.value)} 22 | placeholder="Type something..." 23 | /> 24 |

Debounced Text: {debouncedText}

25 |
26 | ); 27 | } 28 | ``` 29 | 30 | ### API 31 | 32 | Parameters 33 | 34 | - `value` : `any` - The value to debounce. 35 | - `delay` : `number` - The time in milliseconds to delay the value update. 36 | 37 | Returns 38 | 39 | A debounced value that is updated after the specified delay. 40 | -------------------------------------------------------------------------------- /docs/docs/hooks/useDebouncedCallback.md: -------------------------------------------------------------------------------- 1 | --- 2 | id: useDebouncedCallback 3 | title: useDebouncedCallback 4 | sidebar_label: useDebouncedCallback 5 | --- 6 | 7 | Hook to create a debounced version of a callback function. 8 | 9 | ### Usage 10 | 11 | ```jsx live 12 | function App() { 13 | const [value, setValue] = useState(""); 14 | 15 | const debouncedCallback = useDebouncedCallback((newValue) => { 16 | console.log("Debounced value:", newValue); 17 | }, 300); 18 | 19 | const handleChange = (event: React.ChangeEvent) => { 20 | setValue(event.target.value); 21 | debouncedCallback(event.target.value); 22 | }; 23 | 24 | return ( 25 |
26 | 27 |
28 | ); 29 | } 30 | ``` 31 | 32 | ### API 33 | 34 | Parameters 35 | 36 | - `callback` : `Function` - The callback function to debounce. 37 | - `delay` : `number` - The time in milliseconds to delay the callback execution. 38 | 39 | Returns 40 | 41 | A debounced version of the callback function that is executed after the specified delay. 42 | -------------------------------------------------------------------------------- /docs/docs/hooks/useDeviceOrientation.md: -------------------------------------------------------------------------------- 1 | --- 2 | id: useDeviceOrientation 3 | title: useDeviceOrientation 4 | sidebar_label: useDeviceOrientation 5 | --- 6 | 7 | Hook to get the current orientation of the device. 8 | 9 | ### Usage 10 | 11 | ```jsx live 12 | function App() { 13 | const orientation = useDeviceOrientation(); 14 | 15 | return ( 16 |
17 |

Device Orientation: {orientation}

18 |
19 | ); 20 | } 21 | ``` 22 | 23 | ### API 24 | 25 | Returns: `string` 26 | 27 | A string indicating whether the device is in portrait or landscape mode. 28 | 29 | Possible return values: "portrait" or "landscape". 30 | -------------------------------------------------------------------------------- /docs/docs/hooks/useDimensions.md: -------------------------------------------------------------------------------- 1 | --- 2 | id: useDimensions 3 | title: useDimensions 4 | sidebar_label: useDimensions 5 | --- 6 | 7 | Hook to get the dimensions (width and height) of a specified element. 8 | 9 | ### Usage 10 | 11 | ```jsx live 12 | function App() { 13 | const elementRef = useRef(null); 14 | const dimensions = useDimensions(elementRef, 200); 15 | 16 | return ( 17 |
18 |

Element Dimensions

19 |

Width: {dimensions.width}

20 |

Height: {dimensions.height}

21 |
22 | ); 23 | } 24 | ``` 25 | 26 | ### API 27 | 28 | Parameters 29 | 30 | - `ref` : `elementRef` - The ref to the element to track dimensions. 31 | - `throttleTime` : `number` - The time in milliseconds to throttle the resize event handler. Defaults to 200ms. 32 | 33 | Returns : An object with the following properties: 34 | 35 | - `width` : number - The width of the element. 36 | - `height` : number - The height of the element. 37 | -------------------------------------------------------------------------------- /docs/docs/hooks/useEventListener.md: -------------------------------------------------------------------------------- 1 | --- 2 | id: useEventListener 3 | title: useEventListener 4 | sidebar_label: useEventListener 5 | --- 6 | 7 | Hook to attach an event listener to a DOM element and clean it up on unmount. 8 | 9 | ### Usage 10 | 11 | ```jsx live 12 | function App() { 13 | const elementRef = useRef(null); 14 | 15 | useEventListener( 16 | "click", 17 | (event) => { 18 | alert("Element clicked!", event); 19 | }, 20 | elementRef 21 | ); 22 | 23 | return
Click me!
; 24 | } 25 | ``` 26 | 27 | ### API 28 | 29 | Parameters 30 | 31 | - `eventName` : `string` - The name of the event to listen for. 32 | - `handler` : `function` - The event handler function. 33 | - `ref` : `elementRef` - The ref to the element to attach the event listener. 34 | - `options` : `boolean | AddEventListenerOptions` - An options object that specifies characteristics about the event listener. Defaults to `{}`. 35 | -------------------------------------------------------------------------------- /docs/docs/hooks/useFavicon.md: -------------------------------------------------------------------------------- 1 | --- 2 | id: useFavicon 3 | title: useFavicon 4 | sidebar_label: useFavicon 5 | --- 6 | 7 | Hook to set and update the favicon of the webpage. 8 | 9 | ### Usage 10 | 11 | ```jsx live 12 | function App() { 13 | const changeFavicon = useFavicon(""); 14 | 15 | const handleFaviconChange = () => { 16 | changeFavicon("https://github.githubassets.com/favicons/favicon.svg"); 17 | }; 18 | 19 | return ( 20 |
21 |

Hello, world!

22 | 23 |
24 | ); 25 | } 26 | ``` 27 | 28 | ### API 29 | 30 | Parameter: 31 | 32 | `initialFaviconUrl`: string - The initial URL of the favicon to set. 33 | 34 | Returns : `function` 35 | 36 | A function to change the favicon of the webpage. 37 | -------------------------------------------------------------------------------- /docs/docs/hooks/useFetch.md: -------------------------------------------------------------------------------- 1 | --- 2 | id: useFetch 3 | title: useFetch 4 | sidebar_label: useFetch 5 | --- 6 | 7 | Fetch data from an API endpoint with the `useFetch` hook. 8 | 9 | ### Usage 10 | 11 | ```jsx live 12 | function App() { 13 | const { data, loading, error, refetch } = useFetch( 14 | "https://jsonplaceholder.typicode.com/posts" 15 | ); 16 | 17 | if (loading) return
Loading...
; 18 | if (error) return
Error: {error.message}
; 19 | 20 | return ( 21 |
22 | 23 |
    24 | {data?.map((post) => ( 25 |
  • {post.title}
  • 26 | ))} 27 |
28 |
29 | ); 30 | } 31 | ``` 32 | 33 | ### API 34 | 35 | Parameters 36 | 37 | - `url` : `string` - The URL of the API endpoint to fetch data from. 38 | - `options` : `RequestInit` - An object containing any custom settings that you want to apply to the request. Defaults to `{}`. 39 | 40 | - `method` : `string` - The HTTP method to use for the request. Defaults to `GET`. 41 | - `headers` : `HeadersInit` - Any headers you want to include in the request. 42 | - `body` : `BodyInit` - The body of the request. 43 | 44 | Returns : An object with the following properties: 45 | 46 | - `data` : `any` - The data fetched from the API endpoint. 47 | - `loading` : `boolean` - A boolean indicating whether the request is in progress. 48 | - `error` : `Error | null` - An error object if the request fails, `null` otherwise. 49 | - `refetch` : `() => void` - A function to refetch the data from the API endpoint. 50 | -------------------------------------------------------------------------------- /docs/docs/hooks/useFocusBlur.md: -------------------------------------------------------------------------------- 1 | --- 2 | id: useFocusBlur 3 | title: useFocusBlur 4 | sidebar_label: useFocusBlur 5 | --- 6 | 7 | Hook to get focus and blur functions for an element. 8 | 9 | ### Usage 10 | 11 | ```jsx live 12 | function App() { 13 | const inputRef = useRef(null); 14 | const { focus, blur } = useFocusBlur(inputRef); 15 | 16 | return ( 17 |
18 | 19 | 20 | 21 |
22 | ); 23 | } 24 | ``` 25 | 26 | ### API 27 | 28 | Parameter 29 | 30 | - `elementRef` : A React ref object pointing to the element whose focus and blur functions need to be tracked. 31 | 32 | Returns : An object with the following properties: 33 | 34 | - `focus` : A function to focus the element. 35 | - `blur` : A function to blur the element. 36 | -------------------------------------------------------------------------------- /docs/docs/hooks/useGeolocation.md: -------------------------------------------------------------------------------- 1 | --- 2 | id: useGeolocation 3 | title: useGeolocation 4 | sidebar_label: useGeolocation 5 | --- 6 | 7 | Hook to get the current geolocation. 8 | 9 | ### Usage 10 | 11 | ```jsx live 12 | function App() { 13 | const geolocation = useGeolocation(); 14 | 15 | return ( 16 |
17 |

Latitude: {geolocation.latitude}

18 |

Longitude: {geolocation.longitude}

19 |

Accuracy: {geolocation.accuracy} meters

20 |

Altitude: {geolocation.altitude}

21 |

Altitude Accuracy: {geolocation.altitudeAccuracy} meters

22 |

Heading: {geolocation.heading}

23 |

Speed: {geolocation.speed}

24 |

Timestamp: {new Date(geolocation.timestamp).toLocaleString()}

25 | {geolocation.error && ( 26 |

Error: {geolocation.error.message}

27 | )} 28 |
29 | ); 30 | } 31 | ``` 32 | 33 | ### API 34 | 35 | Returns : `Geolocation` 36 | 37 | An `Geolocation` containing the following properties: 38 | 39 | - `latitude` : The latitude in decimal degrees. 40 | - `longitude` : The longitude in decimal degrees. 41 | - `accuracy` : The accuracy of the latitude and longitude in meters. 42 | - `altitude` : The altitude in meters above the reference ellipsoid. 43 | - `altitudeAccuracy` : The accuracy of the altitude in meters. 44 | - `heading` : The direction of travel in degrees. 45 | - `speed` : The speed in meters per second. 46 | - `timestamp` : The time at which the location or error was occurred. 47 | - `error` : `GeolocationError` 48 | 49 | An `GeolocationError` containing the following properties: 50 | 51 | - `code` : The error code. 52 | - `message` : The error message. 53 | -------------------------------------------------------------------------------- /docs/docs/hooks/useHistory.md: -------------------------------------------------------------------------------- 1 | --- 2 | id: useHistory 3 | title: useHistory 4 | sidebar_label: useHistory 5 | --- 6 | 7 | Hook to manage browser history. 8 | 9 | ### Usage 10 | 11 | ```jsx live 12 | function App() { 13 | const { push, replace, goBack, goForward, state } = useHistory(); 14 | 15 | return ( 16 |
17 | 20 | 23 | 24 | 25 |
Current State: {JSON.stringify(state)}
26 |
27 | ); 28 | } 29 | ``` 30 | 31 | ### API 32 | 33 | Returns : An object with the following properties: 34 | 35 | - `history` : `History` - The history object. 36 | - `state` : `HistoryState | null` - The current state object. 37 | - `push` : `(path: string, state?: HistoryState) => void` - Pushes a new entry onto the history stack. 38 | - `replace` : `(path: string, state?: HistoryState) => void` - Replaces the current entry on the history stack. 39 | - `goBack` : `() => void` - Moves back one entry in the history stack. 40 | - `goForward` : `() => void` - Moves forward one entry in the history stack. 41 | -------------------------------------------------------------------------------- /docs/docs/hooks/useHover.md: -------------------------------------------------------------------------------- 1 | --- 2 | id: useHover 3 | title: useHover 4 | sidebar_label: useHover 5 | --- 6 | 7 | Hook to determine if an element is hovered. 8 | 9 | ### Usage 10 | 11 | ```jsx live 12 | function App() { 13 | const elementRef = useRef(null); 14 | const isHovered = useHover(elementRef); 15 | 16 | return ( 17 |
24 | {isHovered ? "Hovered!" : "Hover over me!"} 25 |
26 | ); 27 | } 28 | ``` 29 | 30 | ### API 31 | 32 | Parameter 33 | 34 | ref : `elementRef` - The ref to the element to track hover state. 35 | 36 | Returns : `boolean` 37 | 38 | An boolean indicating if the element is hovered or not. 39 | -------------------------------------------------------------------------------- /docs/docs/hooks/useIdle.md: -------------------------------------------------------------------------------- 1 | --- 2 | id: useIdle 3 | title: useIdle 4 | sidebar_label: useIdle 5 | --- 6 | 7 | Hook to detect user inactivity. 8 | 9 | ### Usage 10 | 11 | ```jsx live 12 | function App() { 13 | const isIdle = useIdle({ timeout: 5000 }); 14 | 15 | return ( 16 |
17 |

User Idle Hook

18 |

{isIdle ? "User is idle" : "User is active"}

19 |
20 | ); 21 | } 22 | ``` 23 | 24 | ### API 25 | 26 | Parameter: 27 | 28 | - `options` : `UseIdleOptions` - An object specifying the timeout in milliseconds. 29 | 30 | - `UseIdleOptions` includes the following properties: 31 | 32 | - `timeout` : `number` - The time in milliseconds to consider the user as idle. 33 | 34 | Returns : A boolean value indicating whether the user is idle or not, updated in real-time. Useful for tracking user inactivity. 35 | -------------------------------------------------------------------------------- /docs/docs/hooks/useIntersectionObserver.md: -------------------------------------------------------------------------------- 1 | --- 2 | id: useIntersectionObserver 3 | title: useIntersectionObserver 4 | sidebar_label: useIntersectionObserver 5 | --- 6 | 7 | Hook to observe the visibility of an element using the Intersection Observer API. 8 | 9 | ### Usage 10 | 11 | ```jsx live 12 | function App() { 13 | const elementRef = useRef(null); 14 | 15 | const entry = useIntersectionObserver(elementRef, { 16 | threshold: 1, 17 | }); 18 | 19 | return ( 20 |
21 |
28 | {entry?.isIntersecting ? "In view" : "Out of view"} 29 |
30 |
31 | ); 32 | } 33 | ``` 34 | 35 | ### API 36 | 37 | Parameters 38 | 39 | - `options` : `IntersectionObserverOptions` - The Intersection Observer options. These include: 40 | - `root` : `Element` - The element that is used as the viewport for checking visibility of the target. 41 | - `rootMargin` : `string` - Margin around the root. 42 | - `threshold` : `number | number[]` - A single number or an array of numbers which indicate at what percentage of the target's visibility the observer's callback should be executed. 43 | 44 | Returns 45 | 46 | - `observer` : `(node: Element | null) => void` - A callback ref to set the target element to be observed. 47 | - `entry` : `IntersectionObserverEntry | null` - The IntersectionObserverEntry providing information about the intersection of the target with the root. 48 | -------------------------------------------------------------------------------- /docs/docs/hooks/useKeyCombo.md: -------------------------------------------------------------------------------- 1 | --- 2 | id: useKeyCombo 3 | title: useKeyCombo 4 | sidebar_label: useKeyCombo 5 | --- 6 | 7 | Hook to detect if a specified key combination is pressed. 8 | 9 | ### Usage 10 | 11 | ```jsx live 12 | function App() { 13 | const isCtrlShiftPressed = useKeyCombo(["Control", "Shift"]); 14 | 15 | return ( 16 |
17 |

Press the Ctrl + Shift keys

18 | {isCtrlShiftPressed &&

Ctrl + Shift keys are pressed!

} 19 |
20 | ); 21 | } 22 | ``` 23 | 24 | ### API 25 | 26 | Parameter 27 | 28 | - `keys` : `string[]` - An array of keys to detect. 29 | 30 | Returns : `boolean` 31 | 32 | A boolean indicating if the specified key combination is pressed or not. 33 | -------------------------------------------------------------------------------- /docs/docs/hooks/useKeyPress.md: -------------------------------------------------------------------------------- 1 | --- 2 | id: useKeyPress 3 | title: useKeyPress 4 | sidebar_label: useKeyPress 5 | --- 6 | 7 | Hook to detect if a specified key is pressed. 8 | 9 | ### Usage 10 | 11 | ```jsx live 12 | function App() { 13 | const isEnterPressed = useKeyPress("Enter"); 14 | 15 | return ( 16 |
17 |

Press the Enter key

18 | {isEnterPressed &&

Enter key is pressed!

} 19 |
20 | ); 21 | } 22 | ``` 23 | 24 | ### API 25 | 26 | Parameter 27 | 28 | - `key` : `string` - The key to detect. 29 | 30 | Returns : `boolean` 31 | 32 | A boolean indicating if the specified key is pressed or not. 33 | -------------------------------------------------------------------------------- /docs/docs/hooks/useLocalStorage.md: -------------------------------------------------------------------------------- 1 | --- 2 | id: useLocalStorage 3 | title: useLocalStorage 4 | sidebar_label: useLocalStorage 5 | --- 6 | 7 | Hook to manage a value that syncs with localStorage. 8 | 9 | ### Usage 10 | 11 | ```jsx live 12 | function App() { 13 | const [name, setName] = useLocalStorage("name", "John Doe"); 14 | 15 | return ( 16 |
17 |

Name: {name}

18 | setName(e.target.value)} 22 | /> 23 |
24 | ); 25 | } 26 | ``` 27 | 28 | ### API 29 | 30 | Parameter 31 | 32 | - `key` : string - The key to store the value in localStorage. 33 | - `initialValue` : T - The initial value to store in localStorage. 34 | 35 | Returns : An array with the following elements: 36 | 37 | - `value` : T - The value stored in localStorage. 38 | - `setValue` : (value: T) => void - A function to set the value in localStorage. 39 | -------------------------------------------------------------------------------- /docs/docs/hooks/useLongPress.md: -------------------------------------------------------------------------------- 1 | --- 2 | id: useLongPress 3 | title: useLongPress 4 | sidebar_label: useLongPress 5 | --- 6 | 7 | Enable precise control of long-press interactions for both touch and mouse events with `useLongPress`. 8 | 9 | ### Usage 10 | 11 | ```jsx live 12 | function App() { 13 | const buttonRef = useRef(null); 14 | 15 | const onLongPress = () => { 16 | console.log("Long press triggered!"); 17 | alert("Long press triggered!"); 18 | }; 19 | 20 | const onPress = () => { 21 | console.log("Press started!"); 22 | }; 23 | 24 | const onRelease = () => { 25 | console.log("Press released!"); 26 | }; 27 | 28 | useLongPress(buttonRef, { 29 | threshold: 1500, 30 | onLongPress, 31 | onPress, 32 | onRelease, 33 | }); 34 | 35 | return ; 36 | } 37 | ``` 38 | 39 | ### API 40 | 41 | Parameters 42 | 43 | - `ref` : `elementRef` - The ref to the element to track long press interactions. 44 | - `options` : `LongPressOptions` - An object with the following properties: 45 | - `threshold` : `number` - The time in milliseconds to trigger the long press event. Defaults to 500ms. 46 | - `onLongPress` : `() => void` - The function to call when the long press event is triggered. 47 | - `onPress` : `() => void` - The function to call when the press event starts. 48 | - `onRelease` : `() => void` - The function to call when the press event is released. 49 | -------------------------------------------------------------------------------- /docs/docs/hooks/useMediaQuery.md: -------------------------------------------------------------------------------- 1 | --- 2 | id: useMediaQuery 3 | title: useMediaQuery 4 | sidebar_label: useMediaQuery 5 | --- 6 | 7 | Hook to detect media query matches. 8 | 9 | ### Usage 10 | 11 | ```jsx live 12 | function App() { 13 | const isMobile = useMediaQuery("(max-width: 600px)"); 14 | 15 | const isDesktop = useMediaQuery("(min-width: 1024px)"); 16 | 17 | return ( 18 | <> 19 |
20 |

Mobile View : {isMobile ? "true" : "false"}

21 |
22 |
23 |

Desktop View : {isDesktop ? "true" : "false"}

24 |
25 | 26 | ); 27 | } 28 | ``` 29 | 30 | ### API 31 | 32 | Parameter 33 | 34 | - `query` : A string representing the media query to match. 35 | 36 | Returns : `boolean` 37 | 38 | A boolean indicating if the media query matches or not. 39 | -------------------------------------------------------------------------------- /docs/docs/hooks/useMouse.md: -------------------------------------------------------------------------------- 1 | --- 2 | id: useMouse 3 | title: useMouse 4 | sidebar_label: useMouse 5 | --- 6 | 7 | Hook to track the mouse position relative to a specified element. 8 | 9 | ### Usage 10 | 11 | ```jsx live 12 | function App() { 13 | const elementRef = useRef(null); 14 | const { x, y, elementX, elementY, pageX, pageY } = useMouse(elementRef); 15 | 16 | return ( 17 |
21 |

Mouse Position

22 |

23 | Relative to Element - X: {x}, Y: {y} 24 |

25 |

26 | Element X: {elementX}, Element Y: {elementY} 27 |

28 |

29 | Page X: {pageX}, Page Y: {pageY} 30 |

31 |
32 | ); 33 | } 34 | ``` 35 | 36 | ### API 37 | 38 | Parameters 39 | 40 | - `ref` : `elementRef` - The ref to the element to track mouse position. 41 | 42 | Returns : An object with the following properties: 43 | 44 | - `x` : number - The x position of the mouse relative to the element. 45 | - `y` : number - The y position of the mouse relative to the element. 46 | - `elementX` : number - The x position of the mouse relative to the viewport. 47 | - `elementY` : number - The y position of the mouse relative to the viewport. 48 | - `pageX` : number - The x position of the mouse relative to the page. 49 | - `pageY` : number - The y position of the mouse relative to the page. 50 | -------------------------------------------------------------------------------- /docs/docs/hooks/useMutationObserver.md: -------------------------------------------------------------------------------- 1 | --- 2 | id: useMutationObserver 3 | title: useMutationObserver 4 | sidebar_label: useMutationObserver 5 | --- 6 | 7 | Hook to observe changes to a DOM element using MutationObserver. 8 | 9 | ### Usage 10 | 11 | ```jsx live 12 | function App() { 13 | const elementRef = useRef(null); 14 | 15 | useMutationObserver( 16 | elementRef, 17 | (mutations) => { 18 | mutations.forEach((mutation) => { 19 | console.log(mutation); 20 | }); 21 | }, 22 | { 23 | childList: true, 24 | attributes: true, 25 | } 26 | ); 27 | 28 | return ( 29 |
30 | // Try changing the style of this element from the dev tools 31 |

Observe changes to this element

32 |
33 | ); 34 | } 35 | ``` 36 | 37 | ### API 38 | 39 | Parameters: 40 | 41 | - `ref` - The React ref to the element to observe. 42 | - `callback` - A function to handle mutations. 43 | - `options` : `UseMutationObserverOptions` - An object specifying which DOM mutations to observe. 44 | 45 | `UseMutationObserverOptions` includes the following properties: 46 | 47 | - `childList` : `boolean` - Set to `true` to observe changes to the children of the target element. 48 | - `attributes` : `boolean` - Set to `true` to observe changes to the attributes of the target element. 49 | - `characterData` : `boolean` - Set to `true` to observe changes to the data of the target element. 50 | - `subtree` : `boolean` - Set to `true` to observe changes to the descendants of the target element. 51 | - `attributeOldValue` : `boolean` - Set to `true` to record the previous value of attribute mutations. 52 | - `characterDataOldValue` : `boolean` - Set to `true` to record the previous value of character data mutations. 53 | - `attributeFilter` : `string[]` - An array of attribute names to observe. If omitted, all attributes will be observed. 54 | - `characterDataOldValue` : `boolean` - Set to `true` to record the previous value of character data before it was changed. 55 | -------------------------------------------------------------------------------- /docs/docs/hooks/useNotification.md: -------------------------------------------------------------------------------- 1 | --- 2 | id: useNotification 3 | title: useNotification 4 | sidebar_label: useNotification 5 | --- 6 | 7 | Hook to trigger browser notifications. 8 | 9 | ### Usage 10 | 11 | ```jsx live 12 | function App() { 13 | const { 14 | permission, 15 | showNotification, 16 | requestPermission, 17 | updateNotification, 18 | } = useNotification("Hello!", { 19 | body: "This is a notification body", 20 | icon: "/path/to/icon.png", 21 | }); 22 | 23 | useEffect(() => { 24 | if (permission === "granted") { 25 | showNotification(); 26 | } else if (permission === "default") { 27 | requestPermission(); 28 | } 29 | }, [permission, showNotification, requestPermission]); 30 | 31 | const handleUpdateNotification = () => { 32 | updateNotification("Updated Title!", { 33 | body: "This is an updated notification body", 34 | icon: "/path/to/updated-icon.png", 35 | }); 36 | }; 37 | 38 | return ( 39 |
40 | 41 | 42 |
43 | ); 44 | } 45 | ``` 46 | 47 | ### API 48 | 49 | Parameters 50 | 51 | - `title` : `string` - The title of the notification. 52 | - `options` : `NotificationOptions` - Optional configuration for the notification. These include: 53 | - `body` : `string` - The body text of the notification. 54 | - `icon` : `string` - The URL of an icon to be displayed with the notification. 55 | - `dir` : `NotificationDirection` - The direction of the notification; it can be auto, ltr, or rtl. 56 | - `lang` : `string` - The language of the notification. 57 | - `tag` : `string` - An identifying tag for the notification. 58 | - `renotify` : `boolean` - Whether to re-notify if a notification with the same tag is already displayed. 59 | - `silent` : `boolean` - Whether the notification should be silent. 60 | - `requireInteraction` : `boolean` - Whether the notification should remain active until the user clicks or dismisses it. 61 | - `badge` : `string` - URL of an image to represent the notification when there is not enough space to display the icon. 62 | - `vibrate` : `number | number[]` - A vibration pattern for the device. 63 | - `timestamp` : `number` - The time the notification was created. 64 | - `image` : `string` - URL of an image to be displayed with the notification. 65 | 66 | Returns 67 | 68 | - `permission` : `NotificationPermission` - The current permission status for notifications. 69 | - `showNotification` : `() => void` - A function to trigger the notification. 70 | - `requestPermission` : `() => void` - A function to request notification permission from the user. 71 | - `updateNotification` : `(newTitle: string, newOptions: NotificationOptions) => void` - A function to update the notification with new title and options. 72 | -------------------------------------------------------------------------------- /docs/docs/hooks/useOnlineStatus.md: -------------------------------------------------------------------------------- 1 | --- 2 | id: useOnlineStatus 3 | title: useOnlineStatus 4 | sidebar_label: useOnlineStatus 5 | --- 6 | 7 | Hook to get the online status of the browser. 8 | 9 | ### Usage 10 | 11 | ```jsx live 12 | function App() { 13 | const isOnline = useOnlineStatus(); 14 | 15 | return ( 16 |
17 |

{isOnline ? "You are online" : "You are offline"}

18 |
19 | ); 20 | } 21 | ``` 22 | 23 | ### API 24 | 25 | Returns : `boolean` 26 | 27 | A boolean indicating whether the browser is online or offline. 28 | -------------------------------------------------------------------------------- /docs/docs/hooks/usePreferredLanguage.md: -------------------------------------------------------------------------------- 1 | --- 2 | id: usePreferredLanguage 3 | title: usePreferredLanguage 4 | sidebar_label: usePreferredLanguage 5 | --- 6 | 7 | Hook to get the user's preferred language from the browser. 8 | 9 | ### Usage 10 | 11 | ```jsx live 12 | function App() { 13 | const { language, languages, isSupported } = usePreferredLanguage(); 14 | 15 | return ( 16 |
17 | {isSupported ? ( 18 |

Your preferred language is: {language}

19 | ) : ( 20 |

Preferred language detection is not supported on this device.

21 | )} 22 |
23 | ); 24 | } 25 | ``` 26 | 27 | ### API 28 | 29 | Returns : An object with the following properties: 30 | 31 | - `language` : `string` - The user's preferred language. 32 | - `languages` : `string[]` - An array of the user's preferred languages. 33 | - `isSupported` : `boolean` - A boolean indicating whether preferred language detection is supported on the device. 34 | -------------------------------------------------------------------------------- /docs/docs/hooks/usePrevious.md: -------------------------------------------------------------------------------- 1 | --- 2 | id: usePrevious 3 | title: usePrevious 4 | sidebar_label: usePrevious 5 | --- 6 | 7 | Hook to get the previous value of a state or prop. 8 | 9 | ### Usage 10 | 11 | ```jsx live 12 | function App() { 13 | const [count, setCount] = useState(0); 14 | const prevCount = usePrevious(count); 15 | 16 | useEffect(() => { 17 | console.log(`Current count: ${count}, Previous count: ${prevCount}`); 18 | }, [prevCount, count]); 19 | 20 | return ( 21 |
22 |

Current count: {count}

23 |

Previous count: {prevCount}

24 | 25 |
26 | ); 27 | } 28 | ``` 29 | 30 | ### API 31 | 32 | Parameter: 33 | 34 | - `value` : `any` - The value to track. 35 | 36 | Returns: 37 | 38 | The previous value of the specified value, updated in real-time. Useful for tracking state or prop changes. 39 | -------------------------------------------------------------------------------- /docs/docs/hooks/useRandomColor.md: -------------------------------------------------------------------------------- 1 | --- 2 | id: useRandomColor 3 | title: useRandomColor 4 | sidebar_label: useRandomColor 5 | --- 6 | 7 | Hook to generate a random color. 8 | 9 | ### Usage 10 | 11 | ```jsx live 12 | function App() { 13 | const { color, generateNewColor } = useRandomColor(); 14 | 15 | return ( 16 |
17 |

Random Color Background

18 | 19 |
20 | ); 21 | } 22 | ``` 23 | 24 | ### API 25 | 26 | Returns: 27 | 28 | An object containing the following properties: 29 | 30 | - `color`: A string representing the current random color. 31 | - `generateNewColor`: A function that generates a new random color and updates the `color` property. 32 | -------------------------------------------------------------------------------- /docs/docs/hooks/useScript.md: -------------------------------------------------------------------------------- 1 | --- 2 | id: useScript 3 | title: useScript 4 | sidebar_label: useScript 5 | --- 6 | 7 | Hook to dynamically load an external script. 8 | 9 | ### Usage 10 | 11 | ```jsx live 12 | function App() { 13 | const { loading, error } = useScript( 14 | "https://example.com/external-script.js", 15 | { 16 | removeOnUnmount: true, 17 | async: true, 18 | defer: true, 19 | } 20 | ); 21 | 22 | if (loading) return
Loading script...
; 23 | if (error) return
Error loading script: {error.message}
; 24 | 25 | return ( 26 |
27 |

Script Loaded Successfully

28 | {/* Your component code */} 29 |
30 | ); 31 | } 32 | ``` 33 | 34 | ### API 35 | 36 | Parameter 37 | 38 | - `url` : string - The URL of the script to load. 39 | - `options` : object - An object with the following properties: 40 | - `removeOnUnmount` : boolean - Whether to remove the script when the component unmounts. Defaults to `false`. 41 | - `async` : boolean - Whether to load the script asynchronously. Defaults to `true`. 42 | - `defer` : boolean - Whether to load the script with the `defer` attribute. Defaults to `false`. 43 | 44 | Returns : An object with the following properties: 45 | 46 | - `loading` : boolean - A boolean value indicating whether the script is still loading. 47 | - `error` : Error | null - An error object if the script loading failed, otherwise `null`. 48 | -------------------------------------------------------------------------------- /docs/docs/hooks/useScrollIntoPosition.md: -------------------------------------------------------------------------------- 1 | --- 2 | id: useScrollIntoPosition 3 | title: useScrollIntoPosition 4 | sidebar_label: useScrollIntoPosition 5 | --- 6 | 7 | Hook to scroll an element to a specific position. 8 | 9 | ### Usage 10 | 11 | ```jsx live 12 | function App() { 13 | const elementRef = useRef(null); 14 | const scrollToPosition = useScrollIntoPosition(elementRef); 15 | 16 | const handleScroll = () => { 17 | scrollToPosition({ x: 100, y: 200, behavior: "smooth" }); 18 | }; 19 | 20 | return ( 21 |
22 |
26 | {/* Content here */} 27 |
28 |
29 | 30 |
31 | ); 32 | } 33 | ``` 34 | 35 | ### API 36 | 37 | Parameter 38 | 39 | `elementRef` : A ref to the element that you want to scroll. 40 | 41 | Returns : `ScrollToPosition` 42 | 43 | A function to scroll the element to the specified x and y coordinates. 44 | 45 | Function parameters 46 | 47 | `x` : A number indicating the x-coordinate to scroll to. 48 | 49 | `y` : A number indicating the y-coordinate to scroll to. 50 | 51 | `behavior` : A string indicating the scroll behavior ('auto' or 'smooth'). Defaults to 'auto'. 52 | -------------------------------------------------------------------------------- /docs/docs/hooks/useScrollLock.md: -------------------------------------------------------------------------------- 1 | --- 2 | id: useScrollLock 3 | title: useScrollLock 4 | sidebar_label: useScrollLock 5 | --- 6 | 7 | Hook to lock and unlock scrolling on the body element with an extra layer of security using MutationObserver. 8 | 9 | ### Usage 10 | 11 | ```jsx live 12 | function App() { 13 | const { lockScroll, unlockScroll, isLocked } = useScrollLock(); 14 | 15 | return ( 16 |
17 | 18 | 19 |

{`Scroll is ${isLocked ? "locked" : "unlocked"}`}

20 |
21 | ); 22 | } 23 | ``` 24 | 25 | ### API 26 | 27 | Returns 28 | 29 | - `lockScroll` : `() => void` - Locks scrolling on the body element. 30 | - `unlockScroll` : `() => void` - Unlocks scrolling on the body element. 31 | - `isLocked` : `boolean` - A boolean indicating if the scroll is locked or not. 32 | -------------------------------------------------------------------------------- /docs/docs/hooks/useScrollPosition.md: -------------------------------------------------------------------------------- 1 | --- 2 | id: useScrollPosition 3 | title: useScrollPosition 4 | sidebar_label: useScrollPosition 5 | --- 6 | 7 | Hook to get the current scroll position of a specified element. 8 | 9 | ### Usage 10 | 11 | ```jsx live 12 | function App() { 13 | const elementRef = useRef(null); 14 | const scrollPosition = useScrollPosition(elementRef, 200); // Throttle time is 200ms 15 | 16 | return ( 17 |
18 |
22 | {/* Content goes here */} 23 |
24 |
25 |

26 | Scroll X: {scrollPosition.x}, Scroll Y: {scrollPosition.y} 27 |

28 |
29 | ); 30 | } 31 | ``` 32 | 33 | ### API 34 | 35 | Parameter 36 | `elementRef` : A React ref object pointing to the element whose scroll position needs to be tracked. 37 | 38 | - `throttleTime` : A number indicating the time in milliseconds to throttle the window resize event. Defaults to 200. 39 | 40 | Returns : `ScrollPosition` 41 | 42 | - `x` : A number or null indicating the current horizontal scroll position of the window. 43 | - `y` : A number or null indicating the current vertical scroll position of the window. 44 | -------------------------------------------------------------------------------- /docs/docs/hooks/useSessionStorage.md: -------------------------------------------------------------------------------- 1 | --- 2 | id: useSessionStorage 3 | title: useSessionStorage 4 | sidebar_label: useSessionStorage 5 | --- 6 | 7 | Hook to manage a value that syncs with sessionStorage. 8 | 9 | ### Usage 10 | 11 | ```jsx live 12 | function App() { 13 | const [name, setName] = useSessionStorage < string > ("name", "John Doe"); 14 | 15 | return ( 16 |
17 |

Name: {name}

18 | setName(e.target.value)} 22 | /> 23 |
24 | ); 25 | } 26 | ``` 27 | 28 | ### API 29 | 30 | Parameter 31 | 32 | - `key` : string - The key to store the value in sessionStoage. 33 | - `initialValue` : T - The initial value to store in sessionStoage. 34 | 35 | Returns : An array with the following elements: 36 | 37 | - `value` : T - The value stored in sessionStoage. 38 | - `setValue` : (value: T) => void - A function to set the value in sessionStoage. 39 | -------------------------------------------------------------------------------- /docs/docs/hooks/useSound.md: -------------------------------------------------------------------------------- 1 | --- 2 | id: useSound 3 | title: useSound 4 | sidebar_label: useSound 5 | --- 6 | 7 | Hook to play and manage sound effects. 8 | 9 | ### Usage 10 | 11 | ```jsx live 12 | function App() { 13 | const { play, pause, stop, setVolume, isPlaying, error } = useSound( 14 | "https://file-examples.com/storage/fe44eeb9cb66ab8ce934f14/2017/11/file_example_MP3_700KB.mp3" 15 | ); 16 | 17 | return ( 18 |
19 | 22 | 25 | 28 |

29 | 30 | setVolume(Number(e.target.value))} 36 | /> 37 |

{isPlaying ? "Playing" : "Paused"}

38 |

39 | {error &&

Error loading sound: {error.message}

} 40 |
41 | ); 42 | } 43 | ``` 44 | 45 | ### API 46 | 47 | Parameters 48 | 49 | - `src` : `string` - The URL of the sound file to play. 50 | 51 | Returns : Object containing the following properties: 52 | 53 | - `play`: `() => void` - A function to play the sound. 54 | - `pause`: `() => void` - A function to pause the sound. 55 | - `stop`: `() => void` - A function to stop the sound. 56 | - `setVolume`: `(volume: number) => void` - A function to set the volume of the sound. 57 | - `isPlaying`: `boolean` - Whether the sound is currently playing. 58 | - `error`: `Error | null` - The error object if the sound fails to load. 59 | -------------------------------------------------------------------------------- /docs/docs/hooks/useStopwatch.md: -------------------------------------------------------------------------------- 1 | --- 2 | id: useStopwatch 3 | title: useStopwatch 4 | sidebar_label: useStopwatch 5 | --- 6 | 7 | Hook to provide stopwatch functionality with SSR compatibility. 8 | 9 | ### Usage 10 | 11 | ```jsx live 12 | function App() { 13 | const { time, isRunning, start, stop, reset } = useStopwatch(); 14 | 15 | return ( 16 |
17 |

{time} seconds

18 | 21 | 24 | 25 |
26 | ); 27 | } 28 | ``` 29 | 30 | ### API 31 | 32 | Returns : An object with the following properties: 33 | 34 | - `time` : The current time elapsed in seconds. 35 | - `isRunning` : A boolean indicating whether the stopwatch is running. 36 | - `start` : A function to start the stopwatch. 37 | - `stop` : A function to stop the stopwatch. 38 | - `reset` : A function to reset the stopwatch. 39 | -------------------------------------------------------------------------------- /docs/docs/hooks/useSystemTheme.md: -------------------------------------------------------------------------------- 1 | --- 2 | id: useSystemTheme 3 | title: useSystemTheme 4 | sidebar_label: useSystemTheme 5 | --- 6 | 7 | Hook to get the current system theme. 8 | 9 | ### Usage 10 | 11 | ```jsx live 12 | function App() { 13 | const theme = useSystemTheme(); 14 | 15 | return ( 16 |
17 |

Current System Theme: {theme}

18 |
19 | ); 20 | } 21 | ``` 22 | 23 | ### API 24 | 25 | Returns : `Theme` 26 | 27 | The current system theme, either light or dark. 28 | -------------------------------------------------------------------------------- /docs/docs/hooks/useTitle.md: -------------------------------------------------------------------------------- 1 | --- 2 | id: useTitle 3 | title: useTitle 4 | sidebar_label: useTitle 5 | --- 6 | 7 | Hook to set and get the document title. 8 | 9 | ### Usage 10 | 11 | ```jsx live 12 | function App() { 13 | const { setTitle } = useTitle("Initial Title"); 14 | 15 | const changeTitle = () => { 16 | setTitle("New Title"); 17 | }; 18 | 19 | return ( 20 |
21 | 22 |
23 | ); 24 | } 25 | ``` 26 | 27 | ### API 28 | 29 | Parameter : `initialTitle*: string` 30 | 31 | Returns : `Object` 32 | 33 | - `setTitle` : (newTitle: string) => void - A function to set the document title. 34 | -------------------------------------------------------------------------------- /docs/docs/hooks/useTouch.md: -------------------------------------------------------------------------------- 1 | --- 2 | id: useTouch 3 | title: useTouch 4 | sidebar_label: useTouch 5 | --- 6 | 7 | Hook to track touch events on a specified element. 8 | 9 | ### Usage 10 | 11 | ```jsx live 12 | function App() { 13 | const elementRef = useRef(null); 14 | const { touchStart, touchMove, touchEnd } = useTouch(elementRef); 15 | 16 | return ( 17 |
21 |

22 | Touch Start: {touchStart.x}, {touchStart.y} 23 |

24 |

25 | Touch Move: {touchMove.x}, {touchMove.y} 26 |

27 |

28 | Touch End: {touchEnd.x}, {touchEnd.y} 29 |

30 |
31 | ); 32 | } 33 | ``` 34 | 35 | ### API 36 | 37 | Parameter : `elementRef` : `React.RefObject` - The reference to the element to track touch events on. 38 | 39 | Returns : An object with the following properties: 40 | 41 | - `touchStart` : `TouchCoordinates` - The coordinates of the touch start event. 42 | - `touchMove` : `TouchCoordinates` - The coordinates of the touch move event. 43 | - `touchEnd` : `TouchCoordinates` - The coordinates of the touch end event. 44 | - `TouchCoordinates` : `{ x: number, y: number }` - The x and y coordinates of the touch event. 45 | -------------------------------------------------------------------------------- /docs/docs/hooks/useTouchSwipe.md: -------------------------------------------------------------------------------- 1 | --- 2 | id: useTouchSwipe 3 | title: useTouchSwipe 4 | sidebar_label: useTouchSwipe 5 | --- 6 | 7 | Hook to detect touch swipe gestures on a specified element. 8 | 9 | ### Usage 10 | 11 | ```jsx live 12 | function App() { 13 | const elementRef = useRef(null); 14 | const { swipeState, reset } = useTouchSwipe(elementRef); 15 | 16 | return ( 17 | <> 18 |
22 |

Swipe direction: {swipeState.direction ?? "Please swipe"}

23 |
24 | 25 | 26 | ); 27 | } 28 | ``` 29 | 30 | ### API 31 | 32 | Parameter : `elementRef` : `React.RefObject` - The reference to the element to detect touch swipe gestures on. 33 | 34 | Returns : An object with the following properties: 35 | 36 | - `swipeState` : `SwipeState` - The swipe state object. 37 | - `SwipeState` : `{ direction: SwipeDirection, x: number, y: number }` - 38 | - The direction of the swipe and the x and y coordinates of the swipe event. 39 | - `SwipeDirection` : `'up' | 'down' | 'left' | 'right'` - The direction of the swipe. 40 | - `x` : `number` - The x coordinate of the swipe event. 41 | - `y` : `number` - The y coordinate of the swipe event. 42 | - `reset` : `() => void` - Resets the swipe state. 43 | -------------------------------------------------------------------------------- /docs/docs/hooks/useUpdateEffect.md: -------------------------------------------------------------------------------- 1 | --- 2 | id: useUpdateEffect 3 | title: useUpdateEffect 4 | sidebar_label: useUpdateEffect 5 | --- 6 | 7 | Hook that runs an effect only when the component updates, skipping the initial render. 8 | 9 | ### Usage 10 | 11 | ```jsx live 12 | function App() { 13 | const [count, setCount] = useState(0); 14 | 15 | useUpdateEffect(() => { 16 | console.log("Effect runs on updates only"); 17 | }, [count]); 18 | 19 | return ( 20 |
21 |

Count: {count}

22 | 23 |
24 | ); 25 | } 26 | ``` 27 | 28 | ### API 29 | 30 | Parameters 31 | 32 | - `effect` : `Function` - The effect function to run. 33 | - `deps` : `DependencyList` - The dependencies to watch for changes. The effect will run only when these dependencies change. 34 | -------------------------------------------------------------------------------- /docs/docs/hooks/useVibration.md: -------------------------------------------------------------------------------- 1 | --- 2 | id: useVibration 3 | title: useVibration 4 | sidebar_label: useVibration 5 | --- 6 | 7 | Hook to manage vibration on supported devices. 8 | 9 | ### Usage 10 | 11 | ```jsx live 12 | function App() { 13 | const { vibrate, stop, isSupported, error } = useVibration(); 14 | 15 | return ( 16 |
17 | 18 | 19 |

20 | {isSupported 21 | ? "Vibration is supported on this device." 22 | : "Vibration is not supported on this device."} 23 |

24 | {error &&

Error: {error.message}

} 25 |
26 | ); 27 | } 28 | ``` 29 | 30 | ### API 31 | 32 | Returns : An object with the following properties: 33 | 34 | - `vibrate` : `(pattern: number | number[]) => void` - Function to start vibration with the given pattern. 35 | - `stop` : `() => void` - Function to stop vibration. 36 | - `isSupported` : `boolean` - A boolean indicating whether vibration is supported on the device. 37 | - `error` : `Error | null` - An error object if an error occurred while trying to vibrate. 38 | -------------------------------------------------------------------------------- /docs/docs/hooks/useWindowFocus.md: -------------------------------------------------------------------------------- 1 | --- 2 | id: useWindowFocus 3 | title: useWindowFocus 4 | sidebar_label: useWindowFocus 5 | --- 6 | 7 | Hook to track the focus state of the window. 8 | 9 | ### Usage 10 | 11 | ```jsx live 12 | function App() { 13 | const isWindowFocused = useWindowFocus(); 14 | 15 | return ( 16 |
17 |

Window Focus Hook

18 |

{isWindowFocused ? "Window is focused" : "Window is not focused"}

19 |
20 | ); 21 | } 22 | ``` 23 | 24 | ### API 25 | 26 | Returns : A boolean value indicating whether the window is focused or not, updated in real-time. Useful for tracking the if the user is currently interacting with the window. 27 | -------------------------------------------------------------------------------- /docs/docs/hooks/useWindowScrollIntoPosition.md: -------------------------------------------------------------------------------- 1 | --- 2 | id: useWindowScrollIntoPosition 3 | title: useWindowScrollIntoPosition 4 | sidebar_label: useWindowScrollIntoPosition 5 | --- 6 | 7 | Hook to scroll the window to a specific position. 8 | 9 | ### Usage 10 | 11 | ```jsx live 12 | function App() { 13 | const scrollToPosition = useWindowScrollIntoPosition(); 14 | 15 | const handleScroll = () => { 16 | scrollToPosition({ x: 100, y: 0, behavior: "smooth" }); 17 | }; 18 | 19 | return ( 20 |
21 | 22 |
23 | ); 24 | } 25 | ``` 26 | 27 | ### API 28 | 29 | Returns : `ScrollToPosition` 30 | 31 | A function to scroll the window to the specified x and y coordinates. 32 | 33 | Function parameters 34 | 35 | `x` : A number indicating the x-coordinate to scroll to. 36 | 37 | `y` : A number indicating the y-coordinate to scroll to. 38 | 39 | `behavior` : A string indicating the scroll behavior ('auto' or 'smooth'). Defaults to 'auto'. 40 | -------------------------------------------------------------------------------- /docs/docs/hooks/useWindowScrollPosition.md: -------------------------------------------------------------------------------- 1 | --- 2 | id: useWindowScrollPosition 3 | title: useWindowScrollPosition 4 | sidebar_label: useWindowScrollPosition 5 | --- 6 | 7 | Hook to get the current scroll position of the window. 8 | 9 | ### Usage 10 | 11 | ```jsx live 12 | function App() { 13 | const { x, y } = useWindowScrollPosition(200); // Optional throttle time 14 | 15 | return ( 16 |
17 |

Scroll X: {x}

18 |

Scroll Y: {y}

19 |
20 | ); 21 | } 22 | ``` 23 | 24 | ### API 25 | 26 | Parameter 27 | 28 | - `throttleTime` : A number indicating the time in milliseconds to throttle the window scroll event. Defaults to 200. 29 | 30 | Returns : `ScrollPosition` 31 | 32 | - `x` : A number or null indicating the current horizontal scroll position of the window. 33 | - `y` : A number or null indicating the current vertical scroll position of the window. 34 | -------------------------------------------------------------------------------- /docs/docs/hooks/useWindowSize.md: -------------------------------------------------------------------------------- 1 | --- 2 | id: useWindowSize 3 | title: useWindowSize 4 | sidebar_label: useWindowSize 5 | --- 6 | 7 | Hook to get the current window size. 8 | 9 | ### Usage 10 | 11 | ```jsx live 12 | function App() { 13 | const { width, height } = useWindowSize(200); // Optional throttle time 14 | 15 | return ( 16 |
17 |

Window Width: {width}px

18 |

Window Height: {height}px

19 |
20 | ); 21 | } 22 | ``` 23 | 24 | ### API 25 | 26 | Parameter 27 | 28 | - `throttleTime` : A number indicating the time in milliseconds to throttle the window resize event. Defaults to 200. 29 | 30 | Returns : `WindowSize` 31 | 32 | - `width` : A number or null indicating the current width of the window. 33 | - `height` : A number or null indicating the current height of the window. 34 | -------------------------------------------------------------------------------- /docs/docs/hooks/useWindowTouchSwipe.md: -------------------------------------------------------------------------------- 1 | --- 2 | id: useWindowTouchSwipe 3 | title: useWindowTouchSwipe 4 | sidebar_label: useWindowTouchSwipe 5 | --- 6 | 7 | Hook to detect touch swipe gestures. 8 | 9 | ### Usage 10 | 11 | ```jsx live 12 | function App() { 13 | const { swipeState, reset } = useWindowTouchSwipe(); 14 | 15 | return ( 16 |
17 |

Swipe direction: {swipeState.direction ?? "Please swipe"}

18 | 19 |
20 | ); 21 | } 22 | ``` 23 | 24 | ### API 25 | 26 | Returns : An object with the following properties: 27 | 28 | - `swipeState` : `SwipeState` - The swipe state object. 29 | - `SwipeState` : `{ direction: SwipeDirection, x: number, y: number }` - 30 | - The direction of the swipe and the x and y coordinates of the swipe event. 31 | - `SwipeDirection` : `'up' | 'down' | 'left' | 'right'` - The direction of the swipe. 32 | - `x` : `number` - The x coordinate of the swipe event. 33 | - `y` : `number` - The y coordinate of the swipe event. 34 | - `reset` : `() => void` - Resets the swipe state. 35 | -------------------------------------------------------------------------------- /docs/docs/intro.md: -------------------------------------------------------------------------------- 1 | --- 2 | sidebar_position: 1 3 | --- 4 | 5 | # Introduction 6 | 7 | React Fast Hooks is a library that provides a set of hooks that are optimized for performance. The hooks are designed to be as fast as possible and to minimize the number of re-renders. 8 | 9 | ## Installation 10 | 11 | Install [`react-fast-hooks`](https://www.npmjs.com/package/react-fast-hooks/v/latest) using your preferred package manager. 12 | 13 | ```bash title="Using npm" 14 | npm install react-fast-hooks 15 | ``` 16 | 17 | ```bash title="Using Yarn" 18 | yarn add react-fast-hooks 19 | ``` 20 | -------------------------------------------------------------------------------- /docs/docusaurus.config.ts: -------------------------------------------------------------------------------- 1 | import dotenv from "dotenv"; 2 | dotenv.config(); 3 | import { themes as prismThemes } from "prism-react-renderer"; 4 | import type { Config } from "@docusaurus/types"; 5 | import type * as Preset from "@docusaurus/preset-classic"; 6 | 7 | const config: Config = { 8 | title: "React-Fast-Hooks", 9 | tagline: "Fasten Your React Development", 10 | favicon: "img/favicon.ico", 11 | // ---- 12 | 13 | url: "https://jpranays.github.io", 14 | baseUrl: "/react-fast-hooks/", // Update this if your repo name is different 15 | onBrokenLinks: "throw", 16 | onBrokenMarkdownLinks: "warn", 17 | organizationName: "jpranays", // Your GitHub username or organization name 18 | projectName: "react-fast-hooks", // Your repo name 19 | // ---- 20 | 21 | // url: "https://react-fast-hooks.netlify.app/", 22 | // baseUrl: "/", 23 | 24 | // organizationName: "jpranays", 25 | // projectName: "react-fast-hooks", 26 | 27 | // onBrokenLinks: "throw", 28 | // onBrokenMarkdownLinks: "warn", 29 | 30 | i18n: { 31 | defaultLocale: "en", 32 | locales: ["en"], 33 | }, 34 | presets: [ 35 | [ 36 | "classic", 37 | { 38 | docs: { 39 | sidebarPath: "./sidebars.ts", 40 | }, 41 | theme: { 42 | customCss: "./src/css/custom.css", 43 | }, 44 | } satisfies Preset.Options, 45 | ], 46 | ], 47 | 48 | themeConfig: { 49 | algolia: { 50 | apiKey: process.env.ALGOLIA_API_KEY!, 51 | appId: process.env.ALGOLIA_APP_ID!, 52 | indexName: process.env.ALGOLIA_INDEX_NAME!, 53 | contextualSearch: true, 54 | }, 55 | colorMode: { 56 | defaultMode: "dark", 57 | disableSwitch: false, 58 | respectPrefersColorScheme: true, 59 | }, 60 | navbar: { 61 | title: "react-fast-hooks", 62 | items: [ 63 | { 64 | type: "docSidebar", 65 | sidebarId: "docsSidebar", 66 | position: "left", 67 | label: "docs", 68 | }, 69 | { 70 | href: "https://github.com/jpranays/react-fast-hooks", 71 | "aria-label": "GitHub", 72 | className: "navbar__icon navbar__github", 73 | position: "right", 74 | html: '', 75 | }, 76 | ], 77 | }, 78 | prism: { 79 | theme: prismThemes.nightOwlLight, 80 | darkTheme: prismThemes.vsDark, 81 | }, 82 | } satisfies Preset.ThemeConfig, 83 | themes: ["@docusaurus/theme-live-codeblock"], 84 | }; 85 | 86 | export default config; 87 | -------------------------------------------------------------------------------- /docs/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "docs", 3 | "version": "0.0.0", 4 | "private": true, 5 | "scripts": { 6 | "docusaurus": "docusaurus", 7 | "start": "docusaurus start --port 3001", 8 | "build": "docusaurus build", 9 | "swizzle": "docusaurus swizzle", 10 | "deploy": "docusaurus deploy", 11 | "clear": "docusaurus clear", 12 | "serve": "docusaurus serve", 13 | "write-translations": "docusaurus write-translations", 14 | "write-heading-ids": "docusaurus write-heading-ids", 15 | "typecheck": "tsc" 16 | }, 17 | "dependencies": { 18 | "@docusaurus/core": "3.8.0", 19 | "@docusaurus/preset-classic": "3.8.0", 20 | "@docusaurus/theme-live-codeblock": "^3.8.0", 21 | "@docusaurus/theme-search-algolia": "^3.8.0", 22 | "@mdx-js/react": "^3.1.0", 23 | "clsx": "^2.0.0", 24 | "docs": "file:", 25 | "dotenv": "^16.5.0", 26 | "font-awesome": "^4.7.0", 27 | "prism-react-renderer": "^2.4.1", 28 | "react": "^18.0.0", 29 | "react-dom": "^18.0.0", 30 | "react-fast-hooks": "^1.1.1" 31 | }, 32 | "devDependencies": { 33 | "@docusaurus/module-type-aliases": "3.4.0", 34 | "@docusaurus/tsconfig": "3.4.0", 35 | "@docusaurus/types": "3.4.0", 36 | "typescript": "~5.2.2" 37 | }, 38 | "browserslist": { 39 | "production": [ 40 | ">0.5%", 41 | "not dead", 42 | "not op_mini all" 43 | ], 44 | "development": [ 45 | "last 3 chrome version", 46 | "last 3 firefox version", 47 | "last 5 safari version" 48 | ] 49 | }, 50 | "engines": { 51 | "node": ">=18.0" 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /docs/sidebars.ts: -------------------------------------------------------------------------------- 1 | import type { SidebarsConfig } from "@docusaurus/plugin-content-docs"; 2 | 3 | /** 4 | * Creating a sidebar enables you to: 5 | - create an ordered group of docs 6 | - render a sidebar for each doc of that group 7 | - provide next/previous navigation 8 | 9 | The sidebars can be generated from the filesystem, or explicitly defined here. 10 | 11 | Create as many sidebars as you want. 12 | */ 13 | const sidebars: SidebarsConfig = { 14 | // By default, Docusaurus generates a sidebar from the docs folder structure 15 | docsSidebar: [ 16 | { 17 | type: "autogenerated", 18 | dirName: ".", 19 | }, 20 | ], 21 | 22 | // But you can create a sidebar manually 23 | // docsSidebar: [ 24 | // 'intro', 25 | // { 26 | // type: 'category', 27 | // label: 'Hooks', 28 | // items: ['hooks/useSystemTheme'], 29 | // }, 30 | // ], 31 | }; 32 | 33 | export default sidebars; 34 | -------------------------------------------------------------------------------- /docs/src/components/HomepageFeatures/index.tsx: -------------------------------------------------------------------------------- 1 | import clsx from "clsx"; 2 | import Heading from "@theme/Heading"; 3 | import styles from "./styles.module.css"; 4 | 5 | type FeatureItem = { 6 | title: string; 7 | description: JSX.Element; 8 | }; 9 | 10 | const FeatureList: FeatureItem[] = [ 11 | { 12 | title: "Lightweight and Fast", 13 | description: ( 14 | <> 15 | Designed to be minimal in size, ensuring your application remains 16 | performant and fast. 17 | 18 | ), 19 | }, 20 | { 21 | title: "SSR-Friendly", 22 | description: ( 23 | <> 24 | Built with Server-Side Rendering (SSR) compatibility, making it perfect for Next.js. 25 | 26 | ), 27 | }, 28 | { 29 | title: "Typed with TypeScript", 30 | description: ( 31 | <> 32 | Full TypeScript support, including comprehensive type definitions. 33 | ), 34 | }, 35 | { 36 | title: "Tree Shaking Support", 37 | description: ( 38 | <> 39 | Optimized for tree shaking, ensuring only the code you use is included in your final bundle. 40 | ), 41 | }, 42 | { 43 | title: "Cross-Browser Compatibility", 44 | description: ( 45 | <> 46 | Ensures consistent behavior across all major browsers. 47 | ), 48 | }, 49 | { 50 | title: "Ease of Use", 51 | description: ( 52 | <> 53 | Designed with simplicity and ease of integration in mind. 54 | ), 55 | }, 56 | ]; 57 | 58 | function Feature({ title,description }: FeatureItem) { 59 | return ( 60 |
61 |
62 | {title} 67 |

{description}

68 |
69 |
70 | ); 71 | } 72 | 73 | export default function HomepageFeatures(): JSX.Element { 74 | return ( 75 |
76 |
77 |
78 | {FeatureList.map((props, idx) => ( 79 | 80 | ))} 81 |
82 |
83 |
84 | ); 85 | } 86 | -------------------------------------------------------------------------------- /docs/src/components/HomepageFeatures/styles.module.css: -------------------------------------------------------------------------------- 1 | .features { 2 | display: flex; 3 | align-items: center; 4 | padding: 2rem 0; 5 | width: 100%; 6 | } 7 | 8 | .featureSvg { 9 | height: 200px; 10 | width: 200px; 11 | } 12 | -------------------------------------------------------------------------------- /docs/src/css/custom.css: -------------------------------------------------------------------------------- 1 | @import "font-awesome/css/font-awesome.min.css"; 2 | :root { 3 | --ifm-color-primary: #007bff; /* Bright Blue */ 4 | --ifm-color-primary-dark: #0056b3; /* Darker Blue */ 5 | --ifm-color-primary-darker: #004085; /* Even Darker Blue */ 6 | --ifm-color-primary-darkest: #003366; /* Navy Blue */ 7 | --ifm-color-primary-light: #66b2ff; /* Light Blue */ 8 | --ifm-color-primary-lighter: #cce5ff; /* Very Light Blue */ 9 | --ifm-color-primary-lightest: #e6f0ff; /* Pale Blue */ 10 | --docusaurus-highlighted-code-line-bg: rgba( 11 | 0, 12 | 0, 13 | 0, 14 | 0.1 15 | ); /* Subtle Highlight */ 16 | --hero-baner-bg: #f8f9fa; /* Light Gray */ 17 | --background-color: #ffffff; /* White */ 18 | } 19 | 20 | [data-theme="dark"] { 21 | --ifm-color-primary: #66b2ff; /* Light Blue */ 22 | --ifm-color-primary-dark: #007bff; /* Bright Blue */ 23 | --ifm-color-primary-darker: #0056b3; /* Darker Blue */ 24 | --ifm-color-primary-darkest: #003366; /* Navy Blue */ 25 | --ifm-color-primary-light: #80cfff; /* Light Cyan */ 26 | --ifm-color-primary-lighter: #cce5ff; /* Very Light Blue */ 27 | --ifm-color-primary-lightest: #e6f0ff; /* Pale Blue */ 28 | --hero-baner-bg: #212529; /* Dark Gray */ 29 | --docusaurus-highlighted-code-line-bg: rgba( 30 | 255, 31 | 255, 32 | 255, 33 | 0.1 34 | ); /* Subtle Highlight */ 35 | --background-color: #121212; /* Very Dark Gray */ 36 | } 37 | .navbar__items--right { 38 | gap: 0.5rem; 39 | } 40 | .navbar__icon { 41 | height: 2rem; 42 | width: 2rem; 43 | } 44 | 45 | .navbar__github { 46 | -webkit-tap-highlight-color: transparent; 47 | display: flex; 48 | align-items: center; 49 | justify-content: center; 50 | border-radius: 50%; 51 | font-size: 1.7rem; 52 | transition: background var(--ifm-transition-fast); 53 | } 54 | 55 | html[data-theme="light"] .navbar__github { 56 | color: #000; 57 | } 58 | 59 | html[data-theme="dark"] .navbar__github { 60 | color: #fff; 61 | } 62 | 63 | .navbar__github:hover { 64 | background: var(--ifm-color-emphasis-200); 65 | } 66 | [data-theme="light"] .DocSearch { 67 | /* --docsearch-primary-color: var(--ifm-color-primary); */ 68 | /* --docsearch-text-color: var(--ifm-font-color-base); */ 69 | --docsearch-muted-color: var(--ifm-color-secondary-darkest); 70 | --docsearch-container-background: rgba(94, 100, 112, 0.7); 71 | /* Modal */ 72 | --docsearch-modal-background: var(--ifm-color-secondary-lighter); 73 | /* Search box */ 74 | --docsearch-searchbox-background: var(--ifm-color-secondary); 75 | --docsearch-searchbox-focus-background: var(--ifm-color-white); 76 | /* Hit */ 77 | --docsearch-hit-color: var(--ifm-font-color-base); 78 | --docsearch-hit-active-color: var(--ifm-color-white); 79 | --docsearch-hit-background: var(--ifm-color-white); 80 | /* Footer */ 81 | --docsearch-footer-background: var(--ifm-color-white); 82 | } 83 | 84 | [data-theme="dark"] .DocSearch { 85 | --docsearch-text-color: var(--ifm-font-color-base); 86 | --docsearch-muted-color: var(--ifm-color-secondary-darkest); 87 | --docsearch-container-background: rgba(47, 55, 69, 0.7); 88 | /* Modal */ 89 | --docsearch-modal-background: var(--ifm-background-color); 90 | /* Search box */ 91 | --docsearch-searchbox-background: var(--ifm-background-color); 92 | --docsearch-searchbox-focus-background: var(--ifm-color-black); 93 | /* Hit */ 94 | --docsearch-hit-color: var(--ifm-font-color-base); 95 | --docsearch-hit-active-color: var(--ifm-color-white); 96 | --docsearch-hit-background: var(--ifm-color-emphasis-100); 97 | /* Footer */ 98 | --docsearch-footer-background: var(--ifm-background-surface-color); 99 | --docsearch-key-gradient: linear-gradient( 100 | -26.5deg, 101 | var(--ifm-color-emphasis-200) 0%, 102 | var(--ifm-color-emphasis-100) 100% 103 | ); 104 | } 105 | .DocSearch-Logo svg * { 106 | fill: var(--ifm-color-primary); 107 | } 108 | .buttonGroup_node_modules-\@docusaurus-theme-classic-lib-theme-CodeBlock-Content-styles-module 109 | button ,.clean-btn{ 110 | opacity: 0.5 !important; 111 | } 112 | .algoliaLogoPathFill_WdUC + path{ 113 | fill: var(--ifm-color-primary) !important; 114 | & + path{ 115 | fill: var(--hero-baner-bg) !important; 116 | } 117 | } -------------------------------------------------------------------------------- /docs/src/pages/index.module.css: -------------------------------------------------------------------------------- 1 | .heroBanner { 2 | padding: 4rem 0; 3 | text-align: center; 4 | position: relative; 5 | overflow: hidden; 6 | color: var(--ifm-color-primary); 7 | background-color: var(--hero-baner-bg); 8 | background: url(../../static/bg.svg) no-repeat center center; 9 | background-size: cover; 10 | } 11 | 12 | @media screen and (max-width: 996px) { 13 | .heroBanner { 14 | padding: 2rem; 15 | } 16 | } 17 | 18 | .buttons { 19 | display: flex; 20 | align-items: center; 21 | justify-content: center; 22 | } 23 | -------------------------------------------------------------------------------- /docs/src/pages/index.tsx: -------------------------------------------------------------------------------- 1 | import clsx from 'clsx'; 2 | import Link from '@docusaurus/Link'; 3 | import useDocusaurusContext from '@docusaurus/useDocusaurusContext'; 4 | import Layout from '@theme/Layout'; 5 | import HomepageFeatures from '@site/src/components/HomepageFeatures'; 6 | import Heading from '@theme/Heading'; 7 | 8 | import styles from './index.module.css'; 9 | 10 | function HomepageHeader() { 11 | const {siteConfig} = useDocusaurusContext(); 12 | return ( 13 |
14 |
15 | 16 | {siteConfig.title} 17 | 18 |

{siteConfig.tagline}

19 |
20 | 23 | Get started 24 | 25 |
26 |
27 |
28 | ); 29 | } 30 | 31 | export default function Home(): JSX.Element { 32 | const {siteConfig} = useDocusaurusContext(); 33 | return ( 34 | 37 | 38 |
41 | 42 |
43 |
44 | ); 45 | } 46 | -------------------------------------------------------------------------------- /docs/src/theme/ReactLiveScope/index.js: -------------------------------------------------------------------------------- 1 | import { useHistory } from "@docusaurus/router"; 2 | import React from "react"; 3 | import { 4 | useBattery, 5 | useClickOutside, 6 | useClipboard, 7 | useCookie, 8 | useDebounce, 9 | useDebouncedCallback, 10 | useDeviceOrientation, 11 | useDimensions, 12 | useEventListener, 13 | useFavicon, 14 | useFetch, 15 | useFocusBlur, 16 | useGeolocation, 17 | useHover, 18 | useIdle, 19 | useIntersectionObserver, 20 | useKeyCombo, 21 | useKeyPress, 22 | useLocalStorage, 23 | useLongPress, 24 | useMediaQuery, 25 | useMouse, 26 | useMutationObserver, 27 | useNotification, 28 | useOnlineStatus, 29 | usePreferredLanguage, 30 | usePrevious, 31 | useRandomColor, 32 | useScript, 33 | useScrollIntoPosition, 34 | useScrollLock, 35 | useScrollPosition, 36 | useSessionStorage, 37 | useSound, 38 | useStopwatch, 39 | useSystemTheme, 40 | useTitle, 41 | useTouch, 42 | useTouchSwipe, 43 | useUpdateEffect, 44 | useVibration, 45 | useWindowFocus, 46 | useWindowScrollIntoPosition, 47 | useWindowScrollPosition, 48 | useWindowSize, 49 | useWindowTouchSwipe, 50 | } from "react-fast-hooks"; 51 | 52 | const ReactLiveScope = { 53 | React, 54 | ...React, 55 | useBattery, 56 | useClickOutside, 57 | useClipboard, 58 | useCookie, 59 | useDebounce, 60 | useDebouncedCallback, 61 | useDeviceOrientation, 62 | useDimensions, 63 | useEventListener, 64 | useFavicon, 65 | useFetch, 66 | useFocusBlur, 67 | useGeolocation, 68 | useHistory, 69 | useHover, 70 | useIdle, 71 | useIntersectionObserver, 72 | useKeyCombo, 73 | useKeyPress, 74 | useLocalStorage, 75 | useLongPress, 76 | useMediaQuery, 77 | useMouse, 78 | useMutationObserver, 79 | useNotification, 80 | useOnlineStatus, 81 | usePreferredLanguage, 82 | usePrevious, 83 | useRandomColor, 84 | useScript, 85 | useScrollIntoPosition, 86 | useScrollLock, 87 | useScrollPosition, 88 | useSessionStorage, 89 | useSound, 90 | useStopwatch, 91 | useSystemTheme, 92 | useTitle, 93 | useTouch, 94 | useTouchSwipe, 95 | useUpdateEffect, 96 | useVibration, 97 | useWindowFocus, 98 | useWindowScrollIntoPosition, 99 | useWindowScrollPosition, 100 | useWindowSize, 101 | useWindowTouchSwipe 102 | }; 103 | 104 | export default ReactLiveScope; 105 | -------------------------------------------------------------------------------- /docs/src/theme/Root.js: -------------------------------------------------------------------------------- 1 | import React, { useEffect } from "react"; 2 | import { useLocation } from "@docusaurus/router"; 3 | const scrollSidebarIntoView = () => { 4 | const activeLink = document.querySelectorAll(".menu__link--active"); 5 | if (activeLink && activeLink.length > 1) { 6 | activeLink[1].scrollIntoView({ behavior: "smooth", block: "nearest" }); 7 | } 8 | }; 9 | 10 | function Root({ children }) { 11 | const location = useLocation(); 12 | useEffect(() => { 13 | scrollSidebarIntoView(); 14 | }, [location.pathname]); 15 | 16 | return <>{children}; 17 | } 18 | 19 | export default Root; 20 | -------------------------------------------------------------------------------- /docs/static/.nojekyll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jpranays/react-fast-hooks/581440f3b10aab61dd8f8bcde2225f2a531f16c7/docs/static/.nojekyll -------------------------------------------------------------------------------- /docs/static/img/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jpranays/react-fast-hooks/581440f3b10aab61dd8f8bcde2225f2a531f16c7/docs/static/img/favicon.ico -------------------------------------------------------------------------------- /docs/static/test-sound.mp3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jpranays/react-fast-hooks/581440f3b10aab61dd8f8bcde2225f2a531f16c7/docs/static/test-sound.mp3 -------------------------------------------------------------------------------- /docs/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | // This file is not used in compilation. It is here just for a nice editor experience. 3 | "extends": "@docusaurus/tsconfig", 4 | "compilerOptions": { 5 | "baseUrl": "." 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "react-fast-hooks", 3 | "version": "1.1.1", 4 | "description": "A collection of custom React hooks", 5 | "main": "dist/index.esm.js", 6 | "module": "dist/index.esm.js", 7 | "types": "dist/index.d.ts", 8 | "scripts": { 9 | "build": "rollup -c", 10 | "build-dev": "rollup -c --watch" 11 | }, 12 | "files": [ 13 | "dist/index.esm.js", 14 | "dist/index.d.ts" 15 | ], 16 | "keywords": [ 17 | "react", 18 | "hooks", 19 | "utility-hooks", 20 | "custom-hooks", 21 | "fast-hooks" 22 | ], 23 | "peerDependencies": { 24 | "react": "^16.8.0 || ^17.0.0 || ^18.0.0" 25 | }, 26 | "devDependencies": { 27 | "@babel/core": "^7.24.9", 28 | "@babel/preset-env": "^7.24.8", 29 | "@babel/preset-react": "^7.24.7", 30 | "@rollup/plugin-babel": "^6.0.4", 31 | "@rollup/plugin-commonjs": "^26.0.1", 32 | "@rollup/plugin-node-resolve": "^15.2.3", 33 | "@rollup/plugin-terser": "^0.4.4", 34 | "@rollup/plugin-typescript": "^11.1.6", 35 | "@types/node": "^20.14.11", 36 | "@types/react": "^18.3.3", 37 | "react": "^18.3.1", 38 | "rollup": "^4.19.0", 39 | "rollup-plugin-cleanup": "^3.2.1", 40 | "rollup-plugin-delete": "^2.0.0", 41 | "rollup-plugin-dts": "^6.1.1", 42 | "tslib": "^2.6.3", 43 | "typescript": "^5.5.3" 44 | }, 45 | "repository": { 46 | "type": "git", 47 | "url": "https://github.com/jpranays/react-fast-hooks.git" 48 | }, 49 | "homepage": "https://jpranays.github.io/react-fast-hooks/", 50 | "author": "Pranay ", 51 | "license": "MIT" 52 | } 53 | -------------------------------------------------------------------------------- /rollup.config.mjs: -------------------------------------------------------------------------------- 1 | import resolve from "@rollup/plugin-node-resolve"; 2 | import commonjs from "@rollup/plugin-commonjs"; 3 | import typescript from "@rollup/plugin-typescript"; 4 | import terser from "@rollup/plugin-terser"; 5 | import dts from "rollup-plugin-dts"; 6 | 7 | export default [ 8 | { 9 | input: "src/index.ts", 10 | output: [ 11 | { 12 | file: "dist/index.esm.js", 13 | format: "esm", 14 | sourcemap: false, 15 | }, 16 | ], 17 | external: ["react"], 18 | plugins: [ 19 | resolve(), 20 | commonjs(), 21 | typescript({ 22 | tsconfig: "./tsconfig.json", 23 | outputToFilesystem: true, 24 | }), 25 | terser(), 26 | ], 27 | }, 28 | { 29 | input: "./dist/types/index.d.ts", 30 | output: [{ file: "dist/index.d.ts", format: "es" }], 31 | plugins: [dts()], 32 | }, 33 | ]; 34 | -------------------------------------------------------------------------------- /src/hooks/useBattery.ts: -------------------------------------------------------------------------------- 1 | import { useState, useEffect } from 'react'; 2 | import { isBrowser } from '../utils'; // Assuming this utility function checks if the code is running in a browser 3 | 4 | interface BatteryManager { 5 | level: number; 6 | charging: boolean; 7 | chargingTime: number; 8 | dischargingTime: number; 9 | addEventListener( 10 | type: string, 11 | listener: EventListener | EventListenerObject | null, 12 | options?: boolean | AddEventListenerOptions, 13 | ): void; 14 | removeEventListener( 15 | type: string, 16 | listener: EventListener | EventListenerObject | null, 17 | options?: boolean | EventListenerOptions, 18 | ): void; 19 | } 20 | 21 | interface BatteryState { 22 | supported: boolean; 23 | loading: boolean; 24 | level: number | null; 25 | charging: boolean | null; 26 | chargingTime: number | null; 27 | dischargingTime: number | null; 28 | } 29 | 30 | interface NavigatorWithBattery extends Navigator { 31 | getBattery: () => Promise; 32 | } 33 | 34 | /** 35 | * Hook to get battery status. 36 | * 37 | * @returns An object with battery status. 38 | */ 39 | 40 | const useBattery = (): BatteryState => { 41 | const [batteryState, setBatteryState] = useState({ 42 | supported: true, 43 | loading: true, 44 | level: null, 45 | charging: null, 46 | chargingTime: null, 47 | dischargingTime: null, 48 | }); 49 | 50 | useEffect(() => { 51 | if (!isBrowser()) { 52 | setBatteryState((prevState) => ({ 53 | ...prevState, 54 | supported: false, 55 | loading: false, 56 | })); 57 | return; 58 | } 59 | 60 | const _navigator = navigator as NavigatorWithBattery; 61 | let battery: BatteryManager | null = null; 62 | 63 | const handleBatteryChange = () => { 64 | if (battery) { 65 | setBatteryState({ 66 | supported: true, 67 | loading: false, 68 | level: battery.level, 69 | charging: battery.charging, 70 | chargingTime: battery.chargingTime, 71 | dischargingTime: battery.dischargingTime, 72 | }); 73 | } 74 | }; 75 | 76 | _navigator.getBattery().then((_battery) => { 77 | battery = _battery; 78 | handleBatteryChange(); 79 | 80 | _battery.addEventListener('levelchange', handleBatteryChange); 81 | _battery.addEventListener('chargingchange', handleBatteryChange); 82 | _battery.addEventListener('chargingtimechange', handleBatteryChange); 83 | _battery.addEventListener('dischargingtimechange', handleBatteryChange); 84 | }); 85 | 86 | return () => { 87 | if (battery) { 88 | battery.removeEventListener('levelchange', handleBatteryChange); 89 | battery.removeEventListener('chargingchange', handleBatteryChange); 90 | battery.removeEventListener('chargingtimechange', handleBatteryChange); 91 | battery.removeEventListener('dischargingtimechange', handleBatteryChange); 92 | } 93 | }; 94 | }, []); 95 | 96 | return batteryState; 97 | }; 98 | 99 | export default useBattery; -------------------------------------------------------------------------------- /src/hooks/useClickOutside.ts: -------------------------------------------------------------------------------- 1 | import { useEffect, useCallback } from "react"; 2 | import { isBrowser } from "../utils"; 3 | 4 | interface UseClickOutside { 5 | (elementRef: React.RefObject, onClickOutside: () => void): void; 6 | } 7 | 8 | type onClickOutside = (e: MouseEvent) => void; 9 | 10 | /** 11 | * Hook to detect clicks outside of a specified element. 12 | * 13 | * @param {React.RefObject} elementRef - A ref to the element to detect clicks outside of. 14 | * @param {onClickOutside} onClickOutside - A callback function to execute when a click outside is detected. 15 | */ 16 | const useClickOutside: UseClickOutside = ( 17 | elementRef: React.RefObject, 18 | onClickOutside: onClickOutside 19 | ) => { 20 | const handleClickOutside = useCallback( 21 | (event: MouseEvent) => { 22 | if ( 23 | elementRef.current && 24 | !elementRef.current.contains(event.target as Node) 25 | ) { 26 | onClickOutside(event); 27 | } 28 | }, 29 | [elementRef, onClickOutside] 30 | ); 31 | 32 | useEffect(() => { 33 | if (!isBrowser()) { 34 | return; 35 | } 36 | 37 | document.addEventListener("click", handleClickOutside); 38 | 39 | return () => { 40 | document.removeEventListener("click", handleClickOutside); 41 | }; 42 | }, [handleClickOutside]); 43 | 44 | return; 45 | }; 46 | 47 | export default useClickOutside; 48 | -------------------------------------------------------------------------------- /src/hooks/useClipboard.ts: -------------------------------------------------------------------------------- 1 | import { useState } from "react"; 2 | import { isBrowser } from "../utils"; 3 | 4 | interface ClipboardHook { 5 | copy: (text: string) => Promise; 6 | isCopied: boolean; 7 | } 8 | 9 | /** 10 | * Hook to copy text to the clipboard. 11 | * 12 | * @returns An object with `copy` function and `isCopied` boolean state. 13 | */ 14 | const useClipboard = (): ClipboardHook => { 15 | const [isCopied, setIsCopied] = useState(false); 16 | 17 | const copy = async (text: string) => { 18 | if (!isBrowser()) { 19 | console.warn("Clipboard API is not available in SSR."); 20 | return; 21 | } 22 | 23 | try { 24 | await navigator.clipboard.writeText(text); 25 | setIsCopied(true); 26 | setTimeout(() => setIsCopied(false), 2000); // Reset after 2 seconds 27 | } catch (err) { 28 | console.error("Failed to copy text to clipboard:", err); 29 | setIsCopied(false); 30 | } 31 | }; 32 | 33 | return { copy, isCopied }; 34 | }; 35 | 36 | export default useClipboard; 37 | -------------------------------------------------------------------------------- /src/hooks/useCookie.ts: -------------------------------------------------------------------------------- 1 | import { useState, useCallback } from "react"; 2 | import { isBrowser } from "../utils"; 3 | 4 | interface CookieOptions { 5 | expires?: number | Date; // expires in seconds or a Date object 6 | path?: string; // path of the cookie 7 | domain?: string; // domain of the cookie 8 | secure?: boolean; // whether the cookie is secure 9 | sameSite?: "Lax" | "Strict" | "None"; // SameSite attribute 10 | } 11 | 12 | interface UseCookie { 13 | value: string | undefined; 14 | setCookie: (value: string, options?: CookieOptions) => void; 15 | removeCookie: () => void; 16 | hasCookie: () => boolean; 17 | } 18 | 19 | /** 20 | * Hook to manage a cookie in React state. 21 | * 22 | * @param {string} name - The name of the cookie. 23 | * @returns An object containing the cookie value and helper methods to interact with it. 24 | */ 25 | const useCookie = (name: string): UseCookie => { 26 | const getCookie = useCallback((): string | undefined => { 27 | if (isBrowser()) { 28 | const match = document.cookie.match(new RegExp(`(^| )${name}=([^;]+)`)); 29 | return match ? decodeURIComponent(match[2]) : undefined; 30 | } 31 | }, [name]); 32 | 33 | const [value, setValue] = useState( 34 | isBrowser() ? getCookie() : undefined 35 | ); 36 | 37 | const setCookie = useCallback( 38 | (value: string, options: CookieOptions = {}) => { 39 | if (isBrowser()) { 40 | let cookieString = `${name}=${encodeURIComponent(value)}`; 41 | 42 | if (options.expires) { 43 | const expires = 44 | options.expires instanceof Date 45 | ? options.expires 46 | : new Date(Date.now() + options.expires * 1000); 47 | cookieString += `; expires=${expires.toUTCString()}`; 48 | } 49 | 50 | if (options.path) { 51 | cookieString += `; path=${options.path}`; 52 | } 53 | 54 | if (options.domain) { 55 | cookieString += `; domain=${options.domain}`; 56 | } 57 | 58 | if (options.secure) { 59 | cookieString += `; secure`; 60 | } 61 | 62 | if (options.sameSite) { 63 | cookieString += `; samesite=${options.sameSite}`; 64 | } 65 | 66 | document.cookie = cookieString; 67 | setValue(value); 68 | } 69 | }, 70 | [name] 71 | ); 72 | 73 | const removeCookie = useCallback(() => { 74 | setCookie("", { expires: -1 }); 75 | }, [setCookie]); 76 | 77 | const hasCookie = useCallback((): boolean => { 78 | return isBrowser() && getCookie() !== undefined; 79 | }, [getCookie]); 80 | 81 | return { 82 | value, 83 | setCookie, 84 | removeCookie, 85 | hasCookie, 86 | }; 87 | }; 88 | 89 | export default useCookie; 90 | -------------------------------------------------------------------------------- /src/hooks/useDebounce.ts: -------------------------------------------------------------------------------- 1 | import { useState, useEffect } from "react"; 2 | import { isBrowser } from "../utils"; 3 | 4 | /** 5 | * Hook to debounce a value. 6 | * 7 | * @param value The value to debounce. 8 | * @param delay The debounce delay in milliseconds. 9 | * @returns The debounced value. 10 | */ 11 | const useDebounce = (value: T, delay: number): T => { 12 | const [debouncedValue, setDebouncedValue] = useState(value); 13 | 14 | useEffect(() => { 15 | if (!isBrowser()) { 16 | return; 17 | } 18 | 19 | const handler = setTimeout(() => { 20 | setDebouncedValue(value); 21 | }, delay); 22 | 23 | return () => { 24 | clearTimeout(handler); 25 | }; 26 | }, [value, delay]); 27 | 28 | return debouncedValue; 29 | }; 30 | 31 | export default useDebounce; 32 | -------------------------------------------------------------------------------- /src/hooks/useDebouncedCallback.ts: -------------------------------------------------------------------------------- 1 | import { useCallback, useRef } from "react"; 2 | import { isBrowser, debounce } from "../utils"; 3 | 4 | /** 5 | * Hook to create a debounced version of a callback function. 6 | * 7 | * @param {Function} callback - The original callback function to debounce. 8 | * @param {number} delay - The debounce delay in milliseconds. 9 | * @returns A debounced version of the callback function. 10 | */ 11 | const useDebouncedCallback = (callback: Function, delay: number): Function => { 12 | const callbackRef = useRef(callback); 13 | 14 | callbackRef.current = callback; 15 | 16 | return useCallback( 17 | debounce((...args: any) => { 18 | if (isBrowser()) { 19 | callbackRef.current(...args); 20 | } 21 | }, delay), 22 | [delay] 23 | ); 24 | }; 25 | 26 | export default useDebouncedCallback; 27 | -------------------------------------------------------------------------------- /src/hooks/useDeviceOrientation.ts: -------------------------------------------------------------------------------- 1 | import { useState, useEffect } from "react"; 2 | import { isBrowser } from "../utils"; 3 | 4 | type Orientation = "portrait" | "landscape"; 5 | 6 | /** 7 | * Hook to get the current orientation of the device. 8 | * 9 | * @returns A string indicating whether the device is in portrait or landscape mode. 10 | */ 11 | 12 | const useDeviceOrientation = (): Orientation => { 13 | const portraitMediaQuery = window.matchMedia("(orientation: portrait)"); 14 | 15 | const [orientation, setOrientation] = useState( 16 | portraitMediaQuery.matches ? "portrait" : "landscape" 17 | ); 18 | 19 | useEffect(() => { 20 | if (!isBrowser()) { 21 | return; 22 | } 23 | 24 | const handleOrientationChange = () => { 25 | if (portraitMediaQuery.matches) { 26 | setOrientation("portrait"); 27 | } else { 28 | setOrientation("landscape"); 29 | } 30 | }; 31 | 32 | portraitMediaQuery.addEventListener("change", handleOrientationChange); 33 | 34 | return () => { 35 | portraitMediaQuery.removeEventListener("change", handleOrientationChange); 36 | }; 37 | }, []); 38 | 39 | return orientation; 40 | }; 41 | 42 | export default useDeviceOrientation; 43 | -------------------------------------------------------------------------------- /src/hooks/useDimensions.ts: -------------------------------------------------------------------------------- 1 | import { useState, useEffect, useCallback } from "react"; 2 | import { isBrowser, throttle } from "../utils"; 3 | 4 | interface Dimensions { 5 | width: number | null; 6 | height: number | null; 7 | } 8 | 9 | interface UseDimensions { 10 | (elementRef: React.RefObject, throttleTime?: number): Dimensions; 11 | } 12 | 13 | /** 14 | * Hook to get the dimensions (width and height) of a specified element. 15 | * 16 | * @param {React.RefObject} elementRef - A ref to the element to track the dimensions. 17 | * @param {number} [throttleTime=200] - The time in milliseconds to throttle the resize event handler. Defaults to 200ms. 18 | * @returns An object with the width and height of the element. 19 | */ 20 | const useDimensions: UseDimensions = ( 21 | elementRef: React.RefObject, 22 | throttleTime: number = 200 23 | ): Dimensions => { 24 | const [dimensions, setDimensions] = useState({ 25 | width: null, 26 | height: null, 27 | }); 28 | 29 | const updateDimensions = useCallback(() => { 30 | if (isBrowser() && elementRef.current) { 31 | const { offsetWidth, offsetHeight } = elementRef.current; 32 | setDimensions({ 33 | width: offsetWidth, 34 | height: offsetHeight, 35 | }); 36 | } 37 | }, [elementRef]); 38 | 39 | const handleResize = useCallback(throttle(updateDimensions, throttleTime), [ 40 | updateDimensions, 41 | throttleTime, 42 | ]); 43 | 44 | useEffect(() => { 45 | if (!isBrowser() || !elementRef.current) { 46 | return; 47 | } 48 | 49 | updateDimensions(); 50 | 51 | window.addEventListener("resize", handleResize); 52 | 53 | return () => { 54 | window.removeEventListener("resize", handleResize); 55 | }; 56 | }, [elementRef, handleResize]); 57 | 58 | return dimensions; 59 | }; 60 | 61 | export default useDimensions; 62 | -------------------------------------------------------------------------------- /src/hooks/useEventListener.ts: -------------------------------------------------------------------------------- 1 | import { useEffect, useRef } from "react"; 2 | import { isBrowser } from "../utils"; 3 | 4 | /** 5 | * Hook to attach an event listener to a DOM element and clean it up on unmount. 6 | * 7 | * @param {string} eventName - The name of the event to listen for. 8 | * @param {Function} handler - The callback function to handle the event. 9 | * @param {React.RefObject} elementRef - A ref to the element to attach the event listener to. Defaults to window. 10 | * @param {boolean | AddEventListenerOptions} options - An options object that specifies characteristics about the event listener. 11 | */ 12 | 13 | const useEventListener = ( 14 | eventName: string, 15 | handler: (event: Event) => void, 16 | elementRef?: React.RefObject, 17 | options?: boolean | AddEventListenerOptions 18 | ) => { 19 | const savedHandler = useRef<(event: Event) => void>(); 20 | 21 | useEffect(() => { 22 | savedHandler.current = handler; 23 | }, [handler]); 24 | 25 | useEffect(() => { 26 | const element = (elementRef && elementRef.current) || window; 27 | if (!isBrowser() || !element) return; 28 | 29 | const eventListener = (event: Event) => { 30 | if (savedHandler.current) { 31 | savedHandler.current(event); 32 | } 33 | }; 34 | 35 | element.addEventListener(eventName, eventListener, options); 36 | 37 | return () => { 38 | element.removeEventListener(eventName, eventListener, options); 39 | }; 40 | }, [eventName, elementRef, options]); 41 | }; 42 | 43 | export default useEventListener; 44 | -------------------------------------------------------------------------------- /src/hooks/useFavicon.ts: -------------------------------------------------------------------------------- 1 | import { useCallback, useEffect, useState } from "react"; 2 | import { isBrowser } from "../utils"; 3 | 4 | type SetFaviconFn = (faviconUrl: string) => void; 5 | interface UseFavicon { 6 | (initialFaviconUrl: string): SetFaviconFn; 7 | } 8 | 9 | /** 10 | * Hook to set and update the favicon of the webpage. 11 | * 12 | * @param {string} initialFaviconUrl - The initial URL of the favicon to set. 13 | * @returns A function to change the favicon URL. 14 | */ 15 | const useFavicon: UseFavicon = (initialFaviconUrl: string): SetFaviconFn => { 16 | const [faviconUrl, setFaviconUrl] = useState(initialFaviconUrl); 17 | 18 | useEffect(() => { 19 | if (!isBrowser()) return; 20 | 21 | const existingLink = document.querySelector( 22 | "link[rel='icon']" 23 | ) as HTMLLinkElement; 24 | const link: HTMLLinkElement = 25 | existingLink || document.createElement("link"); 26 | link.rel = "icon"; 27 | link.href = faviconUrl; 28 | 29 | if (!existingLink) { 30 | document.head.appendChild(link); 31 | } 32 | }, [faviconUrl]); 33 | 34 | const changeFavicon = useCallback((newFaviconUrl: string) => { 35 | setFaviconUrl(newFaviconUrl); 36 | }, []); 37 | 38 | return changeFavicon; 39 | }; 40 | 41 | export default useFavicon; 42 | -------------------------------------------------------------------------------- /src/hooks/useFetch.ts: -------------------------------------------------------------------------------- 1 | import { useState, useEffect, useCallback } from "react"; 2 | import { isBrowser } from "../utils"; 3 | 4 | interface FetchOptions { 5 | method?: string; 6 | headers?: HeadersInit; 7 | body?: BodyInit | null; 8 | } 9 | 10 | interface FetchResult { 11 | data: T | null; 12 | loading: boolean; 13 | error: Error | null; 14 | refetch: () => void; 15 | } 16 | 17 | /** 18 | * Hook to fetch data from an API endpoint. 19 | * 20 | * @param {string} url - The URL of the API endpoint. 21 | * @param {FetchOptions} [options] - Optional configuration for the fetch request. 22 | * @returns An object containing the fetched data, loading state, error state, and a refetch function. 23 | */ 24 | const useFetch = ( 25 | url: string, 26 | options: FetchOptions = {} 27 | ): FetchResult => { 28 | const [data, setData] = useState(null); 29 | const [loading, setLoading] = useState(false); 30 | const [error, setError] = useState(null); 31 | const [refetch, setRefetch] = useState(false); 32 | 33 | const fetchData = useCallback(async () => { 34 | if (!isBrowser()) return; 35 | 36 | setLoading(true); 37 | setError(null); 38 | 39 | try { 40 | const response = await fetch(url, { 41 | method: options.method || "GET", 42 | headers: options.headers, 43 | body: options.body, 44 | }); 45 | 46 | if (!response.ok) { 47 | throw new Error(`Error: ${response.statusText}`); 48 | } 49 | 50 | const result = await response.json(); 51 | setData(result); 52 | } catch (err) { 53 | setError(err as Error); 54 | } finally { 55 | setLoading(false); 56 | } 57 | }, [url, options]); 58 | 59 | useEffect(() => { 60 | fetchData(); 61 | }, []); 62 | 63 | useEffect(() => { 64 | if (refetch) { 65 | fetchData(); 66 | setRefetch(false); 67 | } 68 | }, [refetch]); 69 | 70 | return { data, loading, error, refetch: () => setRefetch(true) }; 71 | }; 72 | 73 | export default useFetch; 74 | -------------------------------------------------------------------------------- /src/hooks/useFocusBlur.ts: -------------------------------------------------------------------------------- 1 | import { useCallback } from "react"; 2 | import { isBrowser } from "../utils"; 3 | 4 | interface UseFocusBlur { 5 | (elementRef: React.RefObject): { focus: () => void; blur: () => void }; 6 | } 7 | 8 | /** 9 | * Hook to get focus and blur functions for an element. 10 | * 11 | * @param {React.RefObject} elementRef - A ref to the element. 12 | * @returns An object with `focus` and `blur` functions. 13 | */ 14 | const useFocusBlur: UseFocusBlur = (elementRef: React.RefObject) => { 15 | const focus = useCallback(() => { 16 | if (isBrowser() && elementRef.current) { 17 | elementRef.current.focus(); 18 | } 19 | }, [elementRef]); 20 | 21 | const blur = useCallback(() => { 22 | if (isBrowser() && elementRef.current) { 23 | elementRef.current.blur(); 24 | } 25 | }, [elementRef]); 26 | 27 | return { focus, blur }; 28 | }; 29 | 30 | export default useFocusBlur; 31 | -------------------------------------------------------------------------------- /src/hooks/useGeoLocation.ts: -------------------------------------------------------------------------------- 1 | import { useEffect, useState } from "react"; 2 | import { isBrowser } from "../utils"; 3 | 4 | interface GeolocationState { 5 | accuracy: number | null; 6 | altitude: number | null; 7 | altitudeAccuracy: number | null; 8 | heading: number | null; 9 | latitude: number | null; 10 | longitude: number | null; 11 | speed: number | null; 12 | timestamp: number; 13 | error: GeolocationPositionError | null; 14 | } 15 | 16 | /** 17 | * Hook to get the current geolocation. 18 | * 19 | * @returns The geolocation state. 20 | */ 21 | const useGeolocation = (): GeolocationState => { 22 | const [state, setState] = useState({ 23 | accuracy: null, 24 | altitude: null, 25 | altitudeAccuracy: null, 26 | heading: null, 27 | latitude: null, 28 | longitude: null, 29 | speed: null, 30 | timestamp: Date.now(), 31 | error: null, 32 | }); 33 | 34 | useEffect(() => { 35 | if (!isBrowser()) { 36 | return; 37 | } 38 | 39 | let mounted = true; 40 | let watchId: number; 41 | 42 | const onEvent = (event: GeolocationPosition) => { 43 | if (mounted) { 44 | setState({ 45 | accuracy: event.coords.accuracy, 46 | altitude: event.coords.altitude, 47 | altitudeAccuracy: event.coords.altitudeAccuracy, 48 | heading: event.coords.heading, 49 | latitude: event.coords.latitude, 50 | longitude: event.coords.longitude, 51 | speed: event.coords.speed, 52 | timestamp: event.timestamp, 53 | error: null, 54 | }); 55 | } 56 | }; 57 | 58 | const onError = (error: GeolocationPositionError) => { 59 | setState({ 60 | accuracy: null, 61 | altitude: null, 62 | altitudeAccuracy: null, 63 | heading: null, 64 | latitude: null, 65 | longitude: null, 66 | speed: null, 67 | timestamp: Date.now(), 68 | error: error, 69 | }); 70 | }; 71 | 72 | navigator.geolocation.getCurrentPosition(onEvent, onError); 73 | watchId = navigator.geolocation.watchPosition(onEvent, onError); 74 | 75 | return () => { 76 | mounted = false; 77 | navigator.geolocation.clearWatch(watchId); 78 | }; 79 | }, []); 80 | 81 | return state; 82 | }; 83 | 84 | export default useGeolocation; 85 | -------------------------------------------------------------------------------- /src/hooks/useHistory.ts: -------------------------------------------------------------------------------- 1 | import { useState, useEffect, useCallback } from "react"; 2 | import { isBrowser } from "../utils"; // Make sure to use isBrowser from your utils 3 | 4 | interface HistoryState { 5 | [key: string]: any; 6 | } 7 | 8 | interface UseHistory { 9 | history: History; 10 | state: HistoryState | null; 11 | push: (path: string, state?: HistoryState) => void; 12 | replace: (path: string, state?: HistoryState) => void; 13 | goBack: () => void; 14 | goForward: () => void; 15 | } 16 | 17 | /** 18 | * Hook to manage browser history. 19 | * 20 | * @returns {UseHistory} An object containing the history instance and utility functions to interact with it. 21 | */ 22 | const useHistory = (): UseHistory => { 23 | const [history, setHistory] = useState(window.history); 24 | const [state, setState] = useState(null); 25 | 26 | const push = useCallback((path: string, state?: HistoryState) => { 27 | if (isBrowser()) { 28 | window.history.pushState(state, "", path); 29 | setState(state || null); 30 | } 31 | }, []); 32 | 33 | const replace = useCallback((path: string, state?: HistoryState) => { 34 | if (isBrowser()) { 35 | window.history.replaceState(state, "", path); 36 | setState(state || null); 37 | } 38 | }, []); 39 | 40 | const goBack = useCallback(() => { 41 | if (isBrowser()) { 42 | window.history.back(); 43 | } 44 | }, []); 45 | 46 | const goForward = useCallback(() => { 47 | if (isBrowser()) { 48 | window.history.forward(); 49 | } 50 | }, []); 51 | 52 | useEffect(() => { 53 | const handlePopState = (event: PopStateEvent) => { 54 | setState(event.state || null); 55 | }; 56 | 57 | if (isBrowser()) { 58 | window.addEventListener("popstate", handlePopState); 59 | return () => { 60 | window.removeEventListener("popstate", handlePopState); 61 | }; 62 | } 63 | }, []); 64 | 65 | return { 66 | history, 67 | state, 68 | push, 69 | replace, 70 | goBack, 71 | goForward, 72 | }; 73 | }; 74 | 75 | export default useHistory; 76 | -------------------------------------------------------------------------------- /src/hooks/useHover.ts: -------------------------------------------------------------------------------- 1 | import { useState, useEffect, useCallback, RefObject } from "react"; 2 | import { isBrowser } from "../utils"; 3 | 4 | interface UseHover { 5 | (ref: RefObject): boolean; 6 | } 7 | 8 | /** 9 | * Hook to determine if an element is hovered. 10 | * 11 | * @param {RefObject} ref - The ref to the element to track hover state. 12 | * @returns A boolean whether the element is hovered or not. 13 | */ 14 | const useHover: UseHover = (ref: RefObject): boolean => { 15 | const [isHovered, setIsHovered] = useState(false); 16 | 17 | const handleMouseEnter = useCallback(() => { 18 | setIsHovered(true); 19 | }, []); 20 | 21 | const handleMouseLeave = useCallback(() => { 22 | setIsHovered(false); 23 | }, []); 24 | 25 | useEffect(() => { 26 | if (!isBrowser() || !ref.current) { 27 | return; 28 | } 29 | 30 | const element = ref.current; 31 | 32 | element.addEventListener("mouseenter", handleMouseEnter); 33 | element.addEventListener("mouseleave", handleMouseLeave); 34 | 35 | return () => { 36 | element.removeEventListener("mouseenter", handleMouseEnter); 37 | element.removeEventListener("mouseleave", handleMouseLeave); 38 | }; 39 | }, [ref, handleMouseEnter, handleMouseLeave]); 40 | 41 | return isHovered; 42 | }; 43 | 44 | export default useHover; 45 | -------------------------------------------------------------------------------- /src/hooks/useIdle.ts: -------------------------------------------------------------------------------- 1 | import { useState, useEffect, useRef, useCallback } from "react"; 2 | import { isBrowser } from "../utils"; 3 | 4 | interface UseIdleOptions { 5 | timeout: number; 6 | } 7 | 8 | interface UseIdle { 9 | (options: UseIdleOptions): boolean; 10 | } 11 | 12 | /** 13 | * Hook to detect user inactivity. 14 | * 15 | * @param {UseIdleOptions} options - An object containing the timeout in milliseconds. 16 | * @returns A boolean indicating whether the user is idle. 17 | */ 18 | const useIdle: UseIdle = ({ timeout }: UseIdleOptions): boolean => { 19 | const [isIdle, setIsIdle] = useState(false); 20 | const idleTimeoutRef = useRef(); 21 | const isIdleRef = useRef(false); 22 | 23 | const handleActivity = useCallback(() => { 24 | if (isIdleRef.current) { 25 | setIsIdle(false); 26 | isIdleRef.current = false; 27 | } 28 | clearTimeout(idleTimeoutRef.current); 29 | idleTimeoutRef.current = window.setTimeout(() => { 30 | setIsIdle(true); 31 | isIdleRef.current = true; 32 | }, timeout); 33 | }, [timeout]); 34 | 35 | useEffect(() => { 36 | if (!isBrowser()) { 37 | return; 38 | } 39 | 40 | const events = [ 41 | "mousemove", 42 | "mousedown", 43 | "keydown", 44 | "touchstart", 45 | "scroll", 46 | ]; 47 | events.forEach((event) => window.addEventListener(event, handleActivity)); 48 | 49 | idleTimeoutRef.current = window.setTimeout(() => { 50 | setIsIdle(true); 51 | isIdleRef.current = true; 52 | }, timeout); 53 | 54 | return () => { 55 | events.forEach((event) => 56 | window.removeEventListener(event, handleActivity) 57 | ); 58 | clearTimeout(idleTimeoutRef.current); 59 | }; 60 | }, [handleActivity, timeout]); 61 | 62 | return isIdle; 63 | }; 64 | 65 | export default useIdle; 66 | -------------------------------------------------------------------------------- /src/hooks/useIntersectionObserver.ts: -------------------------------------------------------------------------------- 1 | import { useState, useEffect, useCallback, RefObject } from "react"; 2 | import { isBrowser } from "../utils"; 3 | 4 | interface IntersectionObserverOptions { 5 | root?: Element | null; 6 | rootMargin?: string; 7 | threshold?: number | number[]; 8 | } 9 | 10 | interface UseIntersectionObserver { 11 | ( 12 | ref: RefObject, 13 | options?: IntersectionObserverOptions 14 | ): IntersectionObserverEntry | null; 15 | } 16 | 17 | /** 18 | * Hook to observe the visibility of an element using the Intersection Observer API. 19 | * 20 | * @param {React.RefObject} ref - A ref to the element to observe. 21 | * @param {IntersectionObserverOptions} [options] - The Intersection Observer options. 22 | * @returns The IntersectionObserverEntry providing information about the intersection of the target with the root. 23 | */ 24 | const useIntersectionObserver: UseIntersectionObserver = ( 25 | ref: React.RefObject, 26 | options: IntersectionObserverOptions = {} 27 | ) => { 28 | const [entry, setEntry] = useState(null); 29 | 30 | useEffect(() => { 31 | if (!isBrowser() || !ref.current || !window.IntersectionObserver) { 32 | return; 33 | } 34 | 35 | const observer = new IntersectionObserver( 36 | ([entry]) => setEntry(entry), 37 | options 38 | ); 39 | 40 | const element = ref.current; 41 | observer.observe(element); 42 | 43 | return () => { 44 | observer.disconnect(); 45 | }; 46 | }, []); 47 | 48 | return entry; 49 | }; 50 | 51 | export default useIntersectionObserver; 52 | -------------------------------------------------------------------------------- /src/hooks/useKeyCombo.ts: -------------------------------------------------------------------------------- 1 | import { useState, useEffect } from "react"; 2 | import { isBrowser } from "../utils"; 3 | 4 | interface KeyCombo { 5 | [key: string]: boolean; 6 | } 7 | 8 | interface UseKeyCombo { 9 | (keys: string[]): boolean; 10 | } 11 | 12 | /** 13 | * Hook to detect if a specified key combination is pressed. 14 | * 15 | * @param {string[]} keys - The key combination to detect. 16 | * @returns A boolean true if the key combination is pressed, false otherwise. 17 | */ 18 | const useKeyCombo: UseKeyCombo = (keys) => { 19 | const [keyComboPressed, setKeyComboPressed] = useState(false); 20 | const pressedKeys: KeyCombo = {}; 21 | 22 | const downHandler = ({ key }: KeyboardEvent) => { 23 | pressedKeys[key] = true; 24 | checkKeyCombo(); 25 | }; 26 | 27 | const upHandler = ({ key }: KeyboardEvent) => { 28 | pressedKeys[key] = false; 29 | checkKeyCombo(); 30 | }; 31 | 32 | const checkKeyCombo = () => { 33 | const allKeysPressed = keys.every((key) => pressedKeys[key]); 34 | setKeyComboPressed(allKeysPressed); 35 | }; 36 | 37 | useEffect(() => { 38 | if (!isBrowser()) { 39 | return; 40 | } 41 | 42 | window.addEventListener("keydown", downHandler); 43 | window.addEventListener("keyup", upHandler); 44 | 45 | return () => { 46 | window.removeEventListener("keydown", downHandler); 47 | window.removeEventListener("keyup", upHandler); 48 | }; 49 | }, [keys]); 50 | 51 | return keyComboPressed; 52 | }; 53 | 54 | export default useKeyCombo; 55 | -------------------------------------------------------------------------------- /src/hooks/useKeyPress.ts: -------------------------------------------------------------------------------- 1 | import { useState, useEffect } from "react"; 2 | import { isBrowser } from "../utils"; 3 | 4 | interface UseKeyPress { 5 | (targetKey: string): boolean; 6 | } 7 | 8 | /** 9 | * Hook to detect if a specified key is pressed. 10 | * 11 | * @param {string} targetKey - The key to detect. 12 | * @returns A boolean true if the key is pressed, false otherwise. 13 | */ 14 | const useKeyPress: UseKeyPress = (targetKey: string) => { 15 | const [keyPressed, setKeyPressed] = useState(false); 16 | 17 | const downHandler = ({ key }: KeyboardEvent) => { 18 | if (key === targetKey) { 19 | setKeyPressed(true); 20 | } 21 | }; 22 | 23 | const upHandler = ({ key }: KeyboardEvent) => { 24 | if (key === targetKey) { 25 | setKeyPressed(false); 26 | } 27 | }; 28 | 29 | useEffect(() => { 30 | if (!isBrowser()) { 31 | return; 32 | } 33 | 34 | window.addEventListener("keypress", downHandler); 35 | window.addEventListener("keyup", upHandler); 36 | 37 | return () => { 38 | window.removeEventListener("keypress", downHandler); 39 | window.removeEventListener("keyup", upHandler); 40 | }; 41 | }, [targetKey]); 42 | 43 | return keyPressed; 44 | }; 45 | 46 | export default useKeyPress; 47 | -------------------------------------------------------------------------------- /src/hooks/useLocalStorage.ts: -------------------------------------------------------------------------------- 1 | import { useState, useEffect } from 'react'; 2 | import { isBrowser } from '../utils'; 3 | 4 | interface UseLocalStorage { 5 | (key: string, initialValue: T): [T, (value: T) => void]; 6 | } 7 | 8 | /** 9 | * Hook to manage a value in localStorage. 10 | * 11 | * @param key The key under which the value is stored in localStorage. 12 | * @param initialValue The initial value to use if there is no value in localStorage. 13 | * @returns An array with the current value and a function to update it. 14 | */ 15 | const useLocalStorage: UseLocalStorage = (key, initialValue) => { 16 | const [storedValue, setStoredValue] = useState(() => { 17 | if (!isBrowser()) { 18 | return initialValue; 19 | } 20 | try { 21 | const item = window.localStorage.getItem(key); 22 | return item ? JSON.parse(item) : initialValue; 23 | } catch (error) { 24 | console.warn(`Error reading localStorage key "${key}":`, error); 25 | return initialValue; 26 | } 27 | }); 28 | 29 | const setValue = (value: any) => { 30 | try { 31 | const valueToStore = value instanceof Function ? value(storedValue) : value; 32 | setStoredValue(valueToStore); 33 | if (isBrowser()) { 34 | window.localStorage.setItem(key, JSON.stringify(valueToStore)); 35 | } 36 | } catch (error) { 37 | console.warn(`Error setting localStorage key "${key}":`, error); 38 | } 39 | }; 40 | 41 | return [storedValue, setValue]; 42 | }; 43 | 44 | export default useLocalStorage; 45 | -------------------------------------------------------------------------------- /src/hooks/useLongPress.ts: -------------------------------------------------------------------------------- 1 | import { useEffect, useCallback, useRef } from "react"; 2 | import { isBrowser } from "../utils"; 3 | 4 | interface UseLongPressOptions { 5 | threshold?: number; 6 | onLongPress: () => void; 7 | onPress?: () => void; 8 | onRelease?: () => void; 9 | } 10 | 11 | interface UseLongPress { 12 | ( 13 | elementRef: React.RefObject, 14 | options: UseLongPressOptions 15 | ): void; 16 | } 17 | 18 | /** 19 | * Hook to enable precise control of long-press interactions for both touch and mouse events. 20 | * 21 | * @param {React.RefObject} elementRef - A ref to the element to track the long press. 22 | * @param {UseLongPressOptions} options - Configuration options for the long press. 23 | */ 24 | const useLongPress: UseLongPress = ( 25 | elementRef: React.RefObject, 26 | { threshold = 500, onLongPress, onPress, onRelease }: UseLongPressOptions 27 | ) => { 28 | const timerRef = useRef(null); 29 | 30 | const startPressTimer = useCallback(() => { 31 | if (onPress) onPress(); 32 | timerRef.current = setTimeout(() => { 33 | if (onLongPress) onLongPress(); 34 | }, threshold); 35 | }, [onLongPress, onPress, threshold]); 36 | 37 | const clearPressTimer = useCallback(() => { 38 | if (timerRef.current) clearTimeout(timerRef.current); 39 | if (onRelease) onRelease(); 40 | }, [onRelease]); 41 | 42 | useEffect(() => { 43 | if (!isBrowser() || !elementRef.current) return; 44 | 45 | const element = elementRef.current; 46 | 47 | const handleMouseDown = startPressTimer; 48 | const handleMouseUp = clearPressTimer; 49 | const handleTouchStart = startPressTimer; 50 | const handleTouchEnd = clearPressTimer; 51 | 52 | element.addEventListener("mousedown", handleMouseDown); 53 | element.addEventListener("mouseup", handleMouseUp); 54 | element.addEventListener("touchstart", handleTouchStart); 55 | element.addEventListener("touchend", handleTouchEnd); 56 | 57 | return () => { 58 | element.removeEventListener("mousedown", handleMouseDown); 59 | element.removeEventListener("mouseup", handleMouseUp); 60 | element.removeEventListener("touchstart", handleTouchStart); 61 | element.removeEventListener("touchend", handleTouchEnd); 62 | }; 63 | }, [elementRef, startPressTimer, clearPressTimer]); 64 | 65 | useEffect(() => { 66 | if (!isBrowser()) return; 67 | return () => { 68 | if (timerRef.current) clearTimeout(timerRef.current); 69 | }; 70 | }, []); 71 | }; 72 | 73 | export default useLongPress; 74 | -------------------------------------------------------------------------------- /src/hooks/useMediaQuery.ts: -------------------------------------------------------------------------------- 1 | import { useState, useEffect } from "react"; 2 | import { isBrowser } from "../utils"; 3 | 4 | /** 5 | * Hook to detect media query matches. 6 | * 7 | * @param query The media query string to match against. 8 | * @returns A boolean true if the media query matches, otherwise false. 9 | */ 10 | const useMediaQuery = (query: string): boolean => { 11 | const [matches, setMatches] = useState(() => { 12 | if (isBrowser() && window.matchMedia) { 13 | return window.matchMedia(query).matches; 14 | } 15 | return false; 16 | }); 17 | 18 | useEffect(() => { 19 | if (!isBrowser() || !window.matchMedia) { 20 | return; 21 | } 22 | 23 | const mediaQueryList = window.matchMedia(query); 24 | 25 | const handleChange = (event: MediaQueryListEvent) => { 26 | setMatches(event.matches); 27 | }; 28 | 29 | mediaQueryList.addEventListener("change", handleChange); 30 | 31 | return () => { 32 | mediaQueryList.removeEventListener("change", handleChange); 33 | }; 34 | }, [query]); 35 | 36 | return matches; 37 | }; 38 | 39 | export default useMediaQuery; 40 | -------------------------------------------------------------------------------- /src/hooks/useMouse.ts: -------------------------------------------------------------------------------- 1 | import { useState, useEffect } from "react"; 2 | import { isBrowser } from "../utils"; 3 | 4 | interface MousePosition { 5 | x: number; 6 | y: number; 7 | elementX: number; 8 | elementY: number; 9 | pageX: number; 10 | pageY: number; 11 | } 12 | 13 | interface UseMouse { 14 | (elementRef: React.RefObject): MousePosition; 15 | } 16 | 17 | /** 18 | * Hook to track the mouse position relative to a specified element. 19 | * 20 | * @param {React.RefObject} elementRef - A ref to the element to track the mouse position. 21 | * @returns An object with the current mouse x and y coordinates relative to the element. 22 | */ 23 | const useMouse: UseMouse = (elementRef: React.RefObject): MousePosition => { 24 | const [mousePosition, setMousePosition] = useState({ 25 | x: 0, 26 | y: 0, 27 | elementX: 0, 28 | elementY: 0, 29 | pageX: 0, 30 | pageY: 0, 31 | }); 32 | 33 | useEffect(() => { 34 | if (!isBrowser() || !elementRef.current) { 35 | return; 36 | } 37 | 38 | const handleMouseMove = (event: MouseEvent) => { 39 | const element = elementRef.current; 40 | if (element) { 41 | const rect = element.getBoundingClientRect(); 42 | setMousePosition({ 43 | x: event.clientX - rect.left, 44 | y: event.clientY - rect.top, 45 | elementX: event.clientX, 46 | elementY: event.clientY, 47 | pageX: event.pageX, 48 | pageY: event.pageY, 49 | }); 50 | } 51 | }; 52 | 53 | const element = elementRef.current; 54 | element.addEventListener("mousemove", handleMouseMove); 55 | 56 | return () => { 57 | element.removeEventListener("mousemove", handleMouseMove); 58 | }; 59 | }, [elementRef]); 60 | 61 | return mousePosition; 62 | }; 63 | 64 | export default useMouse; 65 | -------------------------------------------------------------------------------- /src/hooks/useMutationObserver.ts: -------------------------------------------------------------------------------- 1 | import { useEffect, useRef } from "react"; 2 | import { isBrowser } from "../utils"; 3 | 4 | interface UseMutationObserverOptions { 5 | childList?: boolean; 6 | attributes?: boolean; 7 | characterData?: boolean; 8 | subtree?: boolean; 9 | attributeOldValue?: boolean; 10 | characterDataOldValue?: boolean; 11 | attributeFilter?: string[]; 12 | } 13 | 14 | type MutationCallback = ( 15 | mutations: MutationRecord[], 16 | observer: MutationObserver 17 | ) => void; 18 | 19 | /** 20 | * Hook to observe changes to a DOM element using MutationObserver. 21 | * 22 | * @param {React.RefObject} ref - A React ref to the element to observe. 23 | * @param {MutationCallback} callback - A function to handle mutations. 24 | * @param {UseMutationObserverOptions} options - An object specifying which DOM mutations to observe. 25 | */ 26 | const useMutationObserver = ( 27 | ref: React.RefObject, 28 | callback: MutationCallback, 29 | options: UseMutationObserverOptions 30 | ): void => { 31 | const observer = useRef(null); 32 | 33 | useEffect(() => { 34 | if (!isBrowser() || !ref.current || !window.MutationObserver) { 35 | return; 36 | } 37 | 38 | observer.current = new MutationObserver(callback); 39 | 40 | observer.current.observe(ref.current, { 41 | childList: options.childList ?? true, 42 | attributes: options.attributes ?? true, 43 | characterData: options.characterData ?? false, 44 | subtree: options.subtree ?? false, 45 | attributeOldValue: options.attributeOldValue ?? false, 46 | characterDataOldValue: options.characterDataOldValue ?? false, 47 | attributeFilter: options.attributeFilter, 48 | }); 49 | 50 | return () => { 51 | observer.current?.disconnect(); 52 | }; 53 | }, [ref, callback, options]); 54 | 55 | return; 56 | }; 57 | 58 | export default useMutationObserver; 59 | -------------------------------------------------------------------------------- /src/hooks/useNotification.ts: -------------------------------------------------------------------------------- 1 | import { useState, useCallback, useEffect, useRef } from "react"; 2 | import { isBrowser } from "../utils"; 3 | 4 | interface NotificationOptions { 5 | body?: string; 6 | icon?: string; 7 | dir?: NotificationDirection; 8 | lang?: string; 9 | tag?: string; 10 | renotify?: boolean; 11 | silent?: boolean; 12 | requireInteraction?: boolean; 13 | badge?: string; 14 | vibrate?: number | number[]; 15 | timestamp?: number; 16 | image?: string; 17 | } 18 | 19 | interface UseNotificationReturn { 20 | permission: NotificationPermission; 21 | showNotification: () => void; 22 | requestPermission: () => void; 23 | updateNotification: ( 24 | newTitle: string, 25 | newOptions?: NotificationOptions 26 | ) => void; 27 | } 28 | 29 | /** 30 | * Hook to trigger browser notifications. 31 | * 32 | * @param {string} title - The title of the notification. 33 | * @param {NotificationOptions} [options] - Optional configuration for the notification. 34 | * @returns An object containing the notification permission status and functions to trigger, request permission, and update the notification. 35 | */ 36 | const useNotification = ( 37 | title: string, 38 | options: NotificationOptions = {} 39 | ): UseNotificationReturn => { 40 | const [permission, setPermission] = useState( 41 | isBrowser() ? Notification.permission : "default" 42 | ); 43 | const notificationRef = useRef(null); 44 | 45 | const requestPermission = useCallback(async () => { 46 | if (!isBrowser()) return; 47 | const result = await Notification.requestPermission(); 48 | setPermission(result); 49 | }, []); 50 | 51 | const showNotification = useCallback(() => { 52 | if (!isBrowser() || permission !== "granted") return; 53 | 54 | notificationRef.current = new Notification(title, options); 55 | }, [permission, title, options]); 56 | 57 | const updateNotification = useCallback( 58 | (newTitle: string, newOptions: NotificationOptions = {}) => { 59 | if (!isBrowser() || permission !== "granted") return; 60 | 61 | notificationRef.current?.close(); 62 | notificationRef.current = new Notification(newTitle, newOptions); 63 | }, 64 | [permission] 65 | ); 66 | 67 | useEffect(() => { 68 | if (isBrowser() && permission === "default") { 69 | requestPermission(); 70 | } 71 | }, [permission, requestPermission]); 72 | 73 | return { 74 | permission, 75 | showNotification, 76 | requestPermission, 77 | updateNotification, 78 | }; 79 | }; 80 | 81 | export default useNotification; 82 | -------------------------------------------------------------------------------- /src/hooks/useOnlineStatus.ts: -------------------------------------------------------------------------------- 1 | import { useEffect, useState } from "react"; 2 | import { isBrowser } from "../utils"; 3 | 4 | /** 5 | * Hook to get the online status of the browser. 6 | * 7 | * @returns {boolean} A boolean true if the browser is online, otherwise false. 8 | */ 9 | const useOnlineStatus = (): boolean => { 10 | const [isOnline, setIsOnline] = useState(() => (isBrowser() ? navigator.onLine : false)); 11 | 12 | useEffect(() => { 13 | if (!isBrowser()) { 14 | return; 15 | } 16 | 17 | const handleOnline = () => setIsOnline(true); 18 | const handleOffline = () => setIsOnline(false); 19 | 20 | window.addEventListener("online", handleOnline); 21 | window.addEventListener("offline", handleOffline); 22 | 23 | return () => { 24 | window.removeEventListener("online", handleOnline); 25 | window.removeEventListener("offline", handleOffline); 26 | }; 27 | }, []); 28 | 29 | return isOnline; 30 | }; 31 | 32 | export default useOnlineStatus; 33 | -------------------------------------------------------------------------------- /src/hooks/usePreferredLanguage.ts: -------------------------------------------------------------------------------- 1 | import { useState, useEffect } from "react"; 2 | import { isBrowser } from "../utils"; 3 | 4 | interface UsePreferredLanguage { 5 | language: string; 6 | languages: Array; 7 | isSupported: boolean; 8 | } 9 | 10 | /** 11 | * Hook to get the user's preferred language from the browser. 12 | * 13 | * @returns {UsePreferredLanguage} An object containing the preferred language and a boolean indicating support. 14 | */ 15 | const usePreferredLanguage = (): UsePreferredLanguage => { 16 | const [language, setLanguage] = useState( 17 | isBrowser() ? navigator.language : "" 18 | ); 19 | const [languages, setLanguages] = useState>( 20 | isBrowser() ? Array.from(navigator.languages) : [] 21 | ); 22 | const [isSupported, setIsSupported] = useState( 23 | isBrowser() && !!navigator.language 24 | ); 25 | 26 | useEffect(() => { 27 | if (isBrowser()) { 28 | if (navigator.language) { 29 | setLanguage(navigator.language); 30 | setIsSupported(true); 31 | } 32 | if (navigator.languages && navigator.languages.length > 0) { 33 | setLanguages(Array.from(navigator.languages)); 34 | setIsSupported(true); 35 | } else { 36 | setIsSupported(false); 37 | } 38 | } else { 39 | setIsSupported(false); 40 | } 41 | }, []); 42 | 43 | return { 44 | language, 45 | languages, 46 | isSupported, 47 | }; 48 | }; 49 | 50 | export default usePreferredLanguage; 51 | -------------------------------------------------------------------------------- /src/hooks/usePrevious.ts: -------------------------------------------------------------------------------- 1 | import { useRef, useEffect } from "react"; 2 | import { isBrowser } from "../utils"; 3 | 4 | /** 5 | Hook to get the previous value of a state or prop. 6 | * 7 | * @returns {T | undefined} The previous value of the state or prop. 8 | */ 9 | export default function usePrevious(value: T): T | undefined { 10 | const ref = useRef(); 11 | useEffect(() => { 12 | if (isBrowser()) { 13 | ref.current = value; 14 | } 15 | }, [value]); 16 | 17 | return ref.current; 18 | } 19 | -------------------------------------------------------------------------------- /src/hooks/useRandomColor.ts: -------------------------------------------------------------------------------- 1 | import { useState, useCallback } from "react"; 2 | import { isBrowser } from "../utils"; 3 | 4 | interface UseRandomColorResult { 5 | color: string; 6 | generateNewColor: () => void; 7 | } 8 | 9 | /** 10 | * Hook to generate a random color. 11 | * 12 | * @returns An object containing a string representing a random color in hexadecimal format and a function to generate a new random color. 13 | */ 14 | const useRandomColor = (): UseRandomColorResult => { 15 | const generateRandomColor = (): string => { 16 | const letters = "0123456789ABCDEF"; 17 | let color = "#"; 18 | for (let i = 0; i < 6; i++) { 19 | color += letters[Math.floor(Math.random() * 16)]; 20 | } 21 | return color; 22 | }; 23 | 24 | const [color, setColor] = useState( 25 | isBrowser() ? generateRandomColor() : "#000000" 26 | ); 27 | 28 | const generateNewColor = useCallback(() => { 29 | setColor(generateRandomColor()); 30 | }, []); 31 | 32 | return { color, generateNewColor }; 33 | }; 34 | 35 | export default useRandomColor; 36 | -------------------------------------------------------------------------------- /src/hooks/useScript.ts: -------------------------------------------------------------------------------- 1 | import { useState, useEffect } from "react"; 2 | import { isBrowser } from "../utils"; 3 | 4 | interface ScriptStatus { 5 | loading: boolean; 6 | error: Error | null; 7 | } 8 | 9 | interface UseScript { 10 | (src: string, options: options): ScriptStatus; 11 | } 12 | interface options { 13 | removeOnUnmount?: boolean; 14 | async?: boolean; 15 | defer?: boolean; 16 | } 17 | 18 | /** 19 | * Hook to dynamically load an external script. 20 | * 21 | * @param src - The URL of the script to load. 22 | * @param options - An object containing options for the script. 23 | * @returns An object containing the script loading status and any potential error. 24 | */ 25 | const useScript: UseScript = (src: string, options: options = {}) => { 26 | const [status, setStatus] = useState({ 27 | loading: true, 28 | error: null, 29 | }); 30 | 31 | useEffect(() => { 32 | if (!isBrowser()) return; 33 | 34 | const script = document.createElement("script"); 35 | script.src = src; 36 | script.async = options.async ?? true; 37 | script.defer = options.defer ?? false; 38 | 39 | const handleLoad = () => { 40 | setStatus({ loading: false, error: null }); 41 | }; 42 | 43 | const handleError = () => { 44 | setStatus({ 45 | loading: false, 46 | error: new Error(`Failed to load script: ${src}`), 47 | }); 48 | }; 49 | 50 | script.addEventListener("load", handleLoad); 51 | script.addEventListener("error", handleError); 52 | 53 | document.body.appendChild(script); 54 | 55 | return () => { 56 | script.removeEventListener("load", handleLoad); 57 | script.removeEventListener("error", handleError); 58 | if (options.removeOnUnmount) { 59 | document.body.removeChild(script); 60 | } 61 | }; 62 | }, [src]); 63 | 64 | return status; 65 | }; 66 | 67 | export default useScript; 68 | -------------------------------------------------------------------------------- /src/hooks/useScrollIntoPosition.ts: -------------------------------------------------------------------------------- 1 | import { useCallback } from "react"; 2 | import { isBrowser } from "../utils"; 3 | 4 | interface ScrollPosition { 5 | x: number; 6 | y: number; 7 | behavior?: ScrollBehavior; 8 | } 9 | 10 | interface UseScrollIntoPosition { 11 | (elementRef: React.RefObject): ( 12 | position: ScrollPosition 13 | ) => void; 14 | } 15 | 16 | /** 17 | * Hook to scroll an element to a specific position. 18 | * 19 | * @param {React.RefObject} elementRef - A ref to the element to scroll. 20 | * @returns A function to scroll the element to the specified x and y coordinates. 21 | */ 22 | const useScrollIntoPosition: UseScrollIntoPosition = ( 23 | elementRef: React.RefObject 24 | ) => { 25 | const scrollToPosition = useCallback( 26 | (position: ScrollPosition) => { 27 | if (isBrowser() && elementRef.current) { 28 | elementRef.current.scrollTo({ 29 | left: position.x, 30 | top: position.y, 31 | behavior: position.behavior || "auto", 32 | }); 33 | } 34 | }, 35 | [elementRef] 36 | ); 37 | 38 | return scrollToPosition; 39 | }; 40 | 41 | export default useScrollIntoPosition; 42 | -------------------------------------------------------------------------------- /src/hooks/useScrollLock.ts: -------------------------------------------------------------------------------- 1 | import { useCallback, useEffect, useState } from "react"; 2 | import { isBrowser } from "../utils"; 3 | 4 | interface UseScrollLock { 5 | (): { 6 | lockScroll: () => void; 7 | unlockScroll: () => void; 8 | isLocked: boolean; 9 | }; 10 | } 11 | 12 | /** 13 | * Hook to lock and unlock scrolling on the body element with an extra layer of security using MutationObserver. 14 | * 15 | * @returns An object containing methods to lock/unlock scrolling and a boolean indicating if the scroll is locked. 16 | */ 17 | const useScrollLock: UseScrollLock = () => { 18 | const [isLocked, setIsLocked] = useState(false); 19 | 20 | const lockScroll = useCallback(() => { 21 | if (isBrowser()) { 22 | document.body.style.overflow = "hidden"; 23 | setIsLocked(true); 24 | } 25 | }, []); 26 | 27 | const unlockScroll = useCallback(() => { 28 | if (isBrowser()) { 29 | document.body.style.overflow = ""; 30 | setIsLocked(false); 31 | } 32 | }, []); 33 | 34 | useEffect(() => { 35 | if (!isBrowser() || !window.MutationObserver) { 36 | return; 37 | } 38 | 39 | const observer = new MutationObserver((mutations) => { 40 | mutations.forEach((mutation) => { 41 | if ( 42 | mutation.type === "attributes" && 43 | mutation.attributeName === "style" 44 | ) { 45 | const overflow = document.body.style.overflow; 46 | if (isLocked && overflow !== "hidden") { 47 | document.body.style.overflow = "hidden"; 48 | } 49 | } 50 | }); 51 | }); 52 | 53 | observer.observe(document.body, { 54 | attributes: true, 55 | attributeFilter: ["style"], 56 | }); 57 | 58 | return () => { 59 | observer.disconnect(); 60 | if (isLocked) { 61 | document.body.style.overflow = ""; 62 | } 63 | }; 64 | }, [isLocked]); 65 | 66 | return { 67 | lockScroll, 68 | unlockScroll, 69 | isLocked, 70 | }; 71 | }; 72 | 73 | export default useScrollLock; 74 | -------------------------------------------------------------------------------- /src/hooks/useScrollPosition.ts: -------------------------------------------------------------------------------- 1 | import { useState, useEffect, useCallback } from "react"; 2 | import { isBrowser, throttle } from "../utils"; 3 | 4 | interface ScrollPosition { 5 | x: number; 6 | y: number; 7 | } 8 | 9 | interface UseScrollPosition { 10 | ( 11 | elementRef: React.RefObject, 12 | throttleTime?: number 13 | ): ScrollPosition; 14 | } 15 | 16 | /** 17 | * Hook to get the current scroll position of a specified element. 18 | * 19 | * @param {React.RefObject} elementRef - A ref to the element to track the scroll position. 20 | * @param {number} [throttleTime=200] - The time in milliseconds to throttle the scroll event handler. Defaults to 200ms. 21 | * @returns The current scroll position of the element. 22 | */ 23 | const useScrollPosition: UseScrollPosition = ( 24 | elementRef: React.RefObject, 25 | throttleTime: number = 200 26 | ) => { 27 | const [scrollPosition, setScrollPosition] = useState({ 28 | x: 0, 29 | y: 0, 30 | }); 31 | 32 | const handleScroll = useCallback( 33 | throttle(() => { 34 | if (isBrowser() && elementRef.current) { 35 | const { scrollLeft, scrollTop } = elementRef.current; 36 | setScrollPosition({ x: scrollLeft, y: scrollTop }); 37 | } 38 | }, throttleTime), 39 | [elementRef, throttleTime] 40 | ); 41 | 42 | useEffect(() => { 43 | if (!isBrowser() || !elementRef.current) { 44 | return; 45 | } 46 | 47 | const element = elementRef.current; 48 | 49 | element.addEventListener("scroll", handleScroll); 50 | 51 | return () => { 52 | element.removeEventListener("scroll", handleScroll); 53 | }; 54 | }, [elementRef, handleScroll]); 55 | 56 | return scrollPosition; 57 | }; 58 | 59 | export default useScrollPosition; 60 | -------------------------------------------------------------------------------- /src/hooks/useSessionStorage.ts: -------------------------------------------------------------------------------- 1 | import { useState, useEffect } from 'react'; 2 | import { isBrowser } from '../utils'; 3 | 4 | interface UseSessionStorage { 5 | (key: string, initialValue: T): [T, (value: T) => void]; 6 | } 7 | 8 | /** 9 | * Hook to manage a value in sessionStorage. 10 | * 11 | * @param key The key under which the value is stored in sessionStorage. 12 | * @param initialValue The initial value to use if there is no value in sessionStorage. 13 | * @returns An array with the current value and a function to update it. 14 | */ 15 | const useSessionStorage: UseSessionStorage = (key, initialValue) => { 16 | const [storedValue, setStoredValue] = useState(() => { 17 | if (!isBrowser()) { 18 | return initialValue; 19 | } 20 | try { 21 | const item = window.sessionStorage.getItem(key); 22 | return item ? JSON.parse(item) : initialValue; 23 | } catch (error) { 24 | console.warn(`Error reading sessionStorage key "${key}":`, error); 25 | return initialValue; 26 | } 27 | }); 28 | 29 | const setValue = (value: any) => { 30 | try { 31 | const valueToStore = value instanceof Function ? value(storedValue) : value; 32 | setStoredValue(valueToStore); 33 | if (isBrowser()) { 34 | window.sessionStorage.setItem(key, JSON.stringify(valueToStore)); 35 | } 36 | } catch (error) { 37 | console.warn(`Error setting sessionStorage key "${key}":`, error); 38 | } 39 | }; 40 | 41 | return [storedValue, setValue]; 42 | }; 43 | 44 | export default useSessionStorage; 45 | -------------------------------------------------------------------------------- /src/hooks/useSound.ts: -------------------------------------------------------------------------------- 1 | import { useState, useEffect, useCallback } from "react"; 2 | import { isBrowser } from "../utils"; 3 | 4 | interface UseSound { 5 | play: () => void; 6 | pause: () => void; 7 | stop: () => void; 8 | setVolume: (volume: number) => void; 9 | isPlaying: boolean; 10 | error: Error | null; 11 | } 12 | 13 | /** 14 | * Hook to play and manage sound effects. 15 | * 16 | * @param {string} url - The URL of the sound file. 17 | * @returns An object containing functions to play, pause, stop the sound, set volume, and state variables for the playing status and errors. 18 | */ 19 | const useSound = (url: string): UseSound => { 20 | const [audio, setAudio] = useState(null); 21 | const [isPlaying, setIsPlaying] = useState(false); 22 | const [error, setError] = useState(null); 23 | 24 | useEffect(() => { 25 | if (!isBrowser() || !window.Audio) { 26 | setError(new Error("Sound is not supported in this environment.")); 27 | return; 28 | } 29 | 30 | const audioElement = new Audio(url); 31 | setAudio(audioElement); 32 | 33 | const handlePlay = () => setIsPlaying(true); 34 | const handlePause = () => setIsPlaying(false); 35 | const handleError = (e: any) => setError(e); 36 | 37 | audioElement.addEventListener("play", handlePlay); 38 | audioElement.addEventListener("pause", handlePause); 39 | audioElement.addEventListener("error", handleError); 40 | 41 | return () => { 42 | audioElement.removeEventListener("play", handlePlay); 43 | audioElement.removeEventListener("pause", handlePause); 44 | audioElement.removeEventListener("error", handleError); 45 | audioElement.pause(); 46 | audioElement.currentTime = 0; 47 | }; 48 | }, [url]); 49 | 50 | const play = useCallback(() => { 51 | if (audio) { 52 | audio.play().catch((e) => setError(e)); 53 | } 54 | }, [audio]); 55 | 56 | const pause = useCallback(() => { 57 | if (audio) { 58 | audio.pause(); 59 | } 60 | }, [audio]); 61 | 62 | const stop = useCallback(() => { 63 | if (audio) { 64 | audio.pause(); 65 | audio.currentTime = 0; 66 | } 67 | }, [audio]); 68 | 69 | const setVolume = useCallback( 70 | (volume: number) => { 71 | if (audio) { 72 | audio.volume = volume; 73 | } 74 | }, 75 | [audio] 76 | ); 77 | 78 | return { 79 | play, 80 | pause, 81 | stop, 82 | setVolume, 83 | isPlaying, 84 | error, 85 | }; 86 | }; 87 | 88 | export default useSound; 89 | -------------------------------------------------------------------------------- /src/hooks/useStopWatch.ts: -------------------------------------------------------------------------------- 1 | import { useState, useRef, useCallback, useEffect } from "react"; 2 | import { isBrowser } from "../utils"; 3 | 4 | interface UseStopwatch { 5 | (): { 6 | time: number; 7 | isRunning: boolean; 8 | start: () => void; 9 | stop: () => void; 10 | reset: () => void; 11 | }; 12 | } 13 | 14 | /** 15 | * Hook to provide stopwatch functionality with SSR compatibility. 16 | * 17 | * @returns An object containing the current time in milliseconds, isRunning state, and functions to start, stop, and reset the stopwatch. 18 | */ 19 | const useStopwatch: UseStopwatch = () => { 20 | const [time, setTime] = useState(0); 21 | const [isRunning, setIsRunning] = useState(false); 22 | const timerRef = useRef(null); 23 | 24 | const start = useCallback(() => { 25 | if (isBrowser() && !isRunning) { 26 | setIsRunning(true); 27 | timerRef.current = setInterval(() => { 28 | setTime((prevTime) => prevTime + 1); 29 | }, 1000); 30 | } 31 | }, [isRunning]); 32 | 33 | const stop = useCallback(() => { 34 | if (isBrowser() && isRunning) { 35 | setIsRunning(false); 36 | if (timerRef.current) { 37 | clearInterval(timerRef.current); 38 | timerRef.current = null; 39 | } 40 | } 41 | }, [isRunning]); 42 | 43 | const reset = useCallback(() => { 44 | if (isBrowser()) { 45 | setIsRunning(false); 46 | setTime(0); 47 | if (timerRef.current) { 48 | clearInterval(timerRef.current); 49 | timerRef.current = null; 50 | } 51 | } 52 | }, []); 53 | 54 | useEffect(() => { 55 | return () => { 56 | if (timerRef.current) { 57 | clearInterval(timerRef.current); 58 | } 59 | }; 60 | }, []); 61 | 62 | return { 63 | time, 64 | isRunning, 65 | start, 66 | stop, 67 | reset, 68 | }; 69 | }; 70 | 71 | export default useStopwatch; 72 | -------------------------------------------------------------------------------- /src/hooks/useSystemTheme.ts: -------------------------------------------------------------------------------- 1 | import { useEffect, useState } from "react"; 2 | import { isBrowser } from "../utils"; 3 | 4 | const DARK_MODE_QUERY = "(prefers-color-scheme: dark)"; 5 | const LIGHT_THEME = "light" as const; 6 | const DARK_THEME = "dark" as const; 7 | 8 | type Theme = typeof LIGHT_THEME | typeof DARK_THEME; 9 | 10 | const getSystemTheme = (): Theme => { 11 | if (isBrowser() && window.matchMedia) { 12 | const query = window.matchMedia(DARK_MODE_QUERY); 13 | if (query.matches) { 14 | return DARK_THEME; 15 | } 16 | } 17 | return LIGHT_THEME; // Default to light if no preference or prefers light mode 18 | }; 19 | 20 | /** 21 | * Hook to get the system theme. 22 | * @returns {Theme} The current system theme value (light or dark). 23 | */ 24 | const useSystemTheme = (): Theme => { 25 | const [theme, setTheme] = useState(() => getSystemTheme()); 26 | 27 | useEffect(() => { 28 | if (isBrowser() && window.matchMedia) { 29 | const query = window.matchMedia(DARK_MODE_QUERY); 30 | 31 | const handleChange = () => { 32 | setTheme(getSystemTheme()); 33 | }; 34 | 35 | query.addEventListener("change", handleChange); 36 | 37 | return () => { 38 | query.removeEventListener("change", handleChange); 39 | }; 40 | } 41 | }, []); 42 | 43 | return theme; 44 | }; 45 | 46 | export default useSystemTheme; 47 | -------------------------------------------------------------------------------- /src/hooks/useTitle.ts: -------------------------------------------------------------------------------- 1 | import { useEffect, useState, useCallback } from "react"; 2 | import { isBrowser } from "../utils"; 3 | 4 | interface UseTitleResult { 5 | setTitle: (newTitle: string) => void; 6 | } 7 | 8 | /** 9 | * Hook to set and get the document title. 10 | * 11 | * @param {string} initialTitle - The initial title to set. 12 | * @returns An object with the setTitle function. 13 | */ 14 | const useTitle = (initialTitle: string): UseTitleResult => { 15 | const setTitle = useCallback((newTitle: string) => { 16 | if (isBrowser()) { 17 | document.title = newTitle; 18 | } 19 | }, []); 20 | 21 | useEffect(() => { 22 | if (isBrowser()) { 23 | document.title = initialTitle; 24 | } 25 | }, [initialTitle]); 26 | 27 | return { 28 | setTitle, 29 | }; 30 | }; 31 | 32 | export default useTitle; 33 | 34 | -------------------------------------------------------------------------------- /src/hooks/useTouch.ts: -------------------------------------------------------------------------------- 1 | import { useState, useEffect, useCallback } from "react"; 2 | import { isBrowser } from "../utils"; 3 | 4 | interface TouchPosition { 5 | x: number | null; 6 | y: number | null; 7 | } 8 | 9 | interface UseTouch { 10 | (elementRef: React.RefObject): { 11 | touchStart: TouchPosition; 12 | touchMove: TouchPosition; 13 | touchEnd: TouchPosition; 14 | }; 15 | } 16 | 17 | /** 18 | * Hook to track touch events on a specified element. 19 | * 20 | * @param {React.RefObject} elementRef - A ref to the element to track touch events. 21 | * @returns An object with the current touch start, move, and end positions. 22 | */ 23 | const useTouch: UseTouch = (elementRef: React.RefObject) => { 24 | const [touchStart, setTouchStart] = useState({ 25 | x: null, 26 | y: null, 27 | }); 28 | const [touchMove, setTouchMove] = useState({ 29 | x: null, 30 | y: null, 31 | }); 32 | const [touchEnd, setTouchEnd] = useState({ x: null, y: null }); 33 | 34 | const handleTouchStart = useCallback((event: TouchEvent) => { 35 | const touch = event.touches[0]; 36 | setTouchStart({ x: touch.clientX, y: touch.clientY }); 37 | }, []); 38 | 39 | const handleTouchMove = useCallback((event: TouchEvent) => { 40 | const touch = event.touches[0]; 41 | setTouchMove({ x: touch.clientX, y: touch.clientY }); 42 | }, []); 43 | 44 | const handleTouchEnd = useCallback(() => { 45 | setTouchEnd(touchMove); 46 | setTouchMove({ x: null, y: null }); 47 | setTouchStart({ x: null, y: null }); 48 | }, [touchMove]); 49 | 50 | useEffect(() => { 51 | if (!isBrowser() || !elementRef.current) { 52 | return; 53 | } 54 | 55 | const element = elementRef.current; 56 | element.addEventListener("touchstart", handleTouchStart); 57 | element.addEventListener("touchmove", handleTouchMove); 58 | element.addEventListener("touchend", handleTouchEnd); 59 | 60 | return () => { 61 | element.removeEventListener("touchstart", handleTouchStart); 62 | element.removeEventListener("touchmove", handleTouchMove); 63 | element.removeEventListener("touchend", handleTouchEnd); 64 | }; 65 | }, [elementRef, handleTouchStart, handleTouchMove, handleTouchEnd]); 66 | 67 | return { touchStart, touchMove, touchEnd }; 68 | }; 69 | 70 | export default useTouch; 71 | -------------------------------------------------------------------------------- /src/hooks/useTouchSwipe.ts: -------------------------------------------------------------------------------- 1 | import { useState, useEffect, useCallback, useRef } from 'react'; 2 | import { isBrowser } from '../utils'; 3 | 4 | interface SwipeState { 5 | startX: number | null; 6 | startY: number | null; 7 | endX: number | null; 8 | endY: number | null; 9 | direction: 'left' | 'right' | 'up' | 'down' | null; 10 | } 11 | 12 | interface UseTouchSwipe { 13 | swipeState: SwipeState; 14 | reset: () => void; 15 | } 16 | 17 | /** 18 | * Hook to detect touch swipe gestures. 19 | * 20 | * @param {React.RefObject} ref - The ref of the element to attach the touch events to. 21 | * @returns {UseTouchSwipe} The current swipe state and a reset function. 22 | */ 23 | const useTouchSwipe = (ref: React.RefObject): UseTouchSwipe => { 24 | const [swipeState, setSwipeState] = useState({ 25 | startX: null, 26 | startY: null, 27 | endX: null, 28 | endY: null, 29 | direction: null, 30 | }); 31 | 32 | const handleTouchStart = useCallback((event: TouchEvent) => { 33 | const touch = event.touches[0]; 34 | setSwipeState((prevState) => ({ 35 | ...prevState, 36 | startX: touch.clientX, 37 | startY: touch.clientY, 38 | })); 39 | }, []); 40 | 41 | const handleTouchMove = useCallback((event: TouchEvent) => { 42 | const touch = event.touches[0]; 43 | setSwipeState((prevState) => ({ 44 | ...prevState, 45 | endX: touch.clientX, 46 | endY: touch.clientY, 47 | })); 48 | }, []); 49 | 50 | const handleTouchEnd = useCallback(() => { 51 | setSwipeState((prevState) => { 52 | const { startX, startY, endX, endY } = prevState; 53 | if (startX === null || startY === null || endX === null || endY === null) { 54 | return prevState; 55 | } 56 | const deltaX = endX - startX; 57 | const deltaY = endY - startY; 58 | let direction: 'left' | 'right' | 'up' | 'down' | null = null; 59 | if (Math.abs(deltaX) > Math.abs(deltaY)) { 60 | direction = deltaX > 0 ? 'right' : 'left'; 61 | } else { 62 | direction = deltaY > 0 ? 'down' : 'up'; 63 | } 64 | return { ...prevState, direction }; 65 | }); 66 | }, []); 67 | 68 | useEffect(() => { 69 | if (!isBrowser() || !ref.current) return; 70 | 71 | const element = ref.current; 72 | 73 | element.addEventListener('touchstart', handleTouchStart); 74 | element.addEventListener('touchmove', handleTouchMove); 75 | element.addEventListener('touchend', handleTouchEnd); 76 | 77 | return () => { 78 | element.removeEventListener('touchstart', handleTouchStart); 79 | element.removeEventListener('touchmove', handleTouchMove); 80 | element.removeEventListener('touchend', handleTouchEnd); 81 | }; 82 | }, [ref, handleTouchStart, handleTouchMove, handleTouchEnd]); 83 | 84 | const reset = () => { 85 | setSwipeState({ 86 | startX: null, 87 | startY: null, 88 | endX: null, 89 | endY: null, 90 | direction: null, 91 | }); 92 | }; 93 | 94 | return { swipeState, reset }; 95 | }; 96 | 97 | export default useTouchSwipe; 98 | -------------------------------------------------------------------------------- /src/hooks/useUpdateEffect.ts: -------------------------------------------------------------------------------- 1 | import { useEffect, useRef } from "react"; 2 | import { isBrowser } from "../utils"; 3 | 4 | /** 5 | * Hook to run an effect only on updates, not on initial mount. 6 | * 7 | * @param {Function} effect - The effect function to run. 8 | * @param {Array} deps - The dependency array for the effect. 9 | */ 10 | const useUpdateEffect = ( 11 | effect: React.EffectCallback, 12 | deps: React.DependencyList 13 | ) => { 14 | const isFirstMount = useRef(true); 15 | 16 | useEffect(() => { 17 | if (!isBrowser()) { 18 | return; 19 | } 20 | 21 | if (isFirstMount.current) { 22 | isFirstMount.current = false; 23 | return; 24 | } 25 | 26 | return effect(); 27 | }, deps); 28 | }; 29 | 30 | export default useUpdateEffect; 31 | -------------------------------------------------------------------------------- /src/hooks/useVibration.ts: -------------------------------------------------------------------------------- 1 | import { useCallback, useState, useEffect } from "react"; 2 | import { isBrowser } from "../utils"; 3 | 4 | interface UseVibration { 5 | vibrate: (pattern: number | number[]) => void; 6 | stop: () => void; 7 | isSupported: boolean; 8 | error: Error | null; 9 | } 10 | 11 | /** 12 | * Hook to manage vibration on supported devices. 13 | * 14 | * @returns {UseVibration} An object containing functions to vibrate, stop vibration, check support, and state variables for error. 15 | */ 16 | const useVibration = (): UseVibration => { 17 | const [isSupported, setIsSupported] = useState( 18 | isBrowser() && "vibrate" in navigator 19 | ); 20 | const [error, setError] = useState(null); 21 | 22 | useEffect(() => { 23 | if (!isBrowser()) { 24 | setIsSupported(false); 25 | return; 26 | } 27 | setIsSupported("vibrate" in navigator); 28 | }, []); 29 | 30 | const vibrate = useCallback( 31 | (pattern: number | number[]) => { 32 | if (isSupported) { 33 | try { 34 | navigator.vibrate(pattern); 35 | } catch (e) { 36 | setError(e as Error); 37 | } 38 | } else { 39 | setError(new Error("Vibration is not supported on this device.")); 40 | } 41 | }, 42 | [isSupported] 43 | ); 44 | 45 | const stop = useCallback(() => { 46 | if (isSupported) { 47 | navigator.vibrate(0); 48 | } 49 | }, [isSupported]); 50 | 51 | return { 52 | vibrate, 53 | stop, 54 | isSupported, 55 | error, 56 | }; 57 | }; 58 | 59 | export default useVibration; 60 | -------------------------------------------------------------------------------- /src/hooks/useWindowFocus.ts: -------------------------------------------------------------------------------- 1 | import { useState, useEffect } from "react"; 2 | import { isBrowser } from "../utils"; 3 | 4 | /** 5 | * Hook to track the focus state of the window. 6 | * 7 | * @returns A boolean indicating whether the window is focused. 8 | */ 9 | const useWindowFocus = (): boolean => { 10 | const [isFocused, setIsFocused] = useState(isBrowser() ? document.hasFocus() : false); 11 | 12 | useEffect(() => { 13 | if (!isBrowser()) { 14 | return; 15 | } 16 | 17 | const handleFocus = () => setIsFocused(true); 18 | const handleBlur = () => setIsFocused(false); 19 | 20 | window.addEventListener("focus", handleFocus); 21 | window.addEventListener("blur", handleBlur); 22 | 23 | return () => { 24 | window.removeEventListener("focus", handleFocus); 25 | window.removeEventListener("blur", handleBlur); 26 | }; 27 | }, []); 28 | 29 | return isFocused; 30 | }; 31 | 32 | export default useWindowFocus; 33 | -------------------------------------------------------------------------------- /src/hooks/useWindowScrollIntoPosition.ts: -------------------------------------------------------------------------------- 1 | import { useEffect, useCallback } from "react"; 2 | import { isBrowser } from "../utils"; 3 | 4 | interface ScrollPosition { 5 | x: number; 6 | y: number; 7 | behavior?: ScrollBehavior; 8 | } 9 | 10 | interface UseWindowScrollIntoPosition { 11 | (): (position: ScrollPosition) => void; 12 | } 13 | 14 | /** 15 | * Hook to scroll the window to a specific position. 16 | * 17 | * @returns A function to scroll the window to the specified x and y coordinates. 18 | */ 19 | const useWindowScrollIntoPosition: UseWindowScrollIntoPosition = () => { 20 | const scrollToPosition = useCallback((position: ScrollPosition) => { 21 | if (isBrowser()) { 22 | window.scrollTo({ 23 | left: position.x, 24 | top: position.y, 25 | behavior: position.behavior || "auto", 26 | }); 27 | } 28 | }, []); 29 | 30 | return scrollToPosition; 31 | }; 32 | 33 | export default useWindowScrollIntoPosition; 34 | -------------------------------------------------------------------------------- /src/hooks/useWindowScrollPosition.ts: -------------------------------------------------------------------------------- 1 | import { useState, useEffect, useCallback } from "react"; 2 | import { isBrowser, throttle } from "../utils"; 3 | 4 | interface WindowScrollPosition { 5 | x: number | null; 6 | y: number | null; 7 | } 8 | 9 | const getWindowScrollPosition = (): WindowScrollPosition => ({ 10 | x: isBrowser() ? window.scrollX : null, 11 | y: isBrowser() ? window.scrollY : null, 12 | }); 13 | 14 | /** 15 | * Hook to get the current window scroll position. 16 | * 17 | * @param {number} [throttleTime=200] - The time in milliseconds to throttle the scroll event handler. Defaults to 200ms. 18 | * @returns An object with the current window scroll position (x and y). 19 | */ 20 | const useWindowScrollPosition = (throttleTime: number = 200): WindowScrollPosition => { 21 | const [scrollPosition, setScrollPosition] = useState(getWindowScrollPosition); 22 | 23 | const handleScroll = useCallback( 24 | throttle(() => { 25 | setScrollPosition(getWindowScrollPosition()); 26 | }, throttleTime), 27 | [throttleTime] 28 | ); 29 | 30 | useEffect(() => { 31 | if (!isBrowser()) { 32 | return; 33 | } 34 | 35 | window.addEventListener("scroll", handleScroll); 36 | 37 | return () => { 38 | window.removeEventListener("scroll", handleScroll); 39 | }; 40 | }, [handleScroll]); 41 | 42 | return scrollPosition; 43 | }; 44 | 45 | export default useWindowScrollPosition; 46 | -------------------------------------------------------------------------------- /src/hooks/useWindowSize.ts: -------------------------------------------------------------------------------- 1 | import { useState, useEffect, useCallback } from "react"; 2 | import { isBrowser, throttle } from "../utils"; 3 | 4 | interface WindowSize { 5 | width: number | null; 6 | height: number | null; 7 | } 8 | 9 | const getWindowSize = (): WindowSize => ({ 10 | width: isBrowser() ? window.innerWidth : null, 11 | height: isBrowser() ? window.innerHeight : null, 12 | }); 13 | 14 | /** 15 | * Hook to get the current window size. 16 | * 17 | * @param {number} [throttleTime=200] - The time in milliseconds to throttle the resize event handler. Defaults to 200ms. 18 | * @returns An object with the current window width and height. 19 | */ 20 | const useWindowSize = (throttleTime: number = 200): WindowSize => { 21 | const [windowSize, setWindowSize] = useState(getWindowSize); 22 | 23 | const handleResize = useCallback( 24 | throttle(() => { 25 | setWindowSize(getWindowSize()); 26 | }, throttleTime), 27 | [throttleTime] 28 | ); 29 | 30 | useEffect(() => { 31 | if (!isBrowser()) { 32 | return; 33 | } 34 | 35 | window.addEventListener("resize", handleResize); 36 | 37 | return () => { 38 | window.removeEventListener("resize", handleResize); 39 | }; 40 | }, [handleResize]); 41 | 42 | return windowSize; 43 | }; 44 | 45 | export default useWindowSize; 46 | -------------------------------------------------------------------------------- /src/hooks/useWindowTouchSwipe.ts: -------------------------------------------------------------------------------- 1 | import { useState, useEffect, useCallback } from "react"; 2 | import { isBrowser } from "../utils"; 3 | 4 | interface SwipeState { 5 | startX: number | null; 6 | startY: number | null; 7 | endX: number | null; 8 | endY: number | null; 9 | direction: "left" | "right" | "up" | "down" | null; 10 | } 11 | 12 | interface useWindowTouchSwipe { 13 | swipeState: SwipeState; 14 | reset: () => void; 15 | } 16 | 17 | /** 18 | * Hook to detect touch swipe gestures. 19 | * 20 | * @returns {useWindowTouchSwipe} The current swipe state and a reset function. 21 | */ 22 | const useWindowTouchSwipe = (): useWindowTouchSwipe => { 23 | const [swipeState, setSwipeState] = useState({ 24 | startX: null, 25 | startY: null, 26 | endX: null, 27 | endY: null, 28 | direction: null, 29 | }); 30 | 31 | const handleTouchStart = useCallback((event: TouchEvent) => { 32 | const touch = event.touches[0]; 33 | setSwipeState((prevState) => ({ 34 | ...prevState, 35 | startX: touch.clientX, 36 | startY: touch.clientY, 37 | })); 38 | }, []); 39 | 40 | const handleTouchMove = useCallback((event: TouchEvent) => { 41 | const touch = event.touches[0]; 42 | setSwipeState((prevState) => ({ 43 | ...prevState, 44 | endX: touch.clientX, 45 | endY: touch.clientY, 46 | })); 47 | }, []); 48 | 49 | const handleTouchEnd = useCallback(() => { 50 | setSwipeState((prevState) => { 51 | const { startX, startY, endX, endY } = prevState; 52 | if ( 53 | startX === null || 54 | startY === null || 55 | endX === null || 56 | endY === null 57 | ) { 58 | return prevState; 59 | } 60 | const deltaX = endX - startX; 61 | const deltaY = endY - startY; 62 | let direction: "left" | "right" | "up" | "down" | null = null; 63 | if (Math.abs(deltaX) > Math.abs(deltaY)) { 64 | direction = deltaX > 0 ? "right" : "left"; 65 | } else { 66 | direction = deltaY > 0 ? "down" : "up"; 67 | } 68 | return { ...prevState, direction }; 69 | }); 70 | }, []); 71 | 72 | useEffect(() => { 73 | if (!isBrowser()) return; 74 | 75 | window.addEventListener("touchstart", handleTouchStart); 76 | window.addEventListener("touchmove", handleTouchMove); 77 | window.addEventListener("touchend", handleTouchEnd); 78 | 79 | return () => { 80 | window.removeEventListener("touchstart", handleTouchStart); 81 | window.removeEventListener("touchmove", handleTouchMove); 82 | window.removeEventListener("touchend", handleTouchEnd); 83 | }; 84 | }, [handleTouchStart, handleTouchMove, handleTouchEnd]); 85 | 86 | const reset = () => { 87 | setSwipeState({ 88 | startX: null, 89 | startY: null, 90 | endX: null, 91 | endY: null, 92 | direction: null, 93 | }); 94 | }; 95 | 96 | return { swipeState, reset }; 97 | }; 98 | 99 | export default useWindowTouchSwipe; 100 | -------------------------------------------------------------------------------- /src/index.ts: -------------------------------------------------------------------------------- 1 | export { default as useSystemTheme } from "./hooks/useSystemTheme"; 2 | export { default as useOnlineStatus } from "./hooks/useOnlineStatus"; 3 | export { default as useClipboard } from "./hooks/useClipboard"; 4 | export { default as useGeolocation } from "./hooks/useGeoLocation"; 5 | export { default as useTitle } from "./hooks/useTitle"; 6 | export { default as useBattery } from "./hooks/useBattery"; 7 | export { default as useWindowSize } from "./hooks/useWindowSize"; 8 | export { default as useWindowScrollPosition } from "./hooks/useWindowScrollPosition"; 9 | export { default as useWindowScrollIntoPosition } from "./hooks/useWindowScrollIntoPosition"; 10 | export { default as useScrollPosition } from "./hooks/useScrollPosition"; 11 | export { default as useScrollIntoPosition } from "./hooks/useScrollIntoPosition"; 12 | export { default as useFocusBlur } from "./hooks/useFocusBlur"; 13 | export { default as useStopwatch } from "./hooks/useStopwatch"; 14 | export { default as useFavicon } from "./hooks/useFavicon"; 15 | export { default as useScript } from "./hooks/useScript"; 16 | export { default as useHover } from "./hooks/useHover"; 17 | export { default as useMediaQuery } from "./hooks/useMediaQuery"; 18 | export { default as useLocalStorage } from "./hooks/useLocalStorage"; 19 | export { default as useSessionStorage } from "./hooks/useSessionStorage"; 20 | export { default as useDeviceOrientation } from "./hooks/useDeviceOrientation"; 21 | export { default as useDimensions } from "./hooks/useDimensions"; 22 | export { default as useKeyPress } from "./hooks/useKeyPress"; 23 | export { default as useKeyCombo } from "./hooks/useKeyCombo"; 24 | export { default as useClickOutside } from "./hooks/useClickOutside"; 25 | export { default as useIntersectionObserver } from "./hooks/useIntersectionObserver"; 26 | export { default as useMutationObserver } from "./hooks/useMutationObserver"; 27 | export { default as useEventListener } from "./hooks/useEventListener"; 28 | export { default as useWindowFocus } from "./hooks/useWindowFocus"; 29 | export { default as useIdle } from "./hooks/useIdle"; 30 | export { default as useMouse } from "./hooks/useMouse"; 31 | export { default as useLongPress } from "./hooks/useLongPress"; 32 | export { default as useFetch } from "./hooks/useFetch"; 33 | export { default as useScrollLock } from "./hooks/useScrollLock"; 34 | export { default as useRandomColor } from "./hooks/useRandomColor"; 35 | export { default as useDebounce } from "./hooks/useDebounce"; 36 | export { default as usePrevious } from "./hooks/usePrevious"; 37 | export { default as useDebouncedCallback } from "./hooks/useDebouncedCallback"; 38 | export { default as useCookie } from "./hooks/useCookie"; 39 | export { default as useUpdateEffect } from "./hooks/useUpdateEffect"; 40 | export { default as useSound } from "./hooks/useSound"; 41 | export { default as useVibration } from "./hooks/useVibration"; 42 | export { default as usePreferredLanguage } from "./hooks/usePreferredLanguage"; 43 | export { default as useNotification } from "./hooks/useNotification"; 44 | export { default as useHistory } from "./hooks/useHistory"; 45 | export { default as useTouch } from "./hooks/useTouch"; 46 | export { default as useWindowTouchSwipe } from "./hooks/useWindowTouchSwipe"; 47 | export { default as useTouchSwipe } from "./hooks/useTouchSwipe"; -------------------------------------------------------------------------------- /src/utils/index.ts: -------------------------------------------------------------------------------- 1 | export const isBrowser = (): boolean => { 2 | return typeof window !== "undefined" && typeof window.document !== "undefined" 3 | ? true 4 | : false; 5 | }; 6 | 7 | export const throttle = (func: Function, wait: number) => { 8 | let timeout: NodeJS.Timeout | null = null; 9 | return function (this: any, ...args: any[]) { 10 | if (timeout) return; 11 | timeout = setTimeout(() => { 12 | func.apply(this, args); 13 | timeout = null; 14 | }, wait); 15 | }; 16 | }; 17 | 18 | export function debounce(func: Function, delay: number) { 19 | let timeoutId: ReturnType; 20 | 21 | return function (...args: any[]) { 22 | clearTimeout(timeoutId); 23 | timeoutId = setTimeout(() => { 24 | func(...args); 25 | }, delay); 26 | }; 27 | } 28 | -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "es5", 4 | "module": "esnext", 5 | "lib": ["dom", "es2015", "es2017"], 6 | "allowJs": true, 7 | "jsx": "react", 8 | "declaration": true, 9 | "declarationMap": false, 10 | "emitDeclarationOnly": true, 11 | "declarationDir": "./dist/types", 12 | "outDir": "./dist", 13 | "rootDir": "./src", 14 | "strict": true, 15 | "moduleResolution": "node", 16 | "esModuleInterop": true, 17 | "skipLibCheck": true, 18 | "forceConsistentCasingInFileNames": true, 19 | "composite": true 20 | }, 21 | "include": ["src"], 22 | "exclude": ["node_modules", "dist"] 23 | } 24 | --------------------------------------------------------------------------------