# Context Menu

Displays a menu of actions triggered by a right click. The Angular version maps the
shadcn `ContextMenuTrigger` to a directive on any focusable host and reuses the
shared menu primitives from [Dropdown Menu](../dropdown-menu/README.md) for the
overlay content.

## Import

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

## Composition

The Angular composition stays close to shadcn while exposing the root behavior
through directives and shared menu primitives.

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

## Basic usage

Prefer a focusable trigger so pointer users can right-click and keyboard users can
open the same menu with Shift+F10 or the context-menu key.

```html
<div
  [ContextMenuTrigger]="menu"
  tabindex="0"
  aria-label="Open file actions"
  class="flex h-32 w-full max-w-sm items-center justify-center rounded-xl border border-dashed border-border"
>
  Right-click here
</div>

<ng-template MenuContent #menu="MenuContent">
  <MenuSurface class="w-56">
    <MenuGroup>
      <button MenuItem>Profile</button>
      <button MenuItem>Billing</button>
      <button MenuItem>Team</button>
    </MenuGroup>
  </MenuSurface>
</ng-template>
```

## Common patterns

### Browser-style actions

Use grouped commands and shortcuts for browser or editor surfaces.

```html
<MenuSurface class="w-60">
  <MenuGroup>
    <button MenuItem>
      Back
      <span MenuShortcut>⌘[</span>
    </button>
    <button MenuItem [disabled]="true">
      Forward
      <span MenuShortcut>⌘]</span>
    </button>
    <button MenuItem>
      Reload
      <span MenuShortcut>⌘R</span>
    </button>
  </MenuGroup>
</MenuSurface>
```

### Nested tools menu

Map shadcn `ContextMenuSub` to `MenuTrigger` on a menu item. This keeps submenu
composition explicit and works with the same overlay primitive used by dropdown menus.

```html
<ng-template MenuContent #moreTools="MenuContent">
  <MenuSurface class="w-48">
    <button MenuItem>Save Page...</button>
    <button MenuItem>Create Shortcut...</button>
    <button MenuItem>Name Window...</button>
  </MenuSurface>
</ng-template>

<MenuSurface class="w-56">
  <button MenuItem [MenuTrigger]="moreTools" side="right" align="start">
    More tools
    <span class="ml-auto text-xs text-muted-foreground">›</span>
  </button>
</MenuSurface>
```

### Checkbox rows

Use checkbox rows for independent toggles such as browser preferences.

```ts
const showBookmarks = signal(true);
const showFullUrls = signal(false);
```

```html
<MenuSurface class="w-56">
  <MenuGroup>
    <button MenuCheckboxItem [(checked)]="showBookmarks">Show bookmarks</button>
    <button MenuCheckboxItem [(checked)]="showFullUrls">Show full URLs</button>
  </MenuGroup>
</MenuSurface>
```

### Radio groups

Use `MenuRadioGroup` when the menu exposes an exclusive choice.

```ts
const selectedTheme = signal<'light' | 'dark' | 'system'>('system');
```

```html
<MenuSurface class="w-56">
  <MenuLabel [inset]="true">Theme</MenuLabel>
  <MenuRadioGroup [(value)]="selectedTheme">
    <button MenuRadioItem value="light">Light</button>
    <button MenuRadioItem value="dark">Dark</button>
    <button MenuRadioItem value="system">System</button>
  </MenuRadioGroup>
</MenuSurface>
```

### Destructive rows

Pass `variant="destructive"` when the row should read as irreversible.

```html
<MenuSurface class="w-56">
  <MenuGroup>
    <button MenuItem>Edit</button>
    <button MenuItem>Share</button>
  </MenuGroup>
  <MenuSeparator />
  <MenuGroup>
    <button MenuItem variant="destructive">Delete</button>
  </MenuGroup>
</MenuSurface>
```

### RTL

