@ceed/ads 1.23.3 → 1.23.5

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 (43) hide show
  1. package/dist/components/data-display/Badge.md +71 -39
  2. package/dist/components/data-display/InfoSign.md +74 -98
  3. package/dist/components/data-display/Typography.md +310 -61
  4. package/dist/components/feedback/CircularProgress.md +257 -0
  5. package/dist/components/feedback/Skeleton.md +280 -0
  6. package/dist/components/feedback/llms.txt +2 -0
  7. package/dist/components/inputs/ButtonGroup.md +115 -106
  8. package/dist/components/inputs/Calendar.md +98 -459
  9. package/dist/components/inputs/CurrencyInput.md +181 -8
  10. package/dist/components/inputs/DatePicker.md +108 -436
  11. package/dist/components/inputs/DateRangePicker.md +130 -496
  12. package/dist/components/inputs/FilterMenu.md +169 -19
  13. package/dist/components/inputs/FilterableCheckboxGroup.md +119 -24
  14. package/dist/components/inputs/FormControl.md +361 -0
  15. package/dist/components/inputs/IconButton.md +137 -88
  16. package/dist/components/inputs/MonthPicker.md +95 -427
  17. package/dist/components/inputs/MonthRangePicker.md +89 -471
  18. package/dist/components/inputs/PercentageInput.md +183 -19
  19. package/dist/components/inputs/RadioButton.md +163 -35
  20. package/dist/components/inputs/RadioList.md +241 -0
  21. package/dist/components/inputs/RadioTileGroup.md +146 -62
  22. package/dist/components/inputs/Select.md +219 -328
  23. package/dist/components/inputs/Slider.md +334 -0
  24. package/dist/components/inputs/Switch.md +136 -376
  25. package/dist/components/inputs/Textarea.md +209 -11
  26. package/dist/components/inputs/Uploader/Uploader.md +145 -66
  27. package/dist/components/inputs/llms.txt +3 -0
  28. package/dist/components/navigation/Breadcrumbs.md +80 -322
  29. package/dist/components/navigation/Dropdown.md +92 -221
  30. package/dist/components/navigation/IconMenuButton.md +40 -502
  31. package/dist/components/navigation/InsetDrawer.md +68 -738
  32. package/dist/components/navigation/Link.md +39 -298
  33. package/dist/components/navigation/Menu.md +92 -285
  34. package/dist/components/navigation/MenuButton.md +55 -448
  35. package/dist/components/navigation/Pagination.md +47 -338
  36. package/dist/components/navigation/ProfileMenu.md +45 -268
  37. package/dist/components/navigation/Stepper.md +160 -28
  38. package/dist/components/navigation/Tabs.md +57 -316
  39. package/dist/components/surfaces/Sheet.md +150 -333
  40. package/dist/guides/ThemeProvider.md +116 -0
  41. package/dist/guides/llms.txt +9 -0
  42. package/dist/llms.txt +8 -0
  43. package/package.json +1 -1
@@ -2,7 +2,9 @@
2
2
 
3
3
  ## Introduction
4
4
 
5
- MonthPicker is a form input component that allows users to select a specific month and year from a calendar popup. Unlike DatePicker which allows day-level selection, MonthPicker focuses on month-level granularity. It displays months in a grid format for easy selection and is ideal for scenarios like billing periods, report months, subscription dates, or any use case where day-level precision is unnecessary.
5
+ MonthPicker is a form input component that allows users to select a specific month and year from a calendar popup. Unlike DatePicker which provides day-level selection, MonthPicker focuses on month-level granularity and displays months in a grid format for quick selection.
6
+
7
+ It is ideal for scenarios like billing periods, report months, subscription dates, or any use case where day-level precision is unnecessary. The component supports multiple value formats and display formats, controlled and uncontrolled modes, and date range constraints.
6
8
 
7
9
  ```tsx
8
10
  <MonthPicker />
@@ -25,20 +27,6 @@ MonthPicker is a form input component that allows users to select a specific mon
25
27
  | format | — | — |
26
28
  | onChange | — | — |
27
29
 
28
- > ⚠️ **Usage Warning** ⚠️
29
- >
30
- > MonthPicker has some unique formatting behaviors:
31
- >
32
- > - **Internal value format**: Values internally use full date format (`"YYYY/MM/DD"`) with day set to `01`
33
- > - **Display vs Value**: Input displays `YYYY/MM` but `onChange` receives `YYYY/MM/01`
34
- > - **Format consistency**: Ensure your `value` prop matches the `format` prop
35
- > - **displayFormat options**: Supports special token `MMMM` for full month names
36
-
37
- > 💡 **Use built-in form props**
38
- >
39
- > This component natively supports form elements such as `label` and `helperText` props.
40
- > When building forms, use these built-in props instead of manually composing labels and helper text with Typography.
41
-
42
30
  ## Usage
43
31
 
44
32
  ```tsx
