myoperator-mcp 0.2.380 → 0.2.382
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 +159 -33
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -2628,7 +2628,7 @@ const MONTH_LONG_NAMES = [
|
|
|
2628
2628
|
];
|
|
2629
2629
|
|
|
2630
2630
|
const dateRangePickerTriggerVariants = cva(
|
|
2631
|
-
"flex h-10 w-full items-center gap-2 rounded
|
|
2631
|
+
"flex h-10 w-full items-center gap-2 rounded border border-solid border-semantic-border-input bg-semantic-bg-primary px-4 py-2.5 text-left text-sm text-semantic-text-primary outline-none transition-colors hover:border-semantic-border-input-focus/50 disabled:cursor-not-allowed disabled:opacity-50",
|
|
2632
2632
|
{
|
|
2633
2633
|
variants: {
|
|
2634
2634
|
state: {
|
|
@@ -2736,8 +2736,44 @@ function getCalendarDays(month: Date) {
|
|
|
2736
2736
|
});
|
|
2737
2737
|
}
|
|
2738
2738
|
|
|
2739
|
+
function isMonthSelectable(
|
|
2740
|
+
year: number,
|
|
2741
|
+
monthIndex: number,
|
|
2742
|
+
minDate?: Date,
|
|
2743
|
+
maxDate?: Date
|
|
2744
|
+
) {
|
|
2745
|
+
const firstDay = new Date(year, monthIndex, 1);
|
|
2746
|
+
const lastDay = new Date(year, monthIndex + 1, 0);
|
|
2747
|
+
|
|
2748
|
+
if (minDate && isBeforeDay(lastDay, minDate)) return false;
|
|
2749
|
+
if (maxDate && isAfterDay(firstDay, maxDate)) return false;
|
|
2750
|
+
|
|
2751
|
+
return true;
|
|
2752
|
+
}
|
|
2753
|
+
|
|
2754
|
+
function clampRange(
|
|
2755
|
+
range: DateRangeValue,
|
|
2756
|
+
minDate?: Date,
|
|
2757
|
+
maxDate?: Date
|
|
2758
|
+
): DateRangeValue | null {
|
|
2759
|
+
let { start, end } = range;
|
|
2760
|
+
|
|
2761
|
+
// The window and the preset don't overlap at all \u2014 clamping would collapse
|
|
2762
|
+
// the range onto the boundary day, which is not what the preset means.
|
|
2763
|
+
if (end && minDate && isBeforeDay(end, minDate)) return null;
|
|
2764
|
+
if (start && maxDate && isAfterDay(start, maxDate)) return null;
|
|
2765
|
+
|
|
2766
|
+
if (start && minDate && isBeforeDay(start, minDate)) start = minDate;
|
|
2767
|
+
if (end && maxDate && isAfterDay(end, maxDate)) end = maxDate;
|
|
2768
|
+
|
|
2769
|
+
// The whole preset sits outside the allowed window \u2014 nothing to select.
|
|
2770
|
+
if (start && end && isAfterDay(start, end)) return null;
|
|
2771
|
+
|
|
2772
|
+
return { start, end };
|
|
2773
|
+
}
|
|
2774
|
+
|
|
2739
2775
|
function isPointerInsideElement(
|
|
2740
|
-
event: MouseEvent,
|
|
2776
|
+
event: MouseEvent | PointerEvent,
|
|
2741
2777
|
element: HTMLElement | null
|
|
2742
2778
|
) {
|
|
2743
2779
|
if (!element) return false;
|
|
@@ -2886,6 +2922,11 @@ const DateRangePicker = React.forwardRef<HTMLDivElement, DateRangePickerProps>(
|
|
|
2886
2922
|
// start a new one (false). Drives the "click 1 = start, click 2 = end,
|
|
2887
2923
|
// click 3 = restart" cycle.
|
|
2888
2924
|
const [pendingEnd, setPendingEnd] = React.useState(false);
|
|
2925
|
+
// Month and year share one slot so opening either closes the other \u2014
|
|
2926
|
+
// two independent uncontrolled menus can otherwise sit open at once.
|
|
2927
|
+
const [openMenu, setOpenMenu] = React.useState<"month" | "year" | null>(
|
|
2928
|
+
null
|
|
2929
|
+
);
|
|
2889
2930
|
const [visibleMonth, setVisibleMonth] = React.useState(() =>
|
|
2890
2931
|
startOfMonth(currentValue.start ?? currentValue.end ?? new Date())
|
|
2891
2932
|
);
|
|
@@ -2941,6 +2982,21 @@ const DateRangePicker = React.forwardRef<HTMLDivElement, DateRangePickerProps>(
|
|
|
2941
2982
|
|
|
2942
2983
|
return isBeforeDay(minDate, today) ? today : minDate;
|
|
2943
2984
|
}, [disablePastDates, minDate]);
|
|
2985
|
+
// Year list is centred on the visible year but never offers a year that
|
|
2986
|
+
// has no selectable day in it.
|
|
2987
|
+
const yearOptions = React.useMemo(() => {
|
|
2988
|
+
const centre = visibleMonth.getFullYear();
|
|
2989
|
+
const all = Array.from(
|
|
2990
|
+
{ length: YEAR_OPTIONS_SPAN * 2 + 1 },
|
|
2991
|
+
(_, index) => centre - YEAR_OPTIONS_SPAN + index
|
|
2992
|
+
);
|
|
2993
|
+
|
|
2994
|
+
return all.filter(
|
|
2995
|
+
(year) =>
|
|
2996
|
+
!(effectiveMinDate && year < effectiveMinDate.getFullYear()) &&
|
|
2997
|
+
!(maxDate && year > maxDate.getFullYear())
|
|
2998
|
+
);
|
|
2999
|
+
}, [visibleMonth, effectiveMinDate, maxDate]);
|
|
2944
3000
|
const portalMount =
|
|
2945
3001
|
typeof document !== "undefined"
|
|
2946
3002
|
? usesContainerPortal
|
|
@@ -2989,6 +3045,7 @@ const DateRangePicker = React.forwardRef<HTMLDivElement, DateRangePickerProps>(
|
|
|
2989
3045
|
const latestValue = currentValueRef.current;
|
|
2990
3046
|
setDraftValue(latestValue);
|
|
2991
3047
|
setPendingEnd(false);
|
|
3048
|
+
setOpenMenu(null);
|
|
2992
3049
|
setVisibleMonth(
|
|
2993
3050
|
startOfMonth(latestValue.start ?? latestValue.end ?? new Date())
|
|
2994
3051
|
);
|
|
@@ -2997,7 +3054,7 @@ const DateRangePicker = React.forwardRef<HTMLDivElement, DateRangePickerProps>(
|
|
|
2997
3054
|
React.useEffect(() => {
|
|
2998
3055
|
if (!open) return;
|
|
2999
3056
|
|
|
3000
|
-
const handlePointerDown = (event:
|
|
3057
|
+
const handlePointerDown = (event: PointerEvent) => {
|
|
3001
3058
|
if (
|
|
3002
3059
|
!isPointerInsideElement(event, rootRef.current) &&
|
|
3003
3060
|
!isPointerInsideElement(event, popoverRef.current)
|
|
@@ -3009,14 +3066,17 @@ const DateRangePicker = React.forwardRef<HTMLDivElement, DateRangePickerProps>(
|
|
|
3009
3066
|
const handleKeyDown = (event: KeyboardEvent) => {
|
|
3010
3067
|
if (event.key === "Escape") {
|
|
3011
3068
|
setOpen(false);
|
|
3069
|
+
// Escape must hand focus back to the trigger, otherwise focus is
|
|
3070
|
+
// stranded on a node that is about to unmount.
|
|
3071
|
+
triggerRef.current?.focus();
|
|
3012
3072
|
}
|
|
3013
3073
|
};
|
|
3014
3074
|
|
|
3015
|
-
document.addEventListener("
|
|
3075
|
+
document.addEventListener("pointerdown", handlePointerDown);
|
|
3016
3076
|
document.addEventListener("keydown", handleKeyDown);
|
|
3017
3077
|
|
|
3018
3078
|
return () => {
|
|
3019
|
-
document.removeEventListener("
|
|
3079
|
+
document.removeEventListener("pointerdown", handlePointerDown);
|
|
3020
3080
|
document.removeEventListener("keydown", handleKeyDown);
|
|
3021
3081
|
};
|
|
3022
3082
|
}, [open, setOpen]);
|
|
@@ -3032,10 +3092,21 @@ const DateRangePicker = React.forwardRef<HTMLDivElement, DateRangePickerProps>(
|
|
|
3032
3092
|
[isValueControlled, onValueChange]
|
|
3033
3093
|
);
|
|
3034
3094
|
|
|
3095
|
+
// Radix dismisses the open menu on the same pointerdown that would toggle
|
|
3096
|
+
// the sibling trigger, so its own toggle is swallowed and switching menus
|
|
3097
|
+
// takes two clicks. Drive the slot from the trigger directly and
|
|
3098
|
+
// preventDefault so Radix's toggle stays out of it.
|
|
3099
|
+
const toggleCalendarMenu = (menu: "month" | "year") => {
|
|
3100
|
+
setOpenMenu((current) => (current === menu ? null : menu));
|
|
3101
|
+
};
|
|
3102
|
+
|
|
3035
3103
|
const handlePresetClick = (preset: DateRangePreset) => {
|
|
3036
|
-
const range = preset.getRange();
|
|
3104
|
+
const range = clampRange(preset.getRange(), effectiveMinDate, maxDate);
|
|
3105
|
+
if (!range) return;
|
|
3106
|
+
|
|
3037
3107
|
commitValue(range);
|
|
3038
3108
|
setOpen(false);
|
|
3109
|
+
triggerRef.current?.focus();
|
|
3039
3110
|
};
|
|
3040
3111
|
|
|
3041
3112
|
const handleDayClick = (day: Date) => {
|
|
@@ -3056,6 +3127,7 @@ const DateRangePicker = React.forwardRef<HTMLDivElement, DateRangePickerProps>(
|
|
|
3056
3127
|
setPendingEnd(false);
|
|
3057
3128
|
commitValue(nextValue);
|
|
3058
3129
|
setOpen(false);
|
|
3130
|
+
triggerRef.current?.focus();
|
|
3059
3131
|
};
|
|
3060
3132
|
|
|
3061
3133
|
const popover =
|
|
@@ -3087,23 +3159,34 @@ const DateRangePicker = React.forwardRef<HTMLDivElement, DateRangePickerProps>(
|
|
|
3087
3159
|
onWheel={(event) => event.stopPropagation()}
|
|
3088
3160
|
onTouchMove={(event) => event.stopPropagation()}
|
|
3089
3161
|
>
|
|
3090
|
-
<div className="flex flex-row">
|
|
3162
|
+
<div className="flex flex-col sm:flex-row">
|
|
3091
3163
|
{presets.length > 0 && (
|
|
3092
|
-
<div className="flex
|
|
3093
|
-
{presets.map((preset) =>
|
|
3094
|
-
|
|
3095
|
-
|
|
3096
|
-
|
|
3097
|
-
|
|
3098
|
-
|
|
3099
|
-
|
|
3100
|
-
|
|
3101
|
-
|
|
3102
|
-
|
|
3164
|
+
<div className="flex shrink-0 gap-0.5 border-solid border-semantic-border-layout p-3 max-sm:w-full max-sm:flex-row max-sm:overflow-x-auto max-sm:border-b sm:w-36 sm:flex-col sm:border-r">
|
|
3165
|
+
{presets.map((preset) => {
|
|
3166
|
+
const presetDisabled =
|
|
3167
|
+
clampRange(preset.getRange(), effectiveMinDate, maxDate) ===
|
|
3168
|
+
null;
|
|
3169
|
+
|
|
3170
|
+
return (
|
|
3171
|
+
<button
|
|
3172
|
+
key={preset.label}
|
|
3173
|
+
type="button"
|
|
3174
|
+
disabled={presetDisabled}
|
|
3175
|
+
className={cn(
|
|
3176
|
+
"shrink-0 whitespace-nowrap rounded px-2 py-2 text-left text-sm text-semantic-text-primary transition-colors hover:bg-semantic-bg-hover max-sm:border max-sm:border-solid max-sm:border-semantic-border-layout sm:w-full sm:py-1.5",
|
|
3177
|
+
presetDisabled &&
|
|
3178
|
+
"cursor-not-allowed opacity-40 hover:bg-transparent"
|
|
3179
|
+
)}
|
|
3180
|
+
onClick={() => handlePresetClick(preset)}
|
|
3181
|
+
>
|
|
3182
|
+
{preset.label}
|
|
3183
|
+
</button>
|
|
3184
|
+
);
|
|
3185
|
+
})}
|
|
3103
3186
|
</div>
|
|
3104
3187
|
)}
|
|
3105
3188
|
|
|
3106
|
-
<div className="min-w-
|
|
3189
|
+
<div className="min-w-0 flex-1 p-3 touch-pan-y sm:min-w-[272px]">
|
|
3107
3190
|
<div className="mb-3 flex items-center justify-between gap-2">
|
|
3108
3191
|
<button
|
|
3109
3192
|
type="button"
|
|
@@ -3120,10 +3203,25 @@ const DateRangePicker = React.forwardRef<HTMLDivElement, DateRangePickerProps>(
|
|
|
3120
3203
|
id={\`\${triggerId}-calendar-heading\`}
|
|
3121
3204
|
className="flex items-center gap-2"
|
|
3122
3205
|
>
|
|
3123
|
-
<DropdownMenu
|
|
3206
|
+
<DropdownMenu
|
|
3207
|
+
modal={false}
|
|
3208
|
+
open={openMenu === "month"}
|
|
3209
|
+
onOpenChange={(nextOpen) =>
|
|
3210
|
+
setOpenMenu((current) => {
|
|
3211
|
+
if (nextOpen) return "month";
|
|
3212
|
+
// Clicking the other trigger dismisses this menu
|
|
3213
|
+
// *after* the other one has opened \u2014 only clear the
|
|
3214
|
+
// slot if it is still ours.
|
|
3215
|
+
return current === "month" ? null : current;
|
|
3216
|
+
})
|
|
3217
|
+
}
|
|
3218
|
+
>
|
|
3124
3219
|
<DropdownMenuTrigger asChild>
|
|
3125
3220
|
<button
|
|
3126
3221
|
type="button"
|
|
3222
|
+
data-calendar-menu="month"
|
|
3223
|
+
onPointerDown={(event) => event.preventDefault()}
|
|
3224
|
+
onClick={() => toggleCalendarMenu("month")}
|
|
3127
3225
|
className="rounded border border-solid border-semantic-border-layout px-3 py-1.5 text-sm font-semibold text-semantic-text-primary transition-colors hover:bg-semantic-bg-hover"
|
|
3128
3226
|
>
|
|
3129
3227
|
{MONTH_LONG_NAMES[visibleMonth.getMonth()]}
|
|
@@ -3131,11 +3229,23 @@ const DateRangePicker = React.forwardRef<HTMLDivElement, DateRangePickerProps>(
|
|
|
3131
3229
|
</DropdownMenuTrigger>
|
|
3132
3230
|
<DropdownMenuContent
|
|
3133
3231
|
align="start"
|
|
3232
|
+
// Closing must not pull focus back to the trigger: the
|
|
3233
|
+
// sibling menu opening in the same click would then see
|
|
3234
|
+
// focus land outside itself and dismiss immediately.
|
|
3235
|
+
onCloseAutoFocus={(event) => event.preventDefault()}
|
|
3134
3236
|
className={cn(CALENDAR_DROPDOWN_Z_INDEX, "max-h-[240px] overflow-y-auto")}
|
|
3135
3237
|
>
|
|
3136
3238
|
{MONTH_LONG_NAMES.map((label, monthIndex) => (
|
|
3137
3239
|
<DropdownMenuItem
|
|
3138
3240
|
key={label}
|
|
3241
|
+
disabled={
|
|
3242
|
+
!isMonthSelectable(
|
|
3243
|
+
visibleMonth.getFullYear(),
|
|
3244
|
+
monthIndex,
|
|
3245
|
+
effectiveMinDate,
|
|
3246
|
+
maxDate
|
|
3247
|
+
)
|
|
3248
|
+
}
|
|
3139
3249
|
onSelect={() =>
|
|
3140
3250
|
setVisibleMonth(
|
|
3141
3251
|
startOfMonth(
|
|
@@ -3150,10 +3260,25 @@ const DateRangePicker = React.forwardRef<HTMLDivElement, DateRangePickerProps>(
|
|
|
3150
3260
|
</DropdownMenuContent>
|
|
3151
3261
|
</DropdownMenu>
|
|
3152
3262
|
|
|
3153
|
-
<DropdownMenu
|
|
3263
|
+
<DropdownMenu
|
|
3264
|
+
modal={false}
|
|
3265
|
+
open={openMenu === "year"}
|
|
3266
|
+
onOpenChange={(nextOpen) =>
|
|
3267
|
+
setOpenMenu((current) => {
|
|
3268
|
+
if (nextOpen) return "year";
|
|
3269
|
+
// Clicking the other trigger dismisses this menu
|
|
3270
|
+
// *after* the other one has opened \u2014 only clear the
|
|
3271
|
+
// slot if it is still ours.
|
|
3272
|
+
return current === "year" ? null : current;
|
|
3273
|
+
})
|
|
3274
|
+
}
|
|
3275
|
+
>
|
|
3154
3276
|
<DropdownMenuTrigger asChild>
|
|
3155
3277
|
<button
|
|
3156
3278
|
type="button"
|
|
3279
|
+
data-calendar-menu="year"
|
|
3280
|
+
onPointerDown={(event) => event.preventDefault()}
|
|
3281
|
+
onClick={() => toggleCalendarMenu("year")}
|
|
3157
3282
|
className="flex items-center gap-1 rounded border border-solid border-semantic-border-layout px-3 py-1.5 text-sm font-semibold text-semantic-text-primary transition-colors hover:bg-semantic-bg-hover"
|
|
3158
3283
|
>
|
|
3159
3284
|
{visibleMonth.getFullYear()}
|
|
@@ -3165,12 +3290,13 @@ const DateRangePicker = React.forwardRef<HTMLDivElement, DateRangePickerProps>(
|
|
|
3165
3290
|
</DropdownMenuTrigger>
|
|
3166
3291
|
<DropdownMenuContent
|
|
3167
3292
|
align="start"
|
|
3293
|
+
// Closing must not pull focus back to the trigger: the
|
|
3294
|
+
// sibling menu opening in the same click would then see
|
|
3295
|
+
// focus land outside itself and dismiss immediately.
|
|
3296
|
+
onCloseAutoFocus={(event) => event.preventDefault()}
|
|
3168
3297
|
className={cn(CALENDAR_DROPDOWN_Z_INDEX, "max-h-[240px] overflow-y-auto")}
|
|
3169
3298
|
>
|
|
3170
|
-
{
|
|
3171
|
-
{ length: YEAR_OPTIONS_SPAN * 2 + 1 },
|
|
3172
|
-
(_, index) => visibleMonth.getFullYear() - YEAR_OPTIONS_SPAN + index
|
|
3173
|
-
).map((year) => (
|
|
3299
|
+
{yearOptions.map((year) => (
|
|
3174
3300
|
<DropdownMenuItem
|
|
3175
3301
|
key={year}
|
|
3176
3302
|
onSelect={() =>
|
|
@@ -3198,11 +3324,11 @@ const DateRangePicker = React.forwardRef<HTMLDivElement, DateRangePickerProps>(
|
|
|
3198
3324
|
</button>
|
|
3199
3325
|
</div>
|
|
3200
3326
|
|
|
3201
|
-
<div className="grid grid-cols-7">
|
|
3327
|
+
<div className="grid w-full grid-cols-7">
|
|
3202
3328
|
{weekDays.map((day) => (
|
|
3203
3329
|
<div
|
|
3204
3330
|
key={day}
|
|
3205
|
-
className="flex h-
|
|
3331
|
+
className="flex h-9 items-center justify-center text-xs font-medium text-semantic-text-muted sm:h-8"
|
|
3206
3332
|
>
|
|
3207
3333
|
{day}
|
|
3208
3334
|
</div>
|
|
@@ -3238,7 +3364,7 @@ const DateRangePicker = React.forwardRef<HTMLDivElement, DateRangePickerProps>(
|
|
|
3238
3364
|
<div
|
|
3239
3365
|
key={day.toISOString()}
|
|
3240
3366
|
className={cn(
|
|
3241
|
-
"relative flex h-
|
|
3367
|
+
"relative flex h-9 items-center justify-center sm:h-8",
|
|
3242
3368
|
isInBand && "bg-semantic-info-surface",
|
|
3243
3369
|
isRangeStart && hasRange && "rounded-l-full",
|
|
3244
3370
|
isRangeEnd && hasRange && "rounded-r-full"
|
|
@@ -3251,7 +3377,7 @@ const DateRangePicker = React.forwardRef<HTMLDivElement, DateRangePickerProps>(
|
|
|
3251
3377
|
aria-current={isToday ? "date" : undefined}
|
|
3252
3378
|
disabled={!!isDisabled}
|
|
3253
3379
|
className={cn(
|
|
3254
|
-
"relative flex
|
|
3380
|
+
"relative flex h-9 w-full max-w-9 items-center justify-center rounded-full text-xs transition-colors sm:h-8 sm:max-w-8",
|
|
3255
3381
|
isSelectedEdge
|
|
3256
3382
|
? "bg-semantic-primary text-semantic-text-inverted font-semibold"
|
|
3257
3383
|
: isCurrentMonth
|
|
@@ -3408,9 +3534,9 @@ const dateTimePickerTriggerVariants = cva(
|
|
|
3408
3534
|
{
|
|
3409
3535
|
variants: {
|
|
3410
3536
|
size: {
|
|
3411
|
-
sm: "h-9 gap-2 rounded
|
|
3412
|
-
default: "h-[42px] gap-2 rounded
|
|
3413
|
-
lg: "h-[42px] gap-2 rounded
|
|
3537
|
+
sm: "h-9 gap-2 rounded px-3 py-2 text-sm",
|
|
3538
|
+
default: "h-[42px] gap-2 rounded px-4 py-2.5 text-base",
|
|
3539
|
+
lg: "h-[42px] gap-2 rounded px-4 py-2.5 text-base",
|
|
3414
3540
|
},
|
|
3415
3541
|
state: {
|
|
3416
3542
|
default: "",
|
|
@@ -4604,7 +4730,7 @@ function TimeField({
|
|
|
4604
4730
|
aria-haspopup="listbox"
|
|
4605
4731
|
aria-expanded={open}
|
|
4606
4732
|
className={cn(
|
|
4607
|
-
"flex h-[42px] w-full items-center gap-2 rounded
|
|
4733
|
+
"flex h-[42px] w-full items-center gap-2 rounded border border-solid border-semantic-border-input bg-semantic-bg-primary px-3 text-left text-base text-semantic-text-primary outline-none transition-colors hover:border-semantic-border-input-focus/50",
|
|
4608
4734
|
open &&
|
|
4609
4735
|
"border-semantic-border-input-focus/50 shadow-[0_0_0_1px_rgba(43,188,202,0.15)]"
|
|
4610
4736
|
)}
|
package/package.json
CHANGED