@ceed/cds 1.24.1-next.3 → 1.25.0
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/chunks/rehype-accent-FZRUD7VI.js +39 -0
- package/dist/components/CurrencyInput/CurrencyInput.d.ts +1 -1
- package/dist/components/CurrencyInput/hooks/use-currency-setting.d.ts +2 -2
- package/dist/components/DataTable/components.d.ts +2 -1
- package/dist/components/DataTable/styled.d.ts +3 -1
- package/dist/components/DataTable/types.d.ts +1 -0
- package/dist/components/RadioTileGroup/RadioTileGroup.d.ts +56 -0
- package/dist/components/RadioTileGroup/index.d.ts +3 -0
- package/dist/components/data-display/DataTable.md +77 -1
- package/dist/components/data-display/InfoSign.md +74 -91
- package/dist/components/data-display/Typography.md +411 -94
- package/dist/components/feedback/CircularProgress.md +257 -0
- package/dist/components/feedback/Dialog.md +76 -62
- package/dist/components/feedback/Modal.md +430 -138
- package/dist/components/feedback/Skeleton.md +280 -0
- package/dist/components/feedback/llms.txt +2 -0
- package/dist/components/index.d.ts +1 -0
- package/dist/components/inputs/Autocomplete.md +356 -107
- package/dist/components/inputs/ButtonGroup.md +115 -104
- package/dist/components/inputs/CurrencyInput.md +183 -5
- package/dist/components/inputs/DatePicker.md +108 -431
- package/dist/components/inputs/DateRangePicker.md +131 -492
- package/dist/components/inputs/FilterableCheckboxGroup.md +145 -19
- package/dist/components/inputs/FormControl.md +361 -0
- package/dist/components/inputs/IconButton.md +137 -88
- package/dist/components/inputs/Input.md +204 -73
- package/dist/components/inputs/MonthPicker.md +95 -422
- package/dist/components/inputs/MonthRangePicker.md +89 -466
- package/dist/components/inputs/PercentageInput.md +185 -16
- package/dist/components/inputs/RadioButton.md +163 -35
- package/dist/components/inputs/RadioList.md +241 -0
- package/dist/components/inputs/RadioTileGroup.md +507 -0
- package/dist/components/inputs/Select.md +222 -326
- package/dist/components/inputs/Slider.md +334 -0
- package/dist/components/inputs/Switch.md +143 -376
- package/dist/components/inputs/Textarea.md +213 -10
- package/dist/components/inputs/Uploader/Uploader.md +145 -66
- package/dist/components/inputs/llms.txt +4 -0
- package/dist/components/navigation/Breadcrumbs.md +57 -308
- package/dist/components/navigation/Drawer.md +180 -0
- package/dist/components/navigation/Dropdown.md +98 -215
- package/dist/components/navigation/IconMenuButton.md +40 -502
- package/dist/components/navigation/InsetDrawer.md +281 -650
- package/dist/components/navigation/Link.md +31 -348
- 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/Stepper.md +160 -28
- package/dist/components/navigation/Tabs.md +57 -316
- package/dist/components/surfaces/Accordions.md +49 -804
- package/dist/components/surfaces/Card.md +97 -157
- package/dist/components/surfaces/Divider.md +83 -234
- package/dist/components/surfaces/Sheet.md +153 -328
- package/dist/guides/ThemeProvider.md +89 -0
- package/dist/guides/llms.txt +9 -0
- package/dist/index.browser.js +224 -0
- package/dist/index.browser.js.map +7 -0
- package/dist/index.cjs +648 -390
- package/dist/index.d.ts +1 -1
- package/dist/index.js +563 -361
- package/dist/llms.txt +9 -0
- package/framer/index.js +1 -163
- package/package.json +22 -17
|
@@ -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,15 +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
30
|
## Usage
|
|
38
31
|
|
|
39
32
|
```tsx
|
|
@@ -52,19 +45,14 @@ function MonthForm() {
|
|
|
52
45
|
}
|
|
53
46
|
```
|
|
54
47
|
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
Interactive example with all controls.
|
|
60
|
-
|
|
61
|
-
```tsx
|
|
62
|
-
<MonthPicker />
|
|
63
|
-
```
|
|
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.
|
|
64
52
|
|
|
65
|
-
|
|
53
|
+
## Sizes
|
|
66
54
|
|
|
67
|
-
MonthPicker supports three sizes for different layouts.
|
|
55
|
+
MonthPicker supports three sizes (`sm`, `md`, `lg`) for different layouts and contexts.
|
|
68
56
|
|
|
69
57
|
```tsx
|
|
70
58
|
<Stack gap={2}>
|
|
@@ -74,9 +62,11 @@ MonthPicker supports three sizes for different layouts.
|
|
|
74
62
|
</Stack>
|
|
75
63
|
```
|
|
76
64
|
|
|
65
|
+
## Form Field Features
|
|
66
|
+
|
|
77
67
|
### With Label
|
|
78
68
|
|
|
79
|
-
Add a label above the month picker.
|
|
69
|
+
Add a label above the month picker to indicate the field purpose.
|
|
80
70
|
|
|
81
71
|
```tsx
|
|
82
72
|
<MonthPicker label="Date" />
|
|
@@ -84,7 +74,7 @@ Add a label above the month picker.
|
|
|
84
74
|
|
|
85
75
|
### With Helper Text
|
|
86
76
|
|
|
87
|
-
Provide additional guidance below the input.
|
|
77
|
+
Provide additional guidance below the input to help users understand the expected selection.
|
|
88
78
|
|
|
89
79
|
```tsx
|
|
90
80
|
<MonthPicker
|
|
@@ -93,41 +83,43 @@ Provide additional guidance below the input.
|
|
|
93
83
|
/>
|
|
94
84
|
```
|
|
95
85
|
|
|
96
|
-
###
|
|
86
|
+
### Required Field
|
|
97
87
|
|
|
98
|
-
|
|
88
|
+
Mark the field as required in forms. An asterisk indicator is displayed alongside the label.
|
|
99
89
|
|
|
100
90
|
```tsx
|
|
101
91
|
<MonthPicker
|
|
102
|
-
label="
|
|
103
|
-
helperText="
|
|
104
|
-
|
|
92
|
+
label="Label"
|
|
93
|
+
helperText="I'm helper text"
|
|
94
|
+
required
|
|
105
95
|
/>
|
|
106
96
|
```
|
|
107
97
|
|
|
108
|
-
###
|
|
98
|
+
### Error State
|
|
109
99
|
|
|
110
|
-
|
|
100
|
+
Display validation errors with error styling applied to the input, label, and helper text.
|
|
111
101
|
|
|
112
102
|
```tsx
|
|
113
103
|
<MonthPicker
|
|
114
|
-
label="
|
|
115
|
-
helperText="
|
|
116
|
-
|
|
104
|
+
label="Date"
|
|
105
|
+
helperText="Please select a date"
|
|
106
|
+
error
|
|
117
107
|
/>
|
|
118
108
|
```
|
|
119
109
|
|
|
120
110
|
### Disabled
|
|
121
111
|
|
|
122
|
-
Prevent user interaction when disabled.
|
|
112
|
+
Prevent user interaction when the picker is disabled.
|
|
123
113
|
|
|
124
114
|
```tsx
|
|
125
115
|
<MonthPicker disabled />
|
|
126
116
|
```
|
|
127
117
|
|
|
118
|
+
## Date Constraints
|
|
119
|
+
|
|
128
120
|
### Minimum Date
|
|
129
121
|
|
|
130
|
-
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.
|
|
131
123
|
|
|
132
124
|
```tsx
|
|
133
125
|
<MonthPicker minDate="2024-04-10" />
|
|
@@ -135,7 +127,7 @@ Restrict selection to months on or after a minimum date.
|
|
|
135
127
|
|
|
136
128
|
### Maximum Date
|
|
137
129
|
|
|
138
|
-
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.
|
|
139
131
|
|
|
140
132
|
```tsx
|
|
141
133
|
<MonthPicker maxDate="2024-04-10" />
|
|
@@ -143,7 +135,7 @@ Restrict selection to months on or before a maximum date.
|
|
|
143
135
|
|
|
144
136
|
### Disable Future
|
|
145
137
|
|
|
146
|
-
Prevent selection of
|
|
138
|
+
Prevent selection of any month in the future, relative to the current date.
|
|
147
139
|
|
|
148
140
|
```tsx
|
|
149
141
|
<MonthPicker disableFuture />
|
|
@@ -151,15 +143,17 @@ Prevent selection of months in the future.
|
|
|
151
143
|
|
|
152
144
|
### Disable Past
|
|
153
145
|
|
|
154
|
-
Prevent selection of
|
|
146
|
+
Prevent selection of any month in the past, relative to the current date.
|
|
155
147
|
|
|
156
148
|
```tsx
|
|
157
149
|
<MonthPicker disablePast />
|
|
158
150
|
```
|
|
159
151
|
|
|
152
|
+
## Controlled vs Uncontrolled
|
|
153
|
+
|
|
160
154
|
### Controlled
|
|
161
155
|
|
|
162
|
-
|
|
156
|
+
The parent component manages the month state via the `value` and `onChange` props. External buttons or logic can programmatically update the selected value.
|
|
163
157
|
|
|
164
158
|
```tsx
|
|
165
159
|
<Stack gap={2}>
|
|
@@ -178,7 +172,7 @@ Parent component manages the month state.
|
|
|
178
172
|
|
|
179
173
|
### Uncontrolled
|
|
180
174
|
|
|
181
|
-
|
|
175
|
+
The component manages its own state internally using `defaultValue`. The parent can still listen for changes via `onChange`.
|
|
182
176
|
|
|
183
177
|
```tsx
|
|
184
178
|
<MonthPicker
|
|
@@ -188,9 +182,11 @@ Component manages its own state internally.
|
|
|
188
182
|
/>
|
|
189
183
|
```
|
|
190
184
|
|
|
191
|
-
|
|
185
|
+
## Formats
|
|
192
186
|
|
|
193
|
-
|
|
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.
|
|
194
190
|
|
|
195
191
|
```tsx
|
|
196
192
|
<Stack gap={2}>
|
|
@@ -203,9 +199,9 @@ Different value formats for the `onChange` event.
|
|
|
203
199
|
</Stack>
|
|
204
200
|
```
|
|
205
201
|
|
|
206
|
-
###
|
|
202
|
+
### Display Formats
|
|
207
203
|
|
|
208
|
-
|
|
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.
|
|
209
205
|
|
|
210
206
|
```tsx
|
|
211
207
|
<Stack gap={2}>
|
|
@@ -236,24 +232,21 @@ Different display formats including full month names.
|
|
|
236
232
|
</Stack>
|
|
237
233
|
```
|
|
238
234
|
|
|
239
|
-
|
|
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
|
|
235
|
+
### With Reset Button
|
|
249
236
|
|
|
250
|
-
|
|
237
|
+
A controlled example with an external reset button to clear the selected value.
|
|
251
238
|
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
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
|
+
```
|
|
257
250
|
|
|
258
251
|
## Common Use Cases
|
|
259
252
|
|
|
@@ -263,55 +256,32 @@ Different display formats including full month names.
|
|
|
263
256
|
function BillingPeriodSelector() {
|
|
264
257
|
const [billingMonth, setBillingMonth] = useState('');
|
|
265
258
|
|
|
266
|
-
const handleGenerate = () => {
|
|
267
|
-
const [year, month] = billingMonth.split('/');
|
|
268
|
-
generateInvoice({ year: parseInt(year), month: parseInt(month) });
|
|
269
|
-
};
|
|
270
|
-
|
|
271
259
|
return (
|
|
272
|
-
<
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
/>
|
|
280
|
-
<Button onClick={handleGenerate} disabled={!billingMonth}>
|
|
281
|
-
Generate Invoice
|
|
282
|
-
</Button>
|
|
283
|
-
</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
|
+
/>
|
|
284
267
|
);
|
|
285
268
|
}
|
|
286
269
|
```
|
|
287
270
|
|
|
288
|
-
### Report Month Filter
|
|
271
|
+
### Report Month Filter with Display Format
|
|
289
272
|
|
|
290
273
|
```tsx
|
|
291
|
-
function
|
|
274
|
+
function ReportFilter() {
|
|
292
275
|
const [reportMonth, setReportMonth] = useState('');
|
|
293
276
|
|
|
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
277
|
return (
|
|
303
|
-
<
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
/>
|
|
311
|
-
<Button onClick={() => onFilter(reportMonth)}>
|
|
312
|
-
Generate Report
|
|
313
|
-
</Button>
|
|
314
|
-
</Stack>
|
|
278
|
+
<MonthPicker
|
|
279
|
+
label="Report Month"
|
|
280
|
+
value={reportMonth}
|
|
281
|
+
onChange={(e) => setReportMonth(e.target.value)}
|
|
282
|
+
disableFuture
|
|
283
|
+
displayFormat="MMMM YYYY"
|
|
284
|
+
/>
|
|
315
285
|
);
|
|
316
286
|
}
|
|
317
287
|
```
|
|
@@ -322,7 +292,6 @@ function ReportFilters({ onFilter }) {
|
|
|
322
292
|
function CreditCardExpiry() {
|
|
323
293
|
const [expiry, setExpiry] = useState('');
|
|
324
294
|
|
|
325
|
-
// Get current date for minimum
|
|
326
295
|
const today = new Date();
|
|
327
296
|
const minDate = `${today.getFullYear()}/${String(today.getMonth() + 1).padStart(2, '0')}/01`;
|
|
328
297
|
|
|
@@ -332,7 +301,7 @@ function CreditCardExpiry() {
|
|
|
332
301
|
value={expiry}
|
|
333
302
|
onChange={(e) => setExpiry(e.target.value)}
|
|
334
303
|
minDate={minDate}
|
|
335
|
-
displayFormat="MM/YYYY"
|
|
304
|
+
displayFormat="MM/YYYY"
|
|
336
305
|
helperText="Enter card expiration date"
|
|
337
306
|
required
|
|
338
307
|
/>
|
|
@@ -340,355 +309,59 @@ function CreditCardExpiry() {
|
|
|
340
309
|
}
|
|
341
310
|
```
|
|
342
311
|
|
|
343
|
-
|
|
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
|
|
312
|
+
## Best Practices
|
|
560
313
|
|
|
561
|
-
|
|
314
|
+
1. **Match value format to `format` prop**: The `value` prop must follow the same pattern as `format`. Mismatches cause unexpected behavior.
|
|
562
315
|
|
|
563
316
|
```tsx
|
|
564
|
-
//
|
|
565
|
-
<
|
|
317
|
+
// ✅ Good: Value matches default format
|
|
318
|
+
<MonthPicker value="2024/04/01" />
|
|
566
319
|
|
|
567
|
-
//
|
|
568
|
-
<
|
|
569
|
-
<button aria-label="Next Year">→</button>
|
|
320
|
+
// ❌ Bad: Value missing the day component
|
|
321
|
+
<MonthPicker value="2024/04" />
|
|
570
322
|
```
|
|
571
323
|
|
|
572
|
-
|
|
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
|
|
324
|
+
2. **Use `displayFormat` for user-friendly presentation**: Keep the value format stable for programmatic use, and customize only the visible representation.
|
|
583
325
|
|
|
584
326
|
```tsx
|
|
585
|
-
// ✅ Good:
|
|
327
|
+
// ✅ Good: Separate concerns
|
|
586
328
|
<MonthPicker
|
|
587
|
-
|
|
588
|
-
|
|
329
|
+
format="YYYY/MM/DD"
|
|
330
|
+
displayFormat="MMMM YYYY"
|
|
589
331
|
/>
|
|
590
332
|
```
|
|
591
333
|
|
|
592
|
-
|
|
334
|
+
3. **Provide context with `helperText`**: Guide users on what they are selecting, especially when constraints are applied.
|
|
593
335
|
|
|
594
336
|
```tsx
|
|
595
|
-
// ✅ Good:
|
|
337
|
+
// ✅ Good: Clear guidance
|
|
596
338
|
<MonthPicker
|
|
597
|
-
|
|
598
|
-
|
|
339
|
+
label="Statement Month"
|
|
340
|
+
helperText="Select the month for your account statement"
|
|
341
|
+
disableFuture
|
|
599
342
|
/>
|
|
600
343
|
```
|
|
601
344
|
|
|
602
|
-
|
|
345
|
+
4. **Set reasonable date constraints**: Use `minDate`, `maxDate`, `disableFuture`, or `disablePast` to prevent invalid selections at the UI level.
|
|
603
346
|
|
|
604
347
|
```tsx
|
|
605
|
-
// ✅ Good:
|
|
606
|
-
<MonthPicker
|
|
607
|
-
label="Statement Month"
|
|
608
|
-
helperText="Select the month for your account statement"
|
|
609
|
-
/>
|
|
348
|
+
// ✅ Good: Logical constraints
|
|
349
|
+
<MonthPicker disableFuture minDate="2020/01/01" />
|
|
610
350
|
```
|
|
611
351
|
|
|
612
|
-
|
|
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.
|
|
613
353
|
|
|
614
354
|
```tsx
|
|
615
|
-
// ✅ Good: Extract month/year
|
|
355
|
+
// ✅ Good: Extract month/year
|
|
616
356
|
const handleChange = (e) => {
|
|
617
357
|
const [year, month] = e.target.value.split('/');
|
|
618
358
|
setSelectedPeriod({ year: parseInt(year), month: parseInt(month) });
|
|
619
359
|
};
|
|
620
360
|
```
|
|
621
361
|
|
|
622
|
-
|
|
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
|
-
```
|
|
362
|
+
## Accessibility
|
|
693
363
|
|
|
694
|
-
|
|
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.
|