@aweebit/react-essentials 0.6.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
@@ -1,76 +1,56 @@
1
1
  # @aweebit/react-essentials
2
2
 
3
- ## RestrictedContext
3
+ [![NPM Version](https://img.shields.io/npm/v/%40aweebit%2Freact-essentials)](https://www.npmjs.com/package/@aweebit/react-essentials)
4
4
 
5
- ```ts
6
- type RestrictedContext<T> =
7
- Context<T> extends Provider<T>
8
- ? {
9
- Provider: Provider<T>;
10
- displayName: string;
11
- } & Provider<T>
12
- : {
13
- Provider: Provider<T>;
14
- displayName: string;
15
- };
16
- ```
17
-
18
- Defined in: [misc/createSafeContext.ts:17](https://github.com/aweebit/react-essentials/blob/v0.6.0/src/misc/createSafeContext.ts#L17)
19
-
20
- A React context with a required `displayName` and the obsolete `Consumer`
21
- property purposefully omitted so that it is impossible to pass the context
22
- as an argument to `useContext` or `use` (the hook produced with
23
- [`createSafeContext`](#createsafecontext) should be used instead)
5
+ ### Requirements
24
6
 
25
- ### Type Parameters
7
+ - React ≥ 18
8
+ - TypeScript ≥ 5.4
26
9
 
27
- | Type Parameter |
28
- | -------------- |
29
- | `T` |
10
+ ### Functions
30
11
 
31
- ### See
12
+ - [useEventListener()](#useeventlistener)
13
+ - [useForceUpdate()](#useforceupdate)
14
+ - [useReducerWithDeps()](#usereducerwithdeps)
15
+ - [useStateWithDeps()](#usestatewithdeps)
16
+ - [createSafeContext()](#createsafecontext)
32
17
 
33
- [`createSafeContext`](#createsafecontext)
18
+ ### Types
34
19
 
35
- ---
20
+ - [UseEventListener](#useeventlistener-1)
21
+ - [UseEventListenerWithImplicitWindowTarget](#useeventlistenerwithimplicitwindowtarget)
22
+ - [UseEventListenerWithExplicitTarget](#useeventlistenerwithexplicittarget)
23
+ - [UseEventListenerWithAnyExplicitTarget](#useeventlistenerwithanyexplicittarget)
24
+ - [UseEventListenerWithImplicitWindowTargetArgs](#useeventlistenerwithimplicitwindowtargetargs)
25
+ - [UseEventListenerWithExplicitTargetArgs](#useeventlistenerwithexplicittargetargs)
26
+ - [RestrictedContext](#restrictedcontext)
27
+ - [SafeContext](#safecontext)
36
28
 
37
- ## SafeContext
29
+ ## useEventListener
38
30
 
39
31
  ```ts
40
- type SafeContext<DisplayName, T> = {
41
- [K in `${DisplayName}Context`]: RestrictedContext<T>;
42
- } & { [K in `use${DisplayName}`]: () => T };
32
+ const useEventListener: UseEventListener;
43
33
  ```
44
34
 
45
- Defined in: [misc/createSafeContext.ts:25](https://github.com/aweebit/react-essentials/blob/v0.6.0/src/misc/createSafeContext.ts#L25)
46
-
47
- ### Type Parameters
35
+ Defined in: [hooks/useEventListener.ts:133](https://github.com/aweebit/react-essentials/blob/v0.8.0/src/hooks/useEventListener.ts#L133)
48
36
 
49
- | Type Parameter |
50
- | -------------------------------- |
51
- | `DisplayName` _extends_ `string` |
52
- | `T` |
53
-
54
- ### See
55
-
56
- [`createSafeContext`](#createsafecontext)
57
-
58
- ---
37
+ Adds `handler` as a listener for the event `eventName` of `target` with the
38
+ provided `options` applied
59
39
 
60
- ## useEventListener()
40
+ The following call signatures are available:
61
41
 
62
42
  ```ts
63
- function useEventListener<T>(eventName, handler, element?, options?): void;
43
+ function useEventListener(eventName, handler, options?): void;
44
+ function useEventListener(target, eventName, handler, options?): void;
64
45
  ```
65
46
 
66
- Defined in: [hooks/useEventListener.ts:120](https://github.com/aweebit/react-essentials/blob/v0.6.0/src/hooks/useEventListener.ts#L120)
67
-
68
- Adds `handler` as a listener for the event `eventName` of `element` with the
69
- provided `options` applied
47
+ For the full definition of the hook's type, see [`UseEventListener`](#useeventlistener).
70
48
 
71
- If `element` is `undefined`, `window` is used instead.
49
+ If `target` is not provided, `window` is used instead.
72
50
 
73
- If `element` is `null`, no event listener is added.
51
+ If `target` is `null`, no event listener is added. This is useful when
52
+ working with DOM element refs, or when the event listener needs to be removed
53
+ temporarily.
74
54
 
75
55
  ### Example
76
56
 
@@ -79,34 +59,17 @@ useEventListener('resize', () => {
79
59
  console.log(window.innerWidth, window.innerHeight);
80
60
  });
81
61
 
82
- useEventListener(
83
- 'visibilitychange',
84
- () => console.log(document.visibilityState),
85
- document,
86
- );
62
+ useEventListener(document, 'visibilitychange', () => {
63
+ console.log(document.visibilityState);
64
+ });
87
65
 
88
66
  const buttonRef = useRef<HTMLButtonElement>(null);
89
- useEventListener('click', () => console.log('click'), buttonRef.current);
67
+ useEventListener(buttonRef, 'click', () => console.log('click'));
90
68
  ```
91
69
 
92
- ### Type Parameters
93
-
94
- | Type Parameter |
95
- | --------------------------- |
96
- | `T` _extends_ `EventTarget` |
97
-
98
- ### Parameters
70
+ ### See
99
71
 
100
- | Parameter | Type |
101
- | ----------- | -------------------------------------- |
102
- | `eventName` | `string` |
103
- | `handler` | (`this`, `event`) => `void` |
104
- | `element?` | `null` \| `T` |
105
- | `options?` | `boolean` \| `AddEventListenerOptions` |
106
-
107
- ### Returns
108
-
109
- `void`
72
+ [`UseEventListener`](#useeventlistener)
110
73
 
111
74
  ---
112
75
 
@@ -116,18 +79,104 @@ useEventListener('click', () => console.log('click'), buttonRef.current);
116
79
  function useForceUpdate(callback?): [() => void, bigint];
117
80
  ```
118
81
 
119
- Defined in: [hooks/useForceUpdate.ts:32](https://github.com/aweebit/react-essentials/blob/v0.6.0/src/hooks/useForceUpdate.ts#L32)
82
+ Defined in: [hooks/useForceUpdate.ts:81](https://github.com/aweebit/react-essentials/blob/v0.8.0/src/hooks/useForceUpdate.ts#L81)
120
83
 
121
84
  Enables you to imperatively trigger re-rendering of components
122
85
 
123
86
  This hook is designed in the most general way possible in order to cover all
124
87
  imaginable use cases.
125
88
 
89
+ ### Example
90
+
91
+ Sometimes, React's immutability constraints mean too much unnecessary copying
92
+ of data when new data arrives at a high frequency. In such cases, it might be
93
+ desirable to ignore the constraints by embracing imperative patterns.
94
+ Here is an example of a scenario where that can make sense:
95
+
96
+ ```tsx
97
+ type SensorData = { timestamp: number; value: number };
98
+ const sensorDataRef = useRef<SensorData[]>([]);
99
+ const mostRecentSensorDataTimestampRef = useRef<number>(0);
100
+
101
+ const [forceUpdate, updateCount] = useForceUpdate();
102
+ // Limiting the frequency of forced re-renders with some throttle function:
103
+ const throttledForceUpdateRef = useRef(throttle(forceUpdate));
104
+
105
+ useEffect(() => {
106
+ return sensorDataObservable.subscribe((data: SensorData) => {
107
+ // Imagine new sensor data arrives every 1 millisecond. If we were following
108
+ // React's immutability rules by creating a new array every time, the data
109
+ // that's already there would have to be copied many times before the new
110
+ // data would even get a chance to be reflected in the UI for the first time
111
+ // because it typically takes much longer than 1 millisecond for a new frame
112
+ // to be displayed. To prevent the waste of computational resources, we just
113
+ // mutate the existing array every time instead:
114
+ sensorDataRef.current.push(data);
115
+ if (data.timestamp > mostRecentSensorDataTimestampRef.current) {
116
+ mostRecentSensorDataTimestampRef.current = data.timestamp;
117
+ }
118
+ throttledForceUpdateRef.current();
119
+ });
120
+ }, []);
121
+
122
+ const [timeWindow, setTimeWindow] = useState(1000);
123
+ const selectedSensorData = useMemo(
124
+ () => {
125
+ // Keep this line if you don't want to disable the
126
+ // react-hooks/exhaustive-deps ESLint rule:
127
+ updateCount;
128
+ const threshold = mostRecentSensorDataTimestampRef.current - timeWindow;
129
+ return sensorDataRef.current.filter(
130
+ ({ timestamp }) => timestamp >= threshold,
131
+ );
132
+ },
133
+ // sensorDataRef.current always references the same array, so listing it as a
134
+ // dependency is pointless. Instead, updateCount should be used:
135
+ [updateCount, timeWindow],
136
+ );
137
+ ```
138
+
126
139
  ### Parameters
127
140
 
128
- | Parameter | Type | Description |
129
- | ----------- | ------------ | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
130
- | `callback?` | () => `void` | An optional callback function to call during renders that were triggered with `forceUpdate()` Can be used for conditionally calling state setters when state needs to be reset. That is legal and better than using effects (see [You Might Not Need an Effect \> Adjusting some state when a prop changes](https://react.dev/learn/-might-not-need-an-effect#adjusting-some-state-when-a-prop-changes)), but can often be avoided by using [`useStateWithDeps`](#usestatewithdeps) or [`useReducerWithDeps`](#usereducerwithdeps). Important: the callback function is called once per render, not once per `forceUpdate` call! If React batches `forceUpdate` calls, then it will only be called once. |
141
+ <table>
142
+ <thead>
143
+ <tr>
144
+ <th>Parameter</th>
145
+ <th>Type</th>
146
+ <th>Description</th>
147
+ </tr>
148
+ </thead>
149
+ <tbody>
150
+ <tr>
151
+ <td>
152
+
153
+ `callback?`
154
+
155
+ </td>
156
+ <td>
157
+
158
+ () => `void`
159
+
160
+ </td>
161
+ <td>
162
+
163
+ An optional callback function to call during renders that
164
+ were triggered with `forceUpdate()`
165
+
166
+ Can be used for conditionally calling state setters when state needs to be
167
+ reset. That is legal and better than using effects (see
168
+ [You Might Not Need an Effect \> Adjusting some state when a prop changes](https://react.dev/learn/-might-not-need-an-effect#adjusting-some-state-when-a-prop-changes)),
169
+ but can often be avoided by using [`useStateWithDeps`](#usestatewithdeps) or
170
+ [`useReducerWithDeps`](#usereducerwithdeps).
171
+
172
+ Important: the callback function is called once per render, not once per
173
+ `forceUpdate` call! If React batches `forceUpdate` calls, then it will only
174
+ be called once.
175
+
176
+ </td>
177
+ </tr>
178
+ </tbody>
179
+ </table>
131
180
 
132
181
  ### Returns
133
182
 
@@ -150,11 +199,14 @@ function useReducerWithDeps<S, A>(
150
199
  ): [S, ActionDispatch<A>];
151
200
  ```
152
201
 
153
- Defined in: [hooks/useReducerWithDeps.ts:49](https://github.com/aweebit/react-essentials/blob/v0.6.0/src/hooks/useReducerWithDeps.ts#L49)
202
+ Defined in: [hooks/useReducerWithDeps.ts:52](https://github.com/aweebit/react-essentials/blob/v0.8.0/src/hooks/useReducerWithDeps.ts#L52)
154
203
 
155
204
  `useReducer` hook with an additional dependency array `deps` that resets the
156
205
  state to `initialState` when dependencies change
157
206
 
207
+ For motivation and examples, see
208
+ https://github.com/facebook/react/issues/33041.
209
+
158
210
  ### On linter support
159
211
 
160
212
  The `react-hooks/exhaustive-deps` ESLint rule doesn't support hooks where
@@ -163,7 +215,7 @@ However, as we would like to keep the hook as compatible with `useReducer` as
163
215
  possible, we don't want to artificially change the parameter's position.
164
216
  Therefore, there will be no warnings about missing dependencies.
165
217
  Because of that, additional caution is advised!
166
- Be sure to check no dependencies are missing from the `deps` array.
218
+ Be sure to check that no dependencies are missing from the `deps` array.
167
219
 
168
220
  Related issue: [https://github.com/facebook/react/issues/25443](https://github.com/facebook/react/issues/25443).
169
221
 
@@ -174,18 +226,99 @@ does actually have support for dependency arrays at other positions, see
174
226
 
175
227
  ### Type Parameters
176
228
 
177
- | Type Parameter |
178
- | ---------------------------- |
179
- | `S` |
180
- | `A` _extends_ `AnyActionArg` |
229
+ <table>
230
+ <thead>
231
+ <tr>
232
+ <th>Type Parameter</th>
233
+ </tr>
234
+ </thead>
235
+ <tbody>
236
+ <tr>
237
+ <td>
238
+
239
+ `S`
240
+
241
+ </td>
242
+ </tr>
243
+ <tr>
244
+ <td>
245
+
246
+ `A` _extends_ `AnyActionArg`
247
+
248
+ </td>
249
+ </tr>
250
+ </tbody>
251
+ </table>
181
252
 
182
253
  ### Parameters
183
254
 
184
- | Parameter | Type | Description |
185
- | -------------- | -------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
186
- | `reducer` | (`prevState`, ...`args`) => `S` | The reducer function that specifies how the state gets updated |
187
- | `initialState` | `S` \| (`previousState?`) => `S` | The value to which the state is set when the component is mounted or dependencies change It can also be a function that returns a state value. If the state is reset due to a change of dependencies, this function will be passed the previous state as its argument (will be `undefined` in the first call upon mount). |
188
- | `deps` | `DependencyList` | Dependencies that reset the state to `initialState` |
255
+ <table>
256
+ <thead>
257
+ <tr>
258
+ <th>Parameter</th>
259
+ <th>Type</th>
260
+ <th>Description</th>
261
+ </tr>
262
+ </thead>
263
+ <tbody>
264
+ <tr>
265
+ <td>
266
+
267
+ `reducer`
268
+
269
+ </td>
270
+ <td>
271
+
272
+ (`prevState`, ...`args`) => `S`
273
+
274
+ </td>
275
+ <td>
276
+
277
+ The reducer function that specifies how the state gets updated
278
+
279
+ </td>
280
+ </tr>
281
+ <tr>
282
+ <td>
283
+
284
+ `initialState`
285
+
286
+ </td>
287
+ <td>
288
+
289
+ `S` \| (`previousState?`) => `S`
290
+
291
+ </td>
292
+ <td>
293
+
294
+ The value to which the state is set when the component is
295
+ mounted or dependencies change
296
+
297
+ It can also be a function that returns a state value. If the state is reset
298
+ due to a change of dependencies, this function will be passed the previous
299
+ state as its argument (will be `undefined` in the first call upon mount).
300
+
301
+ </td>
302
+ </tr>
303
+ <tr>
304
+ <td>
305
+
306
+ `deps`
307
+
308
+ </td>
309
+ <td>
310
+
311
+ `DependencyList`
312
+
313
+ </td>
314
+ <td>
315
+
316
+ Dependencies that reset the state to `initialState`
317
+
318
+ </td>
319
+ </tr>
320
+ </tbody>
321
+ </table>
189
322
 
190
323
  ### Returns
191
324
 
@@ -202,23 +335,118 @@ function useStateWithDeps<S>(
202
335
  ): [S, Dispatch<SetStateAction<S>>];
203
336
  ```
204
337
 
205
- Defined in: [hooks/useStateWithDeps.ts:31](https://github.com/aweebit/react-essentials/blob/v0.6.0/src/hooks/useStateWithDeps.ts#L31)
338
+ Defined in: [hooks/useStateWithDeps.ts:65](https://github.com/aweebit/react-essentials/blob/v0.8.0/src/hooks/useStateWithDeps.ts#L65)
206
339
 
207
340
  `useState` hook with an additional dependency array `deps` that resets the
208
341
  state to `initialState` when dependencies change
209
342
 
343
+ For motivation and more examples, see
344
+ https://github.com/facebook/react/issues/33041.
345
+
346
+ ### Example
347
+
348
+ ```tsx
349
+ type Activity = 'breakfast' | 'exercise' | 'swim' | 'board games' | 'dinner';
350
+
351
+ const timeOfDayOptions = ['morning', 'afternoon', 'evening'] as const;
352
+ type TimeOfDay = (typeof timeOfDayOptions)[number];
353
+
354
+ const activityOptionsByTimeOfDay: {
355
+ [K in TimeOfDay]: [Activity, ...Activity[]];
356
+ } = {
357
+ morning: ['breakfast', 'exercise', 'swim'],
358
+ afternoon: ['exercise', 'swim', 'board games'],
359
+ evening: ['board games', 'dinner'],
360
+ };
361
+
362
+ export function Example() {
363
+ const [timeOfDay, setTimeOfDay] = useState<TimeOfDay>('morning');
364
+
365
+ const activityOptions = activityOptionsByTimeOfDay[timeOfDay];
366
+ const [activity, setActivity] = useStateWithDeps<Activity>(
367
+ (prev) => {
368
+ // Make sure activity is always valid for the current timeOfDay value,
369
+ // but also don't reset it unless necessary:
370
+ return prev && activityOptions.includes(prev) ? prev : activityOptions[0];
371
+ },
372
+ [activityOptions],
373
+ );
374
+
375
+ return '...';
376
+ }
377
+ ```
378
+
210
379
  ### Type Parameters
211
380
 
212
- | Type Parameter |
213
- | -------------- |
214
- | `S` |
381
+ <table>
382
+ <thead>
383
+ <tr>
384
+ <th>Type Parameter</th>
385
+ </tr>
386
+ </thead>
387
+ <tbody>
388
+ <tr>
389
+ <td>
390
+
391
+ `S`
392
+
393
+ </td>
394
+ </tr>
395
+ </tbody>
396
+ </table>
215
397
 
216
398
  ### Parameters
217
399
 
218
- | Parameter | Type | Description |
219
- | -------------- | -------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
220
- | `initialState` | `S` \| (`previousState?`) => `S` | The value to which the state is set when the component is mounted or dependencies change It can also be a function that returns a state value. If the state is reset due to a change of dependencies, this function will be passed the previous state as its argument (will be `undefined` in the first call upon mount). |
221
- | `deps` | `DependencyList` | Dependencies that reset the state to `initialState` |
400
+ <table>
401
+ <thead>
402
+ <tr>
403
+ <th>Parameter</th>
404
+ <th>Type</th>
405
+ <th>Description</th>
406
+ </tr>
407
+ </thead>
408
+ <tbody>
409
+ <tr>
410
+ <td>
411
+
412
+ `initialState`
413
+
414
+ </td>
415
+ <td>
416
+
417
+ `S` \| (`previousState?`) => `S`
418
+
419
+ </td>
420
+ <td>
421
+
422
+ The value to which the state is set when the component is
423
+ mounted or dependencies change
424
+
425
+ It can also be a function that returns a state value. If the state is reset
426
+ due to a change of dependencies, this function will be passed the previous
427
+ state as its argument (will be `undefined` in the first call upon mount).
428
+
429
+ </td>
430
+ </tr>
431
+ <tr>
432
+ <td>
433
+
434
+ `deps`
435
+
436
+ </td>
437
+ <td>
438
+
439
+ `DependencyList`
440
+
441
+ </td>
442
+ <td>
443
+
444
+ Dependencies that reset the state to `initialState`
445
+
446
+ </td>
447
+ </tr>
448
+ </tbody>
449
+ </table>
222
450
 
223
451
  ### Returns
224
452
 
@@ -234,39 +462,89 @@ function createSafeContext<T>(): <DisplayName>(
234
462
  ) => SafeContext<DisplayName, T>;
235
463
  ```
236
464
 
237
- Defined in: [misc/createSafeContext.ts:56](https://github.com/aweebit/react-essentials/blob/v0.6.0/src/misc/createSafeContext.ts#L56)
465
+ Defined in: [misc/createSafeContext.ts:95](https://github.com/aweebit/react-essentials/blob/v0.8.0/src/misc/createSafeContext.ts#L95)
238
466
 
239
467
  For a given type `T`, returns a function that produces both a context of that
240
468
  type and a hook that returns the current context value if one was provided,
241
469
  or throws an error otherwise
242
470
 
471
+ The advantages over vanilla `createContext` are that no default value has to
472
+ be provided, and that a meaningful context name is displayed in dev tools
473
+ instead of generic `Context.Provider`.
474
+
243
475
  ### Example
244
476
 
245
477
  ```tsx
246
- const { ItemsContext, useItems } = createSafeContext<string[]>()('Items');
478
+ enum Direction {
479
+ Up,
480
+ Down,
481
+ Left,
482
+ Right,
483
+ }
484
+
485
+ // Before
486
+ const DirectionContext = createContext<Direction | undefined>(undefined);
487
+ DirectionContext.displayName = 'DirectionContext';
488
+
489
+ const useDirection = () => {
490
+ const direction = useContext(DirectionContext);
491
+ if (direction === undefined) {
492
+ // Called outside of a <DirectionContext.Provider> boundary!
493
+ // Or maybe undefined was explicitly provided as the context value
494
+ // (ideally that shouldn't be allowed, but it is because we had to include
495
+ // undefined in the context type so as to provide a meaningful default)
496
+ throw new Error('No DirectionContext value was provided');
497
+ }
498
+ // Thanks to the undefined check, the type is now narrowed down to Direction
499
+ return direction;
500
+ };
501
+
502
+ // After
503
+ const { DirectionContext, useDirection } =
504
+ createSafeContext<Direction>()('Direction'); // That's it :)
247
505
 
248
506
  const Parent = () => (
249
- <ItemsContext value={['compass', 'newspaper', 'banana']}>
507
+ // Providing undefined as the value is not allowed 👍
508
+ <Direction.Provider value={Direction.Up}>
250
509
  <Child />
251
- </ItemsContext>
510
+ </Direction.Provider>
252
511
  );
253
512
 
254
- const Child = () => useItems().join(', ');
513
+ const Child = () => `Current direction: ${Direction[useDirection()]}`;
255
514
  ```
256
515
 
257
516
  ### Type Parameters
258
517
 
259
- | Type Parameter | Default type |
260
- | -------------- | ------------ |
261
- | `T` | `never` |
518
+ <table>
519
+ <thead>
520
+ <tr>
521
+ <th>Type Parameter</th>
522
+ <th>Default type</th>
523
+ </tr>
524
+ </thead>
525
+ <tbody>
526
+ <tr>
527
+ <td>
528
+
529
+ `T`
530
+
531
+ </td>
532
+ <td>
533
+
534
+ `never`
535
+
536
+ </td>
537
+ </tr>
538
+ </tbody>
539
+ </table>
262
540
 
263
541
  ### Returns
264
542
 
265
543
  A function that accepts a single string argument `displayName` (e.g.
266
- `"Items"`) and returns an object with the following properties:
544
+ `"Direction"`) and returns an object with the following properties:
267
545
 
268
- - `` `${displayName}Context` `` (e.g. `ItemsContext`): the context
269
- - `` `use${displayName}` `` (e.g. `useItems`): a hook that returns the
546
+ - `` `${displayName}Context` `` (e.g. `DirectionContext`): the context
547
+ - `` `use${displayName}` `` (e.g. `useDirection`): a hook that returns the
270
548
  current context value if one was provided, or throws an error otherwise
271
549
 
272
550
  ```ts
@@ -275,16 +553,455 @@ A function that accepts a single string argument `displayName` (e.g.
275
553
 
276
554
  #### Type Parameters
277
555
 
278
- | Type Parameter |
279
- | -------------------------------- |
280
- | `DisplayName` _extends_ `string` |
556
+ <table>
557
+ <thead>
558
+ <tr>
559
+ <th>Type Parameter</th>
560
+ </tr>
561
+ </thead>
562
+ <tbody>
563
+ <tr>
564
+ <td>
565
+
566
+ `DisplayName` _extends_ `string`
567
+
568
+ </td>
569
+ </tr>
570
+ </tbody>
571
+ </table>
281
572
 
282
573
  #### Parameters
283
574
 
284
- | Parameter | Type |
285
- | ------------- | ------------------------------------------------------------------------------------------------ |
286
- | `displayName` | \[`T`\] _extends_ \[`never`\] ? `never` : `ArgumentFallback`\<`DisplayName`, `never`, `string`\> |
575
+ <table>
576
+ <thead>
577
+ <tr>
578
+ <th>Parameter</th>
579
+ <th>Type</th>
580
+ </tr>
581
+ </thead>
582
+ <tbody>
583
+ <tr>
584
+ <td>
585
+
586
+ `displayName`
587
+
588
+ </td>
589
+ <td>
590
+
591
+ \[`T`\] _extends_ \[`never`\] ? `never` : `ArgumentFallback`\<`DisplayName`, `never`, `string`\>
592
+
593
+ </td>
594
+ </tr>
595
+ </tbody>
596
+ </table>
287
597
 
288
598
  #### Returns
289
599
 
290
600
  [`SafeContext`](#safecontext)\<`DisplayName`, `T`\>
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
+
917
+ ---
918
+
919
+ ## RestrictedContext
920
+
921
+ ```ts
922
+ type RestrictedContext<T> =
923
+ Context<T> extends Provider<T>
924
+ ? {
925
+ Provider: Provider<T>;
926
+ displayName: string;
927
+ } & Provider<T>
928
+ : {
929
+ Provider: Provider<T>;
930
+ displayName: string;
931
+ };
932
+ ```
933
+
934
+ Defined in: [misc/createSafeContext.ts:18](https://github.com/aweebit/react-essentials/blob/v0.8.0/src/misc/createSafeContext.ts#L18)
935
+
936
+ A React context with a required `displayName` and the obsolete `Consumer`
937
+ property purposefully omitted so that it is impossible to pass the context
938
+ as an argument to `useContext` or `use` (the hook produced with
939
+ [`createSafeContext`](#createsafecontext) should be used instead)
940
+
941
+ ### Type Parameters
942
+
943
+ <table>
944
+ <thead>
945
+ <tr>
946
+ <th>Type Parameter</th>
947
+ </tr>
948
+ </thead>
949
+ <tbody>
950
+ <tr>
951
+ <td>
952
+
953
+ `T`
954
+
955
+ </td>
956
+ </tr>
957
+ </tbody>
958
+ </table>
959
+
960
+ ### See
961
+
962
+ [`createSafeContext`](#createsafecontext)
963
+
964
+ ---
965
+
966
+ ## SafeContext
967
+
968
+ ```ts
969
+ type SafeContext<DisplayName, T> = {
970
+ [K in `${DisplayName}Context`]: RestrictedContext<T>;
971
+ } & { [K in `use${DisplayName}`]: () => T };
972
+ ```
973
+
974
+ Defined in: [misc/createSafeContext.ts:30](https://github.com/aweebit/react-essentials/blob/v0.8.0/src/misc/createSafeContext.ts#L30)
975
+
976
+ The return type of [`createSafeContext`](#createsafecontext)
977
+
978
+ ### Type Parameters
979
+
980
+ <table>
981
+ <thead>
982
+ <tr>
983
+ <th>Type Parameter</th>
984
+ </tr>
985
+ </thead>
986
+ <tbody>
987
+ <tr>
988
+ <td>
989
+
990
+ `DisplayName` _extends_ `string`
991
+
992
+ </td>
993
+ </tr>
994
+ <tr>
995
+ <td>
996
+
997
+ `T`
998
+
999
+ </td>
1000
+ </tr>
1001
+ </tbody>
1002
+ </table>
1003
+
1004
+ ### See
1005
+
1006
+ [`createSafeContext`](#createsafecontext),
1007
+ [`RestrictedContext`](#restrictedcontext)