Skip to content

Commit 90f7e9a

Browse files
authored
feat: add new reverseYears prop (#2822)
* Add an option to reverse the years in the dropdown Fixes #2819 * Reduce diff Signed-off-by: gpbl <[email protected]> --------- Signed-off-by: gpbl <[email protected]>
1 parent 7f2ce05 commit 90f7e9a

File tree

6 files changed

+104
-43
lines changed

6 files changed

+104
-43
lines changed

src/DayPicker.tsx

Lines changed: 14 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -370,20 +370,6 @@ export function DayPicker(initialProps: DayPickerProps) {
370370
/>
371371
)}
372372
{months.map((calendarMonth, displayIndex) => {
373-
const dropdownMonths = getMonthOptions(
374-
calendarMonth.date,
375-
navStart,
376-
navEnd,
377-
formatters,
378-
dateLib,
379-
);
380-
381-
const dropdownYears = getYearOptions(
382-
navStart,
383-
navEnd,
384-
formatters,
385-
dateLib,
386-
);
387373
return (
388374
<components.Month
389375
data-animated-month={props.animate ? "true" : undefined}
@@ -434,7 +420,13 @@ export function DayPicker(initialProps: DayPickerProps) {
434420
components={components}
435421
disabled={Boolean(props.disableNavigation)}
436422
onChange={handleMonthChange(calendarMonth.date)}
437-
options={dropdownMonths}
423+
options={getMonthOptions(
424+
calendarMonth.date,
425+
navStart,
426+
navEnd,
427+
formatters,
428+
dateLib,
429+
)}
438430
style={styles?.[UI.Dropdown]}
439431
value={dateLib.getMonth(calendarMonth.date)}
440432
/>
@@ -452,7 +444,13 @@ export function DayPicker(initialProps: DayPickerProps) {
452444
components={components}
453445
disabled={Boolean(props.disableNavigation)}
454446
onChange={handleYearChange(calendarMonth.date)}
455-
options={dropdownYears}
447+
options={getYearOptions(
448+
navStart,
449+
navEnd,
450+
formatters,
451+
dateLib,
452+
Boolean(props.reverseYears),
453+
)}
456454
style={styles?.[UI.Dropdown]}
457455
value={dateLib.getYear(calendarMonth.date)}
458456
/>

src/helpers/getYearOptions.test.ts

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,3 +44,25 @@ test("return correct dropdown options", () => {
4444
{ value: 2024, label: "2024", disabled: false },
4545
]);
4646
});
47+
48+
test("return reversed dropdown options when reverse is true", () => {
49+
const startMonth = new Date(2022, 0, 1); // January 2022
50+
const endMonth = new Date(2024, 11, 31); // December 2024
51+
const formatters = getFormatters({
52+
formatYearDropdown: (date: Date) => `${date.getFullYear()}`,
53+
});
54+
55+
const result = getYearOptions(
56+
startMonth,
57+
endMonth,
58+
formatters,
59+
defaultDateLib,
60+
true,
61+
);
62+
63+
expect(result).toEqual([
64+
{ value: 2024, label: "2024", disabled: false },
65+
{ value: 2023, label: "2023", disabled: false },
66+
{ value: 2022, label: "2022", disabled: false },
67+
]);
68+
});

src/helpers/getYearOptions.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ import type { Formatters } from "../types/index.js";
1212
* @param navEnd The end date for navigation.
1313
* @param formatters The formatters to use for formatting the year labels.
1414
* @param dateLib The date library to use for date manipulation.
15+
* @param reverse If true, reverses the order of the years (descending).
1516
* @returns An array of dropdown options representing the years, or `undefined`
1617
* if `navStart` or `navEnd` is not provided.
1718
*/
@@ -20,6 +21,7 @@ export function getYearOptions(
2021
navEnd: Date | undefined,
2122
formatters: Pick<Formatters, "formatYearDropdown">,
2223
dateLib: DateLib,
24+
reverse: boolean = false,
2325
): DropdownOption[] | undefined {
2426
if (!navStart) return undefined;
2527
if (!navEnd) return undefined;
@@ -35,6 +37,8 @@ export function getYearOptions(
3537
year = addYears(year, 1);
3638
}
3739

40+
if (reverse) years.reverse();
41+
3842
return years.map((year) => {
3943
const label = formatters.formatYearDropdown(year, dateLib);
4044
return {

src/types/props.ts

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -216,6 +216,15 @@ export interface PropsBase {
216216
*/
217217
captionLayout?: "label" | "dropdown" | "dropdown-months" | "dropdown-years";
218218

219+
/**
220+
* Reverse the order of years in the dropdown when using
221+
* `captionLayout="dropdown"` or `captionLayout="dropdown-years"`.
222+
*
223+
* @since 9.9.0
224+
* @see https://daypicker.dev/docs/customization#caption-layouts
225+
*/
226+
reverseYears?: boolean;
227+
219228
/**
220229
* Adjust the positioning of the navigation buttons.
221230
*

website/docs/docs/customization.mdx

Lines changed: 15 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -9,11 +9,14 @@ Use the customization props to tailor the calendar's appearance.
99
| Prop Name | Type | Description |
1010
| ----------------- | ---------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------- |
1111
| `captionLayout` | `"label"`<br/> `"dropdown"`<br/> `"dropdown-months"`<br/> `"dropdown-years"` | Choose the layout of the month caption. Default is `label`. |
12+
| `reverseYears` | `boolean` | Reverse the order of the years in the dropdown. |
1213
| `navLayout` | `"around"` \| `"after"` | Adjust the positioning of the navigation buttons. |
1314
| `fixedWeeks` | `boolean` | Display 6 weeks per month. |
1415
| `footer` | `ReactNode` \| `string` | Add a footer to the calendar, acting as a [live region](https://developer.mozilla.org/en-US/docs/Web/Accessibility/ARIA/ARIA_Live_Regions). |
1516
| `hideWeekdays` | `boolean` | Hide the row displaying the weekday names. |
1617
| `numberOfMonths` | `number` | The number of displayed months. Default is `1`. |
18+
| `reverseMonths` | `boolean` | When displaying multiple months, reverse the order of the months. |
19+
| `pagedNavigation` | `boolean` | Enable paginated navigation when displaying multiple months. |
1720
| `showOutsideDays` | `boolean` | Display the days falling into other months. |
1821
| `showWeekNumber` | `boolean` | Display the column with the [week numbers](#showweeknumber). |
1922

@@ -34,7 +37,18 @@ Use the `captionLayout` prop to customize the layout of the month caption.
3437

3538
### Caption Dropdown
3639

37-
To enable a navigation dropdown, set `captionLayout="dropdown"`. Use the `startMonth` and `endMonth` properties to define the start and end dates for the calendar navigation.
40+
To enable a navigation dropdown, set `captionLayout` to `dropdown`, `dropdown-months`, or `dropdown-years`.
41+
42+
- When displaying the dropdown for the years, use the `reverseYears` prop to reverse the order of the years.
43+
- Use the `startMonth` and `endMonth` properties to define the start and end dates for the calendar navigation.
44+
45+
:::info Default Range
46+
47+
Without specifying the `startMonth` and `endMonth` properties, the dropdown will display the last 100 years.
48+
49+
:::
50+
51+
#### Example
3852

3953
```tsx
4054
<DayPicker
@@ -49,12 +63,6 @@ To enable a navigation dropdown, set `captionLayout="dropdown"`. Use the `startM
4963
<Examples.Dropdown />
5064
</BrowserWindow>
5165

52-
:::info Default Range
53-
54-
Without specifying the `startMonth` and `endMonth` properties, the dropdown will display the last 100 years.
55-
56-
:::
57-
5866
## Navigation Layouts
5967

6068
Use the `navLayout` prop to adjust the positioning of the navigation buttons.

website/src/components/Playground/CustomizationFieldset.tsx

Lines changed: 40 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,24 @@ export function CustomizationFieldset({
4040
</button>
4141
</legend>
4242
<div className={styles.fields}>
43+
<label>
44+
Navigation Layout:
45+
<select
46+
name="navLayout"
47+
value={props.navLayout ?? ""}
48+
onChange={(e) => {
49+
const newProps = {
50+
...props,
51+
navLayout: e.target.value ?? undefined,
52+
} as DayPickerProps;
53+
setProps(newProps);
54+
}}
55+
>
56+
<option value=""></option>
57+
<option value="around">Around</option>
58+
<option value="after">After</option>
59+
</select>
60+
</label>
4361
<label>
4462
Caption Layout:
4563
<select
@@ -71,28 +89,30 @@ export function CustomizationFieldset({
7189
<option></option>
7290
<option value="label">Label</option>
7391
<option value="dropdown">Dropdown</option>
74-
<option value="dropdown-months">Dropdown months</option>
75-
<option value="dropdown-years">Dropdown years</option>
76-
</select>
77-
</label>
78-
<label>
79-
Navigation Layout:
80-
<select
81-
name="navLayout"
82-
value={props.navLayout ?? ""}
83-
onChange={(e) => {
84-
const newProps = {
85-
...props,
86-
navLayout: e.target.value ?? undefined,
87-
} as DayPickerProps;
88-
setProps(newProps);
89-
}}
90-
>
91-
<option value=""></option>
92-
<option value="around">Around</option>
93-
<option value="after">After</option>
92+
<option value="dropdown-months">Dropdown Months</option>
93+
<option value="dropdown-years">Dropdown Years</option>
9494
</select>
9595
</label>
96+
{(props.captionLayout === "dropdown" ||
97+
props.captionLayout === "dropdown-years") && (
98+
<label>
99+
<input
100+
type="checkbox"
101+
name="reverseYears"
102+
checked={!!props.reverseYears}
103+
onChange={(e) =>
104+
setProps({ ...props, reverseYears: e.target.checked })
105+
}
106+
disabled={
107+
!(
108+
props.captionLayout === "dropdown" ||
109+
props.captionLayout === "dropdown-years"
110+
)
111+
}
112+
/>
113+
Reverse Dropdown Years
114+
</label>
115+
)}
96116
<label>
97117
<input
98118
type="checkbox"

0 commit comments

Comments
 (0)