@ceed/ads 1.20.0 → 1.20.1-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 (30) hide show
  1. package/dist/components/ProfileMenu/ProfileMenu.d.ts +1 -1
  2. package/dist/components/data-display/Markdown.md +832 -0
  3. package/dist/components/feedback/Dialog.md +605 -3
  4. package/dist/components/feedback/Modal.md +656 -24
  5. package/dist/components/feedback/llms.txt +1 -1
  6. package/dist/components/inputs/Autocomplete.md +734 -2
  7. package/dist/components/inputs/Calendar.md +655 -1
  8. package/dist/components/inputs/DatePicker.md +699 -3
  9. package/dist/components/inputs/DateRangePicker.md +815 -1
  10. package/dist/components/inputs/MonthPicker.md +626 -4
  11. package/dist/components/inputs/MonthRangePicker.md +682 -4
  12. package/dist/components/inputs/Select.md +600 -0
  13. package/dist/components/layout/Container.md +507 -0
  14. package/dist/components/navigation/Breadcrumbs.md +582 -0
  15. package/dist/components/navigation/IconMenuButton.md +693 -0
  16. package/dist/components/navigation/InsetDrawer.md +1150 -3
  17. package/dist/components/navigation/Link.md +526 -0
  18. package/dist/components/navigation/MenuButton.md +632 -0
  19. package/dist/components/navigation/NavigationGroup.md +401 -1
  20. package/dist/components/navigation/NavigationItem.md +311 -0
  21. package/dist/components/navigation/Navigator.md +373 -0
  22. package/dist/components/navigation/Pagination.md +521 -0
  23. package/dist/components/navigation/ProfileMenu.md +605 -0
  24. package/dist/components/navigation/Tabs.md +609 -7
  25. package/dist/components/surfaces/Accordions.md +947 -3
  26. package/dist/index.cjs +3 -1
  27. package/dist/index.js +3 -1
  28. package/dist/llms.txt +1 -1
  29. package/framer/index.js +1 -1
  30. package/package.json +3 -2
@@ -2,6 +2,8 @@
2
2
 
3
3
  ## Introduction
4
4
 
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
+
5
7
  ```tsx
6
8
  <DatePicker onChange={fn()} />
7
9
  ```
@@ -26,8 +28,47 @@
26
28
  | disableFuture | — | — |
27
29
  | disablePast | — | — |
28
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
+
40
+ ## Usage
41
+
42
+ ```tsx
43
+ import { DatePicker } from '@ceed/ads';
44
+
45
+ function DateForm() {
46
+ const [date, setDate] = useState('');
47
+
48
+ return (
49
+ <DatePicker
50
+ label="Select Date"
51
+ value={date}
52
+ onChange={(e) => setDate(e.target.value)}
53
+ />
54
+ );
55
+ }
56
+ ```
57
+
58
+ ## Examples
59
+
60
+ ### Playground
61
+
62
+ Interactive example with all controls.
63
+
64
+ ```tsx
65
+ <DatePicker onChange={fn()} />
66
+ ```
67
+
29
68
  ### Sizes
30
69
 
70
+ DatePicker supports three sizes for different layouts.
71
+
31
72
  ```tsx
32
73
  <Stack gap={2}>
33
74
  <DatePicker {...args} size="sm" />
@@ -36,7 +77,9 @@
36
77
  </Stack>
37
78
  ```
38
79
 
39
- ### WithLabel
80
+ ### With Label
81
+
82
+ Add a label above the date picker.
40
83
 
41
84
  ```tsx
42
85
  <DatePicker
@@ -45,7 +88,9 @@
45
88
  />
46
89
  ```
47
90
 
48
- ### WithHelperText
91
+ ### With Helper Text
92
+
93
+ Provide additional guidance below the input.
49
94
 
50
95
  ```tsx
51
96
  <DatePicker
@@ -55,7 +100,9 @@
55
100
  />
56
101
  ```
57
102
 
58
- ### Error
103
+ ### Error State
104
+
105
+ Show validation errors with error styling.
59
106
 
60
107
  ```tsx
61
108
  <DatePicker
@@ -65,3 +112,652 @@
65
112
  error
66
113
  />
67
114
  ```
