@astryxdesign/core 0.6.2 → 0.6.3-canary.0899f21

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 (549) hide show
  1. package/CHANGELOG.md +81 -0
  2. package/dist/BottomSheet/BottomSheet.d.ts +1 -1
  3. package/dist/BottomSheet/BottomSheet.d.ts.map +1 -1
  4. package/dist/BottomSheet/BottomSheet.js +3 -1
  5. package/dist/BottomSheet/BottomSheetPanel.d.ts +7 -5
  6. package/dist/BottomSheet/BottomSheetPanel.d.ts.map +1 -1
  7. package/dist/BottomSheet/BottomSheetPanel.js +56 -19
  8. package/dist/Button/Button.d.ts.map +1 -1
  9. package/dist/Button/Button.js +13 -28
  10. package/dist/Chat/ChatComposer.d.ts.map +1 -1
  11. package/dist/Chat/ChatComposer.js +10 -5
  12. package/dist/Chat/ChatComposerDrawer.d.ts +19 -5
  13. package/dist/Chat/ChatComposerDrawer.d.ts.map +1 -1
  14. package/dist/Chat/ChatComposerDrawer.js +48 -23
  15. package/dist/Chat/ChatComposerInput.d.ts +11 -3
  16. package/dist/Chat/ChatComposerInput.d.ts.map +1 -1
  17. package/dist/Chat/ChatComposerInput.js +63 -16
  18. package/dist/Chat/ChatDictationButton.d.ts +3 -2
  19. package/dist/Chat/ChatDictationButton.d.ts.map +1 -1
  20. package/dist/Chat/ChatDictationButton.js +6 -4
  21. package/dist/Chat/ChatLayout.d.ts +19 -0
  22. package/dist/Chat/ChatLayout.d.ts.map +1 -1
  23. package/dist/Chat/ChatLayout.js +19 -0
  24. package/dist/Chat/ChatLayoutScrollButton.d.ts.map +1 -1
  25. package/dist/Chat/ChatLayoutScrollButton.js +44 -34
  26. package/dist/Chat/ChatMessageBubble.d.ts +2 -0
  27. package/dist/Chat/ChatMessageBubble.d.ts.map +1 -1
  28. package/dist/Chat/ChatMessageBubble.js +5 -3
  29. package/dist/Chat/ChatMessageList.d.ts +2 -1
  30. package/dist/Chat/ChatMessageList.d.ts.map +1 -1
  31. package/dist/Chat/ChatMessageList.js +4 -3
  32. package/dist/Chat/ChatMessageMetadata.d.ts +5 -4
  33. package/dist/Chat/ChatMessageMetadata.d.ts.map +1 -1
  34. package/dist/Chat/ChatMessageMetadata.js +12 -9
  35. package/dist/Chat/ChatSendButton.js +1 -1
  36. package/dist/Chat/index.d.ts +1 -1
  37. package/dist/Chat/index.d.ts.map +1 -1
  38. package/dist/CheckboxInput/CheckboxInput.d.ts.map +1 -1
  39. package/dist/CheckboxInput/CheckboxInput.js +12 -2
  40. package/dist/Citation/Citation.d.ts +1 -1
  41. package/dist/Citation/Citation.d.ts.map +1 -1
  42. package/dist/Citation/Citation.js +3 -2
  43. package/dist/CodeBlock/highlightRanges.d.ts.map +1 -1
  44. package/dist/CodeBlock/highlightRanges.js +14 -3
  45. package/dist/Collapsible/Collapsible.d.ts.map +1 -1
  46. package/dist/Collapsible/Collapsible.js +6 -1
  47. package/dist/CommandPalette/CommandPaletteInput.d.ts.map +1 -1
  48. package/dist/CommandPalette/CommandPaletteInput.js +1 -1
  49. package/dist/ComplexSelector/ComplexSelector.d.ts.map +1 -1
  50. package/dist/ComplexSelector/ComplexSelector.js +1 -1
  51. package/dist/DateInput/DateInput.d.ts.map +1 -1
  52. package/dist/DateInput/DateInput.js +4 -4
  53. package/dist/DateInput/NativeDateField.d.ts.map +1 -1
  54. package/dist/DateInput/NativeDateField.js +16 -16
  55. package/dist/DateInput/TouchDateField.d.ts.map +1 -1
  56. package/dist/DateInput/TouchDateField.js +2 -2
  57. package/dist/DateRangeInput/DateRangeInput.d.ts.map +1 -1
  58. package/dist/DateRangeInput/DateRangeInput.js +4 -4
  59. package/dist/DateTimeInput/DateTimeInput.d.ts.map +1 -1
  60. package/dist/DateTimeInput/DateTimeInput.js +8 -8
  61. package/dist/DateTimeInput/TouchDateTimeField.d.ts.map +1 -1
  62. package/dist/DateTimeInput/TouchDateTimeField.js +4 -4
  63. package/dist/DateTimeInput/nativePickerSegmentStyles.d.ts +9 -3
  64. package/dist/DateTimeInput/nativePickerSegmentStyles.d.ts.map +1 -1
  65. package/dist/DateTimeInput/nativePickerSegmentStyles.js +3 -3
  66. package/dist/Dialog/DialogHeader.d.ts +8 -1
  67. package/dist/Dialog/DialogHeader.d.ts.map +1 -1
  68. package/dist/Dialog/DialogHeader.js +13 -4
  69. package/dist/Field/InputClearButton.d.ts +4 -2
  70. package/dist/Field/InputClearButton.d.ts.map +1 -1
  71. package/dist/Field/InputClearButton.js +4 -2
  72. package/dist/Field/PanelSearchInput.d.ts.map +1 -1
  73. package/dist/Field/PanelSearchInput.js +1 -1
  74. package/dist/FileInput/FileInput.d.ts.map +1 -1
  75. package/dist/FileInput/FileInput.js +7 -7
  76. package/dist/Icon/Icon.d.ts +6 -31
  77. package/dist/Icon/Icon.d.ts.map +1 -1
  78. package/dist/Icon/Icon.js +8 -71
  79. package/dist/Icon/IconDefaultSizeContext.d.ts +4 -0
  80. package/dist/Icon/IconDefaultSizeContext.d.ts.map +1 -0
  81. package/dist/Icon/IconDefaultSizeContext.js +18 -0
  82. package/dist/Icon/IconSize.stylex.d.ts +65 -0
  83. package/dist/Icon/IconSize.stylex.d.ts.map +1 -0
  84. package/dist/Icon/IconSize.stylex.js +75 -0
  85. package/dist/Item/Item.d.ts +1 -1
  86. package/dist/Item/Item.d.ts.map +1 -1
  87. package/dist/Item/Item.js +4 -3
  88. package/dist/Kbd/Kbd.d.ts +5 -3
  89. package/dist/Kbd/Kbd.d.ts.map +1 -1
  90. package/dist/Kbd/Kbd.js +36 -42
  91. package/dist/Link/Link.d.ts.map +1 -1
  92. package/dist/Link/Link.js +6 -2
  93. package/dist/Link/useLinkComponent.d.ts +5 -15
  94. package/dist/Link/useLinkComponent.d.ts.map +1 -1
  95. package/dist/Link/useLinkComponent.js +34 -51
  96. package/dist/List/List.d.ts +19 -1
  97. package/dist/List/List.d.ts.map +1 -1
  98. package/dist/List/List.js +9 -2
  99. package/dist/List/ListContext.d.ts +1 -0
  100. package/dist/List/ListContext.d.ts.map +1 -1
  101. package/dist/List/ListContext.js +2 -1
  102. package/dist/List/ListItem.d.ts +1 -1
  103. package/dist/List/ListItem.d.ts.map +1 -1
  104. package/dist/List/ListItem.js +9 -2
  105. package/dist/Markdown/Markdown.d.ts +8 -2
  106. package/dist/Markdown/Markdown.d.ts.map +1 -1
  107. package/dist/Markdown/Markdown.fr23.bench.d.ts +2 -0
  108. package/dist/Markdown/Markdown.fr23.bench.d.ts.map +1 -0
  109. package/dist/Markdown/Markdown.fr23.bench.js +150 -0
  110. package/dist/Markdown/Markdown.fr23.sampling.d.ts +2 -0
  111. package/dist/Markdown/Markdown.fr23.sampling.d.ts.map +1 -0
  112. package/dist/Markdown/Markdown.fr23.sampling.js +43 -0
  113. package/dist/Markdown/Markdown.js +262 -109
  114. package/dist/Markdown/ast.d.ts +162 -0
  115. package/dist/Markdown/ast.d.ts.map +1 -0
  116. package/dist/Markdown/ast.js +74 -0
  117. package/dist/Markdown/index.d.ts +5 -3
  118. package/dist/Markdown/index.d.ts.map +1 -1
  119. package/dist/Markdown/index.js +3 -2
  120. package/dist/Markdown/parser/index.d.ts +10 -0
  121. package/dist/Markdown/parser/index.d.ts.map +1 -0
  122. package/dist/Markdown/parser/index.js +10 -0
  123. package/dist/Markdown/parser.d.ts +126 -58
  124. package/dist/Markdown/parser.d.ts.map +1 -1
  125. package/dist/Markdown/parser.js +716 -167
  126. package/dist/Markdown/plugins/frontmatter.d.ts +32 -0
  127. package/dist/Markdown/plugins/frontmatter.d.ts.map +1 -0
  128. package/dist/Markdown/plugins/frontmatter.js +132 -0
  129. package/dist/Markdown/plugins/index.d.ts +17 -0
  130. package/dist/Markdown/plugins/index.d.ts.map +1 -0
  131. package/dist/Markdown/plugins/index.js +14 -0
  132. package/dist/Markdown/plugins/protocol.d.ts +191 -0
  133. package/dist/Markdown/plugins/protocol.d.ts.map +1 -0
  134. package/dist/Markdown/plugins/protocol.js +957 -0
  135. package/dist/Markdown/plugins/semanticFence.d.ts +36 -0
  136. package/dist/Markdown/plugins/semanticFence.d.ts.map +1 -0
  137. package/dist/Markdown/plugins/semanticFence.js +213 -0
  138. package/dist/Markdown/plugins/softBreaks.d.ts +3 -0
  139. package/dist/Markdown/plugins/softBreaks.d.ts.map +1 -0
  140. package/dist/Markdown/plugins/softBreaks.js +172 -0
  141. package/dist/Markdown/plugins/sourceDecoration.d.ts +76 -0
  142. package/dist/Markdown/plugins/sourceDecoration.d.ts.map +1 -0
  143. package/dist/Markdown/plugins/sourceDecoration.js +393 -0
  144. package/dist/Markdown/plugins/textTransform.d.ts +30 -0
  145. package/dist/Markdown/plugins/textTransform.d.ts.map +1 -0
  146. package/dist/Markdown/plugins/textTransform.js +374 -0
  147. package/dist/Markdown/remark.d.ts +196 -0
  148. package/dist/Markdown/remark.d.ts.map +1 -0
  149. package/dist/Markdown/remark.js +1062 -0
  150. package/dist/Markdown/url.d.ts +6 -0
  151. package/dist/Markdown/url.d.ts.map +1 -0
  152. package/dist/Markdown/url.js +31 -0
  153. package/dist/Markdown/utils.d.ts +4 -2
  154. package/dist/Markdown/utils.d.ts.map +1 -1
  155. package/dist/Markdown/utils.js +2 -1
  156. package/dist/MetadataList/MetadataList.js +3 -3
  157. package/dist/NumberInput/NumberInput.d.ts.map +1 -1
  158. package/dist/NumberInput/NumberInput.js +4 -4
  159. package/dist/Outline/index.d.ts +1 -0
  160. package/dist/Outline/index.d.ts.map +1 -1
  161. package/dist/Outline/parseOutlineFromMarkdown.d.ts +7 -1
  162. package/dist/Outline/parseOutlineFromMarkdown.d.ts.map +1 -1
  163. package/dist/Outline/parseOutlineFromMarkdown.js +14 -8
  164. package/dist/Outline/useOutlineFromMarkdown.d.ts +3 -1
  165. package/dist/Outline/useOutlineFromMarkdown.d.ts.map +1 -1
  166. package/dist/Outline/useOutlineFromMarkdown.js +8 -3
  167. package/dist/PowerSearch/PowerSearchEditPopover.d.ts.map +1 -1
  168. package/dist/PowerSearch/PowerSearchEditPopover.js +46 -30
  169. package/dist/PowerSearch/PowerSearchValueEditor.d.ts.map +1 -1
  170. package/dist/PowerSearch/PowerSearchValueEditor.js +5 -0
  171. package/dist/ProgressBar/ProgressBar.d.ts.map +1 -1
  172. package/dist/ProgressBar/ProgressBar.js +36 -31
  173. package/dist/RadioList/RadioListItem.d.ts.map +1 -1
  174. package/dist/RadioList/RadioListItem.js +13 -1
  175. package/dist/ScrollableArea/ScrollableArea.d.ts +1 -0
  176. package/dist/ScrollableArea/ScrollableArea.d.ts.map +1 -1
  177. package/dist/ScrollableArea/ScrollableArea.js +1 -0
  178. package/dist/SegmentedControl/SegmentedControlItem.d.ts.map +1 -1
  179. package/dist/SegmentedControl/SegmentedControlItem.js +5 -5
  180. package/dist/Selector/Selector.d.ts +9 -7
  181. package/dist/Selector/Selector.d.ts.map +1 -1
  182. package/dist/Selector/Selector.js +16 -7
  183. package/dist/SideNav/SideNav.d.ts +2 -1
  184. package/dist/SideNav/SideNav.d.ts.map +1 -1
  185. package/dist/SideNav/SideNav.js +9 -3
  186. package/dist/Slider/Slider.d.ts.map +1 -1
  187. package/dist/Slider/Slider.js +28 -12
  188. package/dist/Spinner/Spinner.d.ts.map +1 -1
  189. package/dist/Spinner/Spinner.js +23 -7
  190. package/dist/Switch/Switch.d.ts.map +1 -1
  191. package/dist/Switch/Switch.js +11 -0
  192. package/dist/TabList/Tab.d.ts +1 -1
  193. package/dist/TabList/Tab.d.ts.map +1 -1
  194. package/dist/TabList/Tab.js +20 -7
  195. package/dist/Table/Table.d.ts +1 -0
  196. package/dist/Table/Table.d.ts.map +1 -1
  197. package/dist/Table/Table.js +29 -13
  198. package/dist/TextArea/TextArea.d.ts.map +1 -1
  199. package/dist/TextArea/TextArea.js +1 -1
  200. package/dist/TextInput/TextInput.d.ts.map +1 -1
  201. package/dist/TextInput/TextInput.js +2 -2
  202. package/dist/TimeInput/TimeInput.d.ts.map +1 -1
  203. package/dist/TimeInput/TimeInput.js +4 -4
  204. package/dist/Timer/Timer.d.ts +49 -0
  205. package/dist/Timer/Timer.d.ts.map +1 -0
  206. package/dist/Timer/Timer.js +158 -0
  207. package/dist/Timer/index.d.ts +9 -0
  208. package/dist/Timer/index.d.ts.map +1 -0
  209. package/dist/Timer/index.js +10 -0
  210. package/dist/ToggleButton/ToggleButton.d.ts +9 -6
  211. package/dist/ToggleButton/ToggleButton.d.ts.map +1 -1
  212. package/dist/ToggleButton/ToggleButton.js +15 -27
  213. package/dist/TopNav/TopNavMenu.d.ts +1 -1
  214. package/dist/TopNav/TopNavMenu.d.ts.map +1 -1
  215. package/dist/TopNav/TopNavMenu.js +3 -2
  216. package/dist/TreeList/TreeList.d.ts.map +1 -1
  217. package/dist/TreeList/TreeList.js +3 -0
  218. package/dist/TreeList/TreeListItem.d.ts +6 -1
  219. package/dist/TreeList/TreeListItem.d.ts.map +1 -1
  220. package/dist/TreeList/TreeListItem.js +12 -2
  221. package/dist/TreeList/TreeListTypes.d.ts +8 -1
  222. package/dist/TreeList/TreeListTypes.d.ts.map +1 -1
  223. package/dist/Typeahead/BaseTypeahead.d.ts.map +1 -1
  224. package/dist/Typeahead/BaseTypeahead.js +16 -7
  225. package/dist/astryx.css +27 -11
  226. package/dist/hooks/scrollKeyboardDelegation.d.ts +3 -0
  227. package/dist/hooks/scrollKeyboardDelegation.d.ts.map +1 -0
  228. package/dist/hooks/scrollKeyboardDelegation.js +146 -0
  229. package/dist/hooks/useClickableContainer.d.ts +10 -1
  230. package/dist/hooks/useClickableContainer.d.ts.map +1 -1
  231. package/dist/hooks/useClickableContainer.js +15 -4
  232. package/dist/hooks/useScrollableArea.d.ts +6 -2
  233. package/dist/hooks/useScrollableArea.d.ts.map +1 -1
  234. package/dist/hooks/useScrollableArea.js +17 -5
  235. package/dist/index.d.ts +1 -0
  236. package/dist/index.d.ts.map +1 -1
  237. package/dist/index.js +3 -0
  238. package/dist/theme/declarationBoundary.d.ts +17 -0
  239. package/dist/theme/declarationBoundary.d.ts.map +1 -0
  240. package/dist/theme/declarationBoundary.js +343 -0
  241. package/dist/theme/derivedVarRegistry.d.ts.map +1 -1
  242. package/dist/theme/derivedVarRegistry.js +4 -0
  243. package/dist/theme/generateThemeRules.d.ts +13 -7
  244. package/dist/theme/generateThemeRules.d.ts.map +1 -1
  245. package/dist/theme/generateThemeRules.js +140 -34
  246. package/dist/utils/interactionOverlay.stylex.d.ts +8 -0
  247. package/dist/utils/interactionOverlay.stylex.d.ts.map +1 -1
  248. package/dist/utils/interactionOverlay.stylex.js +9 -0
  249. package/dist/utils/safeUrl.d.ts +11 -0
  250. package/dist/utils/safeUrl.d.ts.map +1 -0
  251. package/dist/utils/safeUrl.js +78 -0
  252. package/locales/af-ZA.json +530 -1
  253. package/locales/ar-SA.json +490 -1
  254. package/locales/ca-ES.json +514 -1
  255. package/locales/cs-CZ.json +498 -1
  256. package/locales/da-DK.json +522 -1
  257. package/locales/de-DE.json +522 -1
  258. package/locales/el-GR.json +498 -1
  259. package/locales/es-ES.json +510 -1
  260. package/locales/fi-FI.json +498 -1
  261. package/locales/fr-FR.json +534 -1
  262. package/locales/he-IL.json +498 -1
  263. package/locales/hu-HU.json +498 -1
  264. package/locales/it-IT.json +510 -1
  265. package/locales/ja-JP.json +490 -1
  266. package/locales/ko-KR.json +498 -1
  267. package/locales/nl-NL.json +534 -1
  268. package/locales/no-NO.json +510 -1
  269. package/locales/pl-PL.json +506 -1
  270. package/locales/pt-BR.json +506 -1
  271. package/locales/pt-PT.json +506 -1
  272. package/locales/ro-RO.json +506 -1
  273. package/locales/ru-RU.json +498 -1
  274. package/locales/sr-SP.json +498 -1
  275. package/locales/sv-SE.json +502 -1
  276. package/locales/tr-TR.json +498 -1
  277. package/locales/uk-UA.json +498 -1
  278. package/locales/vi-VN.json +502 -1
  279. package/locales/zh-CN.json +490 -1
  280. package/locales/zh-TW.json +490 -1
  281. package/package.json +24 -4
  282. package/src/BottomSheet/BottomSheet.doc.mjs +8 -1
  283. package/src/BottomSheet/BottomSheet.spec.md +46 -20
  284. package/src/BottomSheet/BottomSheet.test.tsx +6 -3
  285. package/src/BottomSheet/BottomSheet.tsx +3 -1
  286. package/src/BottomSheet/BottomSheetKeyboard.test.tsx +195 -0
  287. package/src/BottomSheet/BottomSheetPanel.test.tsx +11 -1
  288. package/src/BottomSheet/BottomSheetPanel.tsx +49 -16
  289. package/src/BottomSheet/__tests__/BottomSheetKeyboard.a11y.browser.spec.ts +344 -0
  290. package/src/Button/Button.doc.mjs +5 -5
  291. package/src/Button/Button.tsx +15 -13
  292. package/src/Button/__tests__/Button.a11y.chromium.spec.ts +17 -1
  293. package/src/Button/__tests__/Button.a11y.known-failures.ts +0 -29
  294. package/src/Button/__tests__/Button.a11y.renders.tsx +9 -2
  295. package/src/Button/__tests__/Button.a11y.states.ts +9 -0
  296. package/src/Chat/ChatComposer.doc.mjs +14 -0
  297. package/src/Chat/ChatComposer.spec.md +230 -0
  298. package/src/Chat/ChatComposer.test.tsx +57 -0
  299. package/src/Chat/ChatComposer.tsx +21 -9
  300. package/src/Chat/ChatComposerDrawer.doc.mjs +63 -5
  301. package/src/Chat/ChatComposerDrawer.spec.md +267 -0
  302. package/src/Chat/ChatComposerDrawer.test.tsx +81 -12
  303. package/src/Chat/ChatComposerDrawer.tsx +38 -9
  304. package/src/Chat/ChatComposerInput.doc.mjs +114 -26
  305. package/src/Chat/ChatComposerInput.spec.md +185 -0
  306. package/src/Chat/ChatComposerInput.test.tsx +113 -3
  307. package/src/Chat/ChatComposerInput.tsx +78 -13
  308. package/src/Chat/ChatComposerTokenElement.spec.md +152 -0
  309. package/src/Chat/ChatComposerTokenElement.test.tsx +85 -0
  310. package/src/Chat/ChatDictationButton.doc.mjs +3 -3
  311. package/src/Chat/ChatDictationButton.spec.md +160 -0
  312. package/src/Chat/ChatDictationButton.test.tsx +92 -27
  313. package/src/Chat/ChatDictationButton.tsx +8 -6
  314. package/src/Chat/ChatLayout.doc.mjs +12 -4
  315. package/src/Chat/ChatLayout.spec.md +271 -0
  316. package/src/Chat/ChatLayout.test.tsx +28 -0
  317. package/src/Chat/ChatLayout.tsx +19 -0
  318. package/src/Chat/ChatLayoutScrollButton.spec.md +338 -0
  319. package/src/Chat/ChatLayoutScrollButton.test.tsx +31 -0
  320. package/src/Chat/ChatLayoutScrollButton.tsx +31 -14
  321. package/src/Chat/ChatMessageBubble.doc.mjs +28 -15
  322. package/src/Chat/ChatMessageBubble.spec.md +263 -0
  323. package/src/Chat/ChatMessageBubble.test.tsx +93 -0
  324. package/src/Chat/ChatMessageBubble.tsx +8 -3
  325. package/src/Chat/ChatMessageList.spec.md +222 -0
  326. package/src/Chat/ChatMessageList.test.tsx +64 -2
  327. package/src/Chat/ChatMessageList.tsx +4 -3
  328. package/src/Chat/ChatMessageMetadata.doc.mjs +57 -3
  329. package/src/Chat/ChatMessageMetadata.spec.md +220 -0
  330. package/src/Chat/ChatMessageMetadata.test.tsx +34 -0
  331. package/src/Chat/ChatMessageMetadata.tsx +13 -13
  332. package/src/Chat/ChatSendButton.test.tsx +1 -4
  333. package/src/Chat/ChatSendButton.tsx +1 -1
  334. package/src/Chat/__tests__/ChatLayoutScrollButton.a11y.chromium.spec.ts +514 -0
  335. package/src/Chat/__tests__/ChatLayoutScrollButtonSurface.a11y.chromium.spec.ts +740 -0
  336. package/src/Chat/__tests__/ChatMessageBubble.a11y.chromium.spec.ts +457 -0
  337. package/src/Chat/__tests__/ChatMessageBubble.auditProvenance.test.ts +91 -0
  338. package/src/Chat/__tests__/ChatMessageBubble.auditProvenance.ts +91 -0
  339. package/src/Chat/__tests__/ChatMessageList.a11y.chromium.spec.ts +456 -0
  340. package/src/Chat/__tests__/ChatMessageMetadata.a11y.chromium.spec.ts +413 -0
  341. package/src/Chat/index.ts +1 -0
  342. package/src/CheckboxInput/CheckboxInput.doc.mjs +11 -0
  343. package/src/CheckboxInput/CheckboxInput.test.tsx +34 -0
  344. package/src/CheckboxInput/CheckboxInput.tsx +21 -1
  345. package/src/Citation/Citation.doc.mjs +2 -2
  346. package/src/Citation/Citation.test.tsx +17 -0
  347. package/src/Citation/Citation.tsx +4 -2
  348. package/src/ClickableCard/ClickableCard.doc.mjs +2 -2
  349. package/src/ClickableCard/ClickableCard.test.tsx +102 -5
  350. package/src/CodeBlock/highlightRanges.test.ts +143 -1
  351. package/src/CodeBlock/highlightRanges.ts +15 -5
  352. package/src/Collapsible/Collapsible.doc.mjs +11 -0
  353. package/src/Collapsible/Collapsible.test.tsx +21 -0
  354. package/src/Collapsible/Collapsible.tsx +5 -0
  355. package/src/CommandPalette/CommandPaletteInput.tsx +6 -1
  356. package/src/ComplexSelector/ComplexSelector.tsx +6 -1
  357. package/src/DateInput/DateInput.tsx +6 -1
  358. package/src/DateInput/NativeDateField.tsx +24 -8
  359. package/src/DateInput/TouchDateField.tsx +6 -2
  360. package/src/DateRangeInput/DateRangeInput.tsx +6 -1
  361. package/src/DateTimeInput/DateTimeInput.tsx +6 -1
  362. package/src/DateTimeInput/TouchDateTimeField.tsx +6 -1
  363. package/src/DateTimeInput/nativePickerSegmentStyles.ts +24 -8
  364. package/src/Dialog/Dialog.doc.mjs +2 -0
  365. package/src/Dialog/DialogHeader.doc.mjs +22 -0
  366. package/src/Dialog/DialogHeader.test.tsx +167 -3
  367. package/src/Dialog/DialogHeader.tsx +37 -6
  368. package/src/Dialog/modules/DialogHeader.spec.md +101 -42
  369. package/src/DropdownMenu/DropdownMenu.test.tsx +5 -2
  370. package/src/Field/InputClearButton.test.tsx +17 -3
  371. package/src/Field/InputClearButton.tsx +5 -2
  372. package/src/Field/PanelSearchInput.tsx +5 -2
  373. package/src/FieldStatus/__tests__/StatusMessage.a11y.states.ts +1 -1
  374. package/src/FileInput/FileInput.tsx +11 -2
  375. package/src/Icon/Icon.doc.mjs +7 -5
  376. package/src/Icon/Icon.spec.md +81 -40
  377. package/src/Icon/Icon.test.tsx +6 -3
  378. package/src/Icon/Icon.tsx +20 -68
  379. package/src/Icon/IconDefaultSizeContext.ts +23 -0
  380. package/src/Icon/IconSize.stylex.ts +70 -0
  381. package/src/IconButton/IconButton.doc.mjs +3 -3
  382. package/src/IconButton/IconButton.test.tsx +40 -0
  383. package/src/Item/Item.doc.mjs +6 -2
  384. package/src/Item/Item.tsx +9 -3
  385. package/src/Kbd/Kbd.doc.mjs +3 -3
  386. package/src/Kbd/Kbd.test.tsx +57 -1
  387. package/src/Kbd/Kbd.tsx +57 -37
  388. package/src/Layout/LayoutFooter.doc.mjs +17 -0
  389. package/src/Link/Link.doc.mjs +17 -4
  390. package/src/Link/Link.test.tsx +24 -0
  391. package/src/Link/Link.tsx +5 -0
  392. package/src/Link/LinkProvider.doc.mjs +2 -2
  393. package/src/Link/__tests__/Link.navigation.a11y.chromium.spec.ts +261 -0
  394. package/src/Link/useLinkComponent.test.tsx +333 -0
  395. package/src/Link/useLinkComponent.ts +29 -57
  396. package/src/List/List.doc.mjs +6 -0
  397. package/src/List/List.spec.md +200 -0
  398. package/src/List/List.test.tsx +117 -1
  399. package/src/List/List.tsx +22 -2
  400. package/src/List/ListContext.tsx +3 -1
  401. package/src/List/ListItem.doc.mjs +2 -2
  402. package/src/List/ListItem.source-build.test.mjs +41 -0
  403. package/src/List/ListItem.tsx +26 -2
  404. package/src/Markdown/Markdown.doc.mjs +300 -2
  405. package/src/Markdown/Markdown.fr23.bench.ts +174 -0
  406. package/src/Markdown/Markdown.fr23.perf.test.ts +249 -0
  407. package/src/Markdown/Markdown.fr23.sampling.ts +49 -0
  408. package/src/Markdown/Markdown.helpers.perf.test.ts +489 -0
  409. package/src/Markdown/Markdown.public.test.ts +130 -3
  410. package/src/Markdown/Markdown.renderBoundary.test.tsx +72 -0
  411. package/src/Markdown/Markdown.spec.md +203 -45
  412. package/src/Markdown/Markdown.test.tsx +63 -0
  413. package/src/Markdown/Markdown.tsx +414 -135
  414. package/src/Markdown/ast.test.ts +307 -0
  415. package/src/Markdown/ast.ts +337 -0
  416. package/src/Markdown/incremental.test.ts +12 -0
  417. package/src/Markdown/index.ts +37 -1
  418. package/src/Markdown/modules/remark.spec.md +269 -0
  419. package/src/Markdown/modules/softBreaks.spec.md +137 -0
  420. package/src/Markdown/parser/index.ts +64 -0
  421. package/src/Markdown/parser.public.test.ts +103 -0
  422. package/src/Markdown/parser.test.ts +20 -0
  423. package/src/Markdown/parser.ts +1180 -235
  424. package/src/Markdown/plugins/frontmatter.test.tsx +125 -0
  425. package/src/Markdown/plugins/frontmatter.ts +198 -0
  426. package/src/Markdown/plugins/index.ts +54 -0
  427. package/src/Markdown/plugins/protocol.test.tsx +1022 -0
  428. package/src/Markdown/plugins/protocol.ts +1618 -0
  429. package/src/Markdown/plugins/semanticFence.test.tsx +546 -0
  430. package/src/Markdown/plugins/semanticFence.ts +424 -0
  431. package/src/Markdown/plugins/softBreaks.test.tsx +172 -0
  432. package/src/Markdown/plugins/softBreaks.ts +169 -0
  433. package/src/Markdown/plugins/sourceDecoration.test.tsx +799 -0
  434. package/src/Markdown/plugins/sourceDecoration.ts +539 -0
  435. package/src/Markdown/plugins/textTransform.test.ts +467 -0
  436. package/src/Markdown/plugins/textTransform.ts +554 -0
  437. package/src/Markdown/remark.test.tsx +1877 -0
  438. package/src/Markdown/remark.ts +1574 -0
  439. package/src/Markdown/url.ts +36 -0
  440. package/src/Markdown/utils.ts +13 -1
  441. package/src/MetadataList/MetadataList.test.tsx +4 -2
  442. package/src/MetadataList/MetadataList.tsx +3 -3
  443. package/src/MultiSelector/MultiSelector.test.tsx +1 -35
  444. package/src/MultiSelector/__tests__/MultiSelector.listbox.a11y.test.tsx +128 -0
  445. package/src/NumberInput/NumberInput.tsx +6 -1
  446. package/src/Outline/Outline.doc.mjs +7 -5
  447. package/src/Outline/Outline.spec.md +1 -1
  448. package/src/Outline/index.ts +1 -0
  449. package/src/Outline/modules/parseOutlineFromMarkdown.spec.md +142 -0
  450. package/src/Outline/parseOutlineFromMarkdown.ts +40 -10
  451. package/src/Outline/useOutlineFromMarkdown.ts +15 -3
  452. package/src/PowerSearch/PowerSearch.doc.mjs +2 -2
  453. package/src/PowerSearch/PowerSearchEditPopover.test.tsx +150 -1
  454. package/src/PowerSearch/PowerSearchEditPopover.tsx +51 -28
  455. package/src/PowerSearch/PowerSearchValueEditor.test.tsx +51 -0
  456. package/src/PowerSearch/PowerSearchValueEditor.tsx +4 -0
  457. package/src/ProgressBar/ProgressBar.test.tsx +29 -11
  458. package/src/ProgressBar/ProgressBar.tsx +59 -72
  459. package/src/RadioList/RadioList.doc.mjs +11 -0
  460. package/src/RadioList/RadioList.test.tsx +32 -0
  461. package/src/RadioList/RadioListItem.tsx +25 -1
  462. package/src/ScrollableArea/ScrollableArea.tsx +1 -0
  463. package/src/ScrollableArea/modules/useScrollableArea.spec.md +50 -22
  464. package/src/SegmentedControl/SegmentedControl.doc.mjs +2 -2
  465. package/src/SegmentedControl/SegmentedControl.test.tsx +31 -0
  466. package/src/SegmentedControl/SegmentedControlItem.tsx +6 -9
  467. package/src/Selector/Selector.doc.mjs +2 -2
  468. package/src/Selector/Selector.spec.md +51 -49
  469. package/src/Selector/Selector.test.tsx +61 -55
  470. package/src/Selector/Selector.tsx +34 -15
  471. package/src/Selector/__tests__/Listbox.a11y.chromium.spec.ts +130 -0
  472. package/src/Selector/__tests__/Listbox.a11y.dom.ts +38 -0
  473. package/src/Selector/__tests__/Listbox.a11y.inventory.test.ts +63 -0
  474. package/src/Selector/__tests__/Listbox.a11y.known-failures.ts +37 -0
  475. package/src/Selector/__tests__/Listbox.a11y.states.ts +232 -0
  476. package/src/Selector/__tests__/Selector.a11y.chromium.spec.ts +45 -0
  477. package/src/Selector/__tests__/Selector.listbox.a11y.test.tsx +121 -0
  478. package/src/SideNav/SideNav.doc.mjs +1 -1
  479. package/src/SideNav/SideNav.test.tsx +10 -0
  480. package/src/SideNav/SideNav.tsx +14 -2
  481. package/src/Slider/Slider.doc.mjs +17 -3
  482. package/src/Slider/Slider.test.tsx +221 -0
  483. package/src/Slider/Slider.tsx +40 -9
  484. package/src/Spinner/Spinner.test.tsx +4 -0
  485. package/src/Spinner/Spinner.tsx +31 -18
  486. package/src/Switch/Switch.doc.mjs +11 -0
  487. package/src/Switch/Switch.test.tsx +16 -0
  488. package/src/Switch/Switch.tsx +28 -0
  489. package/src/TabList/Tab.tsx +35 -7
  490. package/src/TabList/TabList.doc.mjs +11 -0
  491. package/src/TabList/TabList.spec.md +204 -0
  492. package/src/TabList/TabList.test.tsx +66 -0
  493. package/src/TabList/__tests__/Tabs.a11y.known-failures.ts +1 -34
  494. package/src/Table/Table.doc.mjs +1 -1
  495. package/src/Table/Table.spec.md +54 -40
  496. package/src/Table/Table.test.tsx +83 -10
  497. package/src/Table/Table.tsx +30 -22
  498. package/src/Table/__tests__/TableScroll.a11y.chromium.spec.ts +137 -0
  499. package/src/TextArea/TextArea.tsx +6 -1
  500. package/src/TextInput/TextInput.test.tsx +20 -1
  501. package/src/TextInput/TextInput.tsx +6 -1
  502. package/src/TimeInput/TimeInput.tsx +6 -1
  503. package/src/Timer/Timer.doc.mjs +183 -0
  504. package/src/Timer/Timer.spec.md +215 -0
  505. package/src/Timer/Timer.test.tsx +302 -0
  506. package/src/Timer/Timer.tsx +258 -0
  507. package/src/Timer/index.ts +11 -0
  508. package/src/ToggleButton/ToggleButton.doc.mjs +3 -3
  509. package/src/ToggleButton/ToggleButton.test.tsx +299 -4
  510. package/src/ToggleButton/ToggleButton.tsx +26 -33
  511. package/src/ToggleButton/ToggleButtonGroup.doc.mjs +3 -3
  512. package/src/ToggleButton/__tests__/ToggleButton.a11y.chromium.spec.ts +209 -0
  513. package/src/Token/Token.doc.mjs +2 -2
  514. package/src/Tokenizer/Tokenizer.spec.md +142 -75
  515. package/src/TopNav/TopNavMenu.doc.mjs +2 -2
  516. package/src/TopNav/TopNavMenu.test.tsx +30 -0
  517. package/src/TopNav/TopNavMenu.tsx +7 -2
  518. package/src/TreeList/TreeList.doc.mjs +3 -3
  519. package/src/TreeList/TreeList.spec.md +123 -75
  520. package/src/TreeList/TreeList.test.tsx +29 -0
  521. package/src/TreeList/TreeList.tsx +3 -0
  522. package/src/TreeList/TreeListItem.tsx +15 -1
  523. package/src/TreeList/TreeListTypes.ts +11 -1
  524. package/src/Typeahead/BaseTypeahead.spec.md +4 -3
  525. package/src/Typeahead/BaseTypeahead.tsx +21 -7
  526. package/src/Typeahead/Typeahead.test.tsx +53 -0
  527. package/src/__tests__/PressedState.a11y.chromium.spec.ts +813 -0
  528. package/src/__tests__/pressState.ts +93 -0
  529. package/src/hooks/scrollKeyboardDelegation.test.ts +155 -0
  530. package/src/hooks/scrollKeyboardDelegation.ts +233 -0
  531. package/src/hooks/useClickableContainer.test.tsx +236 -0
  532. package/src/hooks/useClickableContainer.ts +20 -4
  533. package/src/hooks/useScrollableArea.doc.mjs +15 -3
  534. package/src/hooks/useScrollableArea.test.tsx +59 -1
  535. package/src/hooks/useScrollableArea.ts +34 -10
  536. package/src/index.ts +3 -0
  537. package/src/inputFontFloor.test.ts +106 -0
  538. package/src/tailwind-theme.css +0 -6
  539. package/src/theme/Theme.test.tsx +32 -0
  540. package/src/theme/declarationBoundary.test.ts +126 -0
  541. package/src/theme/declarationBoundary.ts +347 -0
  542. package/src/theme/derivedVarRegistry.test.ts +7 -0
  543. package/src/theme/derivedVarRegistry.ts +1 -0
  544. package/src/theme/generateThemeRules.test.ts +526 -1
  545. package/src/theme/generateThemeRules.ts +228 -50
  546. package/src/theme/tokenValueCompat.test.ts +4 -1
  547. package/src/utils/interactionOverlay.stylex.ts +20 -0
  548. package/src/utils/safeUrl.test.ts +88 -0
  549. package/src/utils/safeUrl.ts +85 -0
