"use client"; import * as React from "react"; export interface ContextualCommand { id: string; group: string; label: string; icon?: React.ComponentType<{ className?: string }>; shortcut?: string; keywords?: string[]; onSelect: () => void; } interface CommandPaletteAPI { registerCommand: (entry: ContextualCommand) => void; unregisterCommand: (id: string) => void; commands: ContextualCommand[]; } const CommandPaletteContext = React.createContext(null); export { CommandPaletteContext }; export function useCommandPalette() { const ctx = React.useContext(CommandPaletteContext); if (!ctx) { throw new Error("useCommandPalette must be used within CommandPaletteProvider"); } return ctx; } export function CommandPaletteProvider({ children }: { children: React.ReactNode }) { const commandsRef = React.useRef>(new Map()); const [, forceUpdate] = React.useReducer((x: number) => x + 1, 0); const registerCommand = React.useCallback((entry: ContextualCommand) => { commandsRef.current.set(entry.id, entry); forceUpdate(); }, []); const unregisterCommand = React.useCallback((id: string) => { commandsRef.current.delete(id); forceUpdate(); }, []); const commands = React.useMemo( () => Array.from(commandsRef.current.values()), // forceUpdate triggers re-render; recompute on each render via ref identity // eslint-disable-next-line react-hooks/exhaustive-deps [commandsRef, forceUpdate], ); const value = React.useMemo( () => ({ registerCommand, unregisterCommand, commands }), [registerCommand, unregisterCommand, commands], ); return ( {children} ); } /** Register a set of commands for the current page. Unregisters on unmount. */ export function usePageCommands(commands: ContextualCommand[]) { const { registerCommand, unregisterCommand } = useCommandPalette(); // Keep the latest commands in a ref so the effect doesn't re-run on every // render when the parent recreates the array. The effect syncs the registry // to the ref contents on each change. const commandsRef = React.useRef(commands); commandsRef.current = commands; React.useEffect(() => { const current = commandsRef.current; for (const cmd of current) { registerCommand(cmd); } return () => { for (const cmd of current) { unregisterCommand(cmd.id); } }; }, [registerCommand, unregisterCommand]); }