# DatePicker

Trigger trông như một field, mở Calendar trong popover, để chọn một ngày hoặc một khoảng ngày trong form. Nó nhận cùng các prop value như Calendar.

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

## Cách dùng

### Khi nào dùng

- Chọn một ngày trong form, cạnh các field khác, với cùng vẻ field như Input.
- Giới hạn lựa chọn ở những ngày thật, với các ngày disabled hoặc một ngày sớm nhất và một ngày muộn nhất.

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

- Cả một tháng trên trang khi ngày là mục đích của màn hình. Dùng Calendar.
- Nhập ngày bằng chữ, chẳng hạn ngày sinh mà người dùng nhớ rõ. Dùng Input.

## Biến thể

### mode

single chọn một Date; range chọn ngày đầu và ngày cuối ({ from, to }) rồi đóng khi cả hai đã được chọn.

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

### weekStartsOn

Ngày đầu tuần trong Calendar: 0 Chủ nhật hoặc 1 Thứ hai. Theo locale khi không được đặt.

Giá trị: `0`, `1`. Mặc định: `undefined`.

### captionLayout

Truyền cho Calendar. dropdown là một select tháng và một select năm. dropdown-months và dropdown-years hiện một select và để phần kia là chữ. label là tháng và năm dưới dạng chữ. Với select năm và không có minDate hoặc maxDate, các năm chạy từ 100 năm trước hôm nay đến 100 năm sau.

Giá trị: `label`, `dropdown`, `dropdown-months`, `dropdown-years`. Mặc định: `dropdown`.

## Ví dụ

### Trong form

Trigger có vẻ field, và lưới mở trong popover.

```tsx
<DatePicker placeholder="Khi nào bắt đầu?" />
```

### Ngày đặt chỗ

Một khoảng trên hai tháng. Popover vẫn mở sau ngày nhận phòng và đóng sau ngày trả phòng.

```tsx
<DatePicker mode="range" numberOfMonths={2} placeholder="Nhận phòng đến trả phòng" />
```

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

### Nên

- Dùng DatePicker trong form, cạnh các field Input với cùng size md.
- Đặt tên bằng một Label trỏ tới id của nó, và mô tả bằng aria-describedby, như mọi field.
- Vô hiệu những ngày không bao giờ chọn được, chẳng hạn ngày đã qua hoặc ngày đóng, ngoài minDate và maxDate.

### Không nên

- Đừng dùng nó khi ngày là cả màn hình; đặt một Calendar trên trang.
- Đừng đặt chữ dài trong trigger; nó hiện một ngày đã định dạng hoặc một khoảng.
- Đừng dùng nó cho ngày người dùng nhớ rõ, chẳng hạn ngày sinh; một Input nhanh hơn.

## Props

| Tên | Kiểu | Giá trị | Mặc định | Mô tả |
| --- | --- | --- | --- | --- |
| `mode` | `enum` | `single`, `range` | `single` | single chọn một Date; range chọn ngày đầu và ngày cuối ({ from, to }) rồi đóng khi cả hai đã được chọn. |
| `value` | `Date \| DateRange` |  |  | Date đã chọn, hoặc ở mode range thì khoảng đã chọn ({ from, to }), khi bạn kiểm soát nó. undefined tường minh thì xóa lựa chọn; bỏ value thì dùng trạng thái nội bộ. Ghép với onValueChange. |
| `defaultValue` | `Date \| DateRange` |  |  | Date, hoặc ở mode range thì khoảng, được chọn ở lần render đầu, khi bạn không kiểm soát nó. |
| `onValueChange` | `(value: Date \| DateRange \| undefined) => void` |  |  | Được gọi với Date đã chọn, hoặc undefined khi người dùng bỏ chọn. Ở mode range chỉ với một khoảng đủ, hoặc undefined khi một khoảng một ngày bị xóa. |
| `disabled` | `boolean` |  | `false` | true thì vô hiệu trigger; một hàm nhận một Date và vô hiệu từng ngày trong Calendar, chẳng hạn cuối tuần hoặc ngày đã qua. |
| `minDate` | `string` |  |  | Không ngày nào trước Date này được chọn hoặc được điều hướng tới. |
| `maxDate` | `string` |  |  | Không ngày nào sau Date này được chọn hoặc được điều hướng tới. |
| `locale` | `string` |  |  | Một đối tượng date-fns Locale cho chữ trên trigger và tên tháng, tên ngày trong tuần của Calendar. Mặc định là enUS. |
| `weekStartsOn` | `enum` | `0`, `1` |  | Ngày đầu tuần trong Calendar: 0 Chủ nhật hoặc 1 Thứ hai. Theo locale khi không được đặt. |
| `numberOfMonths` | `number` |  | `1` | Số tháng Calendar hiện, cạnh nhau từ sm và xếp chồng khi dưới sm. Dùng hai cho các khoảng thường sang tháng khác. |
| `captionLayout` | `enum` | `label`, `dropdown`, `dropdown-months`, `dropdown-years` | `dropdown` | Truyền cho Calendar. dropdown là một select tháng và một select năm. dropdown-months và dropdown-years hiện một select và để phần kia là chữ. label là tháng và năm dưới dạng chữ. Với select năm và không có minDate hoặc maxDate, các năm chạy từ 100 năm trước hôm nay đến 100 năm sau. |
| `rangeStartLabel` | `string` |  | `start of range` | Mode range. Được thêm vào tên truy cập của ngày bắt đầu trong Calendar; dịch nó theo locale. |
| `rangeEndLabel` | `string` |  | `end of range` | Mode range. Được thêm vào tên truy cập của ngày kết thúc trong Calendar; dịch nó theo locale. |
| `placeholder` | `string` |  | `Pick a date` | Chữ hiện trong trigger khi chưa chọn ngày. Nó cũng đặt tên dialog khi không có aria-label. |
| `modal` | `boolean` |  | `false` | Popover đang mở có chặn tương tác với phần còn lại của trang hay không. |

## Cấu tạo

| Phần | Mô tả |
| --- | --- |
| `root` | Button trigger: cùng vẻ field như Input md. |
| `icon` | Icon Tabler Calendar trang trí ở đầu, 16px, màu phụ. |
| `label` | Ngày đã chọn, định dạng long; ở mode range thì hai đầu ở định dạng medium, nối bằng en dash (một ngày nếu khoảng chỉ có một ngày); hoặc placeholder bằng chữ phụ. |
| `content` | Popover chứa một Calendar. |

## Khả năng truy cập

Role: `button`

| Phím | Hành động |
| --- | --- |
| `Space, Enter` | Trên trigger, mở popover và focus vào ngày đã chọn, hoặc hôm nay. |
| `Escape` | Đóng popover và trả focus về trigger. Ở mode range, ngày đầu không có ngày cuối thì bị bỏ và value không đổi. |

- Trigger mở một dialog được đặt tên bằng aria-label hoặc placeholder; bên trong, lưới Calendar giữ mô hình bàn phím riêng.
- Một ngày được chọn thì đóng dialog và focus trở về trigger.
- Ở mode range, popover giữ một bản nháp: nó vẫn mở sau ngày đầu và chỉ gửi onValueChange với một khoảng đủ (rồi đóng), hoặc với undefined khi người dùng xóa một khoảng một ngày. Value của form không bao giờ chỉ có ngày đầu. Đóng khi chỉ có ngày đầu thì bỏ ngày đó.
- Trigger nhận id, aria-label và aria-describedby, nên một Label và một gợi ý có thể đặt tên và mô tả nó như mọi field.

## Cài đặt

```bash
npx werewolf-ui add date-picker
```

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.
