# Button

Kích hoạt một hành động. Solid cho hành động chính trong một view, secondary cho phần còn lại, ghost cho hành động nhẹ trong toolbar và hàng, destructive (hoặc destructive-soft) cho hành động phá hủy. glossy và destructive-glossy là bản nổi của solid và destructive. iconOnly tạo button vuông với aria-label bắt buộc.

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

## Cách dùng

### Khi nào dùng

- Kích hoạt một hành động trên trang hiện tại: lưu, submit một form, mở một dialog, xóa một mục.
- Đánh dấu hành động chính duy nhất của một view bằng variant solid.
- Hành động nhẹ lặp trên mỗi hàng hoặc nằm trong toolbar, với variant ghost. Một icon đứng riêng, với iconOnly và một nhãn cho trình đọc màn hình.

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

- Đi tới trang khác. Dùng một link; để có giao diện của button, truyền asChild và đặt link bên trong, để nó vẫn là link thật.
- Nhãn không phải hành động, chẳng hạn một status. Dùng Badge.

## Biến thể

### variant

solid: hành động chính, trên accent. secondary: hành động trung tính. ghost: hành động trung tính, không nền hoặc viền cho đến khi hover, cho toolbar, button icon và hành động trong hàng. destructive: hành động phá hủy như Xóa, trên nền red solid với color-text-on-danger (4.53:1). destructive-soft: hành động phá hủy nhẹ hơn trên nền red soft. glossy: hành động chính, dạng nổi: nền accent dưới một lớp sáng chiếu từ trên, với cạnh trong và shadow med. destructive-glossy: cùng vẻ nổi đó trên nền red solid.

Giá trị: `solid`, `secondary`, `ghost`, `destructive`, `destructive-soft`, `glossy`, `destructive-glossy`. Mặc định: `solid`.

### size

Chiều cao từ size-element-*: sm 28px, md 32px (mặc định), lg 36px, xl 44px khi dùng chuột. Trên cảm ứng md tăng lên 36px, lg lên 44px và xl lên 48px; sm giữ nguyên vẻ và vùng chạm 44px. Dùng lg hoặc xl cho vùng chạm lớn hơn, chẳng hạn hành động chính của màn hình mobile. Chữ là 14px ở sm, 14px ở md và lg, 16px ở xl.

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

### type

Type native của button.

Giá trị: `button`, `submit`, `reset`. Mặc định: `button`.

## Ví dụ

### Mặc định

```tsx
<Button>Lưu</Button>
```

### Có icon

```tsx
<Button variant="secondary">
  <IconPlus size={16} />
  Tệp mới
</Button>
```

### Dưới dạng link

Giữ ngữ nghĩa của link (href, click giữa) với style của button.

```tsx
<Button asChild variant="secondary">
  <a href="/docs">Đọc tài liệu</a>
</Button>
```

### Chỉ icon

Một button vuông nhẹ trong hàng hoặc toolbar. aria-label đặt tên hành động.

```tsx
<Button variant="ghost" iconOnly aria-label="Thêm thao tác">
  <IconDots size={16} />
</Button>
```

### Glossy

Hành động chính, nổi khỏi trang. Dùng nó thay cho solid, không đặt cạnh solid.

```tsx
<Button variant="glossy" size="xl">Bắt đầu</Button>
```

### Disabled

```tsx
<Button disabled>Lưu</Button>
```

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

### Nên

- Dùng một button solid cho mỗi view, cho hành động chính.
- Chỉ dùng destructive hoặc destructive-soft cho hành động phá hủy, và nói rõ thứ bị phá: Xóa dự án, không phải OK.
- Dùng destructive (solid) cho một hành động phá hủy chính không hoàn tác được, chẳng hạn button xác nhận trong dialog Xóa dự án. Tối đa một cái mỗi view.
- Dùng destructive-soft cho hành động phá hủy phụ hoặc lặp lại, chẳng hạn Xóa trên mỗi hàng table hoặc trong menu.
- Đặt hành động chính ở cuối hàng button (Hủy, rồi Lưu).
- Dùng ghost cho hành động lặp trên mỗi hàng hoặc nằm trong toolbar, để trang không thành một tường các hộp.
- Cho mọi button iconOnly một aria-label đặt tên hành động (Thêm hành động, Đóng), và dùng icon quen thuộc.
- Dùng glossy thay cho solid khi hành động chính cần nổi khỏi trang, chẳng hạn lời gọi hành động trên landing hoặc empty state. Nó vẫn là hành động chính duy nhất trong view đó.
- Chỉ dùng destructive-glossy ở chỗ đáng lẽ dùng destructive: hành động phá hủy chính của view, trong view đã dùng glossy.

### Không nên

