@alessiofrittoli/react-hooks 3.4.0 → 3.5.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -13,7 +13,6 @@
13
13
  [downloads-badge]: https://img.shields.io/npm/dm/%40alessiofrittoli%2Freact-hooks.svg
14
14
  [deps-badge]: https://img.shields.io/librariesio/release/npm/%40alessiofrittoli%2Freact-hooks
15
15
  [deps-url]: https://libraries.io/npm/%40alessiofrittoli%2Freact-hooks
16
-
17
16
  [sponsor-badge]: https://img.shields.io/static/v1?label=Fund%20this%20package&message=%E2%9D%A4&logo=GitHub&color=%23DB61A2
18
17
  [sponsor-url]: https://github.com/sponsors/alessiofrittoli
19
18
 
@@ -34,6 +33,8 @@
34
33
  - [`useEventListener`](#useeventlistener)
35
34
  - [`useIsPortrait`](#useisportrait)
36
35
  - [`useMediaQuery`](#usemediaquery)
36
+ - [`useDocumentVisibility`](#usedocumentvisibility)
37
+ - [`useWakeLock`](#usewakelock)
37
38
  - [DOM API](#dom-api)
38
39
  - [`useFocusTrap`](#usefocustrap)
39
40
  - [`useInView`](#useinview)
@@ -88,16 +89,15 @@ This library may define and exports hooks that requires additional ESLint config
88
89
  Simply imports recommended configuration from `@alessiofrittoli/react-hooks/eslint` and add them to your ESLint configuration like so:
89
90
 
90
91
  ```mjs
91
- import { config as AFReactHooksEslint } from '@alessiofrittoli/react-hooks/eslint'
92
+ import { config as AFReactHooksEslint } from "@alessiofrittoli/react-hooks/eslint";
92
93
 
93
94
  /** @type {import('eslint').Linter.Config[]} */
94
95
  const config = [
95
96
  ...AFReactHooksEslint.recommended,
96
97
  // ... other configurations
97
- ]
98
-
98
+ ];
99
99
 
100
- export default config
100
+ export default config;
101
101
  ```
102
102
 
103
103
  ---
@@ -106,8 +106,9 @@ export default config
106
106
 
107
107
  #### Updates in the latest release 🎉
108
108
 
109
- - Add `useDeferCallback`. See [API Reference](#usedefercallback) for more info.
110
- - Add missing API Referefence sections.
109
+ - Added `useDocumentVisibility`. See [API Reference](#usedocumentvisibility) for more info.
110
+ - Added `useWakeLock`. See [API Reference](#usewakelock) for more info.
111
+ - Added `useDeferCallback`. See [API Reference](#usedefercallback) for more info.
111
112
 
112
113
  ---
113
114
 
@@ -127,8 +128,8 @@ Easly handle Local or Session Storage State.
127
128
 
128
129
  <summary style="cursor:pointer">Type parameters</summary>
129
130
 
130
- | Parameter | Type | Default | Description |
131
- |-----------|------|---------|-------------|
131
+ | Parameter | Type | Default | Description |
132
+ | --------- | ----- | -------- | ----------------------------------------- |
132
133
  | `T` | `any` | `string` | A custom type applied to the stored item. |
133
134
 
134
135
  </details>
@@ -139,11 +140,11 @@ Easly handle Local or Session Storage State.
139
140
 
140
141
  <summary style="cursor:pointer">Parameters</summary>
141
142
 
142
- | Parameter | Type | Default | Description |
143
- |-----------|------|---------|-------------|
144
- | `key` | `string` | - | The storage item key. |
145
- | `initial` | `T` | - | The storage item initial value. |
146
- | `type` | `local\|session` | local | (Optional) The storage API to use. |
143
+ | Parameter | Type | Default | Description |
144
+ | --------- | ---------------- | ------- | ---------------------------------- |
145
+ | `key` | `string` | - | The storage item key. |
146
+ | `initial` | `T` | - | The storage item initial value. |
147
+ | `type` | `local\|session` | local | (Optional) The storage API to use. |
147
148
 
148
149
  </details>
149
150
 
@@ -169,8 +170,10 @@ A tuple with the stored item value or initial value and the setter function.
169
170
 
170
171
  ```tsx
171
172
  import {
172
- useStorage, useLocalStorage, useSessionStorage
173
- } from '@alessiofrittoli/react-hooks'
173
+ useStorage,
174
+ useLocalStorage,
175
+ useSessionStorage,
176
+ } from "@alessiofrittoli/react-hooks";
174
177
  ```
175
178
 
176
179
  ---
@@ -302,7 +305,6 @@ An object with the following properties:
302
305
 
303
306
  ---
304
307
 
305
-
306
308
  ##### `useDarkMode`
307
309
 
308
310
  Easily manage dark mode with full respect for user device preferences.
@@ -317,11 +319,11 @@ This hook is user-oriented and built to honor system-level color scheme settings
317
319
 
318
320
  <summary style="cursor:pointer">Parameters</summary>
319
321
 
320
- | Parameter | Type | Description |
321
- |-----------|------|-------------|
322
- | `options` | `UseDarkModeOptions` | (Optional) Configuration object for the hook. |
323
- | `options.initial` | `boolean` | (Optional) The fallback value to use if no preference is saved in `localStorage`. Defaults to `true` if the device prefers dark mode. |
324
- | `options.docClassNames` | `[dark: string, light: string]` | (Optional) Array of class names to toggle on the `<html>` element, e.g. `['dark', 'light']`. |
322
+ | Parameter | Type | Description |
323
+ | ----------------------- | ------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------- |
324
+ | `options` | `UseDarkModeOptions` | (Optional) Configuration object for the hook. |
325
+ | `options.initial` | `boolean` | (Optional) The fallback value to use if no preference is saved in `localStorage`. Defaults to `true` if the device prefers dark mode. |
326
+ | `options.docClassNames` | `[dark: string, light: string]` | (Optional) Array of class names to toggle on the `<html>` element, e.g. `['dark', 'light']`. |
325
327
 
326
328
  </details>
327
329
 
@@ -352,17 +354,15 @@ An object containing utilities for managing dark mode:
352
354
  ###### Basic usage
353
355
 
354
356
  ```tsx
355
- 'use client'
357
+ "use client";
356
358
 
357
- import { useDarkMode } from '@alessiofrittoli/react-hooks'
359
+ import { useDarkMode } from "@alessiofrittoli/react-hooks";
358
360
 
359
361
  export const Component: React.FC = () => {
360
- const { isDarkMode } = useDarkMode()
362
+ const { isDarkMode } = useDarkMode();
361
363
 
362
- return (
363
- <div>{ isDarkMode ? 'Dark mode enabled' : 'Dark mode disabled' }</div>
364
- )
365
- }
364
+ return <div>{isDarkMode ? "Dark mode enabled" : "Dark mode disabled"}</div>;
365
+ };
366
366
  ```
367
367
 
368
368
  ---
@@ -371,19 +371,17 @@ export const Component: React.FC = () => {
371
371
 
372
372
  ```tsx
373
373
  // Component.tsx
374
- 'use client'
374
+ "use client";
375
375
 
376
- import { useDarkMode } from '@alessiofrittoli/react-hooks'
376
+ import { useDarkMode } from "@alessiofrittoli/react-hooks";
377
377
 
378
378
  export const Component: React.FC = () => {
379
- const { isDarkMode } = useDarkMode( {
380
- docClassNames: [ 'dark', 'light' ],
381
- } )
379
+ const { isDarkMode } = useDarkMode({
380
+ docClassNames: ["dark", "light"],
381
+ });
382
382
 
383
- return (
384
- <div>{ isDarkMode ? 'Dark mode enabled' : 'Dark mode disabled' }</div>
385
- )
386
- }
383
+ return <div>{isDarkMode ? "Dark mode enabled" : "Dark mode disabled"}</div>;
384
+ };
387
385
  ```
388
386
 
389
387
  ```css
@@ -396,15 +394,13 @@ export const Component: React.FC = () => {
396
394
  color-scheme: dark;
397
395
  }
398
396
 
399
- .light body
400
- {
401
- color : black;
397
+ .light body {
398
+ color: black;
402
399
  background: white;
403
400
  }
404
401
 
405
- .dark body
406
- {
407
- color : white;
402
+ .dark body {
403
+ color: white;
408
404
  background: black;
409
405
  }
410
406
  ```
@@ -414,19 +410,15 @@ export const Component: React.FC = () => {
414
410
  ###### Custom theme switcher
415
411
 
416
412
  ```tsx
417
- 'use client'
413
+ "use client";
418
414
 
419
- import { useDarkMode } from '@alessiofrittoli/react-hooks'
415
+ import { useDarkMode } from "@alessiofrittoli/react-hooks";
420
416
 
421
417
  export const ThemeSwitcher: React.FC = () => {
422
- const { isDarkMode, toggleDarkMode } = useDarkMode()
418
+ const { isDarkMode, toggleDarkMode } = useDarkMode();
423
419
 
424
- return (
425
- <button onClick={ toggleDarkMode }>
426
- { isDarkMode ? '🌙' : '☀️' }
427
- </button>
428
- )
429
- }
420
+ return <button onClick={toggleDarkMode}>{isDarkMode ? "🌙" : "☀️"}</button>;
421
+ };
430
422
  ```
431
423
 
432
424
  ---
@@ -436,10 +428,10 @@ export const ThemeSwitcher: React.FC = () => {
436
428
  Browsers automatically apply colorization using:
437
429
 
438
430
  ```html
439
- <meta name='theme-color' media='(prefers-color-scheme: dark)' />
431
+ <meta name="theme-color" media="(prefers-color-scheme: dark)" />
440
432
  ```
441
433
 
442
- This works based on the OS preference — *not your site theme*. That can cause mismatches if, for example, the system is in dark mode but the user disabled dark mode via a web toggle.
434
+ This works based on the OS preference — _not your site theme_. That can cause mismatches if, for example, the system is in dark mode but the user disabled dark mode via a web toggle.
443
435
 
444
436
  To ensure consistency, `useDarkMode` updates these meta tags dynamically based on the actual mode.
445
437
 
@@ -447,8 +439,16 @@ Just make sure to define both `light` and `dark` theme-color tags in your docume
447
439
 
448
440
  ```html
449
441
  <head>
450
- <meta name='theme-color' media='(prefers-color-scheme: light)' content='lime'>
451
- <meta name='theme-color' media='(prefers-color-scheme: dark)' content='aqua'>
442
+ <meta
443
+ name="theme-color"
444
+ media="(prefers-color-scheme: light)"
445
+ content="lime"
446
+ />
447
+ <meta
448
+ name="theme-color"
449
+ media="(prefers-color-scheme: dark)"
450
+ content="aqua"
451
+ />
452
452
  </head>
453
453
  ```
454
454
 
@@ -468,14 +468,14 @@ Attach a new Event listener to the `Window`, `Document`, `MediaQueryList` or an
468
468
 
469
469
  <summary style="cursor:pointer">Window events</summary>
470
470
 
471
- | Parameter | Type | Description |
472
- |-----------|----------|-------------|
473
- | `type` | `K\|K[]` | The `Window` event name or an array of event names. |
474
- | `options` | `WindowListenerOptions<K>` | An object defining init options. |
475
- | `options.listener` | `WindowEventListener<K>` | The Window Event listener. |
476
- | `options.onLoad` | `() => void` | A custom callback executed before event listener get attached. |
477
- | `options.onCleanUp` | `() => void` | A custom callback executed after event listener get removed. |
478
- | `options.options` | `ListenerOptions` | Specifies characteristics about the event listener. See [MDN Reference](https://developer.mozilla.org/en-US/docs/Web/API/EventTarget/addEventListener#options). |
471
+ | Parameter | Type | Description |
472
+ | ------------------- | -------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------- |
473
+ | `type` | `K\|K[]` | The `Window` event name or an array of event names. |
474
+ | `options` | `WindowListenerOptions<K>` | An object defining init options. |
475
+ | `options.listener` | `WindowEventListener<K>` | The Window Event listener. |
476
+ | `options.onLoad` | `() => void` | A custom callback executed before event listener get attached. |
477
+ | `options.onCleanUp` | `() => void` | A custom callback executed after event listener get removed. |
478
+ | `options.options` | `ListenerOptions` | Specifies characteristics about the event listener. See [MDN Reference](https://developer.mozilla.org/en-US/docs/Web/API/EventTarget/addEventListener#options). |
479
479
 
480
480
  </details>
481
481
 
@@ -485,15 +485,15 @@ Attach a new Event listener to the `Window`, `Document`, `MediaQueryList` or an
485
485
 
486
486
  <summary style="cursor:pointer">Document events</summary>
487
487
 
488
- | Parameter | Type | Description |
489
- |-----------|----------|-------------|
490
- | `type` | `K\|K[]` | The `Document` event name or an array of event names. |
491
- | `options` | `DocumentListenerOptions<K>` | An object defining init options. |
492
- | `options.target` | `Document\|null\|React.RefObject<Document\|null>` | The `Document` reference or a React RefObject of the `Document`. |
493
- | `options.listener` | `DocumentEventListener<K>` | The Document Event listener. |
494
- | `options.onLoad` | `() => void` | A custom callback executed before event listener get attached. |
495
- | `options.onCleanUp` | `() => void` | A custom callback executed after event listener get removed. |
496
- | `options.options` | `ListenerOptions` | Specifies characteristics about the event listener. See [MDN Reference](https://developer.mozilla.org/en-US/docs/Web/API/EventTarget/addEventListener#options). |
488
+ | Parameter | Type | Description |
489
+ | ------------------- | ------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------- |
490
+ | `type` | `K\|K[]` | The `Document` event name or an array of event names. |
491
+ | `options` | `DocumentListenerOptions<K>` | An object defining init options. |
492
+ | `options.target` | `Document\|null\|React.RefObject<Document\|null>` | The `Document` reference or a React RefObject of the `Document`. |
493
+ | `options.listener` | `DocumentEventListener<K>` | The Document Event listener. |
494
+ | `options.onLoad` | `() => void` | A custom callback executed before event listener get attached. |
495
+ | `options.onCleanUp` | `() => void` | A custom callback executed after event listener get removed. |
496
+ | `options.options` | `ListenerOptions` | Specifies characteristics about the event listener. See [MDN Reference](https://developer.mozilla.org/en-US/docs/Web/API/EventTarget/addEventListener#options). |
497
497
 
498
498
  </details>
499
499
 
@@ -503,15 +503,15 @@ Attach a new Event listener to the `Window`, `Document`, `MediaQueryList` or an
503
503
 
504
504
  <summary style="cursor:pointer">HTMLElement events</summary>
505
505
 
506
- | Parameter | Type | Description |
507
- |-----------|----------|-------------|
508
- | `type` | `K\|K[]` | The `HTMLElement` event name or an array of event names. |
509
- | `options` | `ElementListenerOptions<K>` | An object defining init options. |
510
- | `options.target` | `T\|React.RefObject<T\| null>` | The React RefObject of the target where the listener get attached to. |
511
- | `options.listener` | `ElementEventListener<K>` | The HTMLElement Event listener. |
512
- | `options.onLoad` | `() => void` | A custom callback executed before event listener get attached. |
513
- | `options.onCleanUp` | `() => void` | A custom callback executed after event listener get removed. |
514
- | `options.options` | `ListenerOptions` | Specifies characteristics about the event listener. See [MDN Reference](https://developer.mozilla.org/en-US/docs/Web/API/EventTarget/addEventListener#options). |
506
+ | Parameter | Type | Description |
507
+ | ------------------- | ------------------------------ | --------------------------------------------------------------------------------------------------------------------------------------------------------------- |
508
+ | `type` | `K\|K[]` | The `HTMLElement` event name or an array of event names. |
509
+ | `options` | `ElementListenerOptions<K>` | An object defining init options. |
510
+ | `options.target` | `T\|React.RefObject<T\| null>` | The React RefObject of the target where the listener get attached to. |
511
+ | `options.listener` | `ElementEventListener<K>` | The HTMLElement Event listener. |
512
+ | `options.onLoad` | `() => void` | A custom callback executed before event listener get attached. |
513
+ | `options.onCleanUp` | `() => void` | A custom callback executed after event listener get removed. |
514
+ | `options.options` | `ListenerOptions` | Specifies characteristics about the event listener. See [MDN Reference](https://developer.mozilla.org/en-US/docs/Web/API/EventTarget/addEventListener#options). |
515
515
 
516
516
  </details>
517
517
 
@@ -521,15 +521,15 @@ Attach a new Event listener to the `Window`, `Document`, `MediaQueryList` or an
521
521
 
522
522
  <summary style="cursor:pointer">MediaQuery events</summary>
523
523
 
524
- | Parameter | Type | Description |
525
- |-----------|----------|-------------|
526
- | `type` | `change` | The `MediaQueryList` event name. |
527
- | `options` | `MediaQueryListenerOptions` | An object defining init options. |
528
- | `options.query` | `string` | The Media Query string to check. |
529
- | `options.listener` | `MediaQueryChangeListener` | The MediaQueryList Event listener. |
530
- | `options.onLoad` | `() => void` | A custom callback executed before event listener get attached. |
531
- | `options.onCleanUp` | `() => void` | A custom callback executed after event listener get removed. |
532
- | `options.options` | `ListenerOptions` | Specifies characteristics about the event listener. See [MDN Reference](https://developer.mozilla.org/en-US/docs/Web/API/EventTarget/addEventListener#options). |
524
+ | Parameter | Type | Description |
525
+ | ------------------- | --------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------- |
526
+ | `type` | `change` | The `MediaQueryList` event name. |
527
+ | `options` | `MediaQueryListenerOptions` | An object defining init options. |
528
+ | `options.query` | `string` | The Media Query string to check. |
529
+ | `options.listener` | `MediaQueryChangeListener` | The MediaQueryList Event listener. |
530
+ | `options.onLoad` | `() => void` | A custom callback executed before event listener get attached. |
531
+ | `options.onCleanUp` | `() => void` | A custom callback executed after event listener get removed. |
532
+ | `options.options` | `ListenerOptions` | Specifies characteristics about the event listener. See [MDN Reference](https://developer.mozilla.org/en-US/docs/Web/API/EventTarget/addEventListener#options). |
533
533
 
534
534
  </details>
535
535
 
@@ -539,15 +539,15 @@ Attach a new Event listener to the `Window`, `Document`, `MediaQueryList` or an
539
539
 
540
540
  <summary style="cursor:pointer">Custom events</summary>
541
541
 
542
- | Parameter | Type | Description |
543
- |-----------|----------|-------------|
544
- | `type` | `K\|K[]` | The custom event name or an array of event names. |
545
- | `options` | `CustomEventListenerOptions<T, K>` | An object defining init options. |
546
- | `options.target` | `Document\|HTMLElement\|null\|React.RefObject<Document\|HTMLElement\|null>` | (Optional) The target where the listener get attached to. If not set, the listener will get attached to the `Window` object. |
547
- | `options.listener` | `( event: T[ K ] ) => void` | The Event listener. |
548
- | `options.onLoad` | `() => void` | A custom callback executed before event listener get attached. |
549
- | `options.onCleanUp` | `() => void` | A custom callback executed after event listener get removed. |
550
- | `options.options` | `ListenerOptions` | Specifies characteristics about the event listener. See [MDN Reference](https://developer.mozilla.org/en-US/docs/Web/API/EventTarget/addEventListener#options). |
542
+ | Parameter | Type | Description |
543
+ | ------------------- | --------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------- |
544
+ | `type` | `K\|K[]` | The custom event name or an array of event names. |
545
+ | `options` | `CustomEventListenerOptions<T, K>` | An object defining init options. |
546
+ | `options.target` | `Document\|HTMLElement\|null\|React.RefObject<Document\|HTMLElement\|null>` | (Optional) The target where the listener get attached to. If not set, the listener will get attached to the `Window` object. |
547
+ | `options.listener` | `( event: T[ K ] ) => void` | The Event listener. |
548
+ | `options.onLoad` | `() => void` | A custom callback executed before event listener get attached. |
549
+ | `options.onCleanUp` | `() => void` | A custom callback executed after event listener get removed. |
550
+ | `options.options` | `ListenerOptions` | Specifies characteristics about the event listener. See [MDN Reference](https://developer.mozilla.org/en-US/docs/Web/API/EventTarget/addEventListener#options). |
551
551
 
552
552
  </details>
553
553
 
@@ -730,9 +730,9 @@ Type: `boolean`
730
730
  ###### Check if user device is in landscape
731
731
 
732
732
  ```tsx
733
- import { useIsPortrait } from '@alessiofrittoli/react-hooks'
733
+ import { useIsPortrait } from "@alessiofrittoli/react-hooks";
734
734
 
735
- const isLandscape = ! useIsPortrait()
735
+ const isLandscape = !useIsPortrait();
736
736
  ```
737
737
 
738
738
  </details>
@@ -747,13 +747,13 @@ Get Document Media matches and listen for changes.
747
747
 
748
748
  <summary style="cursor:pointer">Parameters</summary>
749
749
 
750
- | Parameter | Type | Default | Description |
751
- |-----------|----------|---------|-------------|
752
- | `query` | `string` | - | A string specifying the media query to parse into a `MediaQueryList`. |
753
- | `options` | `UseMediaQueryOptions\|UseMediaQueryStateOptions` | - | An object defining custom options. |
754
- | `options.updateState` | `boolean` | `true` | Indicates whether the hook will dispatch a React state update when the given `query` change event get dispatched. |
755
- | `options.onChange` | `OnChangeHandler` | - | A custom callback that will be invoked on initial page load and when the given `query` change event get dispatched. |
756
- | | | | This callback is required if `updateState` is set to `false`. |
750
+ | Parameter | Type | Default | Description |
751
+ | --------------------- | ------------------------------------------------- | ------- | ------------------------------------------------------------------------------------------------------------------- |
752
+ | `query` | `string` | - | A string specifying the media query to parse into a `MediaQueryList`. |
753
+ | `options` | `UseMediaQueryOptions\|UseMediaQueryStateOptions` | - | An object defining custom options. |
754
+ | `options.updateState` | `boolean` | `true` | Indicates whether the hook will dispatch a React state update when the given `query` change event get dispatched. |
755
+ | `options.onChange` | `OnChangeHandler` | - | A custom callback that will be invoked on initial page load and when the given `query` change event get dispatched. |
756
+ | | | | This callback is required if `updateState` is set to `false`. |
757
757
 
758
758
  </details>
759
759
 
@@ -779,9 +779,9 @@ Type: `boolean|void`
779
779
  ###### Check if user device prefers dark color scheme
780
780
 
781
781
  ```tsx
782
- import { useMediaQuery } from '@alessiofrittoli/react-hooks'
782
+ import { useMediaQuery } from "@alessiofrittoli/react-hooks";
783
783
 
784
- const isDarkOS = useMediaQuery( '(prefers-color-scheme: dark)' )
784
+ const isDarkOS = useMediaQuery("(prefers-color-scheme: dark)");
785
785
  ```
786
786
 
787
787
  ---
@@ -789,14 +789,174 @@ const isDarkOS = useMediaQuery( '(prefers-color-scheme: dark)' )
789
789
  ###### Listen changes with no state updates
790
790
 
791
791
  ```tsx
792
- import { useMediaQuery } from '@alessiofrittoli/react-hooks'
792
+ import { useMediaQuery } from "@alessiofrittoli/react-hooks";
793
793
 
794
- useMediaQuery( '(prefers-color-scheme: dark)', {
794
+ useMediaQuery("(prefers-color-scheme: dark)", {
795
795
  updateState: false,
796
- onChange( matches ) {
797
- console.log( 'is dark OS?', matches )
798
- }
799
- } )
796
+ onChange(matches) {
797
+ console.log("is dark OS?", matches);
798
+ },
799
+ });
800
+ ```
801
+
802
+ </details>
803
+
804
+ ---
805
+
806
+ ##### `useDocumentVisibility`
807
+
808
+ Track the visibility state of the document (i.e., whether the page is visible or hidden).
809
+
810
+ <details>
811
+
812
+ <summary style="cursor:pointer">Parameters</summary>
813
+
814
+ | Parameter | Type | Default | Description |
815
+ | ---------------------------- | ------------------------------------------------------------------------- | ------- | --------------------------------------------------------------------- |
816
+ | `options` | `UseDocumentVisibilityOptions\|StateDisabledUseDocumentVisibilityOptions` | - | Configuration options for the hook. |
817
+ | `options.updateState` | `boolean` | `true` | Whether to update React state about Document visibility state or not. |
818
+ | `options.onVisibilityChange` | `VisibilityChangeHandler` | - | A custom callback executed when Document visiblity sate changes. |
819
+
820
+ </details>
821
+
822
+ ---
823
+
824
+ <details>
825
+
826
+ <summary style="cursor:pointer">Returns</summary>
827
+
828
+ Type: `boolean | void`
829
+
830
+ Returns `true` if the document is visible, `false` if hidden, or `void` if `updateState` is set to `false`.
831
+
832
+ </details>
833
+
834
+ ---
835
+
836
+ <details>
837
+
838
+ <summary style="cursor:pointer">Usage</summary>
839
+
840
+ ###### Simple usage
841
+
842
+ ```tsx
843
+ import { useDocumentVisibility } from "@alessiofrittoli/react-hooks";
844
+
845
+ const isDocumentVisible = useDocumentVisibility();
846
+ ```
847
+
848
+ ---
849
+
850
+ ###### Disable state updates and listen visibility changes
851
+
852
+ ```tsx
853
+ import {
854
+ useDocumentVisibility,
855
+ type VisibilityChangeHandler,
856
+ } from "@alessiofrittoli/react-hooks";
857
+
858
+ const onVisibilityChange = useCallback<VisibilityChangeHandler>((isVisible) => {
859
+ // ... do something
860
+ }, []);
861
+ useDocumentVisibility({ updateState: false, onVisibilityChange });
862
+ ```
863
+
864
+ </details>
865
+
866
+ ---
867
+
868
+ ##### `useWakeLock`
869
+
870
+ Easily manage the [Screen Wake Lock API](https://developer.mozilla.org/en-US/docs/Web/API/Screen_Wake_Lock_API) to prevent the device screen from dimming or locking while your app is in use.
871
+
872
+ <details>
873
+
874
+ <summary style="cursor:pointer">Parameters</summary>
875
+
876
+ | Parameter | Type | Default | Description |
877
+ | ----------------- | ------------------------ | ------- | ---------------------------------------------------------------- |
878
+ | `options` | `UseWakeLockOptions` | - | (Optional) An object defining hook options. |
879
+ | `options.onMount` | `boolean` | `true` | Indicates whether to request the screen WakeLock on mount. |
880
+ | `options.onError` | `OnWakeLockRequestError` | - | A custom callback executed when a screen WakeLock request fails. |
881
+
882
+ </details>
883
+
884
+ ---
885
+
886
+ <details>
887
+
888
+ <summary style="cursor:pointer">Returns</summary>
889
+
890
+ Type: `UseWakeLock`
891
+
892
+ An object returning The current `WakeLockSentinel` instance or `null` if not enabled and utility functions.
893
+
894
+ - `wakeLock`: `WakeLockSentinel | null` — The current Wake Lock instance, or null if not enabled.
895
+ - `enabled`: `boolean` — Whether the Wake Lock is currently active.
896
+ - `requestWakeLock`: `() => Promise<void>` — Manually request the Wake Lock.
897
+ - `releaseWakeLock`: `() => Promise<void>` — Manually release the Wake Lock.
898
+
899
+ </details>
900
+
901
+ ---
902
+
903
+ <details>
904
+
905
+ <summary style="cursor:pointer">Usage</summary>
906
+
907
+ ###### Enable Wake Lock on mount
908
+
909
+ ```tsx
910
+ import { useWakeLock } from "@alessiofrittoli/react-hooks";
911
+
912
+ useWakeLock();
913
+ ```
914
+
915
+ ---
916
+
917
+ ###### Manually enable and disable Wake Lock
918
+
919
+ ```tsx
920
+ import { useWakeLock } from "@alessiofrittoli/react-hooks";
921
+
922
+ export const WakeLockButton: React.FC = () => {
923
+ const { enabled, requestWakeLock, releaseWakeLock } = useWakeLock({
924
+ enableOnLoad: false,
925
+ });
926
+
927
+ return (
928
+ <>
929
+ <h1>Wakelock enabled: {enabled.toString()}</h1>
930
+ <button onClick={requestWakeLock}>Enable wakelock</button>
931
+ <button onClick={releaseWakeLock}>Disable wakelock</button>
932
+ </>
933
+ );
934
+ };
935
+ ```
936
+
937
+ ---
938
+
939
+ ###### Handling Wake Lock errors
940
+
941
+ ```tsx
942
+ import {
943
+ useWakeLock,
944
+ type OnWakeLockRequestError,
945
+ } from "@alessiofrittoli/react-hooks";
946
+
947
+ const onError: OnWakeLockRequestError = (error) => {
948
+ alert("Could not enable Wake Lock: " + error.message);
949
+ };
950
+
951
+ export const WakeLockWithError: React.FC = () => {
952
+ const { enabled, requestWakeLock } = useWakeLock({ onError });
953
+
954
+ return (
955
+ <button onClick={requestWakeLock}>
956
+ {enabled ? "Wake Lock enabled" : "Enable Wake Lock"}
957
+ </button>
958
+ );
959
+ };
800
960
  ```
801
961
 
802
962
  </details>
@@ -815,10 +975,10 @@ This comes pretty handy when rendering a modal that shouldn't be closed without
815
975
 
816
976
  <summary style="cursor:pointer">Parameters</summary>
817
977
 
818
- | Parameter | Type | Description |
819
- |-----------|------|-------------|
820
- | `target` | `React.RefObject<HTMLElement\|null>` | The target HTMLElement React RefObject to trap focus within. |
821
- | | | If no target is given, you must provide the target HTMLElement when calling `setFocusTrap`. |
978
+ | Parameter | Type | Description |
979
+ | --------- | ------------------------------------ | ------------------------------------------------------------------------------------------- |
980
+ | `target` | `React.RefObject<HTMLElement\|null>` | The target HTMLElement React RefObject to trap focus within. |
981
+ | | | If no target is given, you must provide the target HTMLElement when calling `setFocusTrap`. |
822
982
 
823
983
  </details>
824
984
 
@@ -846,22 +1006,22 @@ A tuple containing:
846
1006
  ###### Defining the target on hook initialization
847
1007
 
848
1008
  ```tsx
849
- import { useFocusTrap } from '@alessiofrittoli/react-hooks'
1009
+ import { useFocusTrap } from "@alessiofrittoli/react-hooks";
850
1010
 
851
- const modalRef = useRef<HTMLDivElement>( null )
852
- const [ setFocusTrap, restoreFocusTrap ] = useFocusTrap( modalRef )
1011
+ const modalRef = useRef<HTMLDivElement>(null);
1012
+ const [setFocusTrap, restoreFocusTrap] = useFocusTrap(modalRef);
853
1013
 
854
- const modalOpenHandler = useCallback( () => {
855
- if ( ! modalRef.current ) return
1014
+ const modalOpenHandler = useCallback(() => {
1015
+ if (!modalRef.current) return;
856
1016
  // ... open modal
857
- setFocusTrap()
858
- modalRef.current.focus() // focus the dialog so next tab will focus the next element inside the modal
859
- }, [ setFocusTrap ] )
1017
+ setFocusTrap();
1018
+ modalRef.current.focus(); // focus the dialog so next tab will focus the next element inside the modal
1019
+ }, [setFocusTrap]);
860
1020
 
861
- const modalCloseHandler = useCallback( () => {
1021
+ const modalCloseHandler = useCallback(() => {
862
1022
  // ... close modal
863
- restoreFocusTrap() // cancel focus trap and restore focus to the last active element before enablig the focus trap
864
- }, [ restoreFocusTrap ] )
1023
+ restoreFocusTrap(); // cancel focus trap and restore focus to the last active element before enablig the focus trap
1024
+ }, [restoreFocusTrap]);
865
1025
  ```
866
1026
 
867
1027
  ---
@@ -869,25 +1029,25 @@ const modalCloseHandler = useCallback( () => {
869
1029
  ###### Defining the target ondemand
870
1030
 
871
1031
  ```tsx
872
- import { useFocusTrap } from '@alessiofrittoli/react-hooks'
1032
+ import { useFocusTrap } from "@alessiofrittoli/react-hooks";
873
1033
 
874
- const modalRef = useRef<HTMLDivElement>( null )
875
- const modal2Ref = useRef<HTMLDivElement>( null )
876
- const [ setFocusTrap, restoreFocusTrap ] = useFocusTrap()
1034
+ const modalRef = useRef<HTMLDivElement>(null);
1035
+ const modal2Ref = useRef<HTMLDivElement>(null);
1036
+ const [setFocusTrap, restoreFocusTrap] = useFocusTrap();
877
1037
 
878
- const modalOpenHandler = useCallback( () => {
879
- if ( ! modalRef.current ) return
1038
+ const modalOpenHandler = useCallback(() => {
1039
+ if (!modalRef.current) return;
880
1040
  // ... open modal
881
- setFocusTrap( modalRef.current )
882
- modalRef.current.focus()
883
- }, [ setFocusTrap ] )
1041
+ setFocusTrap(modalRef.current);
1042
+ modalRef.current.focus();
1043
+ }, [setFocusTrap]);
884
1044
 
885
- const modal2OpenHandler = useCallback( () => {
886
- if ( ! modal2Ref.current ) return
1045
+ const modal2OpenHandler = useCallback(() => {
1046
+ if (!modal2Ref.current) return;
887
1047
  // ... open modal
888
- setFocusTrap( modal2Ref.current )
889
- modal2Ref.current.focus()
890
- }, [ setFocusTrap ] )
1048
+ setFocusTrap(modal2Ref.current);
1049
+ modal2Ref.current.focus();
1050
+ }, [setFocusTrap]);
891
1051
  ```
892
1052
 
893
1053
  </details>
@@ -902,33 +1062,33 @@ Check if the given target Element is intersecting with an ancestor Element or wi
902
1062
 
903
1063
  <summary style="cursor:pointer">Parameters</summary>
904
1064
 
905
- | Parameter | Type | Description |
906
- |-----------|------|-------------|
907
- | `target` | `React.RefObject<Element\|null>` | The React.RefObject of the target Element to observe. |
908
- | `options` | `UseInViewOptions` | (Optional) An object defining custom `IntersectionObserver` options. |
909
- | `options.root` | `Element\|Document\|false\|null` | (Optional) Identifies the `Element` or `Document` whose bounds are treated as the bounding box of the viewport for the Element which is the observer's target. |
910
- | `options.margin` | `MarginType` | (Optional) A string, formatted similarly to the CSS margin property's value, which contains offsets for one or more sides of the root's bounding box. |
911
- | `options.amount` | `'all'\|'some'\|number\|number[]` | (Optional) The intersecting target thresholds. |
912
- | | | Threshold can be set to: |
913
- | | | - `all` - `1` will be used. |
914
- | | | - `some` - `0.5` will be used. |
915
- | | | - `number` |
916
- | | | - `number[]` |
917
- | `options.once` | `boolean` | (Optional) By setting this to `true` the observer will be disconnected after the target Element enters the viewport. |
918
- | `options.initial` | `boolean` | (Optional) Initial value. This value is used while server rendering then will be updated in the client based on target visibility. Default: `false`. |
919
- | `options.enable` | `boolean` | (Optional) Defines the initial observation activity. Use the returned `setEnabled` to update this state. Default: `true`. |
920
- | `options.onIntersect` | `OnIntersectStateHandler` | (Optional) A custom callback executed when target element's visibility has crossed one or more thresholds. |
921
- | | | This callback is awaited before any state update. |
922
- | | | If an error is thrown the React State update won't be fired. |
923
- | | | ⚠️ Wrap your callback with `useCallback` to avoid unnecessary `IntersectionObserver` recreation. |
924
- | `options.onEnter` | `OnIntersectHandler` | (Optional) A custom callback executed when target element's visibility has crossed one or more thresholds. |
925
- | | | This callback is awaited before any state update. |
926
- | | | If an error is thrown the React State update won't be fired. |
927
- | | | ⚠️ Wrap your callback with `useCallback` to avoid unnecessary `IntersectionObserver` recreation. |
928
- | `options.onExit` | `OnIntersectHandler` | (Optional) A custom callback executed when target element's visibility has crossed one or more thresholds. |
929
- | | | This callback is awaited before any state update. |
930
- | | | If an error is thrown the React State update won't be fired. |
931
- | | | ⚠️ Wrap your callback with `useCallback` to avoid unnecessary `IntersectionObserver` recreation. |
1065
+ | Parameter | Type | Description |
1066
+ | --------------------- | --------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------- |
1067
+ | `target` | `React.RefObject<Element\|null>` | The React.RefObject of the target Element to observe. |
1068
+ | `options` | `UseInViewOptions` | (Optional) An object defining custom `IntersectionObserver` options. |
1069
+ | `options.root` | `Element\|Document\|false\|null` | (Optional) Identifies the `Element` or `Document` whose bounds are treated as the bounding box of the viewport for the Element which is the observer's target. |
1070
+ | `options.margin` | `MarginType` | (Optional) A string, formatted similarly to the CSS margin property's value, which contains offsets for one or more sides of the root's bounding box. |
1071
+ | `options.amount` | `'all'\|'some'\|number\|number[]` | (Optional) The intersecting target thresholds. |
1072
+ | | | Threshold can be set to: |
1073
+ | | | - `all` - `1` will be used. |
1074
+ | | | - `some` - `0.5` will be used. |
1075
+ | | | - `number` |
1076
+ | | | - `number[]` |
1077
+ | `options.once` | `boolean` | (Optional) By setting this to `true` the observer will be disconnected after the target Element enters the viewport. |
1078
+ | `options.initial` | `boolean` | (Optional) Initial value. This value is used while server rendering then will be updated in the client based on target visibility. Default: `false`. |
1079
+ | `options.enable` | `boolean` | (Optional) Defines the initial observation activity. Use the returned `setEnabled` to update this state. Default: `true`. |
1080
+ | `options.onIntersect` | `OnIntersectStateHandler` | (Optional) A custom callback executed when target element's visibility has crossed one or more thresholds. |
1081
+ | | | This callback is awaited before any state update. |
1082
+ | | | If an error is thrown the React State update won't be fired. |
1083
+ | | | ⚠️ Wrap your callback with `useCallback` to avoid unnecessary `IntersectionObserver` recreation. |
1084
+ | `options.onEnter` | `OnIntersectHandler` | (Optional) A custom callback executed when target element's visibility has crossed one or more thresholds. |
1085
+ | | | This callback is awaited before any state update. |
1086
+ | | | If an error is thrown the React State update won't be fired. |
1087
+ | | | ⚠️ Wrap your callback with `useCallback` to avoid unnecessary `IntersectionObserver` recreation. |
1088
+ | `options.onExit` | `OnIntersectHandler` | (Optional) A custom callback executed when target element's visibility has crossed one or more thresholds. |
1089
+ | | | This callback is awaited before any state update. |
1090
+ | | | If an error is thrown the React State update won't be fired. |
1091
+ | | | ⚠️ Wrap your callback with `useCallback` to avoid unnecessary `IntersectionObserver` recreation. |
932
1092
 
933
1093
  </details>
934
1094
 
@@ -959,46 +1119,44 @@ An object containing:
959
1119
  ###### Basic usage
960
1120
 
961
1121
  ```tsx
962
- 'use client'
1122
+ "use client";
963
1123
 
964
- import { useRef } from 'react'
965
- import { useInView } from '@alessiofrittoli/react-hooks'
1124
+ import { useRef } from "react";
1125
+ import { useInView } from "@alessiofrittoli/react-hooks";
966
1126
 
967
1127
  const UseInViewExample: React.FC = () => {
1128
+ const targetRef = useRef<HTMLDivElement>(null);
1129
+ const { inView } = useInView(ref);
968
1130
 
969
- const targetRef = useRef<HTMLDivElement>( null )
970
- const { inView } = useInView( ref )
971
-
972
- return (
973
- Array.from( Array( 6 ) ).map( ( value, index ) => (
1131
+ return Array.from(Array(6)).map((value, index) => (
1132
+ <div
1133
+ key={index}
1134
+ style={{
1135
+ height: "50vh",
1136
+ border: "1px solid red",
1137
+ display: "flex",
1138
+ alignItems: "center",
1139
+ justifyContent: "center",
1140
+ }}
1141
+ >
974
1142
  <div
975
- key={ index }
976
- style={ {
977
- height : '50vh',
978
- border : '1px solid red',
979
- display : 'flex',
980
- alignItems : 'center',
981
- justifyContent : 'center',
982
- } }
1143
+ ref={index === 2 ? targetRef : undefined}
1144
+ style={{
1145
+ width: 150,
1146
+ height: 150,
1147
+ borderRadius: 12,
1148
+ display: "flex",
1149
+ alignItems: "center",
1150
+ justifyContent: "center",
1151
+ background: inView ? "#51AF83" : "#201A1B",
1152
+ color: inView ? "#201A1B" : "#FFFFFF",
1153
+ }}
983
1154
  >
984
- <div
985
- ref={ index === 2 ? targetRef : undefined }
986
- style={ {
987
- width : 150,
988
- height : 150,
989
- borderRadius : 12,
990
- display : 'flex',
991
- alignItems : 'center',
992
- justifyContent : 'center',
993
- background : inView ? '#51AF83' : '#201A1B',
994
- color : inView ? '#201A1B' : '#FFFFFF',
995
- } }
996
- >{ index + 1 }</div>
1155
+ {index + 1}
997
1156
  </div>
998
- ) )
999
- )
1000
-
1001
- }
1157
+ </div>
1158
+ ));
1159
+ };
1002
1160
  ```
1003
1161
 
1004
1162
  ---
@@ -1006,34 +1164,30 @@ const UseInViewExample: React.FC = () => {
1006
1164
  ###### Disconnect observer after target enters the viewport
1007
1165
 
1008
1166
  ```tsx
1009
- 'use client'
1167
+ "use client";
1010
1168
 
1011
- import { useRef } from 'react'
1012
- import { useInView } from '@alessiofrittoli/react-hooks'
1169
+ import { useRef } from "react";
1170
+ import { useInView } from "@alessiofrittoli/react-hooks";
1013
1171
 
1014
1172
  const OnceExample: React.FC = () => {
1173
+ const targetRef = useRef<HTMLDivElement>(null);
1174
+ const { inView } = useInView(targetRef, { once: true });
1015
1175
 
1016
- const targetRef = useRef<HTMLDivElement>( null )
1017
- const { inView } = useInView( targetRef, { once: true } )
1018
-
1019
- useEffect( () => {
1020
-
1021
- if ( ! inView ) return
1022
- console.count( 'Fired only once: element entered viewport.' )
1023
-
1024
- }, [ inView ] )
1176
+ useEffect(() => {
1177
+ if (!inView) return;
1178
+ console.count("Fired only once: element entered viewport.");
1179
+ }, [inView]);
1025
1180
 
1026
1181
  return (
1027
1182
  <div
1028
- ref={ targetRef }
1029
- style={ {
1030
- height : 200,
1031
- background : inView ? 'lime' : 'gray',
1032
- } }
1183
+ ref={targetRef}
1184
+ style={{
1185
+ height: 200,
1186
+ background: inView ? "lime" : "gray",
1187
+ }}
1033
1188
  />
1034
- )
1035
-
1036
- }
1189
+ );
1190
+ };
1037
1191
  ```
1038
1192
 
1039
1193
  ---
@@ -1041,35 +1195,33 @@ const OnceExample: React.FC = () => {
1041
1195
  ###### Observe target only when needed
1042
1196
 
1043
1197
  ```tsx
1044
- 'use client'
1198
+ "use client";
1045
1199
 
1046
- import { useRef } from 'react'
1047
- import { useInView } from '@alessiofrittoli/react-hooks'
1200
+ import { useRef } from "react";
1201
+ import { useInView } from "@alessiofrittoli/react-hooks";
1048
1202
 
1049
1203
  const OnDemandObservation: React.FC = () => {
1050
-
1051
- const targetRef = useRef<HTMLDivElement>( null )
1052
- const {
1053
- inView, enabled, setEnabled
1054
- } = useInView( targetRef, { enable: false } )
1204
+ const targetRef = useRef<HTMLDivElement>(null);
1205
+ const { inView, enabled, setEnabled } = useInView(targetRef, {
1206
+ enable: false,
1207
+ });
1055
1208
 
1056
1209
  return (
1057
1210
  <div>
1058
- <button onClick={ () => setEnabled( prev => ! prev ) }>
1059
- { enabled ? 'Disconnect observer' : 'Observe' }
1211
+ <button onClick={() => setEnabled((prev) => !prev)}>
1212
+ {enabled ? "Disconnect observer" : "Observe"}
1060
1213
  </button>
1061
1214
  <div
1062
- ref={ targetRef }
1063
- style={ {
1064
- height : 200,
1065
- marginTop : 50,
1066
- background : inView ? 'lime' : 'gray',
1067
- } }
1215
+ ref={targetRef}
1216
+ style={{
1217
+ height: 200,
1218
+ marginTop: 50,
1219
+ background: inView ? "lime" : "gray",
1220
+ }}
1068
1221
  />
1069
1222
  </div>
1070
- )
1071
-
1072
- }
1223
+ );
1224
+ };
1073
1225
  ```
1074
1226
 
1075
1227
  ---
@@ -1077,42 +1229,44 @@ const OnDemandObservation: React.FC = () => {
1077
1229
  ###### Execute custom callback when intersection occurs
1078
1230
 
1079
1231
  ```tsx
1080
- 'use client'
1081
-
1082
- import { useRef } from 'react'
1083
- import { useInView, type OnIntersectStateHandler } from '@alessiofrittoli/react-hooks'
1232
+ "use client";
1084
1233
 
1234
+ import { useRef } from "react";
1235
+ import {
1236
+ useInView,
1237
+ type OnIntersectStateHandler,
1238
+ } from "@alessiofrittoli/react-hooks";
1085
1239
 
1086
1240
  const AsyncStartExample: React.FC = () => {
1241
+ const targetRef = useRef<HTMLDivElement>(null);
1242
+ const onIntersect = useCallback<OnIntersectStateHandler>(
1243
+ async ({ entry, isEntering }) => {
1244
+ if (isEntering) {
1245
+ console.log("Delaying state update...");
1246
+ await new Promise((resolve) => setTimeout(resolve, 1000)); // Simulate delay
1247
+ console.log("Async task completed. `inView` will now be updated.");
1248
+ return;
1249
+ }
1087
1250
 
1088
- const targetRef = useRef<HTMLDivElement>( null )
1089
- const onIntersect = useCallback<OnIntersectStateHandler>( async ( { entry, isEntering } ) => {
1090
-
1091
- if ( isEntering ) {
1092
- console.log( 'Delaying state update...' )
1093
- await new Promise( resolve => setTimeout( resolve, 1000 ) ) // Simulate delay
1094
- console.log( 'Async task completed. `inView` will now be updated.' )
1095
- return
1096
- }
1097
-
1098
- console.log( 'Delaying state update...' )
1099
- await new Promise( resolve => setTimeout( resolve, 1000 ) ) // Simulate delay
1100
- console.log( 'Async task completed. `inView` will now be updated.' )
1101
-
1102
- }, [] )
1251
+ console.log("Delaying state update...");
1252
+ await new Promise((resolve) => setTimeout(resolve, 1000)); // Simulate delay
1253
+ console.log("Async task completed. `inView` will now be updated.");
1254
+ },
1255
+ []
1256
+ );
1103
1257
 
1104
- const { inView } = useInView( targetRef, { onIntersect } )
1258
+ const { inView } = useInView(targetRef, { onIntersect });
1105
1259
 
1106
1260
  return (
1107
1261
  <div
1108
- ref={ targetRef }
1109
- style={ {
1110
- height : 200,
1111
- background : inView ? 'lime' : 'gray',
1112
- } }
1262
+ ref={targetRef}
1263
+ style={{
1264
+ height: 200,
1265
+ background: inView ? "lime" : "gray",
1266
+ }}
1113
1267
  />
1114
- )
1115
- }
1268
+ );
1269
+ };
1116
1270
  ```
1117
1271
 
1118
1272
  ---
@@ -1120,34 +1274,35 @@ const AsyncStartExample: React.FC = () => {
1120
1274
  ###### Execute custom callback when `onEnter` and `onExit`
1121
1275
 
1122
1276
  ```tsx
1123
- 'use client'
1124
-
1125
- import { useRef } from 'react'
1126
- import { useInView, type OnIntersectHandler } from '@alessiofrittoli/react-hooks'
1277
+ "use client";
1127
1278
 
1279
+ import { useRef } from "react";
1280
+ import {
1281
+ useInView,
1282
+ type OnIntersectHandler,
1283
+ } from "@alessiofrittoli/react-hooks";
1128
1284
 
1129
1285
  const AsyncStartExample: React.FC = () => {
1286
+ const targetRef = useRef<HTMLDivElement>(null);
1287
+ const onEnter = useCallback<OnIntersectHandler>(async ({ entry }) => {
1288
+ console.log("In viewport - ", entry);
1289
+ }, []);
1290
+ const onExit = useCallback<OnIntersectHandler>(async ({ entry }) => {
1291
+ console.log("Exited viewport - ", entry);
1292
+ }, []);
1130
1293
 
1131
- const targetRef = useRef<HTMLDivElement>( null )
1132
- const onEnter = useCallback<OnIntersectHandler>( async ( { entry } ) => {
1133
- console.log( 'In viewport - ', entry )
1134
- }, [] )
1135
- const onExit = useCallback<OnIntersectHandler>( async ( { entry } ) => {
1136
- console.log( 'Exited viewport - ', entry )
1137
- }, [] )
1138
-
1139
- const { inView } = useInView( targetRef, { onEnter, onExit } )
1294
+ const { inView } = useInView(targetRef, { onEnter, onExit });
1140
1295
 
1141
1296
  return (
1142
1297
  <div
1143
- ref={ targetRef }
1144
- style={ {
1145
- height : 200,
1146
- background : inView ? 'lime' : 'gray',
1147
- } }
1298
+ ref={targetRef}
1299
+ style={{
1300
+ height: 200,
1301
+ background: inView ? "lime" : "gray",
1302
+ }}
1148
1303
  />
1149
- )
1150
- }
1304
+ );
1305
+ };
1151
1306
  ```
1152
1307
 
1153
1308
  </details>
@@ -1162,8 +1317,8 @@ Prevent Element overflow.
1162
1317
 
1163
1318
  <summary style="cursor:pointer">Parameters</summary>
1164
1319
 
1165
- | Parameter | Type | Default | Description |
1166
- |-----------|------|---------|-------------|
1320
+ | Parameter | Type | Default | Description |
1321
+ | --------- | ------------------------------------ | -------------------------- | -------------------------------------------------- |
1167
1322
  | `target` | `React.RefObject<HTMLElement\|null>` | `Document.documentElement` | (Optional) The React RefObject target HTMLElement. |
1168
1323
 
1169
1324
  </details>
@@ -1243,7 +1398,7 @@ Handle input states with ease.
1243
1398
  <summary style="cursor:pointer">Type Parameters</summary>
1244
1399
 
1245
1400
  | Parameter | Description |
1246
- |-----------|------------------------|
1401
+ | --------- | ---------------------- |
1247
1402
  | `I` | The input value type. |
1248
1403
  | `O` | The output value type. |
1249
1404
 
@@ -1255,15 +1410,15 @@ Handle input states with ease.
1255
1410
 
1256
1411
  <summary style="cursor:pointer">Parameters</summary>
1257
1412
 
1258
- | Parameter | Type | Default | Description |
1259
- |-----------|----------|---------|-----------------------------|
1260
- | `options` | `UseInputOptions<I, O>` | `{}` | An object defining custom options. |
1261
- | `options.inputRef` | `React.RefObject<InputType>` | - | (Optional) The React HTML input element ref. |
1262
- | `options.initialValue` | `O\|null` | - | (Optional) The input initial value. |
1263
- | `options.touchTimeout` | `number` | 600 | (Optional) A timeout in milliseconds which will be used to define the input as "touched" thus validations are triggered and errors can be displayed. |
1264
- | `options.validate` | `ValidateValueHandler<O>` | - | (Optional) Value validation handler. If `parse` callback is given, the `value` will be parsed before validation. |
1265
- | `options.parse` | `ParseValueHandler<I, O>` | - | (Optional) Parse value. |
1266
- | `options.onChange` | `ChangeHandler<O>` | - | (Optional) A callable function executed when the `ChangeEvent` is dispatched on the HTML input element. |
1413
+ | Parameter | Type | Default | Description |
1414
+ | ---------------------- | ---------------------------- | ------- | ---------------------------------------------------------------------------------------------------------------------------------------------------- |
1415
+ | `options` | `UseInputOptions<I, O>` | `{}` | An object defining custom options. |
1416
+ | `options.inputRef` | `React.RefObject<InputType>` | - | (Optional) The React HTML input element ref. |
1417
+ | `options.initialValue` | `O\|null` | - | (Optional) The input initial value. |
1418
+ | `options.touchTimeout` | `number` | 600 | (Optional) A timeout in milliseconds which will be used to define the input as "touched" thus validations are triggered and errors can be displayed. |
1419
+ | `options.validate` | `ValidateValueHandler<O>` | - | (Optional) Value validation handler. If `parse` callback is given, the `value` will be parsed before validation. |
1420
+ | `options.parse` | `ParseValueHandler<I, O>` | - | (Optional) Parse value. |
1421
+ | `options.onChange` | `ChangeHandler<O>` | - | (Optional) A callable function executed when the `ChangeEvent` is dispatched on the HTML input element. |
1267
1422
 
1268
1423
  </details>
1269
1424
 
@@ -1277,18 +1432,18 @@ Type: `UseInputOutput<I, O>`
1277
1432
 
1278
1433
  An object containing the following properties:
1279
1434
 
1280
- | Property | Type | Description |
1281
- |-----------------|------|-------------|
1282
- | `isEmpty` | `boolean` | Indicates whether the Input is empty or not. |
1283
- | `hasError` | `boolean` | Indicates whether the input has error or not. |
1284
- | | | It will return true if the Input does not pass the validation checks and it has been touched. |
1285
- | | | Please refer to the `isValid` property to check the Input validity regardless of whether it has been touched or not. |
1286
- | `changeHandler` | `React.ChangeEventHandler<InputType>` | Change handler callback used to handle Input change events. |
1287
- | `blurHandler` | `() => void` | Blur handler callback used to handle Input blur events. |
1288
- | `setValue` | `( value: O ) => void` | Call `setValue` method to update input value. |
1289
- | `submit` | `() => void` | Call `submit` method to re-run validations and ensure error state is updated successfully. |
1290
- | `reset` | `() => void` | Call `reset` method to reset the Input state. |
1291
- | `focus` | `() => void` | Call `focus` method to focus the Input Element. `inputRef` must be provided in the input options. |
1435
+ | Property | Type | Description |
1436
+ | --------------- | ------------------------------------- | -------------------------------------------------------------------------------------------------------------------- |
1437
+ | `isEmpty` | `boolean` | Indicates whether the Input is empty or not. |
1438
+ | `hasError` | `boolean` | Indicates whether the input has error or not. |
1439
+ | | | It will return true if the Input does not pass the validation checks and it has been touched. |
1440
+ | | | Please refer to the `isValid` property to check the Input validity regardless of whether it has been touched or not. |
1441
+ | `changeHandler` | `React.ChangeEventHandler<InputType>` | Change handler callback used to handle Input change events. |
1442
+ | `blurHandler` | `() => void` | Blur handler callback used to handle Input blur events. |
1443
+ | `setValue` | `( value: O ) => void` | Call `setValue` method to update input value. |
1444
+ | `submit` | `() => void` | Call `submit` method to re-run validations and ensure error state is updated successfully. |
1445
+ | `reset` | `() => void` | Call `reset` method to reset the Input state. |
1446
+ | `focus` | `() => void` | Call `focus` method to focus the Input Element. `inputRef` must be provided in the input options. |
1292
1447
 
1293
1448
  </details>
1294
1449
 
@@ -1302,19 +1457,17 @@ An object containing the following properties:
1302
1457
 
1303
1458
  ```tsx
1304
1459
  const MyComponent: React.FC = () => {
1305
-
1306
- const input = useInput<string>()
1460
+ const input = useInput<string>();
1307
1461
 
1308
1462
  return (
1309
1463
  <input
1310
- type='text'
1311
- value={ input.value || '' }
1312
- onChange={ input.changeHandler }
1313
- onBlur={ input.blurHandler }
1464
+ type="text"
1465
+ value={input.value || ""}
1466
+ onChange={input.changeHandler}
1467
+ onBlur={input.blurHandler}
1314
1468
  />
1315
- )
1316
-
1317
- }
1469
+ );
1470
+ };
1318
1471
  ```
1319
1472
 
1320
1473
  ---
@@ -1322,32 +1475,30 @@ const MyComponent: React.FC = () => {
1322
1475
  ###### Displaying custom error messages
1323
1476
 
1324
1477
  ```tsx
1325
- import { useInput, type ValidateValueHandler } from '@alessiofrittoli/react-hooks'
1478
+ import {
1479
+ useInput,
1480
+ type ValidateValueHandler,
1481
+ } from "@alessiofrittoli/react-hooks";
1326
1482
 
1327
- const isNotEmpty: ValidateValueHandler<string> = value => (
1328
- ! value ? false : value.trim().length > 0
1329
- )
1483
+ const isNotEmpty: ValidateValueHandler<string> = (value) =>
1484
+ !value ? false : value.trim().length > 0;
1330
1485
 
1331
1486
  const MyComponent: React.FC = () => {
1332
-
1333
- const input = useInput<string>( {
1487
+ const input = useInput<string>({
1334
1488
  validate: isNotEmpty,
1335
- } )
1489
+ });
1336
1490
 
1337
1491
  return (
1338
1492
  <>
1339
1493
  <input
1340
- value={ input.value || '' }
1341
- onChange={ input.changeHandler }
1342
- onBlur={ input.blurHandler }
1494
+ value={input.value || ""}
1495
+ onChange={input.changeHandler}
1496
+ onBlur={input.blurHandler}
1343
1497
  />
1344
- { input.hasError && (
1345
- <span>The input cannot be empty.</span>
1346
- ) }
1498
+ {input.hasError && <span>The input cannot be empty.</span>}
1347
1499
  </>
1348
- )
1349
-
1350
- }
1500
+ );
1501
+ };
1351
1502
  ```
1352
1503
 
1353
1504
  ---
@@ -1355,42 +1506,39 @@ const MyComponent: React.FC = () => {
1355
1506
  ###### Parsing and validating parsed value
1356
1507
 
1357
1508
  ```tsx
1358
- import { formatDate, isValidDate } from '@alessiofrittoli/date-utils'
1359
- import { useInput, type ValidateValueHandler, type ParseValueHandler } from '@alessiofrittoli/react-hooks'
1360
-
1361
- const parseStringToDate: ParseValueHandler<string, Date> = value => (
1362
- value ? new Date( value ) : undefined
1363
- )
1364
-
1509
+ import { formatDate, isValidDate } from "@alessiofrittoli/date-utils";
1510
+ import {
1511
+ useInput,
1512
+ type ValidateValueHandler,
1513
+ type ParseValueHandler,
1514
+ } from "@alessiofrittoli/react-hooks";
1365
1515
 
1366
- const validateInputDate: ValidateValueHandler<Date> = value => (
1367
- isValidDate( value ) && value.getTime() > Date.now()
1368
- )
1516
+ const parseStringToDate: ParseValueHandler<string, Date> = (value) =>
1517
+ value ? new Date(value) : undefined;
1369
1518
 
1519
+ const validateInputDate: ValidateValueHandler<Date> = (value) =>
1520
+ isValidDate(value) && value.getTime() > Date.now();
1370
1521
 
1371
1522
  const MyComponent: React.FC = () => {
1372
-
1373
- const input = useInput<string, Date>( {
1374
- parse : parseStringToDate,
1375
- validate : validateInputDate,
1376
- } )
1377
-
1523
+ const input = useInput<string, Date>({
1524
+ parse: parseStringToDate,
1525
+ validate: validateInputDate,
1526
+ });
1378
1527
 
1379
1528
  return (
1380
1529
  <>
1381
1530
  <input
1382
- type='datetime-local'
1383
- value={ input.value ? formatDate( input.value, 'Y-m-dTH:i' ) : '' }
1384
- onChange={ input.changeHandler }
1385
- onBlur={ input.blurHandler }
1531
+ type="datetime-local"
1532
+ value={input.value ? formatDate(input.value, "Y-m-dTH:i") : ""}
1533
+ onChange={input.changeHandler}
1534
+ onBlur={input.blurHandler}
1386
1535
  />
1387
- { input.hasError && (
1536
+ {input.hasError && (
1388
1537
  <span>Please choose a date no earlier than today</span>
1389
- ) }
1538
+ )}
1390
1539
  </>
1391
- )
1392
-
1393
- }
1540
+ );
1541
+ };
1394
1542
  ```
1395
1543
 
1396
1544
  </details>
@@ -1410,10 +1558,10 @@ Take a look at [`deferTask`](https://npmjs.com/package/@alessiofrittoli/web-util
1410
1558
 
1411
1559
  <summary style="cursor:pointer">Type Parameters</summary>
1412
1560
 
1413
- | Parameter | Description |
1414
- |-----------|------------------------------|
1561
+ | Parameter | Description |
1562
+ | --------- | ------------------------------------------------------------------------------------------------- |
1415
1563
  | `T` | The task function definition. `unknown` types will be inherited by your function type definition. |
1416
- | `U` | The task function arguments. `unknown` types will be inherited by your function type. |
1564
+ | `U` | The task function arguments. `unknown` types will be inherited by your function type. |
1417
1565
 
1418
1566
  </details>
1419
1567
 
@@ -1423,9 +1571,9 @@ Take a look at [`deferTask`](https://npmjs.com/package/@alessiofrittoli/web-util
1423
1571
 
1424
1572
  <summary style="cursor:pointer">Parameters</summary>
1425
1573
 
1426
- | Parameter | Type | Description |
1427
- |-----------|----------|-----------------------------|
1428
- | `task` | `T` | The task callable function. |
1574
+ | Parameter | Type | Description |
1575
+ | --------- | ---- | --------------------------- |
1576
+ | `task` | `T` | The task callable function. |
1429
1577
 
1430
1578
  </details>
1431
1579
 
@@ -1473,8 +1621,8 @@ Modified version of `useEffect` that only run once on intial load.
1473
1621
 
1474
1622
  <summary style="cursor:pointer">Parameters</summary>
1475
1623
 
1476
- | Parameter | Type | Description |
1477
- |-----------|------------------------|-------------|
1624
+ | Parameter | Type | Description |
1625
+ | --------- | ---------------------- | ------------------------------------------------------- |
1478
1626
  | `effect` | `React.EffectCallback` | Imperative function that can return a cleanup function. |
1479
1627
 
1480
1628
  </details>
@@ -1486,34 +1634,30 @@ Modified version of `useEffect` that only run once on intial load.
1486
1634
  <summary style="cursor:pointer">Usage</summary>
1487
1635
 
1488
1636
  ```tsx
1489
- 'use client'
1637
+ "use client";
1490
1638
 
1491
- import { useEffect, useState } from 'react'
1492
- import { useEffectOnce } from '@alessiofrittoli/react-hooks'
1639
+ import { useEffect, useState } from "react";
1640
+ import { useEffectOnce } from "@alessiofrittoli/react-hooks";
1493
1641
 
1494
1642
  export const ClientComponent: React.FC = () => {
1643
+ const [count, setCount] = useState(0);
1495
1644
 
1496
- const [ count, setCount ] = useState( 0 )
1497
-
1498
- useEffect( () => {
1499
- const intv = setInterval( () => {
1500
- setCount( prev => prev + 1 ) // update state each 1s
1501
- }, 1000 )
1502
- return () => clearInterval( intv )
1503
- }, [] )
1645
+ useEffect(() => {
1646
+ const intv = setInterval(() => {
1647
+ setCount((prev) => prev + 1); // update state each 1s
1648
+ }, 1000);
1649
+ return () => clearInterval(intv);
1650
+ }, []);
1504
1651
 
1505
- useEffectOnce( () => {
1506
- console.log( 'Component did mount' )
1652
+ useEffectOnce(() => {
1653
+ console.log("Component did mount");
1507
1654
  return () => {
1508
- console.log( 'Component did unmount' )
1509
- }
1510
- } )
1511
-
1512
- return (
1513
- <div>{ count }</div>
1514
- )
1655
+ console.log("Component did unmount");
1656
+ };
1657
+ });
1515
1658
 
1516
- }
1659
+ return <div>{count}</div>;
1660
+ };
1517
1661
  ```
1518
1662
 
1519
1663
  </details>
@@ -1528,9 +1672,9 @@ Modified version of `useEffect` that skips the first render.
1528
1672
 
1529
1673
  <summary style="cursor:pointer">Parameters</summary>
1530
1674
 
1531
- | Parameter | Type | Description |
1532
- |-----------|------------------------|-------------|
1533
- | `effect` | `React.EffectCallback` | Imperative function that can return a cleanup function. |
1675
+ | Parameter | Type | Description |
1676
+ | --------- | ---------------------- | ----------------------------------------------------------------------- |
1677
+ | `effect` | `React.EffectCallback` | Imperative function that can return a cleanup function. |
1534
1678
  | `deps` | `React.DependencyList` | If present, effect will only activate if the values in the list change. |
1535
1679
 
1536
1680
  </details>
@@ -1542,41 +1686,37 @@ Modified version of `useEffect` that skips the first render.
1542
1686
  <summary style="cursor:pointer">Usage</summary>
1543
1687
 
1544
1688
  ```tsx
1545
- 'use client'
1689
+ "use client";
1546
1690
 
1547
- import { useEffect, useState } from 'react'
1548
- import { useUpdateEffect } from '@alessiofrittoli/react-hooks'
1691
+ import { useEffect, useState } from "react";
1692
+ import { useUpdateEffect } from "@alessiofrittoli/react-hooks";
1549
1693
 
1550
1694
  export const ClientComponent: React.FC = () => {
1695
+ const [count, setCount] = useState(0);
1551
1696
 
1552
- const [ count, setCount ] = useState( 0 )
1697
+ useEffect(() => {
1698
+ const intv = setInterval(() => {
1699
+ setCount((prev) => prev + 1);
1700
+ }, 1000);
1701
+ return () => clearInterval(intv);
1702
+ }, []);
1553
1703
 
1554
- useEffect( () => {
1555
- const intv = setInterval( () => {
1556
- setCount( prev => prev + 1 )
1557
- }, 1000 )
1558
- return () => clearInterval( intv )
1559
- }, [] )
1560
-
1561
- useEffect( () => {
1562
- console.log( 'useEffect', count ) // starts from 0
1704
+ useEffect(() => {
1705
+ console.log("useEffect", count); // starts from 0
1563
1706
  return () => {
1564
- console.log( 'useEffect - clean up', count ) // starts from 0
1565
- }
1566
- }, [ count ] )
1707
+ console.log("useEffect - clean up", count); // starts from 0
1708
+ };
1709
+ }, [count]);
1567
1710
 
1568
- useUpdateEffect( () => {
1569
- console.log( 'useUpdateEffect', count ) // starts from 1
1711
+ useUpdateEffect(() => {
1712
+ console.log("useUpdateEffect", count); // starts from 1
1570
1713
  return () => {
1571
- console.log( 'useUpdateEffect - clean up', count ) // starts from 1
1572
- }
1573
- }, [ count ] )
1714
+ console.log("useUpdateEffect - clean up", count); // starts from 1
1715
+ };
1716
+ }, [count]);
1574
1717
 
1575
- return (
1576
- <div>{ count }</div>
1577
- )
1578
-
1579
- }
1718
+ return <div>{count}</div>;
1719
+ };
1580
1720
  ```
1581
1721
 
1582
1722
  </details>
@@ -1607,19 +1747,15 @@ Type: `boolean`
1607
1747
  <summary style="cursor:pointer">Usage</summary>
1608
1748
 
1609
1749
  ```tsx
1610
- 'use client'
1750
+ "use client";
1611
1751
 
1612
- import { useIsClient } from '@alessiofrittoli/react-hooks'
1752
+ import { useIsClient } from "@alessiofrittoli/react-hooks";
1613
1753
 
1614
1754
  export const ClientComponent: React.FC = () => {
1755
+ const isClient = useIsClient();
1615
1756
 
1616
- const isClient = useIsClient()
1617
-
1618
- return (
1619
- <div>Running { ! isClient ? 'server' : 'client' }-side</div>
1620
- )
1621
-
1622
- }
1757
+ return <div>Running {!isClient ? "server" : "client"}-side</div>;
1758
+ };
1623
1759
  ```
1624
1760
 
1625
1761
  </details>
@@ -1650,31 +1786,29 @@ Note that if the React Hook/Component has no state updates, `useIsFirstRender` w
1650
1786
  <summary style="cursor:pointer">Usage</summary>
1651
1787
 
1652
1788
  ```tsx
1653
- 'use client'
1789
+ "use client";
1654
1790
 
1655
- import { useIsFirstRender } from '@alessiofrittoli/react-hooks'
1791
+ import { useIsFirstRender } from "@alessiofrittoli/react-hooks";
1656
1792
 
1657
1793
  export const ClientComponent: React.FC = () => {
1794
+ const isFirstRender = useIsFirstRender();
1795
+ const [counter, setCounter] = useState(0);
1658
1796
 
1659
- const isFirstRender = useIsFirstRender()
1660
- const [ counter, setCounter ] = useState( 0 )
1661
-
1662
- useEffect( () => {
1663
- const intv = setInterval( () => {
1664
- setCounter( prev => prev + 1 )
1665
- }, 1000 )
1666
- return () => clearInterval( intv )
1667
- }, [] )
1797
+ useEffect(() => {
1798
+ const intv = setInterval(() => {
1799
+ setCounter((prev) => prev + 1);
1800
+ }, 1000);
1801
+ return () => clearInterval(intv);
1802
+ }, []);
1668
1803
 
1669
1804
  return (
1670
1805
  <div>
1671
- { isFirstRender ? 'First render' : 'Subsequent render' }
1806
+ {isFirstRender ? "First render" : "Subsequent render"}
1672
1807
  <hr />
1673
- { counter }
1808
+ {counter}
1674
1809
  </div>
1675
- )
1676
-
1677
- }
1810
+ );
1811
+ };
1678
1812
  ```
1679
1813
 
1680
1814
  </details>
@@ -1701,8 +1835,8 @@ Provides functionality for single and group selection, as well as resetting the
1701
1835
 
1702
1836
  <summary style="cursor:pointer">Type Parameters</summary>
1703
1837
 
1704
- | Parameter | Description |
1705
- |-----------|------------------------------|
1838
+ | Parameter | Description |
1839
+ | --------- | -------------------------------------- |
1706
1840
  | `V` | The type of the values in the `array`. |
1707
1841
 
1708
1842
  </details>
@@ -1713,10 +1847,10 @@ Provides functionality for single and group selection, as well as resetting the
1713
1847
 
1714
1848
  <summary style="cursor:pointer">Parameters</summary>
1715
1849
 
1716
- | Parameter | Type | Default | Description |
1717
- |-----------|-------|---------|-----------------------------|
1718
- | `array` | `V[]` | - | The array of items to manage selection for. |
1719
- | `initial` | `V[]` | [] | The initial selection state. |
1850
+ | Parameter | Type | Default | Description |
1851
+ | --------- | ----- | ------- | ------------------------------------------- |
1852
+ | `array` | `V[]` | - | The array of items to manage selection for. |
1853
+ | `initial` | `V[]` | [] | The initial selection state. |
1720
1854
 
1721
1855
  </details>
1722
1856
 
@@ -1746,77 +1880,78 @@ An object containing the selection state and handlers.
1746
1880
  <summary style="cursor:pointer">Usage</summary>
1747
1881
 
1748
1882
  ```tsx
1749
- 'use client'
1883
+ "use client";
1750
1884
 
1751
- import { useCallback, useMemo } from 'react'
1752
- import { useSelection } from '@alessiofrittoli/react-hooks'
1885
+ import { useCallback, useMemo } from "react";
1886
+ import { useSelection } from "@alessiofrittoli/react-hooks";
1753
1887
 
1754
- interface Item
1755
- {
1756
- id : number
1757
- name : string
1888
+ interface Item {
1889
+ id: number;
1890
+ name: string;
1758
1891
  }
1759
1892
 
1760
1893
  const items: Item[] = [
1761
1894
  {
1762
- id : 1,
1763
- name : 'item-1',
1895
+ id: 1,
1896
+ name: "item-1",
1764
1897
  },
1765
1898
  {
1766
- id : 2,
1767
- name : 'item-2',
1899
+ id: 2,
1900
+ name: "item-2",
1768
1901
  },
1769
1902
  {
1770
- id : 3,
1771
- name : 'item-3',
1903
+ id: 3,
1904
+ name: "item-3",
1772
1905
  },
1773
1906
  {
1774
- id : 4,
1775
- name : 'item-4',
1907
+ id: 4,
1908
+ name: "item-4",
1776
1909
  },
1777
1910
  {
1778
- id : 5,
1779
- name : 'item-5',
1911
+ id: 5,
1912
+ name: "item-5",
1780
1913
  },
1781
- ]
1782
-
1914
+ ];
1783
1915
 
1784
1916
  const MyComponent: React.FC = () => {
1785
-
1786
- const {
1787
- setSelection, select, groupSelect, isSelected
1788
- } = useSelection( useMemo( () => items.map( item => item.id ), [] ) )
1789
-
1790
- const clickHandler = useCallback( ( id: Item[ 'id' ] ) => (
1791
- ( event: React.MouseEvent<HTMLButtonElement> ) => {
1792
- if ( event.shiftKey ) {
1793
- return groupSelect( id ) // group select
1917
+ const { setSelection, select, groupSelect, isSelected } = useSelection(
1918
+ useMemo(() => items.map((item) => item.id), [])
1919
+ );
1920
+
1921
+ const clickHandler = useCallback(
1922
+ (id: Item["id"]) => (event: React.MouseEvent<HTMLButtonElement>) => {
1923
+ if (event.shiftKey) {
1924
+ return groupSelect(id); // group select
1794
1925
  }
1795
- if ( event.metaKey || event.ctrlKey ) {
1796
- return select( id ) // toggle single item in selection
1926
+ if (event.metaKey || event.ctrlKey) {
1927
+ return select(id); // toggle single item in selection
1797
1928
  }
1798
- setSelection( prev => (
1799
- prev.includes( id ) ? [] : [ id ] // toggle single item selection
1800
- ) )
1801
- }
1802
- ), [ select, groupSelect, setSelection ] )
1929
+ setSelection(
1930
+ (prev) => (prev.includes(id) ? [] : [id]) // toggle single item selection
1931
+ );
1932
+ },
1933
+ [select, groupSelect, setSelection]
1934
+ );
1803
1935
 
1804
1936
  return (
1805
1937
  <ul>
1806
- { items.map( item => (
1807
- <li key={ item.id }>
1938
+ {items.map((item) => (
1939
+ <li key={item.id}>
1808
1940
  <button
1809
- onClick={ clickHandler( item.id ) }
1810
- style={ {
1811
- border: isSelected( item.id ) ? '1px solid red' : ' 1px solid black'
1812
- } }
1813
- >{ item.name }</button>
1941
+ onClick={clickHandler(item.id)}
1942
+ style={{
1943
+ border: isSelected(item.id)
1944
+ ? "1px solid red"
1945
+ : " 1px solid black",
1946
+ }}
1947
+ >
1948
+ {item.name}
1949
+ </button>
1814
1950
  </li>
1815
- ) ) }
1951
+ ))}
1816
1952
  </ul>
1817
- )
1818
-
1819
- }
1953
+ );
1954
+ };
1820
1955
  ```
1821
1956
 
1822
1957
  </details>
@@ -1842,7 +1977,7 @@ The `Timeout` automatically restarts when the given `value` changes.
1842
1977
  <summary style="cursor:pointer">Type Parameters</summary>
1843
1978
 
1844
1979
  | Parameter | Description |
1845
- |-----------|--------------------------|
1980
+ | --------- | ------------------------ |
1846
1981
  | `T` | The type of the `value`. |
1847
1982
 
1848
1983
  </details>
@@ -1853,10 +1988,10 @@ The `Timeout` automatically restarts when the given `value` changes.
1853
1988
 
1854
1989
  <summary style="cursor:pointer">Parameters</summary>
1855
1990
 
1856
- | Parameter | Type | Default | Description |
1857
- |-----------|----------|---------|-----------------------------|
1991
+ | Parameter | Type | Default | Description |
1992
+ | --------- | -------- | ------- | ----------------------------------------------- |
1858
1993
  | `value` | `T` | - | The value to debounce. This can be of any type. |
1859
- | `delay` | `number` | 500 | The debounce delay in milliseconds. |
1994
+ | `delay` | `number` | 500 | The debounce delay in milliseconds. |
1860
1995
 
1861
1996
  </details>
1862
1997
 
@@ -1879,33 +2014,26 @@ The debounced value, which updates only after the delay has passed.
1879
2014
  <summary style="cursor:pointer">Usage</summary>
1880
2015
 
1881
2016
  ```tsx
1882
- 'use client'
2017
+ "use client";
1883
2018
 
1884
- import { useEffect, useState } from 'react'
1885
- import { useDebounce } from '@alessiofrittoli/react-hooks'
2019
+ import { useEffect, useState } from "react";
2020
+ import { useDebounce } from "@alessiofrittoli/react-hooks";
1886
2021
 
1887
2022
  const MyComponent: React.FC = () => {
2023
+ const [query, setQuery] = useState("");
2024
+ const debouncedQuery = useDebounce(query);
1888
2025
 
1889
- const [ query, setQuery ] = useState( '' )
1890
- const debouncedQuery = useDebounce( query )
2026
+ useEffect(() => {
2027
+ if (!debouncedQuery) return;
1891
2028
 
1892
- useEffect( () => {
1893
- if ( ! debouncedQuery ) return
1894
-
1895
- fetch( '...', {
2029
+ fetch("...", {
1896
2030
  // ...
1897
- body: JSON.stringify( { query: debouncedQuery } )
1898
- } )
1899
-
1900
- }, [ debouncedQuery ] )
1901
-
1902
- return (
1903
- <input
1904
- onChange={ event => setQuery( event.target.value ) }
1905
- />
1906
- )
2031
+ body: JSON.stringify({ query: debouncedQuery }),
2032
+ });
2033
+ }, [debouncedQuery]);
1907
2034
 
1908
- }
2035
+ return <input onChange={(event) => setQuery(event.target.value)} />;
2036
+ };
1909
2037
  ```
1910
2038
 
1911
2039
  </details>
@@ -1925,8 +2053,8 @@ The `Timeout` is automatically cancelled on unmount.
1925
2053
 
1926
2054
  <summary style="cursor:pointer">Type Parameters</summary>
1927
2055
 
1928
- | Parameter | Description |
1929
- |-----------|--------------------------|
2056
+ | Parameter | Description |
2057
+ | --------- | -------------------------------------------------------------- |
1930
2058
  | `T` | An Array defining optional arguments passed to the `callback`. |
1931
2059
 
1932
2060
  </details>
@@ -1937,15 +2065,15 @@ The `Timeout` is automatically cancelled on unmount.
1937
2065
 
1938
2066
  <summary style="cursor:pointer">Parameters</summary>
1939
2067
 
1940
- | Parameter | Type | Default | Description |
1941
- |-----------|----------|---------|-----------------------------|
1942
- | `callback`| `TimerHandler<T>` | - | The function to call when the timer elapses. |
1943
- | `options` | `TimerOptions<T>` | - | (Optional) An object defining custom timer options. |
1944
- | `options.delay` | `number` | `1` | The number of milliseconds to wait before calling the `callback`. |
1945
- | `options.args` | `T` | - | Optional arguments to pass when the `callback` is called. |
1946
- | `options.autoplay` | `boolean` | `true` | Indicates whether auto start the timer. |
1947
- | `options.updateState` | `boolean` | `false` | Whether to update React state about Timer running status. |
1948
- | `options.runOnStart` | `boolean` | `false` | Indicates whether to execute the callback when timer starts. |
2068
+ | Parameter | Type | Default | Description |
2069
+ | --------------------- | ----------------- | ------- | ----------------------------------------------------------------- |
2070
+ | `callback` | `TimerHandler<T>` | - | The function to call when the timer elapses. |
2071
+ | `options` | `TimerOptions<T>` | - | (Optional) An object defining custom timer options. |
2072
+ | `options.delay` | `number` | `1` | The number of milliseconds to wait before calling the `callback`. |
2073
+ | `options.args` | `T` | - | Optional arguments to pass when the `callback` is called. |
2074
+ | `options.autoplay` | `boolean` | `true` | Indicates whether auto start the timer. |
2075
+ | `options.updateState` | `boolean` | `false` | Whether to update React state about Timer running status. |
2076
+ | `options.runOnStart` | `boolean` | `false` | Indicates whether to execute the callback when timer starts. |
1949
2077
 
1950
2078
  </details>
1951
2079
 
@@ -1977,22 +2105,21 @@ If `updateState` is set to `true` then the following property is added in the re
1977
2105
  ##### Basic usage
1978
2106
 
1979
2107
  ```tsx
1980
- 'use client'
2108
+ "use client";
1981
2109
 
1982
- import { useCallback } from 'react'
1983
- import { useInterval } from '@alessiofrittoli/react-hooks'
2110
+ import { useCallback } from "react";
2111
+ import { useInterval } from "@alessiofrittoli/react-hooks";
1984
2112
 
1985
2113
  const MyComponent: React.FC = () => {
1986
-
1987
- const { stop } = useInterval( useCallback( () => {
1988
- console.log( 'tick timer' )
1989
- }, [] ), { delay: 1000 } )
1990
-
1991
- return (
1992
- <button onClick={ stop }>Stop timer</button>
1993
- )
1994
-
1995
- }
2114
+ const { stop } = useInterval(
2115
+ useCallback(() => {
2116
+ console.log("tick timer");
2117
+ }, []),
2118
+ { delay: 1000 }
2119
+ );
2120
+
2121
+ return <button onClick={stop}>Stop timer</button>;
2122
+ };
1996
2123
  ```
1997
2124
 
1998
2125
  ---
@@ -2000,34 +2127,31 @@ const MyComponent: React.FC = () => {
2000
2127
  ##### Rely on state updates
2001
2128
 
2002
2129
  ```tsx
2003
- 'use client'
2130
+ "use client";
2004
2131
 
2005
- import { useCallback } from 'react'
2006
- import { useInterval } from '@alessiofrittoli/react-hooks'
2132
+ import { useCallback } from "react";
2133
+ import { useInterval } from "@alessiofrittoli/react-hooks";
2007
2134
 
2008
2135
  const MyComponent: React.FC = () => {
2009
-
2010
- const { isActive, start, stop } = useInterval( useCallback( () => {
2011
- console.log( 'tick timer' )
2012
- }, [] ), {
2013
- delay : 1000,
2014
- autoplay : false,
2015
- runOnStart : true,
2016
- updateState : true,
2017
- } )
2136
+ const { isActive, start, stop } = useInterval(
2137
+ useCallback(() => {
2138
+ console.log("tick timer");
2139
+ }, []),
2140
+ {
2141
+ delay: 1000,
2142
+ autoplay: false,
2143
+ runOnStart: true,
2144
+ updateState: true,
2145
+ }
2146
+ );
2018
2147
 
2019
2148
  return (
2020
2149
  <>
2021
- { ! isActive && (
2022
- <button onClick={ start }>Start timer</button>
2023
- ) }
2024
- { isActive && (
2025
- <button onClick={ stop }>Stop timer</button>
2026
- ) }
2150
+ {!isActive && <button onClick={start}>Start timer</button>}
2151
+ {isActive && <button onClick={stop}>Stop timer</button>}
2027
2152
  </>
2028
- )
2029
-
2030
- }
2153
+ );
2154
+ };
2031
2155
  ```
2032
2156
 
2033
2157
  </details>
@@ -2055,8 +2179,8 @@ This is a lighter version of [`useInterval`](#useinterval) and is suggested to u
2055
2179
 
2056
2180
  <summary style="cursor:pointer">Type Parameters</summary>
2057
2181
 
2058
- | Parameter | Description |
2059
- |-----------|--------------------------|
2182
+ | Parameter | Description |
2183
+ | --------- | -------------------------------------------------------------- |
2060
2184
  | `T` | An Array defining optional arguments passed to the `callback`. |
2061
2185
 
2062
2186
  </details>
@@ -2067,12 +2191,12 @@ This is a lighter version of [`useInterval`](#useinterval) and is suggested to u
2067
2191
 
2068
2192
  <summary style="cursor:pointer">Parameters</summary>
2069
2193
 
2070
- | Parameter | Type | Default | Description |
2071
- |-----------|----------|---------|-----------------------------|
2072
- | `callback`| `TimerHandler<T>` | - | The function to call when the timer elapses. |
2073
- | `options` | `BasicTimerOptions<T>` | - | (Optional) An object defining custom timer options. |
2074
- | `options.delay` | `number` | `1` | The number of milliseconds to wait before calling the `callback`. |
2075
- | `options.args` | `T` | - | Optional arguments to pass when the `callback` is called. |
2194
+ | Parameter | Type | Default | Description |
2195
+ | --------------- | ---------------------- | ------- | ----------------------------------------------------------------- |
2196
+ | `callback` | `TimerHandler<T>` | - | The function to call when the timer elapses. |
2197
+ | `options` | `BasicTimerOptions<T>` | - | (Optional) An object defining custom timer options. |
2198
+ | `options.delay` | `number` | `1` | The number of milliseconds to wait before calling the `callback`. |
2199
+ | `options.args` | `T` | - | Optional arguments to pass when the `callback` is called. |
2076
2200
 
2077
2201
  </details>
2078
2202
 
@@ -2083,18 +2207,19 @@ This is a lighter version of [`useInterval`](#useinterval) and is suggested to u
2083
2207
  <summary style="cursor:pointer">Usage</summary>
2084
2208
 
2085
2209
  ```tsx
2086
- 'use client'
2210
+ "use client";
2087
2211
 
2088
- import { useCallback } from 'react'
2089
- import { useLightInterval } from '@alessiofrittoli/react-hooks'
2212
+ import { useCallback } from "react";
2213
+ import { useLightInterval } from "@alessiofrittoli/react-hooks";
2090
2214
 
2091
2215
  const MyComponent: React.FC = () => {
2092
-
2093
- useLightInterval( useCallback( () => {
2094
- console.log( 'tick timer' )
2095
- }, [] ), { delay: 1000 } )
2096
-
2097
- }
2216
+ useLightInterval(
2217
+ useCallback(() => {
2218
+ console.log("tick timer");
2219
+ }, []),
2220
+ { delay: 1000 }
2221
+ );
2222
+ };
2098
2223
  ```
2099
2224
 
2100
2225
  </details>
@@ -2122,8 +2247,8 @@ The `Timeout` is automatically cancelled on unmount.
2122
2247
 
2123
2248
  <summary style="cursor:pointer">Type Parameters</summary>
2124
2249
 
2125
- | Parameter | Description |
2126
- |-----------|--------------------------|
2250
+ | Parameter | Description |
2251
+ | --------- | -------------------------------------------------------------- |
2127
2252
  | `T` | An Array defining optional arguments passed to the `callback`. |
2128
2253
 
2129
2254
  </details>
@@ -2134,15 +2259,15 @@ The `Timeout` is automatically cancelled on unmount.
2134
2259
 
2135
2260
  <summary style="cursor:pointer">Parameters</summary>
2136
2261
 
2137
- | Parameter | Type | Default | Description |
2138
- |-----------|----------|---------|-----------------------------|
2139
- | `callback`| `TimerHandler<T>` | - | The function to call when the timer elapses. |
2140
- | `options` | `TimerOptions<T>` | - | (Optional) An object defining custom timer options. |
2141
- | `options.delay` | `number` | `1` | The number of milliseconds to wait before calling the `callback`. |
2142
- | `options.args` | `T` | - | Optional arguments to pass when the `callback` is called. |
2143
- | `options.autoplay` | `boolean` | `true` | Indicates whether auto start the timer. |
2144
- | `options.updateState` | `boolean` | `false` | Whether to update React state about Timer running status. |
2145
- | `options.runOnStart` | `boolean` | `false` | Indicates whether to execute the callback when timer starts. |
2262
+ | Parameter | Type | Default | Description |
2263
+ | --------------------- | ----------------- | ------- | ----------------------------------------------------------------- |
2264
+ | `callback` | `TimerHandler<T>` | - | The function to call when the timer elapses. |
2265
+ | `options` | `TimerOptions<T>` | - | (Optional) An object defining custom timer options. |
2266
+ | `options.delay` | `number` | `1` | The number of milliseconds to wait before calling the `callback`. |
2267
+ | `options.args` | `T` | - | Optional arguments to pass when the `callback` is called. |
2268
+ | `options.autoplay` | `boolean` | `true` | Indicates whether auto start the timer. |
2269
+ | `options.updateState` | `boolean` | `false` | Whether to update React state about Timer running status. |
2270
+ | `options.runOnStart` | `boolean` | `false` | Indicates whether to execute the callback when timer starts. |
2146
2271
 
2147
2272
  </details>
2148
2273
 
@@ -2174,22 +2299,21 @@ If `updateState` is set to `true` then the following property is added in the re
2174
2299
  ##### Basic usage
2175
2300
 
2176
2301
  ```tsx
2177
- 'use client'
2302
+ "use client";
2178
2303
 
2179
- import { useCallback } from 'react'
2180
- import { useTimeout } from '@alessiofrittoli/react-hooks'
2304
+ import { useCallback } from "react";
2305
+ import { useTimeout } from "@alessiofrittoli/react-hooks";
2181
2306
 
2182
2307
  const MyComponent: React.FC = () => {
2183
-
2184
- const { stop } = useTimeout( useCallback( () => {
2185
- console.log( 'tick timer' )
2186
- }, [] ), { delay: 1000 } )
2187
-
2188
- return (
2189
- <button onClick={ stop }>Stop timer</button>
2190
- )
2191
-
2192
- }
2308
+ const { stop } = useTimeout(
2309
+ useCallback(() => {
2310
+ console.log("tick timer");
2311
+ }, []),
2312
+ { delay: 1000 }
2313
+ );
2314
+
2315
+ return <button onClick={stop}>Stop timer</button>;
2316
+ };
2193
2317
  ```
2194
2318
 
2195
2319
  ---
@@ -2197,34 +2321,31 @@ const MyComponent: React.FC = () => {
2197
2321
  ##### Rely on state updates
2198
2322
 
2199
2323
  ```tsx
2200
- 'use client'
2324
+ "use client";
2201
2325
 
2202
- import { useCallback } from 'react'
2203
- import { useTimeout } from '@alessiofrittoli/react-hooks'
2326
+ import { useCallback } from "react";
2327
+ import { useTimeout } from "@alessiofrittoli/react-hooks";
2204
2328
 
2205
2329
  const MyComponent: React.FC = () => {
2206
-
2207
- const { isActive, start, stop } = useTimeout( useCallback( () => {
2208
- console.log( 'tick timer' )
2209
- }, [] ), {
2210
- delay : 1000,
2211
- autoplay : false,
2212
- runOnStart : true,
2213
- updateState : true,
2214
- } )
2330
+ const { isActive, start, stop } = useTimeout(
2331
+ useCallback(() => {
2332
+ console.log("tick timer");
2333
+ }, []),
2334
+ {
2335
+ delay: 1000,
2336
+ autoplay: false,
2337
+ runOnStart: true,
2338
+ updateState: true,
2339
+ }
2340
+ );
2215
2341
 
2216
2342
  return (
2217
2343
  <>
2218
- { ! isActive && (
2219
- <button onClick={ start }>Start timer</button>
2220
- ) }
2221
- { isActive && (
2222
- <button onClick={ stop }>Stop timer</button>
2223
- ) }
2344
+ {!isActive && <button onClick={start}>Start timer</button>}
2345
+ {isActive && <button onClick={stop}>Stop timer</button>}
2224
2346
  </>
2225
- )
2226
-
2227
- }
2347
+ );
2348
+ };
2228
2349
  ```
2229
2350
 
2230
2351
  </details>
@@ -2241,8 +2362,8 @@ This is a lighter version of [`useTimeout`](#usetimeout) and is suggested to use
2241
2362
 
2242
2363
  <summary style="cursor:pointer">Type Parameters</summary>
2243
2364
 
2244
- | Parameter | Description |
2245
- |-----------|--------------------------|
2365
+ | Parameter | Description |
2366
+ | --------- | -------------------------------------------------------------- |
2246
2367
  | `T` | An Array defining optional arguments passed to the `callback`. |
2247
2368
 
2248
2369
  </details>
@@ -2253,12 +2374,12 @@ This is a lighter version of [`useTimeout`](#usetimeout) and is suggested to use
2253
2374
 
2254
2375
  <summary style="cursor:pointer">Parameters</summary>
2255
2376
 
2256
- | Parameter | Type | Default | Description |
2257
- |-----------|----------|---------|-----------------------------|
2258
- | `callback`| `TimerHandler<T>` | - | The function to call when the timer elapses. |
2259
- | `options` | `BasicTimerOptions<T>` | - | (Optional) An object defining custom timer options. |
2260
- | `options.delay` | `number` | `1` | The number of milliseconds to wait before calling the `callback`. |
2261
- | `options.args` | `T` | - | Optional arguments to pass when the `callback` is called. |
2377
+ | Parameter | Type | Default | Description |
2378
+ | --------------- | ---------------------- | ------- | ----------------------------------------------------------------- |
2379
+ | `callback` | `TimerHandler<T>` | - | The function to call when the timer elapses. |
2380
+ | `options` | `BasicTimerOptions<T>` | - | (Optional) An object defining custom timer options. |
2381
+ | `options.delay` | `number` | `1` | The number of milliseconds to wait before calling the `callback`. |
2382
+ | `options.args` | `T` | - | Optional arguments to pass when the `callback` is called. |
2262
2383
 
2263
2384
  </details>
2264
2385
 
@@ -2269,18 +2390,19 @@ This is a lighter version of [`useTimeout`](#usetimeout) and is suggested to use
2269
2390
  <summary style="cursor:pointer">Usage</summary>
2270
2391
 
2271
2392
  ```tsx
2272
- 'use client'
2393
+ "use client";
2273
2394
 
2274
- import { useCallback } from 'react'
2275
- import { useLightTimeout } from '@alessiofrittoli/react-hooks'
2395
+ import { useCallback } from "react";
2396
+ import { useLightTimeout } from "@alessiofrittoli/react-hooks";
2276
2397
 
2277
2398
  const MyComponent: React.FC = () => {
2278
-
2279
- useLightTimeout( useCallback( () => {
2280
- console.log( 'tick timer' )
2281
- }, [] ), { delay: 1000 } )
2282
-
2283
- }
2399
+ useLightTimeout(
2400
+ useCallback(() => {
2401
+ console.log("tick timer");
2402
+ }, []),
2403
+ { delay: 1000 }
2404
+ );
2405
+ };
2284
2406
  ```
2285
2407
 
2286
2408
  </details>