@astryxdesign/core 0.5.1 → 0.5.2-canary.00477a5

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 (270) hide show
  1. package/CHANGELOG.md +19 -0
  2. package/dist/BottomSheet/BottomSheet.d.ts +3 -1
  3. package/dist/BottomSheet/BottomSheet.d.ts.map +1 -1
  4. package/dist/BottomSheet/BottomSheet.js +4 -3
  5. package/dist/BottomSheet/BottomSheetEdgeTint.d.ts +2 -2
  6. package/dist/BottomSheet/BottomSheetEdgeTint.d.ts.map +1 -1
  7. package/dist/BottomSheet/BottomSheetEdgeTint.js +7 -10
  8. package/dist/BottomSheet/BottomSheetSwitcher.d.ts.map +1 -1
  9. package/dist/BottomSheet/BottomSheetSwitcher.js +1 -1
  10. package/dist/Button/Button.d.ts +2 -1
  11. package/dist/Button/Button.d.ts.map +1 -1
  12. package/dist/Button/Button.js +11 -4
  13. package/dist/Carousel/Carousel.d.ts.map +1 -1
  14. package/dist/Carousel/Carousel.js +2 -2
  15. package/dist/Chat/ChatToolCalls.d.ts.map +1 -1
  16. package/dist/Chat/ChatToolCalls.js +34 -17
  17. package/dist/ContextMenu/ContextMenu.d.ts +14 -3
  18. package/dist/ContextMenu/ContextMenu.d.ts.map +1 -1
  19. package/dist/ContextMenu/ContextMenu.js +149 -26
  20. package/dist/ContextMenu/index.d.ts +1 -0
  21. package/dist/ContextMenu/index.d.ts.map +1 -1
  22. package/dist/DropdownMenu/DropdownMenu.d.ts +24 -5
  23. package/dist/DropdownMenu/DropdownMenu.d.ts.map +1 -1
  24. package/dist/DropdownMenu/DropdownMenu.js +340 -26
  25. package/dist/DropdownMenu/DropdownMenuContext.d.ts +1 -1
  26. package/dist/DropdownMenu/DropdownMenuContext.d.ts.map +1 -1
  27. package/dist/DropdownMenu/DropdownMenuItem.d.ts.map +1 -1
  28. package/dist/DropdownMenu/DropdownMenuItem.js +1 -1
  29. package/dist/DropdownMenu/DropdownMenuSubMenu.d.ts +6 -2
  30. package/dist/DropdownMenu/DropdownMenuSubMenu.d.ts.map +1 -1
  31. package/dist/DropdownMenu/DropdownMenuSubMenu.js +43 -14
  32. package/dist/DropdownMenu/MenuBottomSheet.d.ts +20 -0
  33. package/dist/DropdownMenu/MenuBottomSheet.d.ts.map +1 -0
  34. package/dist/DropdownMenu/MenuBottomSheet.js +36 -0
  35. package/dist/DropdownMenu/MenuBottomSheetActionList.d.ts +10 -0
  36. package/dist/DropdownMenu/MenuBottomSheetActionList.d.ts.map +1 -0
  37. package/dist/DropdownMenu/MenuBottomSheetActionList.js +111 -0
  38. package/dist/DropdownMenu/index.d.ts +2 -1
  39. package/dist/DropdownMenu/index.d.ts.map +1 -1
  40. package/dist/DropdownMenu/menuWidth.d.ts +14 -0
  41. package/dist/DropdownMenu/menuWidth.d.ts.map +1 -0
  42. package/dist/DropdownMenu/menuWidth.js +35 -0
  43. package/dist/DropdownMenu/useMenuOverflow.d.ts +10 -0
  44. package/dist/DropdownMenu/useMenuOverflow.d.ts.map +1 -0
  45. package/dist/DropdownMenu/useMenuOverflow.js +60 -0
  46. package/dist/MoreMenu/MoreMenu.d.ts +8 -2
  47. package/dist/MoreMenu/MoreMenu.d.ts.map +1 -1
  48. package/dist/MoreMenu/MoreMenu.js +2 -0
  49. package/dist/MultiSelector/MultiSelector.d.ts +11 -1
  50. package/dist/MultiSelector/MultiSelector.d.ts.map +1 -1
  51. package/dist/MultiSelector/MultiSelector.js +97 -68
  52. package/dist/MultiSelector/index.d.ts +1 -1
  53. package/dist/MultiSelector/index.d.ts.map +1 -1
  54. package/dist/Popover/Popover.d.ts +10 -6
  55. package/dist/Popover/Popover.d.ts.map +1 -1
  56. package/dist/Popover/Popover.js +141 -16
  57. package/dist/Popover/usePopover.d.ts +4 -0
  58. package/dist/Popover/usePopover.d.ts.map +1 -1
  59. package/dist/Popover/usePopover.js +52 -5
  60. package/dist/Selector/Selector.d.ts +10 -0
  61. package/dist/Selector/Selector.d.ts.map +1 -1
  62. package/dist/Selector/Selector.js +106 -80
  63. package/dist/Selector/SelectorBottomSheet.d.ts +21 -0
  64. package/dist/Selector/SelectorBottomSheet.d.ts.map +1 -0
  65. package/dist/Selector/SelectorBottomSheet.js +83 -0
  66. package/dist/Selector/index.d.ts +1 -1
  67. package/dist/Selector/index.d.ts.map +1 -1
  68. package/dist/Selector/selectorPresentation.stylex.d.ts +16 -0
  69. package/dist/Selector/selectorPresentation.stylex.d.ts.map +1 -0
  70. package/dist/Selector/selectorPresentation.stylex.js +21 -0
  71. package/dist/Selector/useSelectorPresentation.d.ts +32 -0
  72. package/dist/Selector/useSelectorPresentation.d.ts.map +1 -0
  73. package/dist/Selector/useSelectorPresentation.js +90 -0
  74. package/dist/Toast/useToastGesture.d.ts.map +1 -1
  75. package/dist/Toast/useToastGesture.js +46 -9
  76. package/dist/astryx.css +19 -1
  77. package/dist/hooks/useAdaptivePresentation.d.ts +5 -0
  78. package/dist/hooks/useAdaptivePresentation.d.ts.map +1 -0
  79. package/dist/hooks/useAdaptivePresentation.js +19 -0
  80. package/dist/hooks/useFocusReturnVisibility.d.ts +7 -0
  81. package/dist/hooks/useFocusReturnVisibility.d.ts.map +1 -0
  82. package/dist/hooks/useFocusReturnVisibility.js +35 -0
  83. package/dist/hooks/useFocusTrap.d.ts.map +1 -1
  84. package/dist/hooks/useFocusTrap.js +12 -0
  85. package/dist/i18n/InternationalizationContext.d.ts +2 -0
  86. package/dist/i18n/InternationalizationContext.d.ts.map +1 -1
  87. package/dist/i18n/InternationalizationContext.js +3 -1
  88. package/dist/i18n/InternationalizationProvider.d.ts.map +1 -1
  89. package/dist/i18n/InternationalizationProvider.js +3 -1
  90. package/dist/i18n/resolve.d.ts +1 -1
  91. package/dist/i18n/resolve.d.ts.map +1 -1
  92. package/dist/i18n/resolve.js +37 -38
  93. package/dist/i18n/useTranslator.d.ts.map +1 -1
  94. package/dist/i18n/useTranslator.js +2 -3
  95. package/locales/af-ZA.json +0 -4
  96. package/locales/ar-SA.json +0 -4
  97. package/locales/ca-ES.json +0 -4
  98. package/locales/cs-CZ.json +0 -4
  99. package/locales/da-DK.json +0 -4
  100. package/locales/de-DE.json +0 -4
  101. package/locales/el-GR.json +0 -4
  102. package/locales/en.json +20 -0
  103. package/locales/es-ES.json +0 -4
  104. package/locales/fi-FI.json +0 -4
  105. package/locales/fr-FR.json +0 -4
  106. package/locales/he-IL.json +0 -4
  107. package/locales/hu-HU.json +0 -4
  108. package/locales/it-IT.json +0 -4
  109. package/locales/ja-JP.json +0 -4
  110. package/locales/ko-KR.json +0 -4
  111. package/locales/nl-NL.json +0 -4
  112. package/locales/no-NO.json +0 -4
  113. package/locales/pl-PL.json +0 -4
  114. package/locales/pseudo.json +15 -0
  115. package/locales/pt-BR.json +0 -4
  116. package/locales/pt-PT.json +0 -4
  117. package/locales/ro-RO.json +0 -4
  118. package/locales/ru-RU.json +0 -4
  119. package/locales/sr-SP.json +0 -4
  120. package/locales/sv-SE.json +0 -4
  121. package/locales/tr-TR.json +0 -4
  122. package/locales/uk-UA.json +0 -4
  123. package/locales/vi-VN.json +0 -4
  124. package/locales/zh-CN.json +0 -4
  125. package/locales/zh-TW.json +0 -4
  126. package/package.json +3 -3
  127. package/src/BottomSheet/BottomSheet.doc.mjs +37 -0
  128. package/src/BottomSheet/BottomSheet.spec.md +177 -0
  129. package/src/BottomSheet/BottomSheet.test.tsx +29 -0
  130. package/src/BottomSheet/BottomSheet.tsx +7 -4
  131. package/src/BottomSheet/BottomSheetEdgeTint.test.tsx +4 -6
  132. package/src/BottomSheet/BottomSheetEdgeTint.tsx +7 -10
  133. package/src/BottomSheet/BottomSheetSwitcher.tsx +1 -2
  134. package/src/Button/Button.doc.mjs +56 -0
  135. package/src/Button/Button.test.tsx +10 -0
  136. package/src/Button/Button.tsx +13 -5
  137. package/src/ButtonGroup/ButtonGroup.doc.mjs +47 -0
  138. package/src/Calendar/Calendar.doc.mjs +1 -1
  139. package/src/Carousel/Carousel.test.tsx +83 -0
  140. package/src/Carousel/Carousel.tsx +8 -2
  141. package/src/Chat/ChatToolCalls.test.tsx +44 -0
  142. package/src/Chat/ChatToolCalls.tsx +36 -15
  143. package/src/CheckboxInput/CheckboxInput.doc.mjs +1 -1
  144. package/src/CheckboxList/CheckboxList.doc.mjs +173 -32
  145. package/src/CheckboxList/CheckboxList.spec.md +214 -0
  146. package/src/CommandPalette/CommandPalette.doc.mjs +72 -0
  147. package/src/CommandPalette/CommandPalette.spec.md +223 -0
  148. package/src/ComplexSelector/ComplexSelector.doc.mjs +44 -2
  149. package/src/ComplexSelector/ComplexSelector.spec.md +189 -0
  150. package/src/ContextMenu/ContextMenu.doc.mjs +13 -1
  151. package/src/ContextMenu/ContextMenu.test.tsx +131 -1
  152. package/src/ContextMenu/ContextMenu.tsx +199 -32
  153. package/src/ContextMenu/index.ts +1 -0
  154. package/src/DateInput/DateInput.doc.mjs +1 -1
  155. package/src/DateRangeInput/DateRangeInput.doc.mjs +1 -1
  156. package/src/DateTimeInput/DateTimeInput.doc.mjs +1 -1
  157. package/src/Divider/Divider.doc.mjs +24 -0
  158. package/src/Divider/Divider.spec.md +150 -0
  159. package/src/DropdownMenu/DropdownMenu.doc.mjs +201 -40
  160. package/src/DropdownMenu/DropdownMenu.test.tsx +518 -7
  161. package/src/DropdownMenu/DropdownMenu.tsx +459 -28
  162. package/src/DropdownMenu/DropdownMenuContext.tsx +1 -1
  163. package/src/DropdownMenu/DropdownMenuItem.tsx +2 -0
  164. package/src/DropdownMenu/DropdownMenuSubMenu.doc.mjs +4 -2
  165. package/src/DropdownMenu/DropdownMenuSubMenu.test.tsx +124 -0
  166. package/src/DropdownMenu/DropdownMenuSubMenu.tsx +72 -17
  167. package/src/DropdownMenu/MenuBottomSheet.tsx +46 -0
  168. package/src/DropdownMenu/MenuBottomSheetActionList.tsx +141 -0
  169. package/src/DropdownMenu/index.ts +2 -0
  170. package/src/DropdownMenu/menuWidth.ts +51 -0
  171. package/src/DropdownMenu/useMenuOverflow.ts +77 -0
  172. package/src/Field/Field.doc.mjs +1 -1
  173. package/src/FieldStatus/FieldStatus.doc.mjs +22 -1
  174. package/src/FieldStatus/FieldStatus.spec.md +212 -0
  175. package/src/FileInput/FileInput.doc.mjs +1 -1
  176. package/src/Grid/Grid.doc.mjs +19 -0
  177. package/src/Grid/Grid.spec.md +161 -0
  178. package/src/Icon/Icon.doc.mjs +196 -48
  179. package/src/Icon/Icon.spec.md +191 -0
  180. package/src/IconButton/IconButton.doc.mjs +38 -0
  181. package/src/Indicator/Indicator.doc.mjs +1 -1
  182. package/src/InputGroup/InputGroup.doc.mjs +1 -1
  183. package/src/Kbd/Kbd.doc.mjs +18 -0
  184. package/src/Kbd/Kbd.spec.md +141 -0
  185. package/src/Layout/Layout.doc.mjs +32 -0
  186. package/src/Layout/Layout.spec.md +199 -0
  187. package/src/Lightbox/Lightbox.doc.mjs +149 -33
  188. package/src/Lightbox/Lightbox.spec.md +197 -0
  189. package/src/Markdown/Markdown.doc.mjs +60 -0
  190. package/src/Markdown/Markdown.spec.md +200 -0
  191. package/src/MobileNav/MobileNav.doc.mjs +140 -32
  192. package/src/MobileNav/MobileNav.spec.md +208 -0
  193. package/src/MoreMenu/MoreMenu.doc.mjs +17 -0
  194. package/src/MoreMenu/MoreMenu.test.tsx +47 -0
  195. package/src/MoreMenu/MoreMenu.tsx +13 -1
  196. package/src/MultiSelector/MultiSelector.doc.mjs +129 -1
  197. package/src/MultiSelector/MultiSelector.spec.md +266 -0
  198. package/src/MultiSelector/MultiSelector.test.tsx +127 -0
  199. package/src/MultiSelector/MultiSelector.tsx +121 -73
  200. package/src/MultiSelector/index.ts +1 -0
  201. package/src/NavIcon/NavIcon.doc.mjs +17 -0
  202. package/src/NavIcon/NavIcon.spec.md +133 -0
  203. package/src/NavMenu/NavHeadingMenu.spec.md +205 -0
  204. package/src/NavMenu/NavMenu.doc.mjs +37 -0
  205. package/src/NumberInput/NumberInput.doc.mjs +1 -1
  206. package/src/Outline/Outline.doc.mjs +35 -0
  207. package/src/Outline/Outline.spec.md +161 -0
  208. package/src/OverflowList/OverflowList.doc.mjs +24 -0
  209. package/src/OverflowList/OverflowList.spec.md +156 -0
  210. package/src/Pagination/Pagination.doc.mjs +74 -0
  211. package/src/Pagination/Pagination.spec.md +225 -0
  212. package/src/Popover/Popover.doc.mjs +11 -11
  213. package/src/Popover/Popover.test.tsx +397 -2
  214. package/src/Popover/Popover.tsx +228 -21
  215. package/src/Popover/usePopover.tsx +92 -15
  216. package/src/PowerSearch/PowerSearch.doc.mjs +1 -1
  217. package/src/ProgressBar/ProgressBar.doc.mjs +198 -38
  218. package/src/ProgressBar/ProgressBar.spec.md +260 -0
  219. package/src/RadioList/RadioList.doc.mjs +1 -1
  220. package/src/Resizable/Resizable.doc.mjs +59 -16
  221. package/src/Resizable/Resizable.spec.md +194 -0
  222. package/src/Section/Section.doc.mjs +17 -0
  223. package/src/Section/Section.spec.md +138 -0
  224. package/src/SegmentedControl/SegmentedControl.doc.mjs +83 -0
  225. package/src/SegmentedControl/SegmentedControl.spec.md +151 -0
  226. package/src/Selector/Selector.doc.mjs +13 -1
  227. package/src/Selector/Selector.test.tsx +135 -0
  228. package/src/Selector/Selector.tsx +141 -82
  229. package/src/Selector/SelectorBottomSheet.tsx +97 -0
  230. package/src/Selector/index.ts +1 -0
  231. package/src/Selector/selectorPresentation.stylex.ts +20 -0
  232. package/src/Selector/useSelectorPresentation.ts +147 -0
  233. package/src/Skeleton/Skeleton.doc.mjs +12 -0
  234. package/src/Skeleton/Skeleton.spec.md +126 -0
  235. package/src/Slider/Slider.doc.mjs +186 -32
  236. package/src/Slider/Slider.spec.md +223 -0
  237. package/src/Stack/Stack.doc.mjs +22 -0
  238. package/src/Stack/Stack.spec.md +154 -0
  239. package/src/StatusDot/StatusDot.doc.mjs +17 -0
  240. package/src/StatusDot/StatusDot.spec.md +137 -0
  241. package/src/Switch/Switch.doc.mjs +41 -1
  242. package/src/Switch/Switch.spec.md +174 -0
  243. package/src/Text/Text.doc.mjs +190 -43
  244. package/src/Text/Text.spec.md +205 -0
  245. package/src/TextArea/TextArea.doc.mjs +256 -46
  246. package/src/TextArea/TextArea.spec.md +204 -0
  247. package/src/TextInput/TextInput.doc.mjs +1 -1
  248. package/src/TimeInput/TimeInput.doc.mjs +1 -1
  249. package/src/Toast/ToastViewport.test.tsx +118 -4
  250. package/src/Toast/useToastGesture.ts +61 -8
  251. package/src/ToggleButton/ToggleButton.doc.mjs +56 -0
  252. package/src/Tokenizer/Tokenizer.doc.mjs +1 -1
  253. package/src/Toolbar/Toolbar.doc.mjs +19 -0
  254. package/src/Toolbar/Toolbar.spec.md +173 -0
  255. package/src/Tooltip/Tooltip.doc.mjs +17 -0
  256. package/src/Tooltip/Tooltip.spec.md +141 -0
  257. package/src/TreeList/TreeList.doc.mjs +58 -0
  258. package/src/TreeList/TreeList.spec.md +220 -0
  259. package/src/Typeahead/Typeahead.doc.mjs +84 -2
  260. package/src/Typeahead/Typeahead.spec.md +250 -0
  261. package/src/hooks/useAdaptivePresentation.ts +35 -0
  262. package/src/hooks/useFocusReturnVisibility.ts +45 -0
  263. package/src/hooks/useFocusTrap.test.tsx +40 -0
  264. package/src/hooks/useFocusTrap.ts +13 -0
  265. package/src/i18n/InternationalizationContext.ts +3 -0
  266. package/src/i18n/InternationalizationProvider.tsx +8 -1
  267. package/src/i18n/__tests__/resolve.test.ts +23 -1
  268. package/src/i18n/resolve.ts +46 -49
  269. package/src/i18n/useTranslator.ts +2 -7
  270. package/src/theme/themingTargets.test.ts +91 -25