Set `dir="rtl"` on the surface and prefer `side="left"` for nested menus so the
submenu opens toward the visual start edge.

```html
<ng-template MenuContent #rtlTools="MenuContent">
  <MenuSurface dir="rtl" lang="ar" class="w-44 text-right">
    <button MenuItem>حفظ الصفحة...</button>
    <button MenuItem>إنشاء اختصار...</button>
  </MenuSurface>
</ng-template>

<MenuSurface dir="rtl" lang="ar" class="w-56 text-right">
  <button MenuItem [MenuTrigger]="rtlTools" side="left" align="start">
    المزيد من الأدوات
    <span class="mr-auto text-xs text-muted-foreground">‹</span>
  </button>
</MenuSurface>
```

## API reference

### `[ContextMenuTrigger]`

| Input                | Type                   | Default    |
| -------------------- | ---------------------- | ---------- |
| `ContextMenuTrigger` | `MenuContentDirective` | _required_ |
| `disabled`           | `boolean`              | `false`    |

Output: `openedChange: boolean`

Methods:

- `openAt(x, y)` opens the projected surface at the given viewport coordinates.
- `close()` closes the active overlay.

### Shared menu parts

| Part                       | Purpose                                                                                  |
| -------------------------- | ---------------------------------------------------------------------------------------- |
| `MenuSurface`              | Overlay container with roving focus, typeahead, Escape close, and Tab-to-close behavior. |
| `MenuGroup`                | Lightweight grouping wrapper for related rows.                                           |
| `button[MenuItem]`         | Standard command row with optional `variant="destructive"`.                              |
| `button[MenuCheckboxItem]` | Toggle row with `[(checked)]` and `role="menuitemcheckbox"`.                             |
| `MenuRadioGroup`           | Exclusive-selection container with signal-friendly `[(value)]`.                          |
| `button[MenuRadioItem]`    | Exclusive option row with `role="menuitemradio"`.                                        |
| `MenuLabel`                | Non-interactive label row.                                                               |
| `MenuShortcut`             | Right-aligned shortcut hint.                                                             |
| `MenuSeparator`            | Visual divider between command groups.                                                   |

For lower-level behavior details, see the Radix Context Menu API reference:
<https://www.radix-ui.com/docs/primitives/components/context-menu#api-reference>.

## Styling and theming

Pass `class` to `MenuSurface`, `MenuGroup`, labels, and items to tune width,
spacing, alignment, and emphasis. Destructive rows use the shared `destructive` theme
tokens. Visible dividers and borders follow the shared border tokens rather than the
current text color.

## Accessibility

- Make the trigger focusable if keyboard users need access to the menu.
- Native `contextmenu` is captured and its default prevented.
- Menu rows expose the expected `menuitem`, `menuitemcheckbox`, and `menuitemradio`
  roles plus `aria-checked` and `aria-disabled` where appropriate.
- Keep item labels short and descriptive, and avoid placing unrelated interactive
  controls inside a menu row.

## Keyboard interactions

- Right click opens the menu at the pointer location.
- Shift+F10 and the context-menu key open the menu at the trigger center when the
  trigger is focusable.
- Arrow Up and Arrow Down move between enabled items.
- Home and End jump to the start or end of the list.
- Typeahead matches row text.
- Enter and Space activate the focused row.
- Escape and Tab close the surface.

## Angular notes

- There is no dedicated `context-menu` root component. The root behavior lives on the
  `[ContextMenuTrigger]` directive plus `ng-template[MenuContent]`.
- Use signals with `[(checked)]` and `[(value)]` for checkbox and radio rows.
- Reuse `MenuTrigger` when a submenu is needed.
- Long-press support depends on the browser firing the native `contextmenu` event.

## Source parity

This implementation keeps the shadcn information architecture while mapping the trigger
to Angular directives, submenu behavior to nested `MenuTrigger` composition, and
checkbox or radio state to signal-friendly APIs.
