@aweebit/react-essentials 0.7.0 → 0.8.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -2,19 +2,50 @@
2
2
 
3
3
  [![NPM Version](https://img.shields.io/npm/v/%40aweebit%2Freact-essentials)](https://www.npmjs.com/package/@aweebit/react-essentials)
4
4
 
5
+ ### Requirements
6
+
7
+ - React ≥ 18
8
+ - TypeScript ≥ 5.4
9
+
10
+ ### Functions
11
+
5
12
  - [useEventListener()](#useeventlistener)
6
13
  - [useForceUpdate()](#useforceupdate)
7
14
  - [useReducerWithDeps()](#usereducerwithdeps)
8
15
  - [useStateWithDeps()](#usestatewithdeps)
9
16
  - [createSafeContext()](#createsafecontext)
17
+
18
+ ### Types
19
+
20
+ - [UseEventListener](#useeventlistener-1)
21
+ - [UseEventListenerWithImplicitWindowTarget](#useeventlistenerwithimplicitwindowtarget)
22
+ - [UseEventListenerWithExplicitTarget](#useeventlistenerwithexplicittarget)
23
+ - [UseEventListenerWithAnyExplicitTarget](#useeventlistenerwithanyexplicittarget)
24
+ - [UseEventListenerWithImplicitWindowTargetArgs](#useeventlistenerwithimplicitwindowtargetargs)
25
+ - [UseEventListenerWithExplicitTargetArgs](#useeventlistenerwithexplicittargetargs)
10
26
  - [RestrictedContext](#restrictedcontext)
11
27
  - [SafeContext](#safecontext)
12
28
 
13
- ## useEventListener()
29
+ ## useEventListener
30
+
31
+ ```ts
32
+ const useEventListener: UseEventListener;
33
+ ```
34
+
35
+ Defined in: [hooks/useEventListener.ts:133](https://github.com/aweebit/react-essentials/blob/v0.8.0/src/hooks/useEventListener.ts#L133)
14
36
 
15
37
  Adds `handler` as a listener for the event `eventName` of `target` with the
16
38
  provided `options` applied
17
39
 
40
+ The following call signatures are available:
41
+
42
+ ```ts
43
+ function useEventListener(eventName, handler, options?): void;
44
+ function useEventListener(target, eventName, handler, options?): void;
45
+ ```
46
+
47
+ For the full definition of the hook's type, see [`UseEventListener`](#useeventlistener).
48
+
18
49
  If `target` is not provided, `window` is used instead.
19
50
 
20
51
  If `target` is `null`, no event listener is added. This is useful when
@@ -33,188 +64,12 @@ useEventListener(document, 'visibilitychange', () => {
33
64
  });
34
65
 
35
66
  const buttonRef = useRef<HTMLButtonElement>(null);
36
- useEventListener(buttonRef.current, 'click', () => console.log('click'));
37
- ```
38
-
39
- ### Call Signature
40
-
41
- ```ts
42
- function useEventListener<K>(eventName, handler, options?): void;
43
- ```
44
-
45
- Defined in: [hooks/useEventListener.ts:99](https://github.com/aweebit/react-essentials/blob/v0.7.0/src/hooks/useEventListener.ts#L99)
46
-
47
- #### Type Parameters
48
-
49
- <table>
50
- <thead>
51
- <tr>
52
- <th>Type Parameter</th>
53
- </tr>
54
- </thead>
55
- <tbody>
56
- <tr>
57
- <td>
58
-
59
- `K` _extends_ keyof `WindowEventMap`
60
-
61
- </td>
62
- </tr>
63
- </tbody>
64
- </table>
65
-
66
- #### Parameters
67
-
68
- <table>
69
- <thead>
70
- <tr>
71
- <th>Parameter</th>
72
- <th>Type</th>
73
- </tr>
74
- </thead>
75
- <tbody>
76
- <tr>
77
- <td>
78
-
79
- `eventName`
80
-
81
- </td>
82
- <td>
83
-
84
- `K`
85
-
86
- </td>
87
- </tr>
88
- <tr>
89
- <td>
90
-
91
- `handler`
92
-
93
- </td>
94
- <td>
95
-
96
- (`this`, `event`) => `void`
97
-
98
- </td>
99
- </tr>
100
- <tr>
101
- <td>
102
-
103
- `options?`
104
-
105
- </td>
106
- <td>
107
-
108
- `boolean` \| `AddEventListenerOptions`
109
-
110
- </td>
111
- </tr>
112
- </tbody>
113
- </table>
114
-
115
- #### Returns
116
-
117
- `void`
118
-
119
- #### See
120
-
121
- [`useEventListener`](#useeventlistener)
122
-
123
- ### Call Signature
124
-
125
- ```ts
126
- function useEventListener<T>(target, eventName, handler, options?): void;
67
+ useEventListener(buttonRef, 'click', () => console.log('click'));
127
68
  ```
128
69
 
129
- Defined in: [hooks/useEventListener.ts:108](https://github.com/aweebit/react-essentials/blob/v0.7.0/src/hooks/useEventListener.ts#L108)
130
-
131
- #### Type Parameters
132
-
133
- <table>
134
- <thead>
135
- <tr>
136
- <th>Type Parameter</th>
137
- </tr>
138
- </thead>
139
- <tbody>
140
- <tr>
141
- <td>
142
-
143
- `T` _extends_ `EventTarget`
144
-
145
- </td>
146
- </tr>
147
- </tbody>
148
- </table>
149
-
150
- #### Parameters
151
-
152
- <table>
153
- <thead>
154
- <tr>
155
- <th>Parameter</th>
156
- <th>Type</th>
157
- </tr>
158
- </thead>
159
- <tbody>
160
- <tr>
161
- <td>
162
-
163
- `target`
164
-
165
- </td>
166
- <td>
167
-
168
- `null` \| `T`
169
-
170
- </td>
171
- </tr>
172
- <tr>
173
- <td>
174
-
175
- `eventName`
176
-
177
- </td>
178
- <td>
179
-
180
- `string`
181
-
182
- </td>
183
- </tr>
184
- <tr>
185
- <td>
186
-
187
- `handler`
188
-
189
- </td>
190
- <td>
191
-
192
- (`this`, `event`) => `void`
193
-
194
- </td>
195
- </tr>
196
- <tr>
197
- <td>
198
-
199
- `options?`
200
-
201
- </td>
202
- <td>
203
-
204
- `boolean` \| `AddEventListenerOptions`
205
-
206
- </td>
207
- </tr>
208
- </tbody>
209
- </table>
210
-
211
- #### Returns
212
-
213
- `void`
214
-
215
- #### See
70
+ ### See
216
71
 
217
- [`useEventListener`](#useeventlistener)
72
+ [`UseEventListener`](#useeventlistener)
218
73
 
219
74
  ---
220
75
 
@@ -224,7 +79,7 @@ Defined in: [hooks/useEventListener.ts:108](https://github.com/aweebit/react-ess
224
79
  function useForceUpdate(callback?): [() => void, bigint];
225
80
  ```
226
81
 
227
- Defined in: [hooks/useForceUpdate.ts:81](https://github.com/aweebit/react-essentials/blob/v0.7.0/src/hooks/useForceUpdate.ts#L81)
82
+ Defined in: [hooks/useForceUpdate.ts:81](https://github.com/aweebit/react-essentials/blob/v0.8.0/src/hooks/useForceUpdate.ts#L81)
228
83
 
229
84
  Enables you to imperatively trigger re-rendering of components
230
85
 
@@ -344,7 +199,7 @@ function useReducerWithDeps<S, A>(
344
199
  ): [S, ActionDispatch<A>];
345
200
  ```
346
201
 
347
- Defined in: [hooks/useReducerWithDeps.ts:52](https://github.com/aweebit/react-essentials/blob/v0.7.0/src/hooks/useReducerWithDeps.ts#L52)
202
+ Defined in: [hooks/useReducerWithDeps.ts:52](https://github.com/aweebit/react-essentials/blob/v0.8.0/src/hooks/useReducerWithDeps.ts#L52)
348
203
 
349
204
  `useReducer` hook with an additional dependency array `deps` that resets the
350
205
  state to `initialState` when dependencies change
@@ -480,7 +335,7 @@ function useStateWithDeps<S>(
480
335
  ): [S, Dispatch<SetStateAction<S>>];
481
336
  ```
482
337
 
483
- Defined in: [hooks/useStateWithDeps.ts:66](https://github.com/aweebit/react-essentials/blob/v0.7.0/src/hooks/useStateWithDeps.ts#L66)
338
+ Defined in: [hooks/useStateWithDeps.ts:65](https://github.com/aweebit/react-essentials/blob/v0.8.0/src/hooks/useStateWithDeps.ts#L65)
484
339
 
485
340
  `useState` hook with an additional dependency array `deps` that resets the
486
341
  state to `initialState` when dependencies change
@@ -607,7 +462,7 @@ function createSafeContext<T>(): <DisplayName>(
607
462
  ) => SafeContext<DisplayName, T>;
608
463
  ```
609
464
 
610
- Defined in: [misc/createSafeContext.ts:89](https://github.com/aweebit/react-essentials/blob/v0.7.0/src/misc/createSafeContext.ts#L89)
465
+ Defined in: [misc/createSafeContext.ts:95](https://github.com/aweebit/react-essentials/blob/v0.8.0/src/misc/createSafeContext.ts#L95)
611
466
 
612
467
  For a given type `T`, returns a function that produces both a context of that
613
468
  type and a hook that returns the current context value if one was provided,
@@ -744,6 +599,321 @@ A function that accepts a single string argument `displayName` (e.g.
744
599
 
745
600
  [`SafeContext`](#safecontext)\<`DisplayName`, `T`\>
746
601
 
602
+ ### See
603
+
604
+ [`SafeContext`](#safecontext)
605
+
606
+ ---
607
+
608
+ ## UseEventListener
609
+
610
+ ```ts
611
+ type UseEventListener = UseEventListenerWithImplicitWindowTarget &
612
+ UseEventListenerWithExplicitTarget<Window, WindowEventMap> &
613
+ UseEventListenerWithExplicitTarget<Document, DocumentEventMap> &
614
+ UseEventListenerWithExplicitTarget<HTMLElement, HTMLElementEventMap> &
615
+ UseEventListenerWithExplicitTarget<SVGElement, SVGElementEventMap> &
616
+ UseEventListenerWithExplicitTarget<MathMLElement, MathMLElementEventMap> &
617
+ UseEventListenerWithAnyExplicitTarget;
618
+ ```
619
+
620
+ Defined in: [hooks/useEventListener.ts:19](https://github.com/aweebit/react-essentials/blob/v0.8.0/src/hooks/useEventListener.ts#L19)
621
+
622
+ The type of [`useEventListener`](#useeventlistener-1)
623
+
624
+ ### See
625
+
626
+ [`useEventListener`](#useeventlistener-1),
627
+ [`UseEventListenerWithImplicitWindowTarget`](#useeventlistenerwithimplicitwindowtarget),
628
+ [`UseEventListenerWithExplicitTarget`](#useeventlistenerwithexplicittarget),
629
+ [`UseEventListenerWithAnyExplicitTarget`](#useeventlistenerwithanyexplicittarget)
630
+
631
+ ---
632
+
633
+ ## UseEventListenerWithImplicitWindowTarget()
634
+
635
+ ```ts
636
+ type UseEventListenerWithImplicitWindowTarget = <K>(...args) => void;
637
+ ```
638
+
639
+ Defined in: [hooks/useEventListener.ts:31](https://github.com/aweebit/react-essentials/blob/v0.8.0/src/hooks/useEventListener.ts#L31)
640
+
641
+ ### Type Parameters
642
+
643
+ <table>
644
+ <thead>
645
+ <tr>
646
+ <th>Type Parameter</th>
647
+ </tr>
648
+ </thead>
649
+ <tbody>
650
+ <tr>
651
+ <td>
652
+
653
+ `K` _extends_ keyof `WindowEventMap`
654
+
655
+ </td>
656
+ </tr>
657
+ </tbody>
658
+ </table>
659
+
660
+ ### Parameters
661
+
662
+ <table>
663
+ <thead>
664
+ <tr>
665
+ <th>Parameter</th>
666
+ <th>Type</th>
667
+ </tr>
668
+ </thead>
669
+ <tbody>
670
+ <tr>
671
+ <td>
672
+
673
+ ...`args`
674
+
675
+ </td>
676
+ <td>
677
+
678
+ [`UseEventListenerWithImplicitWindowTargetArgs`](#useeventlistenerwithimplicitwindowtargetargs)\<`K`\>
679
+
680
+ </td>
681
+ </tr>
682
+ </tbody>
683
+ </table>
684
+
685
+ ### Returns
686
+
687
+ `void`
688
+
689
+ ### See
690
+
691
+ [`useEventListener`](#useeventlistener-1),
692
+ [`UseEventListenerWithImplicitWindowTargetArgs`](#useeventlistenerwithimplicitwindowtargetargs)
693
+
694
+ ---
695
+
696
+ ## UseEventListenerWithExplicitTarget()
697
+
698
+ ```ts
699
+ type UseEventListenerWithExplicitTarget<Target, EventMap> = <T, K>(
700
+ ...args
701
+ ) => void;
702
+ ```
703
+
704
+ Defined in: [hooks/useEventListener.ts:42](https://github.com/aweebit/react-essentials/blob/v0.8.0/src/hooks/useEventListener.ts#L42)
705
+
706
+ ### Type Parameters
707
+
708
+ <table>
709
+ <thead>
710
+ <tr>
711
+ <th>Type Parameter</th>
712
+ <th>Default type</th>
713
+ </tr>
714
+ </thead>
715
+ <tbody>
716
+ <tr>
717
+ <td>
718
+
719
+ `Target` _extends_ `EventTarget`
720
+
721
+ </td>
722
+ <td>
723
+
724
+ &hyphen;
725
+
726
+ </td>
727
+ </tr>
728
+ <tr>
729
+ <td>
730
+
731
+ `EventMap`
732
+
733
+ </td>
734
+ <td>
735
+
736
+ `Record`\<`string`, `Event`\>
737
+
738
+ </td>
739
+ </tr>
740
+ </tbody>
741
+ </table>
742
+
743
+ ### Type Parameters
744
+
745
+ <table>
746
+ <thead>
747
+ <tr>
748
+ <th>Type Parameter</th>
749
+ </tr>
750
+ </thead>
751
+ <tbody>
752
+ <tr>
753
+ <td>
754
+
755
+ `T` _extends_ `Target`
756
+
757
+ </td>
758
+ </tr>
759
+ <tr>
760
+ <td>
761
+
762
+ `K` _extends_ keyof `EventMap`
763
+
764
+ </td>
765
+ </tr>
766
+ </tbody>
767
+ </table>
768
+
769
+ ### Parameters
770
+
771
+ <table>
772
+ <thead>
773
+ <tr>
774
+ <th>Parameter</th>
775
+ <th>Type</th>
776
+ </tr>
777
+ </thead>
778
+ <tbody>
779
+ <tr>
780
+ <td>
781
+
782
+ ...`args`
783
+
784
+ </td>
785
+ <td>
786
+
787
+ [`UseEventListenerWithExplicitTargetArgs`](#useeventlistenerwithexplicittargetargs)\<`EventMap`, `T`, `K`\>
788
+
789
+ </td>
790
+ </tr>
791
+ </tbody>
792
+ </table>
793
+
794
+ ### Returns
795
+
796
+ `void`
797
+
798
+ ### See
799
+
800
+ [`useEventListener`](#useeventlistener-1),
801
+ [`UseEventListenerWithExplicitTargetArgs`](#useeventlistenerwithexplicittargetargs)
802
+
803
+ ---
804
+
805
+ ## UseEventListenerWithAnyExplicitTarget
806
+
807
+ ```ts
808
+ type UseEventListenerWithAnyExplicitTarget =
809
+ UseEventListenerWithExplicitTarget<EventTarget>;
810
+ ```
811
+
812
+ Defined in: [hooks/useEventListener.ts:54](https://github.com/aweebit/react-essentials/blob/v0.8.0/src/hooks/useEventListener.ts#L54)
813
+
814
+ ### See
815
+
816
+ [`useEventListener`](#useeventlistener-1),
817
+ [`UseEventListenerWithExplicitTarget`](#useeventlistenerwithexplicittarget)
818
+
819
+ ---
820
+
821
+ ## UseEventListenerWithImplicitWindowTargetArgs
822
+
823
+ ```ts
824
+ type UseEventListenerWithImplicitWindowTargetArgs<K> =
825
+ UseEventListenerWithExplicitTargetArgs<WindowEventMap, Window, K> extends [
826
+ unknown,
827
+ ...infer Args,
828
+ ]
829
+ ? Args
830
+ : never;
831
+ ```
832
+
833
+ Defined in: [hooks/useEventListener.ts:62](https://github.com/aweebit/react-essentials/blob/v0.8.0/src/hooks/useEventListener.ts#L62)
834
+
835
+ ### Type Parameters
836
+
837
+ <table>
838
+ <thead>
839
+ <tr>
840
+ <th>Type Parameter</th>
841
+ </tr>
842
+ </thead>
843
+ <tbody>
844
+ <tr>
845
+ <td>
846
+
847
+ `K` _extends_ keyof `WindowEventMap`
848
+
849
+ </td>
850
+ </tr>
851
+ </tbody>
852
+ </table>
853
+
854
+ ### See
855
+
856
+ [`useEventListener`](#useeventlistener-1),
857
+ [`UseEventListenerWithExplicitTargetArgs`](#useeventlistenerwithexplicittargetargs)
858
+
859
+ ---
860
+
861
+ ## UseEventListenerWithExplicitTargetArgs
862
+
863
+ ```ts
864
+ type UseEventListenerWithExplicitTargetArgs<EventMap, T, K> = [
865
+ (
866
+ | T
867
+ | (RefObject<T> & {
868
+ addEventListener?: never;
869
+ })
870
+ | null
871
+ ),
872
+ K,
873
+ (this, event) => void,
874
+ AddEventListenerOptions | boolean | undefined,
875
+ ];
876
+ ```
877
+
878
+ Defined in: [hooks/useEventListener.ts:76](https://github.com/aweebit/react-essentials/blob/v0.8.0/src/hooks/useEventListener.ts#L76)
879
+
880
+ ### Type Parameters
881
+
882
+ <table>
883
+ <thead>
884
+ <tr>
885
+ <th>Type Parameter</th>
886
+ </tr>
887
+ </thead>
888
+ <tbody>
889
+ <tr>
890
+ <td>
891
+
892
+ `EventMap`
893
+
894
+ </td>
895
+ </tr>
896
+ <tr>
897
+ <td>
898
+
899
+ `T` _extends_ `EventTarget`
900
+
901
+ </td>
902
+ </tr>
903
+ <tr>
904
+ <td>
905
+
906
+ `K` _extends_ keyof `EventMap`
907
+
908
+ </td>
909
+ </tr>
910
+ </tbody>
911
+ </table>
912
+
913
+ ### See
914
+
915
+ [`useEventListener`](#useeventlistener-1)
916
+
747
917
  ---
748
918
 
749
919
  ## RestrictedContext
@@ -761,7 +931,7 @@ type RestrictedContext<T> =
761
931
  };
762
932
  ```
763
933
 
764
- Defined in: [misc/createSafeContext.ts:17](https://github.com/aweebit/react-essentials/blob/v0.7.0/src/misc/createSafeContext.ts#L17)
934
+ Defined in: [misc/createSafeContext.ts:18](https://github.com/aweebit/react-essentials/blob/v0.8.0/src/misc/createSafeContext.ts#L18)
765
935
 
766
936
  A React context with a required `displayName` and the obsolete `Consumer`
767
937
  property purposefully omitted so that it is impossible to pass the context
@@ -801,7 +971,7 @@ type SafeContext<DisplayName, T> = {
801
971
  } & { [K in `use${DisplayName}`]: () => T };
802
972
  ```
803
973
 
804
- Defined in: [misc/createSafeContext.ts:27](https://github.com/aweebit/react-essentials/blob/v0.7.0/src/misc/createSafeContext.ts#L27)
974
+ Defined in: [misc/createSafeContext.ts:30](https://github.com/aweebit/react-essentials/blob/v0.8.0/src/misc/createSafeContext.ts#L30)
805
975
 
806
976
  The return type of [`createSafeContext`](#createsafecontext)
807
977
 
@@ -833,4 +1003,5 @@ The return type of [`createSafeContext`](#createsafecontext)
833
1003
 
834
1004
  ### See
835
1005
 
836
- [`createSafeContext`](#createsafecontext)
1006
+ [`createSafeContext`](#createsafecontext),
1007
+ [`RestrictedContext`](#restrictedcontext)
@@ -4,16 +4,68 @@
4
4
  * @license MIT
5
5
  * @copyright 2020 Julien CARON
6
6
  */
7
- type UseEventListenerOverloadArgs<EventMap, K extends keyof EventMap, T extends EventTarget> = [
8
- target: T | null,
7
+ import { type RefObject } from 'react';
8
+ /**
9
+ * The type of {@linkcode useEventListener}
10
+ *
11
+ * @see
12
+ * {@linkcode useEventListener},
13
+ * {@linkcode UseEventListenerWithImplicitWindowTarget},
14
+ * {@linkcode UseEventListenerWithExplicitTarget},
15
+ * {@linkcode UseEventListenerWithAnyExplicitTarget}
16
+ */
17
+ export type UseEventListener = UseEventListenerWithImplicitWindowTarget & UseEventListenerWithExplicitTarget<Window, WindowEventMap> & UseEventListenerWithExplicitTarget<Document, DocumentEventMap> & UseEventListenerWithExplicitTarget<HTMLElement, HTMLElementEventMap> & UseEventListenerWithExplicitTarget<SVGElement, SVGElementEventMap> & UseEventListenerWithExplicitTarget<MathMLElement, MathMLElementEventMap> & UseEventListenerWithAnyExplicitTarget;
18
+ /**
19
+ * @see
20
+ * {@linkcode useEventListener},
21
+ * {@linkcode UseEventListenerWithImplicitWindowTargetArgs} */
22
+ export type UseEventListenerWithImplicitWindowTarget = <K extends keyof WindowEventMap>(...args: UseEventListenerWithImplicitWindowTargetArgs<K>) => void;
23
+ /**
24
+ * @see
25
+ * {@linkcode useEventListener},
26
+ * {@linkcode UseEventListenerWithExplicitTargetArgs}
27
+ */
28
+ export type UseEventListenerWithExplicitTarget<Target extends EventTarget, EventMap = Record<string, Event>> = <T extends Target, K extends keyof EventMap>(...args: UseEventListenerWithExplicitTargetArgs<EventMap, T, K>) => void;
29
+ /**
30
+ * @see
31
+ * {@linkcode useEventListener},
32
+ * {@linkcode UseEventListenerWithExplicitTarget}
33
+ */
34
+ export type UseEventListenerWithAnyExplicitTarget = UseEventListenerWithExplicitTarget<EventTarget>;
35
+ /**
36
+ * @see
37
+ * {@linkcode useEventListener},
38
+ * {@linkcode UseEventListenerWithExplicitTargetArgs}
39
+ */
40
+ export type UseEventListenerWithImplicitWindowTargetArgs<K extends keyof WindowEventMap> = UseEventListenerWithExplicitTargetArgs<WindowEventMap, Window, K> extends [
41
+ unknown,
42
+ ...infer Args
43
+ ] ? Args : never;
44
+ /**
45
+ * @see
46
+ * {@linkcode useEventListener}
47
+ */
48
+ export type UseEventListenerWithExplicitTargetArgs<EventMap, T extends EventTarget, K extends keyof EventMap> = [
49
+ target: T | (RefObject<T> & {
50
+ addEventListener?: never;
51
+ }) | null,
9
52
  eventName: K,
10
53
  handler: (this: NoInfer<T>, event: EventMap[K]) => void,
11
- options?: AddEventListenerOptions | boolean
54
+ options?: AddEventListenerOptions | boolean | undefined
12
55
  ];
13
56
  /**
14
57
  * Adds `handler` as a listener for the event `eventName` of `target` with the
15
58
  * provided `options` applied
16
59
  *
60
+ * The following call signatures are available:
61
+ *
62
+ * ```ts
63
+ * function useEventListener(eventName, handler, options?): void;
64
+ * function useEventListener(target, eventName, handler, options?): void;
65
+ * ```
66
+ *
67
+ * For the full definition of the hook's type, see {@linkcode UseEventListener}.
68
+ *
17
69
  * If `target` is not provided, `window` is used instead.
18
70
  *
19
71
  * If `target` is `null`, no event listener is added. This is useful when
@@ -31,44 +83,11 @@ type UseEventListenerOverloadArgs<EventMap, K extends keyof EventMap, T extends
31
83
  * });
32
84
  *
33
85
  * const buttonRef = useRef<HTMLButtonElement>(null);
34
- * useEventListener(buttonRef.current, 'click', () => console.log('click'));
86
+ * useEventListener(buttonRef, 'click', () => console.log('click'));
35
87
  * ```
36
88
  *
37
- * @ignore
38
- */
39
- export declare function useEventListener<K extends keyof WindowEventMap>(eventName: K, handler: (this: Window, event: WindowEventMap[K]) => void, options?: AddEventListenerOptions | boolean): void;
40
- /**
41
- * @see {@linkcode useEventListener}
42
- * @ignore
43
- */
44
- export declare function useEventListener<K extends keyof WindowEventMap>(...args: UseEventListenerOverloadArgs<WindowEventMap, K, Window>): void;
45
- /**
46
- * @see {@linkcode useEventListener}
47
- * @ignore
48
- */
49
- export declare function useEventListener<K extends keyof DocumentEventMap>(...args: UseEventListenerOverloadArgs<DocumentEventMap, K, Document>): void;
50
- /**
51
- * @see {@linkcode useEventListener}
52
- * @ignore
53
- */
54
- export declare function useEventListener<K extends keyof HTMLElementEventMap, T extends HTMLElement>(...args: UseEventListenerOverloadArgs<HTMLElementEventMap, K, T>): void;
55
- /**
56
- * @see {@linkcode useEventListener}
57
- * @ignore
58
- */
59
- export declare function useEventListener<K extends keyof SVGElementEventMap, T extends SVGElement>(...args: UseEventListenerOverloadArgs<SVGElementEventMap, K, T>): void;
60
- /**
61
- * @see {@linkcode useEventListener}
62
- * @ignore
63
- */
64
- export declare function useEventListener<K extends keyof MathMLElementEventMap, T extends MathMLElement>(...args: UseEventListenerOverloadArgs<MathMLElementEventMap, K, T>): void;
65
- /**
66
- * @see {@linkcode useEventListener}
67
- */
68
- export declare function useEventListener<K extends keyof WindowEventMap>(eventName: K, handler: (this: Window, event: WindowEventMap[K]) => void, options?: AddEventListenerOptions | boolean): void;
69
- /**
70
- * @see {@linkcode useEventListener}
89
+ * @see
90
+ * {@linkcode UseEventListener}
71
91
  */
72
- export declare function useEventListener<T extends EventTarget>(target: T | null, eventName: string, handler: (this: NoInfer<T>, event: Event) => void, options?: AddEventListenerOptions | boolean): void;
73
- export {};
92
+ export declare const useEventListener: UseEventListener;
74
93
  //# sourceMappingURL=useEventListener.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"useEventListener.d.ts","sourceRoot":"","sources":["../../src/hooks/useEventListener.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAIH,KAAK,4BAA4B,CAC/B,QAAQ,EACR,CAAC,SAAS,MAAM,QAAQ,EACxB,CAAC,SAAS,WAAW,IACnB;IACF,MAAM,EAAE,CAAC,GAAG,IAAI;IAChB,SAAS,EAAE,CAAC;IACZ,OAAO,EAAE,CAAC,IAAI,EAAE,OAAO,CAAC,CAAC,CAAC,EAAE,KAAK,EAAE,QAAQ,CAAC,CAAC,CAAC,KAAK,IAAI;IACvD,OAAO,CAAC,EAAE,uBAAuB,GAAG,OAAO;CAC5C,CAAC;AAEF;;;;;;;;;;;;;;;;;;;;;;;;;GAyBG;AACH,wBAAgB,gBAAgB,CAAC,CAAC,SAAS,MAAM,cAAc,EAC7D,SAAS,EAAE,CAAC,EACZ,OAAO,EAAE,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,cAAc,CAAC,CAAC,CAAC,KAAK,IAAI,EACzD,OAAO,CAAC,EAAE,uBAAuB,GAAG,OAAO,GAC1C,IAAI,CAAC;AAER;;;GAGG;AACH,wBAAgB,gBAAgB,CAAC,CAAC,SAAS,MAAM,cAAc,EAC7D,GAAG,IAAI,EAAE,4BAA4B,CAAC,cAAc,EAAE,CAAC,EAAE,MAAM,CAAC,GAC/D,IAAI,CAAC;AAER;;;GAGG;AACH,wBAAgB,gBAAgB,CAAC,CAAC,SAAS,MAAM,gBAAgB,EAC/D,GAAG,IAAI,EAAE,4BAA4B,CAAC,gBAAgB,EAAE,CAAC,EAAE,QAAQ,CAAC,GACnE,IAAI,CAAC;AAER;;;GAGG;AACH,wBAAgB,gBAAgB,CAC9B,CAAC,SAAS,MAAM,mBAAmB,EACnC,CAAC,SAAS,WAAW,EACrB,GAAG,IAAI,EAAE,4BAA4B,CAAC,mBAAmB,EAAE,CAAC,EAAE,CAAC,CAAC,GAAG,IAAI,CAAC;AAE1E;;;GAGG;AACH,wBAAgB,gBAAgB,CAC9B,CAAC,SAAS,MAAM,kBAAkB,EAClC,CAAC,SAAS,UAAU,EACpB,GAAG,IAAI,EAAE,4BAA4B,CAAC,kBAAkB,EAAE,CAAC,EAAE,CAAC,CAAC,GAAG,IAAI,CAAC;AAEzE;;;GAGG;AACH,wBAAgB,gBAAgB,CAC9B,CAAC,SAAS,MAAM,qBAAqB,EACrC,CAAC,SAAS,aAAa,EACvB,GAAG,IAAI,EAAE,4BAA4B,CAAC,qBAAqB,EAAE,CAAC,EAAE,CAAC,CAAC,GAAG,IAAI,CAAC;AAE5E;;GAEG;AACH,wBAAgB,gBAAgB,CAAC,CAAC,SAAS,MAAM,cAAc,EAC7D,SAAS,EAAE,CAAC,EACZ,OAAO,EAAE,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,cAAc,CAAC,CAAC,CAAC,KAAK,IAAI,EACzD,OAAO,CAAC,EAAE,uBAAuB,GAAG,OAAO,GAC1C,IAAI,CAAC;AAER;;GAEG;AACH,wBAAgB,gBAAgB,CAAC,CAAC,SAAS,WAAW,EACpD,MAAM,EAAE,CAAC,GAAG,IAAI,EAChB,SAAS,EAAE,MAAM,EACjB,OAAO,EAAE,CAAC,IAAI,EAAE,OAAO,CAAC,CAAC,CAAC,EAAE,KAAK,EAAE,KAAK,KAAK,IAAI,EACjD,OAAO,CAAC,EAAE,uBAAuB,GAAG,OAAO,GAC1C,IAAI,CAAC"}
1
+ {"version":3,"file":"useEventListener.d.ts","sourceRoot":"","sources":["../../src/hooks/useEventListener.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,EAA8B,KAAK,SAAS,EAAE,MAAM,OAAO,CAAC;AAEnE;;;;;;;;GAQG;AACH,MAAM,MAAM,gBAAgB,GAAG,wCAAwC,GACrE,kCAAkC,CAAC,MAAM,EAAE,cAAc,CAAC,GAC1D,kCAAkC,CAAC,QAAQ,EAAE,gBAAgB,CAAC,GAC9D,kCAAkC,CAAC,WAAW,EAAE,mBAAmB,CAAC,GACpE,kCAAkC,CAAC,UAAU,EAAE,kBAAkB,CAAC,GAClE,kCAAkC,CAAC,aAAa,EAAE,qBAAqB,CAAC,GACxE,qCAAqC,CAAC;AAExC;;;8DAG8D;AAC9D,MAAM,MAAM,wCAAwC,GAAG,CACrD,CAAC,SAAS,MAAM,cAAc,EAE9B,GAAG,IAAI,EAAE,4CAA4C,CAAC,CAAC,CAAC,KACrD,IAAI,CAAC;AAEV;;;;GAIG;AACH,MAAM,MAAM,kCAAkC,CAC5C,MAAM,SAAS,WAAW,EAC1B,QAAQ,GAAG,MAAM,CAAC,MAAM,EAAE,KAAK,CAAC,IAC9B,CAAC,CAAC,SAAS,MAAM,EAAE,CAAC,SAAS,MAAM,QAAQ,EAC7C,GAAG,IAAI,EAAE,sCAAsC,CAAC,QAAQ,EAAE,CAAC,EAAE,CAAC,CAAC,KAC5D,IAAI,CAAC;AAEV;;;;GAIG;AACH,MAAM,MAAM,qCAAqC,GAC/C,kCAAkC,CAAC,WAAW,CAAC,CAAC;AAElD;;;;GAIG;AACH,MAAM,MAAM,4CAA4C,CACtD,CAAC,SAAS,MAAM,cAAc,IAE9B,sCAAsC,CAAC,cAAc,EAAE,MAAM,EAAE,CAAC,CAAC,SAAS;IACxE,OAAO;IACP,GAAG,MAAM,IAAI;CACd,GACG,IAAI,GACJ,KAAK,CAAC;AAEZ;;;GAGG;AACH,MAAM,MAAM,sCAAsC,CAChD,QAAQ,EACR,CAAC,SAAS,WAAW,EACrB,CAAC,SAAS,MAAM,QAAQ,IACtB;IACF,MAAM,EAAE,CAAC,GAAG,CAAC,SAAS,CAAC,CAAC,CAAC,GAAG;QAAE,gBAAgB,CAAC,EAAE,KAAK,CAAA;KAAE,CAAC,GAAG,IAAI;IAChE,SAAS,EAAE,CAAC;IACZ,OAAO,EAAE,CAAC,IAAI,EAAE,OAAO,CAAC,CAAC,CAAC,EAAE,KAAK,EAAE,QAAQ,CAAC,CAAC,CAAC,KAAK,IAAI;IACvD,OAAO,CAAC,EAAE,uBAAuB,GAAG,OAAO,GAAG,SAAS;CACxD,CAAC;AAYF;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAmCG;AACH,eAAO,MAAM,gBAAgB,EAAE,gBAkDV,CAAC"}
@@ -9,6 +9,15 @@ import { useEffect, useMemo, useRef } from 'react';
9
9
  * Adds `handler` as a listener for the event `eventName` of `target` with the
10
10
  * provided `options` applied
11
11
  *
12
+ * The following call signatures are available:
13
+ *
14
+ * ```ts
15
+ * function useEventListener(eventName, handler, options?): void;
16
+ * function useEventListener(target, eventName, handler, options?): void;
17
+ * ```
18
+ *
19
+ * For the full definition of the hook's type, see {@linkcode UseEventListener}.
20
+ *
12
21
  * If `target` is not provided, `window` is used instead.
13
22
  *
14
23
  * If `target` is `null`, no event listener is added. This is useful when
@@ -26,21 +35,17 @@ import { useEffect, useMemo, useRef } from 'react';
26
35
  * });
27
36
  *
28
37
  * const buttonRef = useRef<HTMLButtonElement>(null);
29
- * useEventListener(buttonRef.current, 'click', () => console.log('click'));
38
+ * useEventListener(buttonRef, 'click', () => console.log('click'));
30
39
  * ```
40
+ *
41
+ * @see
42
+ * {@linkcode UseEventListener}
31
43
  */
32
- export function useEventListener(...args) {
33
- let eventName;
34
- let handler;
35
- let target;
36
- let options;
37
- if (typeof args[0] === 'string') {
38
- [eventName, handler, options] = args;
39
- }
40
- else {
41
- [target, eventName, handler, options] =
42
- args;
43
- }
44
+ export const useEventListener = function useEventListener(...args) {
45
+ const [target, eventName, handler, options] = typeof args[0] === 'string'
46
+ ? [window, ...args]
47
+ : args;
48
+ const unwrappedTarget = target && !('addEventListener' in target) ? target.current : target;
44
49
  const handlerRef = useRef(handler);
45
50
  handlerRef.current = handler;
46
51
  const { capture = false, once = false, passive, signal, } = typeof options === 'boolean' ? { capture: options } : (options ?? {});
@@ -48,18 +53,17 @@ export function useEventListener(...args) {
48
53
  // eslint-disable-next-line react-hooks/exhaustive-deps
49
54
  [capture, once, passive, signal]);
50
55
  useEffect(() => {
51
- if (target === null) {
56
+ if (unwrappedTarget === null) {
52
57
  // No element has been attached to the ref yet
53
58
  return;
54
59
  }
55
- const definedTarget = target ?? window;
56
60
  const listener = function (event) {
57
61
  handlerRef.current.call(this, event);
58
62
  };
59
- definedTarget.addEventListener(eventName, listener, memoizedOptions);
63
+ unwrappedTarget.addEventListener(eventName, listener, memoizedOptions);
60
64
  return () => {
61
- definedTarget.removeEventListener(eventName, listener, memoizedOptions);
65
+ unwrappedTarget.removeEventListener(eventName, listener, memoizedOptions);
62
66
  };
63
- }, [eventName, target, memoizedOptions]);
64
- }
67
+ }, [unwrappedTarget, eventName, memoizedOptions]);
68
+ };
65
69
  //# sourceMappingURL=useEventListener.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"useEventListener.js","sourceRoot":"","sources":["../../src/hooks/useEventListener.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,EAAE,SAAS,EAAE,OAAO,EAAE,MAAM,EAAE,MAAM,OAAO,CAAC;AA2GnD;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AACH,MAAM,UAAU,gBAAgB,CAC9B,GAAG,IAAwE;IAE3E,IAAI,SAAiB,CAAC;IACtB,IAAI,OAAkD,CAAC;IACvD,IAAI,MAAsC,CAAC;IAC3C,IAAI,OAAsD,CAAC;IAE3D,IAAI,OAAO,IAAI,CAAC,CAAC,CAAC,KAAK,QAAQ,EAAE,CAAC;QAChC,CAAC,SAAS,EAAE,OAAO,EAAE,OAAO,CAAC,GAAG,IAAyC,CAAC;IAC5E,CAAC;SAAM,CAAC;QACN,CAAC,MAAM,EAAE,SAAS,EAAE,OAAO,EAAE,OAAO,CAAC;YACnC,IAAsC,CAAC;IAC3C,CAAC;IAED,MAAM,UAAU,GAAG,MAAM,CAAC,OAAO,CAAC,CAAC;IACnC,UAAU,CAAC,OAAO,GAAG,OAAO,CAAC;IAE7B,MAAM,EACJ,OAAO,GAAG,KAAK,EACf,IAAI,GAAG,KAAK,EACZ,OAAO,EACP,MAAM,GACP,GAAG,OAAO,OAAO,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,OAAO,EAAE,OAAO,EAAE,CAAC,CAAC,CAAC,CAAC,OAAO,IAAI,EAAE,CAAC,CAAC;IAE1E,MAAM,eAAe,GAAG,OAAO,CAC7B,GAAG,EAAE,CAAC,OAAO;IACb,uDAAuD;IACvD,CAAC,OAAO,EAAE,IAAI,EAAE,OAAO,EAAE,MAAM,CAAC,CACjC,CAAC;IAEF,SAAS,CAAC,GAAG,EAAE;QACb,IAAI,MAAM,KAAK,IAAI,EAAE,CAAC;YACpB,8CAA8C;YAC9C,OAAO;QACT,CAAC;QAED,MAAM,aAAa,GAAG,MAAM,IAAI,MAAM,CAAC;QAEvC,MAAM,QAAQ,GAAmB,UAAU,KAAK;YAC9C,UAAU,CAAC,OAAO,CAAC,IAAI,CAAC,IAAI,EAAE,KAAK,CAAC,CAAC;QACvC,CAAC,CAAC;QAEF,aAAa,CAAC,gBAAgB,CAAC,SAAS,EAAE,QAAQ,EAAE,eAAe,CAAC,CAAC;QAErE,OAAO,GAAG,EAAE;YACV,aAAa,CAAC,mBAAmB,CAAC,SAAS,EAAE,QAAQ,EAAE,eAAe,CAAC,CAAC;QAC1E,CAAC,CAAC;IACJ,CAAC,EAAE,CAAC,SAAS,EAAE,MAAM,EAAE,eAAe,CAAC,CAAC,CAAC;AAC3C,CAAC"}
1
+ {"version":3,"file":"useEventListener.js","sourceRoot":"","sources":["../../src/hooks/useEventListener.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,EAAE,SAAS,EAAE,OAAO,EAAE,MAAM,EAAkB,MAAM,OAAO,CAAC;AAyFnE;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAmCG;AACH,MAAM,CAAC,MAAM,gBAAgB,GAAqB,SAAS,gBAAgB,CACzE,GAAG,IAE0C;IAE7C,MAAM,CAAC,MAAM,EAAE,SAAS,EAAE,OAAO,EAAE,OAAO,CAAC,GAMzC,OAAO,IAAI,CAAC,CAAC,CAAC,KAAK,QAAQ;QACzB,CAAC,CAAC,CAAC,MAAM,EAAE,GAAI,IAAwD,CAAC;QACxE,CAAC,CAAE,IAAkD,CAAC;IAE1D,MAAM,eAAe,GACnB,MAAM,IAAI,CAAC,CAAC,kBAAkB,IAAI,MAAM,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC;IAEtE,MAAM,UAAU,GAAG,MAAM,CAAC,OAAO,CAAC,CAAC;IACnC,UAAU,CAAC,OAAO,GAAG,OAAO,CAAC;IAE7B,MAAM,EACJ,OAAO,GAAG,KAAK,EACf,IAAI,GAAG,KAAK,EACZ,OAAO,EACP,MAAM,GACP,GAAG,OAAO,OAAO,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,OAAO,EAAE,OAAO,EAAE,CAAC,CAAC,CAAC,CAAC,OAAO,IAAI,EAAE,CAAC,CAAC;IAE1E,MAAM,eAAe,GAAG,OAAO,CAC7B,GAAG,EAAE,CAAC,OAAO;IACb,uDAAuD;IACvD,CAAC,OAAO,EAAE,IAAI,EAAE,OAAO,EAAE,MAAM,CAAC,CACjC,CAAC;IAEF,SAAS,CAAC,GAAG,EAAE;QACb,IAAI,eAAe,KAAK,IAAI,EAAE,CAAC;YAC7B,8CAA8C;YAC9C,OAAO;QACT,CAAC;QAED,MAAM,QAAQ,GAAmB,UAAU,KAAK;YAC9C,UAAU,CAAC,OAAO,CAAC,IAAI,CAAC,IAAI,EAAE,KAAK,CAAC,CAAC;QACvC,CAAC,CAAC;QAEF,eAAe,CAAC,gBAAgB,CAAC,SAAS,EAAE,QAAQ,EAAE,eAAe,CAAC,CAAC;QAEvE,OAAO,GAAG,EAAE;YACV,eAAe,CAAC,mBAAmB,CAAC,SAAS,EAAE,QAAQ,EAAE,eAAe,CAAC,CAAC;QAC5E,CAAC,CAAC;IACJ,CAAC,EAAE,CAAC,eAAe,EAAE,SAAS,EAAE,eAAe,CAAC,CAAC,CAAC;AACpD,CAAqB,CAAC"}
@@ -1 +1 @@
1
- {"version":3,"file":"useReducerWithDeps.d.ts","sourceRoot":"","sources":["../../src/hooks/useReducerWithDeps.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,cAAc,EAAuB,MAAM,OAAO,CAAC;AAOjE,cAAc;AAEd,MAAM,MAAM,YAAY,GAAG,EAAE,GAAG,CAAC,GAAG,CAAC,CAAC;AAEtC,cAAc;AACd,MAAM,MAAM,cAAc,CAAC,SAAS,SAAS,YAAY,IAAI,CAC3D,GAAG,IAAI,EAAE,SAAS,KACf,IAAI,CAAC;AAEV;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAkCG;AACH,wBAAgB,kBAAkB,CAAC,CAAC,EAAE,CAAC,SAAS,YAAY,EAC1D,OAAO,EAAE,CAAC,SAAS,EAAE,CAAC,EAAE,GAAG,IAAI,EAAE,CAAC,KAAK,CAAC,EACxC,YAAY,EAAE,CAAC,GAAG,CAAC,CAAC,aAAa,CAAC,EAAE,CAAC,KAAK,CAAC,CAAC,EAC5C,IAAI,EAAE,cAAc,GACnB,CAAC,CAAC,EAAE,cAAc,CAAC,CAAC,CAAC,CAAC,CAYxB"}
1
+ {"version":3,"file":"useReducerWithDeps.d.ts","sourceRoot":"","sources":["../../src/hooks/useReducerWithDeps.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,cAAc,EAAU,MAAM,OAAO,CAAC;AAOpD,cAAc;AAEd,MAAM,MAAM,YAAY,GAAG,EAAE,GAAG,CAAC,GAAG,CAAC,CAAC;AAEtC,cAAc;AACd,MAAM,MAAM,cAAc,CAAC,SAAS,SAAS,YAAY,IAAI,CAC3D,GAAG,IAAI,EAAE,SAAS,KACf,IAAI,CAAC;AAEV;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAkCG;AACH,wBAAgB,kBAAkB,CAAC,CAAC,EAAE,CAAC,SAAS,YAAY,EAC1D,OAAO,EAAE,CAAC,SAAS,EAAE,CAAC,EAAE,GAAG,IAAI,EAAE,CAAC,KAAK,CAAC,EACxC,YAAY,EAAE,CAAC,GAAG,CAAC,CAAC,aAAa,CAAC,EAAE,CAAC,KAAK,CAAC,CAAC,EAC5C,IAAI,EAAE,cAAc,GACnB,CAAC,CAAC,EAAE,cAAc,CAAC,CAAC,CAAC,CAAC,CAYxB"}
@@ -1,4 +1,4 @@
1
- import { useCallback, useRef } from 'react';
1
+ import { useRef } from 'react';
2
2
  import { useStateWithDeps } from './useStateWithDeps.js';
3
3
  /**
4
4
  * `useReducer` hook with an additional dependency array `deps` that resets the
@@ -40,9 +40,9 @@ export function useReducerWithDeps(reducer, initialState, deps) {
40
40
  const [state, setState] = useStateWithDeps(initialState, deps);
41
41
  // Only the initially provided reducer is used
42
42
  const reducerRef = useRef(reducer);
43
- const dispatch = useCallback(function dispatch(...args) {
43
+ const dispatch = useRef(function dispatch(...args) {
44
44
  setState((previousState) => reducerRef.current(previousState, ...args));
45
- }, []); // eslint-disable-line react-hooks/exhaustive-deps
45
+ }).current;
46
46
  return [state, dispatch];
47
47
  }
48
48
  //# sourceMappingURL=useReducerWithDeps.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"useReducerWithDeps.js","sourceRoot":"","sources":["../../src/hooks/useReducerWithDeps.ts"],"names":[],"mappings":"AAAA,OAAO,EAAuB,WAAW,EAAE,MAAM,EAAE,MAAM,OAAO,CAAC;AACjE,OAAO,EAAE,gBAAgB,EAAE,MAAM,uBAAuB,CAAC;AAezD;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAkCG;AACH,MAAM,UAAU,kBAAkB,CAChC,OAAwC,EACxC,YAA4C,EAC5C,IAAoB;IAEpB,uDAAuD;IACvD,MAAM,CAAC,KAAK,EAAE,QAAQ,CAAC,GAAG,gBAAgB,CAAC,YAAY,EAAE,IAAI,CAAC,CAAC;IAE/D,8CAA8C;IAC9C,MAAM,UAAU,GAAG,MAAM,CAAC,OAAO,CAAC,CAAC;IAEnC,MAAM,QAAQ,GAAG,WAAW,CAAC,SAAS,QAAQ,CAAC,GAAG,IAAO;QACvD,QAAQ,CAAC,CAAC,aAAa,EAAE,EAAE,CAAC,UAAU,CAAC,OAAO,CAAC,aAAa,EAAE,GAAG,IAAI,CAAC,CAAC,CAAC;IAC1E,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,kDAAkD;IAE1D,OAAO,CAAC,KAAK,EAAE,QAAQ,CAAC,CAAC;AAC3B,CAAC"}
1
+ {"version":3,"file":"useReducerWithDeps.js","sourceRoot":"","sources":["../../src/hooks/useReducerWithDeps.ts"],"names":[],"mappings":"AAAA,OAAO,EAAuB,MAAM,EAAE,MAAM,OAAO,CAAC;AACpD,OAAO,EAAE,gBAAgB,EAAE,MAAM,uBAAuB,CAAC;AAezD;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAkCG;AACH,MAAM,UAAU,kBAAkB,CAChC,OAAwC,EACxC,YAA4C,EAC5C,IAAoB;IAEpB,uDAAuD;IACvD,MAAM,CAAC,KAAK,EAAE,QAAQ,CAAC,GAAG,gBAAgB,CAAC,YAAY,EAAE,IAAI,CAAC,CAAC;IAE/D,8CAA8C;IAC9C,MAAM,UAAU,GAAG,MAAM,CAAC,OAAO,CAAC,CAAC;IAEnC,MAAM,QAAQ,GAAG,MAAM,CAAC,SAAS,QAAQ,CAAC,GAAG,IAAO;QAClD,QAAQ,CAAC,CAAC,aAAa,EAAE,EAAE,CAAC,UAAU,CAAC,OAAO,CAAC,aAAa,EAAE,GAAG,IAAI,CAAC,CAAC,CAAC;IAC1E,CAAC,CAAC,CAAC,OAAO,CAAC;IAEX,OAAO,CAAC,KAAK,EAAE,QAAQ,CAAC,CAAC;AAC3B,CAAC"}
@@ -1 +1 @@
1
- {"version":3,"file":"useStateWithDeps.d.ts","sourceRoot":"","sources":["../../src/hooks/useStateWithDeps.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,EAGL,KAAK,cAAc,EACnB,KAAK,QAAQ,EACb,KAAK,cAAc,EACpB,MAAM,OAAO,CAAC;AAIf;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA+CG;AACH,wBAAgB,gBAAgB,CAAC,CAAC,EAChC,YAAY,EAAE,CAAC,GAAG,CAAC,CAAC,aAAa,CAAC,EAAE,CAAC,KAAK,CAAC,CAAC,EAC5C,IAAI,EAAE,cAAc,GACnB,CAAC,CAAC,EAAE,QAAQ,CAAC,cAAc,CAAC,CAAC,CAAC,CAAC,CAAC,CA0ClC"}
1
+ {"version":3,"file":"useStateWithDeps.d.ts","sourceRoot":"","sources":["../../src/hooks/useStateWithDeps.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,EAEL,KAAK,cAAc,EACnB,KAAK,QAAQ,EACb,KAAK,cAAc,EACpB,MAAM,OAAO,CAAC;AAIf;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA+CG;AACH,wBAAgB,gBAAgB,CAAC,CAAC,EAChC,YAAY,EAAE,CAAC,GAAG,CAAC,CAAC,aAAa,CAAC,EAAE,CAAC,KAAK,CAAC,CAAC,EAC5C,IAAI,EAAE,cAAc,GACnB,CAAC,CAAC,EAAE,QAAQ,CAAC,cAAc,CAAC,CAAC,CAAC,CAAC,CAAC,CA0ClC"}
@@ -4,7 +4,7 @@
4
4
  * @license MIT
5
5
  * @copyright 2020 Peter Juras
6
6
  */
7
- import { useCallback, useRef, } from 'react';
7
+ import { useRef, } from 'react';
8
8
  import { depsAreEqual, isFunction } from '../utils.js';
9
9
  import { useForceUpdate } from './useForceUpdate.js';
10
10
  /**
@@ -78,7 +78,7 @@ export function useStateWithDeps(initialState, deps) {
78
78
  isMounted.current = true;
79
79
  }
80
80
  const [forceUpdate] = useForceUpdate();
81
- const updateState = useCallback(function updateState(newState) {
81
+ const updateState = useRef(function updateState(newState) {
82
82
  let nextState;
83
83
  if (isFunction(newState)) {
84
84
  nextState = newState(state.current);
@@ -90,7 +90,7 @@ export function useStateWithDeps(initialState, deps) {
90
90
  state.current = nextState;
91
91
  forceUpdate();
92
92
  }
93
- }, []); // eslint-disable-line react-hooks/exhaustive-deps
93
+ }).current;
94
94
  return [state.current, updateState];
95
95
  }
96
96
  //# sourceMappingURL=useStateWithDeps.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"useStateWithDeps.js","sourceRoot":"","sources":["../../src/hooks/useStateWithDeps.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,EACL,WAAW,EACX,MAAM,GAIP,MAAM,OAAO,CAAC;AACf,OAAO,EAAE,YAAY,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AACvD,OAAO,EAAE,cAAc,EAAE,MAAM,qBAAqB,CAAC;AAErD;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA+CG;AACH,MAAM,UAAU,gBAAgB,CAC9B,YAA4C,EAC5C,IAAoB;IAEpB,6EAA6E;IAC7E,6EAA6E;IAC7E,2EAA2E;IAC3E,8EAA8E;IAC9E,MAAM,KAAK,GAAG,MAAM,CAAC,SAAc,CAAC,CAAC;IAErC,MAAM,QAAQ,GAAG,MAAM,CAAC,IAAI,CAAC,CAAC;IAC9B,MAAM,SAAS,GAAG,MAAM,CAAC,KAAK,CAAC,CAAC;IAEhC,mEAAmE;IACnE,IAAI,CAAC,SAAS,CAAC,OAAO,IAAI,CAAC,YAAY,CAAC,QAAQ,CAAC,OAAO,EAAE,IAAI,CAAC,EAAE,CAAC;QAChE,wBAAwB;QACxB,IAAI,SAAY,CAAC;QACjB,IAAI,UAAU,CAAC,YAAY,CAAC,EAAE,CAAC;YAC7B,SAAS,GAAG,YAAY,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC;QAC1C,CAAC;aAAM,CAAC;YACN,SAAS,GAAG,YAAY,CAAC;QAC3B,CAAC;QACD,KAAK,CAAC,OAAO,GAAG,SAAS,CAAC;QAC1B,QAAQ,CAAC,OAAO,GAAG,IAAI,CAAC;QACxB,SAAS,CAAC,OAAO,GAAG,IAAI,CAAC;IAC3B,CAAC;IAED,MAAM,CAAC,WAAW,CAAC,GAAG,cAAc,EAAE,CAAC;IAEvC,MAAM,WAAW,GAAG,WAAW,CAAC,SAAS,WAAW,CAClD,QAAuC;QAEvC,IAAI,SAAY,CAAC;QACjB,IAAI,UAAU,CAAC,QAAQ,CAAC,EAAE,CAAC;YACzB,SAAS,GAAG,QAAQ,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC;QACtC,CAAC;aAAM,CAAC;YACN,SAAS,GAAG,QAAQ,CAAC;QACvB,CAAC;QACD,IAAI,CAAC,MAAM,CAAC,EAAE,CAAC,KAAK,CAAC,OAAO,EAAE,SAAS,CAAC,EAAE,CAAC;YACzC,KAAK,CAAC,OAAO,GAAG,SAAS,CAAC;YAC1B,WAAW,EAAE,CAAC;QAChB,CAAC;IACH,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,kDAAkD;IAE1D,OAAO,CAAC,KAAK,CAAC,OAAO,EAAE,WAAW,CAAC,CAAC;AACtC,CAAC"}
1
+ {"version":3,"file":"useStateWithDeps.js","sourceRoot":"","sources":["../../src/hooks/useStateWithDeps.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,EACL,MAAM,GAIP,MAAM,OAAO,CAAC;AACf,OAAO,EAAE,YAAY,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AACvD,OAAO,EAAE,cAAc,EAAE,MAAM,qBAAqB,CAAC;AAErD;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA+CG;AACH,MAAM,UAAU,gBAAgB,CAC9B,YAA4C,EAC5C,IAAoB;IAEpB,6EAA6E;IAC7E,6EAA6E;IAC7E,2EAA2E;IAC3E,8EAA8E;IAC9E,MAAM,KAAK,GAAG,MAAM,CAAC,SAAc,CAAC,CAAC;IAErC,MAAM,QAAQ,GAAG,MAAM,CAAC,IAAI,CAAC,CAAC;IAC9B,MAAM,SAAS,GAAG,MAAM,CAAC,KAAK,CAAC,CAAC;IAEhC,mEAAmE;IACnE,IAAI,CAAC,SAAS,CAAC,OAAO,IAAI,CAAC,YAAY,CAAC,QAAQ,CAAC,OAAO,EAAE,IAAI,CAAC,EAAE,CAAC;QAChE,wBAAwB;QACxB,IAAI,SAAY,CAAC;QACjB,IAAI,UAAU,CAAC,YAAY,CAAC,EAAE,CAAC;YAC7B,SAAS,GAAG,YAAY,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC;QAC1C,CAAC;aAAM,CAAC;YACN,SAAS,GAAG,YAAY,CAAC;QAC3B,CAAC;QACD,KAAK,CAAC,OAAO,GAAG,SAAS,CAAC;QAC1B,QAAQ,CAAC,OAAO,GAAG,IAAI,CAAC;QACxB,SAAS,CAAC,OAAO,GAAG,IAAI,CAAC;IAC3B,CAAC;IAED,MAAM,CAAC,WAAW,CAAC,GAAG,cAAc,EAAE,CAAC;IAEvC,MAAM,WAAW,GAAG,MAAM,CAAC,SAAS,WAAW,CAC7C,QAAuC;QAEvC,IAAI,SAAY,CAAC;QACjB,IAAI,UAAU,CAAC,QAAQ,CAAC,EAAE,CAAC;YACzB,SAAS,GAAG,QAAQ,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC;QACtC,CAAC;aAAM,CAAC;YACN,SAAS,GAAG,QAAQ,CAAC;QACvB,CAAC;QACD,IAAI,CAAC,MAAM,CAAC,EAAE,CAAC,KAAK,CAAC,OAAO,EAAE,SAAS,CAAC,EAAE,CAAC;YACzC,KAAK,CAAC,OAAO,GAAG,SAAS,CAAC;YAC1B,WAAW,EAAE,CAAC;QAChB,CAAC;IACH,CAAC,CAAC,CAAC,OAAO,CAAC;IAEX,OAAO,CAAC,KAAK,CAAC,OAAO,EAAE,WAAW,CAAC,CAAC;AACtC,CAAC"}
@@ -6,7 +6,8 @@ import type { ArgumentFallback } from '../utils.js';
6
6
  * as an argument to `useContext` or `use` (the hook produced with
7
7
  * {@linkcode createSafeContext} should be used instead)
8
8
  *
9
- * @see {@linkcode createSafeContext}
9
+ * @see
10
+ * {@linkcode createSafeContext}
10
11
  */
11
12
  export type RestrictedContext<T> = Context<T> extends Provider<T> ? {
12
13
  Provider: Provider<T>;
@@ -18,7 +19,9 @@ export type RestrictedContext<T> = Context<T> extends Provider<T> ? {
18
19
  /**
19
20
  * The return type of {@linkcode createSafeContext}
20
21
  *
21
- * @see {@linkcode createSafeContext}
22
+ * @see
23
+ * {@linkcode createSafeContext},
24
+ * {@linkcode RestrictedContext}
22
25
  */
23
26
  export type SafeContext<DisplayName extends string, T> = {
24
27
  [K in `${DisplayName}Context`]: RestrictedContext<T>;
@@ -80,6 +83,9 @@ export type SafeContext<DisplayName extends string, T> = {
80
83
  * - ``` `${displayName}Context` ``` (e.g. `DirectionContext`): the context
81
84
  * - ``` `use${displayName}` ``` (e.g. `useDirection`): a hook that returns the
82
85
  * current context value if one was provided, or throws an error otherwise
86
+ *
87
+ * @see
88
+ * {@linkcode SafeContext}
83
89
  */
84
90
  export declare function createSafeContext<T = never>(): <DisplayName extends string>(displayName: [T] extends [never] ? never : ArgumentFallback<DisplayName, never, string>) => SafeContext<DisplayName, T>;
85
91
  //# sourceMappingURL=createSafeContext.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"createSafeContext.d.ts","sourceRoot":"","sources":["../../src/misc/createSafeContext.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,OAAO,EAAE,KAAK,QAAQ,EAA6B,MAAM,OAAO,CAAC;AAC/E,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,aAAa,CAAC;AAIpD;;;;;;;GAOG;AAIH,MAAM,MAAM,iBAAiB,CAAC,CAAC,IAC7B,OAAO,CAAC,CAAC,CAAC,SAAS,QAAQ,CAAC,CAAC,CAAC,GAC1B;IAAE,QAAQ,EAAE,QAAQ,CAAC,CAAC,CAAC,CAAC;IAAC,WAAW,EAAE,MAAM,CAAA;CAAE,GAAG,QAAQ,CAAC,CAAC,CAAC,GAC5D;IAAE,QAAQ,EAAE,QAAQ,CAAC,CAAC,CAAC,CAAC;IAAC,WAAW,EAAE,MAAM,CAAA;CAAE,CAAC;AAErD;;;;GAIG;AACH,MAAM,MAAM,WAAW,CAAC,WAAW,SAAS,MAAM,EAAE,CAAC,IAAI;KACtD,CAAC,IAAI,GAAG,WAAW,SAAS,GAAG,iBAAiB,CAAC,CAAC,CAAC;CACrD,GAAG;KACD,CAAC,IAAI,MAAM,WAAW,EAAE,GAAG,MAAM,CAAC;CACpC,CAAC;AAEF;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAuDG;AACH,wBAAgB,iBAAiB,CAAC,CAAC,GAAG,KAAK,MACjC,WAAW,SAAS,MAAM,EAChC,aAAa,CAAC,CAAC,CAAC,SAAS,CAAC,KAAK,CAAC,GAC5B,KAAK,GACL,gBAAgB,CAAC,WAAW,EAAE,KAAK,EAAE,MAAM,CAAC,KAC/C,WAAW,CAAC,WAAW,EAAE,CAAC,CAAC,CAsB/B"}
1
+ {"version":3,"file":"createSafeContext.d.ts","sourceRoot":"","sources":["../../src/misc/createSafeContext.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,OAAO,EAAE,KAAK,QAAQ,EAA6B,MAAM,OAAO,CAAC;AAC/E,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,aAAa,CAAC;AAIpD;;;;;;;;GAQG;AAIH,MAAM,MAAM,iBAAiB,CAAC,CAAC,IAC7B,OAAO,CAAC,CAAC,CAAC,SAAS,QAAQ,CAAC,CAAC,CAAC,GAC1B;IAAE,QAAQ,EAAE,QAAQ,CAAC,CAAC,CAAC,CAAC;IAAC,WAAW,EAAE,MAAM,CAAA;CAAE,GAAG,QAAQ,CAAC,CAAC,CAAC,GAC5D;IAAE,QAAQ,EAAE,QAAQ,CAAC,CAAC,CAAC,CAAC;IAAC,WAAW,EAAE,MAAM,CAAA;CAAE,CAAC;AAErD;;;;;;GAMG;AACH,MAAM,MAAM,WAAW,CAAC,WAAW,SAAS,MAAM,EAAE,CAAC,IAAI;KACtD,CAAC,IAAI,GAAG,WAAW,SAAS,GAAG,iBAAiB,CAAC,CAAC,CAAC;CACrD,GAAG;KACD,CAAC,IAAI,MAAM,WAAW,EAAE,GAAG,MAAM,CAAC;CACpC,CAAC;AAEF;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA0DG;AACH,wBAAgB,iBAAiB,CAAC,CAAC,GAAG,KAAK,MACjC,WAAW,SAAS,MAAM,EAChC,aAAa,CAAC,CAAC,CAAC,SAAS,CAAC,KAAK,CAAC,GAC5B,KAAK,GACL,gBAAgB,CAAC,WAAW,EAAE,KAAK,EAAE,MAAM,CAAC,KAC/C,WAAW,CAAC,WAAW,EAAE,CAAC,CAAC,CAsB/B"}
@@ -55,6 +55,9 @@ const moValueSymbol = Symbol('noValue');
55
55
  * - ``` `${displayName}Context` ``` (e.g. `DirectionContext`): the context
56
56
  * - ``` `use${displayName}` ``` (e.g. `useDirection`): a hook that returns the
57
57
  * current context value if one was provided, or throws an error otherwise
58
+ *
59
+ * @see
60
+ * {@linkcode SafeContext}
58
61
  */
59
62
  export function createSafeContext() {
60
63
  return (displayName) => {
@@ -1 +1 @@
1
- {"version":3,"file":"createSafeContext.js","sourceRoot":"","sources":["../../src/misc/createSafeContext.ts"],"names":[],"mappings":"AAAA,OAAO,EAA+B,aAAa,EAAE,UAAU,EAAE,MAAM,OAAO,CAAC;AAG/E,MAAM,aAAa,GAAG,MAAM,CAAC,SAAS,CAAC,CAAC;AA6BxC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAuDG;AACH,MAAM,UAAU,iBAAiB;IAC/B,OAAO,CACL,WAEgD,EACnB,EAAE;QAC/B,MAAM,WAAW,GAAG,GAAG,WAA0B,SAAkB,CAAC;QACpE,MAAM,QAAQ,GAAG,MAAM,WAA0B,EAAW,CAAC;QAE7D,MAAM,OAAO,GAAG,aAAa,CAA2B,aAAa,CAAC,CAAC;QACvE,OAAO,CAAC,WAAW,GAAG,WAAW,CAAC;QAElC,OAAO;YACL,CAAC,WAAW,CAAC,EAAE,OAA+B;YAC9C,CAAC,QAAQ,CAAC,EAAE,GAAG,EAAE;gBACf,MAAM,KAAK,GAAG,UAAU,CAAC,OAAO,CAAC,CAAC;gBAClC,IAAI,KAAK,KAAK,aAAa,EAAE,CAAC;oBAC5B,MAAM,IAAI,KAAK,CAAC,MAAM,WAAW,qBAAqB,CAAC,CAAC;gBAC1D,CAAC;gBACD,OAAO,KAAK,CAAC;YACf,CAAC;SAKF,CAAC;IACJ,CAAC,CAAC;AACJ,CAAC"}
1
+ {"version":3,"file":"createSafeContext.js","sourceRoot":"","sources":["../../src/misc/createSafeContext.ts"],"names":[],"mappings":"AAAA,OAAO,EAA+B,aAAa,EAAE,UAAU,EAAE,MAAM,OAAO,CAAC;AAG/E,MAAM,aAAa,GAAG,MAAM,CAAC,SAAS,CAAC,CAAC;AAgCxC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA0DG;AACH,MAAM,UAAU,iBAAiB;IAC/B,OAAO,CACL,WAEgD,EACnB,EAAE;QAC/B,MAAM,WAAW,GAAG,GAAG,WAA0B,SAAkB,CAAC;QACpE,MAAM,QAAQ,GAAG,MAAM,WAA0B,EAAW,CAAC;QAE7D,MAAM,OAAO,GAAG,aAAa,CAA2B,aAAa,CAAC,CAAC;QACvE,OAAO,CAAC,WAAW,GAAG,WAAW,CAAC;QAElC,OAAO;YACL,CAAC,WAAW,CAAC,EAAE,OAA+B;YAC9C,CAAC,QAAQ,CAAC,EAAE,GAAG,EAAE;gBACf,MAAM,KAAK,GAAG,UAAU,CAAC,OAAO,CAAC,CAAC;gBAClC,IAAI,KAAK,KAAK,aAAa,EAAE,CAAC;oBAC5B,MAAM,IAAI,KAAK,CAAC,MAAM,WAAW,qBAAqB,CAAC,CAAC;gBAC1D,CAAC;gBACD,OAAO,KAAK,CAAC;YACf,CAAC;SAKF,CAAC;IACJ,CAAC,CAAC;AACJ,CAAC"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@aweebit/react-essentials",
3
- "version": "0.7.0",
3
+ "version": "0.8.0",
4
4
  "type": "module",
5
5
  "repository": "github:aweebit/react-essentials",
6
6
  "main": "dist/index.js",
@@ -5,117 +5,108 @@
5
5
  * @copyright 2020 Julien CARON
6
6
  */
7
7
 
8
- import { useEffect, useMemo, useRef } from 'react';
9
-
10
- type UseEventListenerOverloadArgs<
11
- EventMap,
12
- K extends keyof EventMap,
13
- T extends EventTarget,
14
- > = [
15
- target: T | null,
16
- eventName: K,
17
- handler: (this: NoInfer<T>, event: EventMap[K]) => void,
18
- options?: AddEventListenerOptions | boolean,
19
- ];
8
+ import { useEffect, useMemo, useRef, type RefObject } from 'react';
20
9
 
21
10
  /**
22
- * Adds `handler` as a listener for the event `eventName` of `target` with the
23
- * provided `options` applied
24
- *
25
- * If `target` is not provided, `window` is used instead.
26
- *
27
- * If `target` is `null`, no event listener is added. This is useful when
28
- * working with DOM element refs, or when the event listener needs to be removed
29
- * temporarily.
30
- *
31
- * @example
32
- * ```tsx
33
- * useEventListener('resize', () => {
34
- * console.log(window.innerWidth, window.innerHeight);
35
- * });
36
- *
37
- * useEventListener(document, 'visibilitychange', () => {
38
- * console.log(document.visibilityState);
39
- * });
40
- *
41
- * const buttonRef = useRef<HTMLButtonElement>(null);
42
- * useEventListener(buttonRef.current, 'click', () => console.log('click'));
43
- * ```
11
+ * The type of {@linkcode useEventListener}
44
12
  *
45
- * @ignore
13
+ * @see
14
+ * {@linkcode useEventListener},
15
+ * {@linkcode UseEventListenerWithImplicitWindowTarget},
16
+ * {@linkcode UseEventListenerWithExplicitTarget},
17
+ * {@linkcode UseEventListenerWithAnyExplicitTarget}
46
18
  */
47
- export function useEventListener<K extends keyof WindowEventMap>(
48
- eventName: K,
49
- handler: (this: Window, event: WindowEventMap[K]) => void,
50
- options?: AddEventListenerOptions | boolean,
51
- ): void;
19
+ export type UseEventListener = UseEventListenerWithImplicitWindowTarget &
20
+ UseEventListenerWithExplicitTarget<Window, WindowEventMap> &
21
+ UseEventListenerWithExplicitTarget<Document, DocumentEventMap> &
22
+ UseEventListenerWithExplicitTarget<HTMLElement, HTMLElementEventMap> &
23
+ UseEventListenerWithExplicitTarget<SVGElement, SVGElementEventMap> &
24
+ UseEventListenerWithExplicitTarget<MathMLElement, MathMLElementEventMap> &
25
+ UseEventListenerWithAnyExplicitTarget;
52
26
 
53
27
  /**
54
- * @see {@linkcode useEventListener}
55
- * @ignore
56
- */
57
- export function useEventListener<K extends keyof WindowEventMap>(
58
- ...args: UseEventListenerOverloadArgs<WindowEventMap, K, Window>
59
- ): void;
28
+ * @see
29
+ * {@linkcode useEventListener},
30
+ * {@linkcode UseEventListenerWithImplicitWindowTargetArgs} */
31
+ export type UseEventListenerWithImplicitWindowTarget = <
32
+ K extends keyof WindowEventMap,
33
+ >(
34
+ ...args: UseEventListenerWithImplicitWindowTargetArgs<K>
35
+ ) => void;
60
36
 
61
37
  /**
62
- * @see {@linkcode useEventListener}
63
- * @ignore
38
+ * @see
39
+ * {@linkcode useEventListener},
40
+ * {@linkcode UseEventListenerWithExplicitTargetArgs}
64
41
  */
65
- export function useEventListener<K extends keyof DocumentEventMap>(
66
- ...args: UseEventListenerOverloadArgs<DocumentEventMap, K, Document>
67
- ): void;
42
+ export type UseEventListenerWithExplicitTarget<
43
+ Target extends EventTarget,
44
+ EventMap = Record<string, Event>,
45
+ > = <T extends Target, K extends keyof EventMap>(
46
+ ...args: UseEventListenerWithExplicitTargetArgs<EventMap, T, K>
47
+ ) => void;
68
48
 
69
49
  /**
70
- * @see {@linkcode useEventListener}
71
- * @ignore
50
+ * @see
51
+ * {@linkcode useEventListener},
52
+ * {@linkcode UseEventListenerWithExplicitTarget}
72
53
  */
73
- export function useEventListener<
74
- K extends keyof HTMLElementEventMap,
75
- T extends HTMLElement,
76
- >(...args: UseEventListenerOverloadArgs<HTMLElementEventMap, K, T>): void;
54
+ export type UseEventListenerWithAnyExplicitTarget =
55
+ UseEventListenerWithExplicitTarget<EventTarget>;
77
56
 
78
57
  /**
79
- * @see {@linkcode useEventListener}
80
- * @ignore
58
+ * @see
59
+ * {@linkcode useEventListener},
60
+ * {@linkcode UseEventListenerWithExplicitTargetArgs}
81
61
  */
82
- export function useEventListener<
83
- K extends keyof SVGElementEventMap,
84
- T extends SVGElement,
85
- >(...args: UseEventListenerOverloadArgs<SVGElementEventMap, K, T>): void;
62
+ export type UseEventListenerWithImplicitWindowTargetArgs<
63
+ K extends keyof WindowEventMap,
64
+ > =
65
+ UseEventListenerWithExplicitTargetArgs<WindowEventMap, Window, K> extends [
66
+ unknown,
67
+ ...infer Args,
68
+ ]
69
+ ? Args
70
+ : never;
86
71
 
87
72
  /**
88
- * @see {@linkcode useEventListener}
89
- * @ignore
73
+ * @see
74
+ * {@linkcode useEventListener}
90
75
  */
91
- export function useEventListener<
92
- K extends keyof MathMLElementEventMap,
93
- T extends MathMLElement,
94
- >(...args: UseEventListenerOverloadArgs<MathMLElementEventMap, K, T>): void;
95
-
96
- /**
97
- * @see {@linkcode useEventListener}
98
- */
99
- export function useEventListener<K extends keyof WindowEventMap>(
76
+ export type UseEventListenerWithExplicitTargetArgs<
77
+ EventMap,
78
+ T extends EventTarget,
79
+ K extends keyof EventMap,
80
+ > = [
81
+ target: T | (RefObject<T> & { addEventListener?: never }) | null,
100
82
  eventName: K,
101
- handler: (this: Window, event: WindowEventMap[K]) => void,
102
- options?: AddEventListenerOptions | boolean,
103
- ): void;
83
+ handler: (this: NoInfer<T>, event: EventMap[K]) => void,
84
+ options?: AddEventListenerOptions | boolean | undefined,
85
+ ];
104
86
 
105
- /**
106
- * @see {@linkcode useEventListener}
107
- */
108
- export function useEventListener<T extends EventTarget>(
109
- target: T | null,
110
- eventName: string,
111
- handler: (this: NoInfer<T>, event: Event) => void,
112
- options?: AddEventListenerOptions | boolean,
113
- ): void;
87
+ type UseEventListenerWithImplicitWindowTargetArgsAny =
88
+ UseEventListenerWithImplicitWindowTargetArgs<keyof WindowEventMap>;
89
+
90
+ type UseEventListenerWithExplicitTargetArgsAny =
91
+ UseEventListenerWithExplicitTargetArgs<
92
+ Record<string, Event>,
93
+ EventTarget,
94
+ string
95
+ >;
114
96
 
115
97
  /**
116
98
  * Adds `handler` as a listener for the event `eventName` of `target` with the
117
99
  * provided `options` applied
118
100
  *
101
+ * The following call signatures are available:
102
+ *
103
+ * ```ts
104
+ * function useEventListener(eventName, handler, options?): void;
105
+ * function useEventListener(target, eventName, handler, options?): void;
106
+ * ```
107
+ *
108
+ * For the full definition of the hook's type, see {@linkcode UseEventListener}.
109
+ *
119
110
  * If `target` is not provided, `window` is used instead.
120
111
  *
121
112
  * If `target` is `null`, no event listener is added. This is useful when
@@ -133,23 +124,29 @@ export function useEventListener<T extends EventTarget>(
133
124
  * });
134
125
  *
135
126
  * const buttonRef = useRef<HTMLButtonElement>(null);
136
- * useEventListener(buttonRef.current, 'click', () => console.log('click'));
127
+ * useEventListener(buttonRef, 'click', () => console.log('click'));
137
128
  * ```
129
+ *
130
+ * @see
131
+ * {@linkcode UseEventListener}
138
132
  */
139
- export function useEventListener(
140
- ...args: UseEventListenerArgsWithoutTarget | UseEventListenerArgsWithTarget
133
+ export const useEventListener: UseEventListener = function useEventListener(
134
+ ...args:
135
+ | UseEventListenerWithImplicitWindowTargetArgsAny
136
+ | UseEventListenerWithExplicitTargetArgsAny
141
137
  ) {
142
- let eventName: string;
143
- let handler: (this: EventTarget, event: Event) => void;
144
- let target: EventTarget | null | undefined;
145
- let options: AddEventListenerOptions | boolean | undefined;
146
-
147
- if (typeof args[0] === 'string') {
148
- [eventName, handler, options] = args as UseEventListenerArgsWithoutTarget;
149
- } else {
150
- [target, eventName, handler, options] =
151
- args as UseEventListenerArgsWithTarget;
152
- }
138
+ const [target, eventName, handler, options]: [
139
+ target: EventTarget | RefObject<EventTarget> | null,
140
+ eventName: string,
141
+ handler: (this: never, event: Event) => void,
142
+ options?: AddEventListenerOptions | boolean | undefined,
143
+ ] =
144
+ typeof args[0] === 'string'
145
+ ? [window, ...(args as UseEventListenerWithImplicitWindowTargetArgsAny)]
146
+ : (args as UseEventListenerWithExplicitTargetArgsAny);
147
+
148
+ const unwrappedTarget =
149
+ target && !('addEventListener' in target) ? target.current : target;
153
150
 
154
151
  const handlerRef = useRef(handler);
155
152
  handlerRef.current = handler;
@@ -168,34 +165,19 @@ export function useEventListener(
168
165
  );
169
166
 
170
167
  useEffect(() => {
171
- if (target === null) {
168
+ if (unwrappedTarget === null) {
172
169
  // No element has been attached to the ref yet
173
170
  return;
174
171
  }
175
172
 
176
- const definedTarget = target ?? window;
177
-
178
173
  const listener: typeof handler = function (event) {
179
174
  handlerRef.current.call(this, event);
180
175
  };
181
176
 
182
- definedTarget.addEventListener(eventName, listener, memoizedOptions);
177
+ unwrappedTarget.addEventListener(eventName, listener, memoizedOptions);
183
178
 
184
179
  return () => {
185
- definedTarget.removeEventListener(eventName, listener, memoizedOptions);
180
+ unwrappedTarget.removeEventListener(eventName, listener, memoizedOptions);
186
181
  };
187
- }, [eventName, target, memoizedOptions]);
188
- }
189
-
190
- type UseEventListenerArgsWithoutTarget = [
191
- eventName: string,
192
- handler: (event: Event) => void,
193
- options?: AddEventListenerOptions | boolean | undefined,
194
- ];
195
-
196
- type UseEventListenerArgsWithTarget = [
197
- target: EventTarget | null,
198
- eventName: string,
199
- handler: (event: Event) => void,
200
- options?: AddEventListenerOptions | boolean | undefined,
201
- ];
182
+ }, [unwrappedTarget, eventName, memoizedOptions]);
183
+ } as UseEventListener;
@@ -1,4 +1,4 @@
1
- import { type DependencyList, useCallback, useRef } from 'react';
1
+ import { type DependencyList, useRef } from 'react';
2
2
  import { useStateWithDeps } from './useStateWithDeps.js';
3
3
 
4
4
  // We cannot simply import the following types from @types/react since they are
@@ -60,9 +60,9 @@ export function useReducerWithDeps<S, A extends AnyActionArg>(
60
60
  // Only the initially provided reducer is used
61
61
  const reducerRef = useRef(reducer);
62
62
 
63
- const dispatch = useCallback(function dispatch(...args: A): void {
63
+ const dispatch = useRef(function dispatch(...args: A): void {
64
64
  setState((previousState) => reducerRef.current(previousState, ...args));
65
- }, []); // eslint-disable-line react-hooks/exhaustive-deps
65
+ }).current;
66
66
 
67
67
  return [state, dispatch];
68
68
  }
@@ -6,7 +6,6 @@
6
6
  */
7
7
 
8
8
  import {
9
- useCallback,
10
9
  useRef,
11
10
  type DependencyList,
12
11
  type Dispatch,
@@ -92,7 +91,7 @@ export function useStateWithDeps<S>(
92
91
 
93
92
  const [forceUpdate] = useForceUpdate();
94
93
 
95
- const updateState = useCallback(function updateState(
94
+ const updateState = useRef(function updateState(
96
95
  newState: S | ((previousState: S) => S),
97
96
  ): void {
98
97
  let nextState: S;
@@ -105,7 +104,7 @@ export function useStateWithDeps<S>(
105
104
  state.current = nextState;
106
105
  forceUpdate();
107
106
  }
108
- }, []); // eslint-disable-line react-hooks/exhaustive-deps
107
+ }).current;
109
108
 
110
109
  return [state.current, updateState];
111
110
  }
@@ -9,7 +9,8 @@ const moValueSymbol = Symbol('noValue');
9
9
  * as an argument to `useContext` or `use` (the hook produced with
10
10
  * {@linkcode createSafeContext} should be used instead)
11
11
  *
12
- * @see {@linkcode createSafeContext}
12
+ * @see
13
+ * {@linkcode createSafeContext}
13
14
  */
14
15
  // The type is conditional so that both React 18 and 19 are correctly supported.
15
16
  // The code duplication is necessary for the type to be displayed correctly by
@@ -22,7 +23,9 @@ export type RestrictedContext<T> =
22
23
  /**
23
24
  * The return type of {@linkcode createSafeContext}
24
25
  *
25
- * @see {@linkcode createSafeContext}
26
+ * @see
27
+ * {@linkcode createSafeContext},
28
+ * {@linkcode RestrictedContext}
26
29
  */
27
30
  export type SafeContext<DisplayName extends string, T> = {
28
31
  [K in `${DisplayName}Context`]: RestrictedContext<T>;
@@ -85,6 +88,9 @@ export type SafeContext<DisplayName extends string, T> = {
85
88
  * - ``` `${displayName}Context` ``` (e.g. `DirectionContext`): the context
86
89
  * - ``` `use${displayName}` ``` (e.g. `useDirection`): a hook that returns the
87
90
  * current context value if one was provided, or throws an error otherwise
91
+ *
92
+ * @see
93
+ * {@linkcode SafeContext}
88
94
  */
89
95
  export function createSafeContext<T = never>() {
90
96
  return <DisplayName extends string>(