import { useStore } from '@nanostores/react'; import { useEffect } from 'react'; import { shortcutsStore, type Shortcuts } from '~/lib/stores/settings'; class ShortcutEventEmitter { #emitter = new EventTarget(); dispatch(type: keyof Shortcuts) { this.#emitter.dispatchEvent(new Event(type)); } on(type: keyof Shortcuts, cb: VoidFunction) { this.#emitter.addEventListener(type, cb); return () => { this.#emitter.removeEventListener(type, cb); }; } } export const shortcutEventEmitter = new ShortcutEventEmitter(); export function useShortcuts(): void { const shortcuts = useStore(shortcutsStore); useEffect(() => { const handleKeyDown = (event: KeyboardEvent): void => { const { key, ctrlKey, shiftKey, altKey, metaKey } = event; for (const name in shortcuts) { const shortcut = shortcuts[name as keyof Shortcuts]; if ( shortcut.key.toLowerCase() === key.toLowerCase() && (shortcut.ctrlOrMetaKey ? ctrlKey || metaKey : (shortcut.ctrlKey === undefined || shortcut.ctrlKey === ctrlKey) && (shortcut.metaKey === undefined || shortcut.metaKey === metaKey)) && (shortcut.shiftKey === undefined || shortcut.shiftKey === shiftKey) && (shortcut.altKey === undefined || shortcut.altKey === altKey) ) { shortcutEventEmitter.dispatch(name as keyof Shortcuts); event.preventDefault(); event.stopPropagation(); shortcut.action(); break; } } }; window.addEventListener('keydown', handleKeyDown); return () => { window.removeEventListener('keydown', handleKeyDown); }; }, [shortcuts]); }