react-day-picker 9.6.2 → 9.6.3

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 (177) hide show
  1. package/dist/cjs/DayPicker.js +14 -2
  2. package/dist/cjs/DayPicker.js.map +1 -1
  3. package/dist/cjs/classes/DateLib.js +4 -4
  4. package/dist/cjs/classes/DateLib.js.map +1 -1
  5. package/dist/esm/DayPicker.js +14 -2
  6. package/dist/esm/DayPicker.js.map +1 -1
  7. package/dist/esm/classes/DateLib.js +1 -1
  8. package/dist/esm/classes/DateLib.js.map +1 -1
  9. package/package.json +2 -4
  10. package/src/.eslintignore +1 -0
  11. package/src/.eslintrc.cjs +27 -0
  12. package/src/DayPicker.test.tsx +199 -0
  13. package/src/DayPicker.tsx +629 -0
  14. package/src/UI.ts +365 -0
  15. package/src/classes/CalendarDay.test.ts +17 -0
  16. package/src/classes/CalendarDay.ts +61 -0
  17. package/src/classes/CalendarMonth.test.ts +28 -0
  18. package/src/classes/CalendarMonth.ts +15 -0
  19. package/src/classes/CalendarWeek.test.ts +21 -0
  20. package/src/classes/CalendarWeek.ts +13 -0
  21. package/src/classes/DateLib.ts +615 -0
  22. package/src/classes/index.ts +4 -0
  23. package/src/components/Button.tsx +13 -0
  24. package/src/components/CaptionLabel.tsx +13 -0
  25. package/src/components/Chevron.tsx +42 -0
  26. package/src/components/Day.tsx +28 -0
  27. package/src/components/DayButton.tsx +29 -0
  28. package/src/components/Dropdown.tsx +71 -0
  29. package/src/components/DropdownNav.tsx +13 -0
  30. package/src/components/Footer.tsx +13 -0
  31. package/src/components/Month.tsx +24 -0
  32. package/src/components/MonthCaption.tsx +23 -0
  33. package/src/components/MonthGrid.tsx +13 -0
  34. package/src/components/Months.tsx +13 -0
  35. package/src/components/MonthsDropdown.tsx +16 -0
  36. package/src/components/Nav.tsx +90 -0
  37. package/src/components/NextMonthButton.tsx +18 -0
  38. package/src/components/Option.tsx +13 -0
  39. package/src/components/PreviousMonthButton.tsx +20 -0
  40. package/src/components/Root.tsx +19 -0
  41. package/src/components/Select.tsx +13 -0
  42. package/src/components/Week.tsx +20 -0
  43. package/src/components/WeekNumber.tsx +21 -0
  44. package/src/components/WeekNumberHeader.tsx +15 -0
  45. package/src/components/Weekday.tsx +13 -0
  46. package/src/components/Weekdays.tsx +17 -0
  47. package/src/components/Weeks.tsx +13 -0
  48. package/src/components/YearsDropdown.tsx +16 -0
  49. package/src/components/custom-components.tsx +26 -0
  50. package/src/formatters/formatCaption.test.ts +27 -0
  51. package/src/formatters/formatCaption.ts +23 -0
  52. package/src/formatters/formatDay.test.ts +7 -0
  53. package/src/formatters/formatDay.ts +16 -0
  54. package/src/formatters/formatMonthDropdown.test.ts +19 -0
  55. package/src/formatters/formatMonthDropdown.ts +15 -0
  56. package/src/formatters/formatWeekNumber.test.ts +5 -0
  57. package/src/formatters/formatWeekNumber.ts +13 -0
  58. package/src/formatters/formatWeekNumberHeader.ts +10 -0
  59. package/src/formatters/formatWeekdayName.test.ts +15 -0
  60. package/src/formatters/formatWeekdayName.ts +16 -0
  61. package/src/formatters/formatYearDropdown.test.ts +7 -0
  62. package/src/formatters/formatYearDropdown.ts +21 -0
  63. package/src/formatters/index.ts +7 -0
  64. package/src/helpers/broadcastCalendar.test.ts +43 -0
  65. package/src/helpers/calculateFocusTarget.ts +51 -0
  66. package/src/helpers/endOfBroadcastWeek.test.ts +25 -0
  67. package/src/helpers/endOfBroadcastWeek.ts +16 -0
  68. package/src/helpers/getBroadcastWeeksInMonth.test.ts +23 -0
  69. package/src/helpers/getBroadcastWeeksInMonth.ts +31 -0
  70. package/src/helpers/getClassNamesForModifiers.ts +26 -0
  71. package/src/helpers/getComponents.ts +11 -0
  72. package/src/helpers/getDataAttributes.test.tsx +48 -0
  73. package/src/helpers/getDataAttributes.tsx +21 -0
  74. package/src/helpers/getDates.test.ts +190 -0
  75. package/src/helpers/getDates.ts +64 -0
  76. package/src/helpers/getDays.test.ts +30 -0
  77. package/src/helpers/getDays.ts +16 -0
  78. package/src/helpers/getDefaultClassNames.test.ts +47 -0
  79. package/src/helpers/getDefaultClassNames.ts +33 -0
  80. package/src/helpers/getDisplayMonths.test.ts +44 -0
  81. package/src/helpers/getDisplayMonths.ts +20 -0
  82. package/src/helpers/getFocusableDate.ts +59 -0
  83. package/src/helpers/getFormatters.test.ts +48 -0
  84. package/src/helpers/getFormatters.ts +19 -0
  85. package/src/helpers/getInitialMonth.test.ts +79 -0
  86. package/src/helpers/getInitialMonth.ts +41 -0
  87. package/src/helpers/getLabels.ts +10 -0
  88. package/src/helpers/getMonthOptions.test.ts +226 -0
  89. package/src/helpers/getMonthOptions.ts +37 -0
  90. package/src/helpers/getMonths.test.ts +88 -0
  91. package/src/helpers/getMonths.ts +90 -0
  92. package/src/helpers/getNavMonth.test.ts +253 -0
  93. package/src/helpers/getNavMonth.ts +70 -0
  94. package/src/helpers/getNextFocus.test.tsx +99 -0
  95. package/src/helpers/getNextFocus.tsx +67 -0
  96. package/src/helpers/getNextMonth.test.ts +101 -0
  97. package/src/helpers/getNextMonth.ts +45 -0
  98. package/src/helpers/getPossibleFocusDate.test.ts +144 -0
  99. package/src/helpers/getPreviousMonth.test.ts +77 -0
  100. package/src/helpers/getPreviousMonth.ts +40 -0
  101. package/src/helpers/getStyleForModifiers.test.ts +92 -0
  102. package/src/helpers/getStyleForModifiers.ts +21 -0
  103. package/src/helpers/getWeekdays.test.ts +44 -0
  104. package/src/helpers/getWeekdays.ts +29 -0
  105. package/src/helpers/getWeeks.test.ts +30 -0
  106. package/src/helpers/getWeeks.ts +9 -0
  107. package/src/helpers/getYearOptions.test.ts +46 -0
  108. package/src/helpers/getYearOptions.ts +34 -0
  109. package/src/helpers/index.ts +2 -0
  110. package/src/helpers/startOfBroadcastWeek.test.ts +24 -0
  111. package/src/helpers/startOfBroadcastWeek.ts +19 -0
  112. package/src/helpers/useControlledValue.test.ts +45 -0
  113. package/src/helpers/useControlledValue.ts +33 -0
  114. package/src/index.ts +15 -0
  115. package/src/jalali.tsx +2 -0
  116. package/src/labels/index.ts +12 -0
  117. package/src/labels/labelDayButton.test.ts +41 -0
  118. package/src/labels/labelDayButton.ts +31 -0
  119. package/src/labels/labelGrid.test.ts +7 -0
  120. package/src/labels/labelGrid.ts +23 -0
  121. package/src/labels/labelGridcell.test.ts +7 -0
  122. package/src/labels/labelGridcell.ts +22 -0
  123. package/src/labels/labelMonthDropdown.test.ts +5 -0
  124. package/src/labels/labelMonthDropdown.ts +12 -0
  125. package/src/labels/labelNav.test.ts +5 -0
  126. package/src/labels/labelNav.ts +10 -0
  127. package/src/labels/labelNext.test.ts +5 -0
  128. package/src/labels/labelNext.ts +13 -0
  129. package/src/labels/labelPrevious.test.ts +5 -0
  130. package/src/labels/labelPrevious.ts +13 -0
  131. package/src/labels/labelWeekNumber.test.ts +5 -0
  132. package/src/labels/labelWeekNumber.ts +15 -0
  133. package/src/labels/labelWeekNumberHeader.test.ts +5 -0
  134. package/src/labels/labelWeekNumberHeader.ts +12 -0
  135. package/src/labels/labelWeekday.test.ts +15 -0
  136. package/src/labels/labelWeekday.ts +16 -0
  137. package/src/labels/labelYearDropdown.test.ts +5 -0
  138. package/src/labels/labelYearDropdown.ts +12 -0
  139. package/src/locale.ts +1 -0
  140. package/src/persian.tsx +86 -0
  141. package/src/selection/useMulti.test.tsx +41 -0
  142. package/src/selection/useMulti.tsx +74 -0
  143. package/src/selection/useRange.test.tsx +154 -0
  144. package/src/selection/useRange.tsx +73 -0
  145. package/src/selection/useSingle.test.tsx +38 -0
  146. package/src/selection/useSingle.tsx +69 -0
  147. package/src/types/deprecated.ts +230 -0
  148. package/src/types/index.ts +4 -0
  149. package/src/types/props.test.tsx +71 -0
  150. package/src/types/props.ts +675 -0
  151. package/src/types/selection.ts +57 -0
  152. package/src/types/shared.ts +442 -0
  153. package/src/useAnimation.test.tsx +134 -0
  154. package/src/useAnimation.ts +203 -0
  155. package/src/useCalendar.ts +178 -0
  156. package/src/useDayPicker.test.tsx +142 -0
  157. package/src/useDayPicker.ts +93 -0
  158. package/src/useFocus.ts +87 -0
  159. package/src/useGetModifiers.test.tsx +154 -0
  160. package/src/useGetModifiers.tsx +122 -0
  161. package/src/useSelection.ts +26 -0
  162. package/src/utc.tsx +10 -0
  163. package/src/utils/addToRange.test.ts +117 -0
  164. package/src/utils/addToRange.ts +87 -0
  165. package/src/utils/dateMatchModifiers.test.ts +120 -0
  166. package/src/utils/dateMatchModifiers.ts +88 -0
  167. package/src/utils/index.ts +7 -0
  168. package/src/utils/rangeContainsDayOfWeek.test.ts +48 -0
  169. package/src/utils/rangeContainsDayOfWeek.ts +35 -0
  170. package/src/utils/rangeContainsModifiers.test.ts +230 -0
  171. package/src/utils/rangeContainsModifiers.ts +125 -0
  172. package/src/utils/rangeIncludesDate.test.ts +46 -0
  173. package/src/utils/rangeIncludesDate.ts +43 -0
  174. package/src/utils/rangeOverlaps.test.ts +60 -0
  175. package/src/utils/rangeOverlaps.ts +22 -0
  176. package/src/utils/typeguards.test.ts +83 -0
  177. package/src/utils/typeguards.ts +70 -0
