@himanshu-sorathiya/react-kit 1.0.25 → 1.0.26
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/dist/events.d.ts +369 -11
- package/dist/events2.js +34 -57
- package/dist/index.d.ts +371 -13
- package/dist/useEventListener.js +32 -24
- package/package.json +1 -1
package/dist/events.d.ts
CHANGED
|
@@ -2,33 +2,264 @@
|
|
|
2
2
|
|
|
3
3
|
import { RefObject } from 'react';
|
|
4
4
|
|
|
5
|
+
/**
|
|
6
|
+
* The native event that triggered a `useClickOutside` handler. Determined
|
|
7
|
+
* by whichever `eventType` was configured — `MouseEvent` for
|
|
8
|
+
* `click`/`mousedown`/`mouseup`, `TouchEvent` for `touchstart`/`touchend`,
|
|
9
|
+
* `PointerEvent` for `pointerdown`/`pointerup`.
|
|
10
|
+
*/
|
|
5
11
|
export type ClickOutsideEvent = MouseEvent | TouchEvent | PointerEvent | Event;
|
|
6
|
-
|
|
12
|
+
/**
|
|
13
|
+
* A single element to check clicks against, or `null` if it isn't mounted
|
|
14
|
+
* yet.
|
|
15
|
+
*/
|
|
16
|
+
export type ClickOutsideTarget = Element | null;
|
|
17
|
+
/**
|
|
18
|
+
* A way of referring to a single {@link ClickOutsideTarget}: a React ref
|
|
19
|
+
* that will (eventually) point at the element, the element itself, or
|
|
20
|
+
* `null`.
|
|
21
|
+
*
|
|
22
|
+
* A ref whose `current` is `null` — for example, because the element hasn't
|
|
23
|
+
* mounted yet — is treated as "outside" for that entry rather than blocking
|
|
24
|
+
* detection. See `useClickOutside`'s docs for details.
|
|
25
|
+
*/
|
|
7
26
|
export type ClickOutsideTargetRef = RefObject<ClickOutsideTarget> | ClickOutsideTarget;
|
|
27
|
+
/**
|
|
28
|
+
* Native events `useClickOutside` can listen for. Defaults to `mousedown`
|
|
29
|
+
* and `touchstart`, which fire before `click`/`mouseup` — this avoids
|
|
30
|
+
* misfiring when a user starts a drag or text selection inside the target
|
|
31
|
+
* and releases outside it.
|
|
32
|
+
*/
|
|
33
|
+
export type ClickOutsideEventName = "mousedown" | "mouseup" | "click" | "touchstart" | "touchend" | "pointerdown" | "pointerup";
|
|
34
|
+
/**
|
|
35
|
+
* Options accepted by `useClickOutside`.
|
|
36
|
+
*/
|
|
8
37
|
export interface UseClickOutsideOptions {
|
|
38
|
+
/**
|
|
39
|
+
* Whether the listener is active. Setting this to `false` fully detaches
|
|
40
|
+
* the underlying listener rather than just skipping the check on each
|
|
41
|
+
* click, so there's no runtime cost while disabled.
|
|
42
|
+
*
|
|
43
|
+
* @default true
|
|
44
|
+
*/
|
|
9
45
|
enabled?: boolean;
|
|
10
|
-
|
|
46
|
+
/**
|
|
47
|
+
* The event(s) that count as a "click." See {@link ClickOutsideEventName}
|
|
48
|
+
* for why `mousedown`/`touchstart` are the default.
|
|
49
|
+
*
|
|
50
|
+
* @default ["mousedown", "touchstart"]
|
|
51
|
+
*/
|
|
52
|
+
eventType?: ClickOutsideEventName | ClickOutsideEventName[];
|
|
53
|
+
/**
|
|
54
|
+
* Whether the listener is registered in the capture phase.
|
|
55
|
+
*
|
|
56
|
+
* Defaults to `true` so this keeps working even if some element between
|
|
57
|
+
* the click and `document` calls `event.stopPropagation()` — a common
|
|
58
|
+
* cause of "click outside stopped working" bugs in bubble-phase
|
|
59
|
+
* listeners.
|
|
60
|
+
*
|
|
61
|
+
* @default true
|
|
62
|
+
*/
|
|
63
|
+
capture?: boolean;
|
|
11
64
|
}
|
|
12
|
-
|
|
65
|
+
/**
|
|
66
|
+
* A function that detaches the listener registered by `useClickOutside`
|
|
67
|
+
* immediately, without waiting for the component to unmount.
|
|
68
|
+
*
|
|
69
|
+
* Safe to call more than once. Note that this does not permanently disable
|
|
70
|
+
* the hook: if `target`, `eventType`, `enabled`, or `capture` change
|
|
71
|
+
* afterwards, a new listener may be attached again on the next render.
|
|
72
|
+
*/
|
|
73
|
+
export type UseClickOutsideReturn = () => void;
|
|
74
|
+
/**
|
|
75
|
+
* Calls `handler` when a click (or the configured event type) happens
|
|
76
|
+
* outside of `target`.
|
|
77
|
+
*
|
|
78
|
+
* `target` may be a single element/ref, or an array of them — the handler
|
|
79
|
+
* only fires when the click is outside *every* target in the array. An
|
|
80
|
+
* unmounted target (a ref whose `current` is `null`) is treated as
|
|
81
|
+
* "outside" for its own entry rather than blocking detection for the
|
|
82
|
+
* others, so it's safe to pass refs that haven't attached yet.
|
|
83
|
+
*
|
|
84
|
+
* @param target The element(s) to detect clicks outside of. Accepts a ref, a direct
|
|
85
|
+
* element, `null`, or an array mixing any of those.
|
|
86
|
+
* @param handler Called with the native event when a click outside is detected. Doesn't
|
|
87
|
+
* need to be memoized.
|
|
88
|
+
* @param options See {@link UseClickOutsideOptions}.
|
|
89
|
+
* @returns A function that detaches the listener on demand.
|
|
90
|
+
*
|
|
91
|
+
* @example
|
|
92
|
+
* ```tsx
|
|
93
|
+
* const modalRef = useRef<HTMLDivElement>(null);
|
|
94
|
+
* useClickOutside(modalRef, () => setOpen(false));
|
|
95
|
+
* ```
|
|
96
|
+
*
|
|
97
|
+
* @example
|
|
98
|
+
* Checking outside multiple elements at once — for example, a dropdown that
|
|
99
|
+
* shouldn't close when its own trigger button is clicked:
|
|
100
|
+
* ```tsx
|
|
101
|
+
* const triggerRef = useRef<HTMLButtonElement>(null);
|
|
102
|
+
* const panelRef = useRef<HTMLDivElement>(null);
|
|
103
|
+
* useClickOutside([triggerRef, panelRef], () => setOpen(false));
|
|
104
|
+
* ```
|
|
105
|
+
*/
|
|
13
106
|
export declare function useClickOutside(target: ClickOutsideTargetRef | ClickOutsideTargetRef[], handler: (event: ClickOutsideEvent) => void, options?: UseClickOutsideOptions): UseClickOutsideReturn;
|
|
107
|
+
/**
|
|
108
|
+
* Any valid DOM event target — the broadest type a listener can be attached
|
|
109
|
+
* to. Used as the generic constraint for {@link UseEventListenerOptions} and
|
|
110
|
+
* {@link TargetRef}.
|
|
111
|
+
*/
|
|
14
112
|
export type TargetType = EventTarget;
|
|
113
|
+
/**
|
|
114
|
+
* A way of referring to a listener target: a React ref that will
|
|
115
|
+
* (eventually) point at the target, the target itself, or `null`.
|
|
116
|
+
*
|
|
117
|
+
* Passing `null` — or a ref whose `current` is `null` — means no listener is
|
|
118
|
+
* attached.
|
|
119
|
+
*/
|
|
15
120
|
export type TargetRef<T extends TargetType> = RefObject<T | null> | T | null;
|
|
121
|
+
/**
|
|
122
|
+
* Options accepted by `useEventListener`, extending the native
|
|
123
|
+
* `AddEventListenerOptions` (`capture`, `passive`, `once`) with a `target`
|
|
124
|
+
* to attach to.
|
|
125
|
+
*/
|
|
16
126
|
export interface UseEventListenerOptions<T extends TargetType> extends AddEventListenerOptions {
|
|
127
|
+
/**
|
|
128
|
+
* The element, ref, `window`, or `document` to attach the listener to.
|
|
129
|
+
*
|
|
130
|
+
* - Omitted → defaults to `window` (or does nothing during SSR, where
|
|
131
|
+
* `window` doesn't exist).
|
|
132
|
+
* - `null`, or a ref whose `current` is `null` → no listener is attached.
|
|
133
|
+
*/
|
|
17
134
|
target?: TargetRef<T>;
|
|
135
|
+
/**
|
|
136
|
+
* An `AbortSignal` to detach the listener(s) from outside the hook.
|
|
137
|
+
*
|
|
138
|
+
* This is combined with the hook's own internal cleanup — aborting this
|
|
139
|
+
* signal detaches the listener(s) immediately, the same as calling the
|
|
140
|
+
* function the hook returns.
|
|
141
|
+
*/
|
|
142
|
+
signal?: AbortSignal;
|
|
18
143
|
}
|
|
19
|
-
|
|
144
|
+
/**
|
|
145
|
+
* A function that detaches the listener(s) registered by `useEventListener`
|
|
146
|
+
* immediately, without waiting for the component to unmount.
|
|
147
|
+
*
|
|
148
|
+
* Safe to call more than once — it's a no-op after the first call. Note
|
|
149
|
+
* that this does not permanently disable the hook: if its dependencies
|
|
150
|
+
* (event name(s), target, `capture`, `passive`, `once`, or `signal`) change
|
|
151
|
+
* afterwards, a new listener may be attached again on the next render.
|
|
152
|
+
*/
|
|
153
|
+
export type UseEventListenerReturn = () => void;
|
|
154
|
+
/**
|
|
155
|
+
* Listens for one or more events on `window` — the default target when none
|
|
156
|
+
* is specified.
|
|
157
|
+
*
|
|
158
|
+
* @param eventName A single event name, or an array of event names, to listen for.
|
|
159
|
+
* @param handler Called with the native event whenever it fires. Doesn't need to be
|
|
160
|
+
* memoized — the latest `handler` is always used, and changing it does not
|
|
161
|
+
* re-attach the listener.
|
|
162
|
+
* @param options Optional. `target` may be omitted (defaults to `window`), or set
|
|
163
|
+
* explicitly to `window` or `null` (to disable).
|
|
164
|
+
* @returns A function that detaches the listener(s) on demand.
|
|
165
|
+
*
|
|
166
|
+
* @example
|
|
167
|
+
* ```tsx
|
|
168
|
+
* useEventListener("resize", () => {
|
|
169
|
+
* console.log(window.innerWidth);
|
|
170
|
+
* });
|
|
171
|
+
* ```
|
|
172
|
+
*/
|
|
20
173
|
export declare function useEventListener<K extends keyof WindowEventMap>(eventName: K | K[], handler: (event: WindowEventMap[K]) => void, options?: UseEventListenerOptions<Window> & {
|
|
21
174
|
target?: Window | null | undefined;
|
|
22
175
|
}): UseEventListenerReturn;
|
|
176
|
+
/**
|
|
177
|
+
* Listens for one or more events on `document`. `target` is required to
|
|
178
|
+
* distinguish this overload from the `window` one.
|
|
179
|
+
*
|
|
180
|
+
* @param eventName A single event name, or an array of event names, to listen for.
|
|
181
|
+
* @param handler Called with the native event whenever it fires. Doesn't need to be
|
|
182
|
+
* memoized — the latest `handler` is always used, and changing it does not
|
|
183
|
+
* re-attach the listener.
|
|
184
|
+
* @param options `target` must be `document`, a ref pointing at `document`, or `null`
|
|
185
|
+
* (to disable).
|
|
186
|
+
* @returns A function that detaches the listener(s) on demand.
|
|
187
|
+
*
|
|
188
|
+
* @example
|
|
189
|
+
* ```tsx
|
|
190
|
+
* useEventListener("visibilitychange", () => {
|
|
191
|
+
* console.log(document.visibilityState);
|
|
192
|
+
* }, { target: document });
|
|
193
|
+
* ```
|
|
194
|
+
*/
|
|
23
195
|
export declare function useEventListener<K extends keyof DocumentEventMap>(eventName: K | K[], handler: (event: DocumentEventMap[K]) => void, options: UseEventListenerOptions<Document> & {
|
|
24
196
|
target: Document | RefObject<Document | null> | null;
|
|
25
197
|
}): UseEventListenerReturn;
|
|
198
|
+
/**
|
|
199
|
+
* Listens for one or more events on an `HTMLElement`, via a ref or the
|
|
200
|
+
* element itself.
|
|
201
|
+
*
|
|
202
|
+
* @param eventName A single event name, or an array of event names, to listen for.
|
|
203
|
+
* @param handler Called with the native event whenever it fires. Doesn't need to be
|
|
204
|
+
* memoized — the latest `handler` is always used, and changing it does not
|
|
205
|
+
* re-attach the listener.
|
|
206
|
+
* @param options `target` must be the element, a ref to it, or `null` (to disable —
|
|
207
|
+
* for example while the ref hasn't attached to a DOM node yet).
|
|
208
|
+
* @returns A function that detaches the listener(s) on demand.
|
|
209
|
+
*
|
|
210
|
+
* @example
|
|
211
|
+
* ```tsx
|
|
212
|
+
* const buttonRef = useRef<HTMLButtonElement>(null);
|
|
213
|
+
* useEventListener("click", () => {
|
|
214
|
+
* console.log("clicked");
|
|
215
|
+
* }, { target: buttonRef });
|
|
216
|
+
* ```
|
|
217
|
+
*/
|
|
26
218
|
export declare function useEventListener<K extends keyof HTMLElementEventMap, T extends HTMLElement = HTMLElement>(eventName: K | K[], handler: (event: HTMLElementEventMap[K]) => void, options: UseEventListenerOptions<T> & {
|
|
27
219
|
target: T | RefObject<T | null> | null;
|
|
28
220
|
}): UseEventListenerReturn;
|
|
221
|
+
/**
|
|
222
|
+
* Listens for one or more events on an `SVGElement`, via a ref or the
|
|
223
|
+
* element itself.
|
|
224
|
+
*
|
|
225
|
+
* @param eventName A single event name, or an array of event names, to listen for.
|
|
226
|
+
* @param handler Called with the native event whenever it fires. Doesn't need to be
|
|
227
|
+
* memoized — the latest `handler` is always used, and changing it does not
|
|
228
|
+
* re-attach the listener.
|
|
229
|
+
* @param options `target` must be the element, a ref to it, or `null` (to disable).
|
|
230
|
+
* @returns A function that detaches the listener(s) on demand.
|
|
231
|
+
*
|
|
232
|
+
* @example
|
|
233
|
+
* ```tsx
|
|
234
|
+
* const circleRef = useRef<SVGCircleElement>(null);
|
|
235
|
+
* useEventListener("click", () => {
|
|
236
|
+
* console.log("circle clicked");
|
|
237
|
+
* }, { target: circleRef });
|
|
238
|
+
* ```
|
|
239
|
+
*/
|
|
29
240
|
export declare function useEventListener<K extends keyof SVGElementEventMap, T extends SVGElement = SVGElement>(eventName: K | K[], handler: (event: SVGElementEventMap[K]) => void, options: UseEventListenerOptions<T> & {
|
|
30
241
|
target: T | RefObject<T | null> | null;
|
|
31
242
|
}): UseEventListenerReturn;
|
|
243
|
+
/**
|
|
244
|
+
* Listens for one or more events on any other `EventTarget` — a custom
|
|
245
|
+
* event emitter, `ShadowRoot`, `MessagePort`, and so on. Since there's no
|
|
246
|
+
* matching `*EventMap` for arbitrary targets, events are typed as the
|
|
247
|
+
* generic `Event`.
|
|
248
|
+
*
|
|
249
|
+
* @param eventName A single event name, or an array of event names, to listen for.
|
|
250
|
+
* @param handler Called with the native event whenever it fires. Doesn't need to be
|
|
251
|
+
* memoized — the latest `handler` is always used, and changing it does not
|
|
252
|
+
* re-attach the listener.
|
|
253
|
+
* @param options `target` must be the target, a ref to it, or `null` (to disable).
|
|
254
|
+
* @returns A function that detaches the listener(s) on demand.
|
|
255
|
+
*
|
|
256
|
+
* @example
|
|
257
|
+
* ```tsx
|
|
258
|
+
* useEventListener("message", (event) => {
|
|
259
|
+
* console.log(event);
|
|
260
|
+
* }, { target: myMessagePort });
|
|
261
|
+
* ```
|
|
262
|
+
*/
|
|
32
263
|
export declare function useEventListener<K extends string, T extends TargetType = TargetType>(eventName: K | K[], handler: (event: Event) => void, options: UseEventListenerOptions<T> & {
|
|
33
264
|
target: T | RefObject<T | null> | null;
|
|
34
265
|
}): UseEventListenerReturn;
|
|
@@ -37,26 +268,153 @@ declare const validKeyEventTypes: readonly [
|
|
|
37
268
|
"keyup",
|
|
38
269
|
"keypress"
|
|
39
270
|
];
|
|
271
|
+
/**
|
|
272
|
+
* The keyboard event types `useKey` can listen for. See
|
|
273
|
+
* {@link validKeyEventTypes}.
|
|
274
|
+
*/
|
|
40
275
|
export type KeyEventType = (typeof validKeyEventTypes)[number];
|
|
41
|
-
|
|
276
|
+
/**
|
|
277
|
+
* Options shared by both variants of {@link UseKeyOptions}.
|
|
278
|
+
*/
|
|
279
|
+
export interface UseKeyBaseOptions {
|
|
280
|
+
/**
|
|
281
|
+
* Whether the listener is active. Setting this to `false` fully detaches
|
|
282
|
+
* the underlying listener rather than just skipping the check on each
|
|
283
|
+
* keystroke, so there's no runtime cost while disabled.
|
|
284
|
+
*
|
|
285
|
+
* @default true
|
|
286
|
+
*/
|
|
42
287
|
enabled?: boolean;
|
|
43
|
-
|
|
288
|
+
/**
|
|
289
|
+
* The element, ref, `window`, or `document` to attach the listener to.
|
|
290
|
+
*
|
|
291
|
+
* @default window
|
|
292
|
+
*/
|
|
293
|
+
target?: RefObject<HTMLElement | null> | HTMLElement | Window | Document | null;
|
|
294
|
+
/**
|
|
295
|
+
* Whether to call `event.preventDefault()` when `key` matches. Applied
|
|
296
|
+
* before `handler` is called, so it still takes effect even if `handler`
|
|
297
|
+
* throws.
|
|
298
|
+
*
|
|
299
|
+
* @default true
|
|
300
|
+
*/
|
|
44
301
|
preventDefault?: boolean;
|
|
302
|
+
/**
|
|
303
|
+
* Whether to call `event.stopPropagation()` when `key` matches. Applied
|
|
304
|
+
* before `handler` is called, so it still takes effect even if `handler`
|
|
305
|
+
* throws.
|
|
306
|
+
*
|
|
307
|
+
* @default true
|
|
308
|
+
*/
|
|
45
309
|
stopPropagation?: boolean;
|
|
310
|
+
/**
|
|
311
|
+
* Whether the listener is registered in the capture phase.
|
|
312
|
+
*
|
|
313
|
+
* Unlike `useClickOutside`, this defaults to `false`. Flip it to `true`
|
|
314
|
+
* if a descendant element calling `event.stopPropagation()` is
|
|
315
|
+
* preventing this shortcut from firing.
|
|
316
|
+
*
|
|
317
|
+
* @default false
|
|
318
|
+
*/
|
|
319
|
+
capture?: boolean;
|
|
320
|
+
/**
|
|
321
|
+
* Whether to ignore the keystroke while focus is inside an `<input>`,
|
|
322
|
+
* `<textarea>`, `<select>`, or any `contenteditable` element — so a
|
|
323
|
+
* shortcut like a bare `"s"` doesn't fire while someone is just typing.
|
|
324
|
+
*
|
|
325
|
+
* @default true
|
|
326
|
+
*/
|
|
46
327
|
ignoreWhenFocusedInInputs?: boolean;
|
|
328
|
+
/**
|
|
329
|
+
* Whether the Ctrl key must be held for a match.
|
|
330
|
+
* @default false
|
|
331
|
+
*/
|
|
47
332
|
ctrlKey?: boolean;
|
|
333
|
+
/**
|
|
334
|
+
* Whether the Shift key must be held for a match.
|
|
335
|
+
* @default false
|
|
336
|
+
*/
|
|
48
337
|
shiftKey?: boolean;
|
|
338
|
+
/**
|
|
339
|
+
* Whether the Alt key (Option, on Mac) must be held for a match.
|
|
340
|
+
* @default false
|
|
341
|
+
*/
|
|
49
342
|
altKey?: boolean;
|
|
343
|
+
/**
|
|
344
|
+
* Whether the Meta key (Cmd on Mac, the Windows key elsewhere) must be
|
|
345
|
+
* held for a match.
|
|
346
|
+
* @default false
|
|
347
|
+
*/
|
|
50
348
|
metaKey?: boolean;
|
|
51
349
|
}
|
|
52
|
-
|
|
53
|
-
|
|
350
|
+
/**
|
|
351
|
+
* Options accepted by `useKey`.
|
|
352
|
+
*
|
|
353
|
+
* `preventRepeat` is only valid together with `eventType: "keydown"` or
|
|
354
|
+
* `"keypress"` — TypeScript rejects it on `"keyup"`, since a keyup event is
|
|
355
|
+
* never marked as auto-repeating.
|
|
356
|
+
*/
|
|
357
|
+
export type UseKeyOptions = UseKeyBaseOptions & ({
|
|
358
|
+
/**
|
|
359
|
+
* Which keyboard event to listen for.
|
|
360
|
+
* @default "keydown"
|
|
361
|
+
*/
|
|
362
|
+
eventType?: Extract<KeyEventType, "keydown" | "keypress">;
|
|
363
|
+
/**
|
|
364
|
+
* If `true`, ignores auto-repeated events fired while the key is
|
|
365
|
+
* held down (based on the native `KeyboardEvent.repeat` flag), so
|
|
366
|
+
* `handler` only fires once per physical press rather than
|
|
367
|
+
* repeatedly while it's held.
|
|
368
|
+
*
|
|
369
|
+
* @default false
|
|
370
|
+
*/
|
|
54
371
|
preventRepeat?: boolean;
|
|
55
372
|
} | {
|
|
56
|
-
eventType: "keyup"
|
|
373
|
+
eventType: Extract<KeyEventType, "keyup">;
|
|
57
374
|
preventRepeat?: never;
|
|
58
375
|
});
|
|
59
|
-
|
|
60
|
-
|
|
376
|
+
/**
|
|
377
|
+
* A function that detaches the listener registered by `useKey` immediately,
|
|
378
|
+
* without waiting for the component to unmount.
|
|
379
|
+
*
|
|
380
|
+
* Safe to call more than once. Note that this does not permanently disable
|
|
381
|
+
* the hook: if `eventType`, `enabled`, `target`, or `capture` change
|
|
382
|
+
* afterwards, a new listener may be attached again on the next render.
|
|
383
|
+
* Changing `key` — or any of the modifier-matching options — does *not*
|
|
384
|
+
* cause a re-attach; those are picked up fresh on the next keystroke
|
|
385
|
+
* without the underlying listener ever being torn down.
|
|
386
|
+
*/
|
|
387
|
+
export type UseKeyReturn = () => void;
|
|
388
|
+
/**
|
|
389
|
+
* Calls `handler` when `key` is pressed (or released, depending on
|
|
390
|
+
* `eventType`), optionally matching an exact combination of modifier keys.
|
|
391
|
+
*
|
|
392
|
+
* Ignores keystrokes that occur during IME composition (for example, while
|
|
393
|
+
* typing pinyin or romaji before a CJK character is confirmed), so
|
|
394
|
+
* shortcuts don't misfire or interfere with the IME's own confirmation key
|
|
395
|
+
* — often Enter. By default, also ignores keystrokes while focus is inside
|
|
396
|
+
* a text input, textarea, select, or contenteditable element — see
|
|
397
|
+
* `ignoreWhenFocusedInInputs` in {@link UseKeyOptions}.
|
|
398
|
+
*
|
|
399
|
+
* @param key The key to match, compared case-insensitively against
|
|
400
|
+
* `KeyboardEvent.key` (e.g. `"Escape"`, `"a"`, `"Enter"`).
|
|
401
|
+
* @param handler Called with the native event when a match is found. Doesn't need to be
|
|
402
|
+
* memoized.
|
|
403
|
+
* @param options See {@link UseKeyOptions}.
|
|
404
|
+
* @returns A function that detaches the listener on demand.
|
|
405
|
+
*
|
|
406
|
+
* @example
|
|
407
|
+
* ```tsx
|
|
408
|
+
* useKey("Escape", () => setOpen(false));
|
|
409
|
+
* ```
|
|
410
|
+
*
|
|
411
|
+
* @example
|
|
412
|
+
* Matching a modifier combination — all four modifier flags are matched
|
|
413
|
+
* exactly, so this only fires for Ctrl+K alone, not Ctrl+Shift+K:
|
|
414
|
+
* ```tsx
|
|
415
|
+
* useKey("k", () => openCommandPalette(), { ctrlKey: true });
|
|
416
|
+
* ```
|
|
417
|
+
*/
|
|
418
|
+
export declare function useKey(key: string, handler: (event: KeyboardEvent) => void, options?: UseKeyOptions): UseKeyReturn;
|
|
61
419
|
|
|
62
420
|
export {};
|
package/dist/events2.js
CHANGED
|
@@ -1,67 +1,44 @@
|
|
|
1
1
|
import { t as e } from "./useEventListener.js";
|
|
2
|
-
import { useEffect as t,
|
|
2
|
+
import { useEffect as t, useRef as n } from "react";
|
|
3
3
|
//#region src/events/useClickOutside/useClickOutside.ts
|
|
4
|
-
var
|
|
5
|
-
function
|
|
6
|
-
let { enabled: o = !0, eventType: s = ["mousedown", "touchstart"] } = a,
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
4
|
+
var r = globalThis.process?.env?.NODE_ENV !== "production";
|
|
5
|
+
function i(t, i, a = {}) {
|
|
6
|
+
let { enabled: o = !0, eventType: s = ["mousedown", "touchstart"], capture: c = !0 } = a, l = n(!1);
|
|
7
|
+
return e(s, (e) => {
|
|
8
|
+
let n = e.target;
|
|
9
|
+
if (!(n instanceof Node)) return;
|
|
10
|
+
let a = Array.isArray(t) ? t : [t];
|
|
11
|
+
r && a.length === 0 && !l.current && (l.current = !0, console.warn("[useClickOutside] Called with an empty target array — every click will be treated as outside.")), a.every((e) => {
|
|
12
|
+
let t = e && "current" in e ? e.current : e;
|
|
13
|
+
return !t || !t.contains(n);
|
|
14
|
+
}) && i(e);
|
|
15
|
+
}, {
|
|
16
|
+
target: o && typeof document < "u" ? document : null,
|
|
17
|
+
capture: c,
|
|
18
|
+
passive: !0
|
|
19
|
+
});
|
|
15
20
|
}
|
|
16
21
|
//#endregion
|
|
17
22
|
//#region src/events/useKey/constants.ts
|
|
18
|
-
var
|
|
23
|
+
var a = [
|
|
19
24
|
"keydown",
|
|
20
25
|
"keyup",
|
|
21
26
|
"keypress"
|
|
22
|
-
],
|
|
23
|
-
function
|
|
24
|
-
let
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
}, [
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
if (!(e instanceof KeyboardEvent)) return;
|
|
38
|
-
let t = e.key.toLowerCase();
|
|
39
|
-
(t === n || f && t === "control" || p && t === "shift" || m && t === "alt" || h && t === "meta") && (b.current = !1);
|
|
40
|
-
}
|
|
41
|
-
function x(e) {
|
|
42
|
-
if (!(e instanceof KeyboardEvent) || !y.current) return;
|
|
43
|
-
let t = e.target;
|
|
44
|
-
if (!(d && t instanceof HTMLElement && (t instanceof HTMLInputElement || t instanceof HTMLTextAreaElement || t instanceof HTMLSelectElement || t.isContentEditable)) && e.ctrlKey === f && e.shiftKey === p && e.altKey === m && e.metaKey === h && n === e.key.toLowerCase()) {
|
|
45
|
-
if (i && b.current) return;
|
|
46
|
-
b.current = !0, v.current(e), a && e.preventDefault(), c && e.stopPropagation();
|
|
47
|
-
}
|
|
48
|
-
}
|
|
49
|
-
return t.addEventListener(r, x), i && (t.addEventListener("keyup", g), window.addEventListener("blur", s)), () => {
|
|
50
|
-
t.removeEventListener(r, x), i && (t.removeEventListener("keyup", g), window.removeEventListener("blur", s));
|
|
51
|
-
};
|
|
52
|
-
}, [
|
|
53
|
-
e,
|
|
54
|
-
a,
|
|
55
|
-
c,
|
|
56
|
-
l,
|
|
57
|
-
u,
|
|
58
|
-
d,
|
|
59
|
-
f,
|
|
60
|
-
p,
|
|
61
|
-
m,
|
|
62
|
-
h,
|
|
63
|
-
_
|
|
64
|
-
]);
|
|
27
|
+
], o = globalThis.process?.env?.NODE_ENV !== "production";
|
|
28
|
+
function s(n, r, i = {}) {
|
|
29
|
+
let { enabled: s = !0, preventDefault: c = !0, stopPropagation: l = !0, eventType: u = "keydown", preventRepeat: d = !1, ignoreWhenFocusedInInputs: f = !0, ctrlKey: p = !1, shiftKey: m = !1, altKey: h = !1, metaKey: g = !1, capture: _ = !1, target: v } = i, y = n.toLowerCase();
|
|
30
|
+
t(() => {
|
|
31
|
+
o && y === "" && console.warn("[useKey] Called with an empty key — this listener will never match.");
|
|
32
|
+
}, [y]);
|
|
33
|
+
let b = a.includes(u) ? u : "keydown", x = d && b !== "keyup";
|
|
34
|
+
return e(b, (e) => {
|
|
35
|
+
if (!(e instanceof KeyboardEvent) || e.isComposing || e.keyCode === 229 || x && e.repeat) return;
|
|
36
|
+
let t = e.target;
|
|
37
|
+
f && t instanceof HTMLElement && (t instanceof HTMLInputElement || t instanceof HTMLTextAreaElement || t instanceof HTMLSelectElement || t.isContentEditable) || !(e.ctrlKey === p && e.shiftKey === m && e.altKey === h && e.metaKey === g) || y !== e.key.toLowerCase() || (c && e.preventDefault(), l && e.stopPropagation(), r(e));
|
|
38
|
+
}, {
|
|
39
|
+
target: s ? v ?? (typeof window > "u" ? null : window) : null,
|
|
40
|
+
capture: _
|
|
41
|
+
});
|
|
65
42
|
}
|
|
66
43
|
//#endregion
|
|
67
|
-
export {
|
|
44
|
+
export { i as n, s as t };
|
package/dist/index.d.ts
CHANGED
|
@@ -3,33 +3,264 @@
|
|
|
3
3
|
import React$1 from 'react';
|
|
4
4
|
import { CSSProperties, Key, RefObject } from 'react';
|
|
5
5
|
|
|
6
|
+
/**
|
|
7
|
+
* The native event that triggered a `useClickOutside` handler. Determined
|
|
8
|
+
* by whichever `eventType` was configured — `MouseEvent` for
|
|
9
|
+
* `click`/`mousedown`/`mouseup`, `TouchEvent` for `touchstart`/`touchend`,
|
|
10
|
+
* `PointerEvent` for `pointerdown`/`pointerup`.
|
|
11
|
+
*/
|
|
6
12
|
export type ClickOutsideEvent = MouseEvent | TouchEvent | PointerEvent | Event;
|
|
7
|
-
|
|
13
|
+
/**
|
|
14
|
+
* A single element to check clicks against, or `null` if it isn't mounted
|
|
15
|
+
* yet.
|
|
16
|
+
*/
|
|
17
|
+
export type ClickOutsideTarget = Element | null;
|
|
18
|
+
/**
|
|
19
|
+
* A way of referring to a single {@link ClickOutsideTarget}: a React ref
|
|
20
|
+
* that will (eventually) point at the element, the element itself, or
|
|
21
|
+
* `null`.
|
|
22
|
+
*
|
|
23
|
+
* A ref whose `current` is `null` — for example, because the element hasn't
|
|
24
|
+
* mounted yet — is treated as "outside" for that entry rather than blocking
|
|
25
|
+
* detection. See `useClickOutside`'s docs for details.
|
|
26
|
+
*/
|
|
8
27
|
export type ClickOutsideTargetRef = React$1.RefObject<ClickOutsideTarget> | ClickOutsideTarget;
|
|
28
|
+
/**
|
|
29
|
+
* Native events `useClickOutside` can listen for. Defaults to `mousedown`
|
|
30
|
+
* and `touchstart`, which fire before `click`/`mouseup` — this avoids
|
|
31
|
+
* misfiring when a user starts a drag or text selection inside the target
|
|
32
|
+
* and releases outside it.
|
|
33
|
+
*/
|
|
34
|
+
export type ClickOutsideEventName = "mousedown" | "mouseup" | "click" | "touchstart" | "touchend" | "pointerdown" | "pointerup";
|
|
35
|
+
/**
|
|
36
|
+
* Options accepted by `useClickOutside`.
|
|
37
|
+
*/
|
|
9
38
|
export interface UseClickOutsideOptions {
|
|
39
|
+
/**
|
|
40
|
+
* Whether the listener is active. Setting this to `false` fully detaches
|
|
41
|
+
* the underlying listener rather than just skipping the check on each
|
|
42
|
+
* click, so there's no runtime cost while disabled.
|
|
43
|
+
*
|
|
44
|
+
* @default true
|
|
45
|
+
*/
|
|
10
46
|
enabled?: boolean;
|
|
11
|
-
|
|
12
|
-
}
|
|
13
|
-
|
|
47
|
+
/**
|
|
48
|
+
* The event(s) that count as a "click." See {@link ClickOutsideEventName}
|
|
49
|
+
* for why `mousedown`/`touchstart` are the default.
|
|
50
|
+
*
|
|
51
|
+
* @default ["mousedown", "touchstart"]
|
|
52
|
+
*/
|
|
53
|
+
eventType?: ClickOutsideEventName | ClickOutsideEventName[];
|
|
54
|
+
/**
|
|
55
|
+
* Whether the listener is registered in the capture phase.
|
|
56
|
+
*
|
|
57
|
+
* Defaults to `true` so this keeps working even if some element between
|
|
58
|
+
* the click and `document` calls `event.stopPropagation()` — a common
|
|
59
|
+
* cause of "click outside stopped working" bugs in bubble-phase
|
|
60
|
+
* listeners.
|
|
61
|
+
*
|
|
62
|
+
* @default true
|
|
63
|
+
*/
|
|
64
|
+
capture?: boolean;
|
|
65
|
+
}
|
|
66
|
+
/**
|
|
67
|
+
* A function that detaches the listener registered by `useClickOutside`
|
|
68
|
+
* immediately, without waiting for the component to unmount.
|
|
69
|
+
*
|
|
70
|
+
* Safe to call more than once. Note that this does not permanently disable
|
|
71
|
+
* the hook: if `target`, `eventType`, `enabled`, or `capture` change
|
|
72
|
+
* afterwards, a new listener may be attached again on the next render.
|
|
73
|
+
*/
|
|
74
|
+
export type UseClickOutsideReturn = () => void;
|
|
75
|
+
/**
|
|
76
|
+
* Calls `handler` when a click (or the configured event type) happens
|
|
77
|
+
* outside of `target`.
|
|
78
|
+
*
|
|
79
|
+
* `target` may be a single element/ref, or an array of them — the handler
|
|
80
|
+
* only fires when the click is outside *every* target in the array. An
|
|
81
|
+
* unmounted target (a ref whose `current` is `null`) is treated as
|
|
82
|
+
* "outside" for its own entry rather than blocking detection for the
|
|
83
|
+
* others, so it's safe to pass refs that haven't attached yet.
|
|
84
|
+
*
|
|
85
|
+
* @param target The element(s) to detect clicks outside of. Accepts a ref, a direct
|
|
86
|
+
* element, `null`, or an array mixing any of those.
|
|
87
|
+
* @param handler Called with the native event when a click outside is detected. Doesn't
|
|
88
|
+
* need to be memoized.
|
|
89
|
+
* @param options See {@link UseClickOutsideOptions}.
|
|
90
|
+
* @returns A function that detaches the listener on demand.
|
|
91
|
+
*
|
|
92
|
+
* @example
|
|
93
|
+
* ```tsx
|
|
94
|
+
* const modalRef = useRef<HTMLDivElement>(null);
|
|
95
|
+
* useClickOutside(modalRef, () => setOpen(false));
|
|
96
|
+
* ```
|
|
97
|
+
*
|
|
98
|
+
* @example
|
|
99
|
+
* Checking outside multiple elements at once — for example, a dropdown that
|
|
100
|
+
* shouldn't close when its own trigger button is clicked:
|
|
101
|
+
* ```tsx
|
|
102
|
+
* const triggerRef = useRef<HTMLButtonElement>(null);
|
|
103
|
+
* const panelRef = useRef<HTMLDivElement>(null);
|
|
104
|
+
* useClickOutside([triggerRef, panelRef], () => setOpen(false));
|
|
105
|
+
* ```
|
|
106
|
+
*/
|
|
14
107
|
export declare function useClickOutside(target: ClickOutsideTargetRef | ClickOutsideTargetRef[], handler: (event: ClickOutsideEvent) => void, options?: UseClickOutsideOptions): UseClickOutsideReturn;
|
|
108
|
+
/**
|
|
109
|
+
* Any valid DOM event target — the broadest type a listener can be attached
|
|
110
|
+
* to. Used as the generic constraint for {@link UseEventListenerOptions} and
|
|
111
|
+
* {@link TargetRef}.
|
|
112
|
+
*/
|
|
15
113
|
export type TargetType = EventTarget;
|
|
114
|
+
/**
|
|
115
|
+
* A way of referring to a listener target: a React ref that will
|
|
116
|
+
* (eventually) point at the target, the target itself, or `null`.
|
|
117
|
+
*
|
|
118
|
+
* Passing `null` — or a ref whose `current` is `null` — means no listener is
|
|
119
|
+
* attached.
|
|
120
|
+
*/
|
|
16
121
|
export type TargetRef<T extends TargetType> = React$1.RefObject<T | null> | T | null;
|
|
122
|
+
/**
|
|
123
|
+
* Options accepted by `useEventListener`, extending the native
|
|
124
|
+
* `AddEventListenerOptions` (`capture`, `passive`, `once`) with a `target`
|
|
125
|
+
* to attach to.
|
|
126
|
+
*/
|
|
17
127
|
export interface UseEventListenerOptions<T extends TargetType> extends AddEventListenerOptions {
|
|
128
|
+
/**
|
|
129
|
+
* The element, ref, `window`, or `document` to attach the listener to.
|
|
130
|
+
*
|
|
131
|
+
* - Omitted → defaults to `window` (or does nothing during SSR, where
|
|
132
|
+
* `window` doesn't exist).
|
|
133
|
+
* - `null`, or a ref whose `current` is `null` → no listener is attached.
|
|
134
|
+
*/
|
|
18
135
|
target?: TargetRef<T>;
|
|
19
|
-
|
|
20
|
-
|
|
136
|
+
/**
|
|
137
|
+
* An `AbortSignal` to detach the listener(s) from outside the hook.
|
|
138
|
+
*
|
|
139
|
+
* This is combined with the hook's own internal cleanup — aborting this
|
|
140
|
+
* signal detaches the listener(s) immediately, the same as calling the
|
|
141
|
+
* function the hook returns.
|
|
142
|
+
*/
|
|
143
|
+
signal?: AbortSignal;
|
|
144
|
+
}
|
|
145
|
+
/**
|
|
146
|
+
* A function that detaches the listener(s) registered by `useEventListener`
|
|
147
|
+
* immediately, without waiting for the component to unmount.
|
|
148
|
+
*
|
|
149
|
+
* Safe to call more than once — it's a no-op after the first call. Note
|
|
150
|
+
* that this does not permanently disable the hook: if its dependencies
|
|
151
|
+
* (event name(s), target, `capture`, `passive`, `once`, or `signal`) change
|
|
152
|
+
* afterwards, a new listener may be attached again on the next render.
|
|
153
|
+
*/
|
|
154
|
+
export type UseEventListenerReturn = () => void;
|
|
155
|
+
/**
|
|
156
|
+
* Listens for one or more events on `window` — the default target when none
|
|
157
|
+
* is specified.
|
|
158
|
+
*
|
|
159
|
+
* @param eventName A single event name, or an array of event names, to listen for.
|
|
160
|
+
* @param handler Called with the native event whenever it fires. Doesn't need to be
|
|
161
|
+
* memoized — the latest `handler` is always used, and changing it does not
|
|
162
|
+
* re-attach the listener.
|
|
163
|
+
* @param options Optional. `target` may be omitted (defaults to `window`), or set
|
|
164
|
+
* explicitly to `window` or `null` (to disable).
|
|
165
|
+
* @returns A function that detaches the listener(s) on demand.
|
|
166
|
+
*
|
|
167
|
+
* @example
|
|
168
|
+
* ```tsx
|
|
169
|
+
* useEventListener("resize", () => {
|
|
170
|
+
* console.log(window.innerWidth);
|
|
171
|
+
* });
|
|
172
|
+
* ```
|
|
173
|
+
*/
|
|
21
174
|
export declare function useEventListener<K extends keyof WindowEventMap>(eventName: K | K[], handler: (event: WindowEventMap[K]) => void, options?: UseEventListenerOptions<Window> & {
|
|
22
175
|
target?: Window | null | undefined;
|
|
23
176
|
}): UseEventListenerReturn;
|
|
177
|
+
/**
|
|
178
|
+
* Listens for one or more events on `document`. `target` is required to
|
|
179
|
+
* distinguish this overload from the `window` one.
|
|
180
|
+
*
|
|
181
|
+
* @param eventName A single event name, or an array of event names, to listen for.
|
|
182
|
+
* @param handler Called with the native event whenever it fires. Doesn't need to be
|
|
183
|
+
* memoized — the latest `handler` is always used, and changing it does not
|
|
184
|
+
* re-attach the listener.
|
|
185
|
+
* @param options `target` must be `document`, a ref pointing at `document`, or `null`
|
|
186
|
+
* (to disable).
|
|
187
|
+
* @returns A function that detaches the listener(s) on demand.
|
|
188
|
+
*
|
|
189
|
+
* @example
|
|
190
|
+
* ```tsx
|
|
191
|
+
* useEventListener("visibilitychange", () => {
|
|
192
|
+
* console.log(document.visibilityState);
|
|
193
|
+
* }, { target: document });
|
|
194
|
+
* ```
|
|
195
|
+
*/
|
|
24
196
|
export declare function useEventListener<K extends keyof DocumentEventMap>(eventName: K | K[], handler: (event: DocumentEventMap[K]) => void, options: UseEventListenerOptions<Document> & {
|
|
25
197
|
target: Document | React$1.RefObject<Document | null> | null;
|
|
26
198
|
}): UseEventListenerReturn;
|
|
199
|
+
/**
|
|
200
|
+
* Listens for one or more events on an `HTMLElement`, via a ref or the
|
|
201
|
+
* element itself.
|
|
202
|
+
*
|
|
203
|
+
* @param eventName A single event name, or an array of event names, to listen for.
|
|
204
|
+
* @param handler Called with the native event whenever it fires. Doesn't need to be
|
|
205
|
+
* memoized — the latest `handler` is always used, and changing it does not
|
|
206
|
+
* re-attach the listener.
|
|
207
|
+
* @param options `target` must be the element, a ref to it, or `null` (to disable —
|
|
208
|
+
* for example while the ref hasn't attached to a DOM node yet).
|
|
209
|
+
* @returns A function that detaches the listener(s) on demand.
|
|
210
|
+
*
|
|
211
|
+
* @example
|
|
212
|
+
* ```tsx
|
|
213
|
+
* const buttonRef = useRef<HTMLButtonElement>(null);
|
|
214
|
+
* useEventListener("click", () => {
|
|
215
|
+
* console.log("clicked");
|
|
216
|
+
* }, { target: buttonRef });
|
|
217
|
+
* ```
|
|
218
|
+
*/
|
|
27
219
|
export declare function useEventListener<K extends keyof HTMLElementEventMap, T extends HTMLElement = HTMLElement>(eventName: K | K[], handler: (event: HTMLElementEventMap[K]) => void, options: UseEventListenerOptions<T> & {
|
|
28
220
|
target: T | React$1.RefObject<T | null> | null;
|
|
29
221
|
}): UseEventListenerReturn;
|
|
222
|
+
/**
|
|
223
|
+
* Listens for one or more events on an `SVGElement`, via a ref or the
|
|
224
|
+
* element itself.
|
|
225
|
+
*
|
|
226
|
+
* @param eventName A single event name, or an array of event names, to listen for.
|
|
227
|
+
* @param handler Called with the native event whenever it fires. Doesn't need to be
|
|
228
|
+
* memoized — the latest `handler` is always used, and changing it does not
|
|
229
|
+
* re-attach the listener.
|
|
230
|
+
* @param options `target` must be the element, a ref to it, or `null` (to disable).
|
|
231
|
+
* @returns A function that detaches the listener(s) on demand.
|
|
232
|
+
*
|
|
233
|
+
* @example
|
|
234
|
+
* ```tsx
|
|
235
|
+
* const circleRef = useRef<SVGCircleElement>(null);
|
|
236
|
+
* useEventListener("click", () => {
|
|
237
|
+
* console.log("circle clicked");
|
|
238
|
+
* }, { target: circleRef });
|
|
239
|
+
* ```
|
|
240
|
+
*/
|
|
30
241
|
export declare function useEventListener<K extends keyof SVGElementEventMap, T extends SVGElement = SVGElement>(eventName: K | K[], handler: (event: SVGElementEventMap[K]) => void, options: UseEventListenerOptions<T> & {
|
|
31
242
|
target: T | React$1.RefObject<T | null> | null;
|
|
32
243
|
}): UseEventListenerReturn;
|
|
244
|
+
/**
|
|
245
|
+
* Listens for one or more events on any other `EventTarget` — a custom
|
|
246
|
+
* event emitter, `ShadowRoot`, `MessagePort`, and so on. Since there's no
|
|
247
|
+
* matching `*EventMap` for arbitrary targets, events are typed as the
|
|
248
|
+
* generic `Event`.
|
|
249
|
+
*
|
|
250
|
+
* @param eventName A single event name, or an array of event names, to listen for.
|
|
251
|
+
* @param handler Called with the native event whenever it fires. Doesn't need to be
|
|
252
|
+
* memoized — the latest `handler` is always used, and changing it does not
|
|
253
|
+
* re-attach the listener.
|
|
254
|
+
* @param options `target` must be the target, a ref to it, or `null` (to disable).
|
|
255
|
+
* @returns A function that detaches the listener(s) on demand.
|
|
256
|
+
*
|
|
257
|
+
* @example
|
|
258
|
+
* ```tsx
|
|
259
|
+
* useEventListener("message", (event) => {
|
|
260
|
+
* console.log(event);
|
|
261
|
+
* }, { target: myMessagePort });
|
|
262
|
+
* ```
|
|
263
|
+
*/
|
|
33
264
|
export declare function useEventListener<K extends string, T extends TargetType = TargetType>(eventName: K | K[], handler: (event: Event) => void, options: UseEventListenerOptions<T> & {
|
|
34
265
|
target: T | React$1.RefObject<T | null> | null;
|
|
35
266
|
}): UseEventListenerReturn;
|
|
@@ -38,27 +269,154 @@ declare const validKeyEventTypes: readonly [
|
|
|
38
269
|
"keyup",
|
|
39
270
|
"keypress"
|
|
40
271
|
];
|
|
272
|
+
/**
|
|
273
|
+
* The keyboard event types `useKey` can listen for. See
|
|
274
|
+
* {@link validKeyEventTypes}.
|
|
275
|
+
*/
|
|
41
276
|
export type KeyEventType = (typeof validKeyEventTypes)[number];
|
|
42
|
-
|
|
277
|
+
/**
|
|
278
|
+
* Options shared by both variants of {@link UseKeyOptions}.
|
|
279
|
+
*/
|
|
280
|
+
export interface UseKeyBaseOptions {
|
|
281
|
+
/**
|
|
282
|
+
* Whether the listener is active. Setting this to `false` fully detaches
|
|
283
|
+
* the underlying listener rather than just skipping the check on each
|
|
284
|
+
* keystroke, so there's no runtime cost while disabled.
|
|
285
|
+
*
|
|
286
|
+
* @default true
|
|
287
|
+
*/
|
|
43
288
|
enabled?: boolean;
|
|
44
|
-
|
|
289
|
+
/**
|
|
290
|
+
* The element, ref, `window`, or `document` to attach the listener to.
|
|
291
|
+
*
|
|
292
|
+
* @default window
|
|
293
|
+
*/
|
|
294
|
+
target?: React$1.RefObject<HTMLElement | null> | HTMLElement | Window | Document | null;
|
|
295
|
+
/**
|
|
296
|
+
* Whether to call `event.preventDefault()` when `key` matches. Applied
|
|
297
|
+
* before `handler` is called, so it still takes effect even if `handler`
|
|
298
|
+
* throws.
|
|
299
|
+
*
|
|
300
|
+
* @default true
|
|
301
|
+
*/
|
|
45
302
|
preventDefault?: boolean;
|
|
303
|
+
/**
|
|
304
|
+
* Whether to call `event.stopPropagation()` when `key` matches. Applied
|
|
305
|
+
* before `handler` is called, so it still takes effect even if `handler`
|
|
306
|
+
* throws.
|
|
307
|
+
*
|
|
308
|
+
* @default true
|
|
309
|
+
*/
|
|
46
310
|
stopPropagation?: boolean;
|
|
311
|
+
/**
|
|
312
|
+
* Whether the listener is registered in the capture phase.
|
|
313
|
+
*
|
|
314
|
+
* Unlike `useClickOutside`, this defaults to `false`. Flip it to `true`
|
|
315
|
+
* if a descendant element calling `event.stopPropagation()` is
|
|
316
|
+
* preventing this shortcut from firing.
|
|
317
|
+
*
|
|
318
|
+
* @default false
|
|
319
|
+
*/
|
|
320
|
+
capture?: boolean;
|
|
321
|
+
/**
|
|
322
|
+
* Whether to ignore the keystroke while focus is inside an `<input>`,
|
|
323
|
+
* `<textarea>`, `<select>`, or any `contenteditable` element — so a
|
|
324
|
+
* shortcut like a bare `"s"` doesn't fire while someone is just typing.
|
|
325
|
+
*
|
|
326
|
+
* @default true
|
|
327
|
+
*/
|
|
47
328
|
ignoreWhenFocusedInInputs?: boolean;
|
|
329
|
+
/**
|
|
330
|
+
* Whether the Ctrl key must be held for a match.
|
|
331
|
+
* @default false
|
|
332
|
+
*/
|
|
48
333
|
ctrlKey?: boolean;
|
|
334
|
+
/**
|
|
335
|
+
* Whether the Shift key must be held for a match.
|
|
336
|
+
* @default false
|
|
337
|
+
*/
|
|
49
338
|
shiftKey?: boolean;
|
|
339
|
+
/**
|
|
340
|
+
* Whether the Alt key (Option, on Mac) must be held for a match.
|
|
341
|
+
* @default false
|
|
342
|
+
*/
|
|
50
343
|
altKey?: boolean;
|
|
344
|
+
/**
|
|
345
|
+
* Whether the Meta key (Cmd on Mac, the Windows key elsewhere) must be
|
|
346
|
+
* held for a match.
|
|
347
|
+
* @default false
|
|
348
|
+
*/
|
|
51
349
|
metaKey?: boolean;
|
|
52
350
|
}
|
|
53
|
-
|
|
54
|
-
|
|
351
|
+
/**
|
|
352
|
+
* Options accepted by `useKey`.
|
|
353
|
+
*
|
|
354
|
+
* `preventRepeat` is only valid together with `eventType: "keydown"` or
|
|
355
|
+
* `"keypress"` — TypeScript rejects it on `"keyup"`, since a keyup event is
|
|
356
|
+
* never marked as auto-repeating.
|
|
357
|
+
*/
|
|
358
|
+
export type UseKeyOptions = UseKeyBaseOptions & ({
|
|
359
|
+
/**
|
|
360
|
+
* Which keyboard event to listen for.
|
|
361
|
+
* @default "keydown"
|
|
362
|
+
*/
|
|
363
|
+
eventType?: Extract<KeyEventType, "keydown" | "keypress">;
|
|
364
|
+
/**
|
|
365
|
+
* If `true`, ignores auto-repeated events fired while the key is
|
|
366
|
+
* held down (based on the native `KeyboardEvent.repeat` flag), so
|
|
367
|
+
* `handler` only fires once per physical press rather than
|
|
368
|
+
* repeatedly while it's held.
|
|
369
|
+
*
|
|
370
|
+
* @default false
|
|
371
|
+
*/
|
|
55
372
|
preventRepeat?: boolean;
|
|
56
373
|
} | {
|
|
57
|
-
eventType: "keyup"
|
|
374
|
+
eventType: Extract<KeyEventType, "keyup">;
|
|
58
375
|
preventRepeat?: never;
|
|
59
376
|
});
|
|
60
|
-
|
|
61
|
-
|
|
377
|
+
/**
|
|
378
|
+
* A function that detaches the listener registered by `useKey` immediately,
|
|
379
|
+
* without waiting for the component to unmount.
|
|
380
|
+
*
|
|
381
|
+
* Safe to call more than once. Note that this does not permanently disable
|
|
382
|
+
* the hook: if `eventType`, `enabled`, `target`, or `capture` change
|
|
383
|
+
* afterwards, a new listener may be attached again on the next render.
|
|
384
|
+
* Changing `key` — or any of the modifier-matching options — does *not*
|
|
385
|
+
* cause a re-attach; those are picked up fresh on the next keystroke
|
|
386
|
+
* without the underlying listener ever being torn down.
|
|
387
|
+
*/
|
|
388
|
+
export type UseKeyReturn = () => void;
|
|
389
|
+
/**
|
|
390
|
+
* Calls `handler` when `key` is pressed (or released, depending on
|
|
391
|
+
* `eventType`), optionally matching an exact combination of modifier keys.
|
|
392
|
+
*
|
|
393
|
+
* Ignores keystrokes that occur during IME composition (for example, while
|
|
394
|
+
* typing pinyin or romaji before a CJK character is confirmed), so
|
|
395
|
+
* shortcuts don't misfire or interfere with the IME's own confirmation key
|
|
396
|
+
* — often Enter. By default, also ignores keystrokes while focus is inside
|
|
397
|
+
* a text input, textarea, select, or contenteditable element — see
|
|
398
|
+
* `ignoreWhenFocusedInInputs` in {@link UseKeyOptions}.
|
|
399
|
+
*
|
|
400
|
+
* @param key The key to match, compared case-insensitively against
|
|
401
|
+
* `KeyboardEvent.key` (e.g. `"Escape"`, `"a"`, `"Enter"`).
|
|
402
|
+
* @param handler Called with the native event when a match is found. Doesn't need to be
|
|
403
|
+
* memoized.
|
|
404
|
+
* @param options See {@link UseKeyOptions}.
|
|
405
|
+
* @returns A function that detaches the listener on demand.
|
|
406
|
+
*
|
|
407
|
+
* @example
|
|
408
|
+
* ```tsx
|
|
409
|
+
* useKey("Escape", () => setOpen(false));
|
|
410
|
+
* ```
|
|
411
|
+
*
|
|
412
|
+
* @example
|
|
413
|
+
* Matching a modifier combination — all four modifier flags are matched
|
|
414
|
+
* exactly, so this only fires for Ctrl+K alone, not Ctrl+Shift+K:
|
|
415
|
+
* ```tsx
|
|
416
|
+
* useKey("k", () => openCommandPalette(), { ctrlKey: true });
|
|
417
|
+
* ```
|
|
418
|
+
*/
|
|
419
|
+
export declare function useKey(key: string, handler: (event: KeyboardEvent) => void, options?: UseKeyOptions): UseKeyReturn;
|
|
62
420
|
export interface DebounceOptions {
|
|
63
421
|
maxWait?: number;
|
|
64
422
|
leading?: boolean;
|
package/dist/useEventListener.js
CHANGED
|
@@ -1,32 +1,40 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { useCallback as e, useEffect as t, useEffectEvent as n, useRef as r } from "react";
|
|
2
2
|
//#region src/events/useEventListener/useEventListener.ts
|
|
3
|
-
var
|
|
4
|
-
function
|
|
5
|
-
let { target:
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
let e =
|
|
10
|
-
|
|
11
|
-
let
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
3
|
+
var i = globalThis.process?.env?.NODE_ENV !== "production";
|
|
4
|
+
function a(a, o, s = {}) {
|
|
5
|
+
let { target: c, capture: l = !1, passive: u = !1, once: d = !1, signal: f } = s, p = c === void 0 ? typeof window > "u" ? null : window : c, m = n(o), h = Array.isArray(a) ? a.join(",") : a, g = r(null), _ = e(() => {
|
|
6
|
+
g.current?.abort(), g.current = null;
|
|
7
|
+
}, []);
|
|
8
|
+
return t(() => {
|
|
9
|
+
let e = Array.isArray(a) ? a : [a];
|
|
10
|
+
i && e.length === 0 && console.warn("[useEventListener] Called with an empty eventName array — no listeners were attached.");
|
|
11
|
+
let t = p && "current" in p ? p.current : p;
|
|
12
|
+
if (!t) return;
|
|
13
|
+
if (!t.addEventListener) {
|
|
14
|
+
i && console.warn("[useEventListener] The resolved target does not implement addEventListener — no listener was attached.", t);
|
|
15
|
+
return;
|
|
16
|
+
}
|
|
17
|
+
let n = new AbortController();
|
|
18
|
+
g.current = n;
|
|
19
|
+
let r = f ? AbortSignal.any([n.signal, f]) : n.signal, o = (e) => m(e);
|
|
20
|
+
return e.forEach((e) => {
|
|
21
|
+
t.addEventListener(e, o, {
|
|
22
|
+
capture: l,
|
|
23
|
+
passive: u,
|
|
24
|
+
once: d,
|
|
25
|
+
signal: r
|
|
17
26
|
});
|
|
18
27
|
}), () => {
|
|
19
|
-
n.
|
|
20
|
-
e.removeEventListener(t, r, { capture: s });
|
|
21
|
-
});
|
|
28
|
+
n.abort(), g.current === n && (g.current = null);
|
|
22
29
|
};
|
|
23
30
|
}, [
|
|
24
|
-
|
|
31
|
+
h,
|
|
32
|
+
p,
|
|
33
|
+
l,
|
|
25
34
|
u,
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
]);
|
|
35
|
+
d,
|
|
36
|
+
f
|
|
37
|
+
]), _;
|
|
30
38
|
}
|
|
31
39
|
//#endregion
|
|
32
|
-
export {
|
|
40
|
+
export { a as t };
|