@@ -210,6 +210,17 @@ export const docs = {
210
210
  ],
211
211
  },
212
212
  usage: {
213
+ accessibility: [
214
+ {
215
+ name: 'Track and thumb',
216
+ category: 'Color contrast',
217
+ criterion: '1.4.11 Non-text Contrast',
218
+ requirement: '3:1',
219
+ states: ['Rest', 'Hover', 'Pointer down'],
220
+ description:
221
+ 'The on and off tracks must each have at least 3:1 contrast with the surface behind them, and the thumb with its track. For Hover and Pointer down, measure the final colors after the tint and the pressed overlay are applied.',
222
+ },
223
+ ],
213
224
  anatomy,
214
225
  description:
215
226
  'A toggle control for on/off states that take effect immediately. Supports labels, descriptions, loading states, and validation. Use it for settings or preferences that apply instantly. For changes requiring a form submission, use a checkbox instead.',
@@ -30,6 +30,7 @@ import {
30
30
  getAllInjectedCss,
31
31
  getForcedColorsRules,
32
32
  } from '../__tests__/forcedColors';
33
+ import {hasPressedArm} from '../__tests__/pressState';
33
34
  import {__resetLiveRegionsForTest} from '../hooks/useAnnounce';
34
35
 
35
36
  afterEach(() => {
@@ -755,6 +756,21 @@ describe('Switch', () => {
755
756
  });
756
757
  });
757
758
 
759
+ describe('pressed state', () => {
760
+ it('paints the pressed overlay on the track and the thumb while the row is pressed', () => {
761
+ const {container} = render(
762
+ <Switch label="Notifications" value={false} onChange={() => {}} />,
763
+ );
764
+ const track = container.querySelector('.astryx-switch');
765
+ const thumb = container.querySelector('.astryx-switch-thumb');
766
+ if (track == null || thumb == null) {
767
+ throw new Error('the switch has no track or thumb to press');
768
+ }
769
+ expect(hasPressedArm(track)).toBe(true);
770
+ expect(hasPressedArm(thumb)).toBe(true);
771
+ });
772
+ });
773
+
758
774
  describe('coarse pointer and RTL hit-target positioning', () => {
759
775
  it.each([
760
776
  ['sm', 'ltr'],
@@ -122,6 +122,15 @@ const thumbOnSizeStyles = stylex.create({
122
122
  },
123
123
  });
124
124
 
125
+ // The pressed overlay, painted as a gradient layer OVER the track's and
126
+ // thumb's own fills so it composes with the on/off colors and the hover tint
127
+ // instead of replacing them. Same token Button's overlay paints with. The
128
+ // switch is a two-part control whose focusable input sits beside the track,
129
+ // so the press is read off the shared scope marker (the row), the way the
130
+ // hover tint already is: pressing the input, the track or the label all
131
+ // activate the row.
132
+ const pressedImage = `linear-gradient(${colorVars['--color-overlay-pressed']}, ${colorVars['--color-overlay-pressed']})`;
133
+
125
134
  const labelWrapperSizeStyles = stylex.create({
126
135
  sm: {
127
136
  minHeight: 20,
@@ -207,6 +216,15 @@ const styles = stylex.create({
207
216
  default: null,
208
217
  '@media (forced-colors: active)': 'CanvasText',
209
218
  },
219
+ // Pressed: the overlay rides on top of the on/off fill. Gated like the
220
+ // hover tint so forced colors keeps its system-color track.
221
+ backgroundImage: {
222
+ default: null,
223
+ [stylex.when.ancestor(':active', switchScope)]: {
224
+ default: null,
225
+ '@media (forced-colors: none)': pressedImage,
226
+ },
227
+ },
210
228
  },
211
229
  // The one ring in the system not drawn by focusOutlineStyles. The focusable
212
230
  // input is a sibling of the track, so the condition has to reach the shared
@@ -278,6 +296,16 @@ const styles = stylex.create({
278
296
  '@media (prefers-reduced-motion: reduce)': '0s',
279
297
  },
280
298
  transitionTimingFunction: easeVars['--ease-standard'],
299
+ // Pressed: the same overlay as the track, so the whole control darkens
300
+ // under the finger rather than the thumb standing out against a darker
301
+ // track.
302
+ backgroundImage: {
303
+ default: null,
304
+ [stylex.when.ancestor(':active', switchScope)]: {
305
+ default: null,
306
+ '@media (forced-colors: none)': pressedImage,
307
+ },
308
+ },
281
309
  },
282
310
  // The thumb fill lives on the on/off styles (not the shared thumb style)
283
311
  // because forced colors needs a per-state system color: CanvasText on the
@@ -137,6 +137,15 @@ const styles = stylex.create({
137
137
  [stylex.when.ancestor(':hover', tabScope)]: {
138
138
  '@media (hover: hover)': colorVars['--color-overlay-hover'],
139
139
  },
140
+ // Pressed: the same layer steps up to the pressed overlay, read off the
141
+ // tab the way the hover is, so a press paints on a finger too. Repeated
142
+ // inside the hover-capable branch so it outranks the hover rule there
143
+ // (a media-nested rule carries extra generated priority; see
144
+ // interactionOverlay.stylex.ts).
145
+ [stylex.when.ancestor(':active', tabScope)]: {
146
+ default: colorVars['--color-overlay-pressed'],
147
+ '@media (hover: hover)': colorVars['--color-overlay-pressed'],
148
+ },
140
149
  },
141
150
  transitionProperty: 'background-color',
142
151
  transitionDuration: durationVars['--duration-fast'],
@@ -249,6 +258,7 @@ export function Tab({
249
258
  xstyle,
250
259
  className,
251
260
  style,
261
+ onClick,
252
262
  ...restProps
253
263
  }: TabProps) {
254
264
  const tabListCtx = useTabListContext();
@@ -263,9 +273,23 @@ export function Tab({
263
273
  const displayIcon = isSelected && selectedIcon ? selectedIcon : icon;
264
274
  const hasVisibleLabel = !isLabelHidden && label !== '';
265
275
 
266
- const handleSelect = useCallback(() => {
267
- tabListCtx.onChange(value);
268
- }, [tabListCtx, value]);
276
+ const isDisabled =
277
+ restProps['aria-disabled'] === true ||
278
+ restProps['aria-disabled'] === 'true';
279
+
280
+ const handleSelect = useCallback(
281
+ (event: React.MouseEvent<HTMLButtonElement | HTMLAnchorElement>) => {
282
+ if (isDisabled) {
283
+ event.preventDefault();
284
+ return;
285
+ }
286
+ onClick?.(event as React.MouseEvent<HTMLButtonElement>);
287
+ if (!event.defaultPrevented) {
288
+ tabListCtx.onChange(value);
289
+ }
290
+ },
291
+ [isDisabled, onClick, tabListCtx, value],
292
+ );
269
293
 
270
294
  useDevWarning(
271
295
  'Tab',
@@ -339,7 +363,7 @@ export function Tab({
339
363
  sizeStyles[size],
340
364
  isSelected && styles.selected,
341
365
  isFill && layoutStyles.fill,
342
- tabScope,
366
+ !isDisabled && tabScope,
343
367
  xstyle,
344
368
  ),
345
369
  className,
@@ -382,10 +406,14 @@ export function Tab({
382
406
  ) : null;
383
407
 
384
408
  if (isLink) {
409
+ // A disabled link tab must not reach a router component: some routers reject
410
+ // a missing destination, while others treat it as the current route. A
411
+ // plain anchor without href preserves the element shape but cannot navigate.
412
+ const LinkRoot = isDisabled ? 'a' : LinkComponent;
385
413
  return (
386
- <LinkComponent
414
+ <LinkRoot
387
415
  ref={ref}
388
- href={href}
416
+ href={isDisabled ? undefined : href}
389
417
  onClick={handleSelect}
390
418
  {...sharedProps}>
391
419
  {hoverBgElement}
@@ -393,7 +421,7 @@ export function Tab({
393
421
  {labelElement}
394
422
  {endContentElement}
395
423
  {indicatorElement}
396
- </LinkComponent>
424
+ </LinkRoot>
397
425
  );
398
426
  }
399
427
 
@@ -103,6 +103,17 @@ export const docs = {
103
103
  {name: 'TabMenu'},
104
104
  ],
105
105
  usage: {
106
+ accessibility: [
107
+ {
108
+ name: 'Tab label',
109
+ category: 'Color contrast',
110
+ criterion: '1.4.3 Contrast (Minimum)',
111
+ requirement: '4.5:1',
112
+ states: ['Rest', 'Hover', 'Pointer down', 'Selected'],
113
+ description:
114
+ 'Each label must have at least 4.5:1 contrast with the tab surface behind it. For Hover and Pointer down, measure the final background after the overlay layer is applied.',
115
+ },
116
+ ],
106
117
  description:
107
118
  'TabList provides tab-style navigation for organizing content into categorized sections. Use it to let users switch between related views without leaving the page, with overflow items handled by a built-in "more" menu.',
108
119
  bestPractices: [
@@ -0,0 +1,204 @@
1
+ ---
2
+ schema_version: 3
3
+ template_version: 5
4
+ kind: component
5
+ id: component:TabList
6
+ authority: current
7
+ archive_reason: null
8
+ superseded_by: null
9
+ approved_by: cixzhang
10
+ approved_at: 2026-09-21
11
+ owners: [cixzhang]
12
+ review_triggers: [public-api, behavior, layout, accessibility]
13
+ verified_by:
14
+ [
15
+ packages/core/src/TabList/TabList.test.tsx,
16
+ apps/storybook/stories/TabList.stories.tsx,
17
+ scripts/check-knowledge.mjs,
18
+ ]
19
+ modules: []
20
+ families: []
21
+ design_specs: []
22
+ architecture:
23
+ [architecture:container-padding, architecture:public-component-api]
24
+ contributing: [contributing:api-conventions]
25
+ system_specs: [spec:AST-002/DEC-1, spec:AST-002/DEC-2, spec:AST-017/DEC-1]
26
+ ---
27
+
28
+ # TabList component contract
29
+
30
+ ## Contract at a glance
31
+
32
+ | Area | Contract |
33
+ | ----------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
34
+ | Public contract | Canonicalize the existing alignment mode as `edgeCompensation?: 'inline'`; deprecate `isFullBleed` and remove it in the next minor release. |
35
+ | Behavior | Move first and last visible tab content toward the host content line, reaching it when the host inset is at least the edge-tab padding, while preserving tab interaction padding, focus-ring room, overflow controls, selection-indicator geometry, and the optional divider rail. |
36
+ | End-user impact | Edge tabs lose unnecessary extra inset where host geometry permits and remain fully interactive without clipped focus, selection, overflow, or divider treatment. |
37
+ | Builder impact | Existing `isFullBleed` callsites keep working during the deprecation window and migrate mechanically to `edgeCompensation="inline"`. |
38
+ | Compatibility/readiness | Current behavior is shipped; the canonical alias is additive, while removing the released legacy prop is a separately implemented breaking change in the next minor release. |
39
+ | Review checks | Reject a behavior change disguised as a rename, directional values without overflow/indicator proof, or early removal of the legacy prop. |
40
+ | Governing rules | `architecture:container-padding/INV9–INV11`; `spec:AST-002/DEC-1–DEC-2`; `spec:AST-017/DEC-1`. |
41
+
42
+ This table is a review projection; the body below is authoritative.
43
+
44
+ ## Intent
45
+
46
+ TabList's current opt-in is edge compensation: it consumes the full inherited
47
+ host inset, moves visible edge-tab content toward the surrounding content line,
48
+ and retains Tab-owned interaction padding plus TabList-owned divider, overflow,
49
+ and indicator geometry. Content reaches the host line only when that inset is at
50
+ least the edge tab's own padding. The public `isFullBleed` name is misleading
51
+ because the strip restores uncovered content inset after the outer box expands.
52
+
53
+ ## Compatibility and migration
54
+
55
+ - Released default preserved: `yes`; omission keeps current TabList geometry.
56
+ - Compatibility class: the canonical alias is additive while the released
57
+ `isFullBleed` prop remains; removing that prop is a breaking change in the next
58
+ minor release under `spec:AST-017/DEC-1`.
59
+ - Controlled/uncontrolled behavior: active-value control is unchanged.
60
+ - Migration decision: `component:TabList/DEC-1`.
61
+
62
+ During the compatibility window:
63
+
64
+ - `edgeCompensation="inline"` is the canonical spelling;
65
+ - omitted `edgeCompensation` plus `isFullBleed={true}` selects the same mode;
66
+ - `isFullBleed` is deprecated and maintained examples use the canonical prop;
67
+ - if both props are supplied, explicit `edgeCompensation` is canonical and the
68
+ legacy boolean cannot disable it.
69
+
70
+ The removal release MUST include a `[breaking]` Changeset for
71
+ `@astryxdesign/core`, consumer release notes, and an `astryx upgrade` codemod that rewrites
72
+ `isFullBleed` to `edgeCompensation="inline"`.
73
+
74
+ ## Ownership boundary
75
+
76
+ **Owns**
77
+
78
+ - The TabList-wide edge-compensation mode and its compatibility alias.
79
+ - The relationship between the outer TabList box, inner strip padding, edge tabs,
80
+ focus-ring room, overflow controls, and selection indicator.
81
+ - Which logical edges are supported by the public mode.
82
+
83
+ **Does not own / non-goals**
84
+
85
+ - Host padding publication, nesting, or overlay resets — owned by
86
+ `architecture:container-padding`.
87
+ - Button or List edge-compensation projections.
88
+ - New `start` or `end` values without separate proof and owner approval.
89
+ - A change to navigation/tab semantics, selection state, keyboard behavior, or
90
+ overflow ownership.
91
+
92
+ ## Public concepts
93
+
94
+ | Concept | Closed values or states | Meaning | Availability by variant/orientation/state | Default | Owner | Stability | Invalid-value behavior |
95
+ | ----------------- | ------------------------ | ---------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------ | --------------- | ------------------- | ------------------------------- | ------------------------------------------------------ |
96
+ | Edge compensation | omitted, `inline` | Consume both inherited inline host insets and move edge-tab content toward the host lines while retaining local interaction and strip-owned geometry | Navigation and tabs patterns across current layout/overflow states | omitted | `component:TabList` | accepted; canonical API pending | Other values are rejected by the public type |
97
+ | Legacy alias | omitted, `false`, `true` | Compatibility spelling for omitted or inline edge compensation | Until the next minor release | omitted/`false` | `component:TabList` | deprecated | `true` maps to `inline`; explicit canonical input wins |
98
+
99
+ ## Behavioral and layout contract
100
+
101
+ | ID | Invariant | Basis | Status |
102
+ | --- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------- | -------------------------------------------------------- |
103
+ | FR1 | The current opt-in MUST remain edge compensation: the outer TabList box consumes the full inherited inline host inset and any `hasDivider` rail spans that expanded width; the inner strip restores `max(host inset - edge-tab padding, 0)` at each logical edge. Visible edge-tab content reaches the host line only when the host inset is at least the tab padding; otherwise it moves toward that line without crossing the host boundary. | Current source and `component:TabList/DEC-1` | Shipped behavior |
104
+ | FR2 | Compensation MUST preserve Tab interaction padding, focus-ring room, overflow detection and controls, scroll access, selection-indicator geometry, and the optional divider rail's expanded inline span. | Current source plus owner direction | Shipped behavior; expanded evidence required with rename |
105
+ | FR3 | `edgeCompensation?: 'inline'` MUST become the canonical API without changing FR1–FR2 geometry or the omitted default. | `architecture:container-padding/INV10`; `component:TabList/DEC-1` | Accepted contract; implementation pending |
106
+ | FR4 | During the deprecation window, omitted `edgeCompensation` plus `isFullBleed={true}` MUST produce the canonical `inline` behavior. Explicit `edgeCompensation` MUST remain authoritative when both props are supplied. | Compatibility decision | Accepted contract; implementation pending |
107
+ | FR5 | `isFullBleed` MUST be removed in the next minor release only after maintained docs/examples use `edgeCompensation`, both paths have compatibility evidence, and the removal includes a `[breaking]` Changeset plus an `astryx upgrade` codemod for mechanical consumer migration. | `component:TabList/DEC-1`; `spec:AST-017/DEC-1` | Accepted contract; implementation pending |
108
+ | FR6 | `start` and `end` MUST remain rejected until per-edge overflow, clipping, scroll-control, focus-ring, indicator, direction, and theme-padding evidence receives owner approval. | Shared logical vocabulary and TabList boundary | Accepted boundary |
109
+
110
+ ### Allowed variation
111
+
112
+ - Layout, size, role, selected value, labels, tab content, and overflow mode may
113
+ vary while the same edge-compensation meaning is preserved.
114
+ - The implementation may retain the current outer-box/inner-strip technique or
115
+ replace it with equivalent geometry that satisfies FR1–FR2.
116
+ - A host may be painted or bounded only where TabList's component-specific
117
+ evidence proves the outer box, clipping, focus, and indicator behavior safe.
118
+
119
+ ### Representative states
120
+
121
+ | State | Required invariant | Allowed variation |
122
+ | --------------------- | ------------------------------------------------------------------------------------------------------------------------ | ----------------------------------------------------------------------------------------------- |
123
+ | Default/omitted | Current TabList box, strip, and tab geometry are unchanged. | Any current layout, role, or overflow mode. |
124
+ | Canonical inline mode | Outer box consumes each host inset; edge content reaches the host line only when that inset is at least the tab padding. | Host inset smaller than, equal to, or larger than edge-tab padding; asymmetric insets; LTR/RTL. |
125
+ | Divider | `hasDivider` rail spans the expanded outer inline width. | Fitting or overflowing strips. |
126
+ | Legacy alias | `isFullBleed={true}` matches canonical inline geometry during the compatibility window. | The canonical prop may also be present. |
127
+ | Overflowing strip | Scroll access, edge fades, controls, and selected-tab reveal remain correct. | Start/end overflow independently. |
128
+ | Focused edge tab | The focus ring remains visible and local to the tab. | Keyboard or pointer focus. |
129
+
130
+ ### Transformation and precedence order
131
+
132
+ - **ORD1 — Public input.** Resolve explicit `edgeCompensation`; otherwise map
133
+ `isFullBleed={true}` to `inline` during the compatibility window; otherwise use
134
+ no compensation.
135
+ - **ORD2 — Host geometry.** Read the matching inherited logical host insets, with
136
+ missing values falling back to zero.
137
+ - **ORD3 — Component geometry.** Resolve edge-tab padding and focus/indicator
138
+ allowances from TabList-owned sources, restore the non-overlapping portion of
139
+ each content inset, and preserve interaction padding and owned affordances.
140
+
141
+ ### Performance and resources
142
+
143
+ - **PR1 — CSS-first geometry.** The rename MUST add no observer, listener,
144
+ state, Effect, or render pass. Existing overflow measurement remains unchanged.
145
+
146
+ ## Accessibility contract
147
+
148
+ - **AR1 — Interaction remains stable.** Edge compensation MUST NOT change the
149
+ tab/nav pattern, accessible names, selected state, keyboard movement, tab stop,
150
+ focus target, or controlled value behavior.
151
+ - **AR2 — Overflow remains reachable.** Compensated edge geometry MUST NOT clip or
152
+ hide a focus ring, selected indicator, visible tab content, or an overflow
153
+ control required to reach offscreen tabs.
154
+
155
+ ## Design relationships
156
+
157
+ | Anatomy or state | Design requirement | Representation authority | Hierarchy role | Component contract |
158
+ | ----------------- | ----------------------------------------------------------------------------------------------------- | ------------------------- | -------------- | ------------------ |
159
+ | Outer TabList box | Consumes the full inherited inline host inset; with `hasDivider`, its rail spans that expanded width. | `component:TabList/DEC-1` | Supporting | FR1–FR3 |
160
+ | Inner strip | Restores `max(host inset - edge-tab padding, 0)` and owns scrolling/fades. | Current TabList behavior | Structural | FR1–FR2 |
161
+ | Edge Tab | Retains interaction padding and visible focus/selection treatment. | Tab composition | Prominent | FR1–FR2, AR1–AR2 |
162
+
163
+ ## Family and system relationships
164
+
165
+ - `architecture:container-padding` owns host publication, the shared
166
+ `edgeCompensation` vocabulary, logical-edge semantics, and overlay reset.
167
+ - `architecture:public-component-api` and `spec:AST-002` own public API
168
+ admission; `spec:AST-017/DEC-1` owns the breaking classification and migration
169
+ evidence required when the released alias is removed.
170
+ - TabList owns its specialized host, overflow, focus, and indicator projection.
171
+
172
+ ## Verification map
173
+
174
+ | Contract | Verification | Representative states | Mutation or failure expectation | Audit section |
175
+ | ---------------- | ----------------------------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------- | ---------------------- |
176
+ | FR1–FR4 | `TabList.test.tsx` and type/docs tests | omitted, canonical, legacy, both props, and `hasDivider` | Alias drift, changed defaults, wrong precedence, or lost divider span fails | `audit:TabList/api` |
177
+ | FR1–FR6, AR1–AR2 | Real-browser TabList geometry and interaction evidence | LTR/RTL; host inset smaller/equal/larger than edge-tab padding; asymmetric/zero inset; divider; fitting/overflowing; selected/focused edge tabs | Wrong bounded movement, clipped focus/indicator/divider, inaccessible overflow, or scroll regression fails | `audit:TabList/visual` |
178
+ | FR5 and docs | `TabList.doc.mjs`, Storybook, `[breaking]` Changeset, `astryx upgrade` codemod tests, and `scripts/check-knowledge.mjs` | canonical examples, deprecated alias, and removal migration | Missing migration guidance, wrong Changeset class, missing codemod rewrite, or stale canonical usage fails | `audit:TabList/docs` |
179
+
180
+ ## Decision log
181
+
182
+ ### DEC-1 — TabList migrates from full-bleed wording to edge compensation
183
+
184
+ **Reference:** `component:TabList/DEC-1`
185
+
186
+ **Decider:** cixzhang, 2026-09-21
187
+
188
+ TabList's current mode consumes the full inherited inline host inset, keeps an
189
+ optional divider across that expanded width, and restores only the portion of
190
+ content inset not already supplied by edge-tab padding. The user-facing intent is
191
+ therefore edge compensation, not a promise that tab content itself reaches an
192
+ outer edge. `edgeCompensation="inline"` becomes the canonical spelling;
193
+ `isFullBleed` remains a compatibility alias until its `[breaking]` next-minor
194
+ removal, with the required codemod and release evidence.
195
+
196
+ ## Open questions
197
+
198
+ None.
199
+
200
+ ## Content boundary
201
+
202
+ This claim-scoped contract does not duplicate TabList's complete navigation,
203
+ selection, overflow, or theming contract, consumer examples, implementation
204
+ steps, or List/Button projections. Those remain with their named owners.
@@ -12,6 +12,7 @@
12
12
  import {describe, it, expect, vi, beforeAll, afterAll} from 'vitest';
13
13
  import {render, screen, fireEvent} from '@testing-library/react';
14
14
  import userEvent from '@testing-library/user-event';
15
+ import {hasPressedArm} from '../__tests__/pressState';
15
16
  import {TabList} from './TabList';
16
17
  import type {TabListProps} from './TabList';
17
18
  import {Tab} from './Tab';
@@ -1515,3 +1516,68 @@ describe('TabList ARIA pattern — any other role', () => {
1515
1516
  );
1516
1517
  });
1517
1518
  });
1519
+
1520
+ describe('pressed state', () => {
1521
+ it('paints the pressed overlay on the tab surface while the tab is pressed', () => {
1522
+ render(
1523
+ <TabList value="home" onChange={() => {}}>
1524
+ <Tab value="home" label="Home" />
1525
+ <Tab value="settings" label="Settings" />
1526
+ </TabList>,
1527
+ );
1528
+ const tab = screen.getByRole('button', {name: 'Settings'});
1529
+ // The hover surface is a child layer read off the tab; the press paints
1530
+ // the same layer, so the assertion is on that layer.
1531
+ const surface = tab.querySelector('span[aria-hidden="true"]');
1532
+ if (surface == null) {
1533
+ throw new Error('the tab has no hover surface to press');
1534
+ }
1535
+ expect(hasPressedArm(surface)).toBe(true);
1536
+ });
1537
+
1538
+ it('does not activate a disabled button tab or call its handler', async () => {
1539
+ const user = userEvent.setup();
1540
+ const onChange = vi.fn();
1541
+ const onClick = vi.fn();
1542
+ render(
1543
+ <TabList value="home" onChange={onChange}>
1544
+ <Tab value="home" label="Home" />
1545
+ <Tab
1546
+ value="settings"
1547
+ label="Settings"
1548
+ aria-disabled="true"
1549
+ onClick={onClick}
1550
+ />
1551
+ </TabList>,
1552
+ );
1553
+ const tab = screen.getByRole('button', {name: 'Settings'});
1554
+ await user.click(tab);
1555
+ expect(onClick).not.toHaveBeenCalled();
1556
+ expect(onChange).not.toHaveBeenCalled();
1557
+ });
1558
+
1559
+ it('removes navigation from a disabled link tab', () => {
1560
+ const onChange = vi.fn();
1561
+ const {container} = render(
1562
+ <LinkProvider component={CustomLink}>
1563
+ <TabList value="home" onChange={onChange}>
1564
+ <Tab value="home" label="Home" />
1565
+ <Tab
1566
+ value="settings"
1567
+ label="Settings"
1568
+ href="/settings"
1569
+ aria-disabled="true"
1570
+ />
1571
+ </TabList>
1572
+ </LinkProvider>,
1573
+ );
1574
+ const tab = container.querySelector('a');
1575
+ if (tab == null) {
1576
+ throw new Error('the disabled link tab did not render an anchor');
1577
+ }
1578
+ expect(tab).not.toHaveAttribute('data-custom-link');
1579
+ expect(tab).not.toHaveAttribute('href');
1580
+ fireEvent.click(tab);
1581
+ expect(onChange).not.toHaveBeenCalled();
1582
+ });
1583
+ });
@@ -9,37 +9,4 @@
9
9
 
10
10
  import type {KnownFailure} from '@astryxdesign/a11y-spec';
11
11
 
12
- const COMMON = {
13
- binding: 'Tab',
14
- state: 'tab-disabled-unselected',
15
- evidenceLayer: 'real-browser',
16
- standardsReference:
17
- 'WCAG 2.2 4.1.2 Name, Role, Value; WAI-ARIA 1.2 aria-disabled',
18
- reason:
19
- 'This migration records the existing behavior without changing the component interaction contract.',
20
- } as const;
21
-
22
- export const TABS_KNOWN_FAILURES: ReadonlyArray<KnownFailure> = [
23
- {
24
- ...COMMON,
25
- expectation: 'tabs.tab.unavailable-pointer-inert',
26
- failureEquals:
27
- 'the tab is reported unavailable, but clicking it selected it',
28
- userImpact:
29
- 'A pointer user can activate a tab that assistive technology reports as unavailable.',
30
- },
31
- {
32
- ...COMMON,
33
- expectation: 'tabs.tab.unavailable-enter-inert',
34
- failureEquals: 'the tab is reported unavailable, but Enter selected it',
35
- userImpact:
36
- 'A keyboard user can activate a focusable tab with Enter after assistive technology reports it unavailable.',
37
- },
38
- {
39
- ...COMMON,
40
- expectation: 'tabs.tab.unavailable-space-inert',
41
- failureEquals: 'the tab is reported unavailable, but Space selected it',
42
- userImpact:
43
- 'A keyboard user can activate a focusable tab with Space after assistive technology reports it unavailable.',
44
- },
45
- ];
12
+ export const TABS_KNOWN_FAILURES: ReadonlyArray<KnownFailure> = [];
@@ -12,7 +12,7 @@ const anatomy = [
12
12
  name: 'Scroll region',
13
13
  required: true,
14
14
  description:
15
- 'Keyboard-focusable outer region that scrolls horizontally when the columns overflow.',
15
+ 'Outer region that scrolls horizontally, enters the keyboard order, and contains overscroll only while the columns overflow.',
16
16
  },
17
17
  {
18
18
  name: 'Header section',