@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
+ 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.
6
+
5
7
  ```tsx
6
8
  <MonthPicker />
7
9
  ```
@@ -23,8 +25,47 @@
23
25
  | format | — | — |
24
26
  | onChange | — | — |
25
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
+
37
+ ## Usage
38
+
39
+ ```tsx
40
+ import { MonthPicker } from '@ceed/ads';
41
+
42
+ function MonthForm() {
43
+ const [month, setMonth] = useState('');
44
+
45
+ return (
46
+ <MonthPicker
47
+ label="Select Month"
48
+ value={month}
49
+ onChange={(e) => setMonth(e.target.value)}
50
+ />
51
+ );
52
+ }
53
+ ```
54
+
55
+ ## Examples
56
+
57
+ ### Playground
58
+
59
+ Interactive example with all controls.
60
+
61
+ ```tsx
62
+ <MonthPicker />
63
+ ```
64
+
26
65
  ### Sizes
27
66
 
67
+ MonthPicker supports three sizes for different layouts.
68
+
28
69
  ```tsx
29
70
  <Stack gap={2}>
30
71
  <MonthPicker size="sm" />
@@ -33,13 +74,17 @@
33
74
  </Stack>
34
75
  ```
35
76
 
36
- ### WithLabel
77
+ ### With Label
78
+
79
+ Add a label above the month picker.
37
80
 
38
81
  ```tsx
39
82
  <MonthPicker label="Date" />
40
83
  ```
41
84
 
42
- ### WithHelperText
85
+ ### With Helper Text
86
+
87
+ Provide additional guidance below the input.
43
88
 
44
89
  ```tsx
45
90
  <MonthPicker
@@ -48,7 +93,9 @@
48
93
  />
49
94
  ```
50
95
 
51
- ### Error
96
+ ### Error State
97
+
98
+ Show validation errors with error styling.
52
99
 
53
100
  ```tsx
54
101
  <MonthPicker
@@ -58,7 +105,92 @@
58
105
  />
59
106
  ```
60
107
 
61
- ### WithFormats
108
+ ### Required Field
109
+
110
+ Mark the field as required in forms.
111
+
112
+ ```tsx
113
+ <MonthPicker
114
+ label="Label"
115
+ helperText="I'm helper text"
116
+ required
117
+ />
118
+ ```
119
+
120
+ ### Disabled
121
+
122
+ Prevent user interaction when disabled.
123
+
124
+ ```tsx
125
+ <MonthPicker disabled />
126
+ ```
127
+
128
+ ### Minimum Date
129
+
130
+ Restrict selection to months on or after a minimum date.
131
+
132
+ ```tsx
133
+ <MonthPicker minDate="2024-04-10" />
134
+ ```
135
+
136
+ ### Maximum Date
137
+
138
+ Restrict selection to months on or before a maximum date.
139
+
140
+ ```tsx
141
+ <MonthPicker maxDate="2024-04-10" />
142
+ ```
143
+
144
+ ### Disable Future
145
+
146
+ Prevent selection of months in the future.
147
+
148
+ ```tsx
149
+ <MonthPicker disableFuture />
150
+ ```
151
+
152
+ ### Disable Past
153
+
154
+ Prevent selection of months in the past.
155
+
156
+ ```tsx
157
+ <MonthPicker disablePast />
158
+ ```
159
+
160
+ ### Controlled
161
+
162
+ Parent component manages the month state.
163
+
164
+ ```tsx
165
+ <Stack gap={2}>
166
+ <MonthPicker {...args} value={value} onChange={e => setValue(e.target.value)} />
167
+ <Button onClick={() => {
168
+ const currentValue = new Date(value);
169
+ currentValue.setMonth(currentValue.getMonth() + 1);
170
+ const year = currentValue.getFullYear();
171
+ const month = String(currentValue.getMonth() + 1).padStart(2, '0');
172
+ setValue(`${year}/${month}/01`);
173
+ }}>
174
+ Next Month
175
+ </Button>
176
+ </Stack>
177
+ ```
178
+
179
+ ### Uncontrolled
180
+
181
+ Component manages its own state internally.
182
+
183
+ ```tsx
184
+ <MonthPicker
185
+ label="Uncontrolled MonthPicker"
186
+ helperText="Please select a date"
187
+ defaultValue="2024/04/01"
188
+ />
189
+ ```
190
+
191
+ ### With Formats
192
+
193
+ Different value formats for the `onChange` event.
62
194
 
63
195
  ```tsx
64
196
  <Stack gap={2}>
@@ -70,3 +202,493 @@
70
202
  <MonthPicker {...args} value={value['DD.MM.YYYY']} label="DD.MM.YYYY" name="DD.MM.YYYY" format="DD.MM.YYYY" onChange={handleChange} />
71
203
  </Stack>
72
204
  ```
