@alessiofrittoli/react-hooks 3.3.0-alpha.2 → 3.3.0-alpha.3
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 +1343 -279
- package/dist/index.d.mts +21 -17
- package/dist/index.d.ts +21 -17
- package/dist/index.js +1 -1
- package/dist/index.mjs +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -29,19 +29,31 @@
|
|
|
29
29
|
- [`useStorage`](#usestorage)
|
|
30
30
|
- [`useLocalStorage`](#uselocalstorage)
|
|
31
31
|
- [`useSessionStorage`](#usesessionstorage)
|
|
32
|
-
- [`
|
|
32
|
+
- [`useConnection`](#useconnection)
|
|
33
33
|
- [`useDarkMode`](#usedarkmode)
|
|
34
|
+
- [`useEventListener`](#useeventlistener)
|
|
34
35
|
- [`useIsPortrait`](#useisportrait)
|
|
36
|
+
- [`useMediaQuery`](#usemediaquery)
|
|
35
37
|
- [DOM API](#dom-api)
|
|
36
|
-
- [`useScrollBlock`](#usescrollblock)
|
|
37
38
|
- [`useFocusTrap`](#usefocustrap)
|
|
38
39
|
- [`useInView`](#useinview)
|
|
40
|
+
- [`useScrollBlock`](#usescrollblock)
|
|
39
41
|
- [Miscellaneous](#miscellaneous)
|
|
42
|
+
- [`useInput`](#useinput)
|
|
40
43
|
- [`useDeferCallback`](#usedefercallback)
|
|
44
|
+
- [`useEffectOnce`](#useeffectonce)
|
|
45
|
+
- [`useUpdateEffect`](#useupdateeffect)
|
|
41
46
|
- [`useIsClient`](#useisclient)
|
|
42
47
|
- [`useIsFirstRender`](#useisfirstrender)
|
|
43
|
-
- [`useUpdateEffect`](#useupdateeffect)
|
|
44
48
|
- [`usePagination`](#usepagination)
|
|
49
|
+
- [`useSelection`](#useselection)
|
|
50
|
+
- [Timers](#timers)
|
|
51
|
+
- [`useDebounce`](#usedebounce)
|
|
52
|
+
- [`useInterval`](#useinterval)
|
|
53
|
+
- [`useIntervalWhenVisible`](#useintervalwhenvisible)
|
|
54
|
+
- [`useLightInterval`](#uselightinterval)
|
|
55
|
+
- [`useTimeout`](#usetimeout)
|
|
56
|
+
- [`useLightTimeout`](#uselighttimeout)
|
|
45
57
|
- [Development](#development)
|
|
46
58
|
- [Install depenendencies](#install-depenendencies)
|
|
47
59
|
- [Build the source code](#build-the-source-code)
|
|
@@ -95,6 +107,7 @@ export default config
|
|
|
95
107
|
#### Updates in the latest release 🎉
|
|
96
108
|
|
|
97
109
|
- Add `useDeferCallback`. See [API Reference](#usedefercallback) for more info.
|
|
110
|
+
- Add missing API Referefence sections.
|
|
98
111
|
|
|
99
112
|
---
|
|
100
113
|
|
|
@@ -269,75 +282,26 @@ Applies the same API Reference.
|
|
|
269
282
|
|
|
270
283
|
---
|
|
271
284
|
|
|
272
|
-
##### `
|
|
273
|
-
|
|
274
|
-
Get Document Media matches and listen for changes.
|
|
275
|
-
|
|
276
|
-
<details>
|
|
277
|
-
|
|
278
|
-
<summary style="cursor:pointer">Parameters</summary>
|
|
279
|
-
|
|
280
|
-
| Parameter | Type | Default | Description |
|
|
281
|
-
|-----------|----------|---------|-------------|
|
|
282
|
-
| `query` | `string` | - | A string specifying the media query to parse into a `MediaQueryList`. |
|
|
283
|
-
| `options` | `UseMediaQueryOptions\|UseMediaQueryStateOptions` | - | An object defining custom options. |
|
|
284
|
-
| `options.updateState` | `boolean` | `true` | Indicates whether the hook will dispatch a React state update when the given `query` change event get dispatched. |
|
|
285
|
-
| `options.onChange` | `OnChangeHandler` | - | A custom callback that will be invoked on initial page load and when the given `query` change event get dispatched. |
|
|
286
|
-
| | | | This callback is required if `updateState` is set to `false`. |
|
|
287
|
-
|
|
288
|
-
</details>
|
|
285
|
+
##### `useConnection`
|
|
289
286
|
|
|
290
|
-
|
|
287
|
+
Get states about Internet Connection.
|
|
291
288
|
|
|
292
289
|
<details>
|
|
293
290
|
|
|
294
291
|
<summary style="cursor:pointer">Returns</summary>
|
|
295
292
|
|
|
296
|
-
Type: `
|
|
297
|
-
|
|
298
|
-
- `true` or `false` if the document currently matches the media query list or not.
|
|
299
|
-
- `void` if `updateState` is set to `false`.
|
|
300
|
-
|
|
301
|
-
</details>
|
|
302
|
-
|
|
303
|
-
---
|
|
304
|
-
|
|
305
|
-
<details>
|
|
306
|
-
|
|
307
|
-
<summary style="cursor:pointer">Usage</summary>
|
|
308
|
-
|
|
309
|
-
###### Check if user device prefers dark color scheme
|
|
310
|
-
|
|
311
|
-
```tsx
|
|
312
|
-
import { useMediaQuery } from '@alessiofrittoli/react-hooks'
|
|
313
|
-
|
|
314
|
-
const isDarkOS = useMediaQuery( '(prefers-color-scheme: dark)' )
|
|
315
|
-
```
|
|
316
|
-
|
|
317
|
-
---
|
|
318
|
-
|
|
319
|
-
###### Listen changes with no state updates
|
|
293
|
+
Type: `UseConnectionReturnType`
|
|
320
294
|
|
|
321
|
-
|
|
322
|
-
import { useMediaQuery } from '@alessiofrittoli/react-hooks'
|
|
295
|
+
An object with the following properties:
|
|
323
296
|
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
console.log( 'is dark OS?', matches )
|
|
328
|
-
}
|
|
329
|
-
} )
|
|
330
|
-
```
|
|
297
|
+
- `connection`: `online | offline` - Indicates the connections status.
|
|
298
|
+
- `isOnline`: `boolean` - Indicates whether the current device is online.
|
|
299
|
+
- `isOffline`: `boolean` - Indicates whether the current device is offline.
|
|
331
300
|
|
|
332
301
|
</details>
|
|
333
302
|
|
|
334
303
|
---
|
|
335
304
|
|
|
336
|
-
##### `useConnection`
|
|
337
|
-
|
|
338
|
-
Docs coming soon
|
|
339
|
-
|
|
340
|
-
---
|
|
341
305
|
|
|
342
306
|
##### `useDarkMode`
|
|
343
307
|
|
|
@@ -492,20 +456,26 @@ Just make sure to define both `light` and `dark` theme-color tags in your docume
|
|
|
492
456
|
|
|
493
457
|
---
|
|
494
458
|
|
|
495
|
-
##### `
|
|
496
|
-
|
|
497
|
-
Check if device is portrait oriented.
|
|
459
|
+
##### `useEventListener`
|
|
498
460
|
|
|
499
|
-
|
|
461
|
+
Attach a new Event listener to the `Window`, `Document`, `MediaQueryList` or an `HTMLElement`.
|
|
500
462
|
|
|
501
463
|
<details>
|
|
502
464
|
|
|
503
|
-
<summary style="cursor:pointer">
|
|
465
|
+
<summary style="cursor:pointer">Parameters</summary>
|
|
504
466
|
|
|
505
|
-
|
|
467
|
+
<details>
|
|
506
468
|
|
|
507
|
-
|
|
508
|
-
|
|
469
|
+
<summary style="cursor:pointer">Window events</summary>
|
|
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). |
|
|
509
479
|
|
|
510
480
|
</details>
|
|
511
481
|
|
|
@@ -513,33 +483,53 @@ Type: `boolean`
|
|
|
513
483
|
|
|
514
484
|
<details>
|
|
515
485
|
|
|
516
|
-
<summary style="cursor:pointer">
|
|
517
|
-
|
|
518
|
-
###### Check if user device is in landscape
|
|
519
|
-
|
|
520
|
-
```tsx
|
|
521
|
-
import { useIsPortrait } from '@alessiofrittoli/react-hooks'
|
|
486
|
+
<summary style="cursor:pointer">Document events</summary>
|
|
522
487
|
|
|
523
|
-
|
|
524
|
-
|
|
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). |
|
|
525
497
|
|
|
526
498
|
</details>
|
|
527
499
|
|
|
528
500
|
---
|
|
529
501
|
|
|
530
|
-
|
|
502
|
+
<details>
|
|
531
503
|
|
|
532
|
-
|
|
504
|
+
<summary style="cursor:pointer">HTMLElement events</summary>
|
|
533
505
|
|
|
534
|
-
|
|
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
|
+
|
|
516
|
+
</details>
|
|
517
|
+
|
|
518
|
+
---
|
|
535
519
|
|
|
536
520
|
<details>
|
|
537
521
|
|
|
538
|
-
<summary style="cursor:pointer">
|
|
522
|
+
<summary style="cursor:pointer">MediaQuery events</summary>
|
|
539
523
|
|
|
540
|
-
| Parameter | Type
|
|
541
|
-
|
|
542
|
-
| `
|
|
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). |
|
|
543
533
|
|
|
544
534
|
</details>
|
|
545
535
|
|
|
@@ -547,11 +537,19 @@ Prevent Element overflow.
|
|
|
547
537
|
|
|
548
538
|
<details>
|
|
549
539
|
|
|
550
|
-
<summary style="cursor:pointer">
|
|
540
|
+
<summary style="cursor:pointer">Custom events</summary>
|
|
551
541
|
|
|
552
|
-
|
|
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). |
|
|
553
551
|
|
|
554
|
-
|
|
552
|
+
</details>
|
|
555
553
|
|
|
556
554
|
</details>
|
|
557
555
|
|
|
@@ -561,176 +559,165 @@ A tuple with block and restore scroll callbacks.
|
|
|
561
559
|
|
|
562
560
|
<summary style="cursor:pointer">Usage</summary>
|
|
563
561
|
|
|
564
|
-
######
|
|
562
|
+
###### Attach listeners to the Window object
|
|
565
563
|
|
|
566
564
|
```tsx
|
|
567
|
-
|
|
565
|
+
'use client'
|
|
568
566
|
|
|
569
|
-
|
|
567
|
+
import { useCallback } from 'react'
|
|
568
|
+
import { useEventListener } from '@alessiofrittoli/react-hooks'
|
|
570
569
|
|
|
571
|
-
const
|
|
572
|
-
...
|
|
573
|
-
blockScroll()
|
|
574
|
-
}, [ blockScroll ] )
|
|
570
|
+
export const MyComponent: React.FC = () => {
|
|
575
571
|
|
|
576
|
-
|
|
577
|
-
|
|
578
|
-
|
|
579
|
-
}, [
|
|
572
|
+
useEventListener( 'popstate', {
|
|
573
|
+
listener: useCallback( event => {
|
|
574
|
+
...
|
|
575
|
+
}, [] ),
|
|
576
|
+
} )
|
|
580
577
|
|
|
581
|
-
|
|
578
|
+
}
|
|
582
579
|
```
|
|
583
580
|
|
|
584
581
|
---
|
|
585
582
|
|
|
586
|
-
######
|
|
583
|
+
###### Attach listeners to the Document object
|
|
587
584
|
|
|
588
585
|
```tsx
|
|
589
|
-
|
|
586
|
+
'use client'
|
|
590
587
|
|
|
591
|
-
|
|
588
|
+
import { useCallback } from 'react'
|
|
589
|
+
import { useEventListener } from '@alessiofrittoli/react-hooks'
|
|
592
590
|
|
|
593
|
-
const
|
|
594
|
-
...
|
|
595
|
-
blockScroll()
|
|
596
|
-
}, [ blockScroll ] )
|
|
591
|
+
export const MyComponent: React.FC = () => {
|
|
597
592
|
|
|
598
|
-
|
|
599
|
-
|
|
600
|
-
|
|
601
|
-
|
|
593
|
+
useEventListener( 'click', {
|
|
594
|
+
target : typeof document !== 'undefined' ? document : null,
|
|
595
|
+
listener : useCallback( event => {
|
|
596
|
+
...
|
|
597
|
+
}, [] ),
|
|
598
|
+
} )
|
|
602
599
|
|
|
603
|
-
|
|
600
|
+
}
|
|
604
601
|
```
|
|
605
602
|
|
|
606
|
-
</details>
|
|
607
|
-
|
|
608
603
|
---
|
|
609
604
|
|
|
610
|
-
|
|
605
|
+
###### Attach listeners to an HTMLElement
|
|
611
606
|
|
|
612
|
-
|
|
607
|
+
```tsx
|
|
608
|
+
'use client'
|
|
613
609
|
|
|
614
|
-
|
|
610
|
+
import { useCallback, useRef } from 'react'
|
|
611
|
+
import { useEventListener } from '@alessiofrittoli/react-hooks'
|
|
615
612
|
|
|
616
|
-
|
|
613
|
+
export const MyComponent: React.FC = () => {
|
|
617
614
|
|
|
618
|
-
|
|
615
|
+
const buttonRef = useRef<HTMLButtonElement>( null )
|
|
619
616
|
|
|
620
|
-
|
|
621
|
-
|
|
622
|
-
|
|
623
|
-
|
|
617
|
+
useEventListener( 'click', {
|
|
618
|
+
target: buttonRef,
|
|
619
|
+
listener: useCallback( event => {
|
|
620
|
+
...
|
|
621
|
+
}, [] ),
|
|
622
|
+
} )
|
|
624
623
|
|
|
625
|
-
|
|
624
|
+
return (
|
|
625
|
+
<button ref={ buttonRef }>Button</button>
|
|
626
|
+
)
|
|
626
627
|
|
|
627
|
-
|
|
628
|
+
}
|
|
629
|
+
```
|
|
628
630
|
|
|
629
|
-
|
|
631
|
+
---
|
|
630
632
|
|
|
631
|
-
|
|
633
|
+
###### Attach listeners to a MediaQueryList
|
|
632
634
|
|
|
633
|
-
|
|
635
|
+
```tsx
|
|
636
|
+
import { useCallback } from 'react'
|
|
637
|
+
import { useEventListener } from '@alessiofrittoli/react-hooks'
|
|
634
638
|
|
|
635
|
-
|
|
639
|
+
export const MyComponent: React.FC = () => {
|
|
636
640
|
|
|
637
|
-
|
|
638
|
-
-
|
|
641
|
+
useEventListener( 'change', {
|
|
642
|
+
query : '(max-width: 768px)',
|
|
643
|
+
listener : useCallback( event => {
|
|
644
|
+
if ( event.matches ) {
|
|
645
|
+
...
|
|
646
|
+
}
|
|
647
|
+
}, [] )
|
|
648
|
+
} )
|
|
639
649
|
|
|
640
|
-
|
|
650
|
+
}
|
|
651
|
+
```
|
|
641
652
|
|
|
642
653
|
---
|
|
643
654
|
|
|
644
|
-
|
|
655
|
+
###### Listen dispatched custom events
|
|
645
656
|
|
|
646
|
-
|
|
657
|
+
```tsx
|
|
658
|
+
import { useCallback } from 'react'
|
|
659
|
+
import { useEventListener } from '@alessiofrittoli/react-hooks'
|
|
647
660
|
|
|
648
|
-
|
|
661
|
+
class CustomEvent extends Event
|
|
662
|
+
{
|
|
663
|
+
isCustom: boolean
|
|
649
664
|
|
|
650
|
-
|
|
651
|
-
|
|
665
|
+
constructor( type: string, eventInitDict?: EventInit )
|
|
666
|
+
{
|
|
667
|
+
super( type, eventInitDict )
|
|
668
|
+
this.isCustom = true
|
|
669
|
+
}
|
|
670
|
+
}
|
|
652
671
|
|
|
653
|
-
const modalRef = useRef<HTMLDivElement>( null )
|
|
654
|
-
const [ setFocusTrap, restoreFocusTrap ] = useFocusTrap( modalRef )
|
|
655
672
|
|
|
656
|
-
|
|
657
|
-
|
|
658
|
-
|
|
659
|
-
setFocusTrap()
|
|
660
|
-
modalRef.current.focus() // focus the dialog so next tab will focus the next element inside the modal
|
|
661
|
-
}, [ setFocusTrap ] )
|
|
673
|
+
type CustomEventMap = {
|
|
674
|
+
customEventName: CustomEvent
|
|
675
|
+
}
|
|
662
676
|
|
|
663
|
-
const modalCloseHandler = useCallback( () => {
|
|
664
|
-
// ... close modal
|
|
665
|
-
restoreFocusTrap() // cancel focus trap and restore focus to the last active element before enablig the focus trap
|
|
666
|
-
}, [ restoreFocusTrap ] )
|
|
667
|
-
```
|
|
668
677
|
|
|
669
|
-
|
|
678
|
+
export const MyComponent: React.FC = () => {
|
|
670
679
|
|
|
671
|
-
|
|
680
|
+
const clickHandler = useCallback( () => {
|
|
681
|
+
document.dispatchEvent( new CustomEvent( 'customEventName' ) )
|
|
682
|
+
}, [] )
|
|
672
683
|
|
|
673
|
-
|
|
674
|
-
|
|
684
|
+
useEventListener<CustomEventMap>( 'customEventName', {
|
|
685
|
+
target : typeof document !== 'undefined' ? document : null,
|
|
686
|
+
listener : useCallback( event => {
|
|
687
|
+
if ( event.isCustom ) {
|
|
688
|
+
...
|
|
689
|
+
}
|
|
690
|
+
}, [] )
|
|
691
|
+
} )
|
|
675
692
|
|
|
676
|
-
const modalRef = useRef<HTMLDivElement>( null )
|
|
677
|
-
const modal2Ref = useRef<HTMLDivElement>( null )
|
|
678
|
-
const [ setFocusTrap, restoreFocusTrap ] = useFocusTrap()
|
|
679
693
|
|
|
680
|
-
|
|
681
|
-
|
|
682
|
-
|
|
683
|
-
setFocusTrap( modalRef.current )
|
|
684
|
-
modalRef.current.focus()
|
|
685
|
-
}, [ setFocusTrap ] )
|
|
694
|
+
return (
|
|
695
|
+
<button onClick={ clickHandler }>Click me to dispatch custom event</button>
|
|
696
|
+
)
|
|
686
697
|
|
|
687
|
-
|
|
688
|
-
if ( ! modal2Ref.current ) return
|
|
689
|
-
// ... open modal
|
|
690
|
-
setFocusTrap( modal2Ref.current )
|
|
691
|
-
modal2Ref.current.focus()
|
|
692
|
-
}, [ setFocusTrap ] )
|
|
698
|
+
}
|
|
693
699
|
```
|
|
694
700
|
|
|
701
|
+
---
|
|
702
|
+
|
|
695
703
|
</details>
|
|
696
704
|
|
|
697
705
|
---
|
|
698
706
|
|
|
699
|
-
##### `
|
|
707
|
+
##### `useIsPortrait`
|
|
700
708
|
|
|
701
|
-
Check if
|
|
709
|
+
Check if device is portrait oriented.
|
|
710
|
+
|
|
711
|
+
React State get updated when device orientation changes.
|
|
702
712
|
|
|
703
713
|
<details>
|
|
704
714
|
|
|
705
|
-
<summary style="cursor:pointer">
|
|
715
|
+
<summary style="cursor:pointer">Returns</summary>
|
|
706
716
|
|
|
707
|
-
|
|
708
|
-
|
|
709
|
-
|
|
710
|
-
|
|
711
|
-
| `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. |
|
|
712
|
-
| `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. |
|
|
713
|
-
| `options.amount` | `'all'\|'some'\|number\|number[]` | (Optional) The intersecting target thresholds. |
|
|
714
|
-
| | | Threshold can be set to: |
|
|
715
|
-
| | | - `all` - `1` will be used. |
|
|
716
|
-
| | | - `some` - `0.5` will be used. |
|
|
717
|
-
| | | - `number` |
|
|
718
|
-
| | | - `number[]` |
|
|
719
|
-
| `options.once` | `boolean` | (Optional) By setting this to `true` the observer will be disconnected after the target Element enters the viewport. |
|
|
720
|
-
| `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`. |
|
|
721
|
-
| `options.enable` | `boolean` | (Optional) Defines the initial observation activity. Use the returned `setEnabled` to update this state. Default: `true`. |
|
|
722
|
-
| `options.onIntersect` | `OnIntersectStateHandler` | (Optional) A custom callback executed when target element's visibility has crossed one or more thresholds. |
|
|
723
|
-
| | | This callback is awaited before any state update. |
|
|
724
|
-
| | | If an error is thrown the React State update won't be fired. |
|
|
725
|
-
| | | ⚠️ Wrap your callback with `useCallback` to avoid unnecessary `IntersectionObserver` recreation. |
|
|
726
|
-
| `options.onEnter` | `OnIntersectHandler` | (Optional) A custom callback executed when target element's visibility has crossed one or more thresholds. |
|
|
727
|
-
| | | This callback is awaited before any state update. |
|
|
728
|
-
| | | If an error is thrown the React State update won't be fired. |
|
|
729
|
-
| | | ⚠️ Wrap your callback with `useCallback` to avoid unnecessary `IntersectionObserver` recreation. |
|
|
730
|
-
| `options.onExit` | `OnIntersectHandler` | (Optional) A custom callback executed when target element's visibility has crossed one or more thresholds. |
|
|
731
|
-
| | | This callback is awaited before any state update. |
|
|
732
|
-
| | | If an error is thrown the React State update won't be fired. |
|
|
733
|
-
| | | ⚠️ Wrap your callback with `useCallback` to avoid unnecessary `IntersectionObserver` recreation. |
|
|
717
|
+
Type: `boolean`
|
|
718
|
+
|
|
719
|
+
- `true` if the device is portrait oriented.
|
|
720
|
+
- `false` otherwise.
|
|
734
721
|
|
|
735
722
|
</details>
|
|
736
723
|
|
|
@@ -738,9 +725,220 @@ Check if the given target Element is intersecting with an ancestor Element or wi
|
|
|
738
725
|
|
|
739
726
|
<details>
|
|
740
727
|
|
|
741
|
-
<summary style="cursor:pointer">
|
|
728
|
+
<summary style="cursor:pointer">Usage</summary>
|
|
742
729
|
|
|
743
|
-
|
|
730
|
+
###### Check if user device is in landscape
|
|
731
|
+
|
|
732
|
+
```tsx
|
|
733
|
+
import { useIsPortrait } from '@alessiofrittoli/react-hooks'
|
|
734
|
+
|
|
735
|
+
const isLandscape = ! useIsPortrait()
|
|
736
|
+
```
|
|
737
|
+
|
|
738
|
+
</details>
|
|
739
|
+
|
|
740
|
+
---
|
|
741
|
+
|
|
742
|
+
##### `useMediaQuery`
|
|
743
|
+
|
|
744
|
+
Get Document Media matches and listen for changes.
|
|
745
|
+
|
|
746
|
+
<details>
|
|
747
|
+
|
|
748
|
+
<summary style="cursor:pointer">Parameters</summary>
|
|
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`. |
|
|
757
|
+
|
|
758
|
+
</details>
|
|
759
|
+
|
|
760
|
+
---
|
|
761
|
+
|
|
762
|
+
<details>
|
|
763
|
+
|
|
764
|
+
<summary style="cursor:pointer">Returns</summary>
|
|
765
|
+
|
|
766
|
+
Type: `boolean|void`
|
|
767
|
+
|
|
768
|
+
- `true` or `false` if the document currently matches the media query list or not.
|
|
769
|
+
- `void` if `updateState` is set to `false`.
|
|
770
|
+
|
|
771
|
+
</details>
|
|
772
|
+
|
|
773
|
+
---
|
|
774
|
+
|
|
775
|
+
<details>
|
|
776
|
+
|
|
777
|
+
<summary style="cursor:pointer">Usage</summary>
|
|
778
|
+
|
|
779
|
+
###### Check if user device prefers dark color scheme
|
|
780
|
+
|
|
781
|
+
```tsx
|
|
782
|
+
import { useMediaQuery } from '@alessiofrittoli/react-hooks'
|
|
783
|
+
|
|
784
|
+
const isDarkOS = useMediaQuery( '(prefers-color-scheme: dark)' )
|
|
785
|
+
```
|
|
786
|
+
|
|
787
|
+
---
|
|
788
|
+
|
|
789
|
+
###### Listen changes with no state updates
|
|
790
|
+
|
|
791
|
+
```tsx
|
|
792
|
+
import { useMediaQuery } from '@alessiofrittoli/react-hooks'
|
|
793
|
+
|
|
794
|
+
useMediaQuery( '(prefers-color-scheme: dark)', {
|
|
795
|
+
updateState: false,
|
|
796
|
+
onChange( matches ) {
|
|
797
|
+
console.log( 'is dark OS?', matches )
|
|
798
|
+
}
|
|
799
|
+
} )
|
|
800
|
+
```
|
|
801
|
+
|
|
802
|
+
</details>
|
|
803
|
+
|
|
804
|
+
---
|
|
805
|
+
|
|
806
|
+
#### DOM API
|
|
807
|
+
|
|
808
|
+
##### `useFocusTrap`
|
|
809
|
+
|
|
810
|
+
Trap focus inside the given HTML Element.
|
|
811
|
+
|
|
812
|
+
This comes pretty handy when rendering a modal that shouldn't be closed without a user required action.
|
|
813
|
+
|
|
814
|
+
<details>
|
|
815
|
+
|
|
816
|
+
<summary style="cursor:pointer">Parameters</summary>
|
|
817
|
+
|
|
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`. |
|
|
822
|
+
|
|
823
|
+
</details>
|
|
824
|
+
|
|
825
|
+
---
|
|
826
|
+
|
|
827
|
+
<details>
|
|
828
|
+
|
|
829
|
+
<summary style="cursor:pointer">Returns</summary>
|
|
830
|
+
|
|
831
|
+
Type: `readonly [ SetFocusTrap, RestoreFocusTrap ]`
|
|
832
|
+
|
|
833
|
+
A tuple containing:
|
|
834
|
+
|
|
835
|
+
- `setFocusTrap`: A function to enable the focus trap. Optionally accept an HTMLElement as target.
|
|
836
|
+
- `restoreFocusTrap`: A function to restore the previous focus state.
|
|
837
|
+
|
|
838
|
+
</details>
|
|
839
|
+
|
|
840
|
+
---
|
|
841
|
+
|
|
842
|
+
<details>
|
|
843
|
+
|
|
844
|
+
<summary style="cursor:pointer">Usage</summary>
|
|
845
|
+
|
|
846
|
+
###### Defining the target on hook initialization
|
|
847
|
+
|
|
848
|
+
```tsx
|
|
849
|
+
import { useFocusTrap } from '@alessiofrittoli/react-hooks'
|
|
850
|
+
|
|
851
|
+
const modalRef = useRef<HTMLDivElement>( null )
|
|
852
|
+
const [ setFocusTrap, restoreFocusTrap ] = useFocusTrap( modalRef )
|
|
853
|
+
|
|
854
|
+
const modalOpenHandler = useCallback( () => {
|
|
855
|
+
if ( ! modalRef.current ) return
|
|
856
|
+
// ... open modal
|
|
857
|
+
setFocusTrap()
|
|
858
|
+
modalRef.current.focus() // focus the dialog so next tab will focus the next element inside the modal
|
|
859
|
+
}, [ setFocusTrap ] )
|
|
860
|
+
|
|
861
|
+
const modalCloseHandler = useCallback( () => {
|
|
862
|
+
// ... close modal
|
|
863
|
+
restoreFocusTrap() // cancel focus trap and restore focus to the last active element before enablig the focus trap
|
|
864
|
+
}, [ restoreFocusTrap ] )
|
|
865
|
+
```
|
|
866
|
+
|
|
867
|
+
---
|
|
868
|
+
|
|
869
|
+
###### Defining the target ondemand
|
|
870
|
+
|
|
871
|
+
```tsx
|
|
872
|
+
import { useFocusTrap } from '@alessiofrittoli/react-hooks'
|
|
873
|
+
|
|
874
|
+
const modalRef = useRef<HTMLDivElement>( null )
|
|
875
|
+
const modal2Ref = useRef<HTMLDivElement>( null )
|
|
876
|
+
const [ setFocusTrap, restoreFocusTrap ] = useFocusTrap()
|
|
877
|
+
|
|
878
|
+
const modalOpenHandler = useCallback( () => {
|
|
879
|
+
if ( ! modalRef.current ) return
|
|
880
|
+
// ... open modal
|
|
881
|
+
setFocusTrap( modalRef.current )
|
|
882
|
+
modalRef.current.focus()
|
|
883
|
+
}, [ setFocusTrap ] )
|
|
884
|
+
|
|
885
|
+
const modal2OpenHandler = useCallback( () => {
|
|
886
|
+
if ( ! modal2Ref.current ) return
|
|
887
|
+
// ... open modal
|
|
888
|
+
setFocusTrap( modal2Ref.current )
|
|
889
|
+
modal2Ref.current.focus()
|
|
890
|
+
}, [ setFocusTrap ] )
|
|
891
|
+
```
|
|
892
|
+
|
|
893
|
+
</details>
|
|
894
|
+
|
|
895
|
+
---
|
|
896
|
+
|
|
897
|
+
##### `useInView`
|
|
898
|
+
|
|
899
|
+
Check if the given target Element is intersecting with an ancestor Element or with a top-level document's viewport.
|
|
900
|
+
|
|
901
|
+
<details>
|
|
902
|
+
|
|
903
|
+
<summary style="cursor:pointer">Parameters</summary>
|
|
904
|
+
|
|
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. |
|
|
932
|
+
|
|
933
|
+
</details>
|
|
934
|
+
|
|
935
|
+
---
|
|
936
|
+
|
|
937
|
+
<details>
|
|
938
|
+
|
|
939
|
+
<summary style="cursor:pointer">Returns</summary>
|
|
940
|
+
|
|
941
|
+
Type: `UseInViewReturnType`
|
|
744
942
|
|
|
745
943
|
An object containing:
|
|
746
944
|
|
|
@@ -956,45 +1154,17 @@ const AsyncStartExample: React.FC = () => {
|
|
|
956
1154
|
|
|
957
1155
|
---
|
|
958
1156
|
|
|
959
|
-
|
|
960
|
-
|
|
961
|
-
---
|
|
962
|
-
|
|
963
|
-
##### `useInput`
|
|
964
|
-
|
|
965
|
-
Docs coming soon
|
|
966
|
-
|
|
967
|
-
---
|
|
968
|
-
|
|
969
|
-
##### `useDeferCallback`
|
|
970
|
-
|
|
971
|
-
`useDeferCallback` will return a memoized and deferred version of the callback that only changes if one of the `inputs` in the dependency list has changed.
|
|
972
|
-
|
|
973
|
-
Since [`deferCallback`](https://npmjs.com/package/@alessiofrittoli/web-utils?activeTab=readme#deferCallback) returns a new function when called, it may cause your child components to uselessly re-validate when a state update occurs in the main component.
|
|
974
|
-
To avoid these pitfalls you can memoize and defer your task with `useDeferCallback`.
|
|
975
|
-
|
|
976
|
-
Take a look at [`deferTask`](https://npmjs.com/package/@alessiofrittoli/web-utils?activeTab=readme#deferTask) to defer single tasks in a function handler.
|
|
977
|
-
|
|
978
|
-
<details>
|
|
979
|
-
|
|
980
|
-
<summary style="cursor:pointer">Type Parameters</summary>
|
|
981
|
-
|
|
982
|
-
| Parameter | Description |
|
|
983
|
-
|-----------|------------------------------|
|
|
984
|
-
| `T` | The task function definition. `unknown` types will be inherited by your function type definition. |
|
|
985
|
-
| `U` | The task function arguments. `unknown` types will be inherited by your function type. |
|
|
986
|
-
|
|
987
|
-
</details>
|
|
1157
|
+
##### `useScrollBlock`
|
|
988
1158
|
|
|
989
|
-
|
|
1159
|
+
Prevent Element overflow.
|
|
990
1160
|
|
|
991
1161
|
<details>
|
|
992
1162
|
|
|
993
1163
|
<summary style="cursor:pointer">Parameters</summary>
|
|
994
1164
|
|
|
995
|
-
| Parameter | Type
|
|
996
|
-
|
|
997
|
-
| `
|
|
1165
|
+
| Parameter | Type | Default | Description |
|
|
1166
|
+
|-----------|------|---------|-------------|
|
|
1167
|
+
| `target` | `React.RefObject<HTMLElement\|null>` | `Document.documentElement` | (Optional) The React RefObject target HTMLElement. |
|
|
998
1168
|
|
|
999
1169
|
</details>
|
|
1000
1170
|
|
|
@@ -1004,9 +1174,9 @@ Take a look at [`deferTask`](https://npmjs.com/package/@alessiofrittoli/web-util
|
|
|
1004
1174
|
|
|
1005
1175
|
<summary style="cursor:pointer">Returns</summary>
|
|
1006
1176
|
|
|
1007
|
-
Type: `(
|
|
1177
|
+
Type: `[ () => void, () => void ]`
|
|
1008
1178
|
|
|
1009
|
-
A
|
|
1179
|
+
A tuple with block and restore scroll callbacks.
|
|
1010
1180
|
|
|
1011
1181
|
</details>
|
|
1012
1182
|
|
|
@@ -1016,44 +1186,109 @@ A new memoized handler which returns a new Promise that returns the `task` resul
|
|
|
1016
1186
|
|
|
1017
1187
|
<summary style="cursor:pointer">Usage</summary>
|
|
1018
1188
|
|
|
1189
|
+
###### Block Document Overflow
|
|
1190
|
+
|
|
1019
1191
|
```tsx
|
|
1020
|
-
|
|
1192
|
+
import { useScrollBlock } from '@alessiofrittoli/react-hooks'
|
|
1021
1193
|
|
|
1022
|
-
|
|
1023
|
-
event => { ... }, []
|
|
1024
|
-
)
|
|
1194
|
+
const [ blockScroll, restoreScroll ] = useScrollBlock()
|
|
1025
1195
|
|
|
1026
|
-
|
|
1027
|
-
|
|
1028
|
-
)
|
|
1196
|
+
const openPopUpHandler = useCallback( () => {
|
|
1197
|
+
...
|
|
1198
|
+
blockScroll()
|
|
1199
|
+
}, [ blockScroll ] )
|
|
1029
1200
|
|
|
1030
|
-
|
|
1201
|
+
const closePopUpHandler = useCallback( () => {
|
|
1202
|
+
...
|
|
1203
|
+
restoreScroll()
|
|
1204
|
+
}, [ restoreScroll ] )
|
|
1205
|
+
|
|
1206
|
+
...
|
|
1207
|
+
```
|
|
1208
|
+
|
|
1209
|
+
---
|
|
1210
|
+
|
|
1211
|
+
###### Block HTML Element Overflow
|
|
1212
|
+
|
|
1213
|
+
```tsx
|
|
1214
|
+
const elementRef = useRef<HTMLDivElement>( null )
|
|
1215
|
+
|
|
1216
|
+
const [ blockScroll, restoreScroll ] = useScrollBlock( elementRef )
|
|
1217
|
+
|
|
1218
|
+
const scrollBlockHandler = useCallback( () => {
|
|
1219
|
+
...
|
|
1220
|
+
blockScroll()
|
|
1221
|
+
}, [ blockScroll ] )
|
|
1222
|
+
|
|
1223
|
+
const scrollRestoreHandler = useCallback( () => {
|
|
1224
|
+
...
|
|
1225
|
+
restoreScroll()
|
|
1226
|
+
}, [ restoreScroll ] )
|
|
1227
|
+
|
|
1228
|
+
...
|
|
1031
1229
|
```
|
|
1032
1230
|
|
|
1033
1231
|
</details>
|
|
1034
1232
|
|
|
1035
1233
|
---
|
|
1036
1234
|
|
|
1037
|
-
|
|
1235
|
+
#### Miscellaneous
|
|
1236
|
+
|
|
1237
|
+
##### `useInput`
|
|
1238
|
+
|
|
1239
|
+
Handle input states with ease.
|
|
1240
|
+
|
|
1241
|
+
<details>
|
|
1242
|
+
|
|
1243
|
+
<summary style="cursor:pointer">Type Parameters</summary>
|
|
1244
|
+
|
|
1245
|
+
| Parameter | Description |
|
|
1246
|
+
|-----------|------------------------|
|
|
1247
|
+
| `I` | The input value type. |
|
|
1248
|
+
| `O` | The output value type. |
|
|
1038
1249
|
|
|
1039
|
-
|
|
1250
|
+
</details>
|
|
1040
1251
|
|
|
1041
1252
|
---
|
|
1042
1253
|
|
|
1043
|
-
|
|
1254
|
+
<details>
|
|
1044
1255
|
|
|
1045
|
-
|
|
1256
|
+
<summary style="cursor:pointer">Parameters</summary>
|
|
1046
1257
|
|
|
1047
|
-
|
|
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. |
|
|
1267
|
+
|
|
1268
|
+
</details>
|
|
1269
|
+
|
|
1270
|
+
---
|
|
1048
1271
|
|
|
1049
1272
|
<details>
|
|
1050
1273
|
|
|
1051
1274
|
<summary style="cursor:pointer">Returns</summary>
|
|
1052
1275
|
|
|
1053
|
-
Type: `
|
|
1276
|
+
Type: `UseInputOutput<I, O>`
|
|
1054
1277
|
|
|
1055
|
-
|
|
1056
|
-
|
|
1278
|
+
An object containing the following properties:
|
|
1279
|
+
|
|
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. |
|
|
1057
1292
|
|
|
1058
1293
|
</details>
|
|
1059
1294
|
|
|
@@ -1066,16 +1301,93 @@ Type: `boolean`
|
|
|
1066
1301
|
###### Basic usage
|
|
1067
1302
|
|
|
1068
1303
|
```tsx
|
|
1069
|
-
|
|
1304
|
+
const MyComponent: React.FC = () => {
|
|
1070
1305
|
|
|
1071
|
-
|
|
1306
|
+
const input = useInput<string>()
|
|
1072
1307
|
|
|
1073
|
-
|
|
1308
|
+
return (
|
|
1309
|
+
<input
|
|
1310
|
+
type='text'
|
|
1311
|
+
value={ input.value || '' }
|
|
1312
|
+
onChange={ input.changeHandler }
|
|
1313
|
+
onBlur={ input.blurHandler }
|
|
1314
|
+
/>
|
|
1315
|
+
)
|
|
1074
1316
|
|
|
1075
|
-
|
|
1317
|
+
}
|
|
1318
|
+
```
|
|
1319
|
+
|
|
1320
|
+
---
|
|
1321
|
+
|
|
1322
|
+
###### Displaying custom error messages
|
|
1323
|
+
|
|
1324
|
+
```tsx
|
|
1325
|
+
import { useInput, type ValidateValueHandler } from '@alessiofrittoli/react-hooks'
|
|
1326
|
+
|
|
1327
|
+
const isNotEmpty: ValidateValueHandler<string> = value => (
|
|
1328
|
+
! value ? false : value.trim().length > 0
|
|
1329
|
+
)
|
|
1330
|
+
|
|
1331
|
+
const MyComponent: React.FC = () => {
|
|
1332
|
+
|
|
1333
|
+
const input = useInput<string>( {
|
|
1334
|
+
validate: isNotEmpty,
|
|
1335
|
+
} )
|
|
1076
1336
|
|
|
1077
1337
|
return (
|
|
1078
|
-
|
|
1338
|
+
<>
|
|
1339
|
+
<input
|
|
1340
|
+
value={ input.value || '' }
|
|
1341
|
+
onChange={ input.changeHandler }
|
|
1342
|
+
onBlur={ input.blurHandler }
|
|
1343
|
+
/>
|
|
1344
|
+
{ input.hasError && (
|
|
1345
|
+
<span>The input cannot be empty.</span>
|
|
1346
|
+
) }
|
|
1347
|
+
</>
|
|
1348
|
+
)
|
|
1349
|
+
|
|
1350
|
+
}
|
|
1351
|
+
```
|
|
1352
|
+
|
|
1353
|
+
---
|
|
1354
|
+
|
|
1355
|
+
###### Parsing and validating parsed value
|
|
1356
|
+
|
|
1357
|
+
```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
|
+
|
|
1365
|
+
|
|
1366
|
+
const validateInputDate: ValidateValueHandler<Date> = value => (
|
|
1367
|
+
isValidDate( value ) && value.getTime() > Date.now()
|
|
1368
|
+
)
|
|
1369
|
+
|
|
1370
|
+
|
|
1371
|
+
const MyComponent: React.FC = () => {
|
|
1372
|
+
|
|
1373
|
+
const input = useInput<string, Date>( {
|
|
1374
|
+
parse : parseStringToDate,
|
|
1375
|
+
validate : validateInputDate,
|
|
1376
|
+
} )
|
|
1377
|
+
|
|
1378
|
+
|
|
1379
|
+
return (
|
|
1380
|
+
<>
|
|
1381
|
+
<input
|
|
1382
|
+
type='datetime-local'
|
|
1383
|
+
value={ input.value ? formatDate( input.value, 'Y-m-dTH:i' ) : '' }
|
|
1384
|
+
onChange={ input.changeHandler }
|
|
1385
|
+
onBlur={ input.blurHandler }
|
|
1386
|
+
/>
|
|
1387
|
+
{ input.hasError && (
|
|
1388
|
+
<span>Please choose a date no earlier than today</span>
|
|
1389
|
+
) }
|
|
1390
|
+
</>
|
|
1079
1391
|
)
|
|
1080
1392
|
|
|
1081
1393
|
}
|
|
@@ -1085,20 +1397,47 @@ export const ClientComponent: React.FC = () => {
|
|
|
1085
1397
|
|
|
1086
1398
|
---
|
|
1087
1399
|
|
|
1088
|
-
##### `
|
|
1400
|
+
##### `useDeferCallback`
|
|
1089
1401
|
|
|
1090
|
-
|
|
1402
|
+
`useDeferCallback` will return a memoized and deferred version of the callback that only changes if one of the `inputs` in the dependency list has changed.
|
|
1403
|
+
|
|
1404
|
+
Since [`deferCallback`](https://npmjs.com/package/@alessiofrittoli/web-utils?activeTab=readme#deferCallback) returns a new function when called, it may cause your child components to uselessly re-validate when a state update occurs in the main component.
|
|
1405
|
+
To avoid these pitfalls you can memoize and defer your task with `useDeferCallback`.
|
|
1406
|
+
|
|
1407
|
+
Take a look at [`deferTask`](https://npmjs.com/package/@alessiofrittoli/web-utils?activeTab=readme#deferTask) to defer single tasks in a function handler.
|
|
1091
1408
|
|
|
1092
1409
|
<details>
|
|
1093
1410
|
|
|
1094
|
-
<summary style="cursor:pointer">
|
|
1411
|
+
<summary style="cursor:pointer">Type Parameters</summary>
|
|
1095
1412
|
|
|
1096
|
-
|
|
1413
|
+
| Parameter | Description |
|
|
1414
|
+
|-----------|------------------------------|
|
|
1415
|
+
| `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. |
|
|
1097
1417
|
|
|
1098
|
-
|
|
1099
|
-
- `false` otherwise.
|
|
1418
|
+
</details>
|
|
1100
1419
|
|
|
1101
|
-
|
|
1420
|
+
---
|
|
1421
|
+
|
|
1422
|
+
<details>
|
|
1423
|
+
|
|
1424
|
+
<summary style="cursor:pointer">Parameters</summary>
|
|
1425
|
+
|
|
1426
|
+
| Parameter | Type | Description |
|
|
1427
|
+
|-----------|----------|-----------------------------|
|
|
1428
|
+
| `task` | `T` | The task callable function. |
|
|
1429
|
+
|
|
1430
|
+
</details>
|
|
1431
|
+
|
|
1432
|
+
---
|
|
1433
|
+
|
|
1434
|
+
<details>
|
|
1435
|
+
|
|
1436
|
+
<summary style="cursor:pointer">Returns</summary>
|
|
1437
|
+
|
|
1438
|
+
Type: `( ...args: U ) => Promise<Awaited<ReturnType<T>>>`
|
|
1439
|
+
|
|
1440
|
+
A new memoized handler which returns a new Promise that returns the `task` result once fulfilled.
|
|
1102
1441
|
|
|
1103
1442
|
</details>
|
|
1104
1443
|
|
|
@@ -1108,31 +1447,70 @@ Note that if the React Hook/Component has no state updates, `useIsFirstRender` w
|
|
|
1108
1447
|
|
|
1109
1448
|
<summary style="cursor:pointer">Usage</summary>
|
|
1110
1449
|
|
|
1111
|
-
|
|
1450
|
+
```tsx
|
|
1451
|
+
const MyComponent: React.FC = () => {
|
|
1452
|
+
|
|
1453
|
+
const clickHandler = useDeferCallback<React.MouseEventHandler>(
|
|
1454
|
+
event => { ... }, []
|
|
1455
|
+
)
|
|
1456
|
+
|
|
1457
|
+
return (
|
|
1458
|
+
<button onClick={ clickHandler }>Button</button>
|
|
1459
|
+
)
|
|
1460
|
+
|
|
1461
|
+
}
|
|
1462
|
+
```
|
|
1463
|
+
|
|
1464
|
+
</details>
|
|
1465
|
+
|
|
1466
|
+
---
|
|
1467
|
+
|
|
1468
|
+
##### `useEffectOnce`
|
|
1469
|
+
|
|
1470
|
+
Modified version of `useEffect` that only run once on intial load.
|
|
1471
|
+
|
|
1472
|
+
<details>
|
|
1473
|
+
|
|
1474
|
+
<summary style="cursor:pointer">Parameters</summary>
|
|
1475
|
+
|
|
1476
|
+
| Parameter | Type | Description |
|
|
1477
|
+
|-----------|------------------------|-------------|
|
|
1478
|
+
| `effect` | `React.EffectCallback` | Imperative function that can return a cleanup function. |
|
|
1479
|
+
|
|
1480
|
+
</details>
|
|
1481
|
+
|
|
1482
|
+
---
|
|
1483
|
+
|
|
1484
|
+
<details>
|
|
1485
|
+
|
|
1486
|
+
<summary style="cursor:pointer">Usage</summary>
|
|
1112
1487
|
|
|
1113
1488
|
```tsx
|
|
1114
1489
|
'use client'
|
|
1115
1490
|
|
|
1116
|
-
import {
|
|
1491
|
+
import { useEffect, useState } from 'react'
|
|
1492
|
+
import { useEffectOnce } from '@alessiofrittoli/react-hooks'
|
|
1117
1493
|
|
|
1118
1494
|
export const ClientComponent: React.FC = () => {
|
|
1119
1495
|
|
|
1120
|
-
const
|
|
1121
|
-
const [ counter, setCounter ] = useState( 0 )
|
|
1496
|
+
const [ count, setCount ] = useState( 0 )
|
|
1122
1497
|
|
|
1123
1498
|
useEffect( () => {
|
|
1124
1499
|
const intv = setInterval( () => {
|
|
1125
|
-
|
|
1500
|
+
setCount( prev => prev + 1 ) // update state each 1s
|
|
1126
1501
|
}, 1000 )
|
|
1127
1502
|
return () => clearInterval( intv )
|
|
1128
1503
|
}, [] )
|
|
1129
1504
|
|
|
1505
|
+
useEffectOnce( () => {
|
|
1506
|
+
console.log( 'Component did mount' )
|
|
1507
|
+
return () => {
|
|
1508
|
+
console.log( 'Component did unmount' )
|
|
1509
|
+
}
|
|
1510
|
+
} )
|
|
1511
|
+
|
|
1130
1512
|
return (
|
|
1131
|
-
<div>
|
|
1132
|
-
{ isFirstRender ? 'First render' : 'Subsequent render' }
|
|
1133
|
-
<hr />
|
|
1134
|
-
{ counter }
|
|
1135
|
-
</div>
|
|
1513
|
+
<div>{ count }</div>
|
|
1136
1514
|
)
|
|
1137
1515
|
|
|
1138
1516
|
}
|
|
@@ -1163,8 +1541,6 @@ Modified version of `useEffect` that skips the first render.
|
|
|
1163
1541
|
|
|
1164
1542
|
<summary style="cursor:pointer">Usage</summary>
|
|
1165
1543
|
|
|
1166
|
-
###### Basic usage
|
|
1167
|
-
|
|
1168
1544
|
```tsx
|
|
1169
1545
|
'use client'
|
|
1170
1546
|
|
|
@@ -1207,19 +1583,707 @@ export const ClientComponent: React.FC = () => {
|
|
|
1207
1583
|
|
|
1208
1584
|
---
|
|
1209
1585
|
|
|
1210
|
-
##### `
|
|
1586
|
+
##### `useIsClient`
|
|
1211
1587
|
|
|
1212
|
-
|
|
1588
|
+
Check if the React Hook or Component where this hook is executed is running in a browser environment.
|
|
1213
1589
|
|
|
1214
|
-
This
|
|
1590
|
+
This is pretty usefull to avoid hydration errors.
|
|
1215
1591
|
|
|
1216
|
-
|
|
1592
|
+
<details>
|
|
1593
|
+
|
|
1594
|
+
<summary style="cursor:pointer">Returns</summary>
|
|
1595
|
+
|
|
1596
|
+
Type: `boolean`
|
|
1597
|
+
|
|
1598
|
+
- `true` if the React Hook or Component is running in a browser environment.
|
|
1599
|
+
- `false` otherwise.
|
|
1600
|
+
|
|
1601
|
+
</details>
|
|
1217
1602
|
|
|
1218
1603
|
---
|
|
1219
1604
|
|
|
1220
|
-
|
|
1605
|
+
<details>
|
|
1606
|
+
|
|
1607
|
+
<summary style="cursor:pointer">Usage</summary>
|
|
1221
1608
|
|
|
1222
|
-
|
|
1609
|
+
```tsx
|
|
1610
|
+
'use client'
|
|
1611
|
+
|
|
1612
|
+
import { useIsClient } from '@alessiofrittoli/react-hooks'
|
|
1613
|
+
|
|
1614
|
+
export const ClientComponent: React.FC = () => {
|
|
1615
|
+
|
|
1616
|
+
const isClient = useIsClient()
|
|
1617
|
+
|
|
1618
|
+
return (
|
|
1619
|
+
<div>Running { ! isClient ? 'server' : 'client' }-side</div>
|
|
1620
|
+
)
|
|
1621
|
+
|
|
1622
|
+
}
|
|
1623
|
+
```
|
|
1624
|
+
|
|
1625
|
+
</details>
|
|
1626
|
+
|
|
1627
|
+
---
|
|
1628
|
+
|
|
1629
|
+
##### `useIsFirstRender`
|
|
1630
|
+
|
|
1631
|
+
Check if is first React Hook/Component render.
|
|
1632
|
+
|
|
1633
|
+
<details>
|
|
1634
|
+
|
|
1635
|
+
<summary style="cursor:pointer">Returns</summary>
|
|
1636
|
+
|
|
1637
|
+
Type: `boolean`
|
|
1638
|
+
|
|
1639
|
+
- `true` at the mount time.
|
|
1640
|
+
- `false` otherwise.
|
|
1641
|
+
|
|
1642
|
+
Note that if the React Hook/Component has no state updates, `useIsFirstRender` will always return `true`.
|
|
1643
|
+
|
|
1644
|
+
</details>
|
|
1645
|
+
|
|
1646
|
+
---
|
|
1647
|
+
|
|
1648
|
+
<details>
|
|
1649
|
+
|
|
1650
|
+
<summary style="cursor:pointer">Usage</summary>
|
|
1651
|
+
|
|
1652
|
+
```tsx
|
|
1653
|
+
'use client'
|
|
1654
|
+
|
|
1655
|
+
import { useIsFirstRender } from '@alessiofrittoli/react-hooks'
|
|
1656
|
+
|
|
1657
|
+
export const ClientComponent: React.FC = () => {
|
|
1658
|
+
|
|
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
|
+
}, [] )
|
|
1668
|
+
|
|
1669
|
+
return (
|
|
1670
|
+
<div>
|
|
1671
|
+
{ isFirstRender ? 'First render' : 'Subsequent render' }
|
|
1672
|
+
<hr />
|
|
1673
|
+
{ counter }
|
|
1674
|
+
</div>
|
|
1675
|
+
)
|
|
1676
|
+
|
|
1677
|
+
}
|
|
1678
|
+
```
|
|
1679
|
+
|
|
1680
|
+
</details>
|
|
1681
|
+
|
|
1682
|
+
---
|
|
1683
|
+
|
|
1684
|
+
##### `usePagination`
|
|
1685
|
+
|
|
1686
|
+
Get pagination informations based on the given options.
|
|
1687
|
+
|
|
1688
|
+
This hook memoize the returned result of the [`paginate`](https://github.com/alessiofrittoli/math-utils/blob/master/docs/helpers/README.md#paginate) function imported from [`@alessiofrittoli/math-utils`](https://npmjs.com/package/@alessiofrittoli/math-utils).
|
|
1689
|
+
|
|
1690
|
+
See [`paginate`](https://github.com/alessiofrittoli/math-utils/blob/master/docs/helpers/README.md#paginate) function Documentation for more information about it.
|
|
1691
|
+
|
|
1692
|
+
---
|
|
1693
|
+
|
|
1694
|
+
##### `useSelection`
|
|
1695
|
+
|
|
1696
|
+
A React hook for managing selection states in an array.
|
|
1697
|
+
|
|
1698
|
+
Provides functionality for single and group selection, as well as resetting the selection.
|
|
1699
|
+
|
|
1700
|
+
<details>
|
|
1701
|
+
|
|
1702
|
+
<summary style="cursor:pointer">Type Parameters</summary>
|
|
1703
|
+
|
|
1704
|
+
| Parameter | Description |
|
|
1705
|
+
|-----------|------------------------------|
|
|
1706
|
+
| `V` | The type of the values in the `array`. |
|
|
1707
|
+
|
|
1708
|
+
</details>
|
|
1709
|
+
|
|
1710
|
+
---
|
|
1711
|
+
|
|
1712
|
+
<details>
|
|
1713
|
+
|
|
1714
|
+
<summary style="cursor:pointer">Parameters</summary>
|
|
1715
|
+
|
|
1716
|
+
| Parameter | Type | Default | Description |
|
|
1717
|
+
|-----------|-------|---------|-----------------------------|
|
|
1718
|
+
| `array` | `V[]` | - | The array of items to manage selection for. |
|
|
1719
|
+
| `initial` | `V[]` | [] | The initial selection state. |
|
|
1720
|
+
|
|
1721
|
+
</details>
|
|
1722
|
+
|
|
1723
|
+
---
|
|
1724
|
+
|
|
1725
|
+
<details>
|
|
1726
|
+
|
|
1727
|
+
<summary style="cursor:pointer">Returns</summary>
|
|
1728
|
+
|
|
1729
|
+
An object containing the selection state and handlers.
|
|
1730
|
+
|
|
1731
|
+
- `selection`: `V[]` - The current selected items.
|
|
1732
|
+
- `hasSelection`: `boolean` - Indicates whether `selection` is not empty. Short-hand for `selection.length > 0`.
|
|
1733
|
+
- `isSelected`: `IsSelectedHandler<V>` - Check if the given `entry` is in the selection.
|
|
1734
|
+
- `setSelection`: `SetSelectionHandler<V>` - A React Dispatch SetStateAction that allows custom selection update.
|
|
1735
|
+
- `select`: `SelectHandler<V>` - Update selection by adding a new `entry` or removing the given `entry` if already exists in the selection.
|
|
1736
|
+
- `groupSelect`: `GroupSelectHandler<V>` - Select all items from the given `array` starting from the first item in the selection up to the given `entry`.
|
|
1737
|
+
- `selectAll`: `SelectAllHandler` - Add all entries from the given `array` to the selection.
|
|
1738
|
+
- `resetSelection`: `ResetSelectionHandler` - Removes all entries from the selection.
|
|
1739
|
+
|
|
1740
|
+
</details>
|
|
1741
|
+
|
|
1742
|
+
---
|
|
1743
|
+
|
|
1744
|
+
<details>
|
|
1745
|
+
|
|
1746
|
+
<summary style="cursor:pointer">Usage</summary>
|
|
1747
|
+
|
|
1748
|
+
```tsx
|
|
1749
|
+
'use client'
|
|
1750
|
+
|
|
1751
|
+
import { useCallback, useMemo } from 'react'
|
|
1752
|
+
import { useSelection } from '@alessiofrittoli/react-hooks'
|
|
1753
|
+
|
|
1754
|
+
interface Item
|
|
1755
|
+
{
|
|
1756
|
+
id : number
|
|
1757
|
+
name : string
|
|
1758
|
+
}
|
|
1759
|
+
|
|
1760
|
+
const items: Item[] = [
|
|
1761
|
+
{
|
|
1762
|
+
id : 1,
|
|
1763
|
+
name : 'item-1',
|
|
1764
|
+
},
|
|
1765
|
+
{
|
|
1766
|
+
id : 2,
|
|
1767
|
+
name : 'item-2',
|
|
1768
|
+
},
|
|
1769
|
+
{
|
|
1770
|
+
id : 3,
|
|
1771
|
+
name : 'item-3',
|
|
1772
|
+
},
|
|
1773
|
+
{
|
|
1774
|
+
id : 4,
|
|
1775
|
+
name : 'item-4',
|
|
1776
|
+
},
|
|
1777
|
+
{
|
|
1778
|
+
id : 5,
|
|
1779
|
+
name : 'item-5',
|
|
1780
|
+
},
|
|
1781
|
+
]
|
|
1782
|
+
|
|
1783
|
+
|
|
1784
|
+
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
|
|
1794
|
+
}
|
|
1795
|
+
if ( event.metaKey || event.ctrlKey ) {
|
|
1796
|
+
return select( id ) // toggle single item in selection
|
|
1797
|
+
}
|
|
1798
|
+
setSelection( prev => (
|
|
1799
|
+
prev.includes( id ) ? [] : [ id ] // toggle single item selection
|
|
1800
|
+
) )
|
|
1801
|
+
}
|
|
1802
|
+
), [ select, groupSelect, setSelection ] )
|
|
1803
|
+
|
|
1804
|
+
return (
|
|
1805
|
+
<ul>
|
|
1806
|
+
{ items.map( item => (
|
|
1807
|
+
<li key={ item.id }>
|
|
1808
|
+
<button
|
|
1809
|
+
onClick={ clickHandler( item.id ) }
|
|
1810
|
+
style={ {
|
|
1811
|
+
border: isSelected( item.id ) ? '1px solid red' : ' 1px solid black'
|
|
1812
|
+
} }
|
|
1813
|
+
>{ item.name }</button>
|
|
1814
|
+
</li>
|
|
1815
|
+
) ) }
|
|
1816
|
+
</ul>
|
|
1817
|
+
)
|
|
1818
|
+
|
|
1819
|
+
}
|
|
1820
|
+
```
|
|
1821
|
+
|
|
1822
|
+
</details>
|
|
1823
|
+
|
|
1824
|
+
---
|
|
1825
|
+
|
|
1826
|
+
#### Timers
|
|
1827
|
+
|
|
1828
|
+
#### `useDebounce`
|
|
1829
|
+
|
|
1830
|
+
Debounce a value by a specified delay.
|
|
1831
|
+
|
|
1832
|
+
This hook returns a debounced version of the input value, which only updates
|
|
1833
|
+
after the specified delay has passed without any changes to the input value.
|
|
1834
|
+
|
|
1835
|
+
It is useful for scenarios like search input fields or other cases where
|
|
1836
|
+
frequent updates should be minimized.
|
|
1837
|
+
|
|
1838
|
+
The `Timeout` automatically restarts when the given `value` changes.
|
|
1839
|
+
|
|
1840
|
+
<details>
|
|
1841
|
+
|
|
1842
|
+
<summary style="cursor:pointer">Type Parameters</summary>
|
|
1843
|
+
|
|
1844
|
+
| Parameter | Description |
|
|
1845
|
+
|-----------|--------------------------|
|
|
1846
|
+
| `T` | The type of the `value`. |
|
|
1847
|
+
|
|
1848
|
+
</details>
|
|
1849
|
+
|
|
1850
|
+
---
|
|
1851
|
+
|
|
1852
|
+
<details>
|
|
1853
|
+
|
|
1854
|
+
<summary style="cursor:pointer">Parameters</summary>
|
|
1855
|
+
|
|
1856
|
+
| Parameter | Type | Default | Description |
|
|
1857
|
+
|-----------|----------|---------|-----------------------------|
|
|
1858
|
+
| `value` | `T` | - | The value to debounce. This can be of any type. |
|
|
1859
|
+
| `delay` | `number` | 500 | The debounce delay in milliseconds. |
|
|
1860
|
+
|
|
1861
|
+
</details>
|
|
1862
|
+
|
|
1863
|
+
---
|
|
1864
|
+
|
|
1865
|
+
<details>
|
|
1866
|
+
|
|
1867
|
+
<summary style="cursor:pointer">Returns</summary>
|
|
1868
|
+
|
|
1869
|
+
Type: `T`
|
|
1870
|
+
|
|
1871
|
+
The debounced value, which updates only after the delay has passed.
|
|
1872
|
+
|
|
1873
|
+
</details>
|
|
1874
|
+
|
|
1875
|
+
---
|
|
1876
|
+
|
|
1877
|
+
<details>
|
|
1878
|
+
|
|
1879
|
+
<summary style="cursor:pointer">Usage</summary>
|
|
1880
|
+
|
|
1881
|
+
```tsx
|
|
1882
|
+
'use client'
|
|
1883
|
+
|
|
1884
|
+
import { useEffect, useState } from 'react'
|
|
1885
|
+
import { useDebounce } from '@alessiofrittoli/react-hooks'
|
|
1886
|
+
|
|
1887
|
+
const MyComponent: React.FC = () => {
|
|
1888
|
+
|
|
1889
|
+
const [ query, setQuery ] = useState( '' )
|
|
1890
|
+
const debouncedQuery = useDebounce( query )
|
|
1891
|
+
|
|
1892
|
+
useEffect( () => {
|
|
1893
|
+
if ( ! debouncedQuery ) return
|
|
1894
|
+
|
|
1895
|
+
fetch( '...', {
|
|
1896
|
+
// ...
|
|
1897
|
+
body: JSON.stringify( { query: debouncedQuery } )
|
|
1898
|
+
} )
|
|
1899
|
+
|
|
1900
|
+
}, [ debouncedQuery ] )
|
|
1901
|
+
|
|
1902
|
+
return (
|
|
1903
|
+
<input
|
|
1904
|
+
onChange={ event => setQuery( event.target.value ) }
|
|
1905
|
+
/>
|
|
1906
|
+
)
|
|
1907
|
+
|
|
1908
|
+
}
|
|
1909
|
+
```
|
|
1910
|
+
|
|
1911
|
+
</details>
|
|
1912
|
+
|
|
1913
|
+
---
|
|
1914
|
+
|
|
1915
|
+
#### `useInterval`
|
|
1916
|
+
|
|
1917
|
+
Schedules repeated execution of `callback` every `delay` milliseconds.
|
|
1918
|
+
|
|
1919
|
+
When `delay` is larger than `2147483647` or less than `1` or `NaN`, the `delay` will be set to `1`. Non-integer delays are truncated to an integer.
|
|
1920
|
+
If `callback` is not a function, a `TypeError` will be thrown.
|
|
1921
|
+
|
|
1922
|
+
The `Timeout` is automatically cancelled on unmount.
|
|
1923
|
+
|
|
1924
|
+
<details>
|
|
1925
|
+
|
|
1926
|
+
<summary style="cursor:pointer">Type Parameters</summary>
|
|
1927
|
+
|
|
1928
|
+
| Parameter | Description |
|
|
1929
|
+
|-----------|--------------------------|
|
|
1930
|
+
| `T` | An Array defining optional arguments passed to the `callback`. |
|
|
1931
|
+
|
|
1932
|
+
</details>
|
|
1933
|
+
|
|
1934
|
+
---
|
|
1935
|
+
|
|
1936
|
+
<details>
|
|
1937
|
+
|
|
1938
|
+
<summary style="cursor:pointer">Parameters</summary>
|
|
1939
|
+
|
|
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. |
|
|
1949
|
+
|
|
1950
|
+
</details>
|
|
1951
|
+
|
|
1952
|
+
---
|
|
1953
|
+
|
|
1954
|
+
<details>
|
|
1955
|
+
|
|
1956
|
+
<summary style="cursor:pointer">Returns</summary>
|
|
1957
|
+
|
|
1958
|
+
Type: `TimerReturnType | StateTimerReturnType`
|
|
1959
|
+
|
|
1960
|
+
An object with timer utilities.
|
|
1961
|
+
|
|
1962
|
+
- start: `StartTimer` - Manually start the timer.
|
|
1963
|
+
- stop: `StopTimer` - Manually stop the timer.
|
|
1964
|
+
|
|
1965
|
+
If `updateState` is set to `true` then the following property is added in the returned object.
|
|
1966
|
+
|
|
1967
|
+
- isActive: `boolean` - Indicates whether the timer is active.
|
|
1968
|
+
|
|
1969
|
+
</details>
|
|
1970
|
+
|
|
1971
|
+
---
|
|
1972
|
+
|
|
1973
|
+
<details>
|
|
1974
|
+
|
|
1975
|
+
<summary style="cursor:pointer">Usage</summary>
|
|
1976
|
+
|
|
1977
|
+
##### Basic usage
|
|
1978
|
+
|
|
1979
|
+
```tsx
|
|
1980
|
+
'use client'
|
|
1981
|
+
|
|
1982
|
+
import { useCallback } from 'react'
|
|
1983
|
+
import { useInterval } from '@alessiofrittoli/react-hooks'
|
|
1984
|
+
|
|
1985
|
+
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
|
+
}
|
|
1996
|
+
```
|
|
1997
|
+
|
|
1998
|
+
---
|
|
1999
|
+
|
|
2000
|
+
##### Rely on state updates
|
|
2001
|
+
|
|
2002
|
+
```tsx
|
|
2003
|
+
'use client'
|
|
2004
|
+
|
|
2005
|
+
import { useCallback } from 'react'
|
|
2006
|
+
import { useInterval } from '@alessiofrittoli/react-hooks'
|
|
2007
|
+
|
|
2008
|
+
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
|
+
} )
|
|
2018
|
+
|
|
2019
|
+
return (
|
|
2020
|
+
<>
|
|
2021
|
+
{ ! isActive && (
|
|
2022
|
+
<button onClick={ start }>Start timer</button>
|
|
2023
|
+
) }
|
|
2024
|
+
{ isActive && (
|
|
2025
|
+
<button onClick={ stop }>Stop timer</button>
|
|
2026
|
+
) }
|
|
2027
|
+
</>
|
|
2028
|
+
)
|
|
2029
|
+
|
|
2030
|
+
}
|
|
2031
|
+
```
|
|
2032
|
+
|
|
2033
|
+
</details>
|
|
2034
|
+
|
|
2035
|
+
---
|
|
2036
|
+
|
|
2037
|
+
#### `useIntervalWhenVisible`
|
|
2038
|
+
|
|
2039
|
+
Schedules repeated execution of `callback` every `delay` milliseconds when `Document` is visible.
|
|
2040
|
+
|
|
2041
|
+
This hook automatically starts and stops the interval based on the `Document` visibility.
|
|
2042
|
+
|
|
2043
|
+
This hook has the same API of [`useInterval`](#useinterval) and automatically starts and stops timers based on `Document` visibility.
|
|
2044
|
+
Refer to [`useInterval`](#useinterval) API Reference for more info.
|
|
2045
|
+
|
|
2046
|
+
---
|
|
2047
|
+
|
|
2048
|
+
#### `useLightInterval`
|
|
2049
|
+
|
|
2050
|
+
Schedules repeated execution of `callback` every `delay` milliseconds.
|
|
2051
|
+
|
|
2052
|
+
This is a lighter version of [`useInterval`](#useinterval) and is suggested to use when a basic functionality is enough (no manual start/stop or state updates).
|
|
2053
|
+
|
|
2054
|
+
<details>
|
|
2055
|
+
|
|
2056
|
+
<summary style="cursor:pointer">Type Parameters</summary>
|
|
2057
|
+
|
|
2058
|
+
| Parameter | Description |
|
|
2059
|
+
|-----------|--------------------------|
|
|
2060
|
+
| `T` | An Array defining optional arguments passed to the `callback`. |
|
|
2061
|
+
|
|
2062
|
+
</details>
|
|
2063
|
+
|
|
2064
|
+
---
|
|
2065
|
+
|
|
2066
|
+
<details>
|
|
2067
|
+
|
|
2068
|
+
<summary style="cursor:pointer">Parameters</summary>
|
|
2069
|
+
|
|
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. |
|
|
2076
|
+
|
|
2077
|
+
</details>
|
|
2078
|
+
|
|
2079
|
+
---
|
|
2080
|
+
|
|
2081
|
+
<details>
|
|
2082
|
+
|
|
2083
|
+
<summary style="cursor:pointer">Usage</summary>
|
|
2084
|
+
|
|
2085
|
+
```tsx
|
|
2086
|
+
'use client'
|
|
2087
|
+
|
|
2088
|
+
import { useCallback } from 'react'
|
|
2089
|
+
import { useLightInterval } from '@alessiofrittoli/react-hooks'
|
|
2090
|
+
|
|
2091
|
+
const MyComponent: React.FC = () => {
|
|
2092
|
+
|
|
2093
|
+
useLightInterval( useCallback( () => {
|
|
2094
|
+
console.log( 'tick timer' )
|
|
2095
|
+
}, [] ), { delay: 1000 } )
|
|
2096
|
+
|
|
2097
|
+
}
|
|
2098
|
+
```
|
|
2099
|
+
|
|
2100
|
+
</details>
|
|
2101
|
+
|
|
2102
|
+
---
|
|
2103
|
+
|
|
2104
|
+
#### `useTimeout`
|
|
2105
|
+
|
|
2106
|
+
Schedules execution of a one-time `callback` after `delay` milliseconds.
|
|
2107
|
+
|
|
2108
|
+
The `callback` will likely not be invoked in precisely `delay` milliseconds.
|
|
2109
|
+
|
|
2110
|
+
Node.js makes no guarantees about the exact timing of when callbacks will fire,
|
|
2111
|
+
nor of their ordering. The callback will be called as close as possible to the
|
|
2112
|
+
time specified.
|
|
2113
|
+
|
|
2114
|
+
When `delay` is larger than `2147483647` or less than `1` or `NaN`, the `delay`
|
|
2115
|
+
will be set to `1`. Non-integer delays are truncated to an integer.
|
|
2116
|
+
|
|
2117
|
+
If `callback` is not a function, a `TypeError` will be thrown.
|
|
2118
|
+
|
|
2119
|
+
The `Timeout` is automatically cancelled on unmount.
|
|
2120
|
+
|
|
2121
|
+
<details>
|
|
2122
|
+
|
|
2123
|
+
<summary style="cursor:pointer">Type Parameters</summary>
|
|
2124
|
+
|
|
2125
|
+
| Parameter | Description |
|
|
2126
|
+
|-----------|--------------------------|
|
|
2127
|
+
| `T` | An Array defining optional arguments passed to the `callback`. |
|
|
2128
|
+
|
|
2129
|
+
</details>
|
|
2130
|
+
|
|
2131
|
+
---
|
|
2132
|
+
|
|
2133
|
+
<details>
|
|
2134
|
+
|
|
2135
|
+
<summary style="cursor:pointer">Parameters</summary>
|
|
2136
|
+
|
|
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. |
|
|
2146
|
+
|
|
2147
|
+
</details>
|
|
2148
|
+
|
|
2149
|
+
---
|
|
2150
|
+
|
|
2151
|
+
<details>
|
|
2152
|
+
|
|
2153
|
+
<summary style="cursor:pointer">Returns</summary>
|
|
2154
|
+
|
|
2155
|
+
Type: `TimerReturnType | StateTimerReturnType`
|
|
2156
|
+
|
|
2157
|
+
An object with timer utilities.
|
|
2158
|
+
|
|
2159
|
+
- start: `StartTimer` - Manually start the timer.
|
|
2160
|
+
- stop: `StopTimer` - Manually stop the timer.
|
|
2161
|
+
|
|
2162
|
+
If `updateState` is set to `true` then the following property is added in the returned object.
|
|
2163
|
+
|
|
2164
|
+
- isActive: `boolean` - Indicates whether the timer is active.
|
|
2165
|
+
|
|
2166
|
+
</details>
|
|
2167
|
+
|
|
2168
|
+
---
|
|
2169
|
+
|
|
2170
|
+
<details>
|
|
2171
|
+
|
|
2172
|
+
<summary style="cursor:pointer">Usage</summary>
|
|
2173
|
+
|
|
2174
|
+
##### Basic usage
|
|
2175
|
+
|
|
2176
|
+
```tsx
|
|
2177
|
+
'use client'
|
|
2178
|
+
|
|
2179
|
+
import { useCallback } from 'react'
|
|
2180
|
+
import { useTimeout } from '@alessiofrittoli/react-hooks'
|
|
2181
|
+
|
|
2182
|
+
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
|
+
}
|
|
2193
|
+
```
|
|
2194
|
+
|
|
2195
|
+
---
|
|
2196
|
+
|
|
2197
|
+
##### Rely on state updates
|
|
2198
|
+
|
|
2199
|
+
```tsx
|
|
2200
|
+
'use client'
|
|
2201
|
+
|
|
2202
|
+
import { useCallback } from 'react'
|
|
2203
|
+
import { useTimeout } from '@alessiofrittoli/react-hooks'
|
|
2204
|
+
|
|
2205
|
+
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
|
+
} )
|
|
2215
|
+
|
|
2216
|
+
return (
|
|
2217
|
+
<>
|
|
2218
|
+
{ ! isActive && (
|
|
2219
|
+
<button onClick={ start }>Start timer</button>
|
|
2220
|
+
) }
|
|
2221
|
+
{ isActive && (
|
|
2222
|
+
<button onClick={ stop }>Stop timer</button>
|
|
2223
|
+
) }
|
|
2224
|
+
</>
|
|
2225
|
+
)
|
|
2226
|
+
|
|
2227
|
+
}
|
|
2228
|
+
```
|
|
2229
|
+
|
|
2230
|
+
</details>
|
|
2231
|
+
|
|
2232
|
+
---
|
|
2233
|
+
|
|
2234
|
+
#### `useLightTimeout`
|
|
2235
|
+
|
|
2236
|
+
Schedules execution of a one-time `callback` after `delay` milliseconds.
|
|
2237
|
+
|
|
2238
|
+
This is a lighter version of [`useTimeout`](#usetimeout) and is suggested to use when a basic functionality is enough (no manual start/stop or state updates).
|
|
2239
|
+
|
|
2240
|
+
<details>
|
|
2241
|
+
|
|
2242
|
+
<summary style="cursor:pointer">Type Parameters</summary>
|
|
2243
|
+
|
|
2244
|
+
| Parameter | Description |
|
|
2245
|
+
|-----------|--------------------------|
|
|
2246
|
+
| `T` | An Array defining optional arguments passed to the `callback`. |
|
|
2247
|
+
|
|
2248
|
+
</details>
|
|
2249
|
+
|
|
2250
|
+
---
|
|
2251
|
+
|
|
2252
|
+
<details>
|
|
2253
|
+
|
|
2254
|
+
<summary style="cursor:pointer">Parameters</summary>
|
|
2255
|
+
|
|
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. |
|
|
2262
|
+
|
|
2263
|
+
</details>
|
|
2264
|
+
|
|
2265
|
+
---
|
|
2266
|
+
|
|
2267
|
+
<details>
|
|
2268
|
+
|
|
2269
|
+
<summary style="cursor:pointer">Usage</summary>
|
|
2270
|
+
|
|
2271
|
+
```tsx
|
|
2272
|
+
'use client'
|
|
2273
|
+
|
|
2274
|
+
import { useCallback } from 'react'
|
|
2275
|
+
import { useLightTimeout } from '@alessiofrittoli/react-hooks'
|
|
2276
|
+
|
|
2277
|
+
const MyComponent: React.FC = () => {
|
|
2278
|
+
|
|
2279
|
+
useLightTimeout( useCallback( () => {
|
|
2280
|
+
console.log( 'tick timer' )
|
|
2281
|
+
}, [] ), { delay: 1000 } )
|
|
2282
|
+
|
|
2283
|
+
}
|
|
2284
|
+
```
|
|
2285
|
+
|
|
2286
|
+
</details>
|
|
1223
2287
|
|
|
1224
2288
|
---
|
|
1225
2289
|
|