UNPKG

shortcutter

Version:

Tiny, dependency-free library to manage keyboard shortcuts in your application.

83 lines (82 loc) 3.25 kB
import { useContexts } from './contexts'; import { useController } from './controller'; import { normalizeKeyCode } from './helpers'; const DEFAULT_CONFIG = { eventTarget: window, defaultContext: 'default', }; export function useShortcutter(customConfig = {}) { const CONFIG = { ...DEFAULT_CONFIG, ...customConfig, }; const { eventTarget, defaultContext } = CONFIG; const contexts = useContexts(); const keysRecorder = useController(); contexts.add(defaultContext); contexts.setActive(defaultContext); eventTarget.addEventListener('keydown', onkeydown); eventTarget.addEventListener('keyup', onkeyup); eventTarget.addEventListener('blur', onblur); eventTarget.addEventListener('unload', onunload); const invokeClbck = (keys, event, phase) => { contexts.getActive().forEach(context => { const ctx = contexts.get(context); if (ctx?.has(keys, phase)) { ctx.get(keys, phase)(event, phase); } }); }; function onkeydown(event) { const previousCombination = keysRecorder.getPressed().join('+'); keysRecorder.press(normalizeKeyCode(event.code)); const nextCombination = keysRecorder.getPressed().join('+'); if (previousCombination !== nextCombination) { if (previousCombination.length) { invokeClbck(previousCombination.split('+'), event, "up"); } invokeClbck(nextCombination.split('+'), event, "down"); } else { invokeClbck(previousCombination.split('+'), event, "press"); } } function onkeyup(event) { const previousCombination = keysRecorder.getPressed().join('+'); keysRecorder.release(normalizeKeyCode(event.code)); const nextCombination = keysRecorder.getPressed().join('+'); if (previousCombination.length) { invokeClbck(previousCombination.split('+'), event, "up"); } if (nextCombination.length) { invokeClbck(nextCombination.split('+'), event, "down"); } } function onblur(event) { const previousCombination = keysRecorder.getPressed().join('+'); if (previousCombination.length) { invokeClbck(previousCombination.split('+'), event, "up"); } keysRecorder.releaseAll(); } function onunload() { eventTarget.removeEventListener('keydown', onkeydown); eventTarget.removeEventListener('keyup', onkeyup); eventTarget.removeEventListener('blur', onblur); eventTarget.removeEventListener('unload', onunload); } return { listen: (context, keys, callback, phases) => { const ctx = contexts.has(context) ? contexts.get(context) : contexts.add(context); ctx?.add(keys, callback, phases); return () => ctx?.remove(keys, phases); }, unlisten: (context, keys, phases) => { const ctx = contexts.get(context); ctx?.remove(keys, phases); }, hasContext: (name) => contexts.has(name), getActiveContext: () => contexts.getActive(), setActiveContext: (name) => contexts.setActive(name), }; }