@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.
- package/dist/components/data-display/Badge.md +71 -39
- package/dist/components/data-display/InfoSign.md +74 -98
- package/dist/components/data-display/Typography.md +310 -61
- package/dist/components/feedback/CircularProgress.md +257 -0
- package/dist/components/feedback/Skeleton.md +280 -0
- package/dist/components/feedback/llms.txt +2 -0
- package/dist/components/inputs/ButtonGroup.md +115 -106
- package/dist/components/inputs/Calendar.md +98 -459
- package/dist/components/inputs/CurrencyInput.md +181 -8
- package/dist/components/inputs/DatePicker.md +108 -436
- package/dist/components/inputs/DateRangePicker.md +130 -496
- package/dist/components/inputs/FilterMenu.md +169 -19
- package/dist/components/inputs/FilterableCheckboxGroup.md +119 -24
- package/dist/components/inputs/FormControl.md +361 -0
- package/dist/components/inputs/IconButton.md +137 -88
- package/dist/components/inputs/MonthPicker.md +95 -427
- package/dist/components/inputs/MonthRangePicker.md +89 -471
- package/dist/components/inputs/PercentageInput.md +183 -19
- package/dist/components/inputs/RadioButton.md +163 -35
- package/dist/components/inputs/RadioList.md +241 -0
- package/dist/components/inputs/RadioTileGroup.md +146 -62
- package/dist/components/inputs/Select.md +219 -328
- package/dist/components/inputs/Slider.md +334 -0
- package/dist/components/inputs/Switch.md +136 -376
- package/dist/components/inputs/Textarea.md +209 -11
- package/dist/components/inputs/Uploader/Uploader.md +145 -66
- package/dist/components/inputs/llms.txt +3 -0
- package/dist/components/navigation/Breadcrumbs.md +80 -322
- package/dist/components/navigation/Dropdown.md +92 -221
- package/dist/components/navigation/IconMenuButton.md +40 -502
- package/dist/components/navigation/InsetDrawer.md +68 -738
- package/dist/components/navigation/Link.md +39 -298
- package/dist/components/navigation/Menu.md +92 -285
- package/dist/components/navigation/MenuButton.md +55 -448
- package/dist/components/navigation/Pagination.md +47 -338
- package/dist/components/navigation/ProfileMenu.md +45 -268
- package/dist/components/navigation/Stepper.md +160 -28
- package/dist/components/navigation/Tabs.md +57 -316
- package/dist/components/surfaces/Sheet.md +150 -333
- package/dist/guides/ThemeProvider.md +116 -0
- package/dist/guides/llms.txt +9 -0
- package/dist/llms.txt +8 -0
- 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
|
|
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
|
-
|
|
61
|
-
|
|
62
|
-
|
|
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
|
-
|
|
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
|
-
###
|
|
86
|
+
### Required Field
|
|
102
87
|
|
|
103
|
-
|
|
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="
|
|
108
|
-
helperText="
|
|
109
|
-
|
|
92
|
+
label="Label"
|
|
93
|
+
helperText="I'm helper text"
|
|
94
|
+
required
|
|
110
95
|
/>
|
|
111
96
|
```
|
|
112
97
|
|
|
113
|
-
###
|
|
98
|
+
### Error State
|
|
114
99
|
|
|
115
|
-
|
|
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="
|
|
120
|
-
helperText="
|
|
121
|
-
|
|
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
|
|
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
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
185
|
+
## Formats
|
|
186
|
+
|
|
187
|
+
### Value Formats
|
|
197
188
|
|
|
198
|
-
|
|
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
|
-
###
|
|
202
|
+
### Display Formats
|
|
212
203
|
|
|
213
|
-
|
|
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
|
-
|
|
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
|
-
|
|
237
|
+
A controlled example with an external reset button to clear the selected value.
|
|
256
238
|
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
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
|
-
<
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
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
|
|
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
|
-
<
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
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"
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
//
|
|
570
|
-
<
|
|
317
|
+
// ✅ Good: Value matches default format
|
|
318
|
+
<MonthPicker value="2024/04/01" />
|
|
571
319
|
|
|
572
|
-
//
|
|
573
|
-
<
|
|
574
|
-
<button aria-label="Next Year">→</button>
|
|
320
|
+
// ❌ Bad: Value missing the day component
|
|
321
|
+
<MonthPicker value="2024/04" />
|
|
575
322
|
```
|
|
576
323
|
|
|
577
|
-
|
|
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:
|
|
327
|
+
// ✅ Good: Separate concerns
|
|
591
328
|
<MonthPicker
|
|
592
|
-
|
|
593
|
-
|
|
329
|
+
format="YYYY/MM/DD"
|
|
330
|
+
displayFormat="MMMM YYYY"
|
|
594
331
|
/>
|
|
595
332
|
```
|
|
596
333
|
|
|
597
|
-
|
|
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:
|
|
337
|
+
// ✅ Good: Clear guidance
|
|
601
338
|
<MonthPicker
|
|
602
|
-
|
|
603
|
-
|
|
339
|
+
label="Statement Month"
|
|
340
|
+
helperText="Select the month for your account statement"
|
|
341
|
+
disableFuture
|
|
604
342
|
/>
|
|
605
343
|
```
|
|
606
344
|
|
|
607
|
-
|
|
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:
|
|
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
|
-
|
|
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
|
|
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
|
-
|
|
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
|
-
|
|
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.
|