1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138
| import { useCallback, useEffect, MutableRefObject } from "react";
type keyType = KeyboardEvent["keyCode"] | KeyboardEvent["key"]; type keyFilter = keyType | Array<keyType>; type EventHandler = (event: KeyboardEvent) => void; type keyEvent = "keydown" | "keyup"; type BasicElement = HTMLElement | Element | Document | Window; type TargetElement = BasicElement | MutableRefObject<null | undefined>; type EventOptions = { events?: Array<keyEvent>; target?: TargetElement; };
const modifierKey: any = { ctrl: (event: KeyboardEvent) => event.ctrlKey, shift: (event: KeyboardEvent) => event.shiftKey, alt: (event: KeyboardEvent) => event.altKey, meta: (event: KeyboardEvent) => event.metaKey };
const defaultEvents: Array<keyEvent> = ["keydown"];
function isType<T>(obj: T): string { return Object.prototype.toString .call(obj) .replace(/^\[object (.+)\]$/, "$1") .toLowerCase(); }
function getTargetElement( target?: TargetElement, defaultElement?: BasicElement ) { if (!target) { return defaultElement; }
if ("current" in target) { return target.current; }
return target; }
const keyActivated = (event: KeyboardEvent, keyFilter: any) => { const type = isType(keyFilter); const { keyCode } = event;
if (type === "number") { return keyCode == keyFilter; }
const keyCodeArr = keyFilter.split("."); let genLen = 0; for (const key of keyCodeArr) { const genModifier = modifierKey[key];
if ((genModifier && genModifier) || keyCode == key) { genLen++; } }
return genLen === keyCodeArr.length; };
const genKeyFormate = (event: KeyboardEvent, keyFilter: any) => { const type = isType(keyFilter);
if (type === "string" || type === "number") { return keyActivated(event, keyFilter); }
if (type === "array") { return keyFilter.some((item: keyFilter) => keyActivated(event, item)); } };
const useKeyPress = ( keyCode: keyFilter, eventHandler?: EventHandler, options: EventOptions = {} ) => { const { target, events = defaultEvents } = options;
const callbackHandler = useCallback( (event) => { if (genKeyFormate(event, keyCode)) { typeof eventHandler === "function" && eventHandler(event); } }, [keyCode] );
useEffect(() => { const el = getTargetElement(target, window)!;
for (const eventName of events) { el.addEventListener(eventName, callbackHandler); }
return () => { for (const eventName of events) { el.removeEventListener(eventName, callbackHandler); } }; }, [keyCode, events, callbackHandler]); };
export default useKeyPress;
|