UNPKG

@acusti/use-keyboard-events

Version:

React hook that takes keyboard event handlers and attaches them to the document

194 lines (193 loc) 5.89 kB
import { c } from "react/compiler-runtime"; import { useEffect } from "react"; const handlersData = { config: /* @__PURE__ */ new Map(), keydown: [], keypress: [], keyup: [] }; const PRIORITY_MIN = -50; const PRIORITY_MAX = 50; const PRIORITY_MODIFIER = PRIORITY_MIN * -1; const noop = () => { }; function addHandler({ eventType, handler, ignoreUsedKeyboardEvents = true, priority: _priority }) { if (!handler) return noop; const priority = Math.min(PRIORITY_MAX + PRIORITY_MODIFIER, Math.max(0, (_priority ?? 0) + PRIORITY_MODIFIER)); const handlersByPriority = handlersData[eventType]; handlersByPriority[priority] ?? (handlersByPriority[priority] = /* @__PURE__ */ new Set()); handlersByPriority[priority].add(handler); handlersData.config.set(handler, { ignoreUsedKeyboardEvents, priority }); return () => { handlersData.config.delete(handler); if (handlersByPriority[priority] == null) return; handlersByPriority[priority].delete(handler); if (!handlersByPriority[priority].size) { delete handlersByPriority[priority]; for (let index = priority; index > -1 && handlersByPriority[index] == null && handlersByPriority.length === index + 1; index--) { handlersByPriority.length = index; } } }; } const IS_APPLE_REGEXP = /mac|iphone|ipad|ipod/i; function isPrimaryModifierPressed(event) { var _a; const platform = ((_a = globalThis.navigator) == null ? void 0 : _a.platform) ?? ""; return IS_APPLE_REGEXP.test(platform) ? event.metaKey : event.ctrlKey; } const NON_TEXT_INPUT_TYPES = /* @__PURE__ */ new Set(["button", "checkbox", "color", "file", "hidden", "image", "radio", "range", "reset", "submit"]); const NON_TEXT_INPUT_USES_KEYS = /* @__PURE__ */ new Set([" ", "ArrowDown", "ArrowLeft", "ArrowRight", "ArrowUp", "Enter"]); const usesKeyEvents = (target) => target.isContentEditable || target.tagName === "TEXTAREA" || target.tagName === "INPUT"; const isEventTargetUsingKeyEvent = (event) => { const target = event.target; if (target == null || !usesKeyEvents(target)) return false; if (target.tagName !== "INPUT") return true; if (!NON_TEXT_INPUT_TYPES.has(target.type)) return true; return NON_TEXT_INPUT_USES_KEYS.has(event.key); }; function addHandlers(doc) { if (!(doc == null ? void 0 : doc.defaultView) || doc.defaultView.__useKeyboardEventsAttached__) { return; } doc.defaultView.__useKeyboardEventsAttached__ = true; doc.addEventListener("keydown", handleKeyboardEvent); doc.addEventListener("keypress", handleKeyboardEvent); doc.addEventListener("keyup", handleKeyboardEvent); return () => { if (doc.defaultView) { doc.defaultView.__useKeyboardEventsAttached__ = false; } doc.removeEventListener("keydown", handleKeyboardEvent); doc.removeEventListener("keypress", handleKeyboardEvent); doc.removeEventListener("keyup", handleKeyboardEvent); }; } function handleKeyboardEvent(event) { const eventType = event.type; const handlersByPriority = handlersData[eventType]; let index = handlersByPriority.length; const targetUsesKeyEvents = isEventTargetUsingKeyEvent(event); while (index--) { const handlers = handlersByPriority[index]; if (handlers != null) { for (const handler of handlers) { const config = handlersData.config.get(handler); if (!targetUsesKeyEvents || (config == null ? void 0 : config.ignoreUsedKeyboardEvents) === false) { const shouldPropagate = handler(event); if (shouldPropagate === false) return; } } } } } function useKeyboardEvents(t0) { const $ = c(16); const { ignoreUsedKeyboardEvents, onKeyDown, onKeyPress, onKeyUp, priority } = t0; let t1; if ($[0] === Symbol.for("react.memo_cache_sentinel")) { t1 = []; $[0] = t1; } else { t1 = $[0]; } useEffect(_temp2, t1); let t2; let t3; if ($[1] !== ignoreUsedKeyboardEvents || $[2] !== onKeyDown || $[3] !== priority) { t2 = () => addHandler({ eventType: "keydown", handler: onKeyDown, ignoreUsedKeyboardEvents, priority }); t3 = [ignoreUsedKeyboardEvents, onKeyDown, priority]; $[1] = ignoreUsedKeyboardEvents; $[2] = onKeyDown; $[3] = priority; $[4] = t2; $[5] = t3; } else { t2 = $[4]; t3 = $[5]; } useEffect(t2, t3); let t4; let t5; if ($[6] !== ignoreUsedKeyboardEvents || $[7] !== onKeyPress || $[8] !== priority) { t4 = () => addHandler({ eventType: "keypress", handler: onKeyPress, ignoreUsedKeyboardEvents, priority }); t5 = [ignoreUsedKeyboardEvents, onKeyPress, priority]; $[6] = ignoreUsedKeyboardEvents; $[7] = onKeyPress; $[8] = priority; $[9] = t4; $[10] = t5; } else { t4 = $[9]; t5 = $[10]; } useEffect(t4, t5); let t6; let t7; if ($[11] !== ignoreUsedKeyboardEvents || $[12] !== onKeyUp || $[13] !== priority) { t6 = () => addHandler({ eventType: "keyup", handler: onKeyUp, ignoreUsedKeyboardEvents, priority }); t7 = [ignoreUsedKeyboardEvents, onKeyUp, priority]; $[11] = ignoreUsedKeyboardEvents; $[12] = onKeyUp; $[13] = priority; $[14] = t6; $[15] = t7; } else { t6 = $[14]; t7 = $[15]; } useEffect(t6, t7); } function _temp2() { addHandlers(document); document.querySelectorAll("iframe").forEach(_temp); } function _temp(iframe) { if (!isSameOriginFrame(iframe) || !iframe.contentDocument) { return; } addHandlers(iframe.contentDocument); } function isSameOriginFrame(iframe) { try { return typeof iframe.contentWindow.location.href === "string"; } catch (err) { return false; } } export { useKeyboardEvents as default, isEventTargetUsingKeyEvent, isPrimaryModifierPressed, usesKeyEvents }; //# sourceMappingURL=useKeyboardEvents.js.map