react-day-picker 9.0.4 → 9.0.6
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 +2 -6
- package/dist/cjs/DayPicker.js.map +1 -1
- package/dist/cjs/package.json +1 -0
- package/dist/cjs/selection/useRange.js +3 -19
- package/dist/cjs/selection/useRange.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 +2 -6
- 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/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/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 +1 -3
- package/examples/__snapshots__/Range.test.tsx.snap +26 -0
- package/examples/__snapshots__/StylingCssModules.test.tsx.snap +11 -0
- package/examples/index.ts +2 -0
- package/package.json +7 -7
- package/src/DayPicker.tsx +12 -7
- package/src/selection/useRange.test.tsx +2 -2
- package/src/selection/useRange.tsx +3 -25
- package/src/style.css +11 -5
- package/src/style.module.css +12 -6
- package/src/utils/addToRange.test.ts +95 -97
- package/src/utils/addToRange.ts +64 -28
- package/website/docs/docs/accessibility.mdx +1 -1
- package/website/docs/docs/selection-modes.mdx +51 -75
- package/website/docs/guides/custom-components.mdx +16 -88
- package/website/docs/intro.mdx +1 -1
- package/website/docs/upgrading.mdx +4 -9
- package/website/README.md +0 -25
|
@@ -1,119 +1,117 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { addToRange } from "./addToRange";
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
describe("addToRange", () => {
|
|
4
|
+
test("add a date to an undefined range", () => {
|
|
5
|
+
const date = new Date(2022, 0, 1);
|
|
6
|
+
const range = addToRange(date, undefined);
|
|
7
|
+
expect(range).toEqual({ from: date, to: date });
|
|
8
|
+
});
|
|
4
9
|
|
|
5
|
-
|
|
10
|
+
test("add a date to an empty range", () => {
|
|
11
|
+
const date = new Date(2022, 0, 1);
|
|
12
|
+
const range = addToRange(date, { from: undefined, to: undefined });
|
|
13
|
+
expect(range).toEqual({ from: date, to: date });
|
|
14
|
+
});
|
|
6
15
|
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
beforeAll(() => {
|
|
12
|
-
result = addToRange(day, range);
|
|
16
|
+
test("add a date to an incomplete range with same start date", () => {
|
|
17
|
+
const date = new Date(2022, 0, 1);
|
|
18
|
+
const range = addToRange(date, { from: date, to: undefined });
|
|
19
|
+
expect(range).toEqual(undefined);
|
|
13
20
|
});
|
|
14
|
-
|
|
15
|
-
|
|
21
|
+
|
|
22
|
+
test("add a date to an incomplete range with earlier date", () => {
|
|
23
|
+
const from = new Date(2022, 0, 1);
|
|
24
|
+
const earlierDate = new Date(2021, 11, 31);
|
|
25
|
+
const range = addToRange(earlierDate, { from: from, to: undefined });
|
|
26
|
+
expect(range).toEqual({ from: earlierDate, to: from });
|
|
16
27
|
});
|
|
17
|
-
});
|
|
18
28
|
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
beforeAll(() => {
|
|
25
|
-
result = addToRange(day, range);
|
|
26
|
-
});
|
|
27
|
-
test("should reset the range", () => {
|
|
28
|
-
expect(result).toEqual({ from: undefined, to: undefined });
|
|
29
|
-
});
|
|
30
|
-
});
|
|
31
|
-
describe('and the day is before "from" day', () => {
|
|
32
|
-
const day = subDays(range.from, 1);
|
|
33
|
-
let result: DateRange | undefined;
|
|
34
|
-
beforeAll(() => {
|
|
35
|
-
result = addToRange(day, range);
|
|
36
|
-
});
|
|
37
|
-
test('should set the day as the "from" range', () => {
|
|
38
|
-
expect(result).toEqual({ from: day, to: range.from });
|
|
39
|
-
});
|
|
40
|
-
});
|
|
41
|
-
describe('and the day is after the "from" day', () => {
|
|
42
|
-
const day = addDays(range.from, 1);
|
|
43
|
-
let result: DateRange | undefined;
|
|
44
|
-
beforeAll(() => {
|
|
45
|
-
result = addToRange(day, range);
|
|
46
|
-
});
|
|
47
|
-
test('should set the day as the "to" date', () => {
|
|
48
|
-
expect(result).toEqual({ from: range.from, to: day });
|
|
49
|
-
});
|
|
29
|
+
test("add a date to an incomplete range with later date", () => {
|
|
30
|
+
const from = new Date(2022, 0, 1);
|
|
31
|
+
const date = new Date(2022, 0, 2);
|
|
32
|
+
const range = addToRange(date, { from: from, to: undefined });
|
|
33
|
+
expect(range).toEqual({ from: from, to: date });
|
|
50
34
|
});
|
|
51
|
-
});
|
|
52
35
|
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
36
|
+
test("add a date to a complete range with same start and end date", () => {
|
|
37
|
+
const date = new Date(2022, 0, 1);
|
|
38
|
+
const from = date;
|
|
39
|
+
const to = date;
|
|
40
|
+
const range = addToRange(date, { from, to }, 0, 0, false);
|
|
41
|
+
expect(range).toEqual(undefined);
|
|
59
42
|
});
|
|
60
|
-
|
|
61
|
-
|
|
43
|
+
|
|
44
|
+
test("add a date to a complete range with same start date", () => {
|
|
45
|
+
const date = new Date(2022, 0, 1);
|
|
46
|
+
const to = new Date(2022, 0, 2);
|
|
47
|
+
const range = addToRange(date, { from: date, to: to });
|
|
48
|
+
expect(range).toEqual({ from: date, to: date });
|
|
62
49
|
});
|
|
63
|
-
});
|
|
64
50
|
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
let result: DateRange | undefined;
|
|
71
|
-
beforeAll(() => {
|
|
72
|
-
result = addToRange(day, range);
|
|
51
|
+
test("add a date to a complete range with same end date", () => {
|
|
52
|
+
const date = new Date(2022, 0, 2);
|
|
53
|
+
const from = new Date(2022, 0, 1);
|
|
54
|
+
const range = addToRange(date, { from: from, to: date });
|
|
55
|
+
expect(range).toEqual({ from: date, to: date });
|
|
73
56
|
});
|
|
74
|
-
|
|
75
|
-
|
|
57
|
+
|
|
58
|
+
test("add a date when inside the range", () => {
|
|
59
|
+
const date = new Date(2022, 0, 1);
|
|
60
|
+
const from = new Date(2021, 11, 31);
|
|
61
|
+
const to = new Date(2022, 0, 2);
|
|
62
|
+
const range = addToRange(date, { from, to });
|
|
63
|
+
expect(range).toEqual({ from, to: date });
|
|
76
64
|
});
|
|
77
|
-
});
|
|
78
65
|
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
beforeAll(() => {
|
|
86
|
-
result = addToRange(day, range);
|
|
66
|
+
test("add an earlier date to a complete range", () => {
|
|
67
|
+
const from = new Date(2022, 0, 1);
|
|
68
|
+
const to = new Date(2022, 0, 2);
|
|
69
|
+
const date = new Date(2021, 11, 31);
|
|
70
|
+
const range = addToRange(date, { from, to });
|
|
71
|
+
expect(range).toEqual({ from: date, to: to });
|
|
87
72
|
});
|
|
88
|
-
|
|
89
|
-
|
|
73
|
+
|
|
74
|
+
test("add a later date to a complete range", () => {
|
|
75
|
+
const date = new Date(2022, 0, 2);
|
|
76
|
+
const from = new Date(2021, 11, 31);
|
|
77
|
+
const to = new Date(2022, 0, 1);
|
|
78
|
+
const range = addToRange(date, { from, to });
|
|
79
|
+
expect(range).toEqual({ from: from, to: date });
|
|
90
80
|
});
|
|
91
|
-
});
|
|
92
81
|
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
const range = { from, to };
|
|
98
|
-
let result: DateRange | undefined;
|
|
99
|
-
beforeAll(() => {
|
|
100
|
-
result = addToRange(day, range);
|
|
82
|
+
test("add a date with min > 0", () => {
|
|
83
|
+
const date = new Date(2022, 0, 1);
|
|
84
|
+
const range = addToRange(date, undefined, 1, 0, false);
|
|
85
|
+
expect(range).toEqual({ from: date, to: undefined });
|
|
101
86
|
});
|
|
102
|
-
|
|
103
|
-
|
|
87
|
+
|
|
88
|
+
test("add a date with max > 0", () => {
|
|
89
|
+
const date = new Date(2022, 0, 1);
|
|
90
|
+
const range = addToRange(date, undefined, 0, 1, false);
|
|
91
|
+
expect(range).toEqual({ from: date, to: date });
|
|
92
|
+
});
|
|
93
|
+
|
|
94
|
+
test("add a date with required set to true", () => {
|
|
95
|
+
const date = new Date(2022, 0, 1);
|
|
96
|
+
const range = addToRange(date, undefined, 0, 0, true);
|
|
97
|
+
expect(range).toEqual({ from: date, to: date });
|
|
98
|
+
});
|
|
99
|
+
|
|
100
|
+
test("when exceeding max, set the start of the range", () => {
|
|
101
|
+
const from = new Date(2022, 0, 1);
|
|
102
|
+
const to = new Date(2022, 0, 2);
|
|
103
|
+
const date = new Date(2022, 0, 4);
|
|
104
|
+
const max = 2;
|
|
105
|
+
const range = addToRange(date, { from, to }, 0, max, false);
|
|
106
|
+
expect(range).toEqual({ from: date, to: undefined });
|
|
104
107
|
});
|
|
105
|
-
});
|
|
106
108
|
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
result = addToRange(day, range);
|
|
115
|
-
});
|
|
116
|
-
test('should set the day as "to"', () => {
|
|
117
|
-
expect(result).toEqual({ from: range.from, to: day });
|
|
109
|
+
test("when below min, set the start of the range", () => {
|
|
110
|
+
const from = new Date(2021, 11, 20);
|
|
111
|
+
const to = new Date(2022, 0, 2);
|
|
112
|
+
const date = new Date(2021, 11, 21);
|
|
113
|
+
const min = 5;
|
|
114
|
+
const range = addToRange(date, { from, to }, min, 0, false);
|
|
115
|
+
expect(range).toEqual({ from: date, to: undefined });
|
|
118
116
|
});
|
|
119
117
|
});
|
package/src/utils/addToRange.ts
CHANGED
|
@@ -10,42 +10,78 @@ import type { DateRange, DateLib } from "../types/index.js";
|
|
|
10
10
|
* @group Utilities
|
|
11
11
|
*/
|
|
12
12
|
export function addToRange(
|
|
13
|
+
/** The date to add to the range. */
|
|
13
14
|
date: Date,
|
|
14
|
-
range
|
|
15
|
+
/** The range where to add `date`. */
|
|
16
|
+
initialRange: DateRange | undefined,
|
|
17
|
+
min = 0,
|
|
18
|
+
max = 0,
|
|
19
|
+
required = false,
|
|
15
20
|
/** @ignore */
|
|
16
21
|
dateLib: DateLib = defaultDateLib
|
|
17
|
-
): DateRange {
|
|
18
|
-
const { from, to } =
|
|
22
|
+
): DateRange | undefined {
|
|
23
|
+
const { from, to } = initialRange || {};
|
|
19
24
|
const { isSameDay, isAfter, isBefore } = dateLib;
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
25
|
+
|
|
26
|
+
let range: DateRange | undefined;
|
|
27
|
+
|
|
28
|
+
if (!from && !to) {
|
|
29
|
+
// the range is empty, add the date
|
|
30
|
+
range = { from: date, to: min > 0 ? undefined : date };
|
|
31
|
+
} else if (from && !to) {
|
|
32
|
+
// adding date to an incomplete range
|
|
27
33
|
if (isSameDay(from, date)) {
|
|
28
|
-
|
|
34
|
+
// adding a date equal to the start of the range
|
|
35
|
+
if (required) {
|
|
36
|
+
range = { from, to: undefined };
|
|
37
|
+
} else {
|
|
38
|
+
range = undefined;
|
|
39
|
+
}
|
|
40
|
+
} else if (isBefore(date, from)) {
|
|
41
|
+
// adding a date before the start of the range
|
|
42
|
+
range = { from: date, to: from };
|
|
43
|
+
} else {
|
|
44
|
+
// adding a date after the start of the range
|
|
45
|
+
range = { from, to: date };
|
|
29
46
|
}
|
|
30
|
-
|
|
31
|
-
|
|
47
|
+
} else if (from && to) {
|
|
48
|
+
// adding date to a complete range
|
|
49
|
+
if (isSameDay(from, date) && isSameDay(to, date)) {
|
|
50
|
+
// adding a date that is equal to both start and end of the range
|
|
51
|
+
if (required) {
|
|
52
|
+
range = { from, to };
|
|
53
|
+
} else {
|
|
54
|
+
range = undefined;
|
|
55
|
+
}
|
|
56
|
+
} else if (isSameDay(from, date)) {
|
|
57
|
+
// adding a date equal to the the start of the range
|
|
58
|
+
range = { from, to: min > 0 ? undefined : date };
|
|
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
|
+
} else if (isBefore(date, from)) {
|
|
63
|
+
// adding a date before the start of the range
|
|
64
|
+
range = { from: date, to: to };
|
|
65
|
+
} else if (isAfter(date, from)) {
|
|
66
|
+
// adding a date after the start of the range
|
|
67
|
+
range = { from, to: date };
|
|
68
|
+
} else if (isAfter(date, to)) {
|
|
69
|
+
// adding a date after the end of the range
|
|
70
|
+
range = { from, to: date };
|
|
71
|
+
} else {
|
|
72
|
+
throw new Error("Invalid range");
|
|
32
73
|
}
|
|
33
|
-
return { from, to: date };
|
|
34
74
|
}
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
return { from: date, to: from };
|
|
44
|
-
}
|
|
45
|
-
if (isSameDay(date, from)) {
|
|
46
|
-
return { from: undefined, to: undefined };
|
|
75
|
+
|
|
76
|
+
// check for min / max
|
|
77
|
+
if (range?.from && range?.to) {
|
|
78
|
+
const diff = dateLib.differenceInCalendarDays(range.to, range.from);
|
|
79
|
+
if (max > 0 && diff > max) {
|
|
80
|
+
range = { from: date, to: undefined };
|
|
81
|
+
} else if (min > 1 && diff < min) {
|
|
82
|
+
range = { from: date, to: undefined };
|
|
47
83
|
}
|
|
48
|
-
return { from, to: date };
|
|
49
84
|
}
|
|
50
|
-
|
|
85
|
+
|
|
86
|
+
return range;
|
|
51
87
|
}
|
|
@@ -76,7 +76,7 @@ DayPicker supports keyboard navigation to make it easier for users to navigate t
|
|
|
76
76
|
| Keys | Function |
|
|
77
77
|
| ---------------------------- | ------------------------------------ |
|
|
78
78
|
| <kbd>Arrow Top</kbd> | Move focus to the previous week. |
|
|
79
|
-
| <kbd>Arrow Right</kbd> | Move focus to the next
|
|
79
|
+
| <kbd>Arrow Right</kbd> | Move focus to the next day. |
|
|
80
80
|
| <kbd>Arrow Bottom</kbd> | Move focus to the next week. |
|
|
81
81
|
| <kbd>Arrow Left</kbd> | Move focus to the previous day. |
|
|
82
82
|
| <kbd>Page Up</kbd> | Move focus to the previous month. |
|
|
@@ -40,23 +40,13 @@ When the `mode` prop is set to `"single"`, only one day can be selected.
|
|
|
40
40
|
| `onSelect` | `(selected, triggerDate, modifiers, e) => void` | Event callback when a date is selected. |
|
|
41
41
|
| `required` | `boolean` | Make the selection required. |
|
|
42
42
|
|
|
43
|
-
|
|
43
|
+
Use the `selected` and `onSelect` props to control the selected date:
|
|
44
44
|
|
|
45
45
|
```tsx
|
|
46
|
-
import { useState } from "react";
|
|
47
|
-
|
|
48
|
-
import { DayPicker } from "react-day-picker";
|
|
49
|
-
|
|
50
46
|
export function App() {
|
|
51
|
-
const
|
|
52
|
-
|
|
53
|
-
return
|
|
54
|
-
<DayPicker
|
|
55
|
-
mode="single"
|
|
56
|
-
selected={selectedDate}
|
|
57
|
-
onSelect={setSelectedDate}
|
|
58
|
-
/>
|
|
59
|
-
);
|
|
47
|
+
const [selected, setSelected] = React.useState<Date | undefined>();
|
|
48
|
+
|
|
49
|
+
return <DayPicker mode="single" selected={selected} onSelect={setSelected} />;
|
|
60
50
|
}
|
|
61
51
|
```
|
|
62
52
|
|
|
@@ -93,103 +83,89 @@ By setting the `mode` prop to `"multiple"`, DayPicker allows selecting multiple
|
|
|
93
83
|
| `min` | `number` | The minimum dates that can be selected. |
|
|
94
84
|
| `max` | `number` | The maximum dates that can be selected. |
|
|
95
85
|
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
Use the `min` and `max` props to limit the number of selectable dates.
|
|
86
|
+
Use the `selected` and `onSelect` props to control the selected date:
|
|
99
87
|
|
|
100
88
|
```tsx
|
|
101
|
-
|
|
102
|
-
|
|
89
|
+
export function App() {
|
|
90
|
+
const [selected, setSelected] = React.useState<Date[] | undefined>();
|
|
103
91
|
|
|
104
|
-
export function MultipleMinMax() {
|
|
105
|
-
const defaultSelected = [new Date(), addDays(new Date(), 1)];
|
|
106
92
|
return (
|
|
107
|
-
<DayPicker
|
|
108
|
-
defaultSelected={defaultSelected}
|
|
109
|
-
mode="multiple"
|
|
110
|
-
min={2}
|
|
111
|
-
max={5}
|
|
112
|
-
/>
|
|
93
|
+
<DayPicker mode="multiple" selected={selected} onSelect={setSelected} />
|
|
113
94
|
);
|
|
114
95
|
}
|
|
115
96
|
```
|
|
116
97
|
|
|
98
|
+
### Min and Max Dates
|
|
99
|
+
|
|
100
|
+
Use the `min` and `max` props to limit the number of selectable dates.
|
|
101
|
+
|
|
102
|
+
```tsx
|
|
103
|
+
<DayPicker mode="multiple" min={2} max={5} />
|
|
104
|
+
```
|
|
105
|
+
|
|
117
106
|
<BrowserWindow>
|
|
118
107
|
<Examples.MultipleMinMax />
|
|
119
108
|
</BrowserWindow>
|
|
120
109
|
|
|
121
|
-
|
|
110
|
+
### Required Selection
|
|
122
111
|
|
|
123
|
-
|
|
112
|
+
By setting the `required` prop, DayPicker requires at least one date to be selected.
|
|
124
113
|
|
|
125
114
|
```tsx
|
|
126
|
-
<DayPicker mode="
|
|
115
|
+
<DayPicker mode="multiple" required selected={[new Date()]} />
|
|
127
116
|
```
|
|
128
117
|
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
| `onSelect` | `(selected, triggerDate, modifiers, e) => void` | Event callback when a date is selected. |
|
|
133
|
-
| `min` | `number` | The minimum dates that can be selected. |
|
|
134
|
-
| `max` | `number` | The maximum dates that can be selected. |
|
|
135
|
-
|
|
136
|
-
```tsx
|
|
137
|
-
import { addDays, format } from "date-fns";
|
|
138
|
-
import { DateRange, DayPicker } from "react-day-picker";
|
|
118
|
+
<BrowserWindow>
|
|
119
|
+
<Examples.MultipleRequired />
|
|
120
|
+
</BrowserWindow>
|
|
139
121
|
|
|
140
|
-
|
|
141
|
-
const defaultMonth = new Date(2020, 5, 15);
|
|
122
|
+
## Range Mode
|
|
142
123
|
|
|
143
|
-
|
|
144
|
-
from: defaultMonth,
|
|
145
|
-
to: addDays(defaultMonth, 4)
|
|
146
|
-
};
|
|
147
|
-
const [range, setRange] = React.useState<DateRange | undefined>(
|
|
148
|
-
defaultSelected
|
|
149
|
-
);
|
|
124
|
+
When the `mode` prop is set to `"range"`, DayPicker allows selecting a continuous range of dates.
|
|
150
125
|
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
mode="range"
|
|
154
|
-
defaultMonth={defaultMonth}
|
|
155
|
-
selected={range}
|
|
156
|
-
onSelect={setRange}
|
|
157
|
-
/>
|
|
158
|
-
);
|
|
159
|
-
}
|
|
126
|
+
```tsx
|
|
127
|
+
<DayPicker mode="range" />
|
|
160
128
|
```
|
|
161
129
|
|
|
162
130
|
<BrowserWindow>
|
|
163
131
|
<Examples.Range />
|
|
164
132
|
</BrowserWindow>
|
|
165
133
|
|
|
134
|
+
### Range Mode Props
|
|
135
|
+
|
|
136
|
+
| Prop Name | Type | Description |
|
|
137
|
+
| ----------------- | ----------------------------------------------- | --------------------------------------- |
|
|
138
|
+
| `selected` | [`DateRange`](../api/type-aliases/DateRange.md) | The selected range. |
|
|
139
|
+
| `onSelect` | `(selected, triggerDate, modifiers, e) => void` | Event callback when a date is selected. |
|
|
140
|
+
| `required` | `boolean` | Make the selection required. |
|
|
141
|
+
| `min` | `number` | The minimum dates that can be selected. |
|
|
142
|
+
| `max` | `number` | The maximum dates that can be selected. |
|
|
143
|
+
| `excludeDisabled` | `boolean` | Exclude disabled dates from the range. |
|
|
144
|
+
|
|
166
145
|
### Min and Max Dates
|
|
167
146
|
|
|
168
|
-
|
|
147
|
+
As default, a range can have length of 0 nights, thus the start date can be the same as the end date. Use the `min` prop to set the minimum number of nights. The range will stay "open" until at least `min` nights are selected.
|
|
148
|
+
|
|
149
|
+
Similarly, you can se the `max` prop to set the maximum number of nights.
|
|
169
150
|
|
|
170
151
|
```tsx
|
|
171
|
-
|
|
152
|
+
<DayPicker mode="range" min={1} max={6} />
|
|
153
|
+
```
|
|
172
154
|
|
|
173
|
-
|
|
155
|
+
<BrowserWindow bodyStyle={{ justifyContent: "start" }}>
|
|
156
|
+
<Examples.RangeMinMax />
|
|
157
|
+
</BrowserWindow>
|
|
174
158
|
|
|
175
|
-
|
|
176
|
-
const [range, setRange] = useState<DateRange | undefined>();
|
|
159
|
+
### Required Ranges
|
|
177
160
|
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
min={3}
|
|
183
|
-
max={9}
|
|
184
|
-
selected={range}
|
|
185
|
-
onSelect={setRange}
|
|
186
|
-
/>
|
|
187
|
-
);
|
|
188
|
-
}
|
|
161
|
+
By setting the `required` prop, a range must be selected.
|
|
162
|
+
|
|
163
|
+
```tsx
|
|
164
|
+
<DayPicker mode="range" required />
|
|
189
165
|
```
|
|
190
166
|
|
|
191
167
|
<BrowserWindow>
|
|
192
|
-
<Examples.
|
|
168
|
+
<Examples.RangeRequired />
|
|
193
169
|
</BrowserWindow>
|
|
194
170
|
|
|
195
171
|
## Disabling Dates
|
|
@@ -4,21 +4,31 @@ sidebar_position: 4
|
|
|
4
4
|
|
|
5
5
|
# Custom Components
|
|
6
6
|
|
|
7
|
-
|
|
7
|
+
With the `components` prop, you can extend each of the rendered HTML elements by using your own components.
|
|
8
8
|
|
|
9
9
|
| Prop Name | Type | Description |
|
|
10
10
|
| ------------ | ------------------------------------------------------------- | -------------------------------------- |
|
|
11
11
|
| `components` | [`CustomComponents`](../api/type-aliases/CustomComponents.md) | Change the components of the calendar. |
|
|
12
12
|
|
|
13
|
-
|
|
13
|
+
You may need to use custom components in advanced applications, for example to:
|
|
14
14
|
|
|
15
|
-
|
|
15
|
+
- Prevent default events from occurring
|
|
16
|
+
- Add new event listeners, such as touch events
|
|
17
|
+
- Display extra content, such as a calendar entry in the day cell
|
|
18
|
+
- Implement buttons or dropdowns using your own design system components
|
|
19
|
+
- Wrap an element with another element, like adding a tooltip to a day cell.
|
|
16
20
|
|
|
17
|
-
|
|
21
|
+
When customizing the components, get familiar with the [API Reference](../api#components) and the [DayPicker Anatomy](../docs/anatomy.mdx). Make sure you don't break the [accessibility](../docs/accessibility.mdx).
|
|
18
22
|
|
|
19
|
-
|
|
23
|
+
:::note Custom Components vs Formatters
|
|
20
24
|
|
|
21
|
-
|
|
25
|
+
Custom components extends DayPicker more than the [formatters](../docs/translation.mdx#custom-formatters), which are used to format the content of the calendar.
|
|
26
|
+
|
|
27
|
+
:::
|
|
28
|
+
|
|
29
|
+
## Implementing a Custom Component
|
|
30
|
+
|
|
31
|
+
Pass the components you want to customize to the `components` prop. This prop accepts any of the [`CustomComponents`](../api/type-aliases/CustomComponents.md).
|
|
22
32
|
|
|
23
33
|
```tsx
|
|
24
34
|
<DayPicker
|
|
@@ -30,13 +40,6 @@ To use custom components, pass the `components` prop. The prop is an object with
|
|
|
30
40
|
/>
|
|
31
41
|
```
|
|
32
42
|
|
|
33
|
-
Each component is the last step before actually rendering its element.
|
|
34
|
-
|
|
35
|
-
- prevent default events to happen - e.g. prevent the click event on a day button to select a day
|
|
36
|
-
- add new event listeners - e.g. add a touch event to select a day
|
|
37
|
-
- display new content - e.g. add a new element to the day cell, such a calendar event.
|
|
38
|
-
- wrap the element with a new component - e.g. wrap the day cell with a tooltip component
|
|
39
|
-
|
|
40
43
|
<details>
|
|
41
44
|
<summary>List of Customizable Components</summary>
|
|
42
45
|
|
|
@@ -124,78 +127,3 @@ The DayPicker context provides the current state of the calendar, such as the se
|
|
|
124
127
|
| Function | Return value | Description |
|
|
125
128
|
| :------------------------------------------------- | ------------------------------------------------------------- | :--------------------------------------------------------------------------- |
|
|
126
129
|
| [`useDayPicker`](../api/functions/useDayPicker.md) | [`DayPickerContext`](../api/type-aliases/DayPickerContext.md) | Return the current state of DayPicker and functions to navigate the calendar |
|
|
127
|
-
|
|
128
|
-
### Examples
|
|
129
|
-
|
|
130
|
-
#### Range Selection with the <kbd>Shift</kbd> Key
|
|
131
|
-
|
|
132
|
-
Implement a custom `Day` component to select ranges while pressing the <kbd>Shift</kbd> key.
|
|
133
|
-
|
|
134
|
-
```tsx
|
|
135
|
-
import React, { MouseEventHandler } from "react";
|
|
136
|
-
|
|
137
|
-
import { isSameDay } from "date-fns";
|
|
138
|
-
import {
|
|
139
|
-
DateRange,
|
|
140
|
-
DayButtonProps,
|
|
141
|
-
DayPicker,
|
|
142
|
-
useDayPicker
|
|
143
|
-
} from "react-day-picker";
|
|
144
|
-
|
|
145
|
-
function CustomDayButton(props: DayButtonProps) {
|
|
146
|
-
// Use the DayPicker hook to get the selected days
|
|
147
|
-
const { selected } = useDayPicker({ mode: "range" });
|
|
148
|
-
|
|
149
|
-
const handleClick: MouseEventHandler<HTMLButtonElement> = (e) => {
|
|
150
|
-
const requireShiftKey =
|
|
151
|
-
selected.from && // The start of the range is selected
|
|
152
|
-
!selected.to && // The second day is not selected
|
|
153
|
-
!isSameDay(props.day.date, selected.from); // User is not clicking the start ot the range again
|
|
154
|
-
|
|
155
|
-
if (!e.shiftKey && requireShiftKey) return;
|
|
156
|
-
|
|
157
|
-
// Call the original onClick event
|
|
158
|
-
props.onClick?.(e);
|
|
159
|
-
};
|
|
160
|
-
|
|
161
|
-
// Pick the button props
|
|
162
|
-
const { day, modifiers, ...buttonProps } = props;
|
|
163
|
-
|
|
164
|
-
return (
|
|
165
|
-
<button {...buttonProps} onClick={handleClick}>
|
|
166
|
-
{props.children}
|
|
167
|
-
</button>
|
|
168
|
-
);
|
|
169
|
-
}
|
|
170
|
-
|
|
171
|
-
export function RangeWithShiftKey() {
|
|
172
|
-
const [range, setRange] = React.useState<DateRange | undefined>({
|
|
173
|
-
from: undefined
|
|
174
|
-
});
|
|
175
|
-
|
|
176
|
-
let footer = "Please pick a day.";
|
|
177
|
-
|
|
178
|
-
if (range?.from && !range?.to) {
|
|
179
|
-
footer = "Press Shift to choose more days.";
|
|
180
|
-
} else if (range?.to) {
|
|
181
|
-
const formattedFrom = range.from?.toDateString();
|
|
182
|
-
const formattedTo = range.to.toDateString();
|
|
183
|
-
footer = `You selected the days between ${formattedFrom} and ${formattedTo}`;
|
|
184
|
-
}
|
|
185
|
-
return (
|
|
186
|
-
<DayPicker
|
|
187
|
-
components={{
|
|
188
|
-
DayButton: CustomDayButton
|
|
189
|
-
}}
|
|
190
|
-
mode="range"
|
|
191
|
-
selected={range}
|
|
192
|
-
onSelect={setRange}
|
|
193
|
-
footer={footer}
|
|
194
|
-
/>
|
|
195
|
-
);
|
|
196
|
-
}
|
|
197
|
-
```
|
|
198
|
-
|
|
199
|
-
<BrowserWindow>
|
|
200
|
-
<Examples.RangeShiftKey />
|
|
201
|
-
</BrowserWindow>
|
package/website/docs/intro.mdx
CHANGED
|
@@ -16,7 +16,7 @@ DayPicker is a [React](https://react.dev) component to create date pickers, cale
|
|
|
16
16
|
- 📅 Supports [selections](./docs/selection-modes.mdx) of single day, multiple days, ranges of days, or [custom selections](./guides/custom-selections.mdx).
|
|
17
17
|
- 🌍 Can be [localized](./docs/localization.mdx) into any language, supports [ISO 8601 dates](./docs/localization.mdx#iso-week-dates), [UTC dates](./docs/localization.mdx#utc-dates), and [Jalali calendar](./docs/localization.mdx#jalali-calendar).
|
|
18
18
|
- 🦮 Complies with WCAG 2.1 AA requirements for [accessibility](./docs/accessibility.mdx).
|
|
19
|
-
- ⚙️ [Customizable components](./guides/custom-components.mdx)
|
|
19
|
+
- ⚙️ [Customizable components](./guides/custom-components.mdx) to extend the rendered elements.
|
|
20
20
|
- 🔤 Easy integration [with input fields](./guides/input-fields.mdx).
|
|
21
21
|
|
|
22
22
|
DayPicker is written in TypeScript and compiled to CommonJS and ESM. It relies on [date-fns](https://date-fns.org) for date manipulation and formatting.
|