@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,957 @@
1
+ // Copyright (c) Meta Platforms, Inc. and affiliates.
2
+
3
+ /**
4
+ * @file protocol.ts
5
+ * @input Markdown plugin definitions, syntax tokenizers, immutable transforms, and renderers
6
+ * @output Public plugin protocol plus validated internal preparation and execution
7
+ * @position Shared Markdown extension boundary consumed by the parser and renderer
8
+ */
9
+
10
+ import { devError, warnOnce } from "../../utils/devWarning.js";
11
+ import { isSafeMarkdownParserUrl } from "../url.js";
12
+ export function isMarkdownExtensionNode(node, plugin, name) {
13
+ return node.type === 'extension' && node.plugin === plugin && node.name === name;
14
+ }
15
+ const markdownTransformPluginName = Symbol('MarkdownTransformPluginName');
16
+ const markdownTransformHasRenderer = Symbol('MarkdownTransformHasRenderer');
17
+ const markdownTransformSourceUnchanged = Symbol('MarkdownTransformSourceUnchanged');
18
+ /** @internal Reads the owning plugin name without expanding the public context. */
19
+ export function getMarkdownTransformPluginName(context) {
20
+ return context[markdownTransformPluginName];
21
+ }
22
+
23
+ /**
24
+ * @internal The ownership facts a Core helper needs to validate the nodes a
25
+ * caller's callback handed it, without seeing the rest of the pipeline.
26
+ */
27
+
28
+ /** @internal Reads this transform's ownership, when Core is running it. */
29
+ export function getMarkdownHelperOwnership(context) {
30
+ const internal = context;
31
+ const pluginName = internal[markdownTransformPluginName];
32
+ const hasRenderer = internal[markdownTransformHasRenderer];
33
+ const sourceUnchanged = internal[markdownTransformSourceUnchanged];
34
+ return pluginName === undefined || hasRenderer === undefined || sourceUnchanged === undefined ? undefined : {
35
+ pluginName,
36
+ hasRenderer,
37
+ sourceUnchanged
38
+ };
39
+ }
40
+ const markdownTransformClaim = Symbol('MarkdownTransformClaim');
41
+ const markdownTransformTrusted = Symbol('MarkdownTransformTrusted');
42
+ /**
43
+ * @internal Marks a Core-authored transform whose OUTPUT STRUCTURE is entirely
44
+ * Core-computed — it never inserts a caller-supplied node, never edits an
45
+ * existing node's meaning, provenance, or ownership, and never mutates its
46
+ * input. Core then skips the validation and immutability guards it applies to
47
+ * plugin-authored output, whose purpose is to contain untrusted structure.
48
+ *
49
+ * Only helpers in this package may be marked, and only when every node they
50
+ * emit is built here from validated inputs. A helper that inserts anything the
51
+ * caller supplied — the text helper's replacement nodes, for example — is NOT
52
+ * trusted: Core must still validate the tree it returns.
53
+ */
54
+ export function markMarkdownTransformTrusted(transform) {
55
+ Object.defineProperty(transform, markdownTransformTrusted, {
56
+ configurable: false,
57
+ enumerable: false,
58
+ value: true,
59
+ writable: false
60
+ });
61
+ return transform;
62
+ }
63
+
64
+ /** @internal Registers a cheap source-level claim check for a helper transform. */
65
+ export function markMarkdownTransformClaim(transform, claims) {
66
+ Object.defineProperty(transform, markdownTransformClaim, {
67
+ configurable: false,
68
+ enumerable: false,
69
+ value: claims,
70
+ writable: false
71
+ });
72
+ return transform;
73
+ }
74
+
75
+ /** Opaque, covariant entry safe to store in heterogeneous plugin lists. */
76
+
77
+ const MARKDOWN_PLUGIN_BRAND = '@astryxdesign/core/MarkdownPluginEntry';
78
+ const markdownPluginDefinition = Symbol.for(MARKDOWN_PLUGIN_BRAND);
79
+ function getMarkdownPluginDefinition(publicEntry) {
80
+ if (publicEntry == null || typeof publicEntry !== 'object' || Object.getPrototypeOf(publicEntry) !== Object.prototype) {
81
+ fail('entries must come from a compatible createMarkdownPlugin()');
82
+ }
83
+ const entry = publicEntry;
84
+ const brand = entry[markdownPluginDefinition];
85
+ const definition = brand?.definition;
86
+ if (Reflect.ownKeys(entry).length !== 3 || typeof entry.name !== 'string' || entry.apiVersion !== 1 || !Object.isFrozen(entry) || brand == null || typeof brand !== 'object' || Object.getPrototypeOf(brand) !== Object.prototype || Reflect.ownKeys(brand).length !== 3 || !Object.isFrozen(brand) || brand.kind !== MARKDOWN_PLUGIN_BRAND || brand.apiVersion !== 1 || definition == null || typeof definition !== 'object' || !Object.isFrozen(definition) || definition.name !== entry.name || definition.apiVersion !== entry.apiVersion) {
87
+ fail('entries must come from a compatible createMarkdownPlugin()');
88
+ }
89
+ return definition;
90
+ }
91
+ function deepFreezeConfig(value, seen = new Set()) {
92
+ if (value != null && typeof value === 'object' && !seen.has(value)) {
93
+ seen.add(value);
94
+ for (const nested of Object.values(value)) {
95
+ deepFreezeConfig(nested, seen);
96
+ }
97
+ Object.freeze(value);
98
+ }
99
+ return value;
100
+ }
101
+ function fail(message) {
102
+ throw new Error(`Markdown plugin: ${message}`);
103
+ }
104
+ function validateSyntax(pluginName, syntax) {
105
+ const contributions = [...(syntax.inline ?? []), ...(syntax.block ?? [])];
106
+ if (contributions.length === 0) {
107
+ fail(`"${pluginName}" syntax must declare an inline or block contribution`);
108
+ }
109
+ for (const contribution of contributions) {
110
+ if (!Number.isFinite(contribution.maxSpan) || contribution.maxSpan <= 0) {
111
+ fail(`"${pluginName}" syntax maxSpan must be positive and finite`);
112
+ }
113
+ for (const prefix of contribution.startsWith) {
114
+ if (prefix === '' || prefix.length > contribution.maxSpan) {
115
+ fail(`"${pluginName}" syntax prefixes must be non-empty and bounded`);
116
+ }
117
+ }
118
+ }
119
+ }
120
+ export function createMarkdownPlugin(definition) {
121
+ if (definition.name.trim() === '') {
122
+ fail('name must be a non-empty string');
123
+ }
124
+ if (definition.apiVersion !== 1) {
125
+ fail(`"${definition.name}" uses unsupported apiVersion`);
126
+ }
127
+ if (typeof definition.transform !== 'undefined' && typeof definition.transform !== 'function') {
128
+ fail(`"${definition.name}" transform must be a function`);
129
+ }
130
+ if ('syntax' in definition && definition.syntax != null) {
131
+ if (definition.parseKey.trim() === '') {
132
+ fail(`"${definition.name}" parseKey must be non-empty`);
133
+ }
134
+ validateSyntax(definition.name, definition.syntax);
135
+ if (Object.keys(definition.renderers).length === 0) {
136
+ fail(`"${definition.name}" syntax must provide renderers`);
137
+ }
138
+ } else if (definition.transform == null) {
139
+ fail(`"${definition.name}" must declare syntax or transform`);
140
+ }
141
+ const frozenDefinition = deepFreezeConfig(definition);
142
+ const brand = Object.freeze({
143
+ kind: MARKDOWN_PLUGIN_BRAND,
144
+ apiVersion: 1,
145
+ definition: frozenDefinition
146
+ });
147
+ return Object.freeze({
148
+ name: frozenDefinition.name,
149
+ apiVersion: 1,
150
+ [markdownPluginDefinition]: brand
151
+ });
152
+ }
153
+ const preparedPluginLists = new WeakMap();
154
+ function appendMapValue(map, key, value) {
155
+ const current = map.get(key);
156
+ if (current == null) {
157
+ map.set(key, [value]);
158
+ } else {
159
+ current.push(value);
160
+ }
161
+ }
162
+ function syntaxOnlyEntry(publicEntry) {
163
+ const entry = publicEntry;
164
+ const definition = getMarkdownPluginDefinition(publicEntry);
165
+ if (definition.transform == null) {
166
+ return publicEntry;
167
+ }
168
+ const syntaxDefinition = Object.freeze({
169
+ ...definition,
170
+ transform: undefined
171
+ });
172
+ return Object.freeze({
173
+ name: entry.name,
174
+ apiVersion: entry.apiVersion,
175
+ [markdownPluginDefinition]: Object.freeze({
176
+ kind: MARKDOWN_PLUGIN_BRAND,
177
+ apiVersion: 1,
178
+ definition: syntaxDefinition
179
+ })
180
+ });
181
+ }
182
+ export function prepareMarkdownPlugins(plugins) {
183
+ if (plugins.length === 0) {
184
+ return undefined;
185
+ }
186
+ const cached = preparedPluginLists.get(plugins);
187
+ if (cached != null) {
188
+ return cached;
189
+ }
190
+ const names = new Set();
191
+ const inlineByFirstCharacter = new Map();
192
+ const blockByFirstCharacter = new Map();
193
+ const transforms = [];
194
+ const renderers = new Map();
195
+ const syntaxIdentity = [];
196
+ const entries = [];
197
+ const syntaxEntries = [];
198
+ for (const publicEntry of plugins) {
199
+ const definition = getMarkdownPluginDefinition(publicEntry);
200
+ const entry = publicEntry;
201
+ if (names.has(definition.name)) {
202
+ fail(`duplicate name "${definition.name}"`);
203
+ }
204
+ names.add(definition.name);
205
+ entries.push(entry);
206
+ if (definition.transform != null) {
207
+ transforms.push({
208
+ pluginName: definition.name,
209
+ transform: definition.transform,
210
+ claims: definition.transform[markdownTransformClaim],
211
+ trusted: definition.transform[markdownTransformTrusted] === true
212
+ });
213
+ }
214
+ if (definition.renderers != null) {
215
+ for (const [nodeName, renderer] of Object.entries(definition.renderers)) {
216
+ renderers.set(`${definition.name}\0${nodeName}`, {
217
+ pluginName: definition.name,
218
+ renderer: renderer
219
+ });
220
+ }
221
+ }
222
+ if ('syntax' in definition && definition.syntax != null) {
223
+ syntaxEntries.push(syntaxOnlyEntry(publicEntry));
224
+ syntaxIdentity.push(`${definition.name}\0${definition.apiVersion}\0${definition.parseKey}`);
225
+ for (const contribution of definition.syntax.inline ?? []) {
226
+ const prepared = {
227
+ pluginName: definition.name,
228
+ display: 'inline',
229
+ contribution
230
+ };
231
+ for (const firstCharacter of new Set(contribution.startsWith.map(prefix => prefix[0]))) {
232
+ appendMapValue(inlineByFirstCharacter, firstCharacter, prepared);
233
+ }
234
+ }
235
+ for (const contribution of definition.syntax.block ?? []) {
236
+ const prepared = {
237
+ pluginName: definition.name,
238
+ display: 'block',
239
+ contribution
240
+ };
241
+ for (const firstCharacter of new Set(contribution.startsWith.map(prefix => prefix[0]))) {
242
+ appendMapValue(blockByFirstCharacter, firstCharacter, prepared);
243
+ }
244
+ }
245
+ }
246
+ }
247
+ const prepared = {
248
+ entries,
249
+ syntaxEntries,
250
+ inlineByFirstCharacter,
251
+ blockByFirstCharacter,
252
+ transforms,
253
+ hasUntrustedTransform: transforms.some(entry => !entry.trusted),
254
+ syntaxIdentity: syntaxIdentity.join('\u0001'),
255
+ renderers
256
+ };
257
+ preparedPluginLists.set(plugins, prepared);
258
+ return prepared;
259
+ }
260
+ export function isMarkdownPluginData(value, seen = new Set()) {
261
+ if (value == null || typeof value === 'boolean' || typeof value === 'string') {
262
+ return true;
263
+ }
264
+ if (typeof value === 'number') {
265
+ return Number.isFinite(value);
266
+ }
267
+ if (typeof value !== 'object' || seen.has(value)) {
268
+ return false;
269
+ }
270
+ seen.add(value);
271
+ let valid;
272
+ if (Array.isArray(value)) {
273
+ valid = value.every(item => isMarkdownPluginData(item, seen));
274
+ } else if (Object.getPrototypeOf(value) !== Object.prototype) {
275
+ valid = false;
276
+ } else {
277
+ valid = Object.values(value).every(item => isMarkdownPluginData(item, seen));
278
+ }
279
+ seen.delete(value);
280
+ return valid;
281
+ }
282
+ export function freezeMarkdownPluginData(value) {
283
+ if (value != null && typeof value === 'object' && !Object.isFrozen(value)) {
284
+ for (const nested of Object.values(value)) {
285
+ freezeMarkdownPluginData(nested);
286
+ }
287
+ Object.freeze(value);
288
+ }
289
+ return value;
290
+ }
291
+ function positionKey(position) {
292
+ const start = position?.start.offset;
293
+ const end = position?.end.offset;
294
+ return start == null || end == null ? null : `${start}:${end}`;
295
+ }
296
+ function codeSourceSignature(node) {
297
+ return JSON.stringify([node.lang, node.meta, node.value, node.position ?? null]);
298
+ }
299
+ function collectCodeInternalProperties(root) {
300
+ const properties = new Map();
301
+ const visit = node => {
302
+ if (node.type === 'code') {
303
+ const descriptors = Object.getOwnPropertySymbols(node).map(symbol => [symbol, Object.getOwnPropertyDescriptor(node, symbol)]).filter(entry => entry[1]?.enumerable === true);
304
+ if (descriptors.length > 0) {
305
+ const key = codeSourceSignature(node);
306
+ properties.set(key, [...(properties.get(key) ?? []), {
307
+ descriptors
308
+ }]);
309
+ }
310
+ }
311
+ if ('children' in node && Array.isArray(node.children)) {
312
+ for (const child of node.children) {
313
+ if (child != null && typeof child === 'object') {
314
+ visit(child);
315
+ }
316
+ }
317
+ }
318
+ };
319
+ visit(root);
320
+ return properties;
321
+ }
322
+ function restoreCodeInternalProperties(previous, next) {
323
+ const properties = collectCodeInternalProperties(previous);
324
+ if (properties.size === 0) {
325
+ return next;
326
+ }
327
+ const visit = node => {
328
+ let current = node;
329
+ if (node.type === 'code') {
330
+ const key = codeSourceSignature(node);
331
+ const queue = properties.get(key);
332
+ const internal = queue?.shift();
333
+ const shouldRestore = internal?.descriptors.some(([symbol, descriptor]) => {
334
+ const current = Object.getOwnPropertyDescriptor(node, symbol);
335
+ return current == null || current.value !== descriptor.value || current.get !== descriptor.get || current.set !== descriptor.set || current.enumerable !== descriptor.enumerable || current.configurable !== descriptor.configurable || current.writable !== descriptor.writable;
336
+ });
337
+ if (internal != null && shouldRestore === true) {
338
+ const clone = {
339
+ ...node
340
+ };
341
+ for (const [symbol, descriptor] of internal.descriptors) {
342
+ Object.defineProperty(clone, symbol, descriptor);
343
+ }
344
+ current = clone;
345
+ }
346
+ }
347
+ if ('children' in current && Array.isArray(current.children)) {
348
+ const currentChildren = current.children;
349
+ const children = currentChildren.map(child => visit(child));
350
+ if (children.some((child, index) => child !== currentChildren[index])) {
351
+ const parent = {
352
+ ...current,
353
+ children
354
+ };
355
+ current = parent;
356
+ }
357
+ }
358
+ return current;
359
+ };
360
+ return visit(next);
361
+ }
362
+ function collectSourceInvariants(root) {
363
+ const positions = new Map();
364
+ const visit = node => {
365
+ const key = positionKey(node.position);
366
+ if (key != null) {
367
+ const record = node;
368
+ const invariant = {
369
+ type: node.type,
370
+ depth: record.depth,
371
+ ordered: record.ordered,
372
+ start: record.start,
373
+ delimiter: record.delimiter,
374
+ plugin: record.plugin,
375
+ name: record.name,
376
+ display: record.display
377
+ };
378
+ positions.set(key, [...(positions.get(key) ?? []), invariant]);
379
+ }
380
+ if ('children' in node && Array.isArray(node.children)) {
381
+ for (const child of node.children) {
382
+ if (child != null && typeof child === 'object') {
383
+ visit(child);
384
+ }
385
+ }
386
+ }
387
+ };
388
+ visit(root);
389
+ return positions;
390
+ }
391
+ function extensionSignature(node) {
392
+ return JSON.stringify([node.plugin, node.name, node.display, node.data, node.source, positionKey(node.position)]);
393
+ }
394
+ function collectExtensionSignatures(root) {
395
+ const signatures = new Map();
396
+ const visit = node => {
397
+ if (node.type === 'extension') {
398
+ const signature = extensionSignature(node);
399
+ const existing = signatures.get(signature);
400
+ signatures.set(signature, {
401
+ plugin: String(node.plugin),
402
+ count: (existing?.count ?? 0) + 1
403
+ });
404
+ }
405
+ if ('children' in node && Array.isArray(node.children)) {
406
+ for (const child of node.children) {
407
+ if (child != null && typeof child === 'object') {
408
+ visit(child);
409
+ }
410
+ }
411
+ }
412
+ };
413
+ visit(root);
414
+ return signatures;
415
+ }
416
+ const sourceHeadingMarker = Symbol('MarkdownSourceHeading');
417
+ function markSourceHeadings(root) {
418
+ const markers = new Set();
419
+ const visit = node => {
420
+ if (node.type === 'heading' && !(sourceHeadingMarker in node)) {
421
+ Object.defineProperty(node, sourceHeadingMarker, {
422
+ configurable: false,
423
+ enumerable: true,
424
+ value: Object.freeze({
425
+ depth: node.depth
426
+ }),
427
+ writable: false
428
+ });
429
+ }
430
+ if (node.type === 'heading') {
431
+ markers.add(node[sourceHeadingMarker]);
432
+ }
433
+ if ('children' in node && Array.isArray(node.children)) {
434
+ for (const child of node.children) {
435
+ if (child != null && typeof child === 'object') {
436
+ visit(child);
437
+ }
438
+ }
439
+ }
440
+ };
441
+ visit(root);
442
+ return markers;
443
+ }
444
+ const PHRASING_TYPES = new Set(['text', 'strong', 'emphasis', 'delete', 'inlineCode', 'inlineMath', 'break', 'link', 'image', 'citation']);
445
+ const BLOCK_TYPES = new Set(['heading', 'paragraph', 'code', 'math', 'blockquote', 'list', 'table', 'thematicBreak', 'image']);
446
+ const PHRASING_PARENTS = new Set(['heading', 'paragraph', 'strong', 'emphasis', 'delete', 'link', 'tableCell']);
447
+ const BLOCK_PARENTS = new Set(['root', 'blockquote', 'listItem']);
448
+ const CHILD_PARENT_TYPES = new Set([...PHRASING_PARENTS, ...BLOCK_PARENTS, 'list', 'table', 'tableRow']);
449
+ function validateAst(root, pluginNames, rendererKeys, sourcePositions, sourceHeadingMarkers, activePluginName, existingExtensions, display) {
450
+ if (root == null || typeof root !== 'object') {
451
+ return false;
452
+ }
453
+ const seen = new Set();
454
+ const seenHeadingMarkers = new Set();
455
+ let count = 0;
456
+ const visit = (value, parent, insideLink) => {
457
+ if (value == null || typeof value !== 'object' || seen.has(value)) {
458
+ return false;
459
+ }
460
+ if (++count > 100_000) {
461
+ return false;
462
+ }
463
+ seen.add(value);
464
+ const node = value;
465
+ const type = node.type;
466
+ if (typeof type !== 'string') {
467
+ return false;
468
+ }
469
+ if (node.data !== undefined && !isMarkdownPluginData(node.data)) {
470
+ return false;
471
+ }
472
+ if (parent != null) {
473
+ const extensionDisplay = type === 'extension' ? node.display : undefined;
474
+ const phrasing = PHRASING_TYPES.has(type) || extensionDisplay === 'inline';
475
+ const block = BLOCK_TYPES.has(type) || extensionDisplay === 'block';
476
+ if (PHRASING_PARENTS.has(parent) && !phrasing || BLOCK_PARENTS.has(parent) && !block || insideLink && type === 'link' || parent === 'list' && type !== 'listItem' || parent === 'table' && type !== 'tableRow' || parent === 'tableRow' && type !== 'tableCell') {
477
+ return false;
478
+ }
479
+ }
480
+ const position = node.position;
481
+ const key = positionKey(position);
482
+ if (position != null) {
483
+ const start = position.start?.offset;
484
+ const end = position.end?.offset;
485
+ if (!Number.isInteger(start) || !Number.isInteger(end) || start < 0 || end < start) {
486
+ return false;
487
+ }
488
+ }
489
+ if (key != null) {
490
+ const invariants = sourcePositions.get(key) ?? [];
491
+ const invariantIndex = invariants.findIndex(invariant => invariant.type === type && invariant.depth === node.depth && invariant.ordered === node.ordered && invariant.start === node.start && invariant.delimiter === node.delimiter && invariant.plugin === node.plugin && invariant.name === node.name && invariant.display === node.display);
492
+ if (invariantIndex < 0) {
493
+ return false;
494
+ }
495
+ invariants.splice(invariantIndex, 1);
496
+ }
497
+ if (type !== 'extension' && node.source !== undefined) {
498
+ return false;
499
+ }
500
+ switch (type) {
501
+ case 'root':
502
+ if (parent != null) {
503
+ return false;
504
+ }
505
+ break;
506
+ case 'heading':
507
+ {
508
+ if (![1, 2, 3, 4, 5, 6].includes(node.depth)) {
509
+ return false;
510
+ }
511
+ const marker = node[sourceHeadingMarker];
512
+ if (marker != null && (!sourceHeadingMarkers.has(marker) || marker.depth !== node.depth || seenHeadingMarkers.has(marker))) {
513
+ return false;
514
+ }
515
+ if (marker != null) {
516
+ seenHeadingMarkers.add(marker);
517
+ }
518
+ break;
519
+ }
520
+ case 'text':
521
+ case 'inlineCode':
522
+ case 'inlineMath':
523
+ case 'math':
524
+ if (typeof node.value !== 'string') {
525
+ return false;
526
+ }
527
+ break;
528
+ case 'code':
529
+ if (typeof node.value !== 'string' || node.lang !== null && typeof node.lang !== 'string' || node.meta !== undefined && typeof node.meta !== 'string') {
530
+ return false;
531
+ }
532
+ break;
533
+ case 'link':
534
+ if (typeof node.url !== 'string' || !isSafeMarkdownParserUrl(node.url)) {
535
+ return false;
536
+ }
537
+ break;
538
+ case 'image':
539
+ if (typeof node.url !== 'string' || !isSafeMarkdownParserUrl(node.url) || typeof node.alt !== 'string') {
540
+ return false;
541
+ }
542
+ break;
543
+ case 'citation':
544
+ if (typeof node.sourceId !== 'string') {
545
+ return false;
546
+ }
547
+ break;
548
+ case 'list':
549
+ if (typeof node.ordered !== 'boolean' || node.start != null && !Number.isFinite(node.start) || node.delimiter != null && node.delimiter !== '.' && node.delimiter !== ')') {
550
+ return false;
551
+ }
552
+ break;
553
+ case 'table':
554
+ if (!Array.isArray(node.align) || !node.align.every(value => value === null || value === 'left' || value === 'center' || value === 'right')) {
555
+ return false;
556
+ }
557
+ break;
558
+ case 'extension':
559
+ {
560
+ if (typeof node.plugin !== 'string' || !pluginNames.has(node.plugin) || typeof node.name !== 'string' || node.display !== 'inline' && node.display !== 'block' || !isMarkdownPluginData(node.data) || !rendererKeys.has(`${node.plugin}\0${node.name}`)) {
561
+ return false;
562
+ }
563
+ const signature = extensionSignature(node);
564
+ const existing = existingExtensions.get(signature);
565
+ if (existing != null && existing.count > 0) {
566
+ existing.count--;
567
+ } else if (node.plugin !== activePluginName || node.source !== undefined || node.position !== undefined) {
568
+ return false;
569
+ }
570
+ break;
571
+ }
572
+ case 'strong':
573
+ case 'emphasis':
574
+ case 'delete':
575
+ case 'break':
576
+ case 'paragraph':
577
+ case 'blockquote':
578
+ case 'listItem':
579
+ case 'tableRow':
580
+ case 'tableCell':
581
+ case 'thematicBreak':
582
+ break;
583
+ default:
584
+ return false;
585
+ }
586
+ if (CHILD_PARENT_TYPES.has(type)) {
587
+ if (!Array.isArray(node.children)) {
588
+ return false;
589
+ }
590
+ for (const child of node.children) {
591
+ if (!visit(child, type, insideLink || type === 'link')) {
592
+ return false;
593
+ }
594
+ }
595
+ } else if ('children' in node) {
596
+ return false;
597
+ }
598
+ return true;
599
+ };
600
+ const candidate = root;
601
+ return visit(candidate, null, false) && candidate.type === 'root' && Array.from(existingExtensions.values()).every(extension => extension.plugin === activePluginName || extension.count === 0) && (display === 'block' || candidate.children.length === 1 && candidate.children[0]?.type === 'paragraph');
602
+ }
603
+
604
+ /**
605
+ * Deeply freezes a Markdown tree.
606
+ *
607
+ * No memo set and no cycle set. Both were measured against this parser's own
608
+ * fixture and together cost four times the freezing they were guarding: a
609
+ * full freeze of a 12k-node tree runs at 19 percent of the parse that built
610
+ * it, a WeakSet memo takes that to 47 percent, and a cycle set to 75. Their
611
+ * absence is safe, not merely cheap: every tree reaching here is acyclic
612
+ * (the parser builds no cycles, and `validateAst` rejects any plugin tree
613
+ * that contains one), and `Object.freeze` on an already-frozen node is a
614
+ * no-op, so re-walking a shared subtree is correct — just not free.
615
+ *
616
+ * Deliberately NOT skipping nodes that look frozen: a node a plugin froze
617
+ * itself may still hold mutable children, and an undecorated sibling a
618
+ * trusted helper carried over by identity must be frozen like any other.
619
+ */
620
+ function freezeAstNode(value) {
621
+ if (value == null || typeof value !== 'object') {
622
+ return;
623
+ }
624
+ if (Array.isArray(value)) {
625
+ for (let index = 0; index < value.length; index++) {
626
+ freezeAstNode(value[index]);
627
+ }
628
+ } else {
629
+ // `for…in` over a plain AST node rather than Object.values: the entries
630
+ // array is the dominant remaining cost of the walk.
631
+ for (const key in value) {
632
+ freezeAstNode(value[key]);
633
+ }
634
+ }
635
+ Object.freeze(value);
636
+ }
637
+ function freezeAst(value) {
638
+ freezeAstNode(value);
639
+ return value;
640
+ }
641
+ const reportedProductionPluginFailures = new Set();
642
+
643
+ /**
644
+ * Freezes only what `next` does not share with `previous`.
645
+ *
646
+ * Valid ONLY when no plugin-authored transform runs in this pipeline. The
647
+ * nodes it skips are the ones a Core helper carried over untouched, and with
648
+ * every transform Core-authored there is no actor that could mutate them:
649
+ * they are left in exactly the state an omitted or empty plugin list leaves
650
+ * them in, which is the state rendering already observes for every
651
+ * zero-plugin document today. The moment one untrusted transform exists,
652
+ * `applyMarkdownTransforms` uses the full `freezeAst` instead, before that
653
+ * transform observes anything — a shared, undecorated sibling included.
654
+ */
655
+ function freezeBuiltAst(previous, next) {
656
+ if (next == null || typeof next !== 'object' || next === previous) {
657
+ return next;
658
+ }
659
+ const before = previous != null && typeof previous === 'object' ? previous : undefined;
660
+ if (Array.isArray(next)) {
661
+ const beforeArray = Array.isArray(previous) ? previous : undefined;
662
+ for (let index = 0; index < next.length; index++) {
663
+ freezeBuiltAst(beforeArray?.[index], next[index]);
664
+ }
665
+ } else {
666
+ for (const key in next) {
667
+ freezeBuiltAst(before?.[key], next[key]);
668
+ }
669
+ }
670
+ Object.freeze(next);
671
+ return next;
672
+ }
673
+ const HELPER_PHRASING_TYPES = new Set(['text', 'strong', 'emphasis', 'delete', 'inlineCode', 'inlineMath', 'break', 'link', 'image', 'citation', 'extension']);
674
+
675
+ /**
676
+ * @internal Validates and freezes phrasing nodes a Core helper's caller just
677
+ * authored, so the helper may put them straight into its output tree.
678
+ * applying exactly the rules `validateAst` applies to newly-introduced nodes:
679
+ * representable typed data only, no authored provenance, no foreign extension
680
+ * ownership, no unrenderable extension, revalidated destinations, no nested
681
+ * link, no block content, no cycles, and a bounded node count.
682
+ *
683
+ * A helper that validates and freezes its callback's output this way has
684
+ * nothing left for Core to check, because every other node it returns is one
685
+ * Core already validated. That is what lets such a helper run on the trusted
686
+ * path while keeping FR10 and FR11 intact.
687
+ *
688
+ * Returns the frozen nodes, or throws — the caller reports the failure
689
+ * through the ordinary transform failure path.
690
+ */
691
+ export function adoptMarkdownHelperNode(node, ownership, insideLink = false) {
692
+ adoptMarkdownHelperNodes(singleNodeScratch(node), ownership, insideLink);
693
+ }
694
+
695
+ /**
696
+ * A one-element view for the single-node case, reused between calls so the
697
+ * common replacement costs no array. Refilled on entry and never held past
698
+ * the synchronous validation below, and a callback that re-enters the
699
+ * helper gets a fresh array rather than disturbing an outer walk.
700
+ */
701
+ let scratchInUse = false;
702
+ const reusableScratch = [undefined];
703
+ function singleNodeScratch(node) {
704
+ if (scratchInUse) {
705
+ return [node];
706
+ }
707
+ reusableScratch[0] = node;
708
+ return reusableScratch;
709
+ }
710
+ export function adoptMarkdownHelperNodes(nodes, ownership, insideLink = false) {
711
+ // The overwhelmingly common replacement is one flat text node. Checking
712
+ // that shape directly avoids the general walk's setup entirely, and this
713
+ // runs once per match.
714
+ if (nodes.length === 1) {
715
+ const only = nodes[0];
716
+ if (only != null && typeof only === 'object' && only.type === 'text' && typeof only.value === 'string') {
717
+ let extra = false;
718
+ for (const key in only) {
719
+ if (key !== 'type' && key !== 'value') {
720
+ extra = true;
721
+ break;
722
+ }
723
+ }
724
+ if (!extra) {
725
+ return;
726
+ }
727
+ }
728
+ }
729
+ // Cycle tracking is allocated only once a node with children appears: the
730
+ // common replacement is a flat node, and this runs once per match.
731
+ let seen;
732
+ let count = 0;
733
+ const visit = (value, withinLink) => {
734
+ if (value == null || typeof value !== 'object' || seen?.has(value)) {
735
+ return false;
736
+ }
737
+ if (++count > 10_000) {
738
+ return false;
739
+ }
740
+ if (Array.isArray(value.children)) {
741
+ seen ??= new Set();
742
+ seen.add(value);
743
+ }
744
+ const node = value;
745
+ const type = node.type;
746
+ if (typeof type !== 'string' || !HELPER_PHRASING_TYPES.has(type)) {
747
+ return false;
748
+ }
749
+ // A helper's callback authors synthetic nodes only: provenance stays
750
+ // Core's to assign, so neither field may be present.
751
+ if (node.position !== undefined) {
752
+ return false;
753
+ }
754
+ if (type !== 'extension' && node.source !== undefined) {
755
+ return false;
756
+ }
757
+ if (node.data !== undefined && !isMarkdownPluginData(node.data)) {
758
+ return false;
759
+ }
760
+ switch (type) {
761
+ case 'text':
762
+ case 'inlineCode':
763
+ case 'inlineMath':
764
+ if (typeof node.value !== 'string') {
765
+ return false;
766
+ }
767
+ break;
768
+ case 'link':
769
+ if (withinLink || typeof node.url !== 'string' || !isSafeMarkdownParserUrl(node.url)) {
770
+ return false;
771
+ }
772
+ break;
773
+ case 'image':
774
+ if (typeof node.url !== 'string' || !isSafeMarkdownParserUrl(node.url) || typeof node.alt !== 'string') {
775
+ return false;
776
+ }
777
+ break;
778
+ case 'citation':
779
+ if (typeof node.sourceId !== 'string') {
780
+ return false;
781
+ }
782
+ break;
783
+ case 'extension':
784
+ if (node.plugin !== ownership.pluginName || typeof node.name !== 'string' || !ownership.hasRenderer(node.name) || node.display !== 'inline' || node.source !== undefined || !isMarkdownPluginData(node.data)) {
785
+ return false;
786
+ }
787
+ break;
788
+ case 'strong':
789
+ case 'emphasis':
790
+ case 'delete':
791
+ case 'break':
792
+ break;
793
+ }
794
+ if (type === 'strong' || type === 'emphasis' || type === 'delete') {
795
+ if (!Array.isArray(node.children)) {
796
+ return false;
797
+ }
798
+ for (const child of node.children) {
799
+ if (!visit(child, withinLink)) {
800
+ return false;
801
+ }
802
+ }
803
+ } else if (type === 'link') {
804
+ if (!Array.isArray(node.children)) {
805
+ return false;
806
+ }
807
+ for (const child of node.children) {
808
+ if (!visit(child, true)) {
809
+ return false;
810
+ }
811
+ }
812
+ } else if ('children' in node) {
813
+ return false;
814
+ }
815
+ return true;
816
+ };
817
+ for (const node of nodes) {
818
+ if (!visit(node, insideLink)) {
819
+ throw new TypeError('Markdown helper callback returned an unrepresentable node');
820
+ }
821
+ }
822
+ // Frozen only once every node passed, so a rejected batch leaves the
823
+ // caller's objects exactly as they were. Freezing is what makes adopting
824
+ // a caller's object safe instead of copying it: the object is now part of
825
+ // an immutable tree, and a later write by whoever still holds a reference
826
+ // cannot reach into the document.
827
+ const reentrant = nodes !== reusableScratch;
828
+ if (!reentrant) {
829
+ scratchInUse = true;
830
+ }
831
+ try {
832
+ for (const node of nodes) {
833
+ freezeAstNode(node);
834
+ }
835
+ } finally {
836
+ if (!reentrant) {
837
+ scratchInUse = false;
838
+ reusableScratch[0] = undefined;
839
+ }
840
+ }
841
+ }
842
+ export function reportMarkdownPluginFailure(pluginName, phase, error) {
843
+ const key = `markdown-plugin:${pluginName}:${phase}`;
844
+ const message = `plugin "${pluginName}" failed in ${phase}; rendered readable fallback.`;
845
+ if (process.env.NODE_ENV === 'production') {
846
+ if (!reportedProductionPluginFailures.has(key)) {
847
+ reportedProductionPluginFailures.add(key);
848
+ devError('Markdown', message);
849
+ }
850
+ return;
851
+ }
852
+ warnOnce(key, 'Markdown', message, error);
853
+ }
854
+ export function applyMarkdownTransforms(root, plugins, source, isFinal, display) {
855
+ if (plugins == null || plugins.transforms.length === 0) {
856
+ return root;
857
+ }
858
+ let pluginNames;
859
+ let rendererKeys;
860
+ let document = root;
861
+ // Heading identity is stamped on the mutable parser tree, before anything
862
+ // freezes it, and only when a plugin-authored transform will actually be
863
+ // validated against it. An all-trusted pipeline never pays for it.
864
+ const sourceHeadingMarkers = plugins.hasUntrustedTransform ? markSourceHeadings(root) : undefined;
865
+ let guarded = false;
866
+ let priorTransformChangedTree = false;
867
+ /** A trusted helper has produced a tree nothing has frozen yet. */
868
+ let deferredFreeze = false;
869
+ for (const prepared of plugins.transforms) {
870
+ if (!priorTransformChangedTree && prepared.claims?.(source) === false) {
871
+ continue;
872
+ }
873
+ // A plugin-authored transform observes deeply frozen input and has its
874
+ // output validated. Both guards exist to contain untrusted structure, so
875
+ // a Core-authored trusted helper needs neither — and a pipeline of only
876
+ // trusted helpers never pays for them at all. Every untrusted transform
877
+ // still receives a frozen tree, including one that follows a trusted
878
+ // helper, whose output is not frozen on the way out.
879
+ if (!prepared.trusted) {
880
+ if (!guarded) {
881
+ pluginNames = new Set(plugins.entries.map(entry => entry.name));
882
+ rendererKeys = new Set(plugins.renderers.keys());
883
+ guarded = true;
884
+ }
885
+ // Deeply freezes the whole tree, including anything a trusted helper
886
+ // left shared and mutable, before plugin-authored code observes it.
887
+ // Subtrees already frozen by an earlier pass are skipped.
888
+ document = freezeAst(document);
889
+ deferredFreeze = false;
890
+ }
891
+ try {
892
+ const context = {
893
+ source,
894
+ isFinal,
895
+ display,
896
+ report(message) {
897
+ reportMarkdownPluginFailure(prepared.pluginName, 'transform', message);
898
+ },
899
+ [markdownTransformPluginName]: prepared.pluginName,
900
+ [markdownTransformHasRenderer]: nodeName => plugins.renderers.has(`${prepared.pluginName}\u0000${nodeName}`),
901
+ [markdownTransformSourceUnchanged]: !priorTransformChangedTree
902
+ };
903
+ const next = prepared.transform(document, context);
904
+ if (next != null && typeof next === 'object' && typeof next.then === 'function') {
905
+ void Promise.resolve(next).catch(() => {});
906
+ throw new TypeError('Async Markdown transforms are not supported');
907
+ }
908
+ if (next === document) {
909
+ continue;
910
+ }
911
+ if (prepared.trusted) {
912
+ priorTransformChangedTree = true;
913
+ // No freeze here. Nothing untrusted can observe this tree yet —
914
+ // only another Core helper, which never mutates its input — so the
915
+ // pipeline freezes once, below, before anything else sees it. That
916
+ // freeze is a FULL walk, never one that stops at nodes merely
917
+ // shared with an earlier unfrozen tree: an undecorated sibling a
918
+ // helper carried over by identity must be frozen too.
919
+ deferredFreeze = true;
920
+ document = next;
921
+ continue;
922
+ }
923
+ const positions = collectSourceInvariants(document);
924
+ const existingExtensions = collectExtensionSignatures(document);
925
+ if (!validateAst(next, pluginNames, rendererKeys, positions, sourceHeadingMarkers, prepared.pluginName, existingExtensions, display)) {
926
+ throw new TypeError('Transform returned an invalid Markdown document');
927
+ }
928
+ priorTransformChangedTree = true;
929
+ document = freezeAst(restoreCodeInternalProperties(document, next));
930
+ } catch (error) {
931
+ reportMarkdownPluginFailure(prepared.pluginName, 'transform', error);
932
+ }
933
+ }
934
+ if (!deferredFreeze) {
935
+ return document;
936
+ }
937
+ // Freeze what the helpers built. With a plugin-authored transform in the
938
+ // list the whole tree is frozen, because that plugin may observe any part
939
+ // of it; with only Core helpers, the untouched remainder is left exactly
940
+ // as a zero-plugin parse leaves it.
941
+ return plugins.hasUntrustedTransform ? freezeAst(document) : freezeBuiltAst(root, document);
942
+ }
943
+ export function getMarkdownExtensionRenderer(plugins, node) {
944
+ return plugins?.renderers.get(`${node.plugin}\0${node.name}`)?.renderer;
945
+ }
946
+ export function markdownExtensionText(plugins, node) {
947
+ const renderer = getMarkdownExtensionRenderer(plugins, node);
948
+ if (renderer == null) {
949
+ return node.source ?? '';
950
+ }
951
+ try {
952
+ return renderer.toText(node);
953
+ } catch (error) {
954
+ reportMarkdownPluginFailure(node.plugin, 'render', error);
955
+ return node.source ?? '';
956
+ }
957
+ }