react-day-picker 8.0.3 → 8.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 (207) hide show
  1. package/README.md +1 -1
  2. package/dist/hooks/useDayRender/useDayRender.d.ts +1 -1
  3. package/dist/hooks/useInput/useInput.d.ts +2 -2
  4. package/dist/index.esm.js +3 -3
  5. package/dist/index.esm.js.map +1 -1
  6. package/dist/index.js +3 -3
  7. package/dist/index.js.map +1 -1
  8. package/dist/react-day-picker.min.js +1 -0
  9. package/dist/style.css +11 -10
  10. package/dist/style.module.css +11 -10
  11. package/dist/types/Styles.d.ts +8 -2
  12. package/package.json +15 -13
  13. package/src/DayPicker.tsx +113 -0
  14. package/src/components/Button/Button.test.tsx +47 -0
  15. package/src/components/Button/Button.tsx +36 -0
  16. package/src/components/Button/index.ts +1 -0
  17. package/src/components/Caption/Caption.test.tsx +86 -0
  18. package/src/components/Caption/Caption.tsx +54 -0
  19. package/src/components/Caption/index.ts +1 -0
  20. package/src/components/CaptionDropdowns/CaptionDropdowns.test.tsx +123 -0
  21. package/src/components/CaptionDropdowns/CaptionDropdowns.tsx +43 -0
  22. package/src/components/CaptionDropdowns/index.ts +1 -0
  23. package/src/components/CaptionLabel/CaptionLabel.test.tsx +29 -0
  24. package/src/components/CaptionLabel/CaptionLabel.tsx +32 -0
  25. package/src/components/CaptionLabel/index.ts +1 -0
  26. package/src/components/CaptionNavigation/CaptionNavigation.test.tsx +172 -0
  27. package/src/components/CaptionNavigation/CaptionNavigation.tsx +63 -0
  28. package/src/components/CaptionNavigation/index.ts +1 -0
  29. package/src/components/Day/Day.test.tsx +84 -0
  30. package/src/components/Day/Day.tsx +30 -0
  31. package/src/components/Day/index.ts +1 -0
  32. package/src/components/DayContent/DayContent.test.tsx +51 -0
  33. package/src/components/DayContent/DayContent.tsx +36 -0
  34. package/src/components/DayContent/index.ts +1 -0
  35. package/src/components/Dropdown/Dropdown.test.tsx +73 -0
  36. package/src/components/Dropdown/Dropdown.tsx +56 -0
  37. package/src/components/Dropdown/index.ts +1 -0
  38. package/src/components/Footer/Footer.test.tsx +29 -0
  39. package/src/components/Footer/Footer.tsx +20 -0
  40. package/src/components/Footer/index.ts +1 -0
  41. package/src/components/Head/Head.test.tsx +117 -0
  42. package/src/components/Head/Head.tsx +51 -0
  43. package/src/components/Head/index.ts +1 -0
  44. package/src/components/Head/utils/getWeekdays.test.ts +36 -0
  45. package/src/components/Head/utils/getWeekdays.ts +22 -0
  46. package/src/components/Head/utils/index.ts +1 -0
  47. package/src/components/IconDropdown/IconDropdown.test.tsx +20 -0
  48. package/src/components/IconDropdown/IconDropdown.tsx +24 -0
  49. package/src/components/IconDropdown/index.ts +1 -0
  50. package/src/components/IconLeft/IconLeft.test.tsx +20 -0
  51. package/src/components/IconLeft/IconLeft.tsx +18 -0
  52. package/src/components/IconLeft/index.ts +1 -0
  53. package/src/components/IconRight/IconRight.test.tsx +20 -0
  54. package/src/components/IconRight/IconRight.tsx +17 -0
  55. package/src/components/IconRight/index.ts +1 -0
  56. package/src/components/Month/Month.test.tsx +216 -0
  57. package/src/components/Month/Month.tsx +53 -0
  58. package/src/components/Month/index.ts +1 -0
  59. package/src/components/MonthsDropdown/MonthsDropdown.test.tsx +99 -0
  60. package/src/components/MonthsDropdown/MonthsDropdown.tsx +75 -0
  61. package/src/components/MonthsDropdown/index.ts +1 -0
  62. package/src/components/Navigation/Navigation.test.tsx +129 -0
  63. package/src/components/Navigation/Navigation.tsx +102 -0
  64. package/src/components/Navigation/index.ts +1 -0
  65. package/src/components/Root/Root.test.tsx +123 -0
  66. package/src/components/Root/Root.tsx +58 -0
  67. package/src/components/Root/index.ts +1 -0
  68. package/src/components/Row/Row.test.tsx +69 -0
  69. package/src/components/Row/Row.tsx +51 -0
  70. package/src/components/Row/index.ts +1 -0
  71. package/src/components/Table/Table.test.tsx +42 -0
  72. package/src/components/Table/Table.tsx +60 -0
  73. package/src/components/Table/__snapshots__/Table.test.tsx.snap +1453 -0
  74. package/src/components/Table/index.ts +1 -0
  75. package/src/components/Table/utils/daysToMonthWeeks.ts +47 -0
  76. package/src/components/Table/utils/getMonthWeeks.test.ts +68 -0
  77. package/src/components/Table/utils/getMonthWeeks.ts +55 -0
  78. package/src/components/WeekNumber/WeekNumber.test.tsx +46 -0
  79. package/src/components/WeekNumber/WeekNumber.tsx +58 -0
  80. package/src/components/WeekNumber/__snapshots__/WeekNumber.test.tsx.snap +11 -0
  81. package/src/components/WeekNumber/index.ts +1 -0
  82. package/src/components/YearsDropdown/YearsDropdown.test.tsx +98 -0
  83. package/src/components/YearsDropdown/YearsDropdown.tsx +76 -0
  84. package/src/components/YearsDropdown/index.ts +1 -0
  85. package/src/contexts/DayPicker/DayPickerContext.tsx +156 -0
  86. package/src/contexts/DayPicker/defaultClassNames.ts +58 -0
  87. package/src/contexts/DayPicker/defaultContextValue.ts +37 -0
  88. package/src/contexts/DayPicker/formatters/formatCaption.test.ts +15 -0
  89. package/src/contexts/DayPicker/formatters/formatCaption.ts +12 -0
  90. package/src/contexts/DayPicker/formatters/formatDay.test.ts +7 -0
  91. package/src/contexts/DayPicker/formatters/formatDay.ts +9 -0
  92. package/src/contexts/DayPicker/formatters/formatMonthCaption.test.ts +15 -0
  93. package/src/contexts/DayPicker/formatters/formatMonthCaption.ts +12 -0
  94. package/src/contexts/DayPicker/formatters/formatWeekNumber.test.ts +5 -0
  95. package/src/contexts/DayPicker/formatters/formatWeekNumber.ts +6 -0
  96. package/src/contexts/DayPicker/formatters/formatWeekdayName.test.ts +15 -0
  97. package/src/contexts/DayPicker/formatters/formatWeekdayName.ts +12 -0
  98. package/src/contexts/DayPicker/formatters/formatYearCaption.test.ts +7 -0
  99. package/src/contexts/DayPicker/formatters/formatYearCaption.ts +11 -0
  100. package/src/contexts/DayPicker/formatters/index.ts +6 -0
  101. package/src/contexts/DayPicker/index.ts +2 -0
  102. package/src/contexts/DayPicker/labels/index.ts +7 -0
  103. package/src/contexts/DayPicker/labels/labelDay.test.ts +7 -0
  104. package/src/contexts/DayPicker/labels/labelDay.ts +10 -0
  105. package/src/contexts/DayPicker/labels/labelMonthDropdown.test.ts +5 -0
  106. package/src/contexts/DayPicker/labels/labelMonthDropdown.ts +6 -0
  107. package/src/contexts/DayPicker/labels/labelNext.test.ts +5 -0
  108. package/src/contexts/DayPicker/labels/labelNext.ts +8 -0
  109. package/src/contexts/DayPicker/labels/labelPrevious.test.ts +5 -0
  110. package/src/contexts/DayPicker/labels/labelPrevious.ts +8 -0
  111. package/src/contexts/DayPicker/labels/labelWeekNumber.test.ts +5 -0
  112. package/src/contexts/DayPicker/labels/labelWeekNumber.ts +8 -0
  113. package/src/contexts/DayPicker/labels/labelWeekday.test.ts +15 -0
  114. package/src/contexts/DayPicker/labels/labelWeekday.ts +10 -0
  115. package/src/contexts/DayPicker/labels/labelYearDropdown.test.ts +5 -0
  116. package/src/contexts/DayPicker/labels/labelYearDropdown.ts +6 -0
  117. package/src/contexts/DayPicker/useDayPicker.test.ts +297 -0
  118. package/src/contexts/DayPicker/useDayPicker.ts +17 -0
  119. package/src/contexts/DayPicker/utils/index.ts +1 -0
  120. package/src/contexts/DayPicker/utils/parseFromToProps.test.ts +47 -0
  121. package/src/contexts/DayPicker/utils/parseFromToProps.ts +32 -0
  122. package/src/contexts/Focus/FocusContext.tsx +174 -0
  123. package/src/contexts/Focus/index.ts +2 -0
  124. package/src/contexts/Focus/useFocusContext.test.ts +183 -0
  125. package/src/contexts/Focus/useFocusContext.ts +12 -0
  126. package/src/contexts/Focus/utils/getInitialFocusTarget.test.tsx +12 -0
  127. package/src/contexts/Focus/utils/getInitialFocusTarget.tsx +44 -0
  128. package/src/contexts/Modifiers/ModifiersContext.tsx +44 -0
  129. package/src/contexts/Modifiers/index.ts +2 -0
  130. package/src/contexts/Modifiers/useModifiers.test.ts +46 -0
  131. package/src/contexts/Modifiers/useModifiers.ts +17 -0
  132. package/src/contexts/Modifiers/utils/getActiveModifiers.test.ts +53 -0
  133. package/src/contexts/Modifiers/utils/getActiveModifiers.ts +33 -0
  134. package/src/contexts/Modifiers/utils/getCustomModifiers.test.ts +14 -0
  135. package/src/contexts/Modifiers/utils/getCustomModifiers.ts +14 -0
  136. package/src/contexts/Modifiers/utils/getInternalModifiers.test.ts +146 -0
  137. package/src/contexts/Modifiers/utils/getInternalModifiers.ts +58 -0
  138. package/src/contexts/Modifiers/utils/isDateInRange.test.ts +28 -0
  139. package/src/contexts/Modifiers/utils/isDateInRange.ts +27 -0
  140. package/src/contexts/Modifiers/utils/isMatch.test.ts +92 -0
  141. package/src/contexts/Modifiers/utils/isMatch.ts +76 -0
  142. package/src/contexts/Modifiers/utils/matcherToArray.test.ts +22 -0
  143. package/src/contexts/Modifiers/utils/matcherToArray.ts +14 -0
  144. package/src/contexts/Navigation/NavigationContext.tsx +84 -0
  145. package/src/contexts/Navigation/index.ts +2 -0
  146. package/src/contexts/Navigation/useNavigation.test.ts +126 -0
  147. package/src/contexts/Navigation/useNavigation.ts +12 -0
  148. package/src/contexts/Navigation/useNavigationState.test.ts +36 -0
  149. package/src/contexts/Navigation/useNavigationState.ts +25 -0
  150. package/src/contexts/Navigation/utils/getDisplayMonths.ts +31 -0
  151. package/src/contexts/Navigation/utils/getInitialMonth.test.ts +56 -0
  152. package/src/contexts/Navigation/utils/getInitialMonth.ts +24 -0
  153. package/src/contexts/Navigation/utils/getNextMonth.test.ts +75 -0
  154. package/src/contexts/Navigation/utils/getNextMonth.ts +45 -0
  155. package/src/contexts/Navigation/utils/getPreviousMonth.test.ts +55 -0
  156. package/src/contexts/Navigation/utils/getPreviousMonth.ts +44 -0
  157. package/src/contexts/RootProvider.tsx +37 -0
  158. package/src/contexts/SelectMultiple/SelectMultipleContext.tsx +135 -0
  159. package/src/contexts/SelectMultiple/index.ts +2 -0
  160. package/src/contexts/SelectMultiple/useSelectMultiple.test.ts +191 -0
  161. package/src/contexts/SelectMultiple/useSelectMultiple.ts +17 -0
  162. package/src/contexts/SelectRange/SelectRangeContext.tsx +158 -0
  163. package/src/contexts/SelectRange/index.ts +2 -0
  164. package/src/contexts/SelectRange/useSelectRange.test.ts +282 -0
  165. package/src/contexts/SelectRange/useSelectRange.ts +15 -0
  166. package/src/contexts/SelectRange/utils/addToRange.test.ts +119 -0
  167. package/src/contexts/SelectRange/utils/addToRange.ts +43 -0
  168. package/src/contexts/SelectSingle/SelectSingleContext.tsx +80 -0
  169. package/src/contexts/SelectSingle/index.ts +2 -0
  170. package/src/contexts/SelectSingle/useSelectSingle.test.ts +81 -0
  171. package/src/contexts/SelectSingle/useSelectSingle.ts +17 -0
  172. package/src/hooks/useActiveModifiers/index.ts +1 -0
  173. package/src/hooks/useActiveModifiers/useActiveModifiers.test.tsx +36 -0
  174. package/src/hooks/useActiveModifiers/useActiveModifiers.tsx +18 -0
  175. package/src/hooks/useControlledValue/index.ts +1 -0
  176. package/src/hooks/useControlledValue/useControlledValue.test.ts +68 -0
  177. package/src/hooks/useControlledValue/useControlledValue.ts +24 -0
  178. package/src/hooks/useDayEventHandlers/index.ts +1 -0
  179. package/src/hooks/useDayEventHandlers/useDayEventHandlers.test.tsx +213 -0
  180. package/src/hooks/useDayEventHandlers/useDayEventHandlers.tsx +195 -0
  181. package/src/hooks/useDayRender/index.ts +1 -0
  182. package/src/hooks/useDayRender/useDayRender.test.tsx +304 -0
  183. package/src/hooks/useDayRender/useDayRender.tsx +123 -0
  184. package/src/hooks/useDayRender/utils/getDayClassNames.test.ts +63 -0
  185. package/src/hooks/useDayRender/utils/getDayClassNames.ts +32 -0
  186. package/src/hooks/useDayRender/utils/getDayStyle.ts +19 -0
  187. package/src/hooks/useInput/index.ts +1 -0
  188. package/src/hooks/useInput/useInput.ts +175 -0
  189. package/src/hooks/useInput/utils/isValidDate.tsx +4 -0
  190. package/src/hooks/useSelectedDays/index.ts +1 -0
  191. package/src/hooks/useSelectedDays/useSelectedDays.test.ts +72 -0
  192. package/src/hooks/useSelectedDays/useSelectedDays.ts +32 -0
  193. package/src/index.ts +43 -0
  194. package/src/style.css +311 -0
  195. package/src/style.css.d.ts +38 -0
  196. package/src/types/DayPickerBase.ts +267 -0
  197. package/src/types/DayPickerDefault.ts +15 -0
  198. package/src/types/DayPickerMultiple.ts +26 -0
  199. package/src/types/DayPickerRange.ts +27 -0
  200. package/src/types/DayPickerSingle.ts +24 -0
  201. package/src/types/EventHandlers.ts +87 -0
  202. package/src/types/Formatters.ts +29 -0
  203. package/src/types/Labels.ts +36 -0
  204. package/src/types/Matchers.ts +106 -0
  205. package/src/types/Modifiers.ts +62 -0
  206. package/src/types/Styles.ts +125 -0
  207. package/tsconfig.json +24 -0
