@astryxdesign/lab 0.7.3-canary.d421aed → 0.7.3-canary.da1020b
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/Comments/CommentComposer.d.ts.map +1 -1
- package/dist/Comments/CommentComposer.js +14 -2
- package/dist/Comments/CommentParts.d.ts.map +1 -1
- package/dist/Comments/CommentParts.js +4 -3
- package/dist/MobileTokenizer/MobileTokenizer.d.ts.map +1 -1
- package/dist/MobileTokenizer/MobileTokenizer.js +49 -11
- package/dist/lab.css +2 -0
- package/package.json +4 -4
- package/src/Comments/CommentComposer.test.tsx +83 -1
- package/src/Comments/CommentComposer.tsx +14 -2
- package/src/Comments/CommentParts.tsx +3 -6
- package/src/MobileTokenizer/MobileTokenizer.test.tsx +138 -0
- package/src/MobileTokenizer/MobileTokenizer.tsx +81 -10
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"CommentComposer.d.ts","sourceRoot":"","sources":["../../src/Comments/CommentComposer.tsx"],"names":[],"mappings":"AAIA;;;;;;;;;;;;;;GAcG;AAEH,OAAO,EAOL,KAAK,SAAS,EACd,KAAK,GAAG,EACT,MAAM,OAAO,CAAC;AAEf,OAAO,KAAK,EAAC,SAAS,EAAC,MAAM,oBAAoB,CAAC;AAGlD,OAAO,EAKL,KAAK,mBAAmB,EAEzB,MAAM,yBAAyB,CAAC;AAqBjC,OAAO,KAAK,EACV,mBAAmB,EACnB,aAAa,EACb,sBAAsB,EACtB,0BAA0B,EAC1B,qBAAqB,EACrB,oBAAoB,EACrB,MAAM,SAAS,CAAC;AAkGjB,0DAA0D;AAC1D,MAAM,WAAW,wBAAwB;IACvC,KAAK,EAAE,MAAM,CAAC;IACd,QAAQ,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;IAClC,QAAQ,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;IAClC,WAAW,EAAE,MAAM,CAAC;IACpB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,YAAY,EAAE,OAAO,CAAC;IACtB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,+CAA+C;IAC/C,YAAY,CAAC,EAAE,MAAM,IAAI,CAAC;IAC1B,QAAQ,CAAC,EAAE,MAAM,IAAI,CAAC;IACtB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,OAAO,EAAE,sBAAsB,CAAC;IAChC,MAAM,CAAC,EAAE,aAAa,CAAC;IACvB,eAAe,CAAC,EAAE,MAAM,IAAI,CAAC;IAC7B,cAAc,EAAE,qBAAqB,CAAC;IACtC,cAAc,CAAC,EAAE,CACf,KAAK,EAAE,SAAS,IAAI,EAAE,KAEtB,SAAS,oBAAoB,EAAE,GAAG,OAAO,CAAC,SAAS,oBAAoB,EAAE,CAAC,CAAC;IAC7E,QAAQ,EAAE,SAAS,mBAAmB,EAAE,CAAC;IACzC,aAAa,EAAE,SAAS,mBAAmB,EAAE,CAAC;IAC9C,cAAc,EAAE,OAAO,CAAC;IACxB,QAAQ,CAAC,EAAE,SAAS,CAAC;IACrB,uEAAuE;IACvE,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,2EAA2E;IAC3E,qBAAqB,CAAC,EAAE,CAAC,SAAS,EAAE,OAAO,KAAK,IAAI,CAAC;IACrD,cAAc,CAAC,EAAE,CAAC,KAAK,EAAE,0BAA0B,KAAK,SAAS,CAAC;IAClE,OAAO,CAAC,EAAE,GAAG,CAAC,WAAW,CAAC,CAAC;IAC3B,SAAS,CAAC,EAAE,IAAI,CAAC,SAAS,CAAC,WAAW,CAAC,EAAE,UAAU,GAAG,UAAU,CAAC,CAAC;CACnE;AAED,kDAAkD;AAClD,wBAAgB,mBAAmB,CAAC,EAClC,MAAM,EACN,aAAa,EACb,OAAO,EACP,YAAY,EACZ,QAAQ,EACR,KAAK,EACL,QAAQ,EACR,cAAc,EACd,cAAc,EACd,YAAY,EACZ,KAAK,EACL,qBAAqB,EACrB,eAAe,EACf,QAAQ,EACR,QAAQ,EACR,YAAY,EACZ,QAAQ,EACR,cAAc,EACd,WAAW,EACX,cAAc,EACd,SAAS,EACT,OAAO,EACP,QAAQ,EAAE,YAAY,EACtB,KAAK,GACN,EAAE,wBAAwB,+
|
|
1
|
+
{"version":3,"file":"CommentComposer.d.ts","sourceRoot":"","sources":["../../src/Comments/CommentComposer.tsx"],"names":[],"mappings":"AAIA;;;;;;;;;;;;;;GAcG;AAEH,OAAO,EAOL,KAAK,SAAS,EACd,KAAK,GAAG,EACT,MAAM,OAAO,CAAC;AAEf,OAAO,KAAK,EAAC,SAAS,EAAC,MAAM,oBAAoB,CAAC;AAGlD,OAAO,EAKL,KAAK,mBAAmB,EAEzB,MAAM,yBAAyB,CAAC;AAqBjC,OAAO,KAAK,EACV,mBAAmB,EACnB,aAAa,EACb,sBAAsB,EACtB,0BAA0B,EAC1B,qBAAqB,EACrB,oBAAoB,EACrB,MAAM,SAAS,CAAC;AAkGjB,0DAA0D;AAC1D,MAAM,WAAW,wBAAwB;IACvC,KAAK,EAAE,MAAM,CAAC;IACd,QAAQ,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;IAClC,QAAQ,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;IAClC,WAAW,EAAE,MAAM,CAAC;IACpB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,YAAY,EAAE,OAAO,CAAC;IACtB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,+CAA+C;IAC/C,YAAY,CAAC,EAAE,MAAM,IAAI,CAAC;IAC1B,QAAQ,CAAC,EAAE,MAAM,IAAI,CAAC;IACtB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,OAAO,EAAE,sBAAsB,CAAC;IAChC,MAAM,CAAC,EAAE,aAAa,CAAC;IACvB,eAAe,CAAC,EAAE,MAAM,IAAI,CAAC;IAC7B,cAAc,EAAE,qBAAqB,CAAC;IACtC,cAAc,CAAC,EAAE,CACf,KAAK,EAAE,SAAS,IAAI,EAAE,KAEtB,SAAS,oBAAoB,EAAE,GAAG,OAAO,CAAC,SAAS,oBAAoB,EAAE,CAAC,CAAC;IAC7E,QAAQ,EAAE,SAAS,mBAAmB,EAAE,CAAC;IACzC,aAAa,EAAE,SAAS,mBAAmB,EAAE,CAAC;IAC9C,cAAc,EAAE,OAAO,CAAC;IACxB,QAAQ,CAAC,EAAE,SAAS,CAAC;IACrB,uEAAuE;IACvE,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,2EAA2E;IAC3E,qBAAqB,CAAC,EAAE,CAAC,SAAS,EAAE,OAAO,KAAK,IAAI,CAAC;IACrD,cAAc,CAAC,EAAE,CAAC,KAAK,EAAE,0BAA0B,KAAK,SAAS,CAAC;IAClE,OAAO,CAAC,EAAE,GAAG,CAAC,WAAW,CAAC,CAAC;IAC3B,SAAS,CAAC,EAAE,IAAI,CAAC,SAAS,CAAC,WAAW,CAAC,EAAE,UAAU,GAAG,UAAU,CAAC,CAAC;CACnE;AAED,kDAAkD;AAClD,wBAAgB,mBAAmB,CAAC,EAClC,MAAM,EACN,aAAa,EACb,OAAO,EACP,YAAY,EACZ,QAAQ,EACR,KAAK,EACL,QAAQ,EACR,cAAc,EACd,cAAc,EACd,YAAY,EACZ,KAAK,EACL,qBAAqB,EACrB,eAAe,EACf,QAAQ,EACR,QAAQ,EACR,YAAY,EACZ,QAAQ,EACR,cAAc,EACd,WAAW,EACX,cAAc,EACd,SAAS,EACT,OAAO,EACP,QAAQ,EAAE,YAAY,EACtB,KAAK,GACN,EAAE,wBAAwB,+BAqW1B;AAED,MAAM,WAAW,oBAAqB,SAAQ,IAAI,CAChD,SAAS,CAAC,WAAW,CAAC,EACtB,UAAU,GAAG,UAAU,CACxB;IACC,yCAAyC;IACzC,GAAG,CAAC,EAAE,GAAG,CAAC,WAAW,CAAC,CAAC;IACvB,6BAA6B;IAC7B,KAAK,EAAE,MAAM,CAAC;IACd,QAAQ,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;IAClC,2EAA2E;IAC3E,QAAQ,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;IAClC,8EAA8E;IAC9E,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,iEAAiE;IACjE,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,6EAA6E;IAC7E,YAAY,CAAC,EAAE,OAAO,CAAC;IACvB,gDAAgD;IAChD,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,sCAAsC;IACtC,OAAO,CAAC,EAAE,MAAM,IAAI,CAAC;IACrB,4EAA4E;IAC5E,MAAM,CAAC,EAAE,aAAa,CAAC;IACvB,qDAAqD;IACrD,eAAe,CAAC,EAAE,MAAM,IAAI,CAAC;IAC7B,2EAA2E;IAC3E,cAAc,CAAC,EAAE,qBAAqB,CAAC;IACvC;;;OAGG;IACH,cAAc,CAAC,EAAE,CACf,KAAK,EAAE,SAAS,IAAI,EAAE,KAEtB,SAAS,oBAAoB,EAAE,GAAG,OAAO,CAAC,SAAS,oBAAoB,EAAE,CAAC,CAAC;IAC7E,wDAAwD;IACxD,QAAQ,CAAC,EAAE,SAAS,mBAAmB,EAAE,CAAC;IAC1C,6DAA6D;IAC7D,aAAa,CAAC,EAAE,SAAS,mBAAmB,EAAE,CAAC;IAC/C,2DAA2D;IAC3D,cAAc,CAAC,EAAE,OAAO,CAAC;IACzB;;;;OAIG;IACH,QAAQ,CAAC,EAAE,SAAS,CAAC;CACtB;AAED;;;;;;;;;GASG;AACH,wBAAgB,eAAe,CAAC,EAC9B,KAAK,EACL,QAAQ,EACR,QAAQ,EACR,WAAW,EACX,KAAK,EACL,YAAoB,EACpB,KAAK,EACL,OAAO,EACP,MAAM,EACN,eAAe,EACf,cAAyB,EACzB,cAAc,EACd,QAAsB,EACtB,aAAiC,EACjC,cAAqB,EACrB,QAAQ,EACR,GAAG,EACH,GAAG,SAAS,EACb,EAAE,oBAAoB,+BAyBtB;yBA5Ce,eAAe"}
|
|
@@ -152,6 +152,8 @@ export function CommentComposerBase({
|
|
|
152
152
|
latestValueRef.current = value;
|
|
153
153
|
const isMountedRef = useRef(true);
|
|
154
154
|
const actionPendingRef = useRef(false);
|
|
155
|
+
const isSubmittingRef = useRef(isSubmitting);
|
|
156
|
+
isSubmittingRef.current = isSubmitting;
|
|
155
157
|
const imageInputRef = useRef(null);
|
|
156
158
|
const inputRef = useRef(null);
|
|
157
159
|
// Focus lands once per `focusKey`, when the input attaches: the handle ref
|
|
@@ -224,7 +226,15 @@ export function CommentComposerBase({
|
|
|
224
226
|
setActionError({
|
|
225
227
|
title: t('@astryx.commentComposer.imagesOnly'),
|
|
226
228
|
actionLabel: t('@astryx.commentComposer.chooseImages'),
|
|
227
|
-
onAction: () =>
|
|
229
|
+
onAction: () => {
|
|
230
|
+
// The picker input is never natively disabled, so its click() would
|
|
231
|
+
// open the file chooser while busy and the busy guard would drop
|
|
232
|
+
// the pick.
|
|
233
|
+
if (isSubmittingRef.current || actionPendingRef.current) {
|
|
234
|
+
return;
|
|
235
|
+
}
|
|
236
|
+
imageInputRef.current?.click();
|
|
237
|
+
}
|
|
228
238
|
});
|
|
229
239
|
return;
|
|
230
240
|
}
|
|
@@ -329,10 +339,12 @@ export function CommentComposerBase({
|
|
|
329
339
|
accept: "image/*",
|
|
330
340
|
multiple: true,
|
|
331
341
|
hidden: true,
|
|
332
|
-
disabled: isBusy,
|
|
333
342
|
onChange: event => {
|
|
334
343
|
const files = Array.from(event.currentTarget.files ?? []);
|
|
335
344
|
event.currentTarget.value = '';
|
|
345
|
+
if (isBusy) {
|
|
346
|
+
return;
|
|
347
|
+
}
|
|
336
348
|
beginImageUpload(files);
|
|
337
349
|
}
|
|
338
350
|
}), /*#__PURE__*/_jsx(IconButton, {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"CommentParts.d.ts","sourceRoot":"","sources":["../../src/Comments/CommentParts.tsx"],"names":[],"mappings":"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
|
|
1
|
+
{"version":3,"file":"CommentParts.d.ts","sourceRoot":"","sources":["../../src/Comments/CommentParts.tsx"],"names":[],"mappings":"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"}
|
|
@@ -334,9 +334,10 @@ export function MetadataActionLink({
|
|
|
334
334
|
type: textType,
|
|
335
335
|
color: "secondary",
|
|
336
336
|
xstyle: partStyles.noWrap,
|
|
337
|
-
"data-metadata-action": actionRole
|
|
338
|
-
|
|
339
|
-
|
|
337
|
+
"data-metadata-action": actionRole
|
|
338
|
+
// Link keeps a disabled link in the tab order (spec:AST-085 FR1).
|
|
339
|
+
,
|
|
340
|
+
isDisabled: isDisabled,
|
|
340
341
|
onClick: event => {
|
|
341
342
|
event.preventDefault();
|
|
342
343
|
if (isDisabled !== true) {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"MobileTokenizer.d.ts","sourceRoot":"","sources":["../../src/MobileTokenizer/MobileTokenizer.tsx"],"names":[],"mappings":"AA+BA,OAAO,KAAK,EAAC,SAAS,EAAC,MAAM,oBAAoB,CAAC;AAYlD,OAAO,KAAK,EAAC,cAAc,EAAE,YAAY,EAAC,MAAM,8BAA8B,CAAC;AAQ/E,MAAM,MAAM,qBAAqB,CAAC,CAAC,SAAS,cAAc,IACtD;IAAC,IAAI,EAAE,CAAC,CAAC;IAAC,IAAI,EAAE,KAAK,CAAA;CAAC,GACtB;IAAC,IAAI,EAAE,CAAC,CAAC;IAAC,IAAI,EAAE,QAAQ,CAAA;CAAC,GACzB;IAAC,IAAI,EAAE,CAAC,CAAC;IAAC,IAAI,EAAE,QAAQ,CAAA;CAAC,GACzB;IAAC,IAAI,EAAE,SAAS,CAAA;CAAC,CAAC;AAEtB,MAAM,WAAW,oBAAoB,CAAC,CAAC,SAAS,cAAc,CAAE,SAAQ,IAAI,CAC1E,SAAS,CAAC,cAAc,CAAC,EACzB,UAAU,CACX;IACC,KAAK,EAAE,MAAM,CAAC;IACd,YAAY,EAAE,YAAY,CAAC,CAAC,CAAC,CAAC;IAC9B,KAAK,EAAE,CAAC,EAAE,CAAC;IACX,QAAQ,EAAE,CAAC,KAAK,EAAE,CAAC,EAAE,EAAE,MAAM,EAAE,qBAAqB,CAAC,CAAC,CAAC,KAAK,IAAI,CAAC;IACjE,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,sBAAsB,CAAC,EAAE,MAAM,CAAC;IAChC,aAAa,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;CACzC;
|
|
1
|
+
{"version":3,"file":"MobileTokenizer.d.ts","sourceRoot":"","sources":["../../src/MobileTokenizer/MobileTokenizer.tsx"],"names":[],"mappings":"AA+BA,OAAO,KAAK,EAAC,SAAS,EAAC,MAAM,oBAAoB,CAAC;AAYlD,OAAO,KAAK,EAAC,cAAc,EAAE,YAAY,EAAC,MAAM,8BAA8B,CAAC;AAQ/E,MAAM,MAAM,qBAAqB,CAAC,CAAC,SAAS,cAAc,IACtD;IAAC,IAAI,EAAE,CAAC,CAAC;IAAC,IAAI,EAAE,KAAK,CAAA;CAAC,GACtB;IAAC,IAAI,EAAE,CAAC,CAAC;IAAC,IAAI,EAAE,QAAQ,CAAA;CAAC,GACzB;IAAC,IAAI,EAAE,CAAC,CAAC;IAAC,IAAI,EAAE,QAAQ,CAAA;CAAC,GACzB;IAAC,IAAI,EAAE,SAAS,CAAA;CAAC,CAAC;AAEtB,MAAM,WAAW,oBAAoB,CAAC,CAAC,SAAS,cAAc,CAAE,SAAQ,IAAI,CAC1E,SAAS,CAAC,cAAc,CAAC,EACzB,UAAU,CACX;IACC,KAAK,EAAE,MAAM,CAAC;IACd,YAAY,EAAE,YAAY,CAAC,CAAC,CAAC,CAAC;IAC9B,KAAK,EAAE,CAAC,EAAE,CAAC;IACX,QAAQ,EAAE,CAAC,KAAK,EAAE,CAAC,EAAE,EAAE,MAAM,EAAE,qBAAqB,CAAC,CAAC,CAAC,KAAK,IAAI,CAAC;IACjE,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,sBAAsB,CAAC,EAAE,MAAM,CAAC;IAChC,aAAa,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;CACzC;AA8KD,wBAAgB,eAAe,CAAC,CAAC,SAAS,cAAc,EAAE,EACxD,KAAK,EACL,YAAY,EACZ,KAAK,EACL,QAAQ,EACR,WAAW,EACX,WAAW,EACX,UAAU,EACV,UAAkB,EAClB,SAAiB,EACjB,UAAU,EACV,YAAiB,EACjB,cAAkB,EAClB,UAAgB,EAChB,sBAA2C,EAC3C,aAAa,EACb,MAAM,GACP,EAAE,oBAAoB,CAAC,CAAC,CAAC,+BA2WzB;yBA5Xe,eAAe"}
|
|
@@ -67,6 +67,14 @@ function ListBulletIcon(props) {
|
|
|
67
67
|
});
|
|
68
68
|
}
|
|
69
69
|
const styles = {
|
|
70
|
+
tokenDisabled: {
|
|
71
|
+
kMwMTN: "x1tgivj0 x1bhcspo",
|
|
72
|
+
$$css: true
|
|
73
|
+
},
|
|
74
|
+
indicatorDisabled: {
|
|
75
|
+
kVAM5u: "x14i3s5s xmnqt3w",
|
|
76
|
+
$$css: true
|
|
77
|
+
},
|
|
70
78
|
footerAction: {
|
|
71
79
|
kzQI83: "x1iyjqo2",
|
|
72
80
|
kCS8Yb: "x1r8uery",
|
|
@@ -229,23 +237,37 @@ export function MobileTokenizer({
|
|
|
229
237
|
"aria-haspopup": "dialog",
|
|
230
238
|
"aria-expanded": activeSheet != null,
|
|
231
239
|
"aria-label": label,
|
|
232
|
-
disabled: isDisabled,
|
|
240
|
+
"aria-disabled": isDisabled || undefined,
|
|
233
241
|
onClick: () => {
|
|
242
|
+
if (isDisabled) {
|
|
243
|
+
return;
|
|
244
|
+
}
|
|
234
245
|
setSelectedItemsAtOpen(value);
|
|
235
246
|
lastLoadScrollHeightRef.current = null;
|
|
236
247
|
setRenderedItemCount(LIST_RENDER_BATCH_SIZE);
|
|
237
248
|
setActiveSheet('manage');
|
|
238
249
|
},
|
|
239
250
|
...{
|
|
240
|
-
|
|
241
|
-
|
|
251
|
+
0: {
|
|
252
|
+
className: "x78zum5 x1a02dak x6s0dn4 xzye2dw xh8yej3 x1gg8mnh xu0wf1k xf314gf xmkeg23 x1y0btm7 x14i3s5s xh6dtrn xjbqb8w x1yc453h x1ypdohk x16khyan"
|
|
253
|
+
},
|
|
254
|
+
1: {
|
|
255
|
+
className: "x78zum5 x1a02dak x6s0dn4 xzye2dw xh8yej3 x1gg8mnh xu0wf1k xf314gf xmkeg23 x1y0btm7 xh6dtrn xjbqb8w x1yc453h x1ypdohk x16khyan x14i3s5s xmnqt3w x1bhcspo"
|
|
256
|
+
}
|
|
257
|
+
}[!!isDisabled << 0],
|
|
242
258
|
children: value.length > 0 ? value.map(item => /*#__PURE__*/_jsx(Token, {
|
|
243
259
|
label: item.label,
|
|
244
|
-
isDisabled: isDisabled
|
|
260
|
+
isDisabled: isDisabled,
|
|
261
|
+
xstyle: isDisabled ? styles.tokenDisabled : undefined
|
|
245
262
|
}, item.id)) : /*#__PURE__*/_jsx("span", {
|
|
246
263
|
...{
|
|
247
|
-
|
|
248
|
-
|
|
264
|
+
0: {
|
|
265
|
+
className: "xv1l7n4"
|
|
266
|
+
},
|
|
267
|
+
1: {
|
|
268
|
+
className: "xv1l7n4 x1bhcspo"
|
|
269
|
+
}
|
|
270
|
+
}[!!isDisabled << 0],
|
|
249
271
|
children: placeholder ?? ''
|
|
250
272
|
})
|
|
251
273
|
}), !isDisabled && /*#__PURE__*/_jsx(BottomSheetSwitcher, {
|
|
@@ -341,23 +363,39 @@ export function MobileTokenizer({
|
|
|
341
363
|
role: "checkbox",
|
|
342
364
|
"aria-checked": isSelected,
|
|
343
365
|
"aria-label": item.label,
|
|
344
|
-
disabled: rowDisabled,
|
|
345
|
-
onClick: () =>
|
|
346
|
-
|
|
347
|
-
|
|
366
|
+
"aria-disabled": rowDisabled || undefined,
|
|
367
|
+
onClick: () => {
|
|
368
|
+
if (rowDisabled) {
|
|
369
|
+
return;
|
|
370
|
+
}
|
|
371
|
+
if (isSelected) {
|
|
372
|
+
handleRemove(item);
|
|
373
|
+
} else {
|
|
374
|
+
handleAdd(item);
|
|
375
|
+
}
|
|
348
376
|
},
|
|
377
|
+
...{
|
|
378
|
+
0: {
|
|
379
|
+
className: "x78zum5 x6s0dn4 x1qughib x1txdalj xh8yej3 x1gg8mnh xce4md1 x7a5moj xc342km xh6dtrn xjbqb8w x1tgivj0 x1yc453h x1ypdohk x16khyan"
|
|
380
|
+
},
|
|
381
|
+
1: {
|
|
382
|
+
className: "x78zum5 x6s0dn4 x1qughib x1txdalj xh8yej3 x1gg8mnh xce4md1 x7a5moj xc342km xh6dtrn xjbqb8w x1yc453h x1ypdohk x16khyan x1tgivj0 x1bhcspo"
|
|
383
|
+
}
|
|
384
|
+
}[!!rowDisabled << 0],
|
|
349
385
|
children: [/*#__PURE__*/_jsx("span", {
|
|
350
386
|
...{
|
|
351
387
|
className: "x1iyjqo2 xeuugli"
|
|
352
388
|
},
|
|
353
389
|
children: /*#__PURE__*/_jsx(Text, {
|
|
354
390
|
type: "body",
|
|
391
|
+
color: rowDisabled ? 'inherit' : undefined,
|
|
355
392
|
children: item.label
|
|
356
393
|
})
|
|
357
394
|
}), /*#__PURE__*/_jsx(CheckboxIndicator, {
|
|
358
395
|
state: isSelected ? 'checked' : 'unchecked',
|
|
359
396
|
size: "md",
|
|
360
|
-
isDisabled: rowDisabled
|
|
397
|
+
isDisabled: rowDisabled,
|
|
398
|
+
xstyle: rowDisabled ? styles.indicatorDisabled : undefined
|
|
361
399
|
})]
|
|
362
400
|
}, item.id);
|
|
363
401
|
})]
|
package/dist/lab.css
CHANGED
|
@@ -157,6 +157,7 @@
|
|
|
157
157
|
.xz7zccy.xz7zccy:hover:where(:not(:disabled,[aria-disabled="true"])):not(#\#):not(#\#){border-color:var(--color-accent)}
|
|
158
158
|
.xg9gykk.xg9gykk:hover:where(:not(:disabled,[aria-disabled="true"])):not(#\#):not(#\#){text-decoration:underline}
|
|
159
159
|
@media (forced-colors: active){.x1w1tqly.x1w1tqly:not(#\#):not(#\#){border-color:CanvasText}}
|
|
160
|
+
@media (forced-colors: active){.xmnqt3w.xmnqt3w:not(#\#):not(#\#){border-color:GrayText}}
|
|
160
161
|
@media (forced-colors: active){.x1n2ykn.x1n2ykn:not(#\#):not(#\#){border-color:Highlight}}
|
|
161
162
|
@media (hover: hover){.xmhmdd9.xmhmdd9.xmhmdd9:hover:where(:not(:disabled,[aria-disabled="true"])):not(#\#):not(#\#){border-color:var(--color-accent)}}
|
|
162
163
|
@media (hover: hover){.x1xwh4np.x1xwh4np.x1xwh4np:hover:where(:not(:disabled,[aria-disabled="true"])):not(#\#):not(#\#){border-color:var(--color-border-emphasized)}}
|
|
@@ -596,6 +597,7 @@
|
|
|
596
597
|
@media (prefers-reduced-motion: reduce) and (not (forced-colors: active)){.x1peun2k.x1peun2k:not(#\#):not(#\#):not(#\#){background-image:none}}
|
|
597
598
|
@media (forced-colors: active){.xwaqzdf.xwaqzdf:not(#\#):not(#\#):not(#\#){box-shadow:none}}
|
|
598
599
|
@media (forced-colors: active){.xs5hli.xs5hli:not(#\#):not(#\#):not(#\#){color:CanvasText}}
|
|
600
|
+
@media (forced-colors: active){.x1bhcspo.x1bhcspo:not(#\#):not(#\#):not(#\#){color:GrayText}}
|
|
599
601
|
@media (forced-colors: active){.x1k5gbb1.x1k5gbb1:not(#\#):not(#\#):not(#\#){color:HighlightText}}
|
|
600
602
|
@media (prefers-reduced-motion: reduce) and (not (forced-colors: active)){.x1wi2gft.x1wi2gft:not(#\#):not(#\#):not(#\#){color:var(--color-text-secondary)}}
|
|
601
603
|
@media (forced-colors: active){.x1tbh5bv.x1tbh5bv:not(#\#):not(#\#):not(#\#){opacity:1}}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@astryxdesign/lab",
|
|
3
|
-
"version": "0.7.3-canary.
|
|
3
|
+
"version": "0.7.3-canary.da1020b",
|
|
4
4
|
"description": "Experimental Astryx components — published to npm only under the @canary dist-tag for early testing; never released as a stable (latest) version.",
|
|
5
5
|
"author": "Meta Open Source",
|
|
6
6
|
"license": "MIT",
|
|
@@ -49,7 +49,7 @@
|
|
|
49
49
|
},
|
|
50
50
|
"peerDependencies": {
|
|
51
51
|
"@stylexjs/stylex": ">=0.10.0",
|
|
52
|
-
"@astryxdesign/core": "0.7.3-canary.
|
|
52
|
+
"@astryxdesign/core": "0.7.3-canary.da1020b",
|
|
53
53
|
"react": ">=19.0.0",
|
|
54
54
|
"react-dom": ">=19.0.0"
|
|
55
55
|
},
|
|
@@ -59,8 +59,8 @@
|
|
|
59
59
|
"d3-shape": "^3.2.0"
|
|
60
60
|
},
|
|
61
61
|
"devDependencies": {
|
|
62
|
-
"@astryxdesign/a11y-spec": "0.7.3-canary.
|
|
63
|
-
"@astryxdesign/cli": "0.7.3-canary.
|
|
62
|
+
"@astryxdesign/a11y-spec": "0.7.3-canary.da1020b",
|
|
63
|
+
"@astryxdesign/cli": "0.7.3-canary.da1020b",
|
|
64
64
|
"@babel/cli": "^7.29.7",
|
|
65
65
|
"@babel/core": "^7.29.7",
|
|
66
66
|
"@babel/preset-react": "^7.29.7",
|
|
@@ -25,7 +25,7 @@ vi.mock('../EmojiPicker/emojiData', () => ({
|
|
|
25
25
|
],
|
|
26
26
|
}));
|
|
27
27
|
|
|
28
|
-
import {CommentComposer} from './CommentComposer';
|
|
28
|
+
import {CommentComposer, CommentComposerBase} from './CommentComposer';
|
|
29
29
|
|
|
30
30
|
const originalMatches = HTMLElement.prototype.matches;
|
|
31
31
|
const popoverOpenState = new WeakMap<HTMLElement, boolean>();
|
|
@@ -101,6 +101,34 @@ describe('CommentComposer', () => {
|
|
|
101
101
|
expect(onSubmit).toHaveBeenCalledWith('Looks good');
|
|
102
102
|
});
|
|
103
103
|
|
|
104
|
+
it('keeps Cancel in the tab order but inert while submitting (AST-085 FR1, FR2)', () => {
|
|
105
|
+
const onCancel = vi.fn();
|
|
106
|
+
render(
|
|
107
|
+
<CommentComposerBase
|
|
108
|
+
value="Draft"
|
|
109
|
+
onChange={() => {}}
|
|
110
|
+
onSubmit={() => {}}
|
|
111
|
+
placeholder="Edit comment"
|
|
112
|
+
onCancel={onCancel}
|
|
113
|
+
context={{kind: 'edit', commentId: 'c1'}}
|
|
114
|
+
contextLabel="Editing comment"
|
|
115
|
+
highlightColor="yellow"
|
|
116
|
+
triggers={[]}
|
|
117
|
+
agentCommands={[]}
|
|
118
|
+
hasEmojiPicker={false}
|
|
119
|
+
isSubmitting
|
|
120
|
+
/>,
|
|
121
|
+
);
|
|
122
|
+
const cancel = screen.getByText('Cancel').closest('a, button')!;
|
|
123
|
+
expect(cancel).toHaveAttribute('aria-disabled', 'true');
|
|
124
|
+
expect(cancel).not.toHaveAttribute('tabindex', '-1');
|
|
125
|
+
act(() => (cancel as HTMLElement).focus());
|
|
126
|
+
expect(cancel).toHaveFocus();
|
|
127
|
+
fireEvent.click(cancel);
|
|
128
|
+
fireEvent.keyDown(cancel, {key: 'Enter'});
|
|
129
|
+
expect(onCancel).not.toHaveBeenCalled();
|
|
130
|
+
});
|
|
131
|
+
|
|
104
132
|
it('shows the placeholder as the input’s name, and keeps Post focusable while submitting', () => {
|
|
105
133
|
const onSubmit = vi.fn();
|
|
106
134
|
const {container} = render(
|
|
@@ -185,6 +213,60 @@ describe('CommentComposer', () => {
|
|
|
185
213
|
);
|
|
186
214
|
});
|
|
187
215
|
|
|
216
|
+
it('keeps the image picker free of native disabled and refuses files while busy (AST-085 FR1, FR2)', async () => {
|
|
217
|
+
const onUploadImages = vi.fn();
|
|
218
|
+
render(
|
|
219
|
+
<CommentComposer
|
|
220
|
+
value="Draft"
|
|
221
|
+
onChange={() => {}}
|
|
222
|
+
onSubmit={() => {}}
|
|
223
|
+
onUploadImages={onUploadImages}
|
|
224
|
+
isSubmitting
|
|
225
|
+
/>,
|
|
226
|
+
);
|
|
227
|
+
const input = document.querySelector('input[type="file"]');
|
|
228
|
+
if (!(input instanceof HTMLInputElement)) {
|
|
229
|
+
throw new Error('File input not found');
|
|
230
|
+
}
|
|
231
|
+
expect(input).not.toHaveAttribute('disabled');
|
|
232
|
+
const file = new File(['png'], 'chart.png', {type: 'image/png'});
|
|
233
|
+
await act(async () => {
|
|
234
|
+
fireEvent.change(input, {target: {files: [file]}});
|
|
235
|
+
await Promise.resolve();
|
|
236
|
+
});
|
|
237
|
+
expect(onUploadImages).not.toHaveBeenCalled();
|
|
238
|
+
});
|
|
239
|
+
|
|
240
|
+
it('does not open the image chooser from the error banner while busy', async () => {
|
|
241
|
+
const onUploadImages = vi.fn();
|
|
242
|
+
const props = {
|
|
243
|
+
value: 'Draft',
|
|
244
|
+
onChange: () => {},
|
|
245
|
+
onSubmit: () => {},
|
|
246
|
+
onUploadImages,
|
|
247
|
+
};
|
|
248
|
+
const view = render(<CommentComposer {...props} />);
|
|
249
|
+
const input = document.querySelector('input[type="file"]');
|
|
250
|
+
if (!(input instanceof HTMLInputElement)) {
|
|
251
|
+
throw new Error('File input not found');
|
|
252
|
+
}
|
|
253
|
+
const openChooser = vi.spyOn(input, 'click').mockImplementation(() => {});
|
|
254
|
+
await act(async () => {
|
|
255
|
+
fireEvent.change(input, {
|
|
256
|
+
target: {
|
|
257
|
+
files: [new File(['%PDF'], 'doc.pdf', {type: 'application/pdf'})],
|
|
258
|
+
},
|
|
259
|
+
});
|
|
260
|
+
});
|
|
261
|
+
view.rerender(<CommentComposer {...props} isSubmitting />);
|
|
262
|
+
fireEvent.click(screen.getByRole('button', {name: 'Choose images'}));
|
|
263
|
+
expect(openChooser).not.toHaveBeenCalled();
|
|
264
|
+
|
|
265
|
+
view.rerender(<CommentComposer {...props} />);
|
|
266
|
+
fireEvent.click(screen.getByRole('button', {name: 'Choose images'}));
|
|
267
|
+
expect(openChooser).toHaveBeenCalledTimes(1);
|
|
268
|
+
});
|
|
269
|
+
|
|
188
270
|
it('refuses files that are not images', async () => {
|
|
189
271
|
const onUploadImages = vi.fn();
|
|
190
272
|
render(
|
|
@@ -239,6 +239,8 @@ export function CommentComposerBase({
|
|
|
239
239
|
latestValueRef.current = value;
|
|
240
240
|
const isMountedRef = useRef(true);
|
|
241
241
|
const actionPendingRef = useRef(false);
|
|
242
|
+
const isSubmittingRef = useRef(isSubmitting);
|
|
243
|
+
isSubmittingRef.current = isSubmitting;
|
|
242
244
|
const imageInputRef = useRef<HTMLInputElement>(null);
|
|
243
245
|
const inputRef = useRef<ChatComposerInputHandle | null>(null);
|
|
244
246
|
// Focus lands once per `focusKey`, when the input attaches: the handle ref
|
|
@@ -323,7 +325,15 @@ export function CommentComposerBase({
|
|
|
323
325
|
setActionError({
|
|
324
326
|
title: t('@astryx.commentComposer.imagesOnly'),
|
|
325
327
|
actionLabel: t('@astryx.commentComposer.chooseImages'),
|
|
326
|
-
onAction: () =>
|
|
328
|
+
onAction: () => {
|
|
329
|
+
// The picker input is never natively disabled, so its click() would
|
|
330
|
+
// open the file chooser while busy and the busy guard would drop
|
|
331
|
+
// the pick.
|
|
332
|
+
if (isSubmittingRef.current || actionPendingRef.current) {
|
|
333
|
+
return;
|
|
334
|
+
}
|
|
335
|
+
imageInputRef.current?.click();
|
|
336
|
+
},
|
|
327
337
|
});
|
|
328
338
|
return;
|
|
329
339
|
}
|
|
@@ -439,10 +449,12 @@ export function CommentComposerBase({
|
|
|
439
449
|
accept="image/*"
|
|
440
450
|
multiple
|
|
441
451
|
hidden
|
|
442
|
-
disabled={isBusy}
|
|
443
452
|
onChange={event => {
|
|
444
453
|
const files = Array.from(event.currentTarget.files ?? []);
|
|
445
454
|
event.currentTarget.value = '';
|
|
455
|
+
if (isBusy) {
|
|
456
|
+
return;
|
|
457
|
+
}
|
|
446
458
|
beginImageUpload(files);
|
|
447
459
|
}}
|
|
448
460
|
/>
|
|
@@ -382,8 +382,8 @@ export function MetadataActionLink({
|
|
|
382
382
|
color="secondary"
|
|
383
383
|
xstyle={partStyles.noWrap}
|
|
384
384
|
data-metadata-action={actionRole}
|
|
385
|
-
|
|
386
|
-
|
|
385
|
+
// Link keeps a disabled link in the tab order (spec:AST-085 FR1).
|
|
386
|
+
isDisabled={isDisabled}
|
|
387
387
|
onClick={event => {
|
|
388
388
|
event.preventDefault();
|
|
389
389
|
if (isDisabled !== true) {
|
|
@@ -725,10 +725,7 @@ export function HistoryDialog({
|
|
|
725
725
|
content={
|
|
726
726
|
<LayoutContent>
|
|
727
727
|
{history.isLoading ? (
|
|
728
|
-
<Spinner
|
|
729
|
-
size="lg"
|
|
730
|
-
label={t('@astryx.comments.historyLoading')}
|
|
731
|
-
/>
|
|
728
|
+
<Spinner size="lg" label={t('@astryx.comments.historyLoading')} />
|
|
732
729
|
) : history.error != null ? (
|
|
733
730
|
<Banner
|
|
734
731
|
status="error"
|
|
@@ -15,6 +15,8 @@ import {
|
|
|
15
15
|
within,
|
|
16
16
|
} from '@testing-library/react';
|
|
17
17
|
import {useState} from 'react';
|
|
18
|
+
import * as stylex from '@stylexjs/stylex';
|
|
19
|
+
import {colorVars} from '@astryxdesign/core/theme/tokens.stylex';
|
|
18
20
|
import {MobileTokenizer, type MobileTokenizerChange} from './MobileTokenizer';
|
|
19
21
|
import type {SearchSource, SearchableItem} from '@astryxdesign/core/Typeahead';
|
|
20
22
|
|
|
@@ -337,4 +339,140 @@ describe('MobileTokenizer (Lab, single-sheet flow)', () => {
|
|
|
337
339
|
expect.objectContaining({type: 'remove'}),
|
|
338
340
|
);
|
|
339
341
|
});
|
|
342
|
+
|
|
343
|
+
it('keeps a disabled trigger focusable without opening the sheet (AST-085 FR1, FR2)', () => {
|
|
344
|
+
render(
|
|
345
|
+
<MobileTokenizer
|
|
346
|
+
label="Tags"
|
|
347
|
+
searchSource={source}
|
|
348
|
+
value={[ITEMS[0]]}
|
|
349
|
+
onChange={() => {}}
|
|
350
|
+
isDisabled
|
|
351
|
+
/>,
|
|
352
|
+
);
|
|
353
|
+
const trigger = screen.getByRole('button', {name: /Tags/});
|
|
354
|
+
expect(trigger).not.toHaveAttribute('disabled');
|
|
355
|
+
expect(trigger).toHaveAttribute('aria-disabled', 'true');
|
|
356
|
+
trigger.focus();
|
|
357
|
+
expect(trigger).toHaveFocus();
|
|
358
|
+
fireEvent.click(trigger);
|
|
359
|
+
expect(trigger).toHaveAttribute('aria-expanded', 'false');
|
|
360
|
+
expect(
|
|
361
|
+
screen.queryByTestId('mobile-tokenizer-list'),
|
|
362
|
+
).not.toBeInTheDocument();
|
|
363
|
+
});
|
|
364
|
+
|
|
365
|
+
it('keeps an unselectable row at the limit focusable but inert (AST-085 FR1, FR2)', async () => {
|
|
366
|
+
const spy = vi.fn();
|
|
367
|
+
render(
|
|
368
|
+
<MobileTokenizer
|
|
369
|
+
label="Tags"
|
|
370
|
+
searchSource={source}
|
|
371
|
+
value={[ITEMS[0]]}
|
|
372
|
+
maxEntries={1}
|
|
373
|
+
debounceMs={0}
|
|
374
|
+
onChange={spy}
|
|
375
|
+
/>,
|
|
376
|
+
);
|
|
377
|
+
fireEvent.click(screen.getByRole('button', {name: /Tags/}));
|
|
378
|
+
const row = await screen.findByRole('checkbox', {name: 'Energizer'});
|
|
379
|
+
expect(row).not.toHaveAttribute('disabled');
|
|
380
|
+
expect(row).toHaveAttribute('aria-disabled', 'true');
|
|
381
|
+
fireEvent.click(row);
|
|
382
|
+
expect(spy).not.toHaveBeenCalled();
|
|
383
|
+
expect(row).toHaveAttribute('aria-checked', 'false');
|
|
384
|
+
// In forced colors its indicator border takes GrayText (AST-085 FR6).
|
|
385
|
+
const indicatorClasses = stylex
|
|
386
|
+
.props(
|
|
387
|
+
stylex.create({
|
|
388
|
+
border: {
|
|
389
|
+
borderColor: {
|
|
390
|
+
default: colorVars['--color-border'],
|
|
391
|
+
'@media (forced-colors: active)': 'GrayText',
|
|
392
|
+
},
|
|
393
|
+
},
|
|
394
|
+
}).border,
|
|
395
|
+
)
|
|
396
|
+
.className!.split(' ')
|
|
397
|
+
.filter(name => !name.includes('__'));
|
|
398
|
+
const indicator = row.querySelector('.astryx-checkbox-indicator')!;
|
|
399
|
+
for (const name of indicatorClasses) {
|
|
400
|
+
expect(indicator).toHaveClass(name);
|
|
401
|
+
}
|
|
402
|
+
});
|
|
403
|
+
|
|
404
|
+
it('paints the placeholder of a disabled empty trigger GrayText in forced colors (AST-085 FR6)', () => {
|
|
405
|
+
const placeholderClasses = stylex
|
|
406
|
+
.props(
|
|
407
|
+
stylex.create({
|
|
408
|
+
placeholder: {
|
|
409
|
+
color: {
|
|
410
|
+
default: colorVars['--color-text-secondary'],
|
|
411
|
+
'@media (forced-colors: active)': 'GrayText',
|
|
412
|
+
},
|
|
413
|
+
},
|
|
414
|
+
}).placeholder,
|
|
415
|
+
)
|
|
416
|
+
.className!.split(' ')
|
|
417
|
+
.filter(name => !name.includes('__'));
|
|
418
|
+
render(
|
|
419
|
+
<MobileTokenizer
|
|
420
|
+
label="Tags"
|
|
421
|
+
searchSource={source}
|
|
422
|
+
value={[]}
|
|
423
|
+
onChange={() => {}}
|
|
424
|
+
placeholder="Add tags"
|
|
425
|
+
isDisabled
|
|
426
|
+
/>,
|
|
427
|
+
);
|
|
428
|
+
const placeholder = screen.getByText('Add tags');
|
|
429
|
+
for (const name of placeholderClasses) {
|
|
430
|
+
expect(placeholder).toHaveClass(name);
|
|
431
|
+
}
|
|
432
|
+
});
|
|
433
|
+
|
|
434
|
+
it('paints a disabled trigger and its tokens GrayText in forced colors (AST-085 FR6)', () => {
|
|
435
|
+
// The same declarations as the component's styles compile to the same
|
|
436
|
+
// atomic classes; without them the tokens keep their CanvasText label.
|
|
437
|
+
const atoms = (style: stylex.StyleXStyles) =>
|
|
438
|
+
stylex
|
|
439
|
+
.props(style)
|
|
440
|
+
.className!.split(' ')
|
|
441
|
+
.filter(name => !name.includes('__'));
|
|
442
|
+
const forced = stylex.create({
|
|
443
|
+
trigger: {
|
|
444
|
+
borderColor: {
|
|
445
|
+
default: colorVars['--color-border'],
|
|
446
|
+
'@media (forced-colors: active)': 'GrayText',
|
|
447
|
+
},
|
|
448
|
+
color: {default: null, '@media (forced-colors: active)': 'GrayText'},
|
|
449
|
+
},
|
|
450
|
+
token: {
|
|
451
|
+
color: {
|
|
452
|
+
default: colorVars['--color-text-primary'],
|
|
453
|
+
'@media (forced-colors: active)': 'GrayText',
|
|
454
|
+
},
|
|
455
|
+
},
|
|
456
|
+
});
|
|
457
|
+
render(
|
|
458
|
+
<MobileTokenizer
|
|
459
|
+
label="Tags"
|
|
460
|
+
searchSource={source}
|
|
461
|
+
value={[ITEMS[0], ITEMS[1]]}
|
|
462
|
+
onChange={() => {}}
|
|
463
|
+
isDisabled
|
|
464
|
+
/>,
|
|
465
|
+
);
|
|
466
|
+
const trigger = screen.getByRole('button', {name: /Tags/});
|
|
467
|
+
for (const name of atoms(forced.trigger)) {
|
|
468
|
+
expect(trigger).toHaveClass(name);
|
|
469
|
+
}
|
|
470
|
+
const tokens = trigger.querySelectorAll('.astryx-token');
|
|
471
|
+
expect(tokens).toHaveLength(2);
|
|
472
|
+
for (const token of tokens) {
|
|
473
|
+
for (const name of atoms(forced.token)) {
|
|
474
|
+
expect(token).toHaveClass(name);
|
|
475
|
+
}
|
|
476
|
+
}
|
|
477
|
+
});
|
|
340
478
|
});
|
|
@@ -118,9 +118,28 @@ const styles = stylex.create({
|
|
|
118
118
|
':is(:disabled,[aria-disabled="true"])': 'default',
|
|
119
119
|
},
|
|
120
120
|
},
|
|
121
|
+
// An aria-disabled button gets no system disabled paint in forced colors;
|
|
122
|
+
// GrayText is the platform's disabled affordance there. Defaults repeat the
|
|
123
|
+
// base values, since StyleX merges per property.
|
|
124
|
+
triggerDisabled: {
|
|
125
|
+
borderColor: {
|
|
126
|
+
default: colorVars['--color-border'],
|
|
127
|
+
'@media (forced-colors: active)': 'GrayText',
|
|
128
|
+
},
|
|
129
|
+
color: {
|
|
130
|
+
default: null,
|
|
131
|
+
'@media (forced-colors: active)': 'GrayText',
|
|
132
|
+
},
|
|
133
|
+
},
|
|
121
134
|
triggerPlaceholder: {
|
|
122
135
|
color: colorVars['--color-text-secondary'],
|
|
123
136
|
},
|
|
137
|
+
triggerPlaceholderDisabled: {
|
|
138
|
+
color: {
|
|
139
|
+
default: colorVars['--color-text-secondary'],
|
|
140
|
+
'@media (forced-colors: active)': 'GrayText',
|
|
141
|
+
},
|
|
142
|
+
},
|
|
124
143
|
sheetBody: {
|
|
125
144
|
display: 'flex',
|
|
126
145
|
flexDirection: 'column',
|
|
@@ -158,6 +177,29 @@ const styles = stylex.create({
|
|
|
158
177
|
':is(:disabled,[aria-disabled="true"])': 'default',
|
|
159
178
|
},
|
|
160
179
|
},
|
|
180
|
+
// A Token authors its own color, which forced colors replace with
|
|
181
|
+
// CanvasText; GrayText marks the tokens of a disabled trigger as disabled.
|
|
182
|
+
// The default repeats Token's own default color.
|
|
183
|
+
tokenDisabled: {
|
|
184
|
+
color: {
|
|
185
|
+
default: colorVars['--color-text-primary'],
|
|
186
|
+
'@media (forced-colors: active)': 'GrayText',
|
|
187
|
+
},
|
|
188
|
+
},
|
|
189
|
+
// Same for the indicator's border: GrayText in forced colors, and the
|
|
190
|
+
// default repeats the indicator's disabled border.
|
|
191
|
+
indicatorDisabled: {
|
|
192
|
+
borderColor: {
|
|
193
|
+
default: colorVars['--color-border'],
|
|
194
|
+
'@media (forced-colors: active)': 'GrayText',
|
|
195
|
+
},
|
|
196
|
+
},
|
|
197
|
+
rowDisabled: {
|
|
198
|
+
color: {
|
|
199
|
+
default: colorVars['--color-text-primary'],
|
|
200
|
+
'@media (forced-colors: active)': 'GrayText',
|
|
201
|
+
},
|
|
202
|
+
},
|
|
161
203
|
rowLabel: {
|
|
162
204
|
flexGrow: 1,
|
|
163
205
|
minWidth: 0,
|
|
@@ -376,20 +418,32 @@ export function MobileTokenizer<T extends SearchableItem>({
|
|
|
376
418
|
aria-haspopup="dialog"
|
|
377
419
|
aria-expanded={activeSheet != null}
|
|
378
420
|
aria-label={label}
|
|
379
|
-
disabled={isDisabled}
|
|
421
|
+
aria-disabled={isDisabled || undefined}
|
|
380
422
|
onClick={() => {
|
|
423
|
+
if (isDisabled) {
|
|
424
|
+
return;
|
|
425
|
+
}
|
|
381
426
|
setSelectedItemsAtOpen(value);
|
|
382
427
|
lastLoadScrollHeightRef.current = null;
|
|
383
428
|
setRenderedItemCount(LIST_RENDER_BATCH_SIZE);
|
|
384
429
|
setActiveSheet('manage');
|
|
385
430
|
}}
|
|
386
|
-
{...stylex.props(styles.trigger)}>
|
|
431
|
+
{...stylex.props(styles.trigger, isDisabled && styles.triggerDisabled)}>
|
|
387
432
|
{value.length > 0 ? (
|
|
388
433
|
value.map(item => (
|
|
389
|
-
<Token
|
|
434
|
+
<Token
|
|
435
|
+
key={item.id}
|
|
436
|
+
label={item.label}
|
|
437
|
+
isDisabled={isDisabled}
|
|
438
|
+
xstyle={isDisabled ? styles.tokenDisabled : undefined}
|
|
439
|
+
/>
|
|
390
440
|
))
|
|
391
441
|
) : (
|
|
392
|
-
<span
|
|
442
|
+
<span
|
|
443
|
+
{...stylex.props(
|
|
444
|
+
styles.triggerPlaceholder,
|
|
445
|
+
isDisabled && styles.triggerPlaceholderDisabled,
|
|
446
|
+
)}>
|
|
393
447
|
{placeholder ?? ''}
|
|
394
448
|
</span>
|
|
395
449
|
)}
|
|
@@ -500,18 +554,35 @@ export function MobileTokenizer<T extends SearchableItem>({
|
|
|
500
554
|
role="checkbox"
|
|
501
555
|
aria-checked={isSelected}
|
|
502
556
|
aria-label={item.label}
|
|
503
|
-
disabled={rowDisabled}
|
|
504
|
-
onClick={() =>
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
|
|
557
|
+
aria-disabled={rowDisabled || undefined}
|
|
558
|
+
onClick={() => {
|
|
559
|
+
if (rowDisabled) {
|
|
560
|
+
return;
|
|
561
|
+
}
|
|
562
|
+
if (isSelected) {
|
|
563
|
+
handleRemove(item);
|
|
564
|
+
} else {
|
|
565
|
+
handleAdd(item);
|
|
566
|
+
}
|
|
567
|
+
}}
|
|
568
|
+
{...stylex.props(
|
|
569
|
+
styles.row,
|
|
570
|
+
rowDisabled && styles.rowDisabled,
|
|
571
|
+
)}>
|
|
508
572
|
<span {...stylex.props(styles.rowLabel)}>
|
|
509
|
-
<Text
|
|
573
|
+
<Text
|
|
574
|
+
type="body"
|
|
575
|
+
color={rowDisabled ? 'inherit' : undefined}>
|
|
576
|
+
{item.label}
|
|
577
|
+
</Text>
|
|
510
578
|
</span>
|
|
511
579
|
<CheckboxIndicator
|
|
512
580
|
state={isSelected ? 'checked' : 'unchecked'}
|
|
513
581
|
size="md"
|
|
514
582
|
isDisabled={rowDisabled}
|
|
583
|
+
xstyle={
|
|
584
|
+
rowDisabled ? styles.indicatorDisabled : undefined
|
|
585
|
+
}
|
|
515
586
|
/>
|
|
516
587
|
</button>
|
|
517
588
|
);
|