@astryxdesign/core 0.6.2 → 0.6.3-canary.01fa439

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 (384) 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/Chat/ChatComposer.d.ts.map +1 -1
  9. package/dist/Chat/ChatComposer.js +10 -5
  10. package/dist/Chat/ChatComposerDrawer.d.ts +19 -5
  11. package/dist/Chat/ChatComposerDrawer.d.ts.map +1 -1
  12. package/dist/Chat/ChatComposerDrawer.js +48 -23
  13. package/dist/Chat/ChatComposerInput.d.ts +11 -3
  14. package/dist/Chat/ChatComposerInput.d.ts.map +1 -1
  15. package/dist/Chat/ChatComposerInput.js +63 -16
  16. package/dist/Chat/ChatDictationButton.d.ts +3 -2
  17. package/dist/Chat/ChatDictationButton.d.ts.map +1 -1
  18. package/dist/Chat/ChatDictationButton.js +6 -4
  19. package/dist/Chat/ChatSendButton.js +1 -1
  20. package/dist/Chat/index.d.ts +1 -1
  21. package/dist/Chat/index.d.ts.map +1 -1
  22. package/dist/CheckboxInput/CheckboxInput.d.ts.map +1 -1
  23. package/dist/CheckboxInput/CheckboxInput.js +12 -2
  24. package/dist/Collapsible/Collapsible.d.ts.map +1 -1
  25. package/dist/Collapsible/Collapsible.js +6 -1
  26. package/dist/CommandPalette/CommandPaletteInput.d.ts.map +1 -1
  27. package/dist/CommandPalette/CommandPaletteInput.js +1 -1
  28. package/dist/ComplexSelector/ComplexSelector.d.ts.map +1 -1
  29. package/dist/ComplexSelector/ComplexSelector.js +1 -1
  30. package/dist/DateInput/DateInput.d.ts.map +1 -1
  31. package/dist/DateInput/DateInput.js +4 -4
  32. package/dist/DateInput/NativeDateField.d.ts.map +1 -1
  33. package/dist/DateInput/NativeDateField.js +16 -16
  34. package/dist/DateInput/TouchDateField.d.ts.map +1 -1
  35. package/dist/DateInput/TouchDateField.js +2 -2
  36. package/dist/DateRangeInput/DateRangeInput.d.ts.map +1 -1
  37. package/dist/DateRangeInput/DateRangeInput.js +4 -4
  38. package/dist/DateTimeInput/DateTimeInput.d.ts.map +1 -1
  39. package/dist/DateTimeInput/DateTimeInput.js +8 -8
  40. package/dist/DateTimeInput/TouchDateTimeField.d.ts.map +1 -1
  41. package/dist/DateTimeInput/TouchDateTimeField.js +4 -4
  42. package/dist/DateTimeInput/nativePickerSegmentStyles.d.ts +9 -3
  43. package/dist/DateTimeInput/nativePickerSegmentStyles.d.ts.map +1 -1
  44. package/dist/DateTimeInput/nativePickerSegmentStyles.js +3 -3
  45. package/dist/Dialog/DialogHeader.d.ts +8 -1
  46. package/dist/Dialog/DialogHeader.d.ts.map +1 -1
  47. package/dist/Dialog/DialogHeader.js +10 -1
  48. package/dist/Field/InputClearButton.d.ts +4 -2
  49. package/dist/Field/InputClearButton.d.ts.map +1 -1
  50. package/dist/Field/InputClearButton.js +4 -2
  51. package/dist/Field/PanelSearchInput.d.ts.map +1 -1
  52. package/dist/Field/PanelSearchInput.js +1 -1
  53. package/dist/FileInput/FileInput.d.ts.map +1 -1
  54. package/dist/FileInput/FileInput.js +7 -7
  55. package/dist/Kbd/Kbd.d.ts +5 -3
  56. package/dist/Kbd/Kbd.d.ts.map +1 -1
  57. package/dist/Kbd/Kbd.js +36 -42
  58. package/dist/Link/Link.d.ts.map +1 -1
  59. package/dist/Link/Link.js +6 -2
  60. package/dist/Markdown/Markdown.d.ts +8 -2
  61. package/dist/Markdown/Markdown.d.ts.map +1 -1
  62. package/dist/Markdown/Markdown.fr23.bench.d.ts +2 -0
  63. package/dist/Markdown/Markdown.fr23.bench.d.ts.map +1 -0
  64. package/dist/Markdown/Markdown.fr23.bench.js +150 -0
  65. package/dist/Markdown/Markdown.fr23.sampling.d.ts +2 -0
  66. package/dist/Markdown/Markdown.fr23.sampling.d.ts.map +1 -0
  67. package/dist/Markdown/Markdown.fr23.sampling.js +43 -0
  68. package/dist/Markdown/Markdown.js +262 -109
  69. package/dist/Markdown/ast.d.ts +162 -0
  70. package/dist/Markdown/ast.d.ts.map +1 -0
  71. package/dist/Markdown/ast.js +74 -0
  72. package/dist/Markdown/index.d.ts +5 -3
  73. package/dist/Markdown/index.d.ts.map +1 -1
  74. package/dist/Markdown/index.js +3 -2
  75. package/dist/Markdown/parser/index.d.ts +10 -0
  76. package/dist/Markdown/parser/index.d.ts.map +1 -0
  77. package/dist/Markdown/parser/index.js +10 -0
  78. package/dist/Markdown/parser.d.ts +126 -58
  79. package/dist/Markdown/parser.d.ts.map +1 -1
  80. package/dist/Markdown/parser.js +716 -167
  81. package/dist/Markdown/plugins/frontmatter.d.ts +32 -0
  82. package/dist/Markdown/plugins/frontmatter.d.ts.map +1 -0
  83. package/dist/Markdown/plugins/frontmatter.js +132 -0
  84. package/dist/Markdown/plugins/index.d.ts +16 -0
  85. package/dist/Markdown/plugins/index.d.ts.map +1 -0
  86. package/dist/Markdown/plugins/index.js +13 -0
  87. package/dist/Markdown/plugins/protocol.d.ts +191 -0
  88. package/dist/Markdown/plugins/protocol.d.ts.map +1 -0
  89. package/dist/Markdown/plugins/protocol.js +957 -0
  90. package/dist/Markdown/plugins/semanticFence.d.ts +36 -0
  91. package/dist/Markdown/plugins/semanticFence.d.ts.map +1 -0
  92. package/dist/Markdown/plugins/semanticFence.js +213 -0
  93. package/dist/Markdown/plugins/sourceDecoration.d.ts +76 -0
  94. package/dist/Markdown/plugins/sourceDecoration.d.ts.map +1 -0
  95. package/dist/Markdown/plugins/sourceDecoration.js +393 -0
  96. package/dist/Markdown/plugins/textTransform.d.ts +30 -0
  97. package/dist/Markdown/plugins/textTransform.d.ts.map +1 -0
  98. package/dist/Markdown/plugins/textTransform.js +374 -0
  99. package/dist/Markdown/remark.d.ts +196 -0
  100. package/dist/Markdown/remark.d.ts.map +1 -0
  101. package/dist/Markdown/remark.js +1062 -0
  102. package/dist/Markdown/url.d.ts +4 -0
  103. package/dist/Markdown/url.d.ts.map +1 -0
  104. package/dist/Markdown/url.js +25 -0
  105. package/dist/Markdown/utils.d.ts +4 -2
  106. package/dist/Markdown/utils.d.ts.map +1 -1
  107. package/dist/Markdown/utils.js +2 -1
  108. package/dist/NumberInput/NumberInput.d.ts.map +1 -1
  109. package/dist/NumberInput/NumberInput.js +4 -4
  110. package/dist/Outline/index.d.ts +1 -0
  111. package/dist/Outline/index.d.ts.map +1 -1
  112. package/dist/Outline/parseOutlineFromMarkdown.d.ts +7 -1
  113. package/dist/Outline/parseOutlineFromMarkdown.d.ts.map +1 -1
  114. package/dist/Outline/parseOutlineFromMarkdown.js +14 -8
  115. package/dist/Outline/useOutlineFromMarkdown.d.ts +3 -1
  116. package/dist/Outline/useOutlineFromMarkdown.d.ts.map +1 -1
  117. package/dist/Outline/useOutlineFromMarkdown.js +8 -3
  118. package/dist/PowerSearch/PowerSearchEditPopover.d.ts.map +1 -1
  119. package/dist/PowerSearch/PowerSearchEditPopover.js +46 -30
  120. package/dist/ProgressBar/ProgressBar.d.ts.map +1 -1
  121. package/dist/ProgressBar/ProgressBar.js +36 -31
  122. package/dist/RadioList/RadioListItem.d.ts.map +1 -1
  123. package/dist/RadioList/RadioListItem.js +13 -1
  124. package/dist/SegmentedControl/SegmentedControlItem.d.ts.map +1 -1
  125. package/dist/SegmentedControl/SegmentedControlItem.js +5 -5
  126. package/dist/Selector/Selector.d.ts +9 -7
  127. package/dist/Selector/Selector.d.ts.map +1 -1
  128. package/dist/Selector/Selector.js +7 -5
  129. package/dist/SideNav/SideNav.d.ts +2 -1
  130. package/dist/SideNav/SideNav.d.ts.map +1 -1
  131. package/dist/SideNav/SideNav.js +9 -3
  132. package/dist/Slider/Slider.d.ts.map +1 -1
  133. package/dist/Slider/Slider.js +28 -12
  134. package/dist/Spinner/Spinner.d.ts.map +1 -1
  135. package/dist/Spinner/Spinner.js +23 -7
  136. package/dist/Switch/Switch.d.ts.map +1 -1
  137. package/dist/Switch/Switch.js +11 -0
  138. package/dist/TabList/Tab.d.ts +1 -1
  139. package/dist/TabList/Tab.d.ts.map +1 -1
  140. package/dist/TabList/Tab.js +20 -7
  141. package/dist/Table/Table.d.ts +1 -0
  142. package/dist/Table/Table.d.ts.map +1 -1
  143. package/dist/Table/Table.js +29 -13
  144. package/dist/TextArea/TextArea.d.ts.map +1 -1
  145. package/dist/TextArea/TextArea.js +1 -1
  146. package/dist/TextInput/TextInput.d.ts.map +1 -1
  147. package/dist/TextInput/TextInput.js +2 -2
  148. package/dist/TimeInput/TimeInput.d.ts.map +1 -1
  149. package/dist/TimeInput/TimeInput.js +4 -4
  150. package/dist/ToggleButton/ToggleButton.d.ts +9 -6
  151. package/dist/ToggleButton/ToggleButton.d.ts.map +1 -1
  152. package/dist/ToggleButton/ToggleButton.js +15 -27
  153. package/dist/TreeList/TreeList.d.ts.map +1 -1
  154. package/dist/TreeList/TreeList.js +3 -0
  155. package/dist/TreeList/TreeListItem.d.ts +6 -1
  156. package/dist/TreeList/TreeListItem.d.ts.map +1 -1
  157. package/dist/TreeList/TreeListItem.js +12 -2
  158. package/dist/TreeList/TreeListTypes.d.ts +8 -1
  159. package/dist/TreeList/TreeListTypes.d.ts.map +1 -1
  160. package/dist/Typeahead/BaseTypeahead.d.ts.map +1 -1
  161. package/dist/Typeahead/BaseTypeahead.js +16 -7
  162. package/dist/astryx.css +18 -7
  163. package/dist/hooks/scrollKeyboardDelegation.d.ts +3 -0
  164. package/dist/hooks/scrollKeyboardDelegation.d.ts.map +1 -0
  165. package/dist/hooks/scrollKeyboardDelegation.js +146 -0
  166. package/dist/hooks/useScrollableArea.d.ts +6 -2
  167. package/dist/hooks/useScrollableArea.d.ts.map +1 -1
  168. package/dist/hooks/useScrollableArea.js +17 -5
  169. package/dist/theme/generateThemeRules.d.ts.map +1 -1
  170. package/dist/theme/generateThemeRules.js +10 -0
  171. package/dist/utils/interactionOverlay.stylex.d.ts +8 -0
  172. package/dist/utils/interactionOverlay.stylex.d.ts.map +1 -1
  173. package/dist/utils/interactionOverlay.stylex.js +9 -0
  174. package/locales/af-ZA.json +530 -1
  175. package/locales/ar-SA.json +490 -1
  176. package/locales/ca-ES.json +514 -1
  177. package/locales/cs-CZ.json +498 -1
  178. package/locales/da-DK.json +522 -1
  179. package/locales/de-DE.json +522 -1
  180. package/locales/el-GR.json +498 -1
  181. package/locales/es-ES.json +510 -1
  182. package/locales/fi-FI.json +498 -1
  183. package/locales/fr-FR.json +534 -1
  184. package/locales/he-IL.json +498 -1
  185. package/locales/hu-HU.json +498 -1
  186. package/locales/it-IT.json +510 -1
  187. package/locales/ja-JP.json +490 -1
  188. package/locales/ko-KR.json +498 -1
  189. package/locales/nl-NL.json +534 -1
  190. package/locales/no-NO.json +510 -1
  191. package/locales/pl-PL.json +506 -1
  192. package/locales/pt-BR.json +506 -1
  193. package/locales/pt-PT.json +506 -1
  194. package/locales/ro-RO.json +506 -1
  195. package/locales/ru-RU.json +498 -1
  196. package/locales/sr-SP.json +498 -1
  197. package/locales/sv-SE.json +502 -1
  198. package/locales/tr-TR.json +498 -1
  199. package/locales/uk-UA.json +498 -1
  200. package/locales/vi-VN.json +502 -1
  201. package/locales/zh-CN.json +490 -1
  202. package/locales/zh-TW.json +490 -1
  203. package/package.json +19 -4
  204. package/src/BottomSheet/BottomSheet.doc.mjs +8 -1
  205. package/src/BottomSheet/BottomSheet.spec.md +46 -20
  206. package/src/BottomSheet/BottomSheet.test.tsx +6 -3
  207. package/src/BottomSheet/BottomSheet.tsx +3 -1
  208. package/src/BottomSheet/BottomSheetKeyboard.test.tsx +195 -0
  209. package/src/BottomSheet/BottomSheetPanel.test.tsx +11 -1
  210. package/src/BottomSheet/BottomSheetPanel.tsx +49 -16
  211. package/src/BottomSheet/__tests__/BottomSheetKeyboard.a11y.browser.spec.ts +344 -0
  212. package/src/Button/__tests__/Button.a11y.chromium.spec.ts +17 -1
  213. package/src/Button/__tests__/Button.a11y.known-failures.ts +0 -29
  214. package/src/Button/__tests__/Button.a11y.renders.tsx +9 -2
  215. package/src/Button/__tests__/Button.a11y.states.ts +9 -0
  216. package/src/Chat/ChatComposer.doc.mjs +14 -0
  217. package/src/Chat/ChatComposer.spec.md +230 -0
  218. package/src/Chat/ChatComposer.test.tsx +57 -0
  219. package/src/Chat/ChatComposer.tsx +21 -9
  220. package/src/Chat/ChatComposerDrawer.doc.mjs +63 -5
  221. package/src/Chat/ChatComposerDrawer.spec.md +267 -0
  222. package/src/Chat/ChatComposerDrawer.test.tsx +81 -12
  223. package/src/Chat/ChatComposerDrawer.tsx +38 -9
  224. package/src/Chat/ChatComposerInput.doc.mjs +114 -26
  225. package/src/Chat/ChatComposerInput.spec.md +185 -0
  226. package/src/Chat/ChatComposerInput.test.tsx +113 -3
  227. package/src/Chat/ChatComposerInput.tsx +78 -13
  228. package/src/Chat/ChatComposerTokenElement.spec.md +152 -0
  229. package/src/Chat/ChatComposerTokenElement.test.tsx +85 -0
  230. package/src/Chat/ChatDictationButton.doc.mjs +3 -3
  231. package/src/Chat/ChatDictationButton.spec.md +160 -0
  232. package/src/Chat/ChatDictationButton.test.tsx +92 -27
  233. package/src/Chat/ChatDictationButton.tsx +8 -6
  234. package/src/Chat/ChatSendButton.test.tsx +1 -4
  235. package/src/Chat/ChatSendButton.tsx +1 -1
  236. package/src/Chat/index.ts +1 -0
  237. package/src/CheckboxInput/CheckboxInput.doc.mjs +11 -0
  238. package/src/CheckboxInput/CheckboxInput.test.tsx +34 -0
  239. package/src/CheckboxInput/CheckboxInput.tsx +21 -1
  240. package/src/ClickableCard/ClickableCard.test.tsx +102 -5
  241. package/src/Collapsible/Collapsible.doc.mjs +11 -0
  242. package/src/Collapsible/Collapsible.test.tsx +21 -0
  243. package/src/Collapsible/Collapsible.tsx +5 -0
  244. package/src/CommandPalette/CommandPaletteInput.tsx +6 -1
  245. package/src/ComplexSelector/ComplexSelector.tsx +6 -1
  246. package/src/DateInput/DateInput.tsx +6 -1
  247. package/src/DateInput/NativeDateField.tsx +24 -8
  248. package/src/DateInput/TouchDateField.tsx +6 -2
  249. package/src/DateRangeInput/DateRangeInput.tsx +6 -1
  250. package/src/DateTimeInput/DateTimeInput.tsx +6 -1
  251. package/src/DateTimeInput/TouchDateTimeField.tsx +6 -1
  252. package/src/DateTimeInput/nativePickerSegmentStyles.ts +24 -8
  253. package/src/Dialog/DialogHeader.doc.mjs +12 -0
  254. package/src/Dialog/DialogHeader.test.tsx +97 -0
  255. package/src/Dialog/DialogHeader.tsx +25 -3
  256. package/src/Dialog/modules/DialogHeader.spec.md +75 -38
  257. package/src/Field/InputClearButton.test.tsx +17 -3
  258. package/src/Field/InputClearButton.tsx +5 -2
  259. package/src/Field/PanelSearchInput.tsx +5 -2
  260. package/src/FieldStatus/__tests__/StatusMessage.a11y.states.ts +1 -1
  261. package/src/FileInput/FileInput.tsx +11 -2
  262. package/src/Kbd/Kbd.doc.mjs +3 -3
  263. package/src/Kbd/Kbd.test.tsx +57 -1
  264. package/src/Kbd/Kbd.tsx +57 -37
  265. package/src/Layout/LayoutFooter.doc.mjs +17 -0
  266. package/src/Link/Link.doc.mjs +11 -0
  267. package/src/Link/Link.test.tsx +24 -0
  268. package/src/Link/Link.tsx +5 -0
  269. package/src/List/List.spec.md +200 -0
  270. package/src/Markdown/Markdown.doc.mjs +272 -0
  271. package/src/Markdown/Markdown.fr23.bench.ts +174 -0
  272. package/src/Markdown/Markdown.fr23.perf.test.ts +249 -0
  273. package/src/Markdown/Markdown.fr23.sampling.ts +49 -0
  274. package/src/Markdown/Markdown.helpers.perf.test.ts +489 -0
  275. package/src/Markdown/Markdown.public.test.ts +126 -3
  276. package/src/Markdown/Markdown.spec.md +197 -44
  277. package/src/Markdown/Markdown.test.tsx +11 -0
  278. package/src/Markdown/Markdown.tsx +414 -135
  279. package/src/Markdown/ast.test.ts +307 -0
  280. package/src/Markdown/ast.ts +337 -0
  281. package/src/Markdown/incremental.test.ts +12 -0
  282. package/src/Markdown/index.ts +37 -1
  283. package/src/Markdown/modules/remark.spec.md +269 -0
  284. package/src/Markdown/parser/index.ts +64 -0
  285. package/src/Markdown/parser.public.test.ts +103 -0
  286. package/src/Markdown/parser.ts +1180 -235
  287. package/src/Markdown/plugins/frontmatter.test.tsx +125 -0
  288. package/src/Markdown/plugins/frontmatter.ts +198 -0
  289. package/src/Markdown/plugins/index.ts +53 -0
  290. package/src/Markdown/plugins/protocol.test.tsx +1022 -0
  291. package/src/Markdown/plugins/protocol.ts +1618 -0
  292. package/src/Markdown/plugins/semanticFence.test.tsx +546 -0
  293. package/src/Markdown/plugins/semanticFence.ts +424 -0
  294. package/src/Markdown/plugins/sourceDecoration.test.tsx +799 -0
  295. package/src/Markdown/plugins/sourceDecoration.ts +539 -0
  296. package/src/Markdown/plugins/textTransform.test.ts +467 -0
  297. package/src/Markdown/plugins/textTransform.ts +554 -0
  298. package/src/Markdown/remark.test.tsx +1877 -0
  299. package/src/Markdown/remark.ts +1574 -0
  300. package/src/Markdown/url.ts +30 -0
  301. package/src/Markdown/utils.ts +13 -1
  302. package/src/MultiSelector/MultiSelector.test.tsx +1 -35
  303. package/src/MultiSelector/__tests__/MultiSelector.listbox.a11y.test.tsx +128 -0
  304. package/src/NumberInput/NumberInput.tsx +6 -1
  305. package/src/Outline/Outline.doc.mjs +7 -5
  306. package/src/Outline/Outline.spec.md +1 -1
  307. package/src/Outline/index.ts +1 -0
  308. package/src/Outline/modules/parseOutlineFromMarkdown.spec.md +142 -0
  309. package/src/Outline/parseOutlineFromMarkdown.ts +40 -10
  310. package/src/Outline/useOutlineFromMarkdown.ts +15 -3
  311. package/src/PowerSearch/PowerSearch.doc.mjs +2 -2
  312. package/src/PowerSearch/PowerSearchEditPopover.test.tsx +150 -1
  313. package/src/PowerSearch/PowerSearchEditPopover.tsx +51 -28
  314. package/src/ProgressBar/ProgressBar.test.tsx +29 -11
  315. package/src/ProgressBar/ProgressBar.tsx +59 -72
  316. package/src/RadioList/RadioList.doc.mjs +11 -0
  317. package/src/RadioList/RadioList.test.tsx +32 -0
  318. package/src/RadioList/RadioListItem.tsx +25 -1
  319. package/src/ScrollableArea/modules/useScrollableArea.spec.md +50 -22
  320. package/src/SegmentedControl/SegmentedControl.doc.mjs +2 -2
  321. package/src/SegmentedControl/SegmentedControl.test.tsx +31 -0
  322. package/src/SegmentedControl/SegmentedControlItem.tsx +6 -9
  323. package/src/Selector/Selector.doc.mjs +2 -2
  324. package/src/Selector/Selector.spec.md +51 -49
  325. package/src/Selector/Selector.test.tsx +61 -55
  326. package/src/Selector/Selector.tsx +23 -14
  327. package/src/Selector/__tests__/Listbox.a11y.chromium.spec.ts +130 -0
  328. package/src/Selector/__tests__/Listbox.a11y.dom.ts +38 -0
  329. package/src/Selector/__tests__/Listbox.a11y.inventory.test.ts +63 -0
  330. package/src/Selector/__tests__/Listbox.a11y.known-failures.ts +37 -0
  331. package/src/Selector/__tests__/Listbox.a11y.states.ts +232 -0
  332. package/src/Selector/__tests__/Selector.listbox.a11y.test.tsx +121 -0
  333. package/src/SideNav/SideNav.doc.mjs +1 -1
  334. package/src/SideNav/SideNav.test.tsx +10 -0
  335. package/src/SideNav/SideNav.tsx +14 -2
  336. package/src/Slider/Slider.doc.mjs +17 -3
  337. package/src/Slider/Slider.test.tsx +221 -0
  338. package/src/Slider/Slider.tsx +40 -9
  339. package/src/Spinner/Spinner.test.tsx +4 -0
  340. package/src/Spinner/Spinner.tsx +31 -18
  341. package/src/Switch/Switch.doc.mjs +11 -0
  342. package/src/Switch/Switch.test.tsx +16 -0
  343. package/src/Switch/Switch.tsx +28 -0
  344. package/src/TabList/Tab.tsx +35 -7
  345. package/src/TabList/TabList.doc.mjs +11 -0
  346. package/src/TabList/TabList.spec.md +204 -0
  347. package/src/TabList/TabList.test.tsx +66 -0
  348. package/src/TabList/__tests__/Tabs.a11y.known-failures.ts +1 -34
  349. package/src/Table/Table.doc.mjs +1 -1
  350. package/src/Table/Table.spec.md +54 -40
  351. package/src/Table/Table.test.tsx +83 -10
  352. package/src/Table/Table.tsx +30 -22
  353. package/src/Table/__tests__/TableScroll.a11y.chromium.spec.ts +137 -0
  354. package/src/TextArea/TextArea.tsx +6 -1
  355. package/src/TextInput/TextInput.test.tsx +20 -1
  356. package/src/TextInput/TextInput.tsx +6 -1
  357. package/src/TimeInput/TimeInput.tsx +6 -1
  358. package/src/ToggleButton/ToggleButton.doc.mjs +3 -3
  359. package/src/ToggleButton/ToggleButton.test.tsx +299 -4
  360. package/src/ToggleButton/ToggleButton.tsx +26 -33
  361. package/src/ToggleButton/ToggleButtonGroup.doc.mjs +3 -3
  362. package/src/ToggleButton/__tests__/ToggleButton.a11y.chromium.spec.ts +209 -0
  363. package/src/Tokenizer/Tokenizer.spec.md +142 -75
  364. package/src/TreeList/TreeList.doc.mjs +3 -3
  365. package/src/TreeList/TreeList.spec.md +123 -75
  366. package/src/TreeList/TreeList.test.tsx +29 -0
  367. package/src/TreeList/TreeList.tsx +3 -0
  368. package/src/TreeList/TreeListItem.tsx +15 -1
  369. package/src/TreeList/TreeListTypes.ts +11 -1
  370. package/src/Typeahead/BaseTypeahead.spec.md +4 -3
  371. package/src/Typeahead/BaseTypeahead.tsx +21 -7
  372. package/src/Typeahead/Typeahead.test.tsx +53 -0
  373. package/src/__tests__/PressedState.a11y.chromium.spec.ts +813 -0
  374. package/src/__tests__/pressState.ts +93 -0
  375. package/src/hooks/scrollKeyboardDelegation.test.ts +155 -0
  376. package/src/hooks/scrollKeyboardDelegation.ts +233 -0
  377. package/src/hooks/useScrollableArea.doc.mjs +15 -3
  378. package/src/hooks/useScrollableArea.test.tsx +59 -1
  379. package/src/hooks/useScrollableArea.ts +34 -10
  380. package/src/inputFontFloor.test.ts +106 -0
  381. package/src/tailwind-theme.css +0 -6
  382. package/src/theme/generateThemeRules.test.ts +30 -0
  383. package/src/theme/generateThemeRules.ts +10 -0
  384. package/src/utils/interactionOverlay.stylex.ts +20 -0
