@ceed/ads 1.29.0 → 1.30.0-next.1

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 (64) hide show
  1. package/dist/components/CurrencyInput/CurrencyInput.d.ts +1 -1
  2. package/dist/components/CurrencyInput/hooks/use-currency-setting.d.ts +2 -2
  3. package/dist/components/DataTable/hooks.d.ts +2 -1
  4. package/dist/components/DataTable/utils.d.ts +1 -0
  5. package/dist/components/ProfileMenu/ProfileMenu.d.ts +1 -1
  6. package/dist/components/SearchBar/SearchBar.d.ts +21 -0
  7. package/dist/components/SearchBar/index.d.ts +3 -0
  8. package/dist/components/data-display/Badge.md +39 -71
  9. package/dist/components/data-display/DataTable.md +1 -1
  10. package/dist/components/data-display/InfoSign.md +98 -74
  11. package/dist/components/data-display/Typography.md +97 -363
  12. package/dist/components/feedback/Dialog.md +62 -76
  13. package/dist/components/feedback/Modal.md +44 -259
  14. package/dist/components/feedback/llms.txt +0 -2
  15. package/dist/components/index.d.ts +2 -0
  16. package/dist/components/inputs/Autocomplete.md +107 -356
  17. package/dist/components/inputs/ButtonGroup.md +106 -115
  18. package/dist/components/inputs/Calendar.md +459 -98
  19. package/dist/components/inputs/CurrencyInput.md +5 -183
  20. package/dist/components/inputs/DatePicker.md +431 -108
  21. package/dist/components/inputs/DateRangePicker.md +492 -131
  22. package/dist/components/inputs/FilterMenu.md +19 -169
  23. package/dist/components/inputs/FilterableCheckboxGroup.md +23 -123
  24. package/dist/components/inputs/IconButton.md +88 -137
  25. package/dist/components/inputs/Input.md +0 -5
  26. package/dist/components/inputs/MonthPicker.md +422 -95
  27. package/dist/components/inputs/MonthRangePicker.md +466 -89
  28. package/dist/components/inputs/PercentageInput.md +16 -185
  29. package/dist/components/inputs/RadioButton.md +35 -163
  30. package/dist/components/inputs/RadioTileGroup.md +61 -150
  31. package/dist/components/inputs/SearchBar.md +44 -0
  32. package/dist/components/inputs/Select.md +326 -222
  33. package/dist/components/inputs/Switch.md +376 -136
  34. package/dist/components/inputs/Textarea.md +10 -213
  35. package/dist/components/inputs/Uploader/Uploader.md +66 -145
  36. package/dist/components/inputs/llms.txt +1 -3
  37. package/dist/components/navigation/Breadcrumbs.md +322 -80
  38. package/dist/components/navigation/Dropdown.md +221 -92
  39. package/dist/components/navigation/IconMenuButton.md +502 -40
  40. package/dist/components/navigation/InsetDrawer.md +738 -68
  41. package/dist/components/navigation/Link.md +298 -39
  42. package/dist/components/navigation/Menu.md +285 -92
  43. package/dist/components/navigation/MenuButton.md +448 -55
  44. package/dist/components/navigation/Pagination.md +338 -47
  45. package/dist/components/navigation/ProfileMenu.md +268 -45
  46. package/dist/components/navigation/Stepper.md +28 -160
  47. package/dist/components/navigation/Tabs.md +316 -57
  48. package/dist/components/surfaces/Sheet.md +334 -151
  49. package/dist/index.browser.js +15 -13
  50. package/dist/index.browser.js.map +4 -4
  51. package/dist/index.cjs +313 -291
  52. package/dist/index.d.ts +1 -1
  53. package/dist/index.js +450 -372
  54. package/dist/llms.txt +1 -8
  55. package/framer/index.js +1 -1
  56. package/package.json +16 -15
  57. package/dist/chunks/rehype-accent-FZRUD7VI.js +0 -39
  58. package/dist/components/feedback/CircularProgress.md +0 -257
  59. package/dist/components/feedback/Skeleton.md +0 -280
  60. package/dist/components/inputs/FormControl.md +0 -361
  61. package/dist/components/inputs/RadioList.md +0 -241
  62. package/dist/components/inputs/Slider.md +0 -334
  63. package/dist/guides/ThemeProvider.md +0 -116
  64. package/dist/guides/llms.txt +0 -9
