@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.
67 lines (64 loc) • 2.5 kB
JavaScript
import { jsx, Fragment } from 'react/jsx-runtime';
import React from 'react';
import { useKeybindy } from './useKeybindy.js';
const KeybindyComponent = ({ scope = 'global', shortcuts = [], children, disabled, onShortcutFired, logs = false, }) => {
const { register, unregister, manager, pushScope, popScope, getScopes, setScope } = useKeybindy({
onShortcutFired,
logs,
});
// Memoize a stable representation of shortcuts, excluding the handler.
// This prevents the effect from re-running unnecessarily.
const stableShortcuts = React.useMemo(() => {
return shortcuts.map(({ keys, options }) => ({ keys, options }));
}, [JSON.stringify(shortcuts.map(s => ({ keys: s.keys, options: s.options })))]);
// Use a ref to store the latest handlers, preventing re-renders from causing issues.
const handlersRef = React.useRef({});
React.useEffect(() => {
handlersRef.current = shortcuts.reduce((acc, { keys, handler }) => {
const key = JSON.stringify(keys);
acc[key] = handler;
return acc;
}, {});
});
React.useEffect(() => {
if (!manager) {
return;
}
if (!getScopes()?.includes(scope)) {
pushScope(scope);
}
setScope(scope);
// Register shortcuts using the stable definitions.
stableShortcuts.forEach(({ keys, options }) => {
const stableHandler = (event, state) => {
const key = JSON.stringify(keys);
const currentHandler = handlersRef.current[key];
if (currentHandler) {
currentHandler(event, state);
}
};
register(keys, stableHandler, { ...options, scope });
});
if (disabled) {
manager.disableAll(scope);
}
else {
manager.enableAll(scope);
}
return () => {
// Unregister using the same stable definitions.
stableShortcuts.forEach(({ keys }) => {
if (Array.isArray(keys[0])) {
keys.forEach(key => unregister(key, scope));
}
else {
unregister(keys, scope);
}
});
popScope();
};
}, [scope, manager, disabled, stableShortcuts]);
return jsx(Fragment, { children: children });
};
const Keybindy = React.memo(KeybindyComponent);
export { Keybindy };