reakeys
Version:
React Hotkeys Hooks
120 lines (119 loc) • 5.28 kB
JavaScript
(function(global, factory) {
typeof exports === "object" && typeof module !== "undefined" ? factory(exports, require("react"), require("ctrl-keys")) : typeof define === "function" && define.amd ? define(["exports", "react", "ctrl-keys"], factory) : (global = typeof globalThis !== "undefined" ? globalThis : global || self, factory(global.reakeys = {}, global.react, global.ctrlKeys));
})(this, function(exports2, react, ctrlKeys) {
"use strict";
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 = ctrlKeys.keys();
const keyupGlobalHandler = ctrlKeys.keys();
const keydownGlobalHandler = ctrlKeys.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 = ctrlKeys.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] = react.useState([]);
react.useLayoutEffect(() => {
if (!isGlobalListenersBinded && window !== void 0) {
window.addEventListener("keypress", keypressGlobalHandler.handle);
window.addEventListener("keyup", keyupGlobalHandler.handle);
window.addEventListener("keydown", keydownGlobalHandler.handle);
isGlobalListenersBinded = true;
}
}, []);
react.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]);
react.useEffect(() => {
setRegistered(hotkeys);
}, []);
return registered;
};
exports2.MODIFIER_KEY = MODIFIER_KEY;
exports2.getHotkeyText = getHotkeyText;
exports2.isMac = isMac;
exports2.useHotkeys = useHotkeys;
Object.defineProperty(exports2, Symbol.toStringTag, { value: "Module" });
});
//# sourceMappingURL=index.umd.cjs.map