@@ -0,0 +1,629 @@
1
+ import React, { useCallback, useMemo, useRef } from "react";
2
+ import type { MouseEvent, FocusEvent, KeyboardEvent, ChangeEvent } from "react";
3
+
4
+ import { UI, DayFlag, SelectionState } from "./UI.js";
5
+ import type { CalendarDay } from "./classes/CalendarDay.js";
6
+ import { DateLib, defaultLocale } from "./classes/DateLib.js";
7
+ import { getClassNamesForModifiers } from "./helpers/getClassNamesForModifiers.js";
8
+ import { getComponents } from "./helpers/getComponents.js";
9
+ import { getDataAttributes } from "./helpers/getDataAttributes.js";
10
+ import { getDefaultClassNames } from "./helpers/getDefaultClassNames.js";
11
+ import { getFormatters } from "./helpers/getFormatters.js";
12
+ import { getMonthOptions } from "./helpers/getMonthOptions.js";
13
+ import { getStyleForModifiers } from "./helpers/getStyleForModifiers.js";
14
+ import { getWeekdays } from "./helpers/getWeekdays.js";
15
+ import { getYearOptions } from "./helpers/getYearOptions.js";
16
+ import * as defaultLabels from "./labels/index.js";
17
+ import type {
18
+ DayPickerProps,
19
+ Modifiers,
20
+ MoveFocusBy,
21
+ MoveFocusDir,
22
+ SelectedValue,
23
+ SelectHandler
24
+ } from "./types/index.js";
25
+ import { useAnimation } from "./useAnimation.js";
26
+ import { useCalendar } from "./useCalendar.js";
27
+ import { type DayPickerContext, dayPickerContext } from "./useDayPicker.js";
28
+ import { useFocus } from "./useFocus.js";
29
+ import { useGetModifiers } from "./useGetModifiers.js";
30
+ import { useSelection } from "./useSelection.js";
31
+ import { rangeIncludesDate } from "./utils/rangeIncludesDate.js";
32
+ import { isDateRange } from "./utils/typeguards.js";
33
+
34
+ /**
35
+ * Render the date picker calendar.
36
+ *
37
+ * @group DayPicker
38
+ * @see https://daypicker.dev
39
+ */
40
+ export function DayPicker(props: DayPickerProps) {
41
+ const { components, formatters, labels, dateLib, locale, classNames } =
42
+ useMemo(() => {
43
+ const locale = { ...defaultLocale, ...props.locale };
44
+
45
+ const dateLib = new DateLib(
46
+ {
47
+ locale,
48
+ weekStartsOn: props.broadcastCalendar ? 1 : props.weekStartsOn,
49
+ firstWeekContainsDate: props.firstWeekContainsDate,
50
+ useAdditionalWeekYearTokens: props.useAdditionalWeekYearTokens,
51
+ useAdditionalDayOfYearTokens: props.useAdditionalDayOfYearTokens,
52
+ timeZone: props.timeZone,
53
+ numerals: props.numerals
54
+ },
55
+ props.dateLib
56
+ );
57
+
58
+ return {
59
+ dateLib,
60
+ components: getComponents(props.components),
61
+ formatters: getFormatters(props.formatters),
62
+ labels: { ...defaultLabels, ...props.labels },
63
+ locale,
64
+ classNames: { ...getDefaultClassNames(), ...props.classNames }
65
+ };
66
+ }, [
67
+ props.locale,
68
+ props.broadcastCalendar,
69
+ props.weekStartsOn,
70
+ props.firstWeekContainsDate,
71
+ props.useAdditionalWeekYearTokens,
72
+ props.useAdditionalDayOfYearTokens,
73
+ props.timeZone,
74
+ props.numerals,
75
+ props.dateLib,
76
+ props.components,
77
+ props.formatters,
78
+ props.labels,
79
+ props.classNames
80
+ ]);
81
+
82
+ const {
83
+ captionLayout,
84
+ mode,
85
+ onDayBlur,
86
+ onDayClick,
87
+ onDayFocus,
88
+ onDayKeyDown,
89
+ onDayMouseEnter,
90
+ onDayMouseLeave,
91
+ onNextClick,
92
+ onPrevClick,
93
+ showWeekNumber,
94
+ styles
95
+ } = props;
96
+
97
+ const {
98
+ formatCaption,
99
+ formatDay,
100
+ formatMonthDropdown,
101
+ formatWeekNumber,
102
+ formatWeekNumberHeader,
103
+ formatWeekdayName,
104
+ formatYearDropdown
105
+ } = formatters;
106
+
107
+ const calendar = useCalendar(props, dateLib);
108
+
109
+ const {
110
+ days,
111
+ months,
112
+ navStart,
113
+ navEnd,
114
+ previousMonth,
115
+ nextMonth,
116
+ goToMonth
117
+ } = calendar;
118
+
119
+ const getModifiers = useGetModifiers(days, props, dateLib);
120
+
121
+ const {
122
+ isSelected,
123
+ select,
124
+ selected: selectedValue
125
+ } = useSelection(props, dateLib) ?? {};
126
+
127
+ const { blur, focused, isFocusTarget, moveFocus, setFocused } = useFocus(
128
+ props,
129
+ calendar,
130
+ getModifiers,
131
+ isSelected ?? (() => false),
132
+ dateLib
133
+ );
134
+
135
+ const {
136
+ labelDayButton,
137
+ labelGridcell,
138
+ labelGrid,
139
+ labelMonthDropdown,
140
+ labelNav,
141
+ labelWeekday,
142
+ labelWeekNumber,
143
+ labelWeekNumberHeader,
144
+ labelYearDropdown
145
+ } = labels;
146
+
147
+ const weekdays = useMemo(
148
+ () => getWeekdays(dateLib, props.ISOWeek),
149
+ [dateLib, props.ISOWeek]
150
+ );
151
+
152
+ const isInteractive = mode !== undefined || onDayClick !== undefined;
153
+
154
+ const handlePreviousClick = useCallback(() => {
155
+ if (!previousMonth) return;
156
+ goToMonth(previousMonth);
157
+ onPrevClick?.(previousMonth);
158
+ }, [previousMonth, goToMonth, onPrevClick]);
159
+
160
+ const handleNextClick = useCallback(() => {
161
+ if (!nextMonth) return;
162
+ goToMonth(nextMonth);
163
+ onNextClick?.(nextMonth);
164
+ }, [goToMonth, nextMonth, onNextClick]);
165
+
166
+ const handleDayClick = useCallback(
167
+ (day: CalendarDay, m: Modifiers) => (e: MouseEvent) => {
168
+ e.preventDefault();
169
+ e.stopPropagation();
170
+ setFocused(day);
171
+ select?.(day.date, m, e);
172
+ onDayClick?.(day.date, m, e);
173
+ },
174
+ [select, onDayClick, setFocused]
175
+ );
176
+
177
+ const handleDayFocus = useCallback(
178
+ (day: CalendarDay, m: Modifiers) => (e: FocusEvent) => {
179
+ setFocused(day);
180
+ onDayFocus?.(day.date, m, e);
181
+ },
182
+ [onDayFocus, setFocused]
183
+ );
184
+
185
+ const handleDayBlur = useCallback(
186
+ (day: CalendarDay, m: Modifiers) => (e: FocusEvent) => {
187
+ blur();
188
+ onDayBlur?.(day.date, m, e);
189
+ },
190
+ [blur, onDayBlur]
191
+ );
192
+
193
+ const handleDayKeyDown = useCallback(
194
+ (day: CalendarDay, modifiers: Modifiers) => (e: KeyboardEvent) => {
195
+ const keyMap: Record<string, [MoveFocusBy, MoveFocusDir]> = {
196
+ ArrowLeft: ["day", props.dir === "rtl" ? "after" : "before"],
197
+ ArrowRight: ["day", props.dir === "rtl" ? "before" : "after"],
198
+ ArrowDown: ["week", "after"],
199
+ ArrowUp: ["week", "before"],
200
+ PageUp: [e.shiftKey ? "year" : "month", "before"],
201
+ PageDown: [e.shiftKey ? "year" : "month", "after"],
202
+ Home: ["startOfWeek", "before"],
203
+ End: ["endOfWeek", "after"]
204
+ };
205
+ if (keyMap[e.key]) {
206
+ e.preventDefault();
207
+ e.stopPropagation();
208
+ const [moveBy, moveDir] = keyMap[e.key];
209
+ moveFocus(moveBy, moveDir);
210
+ }
211
+ onDayKeyDown?.(day.date, modifiers, e);
212
+ },
213
+ [moveFocus, onDayKeyDown, props.dir]
214
+ );
215
+
216
+ const handleDayMouseEnter = useCallback(
217
+ (day: CalendarDay, modifiers: Modifiers) => (e: MouseEvent) => {
218
+ onDayMouseEnter?.(day.date, modifiers, e);
219
+ },
220
+ [onDayMouseEnter]
221
+ );
222
+
223
+ const handleDayMouseLeave = useCallback(
224
+ (day: CalendarDay, modifiers: Modifiers) => (e: MouseEvent) => {
225
+ onDayMouseLeave?.(day.date, modifiers, e);
226
+ },
227
+ [onDayMouseLeave]
228
+ );
229
+
230
+ const handleMonthChange = useCallback(
231
+ (date: Date) => (e: ChangeEvent<HTMLSelectElement>) => {
232
+ const selectedMonth = Number(e.target.value);
233
+ const month = dateLib.setMonth(dateLib.startOfMonth(date), selectedMonth);
234
+ goToMonth(month);
235
+ },
236
+ [dateLib, goToMonth]
237
+ );
238
+
239
+ const handleYearChange = useCallback(
240
+ (date: Date) => (e: ChangeEvent<HTMLSelectElement>) => {
241
+ const selectedYear = Number(e.target.value);
242
+ const month = dateLib.setYear(dateLib.startOfMonth(date), selectedYear);
243
+ goToMonth(month);
244
+ },
245
+ [dateLib, goToMonth]
246
+ );
247
+
248
+ const { className, style } = useMemo(
249
+ () => ({
250
+ className: [classNames[UI.Root], props.className]
251
+ .filter(Boolean)
252
+ .join(" "),
253
+ style: { ...styles?.[UI.Root], ...props.style }
254
+ }),
255
+ [classNames, props.className, props.style, styles]
256
+ );
257
+
258
+ const dataAttributes = getDataAttributes(props);
259
+
260
+ const rootElRef = useRef<HTMLDivElement>(null);
261
+ useAnimation(rootElRef, Boolean(props.animate), {
262
+ classNames,
263
+ months,
264
+ focused,
265
+ dateLib
266
+ });
267
+
268
+ const contextValue: DayPickerContext<DayPickerProps> = {
269
+ dayPickerProps: props,
270
+ selected: selectedValue as SelectedValue<DayPickerProps>,
271
+ select: select as SelectHandler<DayPickerProps>,
272
+ isSelected,
273
+ months,
274
+ nextMonth,
275
+ previousMonth,
276
+ goToMonth,
277
+ getModifiers,
278
+ components,
279
+ classNames,
280
+ styles,
281
+ labels,
282
+ formatters
283
+ };
284
+
285
+ return (
286
+ <dayPickerContext.Provider value={contextValue}>
287
+ <components.Root
288
+ rootRef={props.animate ? rootElRef : undefined}
289
+ className={className}
290
+ style={style}
291
+ dir={props.dir}
292
+ id={props.id}
293
+ lang={props.lang}
294
+ nonce={props.nonce}
295
+ title={props.title}
296
+ role={props.role}
297
+ aria-label={props["aria-label"]}
298
+ {...dataAttributes}
299
+ >
300
+ <components.Months
301
+ className={classNames[UI.Months]}
302
+ style={styles?.[UI.Months]}
303
+ >
304
+ {!props.hideNavigation && (
305
+ <components.Nav
306
+ className={classNames[UI.Nav]}
307
+ style={styles?.[UI.Nav]}
308
+ aria-label={labelNav()}
309
+ onPreviousClick={handlePreviousClick}
310
+ onNextClick={handleNextClick}
311
+ previousMonth={previousMonth}
312
+ nextMonth={nextMonth}
313
+ />
314
+ )}
315
+ {months.map((calendarMonth, displayIndex) => {
316
+ const dropdownMonths = getMonthOptions(
317
+ calendarMonth.date,
318
+ navStart,
319
+ navEnd,
320
+ formatters,
321
+ dateLib
322
+ );
323
+
324
+ const dropdownYears = getYearOptions(
325
+ navStart,
326
+ navEnd,
327
+ formatters,
328
+ dateLib
329
+ );
330
+ return (
331
+ <components.Month
332
+ data-animated-month={props.animate ? "true" : undefined}
333
+ className={classNames[UI.Month]}
334
+ style={styles?.[UI.Month]}
335
+ key={displayIndex}
336
+ displayIndex={displayIndex}
337
+ calendarMonth={calendarMonth}
338
+ >
339
+ <components.MonthCaption
340
+ data-animated-caption={props.animate ? "true" : undefined}
341
+ className={classNames[UI.MonthCaption]}
342
+ style={styles?.[UI.MonthCaption]}
343
+ calendarMonth={calendarMonth}
344
+ displayIndex={displayIndex}
345
+ >
346
+ {captionLayout?.startsWith("dropdown") ? (
347
+ <components.DropdownNav
348
+ className={classNames[UI.Dropdowns]}
349
+ style={styles?.[UI.Dropdowns]}
350
+ >
351
+ {captionLayout === "dropdown" ||
352
+ captionLayout === "dropdown-months" ? (
353
+ <components.MonthsDropdown
354
+ className={classNames[UI.MonthsDropdown]}
355
+ aria-label={labelMonthDropdown()}
356
+ classNames={classNames}
357
+ components={components}
358
+ disabled={Boolean(props.disableNavigation)}
359
+ onChange={handleMonthChange(calendarMonth.date)}
360
+ options={dropdownMonths}
361
+ style={styles?.[UI.Dropdown]}
362
+ value={dateLib.getMonth(calendarMonth.date)}
363
+ />
364
+ ) : (
365
+ <span>
366
+ {formatMonthDropdown(calendarMonth.date, dateLib)}
367
+ </span>
368
+ )}
369
+ {captionLayout === "dropdown" ||
370
+ captionLayout === "dropdown-years" ? (
371
+ <components.YearsDropdown
372
+ className={classNames[UI.YearsDropdown]}
373
+ aria-label={labelYearDropdown(dateLib.options)}
374
+ classNames={classNames}
375
+ components={components}
376
+ disabled={Boolean(props.disableNavigation)}
377
+ onChange={handleYearChange(calendarMonth.date)}
378
+ options={dropdownYears}
379
+ style={styles?.[UI.Dropdown]}
380
+ value={dateLib.getYear(calendarMonth.date)}
381
+ />
382
+ ) : (
383
+ <span>
384
+ {formatYearDropdown(calendarMonth.date, dateLib)}
385
+ </span>
386
+ )}
387
+ <span
388
+ role="status"
389
+ aria-live="polite"
390
+ style={{
391
+ border: 0,
392
+ clip: "rect(0 0 0 0)",
393
+ height: "1px",
394
+ margin: "-1px",
395
+ overflow: "hidden",
396
+ padding: 0,
397
+ position: "absolute",
398
+ width: "1px",
399
+ whiteSpace: "nowrap",
400
+ wordWrap: "normal"
401
+ }}
402
+ >
403
+ {formatCaption(
404
+ calendarMonth.date,
405
+ dateLib.options,
406
+ dateLib
407
+ )}
408
+ </span>
409
+ </components.DropdownNav>
410
+ ) : (
411
+ <components.CaptionLabel
412
+ className={classNames[UI.CaptionLabel]}
413
+ role="status"
414
+ aria-live="polite"
415
+ >
416
+ {formatCaption(
417
+ calendarMonth.date,
418
+ dateLib.options,
419
+ dateLib
420
+ )}
421
+ </components.CaptionLabel>
422
+ )}
423
+ </components.MonthCaption>
424
+ <components.MonthGrid
425
+ role="grid"
426
+ aria-multiselectable={mode === "multiple" || mode === "range"}
427
+ aria-label={
428
+ labelGrid(calendarMonth.date, dateLib.options, dateLib) ||
429
+ undefined
430
+ }
431
+ className={classNames[UI.MonthGrid]}
432
+ style={styles?.[UI.MonthGrid]}
433
+ >
434
+ {!props.hideWeekdays && (
435
+ <components.Weekdays
436
+ data-animated-weekdays={
437
+ props.animate ? "true" : undefined
438
+ }
439
+ className={classNames[UI.Weekdays]}
440
+ style={styles?.[UI.Weekdays]}
441
+ >
442
+ {showWeekNumber && (
443
+ <components.WeekNumberHeader
444
+ aria-label={labelWeekNumberHeader(dateLib.options)}
445
+ className={classNames[UI.WeekNumberHeader]}
446
+ style={styles?.[UI.WeekNumberHeader]}
447
+ scope="col"
448
+ >
449
+ {formatWeekNumberHeader()}
450
+ </components.WeekNumberHeader>
451
+ )}
452
+ {weekdays.map((weekday, i) => (
453
+ <components.Weekday
454
+ aria-label={labelWeekday(
455
+ weekday,
456
+ dateLib.options,
457
+ dateLib
458
+ )}
459
+ className={classNames[UI.Weekday]}
460
+ key={i}
461
+ style={styles?.[UI.Weekday]}
462
+ scope="col"
463
+ >
464
+ {formatWeekdayName(weekday, dateLib.options, dateLib)}
465
+ </components.Weekday>
466
+ ))}
467
+ </components.Weekdays>
468
+ )}
469
+ <components.Weeks
470
+ data-animated-weeks={props.animate ? "true" : undefined}
471
+ className={classNames[UI.Weeks]}
472
+ style={styles?.[UI.Weeks]}
473
+ >
474
+ {calendarMonth.weeks.map((week, weekIndex) => {
475
+ return (
476
+ <components.Week
477
+ className={classNames[UI.Week]}
478
+ key={week.weekNumber}
479
+ style={styles?.[UI.Week]}
480
+ week={week}
481
+ >
482
+ {showWeekNumber && (
483
+ <components.WeekNumber
484
+ week={week}
485
+ style={styles?.[UI.WeekNumber]}
486
+ aria-label={labelWeekNumber(week.weekNumber, {
487
+ locale
488
+ })}
489
+ className={classNames[UI.WeekNumber]}
490
+ scope="row"
491
+ role="rowheader"
492
+ >
493
+ {formatWeekNumber(week.weekNumber)}
494
+ </components.WeekNumber>
495
+ )}
496
+ {week.days.map((day: CalendarDay) => {
497
+ const { date } = day;
498
+ const modifiers = getModifiers(day);
499
+
500
+ modifiers[DayFlag.focused] =
501
+ !modifiers.hidden &&
502
+ Boolean(focused?.isEqualTo(day));
503
+
504
+ modifiers[SelectionState.selected] =
505
+ isSelected?.(date) || modifiers.selected;
506
+
507
+ if (isDateRange(selectedValue)) {
508
+ // add range modifiers
509
+ const { from, to } = selectedValue;
510
+ modifiers[SelectionState.range_start] = Boolean(
511
+ from && to && dateLib.isSameDay(date, from)
512
+ );
513
+ modifiers[SelectionState.range_end] = Boolean(
514
+ from && to && dateLib.isSameDay(date, to)
515
+ );
516
+ modifiers[SelectionState.range_middle] =
517
+ rangeIncludesDate(
518
+ selectedValue,
519
+ date,
520
+ true,
521
+ dateLib
522
+ );
523
+ }
524
+
525
+ const style = getStyleForModifiers(
526
+ modifiers,
527
+ styles,
528
+ props.modifiersStyles
529
+ );
530
+
531
+ const className = getClassNamesForModifiers(
532
+ modifiers,
533
+ classNames,
534
+ props.modifiersClassNames
535
+ );
536
+
537
+ const ariaLabel =
538
+ !isInteractive && !modifiers.hidden
539
+ ? labelGridcell(
540
+ date,
541
+ modifiers,
542
+ dateLib.options,
543
+ dateLib
544
+ )
545
+ : undefined;
546
+
547
+ return (
548
+ <components.Day
549
+ key={`${dateLib.format(date, "yyyy-MM-dd")}_${dateLib.format(day.displayMonth, "yyyy-MM")}`}
550
+ day={day}
551
+ modifiers={modifiers}
552
+ className={className.join(" ")}
553
+ style={style}
554
+ role="gridcell"
555
+ aria-selected={modifiers.selected || undefined}
556
+ aria-label={ariaLabel}
557
+ data-day={dateLib.format(date, "yyyy-MM-dd")}
558
+ data-month={
559
+ day.outside
560
+ ? dateLib.format(date, "yyyy-MM")
561
+ : undefined
562
+ }
563
+ data-selected={modifiers.selected || undefined}
564
+ data-disabled={modifiers.disabled || undefined}
565
+ data-hidden={modifiers.hidden || undefined}
566
+ data-outside={day.outside || undefined}
567
+ data-focused={modifiers.focused || undefined}
568
+ data-today={modifiers.today || undefined}
569
+ >
570
+ {!modifiers.hidden && isInteractive ? (
571
+ <components.DayButton
572
+ className={classNames[UI.DayButton]}
573
+ style={styles?.[UI.DayButton]}
574
+ type="button"
575
+ day={day}
576
+ modifiers={modifiers}
577
+ disabled={modifiers.disabled || undefined}
578
+ tabIndex={isFocusTarget(day) ? 0 : -1}
579
+ aria-label={labelDayButton(
580
+ date,
581
+ modifiers,
582
+ dateLib.options,
583
+ dateLib
584
+ )}
585
+ onClick={handleDayClick(day, modifiers)}
586
+ onBlur={handleDayBlur(day, modifiers)}
587
+ onFocus={handleDayFocus(day, modifiers)}
588
+ onKeyDown={handleDayKeyDown(day, modifiers)}
589
+ onMouseEnter={handleDayMouseEnter(
590
+ day,
591
+ modifiers
592
+ )}
593
+ onMouseLeave={handleDayMouseLeave(
594
+ day,
595
+ modifiers
596
+ )}
597
+ >
598
+ {formatDay(date, dateLib.options, dateLib)}
599
+ </components.DayButton>
600
+ ) : (
601
+ !modifiers.hidden &&
602
+ formatDay(day.date, dateLib.options, dateLib)
603
+ )}
604
+ </components.Day>
605
+ );
606
+ })}
607
+ </components.Week>
608
+ );
609
+ })}
610
+ </components.Weeks>
611
+ </components.MonthGrid>
612
+ </components.Month>
613
+ );
614
+ })}
615
+ </components.Months>
616
+ {props.footer && (
617
+ <components.Footer
618
+ className={classNames[UI.Footer]}
619
+ style={styles?.[UI.Footer]}
620
+ role="status"
621
+ aria-live="polite"
622
+ >
623
+ {props.footer}
624
+ </components.Footer>
625
+ )}
626
+ </components.Root>
627
+ </dayPickerContext.Provider>
628
+ );
629
+ }