@@ -57,19 +45,14 @@ function MonthForm() {
57
45
  }
58
46
  ```
59
47
 
60
- ## Examples
61
-
62
- ### Playground
63
-
64
- Interactive example with all controls.
65
-
66
- ```tsx
67
- <MonthPicker />
68
- ```
48
+ > 💡 **Use built-in form props**
49
+ >
50
+ > This component natively supports form elements such as `label` and `helperText` props.
51
+ > When building forms, use these built-in props instead of manually composing labels and helper text with Typography.
69
52
 
70
- ### Sizes
53
+ ## Sizes
71
54
 
72
- MonthPicker supports three sizes for different layouts.
55
+ MonthPicker supports three sizes (`sm`, `md`, `lg`) for different layouts and contexts.
73
56
 
74
57
  ```tsx
75
58
  <Stack gap={2}>
@@ -79,9 +62,11 @@ MonthPicker supports three sizes for different layouts.
79
62
  </Stack>
80
63
  ```
81
64
 
65
+ ## Form Field Features
66
+
82
67
  ### With Label
83
68
 
84
- Add a label above the month picker.
69
+ Add a label above the month picker to indicate the field purpose.
85
70
 
86
71
  ```tsx
87
72
  <MonthPicker label="Date" />
@@ -89,7 +74,7 @@ Add a label above the month picker.
89
74
 
90
75
  ### With Helper Text
91
76
 
92
- Provide additional guidance below the input.
77
+ Provide additional guidance below the input to help users understand the expected selection.
93
78
 
94
79
  ```tsx
95
80
  <MonthPicker
@@ -98,41 +83,43 @@ Provide additional guidance below the input.
98
83
  />
99
84
  ```
100
85
 
101
- ### Error State
86
+ ### Required Field
102
87
 
103
- Show validation errors with error styling.
88
+ Mark the field as required in forms. An asterisk indicator is displayed alongside the label.
104
89
 
105
90
  ```tsx
106
91
  <MonthPicker
107
- label="Date"
108
- helperText="Please select a date"
109
- error
92
+ label="Label"
93
+ helperText="I'm helper text"
94
+ required
110
95
  />
111
96
  ```
112
97
 
113
- ### Required Field
98
+ ### Error State
114
99
 
115
- Mark the field as required in forms.
100
+ Display validation errors with error styling applied to the input, label, and helper text.
116
101
 
117
102
  ```tsx
118
103
  <MonthPicker
119
- label="Label"
120
- helperText="I'm helper text"
121
- required
104
+ label="Date"
105
+ helperText="Please select a date"
106
+ error
122
107
  />
123
108
  ```
124
109
 
125
110
  ### Disabled
126
111
 
127
- Prevent user interaction when disabled.
112
+ Prevent user interaction when the picker is disabled.
128
113
 
129
114
  ```tsx
130
115
  <MonthPicker disabled />
131
116
  ```
132
117
 
118
+ ## Date Constraints
119
+
133
120
  ### Minimum Date
134
121
 
135
- Restrict selection to months on or after a minimum date.
122
+ Restrict selection to months on or after a minimum date. Months before the limit are visually disabled.
136
123
 
137
124
  ```tsx
138
125
  <MonthPicker minDate="2024-04-10" />
@@ -140,7 +127,7 @@ Restrict selection to months on or after a minimum date.
140
127
 
141
128
  ### Maximum Date
142
129
 
143
- Restrict selection to months on or before a maximum date.
130
+ Restrict selection to months on or before a maximum date. Months after the limit are visually disabled.
144
131
 
145
132
  ```tsx
146
133
  <MonthPicker maxDate="2024-04-10" />
@@ -148,7 +135,7 @@ Restrict selection to months on or before a maximum date.
148
135
 
149
136
  ### Disable Future
150
137
 