- Đừng chỉnh màu qua className. Chọn một variant. Nếu không cái nào khớp, mở một issue thay vì ghi đè.
- Đừng dùng destructive cho cảnh báo hoặc lỗi không phải một hành động.
- Đừng đặt destructive và destructive-soft cạnh nhau. Cái solid mất sức nặng; chọn một cho mỗi nhóm.
- Đừng dùng button để điều hướng. Dùng asChild với một link để nó là link thật.
- Đừng dùng ghost cho hành động chính của một view: không có nền thì nó không được đọc như bước tiếp theo. Dùng solid.
- Đừng dùng iconOnly cho hành động mà chỉ icon thì không rõ. Hiện nhãn.
- Đừng đặt glossy và solid trong cùng một view, hoặc dùng glossy cho hành động secondary. Một button nổi được đọc như cái chính; trộn hai cái trông như hai kiểu, không phải hai cấp.
- Đừng dùng các variant glossy trong UI dày (table, toolbar, form có nhiều hành động). Lớp sáng và đổ bóng dành cho một hành động nổi bật.

## Props

| Tên | Kiểu | Giá trị | Mặc định | Mô tả |
| --- | --- | --- | --- | --- |
| `variant` | `enum` | `solid`, `secondary`, `ghost`, `destructive`, `destructive-soft`, `glossy`, `destructive-glossy` | `solid` | solid: hành động chính, trên accent. secondary: hành động trung tính. ghost: hành động trung tính, không nền hoặc viền cho đến khi hover, cho toolbar, button icon và hành động trong hàng. destructive: hành động phá hủy như Xóa, trên nền red solid với color-text-on-danger (4.53:1). destructive-soft: hành động phá hủy nhẹ hơn trên nền red soft. glossy: hành động chính, dạng nổi: nền accent dưới một lớp sáng chiếu từ trên, với cạnh trong và shadow med. destructive-glossy: cùng vẻ nổi đó trên nền red solid. |
| `size` | `enum` | `sm`, `md`, `lg`, `xl` | `md` | Chiều cao từ size-element-*: sm 28px, md 32px (mặc định), lg 36px, xl 44px khi dùng chuột. Trên cảm ứng md tăng lên 36px, lg lên 44px và xl lên 48px; sm giữ nguyên vẻ và vùng chạm 44px. Dùng lg hoặc xl cho vùng chạm lớn hơn, chẳng hạn hành động chính của màn hình mobile. Chữ là 14px ở sm, 14px ở md và lg, 16px ở xl. |
| `iconOnly` | `boolean` |  | `false` | Button vuông chỉ hiện một icon: rộng bằng cao, không padding nhãn. Bắt buộc aria-label (type bắt buộc điều đó). Truyền icon theo size của button: 16 ở sm, md và lg, 20 ở xl. |
| `disabled` | `boolean` |  | `false` | Không tương tác. Dùng giao diện disabled trung tính cho mọi variant. |
| `asChild` | `boolean` |  | `false` | Render phần tử child (ví dụ một link) với style của button, thay vì một button. |
| `type` | `enum` | `button`, `submit`, `reset` | `button` | Type native của button. |

### Slot

| Tên | Bắt buộc | Mô tả |
| --- | --- | --- |
| `label` | có | Động từ hoặc cụm động từ ngắn, sentence case: Lưu, Xóa dự án. |
| `icon` | không | Icon tùy chọn trước hoặc sau nhãn. |

## Cấu tạo

| Phần | Mô tả |
| --- | --- |
| `root` | Phần tử button, hoặc phần tử child khi asChild được đặt. |
| `icon` | Icon Tabler tùy chọn trước hoặc sau nhãn. 16px ở sm, md và lg, 20px ở xl (DESIGN.md 9.1). Lấy màu theo variant. |
| `hitArea` | ::before trong suốt, căn giữa trên root, không bao giờ nhỏ hơn size-target-min (24px với chuột, 44px trên cảm ứng), nên sm vẫn là vùng chạm 44px. |
| `gloss` | Chỉ glossy và destructive-glossy: một lớp sáng từ lớp highlight ở trên xuống lớp shade ở dưới, vẽ đè lên nền, cộng một cạnh highlight dọc mép trong phía trên và một cạnh shade dọc mép dưới. Do class gloss-on-<solid> của root vẽ, nằm dưới các overlay hover và pressed. |

## Khả năng truy cập

Role: `button`

| Phím | Hành động |
| --- | --- |
| `Tab` | Chuyển focus tới button và hiện focus ring. |
| `Enter, Space` | Kích hoạt button. |

- Mặc định type="button" để không submit form ngoài ý muốn. Truyền type="submit" khi submit form.
- Disabled dùng thuộc tính disabled native, nên button rời thứ tự tab và bỏ qua các cú nhấn.
- Với asChild (ví dụ một link), dùng aria-disabled thay cho disabled. Các style disabled đi theo nó.
- Button chỉ có icon cần một aria-label. Với iconOnly, type bắt buộc nó, nên code không biên dịch nếu thiếu.
- Pressed co button về scale-pressed. Dưới prefers-reduced-motion nó không di chuyển; overlay pressed vẫn hiện.
- Các variant glossy giữ nhãn ở 4.5:1 trở lên trên toàn bộ lớp sáng, lúc nghỉ, khi hover và khi pressed: bộ sinh theme tính các lớp gloss cho việc này và làm build thất bại nếu không đạt.

## Cài đặt

```bash
npx werewolf-ui add button
```

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.
