rx-hotkeys
Version:
Advanced Keyboard Shortcut Management library using rxjs
76 lines • 3.47 kB
JavaScript
import { useEffect, useMemo } from "react";
import { useEventCallback } from "./useEventCallback.js";
import { useHotkeysManager } from "./provider.js";
// Internal hook to handle the common logic for both combination and sequence hotkeys
function useBaseHotkey(type, keyOrSequence, callback, options) {
const manager = useHotkeysManager();
// Generate a stable, unique ID for this hook instance.
const hotkeyId = useMemo(() => `react-hotkey-${Math.random().toString(36).slice(2, 11)}`, []);
// Use the provided useEventCallback hook.
// This creates a stable function `onHotkey` that always calls the latest `callback`.
const onHotkey = useEventCallback(callback);
// Memoize options object to prevent effect re-runs. It's recommended that users memoize this object themselves for performance.
const memoizedOptions = useMemo(() => options, [JSON.stringify(options)]);
useEffect(() => {
if (!manager || !keyOrSequence) {
return;
}
const config = {
id: hotkeyId,
...memoizedOptions,
};
const hotkey$ = type === "combination"
? manager.addCombination({ ...config, keys: keyOrSequence })
: manager.addSequence({ ...config, sequence: keyOrSequence });
const _subscription = hotkey$.subscribe(onHotkey);
return () => {
// The subscription is implicitly cleaned up because remove() completes the Observable.
manager.remove(hotkeyId);
};
// Re-run the effect if the manager, keys, options, or callback changes.
}, [manager, hotkeyId, JSON.stringify(keyOrSequence), memoizedOptions, onHotkey, type]);
}
/**
* React hook to declaratively register a key combination hotkey.
* The hotkey is automatically registered when the component mounts and unregistered when it unmounts.
*
* @param keys The key combination to listen for. Can be a string like "ctrl+s" or an array.
* @param callback The function to execute when the hotkey is triggered.
* @param options An optional configuration object for `preventDefault`, `context`, `target`, etc.
*
* @example
* import { useHotkeys, Keys } from "./wraper";
*
* function MyComponent() {
* const [count, setCount] = useState(0);
*
* // The callback can directly use the latest `count` state without stale closure issues,
* // and we no longer need to pass a dependency array for it.
* useHotkeys("c", () => {
* console.log(`Current count is: ${count}. Incrementing.`);
* setCount(count + 1);
* });
*
* return <div>Count: {count} (Press "c" to increment)</div>;
* }
*/
export function useHotkeys(keys, callback, options) {
useBaseHotkey("combination", keys, callback, options);
}
/**
* React hook to declaratively register a key sequence hotkey.
* The hotkey is automatically registered when the component mounts and unregistered when it unmounts.
*
* @param sequence The key sequence to listen for. Can be a string like "g -> i" or an array.
* @param callback The function to execute when the hotkey is triggered.
* @param options An optional configuration object for `preventDefault`, `context`, `sequenceTimeoutMs`, etc.
*
* @example
* useSequence("g -> i", () => {
* console.log("Navigating to inbox...");
* }, { sequenceTimeoutMs: 1000 });
*/
export function useSequence(sequence, callback, options) {
useBaseHotkey("sequence", sequence, callback, options);
}
//# sourceMappingURL=useHotkeys.js.map