@openway/ui 1.0.0 → 1.0.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (58) hide show
  1. package/README.md +203 -181
  2. package/dist/chunk-X4LIYOS5.js +3 -0
  3. package/dist/chunk-X4LIYOS5.js.map +1 -0
  4. package/dist/index.cjs +5 -1
  5. package/dist/index.cjs.map +1 -1
  6. package/dist/index.d.cts +2740 -1473
  7. package/dist/index.d.ts +2740 -1473
  8. package/dist/index.js +5 -1
  9. package/dist/index.js.map +1 -1
  10. package/dist/query.cjs +3 -0
  11. package/dist/query.cjs.map +1 -0
  12. package/dist/query.d.cts +431 -0
  13. package/dist/query.d.ts +431 -0
  14. package/dist/query.js +3 -0
  15. package/dist/query.js.map +1 -0
  16. package/dist/useInfiniteScroll-D9AW6cQV.d.cts +598 -0
  17. package/dist/useInfiniteScroll-D9AW6cQV.d.ts +598 -0
  18. package/docs/AGENTS.md +144 -0
  19. package/docs/README.md +150 -0
  20. package/docs/SKILL.md +54 -0
  21. package/docs/components/alert.md +246 -0
  22. package/docs/components/badge.md +238 -0
  23. package/docs/components/button.md +262 -0
  24. package/docs/components/carousel.md +354 -0
  25. package/docs/components/checkbox.md +252 -0
  26. package/docs/components/collapse.md +318 -0
  27. package/docs/components/confirm.md +322 -0
  28. package/docs/components/datepicker.md +259 -0
  29. package/docs/components/daterangepicker.md +260 -0
  30. package/docs/components/datetimepicker.md +226 -0
  31. package/docs/components/datetimerangepicker.md +222 -0
  32. package/docs/components/dropdown.md +275 -0
  33. package/docs/components/empty.md +200 -0
  34. package/docs/components/file-preview.md +180 -0
  35. package/docs/components/input.md +559 -0
  36. package/docs/components/modal.md +293 -0
  37. package/docs/components/popover.md +255 -0
  38. package/docs/components/radio.md +245 -0
  39. package/docs/components/select.md +254 -0
  40. package/docs/components/skeleton.md +150 -0
  41. package/docs/components/slider.md +346 -0
  42. package/docs/components/table.md +316 -0
  43. package/docs/components/tabs.md +432 -0
  44. package/docs/components/textarea.md +193 -0
  45. package/docs/components/timepicker.md +242 -0
  46. package/docs/components/timerangepicker.md +210 -0
  47. package/docs/components/toast.md +282 -0
  48. package/docs/components/toggle.md +211 -0
  49. package/docs/components/tooltip.md +213 -0
  50. package/docs/components/upload-avatar.md +318 -0
  51. package/docs/components/upload-file.md +245 -0
  52. package/docs/components/upload-image.md +126 -0
  53. package/docs/hooks/useDebounce.md +92 -0
  54. package/docs/hooks/useInfiniteScroll.md +95 -0
  55. package/docs/hooks/useMutationApp.md +242 -0
  56. package/docs/hooks/useSelectInfiniteQuery.md +123 -0
  57. package/docs/hooks/useTableQuery.md +124 -0
  58. package/package.json +31 -12