@@ -1,8 +1,8 @@
1
1
  # DatePicker
2
2
 
3
- DatePicker is a form input component that allows users to select a single date from a calendar popup or by typing directly into the input field. It provides flexible date formatting options, date range restrictions, and supports both controlled and uncontrolled modes.
3
+ ## Introduction
4
4
 
5
- DatePicker is essential for any form that requires date input -- booking systems, scheduling interfaces, data filtering, and record keeping. It handles the complexity of date parsing, formatting, and validation so consumers can focus on business logic.
5
+ DatePicker is a form input component that allows users to select a single date from a calendar popup or by typing directly into the input field. It provides flexible date formatting options, date range restrictions, and supports both controlled and uncontrolled modes. DatePicker is essential for forms that require date input, such as booking systems, scheduling interfaces, and data filtering.
6
6
 
7
7
  ```tsx
8
8
  <DatePicker onChange={fn()} />
@@ -28,6 +28,15 @@ DatePicker is essential for any form that requires date input -- booking systems
28
28
  | disableFuture | — | — |
29
29
  | disablePast | — | — |
30
30
 
31
+ > ⚠️ **Usage Warning** ⚠️
32
+ >
33
+ > DatePicker involves complex date handling logic:
34
+ >
35
+ > - **Format vs DisplayFormat**: `format` affects the value in `onChange`, while `displayFormat` affects what users see
36
+ > - **Value format consistency**: The `value` and `defaultValue` props must match the `format` prop
37
+ > - **Date validation**: Invalid date strings can cause unexpected behavior
38
+ > - **Timezone considerations**: Be aware of timezone issues when working with dates
39
+
31
40
  ## Usage
32
41
 
33
42
  ```tsx
@@ -46,14 +55,19 @@ function DateForm() {
46
55
  }
47
56
  ```
48
57
 
49
- > **Use built-in form props**
50
- >
51
- > This component natively supports form elements such as `label` and `helperText` props.
52
- > When building forms, use these built-in props instead of manually composing labels and helper text with Typography.
58
+ ## Examples
59
+
60
+ ### Playground
61
+
62
+ Interactive example with all controls.
63
+
64
+ ```tsx
65
+ <DatePicker onChange={fn()} />
66
+ ```
53
67
 
54
- ## Sizes
68
+ ### Sizes
55
69
 
56
- DatePicker supports three sizes (`sm`, `md`, `lg`) to fit different layout densities.
70
+ DatePicker supports three sizes for different layouts.
57
71
 
58
72
  ```tsx
59
73
  <Stack gap={2}>
@@ -63,9 +77,9 @@ DatePicker supports three sizes (`sm`, `md`, `lg`) to fit different layout densi
63
77
  </Stack>
64
78
  ```
65
79
 
66
- ## Label and Helper Text
80
+ ### With Label
67
81
 
68
- Use the `label` prop to provide a visible label, and `helperText` to give users additional guidance about expected input.
82
+ Add a label above the date picker.
69
83
 
70
84
  ```tsx
71
85
  <DatePicker
@@ -74,6 +88,10 @@ Use the `label` prop to provide a visible label, and `helperText` to give users
74
88
  />
75
89
  ```
76
90
 
91
+ ### With Helper Text
92
+
93
+ Provide additional guidance below the input.
94
+
77
95
  ```tsx
78
96
  <DatePicker
79
97
  onChange={fn()}
@@ -82,9 +100,9 @@ Use the `label` prop to provide a visible label, and `helperText` to give users
82
100
  />
83
101
  ```
84
102
 
85
- ## Validation and Error State
103
+ ### Error State
86
104
 
87
- Set `error` to `true` and combine with `helperText` to communicate validation failures. Use the `required` prop to indicate mandatory fields.
105
+ Show validation errors with error styling.
88
106
 
89
107
  ```tsx
90
108
  <DatePicker
@@ -95,6 +113,10 @@ Set `error` to `true` and combine with `helperText` to communicate validation fa
95
113
  />
96
114
  ```
97
115
 
116
+ ### Required Field
117
+
118
+ Mark the field as required in forms.
119
+
98
120
  ```tsx
99
121
  <DatePicker
100
122
  onChange={fn()}
@@ -104,9 +126,9 @@ Set `error` to `true` and combine with `helperText` to communicate validation fa
104
126
  />
