@bug-on/m3-expressive 1.0.0

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 (98) hide show
  1. package/CHANGELOG.md +110 -0
  2. package/README.md +110 -0
  3. package/dist/assets/fonts/GoogleSansFlex-VariableFont.woff2 +0 -0
  4. package/dist/assets/fonts/MaterialSymbolsOutlined-VariableFont_FILL,GRAD,opsz,wght.ttf +0 -0
  5. package/dist/assets/fonts/MaterialSymbolsRounded-VariableFont_FILL,GRAD,opsz,wght.ttf +0 -0
  6. package/dist/assets/fonts/MaterialSymbolsSharp-VariableFont_FILL,GRAD,opsz,wght.ttf +0 -0
  7. package/dist/assets/loading-indicator.svg +19 -0
  8. package/dist/assets/material-symbols-cdn.css +65 -0
  9. package/dist/assets/material-symbols-self-hosted.css +94 -0
  10. package/dist/buttons.d.mts +180 -0
  11. package/dist/buttons.d.ts +180 -0
  12. package/dist/buttons.js +4282 -0
  13. package/dist/buttons.js.map +1 -0
  14. package/dist/buttons.mjs +4227 -0
  15. package/dist/buttons.mjs.map +1 -0
  16. package/dist/core.d.mts +422 -0
  17. package/dist/core.d.ts +422 -0
  18. package/dist/core.js +2581 -0
  19. package/dist/core.js.map +1 -0
  20. package/dist/core.mjs +2547 -0
  21. package/dist/core.mjs.map +1 -0
  22. package/dist/feedback.d.mts +600 -0
  23. package/dist/feedback.d.ts +600 -0
  24. package/dist/feedback.js +2357 -0
  25. package/dist/feedback.js.map +1 -0
  26. package/dist/feedback.mjs +2321 -0
  27. package/dist/feedback.mjs.map +1 -0
  28. package/dist/forms.d.mts +40 -0
  29. package/dist/forms.d.ts +40 -0
  30. package/dist/forms.js +4263 -0
  31. package/dist/forms.js.map +1 -0
  32. package/dist/forms.mjs +4228 -0
  33. package/dist/forms.mjs.map +1 -0
  34. package/dist/icon-button-D-gs0gfj.d.mts +136 -0
  35. package/dist/icon-button-D-gs0gfj.d.ts +136 -0
  36. package/dist/index.css +309 -0
  37. package/dist/index.css.d.ts +2 -0
  38. package/dist/index.d.mts +24 -0
  39. package/dist/index.d.ts +24 -0
  40. package/dist/index.js +23972 -0
  41. package/dist/index.js.map +1 -0
  42. package/dist/index.mjs +23668 -0
  43. package/dist/index.mjs.map +1 -0
  44. package/dist/layout.d.mts +610 -0
  45. package/dist/layout.d.ts +610 -0
  46. package/dist/layout.js +5091 -0
  47. package/dist/layout.js.map +1 -0
  48. package/dist/layout.mjs +5042 -0
  49. package/dist/layout.mjs.map +1 -0
  50. package/dist/material-symbols-cdn.css +65 -0
  51. package/dist/material-symbols-cdn.css.d.ts +2 -0
  52. package/dist/material-symbols-self-hosted.css +94 -0
  53. package/dist/material-symbols-self-hosted.css.d.ts +2 -0
  54. package/dist/md3-DFhj-NZj.d.mts +17 -0
  55. package/dist/md3-DFhj-NZj.d.ts +17 -0
  56. package/dist/navigation.d.mts +2766 -0
  57. package/dist/navigation.d.ts +2766 -0
  58. package/dist/navigation.js +6684 -0
  59. package/dist/navigation.js.map +1 -0
  60. package/dist/navigation.mjs +6573 -0
  61. package/dist/navigation.mjs.map +1 -0
  62. package/dist/overlays.d.mts +161 -0
  63. package/dist/overlays.d.ts +161 -0
  64. package/dist/overlays.js +3298 -0
  65. package/dist/overlays.js.map +1 -0
  66. package/dist/overlays.mjs +3244 -0
  67. package/dist/overlays.mjs.map +1 -0
  68. package/dist/pickers.d.mts +1074 -0
  69. package/dist/pickers.d.ts +1074 -0
  70. package/dist/pickers.js +4240 -0
  71. package/dist/pickers.js.map +1 -0
  72. package/dist/pickers.mjs +4200 -0
  73. package/dist/pickers.mjs.map +1 -0
  74. package/dist/plugin.d.mts +1 -0
  75. package/dist/plugin.d.ts +1 -0
  76. package/dist/plugin.js +13 -0
  77. package/dist/plugin.js.map +1 -0
  78. package/dist/plugin.mjs +3 -0
  79. package/dist/plugin.mjs.map +1 -0
  80. package/dist/scroll-area-CVS6HyLl.d.mts +33 -0
  81. package/dist/scroll-area-CVS6HyLl.d.ts +33 -0
  82. package/dist/shapes.d.mts +1119 -0
  83. package/dist/shapes.d.ts +1119 -0
  84. package/dist/shapes.js +2941 -0
  85. package/dist/shapes.js.map +1 -0
  86. package/dist/shapes.mjs +2889 -0
  87. package/dist/shapes.mjs.map +1 -0
  88. package/dist/side-sheet-modal-BY6VCC8p.d.mts +553 -0
  89. package/dist/side-sheet-modal-CglP6KYA.d.ts +553 -0
  90. package/dist/split-button-trailing-uncheckable-C5CLCIKP.d.ts +731 -0
  91. package/dist/split-button-trailing-uncheckable-MXj_kyNt.d.mts +731 -0
  92. package/dist/text-field-eAIpz9z1.d.mts +1038 -0
  93. package/dist/text-field-eAIpz9z1.d.ts +1038 -0
  94. package/dist/typography-339RV6v7.d.mts +486 -0
  95. package/dist/typography-339RV6v7.d.ts +486 -0
  96. package/dist/typography.css +22 -0
  97. package/dist/typography.css.d.ts +2 -0
  98. package/package.json +207 -0
