Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
30 changes: 30 additions & 0 deletions examples/TestCase2912.test.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
import React from "react";

import { grid } from "@/test/elements";
import { render, screen } from "@/test/render";
import { user } from "@/test/user";

import { TestCase2912 } from "./TestCase2912";

describe("when startMonth moves after the displayed month", () => {
test("should display the new start month as the first month", async () => {
render(<TestCase2912 />);
await user.click(
screen.getByRole("button", { name: "Update start month" }),
);
const grids = screen.getAllByRole("grid");
expect(grids[0]).toHaveAccessibleName("July 2028");
expect(grids[1]).toHaveAccessibleName("August 2028");
expect(grid("July 2028")).toBeInTheDocument();
});
});

describe("when endMonth moves before the displayed month", () => {
test("should display the first month {{numberOfMonths}} months before the new end month", async () => {
render(<TestCase2912 />);
await user.click(screen.getByRole("button", { name: "Update end month" }));
const grids = screen.getAllByRole("grid");
expect(grids[0]).toHaveAccessibleName("June 2024");
expect(grids[1]).toHaveAccessibleName("July 2024");
});
});
38 changes: 38 additions & 0 deletions examples/TestCase2912.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
import { DayPicker } from "@daypicker/react";
import { addYears } from "date-fns";
import React, { useState } from "react";

const today = new Date(2026, 6, 25);

/**
* Reproduction for issue #2912
*
* @see https://github.com/gpbl/react-day-picker/issues/2912
*/
export function TestCase2912() {
const [startMonth, setStartMonth] = useState(() => addYears(today, -5));
const [endMonth, setEndMonth] = useState(() => addYears(today, 5));

const narrowStartMonth = () => setStartMonth(addYears(today, 2));
const narrowEndMonth = () => setEndMonth(addYears(today, -2));

return (
<div>
<div style={{ display: "flex", gap: "10px", padding: "10px" }}>
<button type="button" onClick={narrowStartMonth}>
Update start month
</button>
<button type="button" onClick={narrowEndMonth}>
Update end month
</button>
</div>
<DayPicker
today={today}
startMonth={startMonth}
endMonth={endMonth}
numberOfMonths={2}
captionLayout="dropdown"
/>
</div>
);
}
1 change: 1 addition & 0 deletions examples/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -102,6 +102,7 @@ export * from "./TestCase2585";
export * from "./TestCase2835";
export * from "./TestCase2843";
export * from "./TestCase2864";
export * from "./TestCase2912";
export * from "./Testcase1567";
export * from "./TimeZone";
export * from "./TimeZoneNoonSafe";
Expand Down
100 changes: 0 additions & 100 deletions packages/react-day-picker/src/helpers/getInitialMonth.test.ts

This file was deleted.

46 changes: 0 additions & 46 deletions packages/react-day-picker/src/helpers/getInitialMonth.ts

This file was deleted.

Original file line number Diff line number Diff line change
@@ -0,0 +1,97 @@
import { addMonths, isSameDay, isSameMonth, startOfMonth } from "date-fns";

import { defaultDateLib } from "../classes/DateLib";

import { getValidDisplayedFirstMonth } from "./getValidDisplayedFirstMonth";

test("return start of month", () => {
const displayedFirstMonth = new Date(2010, 11, 12);
const validDisplayedFirstMonth = getValidDisplayedFirstMonth(
displayedFirstMonth,
1,
undefined,
undefined,
defaultDateLib,
);
expect(
isSameDay(validDisplayedFirstMonth, startOfMonth(displayedFirstMonth)),
).toBe(true);
});

describe("when no navStart and navEnd are given", () => {
const displayedFirstMonth = new Date(2010, 11, 12);
const navStart = addMonths(displayedFirstMonth, -1);
const navEnd = addMonths(displayedFirstMonth, 1);
test("return displayedFirstMonth if within range", () => {
const validDisplayedFirstMonth = getValidDisplayedFirstMonth(
displayedFirstMonth,
1,
navStart,
navEnd,
defaultDateLib,
);
expect(isSameMonth(validDisplayedFirstMonth, displayedFirstMonth)).toBe(
true,
);
});

test("return navStart if numberOfMonths value is longer than the valid range when month is after navEnd", () => {
const newDisplayedFirstMonth = addMonths(displayedFirstMonth, 2);
const validDisplayedFirstMonth = getValidDisplayedFirstMonth(
newDisplayedFirstMonth,
6,
navStart,
navEnd,
defaultDateLib,
);
expect(isSameMonth(validDisplayedFirstMonth, navStart)).toBe(true);
});
});

describe("when navStart is given and is after the displayedFirstMonth", () => {
test("return the navStart", () => {
const displayedFirstMonth = new Date(2010, 11, 12);
const navStart = addMonths(displayedFirstMonth, 1);
const validDisplayedFirstMonth = getValidDisplayedFirstMonth(
displayedFirstMonth,
3,
navStart,
undefined,
defaultDateLib,
);
expect(isSameMonth(validDisplayedFirstMonth, navStart)).toBe(true);
});
});

describe("when navEnd is given", () => {
describe("when navEnd is before the displayedFirstMonth", () => {
const displayedFirstMonth = new Date(2010, 11, 12);
const navEnd = addMonths(displayedFirstMonth, -2);
describe("when the number of month is 1", () => {
test("returns the navEnd so the last displayed month does not exceed navEnd", () => {
const validDisplayedFirstMonth = getValidDisplayedFirstMonth(
displayedFirstMonth,
1,
undefined,
navEnd,
defaultDateLib,
);
expect(isSameMonth(validDisplayedFirstMonth, navEnd)).toBe(true);
});
});
describe("when the number of month is 3", () => {
test("returns the month so that displayedFirstMonth + 2 months = navEnd (last displayed month is navEnd)", () => {
const validDisplayedFirstMonth = getValidDisplayedFirstMonth(
displayedFirstMonth,
3,
undefined,
navEnd,
defaultDateLib,
);
// The last displayed month should be navEnd, so initialMonth = navEnd - 2 months
const expectedMonth = addMonths(navEnd, -2);
expect(isSameMonth(validDisplayedFirstMonth, expectedMonth)).toBe(true);
});
});
});
});
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
import type { DateLib } from "../classes/DateLib.js";

/**
* This function computes the valid first month to display, considering constraints such as
* `navStart`, `navEnd`, and the number of months to display.
*
* @param displayedFirstMonth Intended first month to display.
* @param numberOfMonths The number of months to display.
* @param navStart The month where the navigation starts.
* @param navEnd The month where the navigation ends.
* @param dateLib The date library to use for date manipulation.
* @returns The initial month to display.
*/
export function getValidDisplayedFirstMonth(
displayedFirstMonth: Date,
numberOfMonths: number,
navStart: Date | undefined,
navEnd: Date | undefined,
dateLib: DateLib,
): Date {
let validFirstMonth = displayedFirstMonth;
const { differenceInCalendarMonths, addMonths, startOfMonth } = dateLib;

if (
navEnd &&
differenceInCalendarMonths(navEnd, validFirstMonth) < numberOfMonths - 1
) {
const offset = -1 * (numberOfMonths - 1);
validFirstMonth = addMonths(navEnd, offset);
}

if (navStart && differenceInCalendarMonths(validFirstMonth, navStart) < 0) {
validFirstMonth = navStart;
}

return startOfMonth(validFirstMonth);
}
Loading
Loading