105
127
  ```
106
128
 
107
- ## Disabled and Read-Only States
129
+ ### Disabled
108
130
 
109
- The `disabled` prop prevents all interaction. The `readOnly` prop displays the value but blocks changes, while `inputReadOnly` disables keyboard typing but still allows calendar selection -- useful for mobile scenarios.
131
+ Prevent user interaction when disabled.
110
132
 
111
133
  ```tsx
112
134
  <DatePicker
@@ -115,25 +137,9 @@ The `disabled` prop prevents all interaction. The `readOnly` prop displays the v
115
137
  />
116
138
  ```
117
139
 
118
- ```tsx
119
- <DatePicker
120
- onChange={fn()}
121
- value="2024/04/01"
122
- readOnly
123
- />
124
- ```
140
+ ### Minimum Date
125
141
 
126
- ```tsx
127
- <DatePicker
128
- onChange={fn()}
129
- value="2024/04/01"
130
- inputReadOnly
131
- />
132
- ```
133
-
134
- ## Date Restrictions
135
-
136
- Restrict selectable dates using `minDate`, `maxDate`, `disablePast`, `disableFuture`, or the flexible `shouldDisableDate` callback for custom logic such as disabling weekends or holidays.
142
+ Restrict selection to dates on or after a minimum date.
137
143
 
138
144
  ```tsx
139
145
  <DatePicker
@@ -142,6 +148,10 @@ Restrict selectable dates using `minDate`, `maxDate`, `disablePast`, `disableFut
142
148
  />
143
149
  ```
144
150
 
151
+ ### Maximum Date
152
+
153
+ Restrict selection to dates on or before a maximum date.
154
+
145
155
  ```tsx
146
156
  <DatePicker
147
157
  onChange={fn()}
@@ -149,6 +159,10 @@ Restrict selectable dates using `minDate`, `maxDate`, `disablePast`, `disableFut
149
159
  />
150
160
  ```
151
161
 
162
+ ### Disable Future Dates
163
+
164
+ Prevent selection of dates in the future.
165
+
152
166
  ```tsx
153
167
  <DatePicker
154
168
  onChange={fn()}
@@ -156,24 +170,20 @@ Restrict selectable dates using `minDate`, `maxDate`, `disablePast`, `disableFut
156
170
  />
157
171
  ```
158
172
 
159
- ```tsx
160
- <DatePicker
161
- onChange={fn()}
162
- disablePast
163
- />
164
- ```
173
+ ### Disable Past Dates
174
+
175
+ Prevent selection of dates in the past.
165
176
 
166
177
  ```tsx
167
178
  <DatePicker
168
179
  onChange={fn()}
169
180
  disablePast
170
- shouldDisableDate={date => [0, 6].includes(new Date(date).getDay()) || new Date(date).getTime() >= new Date().getTime() + 7 * 24 * 60 * 60 * 1000}
171
181
  />
172
182
  ```
173
183
 
174
- ## Controlled vs Uncontrolled
184
+ ### Controlled
175
185
 
176
- DatePicker works in both controlled mode (you manage `value` via state) and uncontrolled mode (component manages its own state via `defaultValue`).
186
+ Parent component manages the date state.
177
187
 
178
188
  ```tsx
179
189
  <Stack gap={2}>
@@ -191,6 +201,10 @@ DatePicker works in both controlled mode (you manage `value` via state) and unco
191
201
  </Stack>
192
202
  ```
193
203
 
204
+ ### Uncontrolled
205
+
206
+ Component manages its own state internally.
207
+
194
208
  ```tsx
195
209
  <DatePicker
196
210
  onChange={fn()}
@@ -200,9 +214,9 @@ DatePicker works in both controlled mode (you manage `value` via state) and unco
200
214
  />
201
215
  ```
202
216
 
203
- ## Format and Display Format
217
+ ### With Formats
204
218
 
205
- The `format` prop determines the shape of the value emitted through `onChange`, while `displayFormat` controls what users see in the input field. This separation lets you keep a consistent API format (e.g. `YYYY-MM-DD`) while displaying a locale-appropriate format (e.g. `MM/DD/YYYY`).
219
+ Different value formats for the `onChange` event.
206
220
 
207
221
  ```tsx
208
222
  <Stack gap={2}>
@@ -215,6 +229,10 @@ The `format` prop determines the shape of the value emitted through `onChange`,
215
229
  </Stack>
216
230
  ```
217
231
 
