# Command

Searchable command palette primitive for quick actions, navigation, and settings.

Use Command inline for filterable action lists, or compose it with Dialog to recreate shadcn's `CommandDialog` pattern. The same primitive also powers [Combobox](../combobox/README.md).

## Import

Import the command parts directly from the component package.

```ts
import {
  CommandComponent,
  CommandEmptyComponent,
  CommandGroupComponent,
  CommandInputComponent,
  CommandItemComponent,
  CommandListComponent,
  CommandSeparatorComponent,
  CommandShortcutComponent,
} from '@edsis/component/command';
```

When you want a palette launcher like shadcn's `CommandDialog`, add Button and Dialog primitives as well.

```ts
import { ButtonComponent } from '@edsis/component/button';
import {
  DialogComponent,
  DialogDescriptionComponent,
  DialogHeaderComponent,
  DialogTitleComponent,
} from '@edsis/component/dialog';
```

## Composition

The Angular composition mirrors shadcn's structure while keeping overlay behavior separate.

```text
Command
├── input[CommandInput]
└── CommandList
    ├── CommandEmpty
    ├── CommandGroup
    │   ├── button[CommandItem]
    │   └── button[CommandItem]
    ├── CommandSeparator
    └── CommandGroup
        ├── button[CommandItem]
        └── button[CommandItem]
```

## Basic usage

Build the searchable surface from the root, input, list, and grouped items. Add `span[CommandShortcut]` when an item should expose a trailing keyboard hint.

```html
<command class="max-w-md rounded-lg border border-border">
  <input CommandInput placeholder="Type a command or search..." />
  <CommandList>
    <CommandEmpty>No results found.</CommandEmpty>

    <CommandGroup heading="Suggestions">
      <button type="button" CommandItem value="Calendar" (selected)="open('calendar')">
        Calendar
      </button>
      <button type="button" CommandItem value="Search Emoji" (selected)="open('emoji')">
        Search Emoji
      </button>
    </CommandGroup>

    <CommandSeparator />

    <CommandGroup heading="Settings">
      <button type="button" CommandItem value="Profile" (selected)="open('profile')">
        Profile
        <span CommandShortcut>⌘P</span>
      </button>
    </CommandGroup>
  </CommandList>
</command>
```

## Common patterns

### Command palette dialog

shadcn ships a dedicated `CommandDialog` helper. In this Angular library, compose `Dialog` with `Command` instead.

```ts
const commandOpen = signal(false);
```

```html
<button type="button" Button variant="outline" (click)="commandOpen.set(true)">Open menu</button>

<dialog [(open)]="commandOpen">
  <DialogHeader>
    <DialogTitle>Command palette</DialogTitle>
    <DialogDescription> Search for navigation, billing, or settings actions. </DialogDescription>
  </DialogHeader>

  <command class="mt-4 rounded-lg border border-border">
    <input CommandInput placeholder="Type a command or search..." />
    <CommandList>
      <CommandEmpty>No results found.</CommandEmpty>
      <CommandGroup heading="Suggestions">
        <button type="button" CommandItem value="Calendar" (selected)="commandOpen.set(false)">
          Calendar
        </button>
      </CommandGroup>
    </CommandList>
  </command>
</dialog>
```

### Shortcuts

Use `span[CommandShortcut]` for keyboard hints aligned to the trailing edge of each row.

```html
<command class="max-w-md rounded-lg border border-border">
  <input CommandInput placeholder="Search shortcuts..." />
  <CommandList>
    <CommandGroup heading="Quick actions">
      <button type="button" CommandItem value="Profile">
        Profile
        <span CommandShortcut>⌘P</span>
      </button>
      <button type="button" CommandItem value="Billing">
        Billing
        <span CommandShortcut>⌘B</span>
      </button>
    </CommandGroup>
  </CommandList>
</command>
```

### Scrollable command lists

The list container defaults to a scrollable max height. Override it with `class` when the palette needs to expose many groups.

```html
<command class="max-w-xl rounded-lg border border-border">
  <input CommandInput placeholder="Jump to a tool or action..." />
  <CommandList class="max-h-56">
    <CommandEmpty>No results found.</CommandEmpty>
    <CommandGroup heading="Navigation">...</CommandGroup>
    <CommandSeparator />
    <CommandGroup heading="Actions">...</CommandGroup>
    <CommandSeparator />
    <CommandGroup heading="Tools">...</CommandGroup>
  </CommandList>
</command>
```

