@servicetitan/anvil2 2.0.0 → 2.0.2

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 (139) hide show
  1. package/CHANGELOG.md +120 -68
  2. package/dist/Calendar-BFWJ7Rlq.js +2635 -0
  3. package/dist/Calendar-BFWJ7Rlq.js.map +1 -0
  4. package/dist/{Calendar-D4abBZAq.js → Calendar-BO9QiBJG.js} +2 -2
  5. package/dist/{Calendar-D4abBZAq.js.map → Calendar-BO9QiBJG.js.map} +1 -1
  6. package/dist/Calendar.js +2 -2
  7. package/dist/{Combobox-CeADQxTl.js → Combobox-OUK7p5gp.js} +34 -24
  8. package/dist/Combobox-OUK7p5gp.js.map +1 -0
  9. package/dist/Combobox.js +1 -1
  10. package/dist/{DataTable-CVtDYMKC.js → DataTable-BPJeSvOx.js} +1956 -1324
  11. package/dist/DataTable-BPJeSvOx.js.map +1 -0
  12. package/dist/DataTable.css +82 -80
  13. package/dist/{DateFieldRange-BfdBwpwc.js → DateFieldRange-CanMYRgZ.js} +6 -5
  14. package/dist/{DateFieldRange-BfdBwpwc.js.map → DateFieldRange-CanMYRgZ.js.map} +1 -1
  15. package/dist/DateFieldRange.js +1 -1
  16. package/dist/{DateFieldSingle-CVxnfM5x.js → DateFieldSingle-CShe2aHZ.js} +6 -5
  17. package/dist/{DateFieldSingle-CVxnfM5x.js.map → DateFieldSingle-CShe2aHZ.js.map} +1 -1
  18. package/dist/DateFieldSingle.js +1 -1
  19. package/dist/{DateFieldYearless-CgOOwwTc.js → DateFieldYearless-MBQ233Xa.js} +2 -2
  20. package/dist/{DateFieldYearless-CgOOwwTc.js.map → DateFieldYearless-MBQ233Xa.js.map} +1 -1
  21. package/dist/DateFieldYearless.js +1 -1
  22. package/dist/{DateFieldYearlessRange-D8dQk2WI.js → DateFieldYearlessRange-BBtaFzsE.js} +2 -2
  23. package/dist/{DateFieldYearlessRange-D8dQk2WI.js.map → DateFieldYearlessRange-BBtaFzsE.js.map} +1 -1
  24. package/dist/DateFieldYearlessRange.js +1 -1
  25. package/dist/{ListView-CBmaHOY-.js → ListView-CRDUPrbQ.js} +11 -9
  26. package/dist/ListView-CRDUPrbQ.js.map +1 -0
  27. package/dist/ListView.js +1 -1
  28. package/dist/{Menu-d3w2bIdB.js → Menu-Dh0q__vE.js} +7 -5
  29. package/dist/Menu-Dh0q__vE.js.map +1 -0
  30. package/dist/Menu.js +1 -1
  31. package/dist/{NumberField-r0fRpYa0.js → NumberField-Dmm1YQNn.js} +221 -7
  32. package/dist/NumberField-Dmm1YQNn.js.map +1 -0
  33. package/dist/NumberField.js +1 -1
  34. package/dist/{Page-DR5k0MAR.js → Page-C5nExhiH.js} +117 -13
  35. package/dist/Page-C5nExhiH.js.map +1 -0
  36. package/dist/Page.js +1 -1
  37. package/dist/{Pagination-XPZ5UeBs.js → Pagination-CimQTC7M.js} +3 -3
  38. package/dist/{Pagination-XPZ5UeBs.js.map → Pagination-CimQTC7M.js.map} +1 -1
  39. package/dist/Pagination.css +2 -1
  40. package/dist/Pagination.js +1 -1
  41. package/dist/{Popover-U2Eu7v1Q.js → Popover-CJLSDpgR.js} +9 -8
  42. package/dist/Popover-CJLSDpgR.js.map +1 -0
  43. package/dist/Popover.js +1 -1
  44. package/dist/Table.js +1 -1
  45. package/dist/{TimeField-BX9PovdE.js → TimeField-BeaCSkdZ.js} +3 -3
  46. package/dist/{TimeField-BX9PovdE.js.map → TimeField-BeaCSkdZ.js.map} +1 -1
  47. package/dist/TimeField.js +1 -1
  48. package/dist/{Toolbar-BWqguBF1.js → Toolbar-Cjo7eAhI.js} +8 -8
  49. package/dist/{Toolbar-BWqguBF1.js.map → Toolbar-Cjo7eAhI.js.map} +1 -1
  50. package/dist/Toolbar.js +1 -1
  51. package/dist/{YearlessDateInputWithPicker-uG9QMemw.js → YearlessDateInputWithPicker-BVRZlf9Y.js} +3 -3
  52. package/dist/{YearlessDateInputWithPicker-uG9QMemw.js.map → YearlessDateInputWithPicker-BVRZlf9Y.js.map} +1 -1
  53. package/dist/beta/components/Table/DataTable/DataTable.d.ts +8 -10
  54. package/dist/beta/components/Table/DataTable/DataTable.test-data.d.ts +2 -0
  55. package/dist/beta/components/Table/DataTable/internal/DataTableBody.d.ts +6 -1
  56. package/dist/beta/components/Table/DataTable/internal/DataTableBodyRow.d.ts +9 -0
  57. package/dist/beta/components/Table/DataTable/internal/DataTablePagination.d.ts +1 -1
  58. package/dist/beta/components/Table/DataTable/internal/cells/CellError.d.ts +10 -0
  59. package/dist/beta/components/Table/DataTable/internal/cells/CellFocusContext.d.ts +16 -0
  60. package/dist/beta/components/Table/DataTable/internal/cells/DataTableBodyCell.d.ts +19 -37
  61. package/dist/beta/components/Table/DataTable/internal/cells/DataTableBodyImmutableCell.d.ts +32 -0
  62. package/dist/beta/components/Table/DataTable/internal/cells/DataTableBodyMutableCell.d.ts +33 -0
  63. package/dist/beta/components/Table/DataTable/internal/cells/DataTableFooterCell.d.ts +2 -0
  64. package/dist/beta/components/Table/DataTable/internal/cells/DataTableHeaderCell.d.ts +1 -0
  65. package/dist/beta/components/Table/DataTable/internal/constants.d.ts +13 -0
  66. package/dist/beta/components/Table/DataTable/internal/context/focus/DTFocusContext.d.ts +57 -0
  67. package/dist/beta/components/Table/DataTable/internal/context/focus/DTFocusProvider.d.ts +9 -0
  68. package/dist/beta/components/Table/DataTable/internal/context/focus/useDTFocusDispatchContext.d.ts +11 -0
  69. package/dist/beta/components/Table/DataTable/internal/context/focus/useDTFocusStateContext.d.ts +1 -0
  70. package/dist/beta/components/Table/DataTable/internal/context/hover/DTHoverContext.d.ts +31 -0
  71. package/dist/beta/components/Table/DataTable/internal/context/hover/DTHoverProvider.d.ts +3 -0
  72. package/dist/beta/components/Table/DataTable/internal/context/hover/useDTHoverDispatchContext.d.ts +1 -0
  73. package/dist/beta/components/Table/DataTable/internal/context/hover/useDTHoverStateContext.d.ts +4 -0
  74. package/dist/beta/components/Table/DataTable/internal/editable-cells/DataTableEditableMultiselectCell.d.ts +19 -23
  75. package/dist/beta/components/Table/DataTable/internal/editable-cells/DataTableEditableSelectCell.d.ts +6 -25
  76. package/dist/beta/components/Table/DataTable/internal/editable-cells/DataTableEditableTextCell.d.ts +7 -17
  77. package/dist/beta/components/Table/DataTable/internal/editable-cells/types.d.ts +29 -37
  78. package/dist/beta/components/Table/DataTable/internal/util/cellPositionHelpers.d.ts +6 -0
  79. package/dist/beta/components/Table/DataTable/internal/util/cellTypeHelpers.d.ts +42 -0
  80. package/dist/beta/components/Table/{internal → DataTable/internal/util}/getTanStackColumnDef.d.ts +14 -6
  81. package/dist/beta/components/Table/DataTable/stories/DataTable.story-data.d.ts +4 -2
  82. package/dist/beta/components/Table/DataTable/types.d.ts +21 -0
  83. package/dist/beta/components/Table/base/TableContainer.d.ts +3 -14
  84. package/dist/beta/components/Table/createColumnHelper.d.ts +119 -13
  85. package/dist/beta/components/Table/formatters/booleanFormatter.d.ts +22 -0
  86. package/dist/beta/components/Table/formatters/currencyFormatter.d.ts +2 -2
  87. package/dist/beta/components/Table/formatters/dateFormatter.d.ts +34 -0
  88. package/dist/beta/components/Table/formatters/dateTimeFormatter.d.ts +66 -0
  89. package/dist/beta/components/Table/formatters/index.d.ts +7 -0
  90. package/dist/beta/components/Table/formatters/numberFormatter.d.ts +42 -0
  91. package/dist/beta/components/Table/formatters/percentFormatter.d.ts +1 -1
  92. package/dist/beta/components/Table/formatters/presets.d.ts +16 -0
  93. package/dist/beta/components/Table/formatters/timeFormatter.d.ts +28 -0
  94. package/dist/beta/components/Table/formatters/yearlessDateFormatter.d.ts +32 -0
  95. package/dist/beta/components/Table/internal/ResizeHandle.d.ts +2 -1
  96. package/dist/beta/components/Table/internal/getCommonPinningStyles.d.ts +1 -0
  97. package/dist/beta/components/Table/internal/scrollCellIntoView.d.ts +13 -0
  98. package/dist/beta/components/Table/internal/types.d.ts +13 -0
  99. package/dist/beta/components/Table/types.d.ts +52 -8
  100. package/dist/beta.js +4 -4
  101. package/dist/components/DateFieldRange/internal/MaskedDateRangeInput.d.ts +1 -1
  102. package/dist/components/DateFieldSingle/internal/MaskedDateInput.d.ts +1 -1
  103. package/dist/components/Page/Page.d.ts +9 -2
  104. package/dist/components/Page/PageHeader.d.ts +13 -4
  105. package/dist/components/Popover/internal/PopoverContext.d.ts +0 -1
  106. package/dist/components/Popover/internal/usePopoverContext.d.ts +0 -1
  107. package/dist/components/SearchField/SearchField.d.ts +1 -1
  108. package/dist/edit-DQOiktcu.js +6 -0
  109. package/dist/edit-DQOiktcu.js.map +1 -0
  110. package/dist/{index.esm-C2ZhC_8d.js → index.esm-BMOZFPwN.js} +2 -2
  111. package/dist/{index.esm-C2ZhC_8d.js.map → index.esm-BMOZFPwN.js.map} +1 -1
  112. package/dist/index.js +13 -13
  113. package/dist/internal/hooks/useNumberField/internal/createNumberMaskOptions.d.ts +10 -0
  114. package/dist/internal/hooks/useNumberField/internal/createTrailingDecimalHandlers.d.ts +13 -0
  115. package/dist/internal/hooks/useNumberField/internal/createTrailingZerosHandlers.d.ts +16 -0
  116. package/dist/internal/hooks/useNumberField/internal/numberMaskUtils.d.ts +9 -0
  117. package/dist/{Calendar-BEwWBsCE.js → luxon-wpz4A-OQ.js} +3 -2635
  118. package/dist/luxon-wpz4A-OQ.js.map +1 -0
  119. package/dist/{utils-CcMJa47q.js → utils-Cj6v6CZ-.js} +2 -2
  120. package/dist/{utils-CcMJa47q.js.map → utils-Cj6v6CZ-.js.map} +1 -1
  121. package/package.json +1 -1
  122. package/dist/Calendar-BEwWBsCE.js.map +0 -1
  123. package/dist/Combobox-CeADQxTl.js.map +0 -1
  124. package/dist/DataTable-CVtDYMKC.js.map +0 -1
  125. package/dist/ListView-CBmaHOY-.js.map +0 -1
  126. package/dist/Menu-d3w2bIdB.js.map +0 -1
  127. package/dist/NumberField-r0fRpYa0.js.map +0 -1
  128. package/dist/Page-DR5k0MAR.js.map +0 -1
  129. package/dist/Popover-U2Eu7v1Q.js.map +0 -1
  130. package/dist/beta/components/Table/DataTable/internal/DataTableContainer.d.ts +0 -7
  131. package/dist/beta/components/Table/DataTable/internal/DataTableContext.d.ts +0 -25
  132. package/dist/beta/components/Table/DataTable/internal/DataTableContextProvider.d.ts +0 -28
  133. package/dist/beta/components/Table/DataTable/internal/editable-cells/useEditCell.d.ts +0 -11
  134. package/dist/beta/components/Table/DataTable/internal/useDataTableContext.d.ts +0 -4
  135. package/dist/beta/components/Table/internal/focus-management/types.d.ts +0 -34
  136. package/dist/beta/components/Table/internal/focus-management/useFocusManagement.d.ts +0 -27
  137. package/dist/beta/components/Table/internal/focus-management/useHandleKeyDown.d.ts +0 -36
  138. package/dist/beta/components/Table/internal/focus-management/useScrollIntoView.d.ts +0 -9
  139. /package/dist/beta/components/Table/{internal/focus-management → DataTable/internal}/useColumnOrder.d.ts +0 -0