151
- Prevent selection of months in the future.
138
+ Prevent selection of any month in the future, relative to the current date.
152
139
 
153
140
  ```tsx
154
141
  <MonthPicker disableFuture />
@@ -156,15 +143,17 @@ Prevent selection of months in the future.
156
143
 
157
144
  ### Disable Past
158
145
 
159
- Prevent selection of months in the past.
146
+ Prevent selection of any month in the past, relative to the current date.
160
147
 
161
148
  ```tsx
162
149
  <MonthPicker disablePast />
163
150
  ```
164
151
 
152
+ ## Controlled vs Uncontrolled
153
+
165
154
  ### Controlled
166
155
 
167
- Parent component manages the month state.
156
+ The parent component manages the month state via the `value` and `onChange` props. External buttons or logic can programmatically update the selected value.
168
157
 
169
158
  ```tsx
170
159
  <Stack gap={2}>
@@ -183,7 +172,7 @@ Parent component manages the month state.
183
172
 
184
173
  ### Uncontrolled
185
174
 
186
- Component manages its own state internally.
175
+ The component manages its own state internally using `defaultValue`. The parent can still listen for changes via `onChange`.
187
176
 
188
177
  ```tsx
189
178
  <MonthPicker
@@ -193,9 +182,11 @@ Component manages its own state internally.
193
182
  />
194
183
  ```
195
184
 
196
- ### With Formats
185
+ ## Formats
186
+
187
+ ### Value Formats
197
188
 
198
- Different value formats for the `onChange` event.
189
+ The `format` prop determines the shape of the value emitted by `onChange`. Each format includes a day component (set to `01`). The display always defaults to `YYYY/MM` unless `displayFormat` is also set.
199
190
 
200
191
  ```tsx
201
192
  <Stack gap={2}>
@@ -208,9 +199,9 @@ Different value formats for the `onChange` event.
208
199
  </Stack>
209
200
  ```
210
201
 
211
- ### With Display Formats
202
+ ### Display Formats
212
203
 
213
- Different display formats including full month names.
204
+ The `displayFormat` prop controls what users see in the input field, independent of the underlying value format. Supports the special token `MMMM` for full month names.
214
205
 
215
206
  ```tsx
216
207
  <Stack gap={2}>
@@ -241,24 +232,21 @@ Different display formats including full month names.
241
232
  </Stack>
242
233
  ```
243
234
 
244
- ## When to Use
245
-
246
- ### ✅ Good Use Cases
247
-
248
- - **Billing periods**: Monthly invoices, subscription billing cycles
249
- - **Report filtering**: Monthly reports, quarterly summaries
250
- - **Fiscal periods**: Fiscal months, budget allocation periods
251
- - **Expiration dates**: Credit card expiry (month/year)
252
- - **Historical data**: Selecting past months for data analysis
253
- - **Scheduling**: Monthly recurring events
235
+ ### With Reset Button
254
236
 
255
- ### When Not to Use
237
+ A controlled example with an external reset button to clear the selected value.
256
238
 
257
- - **Specific dates**: Use DatePicker when day selection matters
258
- - **Date ranges**: Use DateRangePicker or MonthRangePicker
259
- - **Week selection**: Consider a custom week picker
260
- - **Quarter selection**: Consider a dropdown with Q1-Q4 options
261
- - **Year only**: Use a year picker or simple dropdown
239
+ ```tsx
240
+ <div style={{
241
+ display: 'flex',
242
+ gap: '10px'
243
+ }}>
244
+ <MonthPicker {...props} value={value} onChange={event => {
245
+ setValue(event.target.value);
246
+ }} />
247
+ <Button onClick={() => setValue('')}>Reset</Button>
248
+ </div>
249
+ ```
262
250
 
263
251
  ## Common Use Cases
264
252
 
@@ -268,55 +256,32 @@ Different display formats including full month names.
268
256
  function BillingPeriodSelector() {
269
257
  const [billingMonth, setBillingMonth] = useState('');
270
258
 
271
- const handleGenerate = () => {
272
- const [year, month] = billingMonth.split('/');
273
- generateInvoice({ year: parseInt(year), month: parseInt(month) });
274
- };
275
-
276
259
  return (
277
- <Stack gap={2}>
278
- <MonthPicker
279
- label="Billing Period"
280
- value={billingMonth}
281
- onChange={(e) => setBillingMonth(e.target.value)}
282
- disableFuture
283
- helperText="Select the month for invoice generation"
284
- />
285
- <Button onClick={handleGenerate} disabled={!billingMonth}>
286
- Generate Invoice
287
- </Button>
288
- </Stack>
260
+ <MonthPicker
261
+ label="Billing Period"
262
+ value={billingMonth}
263
+ onChange={(e) => setBillingMonth(e.target.value)}
264
+ disableFuture
265
+ helperText="Select the month for invoice generation"
266
+ />
289
267
  );
290
268
  }