@@ -0,0 +1,1074 @@
1
+ import * as React from 'react';
2
+
3
+ /**
4
+ * @file date-time-pickers/shared/types.ts
5
+ *
6
+ * Shared TypeScript base types cho hệ thống Date Pickers và Time Pickers (tương lai).
7
+ * Được thiết kế để reuse across cả hai picker systems.
8
+ *
9
+ * @see https://m3.material.io/components/date-pickers/overview
10
+ */
11
+ /**
12
+ * Chế độ hiển thị của picker.
13
+ * - `picker` — calendar/dial UI (mặc định)
14
+ * - `input` — text input mode để nhập thủ công
15
+ *
16
+ * Tương đương `DisplayMode` enum trong Android Compose Material3.
17
+ */
18
+ type DisplayMode = "picker" | "input";
19
+ /**
20
+ * Ngày bắt đầu tuần.
21
+ * - `0` = Sunday (US standard)
22
+ * - `1` = Monday (ISO 8601, mặc định của thư viện này)
23
+ */
24
+ type WeekStartsOn = 0 | 1;
25
+ /**
26
+ * Cấu hình locale cho Date Picker.
27
+ * Dùng `Intl.DateTimeFormat` native API — zero bundle overhead.
28
+ *
29
+ * @example
30
+ * ```tsx
31
+ * const state = useDatePickerState({
32
+ * locale: { locale: 'vi-VN', weekStartsOn: 1 }
33
+ * });
34
+ * ```
35
+ */
36
+ interface DateLocale {
37
+ /**
38
+ * BCP 47 language tag.
39
+ * @example 'en-US', 'vi-VN', 'ja-JP'
40
+ * @default navigator.language (runtime)
41
+ */
42
+ locale?: string;
43
+ /**
44
+ * Ngày bắt đầu tuần.
45
+ * @default 1 (Monday)
46
+ */
47
+ weekStartsOn?: WeekStartsOn;
48
+ }
49
+ /** Required version — tất cả fields đã được resolved */
50
+ type ResolvedDateLocale = Required<DateLocale>;
51
+ /**
52
+ * Interface để filter các ngày/năm không thể chọn.
53
+ * Tương đương `SelectableDates` interface trong Android Compose Material3.
54
+ *
55
+ * @example
56
+ * ```tsx
57
+ * // Chặn ngày cuối tuần
58
+ * const selectableDates: SelectableDates = {
59
+ * isSelectableDate(utcMs) {
60
+ * const day = new Date(utcMs).getUTCDay();
61
+ * return day !== 0 && day !== 6;
62
+ * },
63
+ * isSelectableYear(year) {
64
+ * return year >= 2020;
65
+ * }
66
+ * };
67
+ * ```
68
+ */
69
+ interface SelectableDates {
70
+ /**
71
+ * Kiểm tra ngày có thể chọn không.
72
+ * @param utcTimeMs - UTC milliseconds (đã normalize về UTC midnight)
73
+ * @returns `true` nếu ngày có thể chọn
74
+ */
75
+ isSelectableDate(utcTimeMs: number): boolean;
76
+ /**
77
+ * Kiểm tra năm có thể chọn không.
78
+ * Năm không thể chọn sẽ bị disabled trong year grid.
79
+ * @param year - Full year (e.g., 2025)
80
+ * @returns `true` nếu năm có thể chọn
81
+ */
82
+ isSelectableYear(year: number): boolean;
83
+ }
84
+ /**
85
+ * Khoảng ngày với start và end.
86
+ * Cả hai đều có thể null trong quá trình selection.
87
+ */
88
+ interface DateRange {
89
+ /** UTC milliseconds của ngày bắt đầu (UTC midnight). Null nếu chưa chọn. */
90
+ start: number | null;
91
+ /** UTC milliseconds của ngày kết thúc (UTC midnight). Null nếu chưa chọn. */
92
+ end: number | null;
93
+ }
94
+
95
+ /**
96
+ * @file date-picker/date-picker.types.ts
97
+ *
98
+ * TypeScript interfaces và types cho Date Picker component system.
99
+ * Tương đương với DatePickerState + rememberDatePickerState trong Android Compose.
100
+ *
101
+ * @see https://m3.material.io/components/date-pickers/overview
102
+ */
103
+
104
+ /**
105
+ * State object cho DatePicker — hoisted state pattern.
106
+ * Tương đương `DatePickerState` class trong Android Compose Material3.
107
+ *
108
+ * @example
109
+ * ```tsx
110
+ * const state = useDatePickerState({ locale: { locale: 'vi-VN' } });
111
+ *
112
+ * <DatePicker state={state} />
113
+ * <p>Selected: {state.selectedDateMs}</p>
114
+ * ```
115
+ */
116
+ interface DatePickerState {
117
+ /** UTC ms của ngày đang được chọn. Null nếu chưa chọn. */
118
+ readonly selectedDateMs: number | null;
119
+ /** UTC ms của ngày 1 của tháng đang hiển thị trong calendar. */
120
+ readonly displayedMonthMs: number;
121
+ /** Chế độ hiển thị hiện tại: 'picker' | 'input' */
122
+ readonly displayMode: DisplayMode;
123
+ /** Khoảng năm có thể chọn [min, max] */
124
+ readonly yearRange: [number, number];
125
+ /** Locale đã được resolve (với default values) */
126
+ readonly locale: ResolvedDateLocale;
127
+ /** SelectableDates config */
128
+ readonly selectableDates: SelectableDates;
129
+ /** Chọn một ngày theo UTC ms. Truyền null để bỏ chọn. */
130
+ selectDate(ms: number | null): void;
131
+ /** Navigate tháng trước hoặc sau */
132
+ navigateMonth(direction: "prev" | "next"): void;
133
+ /** Navigate đến tháng+năm cụ thể */
134
+ navigateToMonth(year: number, month: number): void;
135
+ /** Chuyển đổi giữa 'picker' và 'input' mode */
136
+ setDisplayMode(mode: DisplayMode): void;
137
+ /** Reset về trạng thái ban đầu */
138
+ reset(): void;
139
+ }
140
+ /**
141
+ * Options cho `useDatePickerState` hook.
142
+ * Tương đương parameters của `rememberDatePickerState()` trong Compose.
143
+ */
144
+ interface UseDatePickerStateOptions {
145
+ /**
146
+ * Ngày được chọn ban đầu (UTC ms hoặc null).
147
+ * @default null
148
+ */
149
+ initialSelectedDateMs?: number | null;
150
+ /**
151
+ * Tháng hiển thị ban đầu (UTC ms của bất kỳ ngày nào trong tháng đó).
152
+ * @default tháng hiện tại
153
+ */
154
+ initialDisplayedMonthMs?: number;
155
+ /**
156
+ * Khoảng năm có thể chọn [min, max].
157
+ * @default [1900, 2100]
158
+ */
159
+ yearRange?: [number, number];
160
+ /**
161
+ * Filter ngày/năm không thể chọn.
162
+ * @default ALL_DATES_SELECTABLE
163
+ */
164
+ selectableDates?: SelectableDates;
165
+ /**
166
+ * Chế độ hiển thị ban đầu.
167
+ * @default 'picker'
168
+ */
169
+ initialDisplayMode?: DisplayMode;
170
+ /**
171
+ * Locale configuration cho calendar.
172
+ * @default { weekStartsOn: 1 } (Monday)
173
+ */
174
+ locale?: DateLocale;
175
+ }
176
+ /**
177
+ * State object cho DateRangePicker — hoisted state pattern.
178
+ * Tương đương `DateRangePickerState` class trong Android Compose Material3.
179
+ */
180
+ interface DateRangePickerState {
181
+ /** UTC ms của ngày bắt đầu. Null nếu chưa chọn. */
182
+ readonly selectedStartMs: number | null;
183
+ /** UTC ms của ngày kết thúc. Null nếu chưa chọn. */
184
+ readonly selectedEndMs: number | null;
185
+ /** UTC ms của ngày 1 của tháng đang hiển thị. */
186
+ readonly displayedMonthMs: number;
187
+ /** Chế độ hiển thị: 'picker' | 'input' */
188
+ readonly displayMode: DisplayMode;
189
+ /** Khoảng năm có thể chọn */
190
+ readonly yearRange: [number, number];
191
+ /** Locale đã được resolve */
192
+ readonly locale: ResolvedDateLocale;
193
+ /** SelectableDates config */
194
+ readonly selectableDates: SelectableDates;
195
+ /**
196
+ * Chọn một ngày.
197
+ * Logic: click 1 = set start, click 2 = set end (nếu ms > start).
198
+ * Nếu ms <= start hoặc đã có cả start lẫn end, reset về start mới.
199
+ */
200
+ selectDate(ms: number): void;
201
+ /** Xóa toàn bộ selection */
202
+ clearRange(): void;
203
+ /** Navigate tháng */
204
+ navigateMonth(direction: "prev" | "next"): void;
205
+ /** Navigate đến tháng+năm cụ thể */
206
+ navigateToMonth(year: number, month: number): void;
207
+ /** Chuyển display mode */
208
+ setDisplayMode(mode: DisplayMode): void;
209
+ /** Reset */
210
+ reset(): void;
211
+ }
212
+ /** Options cho `useDateRangePickerState` */
213
+ interface UseDateRangePickerStateOptions {
214
+ /** Start date ban đầu (UTC ms) */
215
+ initialStartMs?: number | null;
216
+ /** End date ban đầu (UTC ms) */
217
+ initialEndMs?: number | null;
218
+ /** Tháng hiển thị ban đầu */
219
+ initialDisplayedMonthMs?: number;
220
+ /** Khoảng năm @default [1900, 2100] */
221
+ yearRange?: [number, number];
222
+ /** Filter ngày không thể chọn */
223
+ selectableDates?: SelectableDates;
224
+ /** Display mode ban đầu @default 'picker' */
225
+ initialDisplayMode?: DisplayMode;
226
+ /** Locale config */
227
+ locale?: DateLocale;
228
+ }
229
+ /** Props cho `DatePicker` component */
230
+ interface DatePickerProps {
231
+ /** Hoisted state từ `useDatePickerState()` */
232
+ state: DatePickerState;
233
+ /**
234
+ * Hiện nút toggle giữa picker và input mode.
235
+ * @default true
236
+ */
237
+ showModeToggle?: boolean;
238
+ /**
239
+ * Title slot — hiển thị ở phía trên header.
240
+ * @default "Select date"
241
+ */
242
+ title?: React.ReactNode;
243
+ /**
244
+ * Headline slot — hiển thị ngày đang chọn.
245
+ * @default formatted selected date hoặc "--"
246
+ */
247
+ headline?: React.ReactNode;
248
+ /** CSS class bổ sung cho container */
249
+ className?: string;
250
+ }
251
+ /** Props cho `DateRangePicker` component */
252
+ interface DateRangePickerProps {
253
+ /** Hoisted state từ `useDateRangePickerState()` */
254
+ state: DateRangePickerState;
255
+ /**
256
+ * Hiện nút toggle picker/input.
257
+ * @default false (range picker thường không dùng input mode)
258
+ */
259
+ showModeToggle?: boolean;
260
+ /**
261
+ * Title slot.
262
+ * @default "Select dates"
263
+ */
264
+ title?: React.ReactNode;
265
+ /** CSS class bổ sung */
266
+ className?: string;
267
+ }
268
+ /** Props cho `DatePickerDialog` component */
269
+ interface DatePickerDialogProps {
270
+ /** Trạng thái mở/đóng dialog */
271
+ open: boolean;
272
+ /** Callback khi dialog cần đóng (click scrim, Escape) */
273
+ onDismiss: () => void;
274
+ /** Title cho dialog (dùng cho screen reader và accessibility) */
275
+ title?: string;
276
+ /**
277
+ * Nút xác nhận — caller tự render (ví dụ: Button "OK").
278
+ * Dialog không set up event handlers — caller tự xử lý.
279
+ */
280
+ confirmButton: React.ReactNode;
281
+ /**
282
+ * Nút hủy — optional.
283
+ * @default null
284
+ */
285
+ dismissButton?: React.ReactNode;
286
+ /** Content — thường là `DatePicker` hoặc `DateRangePicker` */
287
+ children: React.ReactNode;
288
+ /** CSS class bổ sung cho dialog panel */
289
+ className?: string;
290
+ }
291
+ /** Props cho `DatePickerInput` component */
292
+ interface DatePickerInputProps {
293
+ /**
294
+ * Giá trị text hiện tại (format: "MM/DD/YYYY").
295
+ */
296
+ value: string;
297
+ /** Callback khi user thay đổi text */
298
+ onChange(value: string): void;
299
+ /**
300
+ * Callback khi user confirm ngày (blur hoặc Enter).
301
+ * Truyền parsed UTC ms, hoặc null nếu input không hợp lệ.
302
+ */
303
+ onCommit(ms: number | null): void;
304
+ /** Label cho text field */
305
+ label?: string;
306
+ /** Error message (hiện khi format không hợp lệ) */
307
+ error?: string;
308
+ /** Locale string để hint format phù hợp */
309
+ locale?: string;
310
+ /** CSS class bổ sung */
311
+ className?: string;
312
+ }
313
+
314
+ /**
315
+ * @file date-picker/date-picker.tsx
316
+ *
317
+ * DatePicker — calendar UI component (không bao gồm dialog wrapper).
318
+ * Tương đương composable `DatePicker` trong Android Compose Material3.
319
+ *
320
+ * Layout:
321
+ * CalendarHeader (title, headline, month nav)
322
+ * ↓
323
+ * CalendarGrid | YearPickerGrid (AnimatePresence toggle)
324
+ * ↓
325
+ * DatePickerInput (khi displayMode === 'input')
326
+ *
327
+ * @see https://m3.material.io/components/date-pickers/overview
328
+ */
329
+
330
+ /**
331
+ * DatePicker calendar UI.
332
+ *
333
+ * @example
334
+ * ```tsx
335
+ * const state = useDatePickerState({ locale: { locale: 'vi-VN' } });
336
+ *
337
+ * <DatePicker
338
+ * state={state}
339
+ * showModeToggle
340
+ * title="Chọn ngày"
341
+ * />
342
+ * ```
343
+ */
344
+ declare const DatePicker: React.FC<DatePickerProps>;
345
+
346
+ /**
347
+ * @file date-picker/date-picker.tokens.ts
348
+ *
349
+ * MD3 Design tokens cho Date Picker component.
350
+ * Map từ DatePickerModalTokens.kt → CSS variables trong packages/tailwind/src/index.css.
351
+ *
352
+ * @see docs/m3/date-and-time-pickers/date-pickers/DatePickerModalTokens.kt
353
+ * @see packages/tailwind/src/index.css
354
+ */
355
+ /** Color tokens — dùng CSS custom properties từ MD3 theme */
356
+ declare const DP_COLORS: {
357
+ /** Dialog container — SurfaceContainerHigh */
358
+ readonly container: "var(--md-sys-color-surface-container-high)";
359
+ /** Selected day background — Primary */
360
+ readonly daySelected: "var(--md-sys-color-primary)";
361
+ /** Selected day text — OnPrimary */
362
+ readonly daySelectedText: "var(--md-sys-color-on-primary)";
363
+ /** Today outline — Primary */
364
+ readonly todayOutline: "var(--md-sys-color-primary)";
365
+ /** Today text — Primary */
366
+ readonly todayText: "var(--md-sys-color-primary)";
367
+ /** Unselected day text — OnSurface */
368
+ readonly dayText: "var(--md-sys-color-on-surface)";
369
+ /** Weekday header text — OnSurface */
370
+ readonly weekdayText: "var(--md-sys-color-on-surface)";
371
+ /** Header headline + supporting text — OnSurfaceVariant */
372
+ readonly headerText: "var(--md-sys-color-on-surface-variant)";
373
+ /** Range highlight background — SecondaryContainer */
374
+ readonly rangeHighlight: "var(--md-sys-color-secondary-container)";
375
+ /** Range highlight text — OnSecondaryContainer */
376
+ readonly rangeText: "var(--md-sys-color-on-secondary-container)";
377
+ /** Unselected year text — OnSurfaceVariant */
378
+ readonly yearText: "var(--md-sys-color-on-surface-variant)";
379
+ /** Selected year background — Primary */
380
+ readonly yearSelected: "var(--md-sys-color-primary)";
381
+ /** Selected year text — OnPrimary */
382
+ readonly yearSelectedText: "var(--md-sys-color-on-primary)";
383
+ /** Scrim overlay */
384
+ readonly scrim: "var(--md-sys-color-scrim)";
385
+ };
386
+ /** Shape tokens — corner radii từ MD3 shape scale */
387
+ declare const DP_SHAPE: {
388
+ /** Dialog container — CornerExtraLarge = 28px */
389
+ readonly container: "var(--md-sys-shape-corner-extra-large)";
390
+ /** Day cell — CornerFull = pill */
391
+ readonly day: "var(--md-sys-shape-corner-full)";
392
+ /** Range start/end indicator — CornerFull */
393
+ readonly rangeEndpoint: "var(--md-sys-shape-corner-full)";
394
+ /** Year chip — CornerFull */
395
+ readonly year: "var(--md-sys-shape-corner-full)";
396
+ };
397
+ /** Fixed dimension tokens từ DatePickerModalTokens.kt */
398
+ declare const DP_SIZE: {
399
+ /** Dialog container width */
400
+ readonly containerWidth: 360;
401
+ /** Dialog container height */
402
+ readonly containerHeight: 568;
403
+ /** Day cell width/height */
404
+ readonly dayCell: 40;
405
+ /** Today border width */
406
+ readonly todayOutlineWidth: 1;
407
+ /** Header container height */
408
+ readonly headerHeight: 120;
409
+ /** Range picker header height */
410
+ readonly rangeHeaderHeight: 128;
411
+ /** Year chip height */
412
+ readonly yearChipHeight: 36;
413
+ /** Year chip width */
414
+ readonly yearChipWidth: 72;
415
+ };
416
+ /**
417
+ * Tailwind utility class strings cho Date Picker elements.
418
+ * Sử dụng với `cn()` function.
419
+ */
420
+ declare const DP_CLASSES: {
421
+ /** Dialog container */
422
+ readonly dialog: string;
423
+ /** Day cell container */
424
+ readonly dayCell: string;
425
+ /** Day cell: selected state */
426
+ readonly dayCellSelected: string;
427
+ /** Day cell: today state */
428
+ readonly dayCellToday: string;
429
+ /** Day cell: disabled state */
430
+ readonly dayCellDisabled: "opacity-[0.38] pointer-events-none cursor-not-allowed";
431
+ /** Range highlight (between start and end) */
432
+ readonly rangeHighlight: "bg-m3-secondary-container";
433
+ /** Weekday header row */
434
+ readonly weekdayRow: "text-[length:var(--md-typescale-body-large-size,14px)] text-m3-on-surface";
435
+ };
436
+
437
+ /**
438
+ * @file date-picker/date-picker-dialog.tsx
439
+ *
440
+ * Modal container cho Date Pickers — tái sử dụng Dialog + DialogPortal từ thư viện bug-on/md3-react.
441
+ * Tương đương composable `DatePickerDialog` trong Android Compose Material3.
442
+ *
443
+ * Tokens từ DatePickerModalTokens.kt:
444
+ * - ContainerColor = SurfaceContainerHigh (#ece6f0)
445
+ * - ContainerShape = CornerExtraLarge (28px)
446
+ * - ContainerElevation = Level3
447
+ * - ContainerWidth = 360px, ContainerHeight = 568px (single date)
448
+ *
449
+ * @see https://m3.material.io/components/date-pickers/overview
450
+ */
451
+
452
+ /**
453
+ * Modal Date Picker dialog với MD3 Expressive spring animations.
454
+ *
455
+ * Tái sử dụng `<Dialog>` (Root) và `<DialogPortal>` (AnimatePresence + Portal lifecycle)
456
+ * từ thư viện, trong khi tự quản lý Overlay và Content để giữ đúng
457
+ * layout specs MD3 Date Picker (không có padding p-6, kích thước cố định, animation riêng).
458
+ *
459
+ * @example
460
+ * ```tsx
461
+ * const state = useDatePickerState();
462
+ * const [open, setOpen] = React.useState(false);
463
+ *
464
+ * <DatePickerDialog
465
+ * open={open}
466
+ * onDismiss={() => setOpen(false)}
467
+ * confirmButton={
468
+ * <Button variant="text" onClick={() => { handleConfirm(state.selectedDateMs); setOpen(false); }}>
469
+ * OK
470
+ * </Button>
471
+ * }
472
+ * dismissButton={
473
+ * <Button variant="text" onClick={() => setOpen(false)}>Cancel</Button>
474
+ * }
475
+ * >
476
+ * <DatePicker state={state} />
477
+ * </DatePickerDialog>
478
+ * ```
479
+ */
480
+ declare const DatePickerDialog: React.FC<DatePickerDialogProps>;
481
+
482
+ /**
483
+ * @file date-picker/date-picker-input.tsx
484
+ *
485
+ * Text input mode cho Date Picker — nhập ngày thủ công dạng MM/DD/YYYY.
486
+ * Sử dụng TextField component của thư viện.
487
+ *
488
+ * @see https://m3.material.io/components/date-pickers/overview
489
+ */
490
+
491
+ /**
492
+ * Text input cho Date Picker với format MM/DD/YYYY.
493
+ * Validate realtime, commit khi blur hoặc Enter.
494
+ */
495
+ declare const DatePickerInput: React.FC<DatePickerInputProps>;
496
+
497
+ /**
498
+ * @file date-picker/date-range-picker.tsx
499
+ *
500
+ * DateRangePicker — calendar UI cho chọn khoảng ngày.
501
+ * Tương đương composable `DateRangePicker` trong Android Compose Material3.
502
+ *
503
+ * Khác biệt so với DatePicker:
504
+ * - Highlight range giữa start và end (SecondaryContainer)
505
+ * - Headline hiển thị "Start date → End date"
506
+ * - Default title: "Select dates" (plural)
507
+ *
508
+ * @see https://m3.material.io/components/date-pickers/overview
509
+ */
510
+
511
+ /**
512
+ * DateRangePicker calendar UI.
513
+ *
514
+ * @example
515
+ * ```tsx
516
+ * const state = useDateRangePickerState();
517
+ *
518
+ * <DateRangePicker
519
+ * state={state}
520
+ * title="Select travel dates"
521
+ * />
522
+ * ```
523
+ */
524
+ declare const DateRangePicker: React.FC<DateRangePickerProps>;
525
+
526
+ /**
527
+ * @file date-picker/use-date-picker-state.ts
528
+ *
529
+ * Core state hook cho DatePicker — hoisted state pattern.
530
+ * Tương đương `rememberDatePickerState()` trong Android Compose Material3.
531
+ *
532
+ * @example
533
+ * ```tsx
534
+ * const state = useDatePickerState({
535
+ * locale: { locale: 'vi-VN', weekStartsOn: 1 },
536
+ * selectableDates: {
537
+ * isSelectableDate: (ms) => new Date(ms).getUTCDay() !== 0,
538
+ * isSelectableYear: (year) => year >= 2020,
539
+ * }
540
+ * });
541
+ *
542
+ * <DatePicker state={state} />
543
+ * <p>Selected: {state.selectedDateMs}</p>
544
+ * ```
545
+ */
546
+
547
+ /**
548
+ * Hook quản lý state cho DatePicker.
549
+ *
550
+ * @param options - Cấu hình ban đầu cho state
551
+ * @returns `DatePickerState` object với các actions
552
+ */
553
+ declare const useDatePickerState: (options?: UseDatePickerStateOptions) => DatePickerState;
554
+
555
+ /**
556
+ * @file date-picker/use-date-range-picker-state.ts
557
+ *
558
+ * Core state hook cho DateRangePicker — hoisted state pattern.
559
+ * Tương đương `rememberDateRangePickerState()` trong Android Compose Material3.
560
+ *
561
+ * Logic chọn range:
562
+ * - Click 1: set start date
563
+ * - Click 2 (ms > start): set end date → range complete
564
+ * - Click 2 (ms <= start): reset, set start = ms
565
+ * - Nếu đã có cả start lẫn end: reset, set start = ms
566
+ *
567
+ * @example
568
+ * ```tsx
569
+ * const state = useDateRangePickerState();
570
+ *
571
+ * <DateRangePicker state={state} />
572
+ * <p>Start: {state.selectedStartMs}, End: {state.selectedEndMs}</p>
573
+ * ```
574
+ */
575
+
576
+ /**
577
+ * Hook quản lý state cho DateRangePicker.
578
+ *
579
+ * @param options - Cấu hình ban đầu
580
+ * @returns `DateRangePickerState` object với các actions
581
+ */
582
+ declare const useDateRangePickerState: (options?: UseDateRangePickerStateOptions) => DateRangePickerState;
583
+
584
+ /**
585
+ * @file time-picker/time-picker.types.ts
586
+ *
587
+ * TypeScript interfaces và types cho Time Picker component system.
588
+ * Port từ `TimePickerState` interface trong Android Compose Material3.
589
+ *
590
+ * @see https://m3.material.io/components/time-pickers/overview
591
+ * @see docs/m3/date-and-time-pickers/time-pickers/TimePickerState.md
592
+ */
593
+
594
+ /**
595
+ * Phần nào của time đang được chọn — hour hoặc minute.
596
+ * Tương đương `TimePickerSelectionMode` enum trong Android Compose.
597
+ */
598
+ type TimePickerSelectionMode = "hour" | "minute";
599
+ /** Visual arrangement of the clock display. */
600
+ type TimePickerLayout = "auto" | "vertical" | "horizontal";
601
+ /**
602
+ * State object cho TimePicker — hoisted state pattern.
603
+ * Tương đương `TimePickerState` interface trong Android Compose Material3.
604
+ *
605
+ * Tách biệt `hour`/`minute` (luôn valid) và `hourInput`/`minuteInput`
606
+ * (raw input, có thể invalid mid-typing trong TimeInput mode).
607
+ *
608
+ * @example
609
+ * ```tsx
610
+ * const state = useTimePickerState({ initialHour: 7, initialMinute: 0 });
611
+ *
612
+ * <TimePicker state={state} />
613
+ * <p>Selected: {state.hour}:{String(state.minute).padStart(2, '0')}</p>
614
+ * ```
615
+ */
616
+ interface TimePickerState {
617
+ /** Giờ hiện tại (0-23). Luôn valid. */
618
+ readonly hour: number;
619
+ /** Phút hiện tại (0-59). Luôn valid. */
620
+ readonly minute: number;
621
+ /**
622
+ * Raw input cho giờ — UI bind vào giá trị này.
623
+ * Có thể invalid khi đang nhập (vd: đang gõ "1" trước khi gõ "2").
624
+ * Khi valid thì tự động cập nhật `hour`.
625
+ */
626
+ readonly hourInput: number;
627
+ /**
628
+ * Raw input cho phút — UI bind vào giá trị này.
629
+ * Có thể invalid khi đang nhập.
630
+ * Khi valid thì tự động cập nhật `minute`.
631
+ */
632
+ readonly minuteInput: number;
633
+ /** Sử dụng định dạng 24h (`true`) hay 12h AM/PM (`false`). */
634
+ readonly is24hour: boolean;
635
+ /** Phần nào đang được chọn (hour hoặc minute). */
636
+ readonly selection: TimePickerSelectionMode;
637
+ /** `true` nếu cả hourInput và minuteInput đều valid. */
638
+ readonly isInputValid: boolean;
639
+ /** `true` nếu hourInput là valid hour (0-23 với 24h, 1-12 với 12h). */
640
+ readonly isHourInputValid: boolean;
641
+ /** `true` nếu minuteInput là valid minute (0-59). */
642
+ readonly isMinuteInputValid: boolean;
643
+ /** `true` nếu giờ hiện tại là PM (hour >= 12). */
644
+ readonly isPm: boolean;
645
+ /**
646
+ * Set giờ hợp lệ (0-23). Cũng cập nhật hourInput.
647
+ * Dùng cho clock dial interaction.
648
+ */
649
+ setHour(h: number): void;
650
+ /**
651
+ * Set phút hợp lệ (0-59). Cũng cập nhật minuteInput.
652
+ * Dùng cho clock dial interaction.
653
+ */
654
+ setMinute(m: number): void;
655
+ /**
656
+ * Set raw hour input (có thể invalid).
657
+ * Dùng cho TimeInput text field.
658
+ * Chỉ cập nhật `hour` khi giá trị valid.
659
+ */
660
+ setHourInput(h: number): void;
661
+ /**
662
+ * Set raw minute input (có thể invalid).
663
+ * Dùng cho TimeInput text field.
664
+ * Chỉ cập nhật `minute` khi giá trị valid.
665
+ */
666
+ setMinuteInput(m: number): void;
667
+ /** Đổi selection giữa 'hour' và 'minute'. */
668
+ setSelection(mode: TimePickerSelectionMode): void;
669
+ /**
670
+ * Toggle AM/PM.
671
+ * Tự động convert giờ (vd: 7 AM → 19, 15 PM → 3 AM).
672
+ */
673
+ setIsPm(pm: boolean): void;
674
+ /** Reset về trạng thái ban đầu. */
675
+ reset(): void;
676
+ }
677
+ /**
678
+ * Options cho `useTimePickerState` hook.
679
+ * Tương đương parameters của `rememberTimePickerState()` trong Compose.
680
+ *
681
+ * @example
682
+ * ```tsx
683
+ * const state = useTimePickerState({
684
+ * initialHour: 14,
685
+ * initialMinute: 30,
686
+ * is24hour: true,
687
+ * });
688
+ * ```
689
+ */
690
+ interface UseTimePickerStateOptions {
691
+ /**
692
+ * Giờ ban đầu (0-23).
693
+ * @default 0
694
+ */
695
+ initialHour?: number;
696
+ /**
697
+ * Phút ban đầu (0-59).
698
+ * @default 0
699
+ */
700
+ initialMinute?: number;
701
+ /**
702
+ * Sử dụng định dạng 24h hay 12h AM/PM.
703
+ * @default false (12h format với AM/PM selector)
704
+ */
705
+ is24hour?: boolean;
706
+ }
707
+ /**
708
+ * Props cho `TimePicker` component (dial/clock mode).
709
+ * Tương đương `TimePicker` composable trong Android Compose.
710
+ */
711
+ interface TimePickerProps {
712
+ /** Hoisted state từ `useTimePickerState()`. */
713
+ state: TimePickerState;
714
+ /**
715
+ * Arrangement of the clock header and dial.
716
+ * `auto` uses the Android-style horizontal layout in a sufficiently wide
717
+ * landscape viewport and the vertical layout elsewhere.
718
+ * @default "auto"
719
+ */
720
+ layout?: TimePickerLayout;
721
+ /** CSS class bổ sung cho container. */
722
+ className?: string;
723
+ }
724
+ /**
725
+ * Props cho `TimeInput` component (text input mode).
726
+ * Tương đương `TimeInput` composable trong Android Compose.
727
+ */
728
+ interface TimeInputProps {
729
+ /** Hoisted state từ `useTimePickerState()`. */
730
+ state: TimePickerState;
731
+ /** CSS class bổ sung cho container. */
732
+ className?: string;
733
+ }
734
+ /**
735
+ * Props cho `TimePickerDialog` component.
736
+ * Tương đương `TimePickerDialog` composable trong Android Compose.
737
+ */
738
+ interface TimePickerDialogProps {
739
+ /** Trạng thái mở/đóng dialog. */
740
+ open: boolean;
741
+ /** Callback khi dialog cần đóng (click scrim, Escape). */
742
+ onDismiss: () => void;
743
+ /**
744
+ * Nút xác nhận — caller tự render (vd: Button "OK").
745
+ * Dialog không set up event handlers — caller tự xử lý.
746
+ */
747
+ confirmButton: React.ReactNode;
748
+ /**
749
+ * Nút hủy — optional.
750
+ * @default null
751
+ */
752
+ dismissButton?: React.ReactNode;
753
+ /**
754
+ * Nút toggle giữa Dial và Input mode — optional.
755
+ * Hiển thị ở bottom-left của footer.
756
+ */
757
+ modeToggleButton?: React.ReactNode;
758
+ /**
759
+ * Title hiển thị trên dialog (accessible).
760
+ * @default "Select time"
761
+ */
762
+ title?: string;
763
+ /** Content — thường là `<TimePicker>` hoặc `<TimeInput>`. */
764
+ children: React.ReactNode;
765
+ /** CSS class bổ sung cho dialog panel. */
766
+ className?: string;
767
+ }
768
+
769
+ /**
770
+ * @file time-picker/time-input.tsx
771
+ *
772
+ * TimeInput — text input mode cho time entry.
773
+ *
774
+ * Layout:
775
+ * ```
776
+ * ┌────────────────────────────────┐
777
+ * │ Enter time │ ← headline (labelMedium)
778
+ * │ [07] : [00] [AM] │ ← input fields + PeriodSelector
779
+ * │ [PM] │
780
+ * │ Hour Minute │ ← helper labels (bodySmall)
781
+ * └────────────────────────────────┘
782
+ * ```
783
+ *
784
+ * Behavior:
785
+ * - Hai `<input>` cho giờ và phút
786
+ * - Auto-advance: nhập đủ 2 digits hợp lệ → focus field kế
787
+ * - Validation: error state nếu giá trị ngoài range
788
+ * - AM/PM toggle bên phải (ẩn khi is24hour)
789
+ *
790
+ * Port từ `TimeInputImpl` trong TimePicker.kt.
791
+ *
792
+ * @see docs/m3/date-and-time-pickers/time-pickers/TimePicker.kt (TimeInputImpl)
793
+ */
794
+
795
+ /**
796
+ * TimeInput — text input mode.
797
+ *
798
+ * Dùng cùng với `useTimePickerState`:
799
+ *
800
+ * @example
801
+ * ```tsx
802
+ * const state = useTimePickerState({ initialHour: 9, initialMinute: 30 });
803
+ *
804
+ * // Standalone
805
+ * <TimeInput state={state} />
806
+ *
807
+ * // In dialog (with toggle)
808
+ * <TimePickerDialog
809
+ * open={open}
810
+ * onDismiss={() => setOpen(false)}
811
+ * confirmButton={<Button variant="text" onClick={() => setOpen(false)}>OK</Button>}
812
+ * >
813
+ * <TimeInput state={state} />
814
+ * </TimePickerDialog>
815
+ * ```
816
+ */
817
+ declare const TimeInput: React.FC<TimeInputProps>;
818
+
819
+ /**
820
+ * @file time-picker/time-picker.tsx
821
+ *
822
+ * Android MD3 clock picker. The picker uses a compact vertical arrangement in
823
+ * portrait and moves the clock beside the display on larger landscape screens.
824
+ */
825
+
826
+ declare const TimePicker: React.FC<TimePickerProps>;
827
+
828
+ /**
829
+ * @file time-picker/time-picker.tokens.ts
830
+ *
831
+ * MD3 Design tokens cho Time Picker component system.
832
+ * Verified mapping từ:
833
+ * - TimePickerTokens.kt → ClockDial, TimeSelector, PeriodSelector (Picker mode)
834
+ * - TimeInputTokens.kt → TimeField, PeriodSelector (Input mode)
835
+ *
836
+ * CSS variables → packages/tokens/src/colors.css
837
+ * Tailwind classes → packages/tailwind/src/index.css
838
+ *
839
+ * @see docs/m3/date-and-time-pickers/time-pickers/TimePickerTokens.kt
840
+ * @see docs/m3/date-and-time-pickers/time-pickers/TimeInputTokens.kt
841
+ */
842
+ /**
843
+ * Color tokens cho Time Picker — map từ TimePickerTokens.kt + TimeInputTokens.kt.
844
+ * Dùng CSS custom properties từ MD3 theme (packages/tokens/src/colors.css).
845
+ */
846
+ declare const TP_COLORS: {
847
+ /** Dial background — SurfaceContainerHighest */
848
+ readonly clockDial: "var(--md-sys-color-surface-container-highest)";
849
+ /** Selected number text — OnPrimary */
850
+ readonly clockDialSelected: "var(--md-sys-color-on-primary)";
851
+ /** Unselected number text — OnSurface */
852
+ readonly clockDialUnselected: "var(--md-sys-color-on-surface)";
853
+ /** Selector handle circle — Primary */
854
+ readonly selectorHandle: "var(--md-sys-color-primary)";
855
+ /** Selector track line — Primary */
856
+ readonly selectorTrack: "var(--md-sys-color-primary)";
857
+ /** Selector center dot — Primary */
858
+ readonly selectorCenter: "var(--md-sys-color-primary)";
859
+ /** Picker/Input container — SurfaceContainerHigh */
860
+ readonly container: "var(--md-sys-color-surface-container-high)";
861
+ /** Selected selector (hour/min button) — PrimaryContainer */
862
+ readonly timeSelectorSelected: "var(--md-sys-color-primary-container)";
863
+ /** Unselected selector — SurfaceContainerHighest */
864
+ readonly timeSelectorUnselected: "var(--md-sys-color-surface-container-highest)";
865
+ /** Selected selector text — OnPrimaryContainer */
866
+ readonly timeSelectorSelectedText: "var(--md-sys-color-on-primary-container)";
867
+ /** Unselected selector text — OnSurface */
868
+ readonly timeSelectorUnselectedText: "var(--md-sys-color-on-surface)";
869
+ /** AM/PM selected background — TertiaryContainer */
870
+ readonly periodSelected: "var(--md-sys-color-tertiary-container)";
871
+ /** AM/PM unselected background — transparent */
872
+ readonly periodUnselected: "transparent";
873
+ /** AM/PM selected text — OnTertiaryContainer */
874
+ readonly periodSelectedText: "var(--md-sys-color-on-tertiary-container)";
875
+ /** AM/PM unselected text — OnSurfaceVariant */
876
+ readonly periodUnselectedText: "var(--md-sys-color-on-surface-variant)";
877
+ /** AM/PM border — Outline */
878
+ readonly periodOutline: "var(--md-sys-color-outline)";
879
+ /** Time field default background — SurfaceContainerHighest */
880
+ readonly timeField: "var(--md-sys-color-surface-container-highest)";
881
+ /** Time field focused background — PrimaryContainer */
882
+ readonly timeFieldFocus: "var(--md-sys-color-primary-container)";
883
+ /** Time field focused text — OnPrimaryContainer */
884
+ readonly timeFieldFocusText: "var(--md-sys-color-on-primary-container)";
885
+ /** Time field focus outline — Primary */
886
+ readonly timeFieldFocusOutline: "var(--md-sys-color-primary)";
887
+ /** Time field default text — OnSurface */
888
+ readonly timeFieldText: "var(--md-sys-color-on-surface)";
889
+ /** ":" separator — OnSurface */
890
+ readonly separator: "var(--md-sys-color-on-surface)";
891
+ /** Headline label ("Select time") — OnSurfaceVariant */
892
+ readonly headline: "var(--md-sys-color-on-surface-variant)";
893
+ };
894
+ /**
895
+ * Tailwind utility class strings cho Time Picker elements.
896
+ * Dùng với `cn()` function.
897
+ * Map chính xác từ packages/tailwind/src/index.css (--color-m3-* tokens).
898
+ */
899
+ declare const TP_CLASSES: {
900
+ /** Main picker/input container */
901
+ readonly container: "bg-m3-surface-container-high rounded-m3-xl select-none";
902
+ /** Hour/minute selector button — selected */
903
+ readonly timeSelectorSelected: "bg-m3-primary-container text-m3-on-primary-container";
904
+ /** Hour/minute selector button — unselected */
905
+ readonly timeSelectorUnselected: "bg-m3-surface-container-highest text-m3-on-surface";
906
+ /** AM/PM button — selected */
907
+ readonly periodSelected: "bg-m3-primary-container text-m3-on-primary-container";
908
+ /** AM/PM button — unselected */
909
+ readonly periodUnselected: "bg-transparent text-m3-on-surface-variant";
910
+ /** Time input field — default */
911
+ readonly timeField: "bg-m3-surface-container-highest text-m3-on-surface";
912
+ /** Time input field — focused */
913
+ readonly timeFieldFocused: "bg-m3-primary-container text-m3-on-primary-container ring-2 ring-m3-primary";
914
+ /** Clock dial background circle */
915
+ readonly clockDial: "fill-[var(--md-sys-color-surface-container-highest)]";
916
+ /** Selected number on dial */
917
+ readonly clockDialSelectedText: "fill-[var(--md-sys-color-on-primary)]";
918
+ /** Unselected number on dial */
919
+ readonly clockDialUnselectedText: "fill-[var(--md-sys-color-on-surface)]";
920
+ /** Selector handle, track, center dot */
921
+ readonly selectorPrimary: "fill-m3-primary stroke-m3-primary";
922
+ };
923
+ /**
924
+ * Shape tokens — corner radii từ MD3 shape scale.
925
+ * Map từ ShapeKeyTokens trong TimePickerTokens.kt + TimeInputTokens.kt.
926
+ *
927
+ * Sử dụng Tailwind class names từ packages/tailwind/src/index.css.
928
+ */
929
+ declare const TP_SHAPE: {
930
+ /** Dialog container — CornerExtraLarge = 28px */
931
+ readonly container: "rounded-m3-xl";
932
+ /** Hour/minute selector button — CornerSmall = 8px */
933
+ readonly timeSelector: "rounded-m3-sm";
934
+ /** Period (AM/PM) container — CornerSmall = 8px */
935
+ readonly periodSelector: "rounded-m3-sm";
936
+ /** Clock dial circle — CornerFull */
937
+ readonly clockDial: "rounded-m3-full";
938
+ /** Time field — CornerSmall = 8px */
939
+ readonly timeField: "rounded-m3-sm";
940
+ };
941
+ /**
942
+ * Fixed dimension tokens từ TimePickerTokens.kt + TimeInputTokens.kt.
943
+ * Đơn vị: px (đã convert từ dp).
944
+ */
945
+ declare const TP_SIZE: {
946
+ /** ClockDialContainerSize = 256dp */
947
+ readonly clockDialSize: 256;
948
+ /** ClockDialSelectorHandleContainerSize = 48dp */
949
+ readonly selectorHandleSize: 48;
950
+ /** ClockDialSelectorCenterContainerSize = 8dp */
951
+ readonly selectorCenterSize: 8;
952
+ /** ClockDialSelectorTrackContainerWidth = 2dp */
953
+ readonly selectorTrackWidth: 2;
954
+ /** TimeSelectorContainerWidth = 96dp */
955
+ readonly timeSelectorWidth: 96;
956
+ /** TimeSelectorContainerHeight = 80dp */
957
+ readonly timeSelectorHeight: 80;
958
+ /** TimeSelector24HVerticalContainerWidth = 114dp (24h mode) */
959
+ readonly timeSelector24hWidth: 114;
960
+ /** PeriodSelectorVerticalContainerWidth = 52dp */
961
+ readonly periodSelectorVerticalWidth: 52;
962
+ /** PeriodSelectorVerticalContainerHeight = 80dp */
963
+ readonly periodSelectorVerticalHeight: 80;
964
+ /** PeriodSelectorHorizontalContainerWidth = 216dp */
965
+ readonly periodSelectorHorizWidth: 216;
966
+ /** PeriodSelectorHorizontalContainerHeight = 38dp */
967
+ readonly periodSelectorHorizHeight: 38;
968
+ /** TimeFieldContainerWidth = 96dp */
969
+ readonly timeFieldWidth: 96;
970
+ /** TimeFieldContainerHeight = 72dp */
971
+ readonly timeFieldHeight: 72;
972
+ /** PeriodSelectorContainerHeight (Input mode) = 72dp */
973
+ readonly periodInputHeight: 72;
974
+ /** PeriodSelectorContainerWidth (Input mode) = 52dp */
975
+ readonly periodInputWidth: 52;
976
+ };
977
+
978
+ /**
979
+ * @file time-picker/time-picker-dialog.tsx
980
+ *
981
+ * TimePickerDialog — modal container cho TimePicker và TimeInput.
982
+ * Tái sử dụng Dialog + DialogPortal từ thư viện bug-on/md3-react,
983
+ * giống pattern của DatePickerDialog.
984
+ *
985
+ * Layout:
986
+ * ```
987
+ * ┌─────────────────────┐
988
+ * │ [Content] │ ← TimePicker hoặc TimeInput
989
+ * │─────────────────────│
990
+ * │ 🎹 [Cancel] [OK] │ ← footer: modeToggle + spacer + dismiss + confirm
991
+ * └─────────────────────┘
992
+ * ```
993
+ *
994
+ * Tokens từ TimePickerDialog.kt (dùng chung với DatePickerDialog):
995
+ * - ContainerColor = SurfaceContainerHigh
996
+ * - ContainerShape = CornerExtraLarge (28px)
997
+ * - ContainerElevation = Level3
998
+ *
999
+ * Port từ `TimePickerDialog.kt` và pattern `DatePickerDialog`.
1000
+ *
1001
+ * @see docs/m3/date-and-time-pickers/time-pickers/TimePickerDialog.kt
1002
+ * @see packages/react/src/ui/date-time-pickers/date-picker/date-picker-dialog.tsx
1003
+ */
1004
+
1005
+ /**
1006
+ * TimePickerDialog — modal dialog cho TimePicker / TimeInput.
1007
+ *
1008
+ * Tái sử dụng `<Dialog>` (Root) và `<DialogPortal>` (AnimatePresence + Portal)
1009
+ * từ thư viện, đồng thời tự quản lý Overlay và Content để giữ đúng
1010
+ * layout specs MD3 Time Picker.
1011
+ *
1012
+ * @example Basic usage
1013
+ * ```tsx
1014
+ * const state = useTimePickerState({ initialHour: 7 });
1015
+ * const [open, setOpen] = React.useState(false);
1016
+ * const [mode, setMode] = React.useState<'dial' | 'input'>('dial');
1017
+ *
1018
+ * <TimePickerDialog
1019
+ * open={open}
1020
+ * onDismiss={() => setOpen(false)}
1021
+ * modeToggleButton={
1022
+ * <button onClick={() => setMode(m => m === 'dial' ? 'input' : 'dial')}>
1023
+ * <span className="md-icon">{mode === 'dial' ? 'keyboard' : 'schedule'}</span>
1024
+ * </button>
1025
+ * }
1026
+ * confirmButton={
1027
+ * <Button variant="text" onClick={() => { handleConfirm(state); setOpen(false); }}>
1028
+ * OK
1029
+ * </Button>
1030
+ * }
1031
+ * dismissButton={
1032
+ * <Button variant="text" onClick={() => setOpen(false)}>Cancel</Button>
1033
+ * }
1034
+ * >
1035
+ * {mode === 'dial' ? <TimePicker state={state} /> : <TimeInput state={state} />}
1036
+ * </TimePickerDialog>
1037
+ * ```
1038
+ */
1039
+ declare const TimePickerDialog: React.FC<TimePickerDialogProps>;
1040
+
1041
+ /**
1042
+ * @file time-picker/use-time-picker-state.ts
1043
+ *
1044
+ * Core state hook cho TimePicker — hoisted state pattern.
1045
+ * Port từ `rememberTimePickerState()` trong Android Compose Material3.
1046
+ *
1047
+ * Tách biệt `hour`/`minute` (luôn valid) và `hourInput`/`minuteInput`
1048
+ * (raw input, có thể invalid mid-typing) — giữ nguyên semantics từ Kotlin.
1049
+ *
1050
+ * @see docs/m3/date-and-time-pickers/time-pickers/TimePickerState.md
1051
+ *
1052
+ * @example
1053
+ * ```tsx
1054
+ * const state = useTimePickerState({
1055
+ * initialHour: 7,
1056
+ * initialMinute: 0,
1057
+ * is24hour: false,
1058
+ * });
1059
+ *
1060
+ * <TimePicker state={state} />
1061
+ * <p>{state.hour}:{String(state.minute).padStart(2, '0')} {state.isPm ? 'PM' : 'AM'}</p>
1062
+ * ```
1063
+ */
1064
+
1065
+ /**
1066
+ * Hook quản lý state cho TimePicker và TimeInput.
1067
+ * Tương đương `rememberTimePickerState()` trong Android Compose.
1068
+ *
1069
+ * @param options - Cấu hình ban đầu
1070
+ * @returns `TimePickerState` object với actions
1071
+ */
1072
+ declare const useTimePickerState: (options?: UseTimePickerStateOptions) => TimePickerState;
1073
+
1074
+ export { DP_CLASSES, DP_COLORS, DP_SHAPE, DP_SIZE, type DateLocale, DatePicker, DatePickerDialog, type DatePickerDialogProps, DatePickerInput, type DatePickerInputProps, type DatePickerProps, type DatePickerState, type DateRange, DateRangePicker, type DateRangePickerProps, type DateRangePickerState, type DisplayMode, type SelectableDates, TP_CLASSES, TP_COLORS, TP_SHAPE, TP_SIZE, TimeInput, type TimeInputProps, TimePicker, TimePickerDialog, type TimePickerDialogProps, type TimePickerLayout, type TimePickerProps, type TimePickerSelectionMode, type TimePickerState, type UseDatePickerStateOptions, type UseDateRangePickerStateOptions, type UseTimePickerStateOptions, useDatePickerState, useDateRangePickerState, useTimePickerState };