@astryxdesign/lab 0.7.6-canary.ec128c4 → 0.7.6-canary.f73623d

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/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":"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.ec128c4",
3
+ "version": "0.7.6-canary.f73623d",
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.ec128c4",
52
+ "@astryxdesign/core": "0.7.6-canary.f73623d",
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.ec128c4",
63
- "@astryxdesign/cli": "0.7.6-canary.ec128c4",
62
+ "@astryxdesign/a11y-spec": "0.7.6-canary.f73623d",
63
+ "@astryxdesign/cli": "0.7.6-canary.f73623d",
64
64
  "@babel/cli": "^7.29.7",
65
65
  "@babel/core": "^7.29.7",
66
66
  "@babel/preset-react": "^7.29.7",
@@ -12,6 +12,11 @@ import {
12
12
  it,
13
13
  vi,
14
14
  } from 'vitest';
15
+ const announce = vi.hoisted(() => vi.fn());
16
+ vi.mock('@astryxdesign/core/hooks', async importOriginal => ({
17
+ ...(await importOriginal<typeof import('@astryxdesign/core/hooks')>()),
18
+ useAnnounce: () => announce,
19
+ }));
15
20
  // The full emoji set renders slowly in jsdom; the composer only needs a few.
16
21
  vi.mock('../EmojiPicker/emojiData', () => ({
17
22
  EMOJI_GROUPS: [
@@ -70,6 +75,7 @@ class ResizeObserverStub {
70
75
  }
71
76
 
72
77
  beforeEach(() => {
78
+ announce.mockClear();
73
79
  vi.stubGlobal('ResizeObserver', ResizeObserverStub);
74
80
  Element.prototype.scrollIntoView = () => {};
75
81
  });
@@ -78,6 +84,17 @@ afterEach(() => {
78
84
  vi.unstubAllGlobals();
79
85
  });
80
86
 
87
+ /** The composer's failure Banner, which carries no live role. */
88
+ function composerErrorBanner(): HTMLElement {
89
+ const banner = document.querySelector<HTMLElement>(
90
+ '[data-composer-error="banner"]',
91
+ );
92
+ if (banner == null) {
93
+ throw new Error('Composer error Banner not found');
94
+ }
95
+ return banner;
96
+ }
97
+
81
98
  async function settle() {
82
99
  await act(() => new Promise<void>(resolve => setTimeout(resolve, 0)));
83
100
  }
@@ -289,9 +306,41 @@ describe('CommentComposer', () => {
289
306
  });
290
307
  });
291
308
  expect(onUploadImages).not.toHaveBeenCalled();
292
- expect(screen.getByRole('alert').textContent).toContain(
293
- 'Only image files can be added',
309
+ const banner = composerErrorBanner();
310
+ expect(banner.textContent).toContain('Only image files can be added');
311
+ // The Banner has no live role: it is announced once through the channel.
312
+ expect(banner).not.toHaveAttribute('role');
313
+ expect(announce).toHaveBeenCalledTimes(1);
314
+ expect(announce).toHaveBeenCalledWith(
315
+ expect.stringContaining('Only image files can be added'),
316
+ 'assertive',
317
+ );
318
+ });
319
+
320
+ it('announces a second refusal with the same words again', async () => {
321
+ render(
322
+ <CommentComposer
323
+ value=""
324
+ onChange={() => {}}
325
+ onSubmit={() => {}}
326
+ onUploadImages={vi.fn()}
327
+ />,
294
328
  );
329
+ const input = document.querySelector('input[type="file"]');
330
+ if (!(input instanceof HTMLInputElement)) {
331
+ throw new Error('File input not found');
332
+ }
333
+ for (const name of ['first.pdf', 'second.pdf']) {
334
+ await act(async () => {
335
+ fireEvent.change(input, {
336
+ target: {
337
+ files: [new File(['%PDF'], name, {type: 'application/pdf'})],
338
+ },
339
+ });
340
+ });
341
+ }
342
+ // Each refusal is its own occasion (AST-086 FR6), though the words match.
343
+ expect(announce).toHaveBeenCalledTimes(2);
295
344
  });
296
345
 
297
346
  it('shows an error with Retry, and a quoted passage the viewer can remove', () => {
@@ -309,8 +358,9 @@ describe('CommentComposer', () => {
309
358
  highlightColor="green"
310
359
  />,
311
360
  );
312
- const alert = screen.getByRole('alert');
313
- fireEvent.click(within(alert).getByRole('button', {name: 'Retry'}));
361
+ fireEvent.click(
362
+ within(composerErrorBanner()).getByRole('button', {name: 'Retry'}),
363
+ );
314
364
  expect(onRetry).toHaveBeenCalledTimes(1);
315
365
  expect(
316
366
  document
@@ -259,6 +259,13 @@ export function CommentComposerBase({
259
259
  [focusKey],
260
260
  );
261
261
  const [actionError, setActionError] = useState<ErrorBannerContent>();
262
+ // Counts action failures so each one mounts its own Banner: a second failure
263
+ // with the same words is a new occasion and is announced again (AST-086 FR6).
264
+ const [actionErrorSerial, setActionErrorSerial] = useState(0);
265
+ const reportActionError = (content: ErrorBannerContent) => {
266
+ setActionError(content);
267
+ setActionErrorSerial(serial => serial + 1);
268
+ };
262
269
  const [isActionPending, setIsActionPending] = useState(false);
263
270
  const [isPickerOpen, setIsPickerOpen] = useState(false);
264
271
 
@@ -303,7 +310,7 @@ export function CommentComposerBase({
303
310
  }
304
311
  } catch {
305
312
  if (isMountedRef.current) {
306
- setActionError({
313
+ reportActionError({
307
314
  title: t('@astryx.commentComposer.uploadFailed'),
308
315
  actionLabel: t('@astryx.comments.retry'),
309
316
  onAction: () => beginImageUpload(files),
@@ -322,7 +329,7 @@ export function CommentComposerBase({
322
329
  }
323
330
  const images = files.filter(file => file.type.startsWith('image/'));
324
331
  if (images.length !== files.length) {
325
- setActionError({
332
+ reportActionError({
326
333
  title: t('@astryx.commentComposer.imagesOnly'),
327
334
  actionLabel: t('@astryx.commentComposer.chooseImages'),
328
335
  onAction: () => {
@@ -378,6 +385,7 @@ export function CommentComposerBase({
378
385
  <VStack gap={1} width="100%" aria-busy={isBusy || undefined}>
379
386
  {errorBanner != null && (
380
387
  <ErrorBanner
388
+ key={error != null ? 'error' : `action-${actionErrorSerial}`}
381
389
  content={errorBanner}
382
390
  // The Banner unmounts once the retry starts; keep focus in the input.
383
391
  onBeforeAction={() => inputRef.current?.focus()}