@@ -0,0 +1,2635 @@
1
+ import { jsx, jsxs, Fragment } from 'react/jsx-runtime';
2
+ import { D as DateTime, I as Info } from './luxon-wpz4A-OQ.js';
3
+ import * as React from 'react';
4
+ import { createContext, useContext, forwardRef, useState, useEffect, useRef, useCallback, useMemo, useId } from 'react';
5
+ import { B as Button } from './Button-B__Q1BA5.js';
6
+ import { S as SvgKeyboardArrowDown } from './keyboard_arrow_down-C8WQ38p1.js';
7
+ import { S as SvgKeyboardArrowUp } from './keyboard_arrow_up-CxzK6LAl.js';
8
+ import { S as SvgKeyboardArrowLeft, a as SvgKeyboardArrowRight } from './keyboard_arrow_right-DZWNVytH.js';
9
+ import { c as cx } from './index-SvGbrGuT.js';
10
+ import { S as SrOnly } from './SrOnly-CrdBTl6E.js';
11
+ import { u as useSwipe } from './useSwipe-Cp-CJxLU.js';
12
+ import { G as Grid } from './Grid-BUmKiLhz.js';
13
+ import { S as SelectCard } from './SelectCard-B9RLpwtX.js';
14
+ import { u as useMergeRefs } from './useMergeRefs-Dfmtq9cI.js';
15
+ import { flushSync } from 'react-dom';
16
+ import { u as useOptionallyControlledState } from './useOptionallyControlledState-DbDuos5L.js';
17
+ import { u as usePrevious } from './usePrevious-Bvq-5auG.js';
18
+ import { u as useLayoutPropsUtil } from './useLayoutPropsUtil-BlIWftBb.js';
19
+
20
+ import './Calendar.css';const CalendarContext = createContext(null);
21
+ function useCalendar() {
22
+ const context = useContext(CalendarContext);
23
+ if (!context) {
24
+ throw new Error("useCalendar must be used within a <Calendar>");
25
+ }
26
+ return context;
27
+ }
28
+
29
+ const isSameDay = (d1, d2) => {
30
+ if (!d1 || !d2) return void 0;
31
+ try {
32
+ if (d1.hasSame(d2, "month") && d1.hasSame(d2, "year") && d1.hasSame(d2, "day")) {
33
+ return true;
34
+ }
35
+ return false;
36
+ } catch {
37
+ return false;
38
+ }
39
+ };
40
+ const isSameMonth = (d1, d2) => {
41
+ if (!d1 || !d2) return void 0;
42
+ if (d1.hasSame(d2, "month") && d1.hasSame(d2, "year")) return true;
43
+ return false;
44
+ };
45
+ const isUnavailableDate = (n, unavailable, timeZone) => {
46
+ const tmpSet = /* @__PURE__ */ new Set();
47
+ unavailable.dates?.forEach((date) => {
48
+ tmpSet.add(toDateString(DateTime.fromISO(date, { zone: timeZone })));
49
+ });
50
+ if (unavailable.daysOfWeek?.has(n.weekday)) {
51
+ return true;
52
+ }
53
+ const dateISO = n.toISO();
54
+ if (!dateISO) return;
55
+ return tmpSet.has(
56
+ toDateString(DateTime.fromISO(dateISO, { zone: timeZone }))
57
+ );
58
+ };
59
+ const isBeyondMinDate = (n, minDate) => minDate && minDate.toMillis() > n.toMillis();
60
+ const isBeyondMaxDate = (n, maxDate) => maxDate && maxDate.toMillis() < n.toMillis();
61
+ const normalizeDate = (date, defaultTimeZone) => {
62
+ return DateTime.fromISO(date, { zone: defaultTimeZone }).startOf("day");
63
+ };
64
+ const toDateString = (date) => date.startOf("day").toISO();
65
+ function rangeUpdater(value, newDate, setValue, onSelection) {
66
+ if (value.start && isSameDay(value.start, newDate) && !value.end) {
67
+ setValue((prev) => {
68
+ return { ...prev, end: newDate };
69
+ });
70
+ onSelection?.({
71
+ value: {
72
+ start: toDateString(value.start) ?? void 0,
73
+ end: toDateString(newDate) ?? void 0
74
+ }
75
+ });
76
+ return;
77
+ }
78
+ if (!value.start && !value.end || value.start && value.end || value.start && !value.end && value.start.startOf("day").toMillis() > newDate.startOf("day").toMillis()) {
79
+ setValue({ start: newDate, end: null });
80
+ onSelection?.({
81
+ value: {
82
+ start: toDateString(newDate) ?? void 0,
83
+ end: void 0
84
+ }
85
+ });
86
+ return;
87
+ }
88
+ if (value.start && !value.end && value.start.startOf("day").toMillis() < newDate.startOf("day").toMillis()) {
89
+ setValue((prev) => {
90
+ return { ...prev, end: newDate };
91
+ });
92
+ onSelection?.({
93
+ value: {
94
+ start: toDateString(value.start) ?? void 0,
95
+ end: toDateString(newDate) ?? void 0
96
+ }
97
+ });
98
+ return;
99
+ }
100
+ if (!value.start && value.end) {
101
+ setValue((prev) => {
102
+ return { ...prev, start: newDate };
103
+ });
104
+ onSelection?.({
105
+ value: {
106
+ start: toDateString(newDate) ?? void 0,
107
+ end: toDateString(value.end) ?? void 0
108
+ }
109
+ });
110
+ return;
111
+ }
112
+ }
113
+ const getDateMetadata = (date, dateMetadata) => {
114
+ if (!dateMetadata) return void 0;
115
+ const dateString = date.toISODate();
116
+ return dateString ? dateMetadata.get(dateString) : void 0;
117
+ };
118
+
119
+ const CalendarNow = forwardRef(
120
+ (props, ref) => {
121
+ const { onClick, onClickFixed, ...rest } = props;
122
+ const {
123
+ setFocusedDate,
124
+ setSelectedMonth,
125
+ setSelectedYear,
126
+ value,
127
+ setValue,
128
+ defaultTimeZone,
129
+ unavailable,
130
+ onSelection,
131
+ minDate,
132
+ maxDate,
133
+ controlled,
134
+ range
135
+ } = useCalendar();
136
+ const nToday = DateTime.fromISO(DateTime.now().toISO(), {
137
+ zone: defaultTimeZone
138
+ }).startOf("day");
139
+ const onClickHandler = (e) => {
140
+ onClickFixed?.(e);
141
+ setFocusedDate(nToday);
142
+ setSelectedMonth(nToday.month);
143
+ setSelectedYear(nToday.year);
144
+ if (!range) {
145
+ onSelection?.({
146
+ value: toDateString(nToday) ?? void 0
147
+ });
148
+ if (!controlled) {
149
+ setValue(nToday);
150
+ }
151
+ return;
152
+ }
153
+ rangeUpdater(value, nToday, setValue, onSelection);
154
+ };
155
+ const isDisabled = isBeyondMaxDate(nToday, maxDate) || isBeyondMinDate(nToday, minDate) || isUnavailableDate(nToday, unavailable, defaultTimeZone);
156
+ return /* @__PURE__ */ jsx(
157
+ Button,
158
+ {
159
+ ref,
160
+ onClick: onClickHandler,
161
+ appearance: "ghost",
162
+ disabled: isDisabled,
163
+ "data-anv": "calendar-now",
164
+ size: "small",
165
+ ...rest,
166
+ children: "Today"
167
+ }
168
+ );
169
+ }
170
+ );
171
+ CalendarNow.displayName = "CalendarNowButton";
172
+
173
+ const CalendarYearButton = forwardRef((props, ref) => {
174
+ const { calendarSelectionState, ...rest } = props;
175
+ const { selectedYear, locale } = useCalendar();
176
+ const currentYear = DateTime.fromObject({ year: selectedYear }).setLocale(locale).toLocaleString({ year: "numeric" });
177
+ return /* @__PURE__ */ jsx(
178
+ Button,
179
+ {
180
+ ref,
181
+ appearance: "ghost",
182
+ size: "small",
183
+ icon: {
184
+ after: calendarSelectionState === "year" ? SvgKeyboardArrowUp : SvgKeyboardArrowDown
185
+ },
186
+ ...rest,
187
+ children: currentYear
188
+ }
189
+ );
190
+ });
191
+ CalendarYearButton.displayName = "CalendarYearButton";
192
+
193
+ const calendar = "_calendar_50kmd_2";
194
+ const header = "_header_50kmd_15";
195
+ const controller = "_controller_50kmd_46";
196
+ const spacer = "_spacer_50kmd_54";
197
+ const cell = "_cell_50kmd_67";
198
+ const overflow = "_overflow_50kmd_98";
199
+ const weekday = "_weekday_50kmd_104";
200
+ const range = "_range_50kmd_149";
201
+ const selected = "_selected_50kmd_159";
202
+ const pip = "_pip_50kmd_233";
203
+ const styles$1 = {
204
+ calendar: calendar,
205
+ header: header,
206
+ controller: controller,
207
+ spacer: spacer,
208
+ "day-grid": "_day-grid_50kmd_57",
209
+ cell: cell,
210
+ overflow: overflow,
211
+ weekday: weekday,
212
+ "month-selection": "_month-selection_50kmd_116",
213
+ "selection-checkbox": "_selection-checkbox_50kmd_116",
214
+ "selection-card": "_selection-card_50kmd_126",
215
+ "range-first": "_range-first_50kmd_149",
216
+ "range-last": "_range-last_50kmd_149",
217
+ range: range,
218
+ selected: selected,
219
+ "is-unavailable": "_is-unavailable_50kmd_167",
220
+ "hover-last": "_hover-last_50kmd_225",
221
+ "has-metadata": "_has-metadata_50kmd_229",
222
+ pip: pip,
223
+ "range-fill": "_range-fill_50kmd_245",
224
+ "range-disabled": "_range-disabled_50kmd_255",
225
+ "controller-button": "_controller-button_50kmd_263",
226
+ "year-selector": "_year-selector_50kmd_271"
227
+ };
228
+
229
+ const CalendarPrev = forwardRef(
230
+ (props, ref) => {
231
+ const { onClick, className, ...rest } = props;
232
+ const {
233
+ focusedDate,
234
+ setFocusedDate,
235
+ minDate,
236
+ setSelectedMonth,
237
+ setSelectedYear
238
+ } = useCalendar();
239
+ const [disabled, setDisabled] = useState(false);
240
+ useEffect(() => {
241
+ setDisabled(
242
+ minDate != null && focusedDate.minus({ month: 1 }).endOf("month") < minDate
243
+ );
244
+ }, [minDate, focusedDate]);
245
+ const onClickHandler = (e) => {
246
+ onClick?.(e);
247
+ const targetMonth = focusedDate.minus({ month: 1 }).endOf("month");
248
+ const targetDate = focusedDate.minus({ month: 1 });
249
+ const isCrossingYearBoundary = focusedDate.month === 1 && targetDate.month === 12;
250
+ if (minDate !== null) {
251
+ if (targetDate.toMillis() >= minDate?.toMillis()) {
252
+ setFocusedDate(targetDate);
253
+ setSelectedMonth(targetDate.month);
254
+ if (isCrossingYearBoundary) {
255
+ setSelectedYear(targetDate.year);
256
+ }
257
+ return;
258
+ }
259
+ if (!isSameMonth(targetMonth, focusedDate)) {
260
+ setFocusedDate(minDate);
261
+ setSelectedMonth(minDate.month);
262
+ if (isCrossingYearBoundary) {
263
+ setSelectedYear(minDate.year);
264
+ }
265
+ }
266
+ return;
267
+ }
268
+ setFocusedDate(targetDate);
269
+ setSelectedMonth(targetDate.month);
270
+ if (isCrossingYearBoundary) {
271
+ setSelectedYear(targetDate.year);
272
+ }
273
+ };
274
+ return /* @__PURE__ */ jsx(
275
+ Button,
276
+ {
277
+ ref,
278
+ onClick: onClickHandler,
279
+ className: cx(styles$1["controller-button"], className),
280
+ appearance: "ghost",
281
+ size: "small",
282
+ icon: SvgKeyboardArrowLeft,
283
+ "data-anv": "calendar-prev",
284
+ "aria-label": "Previous Month",
285
+ ...rest,
286
+ disabled
287
+ }
288
+ );
289
+ }
290
+ );
291
+ CalendarPrev.displayName = "CalendarPrevButton";
292
+
293
+ const CalendarNext = forwardRef(
294
+ (props, ref) => {
295
+ const { onClick, className, ...rest } = props;
296
+ const {
297
+ focusedDate,
298
+ setFocusedDate,
299
+ maxDate,
300
+ setSelectedMonth,
301
+ setSelectedYear
302
+ } = useCalendar();
303
+ const [disabled, setDisabled] = useState(false);
304
+ useEffect(() => {
305
+ setDisabled(
306
+ maxDate != null && focusedDate.plus({ month: 1 }).startOf("month") > maxDate
307
+ );
308
+ }, [maxDate, focusedDate]);
309
+ const onClickHandler = (e) => {
310
+ onClick?.(e);
311
+ const targetMonth = focusedDate.plus({ month: 1 }).startOf("month");
312
+ const targetDate = focusedDate.plus({ month: 1 });
313
+ const isCrossingYearBoundary = focusedDate.month === 12 && targetDate.month === 1;
314
+ if (maxDate !== null) {
315
+ if (targetDate.toMillis() <= maxDate?.toMillis()) {
316
+ setFocusedDate(targetDate);
317
+ setSelectedMonth(targetDate.month);
318
+ if (isCrossingYearBoundary) {
319
+ setSelectedYear(targetDate.year);
320
+ }
321
+ return;
322
+ }
323
+ if (!isSameMonth(targetMonth, focusedDate)) {
324
+ setFocusedDate(maxDate);
325
+ setSelectedMonth(maxDate.month);
326
+ if (isCrossingYearBoundary) {
327
+ setSelectedYear(maxDate.year);
328
+ }
329
+ }
330
+ return;
331
+ }
332
+ setFocusedDate(targetDate);
333
+ setSelectedMonth(targetDate.month);
334
+ if (isCrossingYearBoundary) {
335
+ setSelectedYear(targetDate.year);
336
+ }
337
+ };
338
+ return /* @__PURE__ */ jsx(
339
+ Button,
340
+ {
341
+ onClick: onClickHandler,
342
+ appearance: "ghost",
343
+ size: "small",
344
+ className: cx(styles$1["controller-button"], className),
345
+ icon: SvgKeyboardArrowRight,
346
+ "aria-label": "Next Month",
347
+ "data-anv": "calendar-next",
348
+ ref,
349
+ ...rest,
350
+ disabled
351
+ }
352
+ );
353
+ }
354
+ );
355
+ CalendarNext.displayName = "CalendarNextButton";
356
+
357
+ const CalendarMonthButton = forwardRef((props, ref) => {
358
+ const { calendarSelectionState, onClick, ...rest } = props;
359
+ const { selectedMonth, locale } = useCalendar();
360
+ const currentMonth = DateTime.fromObject({ month: selectedMonth }).setLocale(locale).toFormat("MMM");
361
+ return /* @__PURE__ */ jsx(
362
+ Button,
363
+ {
364
+ ref,
365
+ appearance: "ghost",
366
+ size: "small",
367
+ onClick,
368
+ icon: {
369
+ after: calendarSelectionState === "month" ? SvgKeyboardArrowUp : SvgKeyboardArrowDown
370
+ },
371
+ ...rest,
372
+ children: currentMonth
373
+ }
374
+ );
375
+ });
376
+ CalendarMonthButton.displayName = "CalendarMonthButton";
377
+
378
+ const CalendarDay = forwardRef(
379
+ (props, ref) => {
380
+ const { className, date, ...rest } = props;
381
+ const context = useCalendar();
382
+ const {
383
+ disableAutofocus,
384
+ value,
385
+ setValue,
386
+ focusedDate,
387
+ setFocusedDate,
388
+ hoveredDate,
389
+ setHoveredDate,
390
+ onSelection,
391
+ locale,
392
+ minDate,
393
+ maxDate,
394
+ unavailable,
395
+ defaultTimeZone,
396
+ controlled,
397
+ id: uid,
398
+ range,
399
+ dateFormat,
400
+ startDay,
401
+ setSelectedMonth,
402
+ setSelectedYear,
403
+ dateMetadata
404
+ } = context;
405
+ const initialized = useRef(false);
406
+ const futureDateSelection = useCallback(
407
+ (targetDate) => {
408
+ if (maxDate !== null && targetDate.toMillis() > maxDate?.toMillis()) {
409
+ return;
410
+ }
411
+ if (isUnavailableDate(targetDate, unavailable, defaultTimeZone)) {
412
+ let nextFocusDate = targetDate.plus({ days: 1 });
413
+ for (let i = 0; i < 365; i++) {
414
+ if (maxDate !== null && nextFocusDate.toMillis() > maxDate?.toMillis()) {
415
+ break;
416
+ }
417
+ if (isUnavailableDate(nextFocusDate, unavailable, defaultTimeZone)) {
418
+ nextFocusDate = nextFocusDate.plus({ days: 1 });
419
+ } else {
420
+ setFocusedDate(nextFocusDate);
421
+ break;
422
+ }
423
+ }
424
+ return;
425
+ }
426
+ setFocusedDate(targetDate);
427
+ if (targetDate.month !== focusedDate.month) {
428
+ setSelectedMonth(targetDate.month);
429
+ if (targetDate.year !== focusedDate.year) {
430
+ setSelectedYear(targetDate.year);
431
+ }
432
+ }
433
+ },
434
+ // eslint-disable-next-line react-hooks/exhaustive-deps -- we don't need to re-render when the selected month or year changes
435
+ [maxDate, setFocusedDate, defaultTimeZone, unavailable]
436
+ );
437
+ const pastDateSelection = (targetDate) => {
438
+ if (minDate !== null && targetDate.toMillis() < minDate?.toMillis()) {
439
+ return;
440
+ }
441
+ if (isUnavailableDate(targetDate, unavailable, defaultTimeZone)) {
442
+ let prevFocusDate = targetDate.minus({ days: 1 });
443
+ for (let i = 0; i < 365; i++) {
444
+ if (minDate !== null && prevFocusDate.toMillis() < minDate?.toMillis()) {
445
+ break;
446
+ }
447
+ if (isUnavailableDate(prevFocusDate, unavailable, defaultTimeZone)) {
448
+ prevFocusDate = prevFocusDate.minus({ days: 1 });
449
+ } else {
450
+ setFocusedDate(prevFocusDate);
451
+ break;
452
+ }
453
+ }
454
+ return;
455
+ }
456
+ setFocusedDate(targetDate);
457
+ if (targetDate.month !== focusedDate.month) {
458
+ setSelectedMonth(targetDate.month);
459
+ if (targetDate.year !== focusedDate.year) {
460
+ setSelectedYear(targetDate.year);
461
+ }
462
+ }
463
+ };
464
+ const isSelectedDate = (date2, compareDate) => {
465
+ if (!range) {
466
+ return isSameDay(date2, value);
467
+ }
468
+ if (value.start && value.end) {
469
+ return date2.toMillis() >= value.start.startOf("day").toMillis() && date2.toMillis() <= value.end.endOf("day").toMillis();
470
+ }
471
+ return isSameDay(date2, value.start);
472
+ };
473
+ const isRange = (date2) => {
474
+ if (!range) {
475
+ return false;
476
+ }
477
+ if (value.start && value.end) {
478
+ return date2.toMillis() >= value.start.startOf("day").toMillis() && date2.toMillis() <= value.end.endOf("day").toMillis() && !isSameDay(value.start, date2) && !isSameDay(value.end, date2);
479
+ }
480
+ return false;
481
+ };
482
+ const onKeyDownHandler = (e) => {
483
+ switch (e.code) {
484
+ case "Space":
485
+ case "Enter":
486
+ e.preventDefault();
487
+ if (!range) {
488
+ if (!controlled) {
489
+ setValue(isSameDay(value, focusedDate) ? null : focusedDate);
490
+ }
491
+ onSelection?.({
492
+ value: isSameDay(value, focusedDate) ? void 0 : focusedDate.setZone(defaultTimeZone).startOf("day").toISO() ?? void 0
493
+ });
494
+ break;
495
+ }
496
+ rangeUpdater(value, focusedDate, setValue, onSelection);
497
+ break;
498
+ case "ArrowLeft":
499
+ e.preventDefault();
500
+ pastDateSelection(focusedDate.minus({ days: 1 }));
501
+ break;
502
+ case "ArrowRight":
503
+ e.preventDefault();
504
+ futureDateSelection(focusedDate.plus({ days: 1 }));
505
+ break;
506
+ case "ArrowUp":
507
+ e.preventDefault();
508
+ pastDateSelection(focusedDate.minus({ days: 7 }));
509
+ break;
510
+ case "ArrowDown":
511
+ e.preventDefault();
512
+ futureDateSelection(focusedDate.plus({ days: 7 }));
513
+ break;
514
+ case "PageUp":
515
+ e.preventDefault();
516
+ if (e.shiftKey) {
517
+ pastDateSelection(focusedDate.minus({ years: 1 }));
518
+ break;
519
+ }
520
+ pastDateSelection(focusedDate.minus({ months: 1 }));
521
+ break;
522
+ case "PageDown":
523
+ e.preventDefault();
524
+ if (e.shiftKey) {
525
+ futureDateSelection(focusedDate.plus({ years: 1 }));
526
+ break;
527
+ }
528
+ futureDateSelection(focusedDate.plus({ months: 1 }));
529
+ break;
530
+ }
531
+ };
532
+ let startDayIndex = 6;
533
+ switch (startDay) {
534
+ case "Monday":
535
+ startDayIndex = 0;
536
+ break;
537
+ case "Sunday":
538
+ default:
539
+ startDayIndex = 6;
540
+ }
541
+ const weekdaysArr = [];
542
+ for (let i = 0; i < 7; i++) {
543
+ const dayIndex = (startDayIndex + i) % 7;
544
+ weekdaysArr.push(Info.weekdays("narrow", { locale })[dayIndex]);
545
+ }
546
+ const firstDay = focusedDate.startOf("month");
547
+ if (firstDay.weekday !== startDayIndex + 1) {
548
+ for (let i = 1; i < 8; i++) {
549
+ const prevDay = firstDay.minus({ days: i });
550
+ if (prevDay.weekday === startDayIndex + 1) break;
551
+ }
552
+ }
553
+ const onClickHandler = (d) => {
554
+ setFocusedDate(d);
555
+ if (!range) {
556
+ onSelection?.({
557
+ value: toDateString(d.setZone(defaultTimeZone)) ?? void 0
558
+ });
559
+ if (!controlled) {
560
+ setValue(d);
561
+ }
562
+ return;
563
+ }
564
+ rangeUpdater(value, d, setValue, onSelection);
565
+ };
566
+ const onFocusHandler = (d) => {
567
+ setHoveredDate(d);
568
+ };
569
+ const onBlurHandler = () => {
570
+ setHoveredDate(void 0);
571
+ };
572
+ const onMouseEnterHandler = (d) => {
573
+ setHoveredDate(d);
574
+ };
575
+ useEffect(() => {
576
+ if (!initialized.current) {
577
+ initialized.current = true;
578
+ return;
579
+ }
580
+ if (!disableAutofocus) {
581
+ requestAnimationFrame(() => {
582
+ const targetElement = document.getElementById(`${uid}-${focusedDate.toISODate()}`) || document.activeElement?.shadowRoot?.getElementById(
583
+ `${uid}-${focusedDate.toISODate()}`
584
+ );
585
+ targetElement?.focus();
586
+ });
587
+ }
588
+ }, [focusedDate, uid, disableAutofocus]);
589
+ useEffect(() => {
590
+ if (!isUnavailableDate(focusedDate, unavailable, defaultTimeZone)) return;
591
+ futureDateSelection(focusedDate.plus({ days: 1 }));
592
+ }, [focusedDate, futureDateSelection, defaultTimeZone, unavailable]);
593
+ const isDisabled = !isSameMonth(date, focusedDate) || isBeyondMinDate(date, minDate) || isBeyondMaxDate(date, maxDate) || isUnavailableDate(date, unavailable, defaultTimeZone);
594
+ const isUnavailable = isUnavailableDate(date, unavailable, defaultTimeZone);
595
+ const hasMetadata = getDateMetadata(date, dateMetadata);
596
+ const hoverRange = range && hoveredDate && value.start && !value.end && date.toMillis() > value.start.toMillis() && date.toMillis() <= hoveredDate.toMillis();
597
+ const cellCx = cx(styles$1["cell"], {
598
+ [styles$1["selected"]]: !isUnavailable && isSelectedDate(date),
599
+ [styles$1["range-first"]]: range && value.start && (value.end || hoveredDate) && isSameDay(date, value.start),
600
+ [styles$1["range-last"]]: range && (value.start && value.end && isSameDay(date, value.end) || hoverRange && isSameDay(date, hoveredDate)),
601
+ [styles$1["range"]]: isRange(date) || hoverRange,
602
+ [styles$1["is-unavailable"]]: isUnavailable,
603
+ [styles$1["overflow"]]: !isSameMonth(date, focusedDate),
604
+ [styles$1["hover-last"]]: hoverRange && isSameDay(date, hoveredDate),
605
+ [styles$1["has-metadata"]]: hasMetadata
606
+ });
607
+ const isMinDate = minDate !== null && date.toMillis() <= minDate?.toMillis();
608
+ const isMaxDate = maxDate !== null && date.toMillis() >= maxDate?.toMillis();
609
+ return /* @__PURE__ */ jsxs("td", { role: "gridcell", ...rest, ref, children: [
610
+ !isUnavailable && (isRange(date) || hoverRange) ? /* @__PURE__ */ jsx(
611
+ "div",
612
+ {
613
+ role: "presentation",
614
+ className: cx(styles$1["range-fill"], {
615
+ [styles$1["range-disabled"]]: isDisabled,
616
+ [styles$1["hover-last"]]: hoverRange && isSameDay(date, hoveredDate)
617
+ })
618
+ }
619
+ ) : null,
620
+ /* @__PURE__ */ jsxs(
621
+ "button",
622
+ {
623
+ onClick: () => onClickHandler(date),
624
+ onFocus: () => onFocusHandler(date),
625
+ onBlur: () => onBlurHandler(),
626
+ className: cellCx,
627
+ onKeyDown: onKeyDownHandler,
628
+ onMouseEnter: () => onMouseEnterHandler(date),
629
+ tabIndex: disableAutofocus ? -1 : isSameDay(date, focusedDate) ? 0 : -1,
630
+ disabled: isDisabled ? true : void 0,
631
+ "aria-label": `${date.toLocaleString(dateFormat)}${isSelectedDate(date) ? " selected" : ""}${hasMetadata ? `, ${hasMetadata}` : ""}${isMinDate ? ", You are on the first available date" : ""}${isMaxDate ? ", You are on the last available date" : ""}`,
632
+ id: `${uid}-${date.toISODate()}`,
633
+ children: [
634
+ date.day,
635
+ hasMetadata && /* @__PURE__ */ jsx("span", { className: styles$1["pip"], "aria-hidden": "true" })
636
+ ]
637
+ }
638
+ )
639
+ ] }, date.toISODate());
640
+ }
641
+ );
642
+ CalendarDay.displayName = "CalendarDay";
643
+
644
+ const CalendarWeek = forwardRef(
645
+ (props, ref) => {
646
+ const { className, week, ...rest } = props;
647
+ const context = useCalendar();
648
+ const {
649
+ focusedDate,
650
+ setFocusedDate,
651
+ locale,
652
+ maxDate,
653
+ unavailable,
654
+ defaultTimeZone,
655
+ id: uid,
656
+ startDay
657
+ } = context;
658
+ const initialized = useRef(false);
659
+ const futureDateSelection = useCallback(
660
+ (targetDate) => {
661
+ if (maxDate !== null && targetDate.toMillis() > maxDate?.toMillis()) {
662
+ return;
663
+ }
664
+ if (isUnavailableDate(targetDate, unavailable, defaultTimeZone)) {
665
+ let nextFocusDate = targetDate.plus({ days: 1 });
666
+ for (let i = 0; i < 365; i++) {
667
+ if (maxDate !== null && nextFocusDate.toMillis() > maxDate?.toMillis()) {
668
+ break;
669
+ }
670
+ if (isUnavailableDate(nextFocusDate, unavailable, defaultTimeZone)) {
671
+ nextFocusDate = nextFocusDate.plus({ days: 1 });
672
+ } else {
673
+ setFocusedDate(nextFocusDate);
674
+ break;
675
+ }
676
+ }
677
+ return;
678
+ }
679
+ setFocusedDate(targetDate);
680
+ },
681
+ [maxDate, setFocusedDate, defaultTimeZone, unavailable]
682
+ );
683
+ let startDayIndex = 6;
684
+ switch (startDay) {
685
+ case "Monday":
686
+ startDayIndex = 0;
687
+ break;
688
+ case "Sunday":
689
+ default:
690
+ startDayIndex = 6;
691
+ }
692
+ const weekdaysArr = [];
693
+ for (let i = 0; i < 7; i++) {
694
+ const dayIndex = (startDayIndex + i) % 7;
695
+ weekdaysArr.push(Info.weekdays("narrow", { locale })[dayIndex]);
696
+ }
697
+ const firstDay = focusedDate.startOf("month");
698
+ if (firstDay.weekday !== startDayIndex + 1) {
699
+ for (let i = 1; i < 8; i++) {
700
+ const prevDay = firstDay.minus({ days: i });
701
+ if (prevDay.weekday === startDayIndex + 1) break;
702
+ }
703
+ }
704
+ useEffect(() => {
705
+ if (!initialized.current) return;
706
+ setTimeout(() => {
707
+ const targetElement = document.getElementById(
708
+ `${uid}-${focusedDate.toISODate()}`
709
+ );
710
+ targetElement?.focus();
711
+ }, 100);
712
+ }, [focusedDate, uid]);
713
+ useEffect(() => {
714
+ if (!isUnavailableDate(focusedDate, unavailable, defaultTimeZone)) return;
715
+ futureDateSelection(focusedDate.plus({ days: 1 }));
716
+ }, [focusedDate, futureDateSelection, defaultTimeZone, unavailable]);
717
+ return /* @__PURE__ */ jsx("tr", { ...rest, ref, children: week.map((n) => {
718
+ return /* @__PURE__ */ jsx(CalendarDay, { date: n }, n.toISODate());
719
+ }) });
720
+ }
721
+ );
722
+ CalendarWeek.displayName = "CalendarWeek";
723
+
724
+ const CalendarMonth = forwardRef(
725
+ (props, ref) => {
726
+ const { className, ...rest } = props;
727
+ const context = useCalendar();
728
+ const {
729
+ value,
730
+ focusedDate,
731
+ setFocusedDate,
732
+ setHoveredDate,
733
+ locale,
734
+ minDate,
735
+ maxDate,
736
+ unavailable,
737
+ defaultTimeZone,
738
+ id: uid,
739
+ range,
740
+ dateFormat,
741
+ startDay
742
+ } = context;
743
+ const initialized = useRef(false);
744
+ const ViewCX = cx(styles$1["grid"], className);
745
+ const futureDateSelection = useCallback(
746
+ (targetDate) => {
747
+ if (maxDate !== null && targetDate.toMillis() > maxDate?.toMillis()) {
748
+ return;
749
+ }
750
+ if (isUnavailableDate(targetDate, unavailable, defaultTimeZone)) {
751
+ let nextFocusDate = targetDate.plus({ days: 1 });
752
+ for (let i = 0; i < 365; i++) {
753
+ if (maxDate !== null && nextFocusDate.toMillis() > maxDate?.toMillis()) {
754
+ break;
755
+ }
756
+ if (isUnavailableDate(nextFocusDate, unavailable, defaultTimeZone)) {
757
+ nextFocusDate = nextFocusDate.plus({ days: 1 });
758
+ } else {
759
+ setFocusedDate(nextFocusDate);
760
+ break;
761
+ }
762
+ }
763
+ return;
764
+ }
765
+ setFocusedDate(targetDate);
766
+ },
767
+ [maxDate, setFocusedDate, defaultTimeZone, unavailable]
768
+ );
769
+ let startDayIndex = 6;
770
+ switch (startDay) {
771
+ case "Monday":
772
+ startDayIndex = 0;
773
+ break;
774
+ case "Sunday":
775
+ default:
776
+ startDayIndex = 6;
777
+ }
778
+ const weekdaysArr = [];
779
+ for (let i = 0; i < 7; i++) {
780
+ const dayIndex = (startDayIndex + i) % 7;
781
+ weekdaysArr.push(Info.weekdays("narrow", { locale })[dayIndex]);
782
+ }
783
+ const firstDay = focusedDate.startOf("month");
784
+ const lastDay = focusedDate.endOf("month");
785
+ const monthArr = Array.from(new Array(firstDay.daysInMonth)).map((_, i) => {
786
+ return firstDay.plus({ days: i });
787
+ });
788
+ const prevArr = [];
789
+ if (firstDay.weekday !== startDayIndex + 1) {
790
+ for (let i = 1; i < 8; i++) {
791
+ const prevDay = firstDay.minus({ days: i });
792
+ prevArr.push(prevDay);
793
+ if (prevDay.weekday === startDayIndex + 1) break;
794
+ }
795
+ }
796
+ prevArr.reverse();
797
+ const nextArr = Array.from(new Array(14)).map((_, i) => {
798
+ return lastDay.plus({ days: i + 1 });
799
+ });
800
+ const fullArr = [...prevArr, ...monthArr, ...nextArr];
801
+ const splitArr = [...Array(Math.ceil(fullArr.length / 7))].map((_, i) => fullArr.slice(7 * i, 7 + 7 * i)).slice(0, 6);
802
+ const onMouseLeaveHandler = () => {
803
+ setHoveredDate(void 0);
804
+ };
805
+ const onSwipe = (dir) => {
806
+ if (dir === "left") {
807
+ const targetMonth = focusedDate.plus({ month: 1 });
808
+ if (isBeyondMinDate(targetMonth, minDate) || isBeyondMaxDate(targetMonth, maxDate))
809
+ return;
810
+ setFocusedDate(targetMonth);
811
+ return;
812
+ }
813
+ if (dir === "right") {
814
+ const targetMonth = focusedDate.minus({ month: 1 });
815
+ if (isBeyondMinDate(targetMonth, minDate) || isBeyondMaxDate(targetMonth, maxDate))
816
+ return;
817
+ setFocusedDate(targetMonth);
818
+ return;
819
+ }
820
+ };
821
+ const { direction, ...touchProps } = useSwipe(onSwipe);
822
+ useEffect(() => {
823
+ if (!initialized.current) return;
824
+ setTimeout(() => {
825
+ const targetElement = document.getElementById(
826
+ `${uid}-${focusedDate.toISODate()}`
827
+ );
828
+ targetElement?.focus();
829
+ }, 100);
830
+ }, [focusedDate, uid]);
831
+ useEffect(() => {
832
+ if (!isUnavailableDate(focusedDate, unavailable, defaultTimeZone)) return;
833
+ futureDateSelection(focusedDate.plus({ days: 1 }));
834
+ }, [focusedDate, futureDateSelection, defaultTimeZone, unavailable]);
835
+ return /* @__PURE__ */ jsxs(Fragment, { children: [
836
+ /* @__PURE__ */ jsxs(
837
+ "table",
838
+ {
839
+ ref,
840
+ "data-anv": "calendar-month",
841
+ onFocus: () => {
842
+ initialized.current = true;
843
+ },
844
+ onBlur: () => {
845
+ initialized.current = false;
846
+ },
847
+ className: ViewCX,
848
+ onMouseLeave: onMouseLeaveHandler,
849
+ role: "grid",
850
+ ...rest,
851
+ ...touchProps,
852
+ children: [
853
+ /* @__PURE__ */ jsxs("thead", { "aria-hidden": true, className: styles$1["weekdays"], children: [
854
+ /* @__PURE__ */ jsx("tr", { children: weekdaysArr.map((weekday, i) => {
855
+ return /* @__PURE__ */ jsx(
856
+ "th",
857
+ {
858
+ scope: "col",
859
+ className: styles$1["weekday"],
860
+ children: weekday
861
+ },
862
+ `${weekday}${i}`
863
+ );
864
+ }) }),
865
+ /* @__PURE__ */ jsx("tr", { className: styles$1["spacer"], children: /* @__PURE__ */ jsx("td", { colSpan: 7 }) })
866
+ ] }),
867
+ /* @__PURE__ */ jsx(
868
+ "tbody",
869
+ {
870
+ className: styles$1["day-grid"],
871
+ children: splitArr.map((week, i) => {
872
+ return /* @__PURE__ */ jsx(CalendarWeek, { week }, i);
873
+ })
874
+ },
875
+ focusedDate.startOf("month").toMillis()
876
+ )
877
+ ]
878
+ }
879
+ ),
880
+ range && value ? /* @__PURE__ */ jsx(SrOnly, { "aria-live": "polite", children: `Range starts at ${value.start && value.start.toLocaleString(dateFormat)}, ${value.end ? `ends at ${value.end.toLocaleString(dateFormat)}` : "select an end date"}` }) : null
881
+ ] });
882
+ }
883
+ );
884
+ CalendarMonth.displayName = "CalendarMonth";
885
+
886
+ function memo(getDeps, fn, opts) {
887
+ let deps = opts.initialDeps ?? [];
888
+ let result;
889
+ function memoizedFunction() {
890
+ var _a, _b, _c, _d;
891
+ let depTime;
892
+ if (opts.key && ((_a = opts.debug) == null ? void 0 : _a.call(opts))) depTime = Date.now();
893
+ const newDeps = getDeps();
894
+ const depsChanged = newDeps.length !== deps.length || newDeps.some((dep, index) => deps[index] !== dep);
895
+ if (!depsChanged) {
896
+ return result;
897
+ }
898
+ deps = newDeps;
899
+ let resultTime;
900
+ if (opts.key && ((_b = opts.debug) == null ? void 0 : _b.call(opts))) resultTime = Date.now();
901
+ result = fn(...newDeps);
902
+ if (opts.key && ((_c = opts.debug) == null ? void 0 : _c.call(opts))) {
903
+ const depEndTime = Math.round((Date.now() - depTime) * 100) / 100;
904
+ const resultEndTime = Math.round((Date.now() - resultTime) * 100) / 100;
905
+ const resultFpsPercentage = resultEndTime / 16;
906
+ const pad = (str, num) => {
907
+ str = String(str);
908
+ while (str.length < num) {
909
+ str = " " + str;
910
+ }
911
+ return str;
912
+ };
913
+ console.info(
914
+ `%c⏱ ${pad(resultEndTime, 5)} /${pad(depEndTime, 5)} ms`,
915
+ `
916
+ font-size: .6rem;
917
+ font-weight: bold;
918
+ color: hsl(${Math.max(
919
+ 0,
920
+ Math.min(120 - 120 * resultFpsPercentage, 120)
921
+ )}deg 100% 31%);`,
922
+ opts == null ? void 0 : opts.key
923
+ );
924
+ }
925
+ (_d = opts == null ? void 0 : opts.onChange) == null ? void 0 : _d.call(opts, result);
926
+ return result;
927
+ }
928
+ memoizedFunction.updateDeps = (newDeps) => {
929
+ deps = newDeps;
930
+ };
931
+ return memoizedFunction;
932
+ }
933
+ function notUndefined(value, msg) {
934
+ if (value === void 0) {
935
+ throw new Error(`Unexpected undefined${""}`);
936
+ } else {
937
+ return value;
938
+ }
939
+ }
940
+ const approxEqual = (a, b) => Math.abs(a - b) < 1.01;
941
+ const debounce = (targetWindow, fn, ms) => {
942
+ let timeoutId;
943
+ return function(...args) {
944
+ targetWindow.clearTimeout(timeoutId);
945
+ timeoutId = targetWindow.setTimeout(() => fn.apply(this, args), ms);
946
+ };
947
+ };
948
+
949
+ const getRect = (element) => {
950
+ const { offsetWidth, offsetHeight } = element;
951
+ return { width: offsetWidth, height: offsetHeight };
952
+ };
953
+ const defaultKeyExtractor = (index) => index;
954
+ const defaultRangeExtractor = (range) => {
955
+ const start = Math.max(range.startIndex - range.overscan, 0);
956
+ const end = Math.min(range.endIndex + range.overscan, range.count - 1);
957
+ const arr = [];
958
+ for (let i = start; i <= end; i++) {
959
+ arr.push(i);
960
+ }
961
+ return arr;
962
+ };
963
+ const observeElementRect = (instance, cb) => {
964
+ const element = instance.scrollElement;
965
+ if (!element) {
966
+ return;
967
+ }
968
+ const targetWindow = instance.targetWindow;
969
+ if (!targetWindow) {
970
+ return;
971
+ }
972
+ const handler = (rect) => {
973
+ const { width, height } = rect;
974
+ cb({ width: Math.round(width), height: Math.round(height) });
975
+ };
976
+ handler(getRect(element));
977
+ if (!targetWindow.ResizeObserver) {
978
+ return () => {
979
+ };
980
+ }
981
+ const observer = new targetWindow.ResizeObserver((entries) => {
982
+ const run = () => {
983
+ const entry = entries[0];
984
+ if (entry == null ? void 0 : entry.borderBoxSize) {
985
+ const box = entry.borderBoxSize[0];
986
+ if (box) {
987
+ handler({ width: box.inlineSize, height: box.blockSize });
988
+ return;
989
+ }
990
+ }
991
+ handler(getRect(element));
992
+ };
993
+ instance.options.useAnimationFrameWithResizeObserver ? requestAnimationFrame(run) : run();
994
+ });
995
+ observer.observe(element, { box: "border-box" });
996
+ return () => {
997
+ observer.unobserve(element);
998
+ };
999
+ };
1000
+ const addEventListenerOptions = {
1001
+ passive: true
1002
+ };
1003
+ const supportsScrollend = typeof window == "undefined" ? true : "onscrollend" in window;
1004
+ const observeElementOffset = (instance, cb) => {
1005
+ const element = instance.scrollElement;
1006
+ if (!element) {
1007
+ return;
1008
+ }
1009
+ const targetWindow = instance.targetWindow;
1010
+ if (!targetWindow) {
1011
+ return;
1012
+ }
1013
+ let offset = 0;
1014
+ const fallback = instance.options.useScrollendEvent && supportsScrollend ? () => void 0 : debounce(
1015
+ targetWindow,
1016
+ () => {
1017
+ cb(offset, false);
1018
+ },
1019
+ instance.options.isScrollingResetDelay
1020
+ );
1021
+ const createHandler = (isScrolling) => () => {
1022
+ const { horizontal, isRtl } = instance.options;
1023
+ offset = horizontal ? element["scrollLeft"] * (isRtl && -1 || 1) : element["scrollTop"];
1024
+ fallback();
1025
+ cb(offset, isScrolling);
1026
+ };
1027
+ const handler = createHandler(true);
1028
+ const endHandler = createHandler(false);
1029
+ endHandler();
1030
+ element.addEventListener("scroll", handler, addEventListenerOptions);
1031
+ const registerScrollendEvent = instance.options.useScrollendEvent && supportsScrollend;
1032
+ if (registerScrollendEvent) {
1033
+ element.addEventListener("scrollend", endHandler, addEventListenerOptions);
1034
+ }
1035
+ return () => {
1036
+ element.removeEventListener("scroll", handler);
1037
+ if (registerScrollendEvent) {
1038
+ element.removeEventListener("scrollend", endHandler);
1039
+ }
1040
+ };
1041
+ };
1042
+ const measureElement = (element, entry, instance) => {
1043
+ if (entry == null ? void 0 : entry.borderBoxSize) {
1044
+ const box = entry.borderBoxSize[0];
1045
+ if (box) {
1046
+ const size = Math.round(
1047
+ box[instance.options.horizontal ? "inlineSize" : "blockSize"]
1048
+ );
1049
+ return size;
1050
+ }
1051
+ }
1052
+ return element[instance.options.horizontal ? "offsetWidth" : "offsetHeight"];
1053
+ };
1054
+ const elementScroll = (offset, {
1055
+ adjustments = 0,
1056
+ behavior
1057
+ }, instance) => {
1058
+ var _a, _b;
1059
+ const toOffset = offset + adjustments;
1060
+ (_b = (_a = instance.scrollElement) == null ? void 0 : _a.scrollTo) == null ? void 0 : _b.call(_a, {
1061
+ [instance.options.horizontal ? "left" : "top"]: toOffset,
1062
+ behavior
1063
+ });
1064
+ };
1065
+ class Virtualizer {
1066
+ constructor(opts) {
1067
+ this.unsubs = [];
1068
+ this.scrollElement = null;
1069
+ this.targetWindow = null;
1070
+ this.isScrolling = false;
1071
+ this.measurementsCache = [];
1072
+ this.itemSizeCache = /* @__PURE__ */ new Map();
1073
+ this.pendingMeasuredCacheIndexes = [];
1074
+ this.scrollRect = null;
1075
+ this.scrollOffset = null;
1076
+ this.scrollDirection = null;
1077
+ this.scrollAdjustments = 0;
1078
+ this.elementsCache = /* @__PURE__ */ new Map();
1079
+ this.observer = /* @__PURE__ */ (() => {
1080
+ let _ro = null;
1081
+ const get = () => {
1082
+ if (_ro) {
1083
+ return _ro;
1084
+ }
1085
+ if (!this.targetWindow || !this.targetWindow.ResizeObserver) {
1086
+ return null;
1087
+ }
1088
+ return _ro = new this.targetWindow.ResizeObserver((entries) => {
1089
+ entries.forEach((entry) => {
1090
+ const run = () => {
1091
+ this._measureElement(entry.target, entry);
1092
+ };
1093
+ this.options.useAnimationFrameWithResizeObserver ? requestAnimationFrame(run) : run();
1094
+ });
1095
+ });
1096
+ };
1097
+ return {
1098
+ disconnect: () => {
1099
+ var _a;
1100
+ (_a = get()) == null ? void 0 : _a.disconnect();
1101
+ _ro = null;
1102
+ },
1103
+ observe: (target) => {
1104
+ var _a;
1105
+ return (_a = get()) == null ? void 0 : _a.observe(target, { box: "border-box" });
1106
+ },
1107
+ unobserve: (target) => {
1108
+ var _a;
1109
+ return (_a = get()) == null ? void 0 : _a.unobserve(target);
1110
+ }
1111
+ };
1112
+ })();
1113
+ this.range = null;
1114
+ this.setOptions = (opts2) => {
1115
+ Object.entries(opts2).forEach(([key, value]) => {
1116
+ if (typeof value === "undefined") delete opts2[key];
1117
+ });
1118
+ this.options = {
1119
+ debug: false,
1120
+ initialOffset: 0,
1121
+ overscan: 1,
1122
+ paddingStart: 0,
1123
+ paddingEnd: 0,
1124
+ scrollPaddingStart: 0,
1125
+ scrollPaddingEnd: 0,
1126
+ horizontal: false,
1127
+ getItemKey: defaultKeyExtractor,
1128
+ rangeExtractor: defaultRangeExtractor,
1129
+ onChange: () => {
1130
+ },
1131
+ measureElement,
1132
+ initialRect: { width: 0, height: 0 },
1133
+ scrollMargin: 0,
1134
+ gap: 0,
1135
+ indexAttribute: "data-index",
1136
+ initialMeasurementsCache: [],
1137
+ lanes: 1,
1138
+ isScrollingResetDelay: 150,
1139
+ enabled: true,
1140
+ isRtl: false,
1141
+ useScrollendEvent: false,
1142
+ useAnimationFrameWithResizeObserver: false,
1143
+ ...opts2
1144
+ };
1145
+ };
1146
+ this.notify = (sync) => {
1147
+ var _a, _b;
1148
+ (_b = (_a = this.options).onChange) == null ? void 0 : _b.call(_a, this, sync);
1149
+ };
1150
+ this.maybeNotify = memo(
1151
+ () => {
1152
+ this.calculateRange();
1153
+ return [
1154
+ this.isScrolling,
1155
+ this.range ? this.range.startIndex : null,
1156
+ this.range ? this.range.endIndex : null
1157
+ ];
1158
+ },
1159
+ (isScrolling) => {
1160
+ this.notify(isScrolling);
1161
+ },
1162
+ {
1163
+ key: process.env.NODE_ENV !== "production" && "maybeNotify",
1164
+ debug: () => this.options.debug,
1165
+ initialDeps: [
1166
+ this.isScrolling,
1167
+ this.range ? this.range.startIndex : null,
1168
+ this.range ? this.range.endIndex : null
1169
+ ]
1170
+ }
1171
+ );
1172
+ this.cleanup = () => {
1173
+ this.unsubs.filter(Boolean).forEach((d) => d());
1174
+ this.unsubs = [];
1175
+ this.observer.disconnect();
1176
+ this.scrollElement = null;
1177
+ this.targetWindow = null;
1178
+ };
1179
+ this._didMount = () => {
1180
+ return () => {
1181
+ this.cleanup();
1182
+ };
1183
+ };
1184
+ this._willUpdate = () => {
1185
+ var _a;
1186
+ const scrollElement = this.options.enabled ? this.options.getScrollElement() : null;
1187
+ if (this.scrollElement !== scrollElement) {
1188
+ this.cleanup();
1189
+ if (!scrollElement) {
1190
+ this.maybeNotify();
1191
+ return;
1192
+ }
1193
+ this.scrollElement = scrollElement;
1194
+ if (this.scrollElement && "ownerDocument" in this.scrollElement) {
1195
+ this.targetWindow = this.scrollElement.ownerDocument.defaultView;
1196
+ } else {
1197
+ this.targetWindow = ((_a = this.scrollElement) == null ? void 0 : _a.window) ?? null;
1198
+ }
1199
+ this.elementsCache.forEach((cached) => {
1200
+ this.observer.observe(cached);
1201
+ });
1202
+ this._scrollToOffset(this.getScrollOffset(), {
1203
+ adjustments: void 0,
1204
+ behavior: void 0
1205
+ });
1206
+ this.unsubs.push(
1207
+ this.options.observeElementRect(this, (rect) => {
1208
+ this.scrollRect = rect;
1209
+ this.maybeNotify();
1210
+ })
1211
+ );
1212
+ this.unsubs.push(
1213
+ this.options.observeElementOffset(this, (offset, isScrolling) => {
1214
+ this.scrollAdjustments = 0;
1215
+ this.scrollDirection = isScrolling ? this.getScrollOffset() < offset ? "forward" : "backward" : null;
1216
+ this.scrollOffset = offset;
1217
+ this.isScrolling = isScrolling;
1218
+ this.maybeNotify();
1219
+ })
1220
+ );
1221
+ }
1222
+ };
1223
+ this.getSize = () => {
1224
+ if (!this.options.enabled) {
1225
+ this.scrollRect = null;
1226
+ return 0;
1227
+ }
1228
+ this.scrollRect = this.scrollRect ?? this.options.initialRect;
1229
+ return this.scrollRect[this.options.horizontal ? "width" : "height"];
1230
+ };
1231
+ this.getScrollOffset = () => {
1232
+ if (!this.options.enabled) {
1233
+ this.scrollOffset = null;
1234
+ return 0;
1235
+ }
1236
+ this.scrollOffset = this.scrollOffset ?? (typeof this.options.initialOffset === "function" ? this.options.initialOffset() : this.options.initialOffset);
1237
+ return this.scrollOffset;
1238
+ };
1239
+ this.getFurthestMeasurement = (measurements, index) => {
1240
+ const furthestMeasurementsFound = /* @__PURE__ */ new Map();
1241
+ const furthestMeasurements = /* @__PURE__ */ new Map();
1242
+ for (let m = index - 1; m >= 0; m--) {
1243
+ const measurement = measurements[m];
1244
+ if (furthestMeasurementsFound.has(measurement.lane)) {
1245
+ continue;
1246
+ }
1247
+ const previousFurthestMeasurement = furthestMeasurements.get(
1248
+ measurement.lane
1249
+ );
1250
+ if (previousFurthestMeasurement == null || measurement.end > previousFurthestMeasurement.end) {
1251
+ furthestMeasurements.set(measurement.lane, measurement);
1252
+ } else if (measurement.end < previousFurthestMeasurement.end) {
1253
+ furthestMeasurementsFound.set(measurement.lane, true);
1254
+ }
1255
+ if (furthestMeasurementsFound.size === this.options.lanes) {
1256
+ break;
1257
+ }
1258
+ }
1259
+ return furthestMeasurements.size === this.options.lanes ? Array.from(furthestMeasurements.values()).sort((a, b) => {
1260
+ if (a.end === b.end) {
1261
+ return a.index - b.index;
1262
+ }
1263
+ return a.end - b.end;
1264
+ })[0] : void 0;
1265
+ };
1266
+ this.getMeasurementOptions = memo(
1267
+ () => [
1268
+ this.options.count,
1269
+ this.options.paddingStart,
1270
+ this.options.scrollMargin,
1271
+ this.options.getItemKey,
1272
+ this.options.enabled
1273
+ ],
1274
+ (count, paddingStart, scrollMargin, getItemKey, enabled) => {
1275
+ this.pendingMeasuredCacheIndexes = [];
1276
+ return {
1277
+ count,
1278
+ paddingStart,
1279
+ scrollMargin,
1280
+ getItemKey,
1281
+ enabled
1282
+ };
1283
+ },
1284
+ {
1285
+ key: false
1286
+ }
1287
+ );
1288
+ this.getMeasurements = memo(
1289
+ () => [this.getMeasurementOptions(), this.itemSizeCache],
1290
+ ({ count, paddingStart, scrollMargin, getItemKey, enabled }, itemSizeCache) => {
1291
+ if (!enabled) {
1292
+ this.measurementsCache = [];
1293
+ this.itemSizeCache.clear();
1294
+ return [];
1295
+ }
1296
+ if (this.measurementsCache.length === 0) {
1297
+ this.measurementsCache = this.options.initialMeasurementsCache;
1298
+ this.measurementsCache.forEach((item) => {
1299
+ this.itemSizeCache.set(item.key, item.size);
1300
+ });
1301
+ }
1302
+ const min = this.pendingMeasuredCacheIndexes.length > 0 ? Math.min(...this.pendingMeasuredCacheIndexes) : 0;
1303
+ this.pendingMeasuredCacheIndexes = [];
1304
+ const measurements = this.measurementsCache.slice(0, min);
1305
+ for (let i = min; i < count; i++) {
1306
+ const key = getItemKey(i);
1307
+ const furthestMeasurement = this.options.lanes === 1 ? measurements[i - 1] : this.getFurthestMeasurement(measurements, i);
1308
+ const start = furthestMeasurement ? furthestMeasurement.end + this.options.gap : paddingStart + scrollMargin;
1309
+ const measuredSize = itemSizeCache.get(key);
1310
+ const size = typeof measuredSize === "number" ? measuredSize : this.options.estimateSize(i);
1311
+ const end = start + size;
1312
+ const lane = furthestMeasurement ? furthestMeasurement.lane : i % this.options.lanes;
1313
+ measurements[i] = {
1314
+ index: i,
1315
+ start,
1316
+ size,
1317
+ end,
1318
+ key,
1319
+ lane
1320
+ };
1321
+ }
1322
+ this.measurementsCache = measurements;
1323
+ return measurements;
1324
+ },
1325
+ {
1326
+ key: process.env.NODE_ENV !== "production" && "getMeasurements",
1327
+ debug: () => this.options.debug
1328
+ }
1329
+ );
1330
+ this.calculateRange = memo(
1331
+ () => [
1332
+ this.getMeasurements(),
1333
+ this.getSize(),
1334
+ this.getScrollOffset(),
1335
+ this.options.lanes
1336
+ ],
1337
+ (measurements, outerSize, scrollOffset, lanes) => {
1338
+ return this.range = measurements.length > 0 && outerSize > 0 ? calculateRange({
1339
+ measurements,
1340
+ outerSize,
1341
+ scrollOffset,
1342
+ lanes
1343
+ }) : null;
1344
+ },
1345
+ {
1346
+ key: process.env.NODE_ENV !== "production" && "calculateRange",
1347
+ debug: () => this.options.debug
1348
+ }
1349
+ );
1350
+ this.getVirtualIndexes = memo(
1351
+ () => {
1352
+ let startIndex = null;
1353
+ let endIndex = null;
1354
+ const range = this.calculateRange();
1355
+ if (range) {
1356
+ startIndex = range.startIndex;
1357
+ endIndex = range.endIndex;
1358
+ }
1359
+ this.maybeNotify.updateDeps([this.isScrolling, startIndex, endIndex]);
1360
+ return [
1361
+ this.options.rangeExtractor,
1362
+ this.options.overscan,
1363
+ this.options.count,
1364
+ startIndex,
1365
+ endIndex
1366
+ ];
1367
+ },
1368
+ (rangeExtractor, overscan, count, startIndex, endIndex) => {
1369
+ return startIndex === null || endIndex === null ? [] : rangeExtractor({
1370
+ startIndex,
1371
+ endIndex,
1372
+ overscan,
1373
+ count
1374
+ });
1375
+ },
1376
+ {
1377
+ key: process.env.NODE_ENV !== "production" && "getVirtualIndexes",
1378
+ debug: () => this.options.debug
1379
+ }
1380
+ );
1381
+ this.indexFromElement = (node) => {
1382
+ const attributeName = this.options.indexAttribute;
1383
+ const indexStr = node.getAttribute(attributeName);
1384
+ if (!indexStr) {
1385
+ console.warn(
1386
+ `Missing attribute name '${attributeName}={index}' on measured element.`
1387
+ );
1388
+ return -1;
1389
+ }
1390
+ return parseInt(indexStr, 10);
1391
+ };
1392
+ this._measureElement = (node, entry) => {
1393
+ const index = this.indexFromElement(node);
1394
+ const item = this.measurementsCache[index];
1395
+ if (!item) {
1396
+ return;
1397
+ }
1398
+ const key = item.key;
1399
+ const prevNode = this.elementsCache.get(key);
1400
+ if (prevNode !== node) {
1401
+ if (prevNode) {
1402
+ this.observer.unobserve(prevNode);
1403
+ }
1404
+ this.observer.observe(node);
1405
+ this.elementsCache.set(key, node);
1406
+ }
1407
+ if (node.isConnected) {
1408
+ this.resizeItem(index, this.options.measureElement(node, entry, this));
1409
+ }
1410
+ };
1411
+ this.resizeItem = (index, size) => {
1412
+ const item = this.measurementsCache[index];
1413
+ if (!item) {
1414
+ return;
1415
+ }
1416
+ const itemSize = this.itemSizeCache.get(item.key) ?? item.size;
1417
+ const delta = size - itemSize;
1418
+ if (delta !== 0) {
1419
+ if (this.shouldAdjustScrollPositionOnItemSizeChange !== void 0 ? this.shouldAdjustScrollPositionOnItemSizeChange(item, delta, this) : item.start < this.getScrollOffset() + this.scrollAdjustments) {
1420
+ if (process.env.NODE_ENV !== "production" && this.options.debug) {
1421
+ console.info("correction", delta);
1422
+ }
1423
+ this._scrollToOffset(this.getScrollOffset(), {
1424
+ adjustments: this.scrollAdjustments += delta,
1425
+ behavior: void 0
1426
+ });
1427
+ }
1428
+ this.pendingMeasuredCacheIndexes.push(item.index);
1429
+ this.itemSizeCache = new Map(this.itemSizeCache.set(item.key, size));
1430
+ this.notify(false);
1431
+ }
1432
+ };
1433
+ this.measureElement = (node) => {
1434
+ if (!node) {
1435
+ this.elementsCache.forEach((cached, key) => {
1436
+ if (!cached.isConnected) {
1437
+ this.observer.unobserve(cached);
1438
+ this.elementsCache.delete(key);
1439
+ }
1440
+ });
1441
+ return;
1442
+ }
1443
+ this._measureElement(node, void 0);
1444
+ };
1445
+ this.getVirtualItems = memo(
1446
+ () => [this.getVirtualIndexes(), this.getMeasurements()],
1447
+ (indexes, measurements) => {
1448
+ const virtualItems = [];
1449
+ for (let k = 0, len = indexes.length; k < len; k++) {
1450
+ const i = indexes[k];
1451
+ const measurement = measurements[i];
1452
+ virtualItems.push(measurement);
1453
+ }
1454
+ return virtualItems;
1455
+ },
1456
+ {
1457
+ key: process.env.NODE_ENV !== "production" && "getVirtualItems",
1458
+ debug: () => this.options.debug
1459
+ }
1460
+ );
1461
+ this.getVirtualItemForOffset = (offset) => {
1462
+ const measurements = this.getMeasurements();
1463
+ if (measurements.length === 0) {
1464
+ return void 0;
1465
+ }
1466
+ return notUndefined(
1467
+ measurements[findNearestBinarySearch(
1468
+ 0,
1469
+ measurements.length - 1,
1470
+ (index) => notUndefined(measurements[index]).start,
1471
+ offset
1472
+ )]
1473
+ );
1474
+ };
1475
+ this.getOffsetForAlignment = (toOffset, align, itemSize = 0) => {
1476
+ const size = this.getSize();
1477
+ const scrollOffset = this.getScrollOffset();
1478
+ if (align === "auto") {
1479
+ align = toOffset >= scrollOffset + size ? "end" : "start";
1480
+ }
1481
+ if (align === "center") {
1482
+ toOffset += (itemSize - size) / 2;
1483
+ } else if (align === "end") {
1484
+ toOffset -= size;
1485
+ }
1486
+ const maxOffset = this.getTotalSize() + this.options.scrollMargin - size;
1487
+ return Math.max(Math.min(maxOffset, toOffset), 0);
1488
+ };
1489
+ this.getOffsetForIndex = (index, align = "auto") => {
1490
+ index = Math.max(0, Math.min(index, this.options.count - 1));
1491
+ const item = this.measurementsCache[index];
1492
+ if (!item) {
1493
+ return void 0;
1494
+ }
1495
+ const size = this.getSize();
1496
+ const scrollOffset = this.getScrollOffset();
1497
+ if (align === "auto") {
1498
+ if (item.end >= scrollOffset + size - this.options.scrollPaddingEnd) {
1499
+ align = "end";
1500
+ } else if (item.start <= scrollOffset + this.options.scrollPaddingStart) {
1501
+ align = "start";
1502
+ } else {
1503
+ return [scrollOffset, align];
1504
+ }
1505
+ }
1506
+ const toOffset = align === "end" ? item.end + this.options.scrollPaddingEnd : item.start - this.options.scrollPaddingStart;
1507
+ return [
1508
+ this.getOffsetForAlignment(toOffset, align, item.size),
1509
+ align
1510
+ ];
1511
+ };
1512
+ this.isDynamicMode = () => this.elementsCache.size > 0;
1513
+ this.scrollToOffset = (toOffset, { align = "start", behavior } = {}) => {
1514
+ if (behavior === "smooth" && this.isDynamicMode()) {
1515
+ console.warn(
1516
+ "The `smooth` scroll behavior is not fully supported with dynamic size."
1517
+ );
1518
+ }
1519
+ this._scrollToOffset(this.getOffsetForAlignment(toOffset, align), {
1520
+ adjustments: void 0,
1521
+ behavior
1522
+ });
1523
+ };
1524
+ this.scrollToIndex = (index, { align: initialAlign = "auto", behavior } = {}) => {
1525
+ if (behavior === "smooth" && this.isDynamicMode()) {
1526
+ console.warn(
1527
+ "The `smooth` scroll behavior is not fully supported with dynamic size."
1528
+ );
1529
+ }
1530
+ index = Math.max(0, Math.min(index, this.options.count - 1));
1531
+ let attempts = 0;
1532
+ const maxAttempts = 10;
1533
+ const tryScroll = (currentAlign) => {
1534
+ if (!this.targetWindow) return;
1535
+ const offsetInfo = this.getOffsetForIndex(index, currentAlign);
1536
+ if (!offsetInfo) {
1537
+ console.warn("Failed to get offset for index:", index);
1538
+ return;
1539
+ }
1540
+ const [offset, align] = offsetInfo;
1541
+ this._scrollToOffset(offset, { adjustments: void 0, behavior });
1542
+ this.targetWindow.requestAnimationFrame(() => {
1543
+ const currentOffset = this.getScrollOffset();
1544
+ const afterInfo = this.getOffsetForIndex(index, align);
1545
+ if (!afterInfo) {
1546
+ console.warn("Failed to get offset for index:", index);
1547
+ return;
1548
+ }
1549
+ if (!approxEqual(afterInfo[0], currentOffset)) {
1550
+ scheduleRetry(align);
1551
+ }
1552
+ });
1553
+ };
1554
+ const scheduleRetry = (align) => {
1555
+ if (!this.targetWindow) return;
1556
+ attempts++;
1557
+ if (attempts < maxAttempts) {
1558
+ if (process.env.NODE_ENV !== "production" && this.options.debug) {
1559
+ console.info("Schedule retry", attempts, maxAttempts);
1560
+ }
1561
+ this.targetWindow.requestAnimationFrame(() => tryScroll(align));
1562
+ } else {
1563
+ console.warn(
1564
+ `Failed to scroll to index ${index} after ${maxAttempts} attempts.`
1565
+ );
1566
+ }
1567
+ };
1568
+ tryScroll(initialAlign);
1569
+ };
1570
+ this.scrollBy = (delta, { behavior } = {}) => {
1571
+ if (behavior === "smooth" && this.isDynamicMode()) {
1572
+ console.warn(
1573
+ "The `smooth` scroll behavior is not fully supported with dynamic size."
1574
+ );
1575
+ }
1576
+ this._scrollToOffset(this.getScrollOffset() + delta, {
1577
+ adjustments: void 0,
1578
+ behavior
1579
+ });
1580
+ };
1581
+ this.getTotalSize = () => {
1582
+ var _a;
1583
+ const measurements = this.getMeasurements();
1584
+ let end;
1585
+ if (measurements.length === 0) {
1586
+ end = this.options.paddingStart;
1587
+ } else if (this.options.lanes === 1) {
1588
+ end = ((_a = measurements[measurements.length - 1]) == null ? void 0 : _a.end) ?? 0;
1589
+ } else {
1590
+ const endByLane = Array(this.options.lanes).fill(null);
1591
+ let endIndex = measurements.length - 1;
1592
+ while (endIndex >= 0 && endByLane.some((val) => val === null)) {
1593
+ const item = measurements[endIndex];
1594
+ if (endByLane[item.lane] === null) {
1595
+ endByLane[item.lane] = item.end;
1596
+ }
1597
+ endIndex--;
1598
+ }
1599
+ end = Math.max(...endByLane.filter((val) => val !== null));
1600
+ }
1601
+ return Math.max(
1602
+ end - this.options.scrollMargin + this.options.paddingEnd,
1603
+ 0
1604
+ );
1605
+ };
1606
+ this._scrollToOffset = (offset, {
1607
+ adjustments,
1608
+ behavior
1609
+ }) => {
1610
+ this.options.scrollToFn(offset, { behavior, adjustments }, this);
1611
+ };
1612
+ this.measure = () => {
1613
+ this.itemSizeCache = /* @__PURE__ */ new Map();
1614
+ this.notify(false);
1615
+ };
1616
+ this.setOptions(opts);
1617
+ }
1618
+ }
1619
+ const findNearestBinarySearch = (low, high, getCurrentValue, value) => {
1620
+ while (low <= high) {
1621
+ const middle = (low + high) / 2 | 0;
1622
+ const currentValue = getCurrentValue(middle);
1623
+ if (currentValue < value) {
1624
+ low = middle + 1;
1625
+ } else if (currentValue > value) {
1626
+ high = middle - 1;
1627
+ } else {
1628
+ return middle;
1629
+ }
1630
+ }
1631
+ if (low > 0) {
1632
+ return low - 1;
1633
+ } else {
1634
+ return 0;
1635
+ }
1636
+ };
1637
+ function calculateRange({
1638
+ measurements,
1639
+ outerSize,
1640
+ scrollOffset,
1641
+ lanes
1642
+ }) {
1643
+ const lastIndex = measurements.length - 1;
1644
+ const getOffset = (index) => measurements[index].start;
1645
+ if (measurements.length <= lanes) {
1646
+ return {
1647
+ startIndex: 0,
1648
+ endIndex: lastIndex
1649
+ };
1650
+ }
1651
+ let startIndex = findNearestBinarySearch(
1652
+ 0,
1653
+ lastIndex,
1654
+ getOffset,
1655
+ scrollOffset
1656
+ );
1657
+ let endIndex = startIndex;
1658
+ if (lanes === 1) {
1659
+ while (endIndex < lastIndex && measurements[endIndex].end < scrollOffset + outerSize) {
1660
+ endIndex++;
1661
+ }
1662
+ } else if (lanes > 1) {
1663
+ const endPerLane = Array(lanes).fill(0);
1664
+ while (endIndex < lastIndex && endPerLane.some((pos) => pos < scrollOffset + outerSize)) {
1665
+ const item = measurements[endIndex];
1666
+ endPerLane[item.lane] = item.end;
1667
+ endIndex++;
1668
+ }
1669
+ const startPerLane = Array(lanes).fill(scrollOffset + outerSize);
1670
+ while (startIndex >= 0 && startPerLane.some((pos) => pos >= scrollOffset)) {
1671
+ const item = measurements[startIndex];
1672
+ startPerLane[item.lane] = item.start;
1673
+ startIndex--;
1674
+ }
1675
+ startIndex = Math.max(0, startIndex - startIndex % lanes);
1676
+ endIndex = Math.min(lastIndex, endIndex + (lanes - 1 - endIndex % lanes));
1677
+ }
1678
+ return { startIndex, endIndex };
1679
+ }
1680
+
1681
+ const useIsomorphicLayoutEffect = typeof document !== "undefined" ? React.useLayoutEffect : React.useEffect;
1682
+ function useVirtualizerBase(options) {
1683
+ const rerender = React.useReducer(() => ({}), {})[1];
1684
+ const resolvedOptions = {
1685
+ ...options,
1686
+ onChange: (instance2, sync) => {
1687
+ var _a;
1688
+ if (sync) {
1689
+ flushSync(rerender);
1690
+ } else {
1691
+ rerender();
1692
+ }
1693
+ (_a = options.onChange) == null ? void 0 : _a.call(options, instance2, sync);
1694
+ }
1695
+ };
1696
+ const [instance] = React.useState(
1697
+ () => new Virtualizer(resolvedOptions)
1698
+ );
1699
+ instance.setOptions(resolvedOptions);
1700
+ useIsomorphicLayoutEffect(() => {
1701
+ return instance._didMount();
1702
+ }, []);
1703
+ useIsomorphicLayoutEffect(() => {
1704
+ return instance._willUpdate();
1705
+ });
1706
+ return instance;
1707
+ }
1708
+ function useVirtualizer(options) {
1709
+ return useVirtualizerBase({
1710
+ observeElementRect,
1711
+ observeElementOffset,
1712
+ scrollToFn: elementScroll,
1713
+ ...options
1714
+ });
1715
+ }
1716
+
1717
+ const styles = {
1718
+ "year-selector": "_year-selector_1pxps_2",
1719
+ "year-grid": "_year-grid_1pxps_9",
1720
+ "year-item": "_year-item_1pxps_26",
1721
+ "pseudo-focused": "_pseudo-focused_1pxps_29"
1722
+ };
1723
+
1724
+ const useYearSelectorKeys = ({
1725
+ columns,
1726
+ scrollToYear,
1727
+ initialFocus,
1728
+ onSelect,
1729
+ onConfirm,
1730
+ pseudoFocused,
1731
+ setPseudoFocused,
1732
+ min,
1733
+ max,
1734
+ disabled,
1735
+ required
1736
+ }) => {
1737
+ const listRef = useRef(null);
1738
+ useEffect(() => {
1739
+ const list = listRef.current;
1740
+ const handleKeyDown = (e) => {
1741
+ if (pseudoFocused === null) return;
1742
+ if ([
1743
+ "ArrowLeft",
1744
+ "ArrowRight",
1745
+ "ArrowUp",
1746
+ "ArrowDown",
1747
+ "Home",
1748
+ "PageUp",
1749
+ "PageDown",
1750
+ "Enter",
1751
+ " ",
1752
+ "Backspace",
1753
+ "Delete"
1754
+ ].includes(e.key)) {
1755
+ e.preventDefault();
1756
+ if (e.key === "ArrowLeft" || e.key === "ArrowRight" || e.key === "ArrowUp" || e.key === "ArrowDown") {
1757
+ const newYear = e.key === "ArrowLeft" || e.key === "ArrowUp" ? pseudoFocused - 1 : pseudoFocused + 1;
1758
+ const clampedYear = Math.min(Math.max(newYear, min), max);
1759
+ scrollToYear(newYear, { focus: true });
1760
+ setPseudoFocused(newYear);
1761
+ if (!disabled) {
1762
+ onSelect(clampedYear);
1763
+ }
1764
+ return;
1765
+ }
1766
+ if (!required && (e.key === "Backspace" || e.key === "Delete")) {
1767
+ onSelect(null);
1768
+ return;
1769
+ }
1770
+ if (e.key === "PageUp" || e.key === "PageDown") {
1771
+ const newYear = e.key === "PageUp" ? min : max;
1772
+ scrollToYear(newYear, { focus: true });
1773
+ setPseudoFocused(newYear);
1774
+ if (!disabled) {
1775
+ onSelect(newYear);
1776
+ }
1777
+ return;
1778
+ }
1779
+ if (e.key === "Home") {
1780
+ scrollToYear(initialFocus, { focus: true });
1781
+ setPseudoFocused(initialFocus);
1782
+ if (!disabled) {
1783
+ onSelect(initialFocus);
1784
+ }
1785
+ return;
1786
+ }
1787
+ if (e.key === "Enter" || e.key === " ") {
1788
+ if (!disabled) {
1789
+ onConfirm();
1790
+ }
1791
+ return;
1792
+ }
1793
+ }
1794
+ };
1795
+ list?.addEventListener("keydown", handleKeyDown);
1796
+ return () => {
1797
+ list?.removeEventListener("keydown", handleKeyDown);
1798
+ };
1799
+ }, [
1800
+ pseudoFocused,
1801
+ columns,
1802
+ scrollToYear,
1803
+ onSelect,
1804
+ min,
1805
+ max,
1806
+ initialFocus,
1807
+ disabled,
1808
+ setPseudoFocused,
1809
+ required,
1810
+ onConfirm
1811
+ ]);
1812
+ return { listRef };
1813
+ };
1814
+
1815
+ const YearItem = ({
1816
+ year,
1817
+ onChange,
1818
+ selected,
1819
+ pseudoFocused,
1820
+ disabled,
1821
+ onFocus,
1822
+ ...rest
1823
+ }) => {
1824
+ return /* @__PURE__ */ jsx(
1825
+ SelectCard,
1826
+ {
1827
+ disabled,
1828
+ id: year,
1829
+ onChange: !disabled ? () => onChange(year) : () => {
1830
+ },
1831
+ checked: selected,
1832
+ checkboxProps: {
1833
+ tabIndex: -1,
1834
+ onFocus
1835
+ },
1836
+ flexGrow: 1,
1837
+ className: cx(styles["year-item"], {
1838
+ [styles["pseudo-focused"]]: pseudoFocused
1839
+ }),
1840
+ "data-year": year,
1841
+ tabIndex: -1,
1842
+ ...rest,
1843
+ children: year
1844
+ }
1845
+ );
1846
+ };
1847
+
1848
+ const DEFAULT_MIN = 1900;
1849
+ const DEFAULT_MAX = 2200;
1850
+ const currentYear = (/* @__PURE__ */ new Date()).getFullYear();
1851
+ const YearSelector = forwardRef(
1852
+ ({
1853
+ min = DEFAULT_MIN,
1854
+ max = DEFAULT_MAX,
1855
+ value: valueProp,
1856
+ defaultValue: defaultValueProp,
1857
+ onChange,
1858
+ onConfirm,
1859
+ startingYear = currentYear,
1860
+ columns: columnsProp,
1861
+ className,
1862
+ required = false,
1863
+ disabled = false,
1864
+ ariaLabel = "Year selection",
1865
+ rootProps
1866
+ }, ref) => {
1867
+ const columns = Math.max(columnsProp ?? 2, 1);
1868
+ const [value, setValue] = useOptionallyControlledState({
1869
+ controlledValue: valueProp,
1870
+ defaultValue: defaultValueProp ?? null,
1871
+ onChange
1872
+ });
1873
+ const previousValue = usePrevious(value);
1874
+ const initialFocusYear = value ?? startingYear;
1875
+ const [pseudoFocused, setPseudoFocused] = useState(initialFocusYear);
1876
+ const handleChange = (year) => {
1877
+ if (!required && value === year) {
1878
+ setValue(null);
1879
+ return;
1880
+ }
1881
+ setValue(year);
1882
+ if (year !== null) {
1883
+ setPseudoFocused(year);
1884
+ }
1885
+ };
1886
+ const handleItemChange = (year) => {
1887
+ handleChange(year);
1888
+ onConfirm?.(year);
1889
+ };
1890
+ const gap = 12;
1891
+ const rowHeight = 58;
1892
+ const rowCount = Math.ceil((max - min + 1) / columns);
1893
+ const initialOffset = (initialFocusYear - min) * (rowHeight + gap) / columns + gap / 2;
1894
+ const rowVirtualizer = useVirtualizer({
1895
+ count: rowCount,
1896
+ getScrollElement: () => parentRef.current,
1897
+ estimateSize: () => rowHeight,
1898
+ gap,
1899
+ initialOffset,
1900
+ paddingEnd: gap / 2
1901
+ });
1902
+ const scrollToYear = useCallback(
1903
+ (year, { focus } = {}) => {
1904
+ const index = Math.floor((year - min) / columns);
1905
+ rowVirtualizer.scrollToIndex(index, { align: "center" });
1906
+ if (focus) {
1907
+ setPseudoFocused(year);
1908
+ }
1909
+ },
1910
+ [min, columns, rowVirtualizer, setPseudoFocused]
1911
+ );
1912
+ const parentRef = useRef(null);
1913
+ const { listRef } = useYearSelectorKeys({
1914
+ columns,
1915
+ scrollToYear,
1916
+ initialFocus: initialFocusYear,
1917
+ onSelect: handleChange,
1918
+ onConfirm: () => onConfirm?.(value),
1919
+ min,
1920
+ max,
1921
+ disabled,
1922
+ pseudoFocused,
1923
+ setPseudoFocused,
1924
+ required
1925
+ });
1926
+ useEffect(() => {
1927
+ if (value !== null && previousValue !== value) {
1928
+ scrollToYear(value, { focus: true });
1929
+ }
1930
+ }, [value, previousValue, scrollToYear, listRef]);
1931
+ const jointRef = useMergeRefs([parentRef, listRef, ref]);
1932
+ return /* @__PURE__ */ jsx(Fragment, { children: /* @__PURE__ */ jsx(
1933
+ "div",
1934
+ {
1935
+ ref: jointRef,
1936
+ "aria-label": ariaLabel,
1937
+ tabIndex: 0,
1938
+ className: cx(styles["year-selector"], className),
1939
+ role: "spinbutton",
1940
+ "aria-valuenow": value ?? void 0,
1941
+ "aria-valuemin": min,
1942
+ "aria-valuemax": max,
1943
+ "aria-valuetext": value ? `${value}` : "No year selected",
1944
+ "data-test": rowVirtualizer.options.paddingEnd,
1945
+ style: {
1946
+ maxHeight: `${rowVirtualizer.getTotalSize() + 8}px`
1947
+ },
1948
+ ...rootProps,
1949
+ children: /* @__PURE__ */ jsx(
1950
+ "div",
1951
+ {
1952
+ style: {
1953
+ height: `${rowVirtualizer.getTotalSize()}px`,
1954
+ width: "100%",
1955
+ position: "relative"
1956
+ },
1957
+ children: rowVirtualizer.getVirtualItems().map((virtualItem) => {
1958
+ const years = Array.from(
1959
+ { length: columns },
1960
+ (_, i) => virtualItem.index * columns + i + min
1961
+ );
1962
+ return /* @__PURE__ */ jsx(
1963
+ "div",
1964
+ {
1965
+ "data-testid": "v-row",
1966
+ className: styles["year-grid"],
1967
+ style: {
1968
+ transform: `translateY(${virtualItem.start}px)`,
1969
+ gridTemplateColumns: `repeat(${columns}, 1fr)`
1970
+ },
1971
+ children: years.map((year) => {
1972
+ if (year > max) return /* @__PURE__ */ jsx("div", {}, year);
1973
+ return /* @__PURE__ */ jsx(
1974
+ YearItem,
1975
+ {
1976
+ disabled,
1977
+ year,
1978
+ onChange: handleItemChange,
1979
+ selected: value === year,
1980
+ pseudoFocused: pseudoFocused === year,
1981
+ onFocus: () => {
1982
+ listRef.current?.focus();
1983
+ setPseudoFocused(year);
1984
+ }
1985
+ },
1986
+ year
1987
+ );
1988
+ })
1989
+ },
1990
+ virtualItem.key
1991
+ );
1992
+ })
1993
+ }
1994
+ )
1995
+ }
1996
+ ) });
1997
+ }
1998
+ );
1999
+ YearSelector.displayName = "YearSelector";
2000
+
2001
+ const CalendarMonthSelection = forwardRef(({ onMonthSelection, ...props }, ref) => {
2002
+ const { defaultTimeZone, maxDate, minDate, selectedMonth, selectedYear } = useCalendar();
2003
+ const monthSelectionRef = useRef(null);
2004
+ const combinedRef = useMergeRefs([ref, monthSelectionRef]);
2005
+ const currentDate = useMemo(
2006
+ () => DateTime.fromObject({ year: selectedYear, month: selectedMonth }).setZone(defaultTimeZone).startOf("day"),
2007
+ [defaultTimeZone, selectedYear, selectedMonth]
2008
+ );
2009
+ const dates = useMemo(
2010
+ () => Array.from({ length: 12 }, (_, i) => {
2011
+ const date = DateTime.fromObject({
2012
+ year: selectedYear,
2013
+ month: 1
2014
+ }).plus({
2015
+ month: i
2016
+ });
2017
+ const disabled = minDate && date < minDate && !date.hasSame(minDate, "month") || maxDate && date > maxDate && !date.hasSame(maxDate, "month");
2018
+ return {
2019
+ month: date.month,
2020
+ disabled: disabled ?? false
2021
+ };
2022
+ }),
2023
+ [maxDate, minDate, selectedYear]
2024
+ );
2025
+ const classes = cx(styles$1["month-selection"], props.className);
2026
+ const [focusedIndex, setFocusedIndex] = useState(selectedMonth - 1);
2027
+ useEffect(() => {
2028
+ if (minDate || maxDate) {
2029
+ let index = dates.findIndex(({ month }) => month === selectedMonth);
2030
+ while (dates[index].disabled && index < 11) {
2031
+ index++;
2032
+ }
2033
+ setFocusedIndex(index);
2034
+ } else {
2035
+ setFocusedIndex(selectedMonth - 1);
2036
+ }
2037
+ }, [selectedMonth, minDate, maxDate, dates]);
2038
+ const handleKeyDown = useCallback(
2039
+ (e) => {
2040
+ const target = e.target;
2041
+ const cards = monthSelectionRef.current?.querySelectorAll(
2042
+ "input[type='checkbox']"
2043
+ );
2044
+ if (!cards || cards.length === 0) {
2045
+ return;
2046
+ }
2047
+ const cardArray = Array.from(cards);
2048
+ const currentIndex = cardArray.indexOf(target);
2049
+ if (currentIndex === -1) return;
2050
+ const updateFocusedIndex = (index) => {
2051
+ e.preventDefault();
2052
+ cardArray[index].focus();
2053
+ setFocusedIndex(index);
2054
+ };
2055
+ let newIndex;
2056
+ switch (e.key) {
2057
+ case "ArrowLeft":
2058
+ newIndex = currentIndex > 0 ? currentIndex - 1 : 11;
2059
+ while (dates[newIndex].disabled) {
2060
+ newIndex = newIndex > 0 ? newIndex - 1 : 11;
2061
+ }
2062
+ updateFocusedIndex(newIndex);
2063
+ break;
2064
+ case "ArrowRight":
2065
+ newIndex = currentIndex < 11 ? currentIndex + 1 : 0;
2066
+ while (dates[newIndex].disabled) {
2067
+ newIndex = newIndex < 11 ? newIndex + 1 : 0;
2068
+ }
2069
+ updateFocusedIndex(newIndex);
2070
+ break;
2071
+ case "ArrowUp":
2072
+ if (currentIndex < 3) {
2073
+ newIndex = currentIndex + 9;
2074
+ } else {
2075
+ newIndex = currentIndex - 3;
2076
+ }
2077
+ while (dates[newIndex].disabled) {
2078
+ if (newIndex > 2) {
2079
+ newIndex -= 3;
2080
+ } else {
2081
+ newIndex += 9;
2082
+ }
2083
+ }
2084
+ updateFocusedIndex(newIndex);
2085
+ break;
2086
+ case "ArrowDown":
2087
+ if (currentIndex > 8) {
2088
+ newIndex = currentIndex - 9;
2089
+ } else {
2090
+ newIndex = currentIndex + 3;
2091
+ }
2092
+ while (dates[newIndex].disabled) {
2093
+ if (newIndex < 9) {
2094
+ newIndex += 3;
2095
+ } else {
2096
+ newIndex -= 9;
2097
+ }
2098
+ }
2099
+ updateFocusedIndex(newIndex);
2100
+ break;
2101
+ case "Enter":
2102
+ case " ":
2103
+ e.preventDefault();
2104
+ if (!dates[currentIndex].disabled) {
2105
+ onMonthSelection(dates[currentIndex].month);
2106
+ }
2107
+ break;
2108
+ }
2109
+ },
2110
+ [dates, onMonthSelection]
2111
+ );
2112
+ return /* @__PURE__ */ jsx(
2113
+ "div",
2114
+ {
2115
+ ref: combinedRef,
2116
+ "data-anv": "calendar-month-selection",
2117
+ className: classes,
2118
+ ...props,
2119
+ children: /* @__PURE__ */ jsx("div", { role: "grid", "aria-label": "Calendar month selection", children: /* @__PURE__ */ jsx(
2120
+ Grid,
2121
+ {
2122
+ templateColumns: "repeat(3, minmax(0, 1fr))",
2123
+ gap: 3,
2124
+ onKeyDown: handleKeyDown,
2125
+ role: "row",
2126
+ children: dates.map(({ month, disabled }, index) => /* @__PURE__ */ jsx("div", { role: "gridcell", children: /* @__PURE__ */ jsx(
2127
+ SelectCard,
2128
+ {
2129
+ id: month.toString(),
2130
+ disabled,
2131
+ onChange: () => onMonthSelection(month),
2132
+ checked: selectedMonth === month && selectedYear === currentDate.year,
2133
+ checkboxProps: {
2134
+ className: styles$1["selection-checkbox"],
2135
+ tabIndex: focusedIndex === index ? 0 : -1
2136
+ },
2137
+ className: styles$1["selection-card"],
2138
+ children: DateTime.fromObject({ month }).toFormat("MMMM")
2139
+ }
2140
+ ) }, month.toString()))
2141
+ }
2142
+ ) })
2143
+ }
2144
+ );
2145
+ });
2146
+ CalendarMonthSelection.displayName = "CalendarMonthSelection";
2147
+
2148
+ const CalendarBetaPropsContext = createContext({});
2149
+
2150
+ const useCalendarBetaProps = () => {
2151
+ return useContext(CalendarBetaPropsContext);
2152
+ };
2153
+
2154
+ const toolbarFocusStates = ["month", "year", "next", "prev", "now"];
2155
+ const CalendarElement = forwardRef(
2156
+ (props, ref) => {
2157
+ const uid = useId();
2158
+ const { layoutStyles, componentProps } = useLayoutPropsUtil(props);
2159
+ const {
2160
+ children,
2161
+ focusedDate: focusProp,
2162
+ defaultFocusedDate,
2163
+ locale = Intl.DateTimeFormat().resolvedOptions().locale,
2164
+ defaultTimeZone = Intl.DateTimeFormat().resolvedOptions().timeZone,
2165
+ startDay = "Sunday",
2166
+ minDate,
2167
+ maxDate,
2168
+ unavailable = {
2169
+ dates: [],
2170
+ daysOfWeek: []
2171
+ },
2172
+ id,
2173
+ style,
2174
+ value: iValue,
2175
+ defaultValue: iDefaultValue,
2176
+ onSelection,
2177
+ range,
2178
+ className,
2179
+ _disableAutofocus,
2180
+ _disableFocus,
2181
+ ...remainingProps
2182
+ } = componentProps;
2183
+ const { dateMetadata, onMonthView } = useCalendarBetaProps();
2184
+ const calendarRef = useRef(null);
2185
+ const combinedRef = useMergeRefs([ref, calendarRef]);
2186
+ const lastIValue = useRef(iValue);
2187
+ const yearButtonRef = useRef(null);
2188
+ const monthButtonRef = useRef(null);
2189
+ const headerRef = useRef(null);
2190
+ const [toolbarFocus, setToolbarFocus] = useState(toolbarFocusStates[0]);
2191
+ const [calendarWidth, setCalendarWidth] = useState(
2192
+ void 0
2193
+ );
2194
+ const [calendarSelectionState, setCalendarSelectionState] = useState("day");
2195
+ const visibleHeaderButtons = useMemo(() => {
2196
+ if (calendarSelectionState !== "day") {
2197
+ return toolbarFocusStates.slice(0, 2);
2198
+ }
2199
+ return toolbarFocusStates;
2200
+ }, [calendarSelectionState]);
2201
+ useEffect(() => {
2202
+ if (!calendarRef.current || style?.width != null) return;
2203
+ const resizeObserver = new ResizeObserver((entries) => {
2204
+ for (const entry of entries) {
2205
+ const width = entry.contentRect.width;
2206
+ if (calendarSelectionState === "day" && width > 100) {
2207
+ setCalendarWidth(width);
2208
+ }
2209
+ }
2210
+ });
2211
+ resizeObserver.observe(calendarRef.current);
2212
+ return () => {
2213
+ resizeObserver.disconnect();
2214
+ };
2215
+ }, [calendarSelectionState, style?.width]);
2216
+ const styleCombined = {
2217
+ width: calendarWidth,
2218
+ ...style,
2219
+ ...layoutStyles
2220
+ };
2221
+ const classNameCombined = cx(styles$1["calendar"], className);
2222
+ const { nDate, nDefaultDate, nToday } = useMemo(
2223
+ () => ({
2224
+ nDate: iValue ? typeof iValue === "string" ? normalizeDate(iValue, defaultTimeZone) : {
2225
+ start: iValue.start ? normalizeDate(iValue.start, defaultTimeZone) : null,
2226
+ end: iValue.end ? normalizeDate(iValue.end, defaultTimeZone) : null
2227
+ } : null,
2228
+ nDefaultDate: iDefaultValue ? typeof iDefaultValue === "string" ? normalizeDate(iDefaultValue, defaultTimeZone) : {
2229
+ start: iDefaultValue.start ? normalizeDate(iDefaultValue.start, defaultTimeZone) : null,
2230
+ end: iDefaultValue?.end ? normalizeDate(iDefaultValue.end, defaultTimeZone) : null
2231
+ } : null,
2232
+ nToday: typeof iValue === "string" ? normalizeDate(DateTime.now().toISO(), defaultTimeZone) : {
2233
+ start: normalizeDate(DateTime.now().toISO(), defaultTimeZone),
2234
+ end: normalizeDate(DateTime.now().toISO(), defaultTimeZone)
2235
+ }
2236
+ }),
2237
+ [iValue, iDefaultValue, defaultTimeZone]
2238
+ );
2239
+ const [value, setValue] = useState(nDate ?? nDefaultDate ?? nToday);
2240
+ const getInitialDate = useMemo(() => {
2241
+ if (defaultFocusedDate) {
2242
+ return normalizeDate(defaultFocusedDate, defaultTimeZone);
2243
+ }
2244
+ if (iDefaultValue) {
2245
+ const date = typeof iDefaultValue === "string" ? normalizeDate(iDefaultValue, defaultTimeZone) : normalizeDate(
2246
+ iDefaultValue.start ?? iDefaultValue.end ?? "",
2247
+ defaultTimeZone
2248
+ );
2249
+ return date;
2250
+ }
2251
+ if (!DateTime.isDateTime(nDate) && !DateTime.isDateTime(nDefaultDate) && !DateTime.isDateTime(nToday)) {
2252
+ return nDate?.start ?? nDefaultDate?.start ?? nToday?.start;
2253
+ }
2254
+ return nDate ?? nDefaultDate ?? nToday;
2255
+ }, [
2256
+ defaultFocusedDate,
2257
+ iDefaultValue,
2258
+ nDate,
2259
+ nDefaultDate,
2260
+ nToday,
2261
+ defaultTimeZone
2262
+ ]);
2263
+ const initialDate = getInitialDate ?? DateTime.now();
2264
+ const [focusedDate, setFocusedDate] = useState(initialDate);
2265
+ const [hoveredDate, setHoveredDate] = useState();
2266
+ const [selectedMonth, setSelectedMonth] = useState(
2267
+ initialDate.month
2268
+ );
2269
+ const [selectedYear, setSelectedYear] = useState(
2270
+ initialDate.year
2271
+ );
2272
+ const currentVisibleMonth = useMemo(() => {
2273
+ return {
2274
+ year: focusedDate?.year ?? selectedYear,
2275
+ month: focusedDate?.month ?? selectedMonth
2276
+ };
2277
+ }, [focusedDate?.month, focusedDate?.year, selectedYear, selectedMonth]);
2278
+ useEffect(
2279
+ () => onMonthView?.(currentVisibleMonth),
2280
+ // eslint-disable-next-line react-hooks/exhaustive-deps -- omit onMonthView from deps because we don't want to trigger infinite re-renders
2281
+ [currentVisibleMonth]
2282
+ );
2283
+ useEffect(() => {
2284
+ if (!focusProp && !defaultFocusedDate) return;
2285
+ if (focusProp) {
2286
+ setFocusedDate(normalizeDate(focusProp, defaultTimeZone));
2287
+ } else if (defaultFocusedDate) {
2288
+ setFocusedDate(normalizeDate(defaultFocusedDate, defaultTimeZone));
2289
+ setSelectedMonth(
2290
+ normalizeDate(defaultFocusedDate, defaultTimeZone).month
2291
+ );
2292
+ setSelectedYear(
2293
+ normalizeDate(defaultFocusedDate, defaultTimeZone).year
2294
+ );
2295
+ }
2296
+ }, [focusProp, defaultFocusedDate]);
2297
+ useEffect(() => {
2298
+ if (!iValue) {
2299
+ lastIValue.current = iValue;
2300
+ return;
2301
+ }
2302
+ if (typeof iValue === "string") {
2303
+ setValue(normalizeDate(iValue, defaultTimeZone));
2304
+ setFocusedDate(normalizeDate(iValue, defaultTimeZone));
2305
+ } else if (iValue.end && (typeof lastIValue.current !== "object" || lastIValue?.current?.end !== iValue.end)) {
2306
+ setValue({
2307
+ start: iValue.start ? normalizeDate(iValue.start, defaultTimeZone) : null,
2308
+ end: iValue.end ? normalizeDate(iValue.end, defaultTimeZone) : null
2309
+ });
2310
+ setFocusedDate(normalizeDate(iValue.end, defaultTimeZone));
2311
+ } else if (iValue.start && (typeof lastIValue.current !== "object" || lastIValue?.current?.start !== iValue.start)) {
2312
+ setFocusedDate(normalizeDate(iValue.start, defaultTimeZone));
2313
+ }
2314
+ lastIValue.current = iValue;
2315
+ }, [iValue]);
2316
+ const normalizedMinDate = useMemo(
2317
+ () => minDate ? normalizeDate(minDate, defaultTimeZone) : null,
2318
+ [minDate, defaultTimeZone]
2319
+ );
2320
+ const normalizedMaxDate = useMemo(
2321
+ () => maxDate ? normalizeDate(maxDate, defaultTimeZone) : null,
2322
+ [maxDate, defaultTimeZone]
2323
+ );
2324
+ const dateMetadataMap = useMemo(() => {
2325
+ if (!dateMetadata) return void 0;
2326
+ return new Map(dateMetadata.map((item) => [item.date, item.context]));
2327
+ }, [dateMetadata]);
2328
+ const providerValue = useMemo(() => {
2329
+ const format = {
2330
+ weekday: "long",
2331
+ month: "long",
2332
+ day: "2-digit",
2333
+ year: "numeric"
2334
+ };
2335
+ return {
2336
+ disableAutofocus: _disableAutofocus ?? false,
2337
+ focusedDate,
2338
+ setFocusedDate,
2339
+ selectedMonth,
2340
+ setSelectedMonth,
2341
+ selectedYear,
2342
+ setSelectedYear,
2343
+ hoveredDate,
2344
+ setHoveredDate,
2345
+ value,
2346
+ setValue,
2347
+ defaultTimeZone,
2348
+ id: id ?? uid,
2349
+ onSelection,
2350
+ controlled: !!iValue,
2351
+ range,
2352
+ minDate: normalizedMinDate,
2353
+ maxDate: normalizedMaxDate,
2354
+ unavailable: {
2355
+ dates: new Set(unavailable.dates),
2356
+ daysOfWeek: new Set(unavailable.daysOfWeek)
2357
+ },
2358
+ locale,
2359
+ dateFormat: format,
2360
+ startDay,
2361
+ dateMetadata: dateMetadataMap
2362
+ };
2363
+ }, [
2364
+ focusedDate,
2365
+ selectedMonth,
2366
+ selectedYear,
2367
+ hoveredDate,
2368
+ id,
2369
+ locale,
2370
+ normalizedMaxDate,
2371
+ normalizedMinDate,
2372
+ iValue,
2373
+ onSelection,
2374
+ range,
2375
+ defaultTimeZone,
2376
+ uid,
2377
+ unavailable,
2378
+ value,
2379
+ startDay,
2380
+ dateMetadataMap,
2381
+ _disableAutofocus
2382
+ ]);
2383
+ const handleHeaderKeyDown = useCallback(
2384
+ (e) => {
2385
+ switch (e.key) {
2386
+ case "ArrowLeft":
2387
+ e.preventDefault();
2388
+ setToolbarFocus((previousToolbarFocus) => {
2389
+ const newToolbarFocus = previousToolbarFocus === visibleHeaderButtons[0] ? visibleHeaderButtons[visibleHeaderButtons.length - 1] : visibleHeaderButtons[visibleHeaderButtons.indexOf(previousToolbarFocus) - 1] ?? visibleHeaderButtons[visibleHeaderButtons.length - 1];
2390
+ const button = headerRef.current?.querySelector(
2391
+ `[data-calendar-header-button-name="${newToolbarFocus}"]`
2392
+ );
2393
+ if (button && "focus" in button && typeof button.focus === "function") {
2394
+ button.focus();
2395
+ }
2396
+ return newToolbarFocus;
2397
+ });
2398
+ break;
2399
+ case "ArrowRight":
2400
+ e.preventDefault();
2401
+ setToolbarFocus((previousToolbarFocus) => {
2402
+ const newToolbarFocus = previousToolbarFocus === visibleHeaderButtons[visibleHeaderButtons.length - 1] ? visibleHeaderButtons[0] : visibleHeaderButtons[visibleHeaderButtons.indexOf(previousToolbarFocus) + 1] ?? visibleHeaderButtons[0];
2403
+ const button = headerRef.current?.querySelector(
2404
+ `[data-calendar-header-button-name="${newToolbarFocus}"]`
2405
+ );
2406
+ if (button && "focus" in button && typeof button.focus === "function") {
2407
+ button.focus();
2408
+ }
2409
+ return newToolbarFocus;
2410
+ });
2411
+ }
2412
+ },
2413
+ [visibleHeaderButtons]
2414
+ );
2415
+ const handleMonthSelection = useCallback(
2416
+ (month) => {
2417
+ monthButtonRef.current?.focus();
2418
+ setToolbarFocus(toolbarFocusStates[0]);
2419
+ setSelectedMonth(month);
2420
+ setFocusedDate(
2421
+ DateTime.fromObject({
2422
+ year: focusedDate?.year ?? 1,
2423
+ month,
2424
+ day: 1
2425
+ }).setZone(defaultTimeZone).startOf("day")
2426
+ );
2427
+ setCalendarSelectionState("day");
2428
+ },
2429
+ // eslint-disable-next-line react-hooks/exhaustive-deps
2430
+ [focusedDate]
2431
+ );
2432
+ const handleYearSelection = useCallback(
2433
+ (year) => {
2434
+ if (year === null) return;
2435
+ yearButtonRef.current?.focus();
2436
+ setToolbarFocus(toolbarFocusStates[1]);
2437
+ setSelectedYear(year);
2438
+ setFocusedDate(
2439
+ DateTime.fromObject({
2440
+ year,
2441
+ month: focusedDate?.month ?? 1,
2442
+ day: 1
2443
+ }).setZone(defaultTimeZone).startOf("day")
2444
+ );
2445
+ setCalendarSelectionState("day");
2446
+ },
2447
+ // eslint-disable-next-line react-hooks/exhaustive-deps
2448
+ [focusedDate?.month]
2449
+ );
2450
+ return /* @__PURE__ */ jsx(CalendarContext.Provider, { value: providerValue, children: /* @__PURE__ */ jsxs(
2451
+ "div",
2452
+ {
2453
+ ref: combinedRef,
2454
+ id: id ?? uid,
2455
+ style: styleCombined,
2456
+ className: classNameCombined,
2457
+ "data-anv": "calendar",
2458
+ ...remainingProps,
2459
+ children: [
2460
+ /* @__PURE__ */ jsx("div", { className: styles$1["header"], children: /* @__PURE__ */ jsxs(
2461
+ "span",
2462
+ {
2463
+ ref: headerRef,
2464
+ "aria-label": "Calendar navigation",
2465
+ role: "toolbar",
2466
+ onKeyDown: handleHeaderKeyDown,
2467
+ className: styles$1["controller"],
2468
+ children: [
2469
+ /* @__PURE__ */ jsx(
2470
+ CalendarMonthButton,
2471
+ {
2472
+ ref: monthButtonRef,
2473
+ tabIndex: _disableFocus ? -1 : toolbarFocus === toolbarFocusStates[0] ? 0 : -1,
2474
+ "data-calendar-header-button": true,
2475
+ "data-calendar-header-button-name": toolbarFocusStates[0],
2476
+ calendarSelectionState,
2477
+ onClick: () => {
2478
+ setCalendarSelectionState(
2479
+ (prev) => prev === "month" ? "day" : "month"
2480
+ );
2481
+ setToolbarFocus(toolbarFocusStates[0]);
2482
+ }
2483
+ }
2484
+ ),
2485
+ /* @__PURE__ */ jsx(
2486
+ CalendarYearButton,
2487
+ {
2488
+ ref: yearButtonRef,
2489
+ tabIndex: _disableFocus ? -1 : toolbarFocus === toolbarFocusStates[1] ? 0 : -1,
2490
+ "data-calendar-header-button": true,
2491
+ "data-calendar-header-button-name": toolbarFocusStates[1],
2492
+ calendarSelectionState,
2493
+ onClick: () => {
2494
+ setCalendarSelectionState(
2495
+ (prev) => prev === "year" ? "day" : "year"
2496
+ );
2497
+ setToolbarFocus(toolbarFocusStates[1]);
2498
+ }
2499
+ }
2500
+ ),
2501
+ calendarSelectionState === "day" && /* @__PURE__ */ jsxs(Fragment, { children: [
2502
+ /* @__PURE__ */ jsx(
2503
+ CalendarPrev,
2504
+ {
2505
+ tabIndex: _disableFocus ? -1 : toolbarFocus === toolbarFocusStates[2] ? 0 : -1,
2506
+ "data-calendar-header-button": true,
2507
+ "data-calendar-header-button-name": toolbarFocusStates[2],
2508
+ onClick: () => setToolbarFocus(toolbarFocusStates[2])
2509
+ }
2510
+ ),
2511
+ /* @__PURE__ */ jsx(
2512
+ CalendarNext,
2513
+ {
2514
+ tabIndex: _disableFocus ? -1 : toolbarFocus === toolbarFocusStates[3] ? 0 : -1,
2515
+ "data-calendar-header-button": true,
2516
+ "data-calendar-header-button-name": toolbarFocusStates[3],
2517
+ onClick: () => setToolbarFocus(toolbarFocusStates[3])
2518
+ }
2519
+ ),
2520
+ /* @__PURE__ */ jsx(
2521
+ CalendarNow,
2522
+ {
2523
+ tabIndex: _disableFocus ? -1 : toolbarFocus === toolbarFocusStates[4] ? 0 : -1,
2524
+ "data-calendar-header-button": true,
2525
+ "data-calendar-header-button-name": toolbarFocusStates[4],
2526
+ onClickFixed: () => setToolbarFocus(toolbarFocusStates[4])
2527
+ }
2528
+ )
2529
+ ] })
2530
+ ]
2531
+ }
2532
+ ) }),
2533
+ calendarSelectionState === "day" && /* @__PURE__ */ jsx(CalendarMonth, {}),
2534
+ calendarSelectionState === "month" && /* @__PURE__ */ jsx(CalendarMonthSelection, { onMonthSelection: handleMonthSelection }),
2535
+ calendarSelectionState === "year" && // Wrapper div provides some manual offsetting to account for internal padding of the year selector
2536
+ /* @__PURE__ */ jsx("div", { className: styles$1["year-selector"], children: /* @__PURE__ */ jsx(
2537
+ YearSelector,
2538
+ {
2539
+ onConfirm: handleYearSelection,
2540
+ required: true,
2541
+ defaultValue: selectedYear,
2542
+ min: normalizedMinDate?.year,
2543
+ max: normalizedMaxDate?.year
2544
+ }
2545
+ ) })
2546
+ ]
2547
+ }
2548
+ ) });
2549
+ }
2550
+ );
2551
+ CalendarElement.displayName = "Calendar";
2552
+ const Calendar = Object.assign(CalendarElement, {
2553
+ /**
2554
+ * Calendar.Now component for navigating to today's date.
2555
+ *
2556
+ * Features:
2557
+ * - Quick navigation to current date
2558
+ * - Accessible button with proper ARIA labels
2559
+ * - Integrates with calendar context
2560
+ * - Data tracking integration for analytics
2561
+ *
2562
+ * @example
2563
+ * <Calendar.Now />
2564
+ */
2565
+ Now: CalendarNow,
2566
+ /**
2567
+ * Calendar.Month component for displaying the month grid.
2568
+ *
2569
+ * Features:
2570
+ * - Displays calendar days in a table format
2571
+ * - Handles day selection and navigation
2572
+ * - Supports range selection mode
2573
+ * - Accessible with proper ARIA attributes
2574
+ * - Data tracking integration for analytics
2575
+ *
2576
+ * @example
2577
+ * <Calendar.Month />
2578
+ */
2579
+ Month: CalendarMonth,
2580
+ /**
2581
+ * Calendar.Next component for navigating to the next month.
2582
+ *
2583
+ * Features:
2584
+ * - Navigation to next month
2585
+ * - Accessible button with proper ARIA labels
2586
+ * - Integrates with calendar context
2587
+ * - Data tracking integration for analytics
2588
+ *
2589
+ * @example
2590
+ * <Calendar.Next />
2591
+ */
2592
+ Next: CalendarNext,
2593
+ /**
2594
+ * Calendar.Prev component for navigating to the previous month.
2595
+ *
2596
+ * Features:
2597
+ * - Navigation to previous month
2598
+ * - Accessible button with proper ARIA labels
2599
+ * - Integrates with calendar context
2600
+ * - Data tracking integration for analytics
2601
+ *
2602
+ * @example
2603
+ * <Calendar.Prev />
2604
+ */
2605
+ Prev: CalendarPrev,
2606
+ /**
2607
+ * Calendar.MonthButton component for switching to month selection view.
2608
+ *
2609
+ * Features:
2610
+ * - Switches calendar to month selection mode
2611
+ * - Accessible button with proper ARIA labels
2612
+ * - Integrates with calendar context
2613
+ * - Data tracking integration for analytics
2614
+ *
2615
+ * @example
2616
+ * <Calendar.MonthButton />
2617
+ */
2618
+ MonthButton: CalendarMonthButton,
2619
+ /**
2620
+ * Calendar.YearButton component for switching to year selection view.
2621
+ *
2622
+ * Features:
2623
+ * - Switches calendar to year selection mode
2624
+ * - Accessible button with proper ARIA labels
2625
+ * - Integrates with calendar context
2626
+ * - Data tracking integration for analytics
2627
+ *
2628
+ * @example
2629
+ * <Calendar.YearButton />
2630
+ */
2631
+ YearButton: CalendarYearButton
2632
+ });
2633
+
2634
+ export { CalendarBetaPropsContext as C, Calendar as a, CalendarNow as b, CalendarYearButton as c, CalendarPrev as d, CalendarNext as e, CalendarMonthButton as f, CalendarMonth as g, useCalendarBetaProps as u };
2635
+ //# sourceMappingURL=Calendar-BFWJ7Rlq.js.map