Skip to content

Commit

Permalink
fix: captionLayout prop not working as expected (#2177)
Browse files Browse the repository at this point in the history
  • Loading branch information
gpbl authored Jun 1, 2024
1 parent 9bb547b commit 549da00
Show file tree
Hide file tree
Showing 9 changed files with 95 additions and 85 deletions.
2 changes: 1 addition & 1 deletion examples/Dropdown.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,5 +3,5 @@ import React from "react";
import { DayPicker } from "react-day-picker";

export function Dropdown() {
return <DayPicker dropdownNavigation fromYear={2015} toYear={2025} />;
return <DayPicker captionLayout="dropdown" fromYear={2010} />;
}
2 changes: 1 addition & 1 deletion examples/DropdownMultipleMonths.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ export function DropdownMultipleMonths() {
return (
<DayPicker
numberOfMonths={5}
dropdownNavigation
captionLayout="dropdown"
fromYear={2015}
toYear={2025}
/>
Expand Down
15 changes: 4 additions & 11 deletions src/components/MonthCaption.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ export function MonthCaption(props: {
}) {
const {
classNames,
dropdownNavigation,
captionLayout,
formatters: { formatCaption },
locale,
styles
Expand All @@ -36,22 +36,15 @@ export function MonthCaption(props: {
className={classNames[UI.MonthCaption]}
style={styles?.[UI.MonthCaption]}
>
{dropdownNavigation ? (
<DropdownNav
month={props.month}
index={props.index}
showMonths
showYears
/>
) : dropdownNavigation ? (
{captionLayout?.startsWith("dropdown") ? (
<DropdownNav
month={props.month}
index={props.index}
showMonths={
dropdownNavigation === true || dropdownNavigation === "month"
captionLayout === "dropdown" || captionLayout === "dropdown-months"
}
showYears={
dropdownNavigation === true || dropdownNavigation === "year"
captionLayout === "dropdown" || captionLayout === "dropdown-years"
}
/>
) : (
Expand Down
2 changes: 2 additions & 0 deletions src/components/MonthsDropdown.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ export function MonthsDropdown(props: {
const {
classNames,
components,
disableNavigation,
labels: { labelMonthDropdown }
} = useProps();

Expand All @@ -43,6 +44,7 @@ export function MonthsDropdown(props: {
<Dropdown
name="month"
aria-label={labelMonthDropdown()}
aria-disabled={disableNavigation ? "true" : undefined}
rootClassName={classNames[UI.MonthsDropdown]}
options={dropdown.months}
value={props.month.date.getMonth()}
Expand Down
3 changes: 2 additions & 1 deletion src/components/YearsDropdown.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ export function YearsDropdown(props: {
const {
classNames,
components,
disableNavigation,
labels: { labelYearDropdown }
} = useProps();

Expand All @@ -42,8 +43,8 @@ export function YearsDropdown(props: {
const Dropdown = components?.Dropdown ?? DefaultDropdown;
return (
<Dropdown
name="year"
aria-label={labelYearDropdown()}
aria-disabled={disableNavigation ? "true" : undefined}
rootClassName={classNames[UI.YearsDropdown]}
options={dropdown.years}
value={props.month.date.getFullYear()}
Expand Down
61 changes: 30 additions & 31 deletions src/helpers/getFromToDate.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -50,10 +50,10 @@ describe('when "toYear" is passed in', () => {
});
});

describe('when "showCaption" is passed in', () => {
describe('when "captionLayout" is dropdown', () => {
const today = new Date(2024, 4, 3);
const { fromDate, toDate } = getFromToDate({
dropdownNavigation: true,
captionLayout: "dropdown",
today
});
test('"fromDate" should be 100 years ago', () => {
Expand All @@ -62,35 +62,34 @@ describe('when "showCaption" is passed in', () => {
test('"toDate" should be the end of this year', () => {
expect(toDate).toEqual(new Date(2024, 11, 31));
});
});

describe('when "fromYear" and "showCaption" are passed in', () => {
const today = new Date(2024, 4, 3);
const fromYear = 2022;
const { fromDate, toDate } = getFromToDate({
dropdownNavigation: true,
fromYear,
today
});
test('"fromDate" should be equal to the "fromYear"', () => {
expect(fromDate).toEqual(new Date(2022, 0, 1));
});
test('"toDate" should be the end of this year', () => {
expect(toDate).toEqual(new Date(2024, 11, 31));
});
});
describe('when "toYear" and "showCaption" are passed in', () => {
const today = new Date(2021, 4, 3);
const toYear = 2022;
const { toDate, fromDate } = getFromToDate({
dropdownNavigation: true,
toYear,
today
});
test('"fromDate" should be 100 years ago', () => {
expect(fromDate).toEqual(new Date(1921, 0, 1));
describe('when "fromYear" is set', () => {
const today = new Date(2024, 4, 3);
const fromYear = 2022;
const { fromDate, toDate } = getFromToDate({
captionLayout: "dropdown",
fromYear,
today
});
test('"fromDate" should be equal to the "fromYear"', () => {
expect(fromDate).toEqual(new Date(2022, 0, 1));
});
test('"toDate" should be the end of this year', () => {
expect(toDate).toEqual(new Date(2024, 11, 31));
});
});
test('"toDate" should be equal to "toYear"', () => {
expect(toDate).toEqual(new Date(2022, 11, 31));
describe('when "toYear" is set', () => {
const today = new Date(2021, 4, 3);
const toYear = 2022;
const { toDate, fromDate } = getFromToDate({
captionLayout: "dropdown",
toYear,
today
});
test('"fromDate" should be 100 years ago', () => {
expect(fromDate).toEqual(new Date(1921, 0, 1));
});
test('"toDate" should be equal to "toYear"', () => {
expect(toDate).toEqual(new Date(2022, 11, 31));
});
});
});
8 changes: 4 additions & 4 deletions src/helpers/getFromToDate.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,24 +21,24 @@ export function getFromToDate(
| "fromMonth"
| "toMonth"
| "today"
| "dropdownNavigation"
| "captionLayout"
>
): Pick<DayPickerProps<Mode>, "fromDate" | "toDate"> {
const { fromYear, toYear, fromMonth, toMonth } = props;
let { fromDate, toDate } = props;

const hasDropdowns = props.captionLayout?.startsWith("dropdown");
if (fromMonth) {
fromDate = startOfMonth(fromMonth);
} else if (fromYear) {
fromDate = new Date(fromYear, 0, 1);
} else if (!fromDate && props.dropdownNavigation !== undefined) {
} else if (!fromDate && hasDropdowns) {
fromDate = startOfYear(addYears(props.today ?? new Date(), -100));
}
if (toMonth) {
toDate = endOfMonth(toMonth);
} else if (toYear) {
toDate = new Date(toYear, 11, 31);
} else if (!toDate && props.dropdownNavigation) {
} else if (!toDate && hasDropdowns) {
toDate = endOfYear(props.today ?? new Date());
}
return {
Expand Down
16 changes: 9 additions & 7 deletions src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -143,15 +143,17 @@ export interface PropsBase {
/**
* Show dropdowns to navigate between months or years.
*
* - `true`: display the dropdowns for both month and year.
* - `month`: display the dropdown for the month.
* - `year`: display the dropdown for the year.
* - `false`: hide the dropdowns.
* - `true`: display the dropdowns for both month and year
* - `label`: display the month and the year as a label. Change the label with
* the `formatCaption` formatter.
* - `month`: display only the dropdown for the months
* - `year`: display only the dropdown for the years
*
* **Note:** showing the dropdown will default {@link fromYear} to the 100
* years ago, and {@link toYear} to the current year.
* **Note:** showing the dropdown will set the start/end months
* {@link fromYear} to the 100 years ago, and {@link toYear} to the current
* year.
*/
dropdownNavigation?: boolean | "month" | "year";
captionLayout?: "label" | "dropdown" | "dropdown-months" | "dropdown-years";
/**
* Display always 6 weeks per each month, regardless the month’s number of
* weeks. Weeks will be filled with the days from the next month.
Expand Down
71 changes: 42 additions & 29 deletions website/docs/using-daypicker/customization.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -8,37 +8,39 @@ Use the customization props to customize the appearance of the calendar.

### Customization Props

| Prop Name | Type | Description |
| ----------------- | -------------------------------------------------------- | ---------------------------------------------------------------- |
| `captionLayout` | `"dropdown"` \| `"buttons"` \|<br/> `"dropdown-buttons"` | Change the layout of the caption. <br /> Default is `"buttons"`. |
| `showOutsideDays` | `boolean` | Display the days falling into the other months. |
| `fixedWeeks` | `boolean` | Display 6 weeks per months. |
| `hideWeekdayRow` | `boolean` | Hide the row displaying the weekday names. |
| `footer` | `ReactNode` | Displays a footer below the calendar. |
| Prop Name | Type | Description |
| ----------------- | ------------------------------------------------------------------------------------- | ----------------------------------------------------------- |
| `captionLayout` | \| `label`<br/> \| `"dropdown"`<br/> \| `"dropdown-months"`<br/> \|`"dropdown-years"` | Choose the layout of the month caption. Default is `label`. |
| `showOutsideDays` | `boolean` | Display the days falling into the other months. |
| `fixedWeeks` | `boolean` | Display 6 weeks per months. |
| `hideWeekdayRow` | `boolean` | Hide the row displaying the weekday names. |
| `footer` | `ReactNode` | Displays a footer below the calendar. |

## Caption Layout

Use the `captionLayout` prop to the layout of the caption used to navigate the calendar.

As default, DayPicker will show navigation buttons on the top corner.
Use the `captionLayout` prop to choose the layout of the month caption:

```tsx
<DayPicker captionLayout="buttons" /> // Default value
<DayPicker captionLayout="label" /> // Default value: shows the month and year.
```

### Dropdown Navigation

Use `dropdown` or `dropdown-buttons` to display a navigation dropdown.
| Caption Layout | Description |
| ------------------- | ----------------------------------------------------- |
| `"label"` | Display the month and year as a label. Default value. |
| `"dropdown"` | Display a dropdown with the months and years. |
| `"dropdown-months"` | Display a dropdown with the months only. |
| `"dropdown-years"` | Display a dropdown with the years only. |

:::warning
### Caption Dropdown

To use this prop, you need to set both `fromYear` and `toYear`. (This requirement will be removed in a next version.)

:::
Set `captionLayout="dropdown"` to display a navigation dropdown. This will allow navigation within the last 100 years. Use the `from*` and `to*` props to [set the start and end dates](./navigation.mdx#start-and-end-dates).

```tsx
<DayPicker captionLayout="dropdown" fromYear={2010} toYear={2024} />
<DayPicker captionLayout="dropdown-buttons" fromYear={2010} toYear={2024} />
<DayPicker captionLayout="dropdown" />
<DayPicker captionLayout="dropdown-months" /> // Only months
<DayPicker captionLayout="dropdown-years" /> // Only years

<DayPicker captionLayout="dropdown" fromYear={2015} toYear={2025} /> // Set the years range
```

<BrowserWindow>
Expand All @@ -59,17 +61,10 @@ By default, DayPicker hides the days falling into the other months. Use `showOut

### Fixed Weeks

In a year, months can have between 4 an 6 weeks. Use `fixedWeeks` with `showOutsideDays` to always display 6 weeks per month. This will prevent the grid changing its height while navigating the calendar.

:::note

In the current version, this prop requires `showOutsideDays` set to work. This
requirement will be removed in the next major version.

:::
In a year, months can have between 4 an 6 weeks. Use `fixedWeeks` to always display 6 weeks per month. This will prevent the grid changing its height while navigating the calendar.

```tsx
<DayPicker showOutsideDays fixedWeeks />
<DayPicker fixedWeeks showWeekNumber />
```

<BrowserWindow>
Expand Down Expand Up @@ -122,3 +117,21 @@ To display the column with the week numbers, use the `showWeekNumber` prop. Use
<BrowserWindow>
<Examples.Weeknumber />
</BrowserWindow>

## Formatters and Labels

Use the [formatters](./localization.mdx#formatters) and [labels](./localization.mdx#labels) to customize the format of the dates and the ARIA labels.

| Prop Name | Type | Description |
| ------------ | ------------------------------------------------- | ---------------------------------------------- |
| `formatters` | [`Formatters`](../api/type-aliases/Formatters.md) | Format of the dates displayed in the calendar. |
| `labels` | [`Labels`](../api/type-aliases/Labels.md) | Set the ARIA labels used in the calendar. |

## Custom Components

In DayPicker, you can replace the components used internally to render the calendar. See the [Custom Components](../advanced-guides/custom-components.mdx) guide for more information.

| Prop Name | Type | Description |
| ------------ | ------------------------------------------------------------- | ----------------------------------------------------------- |
| `components` | [`CustomComponents`](../api/type-aliases/CustomComponents.md) | Change the internal components used to render the calendar. |
| `classNames` | [`ClassNames`](../api/type-aliases/ClassNames.md) | Use custom class names instead of the default ones. |

0 comments on commit 549da00

Please sign in to comment.