Skip to content

Commit f43f31e

Browse files
authored
fix: select the same day in range mode when range is open and min prop is 0 (#2816)
* examples: add RangeResetSelection * Allow selecting range with equal from and to dates * Add RangeResetSelection tests * fix lint
1 parent 63aa7a2 commit f43f31e

5 files changed

Lines changed: 107 additions & 2 deletions

File tree

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
import { screen } from "@testing-library/react";
2+
import { addDays } from "date-fns";
3+
import React from "react";
4+
import { dateButton } from "@/test/elements";
5+
import { render } from "@/test/render";
6+
import { user } from "@/test/user";
7+
import { RangeResetSelection } from "./RangeResetSelection";
8+
9+
const today = new Date(2022, 8, 12);
10+
11+
beforeAll(() => jest.setSystemTime(today));
12+
afterAll(() => jest.useRealTimers());
13+
14+
beforeEach(() => render(<RangeResetSelection />));
15+
16+
const getFrom = () => screen.getByTestId("from");
17+
const getTo = () => screen.getByTestId("to");
18+
19+
test("select same day range", async () => {
20+
await user.click(dateButton(today));
21+
expect(getFrom()).toHaveTextContent("from: 2022-09-12");
22+
expect(getTo()).toHaveTextContent("to:");
23+
await user.click(dateButton(today));
24+
expect(getFrom()).toHaveTextContent("from: 2022-09-12");
25+
expect(getTo()).toHaveTextContent("to: 2022-09-12");
26+
});
27+
28+
test("start range after click on day with range selected", async () => {
29+
await user.click(dateButton(today));
30+
expect(getFrom()).toHaveTextContent("from: 2022-09-12");
31+
expect(getTo()).toHaveTextContent("to:");
32+
await user.click(dateButton(addDays(today, 1)));
33+
expect(getFrom()).toHaveTextContent("from: 2022-09-12");
34+
expect(getTo()).toHaveTextContent("to: 2022-09-13");
35+
await user.click(dateButton(addDays(today, 4)));
36+
expect(getFrom()).toHaveTextContent("from: 2022-09-16");
37+
expect(getTo()).toHaveTextContent("to:");
38+
await user.click(dateButton(today));
39+
expect(getFrom()).toHaveTextContent("from: 2022-09-12");
40+
expect(getTo()).toHaveTextContent("to: 2022-09-16");
41+
});

examples/RangeResetSelection.tsx

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
import { format } from "date-fns";
2+
import React, { useState } from "react";
3+
4+
import {
5+
type DateRange,
6+
type DayEventHandler,
7+
DayPicker,
8+
type OnSelectHandler,
9+
} from "react-day-picker";
10+
11+
export function RangeResetSelection() {
12+
const [selected, setSelected] = useState<DateRange>();
13+
14+
// use onSelect event which properly handles valid range selection
15+
// based on valid days in the calendar
16+
const handleSelect: OnSelectHandler<DateRange | undefined> = (range) => {
17+
// the other cases are handled by onDayClick handler
18+
if (selected?.from && !selected.to) {
19+
setSelected(range);
20+
}
21+
};
22+
23+
const handleDayClick: DayEventHandler<React.MouseEvent> = (date) => {
24+
// handled by onSelect handler
25+
if (selected?.from && !selected.to) {
26+
return;
27+
}
28+
setSelected({ from: date });
29+
};
30+
31+
return (
32+
<DayPicker
33+
mode="range"
34+
selected={selected}
35+
onSelect={handleSelect}
36+
onDayClick={handleDayClick}
37+
footer={
38+
<div>
39+
<p data-testid="from">
40+
from: {selected?.from && format(selected?.from, "yyyy-MM-dd")}
41+
</p>
42+
<p data-testid="to">
43+
to: {selected?.to && format(selected?.to, "yyyy-MM-dd")}
44+
</p>
45+
</div>
46+
}
47+
/>
48+
);
49+
}

examples/index.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,7 @@ export * from "./RangeLong";
6868
export * from "./RangeLongExcludeDisabled";
6969
export * from "./RangeMinMax";
7070
export * from "./RangeRequired";
71+
export * from "./RangeResetSelection";
7172
export * from "./RangeShiftKey";
7273
export * from "./Rtl";
7374
export * from "./Single";

src/utils/addToRange.test.ts

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,12 +13,24 @@ describe("addToRange", () => {
1313
expect(range).toEqual({ from: date, to: date });
1414
});
1515

16-
test("add a date to an incomplete range with same start date", () => {
16+
test("add a date to an incomplete range with same start date and min = 0", () => {
1717
const date = new Date(2022, 0, 1);
1818
const range = addToRange(date, { from: date, to: undefined });
19+
expect(range).toEqual({ from: date, to: date });
20+
});
21+
22+
test("add a date to an incomplete range with same start date and min > 0", () => {
23+
const date = new Date(2022, 0, 1);
24+
const range = addToRange(date, { from: date, to: undefined }, 1, 0, false);
1925
expect(range).toEqual(undefined);
2026
});
2127

28+
test("add a date to an incomplete range with same start date and min > 0 and required", () => {
29+
const date = new Date(2022, 0, 1);
30+
const range = addToRange(date, { from: date, to: undefined }, 1, 0, true);
31+
expect(range).toEqual({ from: date, to: undefined });
32+
});
33+
2234
test("add a date to an incomplete range with earlier date", () => {
2335
const from = new Date(2022, 0, 1);
2436
const earlierDate = new Date(2021, 11, 31);

src/utils/addToRange.ts

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,9 @@ export function addToRange(
3434
// adding date to an incomplete range
3535
if (isSameDay(from, date)) {
3636
// adding a date equal to the start of the range
37-
if (required) {
37+
if (min === 0) {
38+
range = { from, to: date };
39+
} else if (required) {
3840
range = { from, to: undefined };
3941
} else {
4042
range = undefined;

0 commit comments

Comments
 (0)