UNPKG

@intility/bifrost-react

Version:

React library for Intility's design system, Bifrost.

64 lines (63 loc) 2.33 kB
"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;