205
+
206
+ ### With Display Formats
207
+
208
+ Different display formats including full month names.
209
+
210
+ ```tsx
211
+ <Stack gap={2}>
212
+ <MonthPicker {...args} value={value1} label="YYYY.MM" name="YYYY.MM" displayFormat="YYYY.MM" onChange={e => {
213
+ setValue1(e.target.value);
214
+ args.onChange?.(e);
215
+ }} />
216
+ <MonthPicker {...args} value={value2} label="YYYY/MM" name="YYYY/MM" displayFormat="YYYY/MM" onChange={e => {
217
+ setValue2(e.target.value);
218
+ args.onChange?.(e);
219
+ }} />
220
+ <MonthPicker {...args} value={value3} label="MM/YYYY" name="MM/YYYY" displayFormat="MM/YYYY" onChange={e => {
221
+ setValue3(e.target.value);
222
+ args.onChange?.(e);
223
+ }} />
224
+ <MonthPicker {...args} value={value4} label="YYYY-MM" name="YYYY-MM" displayFormat="YYYY-MM" onChange={e => {
225
+ setValue4(e.target.value);
226
+ args.onChange?.(e);
227
+ }} />
228
+ <MonthPicker {...args} value={value5} label="YYYY-MM-DD" name="YYYY-MM-DD" displayFormat="YYYY-MM-DD" onChange={e => {
229
+ setValue5(e.target.value);
230
+ args.onChange?.(e);
231
+ }} />
232
+ <MonthPicker {...args} value={value6} label="MMMM YYYY" name="MMMM YYYY" displayFormat="MMMM YYYY" onChange={e => {
233
+ setValue6(e.target.value);
234
+ args.onChange?.(e);
235
+ }} />
236
+ </Stack>
237
+ ```
238
+
239
+ ## When to Use
240
+
241
+ ### ✅ Good Use Cases
242
+
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
257
+
258
+ ## Common Use Cases
259
+
260
+ ### Billing Period Selection
261
+
262
+ ```tsx
263
+ function BillingPeriodSelector() {
264
+ const [billingMonth, setBillingMonth] = useState('');
265
+
266
+ const handleGenerate = () => {
267
+ const [year, month] = billingMonth.split('/');
268
+ generateInvoice({ year: parseInt(year), month: parseInt(month) });
269
+ };
270
+
271
+ return (
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>
284
+ );
285
+ }
286
+ ```
287
+
288
+ ### Report Month Filter
289
+
290
+ ```tsx
291
+ function ReportFilters({ onFilter }) {
292
+ const [reportMonth, setReportMonth] = useState('');
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
+
302
+ return (
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>
315
+ );
316
+ }
317
+ ```
318
+
319
+ ### Credit Card Expiry
320
+
321
+ ```tsx
322
+ function CreditCardExpiry() {
323
+ const [expiry, setExpiry] = useState('');
324
+
325
+ // Get current date for minimum
326
+ const today = new Date();
327
+ const minDate = `${today.getFullYear()}/${String(today.getMonth() + 1).padStart(2, '0')}/01`;
328
+
329
+ return (
330
+ <MonthPicker
331
+ label="Card Expiry"
332
+ value={expiry}
333
+ onChange={(e) => setExpiry(e.target.value)}
334
+ minDate={minDate}
335
+ displayFormat="MM/YYYY" // Common credit card format
336
+ helperText="Enter card expiration date"
337
+ required
338
+ />
339
+ );
340
+ }
341
+ ```
342
+
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
+ ```
420
+
421
+ ### Year-Month Comparison
422
+
423
+ ```tsx
424
+ function MonthComparison() {
425
+ const [month1, setMonth1] = useState('');
426
+ const [month2, setMonth2] = useState('');
427
+
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
+ }
451
+ ```
452
+
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
493
+
494
+ ```tsx
495
+ // MonthPicker always uses day=01 in values
496
+ // Even though display shows "2024/04", the value is "2024/04/01"
497
+
498
+ <MonthPicker
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
+ }}
507
+ />
508
+ ```
509
+
510
+ ### Format vs DisplayFormat
511
+
512
+ ```tsx
513
+ // format: Affects the value in onChange
514
+ // displayFormat: Affects what users see in the input
515
+
516
+ <MonthPicker
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
+ }}
522
+ />
523
+ ```
524
+
525
+ ### Controlled vs Uncontrolled
526
+
527
+ ```tsx
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
+ />
540
+ ```
541
+
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
613
+
614
+ ```tsx
615
+ // ✅ Good: Extract month/year when needed
616
+ const handleChange = (e) => {
617
+ const [year, month] = e.target.value.split('/');
618
+ setSelectedPeriod({ year: parseInt(year), month: parseInt(month) });
619
+ };
620
+ ```
621
+
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
+ ```
693
+
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.