@astryxdesign/lab 0.7.6-canary.df8928a → 0.7.6-canary.e428366

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.
Files changed (32) hide show
  1. package/README.md +1 -1
  2. package/dist/CommentPin/CommentPin.d.ts.map +1 -1
  3. package/dist/CommentPin/CommentPin.js +37 -3
  4. package/dist/Comments/CommentComposer.d.ts.map +1 -1
  5. package/dist/Comments/CommentComposer.js +10 -3
  6. package/dist/Comments/CommentParts.d.ts +9 -2
  7. package/dist/Comments/CommentParts.d.ts.map +1 -1
  8. package/dist/Comments/CommentParts.js +32 -15
  9. package/dist/Comments/CommentRow.d.ts.map +1 -1
  10. package/dist/Comments/CommentRow.js +5 -2
  11. package/dist/Comments/Comments.d.ts.map +1 -1
  12. package/dist/Comments/Comments.js +10 -1
  13. package/dist/Comments/CommentsContext.d.ts +2 -0
  14. package/dist/Comments/CommentsContext.d.ts.map +1 -1
  15. package/dist/Comments/CommentsContext.js +7 -3
  16. package/dist/Comments/useStatusAnnouncement.d.ts +26 -0
  17. package/dist/Comments/useStatusAnnouncement.d.ts.map +1 -0
  18. package/dist/Comments/useStatusAnnouncement.js +48 -0
  19. package/package.json +4 -4
  20. package/src/CommentPin/CommentPin.doc.mjs +6 -4
  21. package/src/CommentPin/CommentPin.spec.md +14 -13
  22. package/src/CommentPin/CommentPin.test.tsx +177 -1
  23. package/src/CommentPin/CommentPin.tsx +44 -1
  24. package/src/Comments/CommentComposer.test.tsx +54 -4
  25. package/src/Comments/CommentComposer.tsx +10 -2
  26. package/src/Comments/CommentParts.tsx +50 -14
  27. package/src/Comments/CommentRow.tsx +5 -6
  28. package/src/Comments/Comments.doc.mjs +1 -1
  29. package/src/Comments/Comments.test.tsx +339 -13
  30. package/src/Comments/Comments.tsx +16 -1
  31. package/src/Comments/CommentsContext.tsx +13 -1
  32. package/src/Comments/useStatusAnnouncement.ts +57 -0
