Line data Source code
1 : import * as React from 'react';
2 :
3 : type KeyEventCallback = (event: KeyboardEvent) => void;
4 :
5 : export interface KeyEventHandler {
6 : key: string;
7 : ctrlKey?: boolean;
8 : capture?: boolean;
9 : callback: KeyEventCallback;
10 : }
11 :
12 1 : export function useKeyEvents(subscribers: KeyEventHandler[]) {
13 1 : const subscribersRef = React.useRef<KeyEventHandler[]>([]);
14 1 : React.useEffect(() => {
15 1 : subscribersRef.current = subscribers;
16 1 : }, [subscribers]);
17 1 : const handleKeyPress = React.useCallback((event: KeyboardEvent, capture: boolean) => {
18 1 : for (const subscriber of subscribersRef.current) {
19 1 : const ctrlKeyMatches = subscriber.ctrlKey === undefined || subscriber.ctrlKey === event.ctrlKey;
20 1 : const captureMatches = (subscriber.capture ?? false) === capture;
21 1 : if (captureMatches && ctrlKeyMatches && subscriber.key == event.key) {
22 1 : subscriber.callback(event);
23 : }
24 1 : }
25 1 : }, []);
26 1 : const handleKeyPressCapture = React.useCallback<(event: KeyboardEvent) => void>((event: KeyboardEvent) => {
27 1 : if (event.defaultPrevented) return;
28 1 : handleKeyPress(event, true);
29 1 : }, [handleKeyPress]);
30 1 : const handleKeyPressBubble = React.useCallback<(event: KeyboardEvent) => void>((event: KeyboardEvent) => {
31 1 : if (event.defaultPrevented) return;
32 1 : handleKeyPress(event, false);
33 1 : }, [handleKeyPress]);
34 1 : React.useEffect(() => {
35 1 : const target = document;
36 1 : if (target) {
37 1 : target.addEventListener('keydown', handleKeyPressCapture, true);
38 1 : target.addEventListener('keydown', handleKeyPressBubble);
39 1 : return () => {
40 1 : target.removeEventListener('keydown', handleKeyPressCapture, true);
41 1 : target.removeEventListener('keydown', handleKeyPressBubble);
42 1 : };
43 1 : } else {
44 1 : return () => {};
45 : }
46 1 : }, [handleKeyPressBubble, handleKeyPressCapture, document]);
47 1 : }
|