{
  "$schema": "https://ui.shadcn.com/schema/registry-item.json",
  "name": "command-palette",
  "type": "registry:ui",
  "title": "Command palette",
  "description": "Cmd K style command palette in a dialog with a search field that filters commands as you type, runs the chosen action and closes. Shows an empty state.",
  "dependencies": [
    "lucide-react"
  ],
  "registryDependencies": [
    "https://ui.minidev.pro/r/button.json",
    "https://ui.minidev.pro/r/dialog.json",
    "https://ui.minidev.pro/r/kbd.json"
  ],
  "files": [
    {
      "path": "registry/ui/command-palette.tsx",
      "type": "registry:ui",
      "target": "components/ui/command-palette.tsx",
      "content": "\"use client\"\nimport * as React from \"react\"\nimport { SearchIcon } from \"lucide-react\"\nimport { Button } from \"@/components/ui/button\"\nimport { Kbd } from \"@/components/ui/kbd\"\nimport { Dialog, DialogContent, DialogTitle } from \"@/components/ui/dialog\"\n\n/** A searchable command dialog: type to filter, pick a command, opened from a trigger button or ⌘K. */\ntype Command = { id: string; label: string; onSelect?: () => void }\n\nconst SAMPLE_COMMANDS: Command[] = [\n  { id: \"dashboard\", label: \"Go to dashboard\" },\n  { id: \"new-invoice\", label: \"Create invoice\" },\n  { id: \"new-customer\", label: \"Add customer\" },\n  { id: \"deploys\", label: \"View deploys\" },\n  { id: \"invite\", label: \"Invite teammate\" },\n  { id: \"billing\", label: \"Open billing settings\" },\n  { id: \"workspace\", label: \"Switch workspace: Northwind\" },\n  { id: \"theme\", label: \"Toggle dark mode\" },\n]\n\ntype CommandPaletteProps = {\n  /** Controlled open state. Omit it and the palette manages itself: it renders a trigger and listens for ⌘K / Ctrl+K. */\n  open?: boolean\n  onOpenChange?: (open: boolean) => void\n  /** Commands to search. Defaults to a set of Lumen actions. */\n  commands?: Command[]\n  /** Rendered when the palette is uncontrolled. Defaults to a search button with a ⌘K hint. */\n  trigger?: React.ReactNode\n}\n\nfunction CommandPalette({ open, onOpenChange, commands = SAMPLE_COMMANDS, trigger }: CommandPaletteProps) {\n  const controlled = open !== undefined\n  const [innerOpen, setInnerOpen] = React.useState(false)\n  const isOpen = controlled ? open : innerOpen\n  const setOpen = (o: boolean) => {\n    if (!controlled) setInnerOpen(o)\n    onOpenChange?.(o)\n  }\n  const [q, setQ] = React.useState(\"\")\n  const filtered = commands.filter(c => c.label.toLowerCase().includes(q.toLowerCase()))\n\n  React.useEffect(() => {\n    if (controlled) return\n    const onKey = (e: KeyboardEvent) => {\n      // Another handler (an app-level search, say) that already claimed ⌘K wins.\n      if (e.defaultPrevented) return\n      if ((e.metaKey || e.ctrlKey) && e.key.toLowerCase() === \"k\") {\n        e.preventDefault()\n        setInnerOpen((o) => !o)\n      }\n    }\n    window.addEventListener(\"keydown\", onKey)\n    return () => window.removeEventListener(\"keydown\", onKey)\n  }, [controlled])\n\n  return (\n    <div data-slot=\"command-palette\">\n      {!controlled\n        ? trigger ?? (\n            <Button type=\"button\" variant=\"outline\" className=\"w-64 justify-start gap-2 pr-2 font-normal text-fg-muted\" onClick={() => setOpen(true)}>\n              <SearchIcon />\n              <span className=\"flex-1 text-left\">Search commands…</span>\n              <Kbd>⌘K</Kbd>\n            </Button>\n          )\n        : null}\n      <Dialog open={isOpen} onOpenChange={setOpen}>\n      <DialogContent className=\"top-[20%] max-w-lg translate-y-0 gap-0 overflow-hidden p-0\" showCloseButton={false}>\n        <DialogTitle className=\"sr-only\">Command palette</DialogTitle>\n        <div className=\"flex items-center gap-2 border-b border-border px-3\">\n          <SearchIcon className=\"size-4 text-fg-muted\" />\n          <input aria-label=\"Command search\" value={q} onChange={(e)=>setQ(e.target.value)} placeholder=\"Type a command…\" className=\"h-11 w-full bg-transparent text-sm outline-none\" />\n        </div>\n        <ul className=\"max-h-64 overflow-auto p-1\">\n          {filtered.map(c => (\n            <li key={c.id}>\n              <button type=\"button\" className=\"flex w-full rounded-lg px-2.5 py-2 text-left text-sm hover:bg-sunken\" onClick={() => { c.onSelect?.(); setOpen(false) }}>{c.label}</button>\n            </li>\n          ))}\n          {filtered.length===0 ? <li className=\"px-2.5 py-3 text-xs text-fg-muted\">No commands</li> : null}\n        </ul>\n      </DialogContent>\n    </Dialog>\n    </div>\n  )\n}\nexport { CommandPalette }\nexport type { CommandPaletteProps, Command as CommandPaletteCommand }\n"
    }
  ]
}
