react-day-picker 8.2.1 → 8.3.0

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 (199) hide show
  1. package/dist/index.d.ts +1176 -40
  2. package/dist/index.esm.d.ts +1176 -0
  3. package/dist/index.esm.js +1473 -1496
  4. package/dist/index.esm.js.map +1 -1
  5. package/dist/index.js +1195 -1214
  6. package/dist/index.js.map +1 -1
  7. package/dist/react-day-picker.min.js +1 -1
  8. package/dist/style.css +9 -11
  9. package/dist/style.module.css +9 -11
  10. package/package.json +2 -2
  11. package/src/components/Caption/Caption.tsx +8 -8
  12. package/src/components/CaptionDropdowns/CaptionDropdowns.tsx +6 -4
  13. package/src/components/CaptionNavigation/CaptionNavigation.tsx +6 -8
  14. package/src/components/Dropdown/Dropdown.tsx +5 -5
  15. package/src/components/Head/Head.tsx +6 -4
  16. package/src/components/HeadRow/HeadRow.tsx +2 -1
  17. package/src/components/HeadRow/utils/getWeekdays.test.ts +10 -0
  18. package/src/components/HeadRow/utils/getWeekdays.ts +9 -3
  19. package/src/components/Month/Month.test.tsx +11 -0
  20. package/src/components/Month/Month.tsx +12 -6
  21. package/src/components/MonthsDropdown/MonthsDropdown.tsx +3 -6
  22. package/src/components/Navigation/Navigation.tsx +5 -15
  23. package/src/components/Row/Row.tsx +8 -8
  24. package/src/components/Table/Table.tsx +10 -12
  25. package/src/components/Table/utils/daysToMonthWeeks.ts +15 -3
  26. package/src/components/Table/utils/getMonthWeeks.test.ts +33 -1
  27. package/src/components/Table/utils/getMonthWeeks.ts +2 -3
  28. package/src/components/YearsDropdown/YearsDropdown.tsx +3 -6
  29. package/src/contexts/DayPicker/{useDayPicker.test.ts → DayPickerContext.test.ts} +13 -29
  30. package/src/contexts/DayPicker/DayPickerContext.tsx +41 -53
  31. package/src/contexts/DayPicker/defaultContextValues.ts +85 -0
  32. package/src/contexts/DayPicker/index.ts +0 -1
  33. package/src/contexts/Focus/{useFocusContext.test.ts → FocusContext.test.ts} +0 -0
  34. package/src/contexts/Focus/FocusContext.tsx +19 -6
  35. package/src/contexts/Focus/index.ts +0 -1
  36. package/src/contexts/Focus/utils/getInitialFocusTarget.test.tsx +37 -8
  37. package/src/contexts/Focus/utils/getInitialFocusTarget.tsx +0 -1
  38. package/src/contexts/Focus/utils/getNextFocus.test.tsx +75 -50
  39. package/src/contexts/Focus/utils/getNextFocus.tsx +54 -19
  40. package/src/contexts/Modifiers/{useModifiers.test.ts → ModifiersContext.test.ts} +0 -0
  41. package/src/contexts/Modifiers/ModifiersContext.tsx +16 -1
  42. package/src/contexts/Modifiers/index.ts +1 -1
  43. package/src/contexts/Modifiers/utils/getInternalModifiers.test.ts +3 -2
  44. package/src/contexts/Navigation/{useNavigation.test.ts → NavigationContext.test.ts} +1 -2
  45. package/src/contexts/Navigation/NavigationContext.tsx +15 -1
  46. package/src/contexts/Navigation/index.ts +0 -1
  47. package/src/contexts/SelectMultiple/{useSelectMultiple.test.ts → SelectMultipleContext.test.ts} +4 -2
  48. package/src/contexts/SelectMultiple/SelectMultipleContext.tsx +16 -1
  49. package/src/contexts/SelectMultiple/index.ts +0 -1
  50. package/src/contexts/SelectRange/{useSelectRange.test.ts → SelectRangeContext.test.ts} +4 -21
  51. package/src/contexts/SelectRange/SelectRangeContext.tsx +51 -36
  52. package/src/contexts/SelectRange/index.ts +0 -1
  53. package/src/contexts/SelectSingle/{useSelectSingle.test.ts → SelectSingleContext.test.ts} +1 -1
  54. package/src/contexts/SelectSingle/SelectSingleContext.tsx +16 -1
  55. package/src/contexts/SelectSingle/index.ts +0 -1
  56. package/src/hooks/useDayRender/useDayRender.tsx +5 -4
  57. package/src/style.css +9 -11
  58. package/src/types/DayPickerBase.ts +33 -6
  59. package/src/types/EventHandlers.ts +9 -11
  60. package/dist/DayPicker.d.ts +0 -93
  61. package/dist/components/Button/Button.d.ts +0 -7
  62. package/dist/components/Button/index.d.ts +0 -1
  63. package/dist/components/Caption/Caption.d.ts +0 -19
  64. package/dist/components/Caption/index.d.ts +0 -1
  65. package/dist/components/CaptionDropdowns/CaptionDropdowns.d.ts +0 -5
  66. package/dist/components/CaptionDropdowns/index.d.ts +0 -1
  67. package/dist/components/CaptionLabel/CaptionLabel.d.ts +0 -9
  68. package/dist/components/CaptionLabel/index.d.ts +0 -1
  69. package/dist/components/CaptionNavigation/CaptionNavigation.d.ts +0 -5
  70. package/dist/components/CaptionNavigation/index.d.ts +0 -1
  71. package/dist/components/Day/Day.d.ts +0 -12
  72. package/dist/components/Day/index.d.ts +0 -1
  73. package/dist/components/DayContent/DayContent.d.ts +0 -12
  74. package/dist/components/DayContent/index.d.ts +0 -1
  75. package/dist/components/Dropdown/Dropdown.d.ts +0 -20
  76. package/dist/components/Dropdown/index.d.ts +0 -1
  77. package/dist/components/Footer/Footer.d.ts +0 -2
  78. package/dist/components/Footer/index.d.ts +0 -1
  79. package/dist/components/Head/Head.d.ts +0 -2
  80. package/dist/components/Head/index.d.ts +0 -1
  81. package/dist/components/HeadRow/HeadRow.d.ts +0 -4
  82. package/dist/components/HeadRow/index.d.ts +0 -1
  83. package/dist/components/HeadRow/utils/getWeekdays.d.ts +0 -8
  84. package/dist/components/HeadRow/utils/index.d.ts +0 -1
  85. package/dist/components/IconDropdown/IconDropdown.d.ts +0 -5
  86. package/dist/components/IconDropdown/index.d.ts +0 -1
  87. package/dist/components/IconLeft/IconLeft.d.ts +0 -5
  88. package/dist/components/IconLeft/index.d.ts +0 -1
  89. package/dist/components/IconRight/IconRight.d.ts +0 -5
  90. package/dist/components/IconRight/index.d.ts +0 -1
  91. package/dist/components/Month/Month.d.ts +0 -7
  92. package/dist/components/Month/index.d.ts +0 -1
  93. package/dist/components/MonthsDropdown/MonthsDropdown.d.ts +0 -9
  94. package/dist/components/MonthsDropdown/index.d.ts +0 -1
  95. package/dist/components/Navigation/Navigation.d.ts +0 -20
  96. package/dist/components/Navigation/index.d.ts +0 -1
  97. package/dist/components/Root/Root.d.ts +0 -2
  98. package/dist/components/Root/index.d.ts +0 -1
  99. package/dist/components/Row/Row.d.ts +0 -13
  100. package/dist/components/Row/index.d.ts +0 -1
  101. package/dist/components/Table/Table.d.ts +0 -9
  102. package/dist/components/Table/index.d.ts +0 -1
  103. package/dist/components/Table/utils/daysToMonthWeeks.d.ts +0 -8
  104. package/dist/components/Table/utils/getMonthWeeks.d.ts +0 -21
  105. package/dist/components/WeekNumber/WeekNumber.d.ts +0 -14
  106. package/dist/components/WeekNumber/index.d.ts +0 -1
  107. package/dist/components/YearsDropdown/YearsDropdown.d.ts +0 -15
  108. package/dist/components/YearsDropdown/index.d.ts +0 -1
  109. package/dist/contexts/DayPicker/DayPickerContext.d.ts +0 -50
  110. package/dist/contexts/DayPicker/defaultClassNames.d.ts +0 -5
  111. package/dist/contexts/DayPicker/defaultContextValue.d.ts +0 -6
  112. package/dist/contexts/DayPicker/formatters/formatCaption.d.ts +0 -7
  113. package/dist/contexts/DayPicker/formatters/formatDay.d.ts +0 -7
  114. package/dist/contexts/DayPicker/formatters/formatMonthCaption.d.ts +0 -7
  115. package/dist/contexts/DayPicker/formatters/formatWeekNumber.d.ts +0 -4
  116. package/dist/contexts/DayPicker/formatters/formatWeekdayName.d.ts +0 -7
  117. package/dist/contexts/DayPicker/formatters/formatYearCaption.d.ts +0 -6
  118. package/dist/contexts/DayPicker/formatters/index.d.ts +0 -6
  119. package/dist/contexts/DayPicker/index.d.ts +0 -2
  120. package/dist/contexts/DayPicker/labels/index.d.ts +0 -7
  121. package/dist/contexts/DayPicker/labels/labelDay.d.ts +0 -5
  122. package/dist/contexts/DayPicker/labels/labelMonthDropdown.d.ts +0 -4
  123. package/dist/contexts/DayPicker/labels/labelNext.d.ts +0 -5
  124. package/dist/contexts/DayPicker/labels/labelPrevious.d.ts +0 -5
  125. package/dist/contexts/DayPicker/labels/labelWeekNumber.d.ts +0 -5
  126. package/dist/contexts/DayPicker/labels/labelWeekday.d.ts +0 -5
  127. package/dist/contexts/DayPicker/labels/labelYearDropdown.d.ts +0 -4
  128. package/dist/contexts/DayPicker/useDayPicker.d.ts +0 -8
  129. package/dist/contexts/DayPicker/utils/index.d.ts +0 -1
  130. package/dist/contexts/DayPicker/utils/parseFromToProps.d.ts +0 -6
  131. package/dist/contexts/Focus/FocusContext.d.ts +0 -36
  132. package/dist/contexts/Focus/index.d.ts +0 -2
  133. package/dist/contexts/Focus/useFocusContext.d.ts +0 -8
  134. package/dist/contexts/Focus/utils/getInitialFocusTarget.d.ts +0 -3
  135. package/dist/contexts/Focus/utils/getNextFocus.d.ts +0 -9
  136. package/dist/contexts/Modifiers/ModifiersContext.d.ts +0 -9
  137. package/dist/contexts/Modifiers/index.d.ts +0 -2
  138. package/dist/contexts/Modifiers/useModifiers.d.ts +0 -9
  139. package/dist/contexts/Modifiers/utils/getActiveModifiers.d.ts +0 -7
  140. package/dist/contexts/Modifiers/utils/getCustomModifiers.d.ts +0 -3
  141. package/dist/contexts/Modifiers/utils/getInternalModifiers.d.ts +0 -6
  142. package/dist/contexts/Modifiers/utils/isDateInRange.d.ts +0 -3
  143. package/dist/contexts/Modifiers/utils/isMatch.d.ts +0 -19
  144. package/dist/contexts/Modifiers/utils/matcherToArray.d.ts +0 -3
  145. package/dist/contexts/Navigation/NavigationContext.d.ts +0 -27
  146. package/dist/contexts/Navigation/index.d.ts +0 -2
  147. package/dist/contexts/Navigation/useNavigation.d.ts +0 -8
  148. package/dist/contexts/Navigation/useNavigationState.d.ts +0 -7
  149. package/dist/contexts/Navigation/utils/getDisplayMonths.d.ts +0 -8
  150. package/dist/contexts/Navigation/utils/getInitialMonth.d.ts +0 -3
  151. package/dist/contexts/Navigation/utils/getNextMonth.d.ts +0 -18
  152. package/dist/contexts/Navigation/utils/getPreviousMonth.d.ts +0 -19
  153. package/dist/contexts/RootProvider.d.ts +0 -8
  154. package/dist/contexts/SelectMultiple/SelectMultipleContext.d.ts +0 -35
  155. package/dist/contexts/SelectMultiple/index.d.ts +0 -2
  156. package/dist/contexts/SelectMultiple/useSelectMultiple.d.ts +0 -7
  157. package/dist/contexts/SelectRange/SelectRangeContext.d.ts +0 -36
  158. package/dist/contexts/SelectRange/index.d.ts +0 -2
  159. package/dist/contexts/SelectRange/useSelectRange.d.ts +0 -7
  160. package/dist/contexts/SelectRange/utils/addToRange.d.ts +0 -8
  161. package/dist/contexts/SelectSingle/SelectSingleContext.d.ts +0 -30
  162. package/dist/contexts/SelectSingle/index.d.ts +0 -2
  163. package/dist/contexts/SelectSingle/useSelectSingle.d.ts +0 -7
  164. package/dist/hooks/useActiveModifiers/index.d.ts +0 -1
  165. package/dist/hooks/useActiveModifiers/useActiveModifiers.d.ts +0 -15
  166. package/dist/hooks/useControlledValue/index.d.ts +0 -1
  167. package/dist/hooks/useControlledValue/useControlledValue.d.ts +0 -12
  168. package/dist/hooks/useDayEventHandlers/index.d.ts +0 -1
  169. package/dist/hooks/useDayEventHandlers/useDayEventHandlers.d.ts +0 -26
  170. package/dist/hooks/useDayRender/index.d.ts +0 -1
  171. package/dist/hooks/useDayRender/useDayRender.d.ts +0 -32
  172. package/dist/hooks/useDayRender/utils/getDayClassNames.d.ts +0 -10
  173. package/dist/hooks/useDayRender/utils/getDayStyle.d.ts +0 -5
  174. package/dist/hooks/useId/index.d.ts +0 -1
  175. package/dist/hooks/useId/useId.d.ts +0 -19
  176. package/dist/hooks/useInput/index.d.ts +0 -1
  177. package/dist/hooks/useInput/useInput.d.ts +0 -28
  178. package/dist/hooks/useInput/utils/isValidDate.d.ts +0 -2
  179. package/dist/hooks/useSelectedDays/index.d.ts +0 -1
  180. package/dist/hooks/useSelectedDays/useSelectedDays.d.ts +0 -10
  181. package/dist/types/DayPickerBase.d.ts +0 -255
  182. package/dist/types/DayPickerDefault.d.ts +0 -8
  183. package/dist/types/DayPickerMultiple.d.ts +0 -18
  184. package/dist/types/DayPickerRange.d.ts +0 -19
  185. package/dist/types/DayPickerSingle.d.ts +0 -16
  186. package/dist/types/EventHandlers.d.ts +0 -51
  187. package/dist/types/Formatters.d.ts +0 -24
  188. package/dist/types/Labels.d.ts +0 -28
  189. package/dist/types/Matchers.d.ts +0 -84
  190. package/dist/types/Modifiers.d.ts +0 -49
  191. package/dist/types/Styles.d.ts +0 -102
  192. package/src/contexts/DayPicker/defaultContextValue.ts +0 -37
  193. package/src/contexts/DayPicker/useDayPicker.ts +0 -17
  194. package/src/contexts/Focus/useFocusContext.ts +0 -17
  195. package/src/contexts/Modifiers/useModifiers.ts +0 -20
  196. package/src/contexts/Navigation/useNavigation.ts +0 -17
  197. package/src/contexts/SelectMultiple/useSelectMultiple.ts +0 -21
  198. package/src/contexts/SelectRange/useSelectRange.ts +0 -19
  199. package/src/contexts/SelectSingle/useSelectSingle.ts +0 -21
