{
  "$schema": "https://ui.shadcn.com/schema/registry-item.json",
  "name": "command-bar",
  "title": "Command Bar",
  "description": "A modal command surface with search, grouped actions, keyboard navigation, and shortcuts.",
  "dependencies": [
    "@base-ui/react",
    "lucide-react"
  ],
  "files": [
    {
      "path": "registry/rivetui/components/command-bar/command-bar.tsx",
      "content": "\"use client\";\n\nimport { Dialog as DialogPrimitive } from \"@base-ui/react/dialog\";\nimport { Search, X } from \"lucide-react\";\nimport * as React from \"react\";\n\nimport { cn } from \"@/lib/utils\";\n\ntype CommandBarAction = {\n  id: string;\n  label: string;\n  description?: string;\n  group?: string;\n  keywords?: readonly string[];\n  shortcut?: React.ReactNode;\n  icon?: React.ReactNode;\n  disabled?: boolean;\n  onSelect?: () => void;\n};\n\ntype CommandBarProps = Omit<\n  DialogPrimitive.Root.Props<unknown>,\n  \"children\" | \"defaultOpen\" | \"onOpenChange\" | \"open\"\n> & {\n  actions: readonly CommandBarAction[];\n  children?: React.ReactNode;\n  open?: boolean;\n  defaultOpen?: boolean;\n  onOpenChange?: (open: boolean) => void;\n  onActionSelect?: (action: CommandBarAction) => void;\n  label?: string;\n  placeholder?: string;\n  emptyMessage?: React.ReactNode;\n  hotkey?: boolean;\n  closeOnSelect?: boolean;\n};\n\nfunction CommandBar({\n  actions,\n  children,\n  open: controlledOpen,\n  defaultOpen = false,\n  onOpenChange,\n  onActionSelect,\n  label = \"Command bar\",\n  placeholder = \"Search commands\",\n  emptyMessage = \"No commands found.\",\n  hotkey = true,\n  closeOnSelect = true,\n  ...props\n}: CommandBarProps) {\n  const [uncontrolledOpen, setUncontrolledOpen] = React.useState(defaultOpen);\n  const [query, setQuery] = React.useState(\"\");\n  const [activeId, setActiveId] = React.useState<string | null>(null);\n  const inputRef = React.useRef<HTMLInputElement>(null);\n  const listId = React.useId();\n  const open = controlledOpen ?? uncontrolledOpen;\n\n  const setOpen = React.useCallback(\n    (nextOpen: boolean) => {\n      if (controlledOpen === undefined) {\n        setUncontrolledOpen(nextOpen);\n      }\n      if (!nextOpen) {\n        setQuery(\"\");\n        setActiveId(null);\n      }\n      onOpenChange?.(nextOpen);\n    },\n    [controlledOpen, onOpenChange],\n  );\n\n  React.useEffect(() => {\n    if (!hotkey) {\n      return;\n    }\n\n    function handleKeyDown(event: KeyboardEvent) {\n      if ((event.metaKey || event.ctrlKey) && event.key.toLowerCase() === \"k\") {\n        event.preventDefault();\n        setOpen(!open);\n      }\n    }\n\n    window.addEventListener(\"keydown\", handleKeyDown);\n    return () => window.removeEventListener(\"keydown\", handleKeyDown);\n  }, [hotkey, open, setOpen]);\n\n  const normalizedQuery = query.trim().toLocaleLowerCase();\n  const filteredActions = React.useMemo(() => {\n    if (!normalizedQuery) {\n      return actions;\n    }\n\n    return actions.filter((action) =>\n      [action.label, action.description, action.group, ...(action.keywords ?? [])]\n        .filter(Boolean)\n        .some((value) => value?.toLocaleLowerCase().includes(normalizedQuery)),\n    );\n  }, [actions, normalizedQuery]);\n\n  const enabledActions = filteredActions.filter((action) => !action.disabled);\n  const activeAction =\n    enabledActions.find((action) => action.id === activeId) ?? enabledActions.at(0) ?? null;\n\n  const groupedActions = React.useMemo(() => {\n    const groups = new Map<string, CommandBarAction[]>();\n    for (const action of filteredActions) {\n      const group = action.group ?? \"Actions\";\n      const groupActions = groups.get(group) ?? [];\n      groupActions.push(action);\n      groups.set(group, groupActions);\n    }\n    return [...groups.entries()];\n  }, [filteredActions]);\n\n  function moveActive(direction: 1 | -1) {\n    if (enabledActions.length === 0) {\n      return;\n    }\n    const currentIndex = activeAction\n      ? enabledActions.findIndex((action) => action.id === activeAction.id)\n      : -1;\n    const nextIndex = (currentIndex + direction + enabledActions.length) % enabledActions.length;\n    setActiveId(enabledActions[nextIndex]?.id ?? null);\n  }\n\n  function selectAction(action: CommandBarAction) {\n    if (action.disabled) {\n      return;\n    }\n    action.onSelect?.();\n    onActionSelect?.(action);\n    if (closeOnSelect) {\n      setOpen(false);\n    }\n  }\n\n  function handleInputKeyDown(event: React.KeyboardEvent<HTMLInputElement>) {\n    if (event.key === \"ArrowDown\") {\n      event.preventDefault();\n      moveActive(1);\n    } else if (event.key === \"ArrowUp\") {\n      event.preventDefault();\n      moveActive(-1);\n    } else if (event.key === \"Enter\" && activeAction) {\n      event.preventDefault();\n      selectAction(activeAction);\n    }\n  }\n\n  return (\n    <DialogPrimitive.Root open={open} onOpenChange={(nextOpen) => setOpen(nextOpen)} {...props}>\n      {children}\n      <DialogPrimitive.Portal>\n        <DialogPrimitive.Backdrop className=\"fixed inset-0 z-50 min-h-dvh bg-black/55 transition-opacity duration-100 data-ending-style:opacity-0 data-starting-style:opacity-0 motion-reduce:transition-none dark:bg-black/70\" />\n        <DialogPrimitive.Viewport className=\"fixed inset-0 z-50 flex min-h-dvh items-start justify-center overflow-y-auto px-4 pt-[15vh] pb-8\">\n          <DialogPrimitive.Popup\n            data-slot=\"command-bar\"\n            initialFocus={inputRef}\n            className=\"w-full max-w-xl overflow-hidden border border-border bg-popover text-popover-foreground outline-none transition-[opacity,transform] duration-100 data-ending-style:translate-y-1 data-ending-style:opacity-0 data-starting-style:-translate-y-1 data-starting-style:opacity-0 motion-reduce:transition-none\"\n          >\n            <DialogPrimitive.Title className=\"sr-only\">{label}</DialogPrimitive.Title>\n            <DialogPrimitive.Description className=\"sr-only\">\n              Search and select an available command.\n            </DialogPrimitive.Description>\n\n            <div className=\"relative border-b border-border\">\n              <Search\n                className=\"pointer-events-none absolute top-1/2 left-4 size-4 -translate-y-1/2 text-muted-foreground\"\n                aria-hidden=\"true\"\n              />\n              <input\n                ref={inputRef}\n                type=\"search\"\n                autoComplete=\"off\"\n                autoCapitalize=\"none\"\n                spellCheck={false}\n                data-1p-ignore\n                data-bwignore=\"true\"\n                data-lpignore=\"true\"\n                data-form-type=\"other\"\n                role=\"combobox\"\n                aria-autocomplete=\"list\"\n                aria-controls={listId}\n                aria-expanded=\"true\"\n                aria-activedescendant={activeAction ? `${listId}-${activeAction.id}` : undefined}\n                value={query}\n                onChange={(event) => {\n                  setQuery(event.target.value);\n                  setActiveId(null);\n                }}\n                onKeyDown={handleInputKeyDown}\n                placeholder={placeholder}\n                className=\"h-14 w-full bg-transparent pr-14 pl-11 text-sm outline-none placeholder:text-muted-foreground\"\n              />\n              <DialogPrimitive.Close\n                aria-label=\"Close command bar\"\n                className=\"absolute top-1/2 right-3 grid size-8 -translate-y-1/2 place-items-center text-muted-foreground outline-none transition-colors hover:text-foreground focus-visible:ring-2 focus-visible:ring-ring/40\"\n              >\n                <X className=\"size-4\" aria-hidden=\"true\" />\n              </DialogPrimitive.Close>\n            </div>\n\n            <div\n              id={listId}\n              role=\"listbox\"\n              aria-label=\"Commands\"\n              className=\"max-h-80 overflow-y-auto p-2\"\n            >\n              {groupedActions.map(([group, groupActions], groupIndex) => (\n                <div key={group} className=\"py-1\">\n                  <div\n                    id={`${listId}-group-${groupIndex}`}\n                    className=\"px-3 py-2 font-mono text-[0.625rem] uppercase tracking-[0.14em] text-muted-foreground\"\n                  >\n                    {group}\n                  </div>\n                  {groupActions.map((action) => {\n                    const isActive = action.id === activeAction?.id;\n                    return (\n                      <button\n                        key={action.id}\n                        id={`${listId}-${action.id}`}\n                        type=\"button\"\n                        role=\"option\"\n                        aria-selected={isActive}\n                        disabled={action.disabled}\n                        data-active={isActive ? \"\" : undefined}\n                        onPointerMove={() => {\n                          if (!action.disabled) {\n                            setActiveId(action.id);\n                          }\n                        }}\n                        onClick={() => selectAction(action)}\n                        className={cn(\n                          \"flex min-h-12 w-full items-center gap-3 px-3 py-2 text-left text-sm outline-none transition-colors data-active:bg-accent data-active:text-accent-foreground disabled:pointer-events-none disabled:opacity-40\",\n                        )}\n                      >\n                        {action.icon ? (\n                          <span className=\"grid size-5 shrink-0 place-items-center text-muted-foreground [&>svg]:size-4\">\n                            {action.icon}\n                          </span>\n                        ) : null}\n                        <span className=\"min-w-0 flex-1\">\n                          <span className=\"block truncate font-medium\">{action.label}</span>\n                          {action.description ? (\n                            <span className=\"mt-0.5 block truncate text-xs text-muted-foreground\">\n                              {action.description}\n                            </span>\n                          ) : null}\n                        </span>\n                        {typeof action.shortcut === \"string\" ? (\n                          <kbd className=\"shrink-0 border border-border px-1.5 py-0.5 font-mono text-[0.625rem] text-muted-foreground\">\n                            {action.shortcut}\n                          </kbd>\n                        ) : action.shortcut ? (\n                          <span className=\"shrink-0\">{action.shortcut}</span>\n                        ) : null}\n                      </button>\n                    );\n                  })}\n                </div>\n              ))}\n\n              {filteredActions.length === 0 ? (\n                <div className=\"px-3 py-10 text-center text-sm text-muted-foreground\">\n                  {emptyMessage}\n                </div>\n              ) : null}\n            </div>\n\n            <div className=\"flex flex-wrap items-center gap-x-4 gap-y-2 border-t border-border px-4 py-2.5 font-mono text-[0.625rem] uppercase tracking-[0.1em] text-muted-foreground\">\n              <span>↑↓ Navigate</span>\n              <span>↵ Select</span>\n              <span>Esc Close</span>\n            </div>\n          </DialogPrimitive.Popup>\n        </DialogPrimitive.Viewport>\n      </DialogPrimitive.Portal>\n    </DialogPrimitive.Root>\n  );\n}\n\nfunction CommandBarTrigger<Payload>(props: DialogPrimitive.Trigger.Props<Payload>) {\n  return <DialogPrimitive.Trigger data-slot=\"command-bar-trigger\" {...props} />;\n}\n\nexport type { CommandBarAction, CommandBarProps };\nexport { CommandBar, CommandBarTrigger };\n",
      "type": "registry:ui"
    }
  ],
  "type": "registry:ui"
}