@@ -1,12 +1,29 @@
1
1
  // Copyright (c) Meta Platforms, Inc. and affiliates.
2
2
 
3
+ /** @type {import('@astryxdesign/cli/authoring').ComponentAnatomyElement[]} */
4
+ const anatomy = [
5
+ {
6
+ name: 'Glyph',
7
+ required: true,
8
+ description: 'Visual symbol rendered for the selected icon.',
9
+ },
10
+ ];
11
+
3
12
  /** @type {import('@astryxdesign/cli/authoring').ComponentDoc} */
4
13
 
5
14
  export const docs = {
6
15
  name: 'Icon',
7
16
  displayName: 'Icon',
8
17
  category: 'Content',
9
- keywords: ["icon","svg","glyph","symbol","pictogram","graphic","vector"],
18
+ keywords: [
19
+ 'icon',
20
+ 'svg',
21
+ 'glyph',
22
+ 'symbol',
23
+ 'pictogram',
24
+ 'graphic',
25
+ 'vector',
26
+ ],
10
27
  playground: {
11
28
  // `icon` is required and its type can't be auto-generated, so the
12
29
  // properties-tab preview showed "Missing: icon". Seed a valid semantic
@@ -19,7 +36,8 @@ export const docs = {
19
36
  {
20
37
  name: 'icon',
21
38
  type: 'IconName | ComponentType<SVGProps>',
22
- description: 'Semantic icon name or SVG component. Valid semantic names: close, chevronDown, chevronLeft, chevronRight, chevronsLeft, chevronsRight, check, success, error, warning, info, calendar, clock, externalLink, menu, moreHorizontal, search, arrowUp, arrowDown, arrowsUpDown, funnel, eyeSlash, viewColumns, copy, checkDouble, wrench, stop, microphone. For any icon not in this list, pass an SVG component directly (e.g. import from lucide-react or @heroicons/react). Note: this prop is called `icon`, not `name`.',
39
+ description:
40
+ 'Semantic icon name or SVG component. Valid semantic names: close, chevronDown, chevronLeft, chevronRight, chevronsLeft, chevronsRight, check, success, error, warning, info, calendar, clock, externalLink, menu, moreHorizontal, search, arrowUp, arrowDown, arrowsUpDown, funnel, eyeSlash, viewColumns, copy, checkDouble, wrench, stop, microphone. For any icon not in this list, pass an SVG component directly (e.g. import from lucide-react or @heroicons/react). Note: this prop is called `icon`, not `name`.',
23
41
  required: true,
24
42
  },
25
43
  {
@@ -37,34 +55,79 @@ export const docs = {
37
55
  {
38
56
  name: 'label',
39
57
  type: 'string',
40
- description: 'Accessible name for a MEANINGFUL, standalone icon (a status glyph or icon-only indicator with no adjacent text). Setting it exposes the icon to screen readers as role="img" with this text as the accessible name (aria-label) and removes the default aria-hidden. Omit it (default) for decorative icons and the icon stays hidden from assistive tech (aria-hidden="true"). This is the accessible-name / alt-text prop for icons: one prop instead of manually setting aria-label + role + aria-hidden. An empty string is treated as decorative. Do not set it when an interactive parent (Button, IconButton, link) already names the control.',
58
+ description:
59
+ 'Accessible name for a MEANINGFUL, standalone icon (a status glyph or icon-only indicator with no adjacent text). Setting it exposes the icon to screen readers as role="img" with this text as the accessible name (aria-label) and removes the default aria-hidden. Omit it (default) for decorative icons and the icon stays hidden from assistive tech (aria-hidden="true"). This is the accessible-name / alt-text prop for icons: one prop instead of manually setting aria-label + role + aria-hidden. An empty string is treated as decorative. Do not set it when an interactive parent (Button, IconButton, link) already names the control.',
41
60
  },
42
61
  {
43
62
  name: 'xstyle',
44
63
  type: 'StyleXStyles',
45
64
  description:
46
- 'StyleX styles for customization (color, size, opacity). Folded into the icon\'s own stylex.props() call so it composes with the base color/size styles. Must be a stylex.create() value, not an inline style object like style={{}}.',
65
+ "StyleX styles for customization (color, size, opacity). Folded into the icon's own stylex.props() call so it composes with the base color/size styles. Must be a stylex.create() value, not an inline style object like style={{}}.",
47
66
  },
48
67
  ],
49
68
  theming: {
50
- targets: [
51
- {className: 'astryx-icon', visualProps: ['color', 'size']},
52
- ],
69
+ targets: [{className: 'astryx-icon', visualProps: ['color', 'size']}],
53
70
  },
54
71
  usage: {
55
- description: 'Icons are small visual symbols that represent actions, objects, or concepts. They improve scannability and reinforce meaning alongside text. Supports both direct SVG components and semantic icon names that adapt to the active theme.',
72
+ description:
73
+ 'Icons are small visual symbols that represent actions, objects, or concepts. They improve scannability and reinforce meaning alongside text. Supports both direct SVG components and semantic icon names that adapt to the active theme.',
74
+ anatomy,
56
75
  bestPractices: [
57
- { guidance: true, description: 'Use semantic icon names when available; they adapt to theme changes automatically.' },
58
- { guidance: true, description: "Override icons through the theme, not globally: defineTheme({icons: {close: <XMarkIcon />}}) scopes the swap to the active <Theme>, and extends shallow-merges it into derived themes. registerIcons() mutates a process-wide registry and warns in dev, so keep it for app bootstrap rather than making it a library's theming seam." },
59
- { guidance: true, description: 'Pair icons with text labels for accessibility; icon-only elements need an accessible label.' },
60
- { guidance: true, description: 'For a meaningful standalone icon (no adjacent text), give it an accessible name via the `label` prop: it sets role="img" + aria-label and unhides the icon.' },
61
- { guidance: true, description: 'Use color tokens for icon colors, not hardcoded hex values.' },
62
- { guidance: true, description: 'Be mindful of context; decorative icons in compact components can distract rather than help.' },
63
- { guidance: false, description: 'Use icons as the sole means of conveying meaning; always provide a text alternative.' },
64
- { guidance: false, description: 'Resize icons with arbitrary pixel values; use the provided size props.' },
65
- { guidance: false, description: 'Mix icon styles (e.g. outline and filled) within the same context.' },
66
- { guidance: false, description: 'Render raw SVG elements; always wrap in Icon for consistent sizing and color.' },
67
- { guidance: false, description: 'Pass a `name` prop; Icon uses `icon` (not `name`) to specify which icon to render.' },
76
+ {
77
+ guidance: true,
78
+ description:
79
+ 'Use semantic icon names when available; they adapt to theme changes automatically.',
80
+ },
81
+ {
82
+ guidance: true,
83
+ description:
84
+ "Override icons through the theme, not globally: defineTheme({icons: {close: <XMarkIcon />}}) scopes the swap to the active <Theme>, and extends shallow-merges it into derived themes. registerIcons() mutates a process-wide registry and warns in dev, so keep it for app bootstrap rather than making it a library's theming seam.",
85
+ },
86
+ {
87
+ guidance: true,
88
+ description:
89
+ 'Pair icons with text labels for accessibility; icon-only elements need an accessible label.',
90
+ },
91
+ {
92
+ guidance: true,
93
+ description:
94
+ 'For a meaningful standalone icon (no adjacent text), give it an accessible name via the `label` prop: it sets role="img" + aria-label and unhides the icon.',
95
+ },
96
+ {
97
+ guidance: true,
98
+ description:
99
+ 'Use color tokens for icon colors, not hardcoded hex values.',
100
+ },
101
+ {
102
+ guidance: true,
103
+ description:
104
+ 'Be mindful of context; decorative icons in compact components can distract rather than help.',
105
+ },
106
+ {
107
+ guidance: false,
108
+ description:
109
+ 'Use icons as the sole means of conveying meaning; always provide a text alternative.',
110
+ },
111
+ {
112
+ guidance: false,
113
+ description:
114
+ 'Resize icons with arbitrary pixel values; use the provided size props.',
115
+ },
116
+ {
117
+ guidance: false,
118
+ description:
119
+ 'Mix icon styles (e.g. outline and filled) within the same context.',
120
+ },
121
+ {
122
+ guidance: false,
123
+ description:
124
+ 'Render raw SVG elements; always wrap in Icon for consistent sizing and color.',
125
+ },
126
+ {
127
+ guidance: false,
128
+ description:
129
+ 'Pass a `name` prop; Icon uses `icon` (not `name`) to specify which icon to render.',
130
+ },
68
131
  ],
69
132
  },
70
133
  };
@@ -77,7 +140,8 @@ export const docsZh = {
77
140
  {
78
141
  name: 'icon',
79
142
  type: 'IconName | ComponentType<SVGProps>',
80
- description: '语义图标名称或 SVG 组件。有效语义名称:close, chevronDown, chevronLeft, chevronRight, chevronsLeft, chevronsRight, check, success, error, warning, info, calendar, clock, externalLink, menu, moreHorizontal, search, arrowUp, arrowDown, arrowsUpDown, funnel, eyeSlash, viewColumns, copy, checkDouble, wrench, stop, microphone。列表之外的图标请直接传入 SVG 组件。',
143
+ description:
144
+ '语义图标名称或 SVG 组件。有效语义名称:close, chevronDown, chevronLeft, chevronRight, chevronsLeft, chevronsRight, check, success, error, warning, info, calendar, clock, externalLink, menu, moreHorizontal, search, arrowUp, arrowDown, arrowsUpDown, funnel, eyeSlash, viewColumns, copy, checkDouble, wrench, stop, microphone。列表之外的图标请直接传入 SVG 组件。',
81
145
  required: true,
82
146
  },
83
147
  {
@@ -95,7 +159,8 @@ export const docsZh = {
95
159
  {
96
160
  name: 'label',
97
161
  type: 'string',
98
- description: '有含义的独立图标的可访问名称(无相邻文字的状态图标或纯图标指示器)。设置后会将图标以 role="img" 暴露给辅助技术,并以该文本作为可访问名称(aria-label),同时移除默认的 aria-hidden。省略(默认)用于装饰性图标,图标对辅助技术保持隐藏(aria-hidden="true")。空字符串按装饰性处理。当交互式父元素(Button、IconButton、链接)已命名该控件时请勿设置。',
162
+ description:
163
+ '有含义的独立图标的可访问名称(无相邻文字的状态图标或纯图标指示器)。设置后会将图标以 role="img" 暴露给辅助技术,并以该文本作为可访问名称(aria-label),同时移除默认的 aria-hidden。省略(默认)用于装饰性图标,图标对辅助技术保持隐藏(aria-hidden="true")。空字符串按装饰性处理。当交互式父元素(Button、IconButton、链接)已命名该控件时请勿设置。',
99
164
  },
100
165
  {
101
166
  name: 'xstyle',
@@ -105,22 +170,57 @@ export const docsZh = {
105
170
  },
106
171
  ],
107
172
  theming: {
108
- targets: [
109
- {className: 'astryx-icon', visualProps: ['color', 'size']},
110
- ],
173
+ targets: [{className: 'astryx-icon', visualProps: ['color', 'size']}],
111
174
  },
112
175
  usage: {
113
- description: 'Icons are small visual symbols that represent actions, objects, or concepts. They improve scannability and reinforce meaning alongside text. Supports both direct SVG components and semantic icon names that adapt to the active theme.',
176
+ description:
177
+ 'Icons are small visual symbols that represent actions, objects, or concepts. They improve scannability and reinforce meaning alongside text. Supports both direct SVG components and semantic icon names that adapt to the active theme.',
114
178
  bestPractices: [
115
- { guidance: true, description: 'Use semantic icon names when available; they adapt to theme changes automatically.' },
116
- { guidance: true, description: 'Pair icons with text labels for accessibility; icon-only elements need an accessible label.' },
117
- { guidance: true, description: 'Use color tokens for icon colors, not hardcoded hex values.' },
118
- { guidance: true, description: 'Be mindful of context; decorative icons in compact components can distract rather than help.' },
119
- { guidance: false, description: 'Use icons as the sole means of conveying meaning; always provide a text alternative.' },
120
- { guidance: false, description: 'Resize icons with arbitrary pixel values; use the provided size props.' },
121
- { guidance: false, description: 'Mix icon styles (e.g. outline and filled) within the same context.' },
122
- { guidance: false, description: 'Render raw SVG elements; always wrap in Icon for consistent sizing and color.' },
123
- { guidance: false, description: 'Pass a `name` prop; Icon uses `icon` (not `name`) to specify which icon to render.' },
179
+ {
180
+ guidance: true,
181
+ description:
182
+ 'Use semantic icon names when available; they adapt to theme changes automatically.',
183
+ },
184
+ {
185
+ guidance: true,
186
+ description:
187
+ 'Pair icons with text labels for accessibility; icon-only elements need an accessible label.',
188
+ },
189
+ {
190
+ guidance: true,
191
+ description:
192
+ 'Use color tokens for icon colors, not hardcoded hex values.',
193
+ },
194
+ {
195
+ guidance: true,
196
+ description:
197
+ 'Be mindful of context; decorative icons in compact components can distract rather than help.',
198
+ },
199
+ {
200
+ guidance: false,
201
+ description:
202
+ 'Use icons as the sole means of conveying meaning; always provide a text alternative.',
203
+ },
204
+ {
205
+ guidance: false,
206
+ description:
207
+ 'Resize icons with arbitrary pixel values; use the provided size props.',
208
+ },
209
+ {
210
+ guidance: false,
211
+ description:
212
+ 'Mix icon styles (e.g. outline and filled) within the same context.',
213
+ },
214
+ {
215
+ guidance: false,
216
+ description:
217
+ 'Render raw SVG elements; always wrap in Icon for consistent sizing and color.',
218
+ },
219
+ {
220
+ guidance: false,
221
+ description:
222
+ 'Pass a `name` prop; Icon uses `icon` (not `name`) to specify which icon to render.',
223
+ },
124
224
  ],
125
225
  },
126
226
  };
@@ -130,26 +230,74 @@ export const docsDense = {
130
230
  description:
131
231
  'Renders icons w/ Astryx design system colors + sizes. Supports direct SVG icon components + semantic icon names that adapt to active theme.',
132
232
  usage: {
133
- description: 'Icons are small visual symbols that represent actions, objects, or concepts. They improve scannability and reinforce meaning alongside text. Supports both direct SVG components and semantic icon names that adapt to the active theme.',
233
+ description:
234
+ 'Icons are small visual symbols that represent actions, objects, or concepts. They improve scannability and reinforce meaning alongside text. Supports both direct SVG components and semantic icon names that adapt to the active theme.',
235
+ anatomy,
134
236
  bestPractices: [
135
- { guidance: true, description: 'Use semantic icon names when available; they adapt to theme changes automatically.' },
136
- { guidance: true, description: "Override icons via theme, not globally: defineTheme({icons: {close: <XMarkIcon />}}) scopes the swap to the active <Theme>; extends shallow-merges into derived themes. registerIcons() mutates a global registry and warns in dev: app bootstrap only, not a library theming seam." },
137
- { guidance: true, description: 'Pair icons with text labels for accessibility; icon-only elements need an accessible label.' },
138
- { guidance: true, description: 'For a meaningful standalone icon (no adjacent text), set an accessible name via `label`: sets role="img" + aria-label, unhides icon.' },
139
- { guidance: true, description: 'Use color tokens for icon colors, not hardcoded hex values.' },
140
- { guidance: true, description: 'Be mindful of context; decorative icons in compact components can distract rather than help.' },
141
- { guidance: false, description: 'Use icons as the sole means of conveying meaning; always provide a text alternative.' },
142
- { guidance: false, description: 'Resize icons with arbitrary pixel values; use the provided size props.' },
143
- { guidance: false, description: 'Mix icon styles (e.g. outline and filled) within the same context.' },
144
- { guidance: false, description: 'Render raw SVG elements; always wrap in Icon for consistent sizing and color.' },
145
- { guidance: false, description: '`name` prop, which does not exist. Use `icon` to specify which icon to render.' },
237
+ {
238
+ guidance: true,
239
+ description:
240
+ 'Use semantic icon names when available; they adapt to theme changes automatically.',
241
+ },
242
+ {
243
+ guidance: true,
244
+ description:
245
+ 'Override icons via theme, not globally: defineTheme({icons: {close: <XMarkIcon />}}) scopes the swap to the active <Theme>; extends shallow-merges into derived themes. registerIcons() mutates a global registry and warns in dev: app bootstrap only, not a library theming seam.',
246
+ },
247
+ {
248
+ guidance: true,
249
+ description:
250
+ 'Pair icons with text labels for accessibility; icon-only elements need an accessible label.',
251
+ },
252
+ {
253
+ guidance: true,
254
+ description:
255
+ 'For a meaningful standalone icon (no adjacent text), set an accessible name via `label`: sets role="img" + aria-label, unhides icon.',
256
+ },
257
+ {
258
+ guidance: true,
259
+ description:
260
+ 'Use color tokens for icon colors, not hardcoded hex values.',
261
+ },
262
+ {
263
+ guidance: true,
264
+ description:
265
+ 'Be mindful of context; decorative icons in compact components can distract rather than help.',
266
+ },
267
+ {
268
+ guidance: false,
269
+ description:
270
+ 'Use icons as the sole means of conveying meaning; always provide a text alternative.',
271
+ },
272
+ {
273
+ guidance: false,
274
+ description:
275
+ 'Resize icons with arbitrary pixel values; use the provided size props.',
276
+ },
277
+ {
278
+ guidance: false,
279
+ description:
280
+ 'Mix icon styles (e.g. outline and filled) within the same context.',
281
+ },
282
+ {
283
+ guidance: false,
284
+ description:
285
+ 'Render raw SVG elements; always wrap in Icon for consistent sizing and color.',
286
+ },
287
+ {
288
+ guidance: false,
289
+ description:
290
+ '`name` prop, which does not exist. Use `icon` to specify which icon to render.',
291
+ },
146
292
  ],
147
293
  },
148
294
  propDescriptions: {
149
295
  icon: 'Semantic icon name or SVG component. Valid names: close, chevronDown, chevronLeft, chevronRight, chevronsLeft, chevronsRight, check, success, error, warning, info, calendar, clock, externalLink, menu, moreHorizontal, search, arrowUp, arrowDown, arrowsUpDown, funnel, eyeSlash, viewColumns, copy, checkDouble, wrench, stop, microphone. For others, pass an SVG component.',
150
296
  color: 'Color variant mapped to Astryx icon color tokens.',
151
297
  size: 'Icon size.',
152
- label: 'Accessible name for a meaningful, standalone icon. Sets role="img" + aria-label and drops the default aria-hidden. Omit (default) for decorative icons (stays aria-hidden). Empty string = decorative. The accessible-name/alt-text prop for icons.',
153
- xstyle: 'StyleX styles (color, size, opacity) via stylex.create(); composes with the base color/size styles.',
298
+ label:
299
+ 'Accessible name for a meaningful, standalone icon. Sets role="img" + aria-label and drops the default aria-hidden. Omit (default) for decorative icons (stays aria-hidden). Empty string = decorative. The accessible-name/alt-text prop for icons.',
300
+ xstyle:
301
+ 'StyleX styles (color, size, opacity) via stylex.create(); composes with the base color/size styles.',
154
302
  },
155
303
  };
@@ -0,0 +1,191 @@
1
+ ---
2
+ schema_version: 1
3
+ template_version: 3
4
+ kind: component
5
+ id: component:Icon
6
+ authority: current
7
+ archive_reason: null
8
+ superseded_by: null
9
+ approved_by: cixzhang
10
+ approved_at: 2026-08-30
11
+ owners: [cixzhang, imdreamrunner]
12
+ review_triggers: [public-api, behavior, theming, accessibility]
13
+ verified_by: [packages/core/src/Icon/Icon.test.tsx, scripts/check-knowledge.mjs]
14
+ families: []
15
+ design_specs: []
16
+ architecture:
17
+ [
18
+ architecture:component-theming-surface,
19
+ architecture:icon-resolution-and-component-slots,
20
+ architecture:public-component-api,
21
+ ]
22
+ contributing: []
23
+ system_specs: []
24
+ ---
25
+
26
+ # Icon component contract
27
+
28
+ ## Intent
29
+
30
+ Icon presents one visual symbol with consistent size, color, and accessibility
31
+ semantics. Consumer usage remains documented in `Icon.doc.mjs`.
32
+
33
+ ## Compatibility and migration
34
+
35
+ - Released default preserved: `yes`
36
+ - Compatibility class: additive documentation only; runtime, DOM, styling, and
37
+ public API remain unchanged
38
+ - Controlled/uncontrolled behavior: not applicable
39
+ - Migration decision: none; this record characterizes the released component
40
+
41
+ Consumer migration instructions belong in consumer docs and release notes.
42
+
43
+ ## Ownership boundary
44
+
45
+ **Owns**
46
+
47
+ - Accepting a semantic icon key or a supplied icon component as the glyph source.
48
+ - Applying Icon's size, color, theming target, and accessibility semantics to
49
+ the rendered glyph.
50
+
51
+ **Does not own / non-goals**
52
+
53
+ - The shared registry's key-resolution and fallback order — owned by the shared
54
+ icon system.
55
+ - The meaning of a glyph in product context or whether nearby text makes it
56
+ decorative — owned by the product callsite.
57
+ - Interaction, focus, or control naming — owned by the interactive parent.
58
+ - The artwork supplied by a consumer or registered through a theme.
59
+
60
+ ## Public concepts
61
+
62
+ | Concept | Closed values or states | Meaning | Availability by variant/orientation/state | Default | Owner | Stability | Invalid-value behavior |
63
+ | ------------- | --------------------------------------------------------- | --------------------------------------------------------- | ----------------------------------------- | ---------- | ---------------- | --------- | ------------------------------------------------------ |
64
+ | Glyph source | semantic key, namespaced extension key, or icon component | Selects the visual symbol. | Every render | Required | `component:Icon` | Stable | TypeScript rejects unsupported built-in string values. |
65
+ | Size | `xsm`, `sm`, `md`, `lg` | Selects the icon box size. | Every rendered glyph | `md` | `component:Icon` | Stable | TypeScript rejects unsupported values. |
66
+ | Color | documented semantic and palette values | Selects the glyph color or inherits it from context. | Every rendered glyph | `inherit` | `component:Icon` | Stable | TypeScript rejects unsupported values. |
67
+ | Accessibility | decorative or meaningfully labelled | Controls whether assistive technology receives the glyph. | Every rendered glyph | Decorative | `component:Icon` | Stable | Empty labels use the decorative behavior. |
68
+
69
+ A namespaced key that does not resolve currently renders nothing. This is
70
+ existing behavior, not an intentional fallback promise.
71
+
72
+ ## Behavioral and layout contract
73
+
74
+ Requirements identify their basis so observed code is not mistaken for an
75
+ intentional decision.
76
+
77
+ | ID | Candidate invariant | Basis | Draft review state |
78
+ | --- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------ | ------------------------------------------------------- |
79
+ | FR1 | Icon MUST present at most one glyph from the supplied semantic key, namespaced key, or icon component. | Documented promise and current tests. | Settled intent. |
80
+ | FR2 | Every rendered glyph MUST carry the `icon` theming target with its selected size and color reflected as target data. | Current source, docs, and theming tests. | Settled intent. |
81
+ | FR3 | Icon MUST apply the selected size as width and height for every glyph, plus font size where needed for 1em-based icon sources. This sizing contract MUST NOT promise an HTML or SVG element type. | Human decision, current source, and tests. | Settled intent. |
82
+ | FR4 | Supported SVG and styling escape hatches MUST retain their established merge and override behavior. | Current source and regression tests. | Current compatibility behavior; verify before changing. |
83
+
84
+ ### Allowed variation
85
+
86
+ - **AV1 — Artwork.** The path, view box, and internal structure may vary by icon
87
+ source or theme without changing Icon's one-part consumer anatomy.
88
+ - **AV2 — Rendering strategy.** Icon may render a supplied component directly or
89
+ use an internal wrapper for a resolved key; neither element shape is public
90
+ anatomy.
91
+ - **AV3 — Theme and consumer styling.** Existing theme and styling escape hatches
92
+ may change visual CSS properties without changing glyph ownership.
93
+
94
+ ### Representative states
95
+
96
+ | State | Required invariant | Allowed variation |
97
+ | ------------------------- | ----------------------------------------------------- | ---------------------------------------------- |
98
+ | Semantic key | One resolved glyph carries the `icon` target. | Theme, registry, or built-in artwork. |
99
+ | Namespaced extension key | A resolved extension glyph carries the `icon` target. | Consumer- or library-owned artwork. |
100
+ | Supplied icon component | The supplied glyph carries the `icon` target. | Component implementation and SVG internals. |
101
+ | Unresolved namespaced key | No glyph is currently rendered. | No fallback behavior is established by intent. |
102
+
103
+ ### Transformation and precedence order
104
+
105
+ - **ORD1 — Presentation.** Apply the target, component size and color styles,
106
+ then merge consumer `xstyle`, `className`, inline `style`, and supported
107
+ pass-through props in their established order.
108
+
109
+ ### Performance and resources
110
+
111
+ - **PR1 — Render work.** Icon owns no listeners, observers, or layout
112
+ measurement; semantic resolution is synchronous during render.
113
+
114
+ ## Accessibility contract
115
+
116
+ - **AR1 — Decorative default.** Without a non-empty `label`, Icon MUST hide its
117
+ glyph from assistive technology by default.
118
+ - **AR2 — Meaningful glyph.** A non-empty `label` MUST expose the glyph as an
119
+ image with that accessible name.
120
+ - **AR3 — Parent-owned interaction.** Icon MUST NOT add interactive semantics or
121
+ focus behavior; an interactive parent owns the control and its name.
122
+
123
+ ## Design relationships
124
+
125
+ | Anatomy or state | Design requirement | Representation authority | Hierarchy role | Component contract |
126
+ | ---------------- | ------------------------------------------------------------------- | ------------------------------------------------------------- | ----------------- | ------------------ |
127
+ | Glyph | Carries the selected visual symbol at the requested size and color. | Consumer or registry selects artwork; Icon owns presentation. | Context-dependent | FR1, FR2, FR3 |
128
+
129
+ `Glyph` is the single conceptual consumer part in both source modes. Current
130
+ implementation may render a supplied icon component directly or place a
131
+ registry-resolved icon in an internal wrapper; this contract intentionally does
132
+ not promise a `span`, `svg`, or other element type.
133
+
134
+ ### Theming anatomy
135
+
136
+ <!-- anatomy-theming:v1 -->
137
+
138
+ ```json
139
+ {
140
+ "Glyph": {"target": "icon"}
141
+ }
142
+ ```
143
+
144
+ ## Family and system relationships
145
+
146
+ - `architecture:component-theming-surface` owns the qualification and validation
147
+ rules for the `icon` target.
148
+ - `architecture:icon-resolution-and-component-slots` owns semantic-key and
149
+ component-slot resolution before Icon renders the selected source.
150
+ - `architecture:public-component-api` owns admission and compatibility rules for
151
+ Icon's public props.
152
+ - Icon has no current family contract.
153
+
154
+ ## Verification map
155
+
156
+ | Contract | Verification | Representative states | Mutation or failure expectation | Audit section |
157
+ | ------------------- | ------------------------------------------------------------ | --------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------- | -------------------------- |
158
+ | FR1, FR3 | `Icon.test.tsx` source-mode and sizing suites | Built-in, themed, namespaced, component | Breaking source rendering or cross-mode sizing fails assertions. | `audit:Icon/behavior` |
159
+ | FR2, FR4 | `Icon.test.tsx` target/styling suites plus source inspection | Both source modes; size and color variants | Removing the target or breaking override composition fails existing assertions; `data-size` and `data-color` reflection currently lack focused assertions. | `audit:Icon/theming` |
160
+ | AR1, AR2, AR3 | `Icon.test.tsx` accessible-name suites | Decorative, labelled, explicit ARIA override | Changing default or labelled semantics fails accessibility assertions. | `audit:Icon/accessibility` |
161
+ | Theming anatomy map | `scripts/check-knowledge.mjs` | Canonical consumer anatomy and current target | Missing, extra, prefixed, or stale mappings fail repository validation. | `audit:Icon/theming` |
162
+
163
+ Focused coverage for `data-size` and `data-color` on both glyph source modes is
164
+ a checkable test gap; source inspection is the current evidence for that part of
165
+ FR2.
166
+
167
+ ## Decision log
168
+
169
+ ### DEC-1 — One conceptual Glyph across source modes
170
+
171
+ **Reference:** `component:Icon/DEC-1`
172
+ **Decider:** cixzhang, 2026-08-30
173
+
174
+ Consumers theme and reason about one visual symbol regardless of whether it
175
+ comes from a semantic key or a supplied component. `Glyph` therefore maps to the
176
+ existing `icon` target without freezing either mode's current element shape.
177
+ Icon applies width and height for every source and adds font size where a 1em-
178
+ based source needs it. This preserves one consistent icon box without promising
179
+ a `span`, `svg`, or other element.
180
+
181
+ Rejected: separate wrapper and SVG anatomy entries, because those describe
182
+ implementation strategies rather than stable consumer concepts.
183
+
184
+ ## Open questions
185
+
186
+ None.
187
+
188
+ ## Content boundary
189
+
190
+ This file does not duplicate consumer prop tables/examples, current audit
191
+ results, implementation steps, or system rules. It links to their owners.
@@ -74,6 +74,44 @@ export const docs = {
74
74
 
75
75
  usage: {
76
76
  description: 'A button that shows only an icon with no visible text. Use IconButton in toolbars, table rows, and compact UI where space is tight and the icon is universally understood.',
77
+ accessibility: [
78
+ {
79
+ name: 'Essential icon or spinner arc',
80
+ category: 'Color contrast',
81
+ criterion: '1.4.11 Non-text Contrast',
82
+ requirement: '3:1',
83
+ states: ['Rest', 'Hover', 'Pointer down', 'Loading'],
84
+ description:
85
+ 'IconButton has no visible label. Its icon must have at least 3:1 contrast with the button background in Rest, Hover, and Pointer down. The moving spinner arc must also meet 3:1 while loading.',
86
+ },
87
+ {
88
+ name: 'Visible control boundary',
89
+ category: 'Color contrast',
90
+ criterion: '1.4.11 Non-text Contrast',
91
+ requirement: '3:1 if needed',
92
+ states: ['Rest'],
93
+ description:
94
+ 'The button edge needs 3:1 contrast only when users need it to see the control.',
95
+ },
96
+ {
97
+ name: 'Keyboard focus indicator',
98
+ category: 'Color contrast',
99
+ criterion: '1.4.11 Non-text Contrast',
100
+ requirement: '3:1',
101
+ states: ['Focus visible'],
102
+ description:
103
+ 'The focus outline must have at least 3:1 contrast with the area around the button. Check the red outline on destructive buttons too.',
104
+ },
105
+ {
106
+ name: 'Disabled appearance',
107
+ category: 'Color contrast',
108
+ criterion: '1.4.3 and 1.4.11 exceptions',
109
+ requirement: 'Not required',
110
+ states: ['Disabled'],
111
+ description:
112
+ 'Disabled controls do not need to meet these contrast ratios.',
113
+ },
114
+ ],
77
115
  bestPractices: [
78
116
  { guidance: true, description: 'Make the aria-label specific: a trash icon labeled "Delete conversation" is clearer than just "Delete" for screen readers.' },
79
117
  { guidance: true, description: 'Add a tooltip: even a gear icon can mean Settings, Preferences, or Configure.' },
@@ -6,7 +6,7 @@ export const docs = {
6
6
  name: 'Indicator',
7
7
  displayName: 'Indicator',
8
8
  group: 'Indicator',
9
- category: 'Data Input',
9
+ category: 'Form Controls',
10
10
  isHiddenFromOverview: true,
11
11
  keywords: [
12
12
  'indicator',
@@ -6,7 +6,7 @@ export const docs = {
6
6
  name: 'InputGroup',
7
7
  displayName: 'Input Group',
8
8
  group: 'Field',
9
- category: 'Data Input',
9
+ category: 'Form Controls',
10
10
  isHiddenFromOverview: true,
11
11
  keywords: [
12
12
  'inputgroup',
@@ -1,5 +1,20 @@
1
1
  // Copyright (c) Meta Platforms, Inc. and affiliates.
2
2
 
3
+ /** @type {import('@astryxdesign/cli/authoring').ComponentAnatomyElement[]} */
4
+ const anatomy = [
5
+ {
6
+ name: 'Shortcut',
7
+ required: true,
8
+ description:
9
+ 'Group that presents the complete keyboard shortcut and its accessible name.',
10
+ },
11
+ {
12
+ name: 'Key badge',
13
+ required: true,
14
+ description: 'Painted key badge rendered once for each key in the shortcut.',
15
+ },
16
+ ];
17
+
3
18
  /** @type {import('@astryxdesign/cli/authoring').ComponentDoc} */
4
19
 
5
20
  export const docs = {
@@ -38,6 +53,7 @@ export const docs = {
38
53
  targets: [{className: 'astryx-kbd'}],
39
54
  },
40
55
  usage: {
56
+ anatomy,
41
57
  description: 'Renders a keyboard shortcut as styled key badges. Use Kbd in tooltips, menus, and help text to show key combinations.',
42
58
  bestPractices: [
43
59
  { guidance: true, description: 'Place shortcuts near the action they trigger: in a tooltip, menu item, or inline instruction.' },
@@ -82,6 +98,7 @@ export const docsZh = {
82
98
  targets: [{className: 'astryx-kbd'}],
83
99
  },
84
100
  usage: {
101
+ anatomy,
85
102
  description: 'Renders a keyboard shortcut as styled key badges. Use Kbd in tooltips, menus, and help text to show key combinations.',
86
103
  bestPractices: [
87
104
  { guidance: true, description: 'Place shortcuts near the action they trigger: in a tooltip, menu item, or inline instruction.' },
@@ -96,6 +113,7 @@ export const docsDense = {
96
113
  description:
97
114
  'Renders keyboard shortcut as styled key badges. Use in tooltips, menus + help text to show key combinations.',
98
115
  usage: {
116
+ anatomy,
99
117
  description: 'Renders a keyboard shortcut as styled key badges. Use Kbd in tooltips, menus, and help text to show key combinations.',
100
118
  bestPractices: [
101
119
  { guidance: true, description: 'Place shortcuts near the action they trigger: in a tooltip, menu item, or inline instruction.' },