diff --git a/src/calendar.tsx b/src/calendar.tsx index 4bedbdc06..eb98d3056 100644 --- a/src/calendar.tsx +++ b/src/calendar.tsx @@ -438,9 +438,22 @@ export default class Calendar extends Component { }; handleMonthChange = (date: Date): void => { - const enabledPreSelectionDate = + let enabledPreSelectionDate = this.getEnabledPreSelectionDateForMonth(date) ?? date; + if ( + this.props.maxDate && + isAfter(enabledPreSelectionDate, this.props.maxDate) + ) { + enabledPreSelectionDate = this.props.maxDate; + } + if ( + this.props.minDate && + isBefore(enabledPreSelectionDate, this.props.minDate) + ) { + enabledPreSelectionDate = this.props.minDate; + } + this.handleCustomMonthChange(enabledPreSelectionDate); if (this.props.adjustDateOnChange) { this.props.onSelect(enabledPreSelectionDate); diff --git a/src/test/month_navigation_clamp.test.tsx b/src/test/month_navigation_clamp.test.tsx new file mode 100644 index 000000000..974e440cd --- /dev/null +++ b/src/test/month_navigation_clamp.test.tsx @@ -0,0 +1,52 @@ +import { fireEvent } from "@testing-library/dom"; +import React from "react"; + +import DatePicker from "index"; +import { safeQuerySelector } from "./test_utils"; +import { render } from "@testing-library/react"; + +describe("month navigation clamps to minDate/maxDate (snapback)", () => { + const minDate = new Date(2026, 4, 24); // May 24, 2026 + const maxDate = new Date(2026, 6, 23); // July 23, 2026 + const includeDates = [new Date(2026, 4, 5), new Date(2026, 4, 30)]; // May only + + function navigateToJuly() { + const onMonthChange = jest.fn(); + + const { container } = render( + {}} + minDate={minDate} + maxDate={maxDate} + includeDates={includeDates} + openToDate={new Date(2026, 4, 24)} + onMonthChange={onMonthChange} + showMonthDropdown + dropdownMode="scroll" + />, + ); + + fireEvent.click( + safeQuerySelector(container, ".react-datepicker__month-read-view"), + ); + const july = Array.from( + container.querySelectorAll(".react-datepicker__month-option"), + ).find((option) => option.textContent?.includes("July")); + fireEvent.click(july!); + return { container, onMonthChange }; + } + + it("does not snap back when navigating to a month with no selectable days", () => { + const { container, onMonthChange } = navigateToJuly(); + + expect(onMonthChange).toHaveBeenCalledTimes(1); + expect(onMonthChange.mock.calls[0]?.[0].getMonth()).toBe(6); + expect( + safeQuerySelector(container, ".react-datepicker__month").getAttribute( + "aria-label", + ), + ).toContain("July"); + }); +});