@@ -0,0 +1,489 @@
1
+ // Copyright (c) Meta Platforms, Inc. and affiliates.
2
+
3
+ /**
4
+ * @file Markdown.helpers.perf.test.ts
5
+ * @input Deterministic 200/500-section Markdown with text, fence, and decoration helpers
6
+ * @output Deterministic skip evidence and paired median running-helper evidence
7
+ * @position Helper dispatch regression; full FR23 evidence lands after all helpers
8
+ *
9
+ * The exact FR23 comparison against the omitted/empty pipeline lives in its
10
+ * own file, `Markdown.fr23.perf.test.ts`: it must run in a process that has
11
+ * not already exercised a dozen other plugin configurations, or the engine's
12
+ * state rather than the helpers' work dominates the ratio.
13
+ *
14
+ * A helper that actually runs also pays Core's fixed per-parse transform cost
15
+ * (heading marking, freezing, and validation), which no helper change can
16
+ * move; the running-helper cases below therefore compare against transforms
17
+ * that return their input unchanged so a regression points at the helper.
18
+ * `spec:AST-036` FR23's absolute budgets stay open until that protocol cost
19
+ * and the remaining helpers land.
20
+ */
21
+
22
+ import {describe, expect, it} from 'vitest';
23
+ import {parseMarkdown, parseMarkdownAst} from './parser';
24
+ import {
25
+ applyMarkdownTransforms,
26
+ createMarkdownPlugin,
27
+ prepareMarkdownPlugins,
28
+ type MarkdownExtensionNode,
29
+ type MarkdownTransform,
30
+ } from './plugins/protocol';
31
+ import {createMarkdownFenceTransform} from './plugins/semanticFence';
32
+ import {createMarkdownSourceDecoration} from './plugins/sourceDecoration';
33
+ import {createMarkdownTextTransform} from './plugins/textTransform';
34
+
35
+ let benchmarkSink = 0;
36
+ let transformCalls = 0;
37
+
38
+ function benchmarkDocument(sections: number): string {
39
+ return Array.from({length: sections}, (_, index) =>
40
+ [
41
+ `## Section ${index}`,
42
+ '',
43
+ `AST-${index} belongs to @{owner-${index}} with TODO follow-up.`,
44
+ '',
45
+ `- First item ${index}`,
46
+ '- Second item',
47
+ '',
48
+ `> Quoted detail ${index}`,
49
+ '',
50
+ '| Item | Detail |',
51
+ '| --- | --- |',
52
+ `| ${index} | ordinary prose |`,
53
+ '',
54
+ '```text',
55
+ `opaque ${index}`,
56
+ '```',
57
+ ].join('\n'),
58
+ ).join('\n\n');
59
+ }
60
+
61
+ function median(values: ReadonlyArray<number>): number {
62
+ const sorted = [...values].sort((left, right) => left - right);
63
+ return sorted[Math.floor(sorted.length / 2)];
64
+ }
65
+
66
+ function measureAverage(callback: () => number): number {
67
+ const start = performance.now();
68
+ for (let iteration = 0; iteration < 20; iteration++) {
69
+ benchmarkSink ^= callback();
70
+ }
71
+ return (performance.now() - start) / 20;
72
+ }
73
+
74
+ function pairedMedianRatio(
75
+ baseline: () => number,
76
+ candidate: () => number,
77
+ ): number {
78
+ for (let warmup = 0; warmup < 10; warmup++) {
79
+ benchmarkSink ^= baseline();
80
+ benchmarkSink ^= candidate();
81
+ }
82
+ const ratios: number[] = [];
83
+ for (let round = 0; round < 9; round++) {
84
+ const baselineFirst = round % 2 === 0;
85
+ const first = measureAverage(baselineFirst ? baseline : candidate);
86
+ const second = measureAverage(baselineFirst ? candidate : baseline);
87
+ const baselineTime = baselineFirst ? first : second;
88
+ const candidateTime = baselineFirst ? second : first;
89
+ ratios.push(candidateTime / baselineTime);
90
+ }
91
+ void benchmarkSink;
92
+ return median(ratios);
93
+ }
94
+
95
+ function observeTransformCalls(
96
+ transform: MarkdownTransform,
97
+ ): MarkdownTransform {
98
+ const observed: MarkdownTransform = (root, context) => {
99
+ transformCalls++;
100
+ return transform(root, context);
101
+ };
102
+ // Preserve the helper's private source-claim metadata on the observer.
103
+ Object.defineProperties(
104
+ observed,
105
+ Object.getOwnPropertyDescriptors(transform),
106
+ );
107
+ return observed;
108
+ }
109
+
110
+ const zeroWorkPlugins = [
111
+ ...Array.from({length: 4}, (_, index) =>
112
+ createMarkdownPlugin({
113
+ name: `zero-work-${index}`,
114
+ apiVersion: 1,
115
+ transform: observeTransformCalls(
116
+ createMarkdownTextTransform({
117
+ pattern: new RegExp(`NEVER_MATCH_${index}`, 'g'),
118
+ requiredSubstrings: [`NEVER_MATCH_${index}`],
119
+ replace: () => {
120
+ throw new Error('An unclaimed helper callback ran');
121
+ },
122
+ }),
123
+ ),
124
+ }),
125
+ ),
126
+ createMarkdownPlugin<
127
+ 'zero-work-semantic-fence',
128
+ MarkdownExtensionNode<
129
+ 'zero-work-semantic-fence',
130
+ 'never',
131
+ {readonly value: string},
132
+ 'block'
133
+ >
134
+ >({
135
+ name: 'zero-work-semantic-fence',
136
+ apiVersion: 1,
137
+ transform: observeTransformCalls(
138
+ createMarkdownFenceTransform({
139
+ languages: ['never-fence'],
140
+ createNode: ({code}) => {
141
+ throw new Error(`An unclaimed semantic fence callback ran: ${code}`);
142
+ },
143
+ }),
144
+ ),
145
+ renderers: {
146
+ never: {
147
+ render: () => {
148
+ throw new Error('An unclaimed semantic fence renderer ran');
149
+ },
150
+ toText: node => node.data.value,
151
+ },
152
+ },
153
+ }),
154
+ ...Array.from({length: 5}, (_, index) =>
155
+ createMarkdownPlugin({
156
+ name: `zero-work-decoration-${index}`,
157
+ apiVersion: 1,
158
+ transform: observeTransformCalls(
159
+ createMarkdownSourceDecoration({
160
+ name: `zero-work-decoration-${index}`,
161
+ ranges: [{start: 10_000_000 + index, end: 10_000_100 + index}],
162
+ }),
163
+ ),
164
+ }),
165
+ ),
166
+ ];
167
+
168
+ /**
169
+ * Five decoration helpers that claim the source and sweep the whole block
170
+ * list, but whose ranges sit in the blank lines between blocks and therefore
171
+ * record nothing.
172
+ */
173
+ function gapDecorationPlugins(
174
+ source: string,
175
+ count: number,
176
+ rangesPerHelper: number,
177
+ prefix: string,
178
+ ) {
179
+ const gaps: {start: number; end: number}[] = [];
180
+ for (
181
+ let gap = source.indexOf('\n\n');
182
+ gap >= 0 && gaps.length < rangesPerHelper;
183
+ gap = source.indexOf('\n\n', gap + 1)
184
+ ) {
185
+ gaps.push({start: gap, end: gap + 1});
186
+ }
187
+ if (gaps.length < rangesPerHelper) {
188
+ throw new Error('Fixture has too few block gaps for this case');
189
+ }
190
+ return Array.from({length: count}, (_, index) =>
191
+ createMarkdownPlugin({
192
+ name: `${prefix}-${index}`,
193
+ apiVersion: 1,
194
+ transform: createMarkdownSourceDecoration({
195
+ name: `${prefix}-${index}`,
196
+ ranges: gaps,
197
+ }),
198
+ }),
199
+ );
200
+ }
201
+
202
+ /**
203
+ * Transforms that return their input unchanged. Comparing a helper against
204
+ * these isolates the helper's own dispatch from the fixed per-parse cost Core
205
+ * pays for any running transform (heading marking, freezing, validation),
206
+ * which `spec:AST-036` FR23's absolute budgets also cover but which no helper
207
+ * change can move.
208
+ */
209
+ function identityPlugins(count: number, prefix: string) {
210
+ return Array.from({length: count}, (_, index) =>
211
+ createMarkdownPlugin({
212
+ name: `${prefix}-${index}`,
213
+ apiVersion: 1,
214
+ transform: root => root,
215
+ }),
216
+ );
217
+ }
218
+
219
+ const identityFivePlugins = identityPlugins(5, 'identity-five');
220
+
221
+ /** Matches a prose identifier in every fixture section. */
222
+ const identifierPlugin = createMarkdownPlugin({
223
+ name: 'representative-identifiers',
224
+ apiVersion: 1,
225
+ transform: createMarkdownTextTransform({
226
+ pattern: /\bAST-\d+\b/g,
227
+ requiredSubstrings: ['AST-'],
228
+ replace: match => ({type: 'text', value: match[0].toLowerCase()}),
229
+ }),
230
+ });
231
+
232
+ /** Turns the ordinary text fence each fixture section carries into data. */
233
+ type PerfFenceNode = MarkdownExtensionNode<
234
+ 'representative-fences',
235
+ 'fence',
236
+ {readonly code: string},
237
+ 'block'
238
+ >;
239
+
240
+ const fencePlugin = createMarkdownPlugin<
241
+ 'representative-fences',
242
+ PerfFenceNode
243
+ >({
244
+ name: 'representative-fences',
245
+ apiVersion: 1,
246
+ transform: createMarkdownFenceTransform<readonly ['text'], PerfFenceNode>({
247
+ languages: ['text'],
248
+ createNode: ({code}) => ({
249
+ type: 'extension',
250
+ plugin: 'representative-fences',
251
+ name: 'fence',
252
+ display: 'block',
253
+ data: {code},
254
+ }),
255
+ }),
256
+ renderers: {
257
+ fence: {
258
+ render: ({node}) => node.data.code,
259
+ toText: node => node.data.code,
260
+ },
261
+ },
262
+ });
263
+
264
+ /** Decorates one known source range: the first section heading. */
265
+ function knownRangeDecorationPlugin(source: string) {
266
+ const heading = source.indexOf('## Section 0');
267
+ return createMarkdownPlugin({
268
+ name: 'representative-decoration',
269
+ apiVersion: 1,
270
+ transform: createMarkdownSourceDecoration({
271
+ name: 'representative-decoration',
272
+ ranges: [{start: heading, end: heading + '## Section 0'.length}],
273
+ }),
274
+ });
275
+ }
276
+
277
+ // Each case runs the paired protocol twice (10 warmups, then 9 rounds of two
278
+ // 20-iteration averages per side), so a 500-section case parses ~1500 times.
279
+ // The bounds below are the measured cost plus generous headroom for a busy
280
+ // machine; they exist so a hang fails loudly instead of stalling the suite.
281
+ const TIMEOUT_MS: Readonly<Record<number, number>> = {
282
+ 200: 60_000,
283
+ 500: 180_000,
284
+ };
285
+
286
+ describe('Markdown helper performance', () => {
287
+ // The skip path's real contract is a work count, not a clock: an unclaimed
288
+ // helper's transform must never be entered, for a stable list and for a
289
+ // recreated equivalent one. Asserting the count directly is exact and
290
+ // immune to what else the machine is running; the timing cases below cover
291
+ // the helpers that do run.
292
+ it.each([200, 500])(
293
+ 'skips ten hinted no-claim helpers at %i sections',
294
+ sections => {
295
+ const source = benchmarkDocument(sections);
296
+ const baseline = parseMarkdown(source);
297
+ transformCalls = 0;
298
+
299
+ expect(parseMarkdown(source, {plugins: zeroWorkPlugins})).toEqual(
300
+ baseline,
301
+ );
302
+ expect(parseMarkdown(source, {plugins: [...zeroWorkPlugins]})).toEqual(
303
+ baseline,
304
+ );
305
+ expect(transformCalls).toBe(0);
306
+ },
307
+ TIMEOUT_MS[500],
308
+ );
309
+
310
+ it.each([200, 500])(
311
+ 'adds at most 15 percent over plain transforms for five sweeping decorations at %i sections',
312
+ sections => {
313
+ const source = benchmarkDocument(sections);
314
+ const sweeping = gapDecorationPlugins(source, 5, 1, 'gap-decoration');
315
+ const ratio = pairedMedianRatio(
316
+ () => parseMarkdown(source, {plugins: identityFivePlugins}).length,
317
+ () => parseMarkdown(source, {plugins: sweeping}).length,
318
+ );
319
+ console.log(
320
+ ` ${sections} sections, sweeping decoration over identity: ${ratio.toFixed(3)}`,
321
+ );
322
+ expect(ratio).toBeLessThanOrEqual(1.15);
323
+ },
324
+ TIMEOUT_MS[500],
325
+ );
326
+
327
+ it.each([200, 500])(
328
+ 'costs the ranges it carries, not blocks times ranges, at %i sections',
329
+ sections => {
330
+ const source = benchmarkDocument(sections);
331
+ // The sweep admits and retires each range once, so doubling the
332
+ // ranges over the same document should roughly double the sweep's
333
+ // own work — not square it. Both sides walk every block and decorate
334
+ // nothing, so range count is the only thing that differs, and the
335
+ // bound sits far below the 4x a blocks-times-ranges implementation
336
+ // would show.
337
+ const gaps: {start: number; end: number}[] = [];
338
+ for (
339
+ let gap = source.indexOf('\n\n');
340
+ gap >= 0;
341
+ gap = source.indexOf('\n\n', gap + 1)
342
+ ) {
343
+ gaps.push({start: gap, end: gap + 1});
344
+ }
345
+ const doubled = gaps.flatMap(gap => [
346
+ gap,
347
+ {start: gap.start, end: gap.end + 1},
348
+ ]);
349
+ const plugin = (
350
+ name: string,
351
+ ranges: ReadonlyArray<{start: number; end: number}>,
352
+ ) => [
353
+ createMarkdownPlugin({
354
+ name: `${name}-${sections}`,
355
+ apiVersion: 1,
356
+ transform: createMarkdownSourceDecoration({name, ranges}),
357
+ }),
358
+ ];
359
+
360
+ // Timed on the transform stage alone and compared at the FASTEST
361
+ // sample of each side: this is a few hundred microseconds against a
362
+ // parse of milliseconds, so measuring the whole parse buries it, and
363
+ // a minimum is the least-disturbed sample each side achieved.
364
+ const root = parseMarkdownAst(source);
365
+ const fastestTransform = (
366
+ plugins: ReadonlyArray<ReturnType<typeof createMarkdownPlugin>>,
367
+ ): number => {
368
+ const prepared = prepareMarkdownPlugins(plugins);
369
+ let fastest = Number.POSITIVE_INFINITY;
370
+ for (let sample = 0; sample < 60; sample++) {
371
+ const start = performance.now();
372
+ benchmarkSink ^= applyMarkdownTransforms(
373
+ root,
374
+ prepared,
375
+ source,
376
+ true,
377
+ 'block',
378
+ ).children.length;
379
+ fastest = Math.min(fastest, performance.now() - start);
380
+ }
381
+ void benchmarkSink;
382
+ return fastest;
383
+ };
384
+
385
+ const single = plugin('scale-single', gaps);
386
+ const double = plugin('scale-double', doubled);
387
+ // Warm both before either is recorded.
388
+ fastestTransform(single);
389
+ fastestTransform(double);
390
+ const ratio = fastestTransform(double) / fastestTransform(single);
391
+ console.log(
392
+ ` ${sections} sections, ${doubled.length} ranges over ${gaps.length}: ${ratio.toFixed(3)}`,
393
+ );
394
+ expect(ratio).toBeLessThanOrEqual(2.6);
395
+ },
396
+ TIMEOUT_MS[500],
397
+ );
398
+
399
+ it.each([200, 500])(
400
+ 'adds at most 15 percent to a matching prose helper when it decorates a known range at %i sections',
401
+ sections => {
402
+ const source = benchmarkDocument(sections);
403
+ // The baseline's second transform also returns a replacement root, so
404
+ // both sides pay Core's validation of a changed tree and the ratio
405
+ // reports the decoration walk itself.
406
+ const withoutDecoration = [
407
+ identifierPlugin,
408
+ createMarkdownPlugin({
409
+ name: `representative-replacement-${sections}`,
410
+ apiVersion: 1,
411
+ transform: root => ({...root}),
412
+ }),
413
+ ];
414
+ const withDecoration = [
415
+ identifierPlugin,
416
+ knownRangeDecorationPlugin(source),
417
+ ];
418
+ const ratio = pairedMedianRatio(
419
+ () => parseMarkdown(source, {plugins: withoutDecoration}).length,
420
+ () => parseMarkdown(source, {plugins: withDecoration}).length,
421
+ );
422
+ console.log(
423
+ ` ${sections} sections, known-range decoration over prose helper: ${ratio.toFixed(3)}`,
424
+ );
425
+ expect(ratio).toBeLessThanOrEqual(1.15);
426
+ },
427
+ TIMEOUT_MS[500],
428
+ );
429
+
430
+ it.each([200, 500])(
431
+ 'keeps the representative three-helper set within 25 percent of three plain transforms at %i sections',
432
+ sections => {
433
+ const source = benchmarkDocument(sections);
434
+ // The same set against three transforms that each return a replacement
435
+ // root. Both sides then pay Core's per-transform guards, so this ratio
436
+ // reports what the three helpers themselves cost — the part a helper
437
+ // change can actually move.
438
+ const baseline = Array.from({length: 3}, (_, index) =>
439
+ createMarkdownPlugin({
440
+ name: `representative-baseline-${sections}-${index}`,
441
+ apiVersion: 1,
442
+ transform: root => ({...root}),
443
+ }),
444
+ );
445
+ const representative = [
446
+ identifierPlugin,
447
+ fencePlugin,
448
+ knownRangeDecorationPlugin(source),
449
+ ];
450
+ const ratio = pairedMedianRatio(
451
+ () => parseMarkdown(source, {plugins: baseline}).length,
452
+ () => parseMarkdown(source, {plugins: representative}).length,
453
+ );
454
+ console.log(
455
+ ` ${sections} sections, representative set over three transforms: ${ratio.toFixed(3)}`,
456
+ );
457
+ expect(ratio).toBeLessThanOrEqual(1.25);
458
+ },
459
+ TIMEOUT_MS[500],
460
+ );
461
+
462
+ it.each([200, 500])(
463
+ 'keeps a trusted helper far below an equivalent plugin-authored transform at %i sections',
464
+ sections => {
465
+ const source = benchmarkDocument(sections);
466
+ // Trusted Core helpers skip the guards Core applies to plugin-authored
467
+ // output. Comparing the decoration helper against a plugin transform
468
+ // that returns an equivalent replacement root measures that saving
469
+ // without depending on absolute machine speed.
470
+ const pluginAuthored = createMarkdownPlugin({
471
+ name: `trusted-comparison-${sections}`,
472
+ apiVersion: 1,
473
+ transform: root => ({...root, children: [...root.children]}),
474
+ });
475
+ const ratio = pairedMedianRatio(
476
+ () => parseMarkdown(source, {plugins: [pluginAuthored]}).length,
477
+ () =>
478
+ parseMarkdown(source, {
479
+ plugins: [knownRangeDecorationPlugin(source)],
480
+ }).length,
481
+ );
482
+ console.log(
483
+ ` ${sections} sections, trusted decoration over plugin-authored transform: ${ratio.toFixed(3)}`,
484
+ );
485
+ expect(ratio).toBeLessThanOrEqual(0.85);
486
+ },
487
+ TIMEOUT_MS[500],
488
+ );
489
+ });
@@ -2,9 +2,9 @@
2
2
 
