@astryxdesign/core 0.7.6-canary.cfbc66f → 0.7.6-canary.d18fdaa
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/Badge/Badge.d.ts.map +1 -1
- package/dist/Badge/Badge.js +2 -1
- package/dist/DateInput/MonthScroller.d.ts.map +1 -1
- package/dist/DateInput/MonthScroller.js +17 -18
- package/dist/DropdownMenu/DropdownMenuGroup.d.ts.map +1 -1
- package/dist/DropdownMenu/DropdownMenuGroup.js +2 -1
- package/dist/FileInput/FileInput.d.ts.map +1 -1
- package/dist/FileInput/FileInput.js +33 -22
- package/dist/NumberInput/NumberInput.d.ts.map +1 -1
- package/dist/NumberInput/NumberInput.js +11 -15
- package/dist/Typeahead/BaseTypeahead.d.ts.map +1 -1
- package/dist/Typeahead/BaseTypeahead.js +10 -3
- package/package.json +4 -4
- package/src/Badge/Badge.tsx +2 -1
- package/src/DateInput/MonthScroller.tsx +15 -17
- package/src/DropdownMenu/DropdownMenuGroup.tsx +2 -1
- package/src/FileInput/FileInput.tsx +39 -23
- package/src/NumberInput/NumberInput.tsx +11 -18
- package/src/Typeahead/BaseTypeahead.tsx +18 -2
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Badge.d.ts","sourceRoot":"","sources":["../../src/Badge/Badge.tsx"],"names":[],"mappings":"AAEA;;;;;;;;;;;;GAYG;AAEH,OAAO,KAAK,EAAC,SAAS,EAAC,MAAM,OAAO,CAAC;AACrC,OAAO,KAAK,EAAC,SAAS,EAAC,MAAM,cAAc,CAAC;
|
|
1
|
+
{"version":3,"file":"Badge.d.ts","sourceRoot":"","sources":["../../src/Badge/Badge.tsx"],"names":[],"mappings":"AAEA;;;;;;;;;;;;GAYG;AAEH,OAAO,KAAK,EAAC,SAAS,EAAC,MAAM,OAAO,CAAC;AACrC,OAAO,KAAK,EAAC,SAAS,EAAC,MAAM,cAAc,CAAC;AAY5C,OAAO,KAAK,EAAC,eAAe,EAAC,MAAM,SAAS,CAAC;AAwJ7C;;;GAGG;AACH,MAAM,MAAM,YAAY,GAAG,MAAM,eAAe,CAAC;AAEjD,MAAM,WAAW,UAAW,SAAQ,SAAS,CAAC,eAAe,CAAC;IAC5D,wCAAwC;IACxC,GAAG,CAAC,EAAE,KAAK,CAAC,GAAG,CAAC,eAAe,CAAC,CAAC;IACjC;;;OAGG;IACH,OAAO,CAAC,EAAE,YAAY,CAAC;IACvB;;OAEG;IACH,KAAK,EAAE,SAAS,CAAC;IAEjB;;OAEG;IACH,IAAI,CAAC,EAAE,SAAS,CAAC;CAClB;AAED;;;;;;;;;;;;;GAaG;AACH,wBAAgB,KAAK,CAAC,EACpB,OAAmB,EACnB,KAAK,EACL,IAAI,EACJ,MAAM,EACN,SAAS,EACT,KAAK,EACL,GAAG,EACH,GAAG,KAAK,EACT,EAAE,UAAU,+BA6CZ;yBAtDe,KAAK"}
|
package/dist/Badge/Badge.js
CHANGED
|
@@ -19,6 +19,7 @@ import "../theme/tokens.stylex.js";
|
|
|
19
19
|
import { colorVars, spacingVars, radiusVars, fontWeightVars, typeScaleVars } from "../theme/tokens.stylex.js";
|
|
20
20
|
import { mergeProps } from "../utils/index.js";
|
|
21
21
|
import { themeProps } from "../utils/themeProps.js";
|
|
22
|
+
import { isRenderable } from "../utils/isRenderable.js";
|
|
22
23
|
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
23
24
|
/**
|
|
24
25
|
* Base badge styles
|
|
@@ -187,7 +188,7 @@ export function Badge({
|
|
|
187
188
|
// a client component, so it is tracked in #5585.
|
|
188
189
|
const labelTitle = typeof label === 'number' ? String(label) : typeof label === 'string' && label.length > 0 ? label : undefined;
|
|
189
190
|
// Whether the label renders anything, which is when the badge grows with it.
|
|
190
|
-
const hasLabel = label
|
|
191
|
+
const hasLabel = isRenderable(label);
|
|
191
192
|
return /*#__PURE__*/_jsxs("span", {
|
|
192
193
|
ref: ref,
|
|
193
194
|
...mergeProps(themeProps('badge', {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"MonthScroller.d.ts","sourceRoot":"","sources":["../../src/DateInput/MonthScroller.tsx"],"names":[],"mappings":"AAoDA,OAAO,EACL,KAAK,SAAS,EACd,KAAK,aAAa,EAClB,KAAK,SAAS,EAQf,MAAM,UAAU,CAAC;
|
|
1
|
+
{"version":3,"file":"MonthScroller.d.ts","sourceRoot":"","sources":["../../src/DateInput/MonthScroller.tsx"],"names":[],"mappings":"AAoDA,OAAO,EACL,KAAK,SAAS,EACd,KAAK,aAAa,EAClB,KAAK,SAAS,EAQf,MAAM,UAAU,CAAC;AAgNlB,MAAM,WAAW,mBAAmB;IAClC,0DAA0D;IAC1D,aAAa,EAAE,CAAC,UAAU,EAAE,MAAM,EAAE,QAAQ,CAAC,EAAE,cAAc,KAAK,IAAI,CAAC;CACxE;AAED,MAAM,WAAW,kBAAkB;IACjC,yEAAyE;IACzE,SAAS,CAAC,EAAE,KAAK,CAAC,SAAS,CAAC,mBAAmB,GAAG,IAAI,CAAC,CAAC;IACxD,+CAA+C;IAC/C,aAAa,EAAE,MAAM,CAAC;IACtB,8CAA8C;IAC9C,aAAa,EAAE,MAAM,CAAC;IACtB,iCAAiC;IACjC,iBAAiB,EAAE,MAAM,CAAC;IAC1B,+DAA+D;IAC/D,oBAAoB,EAAE,CAAC,UAAU,EAAE,MAAM,KAAK,IAAI,CAAC;IACnD,+BAA+B;IAC/B,YAAY,EAAE,SAAS,GAAG,IAAI,CAAC;IAC/B,4CAA4C;IAC5C,KAAK,EAAE,SAAS,CAAC;IACjB,2DAA2D;IAC3D,cAAc,EAAE,CAAC,IAAI,EAAE,SAAS,KAAK,OAAO,CAAC;IAC7C,gCAAgC;IAChC,YAAY,EAAE,SAAS,CAAC;IACxB,kCAAkC;IAClC,QAAQ,EAAE,CAAC,KAAK,EAAE,aAAa,KAAK,IAAI,CAAC;CAC1C;AAED;;GAEG;AACH,wBAAgB,aAAa,CAAC,EAC5B,SAAS,EACT,aAAa,EACb,aAAa,EACb,iBAAiB,EACjB,oBAAoB,EACpB,YAAY,EACZ,KAAK,EACL,cAAc,EACd,YAAY,EACZ,QAAQ,GACT,EAAE,kBAAkB,+BA0fpB;yBArgBe,aAAa"}
|
|
@@ -54,8 +54,10 @@ const DAY_SIZE = dateInputTouchSizes.daySize;
|
|
|
54
54
|
*/
|
|
55
55
|
const OVERSCAN = 3;
|
|
56
56
|
|
|
57
|
-
/**
|
|
58
|
-
const
|
|
57
|
+
/** Every listener on the scroller is passive; one options object serves all. */
|
|
58
|
+
const PASSIVE = {
|
|
59
|
+
passive: true
|
|
60
|
+
};
|
|
59
61
|
const styles = {
|
|
60
62
|
spacer: {
|
|
61
63
|
kVAEAm: "x1n2onr6",
|
|
@@ -483,23 +485,20 @@ export function MonthScroller({
|
|
|
483
485
|
onVisibleMonthChangeRef.current(minMonthIndex + row);
|
|
484
486
|
});
|
|
485
487
|
};
|
|
486
|
-
scroller.addEventListener('scroll', onScroll,
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
}
|
|
494
|
-
scroller.addEventListener('touchstart', onTouchStart, {
|
|
495
|
-
passive: true
|
|
496
|
-
});
|
|
488
|
+
scroller.addEventListener('scroll', onScroll, PASSIVE);
|
|
489
|
+
// The user's input on the scroller ends a steer: from here, it's theirs.
|
|
490
|
+
scroller.addEventListener('touchstart', endSteer, PASSIVE);
|
|
491
|
+
scroller.addEventListener('wheel', endSteer, PASSIVE);
|
|
492
|
+
scroller.addEventListener('pointerdown', endSteer, PASSIVE);
|
|
493
|
+
scroller.addEventListener('keydown', endSteer, PASSIVE);
|
|
494
|
+
scroller.addEventListener('touchstart', onTouchStart, PASSIVE);
|
|
497
495
|
return () => {
|
|
498
|
-
scroller.removeEventListener('scroll', onScroll);
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
scroller.removeEventListener('
|
|
496
|
+
scroller.removeEventListener('scroll', onScroll, PASSIVE);
|
|
497
|
+
scroller.removeEventListener('touchstart', endSteer, PASSIVE);
|
|
498
|
+
scroller.removeEventListener('wheel', endSteer, PASSIVE);
|
|
499
|
+
scroller.removeEventListener('pointerdown', endSteer, PASSIVE);
|
|
500
|
+
scroller.removeEventListener('keydown', endSteer, PASSIVE);
|
|
501
|
+
scroller.removeEventListener('touchstart', onTouchStart, PASSIVE);
|
|
503
502
|
if (frameRef.current != null) {
|
|
504
503
|
cancelAnimationFrame(frameRef.current);
|
|
505
504
|
frameRef.current = undefined;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"DropdownMenuGroup.d.ts","sourceRoot":"","sources":["../../src/DropdownMenu/DropdownMenuGroup.tsx"],"names":[],"mappings":"AAIA;;;;;;;;;;;;;;;;;;;;GAoBG;AAEH,OAAO,EAAQ,KAAK,SAAS,EAAC,MAAM,OAAO,CAAC;AAQ5C,OAAO,KAAK,EAAC,SAAS,EAAC,MAAM,cAAc,CAAC;
|
|
1
|
+
{"version":3,"file":"DropdownMenuGroup.d.ts","sourceRoot":"","sources":["../../src/DropdownMenu/DropdownMenuGroup.tsx"],"names":[],"mappings":"AAIA;;;;;;;;;;;;;;;;;;;;GAoBG;AAEH,OAAO,EAAQ,KAAK,SAAS,EAAC,MAAM,OAAO,CAAC;AAQ5C,OAAO,KAAK,EAAC,SAAS,EAAC,MAAM,cAAc,CAAC;AAiB5C,MAAM,WAAW,sBAAuB,SAAQ,IAAI,CAClD,SAAS,CAAC,cAAc,CAAC,EACzB,MAAM,CACP;IACC;;;;OAIG;IACH,KAAK,CAAC,EAAE,SAAS,CAAC;IAClB,sEAAsE;IACtE,QAAQ,CAAC,EAAE,SAAS,CAAC;IACrB,mDAAmD;IACnD,GAAG,CAAC,EAAE,KAAK,CAAC,GAAG,CAAC,cAAc,CAAC,CAAC;CACjC;AAED;;;;;;;;;;;;;;;;;;;;;;GAsBG;AACH,wBAAgB,iBAAiB,CAAC,EAChC,KAAK,EACL,QAAQ,EACR,MAAM,EACN,SAAS,EACT,KAAK,EACL,GAAG,EACH,iBAAiB,EAAE,cAAc,EACjC,GAAG,IAAI,EACR,EAAE,sBAAsB,+BAwBxB;yBAjCe,iBAAiB"}
|
|
@@ -29,6 +29,7 @@ import "../theme/tokens.stylex.js";
|
|
|
29
29
|
import { colorVars, spacingVars, typographyVars, typeScaleVars } from "../theme/tokens.stylex.js";
|
|
30
30
|
import { mergeProps } from "../utils/index.js";
|
|
31
31
|
import { themeProps } from "../utils/themeProps.js";
|
|
32
|
+
import { isRenderable } from "../utils/isRenderable.js";
|
|
32
33
|
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
33
34
|
/**
|
|
34
35
|
* A titled group of menu rows.
|
|
@@ -64,7 +65,7 @@ export function DropdownMenuGroup({
|
|
|
64
65
|
...rest
|
|
65
66
|
}) {
|
|
66
67
|
const headingId = useId();
|
|
67
|
-
const hasTitle = title
|
|
68
|
+
const hasTitle = isRenderable(title);
|
|
68
69
|
return /*#__PURE__*/_jsxs("div", {
|
|
69
70
|
...rest,
|
|
70
71
|
ref: ref,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"FileInput.d.ts","sourceRoot":"","sources":["../../src/FileInput/FileInput.tsx"],"names":[],"mappings":"AAuCA,OAAO,EAGL,KAAK,WAAW,EAChB,KAAK,kBAAkB,EACxB,MAAM,UAAU,CAAC;AAUlB,YAAY,EACV,WAAW,IAAI,eAAe,EAC9B,eAAe,IAAI,mBAAmB,GACvC,MAAM,UAAU,CAAC;AAGlB,OAAO,EACL,KAAK,mBAAmB,EAEzB,MAAM,qBAAqB,CAAC;AAC7B,OAAO,KAAK,EAAC,SAAS,EAAC,MAAM,gBAAgB,CAAC;
|
|
1
|
+
{"version":3,"file":"FileInput.d.ts","sourceRoot":"","sources":["../../src/FileInput/FileInput.tsx"],"names":[],"mappings":"AAuCA,OAAO,EAGL,KAAK,WAAW,EAChB,KAAK,kBAAkB,EACxB,MAAM,UAAU,CAAC;AAUlB,YAAY,EACV,WAAW,IAAI,eAAe,EAC9B,eAAe,IAAI,mBAAmB,GACvC,MAAM,UAAU,CAAC;AAGlB,OAAO,EACL,KAAK,mBAAmB,EAEzB,MAAM,qBAAqB,CAAC;AAC7B,OAAO,KAAK,EAAC,SAAS,EAAC,MAAM,gBAAgB,CAAC;AA2P9C,MAAM,WAAW,cAAe,SAAQ,IAAI,CAC1C,mBAAmB,EACnB,UAAU,GAAG,cAAc,GAAG,OAAO,CACtC;IACC;;OAEG;IACH,GAAG,CAAC,EAAE,KAAK,CAAC,GAAG,CAAC,gBAAgB,CAAC,CAAC;IAClC;;OAEG;IACH,KAAK,EAAE,MAAM,CAAC;IACd;;;OAGG;IACH,aAAa,CAAC,EAAE,OAAO,CAAC;IACxB;;OAEG;IACH,KAAK,EAAE,IAAI,GAAG,IAAI,EAAE,GAAG,IAAI,CAAC;IAC5B;;OAEG;IACH,QAAQ,EAAE,CAAC,KAAK,EAAE,IAAI,GAAG,IAAI,EAAE,GAAG,IAAI,KAAK,IAAI,CAAC;IAChD;;;OAGG;IACH,YAAY,CAAC,EAAE,CAAC,KAAK,EAAE,IAAI,GAAG,IAAI,EAAE,GAAG,IAAI,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;IAC9D;;;OAGG;IACH,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB;;;;OAIG;IACH,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB;;;OAGG;IACH,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB;;OAEG;IACH,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB;;;OAGG;IACH,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB;;;;;;;;;;;;;;;;;;;OAmBG;IACH,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB;;;OAGG;IACH,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB;;;OAGG;IACH,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB;;OAEG;IACH,MAAM,CAAC,EAAE,WAAW,CAAC;IACrB;;;;;;OAMG;IACH,aAAa,CAAC,EAAE,kBAAkB,CAAC;IACnC;;OAEG;IACH,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB;;;OAGG;IACH,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB;;;;;OAKG;IACH,IAAI,CAAC,EAAE,UAAU,GAAG,OAAO,CAAC;IAC5B;;;OAGG;IACH,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB;;;;OAIG;IACH,KAAK,CAAC,EAAE,SAAS,CAAC;IAClB;;OAEG;IACH,YAAY,CAAC,EAAE,MAAM,CAAC;CACvB;AAED;;;;;;;GAOG;AACH,wBAAgB,SAAS,CAAC,EACxB,KAAK,EACL,aAAqB,EACrB,KAAK,EACL,QAAQ,EACR,YAAY,EACZ,MAAM,EACN,UAAkB,EAClB,OAAO,EACP,QAAQ,EACR,UAAkB,EAClB,eAAe,EACf,UAAkB,EAClB,SAAiB,EACjB,MAAM,EAAE,UAAU,EAClB,aAA0B,EAC1B,WAAW,EACX,WAAW,EACX,IAAc,EACd,UAAkB,EAClB,YAAY,EACZ,KAAK,EACL,eAAe,EACf,kBAAkB,EAClB,cAAc,EACd,aAAa,EACb,gBAAgB,EAChB,YAAY,EACZ,GAAG,EACH,EAAE,EAAE,MAAM,EACV,GAAG,SAAS,EACb,EAAE,cAAc,+BA0fhB;yBAzhBe,SAAS"}
|
|
@@ -164,6 +164,11 @@ const styles = {
|
|
|
164
164
|
kSiTet: "xbyyjgo",
|
|
165
165
|
kVAM5u: "xvy26l8 x6q1khz",
|
|
166
166
|
$$css: true
|
|
167
|
+
},
|
|
168
|
+
busy: {
|
|
169
|
+
kkrTdU: "xt0e3qv",
|
|
170
|
+
kGVxlE: "x1gnnqk1",
|
|
171
|
+
$$css: true
|
|
167
172
|
}
|
|
168
173
|
};
|
|
169
174
|
const statusBorderStyles = {
|
|
@@ -243,6 +248,10 @@ export function FileInput({
|
|
|
243
248
|
const [, startTransition] = useTransition();
|
|
244
249
|
const [optimisticValue, setOptimisticValue] = useOptimistic(value);
|
|
245
250
|
const isBusy = isLoading || optimisticValue !== value;
|
|
251
|
+
const isSelectionDisabled = isDisabled || isBusy;
|
|
252
|
+
if (isDragOver && isSelectionDisabled) {
|
|
253
|
+
setIsDragOver(false);
|
|
254
|
+
}
|
|
246
255
|
// A pick is one user action, already announced as "file selected"; a busy
|
|
247
256
|
// period it starts (changeAction, or a caller setting isLoading from
|
|
248
257
|
// onChange) adds no second message (spec:AST-086 FR6). The mark lasts until
|
|
@@ -301,7 +310,7 @@ export function FileInput({
|
|
|
301
310
|
const defaultPlaceholder = isMultiple ? t('@astryx.fileInput.placeholderMultiple') : t('@astryx.fileInput.placeholder');
|
|
302
311
|
const displayPlaceholder = placeholder ?? defaultPlaceholder;
|
|
303
312
|
const handleFiles = useCallback(fileList => {
|
|
304
|
-
if (
|
|
313
|
+
if (isSelectionDisabled) {
|
|
305
314
|
return;
|
|
306
315
|
}
|
|
307
316
|
const {
|
|
@@ -340,7 +349,7 @@ export function FileInput({
|
|
|
340
349
|
await changeAction(result);
|
|
341
350
|
});
|
|
342
351
|
}
|
|
343
|
-
}, [accept,
|
|
352
|
+
}, [accept, isSelectionDisabled, isMultiple, maxFiles, maxSize, onChange, changeAction, startTransition, setOptimisticValue, announce, t, formatList]);
|
|
344
353
|
const handleInputChange = useCallback(e => {
|
|
345
354
|
const fileList = Array.from(e.target.files ?? []);
|
|
346
355
|
handleFiles(fileList);
|
|
@@ -377,20 +386,22 @@ export function FileInput({
|
|
|
377
386
|
}
|
|
378
387
|
}, [onChange, changeAction, startTransition, setOptimisticValue]);
|
|
379
388
|
const handleClick = useCallback(() => {
|
|
380
|
-
if (!
|
|
389
|
+
if (!isSelectionDisabled) {
|
|
381
390
|
inputRef.current?.click();
|
|
382
391
|
}
|
|
383
|
-
}, [
|
|
392
|
+
}, [isSelectionDisabled]);
|
|
384
393
|
|
|
385
394
|
// Explicit keyboard activation so Enter/Space open the picker even where a
|
|
386
|
-
// synthetic keydown does not raise a native click.
|
|
387
|
-
//
|
|
395
|
+
// synthetic keydown does not raise a native click. Disabled and busy triggers
|
|
396
|
+
// also cancel the default activation while remaining focusable.
|
|
388
397
|
const handleKeyDown = useCallback(e => {
|
|
389
|
-
if (
|
|
398
|
+
if (e.key === 'Enter' || e.key === ' ') {
|
|
390
399
|
e.preventDefault();
|
|
391
|
-
|
|
400
|
+
if (!isSelectionDisabled) {
|
|
401
|
+
inputRef.current?.click();
|
|
402
|
+
}
|
|
392
403
|
}
|
|
393
|
-
}, [
|
|
404
|
+
}, [isSelectionDisabled]);
|
|
394
405
|
|
|
395
406
|
// Make the surface clickable without giving it an interactive role. Clicks on
|
|
396
407
|
// the nested clear/status controls are ignored by the hook, so those buttons
|
|
@@ -401,22 +412,22 @@ export function FileInput({
|
|
|
401
412
|
} = useClickableContainer({
|
|
402
413
|
containerRef,
|
|
403
414
|
onClick: handleClick,
|
|
404
|
-
disabled:
|
|
415
|
+
disabled: isSelectionDisabled
|
|
405
416
|
});
|
|
406
417
|
const handleDragEnter = useCallback(e => {
|
|
407
418
|
e.preventDefault();
|
|
408
419
|
e.stopPropagation();
|
|
409
|
-
if (!
|
|
420
|
+
if (!isSelectionDisabled && mode === 'dropzone') {
|
|
410
421
|
setIsDragOver(true);
|
|
411
422
|
}
|
|
412
|
-
}, [
|
|
423
|
+
}, [isSelectionDisabled, mode]);
|
|
413
424
|
const handleDragOver = useCallback(e => {
|
|
414
425
|
e.preventDefault();
|
|
415
426
|
e.stopPropagation();
|
|
416
|
-
if (!
|
|
427
|
+
if (!isSelectionDisabled && mode === 'dropzone') {
|
|
417
428
|
setIsDragOver(true);
|
|
418
429
|
}
|
|
419
|
-
}, [
|
|
430
|
+
}, [isSelectionDisabled, mode]);
|
|
420
431
|
const handleDragLeave = useCallback(e => {
|
|
421
432
|
e.preventDefault();
|
|
422
433
|
e.stopPropagation();
|
|
@@ -432,14 +443,14 @@ export function FileInput({
|
|
|
432
443
|
e.preventDefault();
|
|
433
444
|
e.stopPropagation();
|
|
434
445
|
setIsDragOver(false);
|
|
435
|
-
if (
|
|
446
|
+
if (isSelectionDisabled || mode !== 'dropzone') {
|
|
436
447
|
return;
|
|
437
448
|
}
|
|
438
449
|
const fileList = Array.from(e.dataTransfer.files);
|
|
439
450
|
if (fileList.length > 0) {
|
|
440
451
|
handleFiles(fileList);
|
|
441
452
|
}
|
|
442
|
-
}, [
|
|
453
|
+
}, [isSelectionDisabled, mode, handleFiles]);
|
|
443
454
|
const hasFiles = optimisticValue != null && (Array.isArray(optimisticValue) ? optimisticValue.length > 0 : true);
|
|
444
455
|
const fileNames = hasFiles ? Array.isArray(optimisticValue) ? optimisticValue.map(f => f.name).join(', ') : optimisticValue?.name ?? '' : null;
|
|
445
456
|
|
|
@@ -560,13 +571,13 @@ export function FileInput({
|
|
|
560
571
|
// keyboard focus. Handlers are gated internally by isEnabled.
|
|
561
572
|
disabledMessageTooltip.ref(el);
|
|
562
573
|
},
|
|
563
|
-
onClick: !
|
|
564
|
-
onMouseUp: !
|
|
574
|
+
onClick: !isSelectionDisabled ? onContainerClick : undefined,
|
|
575
|
+
onMouseUp: !isSelectionDisabled ? onContainerMouseUp : undefined,
|
|
565
576
|
...dragDropProps,
|
|
566
577
|
...mergeProps(themeProps('file-input', {
|
|
567
578
|
mode,
|
|
568
579
|
status: status?.type ?? null
|
|
569
|
-
}), stylex.props(isDropzone ? styles.dropzone : styles.compact, isDropzone && !
|
|
580
|
+
}), stylex.props(isDropzone ? styles.dropzone : styles.compact, isDropzone && !isSelectionDisabled && styles.dropzoneHover, isDropzone && !isSelectionDisabled && isDragOver && styles.dropzoneActive, isDropzone && isDisabled && styles.dropzoneDisabled, !isDropzone && isDisabled && styles.compactDisabled, isBusy && styles.busy, status && statusBorderStyles[status.type], controlXstyle), controlClassName, controlStyle),
|
|
570
581
|
children: [/*#__PURE__*/_jsx(VisuallyHidden, {
|
|
571
582
|
children: /*#__PURE__*/_jsx("button", {
|
|
572
583
|
ref: triggerRef,
|
|
@@ -574,7 +585,7 @@ export function FileInput({
|
|
|
574
585
|
// A disabled trigger keeps its Tab stop (spec:AST-085 FR1).
|
|
575
586
|
,
|
|
576
587
|
tabIndex: 0,
|
|
577
|
-
"aria-disabled":
|
|
588
|
+
"aria-disabled": isSelectionDisabled ? 'true' : undefined,
|
|
578
589
|
onClick: handleClick,
|
|
579
590
|
onKeyDown: handleKeyDown
|
|
580
591
|
// aria-label suppresses child content from the accessible name, so
|
|
@@ -602,9 +613,9 @@ export function FileInput({
|
|
|
602
613
|
,
|
|
603
614
|
form: isDisabled ? '' : undefined
|
|
604
615
|
// A label or description click activates this input directly; cancel
|
|
605
|
-
// it so a disabled input never opens the picker (FR2).
|
|
616
|
+
// it so a disabled or busy input never opens the picker (FR2).
|
|
606
617
|
,
|
|
607
|
-
onClick:
|
|
618
|
+
onClick: isSelectionDisabled ? event => event.preventDefault() : rest.onClick,
|
|
608
619
|
onChange: handleInputChange
|
|
609
620
|
// The visually-hidden native input is never focused (tabIndex={-1});
|
|
610
621
|
// its describedby/required/invalid live on the trigger button.
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"NumberInput.d.ts","sourceRoot":"","sources":["../../src/NumberInput/NumberInput.tsx"],"names":[],"mappings":"AAIA;;;;;;;;;;;;;;GAcG;AAEH,OAAO,
|
|
1
|
+
{"version":3,"file":"NumberInput.d.ts","sourceRoot":"","sources":["../../src/NumberInput/NumberInput.tsx"],"names":[],"mappings":"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"}
|
|
@@ -17,7 +17,8 @@
|
|
|
17
17
|
* - /apps/storybook/stories/NumberInput.stories.tsx (storybook stories)
|
|
18
18
|
* - /packages/cli/assets/templates/blocks/components/NumberInput/ (showcase blocks)
|
|
19
19
|
*/
|
|
20
|
-
import { use, useId, useState, useMemo, useCallback,
|
|
20
|
+
import { use, useId, useState, useMemo, useCallback, useRef } from 'react';
|
|
21
|
+
import { flushSync } from 'react-dom';
|
|
21
22
|
import * as stylex from '@stylexjs/stylex';
|
|
22
23
|
import "../theme/tokens.stylex.js";
|
|
23
24
|
import { colorVars, sizeVars, spacingVars, typographyVars, typeScaleVars, borderVars } from "../theme/tokens.stylex.js";
|
|
@@ -367,27 +368,22 @@ export function NumberInput({
|
|
|
367
368
|
// `formatValue` the text at rest differs from the editable text, and putting
|
|
368
369
|
// the editable text in the input after focus collapses that selection to the
|
|
369
370
|
// end, so typing would append. When focus arrives with the text selected,
|
|
370
|
-
//
|
|
371
|
-
|
|
371
|
+
// the focus handler commits the swap and selects the swapped-in text itself:
|
|
372
|
+
// the work one event causes stays in its handler
|
|
373
|
+
// (architecture:react-component-runtime/INV2).
|
|
372
374
|
const handleFocus = useCallback(e => {
|
|
373
375
|
const input = e.currentTarget;
|
|
374
|
-
// Only when focusing swaps the text: otherwise no render follows to
|
|
375
|
-
// consume the flag, and the first keystroke would.
|
|
376
376
|
const editableText = pendingInput ?? (value == null ? '' : formatEditableNumber(value, locale));
|
|
377
|
-
|
|
377
|
+
const shouldReselect = input.value.length > 0 && input.value !== editableText && input.selectionStart === 0 && input.selectionEnd === input.value.length;
|
|
378
378
|
setIsFocused(true);
|
|
379
379
|
onFocus?.(e);
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
}
|
|
385
|
-
reselectOnFocusRef.current = false;
|
|
386
|
-
const input = inputRef.current;
|
|
387
|
-
if (input != null && input === document.activeElement) {
|
|
380
|
+
if (shouldReselect) {
|
|
381
|
+
// Commit the swap now, so the editable text is in the input to select.
|
|
382
|
+
// eslint-disable-next-line @eslint-react/dom-no-flush-sync -- the editable text must be in the input before the focus event selects it
|
|
383
|
+
flushSync(() => {});
|
|
388
384
|
input.setSelectionRange(0, input.value.length);
|
|
389
385
|
}
|
|
390
|
-
}, [
|
|
386
|
+
}, [onFocus, pendingInput, value, locale]);
|
|
391
387
|
const commitPendingInput = useCallback(trigger => {
|
|
392
388
|
if (pendingInput === null) {
|
|
393
389
|
return;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"BaseTypeahead.d.ts","sourceRoot":"","sources":["../../src/Typeahead/BaseTypeahead.tsx"],"names":[],"mappings":"AAIA;;;;;;;;;;;;;GAaG;AAEH,OAAO,KAAK,EAAE,EAMZ,KAAK,SAAS,EACd,KAAK,SAAS,EACf,MAAM,OAAO,CAAC;AAIf,OAAO,KAAK,EAAC,YAAY,EAAC,MAAM,kBAAkB,CAAC;AA2BnD,OAAO,KAAK,EAAC,SAAS,EAAC,MAAM,cAAc,CAAC;AAC5C,OAAO,KAAK,EAAC,cAAc,EAAE,YAAY,EAAC,MAAM,SAAS,CAAC;AAY1D,MAAM,WAAW,kBAAkB,CAAC,CAAC,SAAS,cAAc,CAAE,SAAQ,IAAI,CACxE,SAAS,CAAC,WAAW,CAAC,EACtB,UAAU,CACX;IACC,GAAG,CAAC,EAAE,KAAK,CAAC,GAAG,CAAC,gBAAgB,CAAC,CAAC;IAClC;;OAEG;IACH,YAAY,EAAE,YAAY,CAAC,CAAC,CAAC,CAAC;IAE9B;;OAEG;IACH,KAAK,EAAE,CAAC,GAAG,IAAI,CAAC;IAEhB;;OAEG;IACH,QAAQ,EAAE,CAAC,IAAI,EAAE,CAAC,GAAG,IAAI,KAAK,IAAI,CAAC;IAEnC;;OAEG;IACH,UAAU,CAAC,EAAE,CAAC,IAAI,EAAE,CAAC,KAAK,SAAS,CAAC;IAEpC;;OAEG;IACH,WAAW,CAAC,EAAE,MAAM,CAAC;IAErB;;;OAGG;IACH,iBAAiB,CAAC,EAAE,OAAO,CAAC;IAE5B;;;OAGG;IACH,YAAY,CAAC,EAAE,MAAM,CAAC;IAEtB,mEAAmE;IACnE,SAAS,CAAC,EAAE,MAAM,CAAC;IAEnB;;;;;;;;;;OAUG;IACH,cAAc,CAAC,EAAE,MAAM,CAAC;IAExB;;;;;;;;;;;;;OAaG;IACH,eAAe,CAAC,EAAE,SAAS,CAAC;IAE5B;;;OAGG;IACH,UAAU,CAAC,EAAE,OAAO,CAAC;IAErB;;;;;;;;;OASG;IACH,mBAAmB,CAAC,EAAE,OAAO,CAAC;IAE9B;;;OAGG;IACH,YAAY,CAAC,EAAE,OAAO,CAAC;IAEvB;;OAEG;IACH,aAAa,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;IAExC;;OAEG;IACH,YAAY,CAAC,EAAE,CAAC,MAAM,EAAE,OAAO,KAAK,IAAI,CAAC;IAEzC;;;;;;;;;;;;;;;;;;;OAmBG;IACH,cAAc,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,EAAE,OAAO,EAAE,CAAC,EAAE,KAAK,CAAC,EAAE,CAAC;IAEtD;;;;OAIG;IACH,UAAU,CAAC,EAAE,MAAM,CAAC;IAEpB;;;OAGG;IACH,OAAO,CAAC,EAAE,MAAM,CAAC;IAEjB;;;OAGG;IACH,eAAe,CAAC,EAAE,MAAM,CAAC;IAEzB;;;OAGG;IACH,cAAc,CAAC,EAAE,MAAM,CAAC;IAExB;;OAEG;IACH,WAAW,CAAC,EAAE,YAAY,CAAC;IAE3B;;;;;;;;OAQG;IACH,aAAa,CAAC,EAAE,MAAM,CAAC;IAEvB;;;;OAIG;IACH,SAAS,CAAC,EAAE,SAAS,CAAC,WAAW,GAAG,IAAI,CAAC,CAAC;IAE1C;;;OAGG;IACH,SAAS,CAAC,EAAE,CAAC,CAAC,EAAE,KAAK,CAAC,aAAa,CAAC,gBAAgB,CAAC,KAAK,IAAI,CAAC;IAE/D;;;;OAIG;IACH,IAAI,CAAC,EAAE,IAAI,GAAG,IAAI,GAAG,IAAI,CAAC;CAC3B;AAoKD;;;;;;;;;;;;;;;;;;;GAmBG;AACH,eAAO,MAAM,aAAa,
|
|
1
|
+
{"version":3,"file":"BaseTypeahead.d.ts","sourceRoot":"","sources":["../../src/Typeahead/BaseTypeahead.tsx"],"names":[],"mappings":"AAIA;;;;;;;;;;;;;GAaG;AAEH,OAAO,KAAK,EAAE,EAMZ,KAAK,SAAS,EACd,KAAK,SAAS,EACf,MAAM,OAAO,CAAC;AAIf,OAAO,KAAK,EAAC,YAAY,EAAC,MAAM,kBAAkB,CAAC;AA2BnD,OAAO,KAAK,EAAC,SAAS,EAAC,MAAM,cAAc,CAAC;AAC5C,OAAO,KAAK,EAAC,cAAc,EAAE,YAAY,EAAC,MAAM,SAAS,CAAC;AAY1D,MAAM,WAAW,kBAAkB,CAAC,CAAC,SAAS,cAAc,CAAE,SAAQ,IAAI,CACxE,SAAS,CAAC,WAAW,CAAC,EACtB,UAAU,CACX;IACC,GAAG,CAAC,EAAE,KAAK,CAAC,GAAG,CAAC,gBAAgB,CAAC,CAAC;IAClC;;OAEG;IACH,YAAY,EAAE,YAAY,CAAC,CAAC,CAAC,CAAC;IAE9B;;OAEG;IACH,KAAK,EAAE,CAAC,GAAG,IAAI,CAAC;IAEhB;;OAEG;IACH,QAAQ,EAAE,CAAC,IAAI,EAAE,CAAC,GAAG,IAAI,KAAK,IAAI,CAAC;IAEnC;;OAEG;IACH,UAAU,CAAC,EAAE,CAAC,IAAI,EAAE,CAAC,KAAK,SAAS,CAAC;IAEpC;;OAEG;IACH,WAAW,CAAC,EAAE,MAAM,CAAC;IAErB;;;OAGG;IACH,iBAAiB,CAAC,EAAE,OAAO,CAAC;IAE5B;;;OAGG;IACH,YAAY,CAAC,EAAE,MAAM,CAAC;IAEtB,mEAAmE;IACnE,SAAS,CAAC,EAAE,MAAM,CAAC;IAEnB;;;;;;;;;;OAUG;IACH,cAAc,CAAC,EAAE,MAAM,CAAC;IAExB;;;;;;;;;;;;;OAaG;IACH,eAAe,CAAC,EAAE,SAAS,CAAC;IAE5B;;;OAGG;IACH,UAAU,CAAC,EAAE,OAAO,CAAC;IAErB;;;;;;;;;OASG;IACH,mBAAmB,CAAC,EAAE,OAAO,CAAC;IAE9B;;;OAGG;IACH,YAAY,CAAC,EAAE,OAAO,CAAC;IAEvB;;OAEG;IACH,aAAa,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;IAExC;;OAEG;IACH,YAAY,CAAC,EAAE,CAAC,MAAM,EAAE,OAAO,KAAK,IAAI,CAAC;IAEzC;;;;;;;;;;;;;;;;;;;OAmBG;IACH,cAAc,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,EAAE,OAAO,EAAE,CAAC,EAAE,KAAK,CAAC,EAAE,CAAC;IAEtD;;;;OAIG;IACH,UAAU,CAAC,EAAE,MAAM,CAAC;IAEpB;;;OAGG;IACH,OAAO,CAAC,EAAE,MAAM,CAAC;IAEjB;;;OAGG;IACH,eAAe,CAAC,EAAE,MAAM,CAAC;IAEzB;;;OAGG;IACH,cAAc,CAAC,EAAE,MAAM,CAAC;IAExB;;OAEG;IACH,WAAW,CAAC,EAAE,YAAY,CAAC;IAE3B;;;;;;;;OAQG;IACH,aAAa,CAAC,EAAE,MAAM,CAAC;IAEvB;;;;OAIG;IACH,SAAS,CAAC,EAAE,SAAS,CAAC,WAAW,GAAG,IAAI,CAAC,CAAC;IAE1C;;;OAGG;IACH,SAAS,CAAC,EAAE,CAAC,CAAC,EAAE,KAAK,CAAC,aAAa,CAAC,gBAAgB,CAAC,KAAK,IAAI,CAAC;IAE/D;;;;OAIG;IACH,IAAI,CAAC,EAAE,IAAI,GAAG,IAAI,GAAG,IAAI,CAAC;CAC3B;AAoKD;;;;;;;;;;;;;;;;;;;GAmBG;AACH,eAAO,MAAM,aAAa,EAi8BrB,CAAC,CAAC,SAAS,cAAc,EAC5B,KAAK,EAAE,kBAAkB,CAAC,CAAC,CAAC,KACzB,KAAK,CAAC,YAAY,CAAC"}
|
|
@@ -715,14 +715,21 @@ export const BaseTypeahead = function BaseTypeahead({
|
|
|
715
715
|
if (!popover.isOpen) {
|
|
716
716
|
if (e.key === 'ArrowDown' && (hasEntriesOnFocus || query.length > 0)) {
|
|
717
717
|
e.preventDefault();
|
|
718
|
-
|
|
718
|
+
// Results held from a replaced search source are not current
|
|
719
|
+
// (spec:AST-092 FR4): they count as none, so the new source loads.
|
|
720
|
+
const hasResultsFromCurrentSource = results.length > 0 && resultsGenRef.current >= sourceGenRef.current;
|
|
721
|
+
const isQueryBelowMinLength = isBelowMinQueryLength(query, minQueryLength);
|
|
722
|
+
if (hasResultsFromCurrentSource) {
|
|
719
723
|
popover.show();
|
|
720
724
|
setHighlightedIndex(0);
|
|
725
|
+
} else if (results.length > 0 && query.length > 0 && !isQueryBelowMinLength) {
|
|
726
|
+
// The typed query runs again against the new source.
|
|
727
|
+
void performSearch(query);
|
|
721
728
|
} else if (hasEntriesOnFocus &&
|
|
722
729
|
// A below-threshold query was never searched; falling back to the
|
|
723
730
|
// bootstrap entries here would open a menu of suggestions that
|
|
724
731
|
// ignore what the user has already typed.
|
|
725
|
-
!
|
|
732
|
+
!isQueryBelowMinLength) {
|
|
726
733
|
void performBootstrap();
|
|
727
734
|
}
|
|
728
735
|
}
|
|
@@ -776,7 +783,7 @@ export const BaseTypeahead = function BaseTypeahead({
|
|
|
776
783
|
}
|
|
777
784
|
break;
|
|
778
785
|
}
|
|
779
|
-
}, [isDisabled, popover, results, highlightedIndex, handleSelect, hasEntriesOnFocus, query, minQueryLength, performBootstrap, externalOnKeyDown]);
|
|
786
|
+
}, [isDisabled, popover, results, highlightedIndex, handleSelect, hasEntriesOnFocus, query, minQueryLength, performBootstrap, performSearch, externalOnKeyDown]);
|
|
780
787
|
|
|
781
788
|
// Generate item ID for accessibility
|
|
782
789
|
const getItemId = useCallback(index => `${listboxId}-option-${index}`, [listboxId]);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@astryxdesign/core",
|
|
3
|
-
"version": "0.7.6-canary.
|
|
3
|
+
"version": "0.7.6-canary.d18fdaa",
|
|
4
4
|
"displayName": "Astryx Core",
|
|
5
5
|
"description": "The component library. Accessible, themeable React components with built-in spacing, dark mode, and StyleX styling.",
|
|
6
6
|
"author": "Meta Open Source",
|
|
@@ -860,9 +860,9 @@
|
|
|
860
860
|
"react-dom": ">=19.0.0"
|
|
861
861
|
},
|
|
862
862
|
"devDependencies": {
|
|
863
|
-
"@astryxdesign/a11y-spec": "0.7.6-canary.
|
|
864
|
-
"@astryxdesign/cli": "0.7.6-canary.
|
|
865
|
-
"@astryxdesign/interaction-harness": "0.7.6-canary.
|
|
863
|
+
"@astryxdesign/a11y-spec": "0.7.6-canary.d18fdaa",
|
|
864
|
+
"@astryxdesign/cli": "0.7.6-canary.d18fdaa",
|
|
865
|
+
"@astryxdesign/interaction-harness": "0.7.6-canary.d18fdaa",
|
|
866
866
|
"@babel/cli": "^7.29.7",
|
|
867
867
|
"@babel/core": "^7.29.7",
|
|
868
868
|
"@babel/preset-react": "^7.29.7",
|
package/src/Badge/Badge.tsx
CHANGED
|
@@ -26,6 +26,7 @@ import {
|
|
|
26
26
|
} from '../theme/tokens.stylex';
|
|
27
27
|
import {mergeProps} from '../utils';
|
|
28
28
|
import {themeProps} from '../utils/themeProps';
|
|
29
|
+
import {isRenderable} from '../utils/isRenderable';
|
|
29
30
|
import type {BadgeVariantMap} from './index';
|
|
30
31
|
|
|
31
32
|
/**
|
|
@@ -249,7 +250,7 @@ export function Badge({
|
|
|
249
250
|
? label
|
|
250
251
|
: undefined;
|
|
251
252
|
// Whether the label renders anything, which is when the badge grows with it.
|
|
252
|
-
const hasLabel = label
|
|
253
|
+
const hasLabel = isRenderable(label);
|
|
253
254
|
|
|
254
255
|
return (
|
|
255
256
|
<span
|
|
@@ -85,13 +85,8 @@ const DAY_SIZE = dateInputTouchSizes.daySize;
|
|
|
85
85
|
*/
|
|
86
86
|
const OVERSCAN = 3;
|
|
87
87
|
|
|
88
|
-
/**
|
|
89
|
-
const
|
|
90
|
-
'touchstart',
|
|
91
|
-
'wheel',
|
|
92
|
-
'pointerdown',
|
|
93
|
-
'keydown',
|
|
94
|
-
] as const;
|
|
88
|
+
/** Every listener on the scroller is passive; one options object serves all. */
|
|
89
|
+
const PASSIVE: AddEventListenerOptions = {passive: true};
|
|
95
90
|
|
|
96
91
|
const styles = stylex.create({
|
|
97
92
|
scroller: {
|
|
@@ -682,17 +677,20 @@ export function MonthScroller({
|
|
|
682
677
|
onVisibleMonthChangeRef.current(minMonthIndex + row);
|
|
683
678
|
});
|
|
684
679
|
};
|
|
685
|
-
scroller.addEventListener('scroll', onScroll,
|
|
686
|
-
|
|
687
|
-
|
|
688
|
-
|
|
689
|
-
scroller.addEventListener('
|
|
680
|
+
scroller.addEventListener('scroll', onScroll, PASSIVE);
|
|
681
|
+
// The user's input on the scroller ends a steer: from here, it's theirs.
|
|
682
|
+
scroller.addEventListener('touchstart', endSteer, PASSIVE);
|
|
683
|
+
scroller.addEventListener('wheel', endSteer, PASSIVE);
|
|
684
|
+
scroller.addEventListener('pointerdown', endSteer, PASSIVE);
|
|
685
|
+
scroller.addEventListener('keydown', endSteer, PASSIVE);
|
|
686
|
+
scroller.addEventListener('touchstart', onTouchStart, PASSIVE);
|
|
690
687
|
return () => {
|
|
691
|
-
scroller.removeEventListener('scroll', onScroll);
|
|
692
|
-
|
|
693
|
-
|
|
694
|
-
|
|
695
|
-
scroller.removeEventListener('
|
|
688
|
+
scroller.removeEventListener('scroll', onScroll, PASSIVE);
|
|
689
|
+
scroller.removeEventListener('touchstart', endSteer, PASSIVE);
|
|
690
|
+
scroller.removeEventListener('wheel', endSteer, PASSIVE);
|
|
691
|
+
scroller.removeEventListener('pointerdown', endSteer, PASSIVE);
|
|
692
|
+
scroller.removeEventListener('keydown', endSteer, PASSIVE);
|
|
693
|
+
scroller.removeEventListener('touchstart', onTouchStart, PASSIVE);
|
|
696
694
|
if (frameRef.current != null) {
|
|
697
695
|
cancelAnimationFrame(frameRef.current);
|
|
698
696
|
frameRef.current = undefined;
|
|
@@ -35,6 +35,7 @@ import {
|
|
|
35
35
|
import type {BaseProps} from '../BaseProps';
|
|
36
36
|
import {mergeProps} from '../utils';
|
|
37
37
|
import {themeProps} from '../utils/themeProps';
|
|
38
|
+
import {isRenderable} from '../utils/isRenderable';
|
|
38
39
|
|
|
39
40
|
const styles = stylex.create({
|
|
40
41
|
heading: {
|
|
@@ -98,7 +99,7 @@ export function DropdownMenuGroup({
|
|
|
98
99
|
...rest
|
|
99
100
|
}: DropdownMenuGroupProps) {
|
|
100
101
|
const headingId = useId();
|
|
101
|
-
const hasTitle = title
|
|
102
|
+
const hasTitle = isRenderable(title);
|
|
102
103
|
|
|
103
104
|
return (
|
|
104
105
|
<div
|
|
@@ -238,6 +238,10 @@ const styles = stylex.create({
|
|
|
238
238
|
':focus-within': colorVars['--color-accent'],
|
|
239
239
|
},
|
|
240
240
|
},
|
|
241
|
+
busy: {
|
|
242
|
+
cursor: 'default',
|
|
243
|
+
boxShadow: 'none',
|
|
244
|
+
},
|
|
241
245
|
hiddenInput: {
|
|
242
246
|
position: 'absolute',
|
|
243
247
|
width: 1,
|
|
@@ -500,6 +504,10 @@ export function FileInput({
|
|
|
500
504
|
const [, startTransition] = useTransition();
|
|
501
505
|
const [optimisticValue, setOptimisticValue] = useOptimistic(value);
|
|
502
506
|
const isBusy = isLoading || optimisticValue !== value;
|
|
507
|
+
const isSelectionDisabled = isDisabled || isBusy;
|
|
508
|
+
if (isDragOver && isSelectionDisabled) {
|
|
509
|
+
setIsDragOver(false);
|
|
510
|
+
}
|
|
503
511
|
// A pick is one user action, already announced as "file selected"; a busy
|
|
504
512
|
// period it starts (changeAction, or a caller setting isLoading from
|
|
505
513
|
// onChange) adds no second message (spec:AST-086 FR6). The mark lasts until
|
|
@@ -574,7 +582,7 @@ export function FileInput({
|
|
|
574
582
|
|
|
575
583
|
const handleFiles = useCallback(
|
|
576
584
|
(fileList: File[]) => {
|
|
577
|
-
if (
|
|
585
|
+
if (isSelectionDisabled) {
|
|
578
586
|
return;
|
|
579
587
|
}
|
|
580
588
|
|
|
@@ -625,7 +633,7 @@ export function FileInput({
|
|
|
625
633
|
},
|
|
626
634
|
[
|
|
627
635
|
accept,
|
|
628
|
-
|
|
636
|
+
isSelectionDisabled,
|
|
629
637
|
isMultiple,
|
|
630
638
|
maxFiles,
|
|
631
639
|
maxSize,
|
|
@@ -681,22 +689,24 @@ export function FileInput({
|
|
|
681
689
|
);
|
|
682
690
|
|
|
683
691
|
const handleClick = useCallback(() => {
|
|
684
|
-
if (!
|
|
692
|
+
if (!isSelectionDisabled) {
|
|
685
693
|
inputRef.current?.click();
|
|
686
694
|
}
|
|
687
|
-
}, [
|
|
695
|
+
}, [isSelectionDisabled]);
|
|
688
696
|
|
|
689
697
|
// Explicit keyboard activation so Enter/Space open the picker even where a
|
|
690
|
-
// synthetic keydown does not raise a native click.
|
|
691
|
-
//
|
|
698
|
+
// synthetic keydown does not raise a native click. Disabled and busy triggers
|
|
699
|
+
// also cancel the default activation while remaining focusable.
|
|
692
700
|
const handleKeyDown = useCallback(
|
|
693
701
|
(e: React.KeyboardEvent) => {
|
|
694
|
-
if (
|
|
702
|
+
if (e.key === 'Enter' || e.key === ' ') {
|
|
695
703
|
e.preventDefault();
|
|
696
|
-
|
|
704
|
+
if (!isSelectionDisabled) {
|
|
705
|
+
inputRef.current?.click();
|
|
706
|
+
}
|
|
697
707
|
}
|
|
698
708
|
},
|
|
699
|
-
[
|
|
709
|
+
[isSelectionDisabled],
|
|
700
710
|
);
|
|
701
711
|
|
|
702
712
|
// Make the surface clickable without giving it an interactive role. Clicks on
|
|
@@ -706,29 +716,29 @@ export function FileInput({
|
|
|
706
716
|
useClickableContainer({
|
|
707
717
|
containerRef,
|
|
708
718
|
onClick: handleClick,
|
|
709
|
-
disabled:
|
|
719
|
+
disabled: isSelectionDisabled,
|
|
710
720
|
});
|
|
711
721
|
|
|
712
722
|
const handleDragEnter = useCallback(
|
|
713
723
|
(e: DragEvent) => {
|
|
714
724
|
e.preventDefault();
|
|
715
725
|
e.stopPropagation();
|
|
716
|
-
if (!
|
|
726
|
+
if (!isSelectionDisabled && mode === 'dropzone') {
|
|
717
727
|
setIsDragOver(true);
|
|
718
728
|
}
|
|
719
729
|
},
|
|
720
|
-
[
|
|
730
|
+
[isSelectionDisabled, mode],
|
|
721
731
|
);
|
|
722
732
|
|
|
723
733
|
const handleDragOver = useCallback(
|
|
724
734
|
(e: DragEvent) => {
|
|
725
735
|
e.preventDefault();
|
|
726
736
|
e.stopPropagation();
|
|
727
|
-
if (!
|
|
737
|
+
if (!isSelectionDisabled && mode === 'dropzone') {
|
|
728
738
|
setIsDragOver(true);
|
|
729
739
|
}
|
|
730
740
|
},
|
|
731
|
-
[
|
|
741
|
+
[isSelectionDisabled, mode],
|
|
732
742
|
);
|
|
733
743
|
|
|
734
744
|
const handleDragLeave = useCallback((e: DragEvent) => {
|
|
@@ -751,7 +761,7 @@ export function FileInput({
|
|
|
751
761
|
e.preventDefault();
|
|
752
762
|
e.stopPropagation();
|
|
753
763
|
setIsDragOver(false);
|
|
754
|
-
if (
|
|
764
|
+
if (isSelectionDisabled || mode !== 'dropzone') {
|
|
755
765
|
return;
|
|
756
766
|
}
|
|
757
767
|
const fileList = Array.from(e.dataTransfer.files);
|
|
@@ -759,7 +769,7 @@ export function FileInput({
|
|
|
759
769
|
handleFiles(fileList);
|
|
760
770
|
}
|
|
761
771
|
},
|
|
762
|
-
[
|
|
772
|
+
[isSelectionDisabled, mode, handleFiles],
|
|
763
773
|
);
|
|
764
774
|
|
|
765
775
|
const hasFiles =
|
|
@@ -889,17 +899,21 @@ export function FileInput({
|
|
|
889
899
|
// keyboard focus. Handlers are gated internally by isEnabled.
|
|
890
900
|
disabledMessageTooltip.ref(el);
|
|
891
901
|
}}
|
|
892
|
-
onClick={!
|
|
893
|
-
onMouseUp={!
|
|
902
|
+
onClick={!isSelectionDisabled ? onContainerClick : undefined}
|
|
903
|
+
onMouseUp={!isSelectionDisabled ? onContainerMouseUp : undefined}
|
|
894
904
|
{...dragDropProps}
|
|
895
905
|
{...mergeProps(
|
|
896
906
|
themeProps('file-input', {mode, status: status?.type ?? null}),
|
|
897
907
|
stylex.props(
|
|
898
908
|
isDropzone ? styles.dropzone : styles.compact,
|
|
899
|
-
isDropzone && !
|
|
900
|
-
isDropzone &&
|
|
909
|
+
isDropzone && !isSelectionDisabled && styles.dropzoneHover,
|
|
910
|
+
isDropzone &&
|
|
911
|
+
!isSelectionDisabled &&
|
|
912
|
+
isDragOver &&
|
|
913
|
+
styles.dropzoneActive,
|
|
901
914
|
isDropzone && isDisabled && styles.dropzoneDisabled,
|
|
902
915
|
!isDropzone && isDisabled && styles.compactDisabled,
|
|
916
|
+
isBusy && styles.busy,
|
|
903
917
|
status && statusBorderStyles[status.type],
|
|
904
918
|
controlXstyle,
|
|
905
919
|
),
|
|
@@ -919,7 +933,7 @@ export function FileInput({
|
|
|
919
933
|
type="button"
|
|
920
934
|
// A disabled trigger keeps its Tab stop (spec:AST-085 FR1).
|
|
921
935
|
tabIndex={0}
|
|
922
|
-
aria-disabled={
|
|
936
|
+
aria-disabled={isSelectionDisabled ? 'true' : undefined}
|
|
923
937
|
onClick={handleClick}
|
|
924
938
|
onKeyDown={handleKeyDown}
|
|
925
939
|
// aria-label suppresses child content from the accessible name, so
|
|
@@ -947,8 +961,10 @@ export function FileInput({
|
|
|
947
961
|
// submitted and `required` does not block submission (FR3).
|
|
948
962
|
form={isDisabled ? '' : undefined}
|
|
949
963
|
// A label or description click activates this input directly; cancel
|
|
950
|
-
// it so a disabled input never opens the picker (FR2).
|
|
951
|
-
onClick={
|
|
964
|
+
// it so a disabled or busy input never opens the picker (FR2).
|
|
965
|
+
onClick={
|
|
966
|
+
isSelectionDisabled ? event => event.preventDefault() : rest.onClick
|
|
967
|
+
}
|
|
952
968
|
onChange={handleInputChange}
|
|
953
969
|
// The visually-hidden native input is never focused (tabIndex={-1});
|
|
954
970
|
// its describedby/required/invalid live on the trigger button.
|
|
@@ -24,12 +24,12 @@ import {
|
|
|
24
24
|
useState,
|
|
25
25
|
useMemo,
|
|
26
26
|
useCallback,
|
|
27
|
-
useLayoutEffect,
|
|
28
27
|
useRef,
|
|
29
28
|
type FocusEvent,
|
|
30
29
|
type KeyboardEvent,
|
|
31
30
|
type ReactNode,
|
|
32
31
|
} from 'react';
|
|
32
|
+
import {flushSync} from 'react-dom';
|
|
33
33
|
import * as stylex from '@stylexjs/stylex';
|
|
34
34
|
import {
|
|
35
35
|
colorVars,
|
|
@@ -723,39 +723,32 @@ export function NumberInput({
|
|
|
723
723
|
// `formatValue` the text at rest differs from the editable text, and putting
|
|
724
724
|
// the editable text in the input after focus collapses that selection to the
|
|
725
725
|
// end, so typing would append. When focus arrives with the text selected,
|
|
726
|
-
//
|
|
727
|
-
|
|
728
|
-
|
|
726
|
+
// the focus handler commits the swap and selects the swapped-in text itself:
|
|
727
|
+
// the work one event causes stays in its handler
|
|
728
|
+
// (architecture:react-component-runtime/INV2).
|
|
729
729
|
const handleFocus = useCallback(
|
|
730
730
|
(e: FocusEvent<HTMLInputElement>) => {
|
|
731
731
|
const input = e.currentTarget;
|
|
732
|
-
// Only when focusing swaps the text: otherwise no render follows to
|
|
733
|
-
// consume the flag, and the first keystroke would.
|
|
734
732
|
const editableText =
|
|
735
733
|
pendingInput ??
|
|
736
734
|
(value == null ? '' : formatEditableNumber(value, locale));
|
|
737
|
-
|
|
735
|
+
const shouldReselect =
|
|
738
736
|
input.value.length > 0 &&
|
|
739
737
|
input.value !== editableText &&
|
|
740
738
|
input.selectionStart === 0 &&
|
|
741
739
|
input.selectionEnd === input.value.length;
|
|
742
740
|
setIsFocused(true);
|
|
743
741
|
onFocus?.(e);
|
|
742
|
+
if (shouldReselect) {
|
|
743
|
+
// Commit the swap now, so the editable text is in the input to select.
|
|
744
|
+
// eslint-disable-next-line @eslint-react/dom-no-flush-sync -- the editable text must be in the input before the focus event selects it
|
|
745
|
+
flushSync(() => {});
|
|
746
|
+
input.setSelectionRange(0, input.value.length);
|
|
747
|
+
}
|
|
744
748
|
},
|
|
745
749
|
[onFocus, pendingInput, value, locale],
|
|
746
750
|
);
|
|
747
751
|
|
|
748
|
-
useLayoutEffect(() => {
|
|
749
|
-
if (!reselectOnFocusRef.current) {
|
|
750
|
-
return;
|
|
751
|
-
}
|
|
752
|
-
reselectOnFocusRef.current = false;
|
|
753
|
-
const input = inputRef.current;
|
|
754
|
-
if (input != null && input === document.activeElement) {
|
|
755
|
-
input.setSelectionRange(0, input.value.length);
|
|
756
|
-
}
|
|
757
|
-
}, [displayValue]);
|
|
758
|
-
|
|
759
752
|
const commitPendingInput = useCallback(
|
|
760
753
|
(trigger: 'blur' | 'Enter') => {
|
|
761
754
|
if (pendingInput === null) {
|
|
@@ -1091,15 +1091,30 @@ export const BaseTypeahead = function BaseTypeahead<T extends SearchableItem>({
|
|
|
1091
1091
|
if (!popover.isOpen) {
|
|
1092
1092
|
if (e.key === 'ArrowDown' && (hasEntriesOnFocus || query.length > 0)) {
|
|
1093
1093
|
e.preventDefault();
|
|
1094
|
-
|
|
1094
|
+
// Results held from a replaced search source are not current
|
|
1095
|
+
// (spec:AST-092 FR4): they count as none, so the new source loads.
|
|
1096
|
+
const hasResultsFromCurrentSource =
|
|
1097
|
+
results.length > 0 && resultsGenRef.current >= sourceGenRef.current;
|
|
1098
|
+
const isQueryBelowMinLength = isBelowMinQueryLength(
|
|
1099
|
+
query,
|
|
1100
|
+
minQueryLength,
|
|
1101
|
+
);
|
|
1102
|
+
if (hasResultsFromCurrentSource) {
|
|
1095
1103
|
popover.show();
|
|
1096
1104
|
setHighlightedIndex(0);
|
|
1105
|
+
} else if (
|
|
1106
|
+
results.length > 0 &&
|
|
1107
|
+
query.length > 0 &&
|
|
1108
|
+
!isQueryBelowMinLength
|
|
1109
|
+
) {
|
|
1110
|
+
// The typed query runs again against the new source.
|
|
1111
|
+
void performSearch(query);
|
|
1097
1112
|
} else if (
|
|
1098
1113
|
hasEntriesOnFocus &&
|
|
1099
1114
|
// A below-threshold query was never searched; falling back to the
|
|
1100
1115
|
// bootstrap entries here would open a menu of suggestions that
|
|
1101
1116
|
// ignore what the user has already typed.
|
|
1102
|
-
!
|
|
1117
|
+
!isQueryBelowMinLength
|
|
1103
1118
|
) {
|
|
1104
1119
|
void performBootstrap();
|
|
1105
1120
|
}
|
|
@@ -1170,6 +1185,7 @@ export const BaseTypeahead = function BaseTypeahead<T extends SearchableItem>({
|
|
|
1170
1185
|
query,
|
|
1171
1186
|
minQueryLength,
|
|
1172
1187
|
performBootstrap,
|
|
1188
|
+
performSearch,
|
|
1173
1189
|
externalOnKeyDown,
|
|
1174
1190
|
],
|
|
1175
1191
|
);
|