@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
@@ -20,9 +20,9 @@ export const docs = {
20
20
  {
21
21
  name: 'icon',
22
22
  type: 'ReactNode',
23
- description: 'Icon element rendered inside the button.',
23
+ description: 'Icon element rendered inside the button. An Astryx Icon with no explicit size defaults to sm for sm/md buttons and md for lg buttons.',
24
24
  required: true,
25
- slotElements: [{__element: 'Icon', props: {icon: 'check', size: 'sm'}}],
25
+ slotElements: [{__element: 'Icon', props: {icon: 'check'}}],
26
26
  },
27
27
  {
28
28
  name: 'variant',
@@ -137,7 +137,7 @@ export const docsDense = {
137
137
  },
138
138
  propDescriptions: {
139
139
  label: 'accessible label; used as aria-label, not rendered as visible text',
140
- icon: 'icon element rendered inside button',
140
+ icon: 'icon element rendered inside button; unsized Astryx Icon defaults to sm for sm/md buttons and md for lg',
141
141
  variant: 'visual style variant',
142
142
  size: 'size variant',
143
143
  elevation: 'resting shadow depth: none|low|med|high; raise for a floating action button (FAB)',
@@ -12,6 +12,7 @@
12
12
  import {describe, it, expect, vi} from 'vitest';
13
13
  import {render, screen} from '@testing-library/react';
14
14
  import userEvent from '@testing-library/user-event';
15
+ import {Icon} from '../Icon/Icon';
15
16
  import {IconButton} from './IconButton';
16
17
 
17
18
  describe('IconButton', () => {
@@ -52,6 +53,45 @@ describe('IconButton', () => {
52
53
  expect(screen.getByRole('button', {name: 'Add'})).toBeInTheDocument();
53
54
  });
54
55
 
56
+ it.each([
57
+ ['sm', 'sm', '1rem'],
58
+ ['md', 'sm', '1rem'],
59
+ ['lg', 'md', '1.25rem'],
60
+ ] as const)(
61
+ 'renders the %s button wrapper and inherited Icon at the same size',
62
+ (buttonSize, iconSize, renderedSize) => {
63
+ render(
64
+ <IconButton
65
+ label="Add"
66
+ icon={<Icon icon="check" data-testid="icon" />}
67
+ size={buttonSize}
68
+ />,
69
+ );
70
+
71
+ const icon = screen.getByTestId('icon');
72
+ const wrapper = icon.parentElement;
73
+ expect(wrapper).not.toBeNull();
74
+
75
+ expect(icon).toHaveAttribute('data-size', iconSize);
76
+ expect(getComputedStyle(icon).width).toBe(renderedSize);
77
+ expect(getComputedStyle(icon).height).toBe(renderedSize);
78
+ expect(getComputedStyle(wrapper!).width).toBe(renderedSize);
79
+ expect(getComputedStyle(wrapper!).height).toBe(renderedSize);
80
+ },
81
+ );
82
+
83
+ it('preserves an explicit Astryx Icon size', () => {
84
+ render(
85
+ <IconButton
86
+ label="Add"
87
+ icon={<Icon icon="check" size="lg" data-testid="icon" />}
88
+ size="sm"
89
+ />,
90
+ );
91
+
92
+ expect(screen.getByTestId('icon')).toHaveAttribute('data-size', 'lg');
93
+ });
94
+
55
95
  it('handles click events', async () => {
56
96
  const user = userEvent.setup();
57
97
  const handleClick = vi.fn();
@@ -22,6 +22,10 @@ export const docs = {
22
22
  vars: [
23
23
  {name: '--_item-label-color', description: 'Color of the label line. Unset by default (the label uses the primary text token); a parent sets it to recolor the label it renders, as the destructive dropdown/context menu item does.', default: 'var(--color-text-primary)', private: true},
24
24
  {name: '--_item-description-color', description: 'Companion to --_item-label-color for the secondary description line.', default: 'var(--color-text-secondary)', private: true},
25
+ {name: '--_item-inset-inline', description: 'Inline inset of the row. Item derives its paddingInline from this variable, and List reads it to cancel the inset when edgeCompensation="inline". Set paddingInline on `item` in a theme and both stay in sync.', default: 'var(--spacing-2) (var(--spacing-3) for density="spacious")', private: true},
26
+ ],
27
+ derived: [
28
+ {property: 'paddingInline', vars: ['--_item-inset-inline']},
25
29
  ],
26
30
  },
27
31
  components: [
@@ -43,7 +47,7 @@ export const docs = {
43
47
  {name: 'layout', type: "'stacked' | 'inline'", description: 'How the label and description sit together. stacked puts the description on its own line below the label; inline keeps both on one line, description ellipsizing first, so the row fits a fixed-height host.', default: "'stacked'"},
44
48
  {name: 'onClick', type: '(event: MouseEvent) => void', description: 'Click handler. Makes the item clickable with button semantics.'},
45
49
  {name: 'interactiveRef', type: 'RefObject<HTMLElement | null>', description: 'Ref to a nested control (e.g. a checkbox in startContent) that owns the item\'s keyboard access and action. The row becomes an enlarged click/tap target that delegates surface clicks to it (useClickableContainer) and renders no invisible button/anchor, so the row adds no second tab stop (WCAG 4.1.2). Mutually exclusive with onClick/href; those are ignored when set.'},
46
- {name: 'href', type: 'string', description: 'Link URL. Makes the item a link via an invisible anchor element.'},
50
+ {name: 'href', type: 'string', description: 'Link URL. Makes the item a link via an invisible anchor element. The destination follows the shared navigation rule described on the Link `href` prop.'},
47
51
  {name: 'target', type: "'_blank' | '_self'", description: 'Link target. Only used with href. target="_blank" automatically adds noopener noreferrer.'},
48
52
  {name: 'rel', type: 'string', description: 'Link relationship tokens. noopener noreferrer are merged automatically for target="_blank".'},
49
53
  {name: 'isHighlighted', type: 'boolean', description: 'Highlighted state (hover/keyboard focus appearance).', default: 'false'},
@@ -167,7 +171,7 @@ export const docsDense = {
167
171
  onClick: 'Click handler; enables button semantics.',
168
172
  interactiveRef:
169
173
  'Ref to a nested control that owns the item\'s keyboard access/action; row delegates surface clicks to it (useClickableContainer), no invisible button/anchor, no second tab stop (WCAG 4.1.2). Mutually exclusive with onClick/href.',
170
- href: 'Link URL; enables anchor semantics.',
174
+ href: 'Link URL; enables anchor semantics. Follows the shared navigation rule (see Link href).',
171
175
  target:
172
176
  'Link target, only with href. target="_blank" auto-adds noopener noreferrer.',
173
177
  rel: 'Link relationship tokens. noopener noreferrer are merged for target="_blank".',
package/src/Item/Item.tsx CHANGED
@@ -5,7 +5,7 @@
5
5
  /**
6
6
  * @file Item.tsx
7
7
  * @input Uses React, ReactNode, StyleXStyles, theme tokens, useClickableContainer
8
- * @output Exports Item component, ItemProps type
8
+ * @output Exports Item component, ItemProps type; publishes the shared inline inset
9
9
  * @position Core layout primitive; consumed by index.ts, tested by Item.test.tsx
10
10
  *
11
11
  * SYNC: When modified, update these files to stay in sync:
@@ -209,7 +209,13 @@ const styles = stylex.create({
209
209
  display: 'flex',
210
210
  alignItems: 'center',
211
211
  gap: spacingVars['--spacing-2'],
212
- paddingInline: spacingVars['--spacing-2'],
212
+ // The inline inset is published as --_item-inset-inline and the padding
213
+ // derives from it, so consumers that need to compensate for the inset
214
+ // (List's edgeCompensation) read the var instead of mirroring the values.
215
+ // Themes that set paddingInline on `item` also feed this var via the
216
+ // derived var registry, keeping padding and compensation in sync.
217
+ '--_item-inset-inline': spacingVars['--spacing-2'],
218
+ paddingInline: 'var(--_item-inset-inline)',
213
219
  position: 'relative',
214
220
  boxSizing: 'border-box',
215
221
  textAlign: 'start',
@@ -356,7 +362,7 @@ const densityStyles = stylex.create({
356
362
  },
357
363
  spacious: {
358
364
  paddingBlock: spacingVars['--spacing-3'],
359
- paddingInline: spacingVars['--spacing-3'],
365
+ '--_item-inset-inline': spacingVars['--spacing-3'],
360
366
  },
361
367
  });
362
368
 
@@ -27,7 +27,7 @@ export const docs = {
27
27
  name: 'keys',
28
28
  type: 'string',
29
29
  description:
30
- 'Keyboard shortcut string. Use "+" to separate keys. Special keys: mod (Cmd on Mac), ctrl, alt, shift, enter, backspace, escape, tab, up, down, left, right.',
30
+ 'Keyboard shortcut string. Use "+" to separate keys. Special keys: mod (Cmd on Mac), ctrl, alt, shift, enter, backspace, escape, tab, up, down, left, right, plus. Aliases: esc for escape and return for enter.',
31
31
  required: true,
32
32
  },
33
33
  {
@@ -72,7 +72,7 @@ export const docsZh = {
72
72
  name: 'keys',
73
73
  type: 'string',
74
74
  description:
75
- '键盘快捷键字符串。使用 "+" 分隔各按键。特殊按键:mod(Mac 上为 Cmd)、ctrl、alt、shift、enter、backspace、escape、tab、up、down、left、right。',
75
+ '键盘快捷键字符串。使用 "+" 分隔各按键。特殊按键:mod(Mac 上为 Cmd)、ctrl、alt、shift、enter、backspace、escape、tab、up、down、left、right、plus。别名:esc 等同于 escape,return 等同于 enter。',
76
76
  required: true,
77
77
  },
78
78
  {
@@ -122,7 +122,7 @@ export const docsDense = {
122
122
  ],
123
123
  },
124
124
  propDescriptions: {
125
- keys: 'Shortcut string. "+" separates keys. Special: mod (Cmd on Mac), ctrl, alt, shift, enter, backspace, escape, tab, up, down, left, right.',
125
+ keys: 'Shortcut string. "+" separates keys. Special: mod (Cmd on Mac), ctrl, alt, shift, enter, backspace, escape, tab, up, down, left, right, plus. Aliases: esc for escape, return for enter.',
126
126
  xstyle: 'StyleX styles for layout customization. Must be stylex.create() value.',
127
127
  className: 'CSS class for root element. Prefer xstyle; className for non-StyleX integration.',
128
128
  style: 'Inline styles for root element. Prefer xstyle; inline styles bypass StyleX optimization.',
@@ -10,13 +10,14 @@
10
10
  */
11
11
 
12
12
  import {render, screen} from '@testing-library/react';
13
- import {describe, it, expect, afterEach} from 'vitest';
13
+ import {describe, it, expect, afterEach, vi} from 'vitest';
14
14
  import {Kbd} from './Kbd';
15
15
 
16
16
  describe('Kbd', () => {
17
17
  const originalPlatform = navigator.platform;
18
18
 
19
19
  afterEach(() => {
20
+ vi.restoreAllMocks();
20
21
  // Restore platform after any test that spoofs it \u2014 ensures no
21
22
  // test pollution even if an assertion fails mid-test.
22
23
  Object.defineProperty(navigator, 'platform', {
@@ -72,6 +73,61 @@ describe('Kbd', () => {
72
73
  expect(screen.getByText('Esc')).toBeInTheDocument();
73
74
  });
74
75
 
76
+ it.each([
77
+ {alias: 'esc', display: 'Esc', label: 'Escape'},
78
+ {alias: 'return', display: '\u21B5', label: 'Enter'},
79
+ ])('normalizes the $alias key alias', ({alias, display, label}) => {
80
+ render(<Kbd keys={alias} />);
81
+ expect(screen.getByText(display)).toBeInTheDocument();
82
+ expect(screen.getByRole('img')).toHaveAttribute('aria-label', label);
83
+ });
84
+
85
+ it.each([
86
+ {alias: 'esc', canonical: 'escape'},
87
+ {alias: 'return', canonical: 'enter'},
88
+ ])('$alias renders identically to $canonical', ({alias, canonical}) => {
89
+ const {container, rerender} = render(<Kbd keys={canonical} />);
90
+ const text = container.textContent;
91
+ const label = screen.getByRole('img').getAttribute('aria-label');
92
+ rerender(<Kbd keys={alias} />);
93
+ expect(container.textContent).toBe(text);
94
+ expect(screen.getByRole('img').getAttribute('aria-label')).toBe(label);
95
+ });
96
+
97
+ it.each([
98
+ {keys: 'ctrl + ESC', display: 'Esc', label: 'Control + Escape'},
99
+ {keys: 'shift + RETURN', display: '\u21B5', label: 'Shift + Enter'},
100
+ ])('normalizes aliases inside the $keys combo', ({keys, display, label}) => {
101
+ render(<Kbd keys={keys} />);
102
+ expect(screen.getByText(display)).toBeInTheDocument();
103
+ expect(screen.getByRole('img')).toHaveAttribute('aria-label', label);
104
+ });
105
+
106
+ it('keeps child keys unique after alias normalization', () => {
107
+ const consoleError = vi
108
+ .spyOn(console, 'error')
109
+ .mockImplementation(() => {});
110
+ const {container} = render(
111
+ <Kbd keys="escape+esc+ESC+enter+return+return" />,
112
+ );
113
+ expect(consoleError).not.toHaveBeenCalled();
114
+ expect(
115
+ Array.from(container.querySelectorAll('kbd'), key => key.textContent),
116
+ ).toEqual(['Esc', 'Esc', 'Esc', '↵', '↵', '↵']);
117
+ });
118
+
119
+ it.each(['constructor', '__proto__'])(
120
+ 'renders the unknown %s key without consulting object prototypes',
121
+ key => {
122
+ render(<Kbd keys={key} />);
123
+ expect(screen.getByText(key.toUpperCase())).toBeInTheDocument();
124
+ expect(screen.getByRole('img')).toHaveAttribute(
125
+ 'aria-label',
126
+ key.toUpperCase(),
127
+ );
128
+ },
129
+ );
130
+
75
131
  it('exposes a spoken accessible name and hides the glyphs (obs-1)', () => {
76
132
  render(<Kbd keys="mod+shift+k" />);
77
133
  // The wrapper carries a screen-reader name built from spoken key labels
package/src/Kbd/Kbd.tsx CHANGED
@@ -4,8 +4,8 @@
4
4
 
5
5
  /**
6
6
  * @file Kbd.tsx
7
- * @input Uses React, StyleX, theme tokens
8
- * @output Exports Kbd component and KbdProps
7
+ * @input Uses React, StyleX, theme tokens, shortcut key names and aliases
8
+ * @output Exports Kbd component and KbdProps with canonical shortcut labels
9
9
  * @position Core implementation; renders styled keyboard shortcut indicators
10
10
  *
11
11
  * SYNC: When modified, update:
@@ -61,20 +61,25 @@ const styles = stylex.create({
61
61
  * Note: `mod` is not in this map — it resolves dynamically via platform
62
62
  * detection inside the component.
63
63
  */
64
- const KEY_DISPLAY: Record<string, string> = {
65
- ctrl: '\u2303', // ⌃
66
- alt: '\u2325', // ⌥
67
- shift: '\u21E7', // ⇧
68
- enter: '\u21B5', // ↵
69
- backspace: '\u232B', // ⌫
70
- escape: 'Esc',
71
- tab: '\u21E5', // ⇥
72
- up: '\u2191',
73
- down: '\u2193',
74
- left: '\u2190',
75
- right: '\u2192',
76
- plus: '+',
77
- };
64
+ const KEY_DISPLAY = new Map<string, string>([
65
+ ['ctrl', '\u2303'], // ⌃
66
+ ['alt', '\u2325'], // ⌥
67
+ ['shift', '\u21E7'], // ⇧
68
+ ['enter', '\u21B5'], // ↵
69
+ ['backspace', '\u232B'], // ⌫
70
+ ['escape', 'Esc'],
71
+ ['tab', '\u21E5'], // ⇥
72
+ ['up', '\u2191'],
73
+ ['down', '\u2193'],
74
+ ['left', '\u2190'],
75
+ ['right', '\u2192'],
76
+ ['plus', '+'],
77
+ ]);
78
+
79
+ const KBD_KEY_ALIASES = new Map<string, string>([
80
+ ['esc', 'escape'],
81
+ ['return', 'enter'],
82
+ ]);
78
83
 
79
84
  /**
80
85
  * Resolves a key name to its display string. Handles the platform-aware
@@ -85,7 +90,7 @@ function getKeyDisplay(key: string, isMac: boolean): string {
85
90
  if (key === 'mod') {
86
91
  return isMac ? '\u2318' : 'Ctrl';
87
92
  }
88
- return KEY_DISPLAY[key] ?? key.toUpperCase();
93
+ return KEY_DISPLAY.get(key) ?? key.toUpperCase();
89
94
  }
90
95
 
91
96
  /**
@@ -93,26 +98,26 @@ function getKeyDisplay(key: string, isMac: boolean): string {
93
98
  * (⌘, ⇧, ↵, …) that assistive tech cannot announce meaningfully, so the
94
99
  * accessible name for the shortcut is built from these words instead.
95
100
  */
96
- const KEY_LABEL: Record<string, string> = {
97
- ctrl: 'Control',
98
- alt: 'Alt',
99
- shift: 'Shift',
100
- enter: 'Enter',
101
- backspace: 'Backspace',
102
- escape: 'Escape',
103
- tab: 'Tab',
104
- up: 'Up arrow',
105
- down: 'Down arrow',
106
- left: 'Left arrow',
107
- right: 'Right arrow',
108
- plus: 'Plus',
109
- };
101
+ const KEY_LABEL = new Map<string, string>([
102
+ ['ctrl', 'Control'],
103
+ ['alt', 'Alt'],
104
+ ['shift', 'Shift'],
105
+ ['enter', 'Enter'],
106
+ ['backspace', 'Backspace'],
107
+ ['escape', 'Escape'],
108
+ ['tab', 'Tab'],
109
+ ['up', 'Up arrow'],
110
+ ['down', 'Down arrow'],
111
+ ['left', 'Left arrow'],
112
+ ['right', 'Right arrow'],
113
+ ['plus', 'Plus'],
114
+ ]);
110
115
 
111
116
  function getKeyLabel(key: string, isMac: boolean): string {
112
117
  if (key === 'mod') {
113
118
  return isMac ? 'Command' : 'Control';
114
119
  }
115
- return KEY_LABEL[key] ?? key.toUpperCase();
120
+ return KEY_LABEL.get(key) ?? key.toUpperCase();
116
121
  }
117
122
 
118
123
  function subscribeToPlatformChanges(): () => void {
@@ -127,7 +132,9 @@ export interface KbdProps extends BaseProps<HTMLSpanElement> {
127
132
  ref?: React.Ref<HTMLSpanElement>;
128
133
  /**
129
134
  * Keyboard shortcut string. Use "+" to separate keys.
130
- * Special keys: mod (Cmd on Mac), ctrl, alt, shift, enter, backspace, escape.
135
+ * Special keys: mod (Cmd on Mac), ctrl, alt, shift, enter, backspace, escape,
136
+ * tab, up, down, left, and right.
137
+ * Aliases: "esc" for "escape" and "return" for "enter".
131
138
  * Use "plus" to render a literal "+" key (e.g. "shift+plus").
132
139
  *
133
140
  * @example
@@ -163,11 +170,24 @@ export function Kbd({keys, ref, xstyle, className, style, ...rest}: KbdProps) {
163
170
  getServerPlatformSnapshot,
164
171
  );
165
172
 
166
- const parts = keys.split('+').map(key => key.trim().toLowerCase());
173
+ const keyOccurrences = new Map<string, number>();
174
+ const parts = keys
175
+ .split('+')
176
+ .map(key => key.trim().toLowerCase())
177
+ .map(sourceKey => {
178
+ const occurrence = keyOccurrences.get(sourceKey) ?? 0;
179
+ keyOccurrences.set(sourceKey, occurrence + 1);
180
+ return {
181
+ key: KBD_KEY_ALIASES.get(sourceKey) ?? sourceKey,
182
+ reactKey: `${sourceKey}:${occurrence}`,
183
+ };
184
+ });
167
185
 
168
186
  // Screen-reader name: the joined spoken labels (e.g. "Command + K"), since
169
187
  // the visual glyphs below are announced meaninglessly by assistive tech.
170
- const accessibleName = parts.map(key => getKeyLabel(key, isMac)).join(' + ');
188
+ const accessibleName = parts
189
+ .map(({key}) => getKeyLabel(key, isMac))
190
+ .join(' + ');
171
191
 
172
192
  return (
173
193
  <span
@@ -181,8 +201,8 @@ export function Kbd({keys, ref, xstyle, className, style, ...rest}: KbdProps) {
181
201
  className,
182
202
  style,
183
203
  )}>
184
- {parts.map(key => (
185
- <kbd key={key} aria-hidden="true" {...stylex.props(styles.kbd)}>
204
+ {parts.map(({key, reactKey}) => (
205
+ <kbd key={reactKey} aria-hidden="true" {...stylex.props(styles.kbd)}>
186
206
  {getKeyDisplay(key, isMac)}
187
207
  </kbd>
188
208
  ))}
@@ -8,6 +8,23 @@ export const docs = {
8
8
  displayName: 'Layout Footer',
9
9
  isHiddenFromOverview: true,
10
10
  description: 'Bottom bar for action bars, pagination, and status bars.',
11
+ playground: {
12
+ defaults: {
13
+ children: 'Footer content: status bar or actions',
14
+ hasDivider: true,
15
+ },
16
+ wrapper: {
17
+ component: 'Layout',
18
+ slotProp: 'footer',
19
+ props: {
20
+ content: {
21
+ __element: 'LayoutContent',
22
+ props: {},
23
+ children: 'Main content area',
24
+ },
25
+ },
26
+ },
27
+ },
11
28
  props: [
12
29
  {
13
30
  name: 'children',
@@ -38,7 +38,8 @@ export const docs = {
38
38
  {
39
39
  name: 'href',
40
40
  type: 'string',
41
- description: 'Link destination URL',
41
+ description:
42
+ 'Link destination URL. Astryx-owned links and clickable surfaces block javascript:, vbscript:, and data:text/html after control-character removal, outer-whitespace trimming, and case-insensitive scheme inspection. The same rule covers native anchors, custom routers, Markdown links, and every activation method. Relative paths, fragments, protocol-relative URLs, HTTP(S), mailto, tel, safe custom schemes, and accepted downloads keep their existing behavior. A rejected destination renders inertly without invoking a custom router. There is no bypass prop; exceptional behavior requires caller-owned custom rendering outside this guarantee. Images and other resource URLs have separate policies.',
42
43
  },
43
44
  {
44
45
  name: 'hasUnderline',
@@ -151,7 +152,8 @@ export const docs = {
151
152
  {
152
153
  name: 'component',
153
154
  type: 'LinkComponentType',
154
- description: 'Component to use for all link elements',
155
+ description:
156
+ 'Component to use for all link elements. It receives accepted `href` and `to` values under the shared navigation rule described on the Link `href` prop. Supported structured destinations, including their `protocol`, are checked without changing object identity. If either supplied destination is rejected, Astryx renders inert content without invoking this component; it does not pass undefined or fall back to the other destination.',
155
157
  required: true,
156
158
  },
157
159
  {
@@ -164,6 +166,17 @@ export const docs = {
164
166
  },
165
167
  ],
166
168
  usage: {
169
+ accessibility: [
170
+ {
171
+ name: 'Link text',
172
+ category: 'Color contrast',
173
+ criterion: '1.4.3 Contrast (Minimum)',
174
+ requirement: '4.5:1',
175
+ states: ['Rest', 'Hover', 'Pointer down'],
176
+ description:
177
+ 'Link text must have at least 4.5:1 contrast with the background behind it. For Pointer down, measure against the pressed overlay the link paints behind its text.',
178
+ },
179
+ ],
167
180
  description:
168
181
  'A styled anchor for inline and standalone text navigation. Supports external links, underline variants, tooltips, and custom link components for router integration. Use it for navigating between pages or to external URLs.',
169
182
  bestPractices: [
@@ -344,7 +357,7 @@ export const docsDense = {
344
357
  propDescriptions: {
345
358
  as: 'Custom component to render instead of <a>',
346
359
  label: 'Accessible label (aria-label). Only for non-text content like icon-only links.',
347
- href: 'Link destination URL',
360
+ href: 'Link destination URL. Shared rule blocks javascript:, vbscript:, data:text/html after scheme normalization on every Astryx-owned navigation path. Ordinary URLs, fragments, safe custom schemes, and accepted downloads are preserved. Rejected => inert, no custom router. No bypass prop; exceptional caller-owned rendering is outside the guarantee. Image/resource policy is separate.',
348
361
  hasUnderline: 'Always show underline',
349
362
  isDisabled: 'Disables link',
350
363
  isExternalLink: 'Opens new tab w/ external icon and safe rel tokens',
@@ -365,7 +378,7 @@ export const docsDense = {
365
378
  description:
366
379
  'Provider setting default link component for all Astryx links in subtree.',
367
380
  propDescriptions: {
368
- component: 'Component for all link elements',
381
+ component: 'Component for all link elements. Accepted href/to follow the Link href rule; structured fields including protocol are checked, preserving identity. Either rejected => inert content, no router invocation or fallback.',
369
382
  children: 'Subtree',
370
383
  },
371
384
  },
@@ -12,6 +12,7 @@
12
12
  import {describe, it, expect, vi} from 'vitest';
13
13
  import {fireEvent, render, screen} from '@testing-library/react';
14
14
  import userEvent from '@testing-library/user-event';
15
+ import {hasPressedArm} from '../__tests__/pressState';
15
16
  import {Link} from './Link';
16
17
  import {LinkProvider} from './LinkProvider';
17
18
 
@@ -417,3 +418,26 @@ describe('Link', () => {
417
418
  expect(link).toHaveAttribute('data-color', 'secondary');
418
419
  });
419
420
  });
421
+
422
+ describe('pressed state', () => {
423
+ it('paints the pressed overlay behind a link while it is pressed', () => {
424
+ render(<Link href="/docs">Docs</Link>);
425
+ expect(hasPressedArm(screen.getByRole('link', {name: 'Docs'}))).toBe(true);
426
+ });
427
+
428
+ it('paints it on the button form too', () => {
429
+ render(<Link onClick={() => {}}>Open</Link>);
430
+ expect(hasPressedArm(screen.getByRole('button', {name: 'Open'}))).toBe(
431
+ true,
432
+ );
433
+ });
434
+
435
+ it('does not press a disabled link', () => {
436
+ render(
437
+ <Link href="/docs" isDisabled>
438
+ Docs
439
+ </Link>,
440
+ );
441
+ expect(hasPressedArm(screen.getByText('Docs').closest('a')!)).toBe(false);
442
+ });
443
+ });
package/src/Link/Link.tsx CHANGED
@@ -45,6 +45,7 @@ import {computeTargetAndRel} from './computeTargetAndRel';
45
45
  import {useInteractiveRole} from '../hooks/useInteractiveRole';
46
46
  import {themeProps} from '../utils/themeProps';
47
47
  import {focusOutlineProps} from '../utils/focusOutline.stylex';
48
+ import {interactionOverlayStyles} from '../utils/interactionOverlay.stylex';
48
49
  import {useTranslator} from '../i18n';
49
50
 
50
51
  /**
@@ -368,6 +369,9 @@ export function Link({
368
369
  styles.base,
369
370
  styles.buttonReset,
370
371
  linkColorStyles[color],
372
+ // The system's pressed overlay behind the text; the hover stays the
373
+ // colour change above, so a press is the one background it paints.
374
+ !isDisabled && interactionOverlayStyles.pressedBackgroundColor,
371
375
  hasUnderline && styles.hasUnderline,
372
376
  isStandalone && styles.standalone,
373
377
  isDisabled && styles.disabled,
@@ -427,6 +431,7 @@ export function Link({
427
431
  focusOutlineProps.focusVisible(
428
432
  styles.base,
429
433
  linkColorStyles[color],
434
+ !isDisabled && interactionOverlayStyles.pressedBackgroundColor,
430
435
  hasUnderline && styles.hasUnderline,
431
436
  isStandalone && styles.standalone,
432
437
  isDisabled && styles.disabled,
@@ -13,7 +13,7 @@ export const docs = {
13
13
  description: 'Wraps your app to replace the default <a> tag with a framework-specific link component (e.g. Next.js Link) for client-side routing across all Astryx components.',
14
14
  },
15
15
  props: [
16
- {name: 'component', type: 'LinkComponentType', required: true, description: 'Link component to use for all link elements in the subtree (e.g. Next.js Link).'},
16
+ {name: 'component', type: 'LinkComponentType', required: true, description: 'Link component to use for all link elements in the subtree (e.g. Next.js Link). It receives accepted `href` and `to` values under the shared navigation rule described on the Link `href` prop. Supported structured destinations, including their `protocol`, are checked without changing object identity. If either supplied destination is rejected, Astryx renders inert content without invoking this component; it does not pass undefined or fall back to the other destination.'},
17
17
  {name: 'children', type: 'ReactNode', required: true, description: 'Content to render with the link provider.'},
18
18
  ],
19
19
  };
@@ -25,6 +25,6 @@ export const docsDense = {
25
25
  description: 'Wraps app to replace default <a> tag w/ framework-specific link component (e.g. Next.js Link) for client-side routing across all Astryx components.',
26
26
  },
27
27
  propDescriptions: {
28
- component: 'link component for all link elements in subtree (e.g. Next.js Link)',
28
+ component: 'link component for all link elements in subtree (e.g. Next.js Link). Accepted href/to follow the Link href rule; structured fields including protocol are checked, preserving identity. Either rejected => inert content, no router invocation or fallback.',
29
29
  },
30
30
  };