@@ -0,0 +1,126 @@
1
+ import { RenderResult } from '@testing-library/react-hooks';
2
+ import { addMonths, startOfMonth, subMonths } from 'date-fns';
3
+
4
+ import { customRenderHook } from 'test/render/customRenderHook';
5
+ import { freezeBeforeAll } from 'test/utils';
6
+
7
+ import { DayPickerBase } from 'types/DayPickerBase';
8
+
9
+ import { NavigationContextValue } from './NavigationContext';
10
+ import { useNavigation } from './useNavigation';
11
+
12
+ const today = new Date(2021, 11, 8);
13
+ const todaysMonth = startOfMonth(today);
14
+ freezeBeforeAll(today);
15
+
16
+ let result: RenderResult<NavigationContextValue>;
17
+
18
+ function setup(dayPickerProps?: DayPickerBase) {
19
+ const view = customRenderHook(() => useNavigation(), dayPickerProps);
20
+ result = view.result;
21
+ return result;
22
+ }
23
+
24
+ describe('when rendered', () => {
25
+ beforeEach(() => {
26
+ setup();
27
+ });
28
+ test('the current month should be the today`s month', () => {
29
+ expect(result.current.currentMonth).toEqual(todaysMonth);
30
+ });
31
+ test('the display months should be the today`s month', () => {
32
+ expect(result.current.displayMonths).toEqual([todaysMonth]);
33
+ });
34
+ test('the previous month should be the month before today`s month', () => {
35
+ expect(result.current.previousMonth).toEqual(subMonths(todaysMonth, 1));
36
+ });
37
+ test('the next month should be the month after today`s month', () => {
38
+ expect(result.current.nextMonth).toEqual(addMonths(todaysMonth, 1));
39
+ });
40
+ describe('when goToMonth is called', () => {
41
+ const newMonth = addMonths(todaysMonth, 10);
42
+ beforeEach(() => {
43
+ result.current.goToMonth(newMonth);
44
+ });
45
+ test('should go to the specified month', () => {
46
+ expect(result.current.currentMonth).toEqual(newMonth);
47
+ });
48
+ test('the display months should be the today`s month', () => {
49
+ expect(result.current.displayMonths).toEqual([newMonth]);
50
+ });
51
+ test('the previous month should be the month before today`s month', () => {
52
+ expect(result.current.previousMonth).toEqual(subMonths(newMonth, 1));
53
+ });
54
+ test('the next month should be the month after today`s month', () => {
55
+ expect(result.current.nextMonth).toEqual(addMonths(newMonth, 1));
56
+ });
57
+ });
58
+ describe('when goToDate is called with a date from another month', () => {
59
+ const newDate = addMonths(today, 10);
60
+ beforeEach(() => {
61
+ result.current.goToDate(newDate);
62
+ });
63
+ test('should go to the specified month', () => {
64
+ expect(result.current.currentMonth).toEqual(startOfMonth(newDate));
65
+ });
66
+ });
67
+ describe('when isDateDisplayed is called', () => {
68
+ describe('with a date in the calendar', () => {
69
+ test('should return true', () => {
70
+ expect(result.current.isDateDisplayed(today)).toBe(true);
71
+ });
72
+ });
73
+ describe('with a date not in the calendar', () => {
74
+ test('should return false', () => {
75
+ expect(result.current.isDateDisplayed(addMonths(today, 1))).toBe(false);
76
+ });
77
+ });
78
+ });
79
+ });
80
+
81
+ const numberOfMonths = 2;
82
+ describe('when the number of months is ${numberOfMonths}', () => {
83
+ beforeEach(() => {
84
+ setup({ numberOfMonths: 2 });
85
+ });
86
+ test('the current month should be the today`s month', () => {
87
+ expect(result.current.currentMonth).toEqual(todaysMonth);
88
+ });
89
+ test('the display months should be the today`s and next month', () => {
90
+ expect(result.current.displayMonths).toEqual([
91
+ todaysMonth,
92
+ addMonths(todaysMonth, 1)
93
+ ]);
94
+ });
95
+ test('the previous month should be the month before today`s month', () => {
96
+ expect(result.current.previousMonth).toEqual(subMonths(todaysMonth, 1));
97
+ });
98
+ test('the next month should be the month after today`s month', () => {
99
+ expect(result.current.nextMonth).toEqual(addMonths(todaysMonth, 1));
100
+ });
101
+ });
102
+
103
+ describe(`when the number of months is ${numberOfMonths} and the navigation is paged`, () => {
104
+ beforeEach(() => {
105
+ setup({ numberOfMonths, pagedNavigation: true });
106
+ });
107
+ test('the current month should be the today`s month', () => {
108
+ expect(result.current.currentMonth).toEqual(todaysMonth);
109
+ });
110
+ test('the display months should be the today`s and next month', () => {
111
+ expect(result.current.displayMonths).toEqual([
112
+ todaysMonth,
113
+ addMonths(todaysMonth, 1)
114
+ ]);
115
+ });
116
+ test(`the previous month should be the ${numberOfMonths} months before today's month`, () => {
117
+ expect(result.current.previousMonth).toEqual(
118
+ subMonths(todaysMonth, numberOfMonths)
119
+ );
120
+ });
121
+ test(`the next month should be ${numberOfMonths} months after today's month`, () => {
122
+ expect(result.current.nextMonth).toEqual(
123
+ addMonths(todaysMonth, numberOfMonths)
124
+ );
125
+ });
126
+ });
@@ -0,0 +1,12 @@
1
+ import { useContext } from 'react';
2
+
3
+ import { NavigationContext, NavigationContextValue } from './NavigationContext';
4
+
5
+ /** Hook to access the [[NavigationContext]]. */
6
+ export function useNavigation(): NavigationContextValue {
7
+ const context = useContext(NavigationContext);
8
+ if (!context) {
9
+ throw new Error('useNavigation must be used within a NavigationProvider');
10
+ }
11
+ return context;
12
+ }
@@ -0,0 +1,36 @@
1
+ import { addMonths, startOfMonth } from 'date-fns';
2
+
3
+ import { customRenderHook } from 'test/render/customRenderHook';
4
+ import { freezeBeforeAll } from 'test/utils';
5
+
6
+ import { DayPickerBase } from 'types/DayPickerBase';
7
+
8
+ import { useNavigationState } from './useNavigationState';
9
+
10
+ const today = new Date(2021, 11, 8);
11
+ freezeBeforeAll(today);
12
+
13
+ function setup(dayPickerProps?: DayPickerBase) {
14
+ const { result } = customRenderHook(
15
+ () => useNavigationState(),
16
+ dayPickerProps
17
+ );
18
+ return result;
19
+ }
20
+
21
+ describe('when goToMonth is called', () => {
22
+ test('should set the month in state', () => {
23
+ const result = setup();
24
+ const month = addMonths(today, 2);
25
+ result.current[1](month);
26
+ expect(result.current[0]).toEqual(startOfMonth(month));
27
+ });
28
+ describe('when navigation is disabled', () => {
29
+ test('should not set the month in state', () => {
30
+ const result = setup({ disableNavigation: true });
31
+ const month = addMonths(today, 2);
32
+ result.current[1](month);
33
+ expect(result.current[0]).toEqual(startOfMonth(today));
34
+ });
35
+ });
36
+ });
@@ -0,0 +1,25 @@
1
+ import startOfMonth from 'date-fns/startOfMonth';
2
+
3
+ import { useDayPicker } from 'contexts/DayPicker';
4
+ import { useControlledValue } from 'hooks/useControlledValue';
5
+
6
+ import { getInitialMonth } from './utils/getInitialMonth';
7
+
8
+ /** Controls the navigation state. */
9
+ export function useNavigationState(): [
10
+ /** The month DayPicker is navigating at */
11
+ month: Date,
12
+ /** Go to the specified month. */
13
+ goToMonth: (month: Date) => void
14
+ ] {
15
+ const context = useDayPicker();
16
+ const initialMonth = getInitialMonth(context);
17
+ const [month, setMonth] = useControlledValue(initialMonth, context.month);
18
+
19
+ const goToMonth = (date: Date) => {
20
+ if (context.disableNavigation) return;
21
+ setMonth(startOfMonth(date));
22
+ };
23
+
24
+ return [month, goToMonth];
25
+ }
@@ -0,0 +1,31 @@
1
+ import addMonths from 'date-fns/addMonths';
2
+ import differenceInCalendarMonths from 'date-fns/differenceInCalendarMonths';
3
+ import startOfMonth from 'date-fns/startOfMonth';
4
+
5
+ /**
6
+ * Return the months to display in the component according to the number of
7
+ * months and the from/to date.
8
+ */
9
+ export function getDisplayMonths(
10
+ month: Date,
11
+ {
12
+ reverseMonths,
13
+ numberOfMonths
14
+ }: {
15
+ reverseMonths?: boolean;
16
+ numberOfMonths: number;
17
+ }
18
+ ): Date[] {
19
+ const start = startOfMonth(month);
20
+ const end = startOfMonth(addMonths(start, numberOfMonths));
21
+ const monthsDiff = differenceInCalendarMonths(end, start);
22
+ let months = [];
23
+
24
+ for (let i = 0; i < monthsDiff; i++) {
25
+ const nextMonth = addMonths(start, i);
26
+ months.push(nextMonth);
27
+ }
28
+
29
+ if (reverseMonths) months = months.reverse();
30
+ return months;
31
+ }
@@ -0,0 +1,56 @@
1
+ import { addMonths, isSameMonth } from 'date-fns';
2
+
3
+ import { getInitialMonth } from './getInitialMonth';
4
+
5
+ describe('when no toDate is given', () => {
6
+ describe('when month is in context', () => {
7
+ const month = new Date(2010, 11, 12);
8
+ it('return that month', () => {
9
+ const initialMonth = getInitialMonth({ month });
10
+ expect(isSameMonth(initialMonth, month)).toBe(true);
11
+ });
12
+ });
13
+ describe('when defaultMonth is in context', () => {
14
+ const defaultMonth = new Date(2010, 11, 12);
15
+ it('return that month', () => {
16
+ const initialMonth = getInitialMonth({ defaultMonth });
17
+ expect(isSameMonth(initialMonth, defaultMonth)).toBe(true);
18
+ });
19
+ });
20
+ describe('when no month or defaultMonth are in context', () => {
21
+ const today = new Date(2010, 11, 12);
22
+ it('return the today month', () => {
23
+ const initialMonth = getInitialMonth({ today });
24
+ expect(isSameMonth(initialMonth, today)).toBe(true);
25
+ });
26
+ });
27
+ });
28
+ describe('when toDate is given', () => {
29
+ describe('when toDate is before the default initial date', () => {
30
+ const month = new Date(2010, 11, 12);
31
+ const toDate = addMonths(month, -2);
32
+ describe('when the number of month is 1', () => {
33
+ const numberOfMonths = 1;
34
+ it('return the toDate', () => {
35
+ const initialMonth = getInitialMonth({
36
+ month,
37
+ toDate,
38
+ numberOfMonths
39
+ });
40
+ expect(isSameMonth(initialMonth, toDate)).toBe(true);
41
+ });
42
+ });
43
+ describe('when the number of month is 3', () => {
44
+ const numberOfMonths = 3;
45
+ it('return the toDate plus the number of months', () => {
46
+ const initialMonth = getInitialMonth({
47
+ month,
48
+ toDate,
49
+ numberOfMonths
50
+ });
51
+ const expectedMonth = addMonths(toDate, -1 * (numberOfMonths - 1));
52
+ expect(isSameMonth(initialMonth, expectedMonth)).toBe(true);
53
+ });
54
+ });
55
+ });
56
+ });
@@ -0,0 +1,24 @@
1
+ import addMonths from 'date-fns/addMonths';
2
+ import differenceInCalendarMonths from 'date-fns/differenceInCalendarMonths';
3
+ import startOfMonth from 'date-fns/startOfMonth';
4
+
5
+ import { DayPickerContextValue } from 'contexts/DayPicker';
6
+
7
+ /** Return the initial month according to the given options. */
8
+ export function getInitialMonth(context: Partial<DayPickerContextValue>): Date {
9
+ const { month, defaultMonth, today } = context;
10
+ let initialMonth = month || defaultMonth || today || new Date();
11
+
12
+ const { toDate, fromDate, numberOfMonths = 1 } = context;
13
+
14
+ // Fix the initialMonth if is after the to-date
15
+ if (toDate && differenceInCalendarMonths(toDate, initialMonth) < 0) {
16
+ const offset = -1 * (numberOfMonths - 1);
17
+ initialMonth = addMonths(toDate, offset);
18
+ }
19
+ // Fix the initialMonth if is before the from-date
20
+ if (fromDate && differenceInCalendarMonths(initialMonth, fromDate) < 0) {
21
+ initialMonth = fromDate;
22
+ }
23
+ return startOfMonth(initialMonth);
24
+ }
@@ -0,0 +1,75 @@
1
+ import { addMonths, isSameMonth } from 'date-fns';
2
+
3
+ import { getNextMonth } from './getNextMonth';
4
+
5
+ const startingMonth = new Date(2020, 4, 31);
6
+
7
+ describe('when number of months is 1', () => {
8
+ describe('when the navigation is disabled', () => {
9
+ const disableNavigation = true;
10
+ it('the next month is undefined', () => {
11
+ const result = getNextMonth(startingMonth, { disableNavigation });
12
+ expect(result).toBe(undefined);
13
+ });
14
+ });
15
+ describe('when in the navigable range', () => {
16
+ const toDate = addMonths(startingMonth, 3);
17
+ it('the next month is not undefined', () => {
18
+ const result = getNextMonth(startingMonth, { toDate });
19
+ const expectedNextMonth = addMonths(startingMonth, 1);
20
+ expect(result && isSameMonth(result, expectedNextMonth)).toBeTruthy();
21
+ });
22
+ });
23
+ describe('when not in the navigable range', () => {
24
+ const toDate = startingMonth;
25
+ it('the next month is undefined', () => {
26
+ const result = getNextMonth(startingMonth, { toDate });
27
+ expect(result).toBe(undefined);
28
+ });
29
+ });
30
+ });
31
+ describe('when displaying 3 months', () => {
32
+ const numberOfMonths = 3;
33
+ describe('when the navigation is paged', () => {
34
+ const pagedNavigation = true;
35
+ it('the next month is 3 months ahead', () => {
36
+ const result = getNextMonth(startingMonth, {
37
+ numberOfMonths,
38
+ pagedNavigation
39
+ });
40
+ const expectedNextMonth = addMonths(startingMonth, 3);
41
+ expect(result && isSameMonth(result, expectedNextMonth)).toBeTruthy();
42
+ });
43
+ describe('when the to-date is ahead less than 3 months', () => {
44
+ it('the next month is undefined', () => {
45
+ const result = getNextMonth(startingMonth, {
46
+ numberOfMonths,
47
+ pagedNavigation,
48
+ toDate: addMonths(startingMonth, 1)
49
+ });
50
+ expect(result).toBe(undefined);
51
+ });
52
+ });
53
+ });
54
+ describe('when the navigation is not paged', () => {
55
+ const pagedNavigation = false;
56
+ it('the next month is 1 months ahead', () => {
57
+ const result = getNextMonth(startingMonth, {
58
+ numberOfMonths,
59
+ pagedNavigation
60
+ });
61
+ const expectedNextMonth = addMonths(startingMonth, 1);
62
+ expect(result && isSameMonth(result, expectedNextMonth)).toBeTruthy();
63
+ });
64
+ describe('when the to-date is ahead less than 3 months', () => {
65
+ it('the next month is undefined', () => {
66
+ const result = getNextMonth(startingMonth, {
67
+ numberOfMonths,
68
+ pagedNavigation,
69
+ toDate: addMonths(startingMonth, 2)
70
+ });
71
+ expect(result).toBe(undefined);
72
+ });
73
+ });
74
+ });
75
+ });
@@ -0,0 +1,45 @@
1
+ import addMonths from 'date-fns/addMonths';
2
+ import differenceInCalendarMonths from 'date-fns/differenceInCalendarMonths';
3
+ import startOfMonth from 'date-fns/startOfMonth';
4
+
5
+ /**
6
+ * Returns the next month the user can navigate to according to the given
7
+ * options.
8
+ *
9
+ * Please note that the next month is not always the next calendar month:
10
+ *
11
+ * - if after the `toDate` range, is undefined;
12
+ * - if the navigation is paged, is the number of months displayed ahead.
13
+ *
14
+ */
15
+ export function getNextMonth(
16
+ startingMonth: Date,
17
+ options: {
18
+ numberOfMonths?: number;
19
+ fromDate?: Date;
20
+ toDate?: Date;
21
+ pagedNavigation?: boolean;
22
+ today?: Date;
23
+ disableNavigation?: boolean;
24
+ }
25
+ ): Date | undefined {
26
+ if (options.disableNavigation) {
27
+ return undefined;
28
+ }
29
+ const { toDate, pagedNavigation, numberOfMonths = 1 } = options;
30
+ const offset = pagedNavigation ? numberOfMonths : 1;
31
+ const month = startOfMonth(startingMonth);
32
+
33
+ if (!toDate) {
34
+ return addMonths(month, offset);
35
+ }
36
+
37
+ const monthsDiff = differenceInCalendarMonths(toDate, startingMonth);
38
+
39
+ if (monthsDiff < numberOfMonths) {
40
+ return undefined;
41
+ }
42
+
43
+ // Jump forward as the number of months when paged navigation
44
+ return addMonths(month, offset);
45
+ }
@@ -0,0 +1,55 @@
1
+ import { addMonths, isSameMonth } from 'date-fns';
2
+
3
+ import { getPreviousMonth } from './getPreviousMonth';
4
+
5
+ const startingMonth = new Date(2020, 4, 31);
6
+
7
+ describe('when number of months is 1', () => {
8
+ describe('when the navigation is disabled', () => {
9
+ const disableNavigation = true;
10
+ it('the previous month is undefined', () => {
11
+ const result = getPreviousMonth(startingMonth, { disableNavigation });
12
+ expect(result).toBe(undefined);
13
+ });
14
+ });
15
+ describe('when in the navigable range', () => {
16
+ const fromDate = addMonths(startingMonth, -3);
17
+ it('the previous month is not undefined', () => {
18
+ const result = getPreviousMonth(startingMonth, { fromDate });
19
+ const expectedPrevMonth = addMonths(startingMonth, -1);
20
+ expect(result && isSameMonth(result, expectedPrevMonth)).toBeTruthy();
21
+ });
22
+ });
23
+ describe('when not in the navigable range', () => {
24
+ const fromDate = startingMonth;
25
+ it('the previous month is undefined', () => {
26
+ const result = getPreviousMonth(startingMonth, { fromDate });
27
+ expect(result).toBe(undefined);
28
+ });
29
+ });
30
+ });
31
+ describe('when displaying 3 months', () => {
32
+ const numberOfMonths = 3;
33
+ describe('when the navigation is paged', () => {
34
+ const pagedNavigation = true;
35
+ it('the previous month is 3 months back', () => {
36
+ const result = getPreviousMonth(startingMonth, {
37
+ numberOfMonths,
38
+ pagedNavigation
39
+ });
40
+ const expectedPrevMonth = addMonths(startingMonth, -numberOfMonths);
41
+ expect(result && isSameMonth(result, expectedPrevMonth)).toBeTruthy();
42
+ });
43
+ });
44
+ describe('when the navigation is not paged', () => {
45
+ const pagedNavigation = false;
46
+ it('the previous month is 1 months back', () => {
47
+ const result = getPreviousMonth(startingMonth, {
48
+ numberOfMonths,
49
+ pagedNavigation
50
+ });
51
+ const expectedPrevMonth = addMonths(startingMonth, -1);
52
+ expect(result && isSameMonth(result, expectedPrevMonth)).toBeTruthy();
53
+ });
54
+ });
55
+ });
@@ -0,0 +1,44 @@
1
+ import addMonths from 'date-fns/addMonths';
2
+ import differenceInCalendarMonths from 'date-fns/differenceInCalendarMonths';
3
+ import startOfMonth from 'date-fns/startOfMonth';
4
+
5
+ /**
6
+ * Returns the next previous the user can navigate to, according to the given
7
+ * options.
8
+ *
9
+ * Please note that the previous month is not always the previous calendar
10
+ * month:
11
+ *
12
+ * - if before the `fromDate` date, is `undefined`;
13
+ * - if the navigation is paged, is the number of months displayed before.
14
+ *
15
+ */
16
+ export function getPreviousMonth(
17
+ startingMonth: Date,
18
+ options: {
19
+ numberOfMonths?: number;
20
+ fromDate?: Date;
21
+ toDate?: Date;
22
+ pagedNavigation?: boolean;
23
+ today?: Date;
24
+ disableNavigation?: boolean;
25
+ }
26
+ ): Date | undefined {
27
+ if (options.disableNavigation) {
28
+ return undefined;
29
+ }
30
+ const { fromDate, pagedNavigation, numberOfMonths = 1 } = options;
31
+ const offset = pagedNavigation ? numberOfMonths : 1;
32
+ const month = startOfMonth(startingMonth);
33
+ if (!fromDate) {
34
+ return addMonths(month, -offset);
35
+ }
36
+ const monthsDiff = differenceInCalendarMonths(month, fromDate);
37
+
38
+ if (monthsDiff <= 0) {
39
+ return undefined;
40
+ }
41
+
42
+ // Jump back as the number of months when paged navigation
43
+ return addMonths(month, -offset);
44
+ }
@@ -0,0 +1,37 @@
1
+ import React from 'react';
2
+
3
+ import { ModifiersProvider } from 'contexts/Modifiers/ModifiersContext';
4
+ import { DayPickerBase } from 'types/DayPickerBase';
5
+
6
+ import { DayPickerProvider } from './DayPicker';
7
+ import { FocusProvider } from './Focus';
8
+ import { NavigationProvider } from './Navigation';
9
+ import { SelectMultipleProvider } from './SelectMultiple';
10
+ import { SelectRangeProvider } from './SelectRange';
11
+ import { SelectSingleProvider } from './SelectSingle';
12
+
13
+ /** The props of [[RootProvider]]. */
14
+ export type RootContext = DayPickerBase & {
15
+ children: React.ReactNode;
16
+ };
17
+
18
+ /** Provide the value for all the context providers. */
19
+ export function RootProvider(props: RootContext): JSX.Element {
20
+ const { children, ...initialProps } = props;
21
+
22
+ return (
23
+ <DayPickerProvider initialProps={initialProps}>
24
+ <NavigationProvider>
25
+ <SelectSingleProvider initialProps={initialProps}>
26
+ <SelectMultipleProvider initialProps={initialProps}>
27
+ <SelectRangeProvider initialProps={initialProps}>
28
+ <ModifiersProvider>
29
+ <FocusProvider>{children}</FocusProvider>
30
+ </ModifiersProvider>
31
+ </SelectRangeProvider>
32
+ </SelectMultipleProvider>
33
+ </SelectSingleProvider>
34
+ </NavigationProvider>
35
+ </DayPickerProvider>
36
+ );
37
+ }