# ResizablePanels

Các panel cạnh nhau hoặc chồng lên nhau, với một đường kẻ giữa hai panel mà người dùng kéo hoặc di chuyển bằng phím mũi tên để cho một panel thêm chỗ, như một danh sách cạnh phần chi tiết hoặc một truy vấn phía trên kết quả. Kích thước là phần trăm của nhóm.

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

## Cách dùng

### Khi nào dùng

- Cho người dùng thêm chỗ cho một trong hai hoặc ba panel, như một danh sách cạnh phần chi tiết.
- Chia một trình soạn thảo và kết quả của nó, hoặc một bảng và phần xem trước, theo kích thước người dùng chọn.

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

- Cột điều hướng chính của ứng dụng. Dùng Sidebar.
- Nội dung tràn ra khỏi một khung. Dùng ScrollArea.
- Chuyển giữa các view ở cùng một chỗ. Dùng Tabs.

## Biến thể

### orientation

Đặt trên ResizablePanelGroup. horizontal đặt các panel cạnh nhau, vertical xếp chúng chồng lên nhau.

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

## Ví dụ

### Danh sách và chi tiết

```tsx
<ResizablePanelGroup className="h-64 w-full rounded-container border border-border">
  <ResizablePanel defaultSize={35} minSize={20} className="p-md">
    <p className="text-sm text-text-secondary">Hộp thư đến</p>
  </ResizablePanel>
  <ResizableHandle label="Đổi kích thước hộp thư" />
  <ResizablePanel className="p-md">
    <p className="text-sm text-text-secondary">Tin nhắn</p>
  </ResizablePanel>
</ResizablePanelGroup>
```

### Xếp chồng, có tay nắm

Nhóm dọc đặt các panel chồng lên nhau; tay nắm cho thấy chỗ cần nắm.

```tsx
<ResizablePanelGroup orientation="vertical" className="h-72 w-full rounded-container border border-border">
  <ResizablePanel defaultSize={60} className="p-md">
    <p className="text-sm text-text-secondary">Truy vấn</p>
  </ResizablePanel>
  <ResizableHandle label="Đổi kích thước phần kết quả" withHandle />
  <ResizablePanel className="p-md">
    <p className="text-sm text-text-secondary">Kết quả</p>
  </ResizablePanel>
</ResizablePanelGroup>
```

### Ba panel

```tsx
<ResizablePanelGroup className="h-64 w-full rounded-container border border-border">
  <ResizablePanel defaultSize={25} minSize={15} className="p-md">
    <p className="text-sm text-text-secondary">Thư mục</p>
  </ResizablePanel>
  <ResizableHandle label="Đổi kích thước thư mục" />
  <ResizablePanel className="p-md">
    <p className="text-sm text-text-secondary">Tệp</p>
  </ResizablePanel>
  <ResizableHandle label="Đổi kích thước danh sách tệp" />
  <ResizablePanel defaultSize={30} minSize={20} className="p-md">
    <p className="text-sm text-text-secondary">Xem trước</p>
  </ResizablePanel>
</ResizablePanelGroup>
```

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

### Nên

- Đặt minSize để không panel nào nhỏ hơn mức nội dung cần.
- Lưu bố cục từ onLayout và truyền lại làm defaultSize ở lần ghé sau.
- Dưới md, xếp nội dung chồng lên nhau hoặc hiện từng panel một.

### Không nên

- Đừng dùng cho cột điều hướng chính của ứng dụng. Dùng Sidebar, có thể thu gọn.
- Đừng đặt quá ba panel trong một nhóm.
- Đừng đặt handle ở đầu hoặc cuối; handle nằm giữa hai panel.

## Props

| Tên | Kiểu | Giá trị | Mặc định | Mô tả |
| --- | --- | --- | --- | --- |
| `orientation` | `enum` | `horizontal`, `vertical` | `horizontal` | Đặt trên ResizablePanelGroup. horizontal đặt các panel cạnh nhau, vertical xếp chúng chồng lên nhau. |
| `onLayout` | `(sizes: number[]) => void` |  |  | Đặt trên ResizablePanelGroup. Được gọi với kích thước của mọi panel theo phần trăm sau khi kéo hoặc nhấn phím, để lưu bố cục. |
| `keyboardStep` | `number` |  | `5` | Đặt trên ResizablePanelGroup. Số phần trăm một handle di chuyển với mỗi lần nhấn phím mũi tên. |
| `defaultSize` | `number` |  |  | Đặt trên ResizablePanel. Kích thước ban đầu theo phần trăm. Các panel không có nó chia phần còn lại. |
| `minSize` | `number` |  | `10` | Đặt trên ResizablePanel. Kích thước nhỏ nhất theo phần trăm. |
| `maxSize` | `number` |  | `90` | Đặt trên ResizablePanel. Kích thước lớn nhất theo phần trăm. |
| `label` (bắt buộc) | `string` |  |  | Đặt trên ResizableHandle. Tên của handle, như Đổi kích thước hộp thư. |
| `withHandle` | `boolean` |  | `false` | Đặt trên ResizableHandle. Hiện một ô tay nắm nhỏ trên đường kẻ, cho handle khó tìm. |

### Slot

| Tên | Bắt buộc | Mô tả |
| --- | --- | --- |
| `panels` | không | Children của ResizablePanelGroup: ResizablePanel và ResizableHandle, một handle giữa mỗi hai panel, là children trực tiếp. |

## Cấu tạo

| Phần | Mô tả |
| --- | --- |
| `root` | Nhóm: một hàng hoặc cột flex lấp đầy phần chứa nó. Cho nó chiều cao khi nằm ngang. |
| `panel` | Một panel. Giãn theo phần của nó và tự cuộn khi nội dung lớn hơn. |
| `handle` | Đường kẻ 1px giữa hai panel, focus được và kéo được. |
| `hitArea` | ::before trong suốt ngang qua đường kẻ, rộng size-target-min. |
| `grip` | Ô nhỏ tùy chọn trên đường kẻ cho thấy chỗ cần nắm. |
| `icon` | Icon tay nắm trong ô, 16px. |

## Khả năng truy cập

Role: `separator`

| Phím | Hành động |
| --- | --- |
| `Tab` | Chuyển focus tới handle tiếp theo. |
| `ArrowLeft / ArrowRight` | Trong nhóm nằm ngang, làm panel trước handle nhỏ hơn hoặc lớn hơn keyboardStep phần trăm. |
| `ArrowUp / ArrowDown` | Trong nhóm dọc, làm panel phía trên handle nhỏ hơn hoặc lớn hơn keyboardStep phần trăm. |
| `Home / End` | Làm panel trước handle nhỏ nhất hoặc lớn nhất mà giới hạn cho phép. |

- Mỗi handle là một separator focus được, đặt tên bằng label, như EN `Resize sidebar`. Nó điều khiển panel trước nó (aria-controls).
- aria-valuenow là kích thước của panel trước handle theo phần trăm; aria-valuemin và aria-valuemax là giới hạn của nó, có tính cả giới hạn của panel kế tiếp.
- Nhóm nằm ngang có separator dọc (aria-orientation="vertical") và ngược lại.
- Trên trang phải sang trái, phím mũi tên và thao tác kéo theo hướng đọc.
- Đường kẻ 1px có vùng chạm rộng size-target-min, nên dễ nắm bằng ngón tay.

## Cài đặt

```bash
npx werewolf-ui add resizable-panels
```

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.
