{
  "$schema": "https://ui.shadcn.com/schema/registry-item.json",
  "name": "command",
  "title": "Ninaero command",
  "dependencies": [
    "cmdk@^1.1.1",
    "cn@^0.4.0"
  ],
  "registryDependencies": [
    "https://ninaero.pages.dev/r/theme.json",
    "https://ninaero.pages.dev/r/dialog.json",
    "https://ninaero.pages.dev/r/icons.json",
    "https://ninaero.pages.dev/r/input-group.json",
    "https://ninaero.pages.dev/r/sound-provider.json"
  ],
  "files": [
    {
      "path": "registry/ninaero/ui/command.tsx",
      "content": "\"use client\";\n\nimport { Command as CommandPrimitive } from \"cmdk\";\nimport { cn } from \"cn\";\nimport * as React from \"react\";\n\nimport { CheckIcon, SearchIcon } from \"@/lib/icons\";\nimport {\n  Dialog,\n  DialogContent,\n  DialogDescription,\n  DialogHeader,\n  DialogTitle,\n} from \"@/registry/ninaero/ui/dialog\";\nimport { InputGroup, InputGroupAddon } from \"@/registry/ninaero/ui/input-group\";\n\nimport { itemSoundOptions, SoundGroup, useControlSound, HoverSound } from \"./sound-feedback\";\n\nfunction Command({\n  className,\n  id,\n  value,\n  defaultValue = \"\",\n  sound = true,\n  onValueChange,\n  onKeyDownCapture,\n  onPointerMoveCapture,\n  onInputCapture,\n  ...props\n}: React.ComponentProps<typeof CommandPrimitive> & { sound?: boolean }) {\n  const generatedId = React.useId();\n  const rootId = id ?? generatedId;\n  const [selectedValue, setSelectedValue] = React.useState(defaultValue);\n  const navigation = React.useRef(false);\n  const { play } = useControlSound(sound);\n  return (\n    <SoundGroup sound={sound}>\n      <CommandPrimitive\n        id={rootId}\n        data-slot=\"command\"\n        className={cn(\n          \"flex size-full flex-col overflow-hidden rounded-xl! bg-popover p-1 text-popover-foreground\",\n          className,\n        )}\n        {...props}\n        value={value ?? selectedValue}\n        onKeyDownCapture={(event) => {\n          onKeyDownCapture?.(event);\n          const arrow = [\"ArrowUp\", \"ArrowDown\", \"Home\", \"End\"].includes(event.key);\n          const vim =\n            props.vimBindings !== false &&\n            event.ctrlKey &&\n            [\"n\", \"p\", \"j\", \"k\"].includes(event.key.toLowerCase());\n          navigation.current = !event.defaultPrevented && (arrow || vim);\n        }}\n        onPointerMoveCapture={(event) => {\n          onPointerMoveCapture?.(event);\n          navigation.current = !event.defaultPrevented && event.pointerType !== \"touch\";\n        }}\n        onInputCapture={(event) => {\n          onInputCapture?.(event);\n          navigation.current = false;\n        }}\n        onValueChange={(nextValue) => {\n          if (value === undefined) setSelectedValue(nextValue);\n          onValueChange?.(nextValue);\n          if (navigation.current && nextValue) {\n            const items = document\n              .getElementById(rootId)\n              ?.querySelectorAll<HTMLElement>('[role=\"option\"]');\n            const item = Array.from(items ?? []).find(\n              (option) => option.dataset.value === nextValue,\n            );\n            if (item && item.getAttribute(\"aria-disabled\") !== \"true\") {\n              play(\"tick\", itemSoundOptions(item));\n            }\n          }\n          navigation.current = false;\n        }}\n      />\n    </SoundGroup>\n  );\n}\n\nfunction CommandDialog({\n  title = \"Command Palette\",\n  description = \"Search for a command to run...\",\n  children,\n  className,\n  showCloseButton = false,\n  ...props\n}: Omit<React.ComponentProps<typeof Dialog>, \"children\"> & {\n  title?: string;\n  description?: string;\n  className?: string;\n  showCloseButton?: boolean;\n  children: React.ReactNode;\n}) {\n  return (\n    <Dialog {...props}>\n      <DialogHeader className=\"sr-only\">\n        <DialogTitle>{title}</DialogTitle>\n        <DialogDescription>{description}</DialogDescription>\n      </DialogHeader>\n      <DialogContent\n        className={cn(\"top-1/3 translate-y-0 overflow-hidden rounded-xl! p-0\", className)}\n        showCloseButton={showCloseButton}\n      >\n        {children}\n      </DialogContent>\n    </Dialog>\n  );\n}\n\nfunction CommandInput({\n  className,\n  ...props\n}: React.ComponentProps<typeof CommandPrimitive.Input>) {\n  return (\n    <div data-slot=\"command-input-wrapper\" className=\"p-1 pb-0\">\n      <InputGroup>\n        <HoverSound>\n          <CommandPrimitive.Input\n            data-slot=\"input-group-control\"\n            className={cn(\n              \"h-auto min-h-0 w-full min-w-0 flex-1 self-stretch px-3 py-1 text-base leading-5 disabled:cursor-not-allowed md:text-sm\",\n              className,\n            )}\n            {...props}\n          />\n        </HoverSound>\n        <InputGroupAddon>\n          <SearchIcon className=\"size-4 shrink-0 opacity-50\" />\n        </InputGroupAddon>\n      </InputGroup>\n    </div>\n  );\n}\n\nfunction CommandList({ className, ...props }: React.ComponentProps<typeof CommandPrimitive.List>) {\n  return (\n    <CommandPrimitive.List\n      data-slot=\"command-list\"\n      className={cn(\n        \"no-scrollbar max-h-72 scroll-py-1 overflow-x-hidden overflow-y-auto outline-none\",\n        className,\n      )}\n      {...props}\n    />\n  );\n}\n\nfunction CommandEmpty({\n  className,\n  ...props\n}: React.ComponentProps<typeof CommandPrimitive.Empty>) {\n  return (\n    <CommandPrimitive.Empty\n      data-slot=\"command-empty\"\n      className={cn(\"py-6 text-center text-sm\", className)}\n      {...props}\n    />\n  );\n}\n\nfunction CommandGroup({\n  className,\n  ...props\n}: React.ComponentProps<typeof CommandPrimitive.Group>) {\n  return (\n    <CommandPrimitive.Group\n      data-slot=\"command-group\"\n      className={cn(\n        \"overflow-hidden p-1 text-foreground **:[[cmdk-group-heading]]:px-2 **:[[cmdk-group-heading]]:py-1.5 **:[[cmdk-group-heading]]:text-xs **:[[cmdk-group-heading]]:font-medium **:[[cmdk-group-heading]]:text-muted-foreground\",\n        className,\n      )}\n      {...props}\n    />\n  );\n}\n\nfunction CommandSeparator({\n  className,\n  ...props\n}: React.ComponentProps<typeof CommandPrimitive.Separator>) {\n  return (\n    <CommandPrimitive.Separator\n      data-slot=\"command-separator\"\n      className={cn(\"-mx-1 h-px bg-border\", className)}\n      {...props}\n    />\n  );\n}\n\nfunction CommandItem({\n  className,\n  children,\n  sound = true,\n  onSelect,\n  ...props\n}: React.ComponentProps<typeof CommandPrimitive.Item> & { sound?: boolean }) {\n  const { play } = useControlSound(sound);\n  return (\n    <CommandPrimitive.Item\n      data-slot=\"command-item\"\n      className={cn(\n        \"group/command-item relative flex cursor-default items-center gap-2 rounded-sm px-2 py-1.5 text-sm outline-hidden select-none in-data-[slot=dialog-content]:rounded-lg! data-[disabled=true]:pointer-events-none data-[disabled=true]:opacity-50 data-selected:bg-muted data-selected:text-foreground [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4 data-selected:*:[svg]:text-foreground\",\n        className,\n      )}\n      {...props}\n      onSelect={(value) => {\n        onSelect?.(value);\n        if (!props.disabled) play(\"tap\");\n      }}\n    >\n      {children}\n      <CheckIcon className=\"ml-auto opacity-0 group-has-data-[slot=command-shortcut]/command-item:hidden group-data-[checked=true]/command-item:opacity-100\" />\n    </CommandPrimitive.Item>\n  );\n}\n\nfunction CommandShortcut({ className, ...props }: React.ComponentProps<\"span\">) {\n  return (\n    <span\n      data-slot=\"command-shortcut\"\n      className={cn(\n        \"ml-auto text-xs tracking-widest text-muted-foreground group-data-selected/command-item:text-foreground\",\n        className,\n      )}\n      {...props}\n    />\n  );\n}\n\nexport {\n  Command,\n  CommandDialog,\n  CommandInput,\n  CommandList,\n  CommandEmpty,\n  CommandGroup,\n  CommandItem,\n  CommandShortcut,\n  CommandSeparator,\n};\n",
      "type": "registry:ui"
    }
  ],
  "type": "registry:ui"
}