# Select

Material-backed custom select with shadcn styling for single or multiple choice.

## Import

```ts
import { FormsModule } from '@angular/forms';
import { OptionComponent, SelectComponent } from '@edsis/component/select';
```

## Composition

`SelectField` owns the trigger, overlay, disabled state, and common ARIA passthrough.
Project `SelectItem` children into it for the actual choices.

For grouped menus, the current Angular mapping uses `MatOptgroup` from
`@angular/material/core` inside `SelectField` rather than publishing separate
`SelectGroup`, `SelectLabel`, or `SelectSeparator` wrappers.

```text
SelectField
├── SelectItem
├── SelectItem
└── mat-optgroup (optional grouping bridge)
    ├── SelectItem
    └── SelectItem
```

## Basic Usage

```html
<SelectField
  class="block w-full max-w-xs"
  placeholder="Select a plan"
  [(ngModel)]="plan"
  aria-label="Plan"
>
  <SelectItem value="free">Free</SelectItem>
  <SelectItem value="pro">Pro</SelectItem>
  <SelectItem value="enterprise">Enterprise</SelectItem>
</SelectField>
```

## Common Patterns

### Grouped options

```ts
import { MatOptgroup } from '@angular/material/core';
```

```html
<SelectField
  class="block w-full max-w-sm"
  placeholder="Select produce"
  [(ngModel)]="produce"
  aria-label="Produce"
>
  <mat-optgroup label="Fruits">
    <SelectItem value="apple">Apple</SelectItem>
    <SelectItem value="banana">Banana</SelectItem>
    <SelectItem value="blueberry">Blueberry</SelectItem>
  </mat-optgroup>

  <mat-optgroup label="Vegetables">
    <SelectItem value="carrot">Carrot</SelectItem>
    <SelectItem value="broccoli">Broccoli</SelectItem>
    <SelectItem value="spinach">Spinach</SelectItem>
  </mat-optgroup>
</SelectField>
```

### Disabled trigger

```html
<SelectField placeholder="Disabled" disabled aria-label="Disabled plan">
  <SelectItem value="free">Free</SelectItem>
  <SelectItem value="pro">Pro</SelectItem>
  <SelectItem value="enterprise">Enterprise</SelectItem>
</SelectField>
```

### Searchable options

Search is disabled by default. Add the boolean `search` input when a longer list
benefits from filtering.

```html
<SelectField
  search
  searchPlaceholder="Search fruit"
  searchEmptyText="No fruit found."
  placeholder="Select a fruit"
  [(ngModel)]="fruit"
  aria-label="Select a fruit"
>
  <SelectItem value="apple">Apple</SelectItem>
  <SelectItem value="banana">Banana</SelectItem>
  <SelectItem value="blueberry">Blueberry</SelectItem>
</SelectField>
```

### Scrollable overlay

Long lists scroll automatically inside the overlay panel. You do not need a
separate input for that behavior.

```html
<SelectField
  class="block w-full max-w-md"
  placeholder="Select a timezone"
  [(ngModel)]="timezone"
  aria-label="Timezone"
>
  <mat-optgroup label="North America">
    <SelectItem value="est">Eastern Standard Time</SelectItem>
    <SelectItem value="cst">Central Standard Time</SelectItem>
    <SelectItem value="mst">Mountain Standard Time</SelectItem>
    <SelectItem value="pst">Pacific Standard Time</SelectItem>
  </mat-optgroup>

  <mat-optgroup label="Europe & Africa">
    <SelectItem value="gmt">Greenwich Mean Time</SelectItem>
    <SelectItem value="cet">Central European Time</SelectItem>
    <SelectItem value="eet">Eastern European Time</SelectItem>
  </mat-optgroup>
</SelectField>
```

### Helper and error text

The wrapper accepts `aria-describedby`, so helper or error text can live next to
the trigger instead of inside it.

```html
<SelectField
  class="block w-full max-w-sm"
  placeholder="Select department"
  aria-label="Department"
  aria-describedby="department-error"
  [formControl]="departmentControl"
  required
>
  <SelectItem value="engineering">Engineering</SelectItem>
  <SelectItem value="sales">Sales</SelectItem>
  <SelectItem value="operations">Operations</SelectItem>
</SelectField>

<p id="department-error" class="text-sm font-medium text-destructive">
  Select a department before continuing.
</p>
```

### Multiple selection

```html
<SelectField multiple [(ngModel)]="interests" aria-label="Interests">
  @for (i of all; track i) {
  <SelectItem [value]="i">{{ i }}</SelectItem>
  }
</SelectField>
```

## API Reference

- `SelectComponent` (`SelectField`): `placeholder`, `disabled`, `multiple`, `required`, `search`,
  `searchPlaceholder`, `searchEmptyText`, `aria-label`, `aria-labelledby`, `aria-describedby`, and `class` inputs;
  `valueChange` and `openedChange` outputs.
- `OptionComponent` (`SelectItem`): `value`, `disabled`, and `class` inputs.
- `MatOptgroup` (`mat-optgroup`): `label` and `disabled` inputs for grouped option lists.

Public methods on `SelectComponent`: `open()`, `close()`, `focus()`.

## Styling and Theming

The component uses Material overlay interaction and applies local shadcn bridge
tokens through `select.component.css`.

- The trigger uses the local input, ring, radius, and muted-foreground tokens.
- The panel covers the trigger, matches its horizontal bounds, and falls back upward near the viewport edge.
- Opt-in search uses the same input, radius, spacing, foreground, and ring tokens as the surrounding panel.
- Group labels come from Angular Material `mat-optgroup` and pick up the surrounding theme tokens.

## Accessibility

Built on `mat-select`, which exposes the listbox/combobox interaction contract.

- Provide an accessible name with surrounding copy or `aria-label`/`aria-labelledby`.
- Use `aria-describedby` when helper or validation text is rendered next to the trigger.
- Localize `searchPlaceholder` and `searchEmptyText` when search is enabled.
- Group options only when the categories make the list easier to scan.

## Keyboard Interactions

- `Enter`, `Space`, or `Alt+ArrowDown` opens the trigger.
- Without search, Arrow keys move through the open option list and Material typeahead jumps to matching labels.
- With search enabled, typing filters labels and Arrow keys move only through matching options.
- `Enter` or `Space` confirms the active option, and `Escape` closes the panel.

## Angular Notes

- `SelectField` is intentionally a thin Angular wrapper over `mat-select` rather than a one-to-one Radix port.
- Grouped menus currently rely on `MatOptgroup` from `@angular/material/core`.
- If you want browser-native pickers, semantic `optgroup` nodes, or mobile-first behavior, use `select[NativeSelect]` instead.

## Source Parity

This Angular slice follows the shadcn Select information architecture while staying honest about the local API.

- The public entrypoint exposes `SelectField` and `SelectItem` instead of separate `SelectTrigger`, `SelectContent`, `SelectGroup`, and `SelectItem` components.
- Group labels map to Angular Material `mat-optgroup`; there is no published `SelectSeparator` wrapper today.
- Overlay positioning is item-aligned: the panel covers the trigger and chooses an upward or downward opening direction from the available viewport space.
