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