{
  "$schema": "https://ui.shadcn.com/schema/registry-item.json",
  "name": "command-palette",
  "title": "Command Palette",
  "type": "registry:block",
  "files": [
    {
      "path": "packages/registry-react/blocks/command-palette/CommandPalette.tsx",
      "content": "'use client'\n\nimport * as React from 'react'\nimport {\n  LayoutDashboard,\n  FileText,\n  Inbox,\n  Settings,\n  Users,\n  KanbanSquare,\n  Search,\n  type LucideIcon,\n} from 'lucide-react'\nimport {\n  CommandDialog,\n  CommandEmpty,\n  CommandGroup,\n  CommandInput,\n  CommandItem,\n  CommandList,\n  CommandSeparator,\n  CommandShortcut,\n} from '@/components/ui/command'\n\nexport interface CommandPaletteItem {\n  label: string\n  value?: string\n  hint?: string\n  icon?: LucideIcon\n  onSelect?: () => void\n}\n\nexport interface CommandPaletteGroup {\n  heading: string\n  items: CommandPaletteItem[]\n}\n\nexport interface CommandPaletteProps {\n  groups?: CommandPaletteGroup[]\n  placeholder?: string\n  triggerLabel?: string\n  showTrigger?: boolean\n  onSelect?: (item: CommandPaletteItem) => void\n}\n\nconst defaultGroups: CommandPaletteGroup[] = [\n  {\n    heading: 'Navigate',\n    items: [\n      { label: 'Dashboard', hint: '/dashboard', icon: LayoutDashboard },\n      { label: 'Inbox', hint: '/inbox', icon: Inbox },\n      { label: 'Kanban', hint: '/kanban', icon: KanbanSquare },\n      { label: 'Team', hint: '/team', icon: Users },\n    ],\n  },\n  {\n    heading: 'Settings',\n    items: [\n      { label: 'Profile', hint: '/profile', icon: FileText },\n      { label: 'Settings', hint: '/settings', icon: Settings },\n    ],\n  },\n]\n\nexport function CommandPalette({\n  groups = defaultGroups,\n  placeholder = 'Search pages, commands…',\n  triggerLabel = 'Search pages, commands…',\n  showTrigger = true,\n  onSelect,\n}: CommandPaletteProps) {\n  const [open, setOpen] = React.useState(false)\n  const [triggerShortcut, setTriggerShortcut] = React.useState('⌘K')\n\n  function pick(item: CommandPaletteItem) {\n    setOpen(false)\n    item.onSelect?.()\n    onSelect?.(item)\n  }\n\n  React.useEffect(() => {\n    function onKeydown(e: KeyboardEvent) {\n      if (e.key === 'k' && (e.metaKey || e.ctrlKey)) {\n        e.preventDefault()\n        setOpen((prev) => !prev)\n      }\n    }\n    window.addEventListener('keydown', onKeydown)\n    return () => window.removeEventListener('keydown', onKeydown)\n  }, [])\n\n  React.useEffect(() => {\n    if (typeof navigator === 'undefined') return\n    setTriggerShortcut(/Mac|iPhone|iPad/i.test(navigator.platform) ? '⌘K' : 'Ctrl K')\n  }, [])\n\n  return (\n    <>\n      {showTrigger && (\n        <button\n          type=\"button\"\n          className=\"bg-secondary/50 hover:bg-secondary text-muted-foreground focus-visible:ring-ring relative hidden h-8 w-full items-center gap-2 rounded-lg border border-transparent px-2.5 text-sm shadow-none transition-colors focus-visible:ring-1 focus-visible:outline-none sm:flex md:w-[220px] lg:w-[300px]\"\n          aria-label=\"Open command palette\"\n          onClick={() => setOpen(true)}\n        >\n          <Search className=\"size-3.5 shrink-0\" />\n          <span className=\"flex-1 truncate text-left\">{triggerLabel}</span>\n          <kbd className=\"bg-muted/80 text-muted-foreground pointer-events-none flex h-5 items-center justify-center rounded-md border px-1.5 font-mono text-[10px] font-medium\">\n            <span>{triggerShortcut}</span>\n          </kbd>\n        </button>\n      )}\n\n      <CommandDialog\n        open={open}\n        onOpenChange={setOpen}\n        title=\"Command palette\"\n        description=\"Search pages and run commands\"\n      >\n        <CommandInput placeholder={placeholder} />\n        <CommandList className=\"max-h-[480px]\">\n          <CommandEmpty>No matches.</CommandEmpty>\n          {groups.map((group, gi) => (\n            <React.Fragment key={group.heading}>\n              <CommandGroup heading={group.heading}>\n                {group.items.map((item) => {\n                  const Icon = item.icon\n                  return (\n                    <CommandItem\n                      key={`${group.heading}-${item.label}`}\n                      value={`${group.heading} ${item.label} ${item.hint ?? ''}`}\n                      onSelect={() => pick(item)}\n                    >\n                      {Icon && <Icon className=\"size-4\" />}\n                      <span>{item.label}</span>\n                      {item.hint && (\n                        <CommandShortcut className=\"text-muted-foreground/70\">{item.hint}</CommandShortcut>\n                      )}\n                    </CommandItem>\n                  )\n                })}\n              </CommandGroup>\n              {gi < groups.length - 1 && <CommandSeparator />}\n            </React.Fragment>\n          ))}\n        </CommandList>\n      </CommandDialog>\n    </>\n  )\n}\n",
      "type": "registry:block",
      "target": "~/components/blocks/CommandPalette.tsx"
    }
  ],
  "dependencies": [
    "lucide-react"
  ],
  "devDependencies": [],
  "registryDependencies": [
    "https://uipkge.dev/r/react/command.json",
    "https://uipkge.dev/r/react/kbd.json"
  ],
  "description": "Header-grade search/command palette. Bundles the slim trigger button (with platform-aware ⌘K/Ctrl-K kbd hint) AND the modal CommandDialog into one block; consumers drop it once and the global keyboard shortcut wires itself. Takes a `groups` array of `{ heading, items: [{ label, hint, icon, onSelect }] }` and calls `onSelect`. `showTrigger={false}` hides the inline button so the consumer can control open state from elsewhere.",
  "categories": [
    "dashboard",
    "overlay",
    "navigation"
  ]
}