115
+
116
+ ### Required Field
117
+
118
+ Mark the field as required in forms.
119
+
120
+ ```tsx
121
+ <DatePicker
122
+ onChange={fn()}
123
+ label="Label"
124
+ helperText="I'm helper text"
125
+ required
126
+ />
127
+ ```
128
+
129
+ ### Disabled
130
+
131
+ Prevent user interaction when disabled.
132
+
133
+ ```tsx
134
+ <DatePicker
135
+ onChange={fn()}
136
+ disabled
137
+ />
138
+ ```
139
+
140
+ ### Minimum Date
141
+
142
+ Restrict selection to dates on or after a minimum date.
143
+
144
+ ```tsx
145
+ <DatePicker
146
+ onChange={fn()}
147
+ minDate="2024-04-10"
148
+ />
149
+ ```
150
+
151
+ ### Maximum Date
152
+
153
+ Restrict selection to dates on or before a maximum date.
154
+
155
+ ```tsx
156
+ <DatePicker
157
+ onChange={fn()}
158
+ maxDate="2024-04-10"
159
+ />
160
+ ```
161
+
162
+ ### Disable Future Dates
163
+
164
+ Prevent selection of dates in the future.
165
+
166
+ ```tsx
167
+ <DatePicker
168
+ onChange={fn()}
169
+ disableFuture
170
+ />
171
+ ```
172
+
173
+ ### Disable Past Dates
174
+
175
+ Prevent selection of dates in the past.
176
+
177
+ ```tsx
178
+ <DatePicker
179
+ onChange={fn()}
180
+ disablePast
181
+ />
182
+ ```
183
+
184
+ ### Controlled
185
+
186
+ Parent component manages the date state.
187
+
188
+ ```tsx
189
+ <Stack gap={2}>
190
+ <DatePicker {...args} value={value} onChange={e => setValue(e.target.value)} />
191
+ <Button onClick={() => {
192
+ const currentValue = new Date(value);
193
+ currentValue.setDate(currentValue.getDate() + 1);
194
+ const year = currentValue.getFullYear();
195
+ const month = String(currentValue.getMonth() + 1).padStart(2, '0');
196
+ const day = String(currentValue.getDate()).padStart(2, '0');
197
+ setValue(`${year}/${month}/${day}`);
198
+ }}>
199
+ Next Day
200
+ </Button>
201
+ </Stack>
202
+ ```
203
+
204
+ ### Uncontrolled
205
+
206
+ Component manages its own state internally.
207
+
208
+ ```tsx
209
+ <DatePicker
210
+ onChange={fn()}
211
+ label="Uncontrolled DatePicker"
212
+ helperText="Please select a date"
213
+ defaultValue="2024/04/01"
214
+ />
215
+ ```
216
+
217
+ ### With Formats
218
+
219
+ Different value formats for the `onChange` event.
220
+
221
+ ```tsx
222
+ <Stack gap={2}>
223
+ <DatePicker {...args} value={value['YYYY.MM.DD']} label="YYYY.MM.DD" name="YYYY.MM.DD" format="YYYY.MM.DD" onChange={handleChange} />
224
+ <DatePicker {...args} value={value['YYYY/MM/DD']} label="YYYY/MM/DD" name="YYYY/MM/DD" format="YYYY/MM/DD" onChange={handleChange} />
225
+ <DatePicker {...args} value={value['MM/DD/YYYY']} label="MM/DD/YYYY" name="MM/DD/YYYY" format="MM/DD/YYYY" onChange={handleChange} />
226
+ <DatePicker {...args} value={value['YYYY-MM-DD']} label="YYYY-MM-DD" name="YYYY-MM-DD" format="YYYY-MM-DD" onChange={handleChange} />
227
+ <DatePicker {...args} value={value['DD/MM/YYYY']} label="DD/MM/YYYY" name="DD/MM/YYYY" format="DD/MM/YYYY" onChange={handleChange} />
228
+ <DatePicker {...args} value={value['DD.MM.YYYY']} label="DD.MM.YYYY" name="DD.MM.YYYY" format="DD.MM.YYYY" onChange={handleChange} />
229
+ </Stack>
230
+ ```
231
+
232
+ ### With Display Formats
233
+
234
+ Different display formats shown in the input field.
235
+
236
+ ```tsx
237
+ <Stack gap={2}>
238
+ <DatePicker {...args} value={value1} label="YYYY.MM.DD" name="YYYY.MM.DD" displayFormat="YYYY.MM.DD" onChange={e => {
239
+ setValue1(e.target.value);
240
+ args.onChange?.(e);
241
+ }} />
242
+ <DatePicker {...args} value={value2} label="YYYY/MM/DD" name="YYYY/MM/DD" displayFormat="YYYY/MM/DD" onChange={e => {
243
+ setValue2(e.target.value);
244
+ args.onChange?.(e);
245
+ }} />
246
+ <DatePicker {...args} value={value3} label="MM/DD/YYYY" name="MM/DD/YYYY" displayFormat="MM/DD/YYYY" onChange={e => {
247
+ setValue3(e.target.value);
248
+ args.onChange?.(e);
249
+ }} />
250
+ <DatePicker {...args} value={value4} label="YYYY-MM-DD" name="YYYY-MM-DD" displayFormat="YYYY-MM-DD" onChange={e => {
251
+ setValue4(e.target.value);
252
+ args.onChange?.(e);
253
+ }} />
254
+ <DatePicker {...args} value={value5} label="DD/MM/YYYY" name="DD/MM/YYYY" displayFormat="DD/MM/YYYY" onChange={e => {
255
+ setValue5(e.target.value);
256
+ args.onChange?.(e);
257
+ }} />
258
+ <DatePicker {...args} value={value6} label="DD.MM.YYYY" name="DD.MM.YYYY" displayFormat="DD.MM.YYYY" onChange={e => {
259
+ setValue6(e.target.value);
260
+ args.onChange?.(e);
261
+ }} />
262
+ </Stack>
263
+ ```
264
+
265
+ ### Input Read Only
266
+
267
+ Allow calendar selection only, prevent typing.
268
+
269
+ ```tsx
270
+ <DatePicker
271
+ onChange={fn()}
272
+ value="2024/04/01"
273
+ inputReadOnly
274
+ />
275
+ ```
276
+
277
+ ### Read Only
278
+
279
+ Fully read-only state with no interaction.
280
+
281
+ ```tsx
282
+ <DatePicker
283
+ onChange={fn()}
284
+ value="2024/04/01"
285
+ readOnly
286
+ />
287
+ ```
288
+
289
+ ### Hide Clear Button
290
+
291
+ Remove the clear button from the calendar popup.
292
+
293
+ ```tsx
294
+ <DatePicker
295
+ onChange={fn()}
296
+ value="2024/04/01"
297
+ hideClearButton
298
+ />
299
+ ```
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
+
313
+ ### Synchronized Date Pickers
314
+
315
+ Multiple date pickers sharing the same value.
316
+
317
+ ```tsx
318
+ <Stack gap={2}>
319
+ <DatePicker label="Select Date" value={value} inputReadOnly onChange={e => {
320
+ setValue(e.target.value);
321
+ setValue2(e.target.value);
322
+ }} />
323
+ <DatePicker label="Synchronized" value={value2} disabled />
324
+ </Stack>
325
+ ```
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
+
346
+ ## Common Use Cases
347
+
348
+ ### Form with Validation
349
+
350
+ ```tsx
351
+ function BookingForm() {
352
+ const [checkIn, setCheckIn] = useState('');
353
+ const [error, setError] = useState('');
354
+
355
+ const handleSubmit = () => {
356
+ if (!checkIn) {
357
+ setError('Please select a check-in date');
358
+ return;
359
+ }
360
+ // Submit form
361
+ };
362
+
363
+ return (
364
+ <form onSubmit={handleSubmit}>
365
+ <DatePicker
366
+ label="Check-in Date"
367
+ value={checkIn}
368
+ onChange={(e) => {
369
+ setCheckIn(e.target.value);
370
+ setError('');
371
+ }}
372
+ error={!!error}
373
+ helperText={error || 'Select your arrival date'}
374
+ disablePast
375
+ required
376
+ />
377
+ <Button type="submit">Book Now</Button>
378
+ </form>
379
+ );
380
+ }
381
+ ```
382
+
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
414
+
415
+ ```tsx
416
+ function AppointmentPicker() {
417
+ const [date, setDate] = useState('');
418
+
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
+ };
433
+
434
+ return (
435
+ <DatePicker
436
+ label="Appointment Date"
437
+ value={date}
438
+ onChange={(e) => setDate(e.target.value)}
439
+ shouldDisableDate={shouldDisableDate}
440
+ disablePast
441
+ helperText="Weekdays only, excluding holidays"
442
+ />
443
+ );
444
+ }
445
+ ```
446
+
447
+ ### Different Regional Formats
448
+
449
+ ```tsx
450
+ function RegionalDateForm({ locale }) {
451
+ const [date, setDate] = useState('');
452
+
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
+ };
466
+
467
+ return (
468
+ <DatePicker
469
+ label="Date"
470
+ value={date}
471
+ onChange={(e) => setDate(e.target.value)}
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
492
+ />
493
+ );
494
+ }
495
+ ```
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
+
631
+ ## Best Practices
632
+
633
+ ### ✅ Do
634
+
635
+ 1. **Use appropriate date restrictions**: Set min/max dates when applicable
636
+
637
+ ```tsx
638
+ // ✅ Good: Reasonable date constraints
639
+ <DatePicker
640
+ label="Birth Date"
641
+ disableFuture
642
+ minDate="1900/01/01"
643
+ />
644
+ ```
645
+
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
+ />
654
+ ```
655
+
656
+ 3. **Use consistent formats**: Match your application's locale conventions
657
+
658
+ ```tsx
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
+ ```
665
+
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>}
672
+ ```
673
+
674
+ ### ❌ Don't
675
+
676
+ 1. **Don't use inconsistent value formats**: Always match value format to `format` prop
677
+
678
+ ```tsx
679
+ // ❌ Bad: Mismatched formats
680
+ <DatePicker
681
+ format="YYYY/MM/DD"
682
+ value="04/15/2024" // Wrong! Should be "2024/04/15"
683
+ />
684
+ ```
685
+
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} />
694
+ ```
695
+
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
699
+
700
+ ```tsx
701
+ // ❌ Bad: Placeholder as label
702
+ <DatePicker placeholder="Birth Date" />
703
+
704
+ // ✅ Good: Proper label
705
+ <DatePicker label="Birth Date" />
706
+ ```
707
+
708
+ ## Performance Considerations
709
+
710
+ ### Memoize shouldDisableDate
711
+
712
+ For complex date validation logic, memoize the function:
713
+
714
+ ```tsx
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
720
+
721
+ <DatePicker shouldDisableDate={shouldDisableDate} />
722
+ ```
723
+
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
+ ```
762
+
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.