@astryxdesign/core 0.5.2-canary.c9c8564 → 0.5.2-canary.e03511b

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 (216) hide show
  1. package/dist/BottomSheet/BottomSheet.d.ts +3 -1
  2. package/dist/BottomSheet/BottomSheet.d.ts.map +1 -1
  3. package/dist/BottomSheet/BottomSheet.js +4 -3
  4. package/dist/BottomSheet/BottomSheetEdgeTint.d.ts +2 -2
  5. package/dist/BottomSheet/BottomSheetEdgeTint.d.ts.map +1 -1
  6. package/dist/BottomSheet/BottomSheetEdgeTint.js +7 -10
  7. package/dist/BottomSheet/BottomSheetSwitcher.d.ts.map +1 -1
  8. package/dist/BottomSheet/BottomSheetSwitcher.js +1 -1
  9. package/dist/Button/Button.d.ts +2 -1
  10. package/dist/Button/Button.d.ts.map +1 -1
  11. package/dist/Button/Button.js +11 -4
  12. package/dist/Carousel/Carousel.d.ts.map +1 -1
  13. package/dist/Carousel/Carousel.js +2 -2
  14. package/dist/Chat/ChatToolCalls.d.ts.map +1 -1
  15. package/dist/Chat/ChatToolCalls.js +34 -17
  16. package/dist/ContextMenu/ContextMenu.d.ts +14 -3
  17. package/dist/ContextMenu/ContextMenu.d.ts.map +1 -1
  18. package/dist/ContextMenu/ContextMenu.js +149 -26
  19. package/dist/ContextMenu/index.d.ts +1 -0
  20. package/dist/ContextMenu/index.d.ts.map +1 -1
  21. package/dist/DropdownMenu/DropdownMenu.d.ts +24 -5
  22. package/dist/DropdownMenu/DropdownMenu.d.ts.map +1 -1
  23. package/dist/DropdownMenu/DropdownMenu.js +340 -26
  24. package/dist/DropdownMenu/DropdownMenuContext.d.ts +1 -1
  25. package/dist/DropdownMenu/DropdownMenuContext.d.ts.map +1 -1
  26. package/dist/DropdownMenu/DropdownMenuItem.d.ts.map +1 -1
  27. package/dist/DropdownMenu/DropdownMenuItem.js +1 -1
  28. package/dist/DropdownMenu/DropdownMenuSubMenu.d.ts +6 -2
  29. package/dist/DropdownMenu/DropdownMenuSubMenu.d.ts.map +1 -1
  30. package/dist/DropdownMenu/DropdownMenuSubMenu.js +43 -14
  31. package/dist/DropdownMenu/MenuBottomSheet.d.ts +20 -0
  32. package/dist/DropdownMenu/MenuBottomSheet.d.ts.map +1 -0
  33. package/dist/DropdownMenu/MenuBottomSheet.js +36 -0
  34. package/dist/DropdownMenu/MenuBottomSheetActionList.d.ts +10 -0
  35. package/dist/DropdownMenu/MenuBottomSheetActionList.d.ts.map +1 -0
  36. package/dist/DropdownMenu/MenuBottomSheetActionList.js +111 -0
  37. package/dist/DropdownMenu/index.d.ts +2 -1
  38. package/dist/DropdownMenu/index.d.ts.map +1 -1
  39. package/dist/DropdownMenu/menuWidth.d.ts +14 -0
  40. package/dist/DropdownMenu/menuWidth.d.ts.map +1 -0
  41. package/dist/DropdownMenu/menuWidth.js +35 -0
  42. package/dist/DropdownMenu/useMenuOverflow.d.ts +10 -0
  43. package/dist/DropdownMenu/useMenuOverflow.d.ts.map +1 -0
  44. package/dist/DropdownMenu/useMenuOverflow.js +60 -0
  45. package/dist/MoreMenu/MoreMenu.d.ts +8 -2
  46. package/dist/MoreMenu/MoreMenu.d.ts.map +1 -1
  47. package/dist/MoreMenu/MoreMenu.js +2 -0
  48. package/dist/MultiSelector/MultiSelector.d.ts +11 -1
  49. package/dist/MultiSelector/MultiSelector.d.ts.map +1 -1
  50. package/dist/MultiSelector/MultiSelector.js +97 -68
  51. package/dist/MultiSelector/index.d.ts +1 -1
  52. package/dist/MultiSelector/index.d.ts.map +1 -1
  53. package/dist/Popover/Popover.d.ts +10 -6
  54. package/dist/Popover/Popover.d.ts.map +1 -1
  55. package/dist/Popover/Popover.js +141 -16
  56. package/dist/Popover/usePopover.d.ts +4 -0
  57. package/dist/Popover/usePopover.d.ts.map +1 -1
  58. package/dist/Popover/usePopover.js +52 -5
  59. package/dist/Selector/Selector.d.ts +10 -0
  60. package/dist/Selector/Selector.d.ts.map +1 -1
  61. package/dist/Selector/Selector.js +106 -80
  62. package/dist/Selector/SelectorBottomSheet.d.ts +21 -0
  63. package/dist/Selector/SelectorBottomSheet.d.ts.map +1 -0
  64. package/dist/Selector/SelectorBottomSheet.js +83 -0
  65. package/dist/Selector/index.d.ts +1 -1
  66. package/dist/Selector/index.d.ts.map +1 -1
  67. package/dist/Selector/selectorPresentation.stylex.d.ts +16 -0
  68. package/dist/Selector/selectorPresentation.stylex.d.ts.map +1 -0
  69. package/dist/Selector/selectorPresentation.stylex.js +21 -0
  70. package/dist/Selector/useSelectorPresentation.d.ts +32 -0
  71. package/dist/Selector/useSelectorPresentation.d.ts.map +1 -0
  72. package/dist/Selector/useSelectorPresentation.js +90 -0
  73. package/dist/Toast/useToastGesture.d.ts.map +1 -1
  74. package/dist/Toast/useToastGesture.js +46 -9
  75. package/dist/astryx.css +19 -1
  76. package/dist/hooks/useAdaptivePresentation.d.ts +5 -0
  77. package/dist/hooks/useAdaptivePresentation.d.ts.map +1 -0
  78. package/dist/hooks/useAdaptivePresentation.js +19 -0
  79. package/dist/hooks/useFocusReturnVisibility.d.ts +7 -0
  80. package/dist/hooks/useFocusReturnVisibility.d.ts.map +1 -0
  81. package/dist/hooks/useFocusReturnVisibility.js +35 -0
  82. package/dist/hooks/useFocusTrap.d.ts.map +1 -1
  83. package/dist/hooks/useFocusTrap.js +12 -0
  84. package/locales/en.json +20 -0
  85. package/locales/pseudo.json +15 -0
  86. package/package.json +2 -2
  87. package/src/BottomSheet/BottomSheet.doc.mjs +37 -0
  88. package/src/BottomSheet/BottomSheet.spec.md +177 -0
  89. package/src/BottomSheet/BottomSheet.test.tsx +29 -0
  90. package/src/BottomSheet/BottomSheet.tsx +7 -4
  91. package/src/BottomSheet/BottomSheetEdgeTint.test.tsx +4 -6
  92. package/src/BottomSheet/BottomSheetEdgeTint.tsx +7 -10
  93. package/src/BottomSheet/BottomSheetSwitcher.tsx +1 -2
  94. package/src/Button/Button.doc.mjs +56 -0
  95. package/src/Button/Button.test.tsx +10 -0
  96. package/src/Button/Button.tsx +13 -5
  97. package/src/ButtonGroup/ButtonGroup.doc.mjs +47 -0
  98. package/src/Carousel/Carousel.test.tsx +83 -0
  99. package/src/Carousel/Carousel.tsx +8 -2
  100. package/src/Chat/ChatToolCalls.test.tsx +44 -0
  101. package/src/Chat/ChatToolCalls.tsx +36 -15
  102. package/src/CheckboxList/CheckboxList.doc.mjs +172 -31
  103. package/src/CheckboxList/CheckboxList.spec.md +214 -0
  104. package/src/CommandPalette/CommandPalette.doc.mjs +72 -0
  105. package/src/CommandPalette/CommandPalette.spec.md +223 -0
  106. package/src/ComplexSelector/ComplexSelector.doc.mjs +42 -0
  107. package/src/ComplexSelector/ComplexSelector.spec.md +189 -0
  108. package/src/ContextMenu/ContextMenu.doc.mjs +61 -1
  109. package/src/ContextMenu/ContextMenu.spec.md +206 -0
  110. package/src/ContextMenu/ContextMenu.test.tsx +131 -1
  111. package/src/ContextMenu/ContextMenu.tsx +199 -32
  112. package/src/ContextMenu/index.ts +1 -0
  113. package/src/Divider/Divider.doc.mjs +24 -0
  114. package/src/Divider/Divider.spec.md +150 -0
  115. package/src/DropdownMenu/DropdownMenu.doc.mjs +305 -40
  116. package/src/DropdownMenu/DropdownMenu.spec.md +245 -0
  117. package/src/DropdownMenu/DropdownMenu.test.tsx +518 -7
  118. package/src/DropdownMenu/DropdownMenu.tsx +459 -28
  119. package/src/DropdownMenu/DropdownMenuContext.tsx +1 -1
  120. package/src/DropdownMenu/DropdownMenuItem.tsx +2 -0
  121. package/src/DropdownMenu/DropdownMenuSubMenu.doc.mjs +4 -2
  122. package/src/DropdownMenu/DropdownMenuSubMenu.test.tsx +124 -0
  123. package/src/DropdownMenu/DropdownMenuSubMenu.tsx +72 -17
  124. package/src/DropdownMenu/MenuBottomSheet.tsx +46 -0
  125. package/src/DropdownMenu/MenuBottomSheetActionList.tsx +141 -0
  126. package/src/DropdownMenu/index.ts +2 -0
  127. package/src/DropdownMenu/menuWidth.ts +51 -0
  128. package/src/DropdownMenu/useMenuOverflow.ts +77 -0
  129. package/src/FieldStatus/FieldStatus.doc.mjs +21 -0
  130. package/src/FieldStatus/FieldStatus.spec.md +212 -0
  131. package/src/Grid/Grid.doc.mjs +19 -0
  132. package/src/Grid/Grid.spec.md +161 -0
  133. package/src/Icon/Icon.doc.mjs +196 -48
  134. package/src/Icon/Icon.spec.md +191 -0
  135. package/src/IconButton/IconButton.doc.mjs +38 -0
  136. package/src/Kbd/Kbd.doc.mjs +18 -0
  137. package/src/Kbd/Kbd.spec.md +141 -0
  138. package/src/Layout/Layout.doc.mjs +32 -0
  139. package/src/Layout/Layout.spec.md +199 -0
  140. package/src/Lightbox/Lightbox.doc.mjs +149 -33
  141. package/src/Lightbox/Lightbox.spec.md +197 -0
  142. package/src/Markdown/Markdown.doc.mjs +60 -0
  143. package/src/Markdown/Markdown.spec.md +200 -0
  144. package/src/MobileNav/MobileNav.doc.mjs +140 -32
  145. package/src/MobileNav/MobileNav.spec.md +208 -0
  146. package/src/MoreMenu/MoreMenu.doc.mjs +59 -0
  147. package/src/MoreMenu/MoreMenu.spec.md +221 -0
  148. package/src/MoreMenu/MoreMenu.test.tsx +47 -0
  149. package/src/MoreMenu/MoreMenu.tsx +13 -1
  150. package/src/MultiSelector/MultiSelector.doc.mjs +128 -0
  151. package/src/MultiSelector/MultiSelector.spec.md +266 -0
  152. package/src/MultiSelector/MultiSelector.test.tsx +127 -0
  153. package/src/MultiSelector/MultiSelector.tsx +121 -73
  154. package/src/MultiSelector/index.ts +1 -0
  155. package/src/NavIcon/NavIcon.doc.mjs +17 -0
  156. package/src/NavIcon/NavIcon.spec.md +133 -0
  157. package/src/NavMenu/NavHeadingMenu.spec.md +205 -0
  158. package/src/NavMenu/NavMenu.doc.mjs +37 -0
  159. package/src/Outline/Outline.doc.mjs +35 -0
  160. package/src/Outline/Outline.spec.md +161 -0
  161. package/src/OverflowList/OverflowList.doc.mjs +24 -0
  162. package/src/OverflowList/OverflowList.spec.md +156 -0
  163. package/src/Pagination/Pagination.doc.mjs +74 -0
  164. package/src/Pagination/Pagination.spec.md +225 -0
  165. package/src/Popover/Popover.doc.mjs +11 -11
  166. package/src/Popover/Popover.test.tsx +397 -2
  167. package/src/Popover/Popover.tsx +228 -21
  168. package/src/Popover/usePopover.tsx +92 -15
  169. package/src/ProgressBar/ProgressBar.doc.mjs +198 -38
  170. package/src/ProgressBar/ProgressBar.spec.md +260 -0
  171. package/src/Resizable/Resizable.doc.mjs +59 -16
  172. package/src/Resizable/Resizable.spec.md +194 -0
  173. package/src/Section/Section.doc.mjs +17 -0
  174. package/src/Section/Section.spec.md +138 -0
  175. package/src/SegmentedControl/SegmentedControl.doc.mjs +83 -0
  176. package/src/SegmentedControl/SegmentedControl.spec.md +151 -0
  177. package/src/Selector/Selector.doc.mjs +12 -0
  178. package/src/Selector/Selector.spec.md +202 -0
  179. package/src/Selector/Selector.test.tsx +135 -0
  180. package/src/Selector/Selector.tsx +141 -82
  181. package/src/Selector/SelectorBottomSheet.tsx +97 -0
  182. package/src/Selector/index.ts +1 -0
  183. package/src/Selector/selectorPresentation.stylex.ts +20 -0
  184. package/src/Selector/useSelectorPresentation.ts +147 -0
  185. package/src/Skeleton/Skeleton.doc.mjs +12 -0
  186. package/src/Skeleton/Skeleton.spec.md +126 -0
  187. package/src/Slider/Slider.doc.mjs +184 -30
  188. package/src/Slider/Slider.spec.md +223 -0
  189. package/src/Stack/Stack.doc.mjs +22 -0
  190. package/src/Stack/Stack.spec.md +154 -0
  191. package/src/StatusDot/StatusDot.doc.mjs +17 -0
  192. package/src/StatusDot/StatusDot.spec.md +137 -0
  193. package/src/Switch/Switch.doc.mjs +40 -0
  194. package/src/Switch/Switch.spec.md +174 -0
  195. package/src/Table/Table.doc.mjs +102 -24
  196. package/src/Table/Table.spec.md +283 -0
  197. package/src/Text/Text.doc.mjs +190 -43
  198. package/src/Text/Text.spec.md +205 -0
  199. package/src/TextArea/TextArea.doc.mjs +255 -45
  200. package/src/TextArea/TextArea.spec.md +204 -0
  201. package/src/Toast/ToastViewport.test.tsx +118 -4
  202. package/src/Toast/useToastGesture.ts +61 -8
  203. package/src/ToggleButton/ToggleButton.doc.mjs +56 -0
  204. package/src/Toolbar/Toolbar.doc.mjs +19 -0
  205. package/src/Toolbar/Toolbar.spec.md +173 -0
  206. package/src/Tooltip/Tooltip.doc.mjs +17 -0
  207. package/src/Tooltip/Tooltip.spec.md +141 -0
  208. package/src/TreeList/TreeList.doc.mjs +58 -0
  209. package/src/TreeList/TreeList.spec.md +220 -0
  210. package/src/Typeahead/Typeahead.doc.mjs +83 -1
  211. package/src/Typeahead/Typeahead.spec.md +250 -0
  212. package/src/hooks/useAdaptivePresentation.ts +35 -0
  213. package/src/hooks/useFocusReturnVisibility.ts +45 -0
  214. package/src/hooks/useFocusTrap.test.tsx +40 -0
  215. package/src/hooks/useFocusTrap.ts +13 -0
  216. package/src/theme/themingTargets.test.ts +91 -25
