@kalyx/react 1.0.0-rc.0 → 1.0.0-rc.10
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 +283 -9
- package/README.md +7 -2
- package/dist/index.cjs +827 -410
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +81 -8
- package/dist/index.d.ts +81 -8
- package/dist/index.js +816 -415
- package/dist/index.js.map +1 -1
- package/package.json +18 -3
package/dist/index.cjs
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
"use client";
|
|
1
2
|
'use strict';
|
|
2
3
|
|
|
3
4
|
var react = require('react');
|
|
@@ -57,10 +58,10 @@ function DatePickerRoot({
|
|
|
57
58
|
const currentValue = isControlled ? controlledValue ?? null : uncontrolledValue;
|
|
58
59
|
const [isOpen, setIsOpen] = react.useState(false);
|
|
59
60
|
const [viewMonth, setViewMonth] = react.useState(
|
|
60
|
-
currentValue ?? adapter.today(displayTimezone)
|
|
61
|
+
() => currentValue ?? adapter.today(displayTimezone)
|
|
61
62
|
);
|
|
62
63
|
const [focusedDate, setFocusedDate] = react.useState(
|
|
63
|
-
currentValue ?? adapter.today(displayTimezone)
|
|
64
|
+
() => currentValue ?? adapter.today(displayTimezone)
|
|
64
65
|
);
|
|
65
66
|
useChangeEffect(isOpen, onOpenChange);
|
|
66
67
|
const viewMonthStart = react.useMemo(() => adapter.startOfMonth(viewMonth), [viewMonth, adapter]);
|
|
@@ -151,10 +152,11 @@ function DatePickerRoot({
|
|
|
151
152
|
return /* @__PURE__ */ jsxRuntime.jsx(DatePickerContext.Provider, { value: contextValue, children });
|
|
152
153
|
}
|
|
153
154
|
var DatePickerInput = react.forwardRef(
|
|
154
|
-
function DatePickerInput2({ format: formatProp, onClick, onBlur, onKeyDown, ...props }, ref) {
|
|
155
|
+
function DatePickerInput2({ format: formatProp, name, onClick, onBlur, onKeyDown, ...props }, ref) {
|
|
155
156
|
const ctx = useDatePickerContext("DatePicker.Input");
|
|
156
157
|
const displayFormat = formatProp ?? ctx.displayFormat;
|
|
157
158
|
const [inputText, setInputText] = react.useState(null);
|
|
159
|
+
const isComposingRef = react.useRef(false);
|
|
158
160
|
let formattedValue = "";
|
|
159
161
|
if (ctx.value) {
|
|
160
162
|
try {
|
|
@@ -171,47 +173,62 @@ var DatePickerInput = react.forwardRef(
|
|
|
171
173
|
},
|
|
172
174
|
[ctx, onClick]
|
|
173
175
|
);
|
|
176
|
+
const commitText = react.useCallback(
|
|
177
|
+
(text) => {
|
|
178
|
+
if (!text) {
|
|
179
|
+
ctx.selectDate(null);
|
|
180
|
+
setInputText(null);
|
|
181
|
+
return true;
|
|
182
|
+
}
|
|
183
|
+
const parsed = core.parseInputValue(text, ctx.adapter);
|
|
184
|
+
if (parsed) {
|
|
185
|
+
ctx.selectDate(parsed);
|
|
186
|
+
setInputText(null);
|
|
187
|
+
return true;
|
|
188
|
+
}
|
|
189
|
+
return false;
|
|
190
|
+
},
|
|
191
|
+
[ctx]
|
|
192
|
+
);
|
|
174
193
|
const handleBlur = react.useCallback(
|
|
175
194
|
(e) => {
|
|
176
195
|
if (inputText !== null) {
|
|
177
|
-
|
|
178
|
-
if (parsed) {
|
|
179
|
-
ctx.selectDate(parsed);
|
|
180
|
-
}
|
|
196
|
+
commitText(inputText);
|
|
181
197
|
setInputText(null);
|
|
182
198
|
}
|
|
183
199
|
onBlur?.(e);
|
|
184
200
|
},
|
|
185
|
-
[inputText,
|
|
201
|
+
[inputText, commitText, onBlur]
|
|
186
202
|
);
|
|
187
203
|
const handleChange = react.useCallback(
|
|
188
204
|
(e) => {
|
|
189
205
|
const text = e.target.value;
|
|
190
206
|
setInputText(text);
|
|
191
|
-
if (
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
207
|
+
if (isComposingRef.current) return;
|
|
208
|
+
commitText(text);
|
|
209
|
+
},
|
|
210
|
+
[commitText]
|
|
211
|
+
);
|
|
212
|
+
const handleCompositionStart = react.useCallback(() => {
|
|
213
|
+
isComposingRef.current = true;
|
|
214
|
+
}, []);
|
|
215
|
+
const handleCompositionEnd = react.useCallback(
|
|
216
|
+
(e) => {
|
|
217
|
+
isComposingRef.current = false;
|
|
218
|
+
commitText(e.target.value);
|
|
201
219
|
},
|
|
202
|
-
[
|
|
220
|
+
[commitText]
|
|
203
221
|
);
|
|
204
222
|
const handleKeyDown = react.useCallback(
|
|
205
223
|
(e) => {
|
|
206
224
|
if (e.key === "Escape") {
|
|
207
225
|
ctx.close();
|
|
208
226
|
} else if (e.key === "Enter") {
|
|
227
|
+
if (ctx.isOpen) e.preventDefault();
|
|
209
228
|
if (inputText !== null) {
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
setInputText(null);
|
|
214
|
-
}
|
|
229
|
+
commitText(inputText);
|
|
230
|
+
} else if (ctx.isOpen) {
|
|
231
|
+
ctx.selectDate(ctx.focusedDate);
|
|
215
232
|
}
|
|
216
233
|
} else if (e.key === "ArrowDown" && !ctx.isOpen) {
|
|
217
234
|
e.preventDefault();
|
|
@@ -219,36 +236,42 @@ var DatePickerInput = react.forwardRef(
|
|
|
219
236
|
}
|
|
220
237
|
onKeyDown?.(e);
|
|
221
238
|
},
|
|
222
|
-
[ctx, inputText,
|
|
239
|
+
[ctx, inputText, commitText, onKeyDown]
|
|
223
240
|
);
|
|
224
241
|
const calendarId = `${ctx.pickerId}-calendar`;
|
|
225
|
-
return /* @__PURE__ */ jsxRuntime.
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
242
|
+
return /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
|
|
243
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
244
|
+
"input",
|
|
245
|
+
{
|
|
246
|
+
ref: (node) => {
|
|
247
|
+
ctx.referenceRef.current = node;
|
|
248
|
+
if (typeof ref === "function") ref(node);
|
|
249
|
+
else if (ref) ref.current = node;
|
|
250
|
+
},
|
|
251
|
+
type: "text",
|
|
252
|
+
role: "combobox",
|
|
253
|
+
"aria-expanded": ctx.isOpen,
|
|
254
|
+
"aria-haspopup": "dialog",
|
|
255
|
+
"aria-controls": ctx.isOpen ? calendarId : void 0,
|
|
256
|
+
"aria-autocomplete": "none",
|
|
257
|
+
autoComplete: "off",
|
|
258
|
+
value: displayValue,
|
|
259
|
+
disabled: ctx.isDisabled || props.disabled,
|
|
260
|
+
readOnly: ctx.isReadOnly,
|
|
261
|
+
onChange: handleChange,
|
|
262
|
+
onClick: handleClick,
|
|
263
|
+
onBlur: handleBlur,
|
|
264
|
+
onKeyDown: handleKeyDown,
|
|
265
|
+
onCompositionStart: handleCompositionStart,
|
|
266
|
+
onCompositionEnd: handleCompositionEnd,
|
|
267
|
+
...props
|
|
268
|
+
}
|
|
269
|
+
),
|
|
270
|
+
name ? /* @__PURE__ */ jsxRuntime.jsx("input", { type: "hidden", name, value: ctx.value ?? "" }) : null
|
|
271
|
+
] });
|
|
250
272
|
}
|
|
251
273
|
);
|
|
274
|
+
DatePickerInput.displayName = "DatePicker.Input";
|
|
252
275
|
var DatePickerTrigger = react.forwardRef(
|
|
253
276
|
function DatePickerTrigger2({ onClick, children, ...props }, ref) {
|
|
254
277
|
const ctx = useDatePickerContext("DatePicker.Trigger");
|
|
@@ -272,6 +295,7 @@ var DatePickerTrigger = react.forwardRef(
|
|
|
272
295
|
tabIndex: 0,
|
|
273
296
|
"aria-label": ctx.isOpen ? ctx.labels.triggerClose : ctx.labels.triggerOpen,
|
|
274
297
|
"aria-expanded": ctx.isOpen,
|
|
298
|
+
"aria-haspopup": "dialog",
|
|
275
299
|
"aria-controls": ctx.isOpen ? calendarId : void 0,
|
|
276
300
|
disabled: ctx.isDisabled || props.disabled,
|
|
277
301
|
onClick: handleClick,
|
|
@@ -302,13 +326,20 @@ var DatePickerTrigger = react.forwardRef(
|
|
|
302
326
|
);
|
|
303
327
|
}
|
|
304
328
|
);
|
|
305
|
-
|
|
329
|
+
DatePickerTrigger.displayName = "DatePicker.Trigger";
|
|
330
|
+
var POPOVER_MIDDLEWARE = [react$1.offset(4), react$1.flip(), react$1.shift({ padding: 8 })];
|
|
331
|
+
function usePopover({
|
|
332
|
+
isOpen,
|
|
333
|
+
close,
|
|
334
|
+
referenceRef,
|
|
335
|
+
placement = "bottom-start"
|
|
336
|
+
}) {
|
|
306
337
|
const floatingRef = react.useRef(null);
|
|
307
338
|
const previousFocusRef = react.useRef(null);
|
|
308
|
-
const { refs, floatingStyles } = react$1.useFloating({
|
|
339
|
+
const { refs, floatingStyles, isPositioned } = react$1.useFloating({
|
|
309
340
|
open: isOpen,
|
|
310
341
|
placement,
|
|
311
|
-
middleware:
|
|
342
|
+
middleware: POPOVER_MIDDLEWARE,
|
|
312
343
|
whileElementsMounted: react$1.autoUpdate
|
|
313
344
|
});
|
|
314
345
|
react.useEffect(() => {
|
|
@@ -355,21 +386,46 @@ function usePopover({ isOpen, close, referenceRef, placement = "bottom-start" })
|
|
|
355
386
|
document.addEventListener("keydown", handleKeyDown);
|
|
356
387
|
return () => document.removeEventListener("keydown", handleKeyDown);
|
|
357
388
|
}, [isOpen, close]);
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
389
|
+
react.useEffect(() => {
|
|
390
|
+
if (!isOpen) return;
|
|
391
|
+
function handleFocusOut(e) {
|
|
392
|
+
const next = e.relatedTarget;
|
|
393
|
+
const floating = floatingRef.current;
|
|
394
|
+
const reference = referenceRef.current;
|
|
395
|
+
if (!next) return;
|
|
396
|
+
const insideFloating = floating?.contains(next) ?? false;
|
|
397
|
+
const insideReference = reference?.contains(next) ?? false;
|
|
398
|
+
if (!insideFloating && !insideReference) {
|
|
399
|
+
close();
|
|
400
|
+
}
|
|
401
|
+
}
|
|
402
|
+
const node = floatingRef.current;
|
|
403
|
+
if (!node) return;
|
|
404
|
+
node.addEventListener("focusout", handleFocusOut);
|
|
405
|
+
return () => node.removeEventListener("focusout", handleFocusOut);
|
|
406
|
+
}, [isOpen, close, referenceRef]);
|
|
407
|
+
const setFloatingRef = react.useCallback(
|
|
408
|
+
(node) => {
|
|
409
|
+
floatingRef.current = node;
|
|
410
|
+
refs.setFloating(node);
|
|
411
|
+
if (node && referenceRef.current) {
|
|
412
|
+
refs.setReference(referenceRef.current);
|
|
413
|
+
}
|
|
414
|
+
},
|
|
415
|
+
[refs, referenceRef]
|
|
416
|
+
);
|
|
417
|
+
return { floatingStyles, setFloatingRef, isPositioned };
|
|
363
418
|
}
|
|
364
419
|
function DatePickerPopover({ children, ...props }) {
|
|
365
420
|
const ctx = useDatePickerContext("DatePicker.Popover");
|
|
366
421
|
const calendarId = `${ctx.pickerId}-calendar`;
|
|
367
|
-
const { floatingStyles, setFloatingRef } = usePopover({
|
|
422
|
+
const { floatingStyles, setFloatingRef, isPositioned } = usePopover({
|
|
368
423
|
isOpen: ctx.isOpen,
|
|
369
424
|
close: ctx.close,
|
|
370
425
|
referenceRef: ctx.referenceRef
|
|
371
426
|
});
|
|
372
427
|
if (!ctx.isOpen) return null;
|
|
428
|
+
const { style: userStyle, ...rest } = props;
|
|
373
429
|
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
374
430
|
"div",
|
|
375
431
|
{
|
|
@@ -378,8 +434,12 @@ function DatePickerPopover({ children, ...props }) {
|
|
|
378
434
|
role: "dialog",
|
|
379
435
|
"aria-label": ctx.labels.popoverLabel,
|
|
380
436
|
"aria-modal": "false",
|
|
381
|
-
|
|
382
|
-
|
|
437
|
+
...rest,
|
|
438
|
+
style: {
|
|
439
|
+
...userStyle,
|
|
440
|
+
...floatingStyles,
|
|
441
|
+
visibility: isPositioned ? void 0 : "hidden"
|
|
442
|
+
},
|
|
383
443
|
children
|
|
384
444
|
}
|
|
385
445
|
);
|
|
@@ -402,27 +462,45 @@ var srOnly = {
|
|
|
402
462
|
whiteSpace: "nowrap",
|
|
403
463
|
border: 0
|
|
404
464
|
};
|
|
405
|
-
function DatePickerCalendar({
|
|
465
|
+
function DatePickerCalendar({
|
|
466
|
+
classNames,
|
|
467
|
+
onTitleClick,
|
|
468
|
+
showWeekNumber = false,
|
|
469
|
+
fixedWeeks = false,
|
|
470
|
+
...props
|
|
471
|
+
}) {
|
|
406
472
|
const ctx = useDatePickerContext("DatePicker.Calendar");
|
|
407
473
|
const gridRef = react.useRef(null);
|
|
408
474
|
const [announcement, setAnnouncement] = react.useState("");
|
|
409
475
|
const { adapter, viewMonth, focusedDate, weekStartsOn, disabled, locale, displayTimezone } = ctx;
|
|
410
|
-
const weekdays = core.getWeekdayNames(locale, weekStartsOn);
|
|
411
|
-
const weeks =
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
476
|
+
const weekdays = react.useMemo(() => core.getWeekdayNames(locale, weekStartsOn), [locale, weekStartsOn]);
|
|
477
|
+
const weeks = react.useMemo(
|
|
478
|
+
() => core.getCalendarDays(viewMonth, adapter, {
|
|
479
|
+
weekStartsOn,
|
|
480
|
+
selected: ctx.value,
|
|
481
|
+
focusedDate,
|
|
482
|
+
disabled,
|
|
483
|
+
timezone: displayTimezone,
|
|
484
|
+
fixedWeeks
|
|
485
|
+
}),
|
|
486
|
+
[
|
|
487
|
+
viewMonth,
|
|
488
|
+
adapter,
|
|
489
|
+
weekStartsOn,
|
|
490
|
+
ctx.value,
|
|
491
|
+
focusedDate,
|
|
492
|
+
disabled,
|
|
493
|
+
displayTimezone,
|
|
494
|
+
fixedWeeks
|
|
495
|
+
]
|
|
496
|
+
);
|
|
497
|
+
const thursdayIndex = weekStartsOn === 0 ? 4 : 3;
|
|
418
498
|
const year = adapter.getYear(viewMonth);
|
|
419
499
|
const month = adapter.getMonth(viewMonth);
|
|
420
500
|
const title = core.formatMonthYear(year, month, locale);
|
|
421
501
|
react.useEffect(() => {
|
|
422
502
|
if (!ctx.isOpen || !gridRef.current) return;
|
|
423
|
-
const focusedButton = gridRef.current.querySelector(
|
|
424
|
-
'[data-focused="true"]'
|
|
425
|
-
);
|
|
503
|
+
const focusedButton = gridRef.current.querySelector('[data-focused="true"]');
|
|
426
504
|
focusedButton?.focus({ preventScroll: true });
|
|
427
505
|
}, [focusedDate, ctx.isOpen]);
|
|
428
506
|
const navigateMonth = react.useCallback(
|
|
@@ -496,6 +574,15 @@ function DatePickerCalendar({ classNames, onTitleClick, ...props }) {
|
|
|
496
574
|
}
|
|
497
575
|
if (newFocused) {
|
|
498
576
|
e.preventDefault();
|
|
577
|
+
const skipStep = e.key === "ArrowLeft" || e.key === "ArrowUp" || e.key === "PageUp" || e.key === "Home" ? -1 : 1;
|
|
578
|
+
let attempts = 0;
|
|
579
|
+
while (core.isDateDisabled(newFocused, disabled, adapter) && attempts < 42) {
|
|
580
|
+
newFocused = adapter.addDays(newFocused, skipStep);
|
|
581
|
+
attempts++;
|
|
582
|
+
}
|
|
583
|
+
if (attempts >= 42) {
|
|
584
|
+
return;
|
|
585
|
+
}
|
|
499
586
|
ctx.setFocusedDate(newFocused);
|
|
500
587
|
if (!adapter.isSameMonth(newFocused, viewMonth)) {
|
|
501
588
|
ctx.setViewMonth(newFocused);
|
|
@@ -543,62 +630,170 @@ function DatePickerCalendar({ classNames, onTitleClick, ...props }) {
|
|
|
543
630
|
ref: gridRef,
|
|
544
631
|
role: "grid",
|
|
545
632
|
"aria-label": title,
|
|
633
|
+
"aria-rowcount": weeks.length + 1,
|
|
634
|
+
"aria-colcount": 7,
|
|
546
635
|
className: classNames?.grid,
|
|
547
636
|
onKeyDown: handleKeyDown,
|
|
548
637
|
children: [
|
|
549
|
-
/* @__PURE__ */ jsxRuntime.jsx("thead", { children: /* @__PURE__ */ jsxRuntime.
|
|
550
|
-
"th",
|
|
551
|
-
|
|
552
|
-
|
|
553
|
-
abbr: day.full,
|
|
554
|
-
scope: "col",
|
|
555
|
-
className: classNames?.weekdayHeader,
|
|
556
|
-
children: day.short
|
|
557
|
-
},
|
|
558
|
-
day.short
|
|
559
|
-
)) }) }),
|
|
560
|
-
/* @__PURE__ */ jsxRuntime.jsx("tbody", { children: weeks.map((week, weekIndex) => /* @__PURE__ */ jsxRuntime.jsx("tr", { role: "row", className: classNames?.gridRow, children: week.map((day) => {
|
|
561
|
-
const dayClasses = [
|
|
562
|
-
classNames?.day,
|
|
563
|
-
day.isSelected && classNames?.daySelected,
|
|
564
|
-
day.isToday && classNames?.dayToday,
|
|
565
|
-
day.isDisabled && classNames?.dayDisabled,
|
|
566
|
-
!day.isCurrentMonth && classNames?.dayOutsideMonth
|
|
567
|
-
].filter(Boolean).join(" ") || void 0;
|
|
568
|
-
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
569
|
-
"td",
|
|
638
|
+
/* @__PURE__ */ jsxRuntime.jsx("thead", { children: /* @__PURE__ */ jsxRuntime.jsxs("tr", { role: "row", "aria-rowindex": 1, children: [
|
|
639
|
+
showWeekNumber ? /* @__PURE__ */ jsxRuntime.jsx("th", { scope: "col", "aria-hidden": "true", className: classNames?.weekNumberHeader, children: "#" }) : null,
|
|
640
|
+
weekdays.map((day, colIndex) => /* @__PURE__ */ jsxRuntime.jsx(
|
|
641
|
+
"th",
|
|
570
642
|
{
|
|
571
|
-
role: "
|
|
572
|
-
|
|
573
|
-
"
|
|
574
|
-
"aria-
|
|
575
|
-
className: classNames?.
|
|
576
|
-
children:
|
|
577
|
-
|
|
643
|
+
role: "columnheader",
|
|
644
|
+
abbr: day.full,
|
|
645
|
+
scope: "col",
|
|
646
|
+
"aria-colindex": colIndex + 1,
|
|
647
|
+
className: classNames?.weekdayHeader,
|
|
648
|
+
children: day.short
|
|
649
|
+
},
|
|
650
|
+
day.short
|
|
651
|
+
))
|
|
652
|
+
] }) }),
|
|
653
|
+
/* @__PURE__ */ jsxRuntime.jsx("tbody", { children: weeks.map((week, weekIndex) => /* @__PURE__ */ jsxRuntime.jsxs(
|
|
654
|
+
"tr",
|
|
655
|
+
{
|
|
656
|
+
role: "row",
|
|
657
|
+
"aria-rowindex": weekIndex + 2,
|
|
658
|
+
className: classNames?.gridRow,
|
|
659
|
+
children: [
|
|
660
|
+
showWeekNumber ? /* @__PURE__ */ jsxRuntime.jsx(
|
|
661
|
+
"th",
|
|
578
662
|
{
|
|
579
|
-
|
|
580
|
-
|
|
581
|
-
|
|
582
|
-
"data-
|
|
583
|
-
|
|
584
|
-
"data-today": day.isToday || void 0,
|
|
585
|
-
"data-outside-month": !day.isCurrentMonth || void 0,
|
|
586
|
-
className: dayClasses,
|
|
587
|
-
onClick: () => handleDayClick(day),
|
|
588
|
-
"aria-label": safeFormatFullDate(day.isoString, locale),
|
|
589
|
-
children: day.dayNumber
|
|
663
|
+
scope: "row",
|
|
664
|
+
"aria-hidden": "true",
|
|
665
|
+
className: classNames?.weekNumber,
|
|
666
|
+
"data-week-number": true,
|
|
667
|
+
children: core.getISOWeekNumber(week[thursdayIndex].isoString)
|
|
590
668
|
}
|
|
591
|
-
)
|
|
592
|
-
|
|
593
|
-
|
|
594
|
-
|
|
595
|
-
|
|
669
|
+
) : null,
|
|
670
|
+
week.map((day, colIndex) => {
|
|
671
|
+
const dayClasses = [
|
|
672
|
+
classNames?.day,
|
|
673
|
+
day.isSelected && classNames?.daySelected,
|
|
674
|
+
day.isToday && classNames?.dayToday,
|
|
675
|
+
day.isDisabled && classNames?.dayDisabled,
|
|
676
|
+
!day.isCurrentMonth && classNames?.dayOutsideMonth
|
|
677
|
+
].filter(Boolean).join(" ") || void 0;
|
|
678
|
+
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
679
|
+
"td",
|
|
680
|
+
{
|
|
681
|
+
role: "gridcell",
|
|
682
|
+
"aria-colindex": colIndex + 1,
|
|
683
|
+
"aria-selected": day.isSelected || void 0,
|
|
684
|
+
"aria-disabled": day.isDisabled || void 0,
|
|
685
|
+
"aria-current": day.isToday ? "date" : void 0,
|
|
686
|
+
className: classNames?.gridCell,
|
|
687
|
+
children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
688
|
+
"button",
|
|
689
|
+
{
|
|
690
|
+
type: "button",
|
|
691
|
+
tabIndex: day.isFocused ? 0 : -1,
|
|
692
|
+
disabled: day.isDisabled,
|
|
693
|
+
"data-focused": day.isFocused || void 0,
|
|
694
|
+
"data-selected": day.isSelected || void 0,
|
|
695
|
+
"data-today": day.isToday || void 0,
|
|
696
|
+
"data-outside-month": !day.isCurrentMonth || void 0,
|
|
697
|
+
className: dayClasses,
|
|
698
|
+
onClick: () => handleDayClick(day),
|
|
699
|
+
"aria-label": safeFormatFullDate(day.isoString, locale),
|
|
700
|
+
children: day.dayNumber
|
|
701
|
+
}
|
|
702
|
+
)
|
|
703
|
+
},
|
|
704
|
+
day.isoString
|
|
705
|
+
);
|
|
706
|
+
})
|
|
707
|
+
]
|
|
708
|
+
},
|
|
709
|
+
weekIndex
|
|
710
|
+
)) })
|
|
596
711
|
]
|
|
597
712
|
}
|
|
598
713
|
),
|
|
599
714
|
/* @__PURE__ */ jsxRuntime.jsx("div", { role: "status", "aria-live": "polite", "aria-atomic": "true", style: srOnly, children: announcement })
|
|
600
715
|
] });
|
|
601
716
|
}
|
|
717
|
+
function isRangeFullyDisabled(start, end, rules, adapter) {
|
|
718
|
+
for (const rule of rules) {
|
|
719
|
+
if ("before" in rule && adapter.isBefore(end, rule.before)) return true;
|
|
720
|
+
if ("after" in rule && adapter.isAfter(start, rule.after)) return true;
|
|
721
|
+
}
|
|
722
|
+
return false;
|
|
723
|
+
}
|
|
724
|
+
function useGridState(opts) {
|
|
725
|
+
const { initialIndex, disabledFlags, onSelect, onPageUp, onPageDown, onEscape } = opts;
|
|
726
|
+
const gridRef = react.useRef(null);
|
|
727
|
+
const [focusedIndex, setFocusedIndex] = react.useState(initialIndex);
|
|
728
|
+
const handleKeyDown = (e) => {
|
|
729
|
+
let next = null;
|
|
730
|
+
let step = 1;
|
|
731
|
+
switch (e.key) {
|
|
732
|
+
case "ArrowLeft":
|
|
733
|
+
next = Math.max(0, focusedIndex - 1);
|
|
734
|
+
step = -1;
|
|
735
|
+
break;
|
|
736
|
+
case "ArrowRight":
|
|
737
|
+
next = Math.min(11, focusedIndex + 1);
|
|
738
|
+
break;
|
|
739
|
+
case "ArrowUp":
|
|
740
|
+
next = Math.max(0, focusedIndex - 3);
|
|
741
|
+
step = -1;
|
|
742
|
+
break;
|
|
743
|
+
case "ArrowDown":
|
|
744
|
+
next = Math.min(11, focusedIndex + 3);
|
|
745
|
+
break;
|
|
746
|
+
case "Home":
|
|
747
|
+
next = focusedIndex - focusedIndex % 3;
|
|
748
|
+
step = -1;
|
|
749
|
+
break;
|
|
750
|
+
case "End":
|
|
751
|
+
next = focusedIndex - focusedIndex % 3 + 2;
|
|
752
|
+
break;
|
|
753
|
+
case "PageUp":
|
|
754
|
+
e.preventDefault();
|
|
755
|
+
onPageUp();
|
|
756
|
+
return;
|
|
757
|
+
case "PageDown":
|
|
758
|
+
e.preventDefault();
|
|
759
|
+
onPageDown();
|
|
760
|
+
return;
|
|
761
|
+
case "Enter":
|
|
762
|
+
case " ":
|
|
763
|
+
e.preventDefault();
|
|
764
|
+
onSelect(focusedIndex);
|
|
765
|
+
return;
|
|
766
|
+
case "Escape":
|
|
767
|
+
onEscape();
|
|
768
|
+
return;
|
|
769
|
+
default:
|
|
770
|
+
return;
|
|
771
|
+
}
|
|
772
|
+
if (next === null) return;
|
|
773
|
+
e.preventDefault();
|
|
774
|
+
if (disabledFlags) {
|
|
775
|
+
let attempts = 0;
|
|
776
|
+
while (next >= 0 && next < 12 && disabledFlags[next] && attempts < 12) {
|
|
777
|
+
next += step;
|
|
778
|
+
attempts++;
|
|
779
|
+
}
|
|
780
|
+
if (next < 0 || next >= 12 || disabledFlags[next]) return;
|
|
781
|
+
}
|
|
782
|
+
if (next !== focusedIndex) setFocusedIndex(next);
|
|
783
|
+
};
|
|
784
|
+
react.useEffect(() => {
|
|
785
|
+
if (!disabledFlags || !disabledFlags[focusedIndex]) return;
|
|
786
|
+
const firstEnabled = disabledFlags.findIndex((d) => !d);
|
|
787
|
+
if (firstEnabled !== -1 && firstEnabled !== focusedIndex) {
|
|
788
|
+
setFocusedIndex(firstEnabled);
|
|
789
|
+
}
|
|
790
|
+
}, [disabledFlags, focusedIndex]);
|
|
791
|
+
react.useEffect(() => {
|
|
792
|
+
const btn = gridRef.current?.querySelector('[data-focused="true"]');
|
|
793
|
+
btn?.focus({ preventScroll: true });
|
|
794
|
+
}, [focusedIndex]);
|
|
795
|
+
return { gridRef, focusedIndex, handleKeyDown };
|
|
796
|
+
}
|
|
602
797
|
function DatePickerMonthGrid({
|
|
603
798
|
classNames,
|
|
604
799
|
onSelect,
|
|
@@ -606,15 +801,18 @@ function DatePickerMonthGrid({
|
|
|
606
801
|
...props
|
|
607
802
|
}) {
|
|
608
803
|
const ctx = useDatePickerContext("DatePicker.MonthGrid");
|
|
609
|
-
const { adapter, viewMonth, locale } = ctx;
|
|
804
|
+
const { adapter, viewMonth, locale, displayTimezone } = ctx;
|
|
610
805
|
const currentYear = adapter.getYear(viewMonth);
|
|
611
806
|
const currentMonth = adapter.getMonth(viewMonth);
|
|
612
|
-
const
|
|
613
|
-
|
|
807
|
+
const [today, setToday] = react.useState(null);
|
|
808
|
+
react.useEffect(() => {
|
|
809
|
+
setToday(adapter.today(displayTimezone));
|
|
810
|
+
}, [adapter, displayTimezone]);
|
|
811
|
+
const todayMonth = today !== null ? adapter.getMonth(today) : -1;
|
|
812
|
+
const todayYear = today !== null ? adapter.getYear(today) : -1;
|
|
614
813
|
const navigateYear = react.useCallback(
|
|
615
814
|
(direction) => {
|
|
616
|
-
|
|
617
|
-
ctx.setViewMonth(newDate);
|
|
815
|
+
ctx.setViewMonth(adapter.addYears(viewMonth, direction));
|
|
618
816
|
},
|
|
619
817
|
[adapter, viewMonth, ctx]
|
|
620
818
|
);
|
|
@@ -627,12 +825,13 @@ function DatePickerMonthGrid({
|
|
|
627
825
|
},
|
|
628
826
|
[currentYear, ctx, onSelect]
|
|
629
827
|
);
|
|
630
|
-
const
|
|
631
|
-
|
|
632
|
-
|
|
633
|
-
|
|
634
|
-
|
|
635
|
-
|
|
828
|
+
const { gridRef, focusedIndex, handleKeyDown } = useGridState({
|
|
829
|
+
initialIndex: currentMonth,
|
|
830
|
+
onSelect: handleMonthSelect,
|
|
831
|
+
onPageUp: () => navigateYear(-1),
|
|
832
|
+
onPageDown: () => navigateYear(1),
|
|
833
|
+
onEscape: ctx.close
|
|
834
|
+
});
|
|
636
835
|
return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: classNames?.root, ...props, children: [
|
|
637
836
|
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: classNames?.header, children: [
|
|
638
837
|
/* @__PURE__ */ jsxRuntime.jsx(
|
|
@@ -645,15 +844,7 @@ function DatePickerMonthGrid({
|
|
|
645
844
|
children: "<"
|
|
646
845
|
}
|
|
647
846
|
),
|
|
648
|
-
onTitleClick ? /* @__PURE__ */ jsxRuntime.jsx(
|
|
649
|
-
"button",
|
|
650
|
-
{
|
|
651
|
-
type: "button",
|
|
652
|
-
className: classNames?.title,
|
|
653
|
-
onClick: onTitleClick,
|
|
654
|
-
children: currentYear
|
|
655
|
-
}
|
|
656
|
-
) : /* @__PURE__ */ jsxRuntime.jsx("span", { className: classNames?.title, children: currentYear }),
|
|
847
|
+
onTitleClick ? /* @__PURE__ */ jsxRuntime.jsx("button", { type: "button", className: classNames?.title, onClick: onTitleClick, children: currentYear }) : /* @__PURE__ */ jsxRuntime.jsx("span", { className: classNames?.title, children: currentYear }),
|
|
657
848
|
/* @__PURE__ */ jsxRuntime.jsx(
|
|
658
849
|
"button",
|
|
659
850
|
{
|
|
@@ -668,74 +859,77 @@ function DatePickerMonthGrid({
|
|
|
668
859
|
/* @__PURE__ */ jsxRuntime.jsx(
|
|
669
860
|
"div",
|
|
670
861
|
{
|
|
862
|
+
ref: gridRef,
|
|
671
863
|
role: "grid",
|
|
672
864
|
"aria-label": `${currentYear} months`,
|
|
673
865
|
className: classNames?.grid,
|
|
674
866
|
style: { display: "grid", gridTemplateColumns: "repeat(3, 1fr)" },
|
|
675
|
-
|
|
676
|
-
|
|
867
|
+
onKeyDown: handleKeyDown,
|
|
868
|
+
children: Array.from({ length: 12 }, (_, i) => {
|
|
869
|
+
const isSelected = i === currentMonth;
|
|
870
|
+
const isCurrent = i === todayMonth && currentYear === todayYear;
|
|
871
|
+
const isFocused = i === focusedIndex;
|
|
872
|
+
const cls = [
|
|
677
873
|
classNames?.month,
|
|
678
|
-
|
|
679
|
-
|
|
874
|
+
isSelected && classNames?.monthSelected,
|
|
875
|
+
isCurrent && classNames?.monthCurrent
|
|
680
876
|
].filter(Boolean).join(" ") || void 0;
|
|
681
877
|
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
682
878
|
"button",
|
|
683
879
|
{
|
|
684
880
|
type: "button",
|
|
685
881
|
role: "gridcell",
|
|
686
|
-
|
|
687
|
-
"aria-
|
|
688
|
-
"
|
|
689
|
-
"data-
|
|
690
|
-
|
|
691
|
-
|
|
692
|
-
|
|
882
|
+
tabIndex: isFocused ? 0 : -1,
|
|
883
|
+
"aria-selected": isSelected || void 0,
|
|
884
|
+
"aria-current": isCurrent ? "date" : void 0,
|
|
885
|
+
"data-selected": isSelected || void 0,
|
|
886
|
+
"data-current": isCurrent || void 0,
|
|
887
|
+
"data-focused": isFocused || void 0,
|
|
888
|
+
className: cls,
|
|
889
|
+
onClick: () => handleMonthSelect(i),
|
|
890
|
+
children: core.getMonthName(i, locale)
|
|
693
891
|
},
|
|
694
|
-
|
|
892
|
+
i
|
|
695
893
|
);
|
|
696
894
|
})
|
|
697
895
|
}
|
|
698
896
|
)
|
|
699
897
|
] });
|
|
700
898
|
}
|
|
701
|
-
function DatePickerYearGrid({
|
|
702
|
-
classNames,
|
|
703
|
-
onSelect,
|
|
704
|
-
...props
|
|
705
|
-
}) {
|
|
899
|
+
function DatePickerYearGrid({ classNames, onSelect, ...props }) {
|
|
706
900
|
const ctx = useDatePickerContext("DatePicker.YearGrid");
|
|
707
|
-
const { adapter, viewMonth } = ctx;
|
|
901
|
+
const { adapter, viewMonth, displayTimezone } = ctx;
|
|
708
902
|
const currentYear = adapter.getYear(viewMonth);
|
|
709
|
-
const
|
|
903
|
+
const [today, setToday] = react.useState(null);
|
|
904
|
+
react.useEffect(() => {
|
|
905
|
+
setToday(adapter.today(displayTimezone));
|
|
906
|
+
}, [adapter, displayTimezone]);
|
|
907
|
+
const todayYear = today !== null ? adapter.getYear(today) : -1;
|
|
710
908
|
const decadeStart = currentYear - currentYear % 12;
|
|
711
909
|
const navigateDecade = react.useCallback(
|
|
712
910
|
(direction) => {
|
|
713
|
-
|
|
714
|
-
ctx.setViewMonth(newDate);
|
|
911
|
+
ctx.setViewMonth(adapter.addYears(viewMonth, direction * 12));
|
|
715
912
|
},
|
|
716
913
|
[adapter, viewMonth, ctx]
|
|
717
914
|
);
|
|
718
915
|
const handleYearSelect = react.useCallback(
|
|
719
|
-
(
|
|
916
|
+
(indexInDecade) => {
|
|
917
|
+
const year = decadeStart + indexInDecade;
|
|
720
918
|
const currentMonth = adapter.getMonth(viewMonth);
|
|
721
919
|
const target = new Date(Date.UTC(year, currentMonth, 1)).toISOString();
|
|
722
920
|
ctx.setViewMonth(target);
|
|
723
921
|
ctx.setFocusedDate(target);
|
|
724
922
|
onSelect?.();
|
|
725
923
|
},
|
|
726
|
-
[adapter, viewMonth, ctx, onSelect]
|
|
727
|
-
);
|
|
728
|
-
const
|
|
729
|
-
|
|
730
|
-
|
|
731
|
-
|
|
732
|
-
|
|
733
|
-
|
|
734
|
-
|
|
735
|
-
};
|
|
736
|
-
}),
|
|
737
|
-
[decadeStart, currentYear, todayYear]
|
|
738
|
-
);
|
|
924
|
+
[adapter, viewMonth, ctx, onSelect, decadeStart]
|
|
925
|
+
);
|
|
926
|
+
const { gridRef, focusedIndex, handleKeyDown } = useGridState({
|
|
927
|
+
initialIndex: currentYear - decadeStart,
|
|
928
|
+
onSelect: handleYearSelect,
|
|
929
|
+
onPageUp: () => navigateDecade(-1),
|
|
930
|
+
onPageDown: () => navigateDecade(1),
|
|
931
|
+
onEscape: ctx.close
|
|
932
|
+
});
|
|
739
933
|
const rangeLabel = `${decadeStart}\u2013${decadeStart + 11}`;
|
|
740
934
|
return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: classNames?.root, ...props, children: [
|
|
741
935
|
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: classNames?.header, children: [
|
|
@@ -764,30 +958,38 @@ function DatePickerYearGrid({
|
|
|
764
958
|
/* @__PURE__ */ jsxRuntime.jsx(
|
|
765
959
|
"div",
|
|
766
960
|
{
|
|
961
|
+
ref: gridRef,
|
|
767
962
|
role: "grid",
|
|
768
963
|
"aria-label": rangeLabel,
|
|
769
964
|
className: classNames?.grid,
|
|
770
965
|
style: { display: "grid", gridTemplateColumns: "repeat(3, 1fr)" },
|
|
771
|
-
|
|
772
|
-
|
|
966
|
+
onKeyDown: handleKeyDown,
|
|
967
|
+
children: Array.from({ length: 12 }, (_, i) => {
|
|
968
|
+
const year = decadeStart + i;
|
|
969
|
+
const isSelected = year === currentYear;
|
|
970
|
+
const isCurrent = year === todayYear;
|
|
971
|
+
const isFocused = i === focusedIndex;
|
|
972
|
+
const cls = [
|
|
773
973
|
classNames?.year,
|
|
774
|
-
|
|
775
|
-
|
|
974
|
+
isSelected && classNames?.yearSelected,
|
|
975
|
+
isCurrent && classNames?.yearCurrent
|
|
776
976
|
].filter(Boolean).join(" ") || void 0;
|
|
777
977
|
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
778
978
|
"button",
|
|
779
979
|
{
|
|
780
980
|
type: "button",
|
|
781
981
|
role: "gridcell",
|
|
782
|
-
|
|
783
|
-
"aria-
|
|
784
|
-
"
|
|
785
|
-
"data-
|
|
786
|
-
|
|
787
|
-
|
|
788
|
-
|
|
982
|
+
tabIndex: isFocused ? 0 : -1,
|
|
983
|
+
"aria-selected": isSelected || void 0,
|
|
984
|
+
"aria-current": isCurrent ? "date" : void 0,
|
|
985
|
+
"data-selected": isSelected || void 0,
|
|
986
|
+
"data-current": isCurrent || void 0,
|
|
987
|
+
"data-focused": isFocused || void 0,
|
|
988
|
+
className: cls,
|
|
989
|
+
onClick: () => handleYearSelect(i),
|
|
990
|
+
children: year
|
|
789
991
|
},
|
|
790
|
-
|
|
992
|
+
i
|
|
791
993
|
);
|
|
792
994
|
})
|
|
793
995
|
}
|
|
@@ -796,16 +998,7 @@ function DatePickerYearGrid({
|
|
|
796
998
|
}
|
|
797
999
|
function DatePickerPresets({ classNames, children, ...props }) {
|
|
798
1000
|
const ctx = useDatePickerContext("DatePicker.Presets");
|
|
799
|
-
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
800
|
-
"div",
|
|
801
|
-
{
|
|
802
|
-
role: "group",
|
|
803
|
-
"aria-label": ctx.labels.popoverLabel,
|
|
804
|
-
className: classNames?.root,
|
|
805
|
-
...props,
|
|
806
|
-
children
|
|
807
|
-
}
|
|
808
|
-
);
|
|
1001
|
+
return /* @__PURE__ */ jsxRuntime.jsx("div", { role: "group", "aria-label": ctx.labels.popoverLabel, className: classNames?.root, ...props, children });
|
|
809
1002
|
}
|
|
810
1003
|
function resolveDatePreset(key, today, adapter) {
|
|
811
1004
|
switch (key) {
|
|
@@ -859,11 +1052,7 @@ function DatePickerPreset({
|
|
|
859
1052
|
if (directDate) {
|
|
860
1053
|
target = directDate;
|
|
861
1054
|
} else if (presetKey) {
|
|
862
|
-
target = resolveDatePreset(
|
|
863
|
-
presetKey,
|
|
864
|
-
ctx.adapter.today(ctx.displayTimezone),
|
|
865
|
-
ctx.adapter
|
|
866
|
-
);
|
|
1055
|
+
target = resolveDatePreset(presetKey, ctx.adapter.today(ctx.displayTimezone), ctx.adapter);
|
|
867
1056
|
} else {
|
|
868
1057
|
return false;
|
|
869
1058
|
}
|
|
@@ -873,8 +1062,7 @@ function DatePickerPreset({
|
|
|
873
1062
|
"button",
|
|
874
1063
|
{
|
|
875
1064
|
type: "button",
|
|
876
|
-
|
|
877
|
-
"aria-selected": isActive,
|
|
1065
|
+
"aria-pressed": isActive,
|
|
878
1066
|
"data-active": isActive || void 0,
|
|
879
1067
|
disabled: ctx.isDisabled,
|
|
880
1068
|
onClick: handleClick,
|
|
@@ -938,10 +1126,10 @@ function RangePickerRoot({
|
|
|
938
1126
|
const [selectingTarget, setSelectingTarget] = react.useState("start");
|
|
939
1127
|
const [hoverDate, setHoverDate] = react.useState(null);
|
|
940
1128
|
const [viewMonth, setViewMonth] = react.useState(
|
|
941
|
-
currentValue.start ?? adapter.today(displayTimezone)
|
|
1129
|
+
() => currentValue.start ?? adapter.today(displayTimezone)
|
|
942
1130
|
);
|
|
943
1131
|
const [focusedDate, setFocusedDate] = react.useState(
|
|
944
|
-
currentValue.start ?? adapter.today(displayTimezone)
|
|
1132
|
+
() => currentValue.start ?? adapter.today(displayTimezone)
|
|
945
1133
|
);
|
|
946
1134
|
useChangeEffect(isOpen, onOpenChange);
|
|
947
1135
|
const viewMonthStart = react.useMemo(() => adapter.startOfMonth(viewMonth), [viewMonth, adapter]);
|
|
@@ -1091,6 +1279,8 @@ var RangePickerInput = react.forwardRef(
|
|
|
1091
1279
|
(e) => {
|
|
1092
1280
|
if (e.key === "Escape") {
|
|
1093
1281
|
ctx.close();
|
|
1282
|
+
} else if (e.key === "Enter" && ctx.isOpen) {
|
|
1283
|
+
e.preventDefault();
|
|
1094
1284
|
} else if (e.key === "ArrowDown" && !ctx.isOpen) {
|
|
1095
1285
|
e.preventDefault();
|
|
1096
1286
|
ctx.open();
|
|
@@ -1127,15 +1317,17 @@ var RangePickerInput = react.forwardRef(
|
|
|
1127
1317
|
);
|
|
1128
1318
|
}
|
|
1129
1319
|
);
|
|
1320
|
+
RangePickerInput.displayName = "RangePicker.Input";
|
|
1130
1321
|
function RangePickerPopover({ children, ...props }) {
|
|
1131
1322
|
const ctx = useRangePickerContext("RangePicker.Popover");
|
|
1132
1323
|
const calendarId = `${ctx.pickerId}-calendar`;
|
|
1133
|
-
const { floatingStyles, setFloatingRef } = usePopover({
|
|
1324
|
+
const { floatingStyles, setFloatingRef, isPositioned } = usePopover({
|
|
1134
1325
|
isOpen: ctx.isOpen,
|
|
1135
1326
|
close: ctx.close,
|
|
1136
1327
|
referenceRef: ctx.referenceRef
|
|
1137
1328
|
});
|
|
1138
1329
|
if (!ctx.isOpen) return null;
|
|
1330
|
+
const { style: userStyle, ...rest } = props;
|
|
1139
1331
|
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
1140
1332
|
"div",
|
|
1141
1333
|
{
|
|
@@ -1144,8 +1336,12 @@ function RangePickerPopover({ children, ...props }) {
|
|
|
1144
1336
|
role: "dialog",
|
|
1145
1337
|
"aria-label": ctx.labels.popoverLabel,
|
|
1146
1338
|
"aria-modal": "false",
|
|
1147
|
-
|
|
1148
|
-
|
|
1339
|
+
...rest,
|
|
1340
|
+
style: {
|
|
1341
|
+
...userStyle,
|
|
1342
|
+
...floatingStyles,
|
|
1343
|
+
visibility: isPositioned ? void 0 : "hidden"
|
|
1344
|
+
},
|
|
1149
1345
|
children
|
|
1150
1346
|
}
|
|
1151
1347
|
);
|
|
@@ -1171,6 +1367,8 @@ var srOnly2 = {
|
|
|
1171
1367
|
function RangePickerCalendar({
|
|
1172
1368
|
classNames,
|
|
1173
1369
|
selectionMode = "range",
|
|
1370
|
+
showWeekNumber = false,
|
|
1371
|
+
fixedWeeks = false,
|
|
1174
1372
|
...props
|
|
1175
1373
|
}) {
|
|
1176
1374
|
const ctx = useRangePickerContext("RangePicker.Calendar");
|
|
@@ -1188,23 +1386,36 @@ function RangePickerCalendar({
|
|
|
1188
1386
|
displayTimezone
|
|
1189
1387
|
} = ctx;
|
|
1190
1388
|
const { locale } = ctx;
|
|
1191
|
-
const weekdays = core.getWeekdayNames(locale, weekStartsOn);
|
|
1192
|
-
const weeks =
|
|
1193
|
-
|
|
1194
|
-
|
|
1195
|
-
|
|
1196
|
-
|
|
1197
|
-
|
|
1198
|
-
|
|
1199
|
-
|
|
1389
|
+
const weekdays = react.useMemo(() => core.getWeekdayNames(locale, weekStartsOn), [locale, weekStartsOn]);
|
|
1390
|
+
const weeks = react.useMemo(
|
|
1391
|
+
() => core.getCalendarDays(viewMonth, adapter, {
|
|
1392
|
+
weekStartsOn,
|
|
1393
|
+
focusedDate,
|
|
1394
|
+
disabled,
|
|
1395
|
+
range: value,
|
|
1396
|
+
rangeHover: hoverDate,
|
|
1397
|
+
timezone: displayTimezone,
|
|
1398
|
+
fixedWeeks
|
|
1399
|
+
}),
|
|
1400
|
+
[
|
|
1401
|
+
viewMonth,
|
|
1402
|
+
adapter,
|
|
1403
|
+
weekStartsOn,
|
|
1404
|
+
focusedDate,
|
|
1405
|
+
disabled,
|
|
1406
|
+
value,
|
|
1407
|
+
hoverDate,
|
|
1408
|
+
displayTimezone,
|
|
1409
|
+
fixedWeeks
|
|
1410
|
+
]
|
|
1411
|
+
);
|
|
1412
|
+
const thursdayIndex = weekStartsOn === 0 ? 4 : 3;
|
|
1200
1413
|
const year = adapter.getYear(viewMonth);
|
|
1201
1414
|
const month = adapter.getMonth(viewMonth);
|
|
1202
1415
|
const title = core.formatMonthYear(year, month, locale);
|
|
1203
1416
|
react.useEffect(() => {
|
|
1204
1417
|
if (!ctx.isOpen || !gridRef.current) return;
|
|
1205
|
-
const focusedButton = gridRef.current.querySelector(
|
|
1206
|
-
'[data-focused="true"]'
|
|
1207
|
-
);
|
|
1418
|
+
const focusedButton = gridRef.current.querySelector('[data-focused="true"]');
|
|
1208
1419
|
focusedButton?.focus({ preventScroll: true });
|
|
1209
1420
|
}, [focusedDate, ctx.isOpen]);
|
|
1210
1421
|
const navigateMonth = react.useCallback(
|
|
@@ -1298,6 +1509,13 @@ function RangePickerCalendar({
|
|
|
1298
1509
|
}
|
|
1299
1510
|
if (newFocused) {
|
|
1300
1511
|
e.preventDefault();
|
|
1512
|
+
const skipStep = e.key === "ArrowLeft" || e.key === "ArrowUp" || e.key === "PageUp" || e.key === "Home" ? -1 : 1;
|
|
1513
|
+
let attempts = 0;
|
|
1514
|
+
while (core.isDateDisabled(newFocused, disabled, adapter) && attempts < 42) {
|
|
1515
|
+
newFocused = adapter.addDays(newFocused, skipStep);
|
|
1516
|
+
attempts++;
|
|
1517
|
+
}
|
|
1518
|
+
if (attempts >= 42) return;
|
|
1301
1519
|
ctx.setFocusedDate(newFocused);
|
|
1302
1520
|
if (!adapter.isSameMonth(newFocused, viewMonth)) {
|
|
1303
1521
|
ctx.setViewMonth(newFocused);
|
|
@@ -1307,7 +1525,18 @@ function RangePickerCalendar({
|
|
|
1307
1525
|
}
|
|
1308
1526
|
}
|
|
1309
1527
|
},
|
|
1310
|
-
[
|
|
1528
|
+
[
|
|
1529
|
+
adapter,
|
|
1530
|
+
focusedDate,
|
|
1531
|
+
viewMonth,
|
|
1532
|
+
weekStartsOn,
|
|
1533
|
+
disabled,
|
|
1534
|
+
ctx,
|
|
1535
|
+
selectionMode,
|
|
1536
|
+
selectingTarget,
|
|
1537
|
+
value.start,
|
|
1538
|
+
commitDay
|
|
1539
|
+
]
|
|
1311
1540
|
);
|
|
1312
1541
|
return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: classNames?.root, ...props, onMouseLeave: handleMouseLeave, children: [
|
|
1313
1542
|
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: classNames?.header, children: [
|
|
@@ -1339,63 +1568,90 @@ function RangePickerCalendar({
|
|
|
1339
1568
|
ref: gridRef,
|
|
1340
1569
|
role: "grid",
|
|
1341
1570
|
"aria-label": title,
|
|
1342
|
-
"aria-
|
|
1571
|
+
"aria-rowcount": weeks.length + 1,
|
|
1572
|
+
"aria-colcount": 7,
|
|
1343
1573
|
className: classNames?.grid,
|
|
1344
1574
|
onKeyDown: handleKeyDown,
|
|
1345
1575
|
children: [
|
|
1346
|
-
/* @__PURE__ */ jsxRuntime.jsx("thead", { children: /* @__PURE__ */ jsxRuntime.
|
|
1347
|
-
"th",
|
|
1348
|
-
|
|
1349
|
-
|
|
1350
|
-
abbr: day.full,
|
|
1351
|
-
scope: "col",
|
|
1352
|
-
className: classNames?.weekdayHeader,
|
|
1353
|
-
children: day.short
|
|
1354
|
-
},
|
|
1355
|
-
day.short
|
|
1356
|
-
)) }) }),
|
|
1357
|
-
/* @__PURE__ */ jsxRuntime.jsx("tbody", { children: weeks.map((week, weekIndex) => /* @__PURE__ */ jsxRuntime.jsx("tr", { role: "row", className: classNames?.gridRow, children: week.map((day) => {
|
|
1358
|
-
const dayClasses = [
|
|
1359
|
-
classNames?.day,
|
|
1360
|
-
day.isRangeStart && classNames?.dayRangeStart,
|
|
1361
|
-
day.isRangeEnd && classNames?.dayRangeEnd,
|
|
1362
|
-
day.isInRange && classNames?.dayInRange,
|
|
1363
|
-
day.isToday && classNames?.dayToday,
|
|
1364
|
-
day.isDisabled && classNames?.dayDisabled,
|
|
1365
|
-
!day.isCurrentMonth && classNames?.dayOutsideMonth
|
|
1366
|
-
].filter(Boolean).join(" ") || void 0;
|
|
1367
|
-
const isSelected = selectionMode === "week" ? day.isRangeStart || day.isRangeEnd || day.isInRange : day.isRangeStart || day.isRangeEnd;
|
|
1368
|
-
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
1369
|
-
"td",
|
|
1576
|
+
/* @__PURE__ */ jsxRuntime.jsx("thead", { children: /* @__PURE__ */ jsxRuntime.jsxs("tr", { role: "row", "aria-rowindex": 1, children: [
|
|
1577
|
+
showWeekNumber ? /* @__PURE__ */ jsxRuntime.jsx("th", { scope: "col", "aria-hidden": "true", className: classNames?.weekNumberHeader, children: "#" }) : null,
|
|
1578
|
+
weekdays.map((day, colIndex) => /* @__PURE__ */ jsxRuntime.jsx(
|
|
1579
|
+
"th",
|
|
1370
1580
|
{
|
|
1371
|
-
role: "
|
|
1372
|
-
|
|
1373
|
-
"
|
|
1374
|
-
"aria-
|
|
1375
|
-
className: classNames?.
|
|
1376
|
-
children:
|
|
1377
|
-
|
|
1581
|
+
role: "columnheader",
|
|
1582
|
+
abbr: day.full,
|
|
1583
|
+
scope: "col",
|
|
1584
|
+
"aria-colindex": colIndex + 1,
|
|
1585
|
+
className: classNames?.weekdayHeader,
|
|
1586
|
+
children: day.short
|
|
1587
|
+
},
|
|
1588
|
+
day.short
|
|
1589
|
+
))
|
|
1590
|
+
] }) }),
|
|
1591
|
+
/* @__PURE__ */ jsxRuntime.jsx("tbody", { children: weeks.map((week, weekIndex) => /* @__PURE__ */ jsxRuntime.jsxs(
|
|
1592
|
+
"tr",
|
|
1593
|
+
{
|
|
1594
|
+
role: "row",
|
|
1595
|
+
"aria-rowindex": weekIndex + 2,
|
|
1596
|
+
className: classNames?.gridRow,
|
|
1597
|
+
children: [
|
|
1598
|
+
showWeekNumber ? /* @__PURE__ */ jsxRuntime.jsx(
|
|
1599
|
+
"th",
|
|
1378
1600
|
{
|
|
1379
|
-
|
|
1380
|
-
|
|
1381
|
-
|
|
1382
|
-
"data-
|
|
1383
|
-
|
|
1384
|
-
"data-range-end": day.isRangeEnd || void 0,
|
|
1385
|
-
"data-in-range": day.isInRange || void 0,
|
|
1386
|
-
"data-today": day.isToday || void 0,
|
|
1387
|
-
"data-outside-month": !day.isCurrentMonth || void 0,
|
|
1388
|
-
className: dayClasses,
|
|
1389
|
-
onClick: () => handleDayClick(day),
|
|
1390
|
-
onMouseEnter: () => handleDayMouseEnter(day),
|
|
1391
|
-
"aria-label": safeFormatFullDate2(day.isoString, locale),
|
|
1392
|
-
children: day.dayNumber
|
|
1601
|
+
scope: "row",
|
|
1602
|
+
"aria-hidden": "true",
|
|
1603
|
+
className: classNames?.weekNumber,
|
|
1604
|
+
"data-week-number": true,
|
|
1605
|
+
children: core.getISOWeekNumber(week[thursdayIndex].isoString)
|
|
1393
1606
|
}
|
|
1394
|
-
)
|
|
1395
|
-
|
|
1396
|
-
|
|
1397
|
-
|
|
1398
|
-
|
|
1607
|
+
) : null,
|
|
1608
|
+
week.map((day, colIndex) => {
|
|
1609
|
+
const dayClasses = [
|
|
1610
|
+
classNames?.day,
|
|
1611
|
+
day.isRangeStart && classNames?.dayRangeStart,
|
|
1612
|
+
day.isRangeEnd && classNames?.dayRangeEnd,
|
|
1613
|
+
day.isInRange && classNames?.dayInRange,
|
|
1614
|
+
day.isToday && classNames?.dayToday,
|
|
1615
|
+
day.isDisabled && classNames?.dayDisabled,
|
|
1616
|
+
!day.isCurrentMonth && classNames?.dayOutsideMonth
|
|
1617
|
+
].filter(Boolean).join(" ") || void 0;
|
|
1618
|
+
const isSelected = selectionMode === "week" ? day.isRangeStart || day.isRangeEnd || day.isInRange : day.isRangeStart || day.isRangeEnd;
|
|
1619
|
+
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
1620
|
+
"td",
|
|
1621
|
+
{
|
|
1622
|
+
role: "gridcell",
|
|
1623
|
+
"aria-colindex": colIndex + 1,
|
|
1624
|
+
"aria-selected": isSelected || void 0,
|
|
1625
|
+
"aria-disabled": day.isDisabled || void 0,
|
|
1626
|
+
"aria-current": day.isToday ? "date" : void 0,
|
|
1627
|
+
className: classNames?.gridCell,
|
|
1628
|
+
children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
1629
|
+
"button",
|
|
1630
|
+
{
|
|
1631
|
+
type: "button",
|
|
1632
|
+
tabIndex: day.isFocused ? 0 : -1,
|
|
1633
|
+
disabled: day.isDisabled,
|
|
1634
|
+
"data-focused": day.isFocused || void 0,
|
|
1635
|
+
"data-range-start": day.isRangeStart || void 0,
|
|
1636
|
+
"data-range-end": day.isRangeEnd || void 0,
|
|
1637
|
+
"data-in-range": day.isInRange || void 0,
|
|
1638
|
+
"data-today": day.isToday || void 0,
|
|
1639
|
+
"data-outside-month": !day.isCurrentMonth || void 0,
|
|
1640
|
+
className: dayClasses,
|
|
1641
|
+
onClick: () => handleDayClick(day),
|
|
1642
|
+
onMouseEnter: () => handleDayMouseEnter(day),
|
|
1643
|
+
"aria-label": safeFormatFullDate2(day.isoString, locale),
|
|
1644
|
+
children: day.dayNumber
|
|
1645
|
+
}
|
|
1646
|
+
)
|
|
1647
|
+
},
|
|
1648
|
+
day.isoString
|
|
1649
|
+
);
|
|
1650
|
+
})
|
|
1651
|
+
]
|
|
1652
|
+
},
|
|
1653
|
+
weekIndex
|
|
1654
|
+
)) })
|
|
1399
1655
|
]
|
|
1400
1656
|
}
|
|
1401
1657
|
),
|
|
@@ -1444,9 +1700,7 @@ function resolvePreset(key, today, adapter) {
|
|
|
1444
1700
|
}
|
|
1445
1701
|
case "thisYear": {
|
|
1446
1702
|
const currentMonth = new Date(today).getUTCMonth();
|
|
1447
|
-
const yearStart = adapter.startOfMonth(
|
|
1448
|
-
adapter.addMonths(today, -currentMonth)
|
|
1449
|
-
);
|
|
1703
|
+
const yearStart = adapter.startOfMonth(adapter.addMonths(today, -currentMonth));
|
|
1450
1704
|
return { start: yearStart, end: today };
|
|
1451
1705
|
}
|
|
1452
1706
|
}
|
|
@@ -1459,41 +1713,33 @@ function RangePickerPreset({
|
|
|
1459
1713
|
...props
|
|
1460
1714
|
}) {
|
|
1461
1715
|
const ctx = useRangePickerContext("RangePicker.Preset");
|
|
1716
|
+
const resolved = react.useMemo(() => {
|
|
1717
|
+
if (directRange) return directRange;
|
|
1718
|
+
if (presetKey)
|
|
1719
|
+
return resolvePreset(presetKey, ctx.adapter.today(ctx.displayTimezone), ctx.adapter);
|
|
1720
|
+
return null;
|
|
1721
|
+
}, [directRange, presetKey, ctx.adapter, ctx.displayTimezone]);
|
|
1462
1722
|
const handleClick = react.useCallback(
|
|
1463
1723
|
(e) => {
|
|
1464
1724
|
if (ctx.isDisabled || ctx.isReadOnly) return;
|
|
1465
|
-
|
|
1466
|
-
if (directRange) {
|
|
1467
|
-
resolved = directRange;
|
|
1468
|
-
} else if (presetKey) {
|
|
1469
|
-
resolved = resolvePreset(presetKey, ctx.adapter.today(), ctx.adapter);
|
|
1470
|
-
} else {
|
|
1471
|
-
return;
|
|
1472
|
-
}
|
|
1725
|
+
if (!resolved) return;
|
|
1473
1726
|
ctx.setRange(resolved);
|
|
1474
1727
|
ctx.close();
|
|
1475
1728
|
onClick?.(e);
|
|
1476
1729
|
},
|
|
1477
|
-
[ctx,
|
|
1730
|
+
[ctx, resolved, onClick]
|
|
1478
1731
|
);
|
|
1479
|
-
const isActive = (() => {
|
|
1480
|
-
if (!ctx.value.start || !ctx.value.end)
|
|
1481
|
-
let target;
|
|
1482
|
-
if (directRange) {
|
|
1483
|
-
target = directRange;
|
|
1484
|
-
} else if (presetKey) {
|
|
1485
|
-
target = resolvePreset(presetKey, ctx.adapter.today(), ctx.adapter);
|
|
1486
|
-
} else {
|
|
1732
|
+
const isActive = react.useMemo(() => {
|
|
1733
|
+
if (!ctx.value.start || !ctx.value.end || !resolved || !resolved.start || !resolved.end) {
|
|
1487
1734
|
return false;
|
|
1488
1735
|
}
|
|
1489
|
-
return
|
|
1490
|
-
})
|
|
1736
|
+
return ctx.adapter.isSameDay(ctx.value.start, resolved.start) && ctx.adapter.isSameDay(ctx.value.end, resolved.end);
|
|
1737
|
+
}, [ctx.value.start, ctx.value.end, ctx.adapter, resolved]);
|
|
1491
1738
|
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
1492
1739
|
"button",
|
|
1493
1740
|
{
|
|
1494
1741
|
type: "button",
|
|
1495
|
-
|
|
1496
|
-
"aria-selected": isActive,
|
|
1742
|
+
"aria-pressed": isActive,
|
|
1497
1743
|
"data-active": isActive || void 0,
|
|
1498
1744
|
disabled: ctx.isDisabled,
|
|
1499
1745
|
onClick: handleClick,
|
|
@@ -1526,9 +1772,6 @@ function useTimePickerContext(componentName) {
|
|
|
1526
1772
|
}
|
|
1527
1773
|
return context;
|
|
1528
1774
|
}
|
|
1529
|
-
function getDefaultIso() {
|
|
1530
|
-
return core.DateFnsAdapter.today();
|
|
1531
|
-
}
|
|
1532
1775
|
function TimePickerRoot({
|
|
1533
1776
|
value: controlledValue,
|
|
1534
1777
|
defaultValue,
|
|
@@ -1539,6 +1782,7 @@ function TimePickerRoot({
|
|
|
1539
1782
|
displayTimezone,
|
|
1540
1783
|
disabled = false,
|
|
1541
1784
|
readOnly = false,
|
|
1785
|
+
filterTime,
|
|
1542
1786
|
labels: labelsProp,
|
|
1543
1787
|
children
|
|
1544
1788
|
}) {
|
|
@@ -1552,21 +1796,21 @@ function TimePickerRoot({
|
|
|
1552
1796
|
defaultValue ?? null
|
|
1553
1797
|
);
|
|
1554
1798
|
const currentValue = isControlled ? controlledValue ?? null : uncontrolledValue;
|
|
1555
|
-
const
|
|
1556
|
-
|
|
1557
|
-
|
|
1558
|
-
|
|
1559
|
-
);
|
|
1799
|
+
const currentTime = react.useMemo(() => {
|
|
1800
|
+
if (!currentValue) return { hours: 0, minutes: 0, seconds: 0 };
|
|
1801
|
+
return displayTimezone ? core.getTimeInTimezone(currentValue, displayTimezone) : core.getTime(currentValue);
|
|
1802
|
+
}, [currentValue, displayTimezone]);
|
|
1560
1803
|
const setTime = react.useCallback(
|
|
1561
1804
|
(partial) => {
|
|
1562
1805
|
if (disabled || readOnly) return;
|
|
1563
|
-
const
|
|
1806
|
+
const base = currentValue ?? core.DateFnsAdapter.today(displayTimezone);
|
|
1807
|
+
const newIso = displayTimezone ? core.setTimeInTimezone(base, partial, displayTimezone) : core.setTime(base, partial);
|
|
1564
1808
|
if (!isControlled) {
|
|
1565
1809
|
setUncontrolledValue(newIso);
|
|
1566
1810
|
}
|
|
1567
1811
|
onChange?.(newIso);
|
|
1568
1812
|
},
|
|
1569
|
-
[disabled, readOnly,
|
|
1813
|
+
[disabled, readOnly, currentValue, displayTimezone, isControlled, onChange]
|
|
1570
1814
|
);
|
|
1571
1815
|
const contextValue = react.useMemo(
|
|
1572
1816
|
() => ({
|
|
@@ -1580,9 +1824,23 @@ function TimePickerRoot({
|
|
|
1580
1824
|
isReadOnly: readOnly,
|
|
1581
1825
|
currentTime,
|
|
1582
1826
|
pickerId,
|
|
1583
|
-
labels: mergedLabels
|
|
1827
|
+
labels: mergedLabels,
|
|
1828
|
+
filterTime
|
|
1584
1829
|
}),
|
|
1585
|
-
[
|
|
1830
|
+
[
|
|
1831
|
+
currentValue,
|
|
1832
|
+
setTime,
|
|
1833
|
+
format,
|
|
1834
|
+
step,
|
|
1835
|
+
withSeconds,
|
|
1836
|
+
displayTimezone,
|
|
1837
|
+
disabled,
|
|
1838
|
+
readOnly,
|
|
1839
|
+
currentTime,
|
|
1840
|
+
pickerId,
|
|
1841
|
+
mergedLabels,
|
|
1842
|
+
filterTime
|
|
1843
|
+
]
|
|
1586
1844
|
);
|
|
1587
1845
|
return /* @__PURE__ */ jsxRuntime.jsx(TimePickerContext.Provider, { value: contextValue, children });
|
|
1588
1846
|
}
|
|
@@ -1599,12 +1857,9 @@ var TimePickerInput = react.forwardRef(
|
|
|
1599
1857
|
}
|
|
1600
1858
|
setInputText(null);
|
|
1601
1859
|
}, [inputText, ctx]);
|
|
1602
|
-
const handleChange = react.useCallback(
|
|
1603
|
-
(e)
|
|
1604
|
-
|
|
1605
|
-
},
|
|
1606
|
-
[]
|
|
1607
|
-
);
|
|
1860
|
+
const handleChange = react.useCallback((e) => {
|
|
1861
|
+
setInputText(e.target.value);
|
|
1862
|
+
}, []);
|
|
1608
1863
|
const handleBlur = react.useCallback(
|
|
1609
1864
|
(e) => {
|
|
1610
1865
|
commitInput();
|
|
@@ -1641,6 +1896,7 @@ var TimePickerInput = react.forwardRef(
|
|
|
1641
1896
|
);
|
|
1642
1897
|
}
|
|
1643
1898
|
);
|
|
1899
|
+
TimePickerInput.displayName = "TimePicker.Input";
|
|
1644
1900
|
function useListboxNavigation({
|
|
1645
1901
|
items,
|
|
1646
1902
|
onSelect,
|
|
@@ -1677,9 +1933,7 @@ function useListboxNavigation({
|
|
|
1677
1933
|
onSelect(target);
|
|
1678
1934
|
cancelAnimationFrame(rafIdRef.current);
|
|
1679
1935
|
rafIdRef.current = requestAnimationFrame(() => {
|
|
1680
|
-
const next = listRef.current?.querySelector(
|
|
1681
|
-
'[data-selected="true"]'
|
|
1682
|
-
);
|
|
1936
|
+
const next = listRef.current?.querySelector('[data-selected="true"]');
|
|
1683
1937
|
next?.focus();
|
|
1684
1938
|
});
|
|
1685
1939
|
}
|
|
@@ -1690,17 +1944,41 @@ function useListboxNavigation({
|
|
|
1690
1944
|
}
|
|
1691
1945
|
function TimePickerHourList({ classNames, ...props }) {
|
|
1692
1946
|
const ctx = useTimePickerContext("TimePicker.HourList");
|
|
1693
|
-
const { format, currentTime, isDisabled, isReadOnly } = ctx;
|
|
1694
|
-
const hours = core.generateHours(format);
|
|
1947
|
+
const { format, step, currentTime, isDisabled, isReadOnly, filterTime } = ctx;
|
|
1948
|
+
const hours = react.useMemo(() => core.generateHours(format), [format]);
|
|
1695
1949
|
const selectedHourDisplay = format === "12h" ? core.to12Hour(currentTime.hours).hours12 : currentTime.hours;
|
|
1696
1950
|
const currentPeriod = format === "12h" ? core.to12Hour(currentTime.hours).period : null;
|
|
1951
|
+
const fullyDisabledHours24 = react.useMemo(() => {
|
|
1952
|
+
if (!filterTime) return null;
|
|
1953
|
+
const disabled = /* @__PURE__ */ new Set();
|
|
1954
|
+
for (let h = 0; h < 24; h++) {
|
|
1955
|
+
let allRejected = true;
|
|
1956
|
+
for (let m = 0; m < 60; m += step) {
|
|
1957
|
+
if (!filterTime(h, m)) {
|
|
1958
|
+
allRejected = false;
|
|
1959
|
+
break;
|
|
1960
|
+
}
|
|
1961
|
+
}
|
|
1962
|
+
if (allRejected) disabled.add(h);
|
|
1963
|
+
}
|
|
1964
|
+
return disabled;
|
|
1965
|
+
}, [filterTime, step]);
|
|
1966
|
+
const isHourDisabled = react.useCallback(
|
|
1967
|
+
(hourDisplay) => {
|
|
1968
|
+
if (!fullyDisabledHours24) return false;
|
|
1969
|
+
const hours24 = format === "12h" && currentPeriod ? core.to24Hour(hourDisplay, currentPeriod) : hourDisplay;
|
|
1970
|
+
return fullyDisabledHours24.has(hours24);
|
|
1971
|
+
},
|
|
1972
|
+
[fullyDisabledHours24, format, currentPeriod]
|
|
1973
|
+
);
|
|
1697
1974
|
const handleSelect = react.useCallback(
|
|
1698
1975
|
(hourDisplay) => {
|
|
1699
1976
|
if (isDisabled || isReadOnly) return;
|
|
1977
|
+
if (isHourDisabled(hourDisplay)) return;
|
|
1700
1978
|
const hours24 = format === "12h" && currentPeriod ? core.to24Hour(hourDisplay, currentPeriod) : hourDisplay;
|
|
1701
1979
|
ctx.setTime({ hours: hours24 });
|
|
1702
1980
|
},
|
|
1703
|
-
[format, currentPeriod, ctx, isDisabled, isReadOnly]
|
|
1981
|
+
[format, currentPeriod, ctx, isDisabled, isReadOnly, isHourDisabled]
|
|
1704
1982
|
);
|
|
1705
1983
|
const { listRef, handleKeyDown } = useListboxNavigation({
|
|
1706
1984
|
items: hours,
|
|
@@ -1718,13 +1996,14 @@ function TimePickerHourList({ classNames, ...props }) {
|
|
|
1718
1996
|
...props,
|
|
1719
1997
|
children: hours.map((hour) => {
|
|
1720
1998
|
const isSelected = hour === selectedHourDisplay;
|
|
1999
|
+
const isHourFullyDisabled = isHourDisabled(hour);
|
|
1721
2000
|
const optionClass = [classNames?.option, isSelected && classNames?.optionSelected].filter(Boolean).join(" ") || void 0;
|
|
1722
2001
|
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
1723
2002
|
"li",
|
|
1724
2003
|
{
|
|
1725
2004
|
role: "option",
|
|
1726
2005
|
"aria-selected": isSelected,
|
|
1727
|
-
"aria-disabled": isDisabled || void 0,
|
|
2006
|
+
"aria-disabled": isDisabled || isHourFullyDisabled || void 0,
|
|
1728
2007
|
"aria-label": ctx.labels.hourOption(hour),
|
|
1729
2008
|
"data-selected": isSelected || void 0,
|
|
1730
2009
|
tabIndex: isSelected ? 0 : -1,
|
|
@@ -1741,14 +2020,22 @@ function TimePickerHourList({ classNames, ...props }) {
|
|
|
1741
2020
|
}
|
|
1742
2021
|
function TimePickerMinuteList({ classNames, ...props }) {
|
|
1743
2022
|
const ctx = useTimePickerContext("TimePicker.MinuteList");
|
|
1744
|
-
const { step, currentTime, isDisabled, isReadOnly } = ctx;
|
|
1745
|
-
const minutes = core.generateMinutes(step);
|
|
2023
|
+
const { step, currentTime, isDisabled, isReadOnly, filterTime } = ctx;
|
|
2024
|
+
const minutes = react.useMemo(() => core.generateMinutes(step), [step]);
|
|
2025
|
+
const isMinuteDisabled = react.useCallback(
|
|
2026
|
+
(minute) => {
|
|
2027
|
+
if (!filterTime) return false;
|
|
2028
|
+
return filterTime(currentTime.hours, minute);
|
|
2029
|
+
},
|
|
2030
|
+
[filterTime, currentTime.hours]
|
|
2031
|
+
);
|
|
1746
2032
|
const handleSelect = react.useCallback(
|
|
1747
2033
|
(minute) => {
|
|
1748
2034
|
if (isDisabled || isReadOnly) return;
|
|
2035
|
+
if (isMinuteDisabled(minute)) return;
|
|
1749
2036
|
ctx.setTime({ minutes: minute });
|
|
1750
2037
|
},
|
|
1751
|
-
[ctx, isDisabled, isReadOnly]
|
|
2038
|
+
[ctx, isDisabled, isReadOnly, isMinuteDisabled]
|
|
1752
2039
|
);
|
|
1753
2040
|
const { listRef, handleKeyDown } = useListboxNavigation({
|
|
1754
2041
|
items: minutes,
|
|
@@ -1766,13 +2053,14 @@ function TimePickerMinuteList({ classNames, ...props }) {
|
|
|
1766
2053
|
...props,
|
|
1767
2054
|
children: minutes.map((minute) => {
|
|
1768
2055
|
const isSelected = minute === currentTime.minutes;
|
|
2056
|
+
const isMinuteFullyDisabled = isMinuteDisabled(minute);
|
|
1769
2057
|
const optionClass = [classNames?.option, isSelected && classNames?.optionSelected].filter(Boolean).join(" ") || void 0;
|
|
1770
2058
|
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
1771
2059
|
"li",
|
|
1772
2060
|
{
|
|
1773
2061
|
role: "option",
|
|
1774
2062
|
"aria-selected": isSelected,
|
|
1775
|
-
"aria-disabled": isDisabled || void 0,
|
|
2063
|
+
"aria-disabled": isDisabled || isMinuteFullyDisabled || void 0,
|
|
1776
2064
|
"aria-label": ctx.labels.minuteOption(minute),
|
|
1777
2065
|
"data-selected": isSelected || void 0,
|
|
1778
2066
|
tabIndex: isSelected ? 0 : -1,
|
|
@@ -1789,37 +2077,87 @@ function TimePickerMinuteList({ classNames, ...props }) {
|
|
|
1789
2077
|
}
|
|
1790
2078
|
function TimePickerAmPmToggle({ classNames, ...props }) {
|
|
1791
2079
|
const ctx = useTimePickerContext("TimePicker.AmPmToggle");
|
|
1792
|
-
|
|
1793
|
-
const
|
|
2080
|
+
const amRef = react.useRef(null);
|
|
2081
|
+
const pmRef = react.useRef(null);
|
|
1794
2082
|
const setPeriod = react.useCallback(
|
|
1795
2083
|
(newPeriod) => {
|
|
1796
2084
|
if (ctx.isDisabled || ctx.isReadOnly) return;
|
|
2085
|
+
const { hours12 } = core.to12Hour(ctx.currentTime.hours);
|
|
1797
2086
|
const newHours24 = core.to24Hour(hours12, newPeriod);
|
|
1798
2087
|
ctx.setTime({ hours: newHours24 });
|
|
1799
2088
|
},
|
|
1800
|
-
[
|
|
2089
|
+
[ctx]
|
|
1801
2090
|
);
|
|
2091
|
+
if (ctx.format !== "12h") return null;
|
|
2092
|
+
const { period } = core.to12Hour(ctx.currentTime.hours);
|
|
2093
|
+
const focusOther = (target) => {
|
|
2094
|
+
(target === "AM" ? amRef : pmRef).current?.focus();
|
|
2095
|
+
};
|
|
2096
|
+
const handleKeyDown = (e, target) => {
|
|
2097
|
+
switch (e.key) {
|
|
2098
|
+
case "ArrowRight":
|
|
2099
|
+
case "ArrowDown":
|
|
2100
|
+
case "ArrowLeft":
|
|
2101
|
+
case "ArrowUp": {
|
|
2102
|
+
e.preventDefault();
|
|
2103
|
+
const next = target === "AM" ? "PM" : "AM";
|
|
2104
|
+
setPeriod(next);
|
|
2105
|
+
focusOther(next);
|
|
2106
|
+
break;
|
|
2107
|
+
}
|
|
2108
|
+
case "Home": {
|
|
2109
|
+
e.preventDefault();
|
|
2110
|
+
setPeriod("AM");
|
|
2111
|
+
focusOther("AM");
|
|
2112
|
+
break;
|
|
2113
|
+
}
|
|
2114
|
+
case "End": {
|
|
2115
|
+
e.preventDefault();
|
|
2116
|
+
setPeriod("PM");
|
|
2117
|
+
focusOther("PM");
|
|
2118
|
+
break;
|
|
2119
|
+
}
|
|
2120
|
+
case " ":
|
|
2121
|
+
case "Enter": {
|
|
2122
|
+
e.preventDefault();
|
|
2123
|
+
setPeriod(target);
|
|
2124
|
+
break;
|
|
2125
|
+
}
|
|
2126
|
+
}
|
|
2127
|
+
};
|
|
1802
2128
|
const renderButton = (target) => {
|
|
1803
2129
|
const isSelected = period === target;
|
|
1804
2130
|
const optionClass = [classNames?.option, isSelected && classNames?.optionSelected].filter(Boolean).join(" ") || void 0;
|
|
1805
2131
|
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
1806
2132
|
"button",
|
|
1807
2133
|
{
|
|
2134
|
+
ref: target === "AM" ? amRef : pmRef,
|
|
1808
2135
|
type: "button",
|
|
1809
2136
|
role: "radio",
|
|
1810
2137
|
"aria-checked": isSelected,
|
|
2138
|
+
tabIndex: isSelected ? 0 : -1,
|
|
1811
2139
|
"data-selected": isSelected || void 0,
|
|
1812
2140
|
disabled: ctx.isDisabled,
|
|
1813
2141
|
className: optionClass,
|
|
1814
2142
|
onClick: () => setPeriod(target),
|
|
2143
|
+
onKeyDown: (e) => handleKeyDown(e, target),
|
|
1815
2144
|
children: target
|
|
1816
2145
|
}
|
|
1817
2146
|
);
|
|
1818
2147
|
};
|
|
1819
|
-
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
1820
|
-
|
|
1821
|
-
|
|
1822
|
-
|
|
2148
|
+
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
2149
|
+
"div",
|
|
2150
|
+
{
|
|
2151
|
+
role: "radiogroup",
|
|
2152
|
+
"aria-label": ctx.labels.amPmToggle,
|
|
2153
|
+
className: classNames?.root,
|
|
2154
|
+
...props,
|
|
2155
|
+
children: [
|
|
2156
|
+
renderButton("AM"),
|
|
2157
|
+
renderButton("PM")
|
|
2158
|
+
]
|
|
2159
|
+
}
|
|
2160
|
+
);
|
|
1823
2161
|
}
|
|
1824
2162
|
|
|
1825
2163
|
// src/components/TimePicker/index.ts
|
|
@@ -1829,9 +2167,6 @@ var TimePicker = Object.assign(TimePickerRoot, {
|
|
|
1829
2167
|
MinuteList: TimePickerMinuteList,
|
|
1830
2168
|
AmPmToggle: TimePickerAmPmToggle
|
|
1831
2169
|
});
|
|
1832
|
-
function getDefaultIso2() {
|
|
1833
|
-
return core.DateFnsAdapter.today();
|
|
1834
|
-
}
|
|
1835
2170
|
function DateTimePickerRoot({
|
|
1836
2171
|
value: controlledValue,
|
|
1837
2172
|
defaultValue,
|
|
@@ -1840,6 +2175,8 @@ function DateTimePickerRoot({
|
|
|
1840
2175
|
onCalendarNavigate,
|
|
1841
2176
|
format = "24h",
|
|
1842
2177
|
step = 1,
|
|
2178
|
+
withSeconds = false,
|
|
2179
|
+
filterTime,
|
|
1843
2180
|
disabled = false,
|
|
1844
2181
|
readOnly = false,
|
|
1845
2182
|
weekStartsOn = 0,
|
|
@@ -1867,10 +2204,10 @@ function DateTimePickerRoot({
|
|
|
1867
2204
|
const currentValue = isControlled ? controlledValue ?? null : uncontrolledValue;
|
|
1868
2205
|
const [isOpen, setIsOpen] = react.useState(false);
|
|
1869
2206
|
const [viewMonth, setViewMonth] = react.useState(
|
|
1870
|
-
currentValue ?? adapter.today(displayTimezone)
|
|
2207
|
+
() => currentValue ?? adapter.today(displayTimezone)
|
|
1871
2208
|
);
|
|
1872
2209
|
const [focusedDate, setFocusedDate] = react.useState(
|
|
1873
|
-
currentValue ?? adapter.today(displayTimezone)
|
|
2210
|
+
() => currentValue ?? adapter.today(displayTimezone)
|
|
1874
2211
|
);
|
|
1875
2212
|
useChangeEffect(isOpen, onOpenChange);
|
|
1876
2213
|
const viewMonthStart = react.useMemo(() => adapter.startOfMonth(viewMonth), [viewMonth, adapter]);
|
|
@@ -1880,11 +2217,10 @@ function DateTimePickerRoot({
|
|
|
1880
2217
|
() => Array.isArray(disabled) ? disabled : [],
|
|
1881
2218
|
[disabled]
|
|
1882
2219
|
);
|
|
1883
|
-
const
|
|
1884
|
-
|
|
1885
|
-
|
|
1886
|
-
|
|
1887
|
-
);
|
|
2220
|
+
const currentTime = react.useMemo(() => {
|
|
2221
|
+
if (!currentValue) return { hours: 0, minutes: 0, seconds: 0 };
|
|
2222
|
+
return displayTimezone ? core.getTimeInTimezone(currentValue, displayTimezone) : core.getTime(currentValue);
|
|
2223
|
+
}, [currentValue, displayTimezone]);
|
|
1888
2224
|
const updateValue = react.useCallback(
|
|
1889
2225
|
(next) => {
|
|
1890
2226
|
if (isDisabled || readOnly) return;
|
|
@@ -1910,11 +2246,11 @@ function DateTimePickerRoot({
|
|
|
1910
2246
|
);
|
|
1911
2247
|
const setTime = react.useCallback(
|
|
1912
2248
|
(partial) => {
|
|
1913
|
-
const base = currentValue ??
|
|
2249
|
+
const base = currentValue ?? adapter.today(displayTimezone);
|
|
1914
2250
|
const merged = displayTimezone ? core.setTimeInTimezone(base, partial, displayTimezone) : core.setTime(base, partial);
|
|
1915
2251
|
updateValue(merged);
|
|
1916
2252
|
},
|
|
1917
|
-
[currentValue, updateValue, displayTimezone]
|
|
2253
|
+
[currentValue, updateValue, displayTimezone, adapter]
|
|
1918
2254
|
);
|
|
1919
2255
|
const open = react.useCallback(() => {
|
|
1920
2256
|
if (isDisabled || readOnly) return;
|
|
@@ -1981,15 +2317,29 @@ function DateTimePickerRoot({
|
|
|
1981
2317
|
setTime,
|
|
1982
2318
|
format,
|
|
1983
2319
|
step,
|
|
1984
|
-
withSeconds
|
|
2320
|
+
withSeconds,
|
|
1985
2321
|
displayTimezone,
|
|
1986
2322
|
isDisabled,
|
|
1987
2323
|
isReadOnly: readOnly,
|
|
1988
2324
|
currentTime,
|
|
1989
2325
|
pickerId,
|
|
1990
|
-
labels: mergedTimeLabels
|
|
2326
|
+
labels: mergedTimeLabels,
|
|
2327
|
+
filterTime
|
|
1991
2328
|
}),
|
|
1992
|
-
[
|
|
2329
|
+
[
|
|
2330
|
+
currentValue,
|
|
2331
|
+
setTime,
|
|
2332
|
+
format,
|
|
2333
|
+
step,
|
|
2334
|
+
withSeconds,
|
|
2335
|
+
displayTimezone,
|
|
2336
|
+
isDisabled,
|
|
2337
|
+
readOnly,
|
|
2338
|
+
currentTime,
|
|
2339
|
+
pickerId,
|
|
2340
|
+
mergedTimeLabels,
|
|
2341
|
+
filterTime
|
|
2342
|
+
]
|
|
1993
2343
|
);
|
|
1994
2344
|
return /* @__PURE__ */ jsxRuntime.jsx(DatePickerContext.Provider, { value: dateContext, children: /* @__PURE__ */ jsxRuntime.jsx(TimePickerContext.Provider, { value: timeContext, children }) });
|
|
1995
2345
|
}
|
|
@@ -2017,6 +2367,8 @@ var DateTimePickerInput = react.forwardRef(
|
|
|
2017
2367
|
(e) => {
|
|
2018
2368
|
if (e.key === "Escape") {
|
|
2019
2369
|
ctx.close();
|
|
2370
|
+
} else if (e.key === "Enter" && ctx.isOpen) {
|
|
2371
|
+
e.preventDefault();
|
|
2020
2372
|
} else if (e.key === "ArrowDown" && !ctx.isOpen) {
|
|
2021
2373
|
e.preventDefault();
|
|
2022
2374
|
ctx.open();
|
|
@@ -2052,6 +2404,7 @@ var DateTimePickerInput = react.forwardRef(
|
|
|
2052
2404
|
);
|
|
2053
2405
|
}
|
|
2054
2406
|
);
|
|
2407
|
+
DateTimePickerInput.displayName = "DateTimePicker.Input";
|
|
2055
2408
|
|
|
2056
2409
|
// src/components/DateTimePicker/index.ts
|
|
2057
2410
|
var DateTimePicker = Object.assign(DateTimePickerRoot, {
|
|
@@ -2068,12 +2421,9 @@ function MonthPickerRoot(props) {
|
|
|
2068
2421
|
const displayFormat = props.displayFormat ?? "yyyy-MM";
|
|
2069
2422
|
return /* @__PURE__ */ jsxRuntime.jsx(DatePickerRoot, { ...props, displayFormat });
|
|
2070
2423
|
}
|
|
2071
|
-
function MonthPickerGrid({
|
|
2072
|
-
classNames,
|
|
2073
|
-
...props
|
|
2074
|
-
}) {
|
|
2424
|
+
function MonthPickerGrid({ classNames, ...props }) {
|
|
2075
2425
|
const ctx = useDatePickerContext("MonthPicker.Grid");
|
|
2076
|
-
const { adapter, viewMonth, locale, value, displayTimezone, labels } = ctx;
|
|
2426
|
+
const { adapter, viewMonth, locale, value, displayTimezone, labels, disabled } = ctx;
|
|
2077
2427
|
const currentYear = adapter.getYear(viewMonth);
|
|
2078
2428
|
const [valueYear, valueMonthZeroBased] = react.useMemo(() => {
|
|
2079
2429
|
if (!value) return [null, null];
|
|
@@ -2084,9 +2434,19 @@ function MonthPickerGrid({
|
|
|
2084
2434
|
return [null, null];
|
|
2085
2435
|
}
|
|
2086
2436
|
}, [value, adapter, displayTimezone]);
|
|
2087
|
-
const today =
|
|
2088
|
-
|
|
2089
|
-
|
|
2437
|
+
const [today, setToday] = react.useState(null);
|
|
2438
|
+
react.useEffect(() => {
|
|
2439
|
+
setToday(adapter.today(displayTimezone));
|
|
2440
|
+
}, [adapter, displayTimezone]);
|
|
2441
|
+
const todayYear = today !== null ? adapter.getYear(today) : -1;
|
|
2442
|
+
const todayMonth = today !== null ? adapter.getMonth(today) : -1;
|
|
2443
|
+
const monthDisabledFlags = react.useMemo(
|
|
2444
|
+
() => Array.from({ length: 12 }, (_, i) => {
|
|
2445
|
+
const monthStart = new Date(Date.UTC(currentYear, i, 1)).toISOString();
|
|
2446
|
+
return isRangeFullyDisabled(monthStart, adapter.endOfMonth(monthStart), disabled, adapter);
|
|
2447
|
+
}),
|
|
2448
|
+
[currentYear, disabled, adapter]
|
|
2449
|
+
);
|
|
2090
2450
|
const navigateYear = react.useCallback(
|
|
2091
2451
|
(direction) => {
|
|
2092
2452
|
ctx.setViewMonth(adapter.addYears(viewMonth, direction));
|
|
@@ -2095,19 +2455,23 @@ function MonthPickerGrid({
|
|
|
2095
2455
|
);
|
|
2096
2456
|
const handleMonthSelect = react.useCallback(
|
|
2097
2457
|
(monthIndex) => {
|
|
2098
|
-
|
|
2099
|
-
|
|
2100
|
-
).toISOString();
|
|
2458
|
+
if (monthDisabledFlags[monthIndex]) return;
|
|
2459
|
+
const target = new Date(Date.UTC(currentYear, monthIndex, 1)).toISOString();
|
|
2101
2460
|
ctx.selectDate(target);
|
|
2102
2461
|
},
|
|
2103
|
-
[currentYear, ctx]
|
|
2104
|
-
);
|
|
2105
|
-
const
|
|
2106
|
-
|
|
2107
|
-
|
|
2108
|
-
|
|
2109
|
-
|
|
2110
|
-
|
|
2462
|
+
[currentYear, ctx, monthDisabledFlags]
|
|
2463
|
+
);
|
|
2464
|
+
const naturalIndex = valueYear === currentYear && valueMonthZeroBased !== null ? valueMonthZeroBased : adapter.getMonth(viewMonth);
|
|
2465
|
+
const firstEnabled = monthDisabledFlags.findIndex((d) => !d);
|
|
2466
|
+
const initialIndex = monthDisabledFlags[naturalIndex] ? firstEnabled === -1 ? naturalIndex : firstEnabled : naturalIndex;
|
|
2467
|
+
const { gridRef, focusedIndex, handleKeyDown } = useGridState({
|
|
2468
|
+
initialIndex,
|
|
2469
|
+
disabledFlags: monthDisabledFlags,
|
|
2470
|
+
onSelect: handleMonthSelect,
|
|
2471
|
+
onPageUp: () => navigateYear(-1),
|
|
2472
|
+
onPageDown: () => navigateYear(1),
|
|
2473
|
+
onEscape: ctx.close
|
|
2474
|
+
});
|
|
2111
2475
|
return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: classNames?.root, ...props, children: [
|
|
2112
2476
|
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: classNames?.header, children: [
|
|
2113
2477
|
/* @__PURE__ */ jsxRuntime.jsx(
|
|
@@ -2135,35 +2499,47 @@ function MonthPickerGrid({
|
|
|
2135
2499
|
/* @__PURE__ */ jsxRuntime.jsx(
|
|
2136
2500
|
"div",
|
|
2137
2501
|
{
|
|
2502
|
+
ref: gridRef,
|
|
2138
2503
|
role: "grid",
|
|
2139
2504
|
"aria-label": `${currentYear} months`,
|
|
2140
2505
|
className: classNames?.grid,
|
|
2506
|
+
onKeyDown: handleKeyDown,
|
|
2141
2507
|
children: Array.from({ length: 4 }, (_, rowIndex) => /* @__PURE__ */ jsxRuntime.jsx(
|
|
2142
2508
|
"div",
|
|
2143
2509
|
{
|
|
2144
2510
|
role: "row",
|
|
2145
2511
|
className: classNames?.gridRow,
|
|
2146
2512
|
style: { display: "grid", gridTemplateColumns: "repeat(3, 1fr)" },
|
|
2147
|
-
children:
|
|
2148
|
-
const
|
|
2513
|
+
children: Array.from({ length: 3 }, (_2, col) => {
|
|
2514
|
+
const i = rowIndex * 3 + col;
|
|
2515
|
+
const isSelected = valueYear === currentYear && valueMonthZeroBased === i;
|
|
2516
|
+
const isCurrent = todayYear === currentYear && todayMonth === i;
|
|
2517
|
+
const isFocused = i === focusedIndex;
|
|
2518
|
+
const isDisabled = monthDisabledFlags[i] ?? false;
|
|
2519
|
+
const cls = [
|
|
2149
2520
|
classNames?.month,
|
|
2150
|
-
|
|
2151
|
-
|
|
2521
|
+
isSelected && classNames?.monthSelected,
|
|
2522
|
+
isCurrent && classNames?.monthCurrent,
|
|
2523
|
+
isDisabled && classNames?.monthDisabled
|
|
2152
2524
|
].filter(Boolean).join(" ") || void 0;
|
|
2153
2525
|
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
2154
2526
|
"button",
|
|
2155
2527
|
{
|
|
2156
2528
|
type: "button",
|
|
2157
2529
|
role: "gridcell",
|
|
2158
|
-
|
|
2159
|
-
|
|
2160
|
-
"
|
|
2161
|
-
"
|
|
2162
|
-
|
|
2163
|
-
|
|
2164
|
-
|
|
2530
|
+
tabIndex: isFocused ? 0 : -1,
|
|
2531
|
+
disabled: isDisabled,
|
|
2532
|
+
"aria-selected": isSelected || void 0,
|
|
2533
|
+
"aria-disabled": isDisabled || void 0,
|
|
2534
|
+
"aria-current": isCurrent ? "date" : void 0,
|
|
2535
|
+
"data-selected": isSelected || void 0,
|
|
2536
|
+
"data-current": isCurrent || void 0,
|
|
2537
|
+
"data-focused": isFocused || void 0,
|
|
2538
|
+
className: cls,
|
|
2539
|
+
onClick: () => handleMonthSelect(i),
|
|
2540
|
+
children: core.getMonthName(i, locale)
|
|
2165
2541
|
},
|
|
2166
|
-
|
|
2542
|
+
i
|
|
2167
2543
|
);
|
|
2168
2544
|
})
|
|
2169
2545
|
},
|
|
@@ -2187,7 +2563,7 @@ function YearPickerRoot(props) {
|
|
|
2187
2563
|
}
|
|
2188
2564
|
function YearPickerGrid({ classNames, ...props }) {
|
|
2189
2565
|
const ctx = useDatePickerContext("YearPicker.Grid");
|
|
2190
|
-
const { adapter, viewMonth, value, displayTimezone, labels } = ctx;
|
|
2566
|
+
const { adapter, viewMonth, value, displayTimezone, labels, disabled } = ctx;
|
|
2191
2567
|
const currentYear = adapter.getYear(viewMonth);
|
|
2192
2568
|
const decadeStart = currentYear - currentYear % 12;
|
|
2193
2569
|
const valueYear = react.useMemo(() => {
|
|
@@ -2198,7 +2574,20 @@ function YearPickerGrid({ classNames, ...props }) {
|
|
|
2198
2574
|
return null;
|
|
2199
2575
|
}
|
|
2200
2576
|
}, [value, adapter, displayTimezone]);
|
|
2201
|
-
const
|
|
2577
|
+
const [today, setToday] = react.useState(null);
|
|
2578
|
+
react.useEffect(() => {
|
|
2579
|
+
setToday(adapter.today(displayTimezone));
|
|
2580
|
+
}, [adapter, displayTimezone]);
|
|
2581
|
+
const todayYear = today !== null ? adapter.getYear(today) : -1;
|
|
2582
|
+
const yearDisabledFlags = react.useMemo(
|
|
2583
|
+
() => Array.from({ length: 12 }, (_, i) => {
|
|
2584
|
+
const year = decadeStart + i;
|
|
2585
|
+
const yearStart = new Date(Date.UTC(year, 0, 1)).toISOString();
|
|
2586
|
+
const yearEnd = new Date(Date.UTC(year, 11, 31, 23, 59, 59, 999)).toISOString();
|
|
2587
|
+
return isRangeFullyDisabled(yearStart, yearEnd, disabled, adapter);
|
|
2588
|
+
}),
|
|
2589
|
+
[decadeStart, disabled, adapter]
|
|
2590
|
+
);
|
|
2202
2591
|
const navigateDecade = react.useCallback(
|
|
2203
2592
|
(direction) => {
|
|
2204
2593
|
ctx.setViewMonth(adapter.addYears(viewMonth, direction * 12));
|
|
@@ -2206,19 +2595,24 @@ function YearPickerGrid({ classNames, ...props }) {
|
|
|
2206
2595
|
[adapter, viewMonth, ctx]
|
|
2207
2596
|
);
|
|
2208
2597
|
const handleYearSelect = react.useCallback(
|
|
2209
|
-
(
|
|
2598
|
+
(indexInDecade) => {
|
|
2599
|
+
if (yearDisabledFlags[indexInDecade]) return;
|
|
2600
|
+
const year = decadeStart + indexInDecade;
|
|
2210
2601
|
const target = new Date(Date.UTC(year, 0, 1)).toISOString();
|
|
2211
2602
|
ctx.selectDate(target);
|
|
2212
2603
|
},
|
|
2213
|
-
[ctx]
|
|
2214
|
-
);
|
|
2215
|
-
const
|
|
2216
|
-
|
|
2217
|
-
|
|
2218
|
-
|
|
2219
|
-
|
|
2220
|
-
|
|
2221
|
-
|
|
2604
|
+
[ctx, decadeStart, yearDisabledFlags]
|
|
2605
|
+
);
|
|
2606
|
+
const naturalIndex = valueYear !== null && valueYear >= decadeStart && valueYear <= decadeStart + 11 ? valueYear - decadeStart : currentYear - decadeStart;
|
|
2607
|
+
const firstEnabled = yearDisabledFlags.findIndex((d) => !d);
|
|
2608
|
+
const initialIndex = yearDisabledFlags[naturalIndex] ? firstEnabled === -1 ? naturalIndex : firstEnabled : naturalIndex;
|
|
2609
|
+
const { gridRef, focusedIndex, handleKeyDown } = useGridState({
|
|
2610
|
+
initialIndex,
|
|
2611
|
+
disabledFlags: yearDisabledFlags,
|
|
2612
|
+
onSelect: handleYearSelect,
|
|
2613
|
+
onPageUp: () => navigateDecade(-1),
|
|
2614
|
+
onPageDown: () => navigateDecade(1),
|
|
2615
|
+
onEscape: ctx.close
|
|
2222
2616
|
});
|
|
2223
2617
|
const rangeLabel = `${decadeStart}\u2013${decadeStart + 11}`;
|
|
2224
2618
|
return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: classNames?.root, ...props, children: [
|
|
@@ -2248,35 +2642,48 @@ function YearPickerGrid({ classNames, ...props }) {
|
|
|
2248
2642
|
/* @__PURE__ */ jsxRuntime.jsx(
|
|
2249
2643
|
"div",
|
|
2250
2644
|
{
|
|
2645
|
+
ref: gridRef,
|
|
2251
2646
|
role: "grid",
|
|
2252
2647
|
"aria-label": rangeLabel,
|
|
2253
2648
|
className: classNames?.grid,
|
|
2649
|
+
onKeyDown: handleKeyDown,
|
|
2254
2650
|
children: Array.from({ length: 4 }, (_, rowIndex) => /* @__PURE__ */ jsxRuntime.jsx(
|
|
2255
2651
|
"div",
|
|
2256
2652
|
{
|
|
2257
2653
|
role: "row",
|
|
2258
2654
|
className: classNames?.gridRow,
|
|
2259
2655
|
style: { display: "grid", gridTemplateColumns: "repeat(3, 1fr)" },
|
|
2260
|
-
children:
|
|
2261
|
-
const
|
|
2656
|
+
children: Array.from({ length: 3 }, (_2, col) => {
|
|
2657
|
+
const i = rowIndex * 3 + col;
|
|
2658
|
+
const year = decadeStart + i;
|
|
2659
|
+
const isSelected = year === valueYear;
|
|
2660
|
+
const isCurrent = year === todayYear;
|
|
2661
|
+
const isFocused = i === focusedIndex;
|
|
2662
|
+
const isDisabled = yearDisabledFlags[i] ?? false;
|
|
2663
|
+
const cls = [
|
|
2262
2664
|
classNames?.year,
|
|
2263
|
-
|
|
2264
|
-
|
|
2665
|
+
isSelected && classNames?.yearSelected,
|
|
2666
|
+
isCurrent && classNames?.yearCurrent,
|
|
2667
|
+
isDisabled && classNames?.yearDisabled
|
|
2265
2668
|
].filter(Boolean).join(" ") || void 0;
|
|
2266
2669
|
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
2267
2670
|
"button",
|
|
2268
2671
|
{
|
|
2269
2672
|
type: "button",
|
|
2270
2673
|
role: "gridcell",
|
|
2271
|
-
|
|
2272
|
-
|
|
2273
|
-
"
|
|
2274
|
-
"
|
|
2275
|
-
|
|
2276
|
-
|
|
2277
|
-
|
|
2674
|
+
tabIndex: isFocused ? 0 : -1,
|
|
2675
|
+
disabled: isDisabled,
|
|
2676
|
+
"aria-selected": isSelected || void 0,
|
|
2677
|
+
"aria-disabled": isDisabled || void 0,
|
|
2678
|
+
"aria-current": isCurrent ? "date" : void 0,
|
|
2679
|
+
"data-selected": isSelected || void 0,
|
|
2680
|
+
"data-current": isCurrent || void 0,
|
|
2681
|
+
"data-focused": isFocused || void 0,
|
|
2682
|
+
className: cls,
|
|
2683
|
+
onClick: () => handleYearSelect(i),
|
|
2684
|
+
children: year
|
|
2278
2685
|
},
|
|
2279
|
-
|
|
2686
|
+
i
|
|
2280
2687
|
);
|
|
2281
2688
|
})
|
|
2282
2689
|
},
|
|
@@ -2504,7 +2911,7 @@ function useRangePicker(options = {}) {
|
|
|
2504
2911
|
adapter
|
|
2505
2912
|
};
|
|
2506
2913
|
}
|
|
2507
|
-
function
|
|
2914
|
+
function getDefaultIso() {
|
|
2508
2915
|
return core.DateFnsAdapter.today();
|
|
2509
2916
|
}
|
|
2510
2917
|
function useTimePicker(options = {}) {
|
|
@@ -2522,7 +2929,7 @@ function useTimePicker(options = {}) {
|
|
|
2522
2929
|
defaultValue ?? null
|
|
2523
2930
|
);
|
|
2524
2931
|
const currentValue = isControlled ? controlledValue ?? null : uncontrolledValue;
|
|
2525
|
-
const baseIso = currentValue ??
|
|
2932
|
+
const baseIso = currentValue ?? getDefaultIso();
|
|
2526
2933
|
const currentTime = react.useMemo(
|
|
2527
2934
|
() => displayTimezone ? core.getTimeInTimezone(baseIso, displayTimezone) : core.getTime(baseIso),
|
|
2528
2935
|
[baseIso, displayTimezone]
|
|
@@ -2546,14 +2953,8 @@ function useTimePicker(options = {}) {
|
|
|
2546
2953
|
},
|
|
2547
2954
|
[format, period, setTime]
|
|
2548
2955
|
);
|
|
2549
|
-
const setMinute = react.useCallback(
|
|
2550
|
-
|
|
2551
|
-
[setTime]
|
|
2552
|
-
);
|
|
2553
|
-
const setSecond = react.useCallback(
|
|
2554
|
-
(second) => setTime({ seconds: second }),
|
|
2555
|
-
[setTime]
|
|
2556
|
-
);
|
|
2956
|
+
const setMinute = react.useCallback((minute) => setTime({ minutes: minute }), [setTime]);
|
|
2957
|
+
const setSecond = react.useCallback((second) => setTime({ seconds: second }), [setTime]);
|
|
2557
2958
|
const setPeriod = react.useCallback(
|
|
2558
2959
|
(newPeriod) => {
|
|
2559
2960
|
if (format !== "12h") return;
|
|
@@ -2579,6 +2980,22 @@ function useTimePicker(options = {}) {
|
|
|
2579
2980
|
};
|
|
2580
2981
|
}
|
|
2581
2982
|
|
|
2983
|
+
Object.defineProperty(exports, "DEFAULT_DATEPICKER_LABELS", {
|
|
2984
|
+
enumerable: true,
|
|
2985
|
+
get: function () { return core.DEFAULT_DATEPICKER_LABELS; }
|
|
2986
|
+
});
|
|
2987
|
+
Object.defineProperty(exports, "DEFAULT_DATETIMEPICKER_LABELS", {
|
|
2988
|
+
enumerable: true,
|
|
2989
|
+
get: function () { return core.DEFAULT_DATETIMEPICKER_LABELS; }
|
|
2990
|
+
});
|
|
2991
|
+
Object.defineProperty(exports, "DEFAULT_RANGEPICKER_LABELS", {
|
|
2992
|
+
enumerable: true,
|
|
2993
|
+
get: function () { return core.DEFAULT_RANGEPICKER_LABELS; }
|
|
2994
|
+
});
|
|
2995
|
+
Object.defineProperty(exports, "DEFAULT_TIMEPICKER_LABELS", {
|
|
2996
|
+
enumerable: true,
|
|
2997
|
+
get: function () { return core.DEFAULT_TIMEPICKER_LABELS; }
|
|
2998
|
+
});
|
|
2582
2999
|
Object.defineProperty(exports, "DateFnsAdapter", {
|
|
2583
3000
|
enumerable: true,
|
|
2584
3001
|
get: function () { return core.DateFnsAdapter; }
|