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.
Files changed (38) hide show
  1. package/README.md +1 -1
  2. package/dist/cjs/DayPicker.js +2 -6
  3. package/dist/cjs/DayPicker.js.map +1 -1
  4. package/dist/cjs/package.json +1 -0
  5. package/dist/cjs/selection/useRange.js +3 -19
  6. package/dist/cjs/selection/useRange.js.map +1 -1
  7. package/dist/cjs/utils/addToRange.d.ts +6 -2
  8. package/dist/cjs/utils/addToRange.js +68 -24
  9. package/dist/cjs/utils/addToRange.js.map +1 -1
  10. package/dist/esm/DayPicker.js +2 -6
  11. package/dist/esm/DayPicker.js.map +1 -1
  12. package/dist/esm/selection/useRange.js +3 -19
  13. package/dist/esm/selection/useRange.js.map +1 -1
  14. package/dist/esm/utils/addToRange.d.ts +6 -2
  15. package/dist/esm/utils/addToRange.js +68 -24
  16. package/dist/esm/utils/addToRange.js.map +1 -1
  17. package/examples/MultipleRequired.tsx +7 -0
  18. package/examples/RangeMinMax.test.tsx +5 -16
  19. package/examples/RangeMinMax.tsx +5 -6
  20. package/examples/RangeRequired.tsx +30 -0
  21. package/examples/RangeShiftKey.tsx +1 -3
  22. package/examples/__snapshots__/Range.test.tsx.snap +26 -0
  23. package/examples/__snapshots__/StylingCssModules.test.tsx.snap +11 -0
  24. package/examples/index.ts +2 -0
  25. package/package.json +7 -7
  26. package/src/DayPicker.tsx +12 -7
  27. package/src/selection/useRange.test.tsx +2 -2
  28. package/src/selection/useRange.tsx +3 -25
  29. package/src/style.css +11 -5
  30. package/src/style.module.css +12 -6
  31. package/src/utils/addToRange.test.ts +95 -97
  32. package/src/utils/addToRange.ts +64 -28
  33. package/website/docs/docs/accessibility.mdx +1 -1
  34. package/website/docs/docs/selection-modes.mdx +51 -75
  35. package/website/docs/guides/custom-components.mdx +16 -88
  36. package/website/docs/intro.mdx +1 -1
  37. package/website/docs/upgrading.mdx +4 -9
  38. package/website/README.md +0 -25
@@ -1,119 +1,117 @@
1
- import { addDays, subDays } from "date-fns";
1
+ import { addToRange } from "./addToRange";
2
2
 
