@keybindy/react
Version:
Keybindy for React: Simple, scoped keyboard shortcuts that require little setup. designed to smoothly blend in with your React applications, allowing for robust keybinding functionality without the overhead.
75 lines (72 loc) • 3.11 kB
JavaScript
import { jsx, Fragment } from 'react/jsx-runtime';
import React from 'react';
import { useKeybindy } from './useKeybindy.js';
/**
* `<Keybindy />` is a React component that registers keyboard shortcuts within a given scope. It allows
* users to define custom shortcuts and their associated handlers, while managing scope-based shortcut behavior.
* The component listens for keyboard events and triggers the registered handler when the corresponding keys are pressed.
* It also provides an optional callback (`onShortcutFired`) to notify users when a shortcut is triggered.
*
* @component
*
* @example
* // Basic usage
* <Keybindy scope="global" shortcuts={[{ keys: ['ctrl', 's'], handler: saveDocument }]} >
* <div>Content with shortcuts</div>
* </Keybindy>
*
* @example
* // With custom callback for onShortcutFired
* <Keybindy
* scope="editor"
* shortcuts={[{ keys: ['ctrl', 'e'], handler: editDocument }]}
* onShortcutFired={(info) => console.log('Shortcut fired:', info)}
* >
* <div>Editor with shortcuts</div>
* </Keybindy>
*
* @param {ShortcutProps} props - Props for the Shortcut component.
* @param {string} props.scope - The scope under which the shortcuts should be active.
* @param {ShortcutDefinition[]} [props.shortcuts] - An array of shortcut definitions, each containing keys, handler, and options.
* @param {boolean} [props.disabled=false] - Whether the shortcuts should be disabled for this scope.
* @param {(info: Shortcut) => void} [props.onShortcutFired] - Optional callback triggered when a shortcut is fired, providing the shortcut info.
* @param {React.ReactNode} props.children - The children to be rendered inside the component, which can contain any JSX elements.
*
* @returns {JSX.Element} The rendered component with registered shortcuts within the provided scope.
*/
const Keybindy = ({ scope, shortcuts = [], children, disabled, onShortcutFired, logs = false, }) => {
const { register, unregister, manager, pushScope, popScope, getScopes, setScope } = useKeybindy({
onShortcutFired,
logs,
});
const prevScope = React.useRef(null);
React.useEffect(() => {
prevScope.current = manager.getActiveScope();
// Add scope if doesn't exist
if (!getScopes()?.includes(scope)) {
pushScope(scope);
}
// Set this scope as active
setScope(scope);
// Register all shortcuts for this scope
shortcuts.forEach(({ keys, handler, options }) => {
register(keys, handler, { ...options, scope });
});
if (disabled) {
manager.disableAll(scope);
}
return () => {
shortcuts.forEach(({ keys }) => {
if (Array.isArray(keys[0])) {
keys.forEach(key => unregister(key, scope));
}
else {
unregister(keys, scope);
}
});
popScope();
};
}, [scope, JSON.stringify(shortcuts)]);
return jsx(Fragment, { children: children });
};
export { Keybindy };