232
+ ### With Display Formats
233
+
234
+ Different display formats shown in the input field.
235
+
218
236
  ```tsx
219
237
  <Stack gap={2}>
220
238
  <DatePicker {...args} value={value1} label="YYYY.MM.DD" name="YYYY.MM.DD" displayFormat="YYYY.MM.DD" onChange={e => {
@@ -244,38 +262,33 @@ The `format` prop determines the shape of the value emitted through `onChange`,
244
262
  </Stack>
245
263
  ```
246
264
 
247
- **Supported format tokens:**
265
+ ### Input Read Only
248
266
 
249
- | Token | Description | Example |
250
- | ------ | ------------- | ------- |
251
- | `YYYY` | 4-digit year | 2024 |
252
- | `MM` | 2-digit month | 04 |
253
- | `DD` | 2-digit day | 15 |
254
-
255
- Common patterns: `YYYY/MM/DD` (default), `YYYY-MM-DD` (ISO 8601), `MM/DD/YYYY` (US), `DD/MM/YYYY` (EU), `DD.MM.YYYY` (German), `YYYY.MM.DD` (East Asian).
267
+ Allow calendar selection only, prevent typing.
256
268
 
257
- ## Additional Features
269
+ ```tsx
270
+ <DatePicker
271
+ onChange={fn()}
272
+ value="2024/04/01"
273
+ inputReadOnly
274
+ />
275
+ ```
258
276
 
259
- ### Reset Button
277
+ ### Read Only
260
278
 
261
- Pair DatePicker with an external reset button to programmatically clear the value.
279
+ Fully read-only state with no interaction.
262
280
 
263
281
  ```tsx
264
- <div style={{
265
- display: 'flex',
266
- gap: '10px'
267
- }}>
268
- <DatePicker {...props} value={value} onChange={event => {
269
- onChange?.(event);
270
- setValue(event.target.value);
271
- }} />
272
- <Button onClick={() => setValue('')}>Reset</Button>
273
- </div>
282
+ <DatePicker
283
+ onChange={fn()}
284
+ value="2024/04/01"
285
+ readOnly
286
+ />
274
287
  ```
275
288
 
276
289
  ### Hide Clear Button
277
290
 
278
- Remove the built-in clear button from the calendar popup when clearing is not desired.
291
+ Remove the clear button from the calendar popup.
279
292
 
280
293
  ```tsx
281
294
  <DatePicker
@@ -285,9 +298,21 @@ Remove the built-in clear button from the calendar popup when clearing is not de
285
298
  />
286
299
  ```
287
300
 
301
+ ### Custom Date Disabling
302
+
303
+ Use `shouldDisableDate` to disable specific dates.
304
+
305
+ ```tsx
306
+ <DatePicker
307
+ onChange={fn()}
308
+ disablePast
309
+ shouldDisableDate={date => [0, 6].includes(new Date(date).getDay()) || new Date(date).getTime() >= new Date().getTime() + 7 * 24 * 60 * 60 * 1000}
310
+ />
311
+ ```
312
+
288
313
  ### Synchronized Date Pickers
289
314
 
290
- Multiple DatePicker instances can share the same value for dependent field scenarios.
315
+ Multiple date pickers sharing the same value.
291
316
 
292
317
  ```tsx
293
318
  <Stack gap={2}>
@@ -299,6 +324,25 @@ Multiple DatePicker instances can share the same value for dependent field scena
299
324
  </Stack>
300
325
  ```
301
326
 
327
+ ## When to Use
328
+
329
+ ### ✅ Good Use Cases
330
+
331
+ - **Form date fields**: Birthdays, appointment dates, due dates
332
+ - **Booking systems**: Hotel check-in/out, flight dates, reservations
333
+ - **Scheduling**: Event dates, meeting times, deadlines
334
+ - **Data filtering**: Date range filters in reports and dashboards
335
+ - **Historical data**: Recording when events occurred
336
+ - **Deadline selection**: Task due dates, project milestones
337
+
338
+ ### ❌ When Not to Use
339
+
340
+ - **Date ranges**: Use DateRangePicker for start/end date pairs
341
+ - **Month/Year only**: Use MonthPicker for month-level granularity
342
+ - **Time selection**: Use a dedicated TimePicker component
343
+ - **Relative dates**: For "last 7 days" style filters, use dropdown selection
344
+ - **Known date sets**: For selecting from predefined dates, consider Select or RadioButton
345
+
302
346
  ## Common Use Cases
