tududi/frontend/hooks/useKeyboardShortcuts.ts
Chris 703f6fe506
Add custom keyboard shortcuts (#749)
* Add custom keyboard shortcuts

* fixup! Add custom keyboard shortcuts
2025-12-28 21:58:21 +02:00

75 lines
2.1 KiB
TypeScript

import { useEffect, useCallback, useMemo } from 'react';
import {
KeyboardShortcut,
ShortcutAction,
matchesShortcut,
isInputElement,
getDefaultShortcuts,
} from '../utils/keyboardShortcutsService';
type ShortcutHandlers = Partial<Record<ShortcutAction, () => void>>;
/**
* Hook to register and handle keyboard shortcuts
*
* @param shortcuts - Array of keyboard shortcuts to listen for
* @param handlers - Object mapping actions to handler functions
* @param enabled - Whether shortcuts are currently enabled
*
* @example
* useKeyboardShortcuts(
* userShortcuts,
* {
* inbox: () => navigate('/inbox'),
* task: () => openTaskModal(),
* },
* true
* );
*/
export const useKeyboardShortcuts = (
shortcuts: KeyboardShortcut[] | undefined,
handlers: ShortcutHandlers,
enabled: boolean = true
) => {
// Use defaults if no shortcuts provided
const activeShortcuts = useMemo(
() => shortcuts || getDefaultShortcuts(),
[shortcuts]
);
// Memoize the handler to prevent unnecessary re-renders
const handleKeyDown = useCallback(
(event: KeyboardEvent) => {
// Skip if shortcuts are disabled
if (!enabled) return;
// Skip if user is typing in an input field
if (isInputElement(event.target)) return;
// Check each shortcut for a match
for (const shortcut of activeShortcuts) {
if (matchesShortcut(event, shortcut)) {
const handler = handlers[shortcut.action];
if (handler) {
event.preventDefault();
handler();
}
break;
}
}
},
[activeShortcuts, handlers, enabled]
);
useEffect(() => {
if (!enabled) return;
document.addEventListener('keydown', handleKeyDown);
return () => {
document.removeEventListener('keydown', handleKeyDown);
};
}, [handleKeyDown, enabled]);
};
export default useKeyboardShortcuts;