@kalyx/react 1.0.0-rc.1 → 1.0.0-rc.11
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/CHANGELOG.md +308 -0
- package/README.md +2 -2
- package/dist/index.cjs +821 -385
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +80 -7
- package/dist/index.d.ts +80 -7
- package/dist/index.js +810 -390
- package/dist/index.js.map +1 -1
- package/package.json +18 -3
package/dist/index.js
CHANGED
|
@@ -1,8 +1,9 @@
|
|
|
1
|
-
|
|
2
|
-
import {
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
import {
|
|
1
|
+
"use client";
|
|
2
|
+
import { createContext, forwardRef, useState, useRef, useEffect, useCallback, useContext, useId, useMemo } from 'react';
|
|
3
|
+
import { parseInputValue, formatTimeString, parseTimeString, getTimeInTimezone, getTime, DateFnsAdapter, DEFAULT_DATEPICKER_LABELS, civilMidnightFromUtcDay, getMonthName, getWeekdayNames, getCalendarDays, formatMonthYear, isDateDisabled, getISOWeekNumber, DEFAULT_RANGEPICKER_LABELS, DEFAULT_TIMEPICKER_LABELS, setTimeInTimezone, setTime, to12Hour, to24Hour, generateMinutes, generateHours, formatFullDate } from '@kalyx/core';
|
|
4
|
+
export { DEFAULT_DATEPICKER_LABELS, DEFAULT_DATETIMEPICKER_LABELS, DEFAULT_RANGEPICKER_LABELS, DEFAULT_TIMEPICKER_LABELS, DateFnsAdapter } from '@kalyx/core';
|
|
5
|
+
import { jsxs, Fragment, jsx } from 'react/jsx-runtime';
|
|
6
|
+
import { offset, flip, shift, useFloating, autoUpdate } from '@floating-ui/react';
|
|
6
7
|
|
|
7
8
|
// src/components/DatePicker/Root.tsx
|
|
8
9
|
var DatePickerContext = createContext(null);
|
|
@@ -56,10 +57,10 @@ function DatePickerRoot({
|
|
|
56
57
|
const currentValue = isControlled ? controlledValue ?? null : uncontrolledValue;
|
|
57
58
|
const [isOpen, setIsOpen] = useState(false);
|
|
58
59
|
const [viewMonth, setViewMonth] = useState(
|
|
59
|
-
currentValue ?? adapter.today(displayTimezone)
|
|
60
|
+
() => currentValue ?? adapter.today(displayTimezone)
|
|
60
61
|
);
|
|
61
62
|
const [focusedDate, setFocusedDate] = useState(
|
|
62
|
-
currentValue ?? adapter.today(displayTimezone)
|
|
63
|
+
() => currentValue ?? adapter.today(displayTimezone)
|
|
63
64
|
);
|
|
64
65
|
useChangeEffect(isOpen, onOpenChange);
|
|
65
66
|
const viewMonthStart = useMemo(() => adapter.startOfMonth(viewMonth), [viewMonth, adapter]);
|
|
@@ -150,10 +151,15 @@ function DatePickerRoot({
|
|
|
150
151
|
return /* @__PURE__ */ jsx(DatePickerContext.Provider, { value: contextValue, children });
|
|
151
152
|
}
|
|
152
153
|
var DatePickerInput = forwardRef(
|
|
153
|
-
function DatePickerInput2({ format: formatProp, onClick, onBlur, onKeyDown, ...props }, ref) {
|
|
154
|
+
function DatePickerInput2({ format: formatProp, name, onClick, onBlur, onKeyDown, ...props }, ref) {
|
|
154
155
|
const ctx = useDatePickerContext("DatePicker.Input");
|
|
155
156
|
const displayFormat = formatProp ?? ctx.displayFormat;
|
|
156
157
|
const [inputText, setInputText] = useState(null);
|
|
158
|
+
const isComposingRef = useRef(false);
|
|
159
|
+
useEffect(() => {
|
|
160
|
+
if (isComposingRef.current) return;
|
|
161
|
+
setInputText(null);
|
|
162
|
+
}, [ctx.value]);
|
|
157
163
|
let formattedValue = "";
|
|
158
164
|
if (ctx.value) {
|
|
159
165
|
try {
|
|
@@ -170,47 +176,62 @@ var DatePickerInput = forwardRef(
|
|
|
170
176
|
},
|
|
171
177
|
[ctx, onClick]
|
|
172
178
|
);
|
|
179
|
+
const commitText = useCallback(
|
|
180
|
+
(text) => {
|
|
181
|
+
if (!text) {
|
|
182
|
+
ctx.selectDate(null);
|
|
183
|
+
setInputText(null);
|
|
184
|
+
return true;
|
|
185
|
+
}
|
|
186
|
+
const parsed = parseInputValue(text, ctx.adapter);
|
|
187
|
+
if (parsed) {
|
|
188
|
+
ctx.selectDate(parsed);
|
|
189
|
+
setInputText(null);
|
|
190
|
+
return true;
|
|
191
|
+
}
|
|
192
|
+
return false;
|
|
193
|
+
},
|
|
194
|
+
[ctx]
|
|
195
|
+
);
|
|
173
196
|
const handleBlur = useCallback(
|
|
174
197
|
(e) => {
|
|
175
198
|
if (inputText !== null) {
|
|
176
|
-
|
|
177
|
-
if (parsed) {
|
|
178
|
-
ctx.selectDate(parsed);
|
|
179
|
-
}
|
|
199
|
+
commitText(inputText);
|
|
180
200
|
setInputText(null);
|
|
181
201
|
}
|
|
182
202
|
onBlur?.(e);
|
|
183
203
|
},
|
|
184
|
-
[inputText,
|
|
204
|
+
[inputText, commitText, onBlur]
|
|
185
205
|
);
|
|
186
206
|
const handleChange = useCallback(
|
|
187
207
|
(e) => {
|
|
188
208
|
const text = e.target.value;
|
|
189
209
|
setInputText(text);
|
|
190
|
-
if (
|
|
191
|
-
|
|
192
|
-
setInputText(null);
|
|
193
|
-
return;
|
|
194
|
-
}
|
|
195
|
-
const parsed = parseInputValue(text, ctx.adapter);
|
|
196
|
-
if (parsed) {
|
|
197
|
-
ctx.selectDate(parsed);
|
|
198
|
-
setInputText(null);
|
|
199
|
-
}
|
|
210
|
+
if (isComposingRef.current) return;
|
|
211
|
+
commitText(text);
|
|
200
212
|
},
|
|
201
|
-
[
|
|
213
|
+
[commitText]
|
|
214
|
+
);
|
|
215
|
+
const handleCompositionStart = useCallback(() => {
|
|
216
|
+
isComposingRef.current = true;
|
|
217
|
+
}, []);
|
|
218
|
+
const handleCompositionEnd = useCallback(
|
|
219
|
+
(e) => {
|
|
220
|
+
isComposingRef.current = false;
|
|
221
|
+
commitText(e.target.value);
|
|
222
|
+
},
|
|
223
|
+
[commitText]
|
|
202
224
|
);
|
|
203
225
|
const handleKeyDown = useCallback(
|
|
204
226
|
(e) => {
|
|
205
227
|
if (e.key === "Escape") {
|
|
206
228
|
ctx.close();
|
|
207
229
|
} else if (e.key === "Enter") {
|
|
230
|
+
if (ctx.isOpen) e.preventDefault();
|
|
208
231
|
if (inputText !== null) {
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
setInputText(null);
|
|
213
|
-
}
|
|
232
|
+
commitText(inputText);
|
|
233
|
+
} else if (ctx.isOpen) {
|
|
234
|
+
ctx.selectDate(ctx.focusedDate);
|
|
214
235
|
}
|
|
215
236
|
} else if (e.key === "ArrowDown" && !ctx.isOpen) {
|
|
216
237
|
e.preventDefault();
|
|
@@ -218,36 +239,42 @@ var DatePickerInput = forwardRef(
|
|
|
218
239
|
}
|
|
219
240
|
onKeyDown?.(e);
|
|
220
241
|
},
|
|
221
|
-
[ctx, inputText,
|
|
242
|
+
[ctx, inputText, commitText, onKeyDown]
|
|
222
243
|
);
|
|
223
244
|
const calendarId = `${ctx.pickerId}-calendar`;
|
|
224
|
-
return /* @__PURE__ */
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
245
|
+
return /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
246
|
+
/* @__PURE__ */ jsx(
|
|
247
|
+
"input",
|
|
248
|
+
{
|
|
249
|
+
ref: (node) => {
|
|
250
|
+
ctx.referenceRef.current = node;
|
|
251
|
+
if (typeof ref === "function") ref(node);
|
|
252
|
+
else if (ref) ref.current = node;
|
|
253
|
+
},
|
|
254
|
+
type: "text",
|
|
255
|
+
role: "combobox",
|
|
256
|
+
"aria-expanded": ctx.isOpen,
|
|
257
|
+
"aria-haspopup": "dialog",
|
|
258
|
+
"aria-controls": ctx.isOpen ? calendarId : void 0,
|
|
259
|
+
"aria-autocomplete": "none",
|
|
260
|
+
autoComplete: "off",
|
|
261
|
+
value: displayValue,
|
|
262
|
+
disabled: ctx.isDisabled || props.disabled,
|
|
263
|
+
readOnly: ctx.isReadOnly,
|
|
264
|
+
onChange: handleChange,
|
|
265
|
+
onClick: handleClick,
|
|
266
|
+
onBlur: handleBlur,
|
|
267
|
+
onKeyDown: handleKeyDown,
|
|
268
|
+
onCompositionStart: handleCompositionStart,
|
|
269
|
+
onCompositionEnd: handleCompositionEnd,
|
|
270
|
+
...props
|
|
271
|
+
}
|
|
272
|
+
),
|
|
273
|
+
name ? /* @__PURE__ */ jsx("input", { type: "hidden", name, value: ctx.value ?? "" }) : null
|
|
274
|
+
] });
|
|
249
275
|
}
|
|
250
276
|
);
|
|
277
|
+
DatePickerInput.displayName = "DatePicker.Input";
|
|
251
278
|
var DatePickerTrigger = forwardRef(
|
|
252
279
|
function DatePickerTrigger2({ onClick, children, ...props }, ref) {
|
|
253
280
|
const ctx = useDatePickerContext("DatePicker.Trigger");
|
|
@@ -271,6 +298,7 @@ var DatePickerTrigger = forwardRef(
|
|
|
271
298
|
tabIndex: 0,
|
|
272
299
|
"aria-label": ctx.isOpen ? ctx.labels.triggerClose : ctx.labels.triggerOpen,
|
|
273
300
|
"aria-expanded": ctx.isOpen,
|
|
301
|
+
"aria-haspopup": "dialog",
|
|
274
302
|
"aria-controls": ctx.isOpen ? calendarId : void 0,
|
|
275
303
|
disabled: ctx.isDisabled || props.disabled,
|
|
276
304
|
onClick: handleClick,
|
|
@@ -301,6 +329,8 @@ var DatePickerTrigger = forwardRef(
|
|
|
301
329
|
);
|
|
302
330
|
}
|
|
303
331
|
);
|
|
332
|
+
DatePickerTrigger.displayName = "DatePicker.Trigger";
|
|
333
|
+
var POPOVER_MIDDLEWARE = [offset(4), flip(), shift({ padding: 8 })];
|
|
304
334
|
function usePopover({
|
|
305
335
|
isOpen,
|
|
306
336
|
close,
|
|
@@ -312,7 +342,7 @@ function usePopover({
|
|
|
312
342
|
const { refs, floatingStyles, isPositioned } = useFloating({
|
|
313
343
|
open: isOpen,
|
|
314
344
|
placement,
|
|
315
|
-
middleware:
|
|
345
|
+
middleware: POPOVER_MIDDLEWARE,
|
|
316
346
|
whileElementsMounted: autoUpdate
|
|
317
347
|
});
|
|
318
348
|
useEffect(() => {
|
|
@@ -359,6 +389,24 @@ function usePopover({
|
|
|
359
389
|
document.addEventListener("keydown", handleKeyDown);
|
|
360
390
|
return () => document.removeEventListener("keydown", handleKeyDown);
|
|
361
391
|
}, [isOpen, close]);
|
|
392
|
+
useEffect(() => {
|
|
393
|
+
if (!isOpen) return;
|
|
394
|
+
function handleFocusOut(e) {
|
|
395
|
+
const next = e.relatedTarget;
|
|
396
|
+
const floating = floatingRef.current;
|
|
397
|
+
const reference = referenceRef.current;
|
|
398
|
+
if (!next) return;
|
|
399
|
+
const insideFloating = floating?.contains(next) ?? false;
|
|
400
|
+
const insideReference = reference?.contains(next) ?? false;
|
|
401
|
+
if (!insideFloating && !insideReference) {
|
|
402
|
+
close();
|
|
403
|
+
}
|
|
404
|
+
}
|
|
405
|
+
const node = floatingRef.current;
|
|
406
|
+
if (!node) return;
|
|
407
|
+
node.addEventListener("focusout", handleFocusOut);
|
|
408
|
+
return () => node.removeEventListener("focusout", handleFocusOut);
|
|
409
|
+
}, [isOpen, close, referenceRef]);
|
|
362
410
|
const setFloatingRef = useCallback(
|
|
363
411
|
(node) => {
|
|
364
412
|
floatingRef.current = node;
|
|
@@ -420,20 +468,36 @@ var srOnly = {
|
|
|
420
468
|
function DatePickerCalendar({
|
|
421
469
|
classNames,
|
|
422
470
|
onTitleClick,
|
|
471
|
+
showWeekNumber = false,
|
|
472
|
+
fixedWeeks = false,
|
|
423
473
|
...props
|
|
424
474
|
}) {
|
|
425
475
|
const ctx = useDatePickerContext("DatePicker.Calendar");
|
|
426
476
|
const gridRef = useRef(null);
|
|
427
477
|
const [announcement, setAnnouncement] = useState("");
|
|
428
478
|
const { adapter, viewMonth, focusedDate, weekStartsOn, disabled, locale, displayTimezone } = ctx;
|
|
429
|
-
const weekdays = getWeekdayNames(locale, weekStartsOn);
|
|
430
|
-
const weeks =
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
479
|
+
const weekdays = useMemo(() => getWeekdayNames(locale, weekStartsOn), [locale, weekStartsOn]);
|
|
480
|
+
const weeks = useMemo(
|
|
481
|
+
() => getCalendarDays(viewMonth, adapter, {
|
|
482
|
+
weekStartsOn,
|
|
483
|
+
selected: ctx.value,
|
|
484
|
+
focusedDate,
|
|
485
|
+
disabled,
|
|
486
|
+
timezone: displayTimezone,
|
|
487
|
+
fixedWeeks
|
|
488
|
+
}),
|
|
489
|
+
[
|
|
490
|
+
viewMonth,
|
|
491
|
+
adapter,
|
|
492
|
+
weekStartsOn,
|
|
493
|
+
ctx.value,
|
|
494
|
+
focusedDate,
|
|
495
|
+
disabled,
|
|
496
|
+
displayTimezone,
|
|
497
|
+
fixedWeeks
|
|
498
|
+
]
|
|
499
|
+
);
|
|
500
|
+
const thursdayIndex = weekStartsOn === 0 ? 4 : 3;
|
|
437
501
|
const year = adapter.getYear(viewMonth);
|
|
438
502
|
const month = adapter.getMonth(viewMonth);
|
|
439
503
|
const title = formatMonthYear(year, month, locale);
|
|
@@ -513,6 +577,15 @@ function DatePickerCalendar({
|
|
|
513
577
|
}
|
|
514
578
|
if (newFocused) {
|
|
515
579
|
e.preventDefault();
|
|
580
|
+
const skipStep = e.key === "ArrowLeft" || e.key === "ArrowUp" || e.key === "PageUp" || e.key === "Home" ? -1 : 1;
|
|
581
|
+
let attempts = 0;
|
|
582
|
+
while (isDateDisabled(newFocused, disabled, adapter) && attempts < 42) {
|
|
583
|
+
newFocused = adapter.addDays(newFocused, skipStep);
|
|
584
|
+
attempts++;
|
|
585
|
+
}
|
|
586
|
+
if (attempts >= 42) {
|
|
587
|
+
return;
|
|
588
|
+
}
|
|
516
589
|
ctx.setFocusedDate(newFocused);
|
|
517
590
|
if (!adapter.isSameMonth(newFocused, viewMonth)) {
|
|
518
591
|
ctx.setViewMonth(newFocused);
|
|
@@ -560,62 +633,170 @@ function DatePickerCalendar({
|
|
|
560
633
|
ref: gridRef,
|
|
561
634
|
role: "grid",
|
|
562
635
|
"aria-label": title,
|
|
636
|
+
"aria-rowcount": weeks.length + 1,
|
|
637
|
+
"aria-colcount": 7,
|
|
563
638
|
className: classNames?.grid,
|
|
564
639
|
onKeyDown: handleKeyDown,
|
|
565
640
|
children: [
|
|
566
|
-
/* @__PURE__ */ jsx("thead", { children: /* @__PURE__ */
|
|
567
|
-
"th",
|
|
568
|
-
|
|
569
|
-
|
|
570
|
-
abbr: day.full,
|
|
571
|
-
scope: "col",
|
|
572
|
-
className: classNames?.weekdayHeader,
|
|
573
|
-
children: day.short
|
|
574
|
-
},
|
|
575
|
-
day.short
|
|
576
|
-
)) }) }),
|
|
577
|
-
/* @__PURE__ */ jsx("tbody", { children: weeks.map((week, weekIndex) => /* @__PURE__ */ jsx("tr", { role: "row", className: classNames?.gridRow, children: week.map((day) => {
|
|
578
|
-
const dayClasses = [
|
|
579
|
-
classNames?.day,
|
|
580
|
-
day.isSelected && classNames?.daySelected,
|
|
581
|
-
day.isToday && classNames?.dayToday,
|
|
582
|
-
day.isDisabled && classNames?.dayDisabled,
|
|
583
|
-
!day.isCurrentMonth && classNames?.dayOutsideMonth
|
|
584
|
-
].filter(Boolean).join(" ") || void 0;
|
|
585
|
-
return /* @__PURE__ */ jsx(
|
|
586
|
-
"td",
|
|
641
|
+
/* @__PURE__ */ jsx("thead", { children: /* @__PURE__ */ jsxs("tr", { role: "row", "aria-rowindex": 1, children: [
|
|
642
|
+
showWeekNumber ? /* @__PURE__ */ jsx("th", { scope: "col", "aria-hidden": "true", className: classNames?.weekNumberHeader, children: "#" }) : null,
|
|
643
|
+
weekdays.map((day, colIndex) => /* @__PURE__ */ jsx(
|
|
644
|
+
"th",
|
|
587
645
|
{
|
|
588
|
-
role: "
|
|
589
|
-
|
|
590
|
-
"
|
|
591
|
-
"aria-
|
|
592
|
-
className: classNames?.
|
|
593
|
-
children:
|
|
594
|
-
|
|
646
|
+
role: "columnheader",
|
|
647
|
+
abbr: day.full,
|
|
648
|
+
scope: "col",
|
|
649
|
+
"aria-colindex": colIndex + 1,
|
|
650
|
+
className: classNames?.weekdayHeader,
|
|
651
|
+
children: day.short
|
|
652
|
+
},
|
|
653
|
+
day.short
|
|
654
|
+
))
|
|
655
|
+
] }) }),
|
|
656
|
+
/* @__PURE__ */ jsx("tbody", { children: weeks.map((week, weekIndex) => /* @__PURE__ */ jsxs(
|
|
657
|
+
"tr",
|
|
658
|
+
{
|
|
659
|
+
role: "row",
|
|
660
|
+
"aria-rowindex": weekIndex + 2,
|
|
661
|
+
className: classNames?.gridRow,
|
|
662
|
+
children: [
|
|
663
|
+
showWeekNumber ? /* @__PURE__ */ jsx(
|
|
664
|
+
"th",
|
|
595
665
|
{
|
|
596
|
-
|
|
597
|
-
|
|
598
|
-
|
|
599
|
-
"data-
|
|
600
|
-
|
|
601
|
-
"data-today": day.isToday || void 0,
|
|
602
|
-
"data-outside-month": !day.isCurrentMonth || void 0,
|
|
603
|
-
className: dayClasses,
|
|
604
|
-
onClick: () => handleDayClick(day),
|
|
605
|
-
"aria-label": safeFormatFullDate(day.isoString, locale),
|
|
606
|
-
children: day.dayNumber
|
|
666
|
+
scope: "row",
|
|
667
|
+
"aria-hidden": "true",
|
|
668
|
+
className: classNames?.weekNumber,
|
|
669
|
+
"data-week-number": true,
|
|
670
|
+
children: getISOWeekNumber(week[thursdayIndex].isoString)
|
|
607
671
|
}
|
|
608
|
-
)
|
|
609
|
-
|
|
610
|
-
|
|
611
|
-
|
|
612
|
-
|
|
672
|
+
) : null,
|
|
673
|
+
week.map((day, colIndex) => {
|
|
674
|
+
const dayClasses = [
|
|
675
|
+
classNames?.day,
|
|
676
|
+
day.isSelected && classNames?.daySelected,
|
|
677
|
+
day.isToday && classNames?.dayToday,
|
|
678
|
+
day.isDisabled && classNames?.dayDisabled,
|
|
679
|
+
!day.isCurrentMonth && classNames?.dayOutsideMonth
|
|
680
|
+
].filter(Boolean).join(" ") || void 0;
|
|
681
|
+
return /* @__PURE__ */ jsx(
|
|
682
|
+
"td",
|
|
683
|
+
{
|
|
684
|
+
role: "gridcell",
|
|
685
|
+
"aria-colindex": colIndex + 1,
|
|
686
|
+
"aria-selected": day.isSelected || void 0,
|
|
687
|
+
"aria-disabled": day.isDisabled || void 0,
|
|
688
|
+
"aria-current": day.isToday ? "date" : void 0,
|
|
689
|
+
className: classNames?.gridCell,
|
|
690
|
+
children: /* @__PURE__ */ jsx(
|
|
691
|
+
"button",
|
|
692
|
+
{
|
|
693
|
+
type: "button",
|
|
694
|
+
tabIndex: day.isFocused ? 0 : -1,
|
|
695
|
+
disabled: day.isDisabled,
|
|
696
|
+
"data-focused": day.isFocused || void 0,
|
|
697
|
+
"data-selected": day.isSelected || void 0,
|
|
698
|
+
"data-today": day.isToday || void 0,
|
|
699
|
+
"data-outside-month": !day.isCurrentMonth || void 0,
|
|
700
|
+
className: dayClasses,
|
|
701
|
+
onClick: () => handleDayClick(day),
|
|
702
|
+
"aria-label": safeFormatFullDate(day.isoString, locale),
|
|
703
|
+
children: day.dayNumber
|
|
704
|
+
}
|
|
705
|
+
)
|
|
706
|
+
},
|
|
707
|
+
day.isoString
|
|
708
|
+
);
|
|
709
|
+
})
|
|
710
|
+
]
|
|
711
|
+
},
|
|
712
|
+
weekIndex
|
|
713
|
+
)) })
|
|
613
714
|
]
|
|
614
715
|
}
|
|
615
716
|
),
|
|
616
717
|
/* @__PURE__ */ jsx("div", { role: "status", "aria-live": "polite", "aria-atomic": "true", style: srOnly, children: announcement })
|
|
617
718
|
] });
|
|
618
719
|
}
|
|
720
|
+
function isRangeFullyDisabled(start, end, rules, adapter) {
|
|
721
|
+
for (const rule of rules) {
|
|
722
|
+
if ("before" in rule && adapter.isBefore(end, rule.before)) return true;
|
|
723
|
+
if ("after" in rule && adapter.isAfter(start, rule.after)) return true;
|
|
724
|
+
}
|
|
725
|
+
return false;
|
|
726
|
+
}
|
|
727
|
+
function useGridState(opts) {
|
|
728
|
+
const { initialIndex, disabledFlags, onSelect, onPageUp, onPageDown, onEscape } = opts;
|
|
729
|
+
const gridRef = useRef(null);
|
|
730
|
+
const [focusedIndex, setFocusedIndex] = useState(initialIndex);
|
|
731
|
+
const handleKeyDown = (e) => {
|
|
732
|
+
let next = null;
|
|
733
|
+
let step = 1;
|
|
734
|
+
switch (e.key) {
|
|
735
|
+
case "ArrowLeft":
|
|
736
|
+
next = Math.max(0, focusedIndex - 1);
|
|
737
|
+
step = -1;
|
|
738
|
+
break;
|
|
739
|
+
case "ArrowRight":
|
|
740
|
+
next = Math.min(11, focusedIndex + 1);
|
|
741
|
+
break;
|
|
742
|
+
case "ArrowUp":
|
|
743
|
+
next = Math.max(0, focusedIndex - 3);
|
|
744
|
+
step = -1;
|
|
745
|
+
break;
|
|
746
|
+
case "ArrowDown":
|
|
747
|
+
next = Math.min(11, focusedIndex + 3);
|
|
748
|
+
break;
|
|
749
|
+
case "Home":
|
|
750
|
+
next = focusedIndex - focusedIndex % 3;
|
|
751
|
+
step = -1;
|
|
752
|
+
break;
|
|
753
|
+
case "End":
|
|
754
|
+
next = focusedIndex - focusedIndex % 3 + 2;
|
|
755
|
+
break;
|
|
756
|
+
case "PageUp":
|
|
757
|
+
e.preventDefault();
|
|
758
|
+
onPageUp();
|
|
759
|
+
return;
|
|
760
|
+
case "PageDown":
|
|
761
|
+
e.preventDefault();
|
|
762
|
+
onPageDown();
|
|
763
|
+
return;
|
|
764
|
+
case "Enter":
|
|
765
|
+
case " ":
|
|
766
|
+
e.preventDefault();
|
|
767
|
+
onSelect(focusedIndex);
|
|
768
|
+
return;
|
|
769
|
+
case "Escape":
|
|
770
|
+
onEscape();
|
|
771
|
+
return;
|
|
772
|
+
default:
|
|
773
|
+
return;
|
|
774
|
+
}
|
|
775
|
+
if (next === null) return;
|
|
776
|
+
e.preventDefault();
|
|
777
|
+
if (disabledFlags) {
|
|
778
|
+
let attempts = 0;
|
|
779
|
+
while (next >= 0 && next < 12 && disabledFlags[next] && attempts < 12) {
|
|
780
|
+
next += step;
|
|
781
|
+
attempts++;
|
|
782
|
+
}
|
|
783
|
+
if (next < 0 || next >= 12 || disabledFlags[next]) return;
|
|
784
|
+
}
|
|
785
|
+
if (next !== focusedIndex) setFocusedIndex(next);
|
|
786
|
+
};
|
|
787
|
+
useEffect(() => {
|
|
788
|
+
if (!disabledFlags || !disabledFlags[focusedIndex]) return;
|
|
789
|
+
const firstEnabled = disabledFlags.findIndex((d) => !d);
|
|
790
|
+
if (firstEnabled !== -1 && firstEnabled !== focusedIndex) {
|
|
791
|
+
setFocusedIndex(firstEnabled);
|
|
792
|
+
}
|
|
793
|
+
}, [disabledFlags, focusedIndex]);
|
|
794
|
+
useEffect(() => {
|
|
795
|
+
const btn = gridRef.current?.querySelector('[data-focused="true"]');
|
|
796
|
+
btn?.focus({ preventScroll: true });
|
|
797
|
+
}, [focusedIndex]);
|
|
798
|
+
return { gridRef, focusedIndex, handleKeyDown };
|
|
799
|
+
}
|
|
619
800
|
function DatePickerMonthGrid({
|
|
620
801
|
classNames,
|
|
621
802
|
onSelect,
|
|
@@ -623,15 +804,18 @@ function DatePickerMonthGrid({
|
|
|
623
804
|
...props
|
|
624
805
|
}) {
|
|
625
806
|
const ctx = useDatePickerContext("DatePicker.MonthGrid");
|
|
626
|
-
const { adapter, viewMonth, locale } = ctx;
|
|
807
|
+
const { adapter, viewMonth, locale, displayTimezone } = ctx;
|
|
627
808
|
const currentYear = adapter.getYear(viewMonth);
|
|
628
809
|
const currentMonth = adapter.getMonth(viewMonth);
|
|
629
|
-
const
|
|
630
|
-
|
|
810
|
+
const [today, setToday] = useState(null);
|
|
811
|
+
useEffect(() => {
|
|
812
|
+
setToday(adapter.today(displayTimezone));
|
|
813
|
+
}, [adapter, displayTimezone]);
|
|
814
|
+
const todayMonth = today !== null ? adapter.getMonth(today) : -1;
|
|
815
|
+
const todayYear = today !== null ? adapter.getYear(today) : -1;
|
|
631
816
|
const navigateYear = useCallback(
|
|
632
817
|
(direction) => {
|
|
633
|
-
|
|
634
|
-
ctx.setViewMonth(newDate);
|
|
818
|
+
ctx.setViewMonth(adapter.addYears(viewMonth, direction));
|
|
635
819
|
},
|
|
636
820
|
[adapter, viewMonth, ctx]
|
|
637
821
|
);
|
|
@@ -644,12 +828,13 @@ function DatePickerMonthGrid({
|
|
|
644
828
|
},
|
|
645
829
|
[currentYear, ctx, onSelect]
|
|
646
830
|
);
|
|
647
|
-
const
|
|
648
|
-
|
|
649
|
-
|
|
650
|
-
|
|
651
|
-
|
|
652
|
-
|
|
831
|
+
const { gridRef, focusedIndex, handleKeyDown } = useGridState({
|
|
832
|
+
initialIndex: currentMonth,
|
|
833
|
+
onSelect: handleMonthSelect,
|
|
834
|
+
onPageUp: () => navigateYear(-1),
|
|
835
|
+
onPageDown: () => navigateYear(1),
|
|
836
|
+
onEscape: ctx.close
|
|
837
|
+
});
|
|
653
838
|
return /* @__PURE__ */ jsxs("div", { className: classNames?.root, ...props, children: [
|
|
654
839
|
/* @__PURE__ */ jsxs("div", { className: classNames?.header, children: [
|
|
655
840
|
/* @__PURE__ */ jsx(
|
|
@@ -677,30 +862,37 @@ function DatePickerMonthGrid({
|
|
|
677
862
|
/* @__PURE__ */ jsx(
|
|
678
863
|
"div",
|
|
679
864
|
{
|
|
865
|
+
ref: gridRef,
|
|
680
866
|
role: "grid",
|
|
681
867
|
"aria-label": `${currentYear} months`,
|
|
682
868
|
className: classNames?.grid,
|
|
683
869
|
style: { display: "grid", gridTemplateColumns: "repeat(3, 1fr)" },
|
|
684
|
-
|
|
685
|
-
|
|
870
|
+
onKeyDown: handleKeyDown,
|
|
871
|
+
children: Array.from({ length: 12 }, (_, i) => {
|
|
872
|
+
const isSelected = i === currentMonth;
|
|
873
|
+
const isCurrent = i === todayMonth && currentYear === todayYear;
|
|
874
|
+
const isFocused = i === focusedIndex;
|
|
875
|
+
const cls = [
|
|
686
876
|
classNames?.month,
|
|
687
|
-
|
|
688
|
-
|
|
877
|
+
isSelected && classNames?.monthSelected,
|
|
878
|
+
isCurrent && classNames?.monthCurrent
|
|
689
879
|
].filter(Boolean).join(" ") || void 0;
|
|
690
880
|
return /* @__PURE__ */ jsx(
|
|
691
881
|
"button",
|
|
692
882
|
{
|
|
693
883
|
type: "button",
|
|
694
884
|
role: "gridcell",
|
|
695
|
-
|
|
696
|
-
"aria-
|
|
697
|
-
"
|
|
698
|
-
"data-
|
|
699
|
-
|
|
700
|
-
|
|
701
|
-
|
|
885
|
+
tabIndex: isFocused ? 0 : -1,
|
|
886
|
+
"aria-selected": isSelected || void 0,
|
|
887
|
+
"aria-current": isCurrent ? "date" : void 0,
|
|
888
|
+
"data-selected": isSelected || void 0,
|
|
889
|
+
"data-current": isCurrent || void 0,
|
|
890
|
+
"data-focused": isFocused || void 0,
|
|
891
|
+
className: cls,
|
|
892
|
+
onClick: () => handleMonthSelect(i),
|
|
893
|
+
children: getMonthName(i, locale)
|
|
702
894
|
},
|
|
703
|
-
|
|
895
|
+
i
|
|
704
896
|
);
|
|
705
897
|
})
|
|
706
898
|
}
|
|
@@ -709,38 +901,38 @@ function DatePickerMonthGrid({
|
|
|
709
901
|
}
|
|
710
902
|
function DatePickerYearGrid({ classNames, onSelect, ...props }) {
|
|
711
903
|
const ctx = useDatePickerContext("DatePicker.YearGrid");
|
|
712
|
-
const { adapter, viewMonth } = ctx;
|
|
904
|
+
const { adapter, viewMonth, displayTimezone } = ctx;
|
|
713
905
|
const currentYear = adapter.getYear(viewMonth);
|
|
714
|
-
const
|
|
906
|
+
const [today, setToday] = useState(null);
|
|
907
|
+
useEffect(() => {
|
|
908
|
+
setToday(adapter.today(displayTimezone));
|
|
909
|
+
}, [adapter, displayTimezone]);
|
|
910
|
+
const todayYear = today !== null ? adapter.getYear(today) : -1;
|
|
715
911
|
const decadeStart = currentYear - currentYear % 12;
|
|
716
912
|
const navigateDecade = useCallback(
|
|
717
913
|
(direction) => {
|
|
718
|
-
|
|
719
|
-
ctx.setViewMonth(newDate);
|
|
914
|
+
ctx.setViewMonth(adapter.addYears(viewMonth, direction * 12));
|
|
720
915
|
},
|
|
721
916
|
[adapter, viewMonth, ctx]
|
|
722
917
|
);
|
|
723
918
|
const handleYearSelect = useCallback(
|
|
724
|
-
(
|
|
919
|
+
(indexInDecade) => {
|
|
920
|
+
const year = decadeStart + indexInDecade;
|
|
725
921
|
const currentMonth = adapter.getMonth(viewMonth);
|
|
726
922
|
const target = new Date(Date.UTC(year, currentMonth, 1)).toISOString();
|
|
727
923
|
ctx.setViewMonth(target);
|
|
728
924
|
ctx.setFocusedDate(target);
|
|
729
925
|
onSelect?.();
|
|
730
926
|
},
|
|
731
|
-
[adapter, viewMonth, ctx, onSelect]
|
|
732
|
-
);
|
|
733
|
-
const
|
|
734
|
-
|
|
735
|
-
|
|
736
|
-
|
|
737
|
-
|
|
738
|
-
|
|
739
|
-
|
|
740
|
-
};
|
|
741
|
-
}),
|
|
742
|
-
[decadeStart, currentYear, todayYear]
|
|
743
|
-
);
|
|
927
|
+
[adapter, viewMonth, ctx, onSelect, decadeStart]
|
|
928
|
+
);
|
|
929
|
+
const { gridRef, focusedIndex, handleKeyDown } = useGridState({
|
|
930
|
+
initialIndex: currentYear - decadeStart,
|
|
931
|
+
onSelect: handleYearSelect,
|
|
932
|
+
onPageUp: () => navigateDecade(-1),
|
|
933
|
+
onPageDown: () => navigateDecade(1),
|
|
934
|
+
onEscape: ctx.close
|
|
935
|
+
});
|
|
744
936
|
const rangeLabel = `${decadeStart}\u2013${decadeStart + 11}`;
|
|
745
937
|
return /* @__PURE__ */ jsxs("div", { className: classNames?.root, ...props, children: [
|
|
746
938
|
/* @__PURE__ */ jsxs("div", { className: classNames?.header, children: [
|
|
@@ -769,30 +961,38 @@ function DatePickerYearGrid({ classNames, onSelect, ...props }) {
|
|
|
769
961
|
/* @__PURE__ */ jsx(
|
|
770
962
|
"div",
|
|
771
963
|
{
|
|
964
|
+
ref: gridRef,
|
|
772
965
|
role: "grid",
|
|
773
966
|
"aria-label": rangeLabel,
|
|
774
967
|
className: classNames?.grid,
|
|
775
968
|
style: { display: "grid", gridTemplateColumns: "repeat(3, 1fr)" },
|
|
776
|
-
|
|
777
|
-
|
|
969
|
+
onKeyDown: handleKeyDown,
|
|
970
|
+
children: Array.from({ length: 12 }, (_, i) => {
|
|
971
|
+
const year = decadeStart + i;
|
|
972
|
+
const isSelected = year === currentYear;
|
|
973
|
+
const isCurrent = year === todayYear;
|
|
974
|
+
const isFocused = i === focusedIndex;
|
|
975
|
+
const cls = [
|
|
778
976
|
classNames?.year,
|
|
779
|
-
|
|
780
|
-
|
|
977
|
+
isSelected && classNames?.yearSelected,
|
|
978
|
+
isCurrent && classNames?.yearCurrent
|
|
781
979
|
].filter(Boolean).join(" ") || void 0;
|
|
782
980
|
return /* @__PURE__ */ jsx(
|
|
783
981
|
"button",
|
|
784
982
|
{
|
|
785
983
|
type: "button",
|
|
786
984
|
role: "gridcell",
|
|
787
|
-
|
|
788
|
-
"aria-
|
|
789
|
-
"
|
|
790
|
-
"data-
|
|
791
|
-
|
|
792
|
-
|
|
793
|
-
|
|
985
|
+
tabIndex: isFocused ? 0 : -1,
|
|
986
|
+
"aria-selected": isSelected || void 0,
|
|
987
|
+
"aria-current": isCurrent ? "date" : void 0,
|
|
988
|
+
"data-selected": isSelected || void 0,
|
|
989
|
+
"data-current": isCurrent || void 0,
|
|
990
|
+
"data-focused": isFocused || void 0,
|
|
991
|
+
className: cls,
|
|
992
|
+
onClick: () => handleYearSelect(i),
|
|
993
|
+
children: year
|
|
794
994
|
},
|
|
795
|
-
|
|
995
|
+
i
|
|
796
996
|
);
|
|
797
997
|
})
|
|
798
998
|
}
|
|
@@ -865,8 +1065,7 @@ function DatePickerPreset({
|
|
|
865
1065
|
"button",
|
|
866
1066
|
{
|
|
867
1067
|
type: "button",
|
|
868
|
-
|
|
869
|
-
"aria-selected": isActive,
|
|
1068
|
+
"aria-pressed": isActive,
|
|
870
1069
|
"data-active": isActive || void 0,
|
|
871
1070
|
disabled: ctx.isDisabled,
|
|
872
1071
|
onClick: handleClick,
|
|
@@ -903,6 +1102,17 @@ function useRangePickerContext(componentName) {
|
|
|
903
1102
|
return context;
|
|
904
1103
|
}
|
|
905
1104
|
var EMPTY_RANGE = { start: null, end: null };
|
|
1105
|
+
var SR_ONLY = {
|
|
1106
|
+
position: "absolute",
|
|
1107
|
+
width: 1,
|
|
1108
|
+
height: 1,
|
|
1109
|
+
padding: 0,
|
|
1110
|
+
margin: -1,
|
|
1111
|
+
overflow: "hidden",
|
|
1112
|
+
clip: "rect(0, 0, 0, 0)",
|
|
1113
|
+
whiteSpace: "nowrap",
|
|
1114
|
+
border: 0
|
|
1115
|
+
};
|
|
906
1116
|
function RangePickerRoot({
|
|
907
1117
|
value: controlledValue,
|
|
908
1118
|
defaultValue,
|
|
@@ -929,11 +1139,13 @@ function RangePickerRoot({
|
|
|
929
1139
|
const [isOpen, setIsOpen] = useState(false);
|
|
930
1140
|
const [selectingTarget, setSelectingTarget] = useState("start");
|
|
931
1141
|
const [hoverDate, setHoverDate] = useState(null);
|
|
1142
|
+
const [announcement, setAnnouncement] = useState("");
|
|
1143
|
+
const announce = useCallback((message) => setAnnouncement(message), []);
|
|
932
1144
|
const [viewMonth, setViewMonth] = useState(
|
|
933
|
-
currentValue.start ?? adapter.today(displayTimezone)
|
|
1145
|
+
() => currentValue.start ?? adapter.today(displayTimezone)
|
|
934
1146
|
);
|
|
935
1147
|
const [focusedDate, setFocusedDate] = useState(
|
|
936
|
-
currentValue.start ?? adapter.today(displayTimezone)
|
|
1148
|
+
() => currentValue.start ?? adapter.today(displayTimezone)
|
|
937
1149
|
);
|
|
938
1150
|
useChangeEffect(isOpen, onOpenChange);
|
|
939
1151
|
const viewMonthStart = useMemo(() => adapter.startOfMonth(viewMonth), [viewMonth, adapter]);
|
|
@@ -1031,7 +1243,8 @@ function RangePickerRoot({
|
|
|
1031
1243
|
isDisabled,
|
|
1032
1244
|
isReadOnly: readOnly,
|
|
1033
1245
|
pickerId,
|
|
1034
|
-
labels: mergedLabels
|
|
1246
|
+
labels: mergedLabels,
|
|
1247
|
+
announce
|
|
1035
1248
|
}),
|
|
1036
1249
|
[
|
|
1037
1250
|
currentValue,
|
|
@@ -1054,10 +1267,14 @@ function RangePickerRoot({
|
|
|
1054
1267
|
isDisabled,
|
|
1055
1268
|
readOnly,
|
|
1056
1269
|
pickerId,
|
|
1057
|
-
mergedLabels
|
|
1270
|
+
mergedLabels,
|
|
1271
|
+
announce
|
|
1058
1272
|
]
|
|
1059
1273
|
);
|
|
1060
|
-
return /* @__PURE__ */
|
|
1274
|
+
return /* @__PURE__ */ jsxs(RangePickerContext.Provider, { value: contextValue, children: [
|
|
1275
|
+
children,
|
|
1276
|
+
/* @__PURE__ */ jsx("div", { role: "status", "aria-live": "polite", "aria-atomic": "true", style: SR_ONLY, children: announcement })
|
|
1277
|
+
] });
|
|
1061
1278
|
}
|
|
1062
1279
|
var RangePickerInput = forwardRef(
|
|
1063
1280
|
function RangePickerInput2({ part, format: formatProp, onClick, onKeyDown, ...props }, ref) {
|
|
@@ -1083,6 +1300,8 @@ var RangePickerInput = forwardRef(
|
|
|
1083
1300
|
(e) => {
|
|
1084
1301
|
if (e.key === "Escape") {
|
|
1085
1302
|
ctx.close();
|
|
1303
|
+
} else if (e.key === "Enter" && ctx.isOpen) {
|
|
1304
|
+
e.preventDefault();
|
|
1086
1305
|
} else if (e.key === "ArrowDown" && !ctx.isOpen) {
|
|
1087
1306
|
e.preventDefault();
|
|
1088
1307
|
ctx.open();
|
|
@@ -1119,6 +1338,7 @@ var RangePickerInput = forwardRef(
|
|
|
1119
1338
|
);
|
|
1120
1339
|
}
|
|
1121
1340
|
);
|
|
1341
|
+
RangePickerInput.displayName = "RangePicker.Input";
|
|
1122
1342
|
function RangePickerPopover({ children, ...props }) {
|
|
1123
1343
|
const ctx = useRangePickerContext("RangePicker.Popover");
|
|
1124
1344
|
const calendarId = `${ctx.pickerId}-calendar`;
|
|
@@ -1154,25 +1374,15 @@ function safeFormatFullDate2(iso, locale) {
|
|
|
1154
1374
|
return iso;
|
|
1155
1375
|
}
|
|
1156
1376
|
}
|
|
1157
|
-
var srOnly2 = {
|
|
1158
|
-
position: "absolute",
|
|
1159
|
-
width: "1px",
|
|
1160
|
-
height: "1px",
|
|
1161
|
-
padding: 0,
|
|
1162
|
-
margin: "-1px",
|
|
1163
|
-
overflow: "hidden",
|
|
1164
|
-
clip: "rect(0, 0, 0, 0)",
|
|
1165
|
-
whiteSpace: "nowrap",
|
|
1166
|
-
border: 0
|
|
1167
|
-
};
|
|
1168
1377
|
function RangePickerCalendar({
|
|
1169
1378
|
classNames,
|
|
1170
1379
|
selectionMode = "range",
|
|
1380
|
+
showWeekNumber = false,
|
|
1381
|
+
fixedWeeks = false,
|
|
1171
1382
|
...props
|
|
1172
1383
|
}) {
|
|
1173
1384
|
const ctx = useRangePickerContext("RangePicker.Calendar");
|
|
1174
1385
|
const gridRef = useRef(null);
|
|
1175
|
-
const [announcement, setAnnouncement] = useState("");
|
|
1176
1386
|
const {
|
|
1177
1387
|
adapter,
|
|
1178
1388
|
viewMonth,
|
|
@@ -1185,15 +1395,30 @@ function RangePickerCalendar({
|
|
|
1185
1395
|
displayTimezone
|
|
1186
1396
|
} = ctx;
|
|
1187
1397
|
const { locale } = ctx;
|
|
1188
|
-
const weekdays = getWeekdayNames(locale, weekStartsOn);
|
|
1189
|
-
const weeks =
|
|
1190
|
-
|
|
1191
|
-
|
|
1192
|
-
|
|
1193
|
-
|
|
1194
|
-
|
|
1195
|
-
|
|
1196
|
-
|
|
1398
|
+
const weekdays = useMemo(() => getWeekdayNames(locale, weekStartsOn), [locale, weekStartsOn]);
|
|
1399
|
+
const weeks = useMemo(
|
|
1400
|
+
() => getCalendarDays(viewMonth, adapter, {
|
|
1401
|
+
weekStartsOn,
|
|
1402
|
+
focusedDate,
|
|
1403
|
+
disabled,
|
|
1404
|
+
range: value,
|
|
1405
|
+
rangeHover: hoverDate,
|
|
1406
|
+
timezone: displayTimezone,
|
|
1407
|
+
fixedWeeks
|
|
1408
|
+
}),
|
|
1409
|
+
[
|
|
1410
|
+
viewMonth,
|
|
1411
|
+
adapter,
|
|
1412
|
+
weekStartsOn,
|
|
1413
|
+
focusedDate,
|
|
1414
|
+
disabled,
|
|
1415
|
+
value,
|
|
1416
|
+
hoverDate,
|
|
1417
|
+
displayTimezone,
|
|
1418
|
+
fixedWeeks
|
|
1419
|
+
]
|
|
1420
|
+
);
|
|
1421
|
+
const thursdayIndex = weekStartsOn === 0 ? 4 : 3;
|
|
1197
1422
|
const year = adapter.getYear(viewMonth);
|
|
1198
1423
|
const month = adapter.getMonth(viewMonth);
|
|
1199
1424
|
const title = formatMonthYear(year, month, locale);
|
|
@@ -1209,7 +1434,7 @@ function RangePickerCalendar({
|
|
|
1209
1434
|
ctx.setFocusedDate(adapter.startOfMonth(newMonth));
|
|
1210
1435
|
const y = adapter.getYear(newMonth);
|
|
1211
1436
|
const m = adapter.getMonth(newMonth);
|
|
1212
|
-
|
|
1437
|
+
ctx.announce(formatMonthYear(y, m, locale));
|
|
1213
1438
|
},
|
|
1214
1439
|
[adapter, viewMonth, ctx, locale]
|
|
1215
1440
|
);
|
|
@@ -1221,15 +1446,27 @@ function RangePickerCalendar({
|
|
|
1221
1446
|
const range = { start: weekStart, end: weekEnd };
|
|
1222
1447
|
ctx.setRange(range);
|
|
1223
1448
|
ctx.close();
|
|
1224
|
-
|
|
1225
|
-
`${safeFormatFullDate2(weekStart, locale)} \u2013 ${safeFormatFullDate2(weekEnd, locale)}`
|
|
1449
|
+
ctx.announce(
|
|
1450
|
+
`${ctx.labels.rangeSelected}: ${safeFormatFullDate2(weekStart, locale)} \u2013 ${safeFormatFullDate2(weekEnd, locale)}`
|
|
1226
1451
|
);
|
|
1227
1452
|
} else {
|
|
1453
|
+
const wasPickingStart = selectingTarget === "start";
|
|
1454
|
+
const previousStart = value.start;
|
|
1228
1455
|
ctx.selectDate(iso);
|
|
1229
|
-
|
|
1456
|
+
const formatted = safeFormatFullDate2(iso, locale);
|
|
1457
|
+
if (wasPickingStart) {
|
|
1458
|
+
ctx.announce(`${formatted}. ${ctx.labels.selectingEnd}`);
|
|
1459
|
+
} else if (previousStart) {
|
|
1460
|
+
const [start, end] = adapter.isBefore(iso, previousStart) ? [iso, previousStart] : [previousStart, iso];
|
|
1461
|
+
ctx.announce(
|
|
1462
|
+
`${ctx.labels.rangeSelected}: ${safeFormatFullDate2(start, locale)} \u2013 ${safeFormatFullDate2(end, locale)}`
|
|
1463
|
+
);
|
|
1464
|
+
} else {
|
|
1465
|
+
ctx.announce(formatted);
|
|
1466
|
+
}
|
|
1230
1467
|
}
|
|
1231
1468
|
},
|
|
1232
|
-
[selectionMode, adapter, weekStartsOn, ctx, locale]
|
|
1469
|
+
[selectionMode, adapter, weekStartsOn, ctx, locale, selectingTarget, value.start]
|
|
1233
1470
|
);
|
|
1234
1471
|
const handleDayClick = useCallback(
|
|
1235
1472
|
(day) => {
|
|
@@ -1293,6 +1530,13 @@ function RangePickerCalendar({
|
|
|
1293
1530
|
}
|
|
1294
1531
|
if (newFocused) {
|
|
1295
1532
|
e.preventDefault();
|
|
1533
|
+
const skipStep = e.key === "ArrowLeft" || e.key === "ArrowUp" || e.key === "PageUp" || e.key === "Home" ? -1 : 1;
|
|
1534
|
+
let attempts = 0;
|
|
1535
|
+
while (isDateDisabled(newFocused, disabled, adapter) && attempts < 42) {
|
|
1536
|
+
newFocused = adapter.addDays(newFocused, skipStep);
|
|
1537
|
+
attempts++;
|
|
1538
|
+
}
|
|
1539
|
+
if (attempts >= 42) return;
|
|
1296
1540
|
ctx.setFocusedDate(newFocused);
|
|
1297
1541
|
if (!adapter.isSameMonth(newFocused, viewMonth)) {
|
|
1298
1542
|
ctx.setViewMonth(newFocused);
|
|
@@ -1345,67 +1589,93 @@ function RangePickerCalendar({
|
|
|
1345
1589
|
ref: gridRef,
|
|
1346
1590
|
role: "grid",
|
|
1347
1591
|
"aria-label": title,
|
|
1348
|
-
"aria-
|
|
1592
|
+
"aria-rowcount": weeks.length + 1,
|
|
1593
|
+
"aria-colcount": 7,
|
|
1349
1594
|
className: classNames?.grid,
|
|
1350
1595
|
onKeyDown: handleKeyDown,
|
|
1351
1596
|
children: [
|
|
1352
|
-
/* @__PURE__ */ jsx("thead", { children: /* @__PURE__ */
|
|
1353
|
-
"th",
|
|
1354
|
-
|
|
1355
|
-
|
|
1356
|
-
abbr: day.full,
|
|
1357
|
-
scope: "col",
|
|
1358
|
-
className: classNames?.weekdayHeader,
|
|
1359
|
-
children: day.short
|
|
1360
|
-
},
|
|
1361
|
-
day.short
|
|
1362
|
-
)) }) }),
|
|
1363
|
-
/* @__PURE__ */ jsx("tbody", { children: weeks.map((week, weekIndex) => /* @__PURE__ */ jsx("tr", { role: "row", className: classNames?.gridRow, children: week.map((day) => {
|
|
1364
|
-
const dayClasses = [
|
|
1365
|
-
classNames?.day,
|
|
1366
|
-
day.isRangeStart && classNames?.dayRangeStart,
|
|
1367
|
-
day.isRangeEnd && classNames?.dayRangeEnd,
|
|
1368
|
-
day.isInRange && classNames?.dayInRange,
|
|
1369
|
-
day.isToday && classNames?.dayToday,
|
|
1370
|
-
day.isDisabled && classNames?.dayDisabled,
|
|
1371
|
-
!day.isCurrentMonth && classNames?.dayOutsideMonth
|
|
1372
|
-
].filter(Boolean).join(" ") || void 0;
|
|
1373
|
-
const isSelected = selectionMode === "week" ? day.isRangeStart || day.isRangeEnd || day.isInRange : day.isRangeStart || day.isRangeEnd;
|
|
1374
|
-
return /* @__PURE__ */ jsx(
|
|
1375
|
-
"td",
|
|
1597
|
+
/* @__PURE__ */ jsx("thead", { children: /* @__PURE__ */ jsxs("tr", { role: "row", "aria-rowindex": 1, children: [
|
|
1598
|
+
showWeekNumber ? /* @__PURE__ */ jsx("th", { scope: "col", "aria-hidden": "true", className: classNames?.weekNumberHeader, children: "#" }) : null,
|
|
1599
|
+
weekdays.map((day, colIndex) => /* @__PURE__ */ jsx(
|
|
1600
|
+
"th",
|
|
1376
1601
|
{
|
|
1377
|
-
role: "
|
|
1378
|
-
|
|
1379
|
-
"
|
|
1380
|
-
"aria-
|
|
1381
|
-
className: classNames?.
|
|
1382
|
-
children:
|
|
1383
|
-
|
|
1602
|
+
role: "columnheader",
|
|
1603
|
+
abbr: day.full,
|
|
1604
|
+
scope: "col",
|
|
1605
|
+
"aria-colindex": colIndex + 1,
|
|
1606
|
+
className: classNames?.weekdayHeader,
|
|
1607
|
+
children: day.short
|
|
1608
|
+
},
|
|
1609
|
+
day.short
|
|
1610
|
+
))
|
|
1611
|
+
] }) }),
|
|
1612
|
+
/* @__PURE__ */ jsx("tbody", { children: weeks.map((week, weekIndex) => /* @__PURE__ */ jsxs(
|
|
1613
|
+
"tr",
|
|
1614
|
+
{
|
|
1615
|
+
role: "row",
|
|
1616
|
+
"aria-rowindex": weekIndex + 2,
|
|
1617
|
+
className: classNames?.gridRow,
|
|
1618
|
+
children: [
|
|
1619
|
+
showWeekNumber ? /* @__PURE__ */ jsx(
|
|
1620
|
+
"th",
|
|
1384
1621
|
{
|
|
1385
|
-
|
|
1386
|
-
|
|
1387
|
-
|
|
1388
|
-
"data-
|
|
1389
|
-
|
|
1390
|
-
"data-range-end": day.isRangeEnd || void 0,
|
|
1391
|
-
"data-in-range": day.isInRange || void 0,
|
|
1392
|
-
"data-today": day.isToday || void 0,
|
|
1393
|
-
"data-outside-month": !day.isCurrentMonth || void 0,
|
|
1394
|
-
className: dayClasses,
|
|
1395
|
-
onClick: () => handleDayClick(day),
|
|
1396
|
-
onMouseEnter: () => handleDayMouseEnter(day),
|
|
1397
|
-
"aria-label": safeFormatFullDate2(day.isoString, locale),
|
|
1398
|
-
children: day.dayNumber
|
|
1622
|
+
scope: "row",
|
|
1623
|
+
"aria-hidden": "true",
|
|
1624
|
+
className: classNames?.weekNumber,
|
|
1625
|
+
"data-week-number": true,
|
|
1626
|
+
children: getISOWeekNumber(week[thursdayIndex].isoString)
|
|
1399
1627
|
}
|
|
1400
|
-
)
|
|
1401
|
-
|
|
1402
|
-
|
|
1403
|
-
|
|
1404
|
-
|
|
1628
|
+
) : null,
|
|
1629
|
+
week.map((day, colIndex) => {
|
|
1630
|
+
const dayClasses = [
|
|
1631
|
+
classNames?.day,
|
|
1632
|
+
day.isRangeStart && classNames?.dayRangeStart,
|
|
1633
|
+
day.isRangeEnd && classNames?.dayRangeEnd,
|
|
1634
|
+
day.isInRange && classNames?.dayInRange,
|
|
1635
|
+
day.isToday && classNames?.dayToday,
|
|
1636
|
+
day.isDisabled && classNames?.dayDisabled,
|
|
1637
|
+
!day.isCurrentMonth && classNames?.dayOutsideMonth
|
|
1638
|
+
].filter(Boolean).join(" ") || void 0;
|
|
1639
|
+
const isSelected = selectionMode === "week" ? day.isRangeStart || day.isRangeEnd || day.isInRange : day.isRangeStart || day.isRangeEnd;
|
|
1640
|
+
return /* @__PURE__ */ jsx(
|
|
1641
|
+
"td",
|
|
1642
|
+
{
|
|
1643
|
+
role: "gridcell",
|
|
1644
|
+
"aria-colindex": colIndex + 1,
|
|
1645
|
+
"aria-selected": isSelected || void 0,
|
|
1646
|
+
"aria-disabled": day.isDisabled || void 0,
|
|
1647
|
+
"aria-current": day.isToday ? "date" : void 0,
|
|
1648
|
+
className: classNames?.gridCell,
|
|
1649
|
+
children: /* @__PURE__ */ jsx(
|
|
1650
|
+
"button",
|
|
1651
|
+
{
|
|
1652
|
+
type: "button",
|
|
1653
|
+
tabIndex: day.isFocused ? 0 : -1,
|
|
1654
|
+
disabled: day.isDisabled,
|
|
1655
|
+
"data-focused": day.isFocused || void 0,
|
|
1656
|
+
"data-range-start": day.isRangeStart || void 0,
|
|
1657
|
+
"data-range-end": day.isRangeEnd || void 0,
|
|
1658
|
+
"data-in-range": day.isInRange || void 0,
|
|
1659
|
+
"data-today": day.isToday || void 0,
|
|
1660
|
+
"data-outside-month": !day.isCurrentMonth || void 0,
|
|
1661
|
+
className: dayClasses,
|
|
1662
|
+
onClick: () => handleDayClick(day),
|
|
1663
|
+
onMouseEnter: () => handleDayMouseEnter(day),
|
|
1664
|
+
"aria-label": safeFormatFullDate2(day.isoString, locale),
|
|
1665
|
+
children: day.dayNumber
|
|
1666
|
+
}
|
|
1667
|
+
)
|
|
1668
|
+
},
|
|
1669
|
+
day.isoString
|
|
1670
|
+
);
|
|
1671
|
+
})
|
|
1672
|
+
]
|
|
1673
|
+
},
|
|
1674
|
+
weekIndex
|
|
1675
|
+
)) })
|
|
1405
1676
|
]
|
|
1406
1677
|
}
|
|
1407
|
-
)
|
|
1408
|
-
/* @__PURE__ */ jsx("div", { role: "status", "aria-live": "polite", "aria-atomic": "true", style: srOnly2, children: announcement })
|
|
1678
|
+
)
|
|
1409
1679
|
] });
|
|
1410
1680
|
}
|
|
1411
1681
|
function RangePickerPresets({ classNames, children, ...props }) {
|
|
@@ -1463,41 +1733,33 @@ function RangePickerPreset({
|
|
|
1463
1733
|
...props
|
|
1464
1734
|
}) {
|
|
1465
1735
|
const ctx = useRangePickerContext("RangePicker.Preset");
|
|
1736
|
+
const resolved = useMemo(() => {
|
|
1737
|
+
if (directRange) return directRange;
|
|
1738
|
+
if (presetKey)
|
|
1739
|
+
return resolvePreset(presetKey, ctx.adapter.today(ctx.displayTimezone), ctx.adapter);
|
|
1740
|
+
return null;
|
|
1741
|
+
}, [directRange, presetKey, ctx.adapter, ctx.displayTimezone]);
|
|
1466
1742
|
const handleClick = useCallback(
|
|
1467
1743
|
(e) => {
|
|
1468
1744
|
if (ctx.isDisabled || ctx.isReadOnly) return;
|
|
1469
|
-
|
|
1470
|
-
if (directRange) {
|
|
1471
|
-
resolved = directRange;
|
|
1472
|
-
} else if (presetKey) {
|
|
1473
|
-
resolved = resolvePreset(presetKey, ctx.adapter.today(), ctx.adapter);
|
|
1474
|
-
} else {
|
|
1475
|
-
return;
|
|
1476
|
-
}
|
|
1745
|
+
if (!resolved) return;
|
|
1477
1746
|
ctx.setRange(resolved);
|
|
1478
1747
|
ctx.close();
|
|
1479
1748
|
onClick?.(e);
|
|
1480
1749
|
},
|
|
1481
|
-
[ctx,
|
|
1750
|
+
[ctx, resolved, onClick]
|
|
1482
1751
|
);
|
|
1483
|
-
const isActive = (() => {
|
|
1484
|
-
if (!ctx.value.start || !ctx.value.end)
|
|
1485
|
-
let target;
|
|
1486
|
-
if (directRange) {
|
|
1487
|
-
target = directRange;
|
|
1488
|
-
} else if (presetKey) {
|
|
1489
|
-
target = resolvePreset(presetKey, ctx.adapter.today(), ctx.adapter);
|
|
1490
|
-
} else {
|
|
1752
|
+
const isActive = useMemo(() => {
|
|
1753
|
+
if (!ctx.value.start || !ctx.value.end || !resolved || !resolved.start || !resolved.end) {
|
|
1491
1754
|
return false;
|
|
1492
1755
|
}
|
|
1493
|
-
return
|
|
1494
|
-
})
|
|
1756
|
+
return ctx.adapter.isSameDay(ctx.value.start, resolved.start) && ctx.adapter.isSameDay(ctx.value.end, resolved.end);
|
|
1757
|
+
}, [ctx.value.start, ctx.value.end, ctx.adapter, resolved]);
|
|
1495
1758
|
return /* @__PURE__ */ jsx(
|
|
1496
1759
|
"button",
|
|
1497
1760
|
{
|
|
1498
1761
|
type: "button",
|
|
1499
|
-
|
|
1500
|
-
"aria-selected": isActive,
|
|
1762
|
+
"aria-pressed": isActive,
|
|
1501
1763
|
"data-active": isActive || void 0,
|
|
1502
1764
|
disabled: ctx.isDisabled,
|
|
1503
1765
|
onClick: handleClick,
|
|
@@ -1530,9 +1792,6 @@ function useTimePickerContext(componentName) {
|
|
|
1530
1792
|
}
|
|
1531
1793
|
return context;
|
|
1532
1794
|
}
|
|
1533
|
-
function getDefaultIso() {
|
|
1534
|
-
return DateFnsAdapter.today();
|
|
1535
|
-
}
|
|
1536
1795
|
function TimePickerRoot({
|
|
1537
1796
|
value: controlledValue,
|
|
1538
1797
|
defaultValue,
|
|
@@ -1543,6 +1802,7 @@ function TimePickerRoot({
|
|
|
1543
1802
|
displayTimezone,
|
|
1544
1803
|
disabled = false,
|
|
1545
1804
|
readOnly = false,
|
|
1805
|
+
filterTime,
|
|
1546
1806
|
labels: labelsProp,
|
|
1547
1807
|
children
|
|
1548
1808
|
}) {
|
|
@@ -1556,21 +1816,21 @@ function TimePickerRoot({
|
|
|
1556
1816
|
defaultValue ?? null
|
|
1557
1817
|
);
|
|
1558
1818
|
const currentValue = isControlled ? controlledValue ?? null : uncontrolledValue;
|
|
1559
|
-
const
|
|
1560
|
-
|
|
1561
|
-
|
|
1562
|
-
|
|
1563
|
-
);
|
|
1819
|
+
const currentTime = useMemo(() => {
|
|
1820
|
+
if (!currentValue) return { hours: 0, minutes: 0, seconds: 0 };
|
|
1821
|
+
return displayTimezone ? getTimeInTimezone(currentValue, displayTimezone) : getTime(currentValue);
|
|
1822
|
+
}, [currentValue, displayTimezone]);
|
|
1564
1823
|
const setTime$1 = useCallback(
|
|
1565
1824
|
(partial) => {
|
|
1566
1825
|
if (disabled || readOnly) return;
|
|
1567
|
-
const
|
|
1826
|
+
const base = currentValue ?? DateFnsAdapter.today(displayTimezone);
|
|
1827
|
+
const newIso = displayTimezone ? setTimeInTimezone(base, partial, displayTimezone) : setTime(base, partial);
|
|
1568
1828
|
if (!isControlled) {
|
|
1569
1829
|
setUncontrolledValue(newIso);
|
|
1570
1830
|
}
|
|
1571
1831
|
onChange?.(newIso);
|
|
1572
1832
|
},
|
|
1573
|
-
[disabled, readOnly,
|
|
1833
|
+
[disabled, readOnly, currentValue, displayTimezone, isControlled, onChange]
|
|
1574
1834
|
);
|
|
1575
1835
|
const contextValue = useMemo(
|
|
1576
1836
|
() => ({
|
|
@@ -1584,7 +1844,8 @@ function TimePickerRoot({
|
|
|
1584
1844
|
isReadOnly: readOnly,
|
|
1585
1845
|
currentTime,
|
|
1586
1846
|
pickerId,
|
|
1587
|
-
labels: mergedLabels
|
|
1847
|
+
labels: mergedLabels,
|
|
1848
|
+
filterTime
|
|
1588
1849
|
}),
|
|
1589
1850
|
[
|
|
1590
1851
|
currentValue,
|
|
@@ -1597,7 +1858,8 @@ function TimePickerRoot({
|
|
|
1597
1858
|
readOnly,
|
|
1598
1859
|
currentTime,
|
|
1599
1860
|
pickerId,
|
|
1600
|
-
mergedLabels
|
|
1861
|
+
mergedLabels,
|
|
1862
|
+
filterTime
|
|
1601
1863
|
]
|
|
1602
1864
|
);
|
|
1603
1865
|
return /* @__PURE__ */ jsx(TimePickerContext.Provider, { value: contextValue, children });
|
|
@@ -1606,6 +1868,9 @@ var TimePickerInput = forwardRef(
|
|
|
1606
1868
|
function TimePickerInput2({ onBlur, onKeyDown, ...props }, ref) {
|
|
1607
1869
|
const ctx = useTimePickerContext("TimePicker.Input");
|
|
1608
1870
|
const [inputText, setInputText] = useState(null);
|
|
1871
|
+
useEffect(() => {
|
|
1872
|
+
setInputText(null);
|
|
1873
|
+
}, [ctx.value]);
|
|
1609
1874
|
const displayValue = inputText !== null ? inputText : formatTimeString(ctx.currentTime, ctx.withSeconds);
|
|
1610
1875
|
const commitInput = useCallback(() => {
|
|
1611
1876
|
if (inputText === null) return;
|
|
@@ -1654,6 +1919,7 @@ var TimePickerInput = forwardRef(
|
|
|
1654
1919
|
);
|
|
1655
1920
|
}
|
|
1656
1921
|
);
|
|
1922
|
+
TimePickerInput.displayName = "TimePicker.Input";
|
|
1657
1923
|
function useListboxNavigation({
|
|
1658
1924
|
items,
|
|
1659
1925
|
onSelect,
|
|
@@ -1701,17 +1967,41 @@ function useListboxNavigation({
|
|
|
1701
1967
|
}
|
|
1702
1968
|
function TimePickerHourList({ classNames, ...props }) {
|
|
1703
1969
|
const ctx = useTimePickerContext("TimePicker.HourList");
|
|
1704
|
-
const { format, currentTime, isDisabled, isReadOnly } = ctx;
|
|
1705
|
-
const hours = generateHours(format);
|
|
1970
|
+
const { format, step, currentTime, isDisabled, isReadOnly, filterTime } = ctx;
|
|
1971
|
+
const hours = useMemo(() => generateHours(format), [format]);
|
|
1706
1972
|
const selectedHourDisplay = format === "12h" ? to12Hour(currentTime.hours).hours12 : currentTime.hours;
|
|
1707
1973
|
const currentPeriod = format === "12h" ? to12Hour(currentTime.hours).period : null;
|
|
1974
|
+
const fullyDisabledHours24 = useMemo(() => {
|
|
1975
|
+
if (!filterTime) return null;
|
|
1976
|
+
const disabled = /* @__PURE__ */ new Set();
|
|
1977
|
+
for (let h = 0; h < 24; h++) {
|
|
1978
|
+
let allRejected = true;
|
|
1979
|
+
for (let m = 0; m < 60; m += step) {
|
|
1980
|
+
if (!filterTime(h, m)) {
|
|
1981
|
+
allRejected = false;
|
|
1982
|
+
break;
|
|
1983
|
+
}
|
|
1984
|
+
}
|
|
1985
|
+
if (allRejected) disabled.add(h);
|
|
1986
|
+
}
|
|
1987
|
+
return disabled;
|
|
1988
|
+
}, [filterTime, step]);
|
|
1989
|
+
const isHourDisabled = useCallback(
|
|
1990
|
+
(hourDisplay) => {
|
|
1991
|
+
if (!fullyDisabledHours24) return false;
|
|
1992
|
+
const hours24 = format === "12h" && currentPeriod ? to24Hour(hourDisplay, currentPeriod) : hourDisplay;
|
|
1993
|
+
return fullyDisabledHours24.has(hours24);
|
|
1994
|
+
},
|
|
1995
|
+
[fullyDisabledHours24, format, currentPeriod]
|
|
1996
|
+
);
|
|
1708
1997
|
const handleSelect = useCallback(
|
|
1709
1998
|
(hourDisplay) => {
|
|
1710
1999
|
if (isDisabled || isReadOnly) return;
|
|
2000
|
+
if (isHourDisabled(hourDisplay)) return;
|
|
1711
2001
|
const hours24 = format === "12h" && currentPeriod ? to24Hour(hourDisplay, currentPeriod) : hourDisplay;
|
|
1712
2002
|
ctx.setTime({ hours: hours24 });
|
|
1713
2003
|
},
|
|
1714
|
-
[format, currentPeriod, ctx, isDisabled, isReadOnly]
|
|
2004
|
+
[format, currentPeriod, ctx, isDisabled, isReadOnly, isHourDisabled]
|
|
1715
2005
|
);
|
|
1716
2006
|
const { listRef, handleKeyDown } = useListboxNavigation({
|
|
1717
2007
|
items: hours,
|
|
@@ -1729,13 +2019,14 @@ function TimePickerHourList({ classNames, ...props }) {
|
|
|
1729
2019
|
...props,
|
|
1730
2020
|
children: hours.map((hour) => {
|
|
1731
2021
|
const isSelected = hour === selectedHourDisplay;
|
|
2022
|
+
const isHourFullyDisabled = isHourDisabled(hour);
|
|
1732
2023
|
const optionClass = [classNames?.option, isSelected && classNames?.optionSelected].filter(Boolean).join(" ") || void 0;
|
|
1733
2024
|
return /* @__PURE__ */ jsx(
|
|
1734
2025
|
"li",
|
|
1735
2026
|
{
|
|
1736
2027
|
role: "option",
|
|
1737
2028
|
"aria-selected": isSelected,
|
|
1738
|
-
"aria-disabled": isDisabled || void 0,
|
|
2029
|
+
"aria-disabled": isDisabled || isHourFullyDisabled || void 0,
|
|
1739
2030
|
"aria-label": ctx.labels.hourOption(hour),
|
|
1740
2031
|
"data-selected": isSelected || void 0,
|
|
1741
2032
|
tabIndex: isSelected ? 0 : -1,
|
|
@@ -1752,14 +2043,22 @@ function TimePickerHourList({ classNames, ...props }) {
|
|
|
1752
2043
|
}
|
|
1753
2044
|
function TimePickerMinuteList({ classNames, ...props }) {
|
|
1754
2045
|
const ctx = useTimePickerContext("TimePicker.MinuteList");
|
|
1755
|
-
const { step, currentTime, isDisabled, isReadOnly } = ctx;
|
|
1756
|
-
const minutes = generateMinutes(step);
|
|
2046
|
+
const { step, currentTime, isDisabled, isReadOnly, filterTime } = ctx;
|
|
2047
|
+
const minutes = useMemo(() => generateMinutes(step), [step]);
|
|
2048
|
+
const isMinuteDisabled = useCallback(
|
|
2049
|
+
(minute) => {
|
|
2050
|
+
if (!filterTime) return false;
|
|
2051
|
+
return filterTime(currentTime.hours, minute);
|
|
2052
|
+
},
|
|
2053
|
+
[filterTime, currentTime.hours]
|
|
2054
|
+
);
|
|
1757
2055
|
const handleSelect = useCallback(
|
|
1758
2056
|
(minute) => {
|
|
1759
2057
|
if (isDisabled || isReadOnly) return;
|
|
2058
|
+
if (isMinuteDisabled(minute)) return;
|
|
1760
2059
|
ctx.setTime({ minutes: minute });
|
|
1761
2060
|
},
|
|
1762
|
-
[ctx, isDisabled, isReadOnly]
|
|
2061
|
+
[ctx, isDisabled, isReadOnly, isMinuteDisabled]
|
|
1763
2062
|
);
|
|
1764
2063
|
const { listRef, handleKeyDown } = useListboxNavigation({
|
|
1765
2064
|
items: minutes,
|
|
@@ -1777,13 +2076,14 @@ function TimePickerMinuteList({ classNames, ...props }) {
|
|
|
1777
2076
|
...props,
|
|
1778
2077
|
children: minutes.map((minute) => {
|
|
1779
2078
|
const isSelected = minute === currentTime.minutes;
|
|
2079
|
+
const isMinuteFullyDisabled = isMinuteDisabled(minute);
|
|
1780
2080
|
const optionClass = [classNames?.option, isSelected && classNames?.optionSelected].filter(Boolean).join(" ") || void 0;
|
|
1781
2081
|
return /* @__PURE__ */ jsx(
|
|
1782
2082
|
"li",
|
|
1783
2083
|
{
|
|
1784
2084
|
role: "option",
|
|
1785
2085
|
"aria-selected": isSelected,
|
|
1786
|
-
"aria-disabled": isDisabled || void 0,
|
|
2086
|
+
"aria-disabled": isDisabled || isMinuteFullyDisabled || void 0,
|
|
1787
2087
|
"aria-label": ctx.labels.minuteOption(minute),
|
|
1788
2088
|
"data-selected": isSelected || void 0,
|
|
1789
2089
|
tabIndex: isSelected ? 0 : -1,
|
|
@@ -1800,29 +2100,70 @@ function TimePickerMinuteList({ classNames, ...props }) {
|
|
|
1800
2100
|
}
|
|
1801
2101
|
function TimePickerAmPmToggle({ classNames, ...props }) {
|
|
1802
2102
|
const ctx = useTimePickerContext("TimePicker.AmPmToggle");
|
|
1803
|
-
|
|
1804
|
-
const
|
|
2103
|
+
const amRef = useRef(null);
|
|
2104
|
+
const pmRef = useRef(null);
|
|
1805
2105
|
const setPeriod = useCallback(
|
|
1806
2106
|
(newPeriod) => {
|
|
1807
2107
|
if (ctx.isDisabled || ctx.isReadOnly) return;
|
|
2108
|
+
const { hours12 } = to12Hour(ctx.currentTime.hours);
|
|
1808
2109
|
const newHours24 = to24Hour(hours12, newPeriod);
|
|
1809
2110
|
ctx.setTime({ hours: newHours24 });
|
|
1810
2111
|
},
|
|
1811
|
-
[
|
|
2112
|
+
[ctx]
|
|
1812
2113
|
);
|
|
2114
|
+
if (ctx.format !== "12h") return null;
|
|
2115
|
+
const { period } = to12Hour(ctx.currentTime.hours);
|
|
2116
|
+
const focusOther = (target) => {
|
|
2117
|
+
(target === "AM" ? amRef : pmRef).current?.focus();
|
|
2118
|
+
};
|
|
2119
|
+
const handleKeyDown = (e, target) => {
|
|
2120
|
+
switch (e.key) {
|
|
2121
|
+
case "ArrowRight":
|
|
2122
|
+
case "ArrowDown":
|
|
2123
|
+
case "ArrowLeft":
|
|
2124
|
+
case "ArrowUp": {
|
|
2125
|
+
e.preventDefault();
|
|
2126
|
+
const next = target === "AM" ? "PM" : "AM";
|
|
2127
|
+
setPeriod(next);
|
|
2128
|
+
focusOther(next);
|
|
2129
|
+
break;
|
|
2130
|
+
}
|
|
2131
|
+
case "Home": {
|
|
2132
|
+
e.preventDefault();
|
|
2133
|
+
setPeriod("AM");
|
|
2134
|
+
focusOther("AM");
|
|
2135
|
+
break;
|
|
2136
|
+
}
|
|
2137
|
+
case "End": {
|
|
2138
|
+
e.preventDefault();
|
|
2139
|
+
setPeriod("PM");
|
|
2140
|
+
focusOther("PM");
|
|
2141
|
+
break;
|
|
2142
|
+
}
|
|
2143
|
+
case " ":
|
|
2144
|
+
case "Enter": {
|
|
2145
|
+
e.preventDefault();
|
|
2146
|
+
setPeriod(target);
|
|
2147
|
+
break;
|
|
2148
|
+
}
|
|
2149
|
+
}
|
|
2150
|
+
};
|
|
1813
2151
|
const renderButton = (target) => {
|
|
1814
2152
|
const isSelected = period === target;
|
|
1815
2153
|
const optionClass = [classNames?.option, isSelected && classNames?.optionSelected].filter(Boolean).join(" ") || void 0;
|
|
1816
2154
|
return /* @__PURE__ */ jsx(
|
|
1817
2155
|
"button",
|
|
1818
2156
|
{
|
|
2157
|
+
ref: target === "AM" ? amRef : pmRef,
|
|
1819
2158
|
type: "button",
|
|
1820
2159
|
role: "radio",
|
|
1821
2160
|
"aria-checked": isSelected,
|
|
2161
|
+
tabIndex: isSelected ? 0 : -1,
|
|
1822
2162
|
"data-selected": isSelected || void 0,
|
|
1823
2163
|
disabled: ctx.isDisabled,
|
|
1824
2164
|
className: optionClass,
|
|
1825
2165
|
onClick: () => setPeriod(target),
|
|
2166
|
+
onKeyDown: (e) => handleKeyDown(e, target),
|
|
1826
2167
|
children: target
|
|
1827
2168
|
}
|
|
1828
2169
|
);
|
|
@@ -1849,9 +2190,6 @@ var TimePicker = Object.assign(TimePickerRoot, {
|
|
|
1849
2190
|
MinuteList: TimePickerMinuteList,
|
|
1850
2191
|
AmPmToggle: TimePickerAmPmToggle
|
|
1851
2192
|
});
|
|
1852
|
-
function getDefaultIso2() {
|
|
1853
|
-
return DateFnsAdapter.today();
|
|
1854
|
-
}
|
|
1855
2193
|
function DateTimePickerRoot({
|
|
1856
2194
|
value: controlledValue,
|
|
1857
2195
|
defaultValue,
|
|
@@ -1860,6 +2198,8 @@ function DateTimePickerRoot({
|
|
|
1860
2198
|
onCalendarNavigate,
|
|
1861
2199
|
format = "24h",
|
|
1862
2200
|
step = 1,
|
|
2201
|
+
withSeconds = false,
|
|
2202
|
+
filterTime,
|
|
1863
2203
|
disabled = false,
|
|
1864
2204
|
readOnly = false,
|
|
1865
2205
|
weekStartsOn = 0,
|
|
@@ -1887,10 +2227,10 @@ function DateTimePickerRoot({
|
|
|
1887
2227
|
const currentValue = isControlled ? controlledValue ?? null : uncontrolledValue;
|
|
1888
2228
|
const [isOpen, setIsOpen] = useState(false);
|
|
1889
2229
|
const [viewMonth, setViewMonth] = useState(
|
|
1890
|
-
currentValue ?? adapter.today(displayTimezone)
|
|
2230
|
+
() => currentValue ?? adapter.today(displayTimezone)
|
|
1891
2231
|
);
|
|
1892
2232
|
const [focusedDate, setFocusedDate] = useState(
|
|
1893
|
-
currentValue ?? adapter.today(displayTimezone)
|
|
2233
|
+
() => currentValue ?? adapter.today(displayTimezone)
|
|
1894
2234
|
);
|
|
1895
2235
|
useChangeEffect(isOpen, onOpenChange);
|
|
1896
2236
|
const viewMonthStart = useMemo(() => adapter.startOfMonth(viewMonth), [viewMonth, adapter]);
|
|
@@ -1900,11 +2240,10 @@ function DateTimePickerRoot({
|
|
|
1900
2240
|
() => Array.isArray(disabled) ? disabled : [],
|
|
1901
2241
|
[disabled]
|
|
1902
2242
|
);
|
|
1903
|
-
const
|
|
1904
|
-
|
|
1905
|
-
|
|
1906
|
-
|
|
1907
|
-
);
|
|
2243
|
+
const currentTime = useMemo(() => {
|
|
2244
|
+
if (!currentValue) return { hours: 0, minutes: 0, seconds: 0 };
|
|
2245
|
+
return displayTimezone ? getTimeInTimezone(currentValue, displayTimezone) : getTime(currentValue);
|
|
2246
|
+
}, [currentValue, displayTimezone]);
|
|
1908
2247
|
const updateValue = useCallback(
|
|
1909
2248
|
(next) => {
|
|
1910
2249
|
if (isDisabled || readOnly) return;
|
|
@@ -1930,11 +2269,11 @@ function DateTimePickerRoot({
|
|
|
1930
2269
|
);
|
|
1931
2270
|
const setTime$1 = useCallback(
|
|
1932
2271
|
(partial) => {
|
|
1933
|
-
const base = currentValue ??
|
|
2272
|
+
const base = currentValue ?? adapter.today(displayTimezone);
|
|
1934
2273
|
const merged = displayTimezone ? setTimeInTimezone(base, partial, displayTimezone) : setTime(base, partial);
|
|
1935
2274
|
updateValue(merged);
|
|
1936
2275
|
},
|
|
1937
|
-
[currentValue, updateValue, displayTimezone]
|
|
2276
|
+
[currentValue, updateValue, displayTimezone, adapter]
|
|
1938
2277
|
);
|
|
1939
2278
|
const open = useCallback(() => {
|
|
1940
2279
|
if (isDisabled || readOnly) return;
|
|
@@ -2001,25 +2340,28 @@ function DateTimePickerRoot({
|
|
|
2001
2340
|
setTime: setTime$1,
|
|
2002
2341
|
format,
|
|
2003
2342
|
step,
|
|
2004
|
-
withSeconds
|
|
2343
|
+
withSeconds,
|
|
2005
2344
|
displayTimezone,
|
|
2006
2345
|
isDisabled,
|
|
2007
2346
|
isReadOnly: readOnly,
|
|
2008
2347
|
currentTime,
|
|
2009
2348
|
pickerId,
|
|
2010
|
-
labels: mergedTimeLabels
|
|
2349
|
+
labels: mergedTimeLabels,
|
|
2350
|
+
filterTime
|
|
2011
2351
|
}),
|
|
2012
2352
|
[
|
|
2013
2353
|
currentValue,
|
|
2014
2354
|
setTime$1,
|
|
2015
2355
|
format,
|
|
2016
2356
|
step,
|
|
2357
|
+
withSeconds,
|
|
2017
2358
|
displayTimezone,
|
|
2018
2359
|
isDisabled,
|
|
2019
2360
|
readOnly,
|
|
2020
2361
|
currentTime,
|
|
2021
2362
|
pickerId,
|
|
2022
|
-
mergedTimeLabels
|
|
2363
|
+
mergedTimeLabels,
|
|
2364
|
+
filterTime
|
|
2023
2365
|
]
|
|
2024
2366
|
);
|
|
2025
2367
|
return /* @__PURE__ */ jsx(DatePickerContext.Provider, { value: dateContext, children: /* @__PURE__ */ jsx(TimePickerContext.Provider, { value: timeContext, children }) });
|
|
@@ -2048,6 +2390,8 @@ var DateTimePickerInput = forwardRef(
|
|
|
2048
2390
|
(e) => {
|
|
2049
2391
|
if (e.key === "Escape") {
|
|
2050
2392
|
ctx.close();
|
|
2393
|
+
} else if (e.key === "Enter" && ctx.isOpen) {
|
|
2394
|
+
e.preventDefault();
|
|
2051
2395
|
} else if (e.key === "ArrowDown" && !ctx.isOpen) {
|
|
2052
2396
|
e.preventDefault();
|
|
2053
2397
|
ctx.open();
|
|
@@ -2083,6 +2427,7 @@ var DateTimePickerInput = forwardRef(
|
|
|
2083
2427
|
);
|
|
2084
2428
|
}
|
|
2085
2429
|
);
|
|
2430
|
+
DateTimePickerInput.displayName = "DateTimePicker.Input";
|
|
2086
2431
|
|
|
2087
2432
|
// src/components/DateTimePicker/index.ts
|
|
2088
2433
|
var DateTimePicker = Object.assign(DateTimePickerRoot, {
|
|
@@ -2101,7 +2446,7 @@ function MonthPickerRoot(props) {
|
|
|
2101
2446
|
}
|
|
2102
2447
|
function MonthPickerGrid({ classNames, ...props }) {
|
|
2103
2448
|
const ctx = useDatePickerContext("MonthPicker.Grid");
|
|
2104
|
-
const { adapter, viewMonth, locale, value, displayTimezone, labels } = ctx;
|
|
2449
|
+
const { adapter, viewMonth, locale, value, displayTimezone, labels, disabled } = ctx;
|
|
2105
2450
|
const currentYear = adapter.getYear(viewMonth);
|
|
2106
2451
|
const [valueYear, valueMonthZeroBased] = useMemo(() => {
|
|
2107
2452
|
if (!value) return [null, null];
|
|
@@ -2112,9 +2457,19 @@ function MonthPickerGrid({ classNames, ...props }) {
|
|
|
2112
2457
|
return [null, null];
|
|
2113
2458
|
}
|
|
2114
2459
|
}, [value, adapter, displayTimezone]);
|
|
2115
|
-
const today =
|
|
2116
|
-
|
|
2117
|
-
|
|
2460
|
+
const [today, setToday] = useState(null);
|
|
2461
|
+
useEffect(() => {
|
|
2462
|
+
setToday(adapter.today(displayTimezone));
|
|
2463
|
+
}, [adapter, displayTimezone]);
|
|
2464
|
+
const todayYear = today !== null ? adapter.getYear(today) : -1;
|
|
2465
|
+
const todayMonth = today !== null ? adapter.getMonth(today) : -1;
|
|
2466
|
+
const monthDisabledFlags = useMemo(
|
|
2467
|
+
() => Array.from({ length: 12 }, (_, i) => {
|
|
2468
|
+
const monthStart = new Date(Date.UTC(currentYear, i, 1)).toISOString();
|
|
2469
|
+
return isRangeFullyDisabled(monthStart, adapter.endOfMonth(monthStart), disabled, adapter);
|
|
2470
|
+
}),
|
|
2471
|
+
[currentYear, disabled, adapter]
|
|
2472
|
+
);
|
|
2118
2473
|
const navigateYear = useCallback(
|
|
2119
2474
|
(direction) => {
|
|
2120
2475
|
ctx.setViewMonth(adapter.addYears(viewMonth, direction));
|
|
@@ -2123,17 +2478,23 @@ function MonthPickerGrid({ classNames, ...props }) {
|
|
|
2123
2478
|
);
|
|
2124
2479
|
const handleMonthSelect = useCallback(
|
|
2125
2480
|
(monthIndex) => {
|
|
2481
|
+
if (monthDisabledFlags[monthIndex]) return;
|
|
2126
2482
|
const target = new Date(Date.UTC(currentYear, monthIndex, 1)).toISOString();
|
|
2127
2483
|
ctx.selectDate(target);
|
|
2128
2484
|
},
|
|
2129
|
-
[currentYear, ctx]
|
|
2130
|
-
);
|
|
2131
|
-
const
|
|
2132
|
-
|
|
2133
|
-
|
|
2134
|
-
|
|
2135
|
-
|
|
2136
|
-
|
|
2485
|
+
[currentYear, ctx, monthDisabledFlags]
|
|
2486
|
+
);
|
|
2487
|
+
const naturalIndex = valueYear === currentYear && valueMonthZeroBased !== null ? valueMonthZeroBased : adapter.getMonth(viewMonth);
|
|
2488
|
+
const firstEnabled = monthDisabledFlags.findIndex((d) => !d);
|
|
2489
|
+
const initialIndex = monthDisabledFlags[naturalIndex] ? firstEnabled === -1 ? naturalIndex : firstEnabled : naturalIndex;
|
|
2490
|
+
const { gridRef, focusedIndex, handleKeyDown } = useGridState({
|
|
2491
|
+
initialIndex,
|
|
2492
|
+
disabledFlags: monthDisabledFlags,
|
|
2493
|
+
onSelect: handleMonthSelect,
|
|
2494
|
+
onPageUp: () => navigateYear(-1),
|
|
2495
|
+
onPageDown: () => navigateYear(1),
|
|
2496
|
+
onEscape: ctx.close
|
|
2497
|
+
});
|
|
2137
2498
|
return /* @__PURE__ */ jsxs("div", { className: classNames?.root, ...props, children: [
|
|
2138
2499
|
/* @__PURE__ */ jsxs("div", { className: classNames?.header, children: [
|
|
2139
2500
|
/* @__PURE__ */ jsx(
|
|
@@ -2158,37 +2519,57 @@ function MonthPickerGrid({ classNames, ...props }) {
|
|
|
2158
2519
|
}
|
|
2159
2520
|
)
|
|
2160
2521
|
] }),
|
|
2161
|
-
/* @__PURE__ */ jsx(
|
|
2522
|
+
/* @__PURE__ */ jsx(
|
|
2162
2523
|
"div",
|
|
2163
2524
|
{
|
|
2164
|
-
|
|
2165
|
-
|
|
2166
|
-
|
|
2167
|
-
|
|
2168
|
-
|
|
2169
|
-
|
|
2170
|
-
|
|
2171
|
-
|
|
2172
|
-
|
|
2173
|
-
|
|
2174
|
-
"
|
|
2175
|
-
{
|
|
2176
|
-
|
|
2177
|
-
|
|
2178
|
-
|
|
2179
|
-
|
|
2180
|
-
|
|
2181
|
-
|
|
2182
|
-
|
|
2183
|
-
|
|
2184
|
-
|
|
2185
|
-
|
|
2186
|
-
|
|
2187
|
-
|
|
2188
|
-
|
|
2189
|
-
|
|
2190
|
-
|
|
2191
|
-
|
|
2525
|
+
ref: gridRef,
|
|
2526
|
+
role: "grid",
|
|
2527
|
+
"aria-label": `${currentYear} months`,
|
|
2528
|
+
className: classNames?.grid,
|
|
2529
|
+
onKeyDown: handleKeyDown,
|
|
2530
|
+
children: Array.from({ length: 4 }, (_, rowIndex) => /* @__PURE__ */ jsx(
|
|
2531
|
+
"div",
|
|
2532
|
+
{
|
|
2533
|
+
role: "row",
|
|
2534
|
+
className: classNames?.gridRow,
|
|
2535
|
+
style: { display: "grid", gridTemplateColumns: "repeat(3, 1fr)" },
|
|
2536
|
+
children: Array.from({ length: 3 }, (_2, col) => {
|
|
2537
|
+
const i = rowIndex * 3 + col;
|
|
2538
|
+
const isSelected = valueYear === currentYear && valueMonthZeroBased === i;
|
|
2539
|
+
const isCurrent = todayYear === currentYear && todayMonth === i;
|
|
2540
|
+
const isFocused = i === focusedIndex;
|
|
2541
|
+
const isDisabled = monthDisabledFlags[i] ?? false;
|
|
2542
|
+
const cls = [
|
|
2543
|
+
classNames?.month,
|
|
2544
|
+
isSelected && classNames?.monthSelected,
|
|
2545
|
+
isCurrent && classNames?.monthCurrent,
|
|
2546
|
+
isDisabled && classNames?.monthDisabled
|
|
2547
|
+
].filter(Boolean).join(" ") || void 0;
|
|
2548
|
+
return /* @__PURE__ */ jsx(
|
|
2549
|
+
"button",
|
|
2550
|
+
{
|
|
2551
|
+
type: "button",
|
|
2552
|
+
role: "gridcell",
|
|
2553
|
+
tabIndex: isFocused ? 0 : -1,
|
|
2554
|
+
disabled: isDisabled,
|
|
2555
|
+
"aria-selected": isSelected || void 0,
|
|
2556
|
+
"aria-disabled": isDisabled || void 0,
|
|
2557
|
+
"aria-current": isCurrent ? "date" : void 0,
|
|
2558
|
+
"data-selected": isSelected || void 0,
|
|
2559
|
+
"data-current": isCurrent || void 0,
|
|
2560
|
+
"data-focused": isFocused || void 0,
|
|
2561
|
+
className: cls,
|
|
2562
|
+
onClick: () => handleMonthSelect(i),
|
|
2563
|
+
children: getMonthName(i, locale)
|
|
2564
|
+
},
|
|
2565
|
+
i
|
|
2566
|
+
);
|
|
2567
|
+
})
|
|
2568
|
+
},
|
|
2569
|
+
rowIndex
|
|
2570
|
+
))
|
|
2571
|
+
}
|
|
2572
|
+
)
|
|
2192
2573
|
] });
|
|
2193
2574
|
}
|
|
2194
2575
|
|
|
@@ -2205,7 +2586,7 @@ function YearPickerRoot(props) {
|
|
|
2205
2586
|
}
|
|
2206
2587
|
function YearPickerGrid({ classNames, ...props }) {
|
|
2207
2588
|
const ctx = useDatePickerContext("YearPicker.Grid");
|
|
2208
|
-
const { adapter, viewMonth, value, displayTimezone, labels } = ctx;
|
|
2589
|
+
const { adapter, viewMonth, value, displayTimezone, labels, disabled } = ctx;
|
|
2209
2590
|
const currentYear = adapter.getYear(viewMonth);
|
|
2210
2591
|
const decadeStart = currentYear - currentYear % 12;
|
|
2211
2592
|
const valueYear = useMemo(() => {
|
|
@@ -2216,7 +2597,20 @@ function YearPickerGrid({ classNames, ...props }) {
|
|
|
2216
2597
|
return null;
|
|
2217
2598
|
}
|
|
2218
2599
|
}, [value, adapter, displayTimezone]);
|
|
2219
|
-
const
|
|
2600
|
+
const [today, setToday] = useState(null);
|
|
2601
|
+
useEffect(() => {
|
|
2602
|
+
setToday(adapter.today(displayTimezone));
|
|
2603
|
+
}, [adapter, displayTimezone]);
|
|
2604
|
+
const todayYear = today !== null ? adapter.getYear(today) : -1;
|
|
2605
|
+
const yearDisabledFlags = useMemo(
|
|
2606
|
+
() => Array.from({ length: 12 }, (_, i) => {
|
|
2607
|
+
const year = decadeStart + i;
|
|
2608
|
+
const yearStart = new Date(Date.UTC(year, 0, 1)).toISOString();
|
|
2609
|
+
const yearEnd = new Date(Date.UTC(year, 11, 31, 23, 59, 59, 999)).toISOString();
|
|
2610
|
+
return isRangeFullyDisabled(yearStart, yearEnd, disabled, adapter);
|
|
2611
|
+
}),
|
|
2612
|
+
[decadeStart, disabled, adapter]
|
|
2613
|
+
);
|
|
2220
2614
|
const navigateDecade = useCallback(
|
|
2221
2615
|
(direction) => {
|
|
2222
2616
|
ctx.setViewMonth(adapter.addYears(viewMonth, direction * 12));
|
|
@@ -2224,19 +2618,24 @@ function YearPickerGrid({ classNames, ...props }) {
|
|
|
2224
2618
|
[adapter, viewMonth, ctx]
|
|
2225
2619
|
);
|
|
2226
2620
|
const handleYearSelect = useCallback(
|
|
2227
|
-
(
|
|
2621
|
+
(indexInDecade) => {
|
|
2622
|
+
if (yearDisabledFlags[indexInDecade]) return;
|
|
2623
|
+
const year = decadeStart + indexInDecade;
|
|
2228
2624
|
const target = new Date(Date.UTC(year, 0, 1)).toISOString();
|
|
2229
2625
|
ctx.selectDate(target);
|
|
2230
2626
|
},
|
|
2231
|
-
[ctx]
|
|
2232
|
-
);
|
|
2233
|
-
const
|
|
2234
|
-
|
|
2235
|
-
|
|
2236
|
-
|
|
2237
|
-
|
|
2238
|
-
|
|
2239
|
-
|
|
2627
|
+
[ctx, decadeStart, yearDisabledFlags]
|
|
2628
|
+
);
|
|
2629
|
+
const naturalIndex = valueYear !== null && valueYear >= decadeStart && valueYear <= decadeStart + 11 ? valueYear - decadeStart : currentYear - decadeStart;
|
|
2630
|
+
const firstEnabled = yearDisabledFlags.findIndex((d) => !d);
|
|
2631
|
+
const initialIndex = yearDisabledFlags[naturalIndex] ? firstEnabled === -1 ? naturalIndex : firstEnabled : naturalIndex;
|
|
2632
|
+
const { gridRef, focusedIndex, handleKeyDown } = useGridState({
|
|
2633
|
+
initialIndex,
|
|
2634
|
+
disabledFlags: yearDisabledFlags,
|
|
2635
|
+
onSelect: handleYearSelect,
|
|
2636
|
+
onPageUp: () => navigateDecade(-1),
|
|
2637
|
+
onPageDown: () => navigateDecade(1),
|
|
2638
|
+
onEscape: ctx.close
|
|
2240
2639
|
});
|
|
2241
2640
|
const rangeLabel = `${decadeStart}\u2013${decadeStart + 11}`;
|
|
2242
2641
|
return /* @__PURE__ */ jsxs("div", { className: classNames?.root, ...props, children: [
|
|
@@ -2263,37 +2662,58 @@ function YearPickerGrid({ classNames, ...props }) {
|
|
|
2263
2662
|
}
|
|
2264
2663
|
)
|
|
2265
2664
|
] }),
|
|
2266
|
-
/* @__PURE__ */ jsx(
|
|
2665
|
+
/* @__PURE__ */ jsx(
|
|
2267
2666
|
"div",
|
|
2268
2667
|
{
|
|
2269
|
-
|
|
2270
|
-
|
|
2271
|
-
|
|
2272
|
-
|
|
2273
|
-
|
|
2274
|
-
|
|
2275
|
-
|
|
2276
|
-
|
|
2277
|
-
|
|
2278
|
-
|
|
2279
|
-
"
|
|
2280
|
-
{
|
|
2281
|
-
|
|
2282
|
-
|
|
2283
|
-
|
|
2284
|
-
|
|
2285
|
-
|
|
2286
|
-
|
|
2287
|
-
|
|
2288
|
-
|
|
2289
|
-
|
|
2290
|
-
|
|
2291
|
-
|
|
2292
|
-
|
|
2293
|
-
|
|
2294
|
-
|
|
2295
|
-
|
|
2296
|
-
|
|
2668
|
+
ref: gridRef,
|
|
2669
|
+
role: "grid",
|
|
2670
|
+
"aria-label": rangeLabel,
|
|
2671
|
+
className: classNames?.grid,
|
|
2672
|
+
onKeyDown: handleKeyDown,
|
|
2673
|
+
children: Array.from({ length: 4 }, (_, rowIndex) => /* @__PURE__ */ jsx(
|
|
2674
|
+
"div",
|
|
2675
|
+
{
|
|
2676
|
+
role: "row",
|
|
2677
|
+
className: classNames?.gridRow,
|
|
2678
|
+
style: { display: "grid", gridTemplateColumns: "repeat(3, 1fr)" },
|
|
2679
|
+
children: Array.from({ length: 3 }, (_2, col) => {
|
|
2680
|
+
const i = rowIndex * 3 + col;
|
|
2681
|
+
const year = decadeStart + i;
|
|
2682
|
+
const isSelected = year === valueYear;
|
|
2683
|
+
const isCurrent = year === todayYear;
|
|
2684
|
+
const isFocused = i === focusedIndex;
|
|
2685
|
+
const isDisabled = yearDisabledFlags[i] ?? false;
|
|
2686
|
+
const cls = [
|
|
2687
|
+
classNames?.year,
|
|
2688
|
+
isSelected && classNames?.yearSelected,
|
|
2689
|
+
isCurrent && classNames?.yearCurrent,
|
|
2690
|
+
isDisabled && classNames?.yearDisabled
|
|
2691
|
+
].filter(Boolean).join(" ") || void 0;
|
|
2692
|
+
return /* @__PURE__ */ jsx(
|
|
2693
|
+
"button",
|
|
2694
|
+
{
|
|
2695
|
+
type: "button",
|
|
2696
|
+
role: "gridcell",
|
|
2697
|
+
tabIndex: isFocused ? 0 : -1,
|
|
2698
|
+
disabled: isDisabled,
|
|
2699
|
+
"aria-selected": isSelected || void 0,
|
|
2700
|
+
"aria-disabled": isDisabled || void 0,
|
|
2701
|
+
"aria-current": isCurrent ? "date" : void 0,
|
|
2702
|
+
"data-selected": isSelected || void 0,
|
|
2703
|
+
"data-current": isCurrent || void 0,
|
|
2704
|
+
"data-focused": isFocused || void 0,
|
|
2705
|
+
className: cls,
|
|
2706
|
+
onClick: () => handleYearSelect(i),
|
|
2707
|
+
children: year
|
|
2708
|
+
},
|
|
2709
|
+
i
|
|
2710
|
+
);
|
|
2711
|
+
})
|
|
2712
|
+
},
|
|
2713
|
+
rowIndex
|
|
2714
|
+
))
|
|
2715
|
+
}
|
|
2716
|
+
)
|
|
2297
2717
|
] });
|
|
2298
2718
|
}
|
|
2299
2719
|
|
|
@@ -2514,7 +2934,7 @@ function useRangePicker(options = {}) {
|
|
|
2514
2934
|
adapter
|
|
2515
2935
|
};
|
|
2516
2936
|
}
|
|
2517
|
-
function
|
|
2937
|
+
function getDefaultIso() {
|
|
2518
2938
|
return DateFnsAdapter.today();
|
|
2519
2939
|
}
|
|
2520
2940
|
function useTimePicker(options = {}) {
|
|
@@ -2532,7 +2952,7 @@ function useTimePicker(options = {}) {
|
|
|
2532
2952
|
defaultValue ?? null
|
|
2533
2953
|
);
|
|
2534
2954
|
const currentValue = isControlled ? controlledValue ?? null : uncontrolledValue;
|
|
2535
|
-
const baseIso = currentValue ??
|
|
2955
|
+
const baseIso = currentValue ?? getDefaultIso();
|
|
2536
2956
|
const currentTime = useMemo(
|
|
2537
2957
|
() => displayTimezone ? getTimeInTimezone(baseIso, displayTimezone) : getTime(baseIso),
|
|
2538
2958
|
[baseIso, displayTimezone]
|