@alessiofrittoli/react-hooks 3.3.0-alpha.1 → 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 +1358 -216
- package/dist/eslint.js +1 -1
- package/dist/eslint.mjs +1 -1
- package/dist/index.d.mts +43 -18
- package/dist/index.d.ts +43 -18
- package/dist/index.js +1 -1
- package/dist/index.mjs +1 -1
- package/package.json +3 -3
package/README.md
CHANGED
|
@@ -23,23 +23,37 @@
|
|
|
23
23
|
|
|
24
24
|
- [Getting started](#getting-started)
|
|
25
25
|
- [ESLint Configuration](#eslint-configuration)
|
|
26
|
+
- [What's Changed](#whats-changed)
|
|
26
27
|
- [API Reference](#api-reference)
|
|
27
28
|
- [Browser API](#browser-api)
|
|
28
29
|
- [`useStorage`](#usestorage)
|
|
29
30
|
- [`useLocalStorage`](#uselocalstorage)
|
|
30
31
|
- [`useSessionStorage`](#usesessionstorage)
|
|
31
|
-
- [`
|
|
32
|
+
- [`useConnection`](#useconnection)
|
|
32
33
|
- [`useDarkMode`](#usedarkmode)
|
|
34
|
+
- [`useEventListener`](#useeventlistener)
|
|
33
35
|
- [`useIsPortrait`](#useisportrait)
|
|
36
|
+
- [`useMediaQuery`](#usemediaquery)
|
|
34
37
|
- [DOM API](#dom-api)
|
|
35
|
-
- [`useScrollBlock`](#usescrollblock)
|
|
36
38
|
- [`useFocusTrap`](#usefocustrap)
|
|
37
39
|
- [`useInView`](#useinview)
|
|
40
|
+
- [`useScrollBlock`](#usescrollblock)
|
|
38
41
|
- [Miscellaneous](#miscellaneous)
|
|
42
|
+
- [`useInput`](#useinput)
|
|
43
|
+
- [`useDeferCallback`](#usedefercallback)
|
|
44
|
+
- [`useEffectOnce`](#useeffectonce)
|
|
45
|
+
- [`useUpdateEffect`](#useupdateeffect)
|
|
39
46
|
- [`useIsClient`](#useisclient)
|
|
40
47
|
- [`useIsFirstRender`](#useisfirstrender)
|
|
41
|
-
- [`useUpdateEffect`](#useupdateeffect)
|
|
42
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)
|
|
43
57
|
- [Development](#development)
|
|
44
58
|
- [Install depenendencies](#install-depenendencies)
|
|
45
59
|
- [Build the source code](#build-the-source-code)
|
|
@@ -88,6 +102,15 @@ export default config
|
|
|
88
102
|
|
|
89
103
|
---
|
|
90
104
|
|
|
105
|
+
### What's Changed
|
|
106
|
+
|
|
107
|
+
#### Updates in the latest release 🎉
|
|
108
|
+
|
|
109
|
+
- Add `useDeferCallback`. See [API Reference](#usedefercallback) for more info.
|
|
110
|
+
- Add missing API Referefence sections.
|
|
111
|
+
|
|
112
|
+
---
|
|
113
|
+
|
|
91
114
|
### API Reference
|
|
92
115
|
|
|
93
116
|
#### Browser API
|
|
@@ -259,75 +282,26 @@ Applies the same API Reference.
|
|
|
259
282
|
|
|
260
283
|
---
|
|
261
284
|
|
|
262
|
-
##### `
|
|
263
|
-
|
|
264
|
-
Get Document Media matches and listen for changes.
|
|
265
|
-
|
|
266
|
-
<details>
|
|
267
|
-
|
|
268
|
-
<summary style="cursor:pointer">Parameters</summary>
|
|
269
|
-
|
|
270
|
-
| Parameter | Type | Default | Description |
|
|
271
|
-
|-----------|----------|---------|-------------|
|
|
272
|
-
| `query` | `string` | - | A string specifying the media query to parse into a `MediaQueryList`. |
|
|
273
|
-
| `options` | `UseMediaQueryOptions\|UseMediaQueryStateOptions` | - | An object defining custom options. |
|
|
274
|
-
| `options.updateState` | `boolean` | `true` | Indicates whether the hook will dispatch a React state update when the given `query` change event get dispatched. |
|
|
275
|
-
| `options.onChange` | `OnChangeHandler` | - | A custom callback that will be invoked on initial page load and when the given `query` change event get dispatched. |
|
|
276
|
-
| | | | This callback is required if `updateState` is set to `false`. |
|
|
277
|
-
|
|
278
|
-
</details>
|
|
285
|
+
##### `useConnection`
|
|
279
286
|
|
|
280
|
-
|
|
287
|
+
Get states about Internet Connection.
|
|
281
288
|
|
|
282
289
|
<details>
|
|
283
290
|
|
|
284
291
|
<summary style="cursor:pointer">Returns</summary>
|
|
285
292
|
|
|
286
|
-
Type: `
|
|
287
|
-
|
|
288
|
-
- `true` or `false` if the document currently matches the media query list or not.
|
|
289
|
-
- `void` if `updateState` is set to `false`.
|
|
290
|
-
|
|
291
|
-
</details>
|
|
292
|
-
|
|
293
|
-
---
|
|
294
|
-
|
|
295
|
-
<details>
|
|
296
|
-
|
|
297
|
-
<summary style="cursor:pointer">Usage</summary>
|
|
298
|
-
|
|
299
|
-
###### Check if user device prefers dark color scheme
|
|
300
|
-
|
|
301
|
-
```tsx
|
|
302
|
-
import { useMediaQuery } from '@alessiofrittoli/react-hooks'
|
|
303
|
-
|
|
304
|
-
const isDarkOS = useMediaQuery( '(prefers-color-scheme: dark)' )
|
|
305
|
-
```
|
|
306
|
-
|
|
307
|
-
---
|
|
293
|
+
Type: `UseConnectionReturnType`
|
|
308
294
|
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
```tsx
|
|
312
|
-
import { useMediaQuery } from '@alessiofrittoli/react-hooks'
|
|
295
|
+
An object with the following properties:
|
|
313
296
|
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
console.log( 'is dark OS?', matches )
|
|
318
|
-
}
|
|
319
|
-
} )
|
|
320
|
-
```
|
|
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.
|
|
321
300
|
|
|
322
301
|
</details>
|
|
323
302
|
|
|
324
303
|
---
|
|
325
304
|
|
|
326
|
-
##### `useConnection`
|
|
327
|
-
|
|
328
|
-
Docs coming soon
|
|
329
|
-
|
|
330
|
-
---
|
|
331
305
|
|
|
332
306
|
##### `useDarkMode`
|
|
333
307
|
|
|
@@ -482,20 +456,26 @@ Just make sure to define both `light` and `dark` theme-color tags in your docume
|
|
|
482
456
|
|
|
483
457
|
---
|
|
484
458
|
|
|
485
|
-
##### `
|
|
486
|
-
|
|
487
|
-
Check if device is portrait oriented.
|
|
459
|
+
##### `useEventListener`
|
|
488
460
|
|
|
489
|
-
|
|
461
|
+
Attach a new Event listener to the `Window`, `Document`, `MediaQueryList` or an `HTMLElement`.
|
|
490
462
|
|
|
491
463
|
<details>
|
|
492
464
|
|
|
493
|
-
<summary style="cursor:pointer">
|
|
465
|
+
<summary style="cursor:pointer">Parameters</summary>
|
|
494
466
|
|
|
495
|
-
|
|
467
|
+
<details>
|
|
496
468
|
|
|
497
|
-
|
|
498
|
-
|
|
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). |
|
|
499
479
|
|
|
500
480
|
</details>
|
|
501
481
|
|
|
@@ -503,33 +483,53 @@ Type: `boolean`
|
|
|
503
483
|
|
|
504
484
|
<details>
|
|
505
485
|
|
|
506
|
-
<summary style="cursor:pointer">
|
|
507
|
-
|
|
508
|
-
###### Check if user device is in landscape
|
|
509
|
-
|
|
510
|
-
```tsx
|
|
511
|
-
import { useIsPortrait } from '@alessiofrittoli/react-hooks'
|
|
486
|
+
<summary style="cursor:pointer">Document events</summary>
|
|
512
487
|
|
|
513
|
-
|
|
514
|
-
|
|
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). |
|
|
515
497
|
|
|
516
498
|
</details>
|
|
517
499
|
|
|
518
500
|
---
|
|
519
501
|
|
|
520
|
-
|
|
502
|
+
<details>
|
|
521
503
|
|
|
522
|
-
|
|
504
|
+
<summary style="cursor:pointer">HTMLElement events</summary>
|
|
523
505
|
|
|
524
|
-
|
|
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
|
+
---
|
|
525
519
|
|
|
526
520
|
<details>
|
|
527
521
|
|
|
528
|
-
<summary style="cursor:pointer">
|
|
522
|
+
<summary style="cursor:pointer">MediaQuery events</summary>
|
|
529
523
|
|
|
530
|
-
| Parameter | Type
|
|
531
|
-
|
|
532
|
-
| `
|
|
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
|
|
|
@@ -537,11 +537,19 @@ Prevent Element overflow.
|
|
|
537
537
|
|
|
538
538
|
<details>
|
|
539
539
|
|
|
540
|
-
<summary style="cursor:pointer">
|
|
540
|
+
<summary style="cursor:pointer">Custom events</summary>
|
|
541
541
|
|
|
542
|
-
|
|
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). |
|
|
543
551
|
|
|
544
|
-
|
|
552
|
+
</details>
|
|
545
553
|
|
|
546
554
|
</details>
|
|
547
555
|
|
|
@@ -551,154 +559,354 @@ A tuple with block and restore scroll callbacks.
|
|
|
551
559
|
|
|
552
560
|
<summary style="cursor:pointer">Usage</summary>
|
|
553
561
|
|
|
554
|
-
######
|
|
562
|
+
###### Attach listeners to the Window object
|
|
555
563
|
|
|
556
564
|
```tsx
|
|
557
|
-
|
|
565
|
+
'use client'
|
|
558
566
|
|
|
559
|
-
|
|
567
|
+
import { useCallback } from 'react'
|
|
568
|
+
import { useEventListener } from '@alessiofrittoli/react-hooks'
|
|
560
569
|
|
|
561
|
-
const
|
|
562
|
-
...
|
|
563
|
-
blockScroll()
|
|
564
|
-
}, [ blockScroll ] )
|
|
570
|
+
export const MyComponent: React.FC = () => {
|
|
565
571
|
|
|
566
|
-
|
|
567
|
-
|
|
568
|
-
|
|
569
|
-
}, [
|
|
572
|
+
useEventListener( 'popstate', {
|
|
573
|
+
listener: useCallback( event => {
|
|
574
|
+
...
|
|
575
|
+
}, [] ),
|
|
576
|
+
} )
|
|
570
577
|
|
|
571
|
-
|
|
578
|
+
}
|
|
572
579
|
```
|
|
573
580
|
|
|
574
581
|
---
|
|
575
582
|
|
|
576
|
-
######
|
|
583
|
+
###### Attach listeners to the Document object
|
|
577
584
|
|
|
578
585
|
```tsx
|
|
579
|
-
|
|
586
|
+
'use client'
|
|
580
587
|
|
|
581
|
-
|
|
588
|
+
import { useCallback } from 'react'
|
|
589
|
+
import { useEventListener } from '@alessiofrittoli/react-hooks'
|
|
582
590
|
|
|
583
|
-
const
|
|
584
|
-
...
|
|
585
|
-
blockScroll()
|
|
586
|
-
}, [ blockScroll ] )
|
|
591
|
+
export const MyComponent: React.FC = () => {
|
|
587
592
|
|
|
588
|
-
|
|
589
|
-
|
|
590
|
-
|
|
591
|
-
|
|
593
|
+
useEventListener( 'click', {
|
|
594
|
+
target : typeof document !== 'undefined' ? document : null,
|
|
595
|
+
listener : useCallback( event => {
|
|
596
|
+
...
|
|
597
|
+
}, [] ),
|
|
598
|
+
} )
|
|
592
599
|
|
|
593
|
-
|
|
600
|
+
}
|
|
594
601
|
```
|
|
595
602
|
|
|
596
|
-
</details>
|
|
597
|
-
|
|
598
603
|
---
|
|
599
604
|
|
|
600
|
-
|
|
605
|
+
###### Attach listeners to an HTMLElement
|
|
601
606
|
|
|
602
|
-
|
|
607
|
+
```tsx
|
|
608
|
+
'use client'
|
|
603
609
|
|
|
604
|
-
|
|
610
|
+
import { useCallback, useRef } from 'react'
|
|
611
|
+
import { useEventListener } from '@alessiofrittoli/react-hooks'
|
|
605
612
|
|
|
606
|
-
|
|
613
|
+
export const MyComponent: React.FC = () => {
|
|
607
614
|
|
|
608
|
-
|
|
615
|
+
const buttonRef = useRef<HTMLButtonElement>( null )
|
|
609
616
|
|
|
610
|
-
|
|
611
|
-
|
|
612
|
-
|
|
613
|
-
|
|
617
|
+
useEventListener( 'click', {
|
|
618
|
+
target: buttonRef,
|
|
619
|
+
listener: useCallback( event => {
|
|
620
|
+
...
|
|
621
|
+
}, [] ),
|
|
622
|
+
} )
|
|
614
623
|
|
|
615
|
-
|
|
624
|
+
return (
|
|
625
|
+
<button ref={ buttonRef }>Button</button>
|
|
626
|
+
)
|
|
627
|
+
|
|
628
|
+
}
|
|
629
|
+
```
|
|
616
630
|
|
|
617
631
|
---
|
|
618
632
|
|
|
619
|
-
|
|
633
|
+
###### Attach listeners to a MediaQueryList
|
|
620
634
|
|
|
621
|
-
|
|
635
|
+
```tsx
|
|
636
|
+
import { useCallback } from 'react'
|
|
637
|
+
import { useEventListener } from '@alessiofrittoli/react-hooks'
|
|
622
638
|
|
|
623
|
-
|
|
639
|
+
export const MyComponent: React.FC = () => {
|
|
624
640
|
|
|
625
|
-
|
|
641
|
+
useEventListener( 'change', {
|
|
642
|
+
query : '(max-width: 768px)',
|
|
643
|
+
listener : useCallback( event => {
|
|
644
|
+
if ( event.matches ) {
|
|
645
|
+
...
|
|
646
|
+
}
|
|
647
|
+
}, [] )
|
|
648
|
+
} )
|
|
626
649
|
|
|
627
|
-
|
|
628
|
-
|
|
650
|
+
}
|
|
651
|
+
```
|
|
652
|
+
|
|
653
|
+
---
|
|
654
|
+
|
|
655
|
+
###### Listen dispatched custom events
|
|
656
|
+
|
|
657
|
+
```tsx
|
|
658
|
+
import { useCallback } from 'react'
|
|
659
|
+
import { useEventListener } from '@alessiofrittoli/react-hooks'
|
|
660
|
+
|
|
661
|
+
class CustomEvent extends Event
|
|
662
|
+
{
|
|
663
|
+
isCustom: boolean
|
|
664
|
+
|
|
665
|
+
constructor( type: string, eventInitDict?: EventInit )
|
|
666
|
+
{
|
|
667
|
+
super( type, eventInitDict )
|
|
668
|
+
this.isCustom = true
|
|
669
|
+
}
|
|
670
|
+
}
|
|
671
|
+
|
|
672
|
+
|
|
673
|
+
type CustomEventMap = {
|
|
674
|
+
customEventName: CustomEvent
|
|
675
|
+
}
|
|
676
|
+
|
|
677
|
+
|
|
678
|
+
export const MyComponent: React.FC = () => {
|
|
679
|
+
|
|
680
|
+
const clickHandler = useCallback( () => {
|
|
681
|
+
document.dispatchEvent( new CustomEvent( 'customEventName' ) )
|
|
682
|
+
}, [] )
|
|
683
|
+
|
|
684
|
+
useEventListener<CustomEventMap>( 'customEventName', {
|
|
685
|
+
target : typeof document !== 'undefined' ? document : null,
|
|
686
|
+
listener : useCallback( event => {
|
|
687
|
+
if ( event.isCustom ) {
|
|
688
|
+
...
|
|
689
|
+
}
|
|
690
|
+
}, [] )
|
|
691
|
+
} )
|
|
692
|
+
|
|
693
|
+
|
|
694
|
+
return (
|
|
695
|
+
<button onClick={ clickHandler }>Click me to dispatch custom event</button>
|
|
696
|
+
)
|
|
697
|
+
|
|
698
|
+
}
|
|
699
|
+
```
|
|
700
|
+
|
|
701
|
+
---
|
|
629
702
|
|
|
630
703
|
</details>
|
|
631
704
|
|
|
632
705
|
---
|
|
633
706
|
|
|
634
|
-
|
|
707
|
+
##### `useIsPortrait`
|
|
635
708
|
|
|
636
|
-
|
|
709
|
+
Check if device is portrait oriented.
|
|
637
710
|
|
|
638
|
-
|
|
711
|
+
React State get updated when device orientation changes.
|
|
639
712
|
|
|
640
|
-
|
|
641
|
-
import { useFocusTrap } from '@alessiofrittoli/react-hooks'
|
|
713
|
+
<details>
|
|
642
714
|
|
|
643
|
-
|
|
644
|
-
const [ setFocusTrap, restoreFocusTrap ] = useFocusTrap( modalRef )
|
|
715
|
+
<summary style="cursor:pointer">Returns</summary>
|
|
645
716
|
|
|
646
|
-
|
|
647
|
-
if ( ! modalRef.current ) return
|
|
648
|
-
// ... open modal
|
|
649
|
-
setFocusTrap()
|
|
650
|
-
modalRef.current.focus() // focus the dialog so next tab will focus the next element inside the modal
|
|
651
|
-
}, [ setFocusTrap ] )
|
|
717
|
+
Type: `boolean`
|
|
652
718
|
|
|
653
|
-
|
|
654
|
-
|
|
655
|
-
|
|
656
|
-
|
|
657
|
-
```
|
|
719
|
+
- `true` if the device is portrait oriented.
|
|
720
|
+
- `false` otherwise.
|
|
721
|
+
|
|
722
|
+
</details>
|
|
658
723
|
|
|
659
724
|
---
|
|
660
725
|
|
|
661
|
-
|
|
726
|
+
<details>
|
|
662
727
|
|
|
663
|
-
|
|
664
|
-
import { useFocusTrap } from '@alessiofrittoli/react-hooks'
|
|
728
|
+
<summary style="cursor:pointer">Usage</summary>
|
|
665
729
|
|
|
666
|
-
|
|
667
|
-
const modal2Ref = useRef<HTMLDivElement>( null )
|
|
668
|
-
const [ setFocusTrap, restoreFocusTrap ] = useFocusTrap()
|
|
730
|
+
###### Check if user device is in landscape
|
|
669
731
|
|
|
670
|
-
|
|
671
|
-
|
|
672
|
-
// ... open modal
|
|
673
|
-
setFocusTrap( modalRef.current )
|
|
674
|
-
modalRef.current.focus()
|
|
675
|
-
}, [ setFocusTrap ] )
|
|
732
|
+
```tsx
|
|
733
|
+
import { useIsPortrait } from '@alessiofrittoli/react-hooks'
|
|
676
734
|
|
|
677
|
-
const
|
|
678
|
-
if ( ! modal2Ref.current ) return
|
|
679
|
-
// ... open modal
|
|
680
|
-
setFocusTrap( modal2Ref.current )
|
|
681
|
-
modal2Ref.current.focus()
|
|
682
|
-
}, [ setFocusTrap ] )
|
|
735
|
+
const isLandscape = ! useIsPortrait()
|
|
683
736
|
```
|
|
684
737
|
|
|
685
738
|
</details>
|
|
686
739
|
|
|
687
740
|
---
|
|
688
741
|
|
|
689
|
-
##### `
|
|
742
|
+
##### `useMediaQuery`
|
|
690
743
|
|
|
691
|
-
|
|
744
|
+
Get Document Media matches and listen for changes.
|
|
692
745
|
|
|
693
746
|
<details>
|
|
694
747
|
|
|
695
748
|
<summary style="cursor:pointer">Parameters</summary>
|
|
696
749
|
|
|
697
|
-
| Parameter | Type | Description |
|
|
698
|
-
|
|
699
|
-
| `
|
|
700
|
-
| `options` | `
|
|
701
|
-
| `options.
|
|
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. |
|
|
702
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. |
|
|
703
911
|
| `options.amount` | `'all'\|'some'\|number\|number[]` | (Optional) The intersecting target thresholds. |
|
|
704
912
|
| | | Threshold can be set to: |
|
|
@@ -946,36 +1154,29 @@ const AsyncStartExample: React.FC = () => {
|
|
|
946
1154
|
|
|
947
1155
|
---
|
|
948
1156
|
|
|
949
|
-
|
|
950
|
-
|
|
951
|
-
---
|
|
1157
|
+
##### `useScrollBlock`
|
|
952
1158
|
|
|
953
|
-
|
|
1159
|
+
Prevent Element overflow.
|
|
954
1160
|
|
|
955
|
-
|
|
1161
|
+
<details>
|
|
956
1162
|
|
|
957
|
-
|
|
1163
|
+
<summary style="cursor:pointer">Parameters</summary>
|
|
958
1164
|
|
|
959
|
-
|
|
1165
|
+
| Parameter | Type | Default | Description |
|
|
1166
|
+
|-----------|------|---------|-------------|
|
|
1167
|
+
| `target` | `React.RefObject<HTMLElement\|null>` | `Document.documentElement` | (Optional) The React RefObject target HTMLElement. |
|
|
960
1168
|
|
|
961
|
-
|
|
1169
|
+
</details>
|
|
962
1170
|
|
|
963
1171
|
---
|
|
964
1172
|
|
|
965
|
-
##### `useIsClient`
|
|
966
|
-
|
|
967
|
-
Check if the React Hook or Component where this hook is executed is running in a browser environment.
|
|
968
|
-
|
|
969
|
-
This is pretty usefull to avoid hydration errors.
|
|
970
|
-
|
|
971
1173
|
<details>
|
|
972
1174
|
|
|
973
1175
|
<summary style="cursor:pointer">Returns</summary>
|
|
974
1176
|
|
|
975
|
-
Type: `
|
|
1177
|
+
Type: `[ () => void, () => void ]`
|
|
976
1178
|
|
|
977
|
-
|
|
978
|
-
- `false` otherwise.
|
|
1179
|
+
A tuple with block and restore scroll callbacks.
|
|
979
1180
|
|
|
980
1181
|
</details>
|
|
981
1182
|
|
|
@@ -985,42 +1186,109 @@ Type: `boolean`
|
|
|
985
1186
|
|
|
986
1187
|
<summary style="cursor:pointer">Usage</summary>
|
|
987
1188
|
|
|
988
|
-
######
|
|
1189
|
+
###### Block Document Overflow
|
|
989
1190
|
|
|
990
1191
|
```tsx
|
|
991
|
-
|
|
1192
|
+
import { useScrollBlock } from '@alessiofrittoli/react-hooks'
|
|
992
1193
|
|
|
993
|
-
|
|
1194
|
+
const [ blockScroll, restoreScroll ] = useScrollBlock()
|
|
994
1195
|
|
|
995
|
-
|
|
1196
|
+
const openPopUpHandler = useCallback( () => {
|
|
1197
|
+
...
|
|
1198
|
+
blockScroll()
|
|
1199
|
+
}, [ blockScroll ] )
|
|
996
1200
|
|
|
997
|
-
|
|
1201
|
+
const closePopUpHandler = useCallback( () => {
|
|
1202
|
+
...
|
|
1203
|
+
restoreScroll()
|
|
1204
|
+
}, [ restoreScroll ] )
|
|
998
1205
|
|
|
999
|
-
|
|
1000
|
-
|
|
1001
|
-
)
|
|
1206
|
+
...
|
|
1207
|
+
```
|
|
1002
1208
|
|
|
1003
|
-
|
|
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
|
+
...
|
|
1004
1229
|
```
|
|
1005
1230
|
|
|
1006
1231
|
</details>
|
|
1007
1232
|
|
|
1008
1233
|
---
|
|
1009
1234
|
|
|
1010
|
-
|
|
1235
|
+
#### Miscellaneous
|
|
1011
1236
|
|
|
1012
|
-
|
|
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. |
|
|
1249
|
+
|
|
1250
|
+
</details>
|
|
1251
|
+
|
|
1252
|
+
---
|
|
1253
|
+
|
|
1254
|
+
<details>
|
|
1255
|
+
|
|
1256
|
+
<summary style="cursor:pointer">Parameters</summary>
|
|
1257
|
+
|
|
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
|
+
---
|
|
1013
1271
|
|
|
1014
1272
|
<details>
|
|
1015
1273
|
|
|
1016
1274
|
<summary style="cursor:pointer">Returns</summary>
|
|
1017
1275
|
|
|
1018
|
-
Type: `
|
|
1276
|
+
Type: `UseInputOutput<I, O>`
|
|
1019
1277
|
|
|
1020
|
-
|
|
1021
|
-
- `false` otherwise.
|
|
1278
|
+
An object containing the following properties:
|
|
1022
1279
|
|
|
1023
|
-
|
|
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. |
|
|
1024
1292
|
|
|
1025
1293
|
</details>
|
|
1026
1294
|
|
|
@@ -1033,28 +1301,216 @@ Note that if the React Hook/Component has no state updates, `useIsFirstRender` w
|
|
|
1033
1301
|
###### Basic usage
|
|
1034
1302
|
|
|
1035
1303
|
```tsx
|
|
1036
|
-
|
|
1304
|
+
const MyComponent: React.FC = () => {
|
|
1037
1305
|
|
|
1038
|
-
|
|
1306
|
+
const input = useInput<string>()
|
|
1039
1307
|
|
|
1040
|
-
|
|
1308
|
+
return (
|
|
1309
|
+
<input
|
|
1310
|
+
type='text'
|
|
1311
|
+
value={ input.value || '' }
|
|
1312
|
+
onChange={ input.changeHandler }
|
|
1313
|
+
onBlur={ input.blurHandler }
|
|
1314
|
+
/>
|
|
1315
|
+
)
|
|
1041
1316
|
|
|
1042
|
-
|
|
1043
|
-
|
|
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
|
+
} )
|
|
1336
|
+
|
|
1337
|
+
return (
|
|
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
|
+
</>
|
|
1391
|
+
)
|
|
1392
|
+
|
|
1393
|
+
}
|
|
1394
|
+
```
|
|
1395
|
+
|
|
1396
|
+
</details>
|
|
1397
|
+
|
|
1398
|
+
---
|
|
1399
|
+
|
|
1400
|
+
##### `useDeferCallback`
|
|
1401
|
+
|
|
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.
|
|
1408
|
+
|
|
1409
|
+
<details>
|
|
1410
|
+
|
|
1411
|
+
<summary style="cursor:pointer">Type Parameters</summary>
|
|
1412
|
+
|
|
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. |
|
|
1417
|
+
|
|
1418
|
+
</details>
|
|
1419
|
+
|
|
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.
|
|
1441
|
+
|
|
1442
|
+
</details>
|
|
1443
|
+
|
|
1444
|
+
---
|
|
1445
|
+
|
|
1446
|
+
<details>
|
|
1447
|
+
|
|
1448
|
+
<summary style="cursor:pointer">Usage</summary>
|
|
1449
|
+
|
|
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>
|
|
1487
|
+
|
|
1488
|
+
```tsx
|
|
1489
|
+
'use client'
|
|
1490
|
+
|
|
1491
|
+
import { useEffect, useState } from 'react'
|
|
1492
|
+
import { useEffectOnce } from '@alessiofrittoli/react-hooks'
|
|
1493
|
+
|
|
1494
|
+
export const ClientComponent: React.FC = () => {
|
|
1495
|
+
|
|
1496
|
+
const [ count, setCount ] = useState( 0 )
|
|
1044
1497
|
|
|
1045
1498
|
useEffect( () => {
|
|
1046
1499
|
const intv = setInterval( () => {
|
|
1047
|
-
|
|
1500
|
+
setCount( prev => prev + 1 ) // update state each 1s
|
|
1048
1501
|
}, 1000 )
|
|
1049
1502
|
return () => clearInterval( intv )
|
|
1050
1503
|
}, [] )
|
|
1051
1504
|
|
|
1505
|
+
useEffectOnce( () => {
|
|
1506
|
+
console.log( 'Component did mount' )
|
|
1507
|
+
return () => {
|
|
1508
|
+
console.log( 'Component did unmount' )
|
|
1509
|
+
}
|
|
1510
|
+
} )
|
|
1511
|
+
|
|
1052
1512
|
return (
|
|
1053
|
-
<div>
|
|
1054
|
-
{ isFirstRender ? 'First render' : 'Subsequent render' }
|
|
1055
|
-
<hr />
|
|
1056
|
-
{ counter }
|
|
1057
|
-
</div>
|
|
1513
|
+
<div>{ count }</div>
|
|
1058
1514
|
)
|
|
1059
1515
|
|
|
1060
1516
|
}
|
|
@@ -1085,8 +1541,6 @@ Modified version of `useEffect` that skips the first render.
|
|
|
1085
1541
|
|
|
1086
1542
|
<summary style="cursor:pointer">Usage</summary>
|
|
1087
1543
|
|
|
1088
|
-
###### Basic usage
|
|
1089
|
-
|
|
1090
1544
|
```tsx
|
|
1091
1545
|
'use client'
|
|
1092
1546
|
|
|
@@ -1129,6 +1583,104 @@ export const ClientComponent: React.FC = () => {
|
|
|
1129
1583
|
|
|
1130
1584
|
---
|
|
1131
1585
|
|
|
1586
|
+
##### `useIsClient`
|
|
1587
|
+
|
|
1588
|
+
Check if the React Hook or Component where this hook is executed is running in a browser environment.
|
|
1589
|
+
|
|
1590
|
+
This is pretty usefull to avoid hydration errors.
|
|
1591
|
+
|
|
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>
|
|
1602
|
+
|
|
1603
|
+
---
|
|
1604
|
+
|
|
1605
|
+
<details>
|
|
1606
|
+
|
|
1607
|
+
<summary style="cursor:pointer">Usage</summary>
|
|
1608
|
+
|
|
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
|
+
|
|
1132
1684
|
##### `usePagination`
|
|
1133
1685
|
|
|
1134
1686
|
Get pagination informations based on the given options.
|
|
@@ -1141,7 +1693,597 @@ See [`paginate`](https://github.com/alessiofrittoli/math-utils/blob/master/docs/
|
|
|
1141
1693
|
|
|
1142
1694
|
##### `useSelection`
|
|
1143
1695
|
|
|
1144
|
-
|
|
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>
|
|
1145
2287
|
|
|
1146
2288
|
---
|
|
1147
2289
|
|