# ToggleGroup

Nhóm toggle button có tên, cho một lựa chọn không bắt buộc hoặc vài lựa chọn độc lập. Phím mũi tên chuyển focus mà không đổi lựa chọn.

**Phụ thuộc:** npm: 1 trực tiếp, 4 tổng; registry: 3 trực tiếp, 3 tổng.

## Cách dùng

### Khi nào dùng

- Chọn một hoặc vài lựa chọn toolbar liên quan, chẳng hạn căn chỉnh hoặc định dạng chữ.
- Giữ một bộ lựa chọn gọn cùng nhau, với điều hướng bằng phím mũi tên.

### Khi nào không dùng

- Phải luôn còn một lựa chọn được chọn. Dùng RadioGroup.
- Chuyển giữa các panel nội dung. Dùng Tabs.
- Một lựa chọn độc lập đơn lẻ. Dùng Toggle.

## Biến thể

### variant

Trong suốt khi tắt, hoặc một surface có viền trung tính cho outline.

Giá trị: `default`, `outline`. Mặc định: `default`.

### size

Chiều cao control, cỡ chữ và icon, cùng các bước với Button: sm 28px, md 32px (mặc định), lg 36px, xl 44px với chuột; trên cảm ứng md là 36px, lg 44px và xl 48px. Control nhỏ vẫn giữ vùng nhấn tối thiểu.

Giá trị: `sm`, `md`, `lg`, `xl`. Mặc định: `md`.

### type

single nhận value string và cho phép bỏ chọn. multiple nhận mảng string.

Giá trị: `single`, `multiple`. Mặc định: `undefined`.

### orientation

Điều khiển layout và các phím mũi tên dùng để điều hướng.

Giá trị: `horizontal`, `vertical`. Mặc định: `horizontal`.

### dir

Hướng chữ, được kế thừa khi bỏ qua. RTL đảo các mũi tên ngang.

Giá trị: `ltr`, `rtl`. Mặc định: `ltr`.

## Ví dụ

### Căn chỉnh không bắt buộc

```tsx
<ToggleGroup type="single" aria-label="Căn chỉnh văn bản" defaultValue="left" className="min-w-0 max-w-full flex-wrap gap-y-[max(var(--spacing-xs),calc(var(--size-target-min)-var(--size-element-md)))]">
  <ToggleGroupItem value="left">Trái</ToggleGroupItem>
  <ToggleGroupItem value="center">Giữa</ToggleGroupItem>
  <ToggleGroupItem value="right">Phải</ToggleGroupItem>
</ToggleGroup>
```

### Định dạng độc lập

```tsx
<ToggleGroup type="multiple" aria-label="Định dạng văn bản" defaultValue={["bold"]} className="min-w-0 max-w-full flex-wrap gap-y-[max(var(--spacing-xs),calc(var(--size-target-min)-var(--size-element-md)))]">
  <ToggleGroupItem value="bold">Đậm</ToggleGroupItem>
  <ToggleGroupItem value="italic">In nghiêng</ToggleGroupItem>
</ToggleGroup>
```

### Lựa chọn view theo chiều dọc

```tsx
<ToggleGroup type="single" aria-label="Xem" orientation="vertical" variant="outline" className="min-w-0 max-w-full flex-wrap gap-y-[max(var(--spacing-xs),calc(var(--size-target-min)-var(--size-element-md)))]">
  <ToggleGroupItem value="grid">Lưới</ToggleGroupItem>
  <ToggleGroupItem value="list">Danh sách</ToggleGroupItem>
</ToggleGroup>
```

### Căn chỉnh chỉ bằng icon

Một lựa chọn căn chỉnh không bắt buộc. Mỗi icon có tên truy cập.

```tsx
<ToggleGroup type="single" aria-label="Căn chỉnh văn bản" defaultValue="left" className="min-w-0 max-w-full flex-wrap gap-y-[max(var(--spacing-xs),calc(var(--size-target-min)-var(--size-element-md)))]">
  <ToggleGroupItem value="left" iconOnly aria-label="Căn trái">
    <IconAlignLeft size={16} />
  </ToggleGroupItem>
  <ToggleGroupItem value="center" iconOnly aria-label="Căn giữa">
    <IconAlignCenter size={16} />
  </ToggleGroupItem>
  <ToggleGroupItem value="right" iconOnly aria-label="Căn phải">
    <IconAlignRight size={16} />
  </ToggleGroupItem>
</ToggleGroup>
```

### Icon và chữ định dạng

Nhiều định dạng có thể cùng được chọn. Gạch chân không dùng được.

```tsx
<ToggleGroup type="multiple" aria-label="Định dạng văn bản" variant="outline" defaultValue={["bold"]} className="min-w-0 max-w-full flex-wrap gap-y-[max(var(--spacing-xs),calc(var(--size-target-min)-var(--size-element-md)))]">
  <ToggleGroupItem value="bold">
    <IconBold size={16} />
    Đậm
  </ToggleGroupItem>
  <ToggleGroupItem value="italic">
    <IconItalic size={16} />
    In nghiêng
  </ToggleGroupItem>
  <ToggleGroupItem value="underline" disabled>
    <IconUnderline size={16} />
    Gạch chân
  </ToggleGroupItem>
</ToggleGroup>
```

