# Dropdown Menu

Accessible menu rendered in a CDK overlay with keyboard navigation (arrow keys,
Home/End, type-ahead, Escape).

This Angular implementation follows the shadcn Dropdown Menu information architecture while mapping the React root
component to an explicit trigger directive and projected menu template.

## Import

```ts
import {
  MenuCheckboxItemComponent,
  MenuTriggerDirective,
  MenuContentDirective,
  MenuGroupComponent,
  MenuSurfaceComponent,
  MenuItemComponent,
  MenuRadioGroupComponent,
  MenuRadioItemComponent,
  MenuSeparatorComponent,
  MenuLabelComponent,
  MenuShortcutComponent,
} from '@edsis/component/dropdown-menu';
```

## Usage

```html
<button
  Button
  type="button"
  variant="outline"
  #accountTrigger="MenuTrigger"
  [MenuTrigger]="menu"
  side="bottom"
  align="end"
>
  Open
</button>

<ng-template MenuContent #menu="MenuContent">
  <MenuSurface class="w-56">
    <MenuGroup>
      <MenuLabel>My account</MenuLabel>
      <button MenuItem type="button" (selected)="onProfile(); accountTrigger.close()">
        Profile
        <span MenuShortcut>⌘P</span>
      </button>
      <button MenuItem type="button" (selected)="onSettings(); accountTrigger.close()">
        Settings
      </button>
    </MenuGroup>
    <MenuSeparator />
    <MenuGroup>
      <button MenuItem type="button" disabled>Disabled</button>
      <button
        MenuItem
        type="button"
        variant="destructive"
        (selected)="onSignOut(); accountTrigger.close()"
      >
        Sign out
      </button>
    </MenuGroup>
  </MenuSurface>
</ng-template>
```

Use the trigger export when a standard command row should dismiss the overlay. Checkbox and radio rows can stay open so
the user can adjust multiple settings in one pass.

## Composition

```text
button[Button][MenuTrigger]
└── ng-template[MenuContent]
    └── MenuSurface
        ├── MenuGroup
        │   ├── MenuLabel
        │   ├── button[MenuItem]
        │   └── button[MenuItem][MenuTrigger]
        │       └── ng-template[MenuContent]
        │           └── MenuSurface
        ├── MenuSeparator
        ├── button[MenuCheckboxItem]
        └── MenuRadioGroup
            └── button[MenuRadioItem]
```

## Common patterns

### Basic account menu

```html
<button Button type="button" variant="outline" #menuTrigger="MenuTrigger" [MenuTrigger]="menu">
  Open
</button>

<ng-template MenuContent #menu="MenuContent">
  <MenuSurface class="w-56">
    <MenuGroup>
      <MenuLabel>My Account</MenuLabel>
      <button MenuItem type="button" (selected)="menuTrigger.close()">Profile</button>
      <button MenuItem type="button" (selected)="menuTrigger.close()">Billing</button>
      <button MenuItem type="button" (selected)="menuTrigger.close()">Settings</button>
    </MenuGroup>
    <MenuSeparator />
    <MenuGroup>
      <button MenuItem type="button" (selected)="menuTrigger.close()">GitHub</button>
      <button MenuItem type="button" (selected)="menuTrigger.close()">Support</button>
      <button MenuItem type="button" [disabled]="true">API</button>
    </MenuGroup>
  </MenuSurface>
</ng-template>
```

### Submenu

Map shadcn `DropdownMenuSub` to `MenuTrigger` on a `button[MenuItem]`.

```html
<ng-template MenuContent #inviteUsersMenu="MenuContent">
  <MenuSurface class="w-48">
    <button MenuItem type="button">Email</button>
    <button MenuItem type="button">Message</button>
    <button MenuItem type="button">Calendar invite</button>
  </MenuSurface>
</ng-template>

<MenuSurface class="w-56">
  <MenuGroup>
    <button MenuItem type="button">Team</button>
    <button MenuItem type="button" [MenuTrigger]="inviteUsersMenu" side="right" align="start">
      Invite users
      <span class="ml-auto text-xs text-muted-foreground">›</span>
    </button>
  </MenuGroup>
</MenuSurface>
```

### Checkboxes

Use checkbox rows when the menu exposes independent toggles.

```ts
const showStatusBar = signal(true);
const showActivityBar = signal(false);
const showPanel = signal(false);
```

```html
<MenuSurface class="w-44">
  <MenuGroup>
    <MenuLabel>Appearance</MenuLabel>
    <button MenuCheckboxItem type="button" [(checked)]="showStatusBar">Status Bar</button>
    <button MenuCheckboxItem type="button" [(checked)]="showActivityBar">Activity Bar</button>
    <button MenuCheckboxItem type="button" [(checked)]="showPanel">Panel</button>
  </MenuGroup>
</MenuSurface>
```

### Radio group

Use a radio group for one exclusive choice.

```ts
const panelPosition = signal<'top' | 'bottom' | 'right'>('bottom');
```

```html
<MenuSurface class="w-44">
  <MenuLabel [inset]="true">Panel Position</MenuLabel>
  <MenuRadioGroup [(value)]="panelPosition">
    <button MenuRadioItem type="button" value="top">Top</button>
    <button MenuRadioItem type="button" value="bottom">Bottom</button>
    <button MenuRadioItem type="button" value="right">Right</button>
  </MenuRadioGroup>
</MenuSurface>
```

