# Quantity Control

An accessible, feature-rich Angular quantity selector component with dropdown presets and manual input mode.

## Features

- ✅ **Dropdown with presets** - Quick selection from predefined values
- ✅ **Edit mode** - Manual input for values beyond presets
- ✅ **Smart logic** - Automatically shows/hides Edit based on constraints
- ✅ **Flexible range** - Start from any value (0, 1, or custom)
- ✅ **Full accessibility** - WCAG 2.1 AA compliant with screen reader support
- ✅ **Keyboard navigation** - Arrow keys, Home, End, Enter, Escape
- ✅ **Form integration** - Implements `ControlValueAccessor`
- ✅ **Type-safe** - Full TypeScript support with proper validation

## Installation

```typescript
import { QuantityControlComponent } from '@isa/shared/quantity-control';

@Component({
  // ...
  imports: [QuantityControlComponent],
})
```

## Basic Usage

### Standalone

```html
<shared-quantity-control [value]="quantity" />
```

### With Reactive Forms

```typescript
export class MyComponent {
  quantityControl = new FormControl(1);
}
```

```html
<shared-quantity-control [formControl]="quantityControl" />
```

### With Template-Driven Forms

```html
<shared-quantity-control [(ngModel)]="quantity" />
```

## API

### Inputs

| Input | Type | Default | Description |
|-------|------|---------|-------------|
| `value` | `model<number>` | `1` | Current quantity value (two-way binding) |
| `disabled` | `model<boolean>` | `false` | Whether the control is disabled |
| `min` | `number` | `1` | Minimum selectable value (starting point) |
| `max` | `number \| undefined` | `undefined` | Maximum selectable value (e.g., stock available) |
| `presetLimit` | `number` | `10` | Number of preset options before requiring Edit |
| `ariaLabel` | `string` | `undefined` | Custom ARIA label for accessibility |

### How It Works

**Preset options generated:** `min` to `(min + presetLimit - 1)`

**Edit option shown when:**
- `max` is `undefined` (unlimited), OR
- `max > (min + presetLimit - 1)` (stock exceeds presets)

## Examples

### Standard Use Case (1-10 with unlimited)

```html
<shared-quantity-control
  [(value)]="quantity"
  [min]="1"
  [presetLimit]="10"
/>
```
**Dropdown:** 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, Edit ✅

---

### Start From Zero

```html
<shared-quantity-control
  [(value)]="quantity"
  [min]="0"
  [presetLimit]="10"
/>
```
**Dropdown:** 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, Edit ✅

---

### Limited Stock (No Edit)

```html
<shared-quantity-control
  [(value)]="quantity"
  [min]="1"
  [max]="5"
  [presetLimit]="10"
/>
```
**Dropdown:** 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 (No Edit - max is 5)

---

### High Stock (With Edit)

```html
<shared-quantity-control
  [(value)]="quantity"
  [min]="1"
  [max]="50"
  [presetLimit]="20"
/>
```
**Dropdown:** 1, 2, 3, ... 20, Edit ✅ (allows 21-50)

---

### Custom Range (5-15)

```html
<shared-quantity-control
  [(value)]="quantity"
  [min]="5"
  [presetLimit]="11"
  [max]="15"
/>
```
**Dropdown:** 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15 (No Edit)

---

### With Reactive Forms

```typescript
export class ShoppingCartComponent {
  quantityControl = new FormControl(1, [
    Validators.min(1),
    Validators.max(99)
  ]);
}
```

```html
<shared-quantity-control
  [formControl]="quantityControl"
  [min]="1"
  [max]="99"
  [presetLimit]="10"
/>
```

---

### Disabled State

```html
<shared-quantity-control
  [(value)]="quantity"
  [disabled]="true"
/>
```

---

### Custom ARIA Label

```html
<shared-quantity-control
  [(value)]="quantity"
  [ariaLabel]="'Select number of items to purchase'"
/>
```

## Accessibility

The component implements the **ARIA combobox pattern** and is fully accessible:

- ✅ **Keyboard Navigation:**
  - `Space/Enter` - Open dropdown
  - `Arrow Up/Down` - Navigate options
  - `Home/End` - Jump to first/last option
  - `Enter/Space` - Select option
  - `Escape` - Close dropdown or cancel edit

- ✅ **ARIA Attributes:**
  - `role="combobox"` on host
  - `role="listbox"` on dropdown
  - `role="option"` on each item
  - `aria-expanded`, `aria-haspopup`, `aria-controls`
  - `aria-activedescendant` for keyboard focus
  - `aria-selected` for current value

- ✅ **Screen Reader Support:**
  - Value changes announced
  - Edit mode transitions announced
  - Validation errors announced

- ✅ **E2E Testing:**
  - `data-what="quantity-control"` on button
  - `data-what="quantity-control-option"` on options
  - `data-which` attributes with values

## Validation

### Automatic Validation

The component validates input in Edit mode:

```typescript
// If min=1, entering 0 shows:
"Invalid quantity. Please enter a number greater than or equal to 1."

// If max=50, entering 100 shows:
"Invalid quantity. Maximum available is 50."
```

### Form Validators

Use standard Angular validators with the form control:

```typescript
quantityControl = new FormControl(1, [
  Validators.required,
  Validators.min(0),
  Validators.max(999),
]);
```

## Behavior

### Dropdown

- Click button or press `Space`/`Enter` to open
- Click option to select
- Click outside (backdrop) to close
- Press `Escape` to close

### Edit Mode

- Select "Edit" option from dropdown
- Input field opens with current value pre-selected
- Press `Enter` to save
- Press `Escape` to cancel (reverts to original value)
- Click outside (blur) to save

## Styling

The component uses scoped CSS with these CSS classes:

```css
.quantity-control-button       /* Main button */
.quantity-control-value        /* Value display */
.quantity-control-input        /* Edit mode input */
.options-list                  /* Dropdown container */
.quantity-control-option       /* Each option */
.quantity-control-option.active      /* Keyboard focused */
.quantity-control-option.selected    /* Current value */
```

### Host Classes

```css
:host.disabled    /* Disabled state */
:host.open        /* Dropdown open */
:host.edit-mode   /* Edit mode active */
```

## Performance

- ✅ **OnPush change detection** for optimal performance
- ✅ **Signal-based reactivity** with computed values
- ✅ **Efficient keyboard manager** from Angular CDK
- ✅ **Automatic cleanup** on component destruction

## Browser Support

- Chrome/Edge (latest)
- Firefox (latest)
- Safari (latest)
- Mobile browsers (iOS Safari, Chrome Android)

## Dependencies

- `@angular/core` ^20.1.2
- `@angular/forms` ^20.1.2
- `@angular/cdk` ^20.1.2
- `@ng-icons/core` (for chevron icons)

## Contributing

This component is part of the ISA Frontend monorepo. For changes:

1. Update component code
2. Update tests (when available)
3. Update Storybook stories
4. Update this README if API changes

## License

Internal use only - ISA Frontend Project