### Controlled query

Two-way bind the query when the parent needs to inspect, reset, or prefill the current search string.

```ts
const query = signal('');
```

```html
<command [(query)]="query" class="max-w-md rounded-lg border border-border">
  <input CommandInput placeholder="Filter actions..." />
  <CommandList>...</CommandList>
</command>
```

### RTL

For right-to-left interfaces, apply `dir="rtl"` to the wrapper and input.

```html
<section dir="rtl" lang="ar" class="max-w-md text-right">
  <command class="rounded-lg border border-border">
    <input CommandInput placeholder="اكتب أمرًا أو ابحث..." dir="rtl" />
    <CommandList>
      <CommandEmpty>لم يتم العثور على نتائج.</CommandEmpty>
      <CommandGroup heading="اقتراحات">...</CommandGroup>
      <CommandSeparator />
      <CommandGroup heading="الإعدادات">...</CommandGroup>
    </CommandList>
  </command>
</section>
```

## API reference

### `CommandComponent`

| Input / Model | Type     | Default |
| ------------- | -------- | ------- |
| `query`       | `string` | `''`    |
| `class`       | `string` | `''`    |

### `CommandInputComponent`

| Input         | Type     | Default                       |
| ------------- | -------- | ----------------------------- |
| `placeholder` | `string` | `Type a command or search...` |
| `class`       | `string` | `''`                          |

Behavior:

- Uses `role="combobox"` and `aria-autocomplete="list"`.
- Arrow Down and Arrow Up move the active item.
- Enter selects the active visible item.

### `CommandListComponent`

| Input   | Type     | Default |
| ------- | -------- | ------- |
| `class` | `string` | `''`    |

Behavior: renders the listbox region and scroll container.

### `CommandGroupComponent`

| Input     | Type             | Default |
| --------- | ---------------- | ------- |
| `heading` | `string \| null` | `null`  |
| `class`   | `string`         | `''`    |

### `CommandItemComponent`

| Input / Output | Type                          | Default              |
| -------------- | ----------------------------- | -------------------- |
| `value`        | `string`                      | `''`                 |
| `disabled`     | `boolean`                     | `false`              |
| `class`        | `string`                      | `''`                 |
| `selected`     | `MouseEvent \| KeyboardEvent` | emitted on selection |

Behavior:

- Uses `role="option"`.
- Hides automatically when the current query does not match its `value` or text content.
- Skips selection when `disabled` is `true`.

### Auxiliary parts

- `CommandEmpty` appears only when no visible items match the query.
- `CommandSeparator` renders a divider between groups.
- `span[CommandShortcut]` aligns trailing shortcut text with `ml-auto` styling.

## Styling and theming

Pass `class` to the root and parts to tune borders, width, list height, and embedded dialog layouts.

The primitive already applies shared theme tokens such as `bg-popover`, `text-popover-foreground`, `border-border`, and active-row accent styles. Typical overrides include:

- `rounded-lg border border-border` on the root for shadcn-like cards.
- `max-h-*` on `CommandList` for taller or shorter scroll regions.
- Additional spacing or layout classes on items when an app supplies inline badges or icons.

## Accessibility

- The input uses combobox semantics while the list exposes listbox-style options.
- Items expose `aria-selected`, `data-active`, and disabled state markers.
- Disabled items remain visible for discoverability but are skipped by keyboard selection.
- Keep item labels descriptive and avoid deeply nested interactive content inside a command item.

## Keyboard interactions

- Arrow Down and Arrow Up move the active option through visible items.
- Enter selects the active item.
- Typing filters items by the configured `value` or fallback text content.

## Angular notes

- The root exposes a signal-backed `query` model, so `[(query)]` works naturally in standalone components.
- `button[CommandItem]` is the most practical item host because it preserves native semantics for click and keyboard handlers.
- `ComboboxComponent` already builds on this primitive, so keep command examples action-oriented instead of mixing them with form-specific behavior.
- This primitive intentionally stays presentational. Compose it with higher-level surfaces such as Dialog rather than coupling it to overlay infrastructure.

## Source parity

This Angular implementation follows shadcn's Command information architecture and `cmdk` mental model while translating the dialog helper into existing `Dialog` primitives and Angular selectors.
