myoperator-mcp 0.2.348 → 0.2.350
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 +213 -10
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -1511,6 +1511,11 @@ export interface CreatableMultiSelectProps extends Omit<
|
|
|
1511
1511
|
* If the raw value differs from the sanitized value, \`onInvalidCharacters\` is called.
|
|
1512
1512
|
*/
|
|
1513
1513
|
sanitizeInput?: (raw: string) => string;
|
|
1514
|
+
/**
|
|
1515
|
+
* Applied after \`sanitizeInput\` on typed draft values (e.g. collapse spaces).
|
|
1516
|
+
* Does not affect invalid-character detection.
|
|
1517
|
+
*/
|
|
1518
|
+
normalizeInput?: (sanitized: string) => string;
|
|
1514
1519
|
/** Fired when \`sanitizeInput\` removed one or more characters from the raw input. */
|
|
1515
1520
|
onInvalidCharacters?: () => void;
|
|
1516
1521
|
/**
|
|
@@ -1600,6 +1605,12 @@ function isValueAlreadySelected(
|
|
|
1600
1605
|
});
|
|
1601
1606
|
}
|
|
1602
1607
|
|
|
1608
|
+
function restoreInputCursor(input: HTMLInputElement, cursorPosition: number) {
|
|
1609
|
+
window.requestAnimationFrame(() => {
|
|
1610
|
+
input.setSelectionRange(cursorPosition, cursorPosition);
|
|
1611
|
+
});
|
|
1612
|
+
}
|
|
1613
|
+
|
|
1603
1614
|
const CreatableMultiSelect = React.forwardRef(
|
|
1604
1615
|
(
|
|
1605
1616
|
{
|
|
@@ -1617,6 +1628,7 @@ const CreatableMultiSelect = React.forwardRef(
|
|
|
1617
1628
|
showPerItemCharacterCounter = true,
|
|
1618
1629
|
triggerDisplay = "chips",
|
|
1619
1630
|
sanitizeInput,
|
|
1631
|
+
normalizeInput,
|
|
1620
1632
|
onInvalidCharacters,
|
|
1621
1633
|
onValidInput,
|
|
1622
1634
|
onInputValueChange,
|
|
@@ -1641,6 +1653,17 @@ const CreatableMultiSelect = React.forwardRef(
|
|
|
1641
1653
|
maxLengthPerItem
|
|
1642
1654
|
);
|
|
1643
1655
|
|
|
1656
|
+
const normalizeDraftValue = React.useCallback(
|
|
1657
|
+
(raw: string) => {
|
|
1658
|
+
const sanitized = sanitizeInput ? sanitizeInput(raw) : raw;
|
|
1659
|
+
const normalized = normalizeInput ? normalizeInput(sanitized) : sanitized;
|
|
1660
|
+
return maxLengthPerItem != null
|
|
1661
|
+
? normalized.slice(0, maxLengthPerItem)
|
|
1662
|
+
: normalized;
|
|
1663
|
+
},
|
|
1664
|
+
[maxLengthPerItem, normalizeInput, sanitizeInput]
|
|
1665
|
+
);
|
|
1666
|
+
|
|
1644
1667
|
const addValue = (val: string) => {
|
|
1645
1668
|
const isPreset = options.some((o) => o.value === val);
|
|
1646
1669
|
const afterSanitize = isPreset
|
|
@@ -1648,7 +1671,9 @@ const CreatableMultiSelect = React.forwardRef(
|
|
|
1648
1671
|
: sanitizeInput
|
|
1649
1672
|
? sanitizeInput(val)
|
|
1650
1673
|
: val;
|
|
1651
|
-
const
|
|
1674
|
+
const afterNormalize =
|
|
1675
|
+
isPreset || !normalizeInput ? afterSanitize : normalizeInput(afterSanitize);
|
|
1676
|
+
const trimmed = afterNormalize.trim();
|
|
1652
1677
|
if (
|
|
1653
1678
|
!trimmed ||
|
|
1654
1679
|
isValueAlreadySelected(
|
|
@@ -1837,12 +1862,19 @@ const CreatableMultiSelect = React.forwardRef(
|
|
|
1837
1862
|
if (raw !== sanitized) onInvalidCharacters?.();
|
|
1838
1863
|
else onValidInput?.();
|
|
1839
1864
|
}
|
|
1840
|
-
const nextInput =
|
|
1841
|
-
maxLengthPerItem != null
|
|
1842
|
-
? sanitized.slice(0, maxLengthPerItem)
|
|
1843
|
-
: sanitized;
|
|
1865
|
+
const nextInput = normalizeDraftValue(raw);
|
|
1844
1866
|
setInputValue(nextInput);
|
|
1845
1867
|
onInputValueChange?.(nextInput);
|
|
1868
|
+
|
|
1869
|
+
if (nextInput !== raw) {
|
|
1870
|
+
const input = e.currentTarget;
|
|
1871
|
+
const rawCursor = input.selectionStart ?? raw.length;
|
|
1872
|
+
const nextCursor = Math.min(
|
|
1873
|
+
normalizeDraftValue(raw.slice(0, rawCursor)).length,
|
|
1874
|
+
nextInput.length
|
|
1875
|
+
);
|
|
1876
|
+
restoreInputCursor(input, nextCursor);
|
|
1877
|
+
}
|
|
1846
1878
|
}}
|
|
1847
1879
|
maxLength={maxLengthPerItem}
|
|
1848
1880
|
onKeyDown={handleKeyDown}
|
|
@@ -2104,6 +2136,12 @@ export const creatableToneHintRowClassName = cn(
|
|
|
2104
2136
|
"flex shrink-0 items-center justify-between gap-2 px-4 py-2"
|
|
2105
2137
|
)
|
|
2106
2138
|
|
|
2139
|
+
function restoreInputCursor(input: HTMLInputElement, cursorPosition: number) {
|
|
2140
|
+
window.requestAnimationFrame(() => {
|
|
2141
|
+
input.setSelectionRange(cursorPosition, cursorPosition)
|
|
2142
|
+
})
|
|
2143
|
+
}
|
|
2144
|
+
|
|
2107
2145
|
export interface CreatableSelectOption {
|
|
2108
2146
|
value: string
|
|
2109
2147
|
label: string
|
|
@@ -2183,6 +2221,17 @@ const CreatableSelect = React.forwardRef(
|
|
|
2183
2221
|
// Merge forwarded ref with internal ref
|
|
2184
2222
|
React.useImperativeHandle(ref, () => containerRef.current!)
|
|
2185
2223
|
|
|
2224
|
+
const normalizeSearchValue = React.useCallback(
|
|
2225
|
+
(raw: string) => {
|
|
2226
|
+
const sanitized = sanitizeInput ? sanitizeInput(raw) : raw
|
|
2227
|
+
const normalized = normalizeComboboxInput
|
|
2228
|
+
? normalizeComboboxInput(sanitized)
|
|
2229
|
+
: sanitized
|
|
2230
|
+
return maxLength != null ? normalized.slice(0, maxLength) : normalized
|
|
2231
|
+
},
|
|
2232
|
+
[maxLength, normalizeComboboxInput, sanitizeInput]
|
|
2233
|
+
)
|
|
2234
|
+
|
|
2186
2235
|
const selectedLabel = React.useMemo(() => {
|
|
2187
2236
|
const found = options.find((o) => o.value === value)
|
|
2188
2237
|
return found ? found.label : value || ""
|
|
@@ -2335,13 +2384,19 @@ const CreatableSelect = React.forwardRef(
|
|
|
2335
2384
|
if (raw !== sanitized) onInvalidCharacters?.()
|
|
2336
2385
|
else onValidInput?.()
|
|
2337
2386
|
}
|
|
2338
|
-
const
|
|
2339
|
-
? normalizeComboboxInput(sanitized)
|
|
2340
|
-
: sanitized
|
|
2341
|
-
const nextSearch =
|
|
2342
|
-
maxLength != null ? next.slice(0, maxLength) : next
|
|
2387
|
+
const nextSearch = normalizeSearchValue(raw)
|
|
2343
2388
|
setSearch(nextSearch)
|
|
2344
2389
|
onInputValueChange?.(nextSearch)
|
|
2390
|
+
|
|
2391
|
+
if (nextSearch !== raw) {
|
|
2392
|
+
const input = e.currentTarget
|
|
2393
|
+
const rawCursor = input.selectionStart ?? raw.length
|
|
2394
|
+
const nextCursor = Math.min(
|
|
2395
|
+
normalizeSearchValue(raw.slice(0, rawCursor)).length,
|
|
2396
|
+
nextSearch.length
|
|
2397
|
+
)
|
|
2398
|
+
restoreInputCursor(input, nextCursor)
|
|
2399
|
+
}
|
|
2345
2400
|
}}
|
|
2346
2401
|
maxLength={maxLength}
|
|
2347
2402
|
onKeyDown={handleKeyDown}
|
|
@@ -5152,6 +5207,28 @@ import { cn } from "@/lib/utils";
|
|
|
5152
5207
|
|
|
5153
5208
|
const blockedNumberKeys = new Set(["e", "E"]);
|
|
5154
5209
|
const decimalSeparatorKeys = new Set([".", ","]);
|
|
5210
|
+
const consecutiveSpaceInputTypes = new Set([
|
|
5211
|
+
"email",
|
|
5212
|
+
"password",
|
|
5213
|
+
"search",
|
|
5214
|
+
"tel",
|
|
5215
|
+
"text",
|
|
5216
|
+
"url",
|
|
5217
|
+
]);
|
|
5218
|
+
|
|
5219
|
+
function shouldPreventConsecutiveSpacesForType(
|
|
5220
|
+
type: React.HTMLInputTypeAttribute | undefined
|
|
5221
|
+
): boolean {
|
|
5222
|
+
return type == null || consecutiveSpaceInputTypes.has(type);
|
|
5223
|
+
}
|
|
5224
|
+
|
|
5225
|
+
function collapseConsecutiveSpaces(value: string): string {
|
|
5226
|
+
return value.replace(/ {2,}/g, " ");
|
|
5227
|
+
}
|
|
5228
|
+
|
|
5229
|
+
function getCollapsedCursorPosition(value: string, cursorPosition: number) {
|
|
5230
|
+
return collapseConsecutiveSpaces(value.slice(0, cursorPosition)).length;
|
|
5231
|
+
}
|
|
5155
5232
|
|
|
5156
5233
|
/**
|
|
5157
5234
|
* Input variants for different visual states
|
|
@@ -5209,6 +5286,11 @@ export interface InputProps
|
|
|
5209
5286
|
* Same as \`decimal\` for whole-number-only fields. If both are set, this wins.
|
|
5210
5287
|
*/
|
|
5211
5288
|
allowDecimal?: boolean;
|
|
5289
|
+
/**
|
|
5290
|
+
* Prevents inserting a second consecutive space in text-like inputs while
|
|
5291
|
+
* preserving the user's current cursor position. Defaults to \`true\`.
|
|
5292
|
+
*/
|
|
5293
|
+
preventConsecutiveSpaces?: boolean;
|
|
5212
5294
|
}
|
|
5213
5295
|
|
|
5214
5296
|
const Input = React.forwardRef(
|
|
@@ -5222,11 +5304,13 @@ const Input = React.forwardRef(
|
|
|
5222
5304
|
preventNumberExponent = true,
|
|
5223
5305
|
decimal = true,
|
|
5224
5306
|
allowDecimal,
|
|
5307
|
+
preventConsecutiveSpaces = true,
|
|
5225
5308
|
onFocus,
|
|
5226
5309
|
onBlur,
|
|
5227
5310
|
onWheel,
|
|
5228
5311
|
onKeyDown,
|
|
5229
5312
|
onPaste,
|
|
5313
|
+
onBeforeInput,
|
|
5230
5314
|
onChange,
|
|
5231
5315
|
step,
|
|
5232
5316
|
...props
|
|
@@ -5239,6 +5323,8 @@ const Input = React.forwardRef(
|
|
|
5239
5323
|
type === "number" && preventNumberExponent;
|
|
5240
5324
|
const shouldBlockDecimals =
|
|
5241
5325
|
type === "number" && !decimalAllowed;
|
|
5326
|
+
const shouldPreventConsecutiveSpaces =
|
|
5327
|
+
preventConsecutiveSpaces && shouldPreventConsecutiveSpacesForType(type);
|
|
5242
5328
|
|
|
5243
5329
|
const inputEl = (
|
|
5244
5330
|
<input
|
|
@@ -5302,6 +5388,33 @@ const Input = React.forwardRef(
|
|
|
5302
5388
|
}
|
|
5303
5389
|
onPaste?.(e);
|
|
5304
5390
|
}}
|
|
5391
|
+
onBeforeInput={(e) => {
|
|
5392
|
+
onBeforeInput?.(e);
|
|
5393
|
+
if (!shouldPreventConsecutiveSpaces || e.defaultPrevented) {
|
|
5394
|
+
return;
|
|
5395
|
+
}
|
|
5396
|
+
|
|
5397
|
+
const nativeEvent = e.nativeEvent as InputEvent;
|
|
5398
|
+
if (nativeEvent.inputType !== "insertText" || nativeEvent.data !== " ") {
|
|
5399
|
+
return;
|
|
5400
|
+
}
|
|
5401
|
+
|
|
5402
|
+
const input = e.currentTarget;
|
|
5403
|
+
const selectionStart = input.selectionStart ?? input.value.length;
|
|
5404
|
+
const selectionEnd = input.selectionEnd ?? selectionStart;
|
|
5405
|
+
const nextValue =
|
|
5406
|
+
input.value.slice(0, selectionStart) +
|
|
5407
|
+
nativeEvent.data +
|
|
5408
|
+
input.value.slice(selectionEnd);
|
|
5409
|
+
|
|
5410
|
+
if (nextValue.includes(" ")) {
|
|
5411
|
+
e.preventDefault();
|
|
5412
|
+
input.setSelectionRange(selectionStart, selectionStart);
|
|
5413
|
+
window.requestAnimationFrame(() => {
|
|
5414
|
+
input.setSelectionRange(selectionStart, selectionStart);
|
|
5415
|
+
});
|
|
5416
|
+
}
|
|
5417
|
+
}}
|
|
5305
5418
|
onChange={(e) => {
|
|
5306
5419
|
if (shouldPreventNumberExponent && /[eE]/.test(e.target.value)) {
|
|
5307
5420
|
return;
|
|
@@ -5309,6 +5422,21 @@ const Input = React.forwardRef(
|
|
|
5309
5422
|
if (shouldBlockDecimals && /[.,]/.test(e.target.value)) {
|
|
5310
5423
|
return;
|
|
5311
5424
|
}
|
|
5425
|
+
if (shouldPreventConsecutiveSpaces && e.target.value.includes(" ")) {
|
|
5426
|
+
const input = e.currentTarget;
|
|
5427
|
+
const rawValue = input.value;
|
|
5428
|
+
const rawCursor = input.selectionStart ?? rawValue.length;
|
|
5429
|
+
const collapsedValue = collapseConsecutiveSpaces(rawValue);
|
|
5430
|
+
const nextCursor = Math.min(
|
|
5431
|
+
getCollapsedCursorPosition(rawValue, rawCursor),
|
|
5432
|
+
collapsedValue.length
|
|
5433
|
+
);
|
|
5434
|
+
|
|
5435
|
+
input.value = collapsedValue;
|
|
5436
|
+
window.requestAnimationFrame(() => {
|
|
5437
|
+
input.setSelectionRange(nextCursor, nextCursor);
|
|
5438
|
+
});
|
|
5439
|
+
}
|
|
5312
5440
|
onChange?.(e);
|
|
5313
5441
|
}}
|
|
5314
5442
|
{...props}
|
|
@@ -9351,6 +9479,29 @@ import { Loader2, X } from "lucide-react";
|
|
|
9351
9479
|
|
|
9352
9480
|
import { cn } from "@/lib/utils";
|
|
9353
9481
|
|
|
9482
|
+
const consecutiveSpaceInputTypes = new Set([
|
|
9483
|
+
"email",
|
|
9484
|
+
"password",
|
|
9485
|
+
"search",
|
|
9486
|
+
"tel",
|
|
9487
|
+
"text",
|
|
9488
|
+
"url",
|
|
9489
|
+
]);
|
|
9490
|
+
|
|
9491
|
+
function shouldPreventConsecutiveSpacesForType(
|
|
9492
|
+
type: React.HTMLInputTypeAttribute | undefined
|
|
9493
|
+
): boolean {
|
|
9494
|
+
return type == null || consecutiveSpaceInputTypes.has(type);
|
|
9495
|
+
}
|
|
9496
|
+
|
|
9497
|
+
function collapseConsecutiveSpaces(value: string): string {
|
|
9498
|
+
return value.replace(/ {2,}/g, " ");
|
|
9499
|
+
}
|
|
9500
|
+
|
|
9501
|
+
function getCollapsedCursorPosition(value: string, cursorPosition: number) {
|
|
9502
|
+
return collapseConsecutiveSpaces(value.slice(0, cursorPosition)).length;
|
|
9503
|
+
}
|
|
9504
|
+
|
|
9354
9505
|
/**
|
|
9355
9506
|
* TextField container variants for when icons/prefix/suffix are present
|
|
9356
9507
|
*/
|
|
@@ -9453,6 +9604,11 @@ export interface TextFieldProps
|
|
|
9453
9604
|
labelClassName?: string;
|
|
9454
9605
|
/** Additional class for the input container (includes prefix/suffix/icons) */
|
|
9455
9606
|
inputContainerClassName?: string;
|
|
9607
|
+
/**
|
|
9608
|
+
* Prevents inserting a second consecutive space in text-like inputs while
|
|
9609
|
+
* preserving the user's current cursor position. Defaults to \`true\`.
|
|
9610
|
+
*/
|
|
9611
|
+
preventConsecutiveSpaces?: boolean;
|
|
9456
9612
|
}
|
|
9457
9613
|
|
|
9458
9614
|
const TextField = React.forwardRef(
|
|
@@ -9480,10 +9636,12 @@ const TextField = React.forwardRef(
|
|
|
9480
9636
|
value,
|
|
9481
9637
|
defaultValue,
|
|
9482
9638
|
onChange,
|
|
9639
|
+
onBeforeInput,
|
|
9483
9640
|
onWheel,
|
|
9484
9641
|
disabled,
|
|
9485
9642
|
id,
|
|
9486
9643
|
type,
|
|
9644
|
+
preventConsecutiveSpaces = true,
|
|
9487
9645
|
...props
|
|
9488
9646
|
}: TextFieldProps,
|
|
9489
9647
|
ref: React.ForwardedRef<HTMLInputElement>
|
|
@@ -9510,9 +9668,27 @@ const TextField = React.forwardRef(
|
|
|
9510
9668
|
|
|
9511
9669
|
// Derive state from props
|
|
9512
9670
|
const derivedState = error ? "error" : (state ?? "default");
|
|
9671
|
+
const shouldPreventConsecutiveSpaces =
|
|
9672
|
+
preventConsecutiveSpaces && shouldPreventConsecutiveSpacesForType(type);
|
|
9513
9673
|
|
|
9514
9674
|
// Handle change for both controlled and uncontrolled
|
|
9515
9675
|
const handleChange = (e: React.ChangeEvent<HTMLInputElement>) => {
|
|
9676
|
+
if (shouldPreventConsecutiveSpaces && e.target.value.includes(" ")) {
|
|
9677
|
+
const input = e.currentTarget;
|
|
9678
|
+
const rawValue = input.value;
|
|
9679
|
+
const rawCursor = input.selectionStart ?? rawValue.length;
|
|
9680
|
+
const collapsedValue = collapseConsecutiveSpaces(rawValue);
|
|
9681
|
+
const nextCursor = Math.min(
|
|
9682
|
+
getCollapsedCursorPosition(rawValue, rawCursor),
|
|
9683
|
+
collapsedValue.length
|
|
9684
|
+
);
|
|
9685
|
+
|
|
9686
|
+
input.value = collapsedValue;
|
|
9687
|
+
window.requestAnimationFrame(() => {
|
|
9688
|
+
input.setSelectionRange(nextCursor, nextCursor);
|
|
9689
|
+
});
|
|
9690
|
+
}
|
|
9691
|
+
|
|
9516
9692
|
if (!isControlled) {
|
|
9517
9693
|
setInternalValue(e.target.value);
|
|
9518
9694
|
}
|
|
@@ -9572,6 +9748,33 @@ const TextField = React.forwardRef(
|
|
|
9572
9748
|
maxLength={maxLength}
|
|
9573
9749
|
value={isControlled ? value : undefined}
|
|
9574
9750
|
defaultValue={!isControlled ? defaultValue : undefined}
|
|
9751
|
+
onBeforeInput={(e) => {
|
|
9752
|
+
onBeforeInput?.(e);
|
|
9753
|
+
if (!shouldPreventConsecutiveSpaces || e.defaultPrevented) {
|
|
9754
|
+
return;
|
|
9755
|
+
}
|
|
9756
|
+
|
|
9757
|
+
const nativeEvent = e.nativeEvent as InputEvent;
|
|
9758
|
+
if (nativeEvent.inputType !== "insertText" || nativeEvent.data !== " ") {
|
|
9759
|
+
return;
|
|
9760
|
+
}
|
|
9761
|
+
|
|
9762
|
+
const input = e.currentTarget;
|
|
9763
|
+
const selectionStart = input.selectionStart ?? input.value.length;
|
|
9764
|
+
const selectionEnd = input.selectionEnd ?? selectionStart;
|
|
9765
|
+
const nextValue =
|
|
9766
|
+
input.value.slice(0, selectionStart) +
|
|
9767
|
+
nativeEvent.data +
|
|
9768
|
+
input.value.slice(selectionEnd);
|
|
9769
|
+
|
|
9770
|
+
if (nextValue.includes(" ")) {
|
|
9771
|
+
e.preventDefault();
|
|
9772
|
+
input.setSelectionRange(selectionStart, selectionStart);
|
|
9773
|
+
window.requestAnimationFrame(() => {
|
|
9774
|
+
input.setSelectionRange(selectionStart, selectionStart);
|
|
9775
|
+
});
|
|
9776
|
+
}
|
|
9777
|
+
}}
|
|
9575
9778
|
onChange={handleChange}
|
|
9576
9779
|
onWheel={
|
|
9577
9780
|
type === "number"
|
package/package.json
CHANGED