3
- import type { DateRange } from "../types";
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
- import { addToRange } from "./addToRange";
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
- describe('when no "from" is the range', () => {
8
- const range = { from: undefined };
9
- const day = new Date();
10
- let result: DateRange | undefined;
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
- test('should set "from" as the given day', () => {
15
- expect(result).toEqual({ from: day, to: undefined });
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
- describe('when no "to" is the range', () => {
20
- const day = new Date();
21
- const range = { from: day, to: undefined };
22
- describe('and the day is the same as the "from" day', () => {
23
- let result: DateRange | undefined;
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
- describe('when "from", "to" and "day" are the same', () => {
54
- const day = new Date();
55
- const range = { from: day, to: day };
56
- let result: DateRange | undefined;
57
- beforeAll(() => {
58
- result = addToRange(day, range);
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
- test("should return an undefined range (reset)", () => {
61
- expect(result).toEqual({ from: undefined, to: undefined });
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
- describe('when "to" and "day" are the same', () => {
66
- const from = new Date();
67
- const to = addDays(from, 4);
68
- const day = to;
69
- const range = { from, to };
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
- test('should set "to" to undefined', () => {
75
- expect(result).toEqual({ from: to, to: undefined });
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
- describe('when "from" and "day" are the same', () => {
80
- const from = new Date();
81
- const to = addDays(from, 4);
82
- const day = from;
83
- const range = { from, to };
84
- let result: DateRange | undefined;
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
- test("should reset the range", () => {
89
- expect(result).toEqual({ from: undefined, to: undefined });
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
- describe('when "from" is after "day"', () => {
94
- const day = new Date();
95
- const from = addDays(day, 1);
96
- const to = addDays(from, 4);
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
- test('should set the day as "from"', () => {
103
- expect(result).toEqual({ from: day, to: range.to });
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
- describe('when "from" is before "day"', () => {
108
- const day = new Date();
109
- const from = subDays(day, 1);
110
- const to = addDays(from, 4);
111
- const range = { from, to };
112
- let result: DateRange | undefined;
113
- beforeAll(() => {
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
  });
@@ -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: DateRange | undefined,
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 } = range || {};
22
+ ): DateRange | undefined {
23
+ const { from, to } = initialRange || {};
19
24
  const { isSameDay, isAfter, isBefore } = dateLib;
20
- if (from && to) {
21
- if (isSameDay(to, date) && isSameDay(from, date)) {
22
- return { from: undefined, to: undefined };
23
- }
24
- if (isSameDay(to, date)) {
25
- return { from: to, to: undefined };
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
- return { from: undefined, to: undefined };
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
- if (isAfter(from, date)) {
31
- return { from: date, to };
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
- if (to) {
36
- if (isAfter(date, to)) {
37
- return { from: to, to: date };
38
- }
39
- return { from: date, to };
40
- }
41
- if (from) {
42
- if (isBefore(date, from)) {
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
- return { from: date, to: undefined };
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 da.y |
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
- The following code snippet will render a date picker with a single selected date. When a day is clicked, the `selectedDate` state is updated.
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 initiallySelectedDate = new Date();
52
- const [selectedDate, setSelectedDate] = useState(initiallySelectedDate);
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
- ### Min and Max Dates
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
- import { addDays } from "date-fns";
102
- import { DayPicker } from "react-day-picker";
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
- ## Range Mode
110
+ ### Required Selection
122
111
 
123
- When the `mode` prop is set to `"range"`, DayPicker allows selecting a continuous range of dates.
112
+ By setting the `required` prop, DayPicker requires at least one date to be selected.
124
113
 
125
114
  ```tsx
126
- <DayPicker mode="range" />
115
+ <DayPicker mode="multiple" required selected={[new Date()]} />
127
116
  ```
128
117
 
129
- | Prop Name | Type | Description |
130
- | ---------- | ----------------------------------------------- | --------------------------------------- |
131
- | `selected` | [`DateRange`](../api/type-aliases/DateRange.md) | The selected range. |
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
- export function RangeExample() {
141
- const defaultMonth = new Date(2020, 5, 15);
122
+ ## Range Mode
142
123
 
143
- const defaultSelected: DateRange = {
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
- return (
152
- <DayPicker
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
- Also in range mode, you can set the `min` and `max` props to limit the number of selectable dates.
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
- import { useState } from "react";
152
+ <DayPicker mode="range" min={1} max={6} />
153
+ ```
172
154
 
173
- import { DateRange, DayPicker } from "react-day-picker";
155
+ <BrowserWindow bodyStyle={{ justifyContent: "start" }}>
156
+ <Examples.RangeMinMax />
157
+ </BrowserWindow>
174
158
 
175
- export function RangeMinMax() {
176
- const [range, setRange] = useState<DateRange | undefined>();
159
+ ### Required Ranges
177
160
 
178
- return (
179
- <DayPicker
180
- defaultMonth={new Date(2022, 8)}
181
- mode="range"
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.RangeMinMax />
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
- Custom components allows to customize or replace the components rendering the DayPicker HTML elements.
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
- ## When to use Custom Components
13
+ You may need to use custom components in advanced applications, for example to:
14
14
 
15
- Custom components allow to enhance DayPicker to align it with your design system, to modify navigation behavior, or to present unique content within day cells.
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
- Get familiar with the [API Reference](../api#components) and the [DayPicker Anatomy](../docs/anatomy.mdx) and make sure you don't break [accessibility](../docs/accessibility.mdx) when customizing components.
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
- ## How to Use Custom Components
23
+ :::note Custom Components vs Formatters
20
24
 
21
- To use custom components, pass the `components` prop. The prop is an object with the components you want to customize:
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>
@@ -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) for complete customization.
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.