3
3
  /**
4
4
  * @file Markdown.public.test.ts
5
- * @input Imports Markdown parser functions and node types from the public barrel
6
- * @output Compile-time compatibility coverage for legacy and math-enabled results
7
- * @position Public API test guarding @astryxdesign/core/Markdown
5
+ * @input Imports Markdown parser, plugin factory, visitor, and node types from the public Markdown and plugin barrels
6
+ * @output Compile-time compatibility coverage for legacy, math-enabled, and plugin results
7
+ * @position Public API test guarding @astryxdesign/core/Markdown and /Markdown/plugins
8
8
  */
9
9
 
10
10
  import {describe, expectTypeOf, it} from 'vitest';
@@ -13,7 +13,21 @@ import {
13
13
  parseInline,
14
14
  parseMarkdown,
15
15
  parseMarkdownIncremental,
16
+ visitMarkdownNodes,
16
17
  } from './index';
18
+ import {
19
+ createMarkdownFenceTransform,
20
+ createMarkdownPlugin,
21
+ createMarkdownTextTransform,
22
+ isMarkdownExtensionNode,
23
+ } from './plugins';
24
+ import type {
25
+ MarkdownExtensionNode,
26
+ MarkdownFenceTransformOptions,
27
+ MarkdownPluginEntry,
28
+ MarkdownSyntaxPluginDefinition,
29
+ MarkdownTransform,
30
+ } from './plugins';
17
31
  import type {
18
32
  BlockNode,
19
33
  BlockNodeWithMath,
@@ -154,4 +168,113 @@ describe('Markdown public parser types', () => {
154
168
  Extract<BlockNodeWithMath, {type: 'math'}>['value']
155
169
  >().toBeString();
156
170
  });
171
+
172
+ it('exports typed plugin construction and node-kind visitors', () => {
173
+ type PublicNode = MarkdownExtensionNode<
174
+ 'public-demo',
175
+ 'token',
176
+ {readonly label: string},
177
+ 'inline'
178
+ >;
179
+ const definition = {
180
+ name: 'public-demo',
181
+ apiVersion: 1,
182
+ parseKey: 'v1',
183
+ syntax: {
184
+ inline: [
185
+ {
186
+ startsWith: ['::'],
187
+ maxSpan: 20,
188
+ tokenize: () => ({status: 'no-match'}) as const,
189
+ },
190
+ ],
191
+ },
192
+ renderers: {
193
+ token: {
194
+ render: () => null,
195
+ toText: node => node.data.label,
196
+ },
197
+ },
198
+ } satisfies MarkdownSyntaxPluginDefinition<'public-demo', PublicNode>;
199
+ const plugin = createMarkdownPlugin<'public-demo', PublicNode>(definition);
200
+ const nodes = parseInline('plain', {plugins: [plugin] as const});
201
+
202
+ expectTypeOf(nodes).toEqualTypeOf<InlineNode<PublicNode>[]>();
203
+ expectTypeOf(visitMarkdownNodes).toBeFunction();
204
+ expectTypeOf(createMarkdownTextTransform).toBeFunction();
205
+ expectTypeOf(isMarkdownExtensionNode).toBeFunction();
206
+
207
+ function compileOnlyPluginGuards() {
208
+ // @ts-expect-error transforms that own extension nodes require renderers
209
+ createMarkdownPlugin<'public-demo', PublicNode>({
210
+ name: 'public-demo',
211
+ apiVersion: 1,
212
+ transform: root => root,
213
+ });
214
+ }
215
+ expectTypeOf(compileOnlyPluginGuards).toBeFunction();
216
+ });
217
+
218
+ it('exports a language-narrowed semantic fence transform helper', () => {
219
+ type PublicFenceNode = MarkdownExtensionNode<
220
+ 'public-semantic-fences',
221
+ 'diagram',
222
+ {
223
+ readonly code: string;
224
+ readonly language: 'mermaid' | 'dot';
225
+ readonly meta?: string;
226
+ },
227
+ 'block'
228
+ >;
229
+ const options = {
230
+ languages: ['mermaid', 'dot'] as const,
231
+ createNode: ({language, code, meta}) => {
232
+ expectTypeOf(language).toEqualTypeOf<'mermaid' | 'dot'>();
233
+ expectTypeOf(code).toBeString();
234
+ expectTypeOf(meta).toEqualTypeOf<string | undefined>();
235
+ return {
236
+ type: 'extension',
237
+ plugin: 'public-semantic-fences',
238
+ name: 'diagram',
239
+ display: 'block',
240
+ data: {
241
+ code,
242
+ language,
243
+ ...(meta == null ? {} : {meta}),
244
+ },
245
+ } as const;
246
+ },
247
+ } satisfies MarkdownFenceTransformOptions<
248
+ readonly ['mermaid', 'dot'],
249
+ PublicFenceNode
250
+ >;
251
+ const transform = createMarkdownFenceTransform(options);
252
+ const plugin = createMarkdownPlugin<
253
+ 'public-semantic-fences',
254
+ PublicFenceNode
255
+ >({
256
+ name: 'public-semantic-fences',
257
+ apiVersion: 1,
258
+ transform,
259
+ renderers: {
260
+ diagram: {
261
+ render: () => null,
262
+ toText: node => node.data.code,
263
+ },
264
+ },
265
+ });
266
+ const typedTransform: MarkdownTransform<PublicFenceNode> = transform;
267
+
268
+ expectTypeOf(typedTransform).toBeFunction();
269
+ expectTypeOf(plugin).toEqualTypeOf<MarkdownPluginEntry<PublicFenceNode>>();
270
+
271
+ function compileOnlyFenceGuards() {
272
+ createMarkdownFenceTransform({
273
+ languages: ['mermaid'],
274
+ // @ts-expect-error fence helpers create data nodes; render belongs in renderers
275
+ render: () => null,
276
+ });
277
+ }
278
+ expectTypeOf(compileOnlyFenceGuards).toBeFunction();
279
+ });
157
280
  });