react-day-picker 9.0.3 → 9.0.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +1 -1
- package/dist/cjs/DayPicker.js +8 -2
- package/dist/cjs/DayPicker.js.map +1 -1
- package/dist/cjs/selection/useRange.js +3 -19
- package/dist/cjs/selection/useRange.js.map +1 -1
- package/dist/cjs/types/props.d.ts +4 -0
- package/dist/cjs/useCalendar.js +2 -2
- package/dist/cjs/useCalendar.js.map +1 -1
- package/dist/cjs/utils/addToRange.d.ts +6 -2
- package/dist/cjs/utils/addToRange.js +68 -24
- package/dist/cjs/utils/addToRange.js.map +1 -1
- package/dist/esm/DayPicker.js +8 -2
- package/dist/esm/DayPicker.js.map +1 -1
- package/dist/esm/selection/useRange.js +3 -19
- package/dist/esm/selection/useRange.js.map +1 -1
- package/dist/esm/types/props.d.ts +4 -0
- package/dist/esm/useCalendar.js +2 -2
- package/dist/esm/useCalendar.js.map +1 -1
- package/dist/esm/utils/addToRange.d.ts +6 -2
- package/dist/esm/utils/addToRange.js +68 -24
- package/dist/esm/utils/addToRange.js.map +1 -1
- package/examples/CustomDayButton.test.tsx +26 -0
- package/examples/CustomDayButton.tsx +21 -10
- package/examples/MultipleRequired.tsx +7 -0
- package/examples/RangeMinMax.test.tsx +5 -16
- package/examples/RangeMinMax.tsx +5 -6
- package/examples/RangeRequired.tsx +30 -0
- package/examples/RangeShiftKey.tsx +4 -6
- package/examples/StartEndMonths.test.tsx +30 -0
- package/examples/index.ts +2 -0
- package/package.json +3 -3
- package/src/DayPicker.test.tsx +25 -2
- package/src/DayPicker.tsx +24 -0
- package/src/selection/useRange.test.tsx +2 -2
- package/src/selection/useRange.tsx +3 -25
- package/src/style.css +15 -9
- package/src/style.module.css +15 -9
- package/src/types/props.ts +4 -0
- package/src/useCalendar.ts +7 -2
- package/src/utils/addToRange.test.ts +95 -97
- package/src/utils/addToRange.ts +64 -28
- package/website/docs/docs/selection-modes.mdx +51 -75
- package/website/docs/guides/custom-components.mdx +65 -88
- package/website/docs/intro.mdx +1 -1
- package/website/docs/upgrading.mdx +4 -9
- package/examples/CustomDayDate.test.tsx +0 -16
|
@@ -7,41 +7,85 @@ import { dateLib as defaultDateLib } from "../lib/index.js";
|
|
|
7
7
|
*
|
|
8
8
|
* @group Utilities
|
|
9
9
|
*/
|
|
10
|
-
export function addToRange(
|
|
10
|
+
export function addToRange(
|
|
11
|
+
/** The date to add to the range. */
|
|
12
|
+
date,
|
|
13
|
+
/** The range where to add `date`. */
|
|
14
|
+
initialRange, min = 0, max = 0, required = false,
|
|
11
15
|
/** @ignore */
|
|
12
16
|
dateLib = defaultDateLib) {
|
|
13
|
-
const { from, to } =
|
|
17
|
+
const { from, to } = initialRange || {};
|
|
14
18
|
const { isSameDay, isAfter, isBefore } = dateLib;
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
}
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
19
|
+
let range;
|
|
20
|
+
if (!from && !to) {
|
|
21
|
+
// the range is empty, add the date
|
|
22
|
+
range = { from: date, to: min > 0 ? undefined : date };
|
|
23
|
+
}
|
|
24
|
+
else if (from && !to) {
|
|
25
|
+
// adding date to an incomplete range
|
|
22
26
|
if (isSameDay(from, date)) {
|
|
23
|
-
|
|
27
|
+
// adding a date equal to the start of the range
|
|
28
|
+
if (required) {
|
|
29
|
+
range = { from, to: undefined };
|
|
30
|
+
}
|
|
31
|
+
else {
|
|
32
|
+
range = undefined;
|
|
33
|
+
}
|
|
24
34
|
}
|
|
25
|
-
if (
|
|
26
|
-
|
|
35
|
+
else if (isBefore(date, from)) {
|
|
36
|
+
// adding a date before the start of the range
|
|
37
|
+
range = { from: date, to: from };
|
|
38
|
+
}
|
|
39
|
+
else {
|
|
40
|
+
// adding a date after the start of the range
|
|
41
|
+
range = { from, to: date };
|
|
27
42
|
}
|
|
28
|
-
return { from, to: date };
|
|
29
43
|
}
|
|
30
|
-
if (to) {
|
|
31
|
-
|
|
32
|
-
|
|
44
|
+
else if (from && to) {
|
|
45
|
+
// adding date to a complete range
|
|
46
|
+
if (isSameDay(from, date) && isSameDay(to, date)) {
|
|
47
|
+
// adding a date that is equal to both start and end of the range
|
|
48
|
+
if (required) {
|
|
49
|
+
range = { from, to };
|
|
50
|
+
}
|
|
51
|
+
else {
|
|
52
|
+
range = undefined;
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
else if (isSameDay(from, date)) {
|
|
56
|
+
// adding a date equal to the the start of the range
|
|
57
|
+
range = { from, to: min > 0 ? undefined : date };
|
|
58
|
+
}
|
|
59
|
+
else if (isSameDay(to, date)) {
|
|
60
|
+
// adding a dare equal to the end of the range
|
|
61
|
+
range = { from: date, to: min > 0 ? undefined : date };
|
|
62
|
+
}
|
|
63
|
+
else if (isBefore(date, from)) {
|
|
64
|
+
// adding a date before the start of the range
|
|
65
|
+
range = { from: date, to: to };
|
|
66
|
+
}
|
|
67
|
+
else if (isAfter(date, from)) {
|
|
68
|
+
// adding a date after the start of the range
|
|
69
|
+
range = { from, to: date };
|
|
70
|
+
}
|
|
71
|
+
else if (isAfter(date, to)) {
|
|
72
|
+
// adding a date after the end of the range
|
|
73
|
+
range = { from, to: date };
|
|
74
|
+
}
|
|
75
|
+
else {
|
|
76
|
+
throw new Error("Invalid range");
|
|
33
77
|
}
|
|
34
|
-
return { from: date, to };
|
|
35
78
|
}
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
79
|
+
// check for min / max
|
|
80
|
+
if (range?.from && range?.to) {
|
|
81
|
+
const diff = dateLib.differenceInCalendarDays(range.to, range.from);
|
|
82
|
+
if (max > 0 && diff > max) {
|
|
83
|
+
range = { from: date, to: undefined };
|
|
39
84
|
}
|
|
40
|
-
if (
|
|
41
|
-
|
|
85
|
+
else if (min > 1 && diff < min) {
|
|
86
|
+
range = { from: date, to: undefined };
|
|
42
87
|
}
|
|
43
|
-
return { from, to: date };
|
|
44
88
|
}
|
|
45
|
-
return
|
|
89
|
+
return range;
|
|
46
90
|
}
|
|
47
91
|
//# sourceMappingURL=addToRange.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"addToRange.js","sourceRoot":"","sources":["../../../src/utils/addToRange.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,IAAI,cAAc,EAAE,MAAM,iBAAiB,CAAC;AAG5D;;;;;;;GAOG;AACH,MAAM,UAAU,UAAU,
|
|
1
|
+
{"version":3,"file":"addToRange.js","sourceRoot":"","sources":["../../../src/utils/addToRange.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import React from "react";
|
|
2
|
+
|
|
3
|
+
import { startOfMonth } from "date-fns";
|
|
4
|
+
|
|
5
|
+
import { dateButton } from "@/test/elements";
|
|
6
|
+
import { render, screen, fireEvent } from "@/test/render";
|
|
7
|
+
|
|
8
|
+
import { CustomDayButton } from "./CustomDayButton";
|
|
9
|
+
|
|
10
|
+
const today = new Date(2021, 10, 25);
|
|
11
|
+
beforeAll(() => jest.setSystemTime(today));
|
|
12
|
+
afterAll(() => jest.useRealTimers());
|
|
13
|
+
|
|
14
|
+
beforeEach(() => {
|
|
15
|
+
render(<CustomDayButton />);
|
|
16
|
+
});
|
|
17
|
+
|
|
18
|
+
test("update the footer when a day is double clicked", () => {
|
|
19
|
+
fireEvent.doubleClick(dateButton(today));
|
|
20
|
+
expect(screen.getByText(today.toDateString())).toBeInTheDocument();
|
|
21
|
+
});
|
|
22
|
+
|
|
23
|
+
test("update the footer when a day is single clicked", () => {
|
|
24
|
+
fireEvent.click(dateButton(startOfMonth(today)));
|
|
25
|
+
expect(screen.getByText("Double click to select a date")).toBeInTheDocument();
|
|
26
|
+
});
|
|
@@ -1,16 +1,27 @@
|
|
|
1
1
|
import React from "react";
|
|
2
2
|
|
|
3
|
-
import { DayPicker
|
|
3
|
+
import { DayPicker } from "react-day-picker";
|
|
4
4
|
|
|
5
|
-
function
|
|
6
|
-
const
|
|
5
|
+
export function CustomDayButton() {
|
|
6
|
+
const [selected, setSelected] = React.useState<Date>();
|
|
7
7
|
return (
|
|
8
|
-
<
|
|
9
|
-
|
|
10
|
-
|
|
8
|
+
<DayPicker
|
|
9
|
+
mode="single"
|
|
10
|
+
onSelect={setSelected}
|
|
11
|
+
selected={selected}
|
|
12
|
+
components={{
|
|
13
|
+
DayButton: (props) => {
|
|
14
|
+
const { day, modifiers, ...buttonProps } = props;
|
|
15
|
+
return (
|
|
16
|
+
<button
|
|
17
|
+
{...buttonProps}
|
|
18
|
+
onDoubleClick={() => setSelected(day.date)}
|
|
19
|
+
onClick={() => setSelected(undefined)}
|
|
20
|
+
/>
|
|
21
|
+
);
|
|
22
|
+
}
|
|
23
|
+
}}
|
|
24
|
+
footer={selected?.toDateString() || "Double click to select a date"}
|
|
25
|
+
/>
|
|
11
26
|
);
|
|
12
27
|
}
|
|
13
|
-
|
|
14
|
-
export function CustomDayButton() {
|
|
15
|
-
return <DayPicker mode="single" components={{ DayButton: HighlightDay }} />;
|
|
16
|
-
}
|
|
@@ -8,6 +8,11 @@ import { user } from "@/test/user";
|
|
|
8
8
|
|
|
9
9
|
import { RangeMinMax } from "./RangeMinMax";
|
|
10
10
|
|
|
11
|
+
const today = new Date(2022, 8, 12);
|
|
12
|
+
|
|
13
|
+
beforeAll(() => jest.setSystemTime(today));
|
|
14
|
+
afterAll(() => jest.useRealTimers());
|
|
15
|
+
|
|
11
16
|
beforeEach(() => render(<RangeMinMax />));
|
|
12
17
|
|
|
13
18
|
describe("when a day is clicked", () => {
|
|
@@ -18,22 +23,6 @@ describe("when a day is clicked", () => {
|
|
|
18
23
|
test("should be selected", () => {
|
|
19
24
|
expect(gridcell(firstDay, true)).toHaveAttribute("aria-selected", "true");
|
|
20
25
|
});
|
|
21
|
-
describe("when the day before min is clicked", () => {
|
|
22
|
-
const dayAfter = addDays(firstDay, 1);
|
|
23
|
-
beforeEach(async () => {
|
|
24
|
-
await user.click(dateButton(dayAfter));
|
|
25
|
-
});
|
|
26
|
-
test("the first day should not be selected", () => {
|
|
27
|
-
expect(gridcell(firstDay, true)).not.toHaveAttribute(
|
|
28
|
-
"aria-selected",
|
|
29
|
-
"true"
|
|
30
|
-
);
|
|
31
|
-
});
|
|
32
|
-
test("the day after should be selected", () => {
|
|
33
|
-
expect(gridcell(dayAfter, true)).toHaveAttribute("aria-selected", "true");
|
|
34
|
-
});
|
|
35
|
-
});
|
|
36
|
-
|
|
37
26
|
describe("when the day after min is clicked", () => {
|
|
38
27
|
const dayAfter = addDays(firstDay, 4);
|
|
39
28
|
beforeEach(async () => {
|
package/examples/RangeMinMax.tsx
CHANGED
|
@@ -9,20 +9,19 @@ export function RangeMinMax() {
|
|
|
9
9
|
let footer = `Please pick the first day.`;
|
|
10
10
|
if (range?.from) {
|
|
11
11
|
if (!range.to) {
|
|
12
|
-
footer = format(range.from, "PPP")
|
|
12
|
+
footer = `${format(range.from, "PPP")}—`;
|
|
13
13
|
} else if (range.to) {
|
|
14
|
-
footer = `${format(range.from, "PPP")}
|
|
14
|
+
footer = `${format(range.from, "PPP")}—${format(range.to, "PPP")}`;
|
|
15
15
|
}
|
|
16
16
|
}
|
|
17
17
|
|
|
18
18
|
return (
|
|
19
19
|
<div>
|
|
20
|
-
<p>Select
|
|
20
|
+
<p>Select up to 6 nights.</p>
|
|
21
21
|
<DayPicker
|
|
22
|
-
defaultMonth={new Date(2022, 8)}
|
|
23
22
|
mode="range"
|
|
24
|
-
min={
|
|
25
|
-
max={
|
|
23
|
+
min={1}
|
|
24
|
+
max={6}
|
|
26
25
|
selected={range}
|
|
27
26
|
onSelect={setRange}
|
|
28
27
|
footer={footer}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import React, { useState } from "react";
|
|
2
|
+
|
|
3
|
+
import { addDays, format, startOfMonth } from "date-fns";
|
|
4
|
+
import { DateRange, DayPicker } from "react-day-picker";
|
|
5
|
+
|
|
6
|
+
export function RangeRequired() {
|
|
7
|
+
const [range, setRange] = useState<DateRange>({
|
|
8
|
+
from: startOfMonth(new Date()),
|
|
9
|
+
to: addDays(startOfMonth(new Date()), 4)
|
|
10
|
+
});
|
|
11
|
+
|
|
12
|
+
let footer = `Please pick the first day.`;
|
|
13
|
+
if (range?.from) {
|
|
14
|
+
if (!range.to) {
|
|
15
|
+
footer = `${format(range.from, "PPP")}—`;
|
|
16
|
+
} else if (range.to) {
|
|
17
|
+
footer = `${format(range.from, "PPP")}—${format(range.to, "PPP")}`;
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
return (
|
|
22
|
+
<DayPicker
|
|
23
|
+
mode="range"
|
|
24
|
+
required
|
|
25
|
+
selected={range}
|
|
26
|
+
onSelect={setRange}
|
|
27
|
+
footer={footer}
|
|
28
|
+
/>
|
|
29
|
+
);
|
|
30
|
+
}
|
|
@@ -12,12 +12,10 @@ function DayWithShiftKey(props: DayButtonProps) {
|
|
|
12
12
|
const { selected } = useDayPicker({ mode: "range" });
|
|
13
13
|
|
|
14
14
|
const handleClick: MouseEventHandler<HTMLButtonElement> = (e) => {
|
|
15
|
-
|
|
16
|
-
selected?.from &&
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
!e.shiftKey
|
|
20
|
-
) {
|
|
15
|
+
const requireShiftKey =
|
|
16
|
+
selected?.from && !isSameDay(props.day.date, selected.from);
|
|
17
|
+
|
|
18
|
+
if (!e.shiftKey && requireShiftKey) {
|
|
21
19
|
return;
|
|
22
20
|
}
|
|
23
21
|
props.onClick?.(e);
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import React from "react";
|
|
2
|
+
|
|
3
|
+
import { grid, gridcell, nextButton } from "@/test/elements";
|
|
4
|
+
import { render } from "@/test/render";
|
|
5
|
+
import { user } from "@/test/user";
|
|
6
|
+
|
|
7
|
+
import { StartEndMonths } from "./StartEndMonths";
|
|
8
|
+
|
|
9
|
+
beforeEach(() => {
|
|
10
|
+
render(<StartEndMonths />);
|
|
11
|
+
});
|
|
12
|
+
|
|
13
|
+
test("the first month should be January 2024", () => {
|
|
14
|
+
expect(grid("January 2024")).toBeInTheDocument();
|
|
15
|
+
expect(gridcell(new Date(2024, 0, 31))).toBeInTheDocument();
|
|
16
|
+
});
|
|
17
|
+
|
|
18
|
+
describe("when navigating to the last month", () => {
|
|
19
|
+
beforeEach(async () => {
|
|
20
|
+
// click next button 24 times
|
|
21
|
+
for (let i = 0; i < 24; i++) {
|
|
22
|
+
await user.click(nextButton());
|
|
23
|
+
}
|
|
24
|
+
});
|
|
25
|
+
|
|
26
|
+
test("the last month should be December 2025", () => {
|
|
27
|
+
expect(grid("December 2025")).toBeInTheDocument();
|
|
28
|
+
expect(gridcell(new Date(2025, 11, 31))).toBeInTheDocument();
|
|
29
|
+
});
|
|
30
|
+
});
|
package/examples/index.ts
CHANGED
|
@@ -38,6 +38,7 @@ export * from "./ModifiersStyle";
|
|
|
38
38
|
export * from "./ModifiersToday";
|
|
39
39
|
export * from "./Multiple";
|
|
40
40
|
export * from "./MultipleMinMax";
|
|
41
|
+
export * from "./MultipleRequired";
|
|
41
42
|
export * from "./MultipleMonths";
|
|
42
43
|
export * from "./MultipleMonthsPaged";
|
|
43
44
|
export * from "./NumberingSystem";
|
|
@@ -45,6 +46,7 @@ export * from "./OutsideDays";
|
|
|
45
46
|
export * from "./Range";
|
|
46
47
|
export * from "./RangeExcludeDisabled";
|
|
47
48
|
export * from "./RangeMinMax";
|
|
49
|
+
export * from "./RangeRequired";
|
|
48
50
|
export * from "./RangeShiftKey";
|
|
49
51
|
export * from "./Rtl";
|
|
50
52
|
export * from "./Single";
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "react-day-picker",
|
|
3
|
-
"version": "9.0.
|
|
3
|
+
"version": "9.0.5",
|
|
4
4
|
"description": "Customizable Date Picker for React",
|
|
5
5
|
"author": "Giampaolo Bellavite <io@gpbl.dev>",
|
|
6
6
|
"homepage": "https://daypicker.dev",
|
|
@@ -144,7 +144,7 @@
|
|
|
144
144
|
"@types/node": "^20.14.10",
|
|
145
145
|
"@types/react": "^18.3.3",
|
|
146
146
|
"@types/react-dom": "^18.3.0",
|
|
147
|
-
"@typescript-eslint/eslint-plugin": "^7.
|
|
147
|
+
"@typescript-eslint/eslint-plugin": "^7.18.0",
|
|
148
148
|
"@typescript-eslint/parser": "^7.16.0",
|
|
149
149
|
"date-fns": "^3.6.0",
|
|
150
150
|
"date-fns-jalali": "3.6.0-1",
|
|
@@ -169,7 +169,7 @@
|
|
|
169
169
|
"ts-jest": "^29.2.3",
|
|
170
170
|
"ts-node": "^10.9.2",
|
|
171
171
|
"tslib": "^2.6.3",
|
|
172
|
-
"typescript": "~5.5.
|
|
172
|
+
"typescript": "~5.5.4",
|
|
173
173
|
"typescript-css-modules": "^1.0.4"
|
|
174
174
|
},
|
|
175
175
|
"peerDependencies": {
|
package/src/DayPicker.test.tsx
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import React from "react";
|
|
2
2
|
|
|
3
|
-
import { render, screen } from "@testing-library/react";
|
|
4
|
-
import { startOfMonth } from "date-fns";
|
|
3
|
+
import { fireEvent, render, screen } from "@testing-library/react";
|
|
4
|
+
import { startOfDay, startOfMonth } from "date-fns";
|
|
5
5
|
|
|
6
6
|
import {
|
|
7
7
|
activeElement,
|
|
@@ -108,3 +108,26 @@ describe("when the grid is focused", () => {
|
|
|
108
108
|
});
|
|
109
109
|
});
|
|
110
110
|
});
|
|
111
|
+
|
|
112
|
+
describe("when a day is mouse entered", () => {
|
|
113
|
+
const handleDayMouseEnter = jest.fn();
|
|
114
|
+
const handleDayMouseLeave = jest.fn();
|
|
115
|
+
const today = startOfDay(new Date());
|
|
116
|
+
beforeEach(async () => {
|
|
117
|
+
render(
|
|
118
|
+
<DayPicker
|
|
119
|
+
today={today}
|
|
120
|
+
defaultMonth={today}
|
|
121
|
+
mode="single"
|
|
122
|
+
onDayMouseEnter={handleDayMouseEnter}
|
|
123
|
+
onDayMouseLeave={handleDayMouseLeave}
|
|
124
|
+
/>
|
|
125
|
+
);
|
|
126
|
+
fireEvent.mouseEnter(dateButton(today));
|
|
127
|
+
fireEvent.mouseLeave(dateButton(today));
|
|
128
|
+
});
|
|
129
|
+
test("should call the event handler", async () => {
|
|
130
|
+
expect(handleDayMouseEnter).toHaveBeenCalled();
|
|
131
|
+
expect(handleDayMouseLeave).toHaveBeenCalled();
|
|
132
|
+
});
|
|
133
|
+
});
|
package/src/DayPicker.tsx
CHANGED
|
@@ -69,6 +69,8 @@ export function DayPicker(props: DayPickerProps) {
|
|
|
69
69
|
onDayClick,
|
|
70
70
|
onDayFocus,
|
|
71
71
|
onDayKeyDown,
|
|
72
|
+
onDayMouseEnter,
|
|
73
|
+
onDayMouseLeave,
|
|
72
74
|
onNextClick,
|
|
73
75
|
onPrevClick,
|
|
74
76
|
showWeekNumber,
|
|
@@ -209,6 +211,20 @@ export function DayPicker(props: DayPickerProps) {
|
|
|
209
211
|
[moveFocus, onDayKeyDown, props.dir]
|
|
210
212
|
);
|
|
211
213
|
|
|
214
|
+
const handleDayMouseEnter = useCallback(
|
|
215
|
+
(day: CalendarDay, modifiers: Modifiers) => (e: MouseEvent) => {
|
|
216
|
+
onDayMouseEnter?.(day.date, modifiers, e);
|
|
217
|
+
},
|
|
218
|
+
[onDayMouseEnter]
|
|
219
|
+
);
|
|
220
|
+
|
|
221
|
+
const handleDayMouseLeave = useCallback(
|
|
222
|
+
(day: CalendarDay, modifiers: Modifiers) => (e: MouseEvent) => {
|
|
223
|
+
onDayMouseLeave?.(day.date, modifiers, e);
|
|
224
|
+
},
|
|
225
|
+
[onDayMouseLeave]
|
|
226
|
+
);
|
|
227
|
+
|
|
212
228
|
const { className, style } = useMemo(
|
|
213
229
|
() => ({
|
|
214
230
|
className: [classNames[UI.Root], props.className]
|
|
@@ -552,6 +568,14 @@ export function DayPicker(props: DayPickerProps) {
|
|
|
552
568
|
onBlur={handleDayBlur(day, modifiers)}
|
|
553
569
|
onFocus={handleDayFocus(day, modifiers)}
|
|
554
570
|
onKeyDown={handleDayKeyDown(day, modifiers)}
|
|
571
|
+
onMouseEnter={handleDayMouseEnter(
|
|
572
|
+
day,
|
|
573
|
+
modifiers
|
|
574
|
+
)}
|
|
575
|
+
onMouseLeave={handleDayMouseLeave(
|
|
576
|
+
day,
|
|
577
|
+
modifiers
|
|
578
|
+
)}
|
|
555
579
|
>
|
|
556
580
|
{formatDay(date, formatOptions, dateLib)}
|
|
557
581
|
</components.DayButton>
|
|
@@ -90,7 +90,7 @@ describe("useRange", () => {
|
|
|
90
90
|
|
|
91
91
|
expect(result.current.selected).toEqual({
|
|
92
92
|
from: new Date(2023, 6, 10),
|
|
93
|
-
to:
|
|
93
|
+
to: new Date(2023, 6, 10)
|
|
94
94
|
});
|
|
95
95
|
});
|
|
96
96
|
|
|
@@ -135,7 +135,7 @@ describe("useRange", () => {
|
|
|
135
135
|
|
|
136
136
|
expect(result.current.selected).toEqual({
|
|
137
137
|
from: new Date(2023, 6, 10),
|
|
138
|
-
to:
|
|
138
|
+
to: new Date(2023, 6, 10)
|
|
139
139
|
});
|
|
140
140
|
});
|
|
141
141
|
});
|
|
@@ -24,7 +24,6 @@ export function useRange<T extends DayPickerProps>(
|
|
|
24
24
|
onSelect
|
|
25
25
|
} = props as PropsRange;
|
|
26
26
|
|
|
27
|
-
const { differenceInCalendarDays } = dateLib;
|
|
28
27
|
const [selected, setSelected] = React.useState<DateRange | undefined>(
|
|
29
28
|
initiallySelected
|
|
30
29
|
);
|
|
@@ -49,32 +48,10 @@ export function useRange<T extends DayPickerProps>(
|
|
|
49
48
|
modifiers: Modifiers,
|
|
50
49
|
e: React.MouseEvent | React.KeyboardEvent
|
|
51
50
|
) => {
|
|
51
|
+
const { min, max } = props as PropsRange;
|
|
52
52
|
const newRange = triggerDate
|
|
53
|
-
? addToRange(triggerDate, selected, dateLib)
|
|
53
|
+
? addToRange(triggerDate, selected, min, max, required, dateLib)
|
|
54
54
|
: undefined;
|
|
55
|
-
const { min, max } = props as PropsRange;
|
|
56
|
-
|
|
57
|
-
if (min) {
|
|
58
|
-
if (
|
|
59
|
-
newRange?.from &&
|
|
60
|
-
newRange.to &&
|
|
61
|
-
differenceInCalendarDays(newRange.to, newRange.from) < min - 1
|
|
62
|
-
) {
|
|
63
|
-
newRange.from = triggerDate;
|
|
64
|
-
newRange.to = undefined;
|
|
65
|
-
}
|
|
66
|
-
}
|
|
67
|
-
|
|
68
|
-
if (max) {
|
|
69
|
-
if (
|
|
70
|
-
newRange?.from &&
|
|
71
|
-
newRange.to &&
|
|
72
|
-
differenceInCalendarDays(newRange.to, newRange.from) >= max
|
|
73
|
-
) {
|
|
74
|
-
newRange.from = triggerDate;
|
|
75
|
-
newRange.to = undefined;
|
|
76
|
-
}
|
|
77
|
-
}
|
|
78
55
|
|
|
79
56
|
if (newRange?.from && newRange.to) {
|
|
80
57
|
let newDate = newRange.from;
|
|
@@ -85,6 +62,7 @@ export function useRange<T extends DayPickerProps>(
|
|
|
85
62
|
disabled &&
|
|
86
63
|
dateMatchModifiers(newDate, disabled, dateLib)
|
|
87
64
|
) {
|
|
65
|
+
// if a disabled days is found, the range is reset
|
|
88
66
|
newRange.from = triggerDate;
|
|
89
67
|
newRange.to = undefined;
|
|
90
68
|
break;
|
package/src/style.css
CHANGED
|
@@ -49,7 +49,8 @@
|
|
|
49
49
|
--rdp-week_number-height: var(--rdp-day-height); /* The height of the week number cells. */
|
|
50
50
|
--rdp-week_number-opacity: 0.75; /* The opacity of the week number. */
|
|
51
51
|
--rdp-week_number-width: var(--rdp-day-width); /* The width of the week number cells. */
|
|
52
|
-
|
|
52
|
+
--rdp-weeknumber-text-align: center; /* The text alignment of the weekday cells. */
|
|
53
|
+
|
|
53
54
|
--rdp-weekday-font: 500 smaller var(--rdp-font-family); /* The font of the weekday. */
|
|
54
55
|
--rdp-weekday-opacity: 0.75; /* The opacity of the weekday. */
|
|
55
56
|
--rdp-weekday-padding: 0.5rem 0rem; /* The padding of the weekday. */
|
|
@@ -87,6 +88,7 @@
|
|
|
87
88
|
width: var(--rdp-day-width);
|
|
88
89
|
height: var(--rdp-day-height);
|
|
89
90
|
font: var(--rdp-day-font);
|
|
91
|
+
text-align: center;
|
|
90
92
|
}
|
|
91
93
|
|
|
92
94
|
.rdp-day_button {
|
|
@@ -164,9 +166,10 @@
|
|
|
164
166
|
gap: var(--rdp-dropdown-gap);
|
|
165
167
|
}
|
|
166
168
|
.rdp-dropdown {
|
|
167
|
-
z-index: 2;
|
|
169
|
+
z-index: 2;
|
|
168
170
|
|
|
169
171
|
/* Reset */
|
|
172
|
+
opacity: 0;
|
|
170
173
|
appearance: none;
|
|
171
174
|
position: absolute;
|
|
172
175
|
inset-block-start: 0;
|
|
@@ -176,9 +179,7 @@
|
|
|
176
179
|
margin: 0;
|
|
177
180
|
padding: 0;
|
|
178
181
|
cursor: inherit;
|
|
179
|
-
color: transparent;
|
|
180
182
|
border: none;
|
|
181
|
-
background-color: transparent;
|
|
182
183
|
line-height: inherit;
|
|
183
184
|
}
|
|
184
185
|
|
|
@@ -207,6 +208,10 @@
|
|
|
207
208
|
max-width: fit-content;
|
|
208
209
|
}
|
|
209
210
|
|
|
211
|
+
.rdp-month_grid {
|
|
212
|
+
border-collapse: collapse;
|
|
213
|
+
}
|
|
214
|
+
|
|
210
215
|
.rdp-nav {
|
|
211
216
|
position: absolute;
|
|
212
217
|
inset-block-start: 0;
|
|
@@ -233,10 +238,7 @@
|
|
|
233
238
|
width: var(--rdp-week_number-width);
|
|
234
239
|
border: var(--rdp-week_number-border);
|
|
235
240
|
border-radius: var(--rdp-week_number-border-radius);
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
.rdp-week_number_interactive {
|
|
239
|
-
cursor: pointer;
|
|
241
|
+
text-align: var(--rdp-weeknumber-text-align);
|
|
240
242
|
}
|
|
241
243
|
|
|
242
244
|
/* DAY MODIFIERS */
|
|
@@ -262,7 +264,7 @@
|
|
|
262
264
|
|
|
263
265
|
.rdp-hidden {
|
|
264
266
|
visibility: hidden;
|
|
265
|
-
color: var(
|
|
267
|
+
color: var(--rdp-range_start-color);
|
|
266
268
|
}
|
|
267
269
|
|
|
268
270
|
.rdp-range_start {
|
|
@@ -296,6 +298,10 @@
|
|
|
296
298
|
background-color: var(--rdp-range_end-date-background-color);
|
|
297
299
|
}
|
|
298
300
|
|
|
301
|
+
.rdp-range_start.rdp-range_end {
|
|
302
|
+
background: revert;
|
|
303
|
+
}
|
|
304
|
+
|
|
299
305
|
.rdp-focusable {
|
|
300
306
|
cursor: pointer;
|
|
301
307
|
}
|