### Shortcuts and icons

Project shortcut text and inline icons directly into the row content.

```html
<MenuSurface class="w-56">
  <button MenuItem type="button">
    <svg aria-hidden="true" class="size-4" viewBox="0 0 24 24">...</svg>
    Profile
    <span MenuShortcut>⇧⌘P</span>
  </button>
  <button MenuItem type="button">
    <svg aria-hidden="true" class="size-4" viewBox="0 0 24 24">...</svg>
    Billing
    <span MenuShortcut>⌘B</span>
  </button>
</MenuSurface>
```

### Avatar trigger composition

Also import the avatar entrypoint when the trigger should be an account avatar.

```ts
import {
  AvatarComponent,
  AvatarFallbackComponent,
  AvatarImageComponent,
} from '@edsis/component/avatar';
```

```html
<button
  Button
  type="button"
  variant="ghost"
  size="icon"
  class="h-10 w-10 rounded-full p-0"
  [MenuTrigger]="accountMenu"
  align="end"
>
  <Avatar>
    <AvatarImage src="https://github.com/shadcn.png" alt="Ada Lovelace" />
    <AvatarFallback>AL</AvatarFallback>
  </Avatar>
</button>
```

### RTL

Set `dir="rtl"` and `lang` on the surface, and prefer `side="left"` when nested content should open toward the visual
start edge.

```html
<ng-template MenuContent #rtlAccountMenu="MenuContent">
  <MenuSurface dir="rtl" lang="ar" class="w-44 text-right">
    <button MenuItem type="button">الملف الشخصي</button>
    <button MenuItem type="button">الفوترة</button>
  </MenuSurface>
</ng-template>

<MenuSurface dir="rtl" lang="ar" class="w-56 text-right">
  <button MenuItem type="button" [MenuTrigger]="rtlAccountMenu" side="left" align="start">
    الحساب
    <span class="mr-auto text-xs text-muted-foreground">‹</span>
  </button>
</MenuSurface>
```

## API

### `[MenuTrigger]`

| Input         | Type                                     | Default    |
| ------------- | ---------------------------------------- | ---------- |
| `MenuTrigger` | `MenuContentDirective`                   | _required_ |
| `side`        | `'top' \| 'right' \| 'bottom' \| 'left'` | `'bottom'` |
| `align`       | `'start' \| 'center' \| 'end'`           | `'start'`  |
| `disabled`    | `boolean`                                | `false`    |

Output: `openedChange: boolean`. Methods: `open()`, `close()`, `toggle()`.

### `ng-template[MenuContent]`

Projected template wrapper for the menu surface that is consumed by `[MenuTrigger]`.

### `MenuSurface`

Container with `role="menu"` and arrow key navigation wired through
`FocusKeyManager` (wrapping + type-ahead). Emits `closeRequested` on Tab.

### `MenuItem`

`role="menuitem"`. Inputs: `disabled`, `inset`, `class`. Output: `selected`.

### `MenuCheckboxItem`

`role="menuitemcheckbox"`. Inputs: `[(checked)]`, `disabled`, `variant`, `class`.

### `MenuRadioGroup` and `MenuRadioItem`

Use `[(value)]` on the group and `value` on each radio row. Radio items expose `role="menuitemradio"`.

### Auxiliary

- `MenuGroup` → structural wrapper with `role="group"`.
- `MenuSeparator` → `role="separator"`.
- `MenuLabel` — non-interactive label row.
- `MenuShortcut` — right-aligned shortcut badge.

## Styling and theming

Pass `class` to the surface or individual rows to control width, spacing, and emphasis. Borders and separators use the
shared theme border tokens, destructive rows use the destructive palette, and projected icons inherit the current text
color.

## Accessibility

- Trigger: `aria-haspopup="menu"`, `aria-expanded` reflects state.
- Surface: `role="menu"`, items receive `role="menuitem"`, disabled items get
  `aria-disabled="true"`.
- Checkbox and radio items expose `aria-checked` semantics through the relevant menuitem roles.
- Close on outside click, Escape, or Tab. Focus returns to the trigger.

## Keyboard interactions

- Enter, Space, and ArrowDown on the trigger open the menu.
- Arrow Up and Arrow Down move between enabled rows; Home and End jump to the first or last row.
- Typeahead matches the row label text.
- Enter and Space activate the focused row.

## Angular notes

- There is no React-style `DropdownMenu` root component; the root behavior is handled by `MenuTrigger` and
  `ng-template[MenuContent]`.
- Reuse `MenuTrigger` on `button[MenuItem]` when you need a submenu.
- Standard command rows can dismiss the overlay explicitly through a `#menuTrigger="MenuTrigger"` template reference,
  while checkbox and radio rows can stay open for multi-step preference changes.

## Source parity

This Angular entrypoint keeps the main shadcn dropdown-menu patterns: grouped commands, shortcuts, icons, nested menus,
checkbox items, radio groups, avatar triggers, destructive rows, and RTL guidance. The shadcn page includes additional
permutations such as checkbox-icons, radio-icons, and a very large complex menu; the local demos cover the same
primitives through representative compositions instead of duplicating every permutation one-to-one.