@@ -850,4 +850,87 @@ describe('Carousel', () => {
850
850
  expect(scroller).not.toHaveAttribute('data-padding');
851
851
  });
852
852
  });
853
+
854
+ describe('edge fade', () => {
855
+ function getScroller() {
856
+ const region = screen.getByRole('region');
857
+ return region.firstElementChild as HTMLElement;
858
+ }
859
+
860
+ function makeOverflowing(el: HTMLElement, scrollLeft: number) {
861
+ Object.defineProperty(el, 'scrollWidth', {
862
+ value: 500,
863
+ configurable: true,
864
+ });
865
+ Object.defineProperty(el, 'clientWidth', {
866
+ value: 200,
867
+ configurable: true,
868
+ });
869
+ Object.defineProperty(el, 'scrollLeft', {
870
+ value: scrollLeft,
871
+ writable: true,
872
+ configurable: true,
873
+ });
874
+ fireEvent.scroll(el);
875
+ }
876
+
877
+ function injectedCss(): string {
878
+ let out = '';
879
+ for (const sheet of Array.from(document.styleSheets)) {
880
+ try {
881
+ for (const rule of Array.from(sheet.cssRules)) {
882
+ out += rule.cssText + '\n';
883
+ }
884
+ } catch {
885
+ // Ignore cross-origin sheets.
886
+ }
887
+ }
888
+ return out;
889
+ }
890
+
891
+ it('fades the physical left edge when only the start overflows (LTR)', () => {
892
+ render(
893
+ <Carousel aria-label="Fade">
894
+ <div>Item 1</div>
895
+ <div>Item 2</div>
896
+ </Carousel>,
897
+ );
898
+ const scroller = getScroller();
899
+ makeOverflowing(scroller, 300);
900
+ expect(getComputedStyle(scroller).maskImage).toContain(
901
+ 'linear-gradient(to right',
902
+ );
903
+ });
904
+
905
+ it('fades the physical right edge when only the end overflows (LTR)', () => {
906
+ render(
907
+ <Carousel aria-label="Fade">
908
+ <div>Item 1</div>
909
+ <div>Item 2</div>
910
+ </Carousel>,
911
+ );
912
+ const scroller = getScroller();
913
+ makeOverflowing(scroller, 0);
914
+ expect(getComputedStyle(scroller).maskImage).toContain(
915
+ 'linear-gradient(to left',
916
+ );
917
+ });
918
+
919
+ it('mirrors both single-edge fade gradients under RTL', () => {
920
+ render(
921
+ <Carousel aria-label="Fade">
922
+ <div>Item 1</div>
923
+ <div>Item 2</div>
924
+ </Carousel>,
925
+ );
926
+ const css = injectedCss();
927
+ expect(css).toMatch(
928
+ /:is\(\[dir="rtl"\][^)]*\)[^{]*\{\s*mask-image:\s*linear-gradient\(to left/,
929
+ );
930
+ expect(css).toMatch(
931
+ /:is\(\[dir="rtl"\][^)]*\)[^{]*\{\s*mask-image:\s*linear-gradient\(to right/,
932
+ );
933
+ });
934
+ });
935
+
853
936
  });
@@ -178,10 +178,16 @@ const styles = stylex.create({
178
178
  maskImage: 'none',
179
179
  },
180
180
  fadeStart: {
181
- maskImage: `linear-gradient(to right, transparent 0%, rgba(0,0,0,0.3) 2px, black ${spacingVars['--spacing-1']})`,
181
+ maskImage: {
182
+ default: `linear-gradient(to right, transparent 0%, rgba(0,0,0,0.3) 2px, black ${spacingVars['--spacing-1']})`,
183
+ ':is([dir="rtl"] *)': `linear-gradient(to left, transparent 0%, rgba(0,0,0,0.3) 2px, black ${spacingVars['--spacing-1']})`,
184
+ },
182
185
  },
183
186
  fadeEnd: {
184
- maskImage: `linear-gradient(to left, transparent 0%, rgba(0,0,0,0.3) 2px, black ${spacingVars['--spacing-1']})`,
187
+ maskImage: {
188
+ default: `linear-gradient(to left, transparent 0%, rgba(0,0,0,0.3) 2px, black ${spacingVars['--spacing-1']})`,
189
+ ':is([dir="rtl"] *)': `linear-gradient(to right, transparent 0%, rgba(0,0,0,0.3) 2px, black ${spacingVars['--spacing-1']})`,
190
+ },
185
191
  },
186
192
  fadeBoth: {
187
193
  maskImage: `linear-gradient(to right, transparent 0%, rgba(0,0,0,0.3) 2px, black ${spacingVars['--spacing-1']}, black calc(100% - ${spacingVars['--spacing-1']}), rgba(0,0,0,0.3) calc(100% - 2px), transparent 100%)`,
@@ -46,6 +46,50 @@ describe('ChatToolCalls', () => {
46
46
  expect(screen.queryByText('1.2s')).not.toBeInTheDocument();
47
47
  });
48
48
 
49
+ it.each([
50
+ ['pending', 'Pending'],
51
+ ['running', 'Running'],
52
+ ['complete', 'Complete'],
53
+ ['error', 'Failed'],
54
+ ] as const)(
55
+ 'names the %s status for assistive technology',
56
+ (status, label) => {
57
+ render(<ChatToolCalls calls={[{name: 'bash', status}]} />);
58
+ expect(screen.getByText(label)).toBeInTheDocument();
59
+ },
60
+ );
61
+
62
+ it('includes the status in an expandable row accessible name', () => {
63
+ render(
64
+ <ChatToolCalls
65
+ calls={[
66
+ {
67
+ name: 'readFile',
68
+ status: 'running',
69
+ resultDetail: <div>file contents</div>,
70
+ },
71
+ ]}
72
+ />,
73
+ );
74
+ expect(
75
+ screen.getByRole('button', {name: /Running.*readFile/}),
76
+ ).toBeInTheDocument();
77
+ });
78
+
79
+ it('includes the latest status in a collapsed group accessible name', () => {
80
+ render(
81
+ <ChatToolCalls
82
+ calls={[
83
+ {name: 'searchCode', status: 'complete'},
84
+ {name: 'editFile', status: 'running'},
85
+ ]}
86
+ />,
87
+ );
88
+ expect(
89
+ screen.getByRole('button', {name: /Running.*editFile/}),
90
+ ).toBeInTheDocument();
91
+ });
92
+
49
93
  it('defaults to collapsed', () => {
50
94
  render(
51
95
  <ChatToolCalls
@@ -365,6 +365,26 @@ const STATUS_STYLES: Record<
365
365
  error: styles.colorError,
366
366
  };
367
367
 
368
+ function getStatusAnnouncement(
369
+ t: ReturnType<typeof useTranslator>,
370
+ status: ChatToolCallStatus,
371
+ errorMessage?: string,
372
+ ): string {
373
+ if (status === 'error' && errorMessage != null) {
374
+ return t('@astryx.chatToolCalls.error', {message: errorMessage});
375
+ }
376
+ switch (status) {
377
+ case 'pending':
378
+ return t('@astryx.chatToolCalls.status.pending');
379
+ case 'running':
380
+ return t('@astryx.chatToolCalls.status.running');
381
+ case 'complete':
382
+ return t('@astryx.chatToolCalls.status.complete');
383
+ case 'error':
384
+ return t('@astryx.chatToolCalls.status.error');
385
+ }
386
+ }
387
+
368
388
  function getToolCallKey(call: ChatToolCallItem): string {
369
389
  return getKey(call.key, () =>
370
390
  [
@@ -390,6 +410,11 @@ function CallRow({call}: {call: ChatToolCallItem}) {
390
410
  const hasDetail = call.resultDetail != null;
391
411
  const [isDetailOpen, setIsDetailOpen] = useState(false);
392
412
  const detailId = useId();
413
+ const statusAnnouncement = getStatusAnnouncement(
414
+ t,
415
+ status,
416
+ call.errorMessage,
417
+ );
393
418
 
394
419
  const toggleDetail = hasDetail
395
420
  ? () => setIsDetailOpen(prev => !prev)
@@ -417,9 +442,9 @@ function CallRow({call}: {call: ChatToolCallItem}) {
417
442
  title={status === 'error' ? call.errorMessage : undefined}
418
443
  {...stylex.props(styles.statusIcon, STATUS_STYLES[status])}>
419
444
  {status === 'running' ? (
420
- <Spinner size="sm" shade="subtle" />
445
+ <Spinner size="sm" shade="subtle" aria-hidden="true" />
421
446
  ) : status === 'pending' ? (
422
- <Spinner size="sm" shade="subtle" />
447
+ <Spinner size="sm" shade="subtle" aria-hidden="true" />
423
448
  ) : (
424
449
  <>
425
450
  <span {...stylex.props(styles.statusIconCircle)} />
@@ -432,17 +457,7 @@ function CallRow({call}: {call: ChatToolCallItem}) {
432
457
  </span>
433
458
  </>
434
459
  )}
435
- {status === 'error' && call.errorMessage != null && (
436
- // The title attribute above is hover-only; expose the error detail
437
- // as real text so it reaches screen readers, keyboard, and touch
438
- // users. Rendering it inside the row also folds it into the
439
- // accessible name of expandable (role="button") rows.
440
- <VisuallyHidden>
441
- {t('@astryx.chatToolCalls.error', {
442
- message: call.errorMessage ?? '',
443
- })}
444
- </VisuallyHidden>
445
- )}
460
+ <VisuallyHidden>{statusAnnouncement}</VisuallyHidden>
446
461
  </span>
447
462
  <span {...stylex.props(styles.callName)}>{call.name}</span>
448
463
  {call.node != null && (
@@ -581,6 +596,11 @@ export function ChatToolCalls(props: ChatToolCallsProps) {
581
596
  // Multiple calls: latest call at surface with chevron to expand all
582
597
  const latestCall = calls[calls.length - 1];
583
598
  const latestStatus = latestCall.status ?? 'complete';
599
+ const latestStatusAnnouncement = getStatusAnnouncement(
600
+ t,
601
+ latestStatus,
602
+ latestCall.errorMessage,
603
+ );
584
604
 
585
605
  return (
586
606
  <div
@@ -620,9 +640,9 @@ export function ChatToolCalls(props: ChatToolCallsProps) {
620
640
  <span
621
641
  {...stylex.props(styles.statusIcon, STATUS_STYLES[latestStatus])}>
622
642
  {latestStatus === 'running' ? (
623
- <Spinner size="sm" shade="subtle" />
643
+ <Spinner size="sm" shade="subtle" aria-hidden="true" />
624
644
  ) : latestStatus === 'pending' ? (
625
- <Spinner size="sm" shade="subtle" />
645
+ <Spinner size="sm" shade="subtle" aria-hidden="true" />
626
646
  ) : (
627
647
  <>
628
648
  <span {...stylex.props(styles.statusIconCircle)} />
@@ -635,6 +655,7 @@ export function ChatToolCalls(props: ChatToolCallsProps) {
635
655
  </span>
636
656
  </>
637
657
  )}
658
+ <VisuallyHidden>{latestStatusAnnouncement}</VisuallyHidden>
638
659
  </span>
639
660
  <span {...stylex.props(styles.callName)}>{latestCall.name}</span>
640
661
  {latestCall.target != null && (
@@ -1,5 +1,64 @@
1
1
  // Copyright (c) Meta Platforms, Inc. and affiliates.
2
2
 
3
+ /** @type {import('@astryxdesign/cli/authoring').ComponentAnatomyElement[]} */
4
+ const anatomy = [
5
+ {
6
+ name: 'Group',
7
+ required: true,
8
+ description: 'Container for the labeled checkbox group.',
9
+ },
10
+ {
11
+ name: 'Group label',
12
+ required: true,
13
+ description: 'Text identifying what the checkbox options represent.',
14
+ },
15
+ {
16
+ name: 'Description',
17
+ required: false,
18
+ description: 'Helper text below the group label.',
19
+ },
20
+ {
21
+ name: 'Options list',
22
+ required: true,
23
+ description: 'List containing the available checkbox options.',
24
+ },
25
+ {
26
+ name: 'Option row',
27
+ required: true,
28
+ description: 'Selectable row containing one option.',
29
+ },
30
+ {
31
+ name: 'Checkbox',
32
+ required: true,
33
+ description: 'Selection indicator for an option.',
34
+ },
35
+ {
36
+ name: 'Option label',
37
+ required: true,
38
+ description: 'Primary content identifying an option.',
39
+ },
40
+ {
41
+ name: 'Option description',
42
+ required: false,
43
+ description: 'Secondary text below an option label.',
44
+ },
45
+ {
46
+ name: 'End content',
47
+ required: false,
48
+ description: 'Caller-provided content at the end of an option row.',
49
+ },
50
+ {
51
+ name: 'Spinner',
52
+ required: false,
53
+ description: 'Loading indicator shown inside the pending checkbox.',
54
+ },
55
+ {
56
+ name: 'Status message',
57
+ required: false,
58
+ description: 'Error, warning, or success message below the group.',
59
+ },
60
+ ];
61
+
3
62
  /** @type {import('@astryxdesign/cli/authoring').ComponentDoc} */
4
63
 
5
64
  export const docs = {
@@ -8,13 +67,22 @@ export const docs = {
8
67
  group: 'Checkbox',
9
68
  category: 'Form Controls',
10
69
  isHiddenFromOverview: true,
11
- keywords: ["checkboxlist","checkbox","checkboxgroup","multichoice","multiselect","checklist"],
12
- description: 'Checkbox group container with field integration for label, description, and status.',
70
+ keywords: [
71
+ 'checkboxlist',
72
+ 'checkbox',
73
+ 'checkboxgroup',
74
+ 'multichoice',
75
+ 'multiselect',
76
+ 'checklist',
77
+ ],
78
+ description:
79
+ 'Checkbox group container with field integration for label, description, and status.',
13
80
  props: [
14
81
  {
15
82
  name: 'label',
16
83
  type: 'string',
17
- description: 'Label text for the checkbox group (always rendered for accessibility).',
84
+ description:
85
+ 'Label text for the checkbox group (always rendered for accessibility).',
18
86
  required: true,
19
87
  },
20
88
  {
@@ -97,41 +165,89 @@ export const docs = {
97
165
  {
98
166
  name: 'xstyle',
99
167
  type: 'StyleXStyles',
100
- description: 'StyleX styles for layout customization. Must be a stylex.create() value.',
168
+ description:
169
+ 'StyleX styles for layout customization. Must be a stylex.create() value.',
101
170
  },
102
171
  ],
103
- components: [
104
- {name: 'CheckboxListItem'},
105
- ],
172
+ components: [{name: 'CheckboxListItem'}],
106
173
  usage: {
107
- description: 'CheckboxList shows a small group of checkboxes so users can turn several options on or off at once. Place it in settings pages, filter panels, or forms where every choice should be visible without scrolling. For a single standalone checkbox (like "I agree to the terms"), use CheckboxInput instead. If only one option can be picked, use RadioList. If the list is long enough to need searching or scrolling, use MultiSelector instead.',
174
+ anatomy,
175
+ description:
176
+ 'CheckboxList shows a small group of checkboxes so users can turn several options on or off at once. Place it in settings pages, filter panels, or forms where every choice should be visible without scrolling. For a single standalone checkbox (like "I agree to the terms"), use CheckboxInput instead. If only one option can be picked, use RadioList. If the list is long enough to need searching or scrolling, use MultiSelector instead.',
108
177
  bestPractices: [
109
- { guidance: true, description: 'Keep the list short: three to seven options is the sweet spot. Beyond that, switch to MultiSelector which adds search and scrolling.' },
110
- { guidance: true, description: 'Turn on dividers (hasDividers) when items have helper text underneath; without them the labels and descriptions blur together.' },
111
- { guidance: true, description: 'Write a group label that says what the choices represent: "Export formats" tells users more than "Options".' },
112
- { guidance: false, description: 'Show a CheckboxList when the user can only pick one thing; that is what RadioList is for.' },
113
- { guidance: false, description: 'Put buttons or links inside the trailing slot (endContent); the whole row is already tappable, so a nested button creates two competing click targets.' },
114
- { guidance: false, description: 'Wrap a disabled CheckboxList in Tooltip to explain why it is disabled; disabled controls swallow the hover events the wrapper needs. Use the disabledMessage prop instead.' },
178
+ {
179
+ guidance: true,
180
+ description:
181
+ 'Keep the list short: three to seven options is the sweet spot. Beyond that, switch to MultiSelector which adds search and scrolling.',
182
+ },
183
+ {
184
+ guidance: true,
185
+ description:
186
+ 'Turn on dividers (hasDividers) when items have helper text underneath; without them the labels and descriptions blur together.',
187
+ },
188
+ {
189
+ guidance: true,
190
+ description:
191
+ 'Write a group label that says what the choices represent: "Export formats" tells users more than "Options".',
192
+ },
193
+ {
194
+ guidance: false,
195
+ description:
196
+ 'Show a CheckboxList when the user can only pick one thing; that is what RadioList is for.',
197
+ },
198
+ {
199
+ guidance: false,
200
+ description:
201
+ 'Put buttons or links inside the trailing slot (endContent); the whole row is already tappable, so a nested button creates two competing click targets.',
202
+ },
203
+ {
204
+ guidance: false,
205
+ description:
206
+ 'Wrap a disabled CheckboxList in Tooltip to explain why it is disabled; disabled controls swallow the hover events the wrapper needs. Use the disabledMessage prop instead.',
207
+ },
115
208
  ],
116
209
  },
117
210
  theming: {
118
- targets: [
119
- {className: 'astryx-checkbox-list'},
120
- ],
211
+ targets: [{className: 'astryx-checkbox-list'}],
121
212
  },
122
213
  };
123
214
 
124
215
  /** @type {import('@astryxdesign/cli/authoring').ComponentTranslationDoc} */
125
216
  export const docsZh = {
126
217
  usage: {
127
- description: 'CheckboxList shows a small group of checkboxes so users can turn several options on or off at once. Place it in settings pages, filter panels, or forms where every choice should be visible without scrolling. For a single standalone checkbox (like "I agree to the terms"), use CheckboxInput instead. If only one option can be picked, use RadioList. If the list is long enough to need searching or scrolling, use MultiSelector instead.',
218
+ description:
219
+ 'CheckboxList shows a small group of checkboxes so users can turn several options on or off at once. Place it in settings pages, filter panels, or forms where every choice should be visible without scrolling. For a single standalone checkbox (like "I agree to the terms"), use CheckboxInput instead. If only one option can be picked, use RadioList. If the list is long enough to need searching or scrolling, use MultiSelector instead.',
128
220
  bestPractices: [
129
- { guidance: true, description: 'Keep the list short: three to seven options is the sweet spot. Beyond that, switch to MultiSelector which adds search and scrolling.' },
130
- { guidance: true, description: 'Turn on dividers (hasDividers) when items have helper text underneath; without them the labels and descriptions blur together.' },
131
- { guidance: true, description: 'Write a group label that says what the choices represent: "Export formats" tells users more than "Options".' },
132
- { guidance: false, description: 'Show a CheckboxList when the user can only pick one thing; that is what RadioList is for.' },
133
- { guidance: false, description: 'Put buttons or links inside the trailing slot (endContent); the whole row is already tappable, so a nested button creates two competing click targets.' },
134
- { guidance: false, description: 'Wrap a disabled CheckboxList in Tooltip to explain why it is disabled; disabled controls swallow the hover events the wrapper needs. Use the disabledMessage prop instead.' },
221
+ {
222
+ guidance: true,
223
+ description:
224
+ 'Keep the list short: three to seven options is the sweet spot. Beyond that, switch to MultiSelector which adds search and scrolling.',
225
+ },
226
+ {
227
+ guidance: true,
228
+ description:
229
+ 'Turn on dividers (hasDividers) when items have helper text underneath; without them the labels and descriptions blur together.',
230
+ },
231
+ {
232
+ guidance: true,
233
+ description:
234
+ 'Write a group label that says what the choices represent: "Export formats" tells users more than "Options".',
235
+ },
236
+ {
237
+ guidance: false,
238
+ description:
239
+ 'Show a CheckboxList when the user can only pick one thing; that is what RadioList is for.',
240
+ },
241
+ {
242
+ guidance: false,
243
+ description:
244
+ 'Put buttons or links inside the trailing slot (endContent); the whole row is already tappable, so a nested button creates two competing click targets.',
245
+ },
246
+ {
247
+ guidance: false,
248
+ description:
249
+ 'Wrap a disabled CheckboxList in Tooltip to explain why it is disabled; disabled controls swallow the hover events the wrapper needs. Use the disabledMessage prop instead.',
250
+ },
135
251
  ],
136
252
  },
137
253
  };
@@ -141,14 +257,39 @@ export const docsDense = {
141
257
  description:
142
258
  'Checkbox group component for multi-value selection. Collection mode (parent state) + standalone mode (per-item state).',
143
259
  usage: {
144
- description: 'CheckboxList shows a small group of checkboxes so users can turn several options on or off at once. Place it in settings pages, filter panels, or forms where every choice should be visible without scrolling. For a single standalone checkbox (like "I agree to the terms"), use CheckboxInput instead. If only one option can be picked, use RadioList. If the list is long enough to need searching or scrolling, use MultiSelector instead.',
260
+ description:
261
+ 'CheckboxList shows a small group of checkboxes so users can turn several options on or off at once. Place it in settings pages, filter panels, or forms where every choice should be visible without scrolling. For a single standalone checkbox (like "I agree to the terms"), use CheckboxInput instead. If only one option can be picked, use RadioList. If the list is long enough to need searching or scrolling, use MultiSelector instead.',
145
262
  bestPractices: [
146
- { guidance: true, description: 'Keep the list short: three to seven options is the sweet spot. Beyond that, switch to MultiSelector which adds search and scrolling.' },
147
- { guidance: true, description: 'Turn on dividers (hasDividers) when items have helper text underneath; without them the labels and descriptions blur together.' },
148
- { guidance: true, description: 'Write a group label that says what the choices represent: "Export formats" tells users more than "Options".' },
149
- { guidance: false, description: 'Show a CheckboxList when the user can only pick one thing; that is what RadioList is for.' },
150
- { guidance: false, description: 'Put buttons or links inside the trailing slot (endContent); the whole row is already tappable, so a nested button creates two competing click targets.' },
151
- { guidance: false, description: 'Wrap a disabled CheckboxList in Tooltip to explain why it is disabled; disabled controls swallow the hover events the wrapper needs. Use the disabledMessage prop instead.' },
263
+ {
264
+ guidance: true,
265
+ description:
266
+ 'Keep the list short: three to seven options is the sweet spot. Beyond that, switch to MultiSelector which adds search and scrolling.',
267
+ },
268
+ {
269
+ guidance: true,
270
+ description:
271
+ 'Turn on dividers (hasDividers) when items have helper text underneath; without them the labels and descriptions blur together.',
272
+ },
273
+ {
274
+ guidance: true,
275
+ description:
276
+ 'Write a group label that says what the choices represent: "Export formats" tells users more than "Options".',
277
+ },
278
+ {
279
+ guidance: false,
280
+ description:
281
+ 'Show a CheckboxList when the user can only pick one thing; that is what RadioList is for.',
282
+ },
283
+ {
284
+ guidance: false,
285
+ description:
286
+ 'Put buttons or links inside the trailing slot (endContent); the whole row is already tappable, so a nested button creates two competing click targets.',
287
+ },
288
+ {
289
+ guidance: false,
290
+ description:
291
+ 'Wrap a disabled CheckboxList in Tooltip to explain why it is disabled; disabled controls swallow the hover events the wrapper needs. Use the disabledMessage prop instead.',
292
+ },
152
293
  ],
153
294
  },
154
295
  };