cursedbelt 5.79.1 → 5.79.2
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/react/components/OtpInput.d.ts.map +1 -1
- package/dist/react/components/OtpInput.js +12 -3
- package/dist/react/components/OtpInput.js.map +1 -1
- package/dist/react/components/SelectFieldImpl.d.ts.map +1 -1
- package/dist/react/components/SelectFieldImpl.js +8 -1
- package/dist/react/components/SelectFieldImpl.js.map +1 -1
- package/package.json +1 -1
- package/src/react/components/OtpInput.spec.tsx +27 -1
- package/src/react/components/OtpInput.tsx +12 -4
- package/src/react/components/SelectField.spec.tsx +50 -1
- package/src/react/components/SelectFieldImpl.tsx +6 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"OtpInput.d.ts","sourceRoot":"","sources":["../../../src/react/components/OtpInput.tsx"],"names":[],"mappings":"AAUA,MAAM,WAAW,aAAa;IAC5B,iFAAiF;IACjF,KAAK,EAAE,MAAM,CAAC;IACd,QAAQ,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;IAClC,iEAAiE;IACjE,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,kEAAkE;IAClE,UAAU,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;IACrC;+DAC2D;IAC3D,SAAS,CAAC,EAAE,SAAS,GAAG,MAAM,CAAC;IAC/B,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB,EAAE,CAAC,EAAE,MAAM,CAAC;IACZ,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,cAAc,CAAC,EAAE,IAAI,GAAG,SAAS,CAAC;IAClC,kBAAkB,CAAC,EAAE,MAAM,CAAC;IAC5B,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAKD;;;;;;;;;;;GAWG;AACH,wBAAgB,QAAQ,CAAC,EACvB,KAAK,EACL,QAAQ,EACR,MAAU,EACV,UAAU,EACV,SAAqB,EACrB,QAAQ,EACR,SAAS,EACT,EAAE,EACF,IAAI,EACJ,YAAY,EAAE,SAAS,EACvB,cAAc,EAAE,WAAW,EAC3B,kBAAkB,EAAE,eAAe,EACnC,SAAS,GACV,EAAE,aAAa,+
|
|
1
|
+
{"version":3,"file":"OtpInput.d.ts","sourceRoot":"","sources":["../../../src/react/components/OtpInput.tsx"],"names":[],"mappings":"AAUA,MAAM,WAAW,aAAa;IAC5B,iFAAiF;IACjF,KAAK,EAAE,MAAM,CAAC;IACd,QAAQ,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;IAClC,iEAAiE;IACjE,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,kEAAkE;IAClE,UAAU,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;IACrC;+DAC2D;IAC3D,SAAS,CAAC,EAAE,SAAS,GAAG,MAAM,CAAC;IAC/B,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB,EAAE,CAAC,EAAE,MAAM,CAAC;IACZ,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,cAAc,CAAC,EAAE,IAAI,GAAG,SAAS,CAAC;IAClC,kBAAkB,CAAC,EAAE,MAAM,CAAC;IAC5B,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAKD;;;;;;;;;;;GAWG;AACH,wBAAgB,QAAQ,CAAC,EACvB,KAAK,EACL,QAAQ,EACR,MAAU,EACV,UAAU,EACV,SAAqB,EACrB,QAAQ,EACR,SAAS,EACT,EAAE,EACF,IAAI,EACJ,YAAY,EAAE,SAAS,EACvB,cAAc,EAAE,WAAW,EAC3B,kBAAkB,EAAE,eAAe,EACnC,SAAS,GACV,EAAE,aAAa,+BA8Gf"}
|
|
@@ -31,8 +31,11 @@ export function OtpInput({ value, onChange, length = 6, onComplete, inputMode =
|
|
|
31
31
|
refs.current[clamped]?.focus();
|
|
32
32
|
refs.current[clamped]?.select();
|
|
33
33
|
};
|
|
34
|
-
const handleChange = (index, raw) => {
|
|
35
|
-
|
|
34
|
+
const handleChange = (index, raw, typed) => {
|
|
35
|
+
// A key typed into a box that already holds a character arrives APPENDED to it ("47"),
|
|
36
|
+
// since no box is capped at one: the key is the event's own `data`. An autofill or a
|
|
37
|
+
// replacement carries the whole code in the value.
|
|
38
|
+
const clean = sanitize(typed ?? raw);
|
|
36
39
|
if (!clean) {
|
|
37
40
|
// A deletion/clear of this box: drop just this position.
|
|
38
41
|
if (chars[index])
|
|
@@ -79,6 +82,12 @@ export function OtpInput({ value, onChange, length = 6, onComplete, inputMode =
|
|
|
79
82
|
refs.current[i] = el;
|
|
80
83
|
}, id: i === 0 ? baseId : `${baseId}-${i}`, name: i === 0 ? name : undefined, type: 'text', inputMode: inputMode, autoComplete: i === 0 ? 'one-time-code' : 'off',
|
|
81
84
|
// biome-ignore lint/a11y/noAutofocus: opt-in via prop; first box only
|
|
82
|
-
autoFocus: autoFocus && i === 0,
|
|
85
|
+
autoFocus: autoFocus && i === 0,
|
|
86
|
+
// 🔴 Never 1: a browser that honours `maxLength` on autofill (iOS Safari's "From
|
|
87
|
+
// Messages" chip) would hand the code box one digit. `commit` is the limit.
|
|
88
|
+
maxLength: length, disabled: disabled, value: char, "aria-label": ariaLabel ? `${ariaLabel} digit ${i + 1}` : `Digit ${i + 1}`, "aria-invalid": ariaInvalid, "aria-describedby": i === 0 ? ariaDescribedBy : undefined, onChange: (e) => {
|
|
89
|
+
const input = e.nativeEvent;
|
|
90
|
+
handleChange(i, e.target.value, input.inputType === 'insertText' && input.data ? input.data : null);
|
|
91
|
+
}, onKeyDown: (e) => handleKeyDown(i, e), onPaste: (e) => handlePaste(i, e), onFocus: (e) => e.currentTarget.select(), className: BOX_CLASS }, i))) }));
|
|
83
92
|
}
|
|
84
93
|
//# sourceMappingURL=OtpInput.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"OtpInput.js","sourceRoot":"","sources":["../../../src/react/components/OtpInput.tsx"],"names":[],"mappings":";AAAA,OAAO,EAGL,WAAW,EACX,KAAK,EACL,OAAO,EACP,MAAM,GACP,MAAM,OAAO,CAAC;AACf,OAAO,EAAE,EAAE,EAAE,MAAM,cAAc,CAAC;AAuBlC,MAAM,SAAS,GACb,gZAAgZ,CAAC;AAEnZ;;;;;;;;;;;GAWG;AACH,MAAM,UAAU,QAAQ,CAAC,EACvB,KAAK,EACL,QAAQ,EACR,MAAM,GAAG,CAAC,EACV,UAAU,EACV,SAAS,GAAG,SAAS,EACrB,QAAQ,EACR,SAAS,EACT,EAAE,EACF,IAAI,EACJ,YAAY,EAAE,SAAS,EACvB,cAAc,EAAE,WAAW,EAC3B,kBAAkB,EAAE,eAAe,EACnC,SAAS,GACK;IACd,MAAM,OAAO,GAAG,KAAK,EAAE,CAAC;IACxB,MAAM,MAAM,GAAG,EAAE,IAAI,OAAO,CAAC;IAC7B,MAAM,IAAI,GAAG,MAAM,CAAiC,EAAE,CAAC,CAAC;IACxD,MAAM,KAAK,GAAG,OAAO,CAAC,GAAG,EAAE,CAAC,KAAK,CAAC,IAAI,CAAC,EAAE,MAAM,EAAE,EAAE,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,KAAK,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,CAAC,CAAC,CAAC;IAE/F,MAAM,QAAQ,GAAG,WAAW,CAC1B,CAAC,GAAW,EAAE,EAAE,CAAC,CAAC,SAAS,KAAK,SAAS,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,KAAK,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,KAAK,EAAE,EAAE,CAAC,CAAC,EAC5F,CAAC,SAAS,CAAC,CACZ,CAAC;IAEF,MAAM,MAAM,GAAG,WAAW,CACxB,CAAC,IAAY,EAAE,EAAE;QACf,MAAM,OAAO,GAAG,IAAI,CAAC,KAAK,CAAC,CAAC,EAAE,MAAM,CAAC,CAAC;QACtC,QAAQ,CAAC,OAAO,CAAC,CAAC;QAClB,IAAI,OAAO,CAAC,MAAM,KAAK,MAAM;YAAE,UAAU,EAAE,CAAC,OAAO,CAAC,CAAC;IACvD,CAAC,EACD,CAAC,MAAM,EAAE,QAAQ,EAAE,UAAU,CAAC,CAC/B,CAAC;IAEF,MAAM,QAAQ,GAAG,CAAC,KAAa,EAAE,EAAE;QACjC,MAAM,OAAO,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,IAAI,CAAC,GAAG,CAAC,MAAM,GAAG,CAAC,EAAE,KAAK,CAAC,CAAC,CAAC;QACzD,IAAI,CAAC,OAAO,CAAC,OAAO,CAAC,EAAE,KAAK,EAAE,CAAC;QAC/B,IAAI,CAAC,OAAO,CAAC,OAAO,CAAC,EAAE,MAAM,EAAE,CAAC;IAClC,CAAC,CAAC;IAEF,MAAM,YAAY,GAAG,CAAC,KAAa,EAAE,GAAW,EAAE,EAAE;
|
|
1
|
+
{"version":3,"file":"OtpInput.js","sourceRoot":"","sources":["../../../src/react/components/OtpInput.tsx"],"names":[],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"SelectFieldImpl.d.ts","sourceRoot":"","sources":["../../../src/react/components/SelectFieldImpl.tsx"],"names":[],"mappings":"AAWA,OAAO,EAEL,KAAK,oBAAoB,EAG1B,MAAM,uBAAuB,CAAC;AAE/B;;;GAGG;AACH,MAAM,CAAC,OAAO,UAAU,eAAe,CAAC,EACtC,KAAK,EACL,aAAa,EACb,OAAY,EACZ,MAAW,EACX,WAAuB,EACvB,QAAQ,EACR,UAAiB,EACjB,IAAW,EACX,EAAE,EACF,IAAI,EACJ,QAAQ,EACR,SAAS,EACT,UAAU,EACV,SAAS,EACT,YAAY,EAAE,SAAS,EACvB,iBAAiB,EAAE,cAAc,EACjC,cAAc,EAAE,WAAW,EAC3B,kBAAkB,EAAE,eAAe,EACnC,WAAmB,EACnB,YAAoB,GACrB,EAAE,oBAAoB,+
|
|
1
|
+
{"version":3,"file":"SelectFieldImpl.d.ts","sourceRoot":"","sources":["../../../src/react/components/SelectFieldImpl.tsx"],"names":[],"mappings":"AAWA,OAAO,EAEL,KAAK,oBAAoB,EAG1B,MAAM,uBAAuB,CAAC;AAE/B;;;GAGG;AACH,MAAM,CAAC,OAAO,UAAU,eAAe,CAAC,EACtC,KAAK,EACL,aAAa,EACb,OAAY,EACZ,MAAW,EACX,WAAuB,EACvB,QAAQ,EACR,UAAiB,EACjB,IAAW,EACX,EAAE,EACF,IAAI,EACJ,QAAQ,EACR,SAAS,EACT,UAAU,EACV,SAAS,EACT,YAAY,EAAE,SAAS,EACvB,iBAAiB,EAAE,cAAc,EACjC,cAAc,EAAE,WAAW,EAC3B,kBAAkB,EAAE,eAAe,EACnC,WAAmB,EACnB,YAAoB,GACrB,EAAE,oBAAoB,+BAqGtB"}
|
|
@@ -21,6 +21,13 @@ export default function SelectFieldImpl({ value, onValueChange, options = [], gr
|
|
|
21
21
|
if (initialFocus && !initialOpen)
|
|
22
22
|
triggerRef.current?.focus();
|
|
23
23
|
}, [initialFocus, initialOpen]);
|
|
24
|
-
return (_jsxs(RSelect.Root, { value: value,
|
|
24
|
+
return (_jsxs(RSelect.Root, { value: value,
|
|
25
|
+
// 🔴 "" is never a choice — Radix refuses an item whose value is "". Inside a <form> its
|
|
26
|
+
// hidden native <select> reads "" back for a value code set before that option exists,
|
|
27
|
+
// and reported it here as a pick: collections' Folder picker reset (forge task 3166).
|
|
28
|
+
onValueChange: (next) => {
|
|
29
|
+
if (next !== '')
|
|
30
|
+
onValueChange?.(next);
|
|
31
|
+
}, disabled: disabled, name: name, required: required, defaultOpen: initialOpen, children: [_jsxs(RSelect.Trigger, { ref: triggerRef, id: id, "aria-label": ariaLabel, "aria-labelledby": ariaLabelledBy, "aria-invalid": ariaInvalid, "aria-describedby": ariaDescribedBy, className: cn(RAW_BUTTON, selectTriggerClass({ fieldStyle, size, className })), children: [_jsx("span", { className: SELECT_VALUE_CLASS, children: _jsx(RSelect.Value, { placeholder: placeholder }) }), _jsx(RSelect.Icon, { asChild: true, children: _jsx(ChevronDown, { className: 'size-4 shrink-0 opacity-50' }) })] }), _jsx(RSelect.Portal, { container: container, children: _jsxs(RSelect.Content, { position: 'popper', sideOffset: 4, collisionPadding: FLOATING_COLLISION_PADDING, className: cn(FLOATING_CONTENT_BASE, FLOATING_ANIMATION, 'max-h-[var(--radix-select-content-available-height)] min-w-[var(--radix-select-trigger-width)] p-1'), children: [_jsx(RSelect.ScrollUpButton, { className: 'flex cursor-default items-center justify-center py-1', children: _jsx(ChevronUp, { className: 'size-4' }) }), _jsxs(RSelect.Viewport, { children: [empty && (_jsxs("div", { className: 'flex flex-col gap-0.5 px-2 py-2.5 text-left', children: [_jsx("span", { className: 'text-sm font-medium', children: emptyLabel ?? 'Nothing to choose from yet' }), emptyHint && _jsx("span", { className: 'text-xs text-muted-foreground', children: emptyHint })] })), allGroups.map((group, gi) => (_jsxs(RSelect.Group, { children: [group.label && (_jsx(RSelect.Label, { className: 'px-2 py-1.5 text-xs font-semibold text-muted-foreground', children: group.label })), group.options.map((opt) => (_jsxs(RSelect.Item, { value: opt.value, disabled: opt.disabled, className: cn(FLOATING_ITEM_BASE, 'pr-8'), children: [_jsx(RSelect.ItemIndicator, { className: 'absolute right-2 flex size-4 items-center justify-center', children: _jsx(Check, { className: 'size-3' }) }), _jsx(RSelect.ItemText, { children: opt.label }), opt.description && (_jsx("span", { className: 'text-xs text-muted-foreground', children: opt.description }))] }, opt.value))), gi < allGroups.length - 1 && _jsx(RSelect.Separator, { className: 'my-1 h-px bg-border' })] }, group.label ?? gi)))] }), _jsx(RSelect.ScrollDownButton, { className: 'flex cursor-default items-center justify-center py-1', children: _jsx(ChevronDown, { className: 'size-4' }) })] }) })] }));
|
|
25
32
|
}
|
|
26
33
|
//# sourceMappingURL=SelectFieldImpl.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"SelectFieldImpl.js","sourceRoot":"","sources":["../../../src/react/components/SelectFieldImpl.tsx"],"names":[],"mappings":";AAAA,OAAO,KAAK,OAAO,MAAM,wBAAwB,CAAC;AAClD,OAAO,EAAE,KAAK,EAAE,WAAW,EAAE,SAAS,EAAE,MAAM,cAAc,CAAC;AAC7D,OAAO,EAAE,SAAS,EAAE,MAAM,EAAE,MAAM,OAAO,CAAC;AAC1C,OAAO,EAAE,EAAE,EAAE,UAAU,EAAE,MAAM,cAAc,CAAC;AAC9C,OAAO,EAAE,oBAAoB,EAAE,MAAM,6BAA6B,CAAC;AACnE,OAAO,EACL,kBAAkB,EAClB,0BAA0B,EAC1B,qBAAqB,EACrB,kBAAkB,GACnB,MAAM,0BAA0B,CAAC;AAClC,OAAO,EACL,kBAAkB,EAElB,cAAc,EACd,kBAAkB,GACnB,MAAM,uBAAuB,CAAC;AAE/B;;;GAGG;AACH,MAAM,CAAC,OAAO,UAAU,eAAe,CAAC,EACtC,KAAK,EACL,aAAa,EACb,OAAO,GAAG,EAAE,EACZ,MAAM,GAAG,EAAE,EACX,WAAW,GAAG,SAAS,EACvB,QAAQ,EACR,UAAU,GAAG,IAAI,EACjB,IAAI,GAAG,IAAI,EACX,EAAE,EACF,IAAI,EACJ,QAAQ,EACR,SAAS,EACT,UAAU,EACV,SAAS,EACT,YAAY,EAAE,SAAS,EACvB,iBAAiB,EAAE,cAAc,EACjC,cAAc,EAAE,WAAW,EAC3B,kBAAkB,EAAE,eAAe,EACnC,WAAW,GAAG,KAAK,EACnB,YAAY,GAAG,KAAK,GACC;IACrB,MAAM,SAAS,GAAG,cAAc,CAAC,EAAE,OAAO,EAAE,MAAM,EAAE,CAAC,CAAC;IACtD,MAAM,KAAK,GAAG,SAAS,CAAC,KAAK,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,CAAC,OAAO,CAAC,MAAM,KAAK,CAAC,CAAC,CAAC;IACrE,MAAM,SAAS,GAAG,oBAAoB,EAAE,CAAC;IACzC,MAAM,UAAU,GAAG,MAAM,CAAoB,IAAI,CAAC,CAAC;IAEnD,+FAA+F;IAC/F,wFAAwF;IACxF,SAAS,CAAC,GAAG,EAAE;QACb,IAAI,YAAY,IAAI,CAAC,WAAW;YAAE,UAAU,CAAC,OAAO,EAAE,KAAK,EAAE,CAAC;IAChE,CAAC,EAAE,CAAC,YAAY,EAAE,WAAW,CAAC,CAAC,CAAC;IAEhC,OAAO,CACL,MAAC,OAAO,CAAC,IAAI,IACX,KAAK,EAAE,KAAK,
|
|
1
|
+
{"version":3,"file":"SelectFieldImpl.js","sourceRoot":"","sources":["../../../src/react/components/SelectFieldImpl.tsx"],"names":[],"mappings":";AAAA,OAAO,KAAK,OAAO,MAAM,wBAAwB,CAAC;AAClD,OAAO,EAAE,KAAK,EAAE,WAAW,EAAE,SAAS,EAAE,MAAM,cAAc,CAAC;AAC7D,OAAO,EAAE,SAAS,EAAE,MAAM,EAAE,MAAM,OAAO,CAAC;AAC1C,OAAO,EAAE,EAAE,EAAE,UAAU,EAAE,MAAM,cAAc,CAAC;AAC9C,OAAO,EAAE,oBAAoB,EAAE,MAAM,6BAA6B,CAAC;AACnE,OAAO,EACL,kBAAkB,EAClB,0BAA0B,EAC1B,qBAAqB,EACrB,kBAAkB,GACnB,MAAM,0BAA0B,CAAC;AAClC,OAAO,EACL,kBAAkB,EAElB,cAAc,EACd,kBAAkB,GACnB,MAAM,uBAAuB,CAAC;AAE/B;;;GAGG;AACH,MAAM,CAAC,OAAO,UAAU,eAAe,CAAC,EACtC,KAAK,EACL,aAAa,EACb,OAAO,GAAG,EAAE,EACZ,MAAM,GAAG,EAAE,EACX,WAAW,GAAG,SAAS,EACvB,QAAQ,EACR,UAAU,GAAG,IAAI,EACjB,IAAI,GAAG,IAAI,EACX,EAAE,EACF,IAAI,EACJ,QAAQ,EACR,SAAS,EACT,UAAU,EACV,SAAS,EACT,YAAY,EAAE,SAAS,EACvB,iBAAiB,EAAE,cAAc,EACjC,cAAc,EAAE,WAAW,EAC3B,kBAAkB,EAAE,eAAe,EACnC,WAAW,GAAG,KAAK,EACnB,YAAY,GAAG,KAAK,GACC;IACrB,MAAM,SAAS,GAAG,cAAc,CAAC,EAAE,OAAO,EAAE,MAAM,EAAE,CAAC,CAAC;IACtD,MAAM,KAAK,GAAG,SAAS,CAAC,KAAK,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,CAAC,OAAO,CAAC,MAAM,KAAK,CAAC,CAAC,CAAC;IACrE,MAAM,SAAS,GAAG,oBAAoB,EAAE,CAAC;IACzC,MAAM,UAAU,GAAG,MAAM,CAAoB,IAAI,CAAC,CAAC;IAEnD,+FAA+F;IAC/F,wFAAwF;IACxF,SAAS,CAAC,GAAG,EAAE;QACb,IAAI,YAAY,IAAI,CAAC,WAAW;YAAE,UAAU,CAAC,OAAO,EAAE,KAAK,EAAE,CAAC;IAChE,CAAC,EAAE,CAAC,YAAY,EAAE,WAAW,CAAC,CAAC,CAAC;IAEhC,OAAO,CACL,MAAC,OAAO,CAAC,IAAI,IACX,KAAK,EAAE,KAAK;QACZ,yFAAyF;QACzF,uFAAuF;QACvF,sFAAsF;QACtF,aAAa,EAAE,CAAC,IAAI,EAAE,EAAE;YACtB,IAAI,IAAI,KAAK,EAAE;gBAAE,aAAa,EAAE,CAAC,IAAI,CAAC,CAAC;QACzC,CAAC,EACD,QAAQ,EAAE,QAAQ,EAClB,IAAI,EAAE,IAAI,EACV,QAAQ,EAAE,QAAQ,EAClB,WAAW,EAAE,WAAW,aAExB,MAAC,OAAO,CAAC,OAAO,IACd,GAAG,EAAE,UAAU,EACf,EAAE,EAAE,EAAE,gBACM,SAAS,qBACJ,cAAc,kBACjB,WAAW,sBACP,eAAe,EACjC,SAAS,EAAE,EAAE,CAAC,UAAU,EAAE,kBAAkB,CAAC,EAAE,UAAU,EAAE,IAAI,EAAE,SAAS,EAAE,CAAC,CAAC,aAE9E,eAAM,SAAS,EAAE,kBAAkB,YACjC,KAAC,OAAO,CAAC,KAAK,IAAC,WAAW,EAAE,WAAW,GAAI,GACtC,EACP,KAAC,OAAO,CAAC,IAAI,IAAC,OAAO,kBACnB,KAAC,WAAW,IAAC,SAAS,EAAC,4BAA4B,GAAG,GACzC,IACC,EAClB,KAAC,OAAO,CAAC,MAAM,IAAC,SAAS,EAAE,SAAS,YAClC,MAAC,OAAO,CAAC,OAAO,IACd,QAAQ,EAAC,QAAQ,EACjB,UAAU,EAAE,CAAC,EACb,gBAAgB,EAAE,0BAA0B,EAC5C,SAAS,EAAE,EAAE,CACX,qBAAqB,EACrB,kBAAkB,EAClB,oGAAoG,CACrG,aAED,KAAC,OAAO,CAAC,cAAc,IAAC,SAAS,EAAC,sDAAsD,YACtF,KAAC,SAAS,IAAC,SAAS,EAAC,QAAQ,GAAG,GACT,EACzB,MAAC,OAAO,CAAC,QAAQ,eACd,KAAK,IAAI,CAGR,eAAK,SAAS,EAAC,6CAA6C,aAC1D,eAAM,SAAS,EAAC,qBAAqB,YAClC,UAAU,IAAI,4BAA4B,GACtC,EACN,SAAS,IAAI,eAAM,SAAS,EAAC,+BAA+B,YAAE,SAAS,GAAQ,IAC5E,CACP,EACA,SAAS,CAAC,GAAG,CAAC,CAAC,KAAK,EAAE,EAAE,EAAE,EAAE,CAAC,CAC5B,MAAC,OAAO,CAAC,KAAK,eACX,KAAK,CAAC,KAAK,IAAI,CACd,KAAC,OAAO,CAAC,KAAK,IAAC,SAAS,EAAC,yDAAyD,YAC/E,KAAK,CAAC,KAAK,GACE,CACjB,EACA,KAAK,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,CAC1B,MAAC,OAAO,CAAC,IAAI,IAEX,KAAK,EAAE,GAAG,CAAC,KAAK,EAChB,QAAQ,EAAE,GAAG,CAAC,QAAQ,EACtB,SAAS,EAAE,EAAE,CAAC,kBAAkB,EAAE,MAAM,CAAC,aAEzC,KAAC,OAAO,CAAC,aAAa,IAAC,SAAS,EAAC,0DAA0D,YACzF,KAAC,KAAK,IAAC,SAAS,EAAC,QAAQ,GAAG,GACN,EACxB,KAAC,OAAO,CAAC,QAAQ,cAAE,GAAG,CAAC,KAAK,GAAoB,EAC/C,GAAG,CAAC,WAAW,IAAI,CAClB,eAAM,SAAS,EAAC,+BAA+B,YAAE,GAAG,CAAC,WAAW,GAAQ,CACzE,KAXI,GAAG,CAAC,KAAK,CAYD,CAChB,CAAC,EACD,EAAE,GAAG,SAAS,CAAC,MAAM,GAAG,CAAC,IAAI,KAAC,OAAO,CAAC,SAAS,IAAC,SAAS,EAAC,qBAAqB,GAAG,KAtBjE,KAAK,CAAC,KAAK,IAAI,EAAE,CAuBrB,CACjB,CAAC,IACe,EACnB,KAAC,OAAO,CAAC,gBAAgB,IAAC,SAAS,EAAC,sDAAsD,YACxF,KAAC,WAAW,IAAC,SAAS,EAAC,QAAQ,GAAG,GACT,IACX,GACH,IACJ,CAChB,CAAC;AACJ,CAAC"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "cursedbelt",
|
|
3
|
-
"version": "5.79.
|
|
3
|
+
"version": "5.79.2",
|
|
4
4
|
"license": "ISC",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"description": "The React design system of the cursedbelt split — components, styles, theme. cursedbelt-core below it; server tier in cursedbelt-server.",
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { afterEach, describe, expect, mock, test } from 'bun:test';
|
|
2
|
-
import { cleanup, fireEvent, render } from '@testing-library/react';
|
|
2
|
+
import { act, cleanup, fireEvent, render } from '@testing-library/react';
|
|
3
3
|
import { useState } from 'react';
|
|
4
4
|
import { OtpInput } from './OtpInput.js';
|
|
5
5
|
|
|
@@ -65,6 +65,32 @@ describe('OtpInput', () => {
|
|
|
65
65
|
expect(onComplete).toHaveBeenCalledWith('654321');
|
|
66
66
|
});
|
|
67
67
|
|
|
68
|
+
test('🔴 an autofilled code in the first box fills all six — no box caps it at one digit', () => {
|
|
69
|
+
const onComplete = mock(() => {});
|
|
70
|
+
const { container } = render(<Controlled onComplete={onComplete} />);
|
|
71
|
+
const b = boxes(container);
|
|
72
|
+
// happy-dom does not enforce maxLength on a value set; a phone's autofill does.
|
|
73
|
+
for (const box of b) expect(box.maxLength).toBeGreaterThanOrEqual(6);
|
|
74
|
+
fireEvent.change(b[0], { target: { value: '123456' } });
|
|
75
|
+
expect(val(container)).toBe('123456');
|
|
76
|
+
expect(b.map((x) => x.value)).toEqual(['1', '2', '3', '4', '5', '6']);
|
|
77
|
+
expect(onComplete).toHaveBeenCalledWith('123456');
|
|
78
|
+
});
|
|
79
|
+
|
|
80
|
+
test('a key typed into a box that holds a digit replaces it, not appends to it', () => {
|
|
81
|
+
const { container } = render(<Controlled />);
|
|
82
|
+
const b = boxes(container);
|
|
83
|
+
fireEvent.change(b[0], { target: { value: '1' } });
|
|
84
|
+
fireEvent.change(b[1], { target: { value: '2' } });
|
|
85
|
+
const typed = new InputEvent('input', { bubbles: true, inputType: 'insertText', data: '7' });
|
|
86
|
+
// The browser's own write, under React's value tracker — as a keystroke lands.
|
|
87
|
+
Object.getOwnPropertyDescriptor(HTMLInputElement.prototype, 'value')?.set?.call(b[1], '27');
|
|
88
|
+
act(() => {
|
|
89
|
+
b[1].dispatchEvent(typed);
|
|
90
|
+
});
|
|
91
|
+
expect(val(container)).toBe('17');
|
|
92
|
+
});
|
|
93
|
+
|
|
68
94
|
test('backspace on an empty box clears the previous digit', () => {
|
|
69
95
|
const { container } = render(<Controlled />);
|
|
70
96
|
const b = boxes(container);
|
|
@@ -84,8 +84,11 @@ export function OtpInput({
|
|
|
84
84
|
refs.current[clamped]?.select();
|
|
85
85
|
};
|
|
86
86
|
|
|
87
|
-
const handleChange = (index: number, raw: string) => {
|
|
88
|
-
|
|
87
|
+
const handleChange = (index: number, raw: string, typed: string | null) => {
|
|
88
|
+
// A key typed into a box that already holds a character arrives APPENDED to it ("47"),
|
|
89
|
+
// since no box is capped at one: the key is the event's own `data`. An autofill or a
|
|
90
|
+
// replacement carries the whole code in the value.
|
|
91
|
+
const clean = sanitize(typed ?? raw);
|
|
89
92
|
if (!clean) {
|
|
90
93
|
// A deletion/clear of this box: drop just this position.
|
|
91
94
|
if (chars[index]) commit(chars.slice(0, index).join('') + chars.slice(index + 1).join(''));
|
|
@@ -145,13 +148,18 @@ export function OtpInput({
|
|
|
145
148
|
autoComplete={i === 0 ? 'one-time-code' : 'off'}
|
|
146
149
|
// biome-ignore lint/a11y/noAutofocus: opt-in via prop; first box only
|
|
147
150
|
autoFocus={autoFocus && i === 0}
|
|
148
|
-
maxLength
|
|
151
|
+
// 🔴 Never 1: a browser that honours `maxLength` on autofill (iOS Safari's "From
|
|
152
|
+
// Messages" chip) would hand the code box one digit. `commit` is the limit.
|
|
153
|
+
maxLength={length}
|
|
149
154
|
disabled={disabled}
|
|
150
155
|
value={char}
|
|
151
156
|
aria-label={ariaLabel ? `${ariaLabel} digit ${i + 1}` : `Digit ${i + 1}`}
|
|
152
157
|
aria-invalid={ariaInvalid}
|
|
153
158
|
aria-describedby={i === 0 ? ariaDescribedBy : undefined}
|
|
154
|
-
onChange={(e) =>
|
|
159
|
+
onChange={(e) => {
|
|
160
|
+
const input = e.nativeEvent as InputEvent;
|
|
161
|
+
handleChange(i, e.target.value, input.inputType === 'insertText' && input.data ? input.data : null);
|
|
162
|
+
}}
|
|
155
163
|
onKeyDown={(e) => handleKeyDown(i, e)}
|
|
156
164
|
onPaste={(e) => handlePaste(i, e)}
|
|
157
165
|
onFocus={(e) => e.currentTarget.select()}
|
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
import { afterEach, describe, expect, test } from 'bun:test';
|
|
2
2
|
import { readFileSync } from 'node:fs';
|
|
3
3
|
import { join } from 'node:path';
|
|
4
|
-
import { cleanup, fireEvent, render, screen, waitFor } from '@testing-library/react';
|
|
4
|
+
import { act, cleanup, fireEvent, render, screen, waitFor } from '@testing-library/react';
|
|
5
5
|
import { useState } from 'react';
|
|
6
|
+
import { Button } from './Button.js';
|
|
6
7
|
import { SelectField } from './SelectField.js';
|
|
7
8
|
|
|
8
9
|
afterEach(cleanup);
|
|
@@ -115,3 +116,51 @@ describe('SelectField (lazy)', () => {
|
|
|
115
116
|
expect(screen.getByRole('option', { name: 'Title' })).toBeTruthy();
|
|
116
117
|
});
|
|
117
118
|
});
|
|
119
|
+
|
|
120
|
+
/**
|
|
121
|
+
* 🔴 Inside a <form>, Radix renders a hidden native <select> and copies each value into it; a value
|
|
122
|
+
* that is not one of its options yet reads back as "" and Radix reports `onValueChange("")` — which
|
|
123
|
+
* reset collections' Folder picker after an upload into a NEW folder (forge task 3166).
|
|
124
|
+
*/
|
|
125
|
+
describe('SelectField inside a form', () => {
|
|
126
|
+
function Folder({ calls }: { calls: string[] }) {
|
|
127
|
+
const [value, setValue] = useState('title');
|
|
128
|
+
const [options, setOptions] = useState(OPTIONS);
|
|
129
|
+
return (
|
|
130
|
+
<form>
|
|
131
|
+
<SelectField
|
|
132
|
+
aria-label='Folder'
|
|
133
|
+
name='folder'
|
|
134
|
+
value={value}
|
|
135
|
+
onValueChange={(v) => {
|
|
136
|
+
calls.push(v);
|
|
137
|
+
setValue(v);
|
|
138
|
+
}}
|
|
139
|
+
options={options}
|
|
140
|
+
/>
|
|
141
|
+
<Button
|
|
142
|
+
tooltip='Land the upload in a new folder'
|
|
143
|
+
onClick={() => {
|
|
144
|
+
setValue('landed');
|
|
145
|
+
setOptions([...OPTIONS, { value: 'landed', label: 'Landed' }]);
|
|
146
|
+
}}
|
|
147
|
+
>
|
|
148
|
+
land
|
|
149
|
+
</Button>
|
|
150
|
+
<output data-v>{value}</output>
|
|
151
|
+
</form>
|
|
152
|
+
);
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
test('a value set by code before its option exists is kept — no onValueChange("")', async () => {
|
|
156
|
+
const calls: string[] = [];
|
|
157
|
+
const { container } = render(<Folder calls={calls} />);
|
|
158
|
+
await act(async () => {
|
|
159
|
+
fireEvent.click(screen.getByRole('button', { name: 'land' }));
|
|
160
|
+
await new Promise((r) => setTimeout(r, 20));
|
|
161
|
+
});
|
|
162
|
+
expect(calls).toEqual([]);
|
|
163
|
+
expect(container.querySelector('[data-v]')?.textContent).toBe('landed');
|
|
164
|
+
expect(screen.getByRole('combobox', { name: 'Folder' }).textContent).toContain('Landed');
|
|
165
|
+
});
|
|
166
|
+
});
|
|
@@ -56,7 +56,12 @@ export default function SelectFieldImpl({
|
|
|
56
56
|
return (
|
|
57
57
|
<RSelect.Root
|
|
58
58
|
value={value}
|
|
59
|
-
|
|
59
|
+
// 🔴 "" is never a choice — Radix refuses an item whose value is "". Inside a <form> its
|
|
60
|
+
// hidden native <select> reads "" back for a value code set before that option exists,
|
|
61
|
+
// and reported it here as a pick: collections' Folder picker reset (forge task 3166).
|
|
62
|
+
onValueChange={(next) => {
|
|
63
|
+
if (next !== '') onValueChange?.(next);
|
|
64
|
+
}}
|
|
60
65
|
disabled={disabled}
|
|
61
66
|
name={name}
|
|
62
67
|
required={required}
|