@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.
@@ -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,+BAyV1B;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"}
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: () => imageInputRef.current?.click()
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
- "aria-disabled": isDisabled || undefined,
339
- tabIndex: isDisabled ? -1 : undefined,
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;AAoID,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,+BA8UzB;yBA/Ve,eAAe"}
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
- className: "x78zum5 x1a02dak x6s0dn4 xzye2dw xh8yej3 x1gg8mnh xu0wf1k xf314gf xmkeg23 x1y0btm7 x14i3s5s xh6dtrn xjbqb8w x1yc453h x1ypdohk x16khyan"
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
- className: "xv1l7n4"
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: () => isSelected ? handleRemove(item) : handleAdd(item),
346
- ...{
347
- className: "x78zum5 x6s0dn4 x1qughib x1txdalj xh8yej3 x1gg8mnh xce4md1 x7a5moj xc342km xh6dtrn xjbqb8w x1tgivj0 x1yc453h x1ypdohk x16khyan"
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.d421aed",
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.d421aed",
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.d421aed",
63
- "@astryxdesign/cli": "0.7.3-canary.d421aed",
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: () => imageInputRef.current?.click(),
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
- aria-disabled={isDisabled || undefined}
386
- tabIndex={isDisabled ? -1 : undefined}
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 key={item.id} label={item.label} isDisabled={isDisabled} />
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 {...stylex.props(styles.triggerPlaceholder)}>
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
- isSelected ? handleRemove(item) : handleAdd(item)
506
- }
507
- {...stylex.props(styles.row)}>
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 type="body">{item.label}</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
  );