303
347
 
304
348
  ### Form with Validation
@@ -313,6 +357,7 @@ function BookingForm() {
313
357
  setError('Please select a check-in date');
314
358
  return;
315
359
  }
360
+ // Submit form
316
361
  };
317
362
 
318
363
  return (
@@ -329,21 +374,62 @@ function BookingForm() {
329
374
  disablePast
330
375
  required
331
376
  />
377
+ <Button type="submit">Book Now</Button>
332
378
  </form>
333
379
  );
334
380
  }
335
381
  ```
336
382
 
337
- ### Custom Date Disabling (Weekdays Only)
383
+ ### Date Range Restriction
384
+
385
+ ```tsx
386
+ function EventScheduler() {
387
+ const [eventDate, setEventDate] = useState('');
388
+
389
+ // Event must be within the next 30 days
390
+ const today = new Date();
391
+ const maxDate = new Date(today.getTime() + 30 * 24 * 60 * 60 * 1000);
392
+
393
+ const formatDate = (date) => {
394
+ const year = date.getFullYear();
395
+ const month = String(date.getMonth() + 1).padStart(2, '0');
396
+ const day = String(date.getDate()).padStart(2, '0');
397
+ return `${year}/${month}/${day}`;
398
+ };
399
+
400
+ return (
401
+ <DatePicker
402
+ label="Event Date"
403
+ value={eventDate}
404
+ onChange={(e) => setEventDate(e.target.value)}
405
+ minDate={formatDate(today)}
406
+ maxDate={formatDate(maxDate)}
407
+ helperText="Select a date within the next 30 days"
408
+ />
409
+ );
410
+ }
411
+ ```
412
+
413
+ ### Custom Date Validation
338
414
 
339
415
  ```tsx
