import { useCallback, useEffect, useState } from 'react'; export interface UseCommandPaletteOptions { /** Default hotkey: Cmd-K / Ctrl-K. Pass `null` to disable. */ hotkey?: { key: string; meta?: boolean; ctrl?: boolean; shift?: boolean } | null; /** Initial open state. */ defaultOpen?: boolean; } export interface UseCommandPaletteHelpers { open: boolean; show: () => void; hide: () => void; toggle: () => void; } /** * Manages open/closed state for `` and (optionally) * binds a global hotkey. Drop it next to your app shell: * * ```tsx * const cmdk = useCommandPalette(); * return ( * <> * * * * ); * ``` * * The default hotkey (`Cmd-K` / `Ctrl-K`) is suppressed inside text * inputs unless the user explicitly holds the modifier. */ export function useCommandPalette( options: UseCommandPaletteOptions = {}, ): UseCommandPaletteHelpers { const { hotkey = { key: 'k', meta: true, ctrl: true }, defaultOpen = false } = options; const [open, setOpen] = useState(defaultOpen); const show = useCallback(() => setOpen(true), []); const hide = useCallback(() => setOpen(false), []); const toggle = useCallback(() => setOpen(o => !o), []); useEffect(() => { if (!hotkey) return; const handler = (e: KeyboardEvent) => { if (e.key.toLowerCase() !== hotkey.key.toLowerCase()) return; const wantMeta = hotkey.meta ?? false; const wantCtrl = hotkey.ctrl ?? false; const wantShift = hotkey.shift ?? false; // Match if EITHER meta or ctrl is held when both are flagged (Mac/Win parity). const modOk = wantMeta || wantCtrl ? (wantMeta && e.metaKey) || (wantCtrl && e.ctrlKey) : !e.metaKey && !e.ctrlKey; const shiftOk = wantShift ? e.shiftKey : true; if (modOk && shiftOk) { e.preventDefault(); setOpen(o => !o); } }; window.addEventListener('keydown', handler); return () => window.removeEventListener('keydown', handler); }, [hotkey]); return { open, show, hide, toggle }; }