# ScrollArea

Vùng cuộn với thanh cuộn native mỏng theo theme, cho panel, menu, danh sách bên và khối code có chiều cao cố định. Cách cuộn native và thanh cuộn native giữ nguyên; chỉ màu và độ rộng được style (scrollbar-width thin, scrollbar-color). Không có thumb vẽ riêng. Chính trang vẫn giữ thanh cuộn của trình duyệt.

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

## Cách dùng

### Khi nào dùng

- Giữ danh sách dài, panel hoặc khối code trong chiều cao cố định hoặc tối đa trong khi trang đứng yên.
- Cho vùng cuộn được một thanh cuộn native mỏng theo theme hiện tại.

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

- Cả trang nên cuộn theo nội dung.
- Danh sách quá dài để lướt và cần tìm. Dùng Combobox.

## Biến thể

### orientation

Trục nào được cuộn.

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

### type

auto hiện thanh cuộn native khi nội dung tràn; always giữ chỗ cho thanh (scrollbar-gutter stable) để nội dung không dịch.

Giá trị: `auto`, `always`. Mặc định: `auto`.

## Ví dụ

### Hoạt động gần đây

```tsx
<ScrollArea className="h-48 w-64 max-w-full rounded-container border border-border" label="Hoạt động gần đây">
  <div>
    <div className="border-b border-border px-md py-md">
      <p className="text-sm font-medium">Dự án 01</p>
      <p className="text-xs text-text-secondary">Đã cập nhật ghi chú không gian làm việc</p>
    </div>
    <div className="border-b border-border px-md py-md">
      <p className="text-sm font-medium">Dự án 02</p>
      <p className="text-xs text-text-secondary">Đã cập nhật ghi chú không gian làm việc</p>
    </div>
    <div className="border-b border-border px-md py-md">
      <p className="text-sm font-medium">Dự án 03</p>
      <p className="text-xs text-text-secondary">Đã cập nhật ghi chú không gian làm việc</p>
    </div>
    <div className="border-b border-border px-md py-md">
      <p className="text-sm font-medium">Dự án 04</p>
      <p className="text-xs text-text-secondary">Đã cập nhật ghi chú không gian làm việc</p>
    </div>
    <div className="border-b border-border px-md py-md">
      <p className="text-sm font-medium">Dự án 05</p>
      <p className="text-xs text-text-secondary">Đã cập nhật ghi chú không gian làm việc</p>
    </div>
    <div className="border-b border-border px-md py-md">
      <p className="text-sm font-medium">Dự án 06</p>
      <p className="text-xs text-text-secondary">Đã cập nhật ghi chú không gian làm việc</p>
    </div>
    <div className="border-b border-border px-md py-md">
      <p className="text-sm font-medium">Dự án 07</p>
      <p className="text-xs text-text-secondary">Đã cập nhật ghi chú không gian làm việc</p>
    </div>
    <div className="border-b border-border px-md py-md">
      <p className="text-sm font-medium">Dự án 08</p>
      <p className="text-xs text-text-secondary">Đã cập nhật ghi chú không gian làm việc</p>
    </div>
  </div>
</ScrollArea>
```

### Dự án theo chiều ngang

```tsx
<ScrollArea orientation="horizontal" className="h-40 w-64 max-w-full rounded-container border border-border" label="Dự án">
  <div className="flex gap-md p-md">
    <Card className="w-40 shrink-0">
      <CardContent>Trang web</CardContent>
    </Card>
    <Card className="w-40 shrink-0">
      <CardContent>Ứng dụng di động</CardContent>
    </Card>
    <Card className="w-40 shrink-0">
      <CardContent>Tài liệu</CardContent>
    </Card>
  </div>
</ScrollArea>
```

### Cả hai trục

```tsx
<ScrollArea orientation="both" className="h-48 w-64 max-w-full rounded-container border border-border" label="Cập nhật dự án">
  <div className="w-160">
    <div className="border-b border-border px-md py-md">
      <p className="text-sm font-medium">Dự án 01</p>
      <p className="text-xs text-text-secondary">Đã cập nhật ghi chú không gian làm việc</p>
    </div>
    <div className="border-b border-border px-md py-md">
      <p className="text-sm font-medium">Dự án 02</p>
      <p className="text-xs text-text-secondary">Đã cập nhật ghi chú không gian làm việc</p>
    </div>
    <div className="border-b border-border px-md py-md">
      <p className="text-sm font-medium">Dự án 03</p>
      <p className="text-xs text-text-secondary">Đã cập nhật ghi chú không gian làm việc</p>
    </div>
    <div className="border-b border-border px-md py-md">
      <p className="text-sm font-medium">Dự án 04</p>
      <p className="text-xs text-text-secondary">Đã cập nhật ghi chú không gian làm việc</p>
    </div>
    <div className="border-b border-border px-md py-md">
      <p className="text-sm font-medium">Dự án 05</p>
      <p className="text-xs text-text-secondary">Đã cập nhật ghi chú không gian làm việc</p>
    </div>
    <div className="border-b border-border px-md py-md">
      <p className="text-sm font-medium">Dự án 06</p>
      <p className="text-xs text-text-secondary">Đã cập nhật ghi chú không gian làm việc</p>
    </div>
    <div className="border-b border-border px-md py-md">
      <p className="text-sm font-medium">Dự án 07</p>
      <p className="text-xs text-text-secondary">Đã cập nhật ghi chú không gian làm việc</p>
    </div>
    <div className="border-b border-border px-md py-md">
      <p className="text-sm font-medium">Dự án 08</p>
      <p className="text-xs text-text-secondary">Đã cập nhật ghi chú không gian làm việc</p>
    </div>
  </div>
</ScrollArea>
```

