Press n or j to go to the next uncovered block, b, p or k for the previous block.
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 | 54x 54x 54x 54x 34x 34x 54x 8x 1x 7x 7x 8x 1x 7x 7x 7x 5x 5x 4x 5x 5x 5x 54x 34x 1x 33x 33x 33x 33x 33x | /**
* Custom hook for keyboard shortcut handling
*
* @module hooks/useKeyboardShortcuts
*/
import { useEffect, useCallback, useRef } from 'react';
import { ShortcutMap, UseKeyboardShortcutsOptions } from '../types/keyboard';
import {
getKeyCombination,
shortcutsMatch,
shouldIgnoreKeyboardEvent,
getPlatformShortcut,
areKeyboardShortcutsSupported,
} from '../utils/keyboardUtils';
import logger from '../utils/logger';
/**
* Custom hook for registering and handling keyboard shortcuts
*
* @param options - Configuration options for keyboard shortcuts
*
* @example
* ```tsx
* const shortcuts = {
* 'save': {
* id: 'save',
* keys: 'ctrl+s',
* description: 'Save document',
* category: 'Actions',
* handler: () => handleSave(),
* }
* };
*
* useKeyboardShortcuts({
* shortcuts,
* enabled: true,
* preventDefault: true,
* });
* ```
*/
export function useKeyboardShortcuts(options: UseKeyboardShortcutsOptions): void {
const {
shortcuts,
enabled = true,
preventDefault = true,
stopPropagation = false,
} = options;
const shortcutsRef = useRef<ShortcutMap>(shortcuts);
const optionsRef = useRef({ preventDefault, stopPropagation });
useEffect(() => {
shortcutsRef.current = shortcuts;
optionsRef.current = { preventDefault, stopPropagation };
}, [shortcuts, preventDefault, stopPropagation]);
/**
* Handle keyboard event and match against registered shortcuts
*/
const handleKeyDown = useCallback((event: KeyboardEvent): void => {
if (!areKeyboardShortcutsSupported() || shouldIgnoreKeyboardEvent(event)) {
return;
}
const keyCombination = getKeyCombination(event);
const matchingShortcut = Object.values(shortcutsRef.current).find(shortcut => {
if (shortcut.enabled === false) {
return false;
}
const shortcutKeys = getPlatformShortcut(
shortcut.keys,
shortcut.platformKeys
);
return shortcutsMatch(keyCombination, shortcutKeys);
});
if (matchingShortcut) {
logger.debug('Keyboard shortcut triggered', {
id: matchingShortcut.id,
keys: keyCombination,
description: matchingShortcut.description,
});
if (optionsRef.current.preventDefault) {
event.preventDefault();
}
Iif (optionsRef.current.stopPropagation) {
event.stopPropagation();
}
try {
matchingShortcut.handler();
} catch (error) {
logger.error('Error executing keyboard shortcut handler', {
id: matchingShortcut.id,
error,
});
}
}
}, []);
useEffect(() => {
if (!enabled || !areKeyboardShortcutsSupported()) {
return;
}
logger.debug('Registering keyboard shortcuts');
window.addEventListener('keydown', handleKeyDown);
return () => {
logger.debug('Unregistering keyboard shortcuts');
window.removeEventListener('keydown', handleKeyDown);
};
}, [enabled, handleKeyDown]);
}
|