291
269
  ```
292
270
 
293
- ### Report Month Filter
271
+ ### Report Month Filter with Display Format
294
272
 
295
273
  ```tsx
296
- function ReportFilters({ onFilter }) {
274
+ function ReportFilter() {
297
275
  const [reportMonth, setReportMonth] = useState('');
298
276
 
299
- // Get current month as default
300
- useEffect(() => {
301
- const now = new Date();
302
- const year = now.getFullYear();
303
- const month = String(now.getMonth() + 1).padStart(2, '0');
304
- setReportMonth(`${year}/${month}/01`);
305
- }, []);
306
-
307
277
  return (
308
- <Stack direction="row" gap={2} alignItems="flex-end">
309
- <MonthPicker
310
- label="Report Month"
311
- value={reportMonth}
312
- onChange={(e) => setReportMonth(e.target.value)}
313
- disableFuture
314
- displayFormat="MMMM YYYY" // Shows "January 2024"
315
- />
316
- <Button onClick={() => onFilter(reportMonth)}>
317
- Generate Report
318
- </Button>
319
- </Stack>
278
+ <MonthPicker
279
+ label="Report Month"
280
+ value={reportMonth}
281
+ onChange={(e) => setReportMonth(e.target.value)}
282
+ disableFuture
283
+ displayFormat="MMMM YYYY"
284
+ />
320
285
  );
321
286
  }
322
287
  ```
@@ -327,7 +292,6 @@ function ReportFilters({ onFilter }) {
327
292
  function CreditCardExpiry() {
328
293
  const [expiry, setExpiry] = useState('');
329
294
 
330
- // Get current date for minimum
331
295
  const today = new Date();
332
296
  const minDate = `${today.getFullYear()}/${String(today.getMonth() + 1).padStart(2, '0')}/01`;
333
297
 
@@ -337,7 +301,7 @@ function CreditCardExpiry() {
337
301
  value={expiry}
338
302
  onChange={(e) => setExpiry(e.target.value)}
339
303
  minDate={minDate}
340
- displayFormat="MM/YYYY" // Common credit card format
304
+ displayFormat="MM/YYYY"
341
305
  helperText="Enter card expiration date"
342
306
  required
343
307
  />
@@ -345,355 +309,59 @@ function CreditCardExpiry() {
345
309
  }
346
310
  ```
347
311
 
348
- ### Fiscal Period Selector
349
-
350
- ```tsx
351
- function FiscalPeriodSelector({ fiscalYearStart = 4 }) { // April
352
- const [selectedMonth, setSelectedMonth] = useState('');
353
- const [fiscalPeriod, setFiscalPeriod] = useState('');
354
-
355
- // Calculate fiscal period from selected month
356
- useEffect(() => {
357
- if (!selectedMonth) return;
358
-
359
- const [year, month] = selectedMonth.split('/').map(Number);
360
- const fiscalMonth = month >= fiscalYearStart
361
- ? month - fiscalYearStart + 1
362
- : month + (12 - fiscalYearStart + 1);
363
- const fiscalYear = month >= fiscalYearStart ? year : year - 1;
364
-
365
- setFiscalPeriod(`FY${fiscalYear} P${fiscalMonth}`);
366
- }, [selectedMonth, fiscalYearStart]);
367
-
368
- return (
369
- <Stack gap={2}>
370
- <MonthPicker
371
- label="Select Period"
372
- value={selectedMonth}
373
- onChange={(e) => setSelectedMonth(e.target.value)}
374
- displayFormat="MMMM YYYY"
375
- />
376
- {fiscalPeriod && (
377
- <Typography level="body-sm">Fiscal Period: {fiscalPeriod}</Typography>
378
- )}
379
- </Stack>
380
- );
381
- }
382
- ```
383
-
384
- ### Monthly Budget Allocation
385
-
386
- ```tsx
387
- function BudgetAllocation({ departments }) {
388
- const [selectedMonth, setSelectedMonth] = useState('');
389
- const [budgets, setBudgets] = useState({});
390
-
391
- // Restrict to future months only
392
- const today = new Date();
393
- const nextMonth = new Date(today.getFullYear(), today.getMonth() + 1, 1);
394
- const minDate = `${nextMonth.getFullYear()}/${String(nextMonth.getMonth() + 1).padStart(2, '0')}/01`;
395
-
396
- return (
397
- <form>
398
- <MonthPicker
399
- label="Budget Month"
400
- value={selectedMonth}
401
- onChange={(e) => setSelectedMonth(e.target.value)}
402
- minDate={minDate}
403
- displayFormat="MMMM YYYY"
404
- helperText="Select month for budget allocation"
405
- required
406
- />
407
-
408
- {selectedMonth && departments.map((dept) => (
409
- <CurrencyInput
410
- key={dept.id}
411
- label={`${dept.name} Budget`}
412
- value={budgets[dept.id] || ''}
413
- onChange={(value) => setBudgets(prev => ({
414
- ...prev,
415
- [dept.id]: value
416
- }))}
417
- />
418
- ))}
419
-
420
- <Button type="submit">Allocate Budget</Button>
421
- </form>
422
- );
423
- }
424
- ```
425
-
426
- ### Year-Month Comparison
427
-
428
- ```tsx
429
- function MonthComparison() {
430
- const [month1, setMonth1] = useState('');
431
- const [month2, setMonth2] = useState('');
432
-
433
- return (
434
- <Stack gap={2}>
435
- <Stack direction="row" gap={2}>
436
- <MonthPicker
437
- label="Compare From"
438
- value={month1}
439
- onChange={(e) => setMonth1(e.target.value)}
440
- disableFuture
441
- />
442
- <MonthPicker
443
- label="Compare To"
444
- value={month2}
445
- onChange={(e) => setMonth2(e.target.value)}
446
- disableFuture
447
- minDate={month1} // Must be after first month
448
- />
449
- </Stack>
450
- <Button disabled={!month1 || !month2}>
451
- Compare Months
452
- </Button>
453
- </Stack>
454
- );
455
- }
456
- ```
457
-
458
- ## Props and Customization
459
-
460
- ### Key Props
461
-
462
- | Prop | Type | Default | Description |
463
- | --------------- | ----------------------------------------------------------- | -------------- | --------------------------------------- |
464
- | `value` | `string` | - | Controlled value (format: `YYYY/MM/DD`) |
465
- | `defaultValue` | `string` | - | Default value for uncontrolled mode |
466
- | `onChange` | `(e: { target: { name?: string; value: string } }) => void` | - | Change handler |
467
- | `format` | `string` | `'YYYY/MM/DD'` | Format for `value` and `onChange` |
468
- | `displayFormat` | `string` | `'YYYY/MM'` | Format displayed in the input |
469
- | `label` | `string` | - | Label text |
470
- | `helperText` | `string` | - | Helper text below input |
471
- | `error` | `boolean` | `false` | Error state |
472
- | `size` | `'sm' \| 'md' \| 'lg'` | `'md'` | Component size |
473
- | `disabled` | `boolean` | `false` | Disabled state |
474
- | `required` | `boolean` | `false` | Required field indicator |
475
- | `minDate` | `string` | - | Minimum selectable month |
476
- | `maxDate` | `string` | - | Maximum selectable month |
477
- | `disableFuture` | `boolean` | `false` | Disable all future months |
478
- | `disablePast` | `boolean` | `false` | Disable all past months |
479
-
480
- ### Display Format Tokens
481
-
482
- | Token | Description | Example |
483
- | ------ | --------------- | ------- |
484
- | `YYYY` | 4-digit year | 2024 |
485
- | `MM` | 2-digit month | 04 |
486
- | `DD` | 2-digit day | 01 |
487
- | `MMMM` | Full month name | January |
488
-
489
- Common display format patterns:
490
-
491
- - `YYYY/MM` - Default (2024/04)
492
- - `YYYY-MM` - ISO-like (2024-04)
493
- - `MM/YYYY` - European (04/2024)
494
- - `MMMM YYYY` - Full name (April 2024)
495
- - `YYYY.MM` - Period separator (2024.04)
496
-
497
- ### Value Format Understanding
498
-
499
- ```tsx
500
- // MonthPicker always uses day=01 in values
501
- // Even though display shows "2024/04", the value is "2024/04/01"
502
-
503
- <MonthPicker
504
- value="2024/04/01" // Must include day
505
- displayFormat="YYYY/MM" // Shows "2024/04"
506
- onChange={(e) => {
507
- console.log(e.target.value); // "2024/04/01"
508
- // Extract just year and month
509
- const [year, month] = e.target.value.split('/');
510
- console.log(`${year}-${month}`); // "2024-04"
511
- }}
512
- />
513
- ```
514
-
515
- ### Format vs DisplayFormat
516
-
517
- ```tsx
518
- // format: Affects the value in onChange
519
- // displayFormat: Affects what users see in the input
520
-
521
- <MonthPicker
522
- format="YYYY-MM-DD" // onChange returns "2024-04-01"
523
- displayFormat="MMMM YYYY" // Input shows "April 2024"
524
- onChange={(e) => {
525
- console.log(e.target.value); // "2024-04-01"
526
- }}
527
- />
528
- ```
529
-
530
- ### Controlled vs Uncontrolled
531
-
532
- ```tsx
533
- // Uncontrolled - component manages state
534
- <MonthPicker
535
- defaultValue="2024/04/01"
536
- onChange={(e) => console.log(e.target.value)}
537
- />
538
-
539
- // Controlled - you manage state
540
- const [month, setMonth] = useState('2024/04/01');
541
- <MonthPicker
542
- value={month}
543
- onChange={(e) => setMonth(e.target.value)}
544
- />
545
- ```
546
-
547
- ## Accessibility
548
-
549
- MonthPicker includes built-in accessibility features:
550
-
551
- ### ARIA Attributes
552
-
553
- - Input has proper `role="textbox"`
554
- - Calendar button has `aria-label="Toggle Calendar"`
555
- - Month grid uses proper navigation roles
556
- - Selected month marked with `aria-selected`
557
-
558
- ### Keyboard Navigation
559
-
560
- - **Tab**: Move focus between input and calendar button
561
- - **Enter/Space**: Open calendar when focused on button
562
- - **Arrow Keys**: Navigate between months in calendar
563
- - **Escape**: Close calendar popup
564
- - **Enter**: Select focused month
312
+ ## Best Practices
565
313
 
566
- ### Screen Reader Support
314
+ 1. **Match value format to `format` prop**: The `value` prop must follow the same pattern as `format`. Mismatches cause unexpected behavior.
567
315
 
568
316
  ```tsx
569
- // Months are announced with full context
570
- <button aria-label="April 2024">Apr</button>
317
+ // Good: Value matches default format
318
+ <MonthPicker value="2024/04/01" />
571
319
 
572
- // Navigation buttons are descriptive
573
- <button aria-label="Previous Year">←</button>
574
- <button aria-label="Next Year">→</button>
320
+ // Bad: Value missing the day component
321
+ <MonthPicker value="2024/04" />
575
322
  ```
576
323
 
577
- ### Focus Management
578
-
579
- - Focus moves to current year's month grid when opened
580
- - Focus returns to input when calendar closes
581
- - Clear visual focus indicators on all interactive elements
582
-
583
- ## Best Practices
584
-
585
- ### ✅ Do
586
-
587
- 1. **Use appropriate display formats**: Match the display format to user expectations
324
+ 2. **Use `displayFormat` for user-friendly presentation**: Keep the value format stable for programmatic use, and customize only the visible representation.
588
325
 
589
326
  ```tsx
590
- // ✅ Good: User-friendly display format
327
+ // ✅ Good: Separate concerns
591
328
  <MonthPicker
592
- displayFormat="MMMM YYYY" // "January 2024" is clearer
593
- label="Billing Month"
329
+ format="YYYY/MM/DD"
330
+ displayFormat="MMMM YYYY"
594
331
  />
595
332
  ```
596
333
 
597
- 2. **Set reasonable date limits**: Restrict months based on context
334
+ 3. **Provide context with `helperText`**: Guide users on what they are selecting, especially when constraints are applied.
598
335
 
599
336
  ```tsx
600
- // ✅ Good: Logical constraints for billing
337
+ // ✅ Good: Clear guidance
601
338
  <MonthPicker
602
- disableFuture // Can't bill for future months
603
- minDate="2020/01/01" // Company started in 2020
339
+ label="Statement Month"
340
+ helperText="Select the month for your account statement"
341
+ disableFuture
604
342
  />
605
343
  ```
606
344
 
607
- 3. **Provide context in helper text**: Guide users on selection purpose
345
+ 4. **Set reasonable date constraints**: Use `minDate`, `maxDate`, `disableFuture`, or `disablePast` to prevent invalid selections at the UI level.
608
346
 
609
347
  ```tsx
610
- // ✅ Good: Clear guidance
611
- <MonthPicker
612
- label="Statement Month"
613
- helperText="Select the month for your account statement"
614
- />
348
+ // ✅ Good: Logical constraints
349
+ <MonthPicker disableFuture minDate="2020/01/01" />
615
350
  ```
616
351
 
617
- 4. **Handle the day value**: Remember values include day set to 01
352
+ 5. **Handle the day component in values**: Remember that `onChange` values always include a day set to `01`. Extract year and month when only those parts are needed.
618
353
 
619
354
  ```tsx
620
- // ✅ Good: Extract month/year when needed
355
+ // ✅ Good: Extract month/year
621
356
  const handleChange = (e) => {
622
357
  const [year, month] = e.target.value.split('/');
623
358
  setSelectedPeriod({ year: parseInt(year), month: parseInt(month) });
624
359
  };
625
360
  ```
626
361
 
627
- ### ❌ Don't
628
-
629
- 1. **Don't expect day-only display in values**: Values always include day
630
-
631
- ```tsx
632
- // ❌ Bad: Expecting value without day
633
- <MonthPicker
634
- value="2024/04" // Wrong! Needs "2024/04/01"
635
- />
636
-
637
- // ✅ Good: Full value format
638
- <MonthPicker
639
- value="2024/04/01"
640
- />
641
- ```
642
-
643
- 2. **Don't use inconsistent formats**: Match value format to format prop
644
-
645
- ```tsx
646
- // ❌ Bad: Mismatched formats
647
- <MonthPicker
648
- format="YYYY/MM/DD"
649
- value="04/2024" // Wrong format
650
- />
651
- ```
652
-
653
- 3. **Don't forget to handle empty states**: Validate before processing
654
-
655
- 4. **Don't use for day-level selection**: Use DatePicker when days matter
656
-
657
- ## Performance Considerations
658
-
659
- ### Memoize Handlers
660
-
661
- When using MonthPicker in complex forms:
662
-
663
- ```tsx
664
- const handleChange = useCallback((e) => {
665
- setMonth(e.target.value);
666
- }, []);
667
-
668
- <MonthPicker value={month} onChange={handleChange} />
669
- ```
670
-
671
- ### Extract Month/Year Efficiently
672
-
673
- When you need just the month and year:
674
-
675
- ```tsx
676
- const { year, month } = useMemo(() => {
677
- if (!selectedMonth) return { year: null, month: null };
678
- const [year, month] = selectedMonth.split('/').map(Number);
679
- return { year, month };
680
- }, [selectedMonth]);
681
- ```
682
-
683
- ### Date Calculations
684
-
685
- For fiscal year or period calculations:
686
-
687
- ```tsx
688
- const fiscalData = useMemo(() => {
689
- if (!selectedMonth) return null;
690
-
691
- const [year, month] = selectedMonth.split('/').map(Number);
692
- const fiscalYear = month >= 4 ? year : year - 1;
693
- const fiscalQuarter = Math.ceil((month >= 4 ? month - 3 : month + 9) / 3);
694
-
695
- return { fiscalYear, fiscalQuarter };
696
- }, [selectedMonth]);
697
- ```
362
+ ## Accessibility
698
363
 
699
- MonthPicker simplifies month-level date selection for billing, reporting, and scheduling scenarios. Remember that values always include day (set to 01), and use displayFormat to show user-friendly month representations like full month names.
364
+ - The input has `role="textbox"` and the calendar toggle button has `aria-label="Toggle Calendar"` for screen reader identification.
365
+ - **Keyboard navigation**: Use **Tab** to move focus between the input and calendar button, **Enter/Space** to open the calendar, **Arrow Keys** to navigate months, and **Escape** to close the popup.
366
+ - Each month button in the calendar grid has a descriptive `aria-label` (e.g., "April 2024") so screen readers announce the full context.
367
+ - Focus management moves focus into the calendar grid when opened and returns focus to the input when the calendar is closed.