### Chỗ dành cho thanh cuộn

```tsx
<ScrollArea type="always" className="max-h-48 w-64 max-w-full rounded-container border border-border" label="Tất cả dự án">
  <div>
    <div className="border-b border-border px-md py-md">
      <p className="text-sm font-medium">Dự án 01</p>
      <p className="text-xs text-text-secondary">Đã cập nhật ghi chú không gian làm việc</p>
    </div>
    <div className="border-b border-border px-md py-md">
      <p className="text-sm font-medium">Dự án 02</p>
      <p className="text-xs text-text-secondary">Đã cập nhật ghi chú không gian làm việc</p>
    </div>
    <div className="border-b border-border px-md py-md">
      <p className="text-sm font-medium">Dự án 03</p>
      <p className="text-xs text-text-secondary">Đã cập nhật ghi chú không gian làm việc</p>
    </div>
    <div className="border-b border-border px-md py-md">
      <p className="text-sm font-medium">Dự án 04</p>
      <p className="text-xs text-text-secondary">Đã cập nhật ghi chú không gian làm việc</p>
    </div>
    <div className="border-b border-border px-md py-md">
      <p className="text-sm font-medium">Dự án 05</p>
      <p className="text-xs text-text-secondary">Đã cập nhật ghi chú không gian làm việc</p>
    </div>
    <div className="border-b border-border px-md py-md">
      <p className="text-sm font-medium">Dự án 06</p>
      <p className="text-xs text-text-secondary">Đã cập nhật ghi chú không gian làm việc</p>
    </div>
    <div className="border-b border-border px-md py-md">
      <p className="text-sm font-medium">Dự án 07</p>
      <p className="text-xs text-text-secondary">Đã cập nhật ghi chú không gian làm việc</p>
    </div>
    <div className="border-b border-border px-md py-md">
      <p className="text-sm font-medium">Dự án 08</p>
      <p className="text-xs text-text-secondary">Đã cập nhật ghi chú không gian làm việc</p>
    </div>
  </div>
</ScrollArea>
```

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

### Nên

- Cho root một chiều cao hoặc chiều cao tối đa.
- Dùng trong danh sách DropdownMenu hoặc Combobox chỉ khi chúng cần thanh theo theme; chúng đã cuộn native.
- Đưa đủ nội dung để tràn trục đã chọn. Nội dung ngang cần chiều rộng lớn hơn viewport và không được co.

### Không nên

- Đừng bọc cả trang.
- Đừng giấu thanh cuộn trên nội dung mà người dùng phải biết là cuộn được khi không có tín hiệu khác.

## Props

| Tên | Kiểu | Giá trị | Mặc định | Mô tả |
| --- | --- | --- | --- | --- |
| `orientation` | `enum` | `vertical`, `horizontal`, `both` | `vertical` | Trục nào được cuộn. |
| `type` | `enum` | `auto`, `always` | `auto` | auto hiện thanh cuộn native khi nội dung tràn; always giữ chỗ cho thanh (scrollbar-gutter stable) để nội dung không dịch. |
| `label` | `string` |  |  | Tên accessible của vùng khi viewport focus được. |
| `tabIndex` | `number` |  |  | Trên viewport: ghi đè thứ tự Tab tự động. Mặc định viewport chỉ nhận focus khi không có con nào nhìn thấy, enabled và focus được. |
| `onScroll` | `React.UIEventHandler<HTMLDivElement>` |  |  | Trên viewport: handler của sự kiện scroll native. |
| `style` | `React.CSSProperties` |  |  | Trên viewport: style inline cho phần tử cuộn native. Đặt kích thước bên ngoài bằng className. |
| `className` | `string` |  |  | Trên hộp ngoài: đưa chiều cao, chiều cao tối đa, chiều rộng, viền và bo góc. Viewport lấp đầy hộp này. |

### Slot

| Tên | Bắt buộc | Mô tả |
| --- | --- | --- |
| `children` | có | Nội dung được cuộn. |

## Cấu tạo

| Phần | Mô tả |
| --- | --- |
| `root` | Hộp ngoài với chiều cao cố định hoặc chiều cao tối đa. |
| `viewport` | Phần tử cuộn với overflow auto và thanh cuộn native đã được style. |

## Khả năng truy cập

Role: `region`

| Phím | Hành động |
| --- | --- |
| `Tab` | Đưa focus tới viewport khi viewport không có con focus được, để người dùng bàn phím cuộn được. |
| `Arrow keys / PageUp / PageDown / Home / End` | Cuộn native trên các trục đang bật của viewport đang focus. |

- Cách cuộn native giữ nguyên: lăn chuột, cảm ứng, quán tính và tìm trong trang vẫn chạy.
- Truyền aria-label khi viewport focus được để vùng có tên.
- Khi reduced motion thì không thêm cuộn mượt.
- Thanh cuộn là của trình duyệt, nên giữ hành vi nền tảng (thanh cuộn overlay trên cảm ứng, kéo, nhấn vào track).

## Cài đặt

```bash
npx werewolf-ui add scroll-area
```

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.