package/README.md CHANGED
@@ -24,7 +24,7 @@ See the **[Component Lifecycle](https://github.com/meta/astryx/wiki/Component-Li
24
24
 
25
25
  The [Accessibility Checklist](https://github.com/meta/astryx/wiki/Accessibility-Checklist) is a hard requirement for graduating to core — every item, verified in the promotion PR, alongside the hardening bar linked above.
26
26
 
27
- Lab components get the same scan coverage as core (the `pr-a11y` axe audit and the weekly full scan run against lab too), but a11y findings on a lab component do not block lab merges — they block **promotion**. Iterate freely in lab; clear the checklist to graduate.
27
+ Lab components get the same scan coverage as core (the `pr-a11y` axe audit and the full release-check scan run against lab too), but a11y findings on a lab component do not block lab merges — they block **promotion**. Iterate freely in lab; clear the checklist to graduate.
28
28
 
29
29
  ## Usage
30
30
 
@@ -1 +1 @@
1
- {"version":3,"file":"CommentPin.d.ts","sourceRoot":"","sources":["../../src/CommentPin/CommentPin.tsx"],"names":[],"mappings":"AAyBA,OAAO,KAAK,EAAC,SAAS,EAAC,MAAM,oBAAoB,CAAC;AA4BlD,qEAAqE;AACrE,MAAM,MAAM,cAAc,GAAG,IAAI,GAAG,IAAI,GAAG,IAAI,CAAC;AAEhD,sEAAsE;AACtE,MAAM,WAAW,qBAAqB;IACpC,gEAAgE;IAChE,EAAE,EAAE,MAAM,CAAC;IACX,+DAA+D;IAC/D,IAAI,EAAE,MAAM,CAAC;IACb,8CAA8C;IAC9C,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAED,MAAM,WAAW,eAAgB,SAAQ,IAAI,CAC3C,SAAS,CAAC,iBAAiB,CAAC,EAC5B,UAAU,CACX;IACC,0CAA0C;IAC1C,GAAG,CAAC,EAAE,KAAK,CAAC,GAAG,CAAC,iBAAiB,CAAC,CAAC;IACnC;;;;OAIG;IACH,KAAK,EAAE,MAAM,CAAC;IACd;;;;;;;OAOG;IACH,YAAY,EAAE,SAAS,CAAC,qBAAqB,EAAE,GAAG,qBAAqB,EAAE,CAAC,CAAC;IAC3E;;;;OAIG;IACH,IAAI,CAAC,EAAE,cAAc,CAAC;IACtB;;;;OAIG;IACH,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB;;;;;;OAMG;IACH,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,oEAAoE;IACpE,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB;;;OAGG;IACH,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB;;;;OAIG;IACH,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,yCAAyC;IACzC,UAAU,CAAC,EAAE,OAAO,CAAC;CACtB;AA8ND;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA6BG;AACH,wBAAgB,UAAU,CAAC,EACzB,KAAK,EACL,YAAY,EACZ,IAAW,EACX,WAAe,EACf,WAAe,EACf,UAAkB,EAClB,QAAgB,EAChB,UAAkB,EAClB,UAAkB,EAClB,GAAG,EACH,MAAM,EACN,SAAS,EACT,KAAK,EACL,GAAG,IAAI,EACR,EAAE,eAAe,GAAG,KAAK,CAAC,SAAS,CA4JnC;yBA3Ke,UAAU"}
1
+ {"version":3,"file":"CommentPin.d.ts","sourceRoot":"","sources":["../../src/CommentPin/CommentPin.tsx"],"names":[],"mappings":"AAyBA,OAAO,KAAK,EAAC,SAAS,EAAC,MAAM,oBAAoB,CAAC;AA4BlD,qEAAqE;AACrE,MAAM,MAAM,cAAc,GAAG,IAAI,GAAG,IAAI,GAAG,IAAI,CAAC;AAEhD,sEAAsE;AACtE,MAAM,WAAW,qBAAqB;IACpC,gEAAgE;IAChE,EAAE,EAAE,MAAM,CAAC;IACX,+DAA+D;IAC/D,IAAI,EAAE,MAAM,CAAC;IACb,8CAA8C;IAC9C,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAED,MAAM,WAAW,eAAgB,SAAQ,IAAI,CAC3C,SAAS,CAAC,iBAAiB,CAAC,EAC5B,UAAU,CACX;IACC,0CAA0C;IAC1C,GAAG,CAAC,EAAE,KAAK,CAAC,GAAG,CAAC,iBAAiB,CAAC,CAAC;IACnC;;;;OAIG;IACH,KAAK,EAAE,MAAM,CAAC;IACd;;;;;;;OAOG;IACH,YAAY,EAAE,SAAS,CAAC,qBAAqB,EAAE,GAAG,qBAAqB,EAAE,CAAC,CAAC;IAC3E;;;;OAIG;IACH,IAAI,CAAC,EAAE,cAAc,CAAC;IACtB;;;;OAIG;IACH,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB;;;;;;OAMG;IACH,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,oEAAoE;IACpE,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB;;;OAGG;IACH,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB;;;;OAIG;IACH,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,yCAAyC;IACzC,UAAU,CAAC,EAAE,OAAO,CAAC;CACtB;AA6OD;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA6BG;AACH,wBAAgB,UAAU,CAAC,EACzB,KAAK,EACL,YAAY,EACZ,IAAW,EACX,WAAe,EACf,WAAe,EACf,UAAkB,EAClB,QAAgB,EAChB,UAAkB,EAClB,UAAkB,EAClB,GAAG,EACH,MAAM,EACN,SAAS,EACT,KAAK,EACL,GAAG,IAAI,EACR,EAAE,eAAe,GAAG,KAAK,CAAC,SAAS,CAwLnC;yBAvMe,UAAU"}
@@ -88,6 +88,11 @@ const styles = {
88
88
  kSiTet: "xyd83as x1tbh5bv",
89
89
  $$css: true
90
90
  },
91
+ disabledUnselected: {
92
+ kVAM5u: "x9r1u3d xmnqt3w",
93
+ kMwMTN: "xv1l7n4 x1bhcspo",
94
+ $$css: true
95
+ },
91
96
  overflowCircle: {
92
97
  kg3NbH: "xnjsko4",
93
98
  $$css: true
@@ -269,8 +274,37 @@ export function CommentPin({
269
274
  ref: mergedRef,
270
275
  type: "button",
271
276
  "aria-label": label,
272
- "aria-pressed": isSelected,
273
- disabled: isDisabled,
277
+ "aria-pressed": isSelected
278
+ // A disabled pin keeps its tab stop and is announced as disabled through
279
+ // aria-disabled instead of the native attribute (spec:AST-085 FR1). The
280
+ // activation guards below keep it inert (FR2); focus is kept when the
281
+ // pin becomes disabled while focused (FR4), and the shared focus outline
282
+ // still paints, dimmed with the rest of the pin (FR6).
283
+ ,
284
+ "aria-disabled": isDisabled ? 'true' : undefined,
285
+ onClick: e => {
286
+ if (isDisabled) {
287
+ // A natively disabled element dispatched no click at all, so an
288
+ // aria-disabled pin must not reach the caller's handler, and the
289
+ // click must not leak to a clickable ancestor (annotation surface)
290
+ // the native attribute never let it reach either (FR2).
291
+ e.preventDefault();
292
+ e.stopPropagation();
293
+ return;
294
+ }
295
+ rest.onClick?.(e);
296
+ }
297
+ // The keyboard paths to activation are Enter and Space; other keys still
298
+ // reach caller handlers, as on an enabled pin (FR2).
299
+ ,
300
+ onKeyDown: e => {
301
+ if (isDisabled && (e.key === 'Enter' || e.key === ' ')) {
302
+ e.preventDefault();
303
+ e.stopPropagation();
304
+ return;
305
+ }
306
+ rest.onKeyDown?.(e);
307
+ },
274
308
  ...mergeProps(themeProps('comment-pin', {
275
309
  size: resolvedSize,
276
310
  grouped: isGrouped ? 'grouped' : null,
@@ -279,7 +313,7 @@ export function CommentPin({
279
313
  dimmed: isDimmed ? 'dimmed' : null,
280
314
  resolved: isResolved ? 'resolved' : null,
281
315
  disabled: isDisabled ? 'disabled' : null
282
- }), focusOutlineProps.focusVisible(styles.root, sizeStyles[resolvedSize], interactionOverlayStyles.backgroundImage, (isGrouped || hasUnread) && styles.withCount, isDimmed && !isSelected && styles.dimmed, isSelected && styles.selected, isDisabled && styles.disabled, xstyle), className, style),
316
+ }), focusOutlineProps.focusVisible(styles.root, sizeStyles[resolvedSize], interactionOverlayStyles.backgroundImage, (isGrouped || hasUnread) && styles.withCount, isDimmed && !isSelected && styles.dimmed, isSelected && styles.selected, isDisabled && styles.disabled, isDisabled && !isSelected && styles.disabledUnselected, xstyle), className, style),
283
317
  children: [/*#__PURE__*/_jsx("span", {
284
318
  "aria-hidden": "true",
285
319
  ...{
@@ -1 +1 @@
1
- {"version":3,"file":"CommentComposer.d.ts","sourceRoot":"","sources":["../../src/Comments/CommentComposer.tsx"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"CommentComposer.d.ts","sourceRoot":"","sources":["../../src/Comments/CommentComposer.tsx"],"names":[],"mappings":"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"}
@@ -169,6 +169,13 @@ export function CommentComposerBase({
169
169
  }
170
170
  }, [focusKey]);
171
171
  const [actionError, setActionError] = useState();
172
+ // Counts action failures so each one mounts its own Banner: a second failure
173
+ // with the same words is a new occasion and is announced again (AST-086 FR6).
174
+ const [actionErrorSerial, setActionErrorSerial] = useState(0);
175
+ const reportActionError = content => {
176
+ setActionError(content);
177
+ setActionErrorSerial(serial => serial + 1);
178
+ };
172
179
  const [isActionPending, setIsActionPending] = useState(false);
173
180
  const [isPickerOpen, setIsPickerOpen] = useState(false);
174
181
  const updateActionPending = useCallback(nextPending => {
@@ -205,7 +212,7 @@ export function CommentComposerBase({
205
212
  }
206
213
  } catch {
207
214
  if (isMountedRef.current) {
208
- setActionError({
215
+ reportActionError({
209
216
  title: t('@astryx.commentComposer.uploadFailed'),
210
217
  actionLabel: t('@astryx.comments.retry'),
211
218
  onAction: () => beginImageUpload(files)
@@ -223,7 +230,7 @@ export function CommentComposerBase({
223
230
  }
224
231
  const images = files.filter(file => file.type.startsWith('image/'));
225
232
  if (images.length !== files.length) {
226
- setActionError({
233
+ reportActionError({
227
234
  title: t('@astryx.commentComposer.imagesOnly'),
228
235
  actionLabel: t('@astryx.commentComposer.chooseImages'),
229
236
  onAction: () => {
@@ -276,7 +283,7 @@ export function CommentComposerBase({
276
283
  ,
277
284
  onBeforeAction: () => inputRef.current?.focus(),
278
285
  "data-composer-error": "banner"
279
- }), /*#__PURE__*/_jsx(ChatComposer, {
286
+ }, error != null ? 'error' : `action-${actionErrorSerial}`), /*#__PURE__*/_jsx(ChatComposer, {
280
287
  value: value,
281
288
  onChange: onChange,
282
289
  onSubmit: submitInput,
@@ -132,10 +132,17 @@ export type ErrorBannerContent = {
132
132
  actionLabel?: string;
133
133
  onAction?: () => void;
134
134
  isActionDisabled?: boolean;
135
+ /** Its own retry is running: say nothing until the outcome (FR6). */
136
+ isRetrying?: boolean;
137
+ /** The failure was already announced elsewhere; this Banner stays silent. */
138
+ isAnnounced?: boolean;
135
139
  };
136
140
  /**
137
- * An inline failure as an error Banner. It sets role="alert" itself (Banner
138
- * adds no live-region role from `status`), so mounting it announces it.
141
+ * An inline failure as an error Banner. The Banner carries no live role: it
142
+ * mounts already holding its text, which may not be announced. The failure is
143
+ * announced once, assertively, through the shared channel instead, unless the
144
+ * Banner sits inside a live container such as the chat log, which delivers it
145
+ * (spec:AST-086 FR2, FR4, FR5).
139
146
  */
140
147
  export declare function ErrorBanner({ actionRef, content, onBeforeAction, ...dataProps }: {
141
148
  actionRef?: Ref<HTMLButtonElement>;
@@ -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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"}
@@ -12,7 +12,7 @@
12
12
  * reply rail, activity event row, edit history dialog, and loading skeletons
13
13
  * @position Internal building blocks of the Comments family
14
14
  */
15
- import { useState } from 'react';
15
+ import { useRef, useState } from 'react';
16
16
  import * as stylex from '@stylexjs/stylex';
17
17
  import { Avatar } from '@astryxdesign/core/Avatar';
18
18
  import { Badge } from '@astryxdesign/core/Badge';
@@ -38,6 +38,7 @@ import { useTranslator } from '@astryxdesign/core/i18n';
38
38
  import '@astryxdesign/core/theme/tokens.stylex';
39
39
  import { borderVars, colorVars, durationVars, easeVars, radiusVars, spacingVars } from '@astryxdesign/core/theme/tokens.stylex';
40
40
  import { CommentIcon } from "./icons.js";
41
+ import { useStatusAnnouncement } from "./useStatusAnnouncement.js";
41
42
  import { eventAnchorId } from "./utils.js";
42
43
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
43
44
  /** The 28px avatar column every comment row, reply, and event aligns to. */
@@ -243,8 +244,11 @@ const highlightRules = {
243
244
  /** A failed action as an error Banner with its one recovery action. */
244
245
 
245
246
  /**
246
- * An inline failure as an error Banner. It sets role="alert" itself (Banner
247
- * adds no live-region role from `status`), so mounting it announces it.
247
+ * An inline failure as an error Banner. The Banner carries no live role: it
248
+ * mounts already holding its text, which may not be announced. The failure is
249
+ * announced once, assertively, through the shared channel instead, unless the
250
+ * Banner sits inside a live container such as the chat log, which delivers it
251
+ * (spec:AST-086 FR2, FR4, FR5).
248
252
  */
249
253
  export function ErrorBanner({
250
254
  actionRef,
@@ -259,9 +263,15 @@ export function ErrorBanner({
259
263
  onAction,
260
264
  title
261
265
  } = content;
266
+ const t = useTranslator();
267
+ const bannerRef = useRef(null);
268
+ useStatusAnnouncement(bannerRef, content.isRetrying === true || content.isAnnounced === true ? null : description != null ? t('@astryx.comments.errorAnnouncement', {
269
+ title,
270
+ description
271
+ }) : title, 'assertive');
262
272
  return /*#__PURE__*/_jsx(Banner, {
273
+ ref: bannerRef,
263
274
  status: "error",
264
- role: "alert",
265
275
  container: "card",
266
276
  title: title,
267
277
  description: description,
@@ -405,6 +415,11 @@ export function CommentAnchorQuote({
405
415
  export function CommentProgressStatus({
406
416
  progress
407
417
  }) {
418
+ const labelRef = useRef(null);
419
+ // The label carries no live role: it mounts already holding its text. It is
420
+ // announced politely through the shared channel, unless the chat log around
421
+ // it delivers it (spec:AST-086 FR2, FR4).
422
+ useStatusAnnouncement(labelRef, progress.label, 'polite');
408
423
  return /*#__PURE__*/_jsxs(HStack, {
409
424
  gap: 1,
410
425
  align: "center",
@@ -412,9 +427,9 @@ export function CommentProgressStatus({
412
427
  width: "100%",
413
428
  "data-comment-progress": "shimmer",
414
429
  children: [/*#__PURE__*/_jsx(Text, {
430
+ ref: labelRef,
415
431
  type: "body",
416
432
  color: "secondary",
417
- role: "status",
418
433
  xstyle: partStyles.progressLabel,
419
434
  children: progress.label
420
435
  }), progress.link != null && /*#__PURE__*/_jsx(Link, {
@@ -629,17 +644,19 @@ export function HistoryDialog({
629
644
  onOpenChange: open => !open && onClose(),
630
645
  hasDivider: true
631
646
  }),
632
- content: /*#__PURE__*/_jsx(LayoutContent, {
633
- children: history.isLoading ? /*#__PURE__*/_jsx(Spinner, {
647
+ content: /*#__PURE__*/_jsxs(LayoutContent, {
648
+ children: [/*#__PURE__*/_jsx("div", {
649
+ role: "alert",
650
+ children: !history.isLoading && history.error != null && /*#__PURE__*/_jsx(Banner, {
651
+ status: "error",
652
+ title: t('@astryx.comments.historyFailed'),
653
+ description: history.error,
654
+ container: "section"
655
+ })
656
+ }), history.isLoading ? /*#__PURE__*/_jsx(Spinner, {
634
657
  size: "lg",
635
658
  label: t('@astryx.comments.historyLoading')
636
- }) : history.error != null ? /*#__PURE__*/_jsx(Banner, {
637
- status: "error",
638
- role: "alert",
639
- title: t('@astryx.comments.historyFailed'),
640
- description: history.error,
641
- container: "section"
642
- }) : history.versions.length === 0 ? /*#__PURE__*/_jsx(EmptyState, {
659
+ }) : history.error != null ? null : history.versions.length === 0 ? /*#__PURE__*/_jsx(EmptyState, {
643
660
  title: t('@astryx.comments.historyEmptyTitle'),
644
661
  description: t('@astryx.comments.historyEmptyDescription'),
645
662
  isCompact: true
@@ -671,7 +688,7 @@ export function HistoryDialog({
671
688
  }), renderVersionBody(version)]
672
689
  })
673
690
  }, version.id))
674
- })
691
+ })]
675
692
  })
676
693
  })
677
694
  });
@@ -1 +1 @@
1
- {"version":3,"file":"CommentRow.d.ts","sourceRoot":"","sources":["../../src/Comments/CommentRow.tsx"],"names":[],"mappings":"AAuEA,OAAO,EAKL,KAAK,UAAU,EAChB,MAAM,SAAS,CAAC;AAOjB,MAAM,MAAM,aAAa,GAAG,KAAK,GAAG,QAAQ,CAAC;AAQ7C,eAAO,MAAM,eAAe,EAAE,SAAS,aAAa,EAAsB,CAAC;AA6M3E;;;;GAIG;AACH,wBAAgB,UAAU,CAAC,EACzB,OAAO,EACP,KAAK,EACL,QAA0B,EAC1B,oBAA4B,EAC5B,sBAA8B,EAC9B,QAAQ,GACT,EAAE;IACD,OAAO,EAAE,UAAU,CAAC;IACpB,KAAK,EAAE,CAAC,GAAG,CAAC,CAAC;IACb,2EAA2E;IAC3E,QAAQ,CAAC,EAAE,SAAS,aAAa,EAAE,CAAC;IACpC,oBAAoB,CAAC,EAAE,OAAO,CAAC;IAC/B,kEAAkE;IAClE,sBAAsB,CAAC,EAAE,OAAO,CAAC;IACjC,6DAA6D;IAC7D,QAAQ,EAAE,MAAM,CAAC;CAClB,+BAkkBA"}
1
+ {"version":3,"file":"CommentRow.d.ts","sourceRoot":"","sources":["../../src/Comments/CommentRow.tsx"],"names":[],"mappings":"AAuEA,OAAO,EAKL,KAAK,UAAU,EAChB,MAAM,SAAS,CAAC;AAOjB,MAAM,MAAM,aAAa,GAAG,KAAK,GAAG,QAAQ,CAAC;AAQ7C,eAAO,MAAM,eAAe,EAAE,SAAS,aAAa,EAAsB,CAAC;AA6M3E;;;;GAIG;AACH,wBAAgB,UAAU,CAAC,EACzB,OAAO,EACP,KAAK,EACL,QAA0B,EAC1B,oBAA4B,EAC5B,sBAA8B,EAC9B,QAAQ,GACT,EAAE;IACD,OAAO,EAAE,UAAU,CAAC;IACpB,KAAK,EAAE,CAAC,GAAG,CAAC,CAAC;IACb,2EAA2E;IAC3E,QAAQ,CAAC,EAAE,SAAS,aAAa,EAAE,CAAC;IACpC,oBAAoB,CAAC,EAAE,OAAO,CAAC;IAC/B,kEAAkE;IAClE,sBAAsB,CAAC,EAAE,OAAO,CAAC;IACjC,6DAA6D;IAC7D,QAAQ,EAAE,MAAM,CAAC;CAClB,+BAikBA"}
@@ -371,7 +371,9 @@ export function CommentRow({
371
371
  description: actionError,
372
372
  actionLabel: can.retry ? t('@astryx.comments.retry') : undefined,
373
373
  onAction: can.retry ? () => scope.retry(comment) : undefined,
374
- isActionDisabled: rowActionsBusy
374
+ isActionDisabled: rowActionsBusy,
375
+ isRetrying: isBusy,
376
+ isAnnounced: actionFailure?.isAnnounced
375
377
  }
376
378
  // The Banner unmounts once the retry starts; keep focus on the comment.
377
379
  ,
@@ -397,7 +399,8 @@ export function CommentRow({
397
399
  content: {
398
400
  title: actionFailure.message,
399
401
  actionLabel: actionFailure.retry != null ? t('@astryx.comments.retry') : undefined,
400
- onAction: actionFailure.retry
402
+ onAction: actionFailure.retry,
403
+ isAnnounced: actionFailure.isAnnounced
401
404
  },
402
405
  onBeforeAction: () => articleRef.current?.focus(),
403
406
  "data-comment-action-error": "banner"
@@ -1 +1 @@
1
- {"version":3,"file":"Comments.d.ts","sourceRoot":"","sources":["../../src/Comments/Comments.tsx"],"names":[],"mappings":"AAIA;;;;;;;;;;;;;GAaG;AAEH,OAAO,EAKL,KAAK,SAAS,EACd,KAAK,GAAG,EACT,MAAM,OAAO,CAAC;AAGf,OAAO,KAAK,EAAC,SAAS,EAAC,MAAM,oBAAoB,CAAC;AAsBlD,OAAO,KAAK,EACV,aAAa,EAEb,iBAAiB,EACjB,wBAAwB,EACxB,oBAAoB,EACrB,MAAM,SAAS,CAAC;AAEjB,MAAM,WAAW,aACf,SACE,wBAAwB,EACxB,IAAI,CACF,SAAS,CAAC,WAAW,CAAC,EACtB,MAAM,wBAAwB,GAAG,UAAU,GAAG,UAAU,CACzD;IACH,yCAAyC;IACzC,GAAG,CAAC,EAAE,GAAG,CAAC,WAAW,CAAC,CAAC;IACvB;;;;OAIG;IACH,QAAQ,EAAE,SAAS,iBAAiB,EAAE,CAAC;IACvC,kEAAkE;IAClE,MAAM,CAAC,EAAE,SAAS,oBAAoB,EAAE,CAAC;IACzC;sBACkB;IAClB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,qEAAqE;IACrE,gBAAgB,CAAC,EAAE,KAAK,GAAG,QAAQ,GAAG,MAAM,CAAC;IAC7C,0BAA0B;IAC1B,OAAO,CAAC,EAAE,SAAS,GAAG,UAAU,CAAC;IACjC;;;;;;OAMG;IACH,MAAM,CAAC,EAAE,MAAM,GAAG,UAAU,CAAC;IAC7B;;;;;;OAMG;IACH,gBAAgB,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACjC,kFAAkF;IAClF,sBAAsB,CAAC,EAAE,CAAC,QAAQ,EAAE,MAAM,GAAG,IAAI,KAAK,IAAI,CAAC;IAC3D;;;;OAIG;IACH,cAAc,CAAC,EAAE,aAAa,CAAC;IAC/B,gEAAgE;IAChE,uBAAuB,CAAC,EAAE,MAAM,IAAI,CAAC;IACrC;;;OAGG;IACH,gBAAgB,CAAC,EAAE,SAAS,CAAC;IAC7B,gEAAgE;IAChE,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB,iEAAiE;IACjE,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,WAAW,CAAC,EAAE,MAAM,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IACzC,oDAAoD;IACpD,gBAAgB,CAAC,EAAE,OAAO,CAAC;IAC3B,cAAc,CAAC,EAAE,OAAO,CAAC;IACzB,mEAAmE;IACnE,WAAW,CAAC,EAAE,MAAM,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IACzC,qDAAqD;IACrD,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,8CAA8C;IAC9C,UAAU,CAAC,EAAE,SAAS,CAAC;IACvB,+CAA+C;IAC/C,WAAW,CAAC,EAAE,CAAC,KAAK,EAAE,oBAAoB,KAAK,SAAS,CAAC;CAC1D;AAsCD;;;;;;;;;;;;;;;;GAgBG;AACH,wBAAgB,QAAQ,CAAC,EACvB,QAAQ,EACR,MAAkB,EAClB,KAAK,EAAE,SAAS,EAChB,gBAA2B,EAC3B,OAAoB,EACpB,MAAe,EACf,gBAAgB,EAChB,sBAAsB,EACtB,cAAc,EACd,uBAAuB,EACvB,gBAAgB,EAChB,SAAiB,EACjB,SAAS,EACT,WAAW,EACX,gBAAwB,EACxB,cAAsB,EACtB,WAAW,EACX,aAAa,EACb,UAAU,EACV,WAAW,EACX,WAAW,EACX,IAAoB,EACpB,SAAqB,EACrB,mBAAmB,EACnB,cAAyB,EACzB,eAAe,EACf,aAAa,EACb,gBAAgB,EAChB,eAAe,EACf,qBAAqB,EACrB,eAAe,EACf,cAAqB,EACrB,YAAY,EACZ,qBAAqB,EACrB,QAAQ,EACR,UAAU,EACV,QAAQ,EACR,OAAO,EACP,cAAc,EACd,eAAe,EACf,cAAc,EACd,YAAY,EACZ,cAAc,EACd,YAAY,EACZ,UAAU,EACV,iBAAiB,EACjB,uBAAuB,EACvB,cAAc,EACd,GAAG,EACH,MAAM,EACN,SAAS,EACT,KAAK,EACL,GAAG,IAAI,EACR,EAAE,aAAa,+BAiZf;yBAvce,QAAQ"}
1
+ {"version":3,"file":"Comments.d.ts","sourceRoot":"","sources":["../../src/Comments/Comments.tsx"],"names":[],"mappings":"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"}
@@ -31,6 +31,7 @@ import { useTranslator } from '@astryxdesign/core/i18n';
31
31
  import { CommentComposerBase } from "./CommentComposer.js";
32
32
  import { ActivityEventRow, CommentComposerLoadingSkeleton, CommentThreadLoadingSkeleton, ErrorBanner } from "./CommentParts.js";
33
33
  import { CommentRow, THREAD_DIVIDERS } from "./CommentRow.js";
34
+ import { useStatusAnnouncement } from "./useStatusAnnouncement.js";
34
35
  import { CommentsContextProvider, useCommentsController } from "./CommentsContext.js";
35
36
  import { timelineTime } from "./utils.js";
36
37
  import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
@@ -148,6 +149,14 @@ export function Comments({
148
149
  const loadingOlderRef = useRef(false);
149
150
  const loadOlderButtonRef = useRef(null);
150
151
  const olderRetryRef = useRef(null);
152
+ // The load-failure Banner carries no live role: it mounts already holding
153
+ // its text. It is announced once, assertively, through the shared channel
154
+ // (spec:AST-086 FR2, FR5).
155
+ const loadErrorRef = useRef(null);
156
+ useStatusAnnouncement(loadErrorRef, loadError != null ? t('@astryx.comments.errorAnnouncement', {
157
+ title: t('@astryx.comments.loadFailed'),
158
+ description: loadError
159
+ }) : null, 'assertive');
151
160
  const rootRef = useRef(null);
152
161
  const setRootRef = useCallback(element => {
153
162
  rootRef.current = element;
@@ -380,8 +389,8 @@ export function Comments({
380
389
  container
381
390
  }), stylex.props(!isEmbedded && styles.root, xstyle), className, style),
382
391
  children: [loadError != null && /*#__PURE__*/_jsx(Banner, {
392
+ ref: loadErrorRef,
383
393
  status: "error",
384
- role: "alert",
385
394
  title: t('@astryx.comments.loadFailed'),
386
395
  description: loadError,
387
396
  container: "section",
@@ -32,6 +32,8 @@ export type EditTarget = {
32
32
  export type ActionFailure = {
33
33
  message: string;
34
34
  retry?: () => void;
35
+ /** Already spoken by whoever raised it, so the row's Banner stays silent. */
36
+ isAnnounced?: boolean;
35
37
  };
36
38
  export interface CommentsContextValue {
37
39
  currentUser?: CommentUser;
@@ -1 +1 @@
1
- {"version":3,"file":"CommentsContext.d.ts","sourceRoot":"","sources":["../../src/Comments/CommentsContext.tsx"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"CommentsContext.d.ts","sourceRoot":"","sources":["../../src/Comments/CommentsContext.tsx"],"names":[],"mappings":"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"}
@@ -183,7 +183,7 @@ export function useCommentsController({
183
183
  delete next[commentId];
184
184
  return next;
185
185
  });
186
- const runCommentAction = async (commentId, action, failureMessage, retry) => {
186
+ const runCommentAction = async (commentId, action, failureMessage, retry, isAnnounced) => {
187
187
  setPendingActionIds(previous => new Set(previous).add(commentId));
188
188
  clearActionError(commentId);
189
189
  try {
@@ -194,7 +194,8 @@ export function useCommentsController({
194
194
  ...previous,
195
195
  [commentId]: {
196
196
  message: failureMessage,
197
- retry: retry ?? (() => void runCommentAction(commentId, action, failureMessage))
197
+ retry: retry ?? (() => void runCommentAction(commentId, action, failureMessage)),
198
+ isAnnounced
198
199
  }
199
200
  }));
200
201
  return false;
@@ -288,7 +289,10 @@ export function useCommentsController({
288
289
  setDeleteError(undefined);
289
290
  const succeeded = await runCommentAction(target.id, () => onDelete(target.id), t('@astryx.comments.deleteFailed'),
290
291
  // Retrying a delete asks for confirmation again.
291
- () => setDeleteTarget(target));
292
+ () => setDeleteTarget(target),
293
+ // The dialog announces a failed delete (AST-086 FR1, FR6), so the stored
294
+ // failure the row shows is marked before it first renders.
295
+ true);
292
296
  if (succeeded) {
293
297
  commitAndFocus(() => setDeleteTarget(null), neighborId, neighborId == null ? 'thread' : 'article', rootRef);
294
298
  } else {
@@ -0,0 +1,26 @@
1
+ /**
2
+ * @file useStatusAnnouncement.ts
3
+ * @input Uses React, useAnnounce from core hooks
4
+ * @output Exports useStatusAnnouncement hook
5
+ * @position Internal to Comments; announces a transient status element
6
+ * (error banner, progress label) once instead of mounting it as a live region
7
+ *
8
+ * A live region that mounts already holding its text may not be announced, so
9
+ * the visible element carries no live role (spec:AST-086 FR2). This hook says
10
+ * the words once through the shared channel instead, unless a live container
11
+ * such as a chat log already delivers content added inside it (FR4).
12
+ */
13
+ import { type RefObject } from 'react';
14
+ import type { AnnouncePoliteness } from '@astryxdesign/core/hooks';
15
+ /**
16
+ * Announce `message` once per occasion: when the element first shows it, and
17
+ * again whenever the message changes. A rerender or a StrictMode effect replay
18
+ * does not repeat it, and a message that goes away and comes back is a new
19
+ * occasion (spec:AST-086 FR6).
20
+ *
21
+ * @param ref The visible element, used to find an enclosing live container.
22
+ * @param message The words to say, or `null` for nothing.
23
+ * @param politeness Errors are `'assertive'`, progress is `'polite'` (FR5).
24
+ */
25
+ export declare function useStatusAnnouncement(ref: RefObject<HTMLElement | null>, message: string | null, politeness: AnnouncePoliteness): void;
26
+ //# sourceMappingURL=useStatusAnnouncement.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"useStatusAnnouncement.d.ts","sourceRoot":"","sources":["../../src/Comments/useStatusAnnouncement.ts"],"names":[],"mappings":"AAIA;;;;;;;;;;;GAWG;AAEH,OAAO,EAAoB,KAAK,SAAS,EAAC,MAAM,OAAO,CAAC;AAExD,OAAO,KAAK,EAAC,kBAAkB,EAAC,MAAM,0BAA0B,CAAC;AAKjE;;;;;;;;;GASG;AACH,wBAAgB,qBAAqB,CACnC,GAAG,EAAE,SAAS,CAAC,WAAW,GAAG,IAAI,CAAC,EAClC,OAAO,EAAE,MAAM,GAAG,IAAI,EACtB,UAAU,EAAE,kBAAkB,GAC7B,IAAI,CAkBN"}
@@ -0,0 +1,48 @@
1
+ // Copyright (c) Meta Platforms, Inc. and affiliates.
2
+
3
+ 'use client';
4
+
5
+ /**
6
+ * @file useStatusAnnouncement.ts
7
+ * @input Uses React, useAnnounce from core hooks
8
+ * @output Exports useStatusAnnouncement hook
9
+ * @position Internal to Comments; announces a transient status element
10
+ * (error banner, progress label) once instead of mounting it as a live region
11
+ *
12
+ * A live region that mounts already holding its text may not be announced, so
13
+ * the visible element carries no live role (spec:AST-086 FR2). This hook says
14
+ * the words once through the shared channel instead, unless a live container
15
+ * such as a chat log already delivers content added inside it (FR4).
16
+ */
17
+ import { useEffect, useRef } from 'react';
18
+ import { useAnnounce } from '@astryxdesign/core/hooks';
19
+ const LIVE_CONTAINER_SELECTOR = '[role="log"], [role="status"], [role="alert"], [aria-live="polite"], [aria-live="assertive"]';
20
+
21
+ /**
22
+ * Announce `message` once per occasion: when the element first shows it, and
23
+ * again whenever the message changes. A rerender or a StrictMode effect replay
24
+ * does not repeat it, and a message that goes away and comes back is a new
25
+ * occasion (spec:AST-086 FR6).
26
+ *
27
+ * @param ref The visible element, used to find an enclosing live container.
28
+ * @param message The words to say, or `null` for nothing.
29
+ * @param politeness Errors are `'assertive'`, progress is `'polite'` (FR5).
30
+ */
31
+ export function useStatusAnnouncement(ref, message, politeness) {
32
+ const announce = useAnnounce();
33
+ const announcedRef = useRef(null);
34
+ useEffect(() => {
35
+ if (message == null || message === '') {
36
+ announcedRef.current = null;
37
+ return;
38
+ }
39
+ if (announcedRef.current === message) {
40
+ return;
41
+ }
42
+ announcedRef.current = message;
43
+ const isInsideLiveContainer = ref.current?.parentElement?.closest(LIVE_CONTAINER_SELECTOR) != null;
44
+ if (!isInsideLiveContainer) {
45
+ announce(message, politeness);
46
+ }
47
+ }, [announce, message, politeness, ref]);
48
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@astryxdesign/lab",
3
- "version": "0.7.6-canary.df8928a",
3
+ "version": "0.7.6-canary.e428366",
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.6-canary.df8928a",
52
+ "@astryxdesign/core": "0.7.6-canary.e428366",
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.6-canary.df8928a",
63
- "@astryxdesign/cli": "0.7.6-canary.df8928a",
62
+ "@astryxdesign/a11y-spec": "0.7.6-canary.e428366",
63
+ "@astryxdesign/cli": "0.7.6-canary.e428366",
64
64
  "@babel/cli": "^7.29.7",
65
65
  "@babel/core": "^7.29.7",
66
66
  "@babel/preset-react": "^7.29.7",
@@ -122,7 +122,7 @@ export const docs = {
122
122
  name: 'isDisabled',
123
123
  type: 'boolean',
124
124
  description:
125
- 'Disables activation with native button semantics. Useful for a pending anchor before its thread exists.',
125
+ 'Disables activation: the pin exposes aria-disabled, keeps its tab stop, and blocks every activation path. Useful for a pending anchor before its thread exists.',
126
126
  default: 'false',
127
127
  },
128
128
  {
@@ -164,7 +164,7 @@ export const docs = {
164
164
  category: 'Keyboard',
165
165
  criterion: '2.1.1 Keyboard',
166
166
  description:
167
- 'CommentPin is one native button. Tab reaches an enabled pin; Enter and Space activate it. A disabled pin uses native disabled semantics and is removed from sequential focus order.',
167
+ 'CommentPin is one native button. Tab reaches an enabled pin; Enter and Space activate it. A disabled pin stays in the tab order and is announced as disabled through aria-disabled, and every activation path is blocked.',
168
168
  },
169
169
  {
170
170
  name: 'Selected state and name',
@@ -323,7 +323,8 @@ export const docsZh = {
323
323
  isDimmed:
324
324
  '其他标记被选中时降低此标记的视觉突出度,但不禁用操作;未选中任何标记时不应降低。',
325
325
  isResolved: '所代表的线程是否都已解决;已解决的标记除非被选中否则不渲染。',
326
- isDisabled: '使用原生按钮语义禁用激活。',
326
+ isDisabled:
327
+ '通过 aria-disabled 禁用激活:保留 Tab 焦点,拦截所有激活路径。',
327
328
  onClick: '由产品拥有的激活处理函数。',
328
329
  xstyle: '根按钮的 StyleX 布局样式;由宿主决定内容上方或边距中的位置。',
329
330
  },
@@ -369,7 +370,8 @@ export const docsDense = {
369
370
  isDimmed:
370
371
  'controlled de-emphasis for non-selected siblings only while another pin is selected; remains interactive',
371
372
  isResolved: 'resolved pins render nothing unless selected',
372
- isDisabled: 'native disabled marker',
373
+ isDisabled:
374
+ 'disabled marker: aria-disabled, keeps its tab stop, blocks every activation path',
373
375
  onClick: 'host activation handler',
374
376
  xstyle: 'root layout/positioning styles; marker owns no coordinates',
375
377
  },
@@ -156,18 +156,18 @@ intentional decision. A `current` contract contains no unresolved rows.
156
156
 
157
157
  ### Representative states
158
158
 
159
- | State | Required invariant | Allowed variation |
160
- | ------------------------ | --------------------------------------------------------------------------------------- | ------------------------------------------------------------ |
161
- | Single | first participant Avatar; no visible count; an accent dot after it when unread | identity, selected/dimmed/resolved/disabled state, placement |
162
- | Grouped, one identity | one Avatar plus total thread count | count and states |
163
- | Grouped, two or three | every distinct participant Avatar plus total thread count | ordered identities, count, and states |
164
- | Grouped, more than three | first two distinct Avatars, an ellipsis overflow circle, and total thread count | ordered identities and states |
165
- | Unread | accent dot after the total, or after the participant on a single marker | other states |
166
- | Sizes | 28, 32, or 36px tall with 22, 24, or 28px circles and the same inset on every side | every other state |
167
- | Selected | active accent treatment preserves Avatar and count legibility and wins over dimming | theme paint |
168
- | Dimmed | lower opacity identifies a non-selected sibling without disabling activation | disabled may also apply |
169
- | Resolved | renders nothing unless selected; selected, it takes the selected treatment | disabled may also apply |
170
- | Disabled | native disabled button does not activate and is removed from the sequential focus order | selected representation remains visible |
159
+ | State | Required invariant | Allowed variation |
160
+ | ------------------------ | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------ |
161
+ | Single | first participant Avatar; no visible count; an accent dot after it when unread | identity, selected/dimmed/resolved/disabled state, placement |
162
+ | Grouped, one identity | one Avatar plus total thread count | count and states |
163
+ | Grouped, two or three | every distinct participant Avatar plus total thread count | ordered identities, count, and states |
164
+ | Grouped, more than three | first two distinct Avatars, an ellipsis overflow circle, and total thread count | ordered identities and states |
165
+ | Unread | accent dot after the total, or after the participant on a single marker | other states |
166
+ | Sizes | 28, 32, or 36px tall with 22, 24, or 28px circles and the same inset on every side | every other state |
167
+ | Selected | active accent treatment preserves Avatar and count legibility and wins over dimming | theme paint |
168
+ | Dimmed | lower opacity identifies a non-selected sibling without disabling activation | disabled may also apply |
169
+ | Resolved | renders nothing unless selected; selected, it takes the selected treatment | disabled may also apply |
170
+ | Disabled | an aria-disabled button does not activate but keeps its tab stop, so keyboard and screen-reader users reach it and hear it is unavailable; an unselected disabled pin paints GrayText color and border under forced colors | selected representation remains visible, keeping its Highlight treatment |
171
171
 
172
172
  ### Transformation and precedence order
173
173
 
@@ -203,7 +203,8 @@ durable constraints and their verification target.
203
203
  ## Accessibility contract
204
204
 
205
205
  - **AR1 — Action.** The root is one native `button type="button"` named by the
206
- required `label`; `isDisabled` uses native disabled behavior.
206
+ required `label`; `isDisabled` exposes `aria-disabled="true"` and blocks every
207
+ activation path while the pin keeps its tab stop (`spec:AST-085`).
207
208
  - **AR2 — Selection.** `isSelected` is exposed through `aria-pressed`, one solid
208
209
  2px accent outline outside the pin, and a forced-colors Highlight treatment;
209
210
  the outline hugs the pin while the shared focus-visible outline sits farther