340
416
  function AppointmentPicker() {
341
417
  const [date, setDate] = useState('');
342
418
 
343
- const shouldDisableDate = useCallback((dateString: string) => {
344
- const day = new Date(dateString).getDay();
345
- return day === 0 || day === 6; // Disable weekends
346
- }, []);
419
+ // Disable weekends and holidays
420
+ const shouldDisableDate = (dateString) => {
421
+ const date = new Date(dateString);
422
+ const day = date.getDay();
423
+
424
+ // Disable weekends (Saturday = 6, Sunday = 0)
425
+ if (day === 0 || day === 6) return true;
426
+
427
+ // Disable specific holidays
428
+ const holidays = ['2024/01/01', '2024/12/25'];
429
+ if (holidays.includes(dateString)) return true;
430
+
431
+ return false;
432
+ };
347
433
 
348
434
  return (
349
435
  <DatePicker
@@ -352,89 +438,326 @@ function AppointmentPicker() {
352
438
  onChange={(e) => setDate(e.target.value)}
353
439
  shouldDisableDate={shouldDisableDate}
354
440
  disablePast
355
- helperText="Weekdays only"
441
+ helperText="Weekdays only, excluding holidays"
356
442
  />
357
443
  );
358
444
  }
359
445
  ```
360
446
 
361
- ### Locale-Aware Display
447
+ ### Different Regional Formats
362
448
 
363
449
  ```tsx
364
- function RegionalDateField({ locale }: { locale: string }) {
450
+ function RegionalDateForm({ locale }) {
365
451
  const [date, setDate] = useState('');
366
452
 
367
- const displayFormat = locale === 'en-US' ? 'MM/DD/YYYY'
368
- : locale === 'en-GB' ? 'DD/MM/YYYY'
369
- : 'YYYY-MM-DD';
453
+ // Format based on locale
454
+ const getDisplayFormat = () => {
455
+ switch (locale) {
456
+ case 'en-US':
457
+ return 'MM/DD/YYYY';
458
+ case 'en-GB':
459
+ return 'DD/MM/YYYY';
460
+ case 'de-DE':
461
+ return 'DD.MM.YYYY';
462
+ default:
463
+ return 'YYYY/MM/DD';
464
+ }
465
+ };
370
466
 
371
467
  return (
372
468
  <DatePicker
373
469
  label="Date"
374
470
  value={date}
375
471
  onChange={(e) => setDate(e.target.value)}
376
- format="YYYY/MM/DD"
377
- displayFormat={displayFormat}
472
+ format="YYYY/MM/DD" // Internal value format stays consistent
473
+ displayFormat={getDisplayFormat()} // Display varies by locale
474
+ />
475
+ );
476
+ }
477
+ ```
478
+
479
+ ### Mobile-Friendly Input
480
+
481
+ ```tsx
482
+ function MobileDatePicker() {
483
+ const [date, setDate] = useState('');
484
+
485
+ return (
486
+ <DatePicker
487
+ label="Select Date"
488
+ value={date}
489
+ onChange={(e) => setDate(e.target.value)}
490
+ inputReadOnly // Prevent keyboard on mobile, use calendar only
491
+ size="lg" // Larger touch targets
378
492
  />
379
493
  );
380
494
  }
381
495
  ```
382
496
 
497
+ ### Form Integration with React Hook Form
498
+
499
+ ```tsx
500
+ function DateFormWithHookForm() {
501
+ const { register, handleSubmit, setValue, watch } = useForm();
502
+ const birthDate = watch('birthDate');
503
+
504
+ return (
505
+ <form onSubmit={handleSubmit(onSubmit)}>
506
+ <DatePicker
507
+ label="Birth Date"
508
+ value={birthDate || ''}
509
+ onChange={(e) => setValue('birthDate', e.target.value)}
510
+ disableFuture
511
+ required
512
+ />
513
+ </form>
514
+ );
515
+ }
516
+ ```
517
+
518
+ ## Props and Customization
519
+
520
+ ### Key Props
521
+
522
+ | Prop | Type | Default | Description |
523
+ | ------------------- | ----------------------------------------------------------- | ---------------- | ------------------------------------------- |
524
+ | `value` | `string` | - | Controlled date value (must match `format`) |
525
+ | `defaultValue` | `string` | - | Default value for uncontrolled mode |
526
+ | `onChange` | `(e: { target: { name?: string; value: string } }) => void` | - | Change handler |
527
+ | `format` | `string` | `'YYYY/MM/DD'` | Format for `value` and `onChange` |
528
+ | `displayFormat` | `string` | Same as `format` | Format displayed in the input |
529
+ | `label` | `string` | - | Label text |
530
+ | `helperText` | `string` | - | Helper text below input |
531
+ | `error` | `boolean` | `false` | Error state |
532
+ | `size` | `'sm' \| 'md' \| 'lg'` | `'md'` | Component size |
533
+ | `disabled` | `boolean` | `false` | Disabled state |
534
+ | `required` | `boolean` | `false` | Required field indicator |
535
+ | `minDate` | `string` | - | Minimum selectable date |
536
+ | `maxDate` | `string` | - | Maximum selectable date |
537
+ | `disableFuture` | `boolean` | `false` | Disable all future dates |
538
+ | `disablePast` | `boolean` | `false` | Disable all past dates |
539
+ | `shouldDisableDate` | `(date: string) => boolean` | - | Custom date disable function |
540
+ | `inputReadOnly` | `boolean` | `false` | Prevent typing, calendar only |
541
+ | `readOnly` | `boolean` | `false` | Fully read-only |
542
+ | `hideClearButton` | `boolean` | `false` | Hide clear button in calendar |
543
+
544
+ ### Format vs DisplayFormat
545
+
546
+ Understanding the difference between `format` and `displayFormat`:
547
+
548
+ ```tsx
549
+ // format: Affects the value in onChange
550
+ // displayFormat: Affects what users see in the input
551
+
552
+ <DatePicker
553
+ format="YYYY-MM-DD" // onChange returns "2024-04-15"
554
+ displayFormat="MM/DD/YYYY" // Input shows "04/15/2024"
555
+ onChange={(e) => {
556
+ console.log(e.target.value); // "2024-04-15"
557
+ }}
558
+ />
559
+ ```
560
+
561
+ ### Supported Format Tokens
562
+
563
+ | Token | Description | Example |
564
+ | ------ | ------------- | ------- |
565
+ | `YYYY` | 4-digit year | 2024 |
566
+ | `MM` | 2-digit month | 04 |
567
+ | `DD` | 2-digit day | 15 |
568
+
569
+ Common format patterns:
570
+
571
+ - `YYYY/MM/DD` - ISO-like (default)
572
+ - `YYYY-MM-DD` - ISO 8601
573
+ - `MM/DD/YYYY` - US format
574
+ - `DD/MM/YYYY` - European format
575
+ - `DD.MM.YYYY` - German format
576
+ - `YYYY.MM.DD` - East Asian format
577
+
578
+ ### Controlled vs Uncontrolled
579
+
580
+ ```tsx
581
+ // Uncontrolled - component manages state
582
+ <DatePicker
583
+ defaultValue="2024/04/01"
584
+ onChange={(e) => console.log(e.target.value)}
585
+ />
586
+
587
+ // Controlled - you manage state
588
+ const [date, setDate] = useState('2024/04/01');
589
+ <DatePicker
590
+ value={date}
591
+ onChange={(e) => setDate(e.target.value)}
592
+ />
593
+ ```
594
+
595
+ ## Accessibility
596
+
597
+ DatePicker includes built-in accessibility features:
598
+
599
+ ### ARIA Attributes
600
+
601
+ - Input has proper `role="textbox"`
602
+ - Calendar button has `aria-label="Toggle Calendar"`
603
+ - Calendar popup uses `role="tooltip"` with proper labeling
604
+ - Date buttons announce the full date to screen readers
605
+
606
+ ### Keyboard Navigation
607
+
608
+ - **Tab**: Move focus between input and calendar button
609
+ - **Enter/Space**: Open calendar when focused on button
610
+ - **Arrow Keys**: Navigate within calendar
611
+ - **Escape**: Close calendar popup
612
+ - **Enter**: Select focused date
613
+
614
+ ### Screen Reader Support
615
+
616
+ ```tsx
617
+ // Dates are announced with full context
618
+ <button aria-label="April 15, 2024">15</button>
619
+
620
+ // Navigation buttons are descriptive
621
+ <button aria-label="Previous Month">←</button>
622
+ <button aria-label="Next Month">→</button>
623
+ ```
624
+
625
+ ### Focus Management
626
+
627
+ - Focus moves to calendar when opened
628
+ - Focus returns to input when calendar closes
629
+ - Clear visual focus indicators on all interactive elements
630
+
383
631
  ## Best Practices
384
632
 
385
- 1. **Always provide a label**
633
+ ### Do
634
+
635
+ 1. **Use appropriate date restrictions**: Set min/max dates when applicable
386
636
 
387
637
  ```tsx
388
- {/* Do */}
389
- <DatePicker label="Birth Date" />
638
+ // Good: Reasonable date constraints
639
+ <DatePicker
640
+ label="Birth Date"
641
+ disableFuture
642
+ minDate="1900/01/01"
643
+ />
644
+ ```
390
645
 
391
- {/* Don't */}
392
- <DatePicker placeholder="Birth Date" />
646
+ 2. **Provide clear labels and helper text**: Guide users on expected input
647
+
648
+ ```tsx
649
+ // ✅ Good: Clear guidance
650
+ <DatePicker
651
+ label="Preferred Delivery Date"
652
+ helperText="Select a weekday within the next 2 weeks"
653
+ />
393
654
  ```
394
655
 
395
- 2. **Keep value format consistent with the `format` prop**
656
+ 3. **Use consistent formats**: Match your application's locale conventions
396
657
 
397
658
  ```tsx
398
- {/* Do */}
399
- <DatePicker format="YYYY/MM/DD" value="2024/04/15" />
659
+ // Good: Consistent with app locale
660
+ <DatePicker
661
+ format="YYYY-MM-DD" // API format
662
+ displayFormat="MM/DD/YYYY" // US locale display
663
+ />
664
+ ```
400
665
 
401
- {/* Don't -- mismatched format causes unexpected behavior */}
402
- <DatePicker format="YYYY/MM/DD" value="04/15/2024" />
666
+ 4. **Handle empty states**: Consider what empty value means in your context
667
+
668
+ ```tsx
669
+ // ✅ Good: Clear empty state handling
670
+ const [date, setDate] = useState('');
671
+ {date ? <span>Selected: {date}</span> : <span>No date selected</span>}
403
672
  ```
404
673
 
405
- 3. **Use `displayFormat` to separate API format from UI format**
674
+ ### Don't
675
+
676
+ 1. **Don't use inconsistent value formats**: Always match value format to `format` prop
406
677
 
407
678
  ```tsx
408
- {/* Do -- consistent API format, locale-appropriate display */}
409
- <DatePicker format="YYYY-MM-DD" displayFormat="MM/DD/YYYY" />
679
+ // Bad: Mismatched formats
680
+ <DatePicker
681
+ format="YYYY/MM/DD"
682
+ value="04/15/2024" // Wrong! Should be "2024/04/15"
683
+ />
684
+ ```
410
685
 
411
- {/* Don't -- changing format just for display affects onChange values */}
412
- <DatePicker format="MM/DD/YYYY" />
686
+ 2. **Don't disable validation feedback**: Show errors when dates are invalid
687
+
688
+ ```tsx
689
+ // ❌ Bad: No error feedback
690
+ <DatePicker value={invalidDate} />
691
+
692
+ // ✅ Good: Show validation state
693
+ <DatePicker value={date} error={!isValid} helperText={errorMessage} />
413
694
  ```
414
695
 
415
- 4. **Set appropriate date boundaries for your use case**
696
+ 3. **Don't forget mobile users**: Use `inputReadOnly` for better mobile experience
697
+
698
+ 4. **Don't use placeholder as label**: Use the `label` prop instead
416
699
 
417
700
  ```tsx
418
- {/* Do */}
419
- <DatePicker label="Birth Date" disableFuture minDate="1900/01/01" />
701
+ // Bad: Placeholder as label
702
+ <DatePicker placeholder="Birth Date" />
420
703
 
421
- {/* Don't -- unrestricted date range for a birth date field */}
704
+ // Good: Proper label
422
705
  <DatePicker label="Birth Date" />
423
706
  ```
424
707
 
425
- 5. **Show validation feedback with error and helperText**
708
+ ## Performance Considerations
709
+
710
+ ### Memoize shouldDisableDate
711
+
712
+ For complex date validation logic, memoize the function:
426
713
 
427
714
  ```tsx
428
- {/* Do */}
429
- <DatePicker error={!isValid} helperText={errorMessage} />
715
+ const shouldDisableDate = useCallback((dateString) => {
716
+ const date = new Date(dateString);
717
+ // Complex validation logic
718
+ return isHoliday(date) || isWeekend(date);
719
+ }, [holidays]); // Only recreate when holidays change
430
720
 
431
- {/* Don't -- silently ignore invalid state */}
432
- <DatePicker value={invalidDate} />
721
+ <DatePicker shouldDisableDate={shouldDisableDate} />
433
722
  ```
434
723
 
435
- ## Accessibility
724
+ ### Controlled Component Optimization
725
+
726
+ When using controlled mode, avoid unnecessary state updates:
727
+
728
+ ```tsx
729
+ const handleChange = useCallback((e) => {
730
+ setDate(e.target.value);
731
+ }, []);
732
+
733
+ <DatePicker value={date} onChange={handleChange} />
734
+ ```
735
+
736
+ ### Format Conversion
737
+
738
+ When working with APIs that expect different date formats:
739
+
740
+ ```tsx
741
+ function DateField({ value, onChange, apiFormat = 'YYYY-MM-DD' }) {
742
+ // Convert from API format to display
743
+ const displayValue = useMemo(() =>
744
+ convertFormat(value, apiFormat, 'YYYY/MM/DD'),
745
+ [value, apiFormat]
746
+ );
747
+
748
+ const handleChange = useCallback((e) => {
749
+ // Convert back to API format
750
+ onChange(convertFormat(e.target.value, 'YYYY/MM/DD', apiFormat));
751
+ }, [onChange, apiFormat]);
752
+
753
+ return (
754
+ <DatePicker
755
+ value={displayValue}
756
+ onChange={handleChange}
757
+ format="YYYY/MM/DD"
758
+ />
759
+ );
760
+ }
761
+ ```
436
762
 
437
- - **Keyboard navigation**: Tab moves focus between the input and the calendar toggle button. Arrow keys navigate dates within the open calendar. Enter selects the focused date, and Escape closes the calendar popup.
438
- - **ARIA attributes**: The calendar toggle button has `aria-label="Toggle Calendar"`. The calendar popup uses `role="tooltip"` with descriptive labeling. Each date button announces the full date to screen readers.
439
- - **Focus management**: Focus moves into the calendar when opened and returns to the input when the calendar closes. All interactive elements have clear focus indicators.
440
- - **Use `inputReadOnly` on mobile**: When targeting touch devices, set `inputReadOnly` to prevent the virtual keyboard from appearing and guide users toward the calendar picker instead.
763
+ DatePicker is a fundamental form component for date input. Choose appropriate date restrictions based on your use case, maintain consistent formats throughout your application, and provide clear guidance to users for the best experience.