myoperator-mcp 0.2.328 → 0.2.329
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.js +440 -243
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -2520,13 +2520,6 @@ import { cva, type VariantProps } from "class-variance-authority";
|
|
|
2520
2520
|
import { ChevronLeft, ChevronRight, Clock2, X } from "lucide-react";
|
|
2521
2521
|
|
|
2522
2522
|
import { cn } from "@/lib/utils";
|
|
2523
|
-
import {
|
|
2524
|
-
Select,
|
|
2525
|
-
SelectContent,
|
|
2526
|
-
SelectItem,
|
|
2527
|
-
SelectTrigger,
|
|
2528
|
-
SelectValue,
|
|
2529
|
-
} from "./select";
|
|
2530
2523
|
|
|
2531
2524
|
const DEFAULT_START_TIME = "10:30:00";
|
|
2532
2525
|
const DEFAULT_END_TIME = "12:30:00";
|
|
@@ -2540,14 +2533,8 @@ const POPOVER_WIDTH_VAR = "--date-time-picker-popover-width";
|
|
|
2540
2533
|
const CALENDAR_PLACEMENT: Placement = "bottom-start";
|
|
2541
2534
|
const YEAR_RANGE_BEFORE = 100;
|
|
2542
2535
|
const YEAR_RANGE_AFTER = 10;
|
|
2543
|
-
const
|
|
2544
|
-
"[
|
|
2545
|
-
const CALENDAR_SELECT_TRIGGER_SELECTOR =
|
|
2546
|
-
"[data-date-time-picker-calendar-select-trigger]";
|
|
2547
|
-
const CALENDAR_SELECT_TRIGGER_CLASS = "!w-[90px] !min-w-[90px] !gap-[6px] !px-3";
|
|
2548
|
-
const CALENDAR_SELECT_CONTENT_CLASS =
|
|
2549
|
-
"z-[10060] w-[var(--radix-select-trigger-width)] min-w-[var(--radix-select-trigger-width)] max-h-[min(16rem,var(--radix-select-content-available-height))]";
|
|
2550
|
-
type CalendarSelect = "month" | "year";
|
|
2536
|
+
const CALENDAR_NATIVE_SELECT_CLASS =
|
|
2537
|
+
"h-9 min-w-[90px] rounded-md border border-solid border-semantic-border-input bg-semantic-bg-primary px-3 text-sm text-semantic-text-primary outline-none transition-colors hover:border-semantic-border-input-focus/50 focus:border-semantic-border-input-focus/50 focus:shadow-[0_0_0_1px_rgba(43,188,202,0.15)]";
|
|
2551
2538
|
const DATE_TIME_INPUT_SEGMENT_RANGES = {
|
|
2552
2539
|
day: [0, 2],
|
|
2553
2540
|
month: [3, 5],
|
|
@@ -2570,6 +2557,11 @@ const monthFormatter = new Intl.DateTimeFormat("en-US", {
|
|
|
2570
2557
|
|
|
2571
2558
|
const dateTimePickerVariants = cva("relative inline-block w-full max-w-full", {
|
|
2572
2559
|
variants: {
|
|
2560
|
+
variant: {
|
|
2561
|
+
"date-time": "",
|
|
2562
|
+
"date-only": "",
|
|
2563
|
+
"time-only": "",
|
|
2564
|
+
},
|
|
2573
2565
|
size: {
|
|
2574
2566
|
sm: "sm:w-[280px]",
|
|
2575
2567
|
default: "sm:w-[336px]",
|
|
@@ -2577,6 +2569,7 @@ const dateTimePickerVariants = cva("relative inline-block w-full max-w-full", {
|
|
|
2577
2569
|
},
|
|
2578
2570
|
},
|
|
2579
2571
|
defaultVariants: {
|
|
2572
|
+
variant: "date-time",
|
|
2580
2573
|
size: "default",
|
|
2581
2574
|
},
|
|
2582
2575
|
});
|
|
@@ -2635,6 +2628,10 @@ export interface DateTimePickerProps
|
|
|
2635
2628
|
portalContainer?: HTMLElement | null;
|
|
2636
2629
|
}
|
|
2637
2630
|
|
|
2631
|
+
type DateTimePickerVariant = NonNullable<
|
|
2632
|
+
VariantProps<typeof dateTimePickerVariants>["variant"]
|
|
2633
|
+
>;
|
|
2634
|
+
|
|
2638
2635
|
function normalizeValue(
|
|
2639
2636
|
value?: Partial<DateTimePickerValue>
|
|
2640
2637
|
): DateTimePickerValue {
|
|
@@ -2694,6 +2691,13 @@ function clampMonth(date: Date, minDate?: Date, maxDate?: Date) {
|
|
|
2694
2691
|
return startOfMonth(date);
|
|
2695
2692
|
}
|
|
2696
2693
|
|
|
2694
|
+
function isSelectableDay(date: Date, minDate?: Date, maxDate?: Date) {
|
|
2695
|
+
return (
|
|
2696
|
+
!(minDate && isBeforeDay(date, minDate)) &&
|
|
2697
|
+
!(maxDate && isAfterDay(date, maxDate))
|
|
2698
|
+
);
|
|
2699
|
+
}
|
|
2700
|
+
|
|
2697
2701
|
function getYearOptions(visibleMonth: Date, minDate?: Date, maxDate?: Date) {
|
|
2698
2702
|
const currentYear = new Date().getFullYear();
|
|
2699
2703
|
const selectedYear = visibleMonth.getFullYear();
|
|
@@ -2742,12 +2746,6 @@ function isPointerInsideElement(
|
|
|
2742
2746
|
return false;
|
|
2743
2747
|
}
|
|
2744
2748
|
|
|
2745
|
-
function isPointerInsideSelector(event: MouseEvent, selector: string) {
|
|
2746
|
-
const target = event.target;
|
|
2747
|
-
|
|
2748
|
-
return target instanceof Element && target.closest(selector) !== null;
|
|
2749
|
-
}
|
|
2750
|
-
|
|
2751
2749
|
function formatTimeForDisplay(time: string) {
|
|
2752
2750
|
const [hour = "0", minute = "0"] = time.split(":");
|
|
2753
2751
|
const hourNumber = Number(hour);
|
|
@@ -2768,6 +2766,44 @@ function formatDateForDisplay(date?: Date, time?: string) {
|
|
|
2768
2766
|
return \`\${day}/\${month}/\${year} \${formattedTime}\`;
|
|
2769
2767
|
}
|
|
2770
2768
|
|
|
2769
|
+
function formatDateOnlyForDisplay(date?: Date) {
|
|
2770
|
+
if (!date) return "";
|
|
2771
|
+
|
|
2772
|
+
const month = (date.getMonth() + 1).toString().padStart(2, "0");
|
|
2773
|
+
const day = date.getDate().toString().padStart(2, "0");
|
|
2774
|
+
const year = date.getFullYear();
|
|
2775
|
+
|
|
2776
|
+
return \`\${day}/\${month}/\${year}\`;
|
|
2777
|
+
}
|
|
2778
|
+
|
|
2779
|
+
function formatValueForDisplay(
|
|
2780
|
+
value: DateTimePickerValue,
|
|
2781
|
+
variant: DateTimePickerVariant,
|
|
2782
|
+
showEndTime: boolean,
|
|
2783
|
+
hasTimeValue: boolean
|
|
2784
|
+
) {
|
|
2785
|
+
if (variant === "date-only") {
|
|
2786
|
+
return formatDateOnlyForDisplay(value.date);
|
|
2787
|
+
}
|
|
2788
|
+
|
|
2789
|
+
if (variant === "time-only") {
|
|
2790
|
+
if (!hasTimeValue) return "";
|
|
2791
|
+
|
|
2792
|
+
return showEndTime
|
|
2793
|
+
? \`\${formatTimeForDisplay(value.startTime)} - \${formatTimeForDisplay(value.endTime)}\`
|
|
2794
|
+
: formatTimeForDisplay(value.startTime);
|
|
2795
|
+
}
|
|
2796
|
+
|
|
2797
|
+
return formatDateForDisplay(value.date, value.startTime);
|
|
2798
|
+
}
|
|
2799
|
+
|
|
2800
|
+
function getDefaultPlaceholder(variant: DateTimePickerVariant) {
|
|
2801
|
+
if (variant === "date-only") return "--/--/----";
|
|
2802
|
+
if (variant === "time-only") return "--:-- --";
|
|
2803
|
+
|
|
2804
|
+
return DEFAULT_PLACEHOLDER;
|
|
2805
|
+
}
|
|
2806
|
+
|
|
2771
2807
|
function parseDatePart(datePart: string) {
|
|
2772
2808
|
const isoMatch = datePart.match(/^(\\d{4})-(\\d{1,2})-(\\d{1,2})$/);
|
|
2773
2809
|
const dayFirstMatch = datePart.match(/^(\\d{1,2})[/-](\\d{1,2})[/-](\\d{4})$/);
|
|
@@ -3020,6 +3056,33 @@ function formatTimeInput(restValue: string) {
|
|
|
3020
3056
|
return [timeValue, meridiem].filter(Boolean).join(" ");
|
|
3021
3057
|
}
|
|
3022
3058
|
|
|
3059
|
+
function sanitizeTypedDateInput(value: string, previousValue: string) {
|
|
3060
|
+
const trimmedValue = value.trimStart();
|
|
3061
|
+
if (/^[A-Za-z]/.test(trimmedValue)) return previousValue;
|
|
3062
|
+
|
|
3063
|
+
const normalizedValue = value.toUpperCase().replace(/[^0-9\\s/-]/g, "");
|
|
3064
|
+
const { dateDigits, dateValue, isValid } = splitTypedDateInput(normalizedValue);
|
|
3065
|
+
const limitedDateDigits = dateDigits.slice(0, 8);
|
|
3066
|
+
|
|
3067
|
+
if (!limitedDateDigits) return "";
|
|
3068
|
+
if (!isValid) return previousValue;
|
|
3069
|
+
|
|
3070
|
+
return dateValue;
|
|
3071
|
+
}
|
|
3072
|
+
|
|
3073
|
+
function sanitizeTypedTimeInput(value: string, previousValue: string) {
|
|
3074
|
+
const trimmedValue = value.trimStart();
|
|
3075
|
+
if (/^[A-Za-z]/.test(trimmedValue) && !/^[AP]/i.test(trimmedValue)) {
|
|
3076
|
+
return previousValue;
|
|
3077
|
+
}
|
|
3078
|
+
|
|
3079
|
+
const normalizedValue = value.toUpperCase().replace(/[^0-9\\s:APM]/g, "");
|
|
3080
|
+
const formattedTime = formatTimeInput(normalizedValue);
|
|
3081
|
+
if (formattedTime === null) return previousValue;
|
|
3082
|
+
|
|
3083
|
+
return formattedTime;
|
|
3084
|
+
}
|
|
3085
|
+
|
|
3023
3086
|
function sanitizeTypedDateTimeInput(value: string, previousValue: string) {
|
|
3024
3087
|
const trimmedValue = value.trimStart();
|
|
3025
3088
|
if (/^[A-Za-z]/.test(trimmedValue)) return previousValue;
|
|
@@ -3144,9 +3207,40 @@ function parseTypedDateTime(value: string) {
|
|
|
3144
3207
|
return { date, startTime };
|
|
3145
3208
|
}
|
|
3146
3209
|
|
|
3147
|
-
function
|
|
3210
|
+
function parseTypedDate(value: string) {
|
|
3211
|
+
const typedValue = value.trim();
|
|
3212
|
+
if (!typedValue) return undefined;
|
|
3213
|
+
|
|
3214
|
+
const typedMatch = typedValue.match(
|
|
3215
|
+
/^(\\d{4}-\\d{1,2}-\\d{1,2}|\\d{1,2}[/-]\\d{1,2}[/-]\\d{4})$/
|
|
3216
|
+
);
|
|
3217
|
+
if (!typedMatch) return null;
|
|
3218
|
+
|
|
3219
|
+
return parseDatePart(typedValue);
|
|
3220
|
+
}
|
|
3221
|
+
|
|
3222
|
+
function formatHiddenValue(
|
|
3223
|
+
value: DateTimePickerValue,
|
|
3224
|
+
variant: DateTimePickerVariant,
|
|
3225
|
+
showEndTime: boolean,
|
|
3226
|
+
hasTimeValue: boolean
|
|
3227
|
+
) {
|
|
3228
|
+
if (variant === "time-only") {
|
|
3229
|
+
if (!hasTimeValue) return "";
|
|
3230
|
+
|
|
3231
|
+
return showEndTime ? \`\${value.startTime}/\${value.endTime}\` : value.startTime;
|
|
3232
|
+
}
|
|
3233
|
+
|
|
3148
3234
|
if (!value.date) return "";
|
|
3149
3235
|
|
|
3236
|
+
if (variant === "date-only") {
|
|
3237
|
+
const month = (value.date.getMonth() + 1).toString().padStart(2, "0");
|
|
3238
|
+
const day = value.date.getDate().toString().padStart(2, "0");
|
|
3239
|
+
const year = value.date.getFullYear();
|
|
3240
|
+
|
|
3241
|
+
return \`\${year}-\${month}-\${day}\`;
|
|
3242
|
+
}
|
|
3243
|
+
|
|
3150
3244
|
const month = (value.date.getMonth() + 1).toString().padStart(2, "0");
|
|
3151
3245
|
const day = value.date.getDate().toString().padStart(2, "0");
|
|
3152
3246
|
const year = value.date.getFullYear();
|
|
@@ -3178,12 +3272,13 @@ const DateTimePicker = React.forwardRef<HTMLDivElement, DateTimePickerProps>(
|
|
|
3178
3272
|
(
|
|
3179
3273
|
{
|
|
3180
3274
|
className,
|
|
3275
|
+
variant,
|
|
3181
3276
|
size,
|
|
3182
3277
|
state,
|
|
3183
3278
|
value,
|
|
3184
3279
|
defaultValue,
|
|
3185
3280
|
onValueChange,
|
|
3186
|
-
placeholder
|
|
3281
|
+
placeholder: placeholderProp,
|
|
3187
3282
|
disabled = false,
|
|
3188
3283
|
readOnly = false,
|
|
3189
3284
|
name,
|
|
@@ -3206,15 +3301,26 @@ const DateTimePicker = React.forwardRef<HTMLDivElement, DateTimePickerProps>(
|
|
|
3206
3301
|
) => {
|
|
3207
3302
|
const generatedId = React.useId();
|
|
3208
3303
|
const triggerId = id ?? generatedId;
|
|
3304
|
+
const pickerVariant = variant ?? "date-time";
|
|
3305
|
+
const showCalendar = pickerVariant !== "time-only";
|
|
3306
|
+
const showTimeFields = pickerVariant !== "date-only";
|
|
3307
|
+
const resolvedShowEndTime = showTimeFields && showEndTime;
|
|
3308
|
+
const placeholder = placeholderProp ?? getDefaultPlaceholder(pickerVariant);
|
|
3209
3309
|
const isValueControlled = value !== undefined;
|
|
3210
3310
|
const isOpenControlled = controlledOpen !== undefined;
|
|
3211
3311
|
const [internalValue, setInternalValue] = React.useState(() =>
|
|
3212
3312
|
normalizeValue(defaultValue)
|
|
3213
3313
|
);
|
|
3314
|
+
const [internalHasTimeValue, setInternalHasTimeValue] = React.useState(() =>
|
|
3315
|
+
Boolean(defaultValue?.date || defaultValue?.startTime || defaultValue?.endTime)
|
|
3316
|
+
);
|
|
3214
3317
|
const [internalOpen, setInternalOpen] = React.useState(defaultOpen);
|
|
3215
3318
|
const currentValue = normalizeValue(
|
|
3216
3319
|
isValueControlled ? value : internalValue
|
|
3217
3320
|
);
|
|
3321
|
+
const hasTimeValue = isValueControlled
|
|
3322
|
+
? Boolean(value?.date || value?.startTime || value?.endTime)
|
|
3323
|
+
: internalHasTimeValue;
|
|
3218
3324
|
const open = isOpenControlled ? controlledOpen : internalOpen;
|
|
3219
3325
|
const [visibleMonth, setVisibleMonth] = React.useState(() =>
|
|
3220
3326
|
startOfMonth(currentValue.date ?? new Date())
|
|
@@ -3223,8 +3329,6 @@ const DateTimePicker = React.forwardRef<HTMLDivElement, DateTimePickerProps>(
|
|
|
3223
3329
|
formatDateForDisplay(currentValue.date, currentValue.startTime)
|
|
3224
3330
|
);
|
|
3225
3331
|
const [isDateInputFocused, setIsDateInputFocused] = React.useState(false);
|
|
3226
|
-
const [openCalendarSelect, setOpenCalendarSelect] =
|
|
3227
|
-
React.useState<CalendarSelect | null>(null);
|
|
3228
3332
|
const rootRef = React.useRef<HTMLDivElement | null>(null);
|
|
3229
3333
|
const triggerRef = React.useRef<HTMLDivElement | null>(null);
|
|
3230
3334
|
const popoverRef = React.useRef<HTMLDivElement | null>(null);
|
|
@@ -3270,9 +3374,11 @@ const DateTimePicker = React.forwardRef<HTMLDivElement, DateTimePickerProps>(
|
|
|
3270
3374
|
() => getCalendarDays(visibleMonth),
|
|
3271
3375
|
[visibleMonth]
|
|
3272
3376
|
);
|
|
3273
|
-
const displayValue =
|
|
3274
|
-
currentValue
|
|
3275
|
-
|
|
3377
|
+
const displayValue = formatValueForDisplay(
|
|
3378
|
+
currentValue,
|
|
3379
|
+
pickerVariant,
|
|
3380
|
+
resolvedShowEndTime,
|
|
3381
|
+
hasTimeValue
|
|
3276
3382
|
);
|
|
3277
3383
|
const effectiveMinDate = React.useMemo(() => {
|
|
3278
3384
|
if (!disablePastDates) return minDate;
|
|
@@ -3295,39 +3401,11 @@ const DateTimePicker = React.forwardRef<HTMLDivElement, DateTimePickerProps>(
|
|
|
3295
3401
|
setInternalOpen(nextOpen);
|
|
3296
3402
|
}
|
|
3297
3403
|
|
|
3298
|
-
if (!nextOpen) {
|
|
3299
|
-
setOpenCalendarSelect(null);
|
|
3300
|
-
}
|
|
3301
|
-
|
|
3302
3404
|
onOpenChange?.(nextOpen);
|
|
3303
3405
|
},
|
|
3304
3406
|
[isOpenControlled, onOpenChange]
|
|
3305
3407
|
);
|
|
3306
3408
|
|
|
3307
|
-
const handleCalendarSelectOpenChange = React.useCallback(
|
|
3308
|
-
(select: CalendarSelect, nextOpen: boolean) => {
|
|
3309
|
-
setOpenCalendarSelect((currentSelect) => {
|
|
3310
|
-
if (nextOpen) return select;
|
|
3311
|
-
|
|
3312
|
-
return currentSelect === select ? null : currentSelect;
|
|
3313
|
-
});
|
|
3314
|
-
},
|
|
3315
|
-
[]
|
|
3316
|
-
);
|
|
3317
|
-
|
|
3318
|
-
const handleCalendarSelectTriggerPointerDown = React.useCallback(
|
|
3319
|
-
(
|
|
3320
|
-
select: CalendarSelect,
|
|
3321
|
-
event: React.PointerEvent<HTMLButtonElement>
|
|
3322
|
-
) => {
|
|
3323
|
-
if (openCalendarSelect !== select) return;
|
|
3324
|
-
|
|
3325
|
-
event.preventDefault();
|
|
3326
|
-
setOpenCalendarSelect(null);
|
|
3327
|
-
},
|
|
3328
|
-
[openCalendarSelect]
|
|
3329
|
-
);
|
|
3330
|
-
|
|
3331
3409
|
const setTriggerRef = React.useCallback(
|
|
3332
3410
|
(node: HTMLDivElement | null) => {
|
|
3333
3411
|
triggerRef.current = node;
|
|
@@ -3356,29 +3434,20 @@ const DateTimePicker = React.forwardRef<HTMLDivElement, DateTimePickerProps>(
|
|
|
3356
3434
|
}
|
|
3357
3435
|
}, [displayValue, isDateInputFocused]);
|
|
3358
3436
|
|
|
3359
|
-
React.useEffect(() => {
|
|
3360
|
-
if (!open) {
|
|
3361
|
-
setOpenCalendarSelect(null);
|
|
3362
|
-
}
|
|
3363
|
-
}, [open]);
|
|
3364
|
-
|
|
3365
3437
|
React.useEffect(() => {
|
|
3366
3438
|
if (!open) return;
|
|
3367
3439
|
|
|
3368
3440
|
const handlePointerDown = (event: MouseEvent) => {
|
|
3369
3441
|
if (
|
|
3370
3442
|
!isPointerInsideElement(event, rootRef.current) &&
|
|
3371
|
-
!isPointerInsideElement(event, popoverRef.current)
|
|
3372
|
-
!isPointerInsideSelector(event, CALENDAR_SELECT_CONTENT_SELECTOR)
|
|
3443
|
+
!isPointerInsideElement(event, popoverRef.current)
|
|
3373
3444
|
) {
|
|
3374
|
-
setOpenCalendarSelect(null);
|
|
3375
3445
|
setOpen(false);
|
|
3376
3446
|
}
|
|
3377
3447
|
};
|
|
3378
3448
|
|
|
3379
3449
|
const handleKeyDown = (event: KeyboardEvent) => {
|
|
3380
3450
|
if (event.key === "Escape") {
|
|
3381
|
-
setOpenCalendarSelect(null);
|
|
3382
3451
|
setOpen(false);
|
|
3383
3452
|
}
|
|
3384
3453
|
};
|
|
@@ -3393,9 +3462,15 @@ const DateTimePicker = React.forwardRef<HTMLDivElement, DateTimePickerProps>(
|
|
|
3393
3462
|
}, [open, setOpen]);
|
|
3394
3463
|
|
|
3395
3464
|
const updateValue = React.useCallback(
|
|
3396
|
-
(
|
|
3465
|
+
(
|
|
3466
|
+
nextValue: DateTimePickerValue,
|
|
3467
|
+
options?: { hasTimeValue?: boolean }
|
|
3468
|
+
) => {
|
|
3397
3469
|
if (!isValueControlled) {
|
|
3398
3470
|
setInternalValue(nextValue);
|
|
3471
|
+
if (options?.hasTimeValue !== undefined) {
|
|
3472
|
+
setInternalHasTimeValue(options.hasTimeValue);
|
|
3473
|
+
}
|
|
3399
3474
|
}
|
|
3400
3475
|
|
|
3401
3476
|
onValueChange?.(nextValue);
|
|
@@ -3412,7 +3487,7 @@ const DateTimePicker = React.forwardRef<HTMLDivElement, DateTimePickerProps>(
|
|
|
3412
3487
|
date: undefined,
|
|
3413
3488
|
startTime: currentValue.startTime,
|
|
3414
3489
|
endTime: currentValue.endTime,
|
|
3415
|
-
});
|
|
3490
|
+
}, { hasTimeValue: false });
|
|
3416
3491
|
};
|
|
3417
3492
|
|
|
3418
3493
|
const yearOptions = React.useMemo(
|
|
@@ -3427,9 +3502,129 @@ const DateTimePicker = React.forwardRef<HTMLDivElement, DateTimePickerProps>(
|
|
|
3427
3502
|
[effectiveMinDate, maxDate]
|
|
3428
3503
|
);
|
|
3429
3504
|
|
|
3505
|
+
const syncCalendarMonthAndValue = React.useCallback(
|
|
3506
|
+
(nextMonth: Date) => {
|
|
3507
|
+
const clampedMonth = clampMonth(nextMonth, effectiveMinDate, maxDate);
|
|
3508
|
+
setVisibleMonth(clampedMonth);
|
|
3509
|
+
|
|
3510
|
+
if (pickerVariant === "time-only" || !currentValue.date) return;
|
|
3511
|
+
|
|
3512
|
+
const selectedDay = currentValue.date.getDate();
|
|
3513
|
+
const daysInTargetMonth = getDaysInMonth(
|
|
3514
|
+
clampedMonth.getFullYear(),
|
|
3515
|
+
clampedMonth.getMonth() + 1
|
|
3516
|
+
);
|
|
3517
|
+
|
|
3518
|
+
if (selectedDay > daysInTargetMonth) {
|
|
3519
|
+
const fallbackDate = new Date(
|
|
3520
|
+
clampedMonth.getFullYear(),
|
|
3521
|
+
clampedMonth.getMonth(),
|
|
3522
|
+
1
|
|
3523
|
+
);
|
|
3524
|
+
|
|
3525
|
+
if (!isSelectableDay(fallbackDate, effectiveMinDate, maxDate)) {
|
|
3526
|
+
updateValue({ ...currentValue, date: undefined });
|
|
3527
|
+
return;
|
|
3528
|
+
}
|
|
3529
|
+
|
|
3530
|
+
updateValue({ ...currentValue, date: fallbackDate });
|
|
3531
|
+
return;
|
|
3532
|
+
}
|
|
3533
|
+
|
|
3534
|
+
const nextSelectedDate = new Date(
|
|
3535
|
+
clampedMonth.getFullYear(),
|
|
3536
|
+
clampedMonth.getMonth(),
|
|
3537
|
+
selectedDay
|
|
3538
|
+
);
|
|
3539
|
+
|
|
3540
|
+
if (!isSelectableDay(nextSelectedDate, effectiveMinDate, maxDate)) {
|
|
3541
|
+
updateValue({ ...currentValue, date: undefined });
|
|
3542
|
+
return;
|
|
3543
|
+
}
|
|
3544
|
+
|
|
3545
|
+
if (!isSameDay(currentValue.date, nextSelectedDate)) {
|
|
3546
|
+
updateValue({ ...currentValue, date: nextSelectedDate });
|
|
3547
|
+
}
|
|
3548
|
+
},
|
|
3549
|
+
[
|
|
3550
|
+
currentValue,
|
|
3551
|
+
effectiveMinDate,
|
|
3552
|
+
maxDate,
|
|
3553
|
+
pickerVariant,
|
|
3554
|
+
updateValue,
|
|
3555
|
+
]
|
|
3556
|
+
);
|
|
3557
|
+
|
|
3430
3558
|
const handleTypedDateChange = (
|
|
3431
3559
|
event: React.ChangeEvent<HTMLInputElement>
|
|
3432
3560
|
) => {
|
|
3561
|
+
if (pickerVariant === "time-only") {
|
|
3562
|
+
const nextInputValue = sanitizeTypedTimeInput(
|
|
3563
|
+
event.target.value,
|
|
3564
|
+
dateInputValue
|
|
3565
|
+
);
|
|
3566
|
+
setDateInputValue(nextInputValue);
|
|
3567
|
+
|
|
3568
|
+
if (
|
|
3569
|
+
nextInputValue === dateInputValue &&
|
|
3570
|
+
event.target.value !== dateInputValue
|
|
3571
|
+
) {
|
|
3572
|
+
event.currentTarget.value = nextInputValue;
|
|
3573
|
+
return;
|
|
3574
|
+
}
|
|
3575
|
+
|
|
3576
|
+
const typedTime = parseTimePart(nextInputValue);
|
|
3577
|
+
if (typedTime === undefined) {
|
|
3578
|
+
updateValue({ ...currentValue, date: undefined }, { hasTimeValue: false });
|
|
3579
|
+
return;
|
|
3580
|
+
}
|
|
3581
|
+
|
|
3582
|
+
if (typedTime) {
|
|
3583
|
+
updateValue(
|
|
3584
|
+
{
|
|
3585
|
+
...currentValue,
|
|
3586
|
+
startTime: typedTime,
|
|
3587
|
+
},
|
|
3588
|
+
{ hasTimeValue: true }
|
|
3589
|
+
);
|
|
3590
|
+
}
|
|
3591
|
+
|
|
3592
|
+
return;
|
|
3593
|
+
}
|
|
3594
|
+
|
|
3595
|
+
if (pickerVariant === "date-only") {
|
|
3596
|
+
const nextInputValue = sanitizeTypedDateInput(
|
|
3597
|
+
event.target.value,
|
|
3598
|
+
dateInputValue
|
|
3599
|
+
);
|
|
3600
|
+
setDateInputValue(nextInputValue);
|
|
3601
|
+
|
|
3602
|
+
if (
|
|
3603
|
+
nextInputValue === dateInputValue &&
|
|
3604
|
+
event.target.value !== dateInputValue
|
|
3605
|
+
) {
|
|
3606
|
+
event.currentTarget.value = nextInputValue;
|
|
3607
|
+
return;
|
|
3608
|
+
}
|
|
3609
|
+
|
|
3610
|
+
const typedDate = parseTypedDate(nextInputValue);
|
|
3611
|
+
if (typedDate === undefined) {
|
|
3612
|
+
updateValue({ ...currentValue, date: undefined });
|
|
3613
|
+
return;
|
|
3614
|
+
}
|
|
3615
|
+
|
|
3616
|
+
if (
|
|
3617
|
+
typedDate &&
|
|
3618
|
+
!(effectiveMinDate && isBeforeDay(typedDate, effectiveMinDate)) &&
|
|
3619
|
+
!(maxDate && isAfterDay(typedDate, maxDate))
|
|
3620
|
+
) {
|
|
3621
|
+
updateValue({ ...currentValue, date: typedDate });
|
|
3622
|
+
updateVisibleMonth(typedDate);
|
|
3623
|
+
}
|
|
3624
|
+
|
|
3625
|
+
return;
|
|
3626
|
+
}
|
|
3627
|
+
|
|
3433
3628
|
const nextInputValue = sanitizeTypedDateTimeInput(
|
|
3434
3629
|
event.target.value,
|
|
3435
3630
|
dateInputValue
|
|
@@ -3469,6 +3664,7 @@ const DateTimePicker = React.forwardRef<HTMLDivElement, DateTimePickerProps>(
|
|
|
3469
3664
|
const handleTypedDateKeyDown = (
|
|
3470
3665
|
event: React.KeyboardEvent<HTMLInputElement>
|
|
3471
3666
|
) => {
|
|
3667
|
+
if (pickerVariant === "time-only") return;
|
|
3472
3668
|
if (event.key !== "ArrowUp" && event.key !== "ArrowDown") return;
|
|
3473
3669
|
|
|
3474
3670
|
const direction = event.key === "ArrowUp" ? 1 : -1;
|
|
@@ -3499,12 +3695,19 @@ const DateTimePicker = React.forwardRef<HTMLDivElement, DateTimePickerProps>(
|
|
|
3499
3695
|
);
|
|
3500
3696
|
const [selectionStart, selectionEnd] =
|
|
3501
3697
|
DATE_TIME_INPUT_SEGMENT_RANGES[steppedDateTime.segment];
|
|
3698
|
+
const resolvedInputValue =
|
|
3699
|
+
pickerVariant === "date-only"
|
|
3700
|
+
? formatDateOnlyForDisplay(steppedDateTime.date)
|
|
3701
|
+
: nextInputValue;
|
|
3502
3702
|
|
|
3503
|
-
setDateInputValue(
|
|
3703
|
+
setDateInputValue(resolvedInputValue);
|
|
3504
3704
|
updateValue({
|
|
3505
3705
|
...currentValue,
|
|
3506
3706
|
date: steppedDateTime.date,
|
|
3507
|
-
startTime:
|
|
3707
|
+
startTime:
|
|
3708
|
+
pickerVariant === "date-only"
|
|
3709
|
+
? currentValue.startTime
|
|
3710
|
+
: steppedDateTime.startTime,
|
|
3508
3711
|
});
|
|
3509
3712
|
updateVisibleMonth(steppedDateTime.date);
|
|
3510
3713
|
|
|
@@ -3516,7 +3719,12 @@ const DateTimePicker = React.forwardRef<HTMLDivElement, DateTimePickerProps>(
|
|
|
3516
3719
|
const handleTypedDateBlur = () => {
|
|
3517
3720
|
setIsDateInputFocused(false);
|
|
3518
3721
|
setDateInputValue(
|
|
3519
|
-
|
|
3722
|
+
formatValueForDisplay(
|
|
3723
|
+
currentValue,
|
|
3724
|
+
pickerVariant,
|
|
3725
|
+
resolvedShowEndTime,
|
|
3726
|
+
hasTimeValue
|
|
3727
|
+
)
|
|
3520
3728
|
);
|
|
3521
3729
|
};
|
|
3522
3730
|
|
|
@@ -3530,7 +3738,8 @@ const DateTimePicker = React.forwardRef<HTMLDivElement, DateTimePickerProps>(
|
|
|
3530
3738
|
ref={setPopoverRef}
|
|
3531
3739
|
role="dialog"
|
|
3532
3740
|
aria-modal="false"
|
|
3533
|
-
aria-labelledby={\`\${triggerId}-calendar-heading\`}
|
|
3741
|
+
aria-labelledby={showCalendar ? \`\${triggerId}-calendar-heading\` : undefined}
|
|
3742
|
+
aria-label={showCalendar ? undefined : "Time picker"}
|
|
3534
3743
|
className={cn(
|
|
3535
3744
|
"rounded-lg border border-solid border-semantic-border-layout bg-semantic-bg-primary shadow-lg flex flex-col min-h-0 overflow-y-auto overflow-x-hidden overscroll-contain pointer-events-auto",
|
|
3536
3745
|
"[scrollbar-gutter:stable] [scrollbar-width:thin] [scrollbar-color:var(--semantic-border-secondary)_transparent]",
|
|
@@ -3545,64 +3754,42 @@ const DateTimePicker = React.forwardRef<HTMLDivElement, DateTimePickerProps>(
|
|
|
3545
3754
|
zIndex: 10050,
|
|
3546
3755
|
visibility: isPositioned ? undefined : "hidden",
|
|
3547
3756
|
}}
|
|
3548
|
-
onPointerDown={(event) =>
|
|
3549
|
-
if (
|
|
3550
|
-
event.target instanceof Element &&
|
|
3551
|
-
!event.target.closest(CALENDAR_SELECT_TRIGGER_SELECTOR)
|
|
3552
|
-
) {
|
|
3553
|
-
setOpenCalendarSelect(null);
|
|
3554
|
-
}
|
|
3555
|
-
|
|
3556
|
-
event.stopPropagation();
|
|
3557
|
-
}}
|
|
3757
|
+
onPointerDown={(event) => event.stopPropagation()}
|
|
3558
3758
|
onMouseDown={(event) => event.stopPropagation()}
|
|
3559
3759
|
onWheel={(event) => event.stopPropagation()}
|
|
3560
3760
|
onTouchMove={(event) => event.stopPropagation()}
|
|
3561
3761
|
>
|
|
3562
|
-
|
|
3563
|
-
<div className="
|
|
3564
|
-
<
|
|
3565
|
-
|
|
3566
|
-
|
|
3567
|
-
|
|
3568
|
-
|
|
3569
|
-
|
|
3570
|
-
|
|
3571
|
-
</button>
|
|
3572
|
-
<div className="flex min-w-0 items-center gap-1.5">
|
|
3573
|
-
<label className="sr-only" htmlFor={\`\${triggerId}-month\`}>
|
|
3574
|
-
Month
|
|
3575
|
-
</label>
|
|
3576
|
-
<Select
|
|
3577
|
-
open={openCalendarSelect === "month"}
|
|
3578
|
-
onOpenChange={(nextOpen) =>
|
|
3579
|
-
handleCalendarSelectOpenChange("month", nextOpen)
|
|
3580
|
-
}
|
|
3581
|
-
value={visibleMonth.getMonth().toString()}
|
|
3582
|
-
onValueChange={(nextMonth) =>
|
|
3583
|
-
updateVisibleMonth(
|
|
3584
|
-
new Date(
|
|
3585
|
-
visibleMonth.getFullYear(),
|
|
3586
|
-
Number(nextMonth),
|
|
3587
|
-
1
|
|
3588
|
-
)
|
|
3589
|
-
)
|
|
3762
|
+
{showCalendar && (
|
|
3763
|
+
<div className="p-3 touch-pan-y">
|
|
3764
|
+
<div className="mb-3 flex items-center justify-between gap-2">
|
|
3765
|
+
<button
|
|
3766
|
+
type="button"
|
|
3767
|
+
aria-label="Previous month"
|
|
3768
|
+
className="p-1 rounded hover:bg-semantic-bg-hover text-semantic-text-secondary transition-colors"
|
|
3769
|
+
onClick={() =>
|
|
3770
|
+
syncCalendarMonthAndValue(addMonths(visibleMonth, -1))
|
|
3590
3771
|
}
|
|
3591
3772
|
>
|
|
3592
|
-
<
|
|
3773
|
+
<ChevronLeft className="size-4" aria-hidden="true" />
|
|
3774
|
+
</button>
|
|
3775
|
+
<div className="flex min-w-0 items-center gap-1.5">
|
|
3776
|
+
<label className="sr-only" htmlFor={\`\${triggerId}-month\`}>
|
|
3777
|
+
Month
|
|
3778
|
+
</label>
|
|
3779
|
+
<select
|
|
3593
3780
|
id={\`\${triggerId}-month\`}
|
|
3594
|
-
data-date-time-picker-calendar-select-trigger=""
|
|
3595
3781
|
aria-label="Month"
|
|
3596
|
-
className={
|
|
3597
|
-
|
|
3598
|
-
|
|
3599
|
-
|
|
3600
|
-
|
|
3601
|
-
|
|
3602
|
-
|
|
3603
|
-
|
|
3604
|
-
|
|
3605
|
-
|
|
3782
|
+
className={CALENDAR_NATIVE_SELECT_CLASS}
|
|
3783
|
+
value={visibleMonth.getMonth().toString()}
|
|
3784
|
+
onChange={(event) => {
|
|
3785
|
+
syncCalendarMonthAndValue(
|
|
3786
|
+
new Date(
|
|
3787
|
+
visibleMonth.getFullYear(),
|
|
3788
|
+
Number(event.target.value),
|
|
3789
|
+
1
|
|
3790
|
+
)
|
|
3791
|
+
);
|
|
3792
|
+
}}
|
|
3606
3793
|
>
|
|
3607
3794
|
{monthNames.map((monthName, monthIndex) => {
|
|
3608
3795
|
const optionMonth = new Date(
|
|
@@ -3616,133 +3803,125 @@ const DateTimePicker = React.forwardRef<HTMLDivElement, DateTimePickerProps>(
|
|
|
3616
3803
|
(maxDate && isMonthAfter(optionMonth, maxDate));
|
|
3617
3804
|
|
|
3618
3805
|
return (
|
|
3619
|
-
<
|
|
3806
|
+
<option
|
|
3620
3807
|
key={monthName}
|
|
3621
3808
|
value={monthIndex.toString()}
|
|
3622
3809
|
disabled={!!isDisabled}
|
|
3623
3810
|
>
|
|
3624
3811
|
{monthName}
|
|
3625
|
-
</
|
|
3812
|
+
</option>
|
|
3626
3813
|
);
|
|
3627
3814
|
})}
|
|
3628
|
-
</
|
|
3629
|
-
|
|
3630
|
-
|
|
3631
|
-
|
|
3632
|
-
|
|
3633
|
-
<Select
|
|
3634
|
-
open={openCalendarSelect === "year"}
|
|
3635
|
-
onOpenChange={(nextOpen) =>
|
|
3636
|
-
handleCalendarSelectOpenChange("year", nextOpen)
|
|
3637
|
-
}
|
|
3638
|
-
value={visibleMonth.getFullYear().toString()}
|
|
3639
|
-
onValueChange={(nextYear) =>
|
|
3640
|
-
updateVisibleMonth(
|
|
3641
|
-
new Date(
|
|
3642
|
-
Number(nextYear),
|
|
3643
|
-
visibleMonth.getMonth(),
|
|
3644
|
-
1
|
|
3645
|
-
)
|
|
3646
|
-
)
|
|
3647
|
-
}
|
|
3648
|
-
>
|
|
3649
|
-
<SelectTrigger
|
|
3815
|
+
</select>
|
|
3816
|
+
<label className="sr-only" htmlFor={\`\${triggerId}-year\`}>
|
|
3817
|
+
Year
|
|
3818
|
+
</label>
|
|
3819
|
+
<select
|
|
3650
3820
|
id={\`\${triggerId}-year\`}
|
|
3651
|
-
data-date-time-picker-calendar-select-trigger=""
|
|
3652
3821
|
aria-label="Year"
|
|
3653
|
-
className={
|
|
3654
|
-
|
|
3655
|
-
|
|
3656
|
-
|
|
3657
|
-
|
|
3658
|
-
|
|
3659
|
-
|
|
3660
|
-
|
|
3661
|
-
|
|
3662
|
-
|
|
3822
|
+
className={CALENDAR_NATIVE_SELECT_CLASS}
|
|
3823
|
+
value={visibleMonth.getFullYear().toString()}
|
|
3824
|
+
onChange={(event) => {
|
|
3825
|
+
syncCalendarMonthAndValue(
|
|
3826
|
+
new Date(
|
|
3827
|
+
Number(event.target.value),
|
|
3828
|
+
visibleMonth.getMonth(),
|
|
3829
|
+
1
|
|
3830
|
+
)
|
|
3831
|
+
);
|
|
3832
|
+
}}
|
|
3663
3833
|
>
|
|
3664
3834
|
{yearOptions.map((year) => (
|
|
3665
|
-
<
|
|
3835
|
+
<option key={year} value={year.toString()}>
|
|
3666
3836
|
{year}
|
|
3667
|
-
</
|
|
3837
|
+
</option>
|
|
3668
3838
|
))}
|
|
3669
|
-
</
|
|
3670
|
-
|
|
3671
|
-
|
|
3672
|
-
|
|
3839
|
+
</select>
|
|
3840
|
+
<div id={\`\${triggerId}-calendar-heading\`} className="sr-only">
|
|
3841
|
+
{monthFormatter.format(visibleMonth)}
|
|
3842
|
+
</div>
|
|
3673
3843
|
</div>
|
|
3674
|
-
|
|
3675
|
-
|
|
3676
|
-
|
|
3677
|
-
|
|
3678
|
-
|
|
3679
|
-
|
|
3680
|
-
|
|
3681
|
-
<ChevronRight className="size-4" aria-hidden="true" />
|
|
3682
|
-
</button>
|
|
3683
|
-
</div>
|
|
3684
|
-
|
|
3685
|
-
<div className="grid grid-cols-7">
|
|
3686
|
-
{weekDays.map((day) => (
|
|
3687
|
-
<div
|
|
3688
|
-
key={day}
|
|
3689
|
-
className="flex size-8 items-center justify-center text-xs font-medium text-semantic-text-muted"
|
|
3844
|
+
<button
|
|
3845
|
+
type="button"
|
|
3846
|
+
aria-label="Next month"
|
|
3847
|
+
className="p-1 rounded hover:bg-semantic-bg-hover text-semantic-text-secondary transition-colors"
|
|
3848
|
+
onClick={() =>
|
|
3849
|
+
syncCalendarMonthAndValue(addMonths(visibleMonth, 1))
|
|
3850
|
+
}
|
|
3690
3851
|
>
|
|
3691
|
-
|
|
3692
|
-
</
|
|
3693
|
-
|
|
3694
|
-
{calendarDays.map((day) => {
|
|
3695
|
-
const isCurrentMonth =
|
|
3696
|
-
day.getMonth() === visibleMonth.getMonth();
|
|
3697
|
-
const isSelected = isSameDay(day, currentValue.date);
|
|
3698
|
-
const isToday = isSameDay(day, new Date());
|
|
3699
|
-
const isDisabled =
|
|
3700
|
-
(effectiveMinDate && isBeforeDay(day, effectiveMinDate)) ||
|
|
3701
|
-
(maxDate && isAfterDay(day, maxDate));
|
|
3702
|
-
const dayLabel = day.toLocaleDateString("en-US", {
|
|
3703
|
-
month: "long",
|
|
3704
|
-
day: "numeric",
|
|
3705
|
-
year: "numeric",
|
|
3706
|
-
});
|
|
3707
|
-
|
|
3708
|
-
return (
|
|
3709
|
-
<button
|
|
3710
|
-
key={day.toISOString()}
|
|
3711
|
-
type="button"
|
|
3712
|
-
aria-label={dayLabel}
|
|
3713
|
-
aria-pressed={isSelected}
|
|
3714
|
-
aria-current={isToday ? "date" : undefined}
|
|
3715
|
-
disabled={!!isDisabled}
|
|
3716
|
-
className={cn(
|
|
3717
|
-
"relative flex items-center justify-center size-8 mx-auto rounded-full text-xs transition-colors",
|
|
3718
|
-
isSelected
|
|
3719
|
-
? "bg-semantic-primary text-semantic-text-inverted font-semibold"
|
|
3720
|
-
: isCurrentMonth
|
|
3721
|
-
? "text-semantic-text-primary hover:bg-semantic-bg-hover"
|
|
3722
|
-
: "text-semantic-text-muted hover:bg-semantic-bg-hover",
|
|
3723
|
-
isDisabled &&
|
|
3724
|
-
"opacity-40 cursor-not-allowed pointer-events-none"
|
|
3725
|
-
)}
|
|
3726
|
-
onClick={() => {
|
|
3727
|
-
if (isDisabled) return;
|
|
3852
|
+
<ChevronRight className="size-4" aria-hidden="true" />
|
|
3853
|
+
</button>
|
|
3854
|
+
</div>
|
|
3728
3855
|
|
|
3729
|
-
|
|
3730
|
-
|
|
3731
|
-
|
|
3732
|
-
|
|
3733
|
-
|
|
3856
|
+
<div className="grid grid-cols-7">
|
|
3857
|
+
{weekDays.map((day) => (
|
|
3858
|
+
<div
|
|
3859
|
+
key={day}
|
|
3860
|
+
className="flex size-8 items-center justify-center text-xs font-medium text-semantic-text-muted"
|
|
3734
3861
|
>
|
|
3735
|
-
{day
|
|
3736
|
-
|
|
3737
|
-
|
|
3738
|
-
|
|
3739
|
-
|
|
3740
|
-
|
|
3741
|
-
|
|
3862
|
+
{day}
|
|
3863
|
+
</div>
|
|
3864
|
+
))}
|
|
3865
|
+
{calendarDays.map((day) => {
|
|
3866
|
+
const isCurrentMonth =
|
|
3867
|
+
day.getMonth() === visibleMonth.getMonth();
|
|
3868
|
+
const isSelected = isSameDay(day, currentValue.date);
|
|
3869
|
+
const isToday = isSameDay(day, new Date());
|
|
3870
|
+
const isDisabled =
|
|
3871
|
+
(effectiveMinDate && isBeforeDay(day, effectiveMinDate)) ||
|
|
3872
|
+
(maxDate && isAfterDay(day, maxDate));
|
|
3873
|
+
const dayLabel = day.toLocaleDateString("en-US", {
|
|
3874
|
+
month: "long",
|
|
3875
|
+
day: "numeric",
|
|
3876
|
+
year: "numeric",
|
|
3877
|
+
});
|
|
3878
|
+
|
|
3879
|
+
return (
|
|
3880
|
+
<button
|
|
3881
|
+
key={day.toISOString()}
|
|
3882
|
+
type="button"
|
|
3883
|
+
aria-label={dayLabel}
|
|
3884
|
+
aria-pressed={isSelected}
|
|
3885
|
+
aria-current={isToday ? "date" : undefined}
|
|
3886
|
+
disabled={!!isDisabled}
|
|
3887
|
+
className={cn(
|
|
3888
|
+
"relative flex items-center justify-center size-8 mx-auto rounded-full text-xs transition-colors",
|
|
3889
|
+
isSelected
|
|
3890
|
+
? "bg-semantic-primary text-semantic-text-inverted font-semibold"
|
|
3891
|
+
: isCurrentMonth
|
|
3892
|
+
? "text-semantic-text-primary hover:bg-semantic-bg-hover"
|
|
3893
|
+
: "text-semantic-text-muted hover:bg-semantic-bg-hover",
|
|
3894
|
+
isDisabled &&
|
|
3895
|
+
"opacity-40 cursor-not-allowed pointer-events-none"
|
|
3896
|
+
)}
|
|
3897
|
+
onClick={() => {
|
|
3898
|
+
if (isDisabled) return;
|
|
3899
|
+
|
|
3900
|
+
updateValue({ ...currentValue, date: day });
|
|
3901
|
+
if (closeOnSelect) {
|
|
3902
|
+
setOpen(false);
|
|
3903
|
+
}
|
|
3904
|
+
}}
|
|
3905
|
+
>
|
|
3906
|
+
{day.getDate()}
|
|
3907
|
+
{isToday && !isSelected && (
|
|
3908
|
+
<span className="absolute bottom-0.5 left-1/2 -translate-x-1/2 size-1 rounded-full bg-semantic-primary" />
|
|
3909
|
+
)}
|
|
3910
|
+
</button>
|
|
3911
|
+
);
|
|
3912
|
+
})}
|
|
3913
|
+
</div>
|
|
3742
3914
|
</div>
|
|
3743
|
-
|
|
3915
|
+
)}
|
|
3744
3916
|
|
|
3745
|
-
|
|
3917
|
+
{showTimeFields && (
|
|
3918
|
+
<div
|
|
3919
|
+
className={cn(
|
|
3920
|
+
"space-y-3 bg-semantic-bg-primary p-3",
|
|
3921
|
+
showCalendar &&
|
|
3922
|
+
"border-t border-solid border-semantic-border-layout"
|
|
3923
|
+
)}
|
|
3924
|
+
>
|
|
3746
3925
|
<div className="flex flex-col gap-1.5">
|
|
3747
3926
|
<label
|
|
3748
3927
|
htmlFor={\`\${triggerId}-start-time\`}
|
|
@@ -3762,16 +3941,19 @@ const DateTimePicker = React.forwardRef<HTMLDivElement, DateTimePickerProps>(
|
|
|
3762
3941
|
value={currentValue.startTime}
|
|
3763
3942
|
className="h-8 w-full rounded-md border border-solid border-semantic-border-input bg-semantic-bg-primary pl-9 pr-3 text-sm text-semantic-text-primary outline-none transition-colors hover:border-semantic-border-input-focus/50 focus:border-semantic-border-input-focus/50 focus:shadow-[0_0_0_1px_rgba(43,188,202,0.15)]"
|
|
3764
3943
|
onChange={(event) =>
|
|
3765
|
-
updateValue(
|
|
3766
|
-
|
|
3767
|
-
|
|
3768
|
-
|
|
3944
|
+
updateValue(
|
|
3945
|
+
{
|
|
3946
|
+
...currentValue,
|
|
3947
|
+
startTime: event.target.value,
|
|
3948
|
+
},
|
|
3949
|
+
{ hasTimeValue: true }
|
|
3950
|
+
)
|
|
3769
3951
|
}
|
|
3770
3952
|
/>
|
|
3771
3953
|
</div>
|
|
3772
3954
|
</div>
|
|
3773
3955
|
|
|
3774
|
-
{
|
|
3956
|
+
{resolvedShowEndTime && (
|
|
3775
3957
|
<div className="flex flex-col gap-1.5">
|
|
3776
3958
|
<label
|
|
3777
3959
|
htmlFor={\`\${triggerId}-end-time\`}
|
|
@@ -3791,16 +3973,20 @@ const DateTimePicker = React.forwardRef<HTMLDivElement, DateTimePickerProps>(
|
|
|
3791
3973
|
value={currentValue.endTime}
|
|
3792
3974
|
className="h-8 w-full rounded-md border border-solid border-semantic-border-input bg-semantic-bg-primary pl-9 pr-3 text-sm text-semantic-text-primary outline-none transition-colors hover:border-semantic-border-input-focus/50 focus:border-semantic-border-input-focus/50 focus:shadow-[0_0_0_1px_rgba(43,188,202,0.15)]"
|
|
3793
3975
|
onChange={(event) =>
|
|
3794
|
-
updateValue(
|
|
3795
|
-
|
|
3796
|
-
|
|
3797
|
-
|
|
3976
|
+
updateValue(
|
|
3977
|
+
{
|
|
3978
|
+
...currentValue,
|
|
3979
|
+
endTime: event.target.value,
|
|
3980
|
+
},
|
|
3981
|
+
{ hasTimeValue: true }
|
|
3982
|
+
)
|
|
3798
3983
|
}
|
|
3799
3984
|
/>
|
|
3800
3985
|
</div>
|
|
3801
3986
|
</div>
|
|
3802
3987
|
)}
|
|
3803
|
-
|
|
3988
|
+
</div>
|
|
3989
|
+
)}
|
|
3804
3990
|
</div>,
|
|
3805
3991
|
portalMount
|
|
3806
3992
|
);
|
|
@@ -3824,7 +4010,12 @@ const DateTimePicker = React.forwardRef<HTMLDivElement, DateTimePickerProps>(
|
|
|
3824
4010
|
<input
|
|
3825
4011
|
type="hidden"
|
|
3826
4012
|
name={name}
|
|
3827
|
-
value={formatHiddenValue(
|
|
4013
|
+
value={formatHiddenValue(
|
|
4014
|
+
currentValue,
|
|
4015
|
+
pickerVariant,
|
|
4016
|
+
resolvedShowEndTime,
|
|
4017
|
+
hasTimeValue
|
|
4018
|
+
)}
|
|
3828
4019
|
/>
|
|
3829
4020
|
)}
|
|
3830
4021
|
<div
|
|
@@ -3846,7 +4037,13 @@ const DateTimePicker = React.forwardRef<HTMLDivElement, DateTimePickerProps>(
|
|
|
3846
4037
|
placeholder={placeholder}
|
|
3847
4038
|
aria-haspopup="dialog"
|
|
3848
4039
|
aria-expanded={open}
|
|
3849
|
-
aria-label=
|
|
4040
|
+
aria-label={
|
|
4041
|
+
pickerVariant === "date-only"
|
|
4042
|
+
? "Date"
|
|
4043
|
+
: pickerVariant === "time-only"
|
|
4044
|
+
? "Time"
|
|
4045
|
+
: "Date and time"
|
|
4046
|
+
}
|
|
3850
4047
|
className="min-w-0 flex-1 bg-transparent text-sm text-semantic-text-primary outline-none placeholder:text-semantic-text-placeholder disabled:cursor-not-allowed read-only:cursor-not-allowed"
|
|
3851
4048
|
onFocus={() => {
|
|
3852
4049
|
setIsDateInputFocused(true);
|
|
@@ -3870,7 +4067,7 @@ const DateTimePicker = React.forwardRef<HTMLDivElement, DateTimePickerProps>(
|
|
|
3870
4067
|
<button
|
|
3871
4068
|
type="button"
|
|
3872
4069
|
disabled={disabled || readOnly}
|
|
3873
|
-
aria-label="Open calendar"
|
|
4070
|
+
aria-label={showCalendar ? "Open calendar" : "Open time picker"}
|
|
3874
4071
|
className="inline-flex shrink-0 items-center justify-center rounded text-semantic-text-muted hover:bg-semantic-bg-hover hover:text-semantic-text-primary disabled:cursor-not-allowed"
|
|
3875
4072
|
onClick={() => setOpen(!open)}
|
|
3876
4073
|
>
|
package/package.json
CHANGED