myoperator-mcp 0.2.321 → 0.2.322
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 +458 -50
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -2520,6 +2520,13 @@ 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";
|
|
2523
2530
|
|
|
2524
2531
|
const DEFAULT_START_TIME = "10:30:00";
|
|
2525
2532
|
const DEFAULT_END_TIME = "12:30:00";
|
|
@@ -2533,6 +2540,19 @@ const POPOVER_WIDTH_VAR = "--date-time-picker-popover-width";
|
|
|
2533
2540
|
const CALENDAR_PLACEMENT: Placement = "bottom-start";
|
|
2534
2541
|
const YEAR_RANGE_BEFORE = 100;
|
|
2535
2542
|
const YEAR_RANGE_AFTER = 10;
|
|
2543
|
+
const CALENDAR_SELECT_CONTENT_SELECTOR =
|
|
2544
|
+
"[data-date-time-picker-calendar-select]";
|
|
2545
|
+
const CALENDAR_SELECT_TRIGGER_CLASS = "!w-[90px] !gap-[6px]";
|
|
2546
|
+
const CALENDAR_SELECT_CONTENT_CLASS =
|
|
2547
|
+
"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))]";
|
|
2548
|
+
const DATE_TIME_INPUT_SEGMENT_RANGES = {
|
|
2549
|
+
day: [0, 2],
|
|
2550
|
+
month: [3, 5],
|
|
2551
|
+
year: [6, 10],
|
|
2552
|
+
hour: [11, 13],
|
|
2553
|
+
minute: [14, 16],
|
|
2554
|
+
meridiem: [17, 19],
|
|
2555
|
+
} as const;
|
|
2536
2556
|
|
|
2537
2557
|
const weekDays = ["Su", "Mo", "Tu", "We", "Th", "Fr", "Sa"];
|
|
2538
2558
|
const monthNames = Array.from({ length: 12 }, (_, monthIndex) =>
|
|
@@ -2719,6 +2739,12 @@ function isPointerInsideElement(
|
|
|
2719
2739
|
return false;
|
|
2720
2740
|
}
|
|
2721
2741
|
|
|
2742
|
+
function isPointerInsideSelector(event: MouseEvent, selector: string) {
|
|
2743
|
+
const target = event.target;
|
|
2744
|
+
|
|
2745
|
+
return target instanceof Element && target.closest(selector) !== null;
|
|
2746
|
+
}
|
|
2747
|
+
|
|
2722
2748
|
function formatTimeForDisplay(time: string) {
|
|
2723
2749
|
const [hour = "0", minute = "0"] = time.split(":");
|
|
2724
2750
|
const hourNumber = Number(hour);
|
|
@@ -2796,6 +2822,307 @@ function parseTimePart(timePart?: string) {
|
|
|
2796
2822
|
return \`\${hour.toString().padStart(2, "0")}:\${minuteValue}:\${secondValue}\`;
|
|
2797
2823
|
}
|
|
2798
2824
|
|
|
2825
|
+
function getDaysInMonth(year: number, month: number) {
|
|
2826
|
+
return new Date(year, month, 0).getDate();
|
|
2827
|
+
}
|
|
2828
|
+
|
|
2829
|
+
function getPotentialMaxDay(month: number, year?: number) {
|
|
2830
|
+
if (month === 2 && year === undefined) return 29;
|
|
2831
|
+
if (month === 2) return getDaysInMonth(year ?? 2000, month);
|
|
2832
|
+
if ([4, 6, 9, 11].includes(month)) return 30;
|
|
2833
|
+
|
|
2834
|
+
return 31;
|
|
2835
|
+
}
|
|
2836
|
+
|
|
2837
|
+
function isPotentiallyValidDateParts(
|
|
2838
|
+
dayValue: string,
|
|
2839
|
+
monthValue: string,
|
|
2840
|
+
yearValue: string
|
|
2841
|
+
) {
|
|
2842
|
+
const day = Number(dayValue);
|
|
2843
|
+
const month = Number(monthValue);
|
|
2844
|
+
const year = Number(yearValue);
|
|
2845
|
+
|
|
2846
|
+
if (dayValue.length === 1 && day > 3) return false;
|
|
2847
|
+
if (dayValue.length === 2 && (day < 1 || day > 31)) return false;
|
|
2848
|
+
if (monthValue.length === 1 && month > 1) return false;
|
|
2849
|
+
if (monthValue.length === 2 && (month < 1 || month > 12)) return false;
|
|
2850
|
+
if (yearValue.length === 4 && year < 1000) return false;
|
|
2851
|
+
|
|
2852
|
+
if (dayValue.length === 2 && monthValue.length === 2) {
|
|
2853
|
+
const maxDay = getPotentialMaxDay(
|
|
2854
|
+
month,
|
|
2855
|
+
yearValue.length === 4 ? year : undefined
|
|
2856
|
+
);
|
|
2857
|
+
if (day > maxDay) return false;
|
|
2858
|
+
}
|
|
2859
|
+
|
|
2860
|
+
return true;
|
|
2861
|
+
}
|
|
2862
|
+
|
|
2863
|
+
function isPotentiallyValidDateDigits(dateDigits: string) {
|
|
2864
|
+
return isPotentiallyValidDateParts(
|
|
2865
|
+
dateDigits.slice(0, 2),
|
|
2866
|
+
dateDigits.slice(2, 4),
|
|
2867
|
+
dateDigits.slice(4, 8)
|
|
2868
|
+
);
|
|
2869
|
+
}
|
|
2870
|
+
|
|
2871
|
+
function formatDateDigits(dateDigits: string) {
|
|
2872
|
+
const day = dateDigits.slice(0, 2);
|
|
2873
|
+
const month = dateDigits.slice(2, 4);
|
|
2874
|
+
const year = dateDigits.slice(4, 8);
|
|
2875
|
+
|
|
2876
|
+
if (dateDigits.length <= 2) {
|
|
2877
|
+
return dateDigits.length === 2 ? \`\${day}/\` : day;
|
|
2878
|
+
}
|
|
2879
|
+
|
|
2880
|
+
if (dateDigits.length <= 4) {
|
|
2881
|
+
return \`\${day}/\${dateDigits.length === 4 ? \`\${month}/\` : month}\`;
|
|
2882
|
+
}
|
|
2883
|
+
|
|
2884
|
+
return \`\${day}/\${month}/\${year}\`;
|
|
2885
|
+
}
|
|
2886
|
+
|
|
2887
|
+
function formatSegmentedDateInput(
|
|
2888
|
+
dateSource: string,
|
|
2889
|
+
day: string,
|
|
2890
|
+
month: string,
|
|
2891
|
+
year: string
|
|
2892
|
+
) {
|
|
2893
|
+
const separatorCount = dateSource.match(/[/-]/g)?.length ?? 0;
|
|
2894
|
+
const shouldShowMonth = separatorCount >= 1 || !!month || !!year;
|
|
2895
|
+
const shouldShowYear = separatorCount >= 2 || !!year;
|
|
2896
|
+
|
|
2897
|
+
return [
|
|
2898
|
+
day,
|
|
2899
|
+
shouldShowMonth ? month : undefined,
|
|
2900
|
+
shouldShowYear ? year : undefined,
|
|
2901
|
+
]
|
|
2902
|
+
.filter((part): part is string => part !== undefined)
|
|
2903
|
+
.join("/");
|
|
2904
|
+
}
|
|
2905
|
+
|
|
2906
|
+
function consumeDigits(source: string, maxLength: number) {
|
|
2907
|
+
let digits = "";
|
|
2908
|
+
let endIndex = source.length;
|
|
2909
|
+
|
|
2910
|
+
for (let index = 0; index < source.length; index += 1) {
|
|
2911
|
+
if (!/\\d/.test(source[index])) continue;
|
|
2912
|
+
|
|
2913
|
+
digits += source[index];
|
|
2914
|
+
if (digits.length === maxLength) {
|
|
2915
|
+
endIndex = index + 1;
|
|
2916
|
+
break;
|
|
2917
|
+
}
|
|
2918
|
+
}
|
|
2919
|
+
|
|
2920
|
+
return {
|
|
2921
|
+
digits,
|
|
2922
|
+
rest: source.slice(endIndex),
|
|
2923
|
+
};
|
|
2924
|
+
}
|
|
2925
|
+
|
|
2926
|
+
function splitTypedDateInput(value: string) {
|
|
2927
|
+
const firstSpaceIndex = value.search(/\\s/);
|
|
2928
|
+
const dateSource =
|
|
2929
|
+
firstSpaceIndex === -1 ? value : value.slice(0, firstSpaceIndex);
|
|
2930
|
+
const restValue =
|
|
2931
|
+
firstSpaceIndex === -1 ? "" : value.slice(firstSpaceIndex + 1);
|
|
2932
|
+
|
|
2933
|
+
if (/[/-]/.test(dateSource)) {
|
|
2934
|
+
const [dayPart = "", monthPart = "", yearPart = ""] =
|
|
2935
|
+
dateSource.split(/[/-]/);
|
|
2936
|
+
const dayResult = consumeDigits(dayPart, 2);
|
|
2937
|
+
const monthResult = consumeDigits(\`\${dayResult.rest}\${monthPart}\`, 2);
|
|
2938
|
+
const yearResult = consumeDigits(
|
|
2939
|
+
\`\${monthResult.rest}\${yearPart}\`,
|
|
2940
|
+
4
|
|
2941
|
+
);
|
|
2942
|
+
const day = dayResult.digits;
|
|
2943
|
+
const month = monthResult.digits;
|
|
2944
|
+
const year = yearResult.digits;
|
|
2945
|
+
|
|
2946
|
+
return {
|
|
2947
|
+
dateDigits: \`\${day}\${month}\${year}\`,
|
|
2948
|
+
dateValue: formatSegmentedDateInput(dateSource, day, month, year),
|
|
2949
|
+
isComplete: !!day && !!month && year.length === 4,
|
|
2950
|
+
isValid: isPotentiallyValidDateParts(day, month, year),
|
|
2951
|
+
restValue: [yearResult.rest, restValue].filter(Boolean).join(" "),
|
|
2952
|
+
};
|
|
2953
|
+
}
|
|
2954
|
+
|
|
2955
|
+
let dateDigits = "";
|
|
2956
|
+
let dateEndIndex = value.length;
|
|
2957
|
+
|
|
2958
|
+
for (let index = 0; index < value.length; index += 1) {
|
|
2959
|
+
const character = value[index];
|
|
2960
|
+
|
|
2961
|
+
if (/\\d/.test(character)) {
|
|
2962
|
+
dateDigits += character;
|
|
2963
|
+
if (dateDigits.length === 8) {
|
|
2964
|
+
dateEndIndex = index + 1;
|
|
2965
|
+
break;
|
|
2966
|
+
}
|
|
2967
|
+
}
|
|
2968
|
+
}
|
|
2969
|
+
|
|
2970
|
+
return {
|
|
2971
|
+
dateDigits,
|
|
2972
|
+
dateValue: formatDateDigits(dateDigits),
|
|
2973
|
+
isComplete: dateDigits.length === 8,
|
|
2974
|
+
isValid: isPotentiallyValidDateDigits(dateDigits),
|
|
2975
|
+
restValue: value.slice(dateEndIndex),
|
|
2976
|
+
};
|
|
2977
|
+
}
|
|
2978
|
+
|
|
2979
|
+
function isPotentiallyValidTimeDigits(timeDigits: string) {
|
|
2980
|
+
const hourValue = timeDigits.slice(0, 2);
|
|
2981
|
+
const minuteValue = timeDigits.slice(2, 4);
|
|
2982
|
+
const hour = Number(hourValue);
|
|
2983
|
+
const minute = Number(minuteValue);
|
|
2984
|
+
|
|
2985
|
+
if (hourValue.length === 1 && hour > 1) return false;
|
|
2986
|
+
if (hourValue.length === 2 && (hour < 1 || hour > 12)) return false;
|
|
2987
|
+
if (minuteValue.length === 1 && minute > 5) return false;
|
|
2988
|
+
if (minuteValue.length === 2 && minute > 59) return false;
|
|
2989
|
+
|
|
2990
|
+
return true;
|
|
2991
|
+
}
|
|
2992
|
+
|
|
2993
|
+
function formatMeridiemInput(letters: string) {
|
|
2994
|
+
if (!letters) return "";
|
|
2995
|
+
if ("AM".startsWith(letters)) return letters;
|
|
2996
|
+
if ("PM".startsWith(letters)) return letters;
|
|
2997
|
+
|
|
2998
|
+
return null;
|
|
2999
|
+
}
|
|
3000
|
+
|
|
3001
|
+
function formatTimeInput(restValue: string) {
|
|
3002
|
+
const normalizedValue = restValue.toUpperCase();
|
|
3003
|
+
const timeDigits = normalizedValue.replace(/\\D/g, "").slice(0, 4);
|
|
3004
|
+
const meridiemLetters = normalizedValue.replace(/[^A-Z]/g, "");
|
|
3005
|
+
const meridiem = formatMeridiemInput(meridiemLetters.slice(0, 2));
|
|
3006
|
+
|
|
3007
|
+
if (!timeDigits && !meridiem) return "";
|
|
3008
|
+
if (!isPotentiallyValidTimeDigits(timeDigits) || meridiem === null) {
|
|
3009
|
+
return null;
|
|
3010
|
+
}
|
|
3011
|
+
|
|
3012
|
+
const timeValue =
|
|
3013
|
+
timeDigits.length <= 2
|
|
3014
|
+
? timeDigits
|
|
3015
|
+
: \`\${timeDigits.slice(0, 2)}:\${timeDigits.slice(2, 4)}\`;
|
|
3016
|
+
|
|
3017
|
+
return [timeValue, meridiem].filter(Boolean).join(" ");
|
|
3018
|
+
}
|
|
3019
|
+
|
|
3020
|
+
function sanitizeTypedDateTimeInput(value: string, previousValue: string) {
|
|
3021
|
+
const trimmedValue = value.trimStart();
|
|
3022
|
+
if (/^[A-Za-z]/.test(trimmedValue)) return previousValue;
|
|
3023
|
+
|
|
3024
|
+
const normalizedValue = value
|
|
3025
|
+
.toUpperCase()
|
|
3026
|
+
.replace(/[^0-9\\s/:APM-]/g, "");
|
|
3027
|
+
const { dateDigits, dateValue, isComplete, isValid, restValue } =
|
|
3028
|
+
splitTypedDateInput(normalizedValue);
|
|
3029
|
+
const limitedDateDigits = dateDigits.slice(0, 8);
|
|
3030
|
+
|
|
3031
|
+
if (!limitedDateDigits) return "";
|
|
3032
|
+
if (!isValid) return previousValue;
|
|
3033
|
+
|
|
3034
|
+
const formattedTime = isComplete ? formatTimeInput(restValue) : "";
|
|
3035
|
+
if (formattedTime === null) return previousValue;
|
|
3036
|
+
|
|
3037
|
+
return [dateValue, formattedTime].filter(Boolean).join(" ");
|
|
3038
|
+
}
|
|
3039
|
+
|
|
3040
|
+
type DateTimeInputSegment = keyof typeof DATE_TIME_INPUT_SEGMENT_RANGES;
|
|
3041
|
+
|
|
3042
|
+
function getDateTimeInputSegment(cursorPosition: number): DateTimeInputSegment {
|
|
3043
|
+
if (cursorPosition <= DATE_TIME_INPUT_SEGMENT_RANGES.day[1]) return "day";
|
|
3044
|
+
if (cursorPosition <= DATE_TIME_INPUT_SEGMENT_RANGES.month[1]) return "month";
|
|
3045
|
+
if (cursorPosition <= DATE_TIME_INPUT_SEGMENT_RANGES.year[1]) return "year";
|
|
3046
|
+
if (cursorPosition <= DATE_TIME_INPUT_SEGMENT_RANGES.hour[1]) return "hour";
|
|
3047
|
+
if (cursorPosition <= DATE_TIME_INPUT_SEGMENT_RANGES.minute[1]) {
|
|
3048
|
+
return "minute";
|
|
3049
|
+
}
|
|
3050
|
+
|
|
3051
|
+
return "meridiem";
|
|
3052
|
+
}
|
|
3053
|
+
|
|
3054
|
+
function clampDateToMonth(year: number, month: number, day: number) {
|
|
3055
|
+
return new Date(year, month, Math.min(day, getDaysInMonth(year, month + 1)));
|
|
3056
|
+
}
|
|
3057
|
+
|
|
3058
|
+
function stepDateTimeInputValue(
|
|
3059
|
+
value: string,
|
|
3060
|
+
cursorPosition: number,
|
|
3061
|
+
direction: 1 | -1,
|
|
3062
|
+
fallbackTime: string
|
|
3063
|
+
) {
|
|
3064
|
+
const typedDateTime = parseTypedDateTime(value);
|
|
3065
|
+
if (!typedDateTime) return null;
|
|
3066
|
+
|
|
3067
|
+
const segment = getDateTimeInputSegment(cursorPosition);
|
|
3068
|
+
const nextDate = new Date(typedDateTime.date);
|
|
3069
|
+
const [hourValue = "0", minuteValue = "0", secondValue = "00"] = (
|
|
3070
|
+
typedDateTime.startTime ?? fallbackTime
|
|
3071
|
+
).split(":");
|
|
3072
|
+
nextDate.setHours(Number(hourValue), Number(minuteValue), Number(secondValue));
|
|
3073
|
+
|
|
3074
|
+
if (segment === "day") {
|
|
3075
|
+
nextDate.setDate(nextDate.getDate() + direction);
|
|
3076
|
+
} else if (segment === "month") {
|
|
3077
|
+
const day = nextDate.getDate();
|
|
3078
|
+
const steppedMonth = clampDateToMonth(
|
|
3079
|
+
nextDate.getFullYear(),
|
|
3080
|
+
nextDate.getMonth() + direction,
|
|
3081
|
+
day
|
|
3082
|
+
);
|
|
3083
|
+
nextDate.setFullYear(
|
|
3084
|
+
steppedMonth.getFullYear(),
|
|
3085
|
+
steppedMonth.getMonth(),
|
|
3086
|
+
steppedMonth.getDate()
|
|
3087
|
+
);
|
|
3088
|
+
} else if (segment === "year") {
|
|
3089
|
+
const day = nextDate.getDate();
|
|
3090
|
+
const steppedYear = clampDateToMonth(
|
|
3091
|
+
nextDate.getFullYear() + direction,
|
|
3092
|
+
nextDate.getMonth(),
|
|
3093
|
+
day
|
|
3094
|
+
);
|
|
3095
|
+
nextDate.setFullYear(
|
|
3096
|
+
steppedYear.getFullYear(),
|
|
3097
|
+
steppedYear.getMonth(),
|
|
3098
|
+
steppedYear.getDate()
|
|
3099
|
+
);
|
|
3100
|
+
} else if (segment === "hour") {
|
|
3101
|
+
nextDate.setHours(nextDate.getHours() + direction);
|
|
3102
|
+
} else if (segment === "minute") {
|
|
3103
|
+
nextDate.setMinutes(nextDate.getMinutes() + direction);
|
|
3104
|
+
} else {
|
|
3105
|
+
nextDate.setHours(nextDate.getHours() + 12 * direction);
|
|
3106
|
+
}
|
|
3107
|
+
|
|
3108
|
+
const startTime = \`\${nextDate
|
|
3109
|
+
.getHours()
|
|
3110
|
+
.toString()
|
|
3111
|
+
.padStart(2, "0")}:\${nextDate
|
|
3112
|
+
.getMinutes()
|
|
3113
|
+
.toString()
|
|
3114
|
+
.padStart(2, "0")}:\${nextDate
|
|
3115
|
+
.getSeconds()
|
|
3116
|
+
.toString()
|
|
3117
|
+
.padStart(2, "0")}\`;
|
|
3118
|
+
|
|
3119
|
+
return {
|
|
3120
|
+
date: startOfDay(nextDate),
|
|
3121
|
+
startTime,
|
|
3122
|
+
segment,
|
|
3123
|
+
};
|
|
3124
|
+
}
|
|
3125
|
+
|
|
2799
3126
|
function parseTypedDateTime(value: string) {
|
|
2800
3127
|
const typedValue = value.trim();
|
|
2801
3128
|
if (!typedValue) return undefined;
|
|
@@ -3002,7 +3329,8 @@ const DateTimePicker = React.forwardRef<HTMLDivElement, DateTimePickerProps>(
|
|
|
3002
3329
|
const handlePointerDown = (event: MouseEvent) => {
|
|
3003
3330
|
if (
|
|
3004
3331
|
!isPointerInsideElement(event, rootRef.current) &&
|
|
3005
|
-
!isPointerInsideElement(event, popoverRef.current)
|
|
3332
|
+
!isPointerInsideElement(event, popoverRef.current) &&
|
|
3333
|
+
!isPointerInsideSelector(event, CALENDAR_SELECT_CONTENT_SELECTOR)
|
|
3006
3334
|
) {
|
|
3007
3335
|
setOpen(false);
|
|
3008
3336
|
}
|
|
@@ -3061,9 +3389,20 @@ const DateTimePicker = React.forwardRef<HTMLDivElement, DateTimePickerProps>(
|
|
|
3061
3389
|
const handleTypedDateChange = (
|
|
3062
3390
|
event: React.ChangeEvent<HTMLInputElement>
|
|
3063
3391
|
) => {
|
|
3064
|
-
const nextInputValue =
|
|
3392
|
+
const nextInputValue = sanitizeTypedDateTimeInput(
|
|
3393
|
+
event.target.value,
|
|
3394
|
+
dateInputValue
|
|
3395
|
+
);
|
|
3065
3396
|
setDateInputValue(nextInputValue);
|
|
3066
3397
|
|
|
3398
|
+
if (
|
|
3399
|
+
nextInputValue === dateInputValue &&
|
|
3400
|
+
event.target.value !== dateInputValue
|
|
3401
|
+
) {
|
|
3402
|
+
event.currentTarget.value = nextInputValue;
|
|
3403
|
+
return;
|
|
3404
|
+
}
|
|
3405
|
+
|
|
3067
3406
|
const typedDateTime = parseTypedDateTime(nextInputValue);
|
|
3068
3407
|
if (typedDateTime === undefined) {
|
|
3069
3408
|
updateValue({ ...currentValue, date: undefined });
|
|
@@ -3086,6 +3425,53 @@ const DateTimePicker = React.forwardRef<HTMLDivElement, DateTimePickerProps>(
|
|
|
3086
3425
|
}
|
|
3087
3426
|
};
|
|
3088
3427
|
|
|
3428
|
+
const handleTypedDateKeyDown = (
|
|
3429
|
+
event: React.KeyboardEvent<HTMLInputElement>
|
|
3430
|
+
) => {
|
|
3431
|
+
if (event.key !== "ArrowUp" && event.key !== "ArrowDown") return;
|
|
3432
|
+
|
|
3433
|
+
const direction = event.key === "ArrowUp" ? 1 : -1;
|
|
3434
|
+
const cursorPosition =
|
|
3435
|
+
event.currentTarget.selectionStart ?? dateInputValue.length;
|
|
3436
|
+
const inputElement = event.currentTarget;
|
|
3437
|
+
const steppedDateTime = stepDateTimeInputValue(
|
|
3438
|
+
dateInputValue,
|
|
3439
|
+
cursorPosition,
|
|
3440
|
+
direction,
|
|
3441
|
+
currentValue.startTime
|
|
3442
|
+
);
|
|
3443
|
+
|
|
3444
|
+
if (!steppedDateTime) return;
|
|
3445
|
+
if (
|
|
3446
|
+
(effectiveMinDate &&
|
|
3447
|
+
isBeforeDay(steppedDateTime.date, effectiveMinDate)) ||
|
|
3448
|
+
(maxDate && isAfterDay(steppedDateTime.date, maxDate))
|
|
3449
|
+
) {
|
|
3450
|
+
return;
|
|
3451
|
+
}
|
|
3452
|
+
|
|
3453
|
+
event.preventDefault();
|
|
3454
|
+
|
|
3455
|
+
const nextInputValue = formatDateForDisplay(
|
|
3456
|
+
steppedDateTime.date,
|
|
3457
|
+
steppedDateTime.startTime
|
|
3458
|
+
);
|
|
3459
|
+
const [selectionStart, selectionEnd] =
|
|
3460
|
+
DATE_TIME_INPUT_SEGMENT_RANGES[steppedDateTime.segment];
|
|
3461
|
+
|
|
3462
|
+
setDateInputValue(nextInputValue);
|
|
3463
|
+
updateValue({
|
|
3464
|
+
...currentValue,
|
|
3465
|
+
date: steppedDateTime.date,
|
|
3466
|
+
startTime: steppedDateTime.startTime,
|
|
3467
|
+
});
|
|
3468
|
+
updateVisibleMonth(steppedDateTime.date);
|
|
3469
|
+
|
|
3470
|
+
window.requestAnimationFrame(() => {
|
|
3471
|
+
inputElement.setSelectionRange(selectionStart, selectionEnd);
|
|
3472
|
+
});
|
|
3473
|
+
};
|
|
3474
|
+
|
|
3089
3475
|
const handleTypedDateBlur = () => {
|
|
3090
3476
|
setIsDateInputFocused(false);
|
|
3091
3477
|
setDateInputValue(
|
|
@@ -3133,71 +3519,89 @@ const DateTimePicker = React.forwardRef<HTMLDivElement, DateTimePickerProps>(
|
|
|
3133
3519
|
>
|
|
3134
3520
|
<ChevronLeft className="size-4" aria-hidden="true" />
|
|
3135
3521
|
</button>
|
|
3136
|
-
<div className="flex min-w-0 items-center gap-
|
|
3522
|
+
<div className="flex min-w-0 items-center gap-1.5">
|
|
3137
3523
|
<label className="sr-only" htmlFor={\`\${triggerId}-month\`}>
|
|
3138
3524
|
Month
|
|
3139
3525
|
</label>
|
|
3140
|
-
<
|
|
3141
|
-
|
|
3142
|
-
|
|
3143
|
-
value={visibleMonth.getMonth()}
|
|
3144
|
-
className="h-8 rounded-md border border-solid border-semantic-border-input bg-semantic-bg-primary px-2 text-sm font-medium text-semantic-text-primary outline-none transition-colors hover:border-semantic-border-input-focus/50 focus:border-semantic-border-input-focus/50"
|
|
3145
|
-
onChange={(event) =>
|
|
3526
|
+
<Select
|
|
3527
|
+
value={visibleMonth.getMonth().toString()}
|
|
3528
|
+
onValueChange={(nextMonth) =>
|
|
3146
3529
|
updateVisibleMonth(
|
|
3147
3530
|
new Date(
|
|
3148
3531
|
visibleMonth.getFullYear(),
|
|
3149
|
-
Number(
|
|
3532
|
+
Number(nextMonth),
|
|
3150
3533
|
1
|
|
3151
3534
|
)
|
|
3152
3535
|
)
|
|
3153
3536
|
}
|
|
3154
3537
|
>
|
|
3155
|
-
|
|
3156
|
-
|
|
3157
|
-
|
|
3158
|
-
|
|
3159
|
-
|
|
3160
|
-
|
|
3161
|
-
|
|
3162
|
-
|
|
3163
|
-
|
|
3164
|
-
|
|
3165
|
-
|
|
3166
|
-
|
|
3167
|
-
|
|
3168
|
-
|
|
3169
|
-
|
|
3170
|
-
|
|
3171
|
-
|
|
3172
|
-
|
|
3173
|
-
|
|
3174
|
-
|
|
3175
|
-
|
|
3176
|
-
|
|
3538
|
+
<SelectTrigger
|
|
3539
|
+
id={\`\${triggerId}-month\`}
|
|
3540
|
+
aria-label="Month"
|
|
3541
|
+
className={CALENDAR_SELECT_TRIGGER_CLASS}
|
|
3542
|
+
>
|
|
3543
|
+
<SelectValue />
|
|
3544
|
+
</SelectTrigger>
|
|
3545
|
+
<SelectContent
|
|
3546
|
+
data-date-time-picker-calendar-select=""
|
|
3547
|
+
className={CALENDAR_SELECT_CONTENT_CLASS}
|
|
3548
|
+
>
|
|
3549
|
+
{monthNames.map((monthName, monthIndex) => {
|
|
3550
|
+
const optionMonth = new Date(
|
|
3551
|
+
visibleMonth.getFullYear(),
|
|
3552
|
+
monthIndex,
|
|
3553
|
+
1
|
|
3554
|
+
);
|
|
3555
|
+
const isDisabled =
|
|
3556
|
+
(effectiveMinDate &&
|
|
3557
|
+
isMonthBefore(optionMonth, effectiveMinDate)) ||
|
|
3558
|
+
(maxDate && isMonthAfter(optionMonth, maxDate));
|
|
3559
|
+
|
|
3560
|
+
return (
|
|
3561
|
+
<SelectItem
|
|
3562
|
+
key={monthName}
|
|
3563
|
+
value={monthIndex.toString()}
|
|
3564
|
+
disabled={!!isDisabled}
|
|
3565
|
+
>
|
|
3566
|
+
{monthName}
|
|
3567
|
+
</SelectItem>
|
|
3568
|
+
);
|
|
3569
|
+
})}
|
|
3570
|
+
</SelectContent>
|
|
3571
|
+
</Select>
|
|
3177
3572
|
<label className="sr-only" htmlFor={\`\${triggerId}-year\`}>
|
|
3178
3573
|
Year
|
|
3179
3574
|
</label>
|
|
3180
|
-
<
|
|
3181
|
-
|
|
3182
|
-
|
|
3183
|
-
value={visibleMonth.getFullYear()}
|
|
3184
|
-
className="h-8 rounded-md border border-solid border-semantic-border-input bg-semantic-bg-primary px-2 text-sm font-medium text-semantic-text-primary outline-none transition-colors hover:border-semantic-border-input-focus/50 focus:border-semantic-border-input-focus/50"
|
|
3185
|
-
onChange={(event) =>
|
|
3575
|
+
<Select
|
|
3576
|
+
value={visibleMonth.getFullYear().toString()}
|
|
3577
|
+
onValueChange={(nextYear) =>
|
|
3186
3578
|
updateVisibleMonth(
|
|
3187
3579
|
new Date(
|
|
3188
|
-
Number(
|
|
3580
|
+
Number(nextYear),
|
|
3189
3581
|
visibleMonth.getMonth(),
|
|
3190
3582
|
1
|
|
3191
3583
|
)
|
|
3192
3584
|
)
|
|
3193
3585
|
}
|
|
3194
3586
|
>
|
|
3195
|
-
|
|
3196
|
-
|
|
3197
|
-
|
|
3198
|
-
|
|
3199
|
-
|
|
3200
|
-
|
|
3587
|
+
<SelectTrigger
|
|
3588
|
+
id={\`\${triggerId}-year\`}
|
|
3589
|
+
aria-label="Year"
|
|
3590
|
+
className={CALENDAR_SELECT_TRIGGER_CLASS}
|
|
3591
|
+
>
|
|
3592
|
+
<SelectValue />
|
|
3593
|
+
</SelectTrigger>
|
|
3594
|
+
<SelectContent
|
|
3595
|
+
data-date-time-picker-calendar-select=""
|
|
3596
|
+
className={CALENDAR_SELECT_CONTENT_CLASS}
|
|
3597
|
+
>
|
|
3598
|
+
{yearOptions.map((year) => (
|
|
3599
|
+
<SelectItem key={year} value={year.toString()}>
|
|
3600
|
+
{year}
|
|
3601
|
+
</SelectItem>
|
|
3602
|
+
))}
|
|
3603
|
+
</SelectContent>
|
|
3604
|
+
</Select>
|
|
3201
3605
|
<div id={\`\${triggerId}-calendar-heading\`} className="sr-only">
|
|
3202
3606
|
{monthFormatter.format(visibleMonth)}
|
|
3203
3607
|
</div>
|
|
@@ -3384,6 +3788,7 @@ const DateTimePicker = React.forwardRef<HTMLDivElement, DateTimePickerProps>(
|
|
|
3384
3788
|
}}
|
|
3385
3789
|
onClick={() => setOpen(true)}
|
|
3386
3790
|
onChange={handleTypedDateChange}
|
|
3791
|
+
onKeyDown={handleTypedDateKeyDown}
|
|
3387
3792
|
onBlur={handleTypedDateBlur}
|
|
3388
3793
|
/>
|
|
3389
3794
|
{showClear && displayValue && !disabled && !readOnly && (
|
|
@@ -6607,7 +7012,7 @@ const ReplyQuote = React.forwardRef(
|
|
|
6607
7012
|
<div
|
|
6608
7013
|
ref={ref}
|
|
6609
7014
|
className={cn(
|
|
6610
|
-
"tw-w-full tw-min-w-0 tw-bg-[var(--semantic-bg-ui,#F5F5F5)] tw-border-l-[3px] tw-border-solid tw-border-[var(--semantic-border-accent,#27ABB8)] tw-rounded-sm tw-px-4 tw-py-1.5 tw-mb-2 tw-h-[56px] tw-flex tw-flex-col tw-justify-center tw-gap-0 tw-overflow-hidden tw-cursor-pointer hover:tw-bg-[var(--semantic-bg-hover,#D5D7DA)] tw-transition-colors",
|
|
7015
|
+
"tw-max-w-full tw-min-w-0 tw-bg-[var(--semantic-bg-ui,#F5F5F5)] tw-border-l-[3px] tw-border-solid tw-border-[var(--semantic-border-accent,#27ABB8)] tw-rounded-sm tw-px-4 tw-py-1.5 tw-mb-2 tw-h-[56px] tw-flex tw-flex-col tw-justify-center tw-gap-0 tw-overflow-hidden tw-cursor-pointer hover:tw-bg-[var(--semantic-bg-hover,#D5D7DA)] tw-transition-colors",
|
|
6611
7016
|
isInteractive && "focus-visible:tw-ring-2 focus-visible:tw-ring-[var(--semantic-border-focus,#2BBCCA)] focus-visible:tw-ring-offset-1 focus-visible:tw-outline-none",
|
|
6612
7017
|
className
|
|
6613
7018
|
)}
|
|
@@ -6621,9 +7026,9 @@ const ReplyQuote = React.forwardRef(
|
|
|
6621
7026
|
<p className="tw-m-0 tw-min-w-0 tw-shrink-0 tw-truncate tw-text-[14px] tw-font-semibold tw-leading-5 tw-tracking-[0.014px] tw-text-[var(--semantic-text-primary,#181D27)]">
|
|
6622
7027
|
{sender}
|
|
6623
7028
|
</p>
|
|
6624
|
-
<
|
|
7029
|
+
<div className="tw-m-0 tw-min-h-0 tw-min-w-0 tw-flex-1 tw-overflow-hidden tw-text-ellipsis tw-whitespace-nowrap tw-text-[14px] tw-leading-5 tw-text-[var(--semantic-text-muted,#717680)] [&_*]:tw-inline">
|
|
6625
7030
|
{message}
|
|
6626
|
-
</
|
|
7031
|
+
</div>
|
|
6627
7032
|
</div>
|
|
6628
7033
|
);
|
|
6629
7034
|
}
|
|
@@ -6977,6 +7382,7 @@ const SelectField = React.forwardRef(
|
|
|
6977
7382
|
</SelectTrigger>
|
|
6978
7383
|
<SelectContent
|
|
6979
7384
|
onViewportScrollEnd={hasMore !== false ? onScrollEnd : undefined}
|
|
7385
|
+
hideScrollButtons={totalRendered === 0}
|
|
6980
7386
|
>
|
|
6981
7387
|
{/* Search input */}
|
|
6982
7388
|
{searchable && (
|
|
@@ -7233,6 +7639,7 @@ export type SelectContentProps = React.ComponentPropsWithoutRef<
|
|
|
7233
7639
|
* can still read scrollTop/scrollHeight/clientHeight from it.
|
|
7234
7640
|
*/
|
|
7235
7641
|
onViewportScrollEnd?: (event: React.UIEvent<HTMLDivElement>) => void;
|
|
7642
|
+
hideScrollButtons?: boolean;
|
|
7236
7643
|
};
|
|
7237
7644
|
|
|
7238
7645
|
const BOTTOM_THRESHOLD_PX = 24;
|
|
@@ -7245,6 +7652,7 @@ const SelectContent = React.forwardRef(
|
|
|
7245
7652
|
children,
|
|
7246
7653
|
position = "popper",
|
|
7247
7654
|
onViewportScrollEnd,
|
|
7655
|
+
hideScrollButtons,
|
|
7248
7656
|
...props
|
|
7249
7657
|
}: SelectContentProps,
|
|
7250
7658
|
ref: React.Ref<React.ElementRef<typeof SelectPrimitive.Content>>
|
|
@@ -7318,7 +7726,7 @@ const SelectContent = React.forwardRef(
|
|
|
7318
7726
|
position={position}
|
|
7319
7727
|
{...props}
|
|
7320
7728
|
>
|
|
7321
|
-
<SelectScrollUpButton />
|
|
7729
|
+
{!hideScrollButtons && <SelectScrollUpButton />}
|
|
7322
7730
|
<SelectPrimitive.Viewport
|
|
7323
7731
|
ref={setViewport}
|
|
7324
7732
|
data-select-viewport=""
|
|
@@ -7330,7 +7738,7 @@ const SelectContent = React.forwardRef(
|
|
|
7330
7738
|
>
|
|
7331
7739
|
{children}
|
|
7332
7740
|
</SelectPrimitive.Viewport>
|
|
7333
|
-
<SelectScrollDownButton />
|
|
7741
|
+
{!hideScrollButtons && <SelectScrollDownButton />}
|
|
7334
7742
|
</SelectPrimitive.Content>
|
|
7335
7743
|
</SelectPrimitive.Portal>
|
|
7336
7744
|
);
|
package/package.json
CHANGED