@mirohq/design-system-calendar 2.4.42 → 2.5.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/main.js +1268 -63
- package/dist/main.js.map +1 -1
- package/dist/module.js +1272 -67
- package/dist/module.js.map +1 -1
- package/dist/types.d.ts +48 -2
- package/package.json +5 -5
package/dist/main.js
CHANGED
|
@@ -123,6 +123,18 @@ const ClearAction = React.forwardRef(({ "aria-label": ariaLabel, label, ...restP
|
|
|
123
123
|
/* @__PURE__ */ jsxRuntime.jsx(designSystemTooltip.Tooltip.Content, { children: label })
|
|
124
124
|
] }));
|
|
125
125
|
|
|
126
|
+
const PERIOD_TO_VIEW_MODE = {
|
|
127
|
+
quarter: "quarters",
|
|
128
|
+
month: "months"
|
|
129
|
+
};
|
|
130
|
+
const getNavigationYear = (value) => {
|
|
131
|
+
var _a;
|
|
132
|
+
if (value == null) {
|
|
133
|
+
return (/* @__PURE__ */ new Date()).getFullYear();
|
|
134
|
+
}
|
|
135
|
+
const date = "start" in value ? value.start : value;
|
|
136
|
+
return (_a = date == null ? void 0 : date.year) != null ? _a : (/* @__PURE__ */ new Date()).getFullYear();
|
|
137
|
+
};
|
|
126
138
|
const CalendarContext = React.createContext({});
|
|
127
139
|
const CalendarProvider = ({
|
|
128
140
|
children,
|
|
@@ -136,7 +148,7 @@ const CalendarProvider = ({
|
|
|
136
148
|
onClose,
|
|
137
149
|
...restProps
|
|
138
150
|
}) => {
|
|
139
|
-
var _a;
|
|
151
|
+
var _a, _b;
|
|
140
152
|
const [immediateSave, setImmediateSave] = React.useState(false);
|
|
141
153
|
const [internalCalendarValue, setInternalCalendarValue] = React.useState(valueProp != null ? valueProp : defaultValueProp);
|
|
142
154
|
const visibleDuration = React.useMemo(
|
|
@@ -150,6 +162,13 @@ const CalendarProvider = ({
|
|
|
150
162
|
defaultProp: defaultValueProp,
|
|
151
163
|
onChange: onValueChange
|
|
152
164
|
});
|
|
165
|
+
const defaultViewMode = (_a = restProps.period != null ? PERIOD_TO_VIEW_MODE[restProps.period] : void 0) != null ? _a : "days";
|
|
166
|
+
const [viewMode, setViewMode] = React.useState(defaultViewMode);
|
|
167
|
+
const [navigationYear, setNavigationYear] = React.useState(
|
|
168
|
+
() => getNavigationYear(value)
|
|
169
|
+
);
|
|
170
|
+
const valueRef = React.useRef(value);
|
|
171
|
+
valueRef.current = value;
|
|
153
172
|
const [open = false, setOpen] = reactUseControllableState.useControllableState({
|
|
154
173
|
prop: openProp,
|
|
155
174
|
defaultProp: defaultOpenProp,
|
|
@@ -157,10 +176,20 @@ const CalendarProvider = ({
|
|
|
157
176
|
if (state) {
|
|
158
177
|
onOpen == null ? void 0 : onOpen();
|
|
159
178
|
} else {
|
|
179
|
+
setViewMode(defaultViewMode);
|
|
160
180
|
onClose == null ? void 0 : onClose();
|
|
161
181
|
}
|
|
162
182
|
}
|
|
163
183
|
});
|
|
184
|
+
const valueYear = getNavigationYear(value);
|
|
185
|
+
React.useEffect(() => {
|
|
186
|
+
setNavigationYear(valueYear);
|
|
187
|
+
}, [valueYear]);
|
|
188
|
+
React.useEffect(() => {
|
|
189
|
+
if (open) {
|
|
190
|
+
setNavigationYear(getNavigationYear(valueRef.current));
|
|
191
|
+
}
|
|
192
|
+
}, [open]);
|
|
164
193
|
const onCalendarDateClick = React.useCallback(
|
|
165
194
|
(value2) => {
|
|
166
195
|
if (immediateSave) {
|
|
@@ -176,11 +205,15 @@ const CalendarProvider = ({
|
|
|
176
205
|
setValue(internalCalendarValue);
|
|
177
206
|
setOpen(false);
|
|
178
207
|
};
|
|
208
|
+
const periodImpliesNavigation = restProps.period === "quarter" || restProps.period === "month" || restProps.period === "week";
|
|
209
|
+
const effectivePeriodNavigation = restProps.navigation === true && visibleMonths <= 1 || periodImpliesNavigation;
|
|
210
|
+
const effectiveViewMode = effectivePeriodNavigation ? viewMode : "days";
|
|
179
211
|
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
180
212
|
CalendarContext.Provider,
|
|
181
213
|
{
|
|
182
214
|
value: {
|
|
183
215
|
...restProps,
|
|
216
|
+
navigation: effectivePeriodNavigation,
|
|
184
217
|
visibleDuration,
|
|
185
218
|
value,
|
|
186
219
|
setValue,
|
|
@@ -189,8 +222,11 @@ const CalendarProvider = ({
|
|
|
189
222
|
onCalendarDateClick,
|
|
190
223
|
setImmediateSave,
|
|
191
224
|
onSaveClick,
|
|
192
|
-
|
|
193
|
-
|
|
225
|
+
calendarValue: (_b = immediateSave ? internalCalendarValue : value) != null ? _b : null,
|
|
226
|
+
viewMode: effectiveViewMode,
|
|
227
|
+
setViewMode,
|
|
228
|
+
navigationYear,
|
|
229
|
+
setNavigationYear
|
|
194
230
|
},
|
|
195
231
|
children
|
|
196
232
|
}
|
|
@@ -253,6 +289,298 @@ const Trigger = React.forwardRef(
|
|
|
253
289
|
}
|
|
254
290
|
);
|
|
255
291
|
|
|
292
|
+
const DECADE_SIZE = 12;
|
|
293
|
+
|
|
294
|
+
const StyledValue = designSystemStitches.styled(designSystemPrimitive.Primitive.span, {});
|
|
295
|
+
|
|
296
|
+
const en = {
|
|
297
|
+
quarter: (q) => "Q".concat(q),
|
|
298
|
+
quarterWithYear: (label, year) => "".concat(label, " ").concat(year),
|
|
299
|
+
views: { months: "months", quarters: "quarters", years: "years" },
|
|
300
|
+
switchView: (title, nextView) => "".concat(title, ", switch to ").concat(nextView, " view"),
|
|
301
|
+
previousYear: "Previous year",
|
|
302
|
+
nextYear: "Next year",
|
|
303
|
+
previousYears: (n) => "Previous ".concat(n, " years"),
|
|
304
|
+
nextYears: (n) => "Next ".concat(n, " years")
|
|
305
|
+
};
|
|
306
|
+
const STRINGS = {
|
|
307
|
+
en,
|
|
308
|
+
de: {
|
|
309
|
+
quarter: (q) => "Q".concat(q),
|
|
310
|
+
quarterWithYear: (label, year) => "".concat(label, " ").concat(year),
|
|
311
|
+
views: { months: "Monate", quarters: "Quartale", years: "Jahre" },
|
|
312
|
+
switchView: (title, nextView) => "".concat(title, ", zur Ansicht ").concat(nextView, " wechseln"),
|
|
313
|
+
previousYear: "Vorheriges Jahr",
|
|
314
|
+
nextYear: "N\xE4chstes Jahr",
|
|
315
|
+
previousYears: (n) => "Vorherige ".concat(n, " Jahre"),
|
|
316
|
+
nextYears: (n) => "N\xE4chste ".concat(n, " Jahre")
|
|
317
|
+
},
|
|
318
|
+
es: {
|
|
319
|
+
quarter: (q) => "T".concat(q),
|
|
320
|
+
quarterWithYear: (label, year) => "".concat(label, " ").concat(year),
|
|
321
|
+
views: { months: "meses", quarters: "trimestres", years: "a\xF1os" },
|
|
322
|
+
switchView: (title, nextView) => "".concat(title, ", cambiar a la vista de ").concat(nextView),
|
|
323
|
+
previousYear: "A\xF1o anterior",
|
|
324
|
+
nextYear: "A\xF1o siguiente",
|
|
325
|
+
previousYears: (n) => "".concat(n, " a\xF1os anteriores"),
|
|
326
|
+
nextYears: (n) => "".concat(n, " a\xF1os siguientes")
|
|
327
|
+
},
|
|
328
|
+
fr: {
|
|
329
|
+
quarter: (q) => "T".concat(q),
|
|
330
|
+
quarterWithYear: (label, year) => "".concat(label, " ").concat(year),
|
|
331
|
+
views: { months: "mois", quarters: "trimestres", years: "ann\xE9es" },
|
|
332
|
+
switchView: (title, nextView) => "".concat(title, ", passer \xE0 la vue ").concat(nextView),
|
|
333
|
+
previousYear: "Ann\xE9e pr\xE9c\xE9dente",
|
|
334
|
+
nextYear: "Ann\xE9e suivante",
|
|
335
|
+
previousYears: (n) => "".concat(n, " ann\xE9es pr\xE9c\xE9dentes"),
|
|
336
|
+
nextYears: (n) => "".concat(n, " ann\xE9es suivantes")
|
|
337
|
+
},
|
|
338
|
+
it: {
|
|
339
|
+
quarter: (q) => "T".concat(q),
|
|
340
|
+
quarterWithYear: (label, year) => "".concat(label, " ").concat(year),
|
|
341
|
+
views: { months: "mesi", quarters: "trimestri", years: "anni" },
|
|
342
|
+
switchView: (title, nextView) => "".concat(title, ", passa alla vista ").concat(nextView),
|
|
343
|
+
previousYear: "Anno precedente",
|
|
344
|
+
nextYear: "Anno successivo",
|
|
345
|
+
previousYears: (n) => "".concat(n, " anni precedenti"),
|
|
346
|
+
nextYears: (n) => "".concat(n, " anni successivi")
|
|
347
|
+
},
|
|
348
|
+
ja: {
|
|
349
|
+
quarter: (q) => "\u7B2C".concat(q, "\u56DB\u534A\u671F"),
|
|
350
|
+
quarterWithYear: (label, year) => "".concat(year, "\u5E74").concat(label),
|
|
351
|
+
views: { months: "\u6708", quarters: "\u56DB\u534A\u671F", years: "\u5E74" },
|
|
352
|
+
switchView: (title, nextView) => "".concat(title, "\u3001").concat(nextView, "\u8868\u793A\u306B\u5207\u308A\u66FF\u3048"),
|
|
353
|
+
previousYear: "\u524D\u5E74",
|
|
354
|
+
nextYear: "\u7FCC\u5E74",
|
|
355
|
+
previousYears: (n) => "\u524D\u306E".concat(n, "\u5E74"),
|
|
356
|
+
nextYears: (n) => "\u6B21\u306E".concat(n, "\u5E74")
|
|
357
|
+
},
|
|
358
|
+
ko: {
|
|
359
|
+
quarter: (q) => "".concat(q, "\uBD84\uAE30"),
|
|
360
|
+
quarterWithYear: (label, year) => "".concat(year, "\uB144 ").concat(label),
|
|
361
|
+
views: { months: "\uC6D4", quarters: "\uBD84\uAE30", years: "\uB144" },
|
|
362
|
+
switchView: (title, nextView) => "".concat(title, ", ").concat(nextView, " \uBCF4\uAE30\uB85C \uC804\uD658"),
|
|
363
|
+
previousYear: "\uC774\uC804 \uD574",
|
|
364
|
+
nextYear: "\uB2E4\uC74C \uD574",
|
|
365
|
+
previousYears: (n) => "\uC774\uC804 ".concat(n, "\uB144"),
|
|
366
|
+
nextYears: (n) => "\uB2E4\uC74C ".concat(n, "\uB144")
|
|
367
|
+
},
|
|
368
|
+
nl: {
|
|
369
|
+
quarter: (q) => "K".concat(q),
|
|
370
|
+
quarterWithYear: (label, year) => "".concat(label, " ").concat(year),
|
|
371
|
+
views: { months: "maanden", quarters: "kwartalen", years: "jaren" },
|
|
372
|
+
switchView: (title, nextView) => "".concat(title, ", ga naar weergave ").concat(nextView),
|
|
373
|
+
previousYear: "Vorig jaar",
|
|
374
|
+
nextYear: "Volgend jaar",
|
|
375
|
+
previousYears: (n) => "Vorige ".concat(n, " jaar"),
|
|
376
|
+
nextYears: (n) => "Volgende ".concat(n, " jaar")
|
|
377
|
+
},
|
|
378
|
+
pl: {
|
|
379
|
+
quarter: (q) => "K".concat(q),
|
|
380
|
+
quarterWithYear: (label, year) => "".concat(label, " ").concat(year),
|
|
381
|
+
views: { months: "miesi\u0105ce", quarters: "kwarta\u0142y", years: "lata" },
|
|
382
|
+
switchView: (title, nextView) => "".concat(title, ", prze\u0142\u0105cz na widok: ").concat(nextView),
|
|
383
|
+
previousYear: "Poprzedni rok",
|
|
384
|
+
nextYear: "Nast\u0119pny rok",
|
|
385
|
+
previousYears: (n) => "Poprzednie ".concat(n, " lat"),
|
|
386
|
+
nextYears: (n) => "Nast\u0119pne ".concat(n, " lat")
|
|
387
|
+
},
|
|
388
|
+
pt: {
|
|
389
|
+
quarter: (q) => "T".concat(q),
|
|
390
|
+
quarterWithYear: (label, year) => "".concat(label, " ").concat(year),
|
|
391
|
+
views: { months: "meses", quarters: "trimestres", years: "anos" },
|
|
392
|
+
switchView: (title, nextView) => "".concat(title, ", mudar para a visualiza\xE7\xE3o de ").concat(nextView),
|
|
393
|
+
previousYear: "Ano anterior",
|
|
394
|
+
nextYear: "Pr\xF3ximo ano",
|
|
395
|
+
previousYears: (n) => "".concat(n, " anos anteriores"),
|
|
396
|
+
nextYears: (n) => "Pr\xF3ximos ".concat(n, " anos")
|
|
397
|
+
},
|
|
398
|
+
ru: {
|
|
399
|
+
quarter: (q) => "".concat(q, " \u043A\u0432."),
|
|
400
|
+
quarterWithYear: (label, year) => "".concat(label, " ").concat(year),
|
|
401
|
+
views: { months: "\u043C\u0435\u0441\u044F\u0446\u044B", quarters: "\u043A\u0432\u0430\u0440\u0442\u0430\u043B\u044B", years: "\u0433\u043E\u0434\u044B" },
|
|
402
|
+
switchView: (title, nextView) => "".concat(title, ", \u043F\u0435\u0440\u0435\u043A\u043B\u044E\u0447\u0438\u0442\u044C\u0441\u044F \u043D\u0430 ").concat(nextView),
|
|
403
|
+
previousYear: "\u041F\u0440\u0435\u0434\u044B\u0434\u0443\u0449\u0438\u0439 \u0433\u043E\u0434",
|
|
404
|
+
nextYear: "\u0421\u043B\u0435\u0434\u0443\u044E\u0449\u0438\u0439 \u0433\u043E\u0434",
|
|
405
|
+
previousYears: (n) => "\u041F\u0440\u0435\u0434\u044B\u0434\u0443\u0449\u0438\u0435 ".concat(n, " \u043B\u0435\u0442"),
|
|
406
|
+
nextYears: (n) => "\u0421\u043B\u0435\u0434\u0443\u044E\u0449\u0438\u0435 ".concat(n, " \u043B\u0435\u0442")
|
|
407
|
+
},
|
|
408
|
+
tr: {
|
|
409
|
+
quarter: (q) => "\xC7".concat(q),
|
|
410
|
+
quarterWithYear: (label, year) => "".concat(label, " ").concat(year),
|
|
411
|
+
views: { months: "aylar", quarters: "\xE7eyrekler", years: "y\u0131llar" },
|
|
412
|
+
switchView: (title, nextView) => "".concat(title, ", ").concat(nextView, " g\xF6r\xFCn\xFCm\xFCne ge\xE7"),
|
|
413
|
+
previousYear: "\xD6nceki y\u0131l",
|
|
414
|
+
nextYear: "Sonraki y\u0131l",
|
|
415
|
+
previousYears: (n) => "\xD6nceki ".concat(n, " y\u0131l"),
|
|
416
|
+
nextYears: (n) => "Sonraki ".concat(n, " y\u0131l")
|
|
417
|
+
},
|
|
418
|
+
uk: {
|
|
419
|
+
quarter: (q) => "".concat(q, " \u043A\u0432."),
|
|
420
|
+
quarterWithYear: (label, year) => "".concat(label, " ").concat(year),
|
|
421
|
+
views: { months: "\u043C\u0456\u0441\u044F\u0446\u0456", quarters: "\u043A\u0432\u0430\u0440\u0442\u0430\u043B\u0438", years: "\u0440\u043E\u043A\u0438" },
|
|
422
|
+
switchView: (title, nextView) => "".concat(title, ", \u043F\u0435\u0440\u0435\u0439\u0442\u0438 \u0434\u043E ").concat(nextView),
|
|
423
|
+
previousYear: "\u041F\u043E\u043F\u0435\u0440\u0435\u0434\u043D\u0456\u0439 \u0440\u0456\u043A",
|
|
424
|
+
nextYear: "\u041D\u0430\u0441\u0442\u0443\u043F\u043D\u0438\u0439 \u0440\u0456\u043A",
|
|
425
|
+
previousYears: (n) => "\u041F\u043E\u043F\u0435\u0440\u0435\u0434\u043D\u0456 ".concat(n, " \u0440\u043E\u043A\u0456\u0432"),
|
|
426
|
+
nextYears: (n) => "\u041D\u0430\u0441\u0442\u0443\u043F\u043D\u0456 ".concat(n, " \u0440\u043E\u043A\u0456\u0432")
|
|
427
|
+
},
|
|
428
|
+
zh: {
|
|
429
|
+
quarter: (q) => "\u7B2C".concat(q, "\u5B63\u5EA6"),
|
|
430
|
+
quarterWithYear: (label, year) => "".concat(year, "\u5E74").concat(label),
|
|
431
|
+
views: { months: "\u6708\u4EFD", quarters: "\u5B63\u5EA6", years: "\u5E74\u4EFD" },
|
|
432
|
+
switchView: (title, nextView) => "".concat(title, "\uFF0C\u5207\u6362\u5230").concat(nextView, "\u89C6\u56FE"),
|
|
433
|
+
previousYear: "\u4E0A\u4E00\u5E74",
|
|
434
|
+
nextYear: "\u4E0B\u4E00\u5E74",
|
|
435
|
+
previousYears: (n) => "\u524D".concat(n, "\u5E74"),
|
|
436
|
+
nextYears: (n) => "\u540E".concat(n, "\u5E74")
|
|
437
|
+
}
|
|
438
|
+
};
|
|
439
|
+
const getCalendarStrings = (locale) => {
|
|
440
|
+
var _a;
|
|
441
|
+
return (_a = STRINGS[locale.split(/[-_]/)[0].toLowerCase()]) != null ? _a : en;
|
|
442
|
+
};
|
|
443
|
+
const useCalendarStrings = () => {
|
|
444
|
+
const { locale } = reactAria.useLocale();
|
|
445
|
+
return React.useMemo(() => getCalendarStrings(locale), [locale]);
|
|
446
|
+
};
|
|
447
|
+
|
|
448
|
+
const DEFAULT_FORMAT = {
|
|
449
|
+
day: "2-digit",
|
|
450
|
+
month: "short",
|
|
451
|
+
year: "numeric"
|
|
452
|
+
};
|
|
453
|
+
const PERIOD_DAY_FORMAT = {
|
|
454
|
+
day: "numeric",
|
|
455
|
+
month: "short"
|
|
456
|
+
};
|
|
457
|
+
const PERIOD_WEEK_FORMAT = PERIOD_DAY_FORMAT;
|
|
458
|
+
const PERIOD_MONTH_FORMAT = {
|
|
459
|
+
month: "short",
|
|
460
|
+
year: "2-digit"
|
|
461
|
+
};
|
|
462
|
+
function formatDate(date, formatter, timeZone) {
|
|
463
|
+
return formatter.format(date.toDate(timeZone));
|
|
464
|
+
}
|
|
465
|
+
function formatValue(value, formatter, timeZone) {
|
|
466
|
+
if (value == null || value === void 0) {
|
|
467
|
+
return void 0;
|
|
468
|
+
}
|
|
469
|
+
if ("start" in value) {
|
|
470
|
+
if (value.start == null || value.end == null) {
|
|
471
|
+
return void 0;
|
|
472
|
+
}
|
|
473
|
+
return "".concat(formatDate(value.start, formatter, timeZone), " - ").concat(formatDate(
|
|
474
|
+
value.end,
|
|
475
|
+
formatter,
|
|
476
|
+
timeZone
|
|
477
|
+
));
|
|
478
|
+
}
|
|
479
|
+
return formatDate(value, formatter, timeZone);
|
|
480
|
+
}
|
|
481
|
+
function isCurrentPeriod(value, period, locale) {
|
|
482
|
+
const todayDate = date.today(date.getLocalTimeZone());
|
|
483
|
+
switch (period) {
|
|
484
|
+
case "day":
|
|
485
|
+
case void 0:
|
|
486
|
+
return date.isSameDay(value, todayDate);
|
|
487
|
+
case "week": {
|
|
488
|
+
const currentWeekStart = date.startOfWeek(todayDate, locale);
|
|
489
|
+
const selectedWeekStart = date.startOfWeek(value, locale);
|
|
490
|
+
return date.isSameDay(currentWeekStart, selectedWeekStart);
|
|
491
|
+
}
|
|
492
|
+
case "month":
|
|
493
|
+
return value.year === todayDate.year && value.month === todayDate.month;
|
|
494
|
+
case "quarter": {
|
|
495
|
+
const currentQuarter = Math.ceil(todayDate.month / 3);
|
|
496
|
+
const selectedQuarter = Math.ceil(value.month / 3);
|
|
497
|
+
return value.year === todayDate.year && selectedQuarter === currentQuarter;
|
|
498
|
+
}
|
|
499
|
+
default:
|
|
500
|
+
return false;
|
|
501
|
+
}
|
|
502
|
+
}
|
|
503
|
+
const Value = React.forwardRef(({ format, currentLabel, ...restProps }, forwardRef) => {
|
|
504
|
+
const { value, period, formatQuarterLabel } = useCalendarContext();
|
|
505
|
+
const { locale } = reactAria.useLocale();
|
|
506
|
+
const strings = useCalendarStrings();
|
|
507
|
+
const yearFormatter = React.useMemo(
|
|
508
|
+
() => new Intl.NumberFormat(locale, { useGrouping: false }),
|
|
509
|
+
[locale]
|
|
510
|
+
);
|
|
511
|
+
const timeZone = React.useMemo(date.getLocalTimeZone, []);
|
|
512
|
+
const effectivePeriod = period != null ? period : "day";
|
|
513
|
+
const periodFormat = React.useMemo(() => {
|
|
514
|
+
if (format != null) return format;
|
|
515
|
+
if (period == null) return DEFAULT_FORMAT;
|
|
516
|
+
switch (period) {
|
|
517
|
+
case "day":
|
|
518
|
+
return PERIOD_DAY_FORMAT;
|
|
519
|
+
case "week":
|
|
520
|
+
return PERIOD_WEEK_FORMAT;
|
|
521
|
+
case "month":
|
|
522
|
+
return PERIOD_MONTH_FORMAT;
|
|
523
|
+
default:
|
|
524
|
+
return DEFAULT_FORMAT;
|
|
525
|
+
}
|
|
526
|
+
}, [format, period]);
|
|
527
|
+
const formatWithTimeZone = React.useMemo(
|
|
528
|
+
() => ({ ...periodFormat, timeZone }),
|
|
529
|
+
[periodFormat, timeZone]
|
|
530
|
+
);
|
|
531
|
+
const dateFormatter = reactAria.useDateFormatter(formatWithTimeZone);
|
|
532
|
+
const dayOnlyFormat = React.useMemo(
|
|
533
|
+
() => ({ day: "numeric", timeZone }),
|
|
534
|
+
[timeZone]
|
|
535
|
+
);
|
|
536
|
+
const dayOnlyFormatter = reactAria.useDateFormatter(dayOnlyFormat);
|
|
537
|
+
let valueToDisplay;
|
|
538
|
+
if (value == null) {
|
|
539
|
+
valueToDisplay = void 0;
|
|
540
|
+
} else if ("start" in value) {
|
|
541
|
+
valueToDisplay = formatValue(value, dateFormatter, timeZone);
|
|
542
|
+
} else {
|
|
543
|
+
switch (effectivePeriod) {
|
|
544
|
+
case "week": {
|
|
545
|
+
const calendarDate = value;
|
|
546
|
+
const weekStart = date.startOfWeek(calendarDate, locale);
|
|
547
|
+
const weekEnd = date.endOfWeek(calendarDate, locale);
|
|
548
|
+
const startStr = formatDate(weekStart, dateFormatter, timeZone);
|
|
549
|
+
if (weekStart.month === weekEnd.month) {
|
|
550
|
+
const endDay = dayOnlyFormatter.format(weekEnd.toDate(timeZone));
|
|
551
|
+
valueToDisplay = "".concat(startStr, " - ").concat(endDay);
|
|
552
|
+
} else {
|
|
553
|
+
const endStr = formatDate(weekEnd, dateFormatter, timeZone);
|
|
554
|
+
if (startStr != null && endStr != null) {
|
|
555
|
+
valueToDisplay = "".concat(startStr, " - ").concat(endStr);
|
|
556
|
+
}
|
|
557
|
+
}
|
|
558
|
+
break;
|
|
559
|
+
}
|
|
560
|
+
case "quarter": {
|
|
561
|
+
const quarter = Math.ceil(value.month / 3);
|
|
562
|
+
valueToDisplay = strings.quarterWithYear(
|
|
563
|
+
(formatQuarterLabel != null ? formatQuarterLabel : strings.quarter)(quarter),
|
|
564
|
+
yearFormatter.format(value.year)
|
|
565
|
+
);
|
|
566
|
+
break;
|
|
567
|
+
}
|
|
568
|
+
case "month": {
|
|
569
|
+
valueToDisplay = formatDate(value, dateFormatter, timeZone);
|
|
570
|
+
break;
|
|
571
|
+
}
|
|
572
|
+
default: {
|
|
573
|
+
valueToDisplay = formatDate(value, dateFormatter, timeZone);
|
|
574
|
+
break;
|
|
575
|
+
}
|
|
576
|
+
}
|
|
577
|
+
if (valueToDisplay != null && currentLabel != null && !("start" in value) && isCurrentPeriod(value, period, locale)) {
|
|
578
|
+
valueToDisplay = "".concat(valueToDisplay, " (").concat(currentLabel, ")");
|
|
579
|
+
}
|
|
580
|
+
}
|
|
581
|
+
return /* @__PURE__ */ jsxRuntime.jsx(StyledValue, { ref: forwardRef, ...restProps, children: valueToDisplay });
|
|
582
|
+
});
|
|
583
|
+
|
|
256
584
|
const StyledContent = designSystemStitches.styled(RadixPopover.Content, {
|
|
257
585
|
...designSystemStyles.floating.css(),
|
|
258
586
|
zIndex: "$calendar",
|
|
@@ -274,12 +602,54 @@ const StyledClearContent = designSystemStitches.styled(designSystemPrimitive.Pri
|
|
|
274
602
|
padding: "$200",
|
|
275
603
|
borderTop: "1px solid $border-default"
|
|
276
604
|
});
|
|
605
|
+
const StyledGoToCurrent = designSystemStitches.styled(designSystemBaseButton.BaseButton, {
|
|
606
|
+
display: "flex",
|
|
607
|
+
alignItems: "center",
|
|
608
|
+
gap: "$100",
|
|
609
|
+
marginTop: "$150",
|
|
610
|
+
padding: "$100 $150",
|
|
611
|
+
borderRadius: "$calendar",
|
|
612
|
+
color: "$text-secondary",
|
|
613
|
+
fontSize: "$body-xs",
|
|
614
|
+
lineHeight: "$body-xs",
|
|
615
|
+
fontWeight: "$body-xs",
|
|
616
|
+
"& svg": {
|
|
617
|
+
width: "16px",
|
|
618
|
+
height: "16px",
|
|
619
|
+
color: "$icon-secondary"
|
|
620
|
+
},
|
|
621
|
+
_hover: {
|
|
622
|
+
backgroundColor: "$background-interactive-surface-secondary-hover"
|
|
623
|
+
},
|
|
624
|
+
...designSystemStyles.focus.css({
|
|
625
|
+
boxShadow: "$focus",
|
|
626
|
+
outline: "1px solid transparent"
|
|
627
|
+
})
|
|
628
|
+
});
|
|
277
629
|
|
|
278
630
|
const StyledHeaderTitle = designSystemStitches.styled(designSystemTypography.Heading, {
|
|
279
631
|
margin: 0,
|
|
280
632
|
flex: "2",
|
|
281
633
|
textAlign: "center"
|
|
282
634
|
});
|
|
635
|
+
const StyledHeaderTitleButton = designSystemStitches.styled(designSystemBaseButton.BaseButton, {
|
|
636
|
+
display: "inline-block",
|
|
637
|
+
textAlign: "center",
|
|
638
|
+
fontSize: "$250",
|
|
639
|
+
fontWeight: "$bold",
|
|
640
|
+
lineHeight: "$250",
|
|
641
|
+
color: "$text-interactive-primary",
|
|
642
|
+
borderRadius: "$button",
|
|
643
|
+
padding: "$50 $100",
|
|
644
|
+
...designSystemStyles.focus.css({
|
|
645
|
+
boxShadow: "$focus",
|
|
646
|
+
outline: "1px solid transparent"
|
|
647
|
+
}),
|
|
648
|
+
_hover: {
|
|
649
|
+
color: "$text-interactive-primary-hover",
|
|
650
|
+
backgroundColor: "$background-interactive-surface-secondary-hover"
|
|
651
|
+
}
|
|
652
|
+
});
|
|
283
653
|
const StyledHeaderPlaceholder = designSystemStitches.styled("div", {
|
|
284
654
|
height: "$8",
|
|
285
655
|
// to compensate icon buttons' width and space between 2 calendars
|
|
@@ -307,25 +677,88 @@ const Header = ({
|
|
|
307
677
|
state,
|
|
308
678
|
prevButtonProps,
|
|
309
679
|
nextButtonProps,
|
|
310
|
-
visibleMonths
|
|
680
|
+
visibleMonths,
|
|
681
|
+
yearFormatter,
|
|
682
|
+
onPrevOverride,
|
|
683
|
+
onNextOverride,
|
|
684
|
+
onZoomOut,
|
|
685
|
+
isPrevDisabled,
|
|
686
|
+
isNextDisabled
|
|
311
687
|
}) => {
|
|
688
|
+
const { navigation, viewMode, navigationYear, formatSwitchViewLabel } = useCalendarContext();
|
|
689
|
+
const strings = useCalendarStrings();
|
|
312
690
|
const monthDateFormatter = reactAria.useDateFormatter({
|
|
313
691
|
month: "long",
|
|
314
692
|
year: "numeric",
|
|
315
693
|
timeZone: state.timeZone
|
|
316
694
|
});
|
|
695
|
+
const getTitleText = () => {
|
|
696
|
+
switch (viewMode) {
|
|
697
|
+
case "months":
|
|
698
|
+
case "quarters":
|
|
699
|
+
return yearFormatter.format(navigationYear);
|
|
700
|
+
case "years": {
|
|
701
|
+
const decadeStart = Math.floor(navigationYear / DECADE_SIZE) * DECADE_SIZE;
|
|
702
|
+
return "".concat(yearFormatter.format(decadeStart), "\u2013").concat(yearFormatter.format(
|
|
703
|
+
decadeStart + DECADE_SIZE - 1
|
|
704
|
+
));
|
|
705
|
+
}
|
|
706
|
+
default:
|
|
707
|
+
return monthDateFormatter.format(
|
|
708
|
+
state.visibleRange.start.toDate(state.timeZone)
|
|
709
|
+
);
|
|
710
|
+
}
|
|
711
|
+
};
|
|
712
|
+
const getNextViewLabel = () => {
|
|
713
|
+
if (viewMode === "days") return strings.views.months;
|
|
714
|
+
if (viewMode === "months" || viewMode === "quarters") {
|
|
715
|
+
return strings.views.years;
|
|
716
|
+
}
|
|
717
|
+
return "";
|
|
718
|
+
};
|
|
719
|
+
const isTopLevel = viewMode === "years";
|
|
720
|
+
const showClickableTitle = navigation === true && !isTopLevel;
|
|
721
|
+
const isDayView = viewMode === "days";
|
|
722
|
+
const stepLabels = viewMode === "years" ? {
|
|
723
|
+
prev: strings.previousYears(DECADE_SIZE),
|
|
724
|
+
next: strings.nextYears(DECADE_SIZE)
|
|
725
|
+
} : { prev: strings.previousYear, next: strings.nextYear };
|
|
317
726
|
return /* @__PURE__ */ jsxRuntime.jsxs(StyledHeader, { children: [
|
|
318
|
-
/* @__PURE__ */ jsxRuntime.jsx(HeaderButton, { ...prevButtonProps, children: /* @__PURE__ */ jsxRuntime.jsx(designSystemIcons.IconChevronLeft, {}) })
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
727
|
+
isDayView ? /* @__PURE__ */ jsxRuntime.jsx(HeaderButton, { ...prevButtonProps, children: /* @__PURE__ */ jsxRuntime.jsx(designSystemIcons.IconChevronLeft, {}) }) : /* @__PURE__ */ jsxRuntime.jsx(
|
|
728
|
+
HeaderButton,
|
|
729
|
+
{
|
|
730
|
+
"aria-label": stepLabels.prev,
|
|
731
|
+
isDisabled: isPrevDisabled,
|
|
732
|
+
onClick: onPrevOverride,
|
|
733
|
+
children: /* @__PURE__ */ jsxRuntime.jsx(designSystemIcons.IconChevronLeft, {})
|
|
734
|
+
}
|
|
735
|
+
),
|
|
736
|
+
/* @__PURE__ */ jsxRuntime.jsx(StyledHeaderTitle, { level: 2, styledAs: "h3", children: showClickableTitle ? /* @__PURE__ */ jsxRuntime.jsx(
|
|
737
|
+
StyledHeaderTitleButton,
|
|
738
|
+
{
|
|
739
|
+
onClick: onZoomOut,
|
|
740
|
+
"aria-label": (formatSwitchViewLabel != null ? formatSwitchViewLabel : strings.switchView)(
|
|
741
|
+
getTitleText(),
|
|
742
|
+
getNextViewLabel()
|
|
743
|
+
),
|
|
744
|
+
children: getTitleText()
|
|
745
|
+
}
|
|
746
|
+
) : getTitleText() }),
|
|
747
|
+
visibleMonths === 2 && isDayView && /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
|
|
323
748
|
/* @__PURE__ */ jsxRuntime.jsx(StyledHeaderPlaceholder, {}),
|
|
324
749
|
/* @__PURE__ */ jsxRuntime.jsx(StyledHeaderTitle, { level: 2, styledAs: "h3", children: monthDateFormatter.format(
|
|
325
750
|
state.visibleRange.start.add({ months: 1 }).toDate(state.timeZone)
|
|
326
751
|
) })
|
|
327
752
|
] }),
|
|
328
|
-
/* @__PURE__ */ jsxRuntime.jsx(HeaderButton, { ...nextButtonProps, children: /* @__PURE__ */ jsxRuntime.jsx(designSystemIcons.IconChevronRight, {}) })
|
|
753
|
+
isDayView ? /* @__PURE__ */ jsxRuntime.jsx(HeaderButton, { ...nextButtonProps, children: /* @__PURE__ */ jsxRuntime.jsx(designSystemIcons.IconChevronRight, {}) }) : /* @__PURE__ */ jsxRuntime.jsx(
|
|
754
|
+
HeaderButton,
|
|
755
|
+
{
|
|
756
|
+
"aria-label": stepLabels.next,
|
|
757
|
+
isDisabled: isNextDisabled,
|
|
758
|
+
onClick: onNextOverride,
|
|
759
|
+
children: /* @__PURE__ */ jsxRuntime.jsx(designSystemIcons.IconChevronRight, {})
|
|
760
|
+
}
|
|
761
|
+
)
|
|
329
762
|
] });
|
|
330
763
|
};
|
|
331
764
|
|
|
@@ -405,13 +838,30 @@ const StyledCellContent = designSystemStitches.styled(designSystemPrimitive.Prim
|
|
|
405
838
|
true: {
|
|
406
839
|
display: "none"
|
|
407
840
|
}
|
|
841
|
+
},
|
|
842
|
+
outsideMonth: {
|
|
843
|
+
true: {
|
|
844
|
+
color: "$text-secondary",
|
|
845
|
+
'&[aria-disabled="true"]': {
|
|
846
|
+
textDecoration: "none"
|
|
847
|
+
}
|
|
848
|
+
}
|
|
408
849
|
}
|
|
850
|
+
},
|
|
851
|
+
// Week period: the row is the week, so hovering or focusing anywhere in it
|
|
852
|
+
// highlights the whole week. Cells in the selected week carry no
|
|
853
|
+
// data-week-hover, so the selected styling is not overridden.
|
|
854
|
+
"tr:hover > td > &[data-week-hover], tr:focus-within > td > &[data-week-hover]": {
|
|
855
|
+
backgroundColor: "$background-interactive-surface-secondary-hover",
|
|
856
|
+
borderRadius: 0
|
|
409
857
|
}
|
|
410
858
|
});
|
|
411
859
|
|
|
412
860
|
const Cell = (props) => {
|
|
413
861
|
let { state, date: date$1, currentMonth } = props;
|
|
414
862
|
const ref = React.useRef(null);
|
|
863
|
+
const { period, minDate, maxDate, onCalendarDateClick } = useCalendarContext();
|
|
864
|
+
const { locale } = reactAria.useLocale();
|
|
415
865
|
const { cellProps, buttonProps, isSelected, formattedDate } = reactAria.useCalendarCell(
|
|
416
866
|
{ date: date$1 },
|
|
417
867
|
state,
|
|
@@ -424,15 +874,65 @@ const Cell = (props) => {
|
|
|
424
874
|
const { focusProps } = reactAria.useFocusRing();
|
|
425
875
|
const isRange = isSelected && (!isSelectionStart || !isSelectionEnd);
|
|
426
876
|
const rangeVariant = isRange ? isSelectionStart ? "start" : isSelectionEnd ? "end" : "middle" : void 0;
|
|
427
|
-
|
|
877
|
+
let effectiveSelected = isSelected && (isSelectionStart || isSelectionEnd);
|
|
878
|
+
let effectiveRange = rangeVariant;
|
|
879
|
+
const isWeekPeriod = period === "week";
|
|
880
|
+
if (isWeekPeriod) {
|
|
881
|
+
const selectedValue = props.state.value;
|
|
882
|
+
if (selectedValue != null) {
|
|
883
|
+
const weekStart2 = date.startOfWeek(selectedValue, locale);
|
|
884
|
+
const weekEnd2 = date.endOfWeek(selectedValue, locale);
|
|
885
|
+
const inWeek = date$1.compare(weekStart2) >= 0 && date$1.compare(weekEnd2) <= 0;
|
|
886
|
+
if (inWeek) {
|
|
887
|
+
const isStart = date.isSameDay(date$1, weekStart2);
|
|
888
|
+
const isEnd = date.isSameDay(date$1, weekEnd2);
|
|
889
|
+
effectiveSelected = isStart || isEnd;
|
|
890
|
+
effectiveRange = isStart ? "start" : isEnd ? "end" : "middle";
|
|
891
|
+
} else {
|
|
892
|
+
effectiveSelected = false;
|
|
893
|
+
effectiveRange = void 0;
|
|
894
|
+
}
|
|
895
|
+
}
|
|
896
|
+
}
|
|
897
|
+
const weekStart = isWeekPeriod ? date.startOfWeek(date$1, locale) : null;
|
|
898
|
+
const weekEnd = isWeekPeriod ? date.endOfWeek(date$1, locale) : null;
|
|
899
|
+
const isWeekOutOfBounds = minDate != null && weekStart != null && weekStart.compare(minDate) < 0 || maxDate != null && weekEnd != null && weekEnd.compare(maxDate) > 0;
|
|
900
|
+
const enableOutsideDay = isWeekPeriod && isOutsideMonth && !isWeekOutOfBounds;
|
|
901
|
+
const selectWeek = () => {
|
|
902
|
+
if (weekStart != null) {
|
|
903
|
+
onCalendarDateClick(weekStart);
|
|
904
|
+
}
|
|
905
|
+
};
|
|
906
|
+
let weekDayProps = {};
|
|
907
|
+
if (isWeekPeriod && isWeekOutOfBounds) {
|
|
908
|
+
weekDayProps = { "aria-disabled": true, tabIndex: -1 };
|
|
909
|
+
} else if (enableOutsideDay) {
|
|
910
|
+
weekDayProps = {
|
|
911
|
+
"aria-disabled": void 0,
|
|
912
|
+
tabIndex: effectiveRange === "start" ? 0 : -1,
|
|
913
|
+
onClick: selectWeek,
|
|
914
|
+
onKeyDown: (event) => {
|
|
915
|
+
if (event.key === "Enter" || event.key === " ") {
|
|
916
|
+
event.preventDefault();
|
|
917
|
+
event.stopPropagation();
|
|
918
|
+
selectWeek();
|
|
919
|
+
}
|
|
920
|
+
}
|
|
921
|
+
};
|
|
922
|
+
}
|
|
923
|
+
const gridCellProps = isWeekPeriod && (enableOutsideDay || isWeekOutOfBounds) ? { ...cellProps, "aria-disabled": isWeekOutOfBounds ? true : void 0 } : cellProps;
|
|
924
|
+
return /* @__PURE__ */ jsxRuntime.jsx(StyledCell, { ...gridCellProps, children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
428
925
|
StyledCellContent,
|
|
429
926
|
{
|
|
430
927
|
...reactAria.mergeProps(buttonProps, focusProps),
|
|
928
|
+
...weekDayProps,
|
|
431
929
|
ref,
|
|
432
|
-
selected:
|
|
930
|
+
selected: effectiveSelected,
|
|
433
931
|
today: date.isToday(date$1, date.getLocalTimeZone()),
|
|
434
|
-
range:
|
|
435
|
-
hidden: isOutsideMonth,
|
|
932
|
+
range: effectiveRange,
|
|
933
|
+
hidden: isOutsideMonth && !isWeekPeriod,
|
|
934
|
+
outsideMonth: isOutsideMonth && isWeekPeriod,
|
|
935
|
+
"data-week-hover": isWeekPeriod && effectiveRange == null ? "" : void 0,
|
|
436
936
|
children: formattedDate
|
|
437
937
|
}
|
|
438
938
|
) });
|
|
@@ -476,6 +976,507 @@ const Grid = React.forwardRef(
|
|
|
476
976
|
}
|
|
477
977
|
);
|
|
478
978
|
|
|
979
|
+
const StyledPeriodGrid = designSystemStitches.styled(designSystemPrimitive.Primitive.div, {
|
|
980
|
+
display: "grid",
|
|
981
|
+
gap: "$50",
|
|
982
|
+
padding: "$50 0",
|
|
983
|
+
// Match the day grid width: 7 cells × $10 (40px) = 280px
|
|
984
|
+
width: "calc($10 * 7)",
|
|
985
|
+
variants: {
|
|
986
|
+
columns: {
|
|
987
|
+
2: { gridTemplateColumns: "repeat(2, 1fr)" },
|
|
988
|
+
3: { gridTemplateColumns: "repeat(3, 1fr)" },
|
|
989
|
+
4: { gridTemplateColumns: "repeat(4, 1fr)" }
|
|
990
|
+
}
|
|
991
|
+
},
|
|
992
|
+
defaultVariants: {
|
|
993
|
+
columns: 4
|
|
994
|
+
}
|
|
995
|
+
});
|
|
996
|
+
const StyledPeriodRow = designSystemStitches.styled(designSystemPrimitive.Primitive.div, {
|
|
997
|
+
display: "contents"
|
|
998
|
+
});
|
|
999
|
+
const StyledPeriodGridCell = designSystemStitches.styled(designSystemPrimitive.Primitive.div, {
|
|
1000
|
+
display: "contents"
|
|
1001
|
+
});
|
|
1002
|
+
const StyledPeriodCell = designSystemStitches.styled(designSystemBaseButton.BaseButton, {
|
|
1003
|
+
justifyContent: "center",
|
|
1004
|
+
height: "$10",
|
|
1005
|
+
color: "$text-default",
|
|
1006
|
+
fontSize: "$200",
|
|
1007
|
+
...designSystemStyles.focus.css({
|
|
1008
|
+
position: "relative",
|
|
1009
|
+
zIndex: "1",
|
|
1010
|
+
boxShadow: "$focus",
|
|
1011
|
+
outline: "1px solid transparent"
|
|
1012
|
+
}),
|
|
1013
|
+
'&:not([aria-disabled="true"])': {
|
|
1014
|
+
_hover: {
|
|
1015
|
+
backgroundColor: "$background-interactive-surface-secondary-hover"
|
|
1016
|
+
}
|
|
1017
|
+
},
|
|
1018
|
+
'&[aria-disabled="true"]': {
|
|
1019
|
+
color: "$text-disabled"
|
|
1020
|
+
},
|
|
1021
|
+
variants: {
|
|
1022
|
+
current: {
|
|
1023
|
+
true: {
|
|
1024
|
+
backgroundColor: "$background-interactive-surface-secondary-hover",
|
|
1025
|
+
color: "$text-default"
|
|
1026
|
+
}
|
|
1027
|
+
},
|
|
1028
|
+
selected: {
|
|
1029
|
+
true: {
|
|
1030
|
+
backgroundColor: "$background-interactive-selected",
|
|
1031
|
+
color: "$text-on-interactive-primary",
|
|
1032
|
+
"& span": {
|
|
1033
|
+
color: "inherit"
|
|
1034
|
+
},
|
|
1035
|
+
'&:not([aria-disabled="true"])': {
|
|
1036
|
+
_hover: {
|
|
1037
|
+
backgroundColor: "$background-interactive-primary-hover",
|
|
1038
|
+
color: "$text-on-interactive-primary"
|
|
1039
|
+
}
|
|
1040
|
+
}
|
|
1041
|
+
}
|
|
1042
|
+
},
|
|
1043
|
+
tall: {
|
|
1044
|
+
true: {
|
|
1045
|
+
height: "$14",
|
|
1046
|
+
flexDirection: "column",
|
|
1047
|
+
gap: "$25"
|
|
1048
|
+
}
|
|
1049
|
+
}
|
|
1050
|
+
}
|
|
1051
|
+
});
|
|
1052
|
+
const StyledPeriodCellLabel = designSystemStitches.styled(designSystemPrimitive.Primitive.span, {
|
|
1053
|
+
fontSize: "$100",
|
|
1054
|
+
color: "$text-secondary"
|
|
1055
|
+
});
|
|
1056
|
+
|
|
1057
|
+
const useGridNavigation = ({
|
|
1058
|
+
rows,
|
|
1059
|
+
columns,
|
|
1060
|
+
selectedIndex,
|
|
1061
|
+
currentIndex,
|
|
1062
|
+
resetKey,
|
|
1063
|
+
focusOnMount
|
|
1064
|
+
}) => {
|
|
1065
|
+
const cellRefs = React.useRef(/* @__PURE__ */ new Map());
|
|
1066
|
+
const [focusedRow, setFocusedRow] = React.useState(0);
|
|
1067
|
+
const [focusedCol, setFocusedCol] = React.useState(0);
|
|
1068
|
+
const hasFocusedRef = React.useRef(false);
|
|
1069
|
+
const key = (r, c) => "".concat(r, "-").concat(c);
|
|
1070
|
+
const isEnabled = React.useCallback((r, c) => {
|
|
1071
|
+
const el = cellRefs.current.get(key(r, c));
|
|
1072
|
+
return el != null && el.getAttribute("aria-disabled") !== "true";
|
|
1073
|
+
}, []);
|
|
1074
|
+
const findFirstEnabled = React.useCallback(() => {
|
|
1075
|
+
for (let r = 0; r < rows; r++) {
|
|
1076
|
+
for (let c = 0; c < columns; c++) {
|
|
1077
|
+
if (isEnabled(r, c)) {
|
|
1078
|
+
return [r, c];
|
|
1079
|
+
}
|
|
1080
|
+
}
|
|
1081
|
+
}
|
|
1082
|
+
return null;
|
|
1083
|
+
}, [rows, columns, isEnabled]);
|
|
1084
|
+
const focusCell = React.useCallback(
|
|
1085
|
+
(row, col) => {
|
|
1086
|
+
var _a;
|
|
1087
|
+
if (isEnabled(row, col)) {
|
|
1088
|
+
(_a = cellRefs.current.get(key(row, col))) == null ? void 0 : _a.focus();
|
|
1089
|
+
}
|
|
1090
|
+
},
|
|
1091
|
+
[isEnabled]
|
|
1092
|
+
);
|
|
1093
|
+
const resolveFocusTarget = React.useCallback(() => {
|
|
1094
|
+
for (const index of [selectedIndex, currentIndex]) {
|
|
1095
|
+
if (index == null || index < 0 || index >= rows * columns) {
|
|
1096
|
+
continue;
|
|
1097
|
+
}
|
|
1098
|
+
const candidate = [
|
|
1099
|
+
Math.floor(index / columns),
|
|
1100
|
+
index % columns
|
|
1101
|
+
];
|
|
1102
|
+
if (isEnabled(...candidate)) {
|
|
1103
|
+
return candidate;
|
|
1104
|
+
}
|
|
1105
|
+
}
|
|
1106
|
+
return findFirstEnabled();
|
|
1107
|
+
}, [selectedIndex, currentIndex, rows, columns, isEnabled, findFirstEnabled]);
|
|
1108
|
+
React.useLayoutEffect(() => {
|
|
1109
|
+
const target = resolveFocusTarget();
|
|
1110
|
+
if (target == null) {
|
|
1111
|
+
return;
|
|
1112
|
+
}
|
|
1113
|
+
const [row, col] = target;
|
|
1114
|
+
setFocusedRow(row);
|
|
1115
|
+
setFocusedCol(col);
|
|
1116
|
+
if (focusOnMount === true && !hasFocusedRef.current) {
|
|
1117
|
+
hasFocusedRef.current = true;
|
|
1118
|
+
focusCell(row, col);
|
|
1119
|
+
}
|
|
1120
|
+
}, [resolveFocusTarget, focusCell, focusOnMount, resetKey]);
|
|
1121
|
+
const findNextEnabled = React.useCallback(
|
|
1122
|
+
(row, col, dr, dc) => {
|
|
1123
|
+
let r = row + dr;
|
|
1124
|
+
let c = col + dc;
|
|
1125
|
+
while (r >= 0 && r < rows && c >= 0 && c < columns) {
|
|
1126
|
+
if (isEnabled(r, c)) {
|
|
1127
|
+
return [r, c];
|
|
1128
|
+
}
|
|
1129
|
+
r += dr;
|
|
1130
|
+
c += dc;
|
|
1131
|
+
}
|
|
1132
|
+
return [row, col];
|
|
1133
|
+
},
|
|
1134
|
+
[rows, columns, isEnabled]
|
|
1135
|
+
);
|
|
1136
|
+
const getCellProps = React.useCallback(
|
|
1137
|
+
(row, col) => ({
|
|
1138
|
+
tabIndex: row === focusedRow && col === focusedCol ? 0 : -1,
|
|
1139
|
+
ref: (el) => {
|
|
1140
|
+
const k = key(row, col);
|
|
1141
|
+
if (el != null) {
|
|
1142
|
+
cellRefs.current.set(k, el);
|
|
1143
|
+
} else {
|
|
1144
|
+
cellRefs.current.delete(k);
|
|
1145
|
+
}
|
|
1146
|
+
},
|
|
1147
|
+
onFocus: () => {
|
|
1148
|
+
setFocusedRow(row);
|
|
1149
|
+
setFocusedCol(col);
|
|
1150
|
+
},
|
|
1151
|
+
onKeyDown: (e) => {
|
|
1152
|
+
let nextRow = row;
|
|
1153
|
+
let nextCol = col;
|
|
1154
|
+
switch (e.key) {
|
|
1155
|
+
case "ArrowRight":
|
|
1156
|
+
if (col < columns - 1) {
|
|
1157
|
+
[nextRow, nextCol] = findNextEnabled(row, col, 0, 1);
|
|
1158
|
+
}
|
|
1159
|
+
break;
|
|
1160
|
+
case "ArrowLeft":
|
|
1161
|
+
if (col > 0) {
|
|
1162
|
+
[nextRow, nextCol] = findNextEnabled(row, col, 0, -1);
|
|
1163
|
+
}
|
|
1164
|
+
break;
|
|
1165
|
+
case "ArrowDown":
|
|
1166
|
+
if (row < rows - 1) {
|
|
1167
|
+
[nextRow, nextCol] = findNextEnabled(row, col, 1, 0);
|
|
1168
|
+
}
|
|
1169
|
+
break;
|
|
1170
|
+
case "ArrowUp":
|
|
1171
|
+
if (row > 0) {
|
|
1172
|
+
[nextRow, nextCol] = findNextEnabled(row, col, -1, 0);
|
|
1173
|
+
}
|
|
1174
|
+
break;
|
|
1175
|
+
case "Home": {
|
|
1176
|
+
for (let r = 0; r < rows; r++) {
|
|
1177
|
+
for (let c = 0; c < columns; c++) {
|
|
1178
|
+
if (isEnabled(r, c)) {
|
|
1179
|
+
[nextRow, nextCol] = [r, c];
|
|
1180
|
+
r = rows;
|
|
1181
|
+
break;
|
|
1182
|
+
}
|
|
1183
|
+
}
|
|
1184
|
+
}
|
|
1185
|
+
break;
|
|
1186
|
+
}
|
|
1187
|
+
case "End": {
|
|
1188
|
+
for (let r = rows - 1; r >= 0; r--) {
|
|
1189
|
+
for (let c = columns - 1; c >= 0; c--) {
|
|
1190
|
+
if (isEnabled(r, c)) {
|
|
1191
|
+
[nextRow, nextCol] = [r, c];
|
|
1192
|
+
r = -1;
|
|
1193
|
+
break;
|
|
1194
|
+
}
|
|
1195
|
+
}
|
|
1196
|
+
}
|
|
1197
|
+
break;
|
|
1198
|
+
}
|
|
1199
|
+
default:
|
|
1200
|
+
return;
|
|
1201
|
+
}
|
|
1202
|
+
if (nextRow !== row || nextCol !== col) {
|
|
1203
|
+
e.preventDefault();
|
|
1204
|
+
focusCell(nextRow, nextCol);
|
|
1205
|
+
}
|
|
1206
|
+
}
|
|
1207
|
+
}),
|
|
1208
|
+
[
|
|
1209
|
+
focusedRow,
|
|
1210
|
+
focusedCol,
|
|
1211
|
+
rows,
|
|
1212
|
+
columns,
|
|
1213
|
+
focusCell,
|
|
1214
|
+
findNextEnabled,
|
|
1215
|
+
isEnabled
|
|
1216
|
+
]
|
|
1217
|
+
);
|
|
1218
|
+
return { getCellProps };
|
|
1219
|
+
};
|
|
1220
|
+
|
|
1221
|
+
const ROWS$2 = 3;
|
|
1222
|
+
const COLUMNS$2 = 4;
|
|
1223
|
+
const MonthGrid = ({
|
|
1224
|
+
navigationYear,
|
|
1225
|
+
timeZone,
|
|
1226
|
+
onMonthSelect,
|
|
1227
|
+
currentMonth,
|
|
1228
|
+
currentYear,
|
|
1229
|
+
selectedMonth,
|
|
1230
|
+
selectedYear,
|
|
1231
|
+
minDate,
|
|
1232
|
+
maxDate,
|
|
1233
|
+
yearFormatter,
|
|
1234
|
+
focusOnMount
|
|
1235
|
+
}) => {
|
|
1236
|
+
const monthFormatter = reactAria.useDateFormatter({
|
|
1237
|
+
month: "short",
|
|
1238
|
+
timeZone
|
|
1239
|
+
});
|
|
1240
|
+
const { getCellProps } = useGridNavigation({
|
|
1241
|
+
rows: ROWS$2,
|
|
1242
|
+
columns: COLUMNS$2,
|
|
1243
|
+
selectedIndex: selectedYear === navigationYear && selectedMonth != null ? selectedMonth - 1 : -1,
|
|
1244
|
+
currentIndex: currentYear === navigationYear && currentMonth != null ? currentMonth - 1 : -1,
|
|
1245
|
+
resetKey: navigationYear,
|
|
1246
|
+
focusOnMount
|
|
1247
|
+
});
|
|
1248
|
+
const isMonthDisabled = (month) => {
|
|
1249
|
+
if (minDate != null) {
|
|
1250
|
+
const minYear = minDate.year;
|
|
1251
|
+
const minMonth = minDate.month;
|
|
1252
|
+
if (navigationYear < minYear || navigationYear === minYear && month < minMonth) {
|
|
1253
|
+
return true;
|
|
1254
|
+
}
|
|
1255
|
+
}
|
|
1256
|
+
if (maxDate != null) {
|
|
1257
|
+
const maxYear = maxDate.year;
|
|
1258
|
+
const maxMonth = maxDate.month;
|
|
1259
|
+
if (navigationYear > maxYear || navigationYear === maxYear && month > maxMonth) {
|
|
1260
|
+
return true;
|
|
1261
|
+
}
|
|
1262
|
+
}
|
|
1263
|
+
return false;
|
|
1264
|
+
};
|
|
1265
|
+
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
1266
|
+
StyledPeriodGrid,
|
|
1267
|
+
{
|
|
1268
|
+
columns: 4,
|
|
1269
|
+
role: "grid",
|
|
1270
|
+
"aria-label": yearFormatter.format(navigationYear),
|
|
1271
|
+
children: Array.from({ length: ROWS$2 }, (_, row) => /* @__PURE__ */ jsxRuntime.jsx(StyledPeriodRow, { role: "row", children: Array.from({ length: COLUMNS$2 }, (_2, col) => {
|
|
1272
|
+
const month = row * COLUMNS$2 + col + 1;
|
|
1273
|
+
const date$1 = new date.CalendarDate(navigationYear, month, 1).toDate(
|
|
1274
|
+
timeZone
|
|
1275
|
+
);
|
|
1276
|
+
const label = monthFormatter.format(date$1);
|
|
1277
|
+
const disabled = isMonthDisabled(month);
|
|
1278
|
+
const isCurrent = navigationYear === currentYear && month === currentMonth;
|
|
1279
|
+
const isSelected = navigationYear === selectedYear && month === selectedMonth;
|
|
1280
|
+
const cellProps = getCellProps(row, col);
|
|
1281
|
+
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
1282
|
+
StyledPeriodGridCell,
|
|
1283
|
+
{
|
|
1284
|
+
role: "gridcell",
|
|
1285
|
+
"aria-selected": isSelected || void 0,
|
|
1286
|
+
children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
1287
|
+
StyledPeriodCell,
|
|
1288
|
+
{
|
|
1289
|
+
...cellProps,
|
|
1290
|
+
current: isCurrent,
|
|
1291
|
+
selected: isSelected,
|
|
1292
|
+
"aria-current": isCurrent ? "date" : void 0,
|
|
1293
|
+
"aria-disabled": disabled || void 0,
|
|
1294
|
+
"aria-label": "".concat(label, " ").concat(yearFormatter.format(
|
|
1295
|
+
navigationYear
|
|
1296
|
+
)),
|
|
1297
|
+
onPress: () => onMonthSelect(month),
|
|
1298
|
+
children: label
|
|
1299
|
+
}
|
|
1300
|
+
)
|
|
1301
|
+
},
|
|
1302
|
+
month
|
|
1303
|
+
);
|
|
1304
|
+
}) }, row))
|
|
1305
|
+
}
|
|
1306
|
+
);
|
|
1307
|
+
};
|
|
1308
|
+
|
|
1309
|
+
const ROWS$1 = 2;
|
|
1310
|
+
const COLUMNS$1 = 2;
|
|
1311
|
+
const QUARTER_MONTHS = [
|
|
1312
|
+
[1, 3],
|
|
1313
|
+
[4, 6],
|
|
1314
|
+
[7, 9],
|
|
1315
|
+
[10, 12]
|
|
1316
|
+
];
|
|
1317
|
+
const QuarterGrid = ({
|
|
1318
|
+
navigationYear,
|
|
1319
|
+
timeZone,
|
|
1320
|
+
onQuarterSelect,
|
|
1321
|
+
currentQuarter,
|
|
1322
|
+
currentYear,
|
|
1323
|
+
selectedQuarter,
|
|
1324
|
+
selectedYear,
|
|
1325
|
+
minDate,
|
|
1326
|
+
maxDate,
|
|
1327
|
+
formatQuarterLabel,
|
|
1328
|
+
yearFormatter,
|
|
1329
|
+
focusOnMount
|
|
1330
|
+
}) => {
|
|
1331
|
+
const strings = useCalendarStrings();
|
|
1332
|
+
const monthFormatter = reactAria.useDateFormatter({
|
|
1333
|
+
month: "short",
|
|
1334
|
+
timeZone
|
|
1335
|
+
});
|
|
1336
|
+
const { getCellProps } = useGridNavigation({
|
|
1337
|
+
rows: ROWS$1,
|
|
1338
|
+
columns: COLUMNS$1,
|
|
1339
|
+
selectedIndex: selectedYear === navigationYear && selectedQuarter != null ? selectedQuarter - 1 : -1,
|
|
1340
|
+
currentIndex: currentYear === navigationYear && currentQuarter != null ? currentQuarter - 1 : -1,
|
|
1341
|
+
resetKey: navigationYear,
|
|
1342
|
+
focusOnMount
|
|
1343
|
+
});
|
|
1344
|
+
const isQuarterDisabled = (quarter) => {
|
|
1345
|
+
const [startMonth, endMonth] = QUARTER_MONTHS[quarter - 1];
|
|
1346
|
+
if (minDate != null) {
|
|
1347
|
+
if (navigationYear < minDate.year || navigationYear === minDate.year && endMonth < minDate.month) {
|
|
1348
|
+
return true;
|
|
1349
|
+
}
|
|
1350
|
+
}
|
|
1351
|
+
if (maxDate != null) {
|
|
1352
|
+
if (navigationYear > maxDate.year || navigationYear === maxDate.year && startMonth > maxDate.month) {
|
|
1353
|
+
return true;
|
|
1354
|
+
}
|
|
1355
|
+
}
|
|
1356
|
+
return false;
|
|
1357
|
+
};
|
|
1358
|
+
const formatRange = (quarter) => {
|
|
1359
|
+
const [startMonth, endMonth] = QUARTER_MONTHS[quarter - 1];
|
|
1360
|
+
const start = monthFormatter.format(
|
|
1361
|
+
new date.CalendarDate(navigationYear, startMonth, 1).toDate(timeZone)
|
|
1362
|
+
);
|
|
1363
|
+
const end = monthFormatter.format(
|
|
1364
|
+
new date.CalendarDate(navigationYear, endMonth, 1).toDate(timeZone)
|
|
1365
|
+
);
|
|
1366
|
+
return "".concat(start, " \u2013 ").concat(end);
|
|
1367
|
+
};
|
|
1368
|
+
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
1369
|
+
StyledPeriodGrid,
|
|
1370
|
+
{
|
|
1371
|
+
columns: 2,
|
|
1372
|
+
role: "grid",
|
|
1373
|
+
"aria-label": yearFormatter.format(navigationYear),
|
|
1374
|
+
children: Array.from({ length: ROWS$1 }, (_, row) => /* @__PURE__ */ jsxRuntime.jsx(StyledPeriodRow, { role: "row", children: Array.from({ length: COLUMNS$1 }, (_2, col) => {
|
|
1375
|
+
const quarter = row * COLUMNS$1 + col + 1;
|
|
1376
|
+
const disabled = isQuarterDisabled(quarter);
|
|
1377
|
+
const isCurrent = navigationYear === currentYear && quarter === currentQuarter;
|
|
1378
|
+
const isSelected = navigationYear === selectedYear && quarter === selectedQuarter;
|
|
1379
|
+
const cellProps = getCellProps(row, col);
|
|
1380
|
+
const rangeLabel = formatRange(quarter);
|
|
1381
|
+
const label = (formatQuarterLabel != null ? formatQuarterLabel : strings.quarter)(quarter);
|
|
1382
|
+
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
1383
|
+
StyledPeriodGridCell,
|
|
1384
|
+
{
|
|
1385
|
+
role: "gridcell",
|
|
1386
|
+
"aria-selected": isSelected || void 0,
|
|
1387
|
+
children: /* @__PURE__ */ jsxRuntime.jsxs(
|
|
1388
|
+
StyledPeriodCell,
|
|
1389
|
+
{
|
|
1390
|
+
...cellProps,
|
|
1391
|
+
current: isCurrent,
|
|
1392
|
+
selected: isSelected,
|
|
1393
|
+
tall: true,
|
|
1394
|
+
"aria-current": isCurrent ? "date" : void 0,
|
|
1395
|
+
"aria-disabled": disabled || void 0,
|
|
1396
|
+
"aria-label": "".concat(label, " ").concat(yearFormatter.format(
|
|
1397
|
+
navigationYear
|
|
1398
|
+
), ", ").concat(rangeLabel),
|
|
1399
|
+
onPress: () => onQuarterSelect(quarter),
|
|
1400
|
+
children: [
|
|
1401
|
+
label,
|
|
1402
|
+
/* @__PURE__ */ jsxRuntime.jsx(StyledPeriodCellLabel, { children: rangeLabel })
|
|
1403
|
+
]
|
|
1404
|
+
}
|
|
1405
|
+
)
|
|
1406
|
+
},
|
|
1407
|
+
quarter
|
|
1408
|
+
);
|
|
1409
|
+
}) }, row))
|
|
1410
|
+
}
|
|
1411
|
+
);
|
|
1412
|
+
};
|
|
1413
|
+
|
|
1414
|
+
const ROWS = 3;
|
|
1415
|
+
const COLUMNS = 4;
|
|
1416
|
+
const TOTAL_CELLS = ROWS * COLUMNS;
|
|
1417
|
+
const YearGrid = ({
|
|
1418
|
+
decadeStart,
|
|
1419
|
+
onYearSelect,
|
|
1420
|
+
currentYear,
|
|
1421
|
+
selectedYear,
|
|
1422
|
+
minDate,
|
|
1423
|
+
maxDate,
|
|
1424
|
+
yearFormatter,
|
|
1425
|
+
focusOnMount
|
|
1426
|
+
}) => {
|
|
1427
|
+
const { getCellProps } = useGridNavigation({
|
|
1428
|
+
rows: ROWS,
|
|
1429
|
+
columns: COLUMNS,
|
|
1430
|
+
selectedIndex: selectedYear != null ? selectedYear - decadeStart : -1,
|
|
1431
|
+
currentIndex: currentYear != null ? currentYear - decadeStart : -1,
|
|
1432
|
+
resetKey: decadeStart,
|
|
1433
|
+
focusOnMount
|
|
1434
|
+
});
|
|
1435
|
+
const isYearDisabled = (year) => {
|
|
1436
|
+
if (minDate != null && year < minDate.year) return true;
|
|
1437
|
+
if (maxDate != null && year > maxDate.year) return true;
|
|
1438
|
+
return false;
|
|
1439
|
+
};
|
|
1440
|
+
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
1441
|
+
StyledPeriodGrid,
|
|
1442
|
+
{
|
|
1443
|
+
columns: 4,
|
|
1444
|
+
role: "grid",
|
|
1445
|
+
"aria-label": "".concat(yearFormatter.format(decadeStart), "\u2013").concat(yearFormatter.format(
|
|
1446
|
+
decadeStart + TOTAL_CELLS - 1
|
|
1447
|
+
)),
|
|
1448
|
+
children: Array.from({ length: ROWS }, (_, row) => /* @__PURE__ */ jsxRuntime.jsx(StyledPeriodRow, { role: "row", children: Array.from({ length: COLUMNS }, (_2, col) => {
|
|
1449
|
+
const year = decadeStart + row * COLUMNS + col;
|
|
1450
|
+
const disabled = isYearDisabled(year);
|
|
1451
|
+
const isCurrent = year === currentYear;
|
|
1452
|
+
const isSelected = year === selectedYear;
|
|
1453
|
+
const cellProps = getCellProps(row, col);
|
|
1454
|
+
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
1455
|
+
StyledPeriodGridCell,
|
|
1456
|
+
{
|
|
1457
|
+
role: "gridcell",
|
|
1458
|
+
"aria-selected": isSelected || void 0,
|
|
1459
|
+
children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
1460
|
+
StyledPeriodCell,
|
|
1461
|
+
{
|
|
1462
|
+
...cellProps,
|
|
1463
|
+
current: isCurrent,
|
|
1464
|
+
selected: isSelected,
|
|
1465
|
+
"aria-current": isCurrent ? "date" : void 0,
|
|
1466
|
+
"aria-disabled": disabled || void 0,
|
|
1467
|
+
"aria-label": yearFormatter.format(year),
|
|
1468
|
+
onPress: () => onYearSelect(year),
|
|
1469
|
+
children: yearFormatter.format(year)
|
|
1470
|
+
}
|
|
1471
|
+
)
|
|
1472
|
+
},
|
|
1473
|
+
year
|
|
1474
|
+
);
|
|
1475
|
+
}) }, row))
|
|
1476
|
+
}
|
|
1477
|
+
);
|
|
1478
|
+
};
|
|
1479
|
+
|
|
479
1480
|
const StyledPredefinedRanges = designSystemStitches.styled(designSystemPrimitive.Primitive.div, {
|
|
480
1481
|
display: "flex",
|
|
481
1482
|
flexDirection: "column",
|
|
@@ -520,9 +1521,31 @@ const PredefinedRanges = () => {
|
|
|
520
1521
|
};
|
|
521
1522
|
|
|
522
1523
|
const CONTENT_OFFSET = parseInt(designSystemStitches.theme.space[50]);
|
|
1524
|
+
const VIEW_MODE_UP = {
|
|
1525
|
+
days: "months",
|
|
1526
|
+
months: "years",
|
|
1527
|
+
quarters: "years",
|
|
1528
|
+
years: "years"
|
|
1529
|
+
};
|
|
523
1530
|
const SharedContent = React.forwardRef(
|
|
524
1531
|
({ calendarProps, prevButtonProps, nextButtonProps, state }, forwardRef) => {
|
|
525
|
-
const {
|
|
1532
|
+
const {
|
|
1533
|
+
visibleDuration,
|
|
1534
|
+
viewMode,
|
|
1535
|
+
setViewMode,
|
|
1536
|
+
navigationYear,
|
|
1537
|
+
setNavigationYear,
|
|
1538
|
+
navigation,
|
|
1539
|
+
period,
|
|
1540
|
+
picker,
|
|
1541
|
+
minDate,
|
|
1542
|
+
maxDate,
|
|
1543
|
+
onCalendarDateClick,
|
|
1544
|
+
formatQuarterLabel,
|
|
1545
|
+
goToCurrentLabel,
|
|
1546
|
+
value: selectedValue
|
|
1547
|
+
} = useCalendarContext();
|
|
1548
|
+
const { locale } = reactAria.useLocale();
|
|
526
1549
|
const monthDateFormatter = reactAria.useDateFormatter({
|
|
527
1550
|
month: "long",
|
|
528
1551
|
year: "numeric",
|
|
@@ -534,8 +1557,185 @@ const SharedContent = React.forwardRef(
|
|
|
534
1557
|
const nextAriaLabel = "".concat(nextButtonProps["aria-label"], ", ").concat(monthDateFormatter.format(
|
|
535
1558
|
state.visibleRange.start.add({ months: visibleDuration.months === 2 ? 2 : 1 }).toDate(state.timeZone)
|
|
536
1559
|
));
|
|
1560
|
+
const todayDate = React.useMemo(() => date.today(date.getLocalTimeZone()), []);
|
|
1561
|
+
const currentYear = todayDate.year;
|
|
1562
|
+
const currentMonth = todayDate.month;
|
|
1563
|
+
const yearFormatter = React.useMemo(
|
|
1564
|
+
() => new Intl.NumberFormat(locale, { useGrouping: false }),
|
|
1565
|
+
[locale]
|
|
1566
|
+
);
|
|
1567
|
+
const handleZoomOut = React.useCallback(() => {
|
|
1568
|
+
if (viewMode === "days") {
|
|
1569
|
+
setNavigationYear(state.visibleRange.start.year);
|
|
1570
|
+
}
|
|
1571
|
+
setViewMode(VIEW_MODE_UP[viewMode]);
|
|
1572
|
+
}, [
|
|
1573
|
+
viewMode,
|
|
1574
|
+
setViewMode,
|
|
1575
|
+
setNavigationYear,
|
|
1576
|
+
state.visibleRange.start.year
|
|
1577
|
+
]);
|
|
1578
|
+
const handleMonthSelect = React.useCallback(
|
|
1579
|
+
(month) => {
|
|
1580
|
+
if (period === "month") {
|
|
1581
|
+
const date$1 = new date.CalendarDate(navigationYear, month, 1);
|
|
1582
|
+
onCalendarDateClick(date$1);
|
|
1583
|
+
} else {
|
|
1584
|
+
state.setFocusedDate(new date.CalendarDate(navigationYear, month, 1));
|
|
1585
|
+
state.setFocused(true);
|
|
1586
|
+
setViewMode("days");
|
|
1587
|
+
}
|
|
1588
|
+
},
|
|
1589
|
+
[navigationYear, state, setViewMode, period, onCalendarDateClick]
|
|
1590
|
+
);
|
|
1591
|
+
const handleQuarterSelect = React.useCallback(
|
|
1592
|
+
(quarter) => {
|
|
1593
|
+
const firstMonth = (quarter - 1) * 3 + 1;
|
|
1594
|
+
const date$1 = new date.CalendarDate(navigationYear, firstMonth, 1);
|
|
1595
|
+
onCalendarDateClick(date$1);
|
|
1596
|
+
},
|
|
1597
|
+
[navigationYear, onCalendarDateClick]
|
|
1598
|
+
);
|
|
1599
|
+
const handleYearSelect = React.useCallback(
|
|
1600
|
+
(year) => {
|
|
1601
|
+
setNavigationYear(year);
|
|
1602
|
+
setViewMode(period === "quarter" ? "quarters" : "months");
|
|
1603
|
+
},
|
|
1604
|
+
[setNavigationYear, setViewMode, period]
|
|
1605
|
+
);
|
|
1606
|
+
const handlePrevOverride = React.useCallback(() => {
|
|
1607
|
+
if (viewMode === "years") {
|
|
1608
|
+
setNavigationYear((y) => y - DECADE_SIZE);
|
|
1609
|
+
} else {
|
|
1610
|
+
setNavigationYear((y) => y - 1);
|
|
1611
|
+
}
|
|
1612
|
+
}, [viewMode, setNavigationYear]);
|
|
1613
|
+
const handleNextOverride = React.useCallback(() => {
|
|
1614
|
+
if (viewMode === "years") {
|
|
1615
|
+
setNavigationYear((y) => y + DECADE_SIZE);
|
|
1616
|
+
} else {
|
|
1617
|
+
setNavigationYear((y) => y + 1);
|
|
1618
|
+
}
|
|
1619
|
+
}, [viewMode, setNavigationYear]);
|
|
1620
|
+
const decadeStart = Math.floor(navigationYear / DECADE_SIZE) * DECADE_SIZE;
|
|
1621
|
+
const [isPrevDisabled, isNextDisabled] = React.useMemo(() => {
|
|
1622
|
+
if (viewMode === "days") {
|
|
1623
|
+
return [void 0, void 0];
|
|
1624
|
+
}
|
|
1625
|
+
if (viewMode === "years") {
|
|
1626
|
+
return [
|
|
1627
|
+
minDate != null && decadeStart - 1 < minDate.year,
|
|
1628
|
+
maxDate != null && decadeStart + DECADE_SIZE > maxDate.year
|
|
1629
|
+
];
|
|
1630
|
+
}
|
|
1631
|
+
return [
|
|
1632
|
+
minDate != null && navigationYear - 1 < minDate.year,
|
|
1633
|
+
maxDate != null && navigationYear + 1 > maxDate.year
|
|
1634
|
+
];
|
|
1635
|
+
}, [viewMode, decadeStart, navigationYear, minDate, maxDate]);
|
|
1636
|
+
const currentQuarter = Math.ceil(currentMonth / 3);
|
|
1637
|
+
const handleGoToCurrent = React.useCallback(() => {
|
|
1638
|
+
const now = date.today(date.getLocalTimeZone());
|
|
1639
|
+
let date$1;
|
|
1640
|
+
switch (period) {
|
|
1641
|
+
case "week":
|
|
1642
|
+
date$1 = date.startOfWeek(now, locale);
|
|
1643
|
+
break;
|
|
1644
|
+
case "month":
|
|
1645
|
+
date$1 = new date.CalendarDate(currentYear, currentMonth, 1);
|
|
1646
|
+
break;
|
|
1647
|
+
case "quarter": {
|
|
1648
|
+
const firstMonth = (currentQuarter - 1) * 3 + 1;
|
|
1649
|
+
date$1 = new date.CalendarDate(currentYear, firstMonth, 1);
|
|
1650
|
+
break;
|
|
1651
|
+
}
|
|
1652
|
+
default:
|
|
1653
|
+
date$1 = now;
|
|
1654
|
+
break;
|
|
1655
|
+
}
|
|
1656
|
+
onCalendarDateClick(date$1);
|
|
1657
|
+
}, [
|
|
1658
|
+
period,
|
|
1659
|
+
locale,
|
|
1660
|
+
currentYear,
|
|
1661
|
+
currentMonth,
|
|
1662
|
+
currentQuarter,
|
|
1663
|
+
onCalendarDateClick
|
|
1664
|
+
]);
|
|
1665
|
+
const prevViewModeRef = React.useRef(viewMode);
|
|
1666
|
+
const shouldAutoFocus = prevViewModeRef.current !== viewMode && viewMode !== "days";
|
|
1667
|
+
React.useEffect(() => {
|
|
1668
|
+
prevViewModeRef.current = viewMode;
|
|
1669
|
+
}, [viewMode]);
|
|
1670
|
+
const selectedDate = selectedValue != null && !("start" in selectedValue) ? selectedValue : null;
|
|
1671
|
+
const selectedYear = selectedDate == null ? void 0 : selectedDate.year;
|
|
1672
|
+
const selectedMonth = selectedDate == null ? void 0 : selectedDate.month;
|
|
1673
|
+
const selectedQuarter = selectedMonth != null ? Math.ceil(selectedMonth / 3) : void 0;
|
|
1674
|
+
const isSelectionInCurrentPeriod = React.useMemo(
|
|
1675
|
+
() => selectedDate != null && isCurrentPeriod(selectedDate, period, locale),
|
|
1676
|
+
[selectedDate, period, locale]
|
|
1677
|
+
);
|
|
1678
|
+
const showGoToCurrent = goToCurrentLabel != null && picker === "single" && !isSelectionInCurrentPeriod;
|
|
1679
|
+
const renderGrid = () => {
|
|
1680
|
+
switch (viewMode) {
|
|
1681
|
+
case "months":
|
|
1682
|
+
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
1683
|
+
MonthGrid,
|
|
1684
|
+
{
|
|
1685
|
+
navigationYear,
|
|
1686
|
+
timeZone: state.timeZone,
|
|
1687
|
+
onMonthSelect: handleMonthSelect,
|
|
1688
|
+
currentMonth,
|
|
1689
|
+
currentYear,
|
|
1690
|
+
selectedMonth,
|
|
1691
|
+
selectedYear,
|
|
1692
|
+
minDate,
|
|
1693
|
+
maxDate,
|
|
1694
|
+
yearFormatter,
|
|
1695
|
+
focusOnMount: shouldAutoFocus
|
|
1696
|
+
}
|
|
1697
|
+
);
|
|
1698
|
+
case "quarters":
|
|
1699
|
+
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
1700
|
+
QuarterGrid,
|
|
1701
|
+
{
|
|
1702
|
+
navigationYear,
|
|
1703
|
+
timeZone: state.timeZone,
|
|
1704
|
+
onQuarterSelect: handleQuarterSelect,
|
|
1705
|
+
currentQuarter,
|
|
1706
|
+
currentYear,
|
|
1707
|
+
selectedQuarter,
|
|
1708
|
+
selectedYear,
|
|
1709
|
+
minDate,
|
|
1710
|
+
maxDate,
|
|
1711
|
+
formatQuarterLabel,
|
|
1712
|
+
yearFormatter,
|
|
1713
|
+
focusOnMount: shouldAutoFocus
|
|
1714
|
+
}
|
|
1715
|
+
);
|
|
1716
|
+
case "years":
|
|
1717
|
+
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
1718
|
+
YearGrid,
|
|
1719
|
+
{
|
|
1720
|
+
decadeStart,
|
|
1721
|
+
onYearSelect: handleYearSelect,
|
|
1722
|
+
currentYear,
|
|
1723
|
+
selectedYear,
|
|
1724
|
+
minDate,
|
|
1725
|
+
maxDate,
|
|
1726
|
+
yearFormatter,
|
|
1727
|
+
focusOnMount: shouldAutoFocus
|
|
1728
|
+
}
|
|
1729
|
+
);
|
|
1730
|
+
default:
|
|
1731
|
+
return /* @__PURE__ */ jsxRuntime.jsxs(StyledGridContent, { children: [
|
|
1732
|
+
/* @__PURE__ */ jsxRuntime.jsx(StyledBodyContentLeft, { children: /* @__PURE__ */ jsxRuntime.jsx(Grid, { state }) }),
|
|
1733
|
+
visibleDuration.months === 2 && /* @__PURE__ */ jsxRuntime.jsx(StyledBodyContentRight, { children: /* @__PURE__ */ jsxRuntime.jsx(Grid, { state, offset: { months: 1 } }) })
|
|
1734
|
+
] });
|
|
1735
|
+
}
|
|
1736
|
+
};
|
|
537
1737
|
return /* @__PURE__ */ jsxRuntime.jsxs(StyledCalendarBody, { ...calendarProps, ref: forwardRef, children: [
|
|
538
|
-
/* @__PURE__ */ jsxRuntime.jsx(PredefinedRanges, {}),
|
|
1738
|
+
viewMode === "days" && /* @__PURE__ */ jsxRuntime.jsx(PredefinedRanges, {}),
|
|
539
1739
|
/* @__PURE__ */ jsxRuntime.jsxs(designSystemFlex.Flex, { direction: "column", children: [
|
|
540
1740
|
/* @__PURE__ */ jsxRuntime.jsx(
|
|
541
1741
|
Header,
|
|
@@ -549,12 +1749,19 @@ const SharedContent = React.forwardRef(
|
|
|
549
1749
|
...nextButtonProps,
|
|
550
1750
|
"aria-label": nextAriaLabel
|
|
551
1751
|
},
|
|
552
|
-
visibleMonths: visibleDuration.months
|
|
1752
|
+
visibleMonths: visibleDuration.months,
|
|
1753
|
+
yearFormatter,
|
|
1754
|
+
onPrevOverride: handlePrevOverride,
|
|
1755
|
+
onNextOverride: handleNextOverride,
|
|
1756
|
+
isPrevDisabled,
|
|
1757
|
+
isNextDisabled,
|
|
1758
|
+
onZoomOut: navigation === true ? handleZoomOut : void 0
|
|
553
1759
|
}
|
|
554
1760
|
),
|
|
555
|
-
|
|
556
|
-
|
|
557
|
-
|
|
1761
|
+
renderGrid(),
|
|
1762
|
+
showGoToCurrent && /* @__PURE__ */ jsxRuntime.jsxs(StyledGoToCurrent, { onPress: handleGoToCurrent, children: [
|
|
1763
|
+
/* @__PURE__ */ jsxRuntime.jsx(designSystemIcons.IconClock, { "aria-hidden": "true" }),
|
|
1764
|
+
goToCurrentLabel
|
|
558
1765
|
] })
|
|
559
1766
|
] })
|
|
560
1767
|
] });
|
|
@@ -567,15 +1774,31 @@ const DatePickerContent = () => {
|
|
|
567
1774
|
visibleDuration,
|
|
568
1775
|
minDate,
|
|
569
1776
|
maxDate,
|
|
570
|
-
onCalendarDateClick
|
|
1777
|
+
onCalendarDateClick,
|
|
1778
|
+
period
|
|
571
1779
|
} = useCalendarContext();
|
|
1780
|
+
const handleChange = React.useCallback(
|
|
1781
|
+
(date$1) => {
|
|
1782
|
+
if (period === "week") {
|
|
1783
|
+
const weekStart = date.startOfWeek(date$1, locale);
|
|
1784
|
+
const weekEnd = weekStart.add({ days: 6 });
|
|
1785
|
+
if (minDate != null && weekStart.compare(minDate) < 0 || maxDate != null && weekEnd.compare(maxDate) > 0) {
|
|
1786
|
+
return;
|
|
1787
|
+
}
|
|
1788
|
+
onCalendarDateClick(weekStart);
|
|
1789
|
+
} else {
|
|
1790
|
+
onCalendarDateClick(date$1);
|
|
1791
|
+
}
|
|
1792
|
+
},
|
|
1793
|
+
[period, locale, minDate, maxDate, onCalendarDateClick]
|
|
1794
|
+
);
|
|
572
1795
|
const state = reactStately.useCalendarState({
|
|
573
1796
|
value: calendarValue,
|
|
574
1797
|
visibleDuration,
|
|
575
1798
|
minValue: minDate,
|
|
576
1799
|
maxValue: maxDate,
|
|
577
1800
|
autoFocus: true,
|
|
578
|
-
onChange:
|
|
1801
|
+
onChange: handleChange,
|
|
579
1802
|
locale,
|
|
580
1803
|
createCalendar: date.createCalendar
|
|
581
1804
|
});
|
|
@@ -672,44 +1895,6 @@ const Content = React.forwardRef(
|
|
|
672
1895
|
}
|
|
673
1896
|
);
|
|
674
1897
|
|
|
675
|
-
const StyledValue = designSystemStitches.styled(designSystemPrimitive.Primitive.span, {});
|
|
676
|
-
|
|
677
|
-
const DEFAULT_FORMAT = {
|
|
678
|
-
day: "2-digit",
|
|
679
|
-
month: "short",
|
|
680
|
-
year: "numeric"
|
|
681
|
-
};
|
|
682
|
-
function formatDate(date, formatter, timeZone) {
|
|
683
|
-
return formatter.format(date.toDate(timeZone));
|
|
684
|
-
}
|
|
685
|
-
function formatValue(value, formatter, timeZone) {
|
|
686
|
-
if (value == null || value === void 0) {
|
|
687
|
-
return void 0;
|
|
688
|
-
}
|
|
689
|
-
if ("start" in value) {
|
|
690
|
-
if (value.start == null || value.end == null) {
|
|
691
|
-
return void 0;
|
|
692
|
-
}
|
|
693
|
-
return "".concat(formatDate(value.start, formatter, timeZone), " - ").concat(formatDate(
|
|
694
|
-
value.end,
|
|
695
|
-
formatter,
|
|
696
|
-
timeZone
|
|
697
|
-
));
|
|
698
|
-
}
|
|
699
|
-
return formatDate(value, formatter, timeZone);
|
|
700
|
-
}
|
|
701
|
-
const Value = React.forwardRef(({ format = DEFAULT_FORMAT, ...restProps }, forwardRef) => {
|
|
702
|
-
const { value } = useCalendarContext();
|
|
703
|
-
const timeZone = React.useMemo(date.getLocalTimeZone, [format]);
|
|
704
|
-
const formatWithTimeZone = React.useMemo(
|
|
705
|
-
() => ({ ...format, timeZone }),
|
|
706
|
-
[format, timeZone]
|
|
707
|
-
);
|
|
708
|
-
const dateFormatter = reactAria.useDateFormatter(formatWithTimeZone);
|
|
709
|
-
const valueToDisplay = formatValue(value, dateFormatter, timeZone);
|
|
710
|
-
return /* @__PURE__ */ jsxRuntime.jsx(StyledValue, { ref: forwardRef, ...restProps, children: valueToDisplay });
|
|
711
|
-
});
|
|
712
|
-
|
|
713
1898
|
const ClearButton = React.forwardRef(({ onClear, children, ...restProps }, forwardRef) => {
|
|
714
1899
|
const { value, setValue } = useCalendarContext();
|
|
715
1900
|
const onClearHandler = () => {
|
|
@@ -800,6 +1985,11 @@ const Calendar = React.forwardRef(
|
|
|
800
1985
|
"aria-disabled": ariaDisabled,
|
|
801
1986
|
children,
|
|
802
1987
|
predefinedValues,
|
|
1988
|
+
navigation,
|
|
1989
|
+
period,
|
|
1990
|
+
formatQuarterLabel,
|
|
1991
|
+
formatSwitchViewLabel,
|
|
1992
|
+
goToCurrentLabel,
|
|
803
1993
|
...props
|
|
804
1994
|
}, forwardRef) => {
|
|
805
1995
|
const providerProps = {
|
|
@@ -816,7 +2006,12 @@ const Calendar = React.forwardRef(
|
|
|
816
2006
|
onOpen,
|
|
817
2007
|
disabled,
|
|
818
2008
|
ariaDisabled,
|
|
819
|
-
predefinedValues
|
|
2009
|
+
predefinedValues,
|
|
2010
|
+
navigation,
|
|
2011
|
+
period,
|
|
2012
|
+
formatQuarterLabel,
|
|
2013
|
+
formatSwitchViewLabel,
|
|
2014
|
+
goToCurrentLabel
|
|
820
2015
|
};
|
|
821
2016
|
const validatedLocale = getValidLocale(locale);
|
|
822
2017
|
return /* @__PURE__ */ jsxRuntime.jsx(reactAria.I18nProvider, { locale: validatedLocale, children: /* @__PURE__ */ jsxRuntime.jsx(CalendarProvider, { ...providerProps, children: /* @__PURE__ */ jsxRuntime.jsx(Root, { ...props, ref: forwardRef, children }) }) });
|
|
@@ -831,7 +2026,12 @@ const CalendarGrid = ({
|
|
|
831
2026
|
visibleMonths,
|
|
832
2027
|
minDate,
|
|
833
2028
|
maxDate,
|
|
834
|
-
predefinedValues
|
|
2029
|
+
predefinedValues,
|
|
2030
|
+
navigation,
|
|
2031
|
+
period,
|
|
2032
|
+
formatQuarterLabel,
|
|
2033
|
+
formatSwitchViewLabel,
|
|
2034
|
+
goToCurrentLabel
|
|
835
2035
|
}) => {
|
|
836
2036
|
const providerProps = {
|
|
837
2037
|
picker,
|
|
@@ -841,7 +2041,12 @@ const CalendarGrid = ({
|
|
|
841
2041
|
visibleMonths,
|
|
842
2042
|
minDate,
|
|
843
2043
|
maxDate,
|
|
844
|
-
predefinedValues
|
|
2044
|
+
predefinedValues,
|
|
2045
|
+
navigation,
|
|
2046
|
+
period,
|
|
2047
|
+
formatQuarterLabel,
|
|
2048
|
+
formatSwitchViewLabel,
|
|
2049
|
+
goToCurrentLabel
|
|
845
2050
|
};
|
|
846
2051
|
const validatedLocale = getValidLocale(locale);
|
|
847
2052
|
return /* @__PURE__ */ jsxRuntime.jsx(reactAria.I18nProvider, { locale: validatedLocale, children: /* @__PURE__ */ jsxRuntime.jsx(CalendarProvider, { ...providerProps, children: /* @__PURE__ */ jsxRuntime.jsx(CalendarGridContent, {}) }) });
|