@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
@@ -4,7 +4,7 @@
4
4
 
5
5
  /**
6
6
  * @file ListItem.tsx
7
- * @input Uses React, ReactNode, StyleXStyles, theme tokens
7
+ * @input Uses React, ReactNode, StyleXStyles, theme tokens, List edge compensation
8
8
  * @output Exports ListItem component, ListItemProps type
9
9
  * @position Core implementation; consumed by List, index.ts, tested by List.test.tsx
10
10
  *
@@ -124,12 +124,34 @@ const styles = stylex.create({
124
124
  withCounter: {
125
125
  counterIncrement: 'astryx-list',
126
126
  },
127
+ // List's inline edge compensation cancels as much of the row's built-in
128
+ // inline inset as the container padding allows (e.g. under a heading).
129
+ // The margins read --_item-inset-inline — the same variable Item derives
130
+ // its paddingInline from — on the row element itself (custom properties
131
+ // only cascade downward, so the <ul> could not read it). Density changes
132
+ // and theme paddingInline overrides on `item` move both values together.
133
+ // Each edge clamps against ITS OWN container padding var: a single
134
+ // start-var clamp on both margins over-cancels the end edge under
135
+ // asymmetric container padding (16px start / 4px end) and the selected
136
+ // row paints past the outer border. Logical properties keep RTL correct,
137
+ // and a zero-padding/full-bleed surface (min(inset, 0px) = 0px) leaves
138
+ // the row in place instead of pulling it outside its content edge.
139
+ inlineEdgeCompensation: {
140
+ marginInlineStart:
141
+ 'calc(-1 * min(var(--_item-inset-inline), var(--container-padding-inline-start, 0px)))',
142
+ marginInlineEnd:
143
+ 'calc(-1 * min(var(--_item-inset-inline), var(--container-padding-inline-end, 0px)))',
144
+ },
127
145
  withDivider: {
128
146
  borderBlockEndWidth: borderVars['--border-width'],
129
147
  borderBlockEndStyle: 'solid',
130
148
  borderBlockEndColor: colorVars['--color-border'],
149
+ // A longhand, not the `borderBlockEnd` shorthand: StyleX's default
150
+ // property-specificity mode drops border shorthands silently, so the
151
+ // shorthand never reached the shipped CSS and the last item kept its
152
+ // divider.
131
153
  ':last-child': {
132
- borderBlockEnd: 'none',
154
+ borderBlockEndWidth: 0,
133
155
  },
134
156
  },
135
157
  });
@@ -226,6 +248,7 @@ export function ListItem({
226
248
  const density = ctx?.density ?? 'balanced';
227
249
  const hasDividers = ctx?.hasDividers ?? false;
228
250
  const listStyle = ctx?.listStyle ?? 'none';
251
+ const edgeCompensation = ctx?.edgeCompensation;
229
252
  const hasMarkers = listStyle !== 'none';
230
253
 
231
254
  const marker =
@@ -262,6 +285,7 @@ export function ListItem({
262
285
  hasMarkers && styles.withCounter,
263
286
  hasDividers && styles.withDivider,
264
287
  hasDividers && embeddedStyles.noRadius,
288
+ edgeCompensation === 'inline' && styles.inlineEdgeCompensation,
265
289
  xstyle,
266
290
  ]}
267
291
  {...mergeProps(themeProps('list-item'), {className, style})}
@@ -112,7 +112,7 @@ export const docs = {
112
112
  name: 'onLinkClick',
113
113
  type: '(href: string, event: MouseEvent) => void | false',
114
114
  description:
115
- 'Handler for link clicks. Return false to prevent the default navigation behavior.',
115
+ 'Handler for link clicks. Return false to prevent the default navigation behavior. Link destinations in the markdown follow the shared navigation rule described on the Link `href` prop: a blocked destination renders as plain text and never reaches this handler or a custom link renderer. Image URLs use a separate, stricter policy (every data: URL is rejected).',
116
116
  },
117
117
  {
118
118
  name: 'sources',
@@ -141,6 +141,12 @@ export const docs = {
141
141
  'Alignment of prose content within the container when contentWidth is narrower than the available space.',
142
142
  default: "'start'",
143
143
  },
144
+ {
145
+ name: 'plugins',
146
+ type: 'readonly MarkdownPluginEntry[]',
147
+ description:
148
+ 'Ordered extensions created by createMarkdownPlugin(). Plugins may add bounded syntax, immutable typed AST transforms, and typed extension renderers. Use isMarkdownExtensionNode() to narrow extension data observed from other plugins. Renderer callbacks are pure; return a child component when hooks are needed. Omitted and empty lists preserve the released Markdown behavior.',
149
+ },
144
150
  {
145
151
  name: 'inlinePlugins',
146
152
  type: 'MarkdownInlinePlugin[]',
@@ -241,6 +247,46 @@ export const docs = {
241
247
  description:
242
248
  'Use contentWidth to keep prose at a readable line length in wide layouts.',
243
249
  },
250
+ {
251
+ guidance: true,
252
+ description:
253
+ 'Use plugins created by createMarkdownPlugin for reusable syntax, immutable AST transforms, and typed extension rendering. Keep the ordered list stable while its syntax configuration is unchanged.',
254
+ },
255
+ {
256
+ guidance: true,
257
+ description:
258
+ 'Add markdownSoftBreaksPlugin when single line endings are meaningful. It matches remark-breaks for supported Markdown, including multiline link labels, while code and other opaque content stay unchanged.',
259
+ },
260
+ {
261
+ guidance: true,
262
+ description:
263
+ 'Use createMarkdownTextTransform for prose matching; it preserves code, links, images, citations, math, and accepted extension syntax as protected contexts. Provide requiredSubstrings only when they conservatively cover every possible match.',
264
+ },
265
+ {
266
+ guidance: true,
267
+ description:
268
+ 'Use createMarkdownFenceTransform for declared code-fence languages with semantic data. createNode returns an owned block extension node; its standard plugin renderer and toText own presentation. components.code still wins, and a declined or failed proposal keeps the accessible, copyable CodeBlock fallback.',
269
+ },
270
+ {
271
+ guidance: true,
272
+ description:
273
+ 'Use createMarkdownSourceDecoration to attach non-visual metadata — search hits, review annotations — to the blocks a source range touches, and getMarkdownSourceDecorations to read it back in a later plugin. Decorations appear on the settled document rather than on partial streaming chunks, and never change rendering, copyable text, accessible names, ids, focus order, or navigation.',
274
+ },
275
+ {
276
+ guidance: true,
277
+ description:
278
+ 'Import parseMarkdownAst or parseInlineAst from @astryxdesign/core/Markdown/parser when server or React Server Component code needs to run plugins against the canonical readonly tree. The parser and plugin subpaths have no use-client boundary. The Markdown component remains client-owned, so function-bearing plugin entries must not be passed across an RSC serialization boundary.',
279
+ },
280
+ {
281
+ guidance: true,
282
+ description:
283
+ 'Use createMarkdownFrontmatter for typed document metadata. Its parse() method gives the host metadata directly; its plugin removes a complete leading block before rendering and withholds an unfinished block during streaming.',
284
+ },
285
+ {
286
+ guidance: true,
287
+ description:
288
+ "Import createMarkdownRemarkTransform from '@astryxdesign/core/Markdown/remark' only to reuse an existing synchronous transform-only Remark plugin; it stays out of every other bundle. Prove each plugin with fixtures: anything outside the supported MDAST subset — async work, parser or compiler plugins, processor state, raw HTML, unsupported nodes, forged positions, or metadata Astryx cannot represent — keeps the last valid document and reports one diagnostic.",
289
+ },
244
290
  {
245
291
  guidance: true,
246
292
  description:
@@ -288,6 +334,170 @@ import {Text} from '@astryxdesign/core/Text';
288
334
  {'Visit https://example.com or email contact@example.com. ' +
289
335
  'You can also bracket links: <https://docs.example.com>.'}
290
336
  </Markdown>;
337
+ `,
338
+ },
339
+ {
340
+ label: 'First-party soft breaks',
341
+ code: `
342
+ import {Markdown} from '@astryxdesign/core/Markdown';
343
+ import {markdownSoftBreaksPlugin} from '@astryxdesign/core/Markdown/plugins';
344
+
345
+ <Markdown plugins={[markdownSoftBreaksPlugin]}>
346
+ {'First line\\nSecond line'}
347
+ </Markdown>;
348
+ `,
349
+ },
350
+ {
351
+ label: 'Text transform helper',
352
+ code: `
353
+ import {Markdown} from '@astryxdesign/core/Markdown';
354
+ import {
355
+ createMarkdownPlugin,
356
+ createMarkdownTextTransform,
357
+ } from '@astryxdesign/core/Markdown/plugins';
358
+
359
+ const finalLabels = createMarkdownPlugin({
360
+ name: 'final-labels',
361
+ apiVersion: 1,
362
+ transform: createMarkdownTextTransform({
363
+ pattern: /\\bDraft\\b/g,
364
+ requiredSubstrings: ['Draft'],
365
+ replace: () => ({type: 'text', value: 'Final'}),
366
+ }),
367
+ });
368
+
369
+ <Markdown plugins={[finalLabels]}># Draft</Markdown>;
370
+ `,
371
+ },
372
+ {
373
+ label: 'Semantic fence helper',
374
+ code: `
375
+ import {Markdown} from '@astryxdesign/core/Markdown';
376
+ import {
377
+ createMarkdownFenceTransform,
378
+ createMarkdownPlugin,
379
+ type MarkdownExtensionNode,
380
+ } from '@astryxdesign/core/Markdown/plugins';
381
+
382
+ type DiagramNode = MarkdownExtensionNode<
383
+ 'diagrams',
384
+ 'diagram',
385
+ {readonly code: string; readonly label?: string},
386
+ 'block'
387
+ >;
388
+
389
+ const diagrams = createMarkdownPlugin<'diagrams', DiagramNode>({
390
+ name: 'diagrams',
391
+ apiVersion: 1,
392
+ transform: createMarkdownFenceTransform({
393
+ languages: ['mermaid'],
394
+ createNode: ({code, meta}) => ({
395
+ type: 'extension',
396
+ plugin: 'diagrams',
397
+ name: 'diagram',
398
+ display: 'block',
399
+ data: {code, ...(meta == null ? {} : {label: meta})},
400
+ }),
401
+ }),
402
+ renderers: {
403
+ diagram: {
404
+ render: ({node}) => (
405
+ <Diagram source={node.data.code} label={node.data.label} />
406
+ ),
407
+ toText: node => node.data.code,
408
+ },
409
+ },
410
+ });
411
+
412
+ <Markdown plugins={[diagrams]}>
413
+ {'\`\`\`mermaid Checkout flow\\ngraph LR; A-->B\\n\`\`\`'}
414
+ </Markdown>;
415
+ `,
416
+ },
417
+ {
418
+ label: 'Source decoration helper',
419
+ code: `
420
+ import {Markdown} from '@astryxdesign/core/Markdown';
421
+ import {
422
+ createMarkdownPlugin,
423
+ createMarkdownSourceDecoration,
424
+ getMarkdownSourceDecorations,
425
+ } from '@astryxdesign/core/Markdown/plugins';
426
+
427
+ // Ranges are UTF-16 offsets into the same string Markdown renders. Every
428
+ // block a range touches is annotated; rendering, copyable text, and ids
429
+ // never change.
430
+ const searchHits = createMarkdownPlugin({
431
+ name: 'search-hits',
432
+ apiVersion: 1,
433
+ transform: createMarkdownSourceDecoration({
434
+ name: 'search-hit',
435
+ ranges: [{start: 0, end: 15, data: {query: 'release'}}],
436
+ }),
437
+ });
438
+
439
+ const readDecorations = createMarkdownPlugin({
440
+ name: 'read-decorations',
441
+ apiVersion: 1,
442
+ transform: root => {
443
+ report(root.children.map(getMarkdownSourceDecorations));
444
+ return root;
445
+ },
446
+ });
447
+
448
+ <Markdown plugins={[searchHits, readDecorations]}>{source}</Markdown>;
449
+ `,
450
+ },
451
+ {
452
+ label: 'Native frontmatter',
453
+ code: `
454
+ import {Markdown} from '@astryxdesign/core/Markdown';
455
+ import {createMarkdownFrontmatter} from '@astryxdesign/core/Markdown/plugins';
456
+
457
+ const frontmatter = createMarkdownFrontmatter({
458
+ name: 'document-metadata',
459
+ parse: fields => ({
460
+ title: fields.title ?? 'Untitled',
461
+ draft: fields.draft === 'true',
462
+ }),
463
+ });
464
+
465
+ const source = '---\\ntitle: Release notes\\ndraft: true\\n---\\n# Shipped';
466
+ const result = frontmatter.parse(source);
467
+
468
+ <Markdown plugins={[frontmatter.plugin]}>{source}</Markdown>;
469
+ `,
470
+ },
471
+ {
472
+ label: 'Compatible Remark plugin',
473
+ code: `
474
+ import {Markdown} from '@astryxdesign/core/Markdown';
475
+ import {createMarkdownPlugin} from '@astryxdesign/core/Markdown/plugins';
476
+ import {createMarkdownRemarkTransform} from '@astryxdesign/core/Markdown/remark';
477
+
478
+ // A synchronous transform-only Remark plugin in the usual attacher shape.
479
+ const remarkRename =
480
+ ({from, to}) =>
481
+ tree => {
482
+ const rename = node => {
483
+ if (node.type === 'text') {
484
+ node.value = node.value.split(from).join(to);
485
+ }
486
+ node.children?.forEach(rename);
487
+ };
488
+ rename(tree);
489
+ };
490
+
491
+ const productName = createMarkdownPlugin({
492
+ name: 'product-name',
493
+ apiVersion: 1,
494
+ transform: createMarkdownRemarkTransform(remarkRename, {
495
+ from: 'Astryx',
496
+ to: 'Astryx Design',
497
+ }),
498
+ });
499
+
500
+ <Markdown plugins={[productName]}># Astryx release notes</Markdown>;
291
501
  `,
292
502
  },
293
503
  {
@@ -397,6 +607,12 @@ export const docsZh = {
397
607
  '当 contentWidth 小于可用空间时,正文内容在容器内的对齐方式。',
398
608
  default: "'start'",
399
609
  },
610
+ {
611
+ name: 'plugins',
612
+ type: 'readonly MarkdownPluginEntry[]',
613
+ description:
614
+ '由 createMarkdownPlugin() 创建的有序扩展。插件可添加有界语法、不可变的类型化 AST 转换和类型化扩展渲染器。使用 isMarkdownExtensionNode() 缩小从其他插件观察到的扩展数据类型。渲染回调必须是纯函数;需要 Hook 时请返回子组件。省略或传入空列表时保持已发布的 Markdown 行为。',
615
+ },
400
616
  {
401
617
  name: 'inlinePlugins',
402
618
  type: 'MarkdownInlinePlugin[]',
@@ -507,6 +723,46 @@ export const docsZh = {
507
723
  description:
508
724
  'Use contentWidth to keep prose at a readable line length in wide layouts.',
509
725
  },
726
+ {
727
+ guidance: true,
728
+ description:
729
+ 'Use plugins created by createMarkdownPlugin for reusable syntax, immutable AST transforms, and typed extension rendering. Keep the ordered list stable while its syntax configuration is unchanged.',
730
+ },
731
+ {
732
+ guidance: true,
733
+ description:
734
+ 'Add markdownSoftBreaksPlugin when single line endings are meaningful. It matches remark-breaks for supported Markdown, including multiline link labels, while code and other opaque content stay unchanged.',
735
+ },
736
+ {
737
+ guidance: true,
738
+ description:
739
+ 'Use createMarkdownTextTransform for prose matching; it preserves code, links, images, citations, math, and accepted extension syntax as protected contexts. Provide requiredSubstrings only when they conservatively cover every possible match.',
740
+ },
741
+ {
742
+ guidance: true,
743
+ description:
744
+ 'Use createMarkdownFenceTransform for declared code-fence languages with semantic data. createNode returns an owned block extension node; its standard plugin renderer and toText own presentation. components.code still wins, and a declined or failed proposal keeps the accessible, copyable CodeBlock fallback.',
745
+ },
746
+ {
747
+ guidance: true,
748
+ description:
749
+ 'Use createMarkdownSourceDecoration to attach non-visual metadata — search hits, review annotations — to the blocks a source range touches, and getMarkdownSourceDecorations to read it back in a later plugin. Decorations appear on the settled document rather than on partial streaming chunks, and never change rendering, copyable text, accessible names, ids, focus order, or navigation.',
750
+ },
751
+ {
752
+ guidance: true,
753
+ description:
754
+ 'Import parseMarkdownAst or parseInlineAst from @astryxdesign/core/Markdown/parser when server or React Server Component code needs to run plugins against the canonical readonly tree. The parser and plugin subpaths have no use-client boundary. The Markdown component remains client-owned, so function-bearing plugin entries must not be passed across an RSC serialization boundary.',
755
+ },
756
+ {
757
+ guidance: true,
758
+ description:
759
+ 'Use createMarkdownFrontmatter for typed document metadata. Its parse() method gives the host metadata directly; its plugin removes a complete leading block before rendering and withholds an unfinished block during streaming.',
760
+ },
761
+ {
762
+ guidance: true,
763
+ description:
764
+ "Import createMarkdownRemarkTransform from '@astryxdesign/core/Markdown/remark' only to reuse an existing synchronous transform-only Remark plugin; it stays out of every other bundle. Prove each plugin with fixtures: anything outside the supported MDAST subset — async work, parser or compiler plugins, processor state, raw HTML, unsupported nodes, forged positions, or metadata Astryx cannot represent — keeps the last valid document and reports one diagnostic.",
765
+ },
510
766
  {
511
767
  guidance: true,
512
768
  description:
@@ -554,6 +810,46 @@ export const docsDense = {
554
810
  description:
555
811
  'Use contentWidth to keep prose at a readable line length in wide layouts.',
556
812
  },
813
+ {
814
+ guidance: true,
815
+ description:
816
+ 'Use plugins created by createMarkdownPlugin for reusable syntax, immutable AST transforms, and typed extension rendering. Keep the ordered list stable while its syntax configuration is unchanged.',
817
+ },
818
+ {
819
+ guidance: true,
820
+ description:
821
+ 'Add markdownSoftBreaksPlugin when single line endings are meaningful. It matches remark-breaks for supported Markdown, including multiline link labels, while code and other opaque content stay unchanged.',
822
+ },
823
+ {
824
+ guidance: true,
825
+ description:
826
+ 'Use createMarkdownTextTransform for prose matching; it preserves code, links, images, citations, math, and accepted extension syntax as protected contexts. Provide requiredSubstrings only when they conservatively cover every possible match.',
827
+ },
828
+ {
829
+ guidance: true,
830
+ description:
831
+ 'Use createMarkdownFenceTransform for declared code-fence languages with semantic data. createNode returns an owned block extension node; its standard plugin renderer and toText own presentation. components.code still wins, and a declined or failed proposal keeps the accessible, copyable CodeBlock fallback.',
832
+ },
833
+ {
834
+ guidance: true,
835
+ description:
836
+ 'Use createMarkdownSourceDecoration to attach non-visual metadata — search hits, review annotations — to the blocks a source range touches, and getMarkdownSourceDecorations to read it back in a later plugin. Decorations appear on the settled document rather than on partial streaming chunks, and never change rendering, copyable text, accessible names, ids, focus order, or navigation.',
837
+ },
838
+ {
839
+ guidance: true,
840
+ description:
841
+ 'Import parseMarkdownAst or parseInlineAst from @astryxdesign/core/Markdown/parser when server or React Server Component code needs to run plugins against the canonical readonly tree. The parser and plugin subpaths have no use-client boundary. The Markdown component remains client-owned, so function-bearing plugin entries must not be passed across an RSC serialization boundary.',
842
+ },
843
+ {
844
+ guidance: true,
845
+ description:
846
+ 'Use createMarkdownFrontmatter for typed document metadata. Its parse() method gives the host metadata directly; its plugin removes a complete leading block before rendering and withholds an unfinished block during streaming.',
847
+ },
848
+ {
849
+ guidance: true,
850
+ description:
851
+ "Import createMarkdownRemarkTransform from '@astryxdesign/core/Markdown/remark' only to reuse a synchronous transform-only Remark plugin; it stays out of every other bundle and unsupported behavior keeps the last valid document with one diagnostic.",
852
+ },
557
853
  {
558
854
  guidance: true,
559
855
  description:
@@ -589,7 +885,7 @@ export const docsDense = {
589
885
  isStreaming:
590
886
  'Incremental parse + fade-in for streamed chunks. Default: false.',
591
887
  onLinkClick:
592
- '(href, event) => void|false. Return false prevents navigation.',
888
+ '(href, event) => void|false. Return false prevents navigation. Link destinations follow the shared navigation rule (see Link href); blocked ones render as text. Image URLs: separate stricter policy.',
593
889
  sources:
594
890
  'Record<string, MarkdownSource>. Citation sources by ID. [id]/【id】 markers render as chips.',
595
891
  citationStyle:
@@ -598,6 +894,8 @@ export const docsDense = {
598
894
  'number|string. Max width for prose (headings, paragraphs, lists). Tables/code unconstrained.',
599
895
  contentAlign:
600
896
  "'start'|'center'. Prose alignment when contentWidth < container. Default: 'start'.",
897
+ plugins:
898
+ 'readonly MarkdownPluginEntry[]. Ordered syntax, immutable AST transforms, and typed extension renderers from createMarkdownPlugin(). Narrow observed extensions with isMarkdownExtensionNode(); renderer callbacks are pure. Default: omitted or empty.',
601
899
  inlinePlugins:
602
900
  'MarkdownInlinePlugin[]. Regex matches in text nodes -> custom inline React elements. Skips inline/fenced code and math.',
603
901
  autolink:
@@ -0,0 +1,174 @@
1
+ // Copyright (c) Meta Platforms, Inc. and affiliates.
2
+
3
+ /**
4
+ * @file Markdown.fr23.bench.ts
5
+ * @input The AST-036 fixture document and the representative helper set
6
+ * @output One JSON line of FR23 ratios on stdout, for the harness that spawns it
7
+ * @position Benchmark body for Markdown.fr23.perf.test.ts; not a test itself
8
+ *
9
+ * Run as its own process, one measurement at a time, by
10
+ * `Markdown.fr23.perf.test.ts`. The fresh process isolates engine state left
11
+ * behind by other plugin configurations. The harness must also run separately
12
+ * from other tests: a child process still shares machine resources, and CPU
13
+ * time does not remove cache or memory-bandwidth contention.
14
+ *
15
+ * The timed region is exactly the spec's protocol — ten untimed warmups,
16
+ * then nine alternating paired rounds averaging 20 iterations a side,
17
+ * reported as the median of the nine paired ratios — against the omitted
18
+ * baseline, for a stable list and a recreated equivalent one. Each ratio
19
+ * comes from one sample, never a selection by the fastest baseline.
20
+ *
21
+ * The harness retries a fresh process only when the A/A control is invalid.
22
+ * A helper-overhead failure is never retried to obtain a passing sample.
23
+ */
24
+
25
+ import {measureMarkdownPairedRatio} from './Markdown.fr23.sampling';
26
+ import {parseMarkdown} from './parser';
27
+ import {createMarkdownPlugin} from './plugins';
28
+ import type {MarkdownExtensionNode} from './plugins';
29
+ import {createMarkdownFenceTransform} from './plugins/semanticFence';
30
+ import {createMarkdownSourceDecoration} from './plugins/sourceDecoration';
31
+ import {createMarkdownTextTransform} from './plugins/textTransform';
32
+
33
+ let benchmarkSink = 0;
34
+
35
+ /** The fixture `spec:AST-036`'s performance evidence protocol describes. */
36
+ function benchmarkDocument(sections: number): string {
37
+ return Array.from({length: sections}, (_, index) =>
38
+ [
39
+ `## Section ${index}`,
40
+ '',
41
+ `AST-${index} belongs to @{owner-${index}} with TODO follow-up.`,
42
+ '',
43
+ `- First item ${index}`,
44
+ '- Second item',
45
+ '',
46
+ `> Quoted detail ${index}`,
47
+ '',
48
+ '| Item | Detail |',
49
+ '| --- | --- |',
50
+ `| ${index} | ordinary prose |`,
51
+ '',
52
+ '```text',
53
+ `opaque ${index}`,
54
+ '```',
55
+ ].join('\n'),
56
+ ).join('\n\n');
57
+ }
58
+
59
+ /** Matches a prose identifier in every fixture section. */
60
+ const identifierPlugin = createMarkdownPlugin({
61
+ name: 'representative-identifiers',
62
+ apiVersion: 1,
63
+ transform: createMarkdownTextTransform({
64
+ pattern: /\bAST-\d+\b/g,
65
+ requiredSubstrings: ['AST-'],
66
+ replace: match => ({type: 'text', value: match[0].toLowerCase()}),
67
+ }),
68
+ });
69
+
70
+ /** Turns the ordinary text fence each fixture section carries into data. */
71
+ type PerfFenceNode = MarkdownExtensionNode<
72
+ 'representative-fences',
73
+ 'fence',
74
+ {readonly code: string},
75
+ 'block'
76
+ >;
77
+
78
+ const fencePlugin = createMarkdownPlugin<
79
+ 'representative-fences',
80
+ PerfFenceNode
81
+ >({
82
+ name: 'representative-fences',
83
+ apiVersion: 1,
84
+ transform: createMarkdownFenceTransform<readonly ['text'], PerfFenceNode>({
85
+ languages: ['text'],
86
+ createNode: ({code}) => ({
87
+ type: 'extension',
88
+ plugin: 'representative-fences',
89
+ name: 'fence',
90
+ display: 'block',
91
+ data: {code},
92
+ }),
93
+ }),
94
+ renderers: {
95
+ fence: {
96
+ render: ({node}) => node.data.code,
97
+ toText: node => node.data.code,
98
+ },
99
+ },
100
+ });
101
+
102
+ /** Decorates one known source range: the first section heading. */
103
+ function knownRangeDecorationPlugin(source: string) {
104
+ const heading = source.indexOf('## Section 0');
105
+ return createMarkdownPlugin({
106
+ name: 'representative-decoration',
107
+ apiVersion: 1,
108
+ transform: createMarkdownSourceDecoration({
109
+ name: 'representative-decoration',
110
+ ranges: [{start: heading, end: heading + '## Section 0'.length}],
111
+ }),
112
+ });
113
+ }
114
+
115
+ /**
116
+ * Brings the whole pipeline to steady state before anything is measured.
117
+ *
118
+ * The spec's ten warmups precede each measurement, but they are not enough
119
+ * for the FIRST one in a fresh process: the parser, the helpers and the
120
+ * protocol are all still being optimized, so whichever side is measured
121
+ * first carries the cold-start cost. Left alone this reliably inflated
122
+ * `stable` — the first of the two — while `recreated`, run moments later on
123
+ * a hot engine, sat where the real cost is. Priming both configurations
124
+ * here removes that ordering bias; it changes nothing inside the timed
125
+ * region, which is still ten warmups and one nine-pair median.
126
+ */
127
+ function primePipeline(
128
+ configurations: ReadonlyArray<() => number>,
129
+ rounds = 40,
130
+ ): void {
131
+ for (let round = 0; round < rounds; round++) {
132
+ for (const run of configurations) {
133
+ benchmarkSink ^= run();
134
+ }
135
+ }
136
+ void benchmarkSink;
137
+ }
138
+
139
+ function measure(sections: number): {
140
+ stable: number;
141
+ recreated: number;
142
+ control: number;
143
+ } {
144
+ const source = benchmarkDocument(sections);
145
+ const representative = [
146
+ identifierPlugin,
147
+ fencePlugin,
148
+ knownRangeDecorationPlugin(source),
149
+ ];
150
+ const empty = () => parseMarkdown(source).length;
151
+ const withStableList = () =>
152
+ parseMarkdown(source, {plugins: representative}).length;
153
+ const withRecreatedList = () =>
154
+ parseMarkdown(source, {plugins: [...representative]}).length;
155
+ primePipeline([empty, withStableList, withRecreatedList]);
156
+ // The A/A control measures identical work. Only a failed control can
157
+ // invalidate this sample; neither helper ratio participates in selection.
158
+ const control = measureMarkdownPairedRatio(empty, empty);
159
+ return {
160
+ stable: measureMarkdownPairedRatio(empty, withStableList),
161
+ recreated: measureMarkdownPairedRatio(empty, withRecreatedList),
162
+ control,
163
+ };
164
+ }
165
+
166
+ const sections = Number(process.argv[2]);
167
+ if (!Number.isInteger(sections) || sections <= 0) {
168
+ console.error(`Expected a section count, received ${process.argv[2]}`);
169
+ process.exit(2);
170
+ }
171
+ // One line on stdout, so the harness can tell a real result from a crash.
172
+ // `process.stdout.write` rather than `console.log`: this file is a
173
+ // benchmark binary, not a module that should be logging.
174
+ process.stdout.write(`${JSON.stringify({sections, ...measure(sections)})}\n`);