Skip to content

Commit

Permalink
fix: dropdown may navigate to the wrong month when multiple months ar…
Browse files Browse the repository at this point in the history
…e set (#1884)
  • Loading branch information
gpbl authored Aug 16, 2023
1 parent 748dca4 commit d993604
Show file tree
Hide file tree
Showing 6 changed files with 92 additions and 4 deletions.
15 changes: 13 additions & 2 deletions src/components/Caption/Caption.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@ export interface CaptionProps {
id?: string;
/** The month where the caption is displayed. */
displayMonth: Date;
/** The index of the month where the caption is displayed. Older custom components may miss this prop. */
displayIndex?: number | undefined;
}

/**
Expand Down Expand Up @@ -44,8 +46,16 @@ export function Caption(props: CaptionProps): JSX.Element {
} else if (captionLayout === 'dropdown-buttons') {
caption = (
<>
<CaptionDropdowns displayMonth={props.displayMonth} id={props.id} />
<CaptionNavigation displayMonth={props.displayMonth} id={props.id} />
<CaptionDropdowns
displayMonth={props.displayMonth}
displayIndex={props.displayIndex}
id={props.id}
/>
<CaptionNavigation
displayMonth={props.displayMonth}
displayIndex={props.displayIndex}
id={props.id}
/>
</>
);
} else {
Expand All @@ -54,6 +64,7 @@ export function Caption(props: CaptionProps): JSX.Element {
<CaptionLabelComponent
id={props.id}
displayMonth={props.displayMonth}
displayIndex={props.displayIndex}
/>
<CaptionNavigation displayMonth={props.displayMonth} id={props.id} />
</>
Expand Down
6 changes: 5 additions & 1 deletion src/components/CaptionDropdowns/CaptionDropdowns.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
import React from 'react';

import { addMonths } from 'date-fns';

import { CaptionProps } from 'components/Caption/Caption';
import { CaptionLabel } from 'components/CaptionLabel';
import { MonthsDropdown } from 'components/MonthsDropdown';
Expand All @@ -16,7 +18,9 @@ export function CaptionDropdowns(props: CaptionProps): JSX.Element {
const { goToMonth } = useNavigation();

const handleMonthChange: MonthChangeEventHandler = (newMonth) => {
goToMonth(newMonth);
goToMonth(
addMonths(newMonth, props.displayIndex ? -props.displayIndex : 0)
);
};
const CaptionLabelComponent = components?.CaptionLabel ?? CaptionLabel;
const captionLabel = (
Expand Down
2 changes: 2 additions & 0 deletions src/components/CaptionLabel/CaptionLabel.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@ export interface CaptionLabelProps {
id?: string;
/** The month where the caption is displayed. */
displayMonth: Date;
/** The index of the month where the caption is displayed. Older custom components may miss this prop. */
displayIndex?: number | undefined;
}

/** Render the caption for the displayed month. This component is used when `captionLayout="buttons"`. */
Expand Down
6 changes: 5 additions & 1 deletion src/components/Month/Month.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,11 @@ export function Month(props: MonthProps) {

return (
<div key={props.displayIndex} className={className.join(' ')} style={style}>
<CaptionComponent id={captionId} displayMonth={props.displayMonth} />
<CaptionComponent
id={captionId}
displayMonth={props.displayMonth}
displayIndex={props.displayIndex}
/>
<Table
id={tableId}
aria-labelledby={captionId}
Expand Down
14 changes: 14 additions & 0 deletions website/examples/dropdown-multiple-months.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
import React from 'react';

import { DayPicker } from 'react-day-picker';

export default function App() {
return (
<DayPicker
numberOfMonths={5}
captionLayout="dropdown-buttons"
fromYear={2015}
toYear={2025}
/>
);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
import React from 'react';

import { axe } from '@site/test/axe';
import { user } from '@site/test/user';
import { freezeBeforeAll } from '@site/test/utils';
import { act, render, screen } from '@testing-library/react';

import { getMonthGrid } from 'react-day-picker/test/selectors';

import Example from '@examples/dropdown-multiple-months';

const today = new Date(2023, 9, 16);
freezeBeforeAll(today);

let container: HTMLElement;
beforeEach(() => (container = render(<Example />).container));

test('should not have AXE violations', async () => {
expect(await axe(container)).toHaveNoViolations();
});

test('should display 5 year dropdowns', () => {
expect(screen.getAllByRole('combobox', { name: 'Year:' })).toHaveLength(5);
});
test('should display 5 month dropdowns', () => {
expect(screen.getAllByRole('combobox', { name: 'Month:' })).toHaveLength(5);
});

describe('when choosing a month from the first drop-down', () => {
const newMonthName = 'January';
beforeEach(() => {
const firstDropDown = screen.getAllByRole('combobox', {
name: 'Month:'
})[0];
return act(() => user.selectOptions(firstDropDown, newMonthName));
});
test('should display the month in the first dropdown', () => {
expect(getMonthGrid(0)).toHaveAccessibleName(`${newMonthName} 2023`);
});
});

describe('when choosing a month from the third drop-down', () => {
const newMonthName = 'October';
beforeEach(() => {
const thirdDropDown = screen.getAllByRole('combobox', {
name: 'Month:'
})[2];
return act(() => user.selectOptions(thirdDropDown, newMonthName));
});
test('should display the month selected the third dropdown', () => {
expect(getMonthGrid(2)).toHaveAccessibleName(`${newMonthName} 2023`);
});
});

0 comments on commit d993604

Please sign in to comment.