@intility/bifrost-react
Version:
React library for Intility's design system, Bifrost.
64 lines (63 loc) • 2.33 kB
JavaScript
"use client";
import { useEffect, useRef, useState } from "react";
/**
* React hook for handling keyboard shortcuts (hotkeys) with Ctrl/⌘ + `key`.
*
* This hook listens for a specific key press combined with the platform's
* primary modifier key (Ctrl on Windows/Linux, ⌘ on macOS) and triggers the
* provided callback when the hotkey is pressed. It prevents the default browser
* behavior for the hotkey and ensures that no other modifier keys (like Shift,
* Alt) are pressed.
*
* @param key The key to listen for (e.g., `"k"` for Ctrl+K or ⌘+K).
* @param callback The function to call when the hotkey is triggered.
* Receives the KeyboardEvent as its argument.
* @returns An object containing:
* - `hotkeyText`: A string representation of the hotkey (e.g., `"Ctrl + K"`
* or `"⌘ + K"`).
*
* @example
* // focus search input on Ctrl/⌘ + K
* const { hotkeyText } = useHotkey("k", (e) => {
* inputRef.current?.focus();
* });
*
* @example
* // save data on Ctrl/⌘ + S
* const { hotkeyText } = useHotkey("s", (e) => {
* saveData();
* });
*/ function useHotkey(key, callback) {
// default to false to avoid hydration mismatch
const [isMac, setIsMac] = useState(false);
useEffect(()=>{
// detect platform client-side only
setIsMac(globalThis.navigator?.userAgent?.includes("Mac"));
}, []);
// avoid re-attaching a new onKeyDown handler on each render by storing
// the callback function reference
const callbackRef = useRef(callback);
callbackRef.current = callback;
useEffect(()=>{
const onKeyDown = (e)=>{
if (e.key !== key.toLowerCase()) return;
const ctrlOrCmdIsPressed = isMac ? e.metaKey : e.ctrlKey;
const otherModifierIsPressed = e.shiftKey || e.altKey || (isMac ? e.ctrlKey : e.metaKey);
if (!ctrlOrCmdIsPressed || otherModifierIsPressed) return;
e.preventDefault();
callbackRef.current(e);
return false;
};
document.addEventListener("keydown", onKeyDown);
return ()=>{
document.removeEventListener("keydown", onKeyDown);
};
}, [
key,
isMac
]);
return {
hotkeyText: `${isMac ? "⌘" : "Ctrl"} + ${key.toUpperCase()}`
};
}
export default useHotkey;