{
  "$schema": "https://ui.shadcn.com/schema/registry-item.json",
  "name": "command",
  "type": "registry:ui",
  "title": "Command",
  "description": "Fluent 2-styled command palette (cmdk surface) with shadcn-style composable APIs, built on @base-ui/react's Autocomplete with NO cmdk dependency. An always-visible, filtered list whose items fire actions (onClick, firing on click and Enter-when-highlighted) rather than persist a selection — Autocomplete's inline-open + selectionMode:'none' model. Includes a Command palette panel, a search input with a leading SearchRegular icon, filtered List/Empty, grouped items with headings, separators, shortcut hints, and a CommandDialog that wraps the kit Dialog.",
  "author": "graundtech <https://github.com/graundtech/fluent2-react-kit>",
  "dependencies": [
    "@base-ui/react",
    "@fluentui/react-icons"
  ],
  "registryDependencies": [
    "https://fluent2-react-kit.graund.io/r/utils.json",
    "https://fluent2-react-kit.graund.io/r/dialog.json"
  ],
  "files": [
    {
      "path": "components/ui/command.tsx",
      "type": "registry:ui",
      "target": "components/ui/command.tsx",
      "content": "\"use client\";\n\nimport { Autocomplete as AutocompletePrimitive } from \"@base-ui/react/autocomplete\";\nimport { SearchRegular } from \"@fluentui/react-icons\";\nimport type { ComponentProps, ReactElement, ReactNode } from \"react\";\n\nimport { cn } from \"@/lib/utils\";\nimport {\n  Dialog,\n  DialogContent,\n  DialogDescription,\n  DialogHeader,\n  DialogTitle,\n  DialogTrigger,\n} from \"./dialog\";\n\n/**\n * Command — Fluent 2-styled, shadcn-API command palette (cmdk surface) built on\n * Base UI, with NO `cmdk` dependency.\n *\n * A command palette is an ALWAYS-VISIBLE filtered list whose items fire actions\n * (open a file, run a command) rather than persist a selection. That single\n * requirement drives the architecture decision below.\n *\n * ## Why `@base-ui/react/autocomplete` and NOT `@base-ui/react/combobox`\n * `combobox.tsx` (the filter-list family reference) documents the boundary: Base\n * UI's Combobox and Autocomplete share one `AriaCombobox` engine but differ on\n * *selection*. Command items **perform actions — they don't hold a value** — which\n * points squarely at Autocomplete, and two Autocomplete-only capabilities make it\n * the honest, least-fought fit (verified against `@base-ui/react@1.6.0` in\n * node_modules before committing):\n *\n * 1. **`selectionMode: 'none'`.** `Autocomplete.Root` is hard-wired to `'none'`\n *    (it Omits `selectedValue`/`onValueChange`/`isItemEqualToValue`/… from its\n *    props). There is no committed selection and no check indicator — exactly a\n *    command list. A Combobox would force a value model we'd have to fight.\n * 2. **`inline` + `open` = a statically-open list with no popup.**\n *    `Autocomplete.Root` exposes `inline`: *\"Whether the list is rendered inline\n *    without using the component's own popup. Specify `open` unconditionally in\n *    conjunction with this prop so the list is considered visible.\"* This is the\n *    always-visible palette panel — `Autocomplete.List` renders directly, with no\n *    `Portal`/`Positioner`/`Popup` and no floating-ui positioning to stub. Combobox\n *    has the same `inline` flag (shared engine), but its selection model is dead\n *    weight here, so Autocomplete is the cleaner primitive.\n *\n * Filtering rides the engine's built-in text filter (`mode=\"list\"`, the default):\n * pass `items` to `<Command>` and render the list with a render-function child,\n * exactly like `Combobox` (the built-in filter runs against the `items` prop). A\n * manual filtered-list fallback was NOT needed — the primitive supports the\n * inline-open + per-item `onClick` model natively.\n *\n * Keyboard is fully wired by the engine over the inline list: ArrowUp/Down roving\n * highlight (`data-highlighted`), Home/End to the ends, and Enter fires the\n * highlighted item — because `Autocomplete.Item.onClick` *\"fires when clicking the\n * item with the pointer, as well as when pressing Enter with the keyboard if the\n * item is highlighted when the Input or List element has focus.\"* That is this\n * kit's `CommandItem` action handler.\n *\n * ## Base UI mapping (conventions §9)\n * Namespace import of `@base-ui/react/autocomplete` (matching the export shape in\n * node_modules, like `select.tsx`/`combobox.tsx`). shadcn/cmdk part names mapped\n * onto Base UI's model:\n *\n * | Exported (cmdk name) | Base UI primitive                                       |\n * | -------------------- | ------------------------------------------------------- |\n * | `Command`            | `Autocomplete.Root` (`inline open`) + panel `<div>`     |\n * | `CommandInput`       | search-row `<div>` + `SearchRegular` + `Autocomplete.Input` |\n * | `CommandList`        | `Autocomplete.List` (the scroll container)              |\n * | `CommandEmpty`       | `Autocomplete.Empty`                                    |\n * | `CommandGroup`       | `Autocomplete.Group` (+ `Autocomplete.GroupLabel` heading) |\n * | `CommandItem`        | `Autocomplete.Item`                                     |\n * | `CommandSeparator`   | `Autocomplete.Separator`                                |\n * | `CommandShortcut`    | plain `<span>` (cmdk parity — no Base UI part)          |\n * | `CommandDialog`      | kit `Dialog` + `DialogContent` wrapping a `Command`     |\n *\n * ## Divergences vs cmdk / shadcn's Command (all deliberate)\n * 1. **Items fire `onClick`, not `onSelect`.** cmdk's `CommandItem` has an\n *    `onSelect(value)` callback; Base UI's `Autocomplete.Item` exposes a native\n *    `onClick` that fires on pointer-click AND Enter-when-highlighted (same effect,\n *    honest primitive prop). No synthetic `onSelect`/`value`-string is faked.\n * 2. **Filtering keys off the `items` prop, not item DOM text.** cmdk filters by\n *    scoring each item's rendered text; Base UI filters the `items` array with its\n *    built-in filter. So a *filtering* palette passes `items` + the render-function\n *    `CommandList` child (like `Combobox`). Static `CommandItem` children still\n *    render, but only the `items` prop is filtered.\n * 3. **`CommandGroup` takes a `heading` prop** (rendered via\n *    `Autocomplete.GroupLabel`), matching shadcn's `<CommandGroup heading=\"…\">`\n *    ergonomics. Base UI's control-level label is not exposed (there is none for a\n *    palette).\n * 4. **`Command` renders the panel element; `Autocomplete.Root` renders none.**\n *    Root is a headless provider, so `Command` wraps a `data-slot=\"command\"` panel\n *    `<div>` inside it. Standalone it carries `border`; `CommandDialog` drops the\n *    border (the Dialog surface owns the elevation).\n * 5. **`CommandEmpty` is a SIBLING of `CommandList`, not a child.** cmdk nests\n *    `CommandEmpty` inside `CommandList`; Base UI's `Autocomplete.List` takes\n *    EITHER a render-function child OR nodes (never a mix), and `Autocomplete.Empty`\n *    is a peer of the list (same as `combobox.tsx`). So place `<CommandEmpty>` next\n *    to `<CommandList>` inside `<Command>`, and give `CommandList` only the\n *    render-function child.\n * 6. **`CommandDialog` accepts a `trigger` element** (forwarded to the kit\n *    `DialogTrigger`'s `render` prop) so an uncontrolled palette works without a\n *    client handler — cmdk's `CommandDialog` is controlled-only. Pass `open`/\n *    `onOpenChange` for the controlled path instead. The `DialogTitle`/\n *    `DialogDescription` are present but `sr-only` (Dialog requires an accessible\n *    name; the palette shows no visible heading).\n *\n * ## `\"use client\"` — required\n * Two reasons, same as `combobox.tsx`: every Base UI Autocomplete part module\n * carries its own `'use client'` (they manage client state), and — decisively —\n * `SearchRegular` from `@fluentui/react-icons` must stay inside a client boundary\n * (its shared icon-sizing module calls `@griffel/react`'s client-only `__styles()`\n * at module scope without a directive, breaking `next build` from an RSC). See\n * conventions §9; `select.tsx`/`checkbox.tsx` are the precedents.\n *\n * ## data-slot note\n * `Autocomplete.Root` renders no DOM element and its props type is strict (no\n * `data-*` passthrough), so it carries no `data-slot`; the `Command` panel `<div>`\n * this file adds does. Every part that renders an element does.\n */\n\n/**\n * Root props, narrowed to a FLAT `items` array (grouping is done with static\n * `CommandGroup` children, not the grouped-items form). Narrowing also sidesteps\n * `Autocomplete.Root`'s two-overload signature, which a spread of the union\n * `items` type can't resolve against.\n */\ntype CommandProps<ItemValue> = Omit<\n  AutocompletePrimitive.Root.Props<ItemValue>,\n  \"items\"\n> & {\n  items?: readonly ItemValue[];\n  className?: string;\n};\n\nfunction Command<ItemValue>({\n  className,\n  children,\n  inline = true,\n  open = true,\n  ...props\n}: CommandProps<ItemValue>) {\n  return (\n    <AutocompletePrimitive.Root inline={inline} open={open} {...props}>\n      <div\n        data-slot=\"command\"\n        className={cn(\n          \"flex h-full w-full flex-col overflow-hidden rounded-md border bg-popover text-popover-foreground\",\n          className\n        )}\n      >\n        {children}\n      </div>\n    </AutocompletePrimitive.Root>\n  );\n}\n\n/**\n * Input — the palette search row (cmdk style): a leading `SearchRegular` icon and\n * a borderless, full-width `Autocomplete.Input` sitting above a `border-b`\n * separator. The input is transparent with no field-chrome (the panel is the\n * surface). `className`/`ref`/`...props` forward to the inner `<input>`; style the\n * row with `wrapperClassName`.\n */\nfunction CommandInput({\n  className,\n  wrapperClassName,\n  \"aria-expanded\": ariaExpanded = true,\n  ...props\n}: ComponentProps<typeof AutocompletePrimitive.Input> & {\n  wrapperClassName?: string;\n}) {\n  return (\n    <div\n      data-slot=\"command-input-wrapper\"\n      className={cn(\n        \"flex h-11 items-center gap-2 border-b px-3\",\n        wrapperClassName\n      )}\n    >\n      <SearchRegular className=\"size-4 shrink-0 text-muted-foreground\" />\n      <AutocompletePrimitive.Input\n        data-slot=\"command-input\"\n        // The list is always visible (inline open), so the combobox input is\n        // permanently expanded. Base UI omits `aria-expanded` in inline mode, so\n        // set it here to satisfy the WAI-ARIA combobox contract.\n        aria-expanded={ariaExpanded}\n        className={cn(\n          \"flex h-full w-full min-w-0 bg-transparent py-3 text-sm outline-none\",\n          \"placeholder:text-muted-foreground selection:bg-primary selection:text-primary-foreground\",\n          \"disabled:cursor-not-allowed disabled:opacity-50\",\n          className\n        )}\n        {...props}\n      />\n    </div>\n  );\n}\n\n/**\n * List — the scrollable items container (Base UI `Autocomplete.List`). `children`\n * may be a render function `(item, index) => …` (the filtering API: pass `items`\n * to `<Command>` and map each) or static `CommandItem` children. Scrolls at\n * `overflow-y-auto`, capped at ~300px like cmdk.\n */\nfunction CommandList({\n  className,\n  ...props\n}: ComponentProps<typeof AutocompletePrimitive.List>) {\n  return (\n    <AutocompletePrimitive.List\n      data-slot=\"command-list\"\n      className={cn(\n        \"max-h-[300px] overflow-x-hidden overflow-y-auto overscroll-contain p-1\",\n        className\n      )}\n      {...props}\n    />\n  );\n}\n\n/**\n * Empty — the no-results state (Base UI `Autocomplete.Empty`). Base UI renders\n * its children only when the filtered list is empty and keeps its root mounted to\n * announce, so always place a `<CommandEmpty>` in the list rather than\n * conditionally rendering it. Muted, centered caption.\n */\nfunction CommandEmpty({\n  className,\n  ...props\n}: ComponentProps<typeof AutocompletePrimitive.Empty>) {\n  return (\n    <AutocompletePrimitive.Empty\n      data-slot=\"command-empty\"\n      className={cn(\"py-6 text-center text-sm text-muted-foreground\", className)}\n      {...props}\n    />\n  );\n}\n\n/**\n * Group — a labelled set of items (Base UI `Autocomplete.Group`). Pass a\n * `heading` for the muted caption (rendered via `Autocomplete.GroupLabel`),\n * matching shadcn's `<CommandGroup heading=\"…\">`. With built-in filtering, pass\n * grouped `items` to `<Command>` so empty groups drop out automatically.\n */\nfunction CommandGroup({\n  className,\n  heading,\n  children,\n  ...props\n}: ComponentProps<typeof AutocompletePrimitive.Group> & {\n  heading?: ReactNode;\n}) {\n  return (\n    <AutocompletePrimitive.Group\n      data-slot=\"command-group\"\n      className={cn(\"overflow-hidden p-1 text-foreground\", className)}\n      {...props}\n    >\n      {heading != null && (\n        <AutocompletePrimitive.GroupLabel\n          data-slot=\"command-group-heading\"\n          // Fluent Menu section header — Caption 1 Stronger (12px bold) in\n          // NeutralForeground2, matching DropdownMenuLabel's pass-2 fix\n          // (Figma validation pass 3 caught this as an intra-kit drift).\n          className=\"px-2 py-1.5 text-xs font-bold text-foreground-2 select-none\"\n        >\n          {heading}\n        </AutocompletePrimitive.GroupLabel>\n      )}\n      {children}\n    </AutocompletePrimitive.Group>\n  );\n}\n\n/**\n * Item — one command (Base UI `Autocomplete.Item`, a `<div role=\"option\">`). Its\n * `onClick` is the action handler: it fires on pointer-click AND on Enter when the\n * item is highlighted (divergence 1). 32px row, 4px list radius, keyboard/hover\n * highlight via `data-highlighted` → `bg-accent`, disabled items muted + inert.\n */\nfunction CommandItem({\n  className,\n  ...props\n}: ComponentProps<typeof AutocompletePrimitive.Item>) {\n  return (\n    <AutocompletePrimitive.Item\n      data-slot=\"command-item\"\n      className={cn(\n        // layout — Fluent 32px row, 4px list radius, gap for a leading icon\n        \"relative flex h-8 w-full cursor-default items-center gap-2 rounded-md px-2 text-sm outline-none select-none\",\n        // rest text is NeutralForeground2, darkening to accent-foreground on\n        // highlight (Figma validation: Fluent list rows rest at #424242)\n        \"text-foreground-2 data-[highlighted]:bg-accent data-[highlighted]:text-accent-foreground\",\n        // disabled item — muted + non-interactive\n        \"data-[disabled]:pointer-events-none data-[disabled]:opacity-50\",\n        // icons a consumer puts inside the item\n        \"[&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4 [&_svg]:text-muted-foreground\",\n        className\n      )}\n      {...props}\n    />\n  );\n}\n\n/**\n * Separator — a thin rule between groups (Base UI `Autocomplete.Separator`).\n */\nfunction CommandSeparator({\n  className,\n  ...props\n}: ComponentProps<typeof AutocompletePrimitive.Separator>) {\n  return (\n    <AutocompletePrimitive.Separator\n      data-slot=\"command-separator\"\n      className={cn(\"pointer-events-none -mx-1 my-1 h-px bg-border\", className)}\n      {...props}\n    />\n  );\n}\n\n/**\n * Shortcut — a right-aligned keyboard-hint caption inside a `CommandItem` (cmdk\n * parity; no Base UI part). `ml-auto` pushes it to the trailing edge.\n */\nfunction CommandShortcut({ className, ...props }: ComponentProps<\"span\">) {\n  return (\n    <span\n      data-slot=\"command-shortcut\"\n      className={cn(\n        \"ml-auto text-xs tracking-widest text-muted-foreground\",\n        className\n      )}\n      {...props}\n    />\n  );\n}\n\n/**\n * Dialog — the palette in a modal (Base UI/kit `Dialog`). Composes the kit\n * `Dialog` + `DialogContent` (`p-0 overflow-hidden`, no ✕) around a borderless\n * `Command`. A `trigger` element opens it uncontrolled (forwarded to\n * `DialogTrigger`'s `render`); pass `open`/`onOpenChange` for the controlled path\n * (divergence 6). `title`/`description` are present for a11y but visually hidden.\n */\nfunction CommandDialog<ItemValue>({\n  title = \"Command Palette\",\n  description = \"Search for a command to run…\",\n  trigger,\n  className,\n  children,\n  // Dialog-level state. Both `Dialog` and `Autocomplete.Root` own `open`/\n  // `defaultOpen`/`onOpenChange`; here they mean the DIALOG. They are pulled out\n  // so they never reach the inner `Command`, whose list stays always-open inline.\n  open,\n  defaultOpen,\n  onOpenChange,\n  modal,\n  ...commandProps\n}: Omit<CommandProps<ItemValue>, \"open\" | \"defaultOpen\" | \"onOpenChange\"> & {\n  title?: string;\n  description?: string;\n  trigger?: ReactElement;\n  open?: ComponentProps<typeof Dialog>[\"open\"];\n  defaultOpen?: ComponentProps<typeof Dialog>[\"defaultOpen\"];\n  onOpenChange?: ComponentProps<typeof Dialog>[\"onOpenChange\"];\n  modal?: ComponentProps<typeof Dialog>[\"modal\"];\n}) {\n  return (\n    <Dialog\n      open={open}\n      defaultOpen={defaultOpen}\n      onOpenChange={onOpenChange}\n      modal={modal}\n    >\n      {trigger != null && <DialogTrigger render={trigger} />}\n      <DialogContent\n        showCloseButton={false}\n        className={cn(\"overflow-hidden p-0\", className)}\n      >\n        <DialogHeader className=\"sr-only\">\n          <DialogTitle>{title}</DialogTitle>\n          <DialogDescription>{description}</DialogDescription>\n        </DialogHeader>\n        <Command className=\"rounded-xl border-0\" {...commandProps}>\n          {children}\n        </Command>\n      </DialogContent>\n    </Dialog>\n  );\n}\n\nexport {\n  Command,\n  CommandDialog,\n  CommandInput,\n  CommandList,\n  CommandEmpty,\n  CommandGroup,\n  CommandItem,\n  CommandSeparator,\n  CommandShortcut,\n};\n"
    }
  ],
  "docs": "A command palette is an always-open, filtered list. Base UI does the filtering, so pass `items` to `<Command>` and render the list with a render-function child. `CommandEmpty` is a SIBLING of `CommandList` (not a child), and items fire a native `onClick` (which also fires on Enter when the item is highlighted):\n\n```tsx\n<Command items={commands}>\n  <CommandInput placeholder=\"Type a command…\" />\n  <CommandEmpty>No results found.</CommandEmpty>\n  <CommandList>\n    {(cmd) => (\n      <CommandItem key={cmd.value} onClick={cmd.run}>\n        {cmd.label}\n        <CommandShortcut>{cmd.shortcut}</CommandShortcut>\n      </CommandItem>\n    )}\n  </CommandList>\n</Command>\n```\n\nUse `CommandGroup heading=\"…\"` for labelled sections and `CommandSeparator` between them. `CommandDialog` composes the kit `Dialog` (hence the `dialog` registry dependency) — pass a `trigger` element for an uncontrolled palette, or `open`/`onOpenChange` to control it. See `command.tsx`'s doc comment for the autocomplete-vs-combobox architecture decision and the full cmdk divergences."
}