@@ -0,0 +1,259 @@
1
+ # 📅 DatePicker Component Suite (`@owa/ui`)
2
+
3
+ Bộ component **DatePicker** & **Calendar** toàn diện, linh hoạt và tương tác cao, thiết kế chuẩn **Design System**, hỗ trợ **3 Chế độ View (Ngày / Tháng / Năm)**, **Định dạng dữ liệu chuẩn hóa (`format`)**, **Hiển thị trực quan thích ứng (`displayFormat`)**, **Số thứ tự tuần (`showWeekNumbers`)**, và tuân thủ đầy đủ tiêu chuẩn **WAI-ARIA Accessibility**.
4
+
5
+ ---
6
+
7
+ ## 🌟 Điểm nổi bật
8
+
9
+ - **Tách bạch giữa Dữ liệu (`format`) và Hiển thị (`displayFormat`)**:
10
+ - `format` *(mặc định `'DD/MM/YYYY'`)*: Đảm bảo dữ liệu lưu trữ trong State/Form và phát ra qua `onChange` luôn đồng nhất 100% theo chuẩn quy định.
11
+ - `displayFormat` *(tùy chọn)*: Cho phép hiển thị giao diện cho người xem khác với dữ liệu lưu trữ (ví dụ: `format="YYYY-MM-DD"` lưu vào database, nhưng `displayFormat="DD/MM/YYYY"` cho người Việt xem).
12
+ - **3 Chế độ Xem Linh Hoạt (`view` & `viewTabs`)**:
13
+ - `days`: Chọn ngày cụ thể trong tháng.
14
+ - `months`: Chọn tháng trong năm (giao diện tự động thích ứng thành `MM-YYYY` / `MM/YYYY` / `YYYY-MM`).
15
+ - `years`: Chọn năm trong thập kỷ (giao diện tự động thích ứng thành `YYYY`).
16
+ - **Drill-down thông minh**: Bấm vào tiêu đề tháng/năm trên lịch để duyệt nhanh mà không làm thay đổi tab đã chọn.
17
+ - **Standalone `<Calendar>` Component**: Có thể sử dụng độc lập dưới dạng lịch gắn tĩnh trên giao diện.
18
+ - **5 Kích thước tiêu chuẩn (`size`)**: `xs` (24px), `sm` (32px), `md` (40px - *mặc định*), `lg` (48px), `xl` (56px).
19
+ - **3 Biến thể giao diện (`variant`)**: `outline` *(mặc định)*, `filled`, `ghost`.
20
+ - **7 Chủ đề màu sắc (`color`)**: `primary`, `secondary`, `error`, `success`, `warning`, `info`, `neutral`.
21
+ - **6 Mức độ bo góc (`radius`)**: `none`, `sm`, `md`, `lg`, `xl`, `full`.
22
+ - **3 Vị trí đặt nhãn (`labelPlacement`)**: `top` *(mặc định)*, `left`, `floating`.
23
+ - **Hỗ trợ Đa Ngôn Ngữ (`locale`)**: Tích hợp sẵn tiếng Việt (`'vi'`), tiếng Anh (`'en'`), và cho phép tùy biến `LocaleConfig`.
24
+ - **Số thứ tự tuần (`showWeekNumbers`)**: Tự động tính số tuần chuẩn ISO 8601 kèm cột header `#` và nhãn `W1` - `W53`.
25
+ - **Safe Config Fallback**: Tích hợp hàm `getSafeConfig` đảm bảo component hoạt động an toàn, không bị crash kể cả khi truyền prop không hợp lệ.
26
+
27
+ ---
28
+
29
+ ## 🚀 Cài đặt & Import
30
+
31
+ ```tsx
32
+ import { DatePicker, Calendar } from "@owa/ui";
33
+ import type {
34
+ DatePickerProps,
35
+ DatePickerConfig,
36
+ CalendarProps,
37
+ CalendarView,
38
+ DatePickerSize,
39
+ DatePickerVariant,
40
+ DatePickerColor,
41
+ DatePickerRadius,
42
+ LabelPlacement,
43
+ LocaleConfig,
44
+ } from "@owa/ui";
45
+ ```
46
+
47
+ ---
48
+
49
+ ## 📖 Hướng dẫn sử dụng
50
+
51
+ ### 1. Cách sử dụng cơ bản
52
+
53
+ ```tsx
54
+ import { useState } from "react";
55
+ import { DatePicker } from "@owa/ui";
56
+
57
+ export function BasicDatePickerExample() {
58
+ const [date, setDate] = useState<string | null>("25/08/2026");
59
+
60
+ return (
61
+ <DatePicker
62
+ label="Ngày sinh"
63
+ value={date}
64
+ onChange={setDate}
65
+ placeholder="DD/MM/YYYY"
66
+ />
67
+ );
68
+ }
69
+ ```
70
+
71
+ ---
72
+
73
+ ### 2. Định dạng Dữ liệu (`format`) và Hiển thị (`displayFormat`)
74
+
75
+ ```tsx
76
+ // 1. Dùng chung 1 format ISO cho cả dữ liệu và hiển thị
77
+ <DatePicker
78
+ label="Ngày hiệu lực (ISO)"
79
+ format="YYYY-MM-DD"
80
+ defaultValue="2026-08-25"
81
+ />
82
+
83
+ // 2. Dữ liệu chuẩn ISO (gửi API) nhưng hiển thị tiếng Việt (DD/MM/YYYY)
84
+ <DatePicker
85
+ label="Ngày ký hợp đồng"
86
+ format="YYYY-MM-DD" // onChange trả về: "2026-08-25"
87
+ displayFormat="DD/MM/YYYY" // Ô input hiển thị: "25/08/2026"
88
+ defaultValue="2026-08-25"
89
+ />
90
+
91
+ // 3. Định dạng Mỹ (MM/DD/YYYY)
92
+ <DatePicker
93
+ label="US Format"
94
+ format="MM/DD/YYYY"
95
+ defaultValue="08/25/2026"
96
+ />
97
+ ```
98
+
99
+ ---
100
+
101
+ ### 3. Tích hợp View Tabs (Ngày / Tháng / Năm)
102
+
103
+ Bật `config={{ showViewTabs: true }}` để cho phép người dùng chuyển nhanh chế độ chọn:
104
+
105
+ ```tsx
106
+ <DatePicker
107
+ label="Thời gian báo cáo"
108
+ format="YYYY-MM-DD"
109
+ displayFormat="DD-MM-YYYY"
110
+ config={{ showViewTabs: true, isClearable: true }}
111
+ // Khi ở Tab Ngày: Hiển thị "25-08-2026", onChange phát "2026-08-25"
112
+ // Khi ở Tab Tháng: Hiển thị "08-2026", onChange phát "2026-08-01"
113
+ // Khi ở Tab Năm: Hiển thị "2026", onChange phát "2026-01-01"
114
+ />
115
+ ```
116
+
117
+ ---
118
+
119
+ ### 4. Standalone `<Calendar>` (Lịch tĩnh)
120
+
121
+ ```tsx
122
+ import { useState } from "react";
123
+ import { Calendar } from "@owa/ui";
124
+
125
+ export function StandaloneCalendarExample() {
126
+ const [selectedDate, setSelectedDate] = useState<Date>(new Date());
127
+ const [view, setView] = useState<"days" | "months" | "years">("days");
128
+
129
+ return (
130
+ <Calendar
131
+ value={selectedDate}
132
+ onChange={setSelectedDate}
133
+ view={view}
134
+ onViewChange={setView}
135
+ showViewTabs={true}
136
+ showWeekNumbers={true}
137
+ color="primary"
138
+ />
139
+ );
140
+ }
141
+ ```
142
+
143
+ ---
144
+
145
+ ### 5. Vị trí đặt nhãn (`labelPlacement`)
146
+
147
+ ```tsx
148
+ // 1. Top (Phía trên - Mặc định)
149
+ <DatePicker label="Ngày bắt đầu" labelPlacement="top" />
150
+
151
+ // 2. Left (Ngang bên trái)
152
+ <DatePicker label="Ngày bắt đầu" labelPlacement="left" />
153
+
154
+ // 3. Floating (Lơ lửng trên viền)
155
+ <DatePicker label="Ngày bắt đầu" labelPlacement="floating" />
156
+ ```
157
+
158
+ ---
159
+
160
+ ### 6. Trạng thái Form & Loading
161
+
162
+ ```tsx
163
+ // Bắt buộc nhập (Required)
164
+ <DatePicker label="Ngày hẹn" config={{ isRequired: true }} />
165
+
166
+ // Báo lỗi (Invalid)
167
+ <DatePicker
168
+ label="Ngày kết thúc"
169
+ defaultValue="10/08/2026"
170
+ errorMessage="Ngày kết thúc phải lớn hơn ngày bắt đầu."
171
+ config={{ isInvalid: true }}
172
+ />
173
+
174
+ // Đang tải (Loading & Spinner)
175
+ <DatePicker
176
+ label="Đang đồng bộ"
177
+ defaultValue="25/08/2026"
178
+ config={{ isLoading: true, showSpinner: true }}
179
+ />
180
+
181
+ // Vô hiệu hóa (Disabled) hoặc Chỉ đọc (ReadOnly)
182
+ <DatePicker label="Không khả dụng" disabled={true} defaultValue="25/08/2026" />
183
+ <DatePicker label="Chỉ xem" readOnly={true} defaultValue="25/08/2026" />
184
+ ```
185
+
186
+ ---
187
+
188
+ ## 🛠 Bảng thông số Props
189
+
190
+ ### `DatePickerProps`
191
+
192
+ | Tên Prop | Kiểu dữ liệu | Giá trị mặc định | Mô tả |
193
+ | :--- | :--- | :---: | :--- |
194
+ | `value` | `Date \| string \| number` | — | Giá trị ngày đang được chọn (Controlled). |
195
+ | `defaultValue` | `Date \| string \| number` | — | Giá trị ngày mặc định ban đầu (Uncontrolled). |
196
+ | `onChange` | `(date: string \| null) => void` | — | Callback kích hoạt khi thay đổi ngày (trả về chuỗi định dạng theo `format`, hoặc `null` khi xóa). |
197
+ | `format` | `string` | `'DD/MM/YYYY'` | Định dạng dữ liệu chính dùng chung cho cả đầu vào (`value`/`defaultValue`) và đầu ra (`onChange`). |
198
+ | `displayFormat` | `string` | Tự động | Định dạng chuỗi hiển thị trực quan trong ô input cho người xem. |
199
+ | `defaultView` | `'days' \| 'months' \| 'years'` | `'days'` | Chế độ xem mặc định ban đầu. |
200
+ | `view` | `'days' \| 'months' \| 'years'` | — | Chế độ xem đang kích hoạt (Controlled). |
201
+ | `onViewChange` | `(view: CalendarView) => void` | — | Callback khi người dùng chuyển đổi chế độ xem. |
202
+ | `viewTabs` | `CalendarView[]` | `['days', 'months', 'years']` | Danh sách các tab hiển thị trên thanh tab. |
203
+ | `minDate` | `Date \| string` | — | Giới hạn ngày nhỏ nhất cho phép chọn. |
204
+ | `maxDate` | `Date \| string` | — | Giới hạn ngày lớn nhất cho phép chọn. |
205
+ | `isDateDisabled` | `(date: Date) => boolean` | — | Hàm callback kiểm tra ngày cụ thể có bị vô hiệu hóa hay không. |
206
+ | `locale` | `'vi' \| 'en' \| LocaleConfig` | `'en'` | Cấu hình ngôn ngữ cho lịch. |
207
+ | `firstDayOfWeek` | `0 \| 1` | `1` | Ngày bắt đầu tuần: `0` (Chủ Nhật) hoặc `1` (Thứ Hai). |
208
+ | `size` | `'xs' \| 'sm' \| 'md' \| 'lg' \| 'xl'` | `'md'` | Kích cỡ ô nhập liệu và các nút bấm. |
209
+ | `variant` | `'outline' \| 'filled' \| 'ghost'` | `'outline'` | Biến thể giao diện của ô nhập liệu. |
210
+ | `color` | `'primary' \| 'secondary' \| 'error' \| 'success' \| 'warning' \| 'info' \| 'neutral'` | `'primary'` | Chủ đề màu sắc theo Design System. |
211
+ | `radius` | `'none' \| 'sm' \| 'md' \| 'lg' \| 'xl' \| 'full'` | — | Độ bo góc của ô nhập và popover. |
212
+ | `label` | `ReactNode` | — | Nhãn tiêu đề hiển thị cho ô nhập liệu. |
213
+ | `labelPlacement` | `'top' \| 'left' \| 'floating'` | `'top'` | Vị trí hiển thị của nhãn. |
214
+ | `placeholder` | `string` | Tự động | Văn bản giữ chỗ khi ô input rỗng. |
215
+ | `helperText` | `ReactNode` | — | Đoạn văn bản hướng dẫn/trợ giúp bên dưới ô. |
216
+ | `errorMessage` | `ReactNode` | — | Thông báo lỗi (tự động bật trạng thái viền đỏ và hiệu ứng xuất hiện). |
217
+ | `disabled` | `boolean` | `false` | Khóa toàn bộ tương tác của ô nhập liệu. |
218
+ | `readOnly` | `boolean` | `false` | Chỉ cho phép xem, không mở popover lịch. |
219
+ | `placement` | `Placement` | `'bottom-start'` | Vị trí mở popover lịch so với ô input (Floating UI). |
220
+ | `config` | `DatePickerConfig` | — | Nhóm cấu hình tập trung các cờ tính năng (xem bảng dưới). |
221
+ | `ref` | `Ref<HTMLInputElement>` | — | Ref chuyển tiếp đến thẻ `<input>` HTML bên dưới. |
222
+
223
+ ---
224
+
225
+ ### `DatePickerConfig`
226
+
227
+ | Cờ thuộc tính | Kiểu dữ liệu | Giá trị mặc định | Mô tả |
228
+ | :--- | :--- | :---: | :--- |
229
+ | `isRequired` | `boolean` | `false` | Hiển thị dấu sao đỏ `*` và đánh dấu `aria-required="true"`. |
230
+ | `isInvalid` | `boolean` | `false` | Bật trạng thái viền đỏ báo lỗi và `aria-invalid="true"`. |
231
+ | `isLoading` | `boolean` | `false` | Khóa tương tác, bật `aria-busy="true"` và `aria-disabled="true"`. |
232
+ | `showSpinner` | `boolean` | `false` | Hiển thị biểu tượng xoay spinner khi `isLoading={true}`. |
233
+ | `isClearable` | `boolean` | `true` | Hiển thị nút xóa nhanh nội dung khi có ngày được chọn. |
234
+ | `isFullWidth` | `boolean` | `false` | Mở rộng chiếm toàn bộ 100% chiều ngang container cha. |
235
+ | `showWeekNumbers` | `boolean` | `false` | Hiển thị cột số thứ tự tuần trong lịch. |
236
+ | `showViewTabs` | `boolean` | `false` | Hiển thị thanh chuyển Tab Ngày / Tháng / Năm. |
237
+ | `closeOnSelect` | `boolean` | `true` | Tự động đóng popover lịch ngay sau khi chọn ngày. |
238
+
239
+ ---
240
+
241
+ ### `CalendarProps` (Standalone)
242
+
243
+ | Tên Prop | Kiểu dữ liệu | Giá trị mặc định | Mô tả |
244
+ | :--- | :--- | :---: | :--- |
245
+ | `value` | `Date \| null` | — | Đối tượng ngày đang được chọn. |
246
+ | `onChange` | `(date: Date) => void` | — | Callback khi chọn ngày trên lịch. |
247
+ | `view` | `'days' \| 'months' \| 'years'` | `'days'` | Chế độ xem hiện tại của lịch. |
248
+ | `onViewChange` | `(view: CalendarView) => void` | — | Callback khi người dùng chuyển đổi chế độ xem. |
249
+ | `minDate` | `Date \| string` | — | Giới hạn ngày nhỏ nhất cho phép chọn. |
250
+ | `maxDate` | `Date \| string` | — | Giới hạn ngày lớn nhất cho phép chọn. |
251
+ | `isDateDisabled` | `(date: Date) => boolean` | — | Hàm kiểm tra ngày bị disable. |
252
+ | `locale` | `'vi' \| 'en' \| LocaleConfig` | `'vi'` | Cấu hình ngôn ngữ cho lịch. |
253
+ | `firstDayOfWeek` | `0 \| 1` | `1` | Ngày bắt đầu tuần: `0` (Chủ Nhật) hoặc `1` (Thứ Hai). |
254
+ | `showWeekNumbers` | `boolean` | `false` | Hiển thị cột số thứ tự tuần. |
255
+ | `showViewTabs` | `boolean` | `false` | Hiển thị thanh Tab Ngày / Tháng / Năm phía trên lịch. |
256
+ | `viewTabs` | `CalendarView[]` | `['days', 'months', 'years']` | Danh sách các tab hiển thị. |
257
+ | `size` | `DatePickerSize` | `'md'` | Kích cỡ các ô ngày và nút bấm trong lịch. |
258
+ | `color` | `DatePickerColor` | `'primary'` | Chủ đề màu sắc theo Design System. |
259
+ | `radius` | `DatePickerRadius` | `'lg'` | Bo góc khung viền lịch. |
@@ -0,0 +1,260 @@
1
+ # 📆 DateRangePicker Component Suite (`@owa/ui`)
2
+
3
+ Bộ component **DateRangePicker** & **DateRangeCalendar** toàn diện, linh hoạt và tương tác cao, thiết kế chuẩn **Design System**, hỗ trợ **Chọn khoảng ngày trên 2 tháng liên tiếp song song**, **3 Chế độ View (Khoảng Ngày / Tháng / Năm)**, **Định dạng dữ liệu chuẩn hóa (`format`)**, **Hiển thị trực quan thích ứng (`displayFormat`)**, **Số thứ tự tuần (`showWeekNumbers`)**, và tuân thủ đầy đủ tiêu chuẩn **WAI-ARIA Accessibility**.
4
+
5
+ ---
6
+
7
+ ## 🌟 Điểm nổi bật
8
+
9
+ - **Chọn khoảng ngày trực quan (2 Tháng song song)**:
10
+ - Hiển thị cùng lúc 2 tháng liên tiếp cạnh nhau giúp người dùng dễ dàng chọn khoảng thời gian kéo dài qua nhiều tháng.
11
+ - Hỗ trợ hiệu ứng rê chuột xem trước khoảng ngày (Hover Range Preview).
12
+ - **Tách bạch giữa Dữ liệu (`format`) và Hiển thị (`displayFormat`)**:
13
+ - `format` *(mặc định `'DD/MM/YYYY'`)*: Dữ liệu phát ra qua `onChange` là mảng 2 phần tử `[string, string]` luôn tuân thủ 100% theo chuẩn quy định (ví dụ: `["2026-08-01", "2026-08-15"]`).
14
+ - `displayFormat` *(tùy chọn)*: Tùy biến hiển thị trên ô input (ví dụ: `01/08/2026 - 15/08/2026`).
15
+ - **3 Chế độ Xem Linh Hoạt (`view` & `viewTabs`)**:
16
+ - `days`: Chọn khoảng ngày cụ thể.
17
+ - `months`: Chọn khoảng tháng trong năm (hiển thị `MM-YYYY - MM-YYYY` hoặc `MM/YYYY - MM/YYYY`).
18
+ - `years`: Chọn khoảng năm trong thập kỷ (hiển thị `YYYY - YYYY`).
19
+ - **Tùy biến ký tự phân cách (`separator`)**: Mặc định là `' - '`, có thể tùy biến thành `' to '`, `' ~ '`...
20
+ - **Standalone `<DateRangeCalendar>` Component**: Có thể sử dụng độc lập dưới dạng lịch chọn range gắn tĩnh trên giao diện.
21
+ - **5 Kích thước tiêu chuẩn (`size`)**: `xs` (24px), `sm` (32px), `md` (40px - *mặc định*), `lg` (48px), `xl` (56px).
22
+ - **3 Biến thể giao diện (`variant`)**: `outline` *(mặc định)*, `filled`, `ghost`.
23
+ - **7 Chủ đề màu sắc (`color`)**: `primary`, `secondary`, `error`, `success`, `warning`, `info`, `neutral`.
24
+ - **6 Mức độ bo góc (`radius`)**: `none`, `sm`, `md`, `lg`, `xl`, `full`.
25
+ - **3 Vị trí đặt nhãn (`labelPlacement`)**: `top` *(mặc định)*, `left`, `floating`.
26
+ - **Hỗ trợ Đa Ngôn Ngữ (`locale`)**: Tích hợp sẵn tiếng Việt (`'vi'`), tiếng Anh (`'en'`), và cho phép tùy biến `LocaleConfig`.
27
+ - **Số thứ tự tuần (`showWeekNumbers`)**: Tự động tính số tuần chuẩn ISO 8601 kèm cột header `#` và nhãn `W1` - `W53`.
28
+
29
+ ---
30
+
31
+ ## 🚀 Cài đặt & Import
32
+
33
+ ```tsx
34
+ import { DateRangePicker, DateRangeCalendar } from "@owa/ui";
35
+ import type {
36
+ DateRangePickerProps,
37
+ DateRangePickerConfig,
38
+ DateRangeCalendarProps,
39
+ DateRange,
40
+ DateRangeValue,
41
+ DateRangePickerSize,
42
+ DateRangePickerVariant,
43
+ DateRangePickerColor,
44
+ DateRangePickerRadius,
45
+ LabelPlacement,
46
+ LocaleConfig,
47
+ } from "@owa/ui";
48
+ ```
49
+
50
+ ---
51
+
52
+ ## 📖 Hướng dẫn sử dụng
53
+
54
+ ### 1. Cách sử dụng cơ bản
55
+
56
+ ```tsx
57
+ import { useState } from "react";
58
+ import { DateRangePicker } from "@owa/ui";
59
+
60
+ export function BasicDateRangePickerExample() {
61
+ const [range, setRange] = useState<[string, string] | null>(["01/08/2026", "15/08/2026"]);
62
+
63
+ return (
64
+ <DateRangePicker
65
+ label="Khoảng thời gian nghỉ phép"
66
+ value={range}
67
+ onChange={setRange}
68
+ placeholder="DD/MM/YYYY - DD/MM/YYYY"
69
+ />
70
+ );
71
+ }
72
+ ```
73
+
74
+ ---
75
+
76
+ ### 2. Định dạng Dữ liệu (`format`) và Hiển thị (`displayFormat`)
77
+
78
+ ```tsx
79
+ // 1. Dùng chung 1 format ISO cho cả dữ liệu và hiển thị
80
+ <DateRangePicker
81
+ label="Khoảng ngày ISO"
82
+ format="YYYY-MM-DD"
83
+ defaultValue={["2026-08-01", "2026-08-15"]}
84
+ />
85
+
86
+ // 2. Dữ liệu chuẩn ISO (gửi API) nhưng hiển thị tiếng Việt
87
+ <DateRangePicker
88
+ label="Khoảng ngày dự án"
89
+ format="YYYY-MM-DD" // onChange trả về: ["2026-08-01", "2026-08-15"]
90
+ displayFormat="DD/MM/YYYY" // Ô input hiển thị: "01/08/2026 - 15/08/2026"
91
+ defaultValue={["2026-08-01", "2026-08-15"]}
92
+ />
93
+
94
+ // 3. Tùy biến ký tự phân cách (separator)
95
+ <DateRangePicker
96
+ label="Khoảng thời gian"
97
+ separator=" to "
98
+ defaultValue={["01/08/2026", "15/08/2026"]}
99
+ />
100
+ ```
101
+
102
+ ---
103
+
104
+ ### 3. Tích hợp View Tabs (Khoảng Ngày / Tháng / Năm)
105
+
106
+ Bật `config={{ showViewTabs: true }}` để cho phép người dùng chọn khoảng tháng hoặc năm:
107
+
108
+ ```tsx
109
+ <DateRangePicker
110
+ label="Kỳ kế toán / Báo cáo tài chính"
111
+ format="YYYY-MM-DD"
112
+ displayFormat="DD-MM-YYYY"
113
+ config={{ showViewTabs: true, isClearable: true }}
114
+ // Khi ở Tab Ngày: Hiển thị "01-08-2026 - 15-08-2026", onChange phát ["2026-08-01", "2026-08-15"]
115
+ // Khi ở Tab Tháng: Hiển thị "03-2026 - 08-2026", onChange phát ["2026-03-01", "2026-08-01"]
116
+ // Khi ở Tab Năm: Hiển thị "2026 - 2030", onChange phát ["2026-01-01", "2030-01-01"]
117
+ />
118
+ ```
119
+
120
+ ---
121
+
122
+ ### 4. Standalone `<DateRangeCalendar>` (Lịch tĩnh 2 tháng)
123
+
124
+ ```tsx
125
+ import { useState } from "react";
126
+ import { DateRangeCalendar } from "@owa/ui";
127
+
128
+ export function StandaloneDateRangeCalendarExample() {
129
+ const [range, setRange] = useState<[Date | null, Date | null]>([
130
+ new Date(2026, 7, 5),
131
+ new Date(2026, 7, 20),
132
+ ]);
133
+
134
+ return (
135
+ <DateRangeCalendar
136
+ value={range}
137
+ onChange={setRange}
138
+ showWeekNumbers={true}
139
+ color="primary"
140
+ />
141
+ );
142
+ }
143
+ ```
144
+
145
+ ---
146
+
147
+ ### 5. Vị trí đặt nhãn (`labelPlacement`)
148
+
149
+ ```tsx
150
+ // 1. Top (Phía trên - Mặc định)
151
+ <DateRangePicker label="Thời gian thực hiện" labelPlacement="top" />
152
+
153
+ // 2. Left (Ngang bên trái)
154
+ <DateRangePicker label="Thời gian thực hiện" labelPlacement="left" />
155
+
156
+ // 3. Floating (Lơ lửng trên viền)
157
+ <DateRangePicker label="Thời gian thực hiện" labelPlacement="floating" />
158
+ ```
159
+
160
+ ---
161
+
162
+ ### 6. Trạng thái Form & Loading
163
+
164
+ ```tsx
165
+ // Bắt buộc nhập (Required)
166
+ <DateRangePicker label="Thời gian hiệu lực" config={{ isRequired: true }} />
167
+
168
+ // Báo lỗi (Invalid)
169
+ <DateRangePicker
170
+ label="Khoảng ngày"
171
+ errorMessage="Khoảng ngày đã chọn không hợp lệ."
172
+ config={{ isInvalid: true }}
173
+ />
174
+
175
+ // Đang tải (Loading & Spinner)
176
+ <DateRangePicker
177
+ label="Đang tải dữ liệu"
178
+ config={{ isLoading: true, showSpinner: true }}
179
+ />
180
+
181
+ // Vô hiệu hóa (Disabled) hoặc Chỉ đọc (ReadOnly)
182
+ <DateRangePicker label="Không khả dụng" disabled={true} />
183
+ <DateRangePicker label="Chỉ xem" readOnly={true} />
184
+ ```
185
+
186
+ ---
187
+
188
+ ## 🛠 Bảng thông số Props
189
+
190
+ ### `DateRangePickerProps`
191
+
192
+ | Tên Prop | Kiểu dữ liệu | Giá trị mặc định | Mô tả |
193
+ | :--- | :--- | :---: | :--- |
194
+ | `value` | `[DateValue, DateValue]` | — | Mảng khoảng ngày đang được chọn (Controlled). |
195
+ | `defaultValue` | `[DateValue, DateValue]` | — | Mảng khoảng ngày mặc định ban đầu (Uncontrolled). |
196
+ | `onChange` | `(range: [string, string] \| null) => void` | — | Callback kích hoạt khi thay đổi khoảng ngày (trả về mảng 2 chuỗi định dạng theo `format`, hoặc `null` khi xóa). |
197
+ | `separator` | `string` | `' - '` | Chuỗi ký tự phân cách giữa 2 ngày trong ô input. |
198
+ | `format` | `string` | `'DD/MM/YYYY'` | Định dạng dữ liệu chính dùng chung cho cả đầu vào (`value`/`defaultValue`) và đầu ra (`onChange`). |
199
+ | `displayFormat` | `string` | Tự động | Định dạng chuỗi hiển thị trực quan trong ô input cho người xem. |
200
+ | `defaultView` | `'days' \| 'months' \| 'years'` | `'days'` | Chế độ xem mặc định ban đầu. |
201
+ | `view` | `'days' \| 'months' \| 'years'` | — | Chế độ xem đang kích hoạt (Controlled). |
202
+ | `onViewChange` | `(view: CalendarView) => void` | — | Callback khi người dùng chuyển đổi chế độ xem. |
203
+ | `viewTabs` | `CalendarView[]` | `['days', 'months', 'years']` | Danh sách các tab hiển thị trên thanh tab. |
204
+ | `minDate` | `Date \| string` | — | Giới hạn ngày nhỏ nhất cho phép chọn. |
205
+ | `maxDate` | `Date \| string` | — | Giới hạn ngày lớn nhất cho phép chọn. |
206
+ | `isDateDisabled` | `(date: Date) => boolean` | — | Hàm callback kiểm tra ngày cụ thể có bị vô hiệu hóa hay không. |
207
+ | `locale` | `'vi' \| 'en' \| LocaleConfig` | `'en'` | Cấu hình ngôn ngữ cho lịch. |
208
+ | `firstDayOfWeek` | `0 \| 1` | `1` | Ngày bắt đầu tuần: `0` (Chủ Nhật) hoặc `1` (Thứ Hai). |
209
+ | `size` | `'xs' \| 'sm' \| 'md' \| 'lg' \| 'xl'` | `'md'` | Kích cỡ ô nhập liệu và các nút bấm. |
210
+ | `variant` | `'outline' \| 'filled' \| 'ghost'` | `'outline'` | Biến thể giao diện của ô nhập liệu. |
211
+ | `color` | `'primary' \| 'secondary' \| 'error' \| 'success' \| 'warning' \| 'info' \| 'neutral'` | `'primary'` | Chủ đề màu sắc theo Design System. |
212
+ | `radius` | `'none' \| 'sm' \| 'md' \| 'lg' \| 'xl' \| 'full'` | — | Độ bo góc của ô nhập và popover. |
213
+ | `label` | `ReactNode` | — | Nhãn tiêu đề hiển thị cho ô nhập liệu. |
214
+ | `labelPlacement` | `'top' \| 'left' \| 'floating'` | `'top'` | Vị trí hiển thị của nhãn. |
215
+ | `placeholder` | `string` | Tự động | Văn bản giữ chỗ khi ô input rỗng. |
216
+ | `helperText` | `ReactNode` | — | Đoạn văn bản hướng dẫn/trợ giúp bên dưới ô. |
217
+ | `errorMessage` | `ReactNode` | — | Thông báo lỗi (tự động bật trạng thái viền đỏ và hiệu ứng xuất hiện). |
218
+ | `disabled` | `boolean` | `false` | Khóa toàn bộ tương tác của ô nhập liệu. |
219
+ | `readOnly` | `boolean` | `false` | Chỉ cho phép xem, không mở popover lịch. |
220
+ | `placement` | `Placement` | `'bottom-start'` | Vị trí mở popover lịch so với ô input (Floating UI). |
221
+ | `config` | `DateRangePickerConfig` | — | Nhóm cấu hình tập trung các cờ tính năng (xem bảng dưới). |
222
+ | `ref` | `Ref<HTMLInputElement>` | — | Ref chuyển tiếp đến thẻ `<input>` HTML bên dưới. |
223
+
224
+ ---
225
+
226
+ ### `DateRangePickerConfig`
227
+
228
+ | Cờ thuộc tính | Kiểu dữ liệu | Giá trị mặc định | Mô tả |
229
+ | :--- | :--- | :---: | :--- |
230
+ | `isRequired` | `boolean` | `false` | Hiển thị dấu sao đỏ `*` và đánh dấu `aria-required="true"`. |
231
+ | `isInvalid` | `boolean` | `false` | Bật trạng thái viền đỏ báo lỗi và `aria-invalid="true"`. |
232
+ | `isLoading` | `boolean` | `false` | Khóa tương tác, bật `aria-busy="true"` và `aria-disabled="true"`. |
233
+ | `showSpinner` | `boolean` | `false` | Hiển thị biểu tượng xoay spinner khi `isLoading={true}`. |
234
+ | `isClearable` | `boolean` | `true` | Hiển thị nút xóa nhanh khoảng ngày đã chọn. |
235
+ | `isFullWidth` | `boolean` | `false` | Mở rộng chiếm toàn bộ 100% chiều ngang container cha. |
236
+ | `showWeekNumbers` | `boolean` | `false` | Hiển thị cột số thứ tự tuần trong cả 2 bảng lịch. |
237
+ | `showViewTabs` | `boolean` | `false` | Hiển thị thanh chuyển Tab Ngày / Tháng / Năm. |
238
+ | `closeOnSelect` | `boolean` | `true` | Tự động đóng popover lịch ngay sau khi chọn xong ngày kết thúc. |
239
+
240
+ ---
241
+
242
+ ### `DateRangeCalendarProps` (Standalone)
243
+
244
+ | Tên Prop | Kiểu dữ liệu | Giá trị mặc định | Mô tả |
245
+ | :--- | :--- | :---: | :--- |
246
+ | `value` | `[Date \| null, Date \| null]` | — | Mảng 2 đối tượng `[start, end]` đang được chọn. |
247
+ | `onChange` | `(range: [Date \| null, Date \| null]) => void` | — | Callback khi chọn khoảng ngày trên lịch. |
248
+ | `view` | `'days' \| 'months' \| 'years'` | `'days'` | Chế độ xem hiện tại của lịch. |
249
+ | `onViewChange` | `(view: CalendarView) => void` | — | Callback khi người dùng chuyển đổi chế độ xem. |
250
+ | `minDate` | `Date \| string` | — | Giới hạn ngày nhỏ nhất cho phép chọn. |
251
+ | `maxDate` | `Date \| string` | — | Giới hạn ngày lớn nhất cho phép chọn. |
252
+ | `isDateDisabled` | `(date: Date) => boolean` | — | Hàm kiểm tra ngày bị disable. |
253
+ | `locale` | `'vi' \| 'en' \| LocaleConfig` | `'vi'` | Cấu hình ngôn ngữ cho lịch. |
254
+ | `firstDayOfWeek` | `0 \| 1` | `1` | Ngày bắt đầu tuần: `0` (Chủ Nhật) hoặc `1` (Thứ Hai). |
255
+ | `showWeekNumbers` | `boolean` | `false` | Hiển thị cột số thứ tự tuần. |
256
+ | `showViewTabs` | `boolean` | `false` | Hiển thị thanh Tab Ngày / Tháng / Năm phía trên lịch. |
257
+ | `viewTabs` | `CalendarView[]` | `['days', 'months', 'years']` | Danh sách các tab hiển thị. |
258
+ | `size` | `DateRangePickerSize` | `'md'` | Kích cỡ các ô ngày và nút bấm trong lịch. |
259
+ | `color` | `DateRangePickerColor` | `'primary'` | Chủ đề màu sắc theo Design System. |
260
+ | `radius` | `DateRangePickerRadius` | `'lg'` | Bo góc khung viền lịch. |