### Lựa chọn icon vô hiệu

```tsx
<ToggleGroup type="multiple" aria-label="Định dạng văn bản đã khóa" disabled defaultValue={["bold"]} className="min-w-0 max-w-full flex-wrap gap-y-[max(var(--spacing-xs),calc(var(--size-target-min)-var(--size-element-md)))]">
  <ToggleGroupItem value="bold" iconOnly aria-label="Đậm">
    <IconBold size={16} />
  </ToggleGroupItem>
  <ToggleGroupItem value="italic" iconOnly aria-label="In nghiêng">
    <IconItalic size={16} />
  </ToggleGroupItem>
</ToggleGroup>
```

## Nên và không nên

### Nên

- Đặt tên nhóm và giữ label của mỗi item ổn định.
- Dùng single cho lựa chọn view không bắt buộc và multiple cho các lựa chọn định dạng độc lập.

### Không nên

- Đừng dùng single khi phải luôn còn đúng một lựa chọn; dùng RadioGroup.
- Đừng lặp value của item trong một nhóm.

## Props

| Tên | Kiểu | Giá trị | Mặc định | Mô tả |
| --- | --- | --- | --- | --- |
| `variant` | `enum` | `default`, `outline` | `default` | Trong suốt khi tắt, hoặc một surface có viền trung tính cho outline. |
| `size` | `enum` | `sm`, `md`, `lg`, `xl` | `md` | Chiều cao control, cỡ chữ và icon, cùng các bước với Button: sm 28px, md 32px (mặc định), lg 36px, xl 44px với chuột; trên cảm ứng md là 36px, lg 44px và xl 48px. Control nhỏ vẫn giữ vùng nhấn tối thiểu. |
| `disabled` | `boolean` |  | `false` | Chặn focus và lựa chọn, và dùng màu disabled. |
| `iconOnly` | `boolean` |  | `false` | Đặt trên ToggleGroupItem. Làm item vuông. Item chỉ có icon cần aria-label. |
| `type` (bắt buộc) | `enum` | `single`, `multiple` |  | single nhận value string và cho phép bỏ chọn. multiple nhận mảng string. |
| `value` | `node` |  |  | Lựa chọn controlled: một string cho single hoặc một mảng string cho multiple. Mỗi item cần value riêng, không trùng. |
| `defaultValue` | `node` |  |  | Lựa chọn ban đầu khi uncontrolled: một string cho single hoặc một mảng string cho multiple. |
| `onValueChange` | `function` |  |  | Nhận một string cho single hoặc một mảng string cho multiple. Xóa lựa chọn single báo một string rỗng. |
| `orientation` | `enum` | `horizontal`, `vertical` | `horizontal` | Điều khiển layout và các phím mũi tên dùng để điều hướng. |
| `dir` | `enum` | `ltr`, `rtl` | `ltr` | Hướng chữ, được kế thừa khi bỏ qua. RTL đảo các mũi tên ngang. |
| `loop` | `boolean` |  | `true` | Vòng điều hướng mũi tên ở hai đầu khi true. |

## Cấu tạo

| Phần | Mô tả |
| --- | --- |
| `root` | Toggle button, trong suốt theo mặc định hoặc surface có viền ở outline. Khi bật dùng cặp accent mềm. |
| `icon` | Icon trang trí tùy chọn, 16px ở sm, md và lg và 20px ở xl. |
| `hitArea` | Pseudo-element trong suốt kéo đích của button tới size-target-min. |
| `wrapper` | Nhóm có tên, với khoảng cách token, ngang theo mặc định và dọc khi được yêu cầu. |

## Khả năng truy cập

Role: `radiogroup (single), toolbar (multiple)`

| Phím | Hành động |
| --- | --- |
| `Tab` | Vào nhóm tại một item, rồi rời nhóm. |
| `ArrowLeft, ArrowRight` | Chuyển focus trong nhóm ngang, bỏ qua item disabled, và tôn trọng hướng chữ. |
| `ArrowUp, ArrowDown` | Chuyển focus trong nhóm dọc và bỏ qua item disabled. |
| `Home, End` | Chuyển focus tới item enabled đầu hoặc cuối. |
| `Space, Enter` | Toggle item đang focus. |

- Nhóm cần aria-label hoặc aria-labelledby.
- Item single có role="radio" và aria-checked. Item multiple có aria-pressed.
- Nhấn một item single đang được chọn thì xóa lựa chọn. Dùng RadioGroup khi một lựa chọn phải vẫn được chọn.
- Item cần các string value không rỗng và không trùng. Item chỉ có icon cần aria-label.
- Size và variant của nhóm là mặc định của item. Một item có thể ghi đè một trong hai mặc định.
- Phím mũi tên chuyển focus; chúng không chọn. loop mặc định là true.

## Cài đặt

```bash
npx werewolf-ui add toggle-group
```

Chạy `npx werewolf-ui init` một lần trong app trước khi thêm component. Init cài token, thêm CSS import và luật cho agent. Add cài component này cùng các dependency và giữ nguyên theme của bạn. Xem [Cài đặt](https://www.werewolf-ui.dev/vi/docs/installation.md) để biết yêu cầu và cách cài qua registry.
