reakeys
Version:
React Hotkeys Hooks
118 lines (117 loc) • 4.48 kB
JavaScript
import { useState, useLayoutEffect, useEffect } from "react";
import { keys } from "ctrl-keys";
function isMac() {
try {
return navigator.platform.toUpperCase().indexOf("MAC") >= 0;
} catch {
return false;
}
}
function getModifierKey() {
return isMac() ? "⌘" : "CTRL";
}
const MODIFIER_KEY = getModifierKey();
function getHotkeyText(hotkey) {
return hotkey.toLowerCase().replace("modifier", getModifierKey()).replace("mod", getModifierKey()).replace("shift", "⇧");
}
let isGlobalListenersBinded = false;
const keypressGlobalHandler = keys();
const keyupGlobalHandler = keys();
const keydownGlobalHandler = keys();
const handlers = /* @__PURE__ */ new Map();
let hotkeys = [];
const extractKeys = (keys2) => {
const normalizedKeys = Array.isArray(keys2) ? keys2.map((key) => key.toLowerCase()) : [keys2.toLowerCase()];
const modKey = isMac() ? "meta" : "ctrl";
return normalizedKeys.map((key) => key.replace("modifier", modKey).replace("mod", modKey));
};
const focusInputWrapper = (callback) => (event) => {
const target = event.target;
const isInput = target.tagName === "INPUT" && !["checkbox", "radio", "range", "button", "file", "reset", "submit", "color"].includes(target.type);
if (target.isContentEditable || (isInput || target.tagName === "TEXTAREA" || target.tagName === "SELECT") && !target.readOnly) {
return;
}
return callback(event);
};
const registerGlobalShortcut = (shortcut) => {
if (!shortcut.action || shortcut.action === "keypress") {
keypressGlobalHandler.add(...extractKeys(shortcut.keys), shortcut.callback);
}
if (shortcut.action === "keyup") {
keyupGlobalHandler.add(...extractKeys(shortcut.keys), shortcut.callback);
}
if (shortcut.action === "keydown") {
keydownGlobalHandler.add(...extractKeys(shortcut.keys), shortcut.callback);
}
};
const removeGlobalShortcut = (shortcut) => {
if (!shortcut.action || shortcut.action === "keypress") {
keypressGlobalHandler.remove(...extractKeys(shortcut.keys), shortcut.callback);
}
if (shortcut.action === "keyup") {
keyupGlobalHandler.remove(...extractKeys(shortcut.keys), shortcut.callback);
}
if (shortcut.action === "keydown") {
keydownGlobalHandler.remove(...extractKeys(shortcut.keys), shortcut.callback);
}
};
const registerElementShortcut = (shortcut) => {
var _a, _b, _c;
const handler = keys();
handler.add(...extractKeys(shortcut.keys), shortcut.callback);
(_b = (_a = shortcut.ref) == null ? void 0 : _a.current) == null ? void 0 : _b.addEventListener(shortcut.action ?? "keypress", handler.handle);
handlers.set((_c = shortcut.ref) == null ? void 0 : _c.current, handler);
};
const removeElementShortcut = (shortcut) => {
var _a, _b, _c, _d;
if (((_a = shortcut.ref) == null ? void 0 : _a.current) && !shortcut.disabled) {
const handler = handlers.get((_b = shortcut.ref) == null ? void 0 : _b.current);
handler == null ? void 0 : handler.remove(...extractKeys(shortcut.keys), shortcut.callback);
(_d = (_c = shortcut.ref) == null ? void 0 : _c.current) == null ? void 0 : _d.removeEventListener(shortcut.action ?? "keypress", handler.handle);
}
};
const useHotkeys = (shortcuts = []) => {
const [registered, setRegistered] = useState([]);
useLayoutEffect(() => {
if (!isGlobalListenersBinded && window !== void 0) {
window.addEventListener("keypress", keypressGlobalHandler.handle);
window.addEventListener("keyup", keyupGlobalHandler.handle);
window.addEventListener("keydown", keydownGlobalHandler.handle);
isGlobalListenersBinded = true;
}
}, []);
useLayoutEffect(() => {
shortcuts.map((shortcut) => {
var _a;
if (shortcut.disabled) {
return;
}
shortcut.callback = focusInputWrapper(shortcut.callback);
if ((_a = shortcut.ref) == null ? void 0 : _a.current) {
registerElementShortcut(shortcut);
hotkeys = [...hotkeys, shortcut];
} else if (!shortcut.ref) {
registerGlobalShortcut(shortcut);
hotkeys = [...hotkeys, shortcut];
}
});
return () => {
shortcuts.map((shortcut) => {
removeElementShortcut(shortcut);
removeGlobalShortcut(shortcut);
hotkeys = hotkeys.filter((hotkey) => shortcut !== hotkey);
});
};
}, [shortcuts]);
useEffect(() => {
setRegistered(hotkeys);
}, []);
return registered;
};
export {
MODIFIER_KEY,
getHotkeyText,
isMac,
useHotkeys
};
//# sourceMappingURL=index.js.map