@@ -1,7 +1,5 @@
1
1
  import React from 'react';
2
2
 
3
- import { IconLeft } from 'components/IconLeft';
4
- import { IconRight } from 'components/IconRight';
5
3
  import { useDayPicker } from 'contexts/DayPicker';
6
4
 
7
5
  import { Button } from '../Button';
@@ -32,7 +30,7 @@ export function Navigation(props: NavigationProps): JSX.Element {
32
30
  classNames,
33
31
  styles,
34
32
  labels: { labelPrevious, labelNext },
35
- components
33
+ components: { IconRight, IconLeft }
36
34
  } = useDayPicker();
37
35
 
38
36
  if (!props.nextMonth && !props.previousMonth) {
@@ -51,8 +49,6 @@ export function Navigation(props: NavigationProps): JSX.Element {
51
49
  classNames.nav_button_next
52
50
  ].join(' ');
53
51
 
54
- const IconRightComponent = components?.IconRight ?? IconRight;
55
- const IconLeftComponent = components?.IconLeft ?? IconLeft;
56
52
  return (
57
53
  <div className={classNames.nav} style={styles.nav}>
58
54
  {!props.hidePrevious && (
@@ -65,15 +61,12 @@ export function Navigation(props: NavigationProps): JSX.Element {
65
61
  onClick={props.onPreviousClick}
66
62
  >
67
63
  {dir === 'rtl' ? (
68
- <IconRightComponent
64
+ <IconRight
69
65
  className={classNames.nav_icon}
70
66
  style={styles.nav_icon}
71
67
  />
72
68
  ) : (
73
- <IconLeftComponent
74
- className={classNames.nav_icon}
75
- style={styles.nav_icon}
76
- />
69
+ <IconLeft className={classNames.nav_icon} style={styles.nav_icon} />
77
70
  )}
78
71
  </Button>
79
72
  )}
@@ -87,12 +80,9 @@ export function Navigation(props: NavigationProps): JSX.Element {
87
80
  onClick={props.onNextClick}
88
81
  >
89
82
  {dir === 'rtl' ? (
90
- <IconLeftComponent
91
- className={classNames.nav_icon}
92
- style={styles.nav_icon}
93
- />
83
+ <IconLeft className={classNames.nav_icon} style={styles.nav_icon} />
94
84
  ) : (
95
- <IconRightComponent
85
+ <IconRight
96
86
  className={classNames.nav_icon}
97
87
  style={styles.nav_icon}
98
88
  />
@@ -2,8 +2,6 @@ import React from 'react';
2
2
 
3
3
  import getUnixTime from 'date-fns/getUnixTime';
4
4
 
5
- import { Day } from 'components/Day';
6
- import { WeekNumber } from 'components/WeekNumber';
7
5
  import { useDayPicker } from 'contexts/DayPicker';
8
6
 
9
7
  /**
@@ -20,16 +18,18 @@ export interface RowProps {
20
18
 
21
19
  /** Render a row in the calendar, with the days and the week number. */
22
20
  export function Row(props: RowProps): JSX.Element {
23
- const { styles, classNames, showWeekNumber, components } = useDayPicker();
24
-
25
- const DayComponent = components?.Day ?? Day;
26
- const WeeknumberComponent = components?.WeekNumber ?? WeekNumber;
21
+ const {
22
+ styles,
23
+ classNames,
24
+ showWeekNumber,
25
+ components: { Day, WeekNumber }
26
+ } = useDayPicker();
27
27
 
28
28
  let weekNumberCell;
29
29
  if (showWeekNumber) {
30
30
  weekNumberCell = (
31
31
  <td className={classNames.cell} style={styles.cell}>
32
- <WeeknumberComponent number={props.weekNumber} dates={props.dates} />
32
+ <WeekNumber number={props.weekNumber} dates={props.dates} />
33
33
  </td>
34
34
  );
35
35
  }
@@ -43,7 +43,7 @@ export function Row(props: RowProps): JSX.Element {
43
43
  style={styles.cell}
44
44
  key={getUnixTime(date)}
45
45
  >
46
- <DayComponent displayMonth={props.displayMonth} date={date} />
46
+ <Day displayMonth={props.displayMonth} date={date} />
47
47
  </td>
48
48
  ))}
49
49
  </tr>
@@ -1,8 +1,5 @@
1
1
  import React from 'react';
2
2
 
3
- import { Footer } from 'components/Footer';
4
- import { Head } from 'components/Head';
5
- import { Row } from 'components/Row';
6
3
  import { useDayPicker } from 'contexts/DayPicker';
7
4
 
8
5
  import { getMonthWeeks } from './utils/getMonthWeeks';
@@ -23,19 +20,20 @@ export function Table(props: TableProps): JSX.Element {
23
20
  styles,
24
21
  hideHead,
25
22
  fixedWeeks,
26
- components,
27
- weekStartsOn
23
+ components: { Head, Row, Footer },
24
+ weekStartsOn,
25
+ firstWeekContainsDate,
26
+ ISOWeek
28
27
  } = useDayPicker();
29
28
 
30
29
  const weeks = getMonthWeeks(props.displayMonth, {
31
30
  useFixedWeeks: Boolean(fixedWeeks),
31
+ ISOWeek,
32
32
  locale,
33
- weekStartsOn
33
+ weekStartsOn,
34
+ firstWeekContainsDate
34
35
  });
35
36
 
36
- const HeadComponent = components?.Head ?? Head;
37
- const RowComponent = components?.Row ?? Row;
38
- const FooterComponent = components?.Footer ?? Footer;
39
37
  return (
40
38
  <table
41
39
  className={classNames.table}
@@ -43,10 +41,10 @@ export function Table(props: TableProps): JSX.Element {
43
41
  role="grid"
44
42
  aria-labelledby={props['aria-labelledby']}
45
43
  >
46
- {!hideHead && <HeadComponent />}
44
+ {!hideHead && <Head />}
47
45
  <tbody className={classNames.tbody} style={styles.tbody}>
48
46
  {weeks.map((week) => (
49
- <RowComponent
47
+ <Row
50
48
  displayMonth={props.displayMonth}
51
49
  key={week.weekNumber}
52
50
  dates={week.dates}
@@ -54,7 +52,7 @@ export function Table(props: TableProps): JSX.Element {
54
52
  />
55
53
  ))}
56
54
  </tbody>
57
- <FooterComponent />
55
+ <Footer />
58
56
  </table>
59
57
  );
60
58
  }
@@ -2,8 +2,11 @@ import type { Locale } from 'date-fns';
2
2
 
3
3
  import addDays from 'date-fns/addDays';
4
4
  import differenceInCalendarDays from 'date-fns/differenceInCalendarDays';
5
+ import endOfISOWeek from 'date-fns/endOfISOWeek';
5
6
  import endOfWeek from 'date-fns/endOfWeek';
7
+ import getISOWeek from 'date-fns/getISOWeek';
6
8
  import getWeek from 'date-fns/getWeek';
9
+ import startOfISOWeek from 'date-fns/startOfISOWeek';
7
10
  import startOfWeek from 'date-fns/startOfWeek';
8
11
 
9
12
  import { MonthWeek } from './getMonthWeeks';
@@ -13,13 +16,19 @@ export function daysToMonthWeeks(
13
16
  fromDate: Date,
14
17
  toDate: Date,
15
18
  options?: {
19
+ ISOWeek?: boolean;
16
20
  locale?: Locale;
17
21
  weekStartsOn?: 0 | 1 | 2 | 3 | 4 | 5 | 6;
18
22
  firstWeekContainsDate?: 1 | 2 | 3 | 4 | 5 | 6 | 7;
19
23
  }
20
24
  ): MonthWeek[] {
21
- const toWeek = endOfWeek(toDate, options);
22
- const fromWeek = startOfWeek(fromDate, options);
25
+ const toWeek = options?.ISOWeek
26
+ ? endOfISOWeek(toDate)
27
+ : endOfWeek(toDate, options);
28
+ const fromWeek = options?.ISOWeek
29
+ ? startOfISOWeek(fromDate)
30
+ : startOfWeek(fromDate, options);
31
+
23
32
  const nOfDays = differenceInCalendarDays(toWeek, fromWeek);
24
33
  const days: Date[] = [];
25
34
 
@@ -28,7 +37,10 @@ export function daysToMonthWeeks(
28
37
  }
29
38
 
30
39
  const weeksInMonth = days.reduce((result: MonthWeek[], date) => {
31
- const weekNumber = getWeek(date, options);
40
+ const weekNumber = options?.ISOWeek
41
+ ? getISOWeek(date)
42
+ : getWeek(date, options);
43
+
32
44
  const existingWeek = result.find(
33
45
  (value) => value.weekNumber === weekNumber
34
46
  );
@@ -60,9 +60,41 @@ describe('when using the "enGB" locale', () => {
60
60
  27, 28, 29, 30, 31, 1, 2
61
61
  ]);
62
62
  });
63
- test('the first week should be the last of January', () => {
63
+ test('the last week should be the last of January', () => {
64
64
  const weekNumbers = weeks.map((week) => week.weekNumber);
65
65
  expect(weekNumbers[weekNumbers.length - 1]).toEqual(5);
66
66
  });
67
67
  });
68
+ describe('when setting a 3 as first day of year', () => {
69
+ const date = new Date(2022, 0);
70
+ const weeks = getMonthWeeks(date, { locale, firstWeekContainsDate: 3 });
71
+ test('the number of week should have number 53', () => {
72
+ const weekNumbers = weeks.map((week) => week.weekNumber);
73
+ expect(weekNumbers[0]).toEqual(53);
74
+ });
75
+ });
76
+ });
77
+
78
+ describe('when using the ISOWeek numbers', () => {
79
+ const locale = enUS;
80
+ describe('when getting the weeks for September 2022', () => {
81
+ const date = new Date(2022, 8);
82
+ const weeks = getMonthWeeks(date, { locale, ISOWeek: true });
83
+ test('the last week should have number 39', () => {
84
+ const weekNumbers = weeks.map((week) => week.weekNumber);
85
+ expect(weekNumbers[weekNumbers.length - 1]).toEqual(39);
86
+ });
87
+ });
88
+ });
89
+
90
+ describe('when not using the ISOWeek numbers', () => {
91
+ const locale = enUS;
92
+ describe('when getting the weeks for September 2022', () => {
93
+ const date = new Date(2022, 8);
94
+ const weeks = getMonthWeeks(date, { locale, ISOWeek: false });
95
+ test('the last week should have number 40', () => {
96
+ const weekNumbers = weeks.map((week) => week.weekNumber);
97
+ expect(weekNumbers[weekNumbers.length - 1]).toEqual(40);
98
+ });
99
+ });
68
100
  });
@@ -20,14 +20,13 @@ export type MonthWeek = {
20
20
  * the first and last week.
21
21
  */
22
22
  export function getMonthWeeks(
23
- /** The month to get the weeks from */
24
23
  month: Date,
25
24
  options: {
26
25
  locale: Locale;
27
- /** Add extra weeks up to 6 weeks */
28
26
  useFixedWeeks?: boolean;
29
27
  weekStartsOn?: 0 | 1 | 2 | 3 | 4 | 5 | 6;
30
28
  firstWeekContainsDate?: 1 | 2 | 3 | 4 | 5 | 6 | 7;
29
+ ISOWeek?: boolean;
31
30
  }
32
31
  ): MonthWeek[] {
33
32
  const weeksInMonth: MonthWeek[] = daysToMonthWeeks(
@@ -36,8 +35,8 @@ export function getMonthWeeks(
36
35
  options
37
36
  );
38
37
 
39
- // Add extra weeks to the month, up to 6 weeks
40
38
  if (options?.useFixedWeeks) {
39
+ // Add extra weeks to the month, up to 6 weeks
41
40
  const nrOfMonthWeeks = getWeeksInMonth(month, options);
42
41
  if (nrOfMonthWeeks < 6) {
43
42
  const lastWeek = weeksInMonth[weeksInMonth.length - 1];
@@ -4,7 +4,6 @@ import setYear from 'date-fns/setYear';
4
4
  import startOfMonth from 'date-fns/startOfMonth';
5
5
  import startOfYear from 'date-fns/startOfYear';
6
6
 
7
- import { Dropdown } from 'components/Dropdown';
8
7
  import { useDayPicker } from 'contexts/DayPicker';
9
8
  import { MonthChangeEventHandler } from 'types/EventHandlers';
10
9
 
@@ -30,7 +29,7 @@ export function YearsDropdown(props: YearsDropdownProps): JSX.Element {
30
29
  locale,
31
30
  styles,
32
31
  classNames,
33
- components,
32
+ components: { Dropdown },
34
33
  formatters: { formatYearCaption },
35
34
  labels: { labelYearDropdown }
36
35
  } = useDayPicker();
@@ -55,10 +54,8 @@ export function YearsDropdown(props: YearsDropdownProps): JSX.Element {
55
54
  props.onChange(newMonth);
56
55
  };
57
56
 
58
- const DropdownComponent = components?.Dropdown ?? Dropdown;
59
-
60
57
  return (
61
- <DropdownComponent
58
+ <Dropdown
62
59
  name="years"
63
60
  aria-label={labelYearDropdown()}
64
61
  className={classNames.dropdown_year}
@@ -72,6 +69,6 @@ export function YearsDropdown(props: YearsDropdownProps): JSX.Element {
72
69
  {formatYearCaption(year, { locale })}
73
70
  </option>
74
71
  ))}
75
- </DropdownComponent>
72
+ </Dropdown>
76
73
  );
77
74
  }
@@ -7,15 +7,18 @@ import { freezeBeforeAll } from 'test/utils';
7
7
 
8
8
  import { CaptionLayout } from 'components/Caption';
9
9
  import { DayPickerContextValue, useDayPicker } from 'contexts/DayPicker';
10
- import { getDefaultContextValue } from 'contexts/DayPicker/defaultContextValue';
11
- import { CustomComponents, DaySelectionMode } from 'types/DayPickerBase';
10
+ import {
11
+ DefaultContextProps,
12
+ getDefaultContextValues
13
+ } from 'contexts/DayPicker/defaultContextValues';
14
+ import { DaySelectionMode } from 'types/DayPickerBase';
12
15
  import { Formatters } from 'types/Formatters';
13
16
  import { Labels } from 'types/Labels';
14
17
  import { DayModifiers, ModifiersClassNames } from 'types/Modifiers';
15
18
  import { ClassNames, Styles } from 'types/Styles';
16
19
 
17
20
  const today = new Date(2022, 5, 13);
18
- const defaults = getDefaultContextValue();
21
+ const defaults = getDefaultContextValues();
19
22
 
20
23
  freezeBeforeAll(today);
21
24
 
@@ -25,20 +28,8 @@ function setup(dayPickerProps?: DayPickerProps) {
25
28
  renderResult = result;
26
29
  }
27
30
 
28
- describe('when passing rendered without props', () => {
29
- type PropName =
30
- | 'captionLayout'
31
- | 'classNames'
32
- | 'formatters'
33
- | 'labels'
34
- | 'locale'
35
- | 'modifiersClassNames'
36
- | 'modifiers'
37
- | 'numberOfMonths'
38
- | 'styles'
39
- | 'today';
40
-
41
- const testPropNames: PropName[] = [
31
+ describe('when rendered without props', () => {
32
+ const testPropNames: DefaultContextProps[] = [
42
33
  'captionLayout',
43
34
  'classNames',
44
35
  'formatters',
@@ -48,7 +39,7 @@ describe('when passing rendered without props', () => {
48
39
  'modifiers',
49
40
  'numberOfMonths',
50
41
  'styles'
51
- // 'today' SKIPPED: this test doesn't pass
42
+ // 'today' // SKIPPED: this test doesn't pass
52
43
  ];
53
44
  beforeAll(() => {
54
45
  setup();
@@ -279,20 +270,13 @@ describe('when passing "labels" from props', () => {
279
270
  });
280
271
  });
281
272
 
282
- describe('when passing "components" from props', () => {
283
- const components: CustomComponents = { Day: jest.fn() };
284
- const dayPickerProps: DayPickerProps = { components };
273
+ describe('when passing an "id" from props', () => {
274
+ const dayPickerProps: DayPickerProps = { id: 'foo' };
285
275
  beforeEach(() => {
286
276
  setup(dayPickerProps);
287
277
  });
288
- test('should override the default "components"', () => {
289
- expect(renderResult.current.components).not.toBe(defaults.components);
290
- });
291
- test('should include the custom "components"', () => {
292
- expect(renderResult.current.components).toStrictEqual({
293
- ...defaults.components,
294
- ...components
295
- });
278
+ test('should return the id', () => {
279
+ expect(renderResult.current.id).toBe('foo');
296
280
  });
297
281
  });
298
282
 
@@ -1,9 +1,13 @@
1
- import React, { createContext, ReactNode } from 'react';
1
+ import React, { createContext, ReactNode, useContext } from 'react';
2
2
 
3
3
  import { DayPickerProps } from 'DayPicker';
4
4
 
5
5
  import { CaptionLayout } from 'components/Caption';
6
- import { DayPickerBase, DaySelectionMode } from 'types/DayPickerBase';
6
+ import {
7
+ Components,
8
+ DayPickerBase,
9
+ DaySelectionMode
10
+ } from 'types/DayPickerBase';
7
11
  import {
8
12
  DayPickerMultipleProps,
9
13
  isDayPickerMultiple
@@ -16,10 +20,13 @@ import { Matcher } from 'types/Matchers';
16
20
  import { DayModifiers, ModifiersClassNames } from 'types/Modifiers';
17
21
  import { ClassNames, Styles } from 'types/Styles';
18
22
 
19
- import { getDefaultContextValue } from './defaultContextValue';
23
+ import { getDefaultContextValues } from './defaultContextValues';
20
24
  import { parseFromToProps } from './utils';
21
25
 
22
- /** The value of the {@link DayPickerContext}. */
26
+ /**
27
+ * The value of the {@link DayPickerContext} extends the props from DayPicker
28
+ * with default and cleaned up values.
29
+ */
23
30
  export interface DayPickerContextValue extends DayPickerBase {
24
31
  mode: DaySelectionMode;
25
32
  onSelect?:
@@ -32,6 +39,7 @@ export interface DayPickerContextValue extends DayPickerBase {
32
39
  selected?: Matcher | Matcher[];
33
40
 
34
41
  captionLayout: CaptionLayout;
42
+ components: Components;
35
43
  classNames: Required<ClassNames>;
36
44
  formatters: Formatters;
37
45
  labels: Labels;
@@ -67,12 +75,14 @@ export interface DayPickerProviderProps {
67
75
  export function DayPickerProvider(props: DayPickerProviderProps): JSX.Element {
68
76
  const { initialProps } = props;
69
77
 
70
- const defaults = getDefaultContextValue();
78
+ const defaultContextValues = getDefaultContextValues();
71
79
 
72
80
  const { fromDate, toDate } = parseFromToProps(initialProps);
73
81
 
74
- let captionLayout = initialProps.captionLayout ?? defaults.captionLayout;
82
+ let captionLayout =
83
+ initialProps.captionLayout ?? defaultContextValues.captionLayout;
75
84
  if (captionLayout !== 'buttons' && (!fromDate || !toDate)) {
85
+ // When no from/to dates are set, the caption is always buttons
76
86
  captionLayout = 'buttons';
77
87
  }
78
88
 
@@ -86,77 +96,41 @@ export function DayPickerProvider(props: DayPickerProviderProps): JSX.Element {
86
96
  }
87
97
 
88
98
  const value: DayPickerContextValue = {
99
+ ...defaultContextValues,
100
+ ...initialProps,
89
101
  captionLayout,
90
- className: initialProps.className,
91
102
  classNames: {
92
- ...defaults.classNames,
103
+ ...defaultContextValues.classNames,
93
104
  ...initialProps.classNames
94
105
  },
95
106
  components: {
96
- ...defaults.components,
107
+ ...defaultContextValues.components,
97
108
  ...initialProps.components
98
109
  },
99
- defaultMonth: initialProps.defaultMonth,
100
- dir: initialProps.dir,
101
- disabled: initialProps.disabled,
102
- disableNavigation: initialProps.disableNavigation,
103
- fixedWeeks: initialProps.fixedWeeks,
104
- footer: initialProps.footer,
105
110
  formatters: {
106
- ...defaults.formatters,
111
+ ...defaultContextValues.formatters,
107
112
  ...initialProps.formatters
108
113
  },
109
114
  fromDate,
110
- hidden: initialProps.hidden,
111
- hideHead: initialProps.hideHead,
112
- initialFocus: initialProps.initialFocus,
113
115
  labels: {
114
- ...defaults.labels,
116
+ ...defaultContextValues.labels,
115
117
  ...initialProps.labels
116
118
  },
117
- locale: initialProps.locale ?? defaults.locale,
118
- mode: initialProps.mode || 'default',
119
+ mode: initialProps.mode || defaultContextValues.mode,
119
120
  modifiers: {
120
- ...defaults.modifiers,
121
+ ...defaultContextValues.modifiers,
121
122
  ...initialProps.modifiers
122
123
  },
123
124
  modifiersClassNames: {
124
- ...defaults.modifiersClassNames,
125
+ ...defaultContextValues.modifiersClassNames,
125
126
  ...initialProps.modifiersClassNames
126
127
  },
127
- modifiersStyles: initialProps.modifiersStyles,
128
- month: initialProps.month,
129
- numberOfMonths: initialProps.numberOfMonths ?? defaults.numberOfMonths,
130
- onDayBlur: initialProps.onDayBlur,
131
- onDayClick: initialProps.onDayClick,
132
- onDayFocus: initialProps.onDayFocus,
133
- onDayKeyDown: initialProps.onDayKeyDown,
134
- onDayKeyPress: initialProps.onDayKeyPress,
135
- onDayKeyUp: initialProps.onDayKeyUp,
136
- onDayMouseEnter: initialProps.onDayMouseEnter,
137
- onDayMouseLeave: initialProps.onDayMouseLeave,
138
- onDayTouchCancel: initialProps.onDayTouchCancel,
139
- onDayTouchEnd: initialProps.onDayTouchEnd,
140
- onDayTouchMove: initialProps.onDayTouchMove,
141
- onDayTouchStart: initialProps.onDayTouchStart,
142
- onMonthChange: initialProps.onMonthChange,
143
- onNextClick: initialProps.onNextClick,
144
- onPrevClick: initialProps.onPrevClick,
145
128
  onSelect,
146
- onWeekNumberClick: initialProps.onWeekNumberClick,
147
- pagedNavigation: initialProps.pagedNavigation,
148
- reverseMonths: initialProps.reverseMonths,
149
- selected: initialProps.selected,
150
- showOutsideDays: initialProps.showOutsideDays,
151
- showWeekNumber: initialProps.showWeekNumber,
152
- style: initialProps.style,
153
129
  styles: {
154
- ...defaults.styles,
130
+ ...defaultContextValues.styles,
155
131
  ...initialProps.styles
156
132
  },
157
- toDate,
158
- today: initialProps.today ?? defaults.today,
159
- weekStartsOn: initialProps.weekStartsOn
133
+ toDate
160
134
  };
161
135
 
162
136
  return (
@@ -165,3 +139,17 @@ export function DayPickerProvider(props: DayPickerProviderProps): JSX.Element {
165
139
  </DayPickerContext.Provider>
166
140
  );
167
141
  }
142
+
143
+ /**
144
+ * Hook to access the {@link DayPickerContextValue}.
145
+ *
146
+ * Use the DayPicker context to access to the props passed to DayPicker inside
147
+ * internal or custom components.
148
+ */
149
+ export function useDayPicker(): DayPickerContextValue {
150
+ const context = useContext(DayPickerContext);
151
+ if (!context) {
152
+ throw new Error(`useDayPicker must be used within a DayPickerProvider.`);
153
+ }
154
+ return context;
155
+ }
@@ -0,0 +1,85 @@
1
+ import enUS from 'date-fns/locale/en-US';
2
+
3
+ import { Caption, CaptionLayout } from 'components/Caption';
4
+ import { CaptionLabel } from 'components/CaptionLabel';
5
+ import { Day } from 'components/Day';
6
+ import { DayContent } from 'components/DayContent';
7
+ import { Dropdown } from 'components/Dropdown';
8
+ import { Footer } from 'components/Footer';
9
+ import { Head } from 'components/Head';
10
+ import { HeadRow } from 'components/HeadRow';
11
+ import { IconDropdown } from 'components/IconDropdown';
12
+ import { IconLeft } from 'components/IconLeft';
13
+ import { IconRight } from 'components/IconRight';
14
+ import { Row } from 'components/Row';
15
+ import { WeekNumber } from 'components/WeekNumber';
16
+ import { DayPickerContextValue } from 'contexts/DayPicker';
17
+ import { Components } from 'types/DayPickerBase';
18
+
19
+ import { defaultClassNames } from './defaultClassNames';
20
+ import * as formatters from './formatters';
21
+ import * as labels from './labels';
22
+
23
+ export type DefaultContextProps =
24
+ | 'captionLayout'
25
+ | 'classNames'
26
+ | 'components'
27
+ | 'formatters'
28
+ | 'locale'
29
+ | 'labels'
30
+ | 'modifiersClassNames'
31
+ | 'modifiers'
32
+ | 'numberOfMonths'
33
+ | 'styles'
34
+ | 'today'
35
+ | 'mode';
36
+
37
+ export type DefaultContextValues = Pick<
38
+ DayPickerContextValue,
39
+ DefaultContextProps
40
+ >;
41
+ /**
42
+ * Returns the default values to use in the DayPickerContext, in case they are
43
+ * not passed down with the DayPicker initial props.
44
+ */
45
+ export function getDefaultContextValues(): DefaultContextValues {
46
+ const captionLayout: CaptionLayout = 'buttons';
47
+ const classNames = defaultClassNames;
48
+ const locale = enUS;
49
+ const modifiersClassNames = {};
50
+ const modifiers = {};
51
+ const numberOfMonths = 1;
52
+ const styles = {};
53
+ const today = new Date();
54
+
55
+ const components: Components = {
56
+ Caption,
57
+ CaptionLabel,
58
+ Day,
59
+ DayContent,
60
+ Dropdown,
61
+ Footer,
62
+ Head,
63
+ HeadRow,
64
+ IconDropdown,
65
+ IconRight,
66
+ IconLeft,
67
+ Row,
68
+ WeekNumber
69
+ };
70
+
71
+ return {
72
+ captionLayout,
73
+ classNames,
74
+ components,
75
+ formatters,
76
+ labels,
77
+ locale,
78
+ modifiersClassNames,
79
+ modifiers,
80
+ numberOfMonths,
81
+ styles,
82
+ today,
83
+ mode: 'default'
84
+ };
85
+ }
@@ -1,2 +1 @@
1
- export * from './useDayPicker';
2
1
  export * from './DayPickerContext';
@@ -1,4 +1,4 @@
1
- import React, { createContext, ReactNode, useState } from 'react';
1
+ import React, { createContext, ReactNode, useContext, useState } from 'react';
2
2
 
3
3
  import isSameDay from 'date-fns/isSameDay';
4
4
 
@@ -81,17 +81,16 @@ export function FocusProvider(props: { children: ReactNode }): JSX.Element {
81
81
  setFocusedDay(date);
82
82
  };
83
83
 
84
- const dayPicker = useDayPicker();
84
+ const context = useDayPicker();
85
85
 
86
86
  const moveFocus = (moveBy: MoveFocusBy, direction: MoveFocusDirection) => {
87
87
  if (!focusedDay) return;
88
- const nextFocused = getNextFocus(
89
- focusedDay,
88
+ const nextFocused = getNextFocus(focusedDay, {
90
89
  moveBy,
91
90
  direction,
92
- dayPicker,
91
+ context,
93
92
  modifiers
94
- );
93
+ });
95
94
  if (isSameDay(focusedDay, nextFocused)) return undefined;
96
95
  navigation.goToDate(nextFocused, focusedDay);
97
96
  focus(nextFocused);
@@ -120,3 +119,17 @@ export function FocusProvider(props: { children: ReactNode }): JSX.Element {
120
119
  </FocusContext.Provider>
121
120
  );
122
121
  }
122
+
123
+ /**
124
+ * Hook to access the {@link FocusContextValue}. Use this hook to handle the
125
+ * focus state of the elements.
126
+ *
127
+ * This hook is meant to be used inside internal or custom components.
128
+ */
129
+ export function useFocusContext(): FocusContextValue {
130
+ const context = useContext(FocusContext);
131
+ if (!context) {
132
+ throw new Error('useFocusContext must be used within a FocusProvider');
133
+ }
134
+ return context;
135
+ }