@mirawision/reactive-hooks
Version:
A comprehensive collection of 50+ React hooks for state management, UI interactions, device APIs, async operations, drag & drop, audio/speech, and more. Full TypeScript support with SSR safety.
66 lines (65 loc) • 2.37 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", { value: true });
exports.useShortcuts = useShortcuts;
const react_1 = require("react");
const use_event_listener_1 = require("./use-event-listener");
/**
* Parses a shortcut combo string into its components.
* Format: "Ctrl+Alt+Shift+Meta+K" or simpler "Ctrl+K"
*/
function parseShortcut(combo) {
const parts = combo.toLowerCase().split('+');
const key = parts.pop() || '';
return {
key: key.length === 1 ? key : key.charAt(0).toUpperCase() + key.slice(1),
ctrl: parts.includes('ctrl'),
alt: parts.includes('alt'),
shift: parts.includes('shift'),
meta: parts.includes('meta'),
};
}
/**
* Checks if a keyboard event matches a parsed shortcut.
*/
function matchesShortcut(event, shortcut) {
// Handle special cases for different keyboard layouts
const eventKey = event.key.toLowerCase();
const shortcutKey = shortcut.key.toLowerCase();
const keyMatches = eventKey === shortcutKey ||
event.code.toLowerCase() === `key${shortcutKey}`;
return (keyMatches &&
event.ctrlKey === shortcut.ctrl &&
event.altKey === shortcut.alt &&
event.shiftKey === shortcut.shift &&
event.metaKey === shortcut.meta);
}
/**
* A hook that sets up keyboard shortcuts with modifier key support.
* @param shortcuts Array of shortcuts with combo strings and handlers
* @param opts Options for target element
*
* @example
* useShortcuts([
* { combo: 'Ctrl+S', handler: (e) => save(e) },
* { combo: 'Ctrl+Shift+Z', handler: (e) => redo(e) }
* ]);
*/
function useShortcuts(shortcuts, opts = {}) {
// Parse shortcuts once
const parsedShortcuts = shortcuts.map(s => ({
...s,
parsed: parseShortcut(s.combo),
}));
// Handle keyboard events
const handleKeyDown = (0, react_1.useCallback)((event) => {
// Find matching shortcut
const matchingShortcut = parsedShortcuts.find(s => matchesShortcut(event, s.parsed));
if (matchingShortcut) {
event.preventDefault();
matchingShortcut.handler(event);
}
}, [parsedShortcuts]);
// Set up event listener
const target = opts.target || (typeof window !== 'undefined' ? window : undefined);
(0, use_event_listener_1.useEventListener)(target, 'keydown', handleKeyDown);
}