@multiplatform.one/rich-text 6.0.4 → 6.3.0

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 (649) hide show
  1. package/README.md +60 -0
  2. package/dist/cjs/RichEditor.cjs +84 -9
  3. package/dist/cjs/RichEditor.native.js +422 -35
  4. package/dist/cjs/RichEditor.native.js.map +1 -1
  5. package/dist/cjs/RichTextEditor/index.cjs +18 -2
  6. package/dist/cjs/RichTextEditor/index.native.js +18 -2
  7. package/dist/cjs/RichTextEditor/index.native.js.map +1 -1
  8. package/dist/cjs/constants.cjs +52 -29
  9. package/dist/cjs/constants.native.js +59 -29
  10. package/dist/cjs/constants.native.js.map +1 -1
  11. package/dist/cjs/editor/BlockDragHandle.cjs +22 -7
  12. package/dist/cjs/editor/BlockDragHandle.native.js +41 -7
  13. package/dist/cjs/editor/BlockDragHandle.native.js.map +1 -1
  14. package/dist/cjs/editor/SlashCommands.cjs +249 -293
  15. package/dist/cjs/editor/SlashCommands.native.js +306 -340
  16. package/dist/cjs/editor/SlashCommands.native.js.map +1 -1
  17. package/dist/cjs/editor/TentapEditor.native.js +44 -12
  18. package/dist/cjs/editor/TentapEditor.native.js.map +1 -1
  19. package/dist/cjs/editor/TiptapEditor.cjs +140 -33
  20. package/dist/cjs/editor/TiptapEditor.native.js +153 -33
  21. package/dist/cjs/editor/TiptapEditor.native.js.map +1 -1
  22. package/dist/cjs/editor/blockAnchor.cjs +43 -0
  23. package/dist/cjs/editor/blockAnchor.native.js +68 -0
  24. package/dist/cjs/editor/blockAnchor.native.js.map +1 -0
  25. package/dist/cjs/editor/codeBlockPreview.cjs +230 -0
  26. package/dist/cjs/editor/codeBlockPreview.native.js +265 -0
  27. package/dist/cjs/editor/codeBlockPreview.native.js.map +1 -0
  28. package/dist/cjs/editor/editorStyles.cjs +203 -34
  29. package/dist/cjs/editor/editorStyles.native.js +203 -34
  30. package/dist/cjs/editor/editorStyles.native.js.map +1 -1
  31. package/dist/cjs/editor/emoji.cjs +128 -0
  32. package/dist/cjs/editor/emoji.native.js +184 -0
  33. package/dist/cjs/editor/emoji.native.js.map +1 -0
  34. package/dist/cjs/editor/lazyKatex.cjs +78 -0
  35. package/dist/cjs/editor/lazyKatex.native.js +117 -0
  36. package/dist/cjs/editor/lazyKatex.native.js.map +1 -0
  37. package/dist/cjs/editor/markdown.cjs +216 -0
  38. package/dist/cjs/editor/markdown.native.js +278 -0
  39. package/dist/cjs/editor/markdown.native.js.map +1 -0
  40. package/dist/cjs/editor/mathematics.cjs +168 -0
  41. package/dist/cjs/editor/mathematics.native.js +202 -0
  42. package/dist/cjs/editor/mathematics.native.js.map +1 -0
  43. package/dist/cjs/editor/media.cjs +138 -0
  44. package/dist/cjs/editor/media.native.js +172 -0
  45. package/dist/cjs/editor/media.native.js.map +1 -0
  46. package/dist/cjs/editor/mentions.cjs +73 -0
  47. package/dist/cjs/editor/mentions.native.js +84 -0
  48. package/dist/cjs/editor/mentions.native.js.map +1 -0
  49. package/dist/cjs/editor/pasteCleanup.cjs +83 -0
  50. package/dist/cjs/editor/pasteCleanup.native.js +175 -0
  51. package/dist/cjs/editor/pasteCleanup.native.js.map +1 -0
  52. package/dist/cjs/editor/suggestionPopup.cjs +297 -0
  53. package/dist/cjs/editor/suggestionPopup.native.js +327 -0
  54. package/dist/cjs/editor/suggestionPopup.native.js.map +1 -0
  55. package/dist/cjs/preview.cjs +263 -0
  56. package/dist/cjs/preview.native.js +294 -0
  57. package/dist/cjs/preview.native.js.map +1 -0
  58. package/dist/cjs/shared/t.cjs +53 -0
  59. package/dist/cjs/shared/t.native.js +56 -0
  60. package/dist/cjs/shared/t.native.js.map +1 -0
  61. package/dist/cjs/shared/url.cjs +35 -0
  62. package/dist/cjs/shared/url.native.js +38 -0
  63. package/dist/cjs/shared/url.native.js.map +1 -0
  64. package/dist/cjs/styled.cjs +13 -6
  65. package/dist/cjs/styled.native.js +13 -6
  66. package/dist/cjs/styled.native.js.map +1 -1
  67. package/dist/cjs/toolbar/BubbleToolbar.cjs +10 -8
  68. package/dist/cjs/toolbar/BubbleToolbar.native.js +10 -8
  69. package/dist/cjs/toolbar/BubbleToolbar.native.js.map +1 -1
  70. package/dist/cjs/toolbar/CodeBlockBubble.cjs +59 -23
  71. package/dist/cjs/toolbar/CodeBlockBubble.native.js +71 -25
  72. package/dist/cjs/toolbar/CodeBlockBubble.native.js.map +1 -1
  73. package/dist/cjs/toolbar/ColorPicker.cjs +19 -54
  74. package/dist/cjs/toolbar/ColorPicker.native.js +81 -179
  75. package/dist/cjs/toolbar/ColorPicker.native.js.map +1 -1
  76. package/dist/cjs/toolbar/FixedToolbar.cjs +33 -10
  77. package/dist/cjs/toolbar/FixedToolbar.native.js +46 -54
  78. package/dist/cjs/toolbar/FixedToolbar.native.js.map +1 -1
  79. package/dist/cjs/toolbar/HeadingPicker.cjs +32 -39
  80. package/dist/cjs/toolbar/HeadingPicker.native.js +61 -51
  81. package/dist/cjs/toolbar/HeadingPicker.native.js.map +1 -1
  82. package/dist/cjs/toolbar/ImageBubble.cjs +20 -43
  83. package/dist/cjs/toolbar/ImageBubble.native.js +20 -43
  84. package/dist/cjs/toolbar/ImageBubble.native.js.map +1 -1
  85. package/dist/cjs/toolbar/ImageDialog.cjs +5 -4
  86. package/dist/cjs/toolbar/ImageDialog.native.js +76 -65
  87. package/dist/cjs/toolbar/ImageDialog.native.js.map +1 -1
  88. package/dist/cjs/toolbar/LinkBubble.cjs +23 -70
  89. package/dist/cjs/toolbar/LinkBubble.native.js +23 -70
  90. package/dist/cjs/toolbar/LinkBubble.native.js.map +1 -1
  91. package/dist/cjs/toolbar/LinkDialog.cjs +19 -18
  92. package/dist/cjs/toolbar/LinkDialog.native.js +86 -83
  93. package/dist/cjs/toolbar/LinkDialog.native.js.map +1 -1
  94. package/dist/cjs/toolbar/ListPicker.cjs +32 -43
  95. package/dist/cjs/toolbar/ListPicker.native.js +43 -44
  96. package/dist/cjs/toolbar/ListPicker.native.js.map +1 -1
  97. package/dist/cjs/toolbar/MathBubble.cjs +159 -0
  98. package/dist/cjs/toolbar/MathBubble.native.js +169 -0
  99. package/dist/cjs/toolbar/MathBubble.native.js.map +1 -0
  100. package/dist/cjs/toolbar/MoreDropdown.cjs +51 -98
  101. package/dist/cjs/toolbar/MoreDropdown.native.js +73 -98
  102. package/dist/cjs/toolbar/MoreDropdown.native.js.map +1 -1
  103. package/dist/cjs/toolbar/StatusBar.cjs +19 -10
  104. package/dist/cjs/toolbar/StatusBar.native.js +19 -10
  105. package/dist/cjs/toolbar/StatusBar.native.js.map +1 -1
  106. package/dist/cjs/toolbar/TableBubble.cjs +77 -95
  107. package/dist/cjs/toolbar/TableBubble.native.js +73 -71
  108. package/dist/cjs/toolbar/TableBubble.native.js.map +1 -1
  109. package/dist/cjs/toolbar/ToolbarButton.cjs +86 -21
  110. package/dist/cjs/toolbar/ToolbarButton.native.js +14 -4
  111. package/dist/cjs/toolbar/ToolbarButton.native.js.map +1 -1
  112. package/dist/cjs/toolbar/icons.cjs +111 -468
  113. package/dist/cjs/toolbar/shortcuts.cjs +73 -24
  114. package/dist/cjs/toolbar/shortcuts.native.js +73 -24
  115. package/dist/cjs/toolbar/shortcuts.native.js.map +1 -1
  116. package/dist/cjs/toolbar/useHorizontalScroll.cjs +25 -5
  117. package/dist/cjs/toolbar/useHorizontalScroll.native.js +25 -5
  118. package/dist/cjs/toolbar/useHorizontalScroll.native.js.map +1 -1
  119. package/dist/cjs/toolbar/useRovingFocus.cjs +80 -0
  120. package/dist/cjs/toolbar/useRovingFocus.native.js +113 -0
  121. package/dist/cjs/toolbar/useRovingFocus.native.js.map +1 -0
  122. package/dist/cjs/types.native.js.map +1 -1
  123. package/dist/esm/RichEditor.mjs +85 -10
  124. package/dist/esm/RichEditor.mjs.map +1 -1
  125. package/dist/esm/RichEditor.native.js +425 -38
  126. package/dist/esm/RichEditor.native.js.map +1 -1
  127. package/dist/esm/RichTextEditor/index.mjs +18 -2
  128. package/dist/esm/RichTextEditor/index.mjs.map +1 -1
  129. package/dist/esm/RichTextEditor/index.native.js +18 -2
  130. package/dist/esm/RichTextEditor/index.native.js.map +1 -1
  131. package/dist/esm/constants.mjs +47 -29
  132. package/dist/esm/constants.mjs.map +1 -1
  133. package/dist/esm/constants.native.js +54 -29
  134. package/dist/esm/constants.native.js.map +1 -1
  135. package/dist/esm/editor/BlockDragHandle.mjs +22 -7
  136. package/dist/esm/editor/BlockDragHandle.mjs.map +1 -1
  137. package/dist/esm/editor/BlockDragHandle.native.js +41 -7
  138. package/dist/esm/editor/BlockDragHandle.native.js.map +1 -1
  139. package/dist/esm/editor/SlashCommands.mjs +250 -294
  140. package/dist/esm/editor/SlashCommands.mjs.map +1 -1
  141. package/dist/esm/editor/SlashCommands.native.js +307 -341
  142. package/dist/esm/editor/SlashCommands.native.js.map +1 -1
  143. package/dist/esm/editor/TentapEditor.native.js +45 -13
  144. package/dist/esm/editor/TentapEditor.native.js.map +1 -1
  145. package/dist/esm/editor/TiptapEditor.mjs +142 -35
  146. package/dist/esm/editor/TiptapEditor.mjs.map +1 -1
  147. package/dist/esm/editor/TiptapEditor.native.js +155 -35
  148. package/dist/esm/editor/TiptapEditor.native.js.map +1 -1
  149. package/dist/esm/editor/blockAnchor.mjs +18 -0
  150. package/dist/esm/editor/blockAnchor.mjs.map +1 -0
  151. package/dist/esm/editor/blockAnchor.native.js +40 -0
  152. package/dist/esm/editor/blockAnchor.native.js.map +1 -0
  153. package/dist/esm/editor/codeBlockPreview.mjs +190 -0
  154. package/dist/esm/editor/codeBlockPreview.mjs.map +1 -0
  155. package/dist/esm/editor/codeBlockPreview.native.js +222 -0
  156. package/dist/esm/editor/codeBlockPreview.native.js.map +1 -0
  157. package/dist/esm/editor/editorStyles.mjs +203 -34
  158. package/dist/esm/editor/editorStyles.mjs.map +1 -1
  159. package/dist/esm/editor/editorStyles.native.js +203 -34
  160. package/dist/esm/editor/editorStyles.native.js.map +1 -1
  161. package/dist/esm/editor/emoji.mjs +88 -0
  162. package/dist/esm/editor/emoji.mjs.map +1 -0
  163. package/dist/esm/editor/emoji.native.js +141 -0
  164. package/dist/esm/editor/emoji.native.js.map +1 -0
  165. package/dist/esm/editor/lazyKatex.mjs +40 -0
  166. package/dist/esm/editor/lazyKatex.mjs.map +1 -0
  167. package/dist/esm/editor/lazyKatex.native.js +76 -0
  168. package/dist/esm/editor/lazyKatex.native.js.map +1 -0
  169. package/dist/esm/editor/markdown.mjs +179 -0
  170. package/dist/esm/editor/markdown.mjs.map +1 -0
  171. package/dist/esm/editor/markdown.native.js +238 -0
  172. package/dist/esm/editor/markdown.native.js.map +1 -0
  173. package/dist/esm/editor/mathematics.mjs +142 -0
  174. package/dist/esm/editor/mathematics.mjs.map +1 -0
  175. package/dist/esm/editor/mathematics.native.js +173 -0
  176. package/dist/esm/editor/mathematics.native.js.map +1 -0
  177. package/dist/esm/editor/media.mjs +113 -0
  178. package/dist/esm/editor/media.mjs.map +1 -0
  179. package/dist/esm/editor/media.native.js +144 -0
  180. package/dist/esm/editor/media.native.js.map +1 -0
  181. package/dist/esm/editor/mentions.mjs +37 -0
  182. package/dist/esm/editor/mentions.mjs.map +1 -0
  183. package/dist/esm/editor/mentions.native.js +45 -0
  184. package/dist/esm/editor/mentions.native.js.map +1 -0
  185. package/dist/esm/editor/pasteCleanup.mjs +57 -0
  186. package/dist/esm/editor/pasteCleanup.mjs.map +1 -0
  187. package/dist/esm/editor/pasteCleanup.native.js +146 -0
  188. package/dist/esm/editor/pasteCleanup.native.js.map +1 -0
  189. package/dist/esm/editor/suggestionPopup.mjs +268 -0
  190. package/dist/esm/editor/suggestionPopup.mjs.map +1 -0
  191. package/dist/esm/editor/suggestionPopup.native.js +295 -0
  192. package/dist/esm/editor/suggestionPopup.native.js.map +1 -0
  193. package/dist/esm/preview.mjs +236 -0
  194. package/dist/esm/preview.mjs.map +1 -0
  195. package/dist/esm/preview.native.js +264 -0
  196. package/dist/esm/preview.native.js.map +1 -0
  197. package/dist/esm/shared/t.mjs +17 -0
  198. package/dist/esm/shared/t.mjs.map +1 -0
  199. package/dist/esm/shared/t.native.js +17 -0
  200. package/dist/esm/shared/t.native.js.map +1 -0
  201. package/dist/esm/shared/url.mjs +10 -0
  202. package/dist/esm/shared/url.mjs.map +1 -0
  203. package/dist/esm/shared/url.native.js +10 -0
  204. package/dist/esm/shared/url.native.js.map +1 -0
  205. package/dist/esm/styled.mjs +13 -6
  206. package/dist/esm/styled.mjs.map +1 -1
  207. package/dist/esm/styled.native.js +13 -6
  208. package/dist/esm/styled.native.js.map +1 -1
  209. package/dist/esm/toolbar/BubbleToolbar.mjs +11 -9
  210. package/dist/esm/toolbar/BubbleToolbar.mjs.map +1 -1
  211. package/dist/esm/toolbar/BubbleToolbar.native.js +11 -9
  212. package/dist/esm/toolbar/BubbleToolbar.native.js.map +1 -1
  213. package/dist/esm/toolbar/CodeBlockBubble.mjs +60 -24
  214. package/dist/esm/toolbar/CodeBlockBubble.mjs.map +1 -1
  215. package/dist/esm/toolbar/CodeBlockBubble.native.js +72 -26
  216. package/dist/esm/toolbar/CodeBlockBubble.native.js.map +1 -1
  217. package/dist/esm/toolbar/ColorPicker.mjs +21 -56
  218. package/dist/esm/toolbar/ColorPicker.mjs.map +1 -1
  219. package/dist/esm/toolbar/ColorPicker.native.js +82 -180
  220. package/dist/esm/toolbar/ColorPicker.native.js.map +1 -1
  221. package/dist/esm/toolbar/FixedToolbar.mjs +34 -11
  222. package/dist/esm/toolbar/FixedToolbar.mjs.map +1 -1
  223. package/dist/esm/toolbar/FixedToolbar.native.js +47 -55
  224. package/dist/esm/toolbar/FixedToolbar.native.js.map +1 -1
  225. package/dist/esm/toolbar/HeadingPicker.mjs +34 -41
  226. package/dist/esm/toolbar/HeadingPicker.mjs.map +1 -1
  227. package/dist/esm/toolbar/HeadingPicker.native.js +63 -53
  228. package/dist/esm/toolbar/HeadingPicker.native.js.map +1 -1
  229. package/dist/esm/toolbar/ImageBubble.mjs +20 -43
  230. package/dist/esm/toolbar/ImageBubble.mjs.map +1 -1
  231. package/dist/esm/toolbar/ImageBubble.native.js +20 -43
  232. package/dist/esm/toolbar/ImageBubble.native.js.map +1 -1
  233. package/dist/esm/toolbar/ImageDialog.mjs +5 -4
  234. package/dist/esm/toolbar/ImageDialog.mjs.map +1 -1
  235. package/dist/esm/toolbar/ImageDialog.native.js +75 -64
  236. package/dist/esm/toolbar/ImageDialog.native.js.map +1 -1
  237. package/dist/esm/toolbar/LinkBubble.mjs +23 -70
  238. package/dist/esm/toolbar/LinkBubble.mjs.map +1 -1
  239. package/dist/esm/toolbar/LinkBubble.native.js +23 -70
  240. package/dist/esm/toolbar/LinkBubble.native.js.map +1 -1
  241. package/dist/esm/toolbar/LinkDialog.mjs +17 -16
  242. package/dist/esm/toolbar/LinkDialog.mjs.map +1 -1
  243. package/dist/esm/toolbar/LinkDialog.native.js +84 -80
  244. package/dist/esm/toolbar/LinkDialog.native.js.map +1 -1
  245. package/dist/esm/toolbar/ListPicker.mjs +33 -44
  246. package/dist/esm/toolbar/ListPicker.mjs.map +1 -1
  247. package/dist/esm/toolbar/ListPicker.native.js +44 -45
  248. package/dist/esm/toolbar/ListPicker.native.js.map +1 -1
  249. package/dist/esm/toolbar/MathBubble.mjs +134 -0
  250. package/dist/esm/toolbar/MathBubble.mjs.map +1 -0
  251. package/dist/esm/toolbar/MathBubble.native.js +141 -0
  252. package/dist/esm/toolbar/MathBubble.native.js.map +1 -0
  253. package/dist/esm/toolbar/MoreDropdown.mjs +50 -97
  254. package/dist/esm/toolbar/MoreDropdown.mjs.map +1 -1
  255. package/dist/esm/toolbar/MoreDropdown.native.js +72 -97
  256. package/dist/esm/toolbar/MoreDropdown.native.js.map +1 -1
  257. package/dist/esm/toolbar/StatusBar.mjs +19 -10
  258. package/dist/esm/toolbar/StatusBar.mjs.map +1 -1
  259. package/dist/esm/toolbar/StatusBar.native.js +19 -10
  260. package/dist/esm/toolbar/StatusBar.native.js.map +1 -1
  261. package/dist/esm/toolbar/TableBubble.mjs +77 -95
  262. package/dist/esm/toolbar/TableBubble.mjs.map +1 -1
  263. package/dist/esm/toolbar/TableBubble.native.js +73 -71
  264. package/dist/esm/toolbar/TableBubble.native.js.map +1 -1
  265. package/dist/esm/toolbar/ToolbarButton.mjs +87 -22
  266. package/dist/esm/toolbar/ToolbarButton.mjs.map +1 -1
  267. package/dist/esm/toolbar/ToolbarButton.native.js +14 -4
  268. package/dist/esm/toolbar/ToolbarButton.native.js.map +1 -1
  269. package/dist/esm/toolbar/icons.mjs +109 -469
  270. package/dist/esm/toolbar/icons.mjs.map +1 -1
  271. package/dist/esm/toolbar/shortcuts.mjs +73 -24
  272. package/dist/esm/toolbar/shortcuts.mjs.map +1 -1
  273. package/dist/esm/toolbar/shortcuts.native.js +73 -24
  274. package/dist/esm/toolbar/shortcuts.native.js.map +1 -1
  275. package/dist/esm/toolbar/useHorizontalScroll.mjs +25 -6
  276. package/dist/esm/toolbar/useHorizontalScroll.mjs.map +1 -1
  277. package/dist/esm/toolbar/useHorizontalScroll.native.js +25 -6
  278. package/dist/esm/toolbar/useHorizontalScroll.native.js.map +1 -1
  279. package/dist/esm/toolbar/useRovingFocus.mjs +55 -0
  280. package/dist/esm/toolbar/useRovingFocus.mjs.map +1 -0
  281. package/dist/esm/toolbar/useRovingFocus.native.js +85 -0
  282. package/dist/esm/toolbar/useRovingFocus.native.js.map +1 -0
  283. package/dist/esm/types.mjs.map +1 -1
  284. package/dist/esm/types.native.js.map +1 -1
  285. package/dist/jsx/RichEditor.mjs +85 -10
  286. package/dist/jsx/RichEditor.mjs.map +1 -1
  287. package/dist/jsx/RichEditor.native.js +422 -35
  288. package/dist/jsx/RichEditor.native.js.map +1 -1
  289. package/dist/jsx/RichTextEditor/index.mjs +18 -2
  290. package/dist/jsx/RichTextEditor/index.mjs.map +1 -1
  291. package/dist/jsx/RichTextEditor/index.native.js +18 -2
  292. package/dist/jsx/RichTextEditor/index.native.js.map +1 -1
  293. package/dist/jsx/constants.mjs +47 -29
  294. package/dist/jsx/constants.mjs.map +1 -1
  295. package/dist/jsx/constants.native.js +59 -29
  296. package/dist/jsx/constants.native.js.map +1 -1
  297. package/dist/jsx/editor/BlockDragHandle.mjs +22 -7
  298. package/dist/jsx/editor/BlockDragHandle.mjs.map +1 -1
  299. package/dist/jsx/editor/BlockDragHandle.native.js +41 -7
  300. package/dist/jsx/editor/BlockDragHandle.native.js.map +1 -1
  301. package/dist/jsx/editor/SlashCommands.mjs +250 -294
  302. package/dist/jsx/editor/SlashCommands.mjs.map +1 -1
  303. package/dist/jsx/editor/SlashCommands.native.js +306 -340
  304. package/dist/jsx/editor/SlashCommands.native.js.map +1 -1
  305. package/dist/jsx/editor/TentapEditor.native.js +44 -12
  306. package/dist/jsx/editor/TentapEditor.native.js.map +1 -1
  307. package/dist/jsx/editor/TiptapEditor.mjs +142 -35
  308. package/dist/jsx/editor/TiptapEditor.mjs.map +1 -1
  309. package/dist/jsx/editor/TiptapEditor.native.js +153 -33
  310. package/dist/jsx/editor/TiptapEditor.native.js.map +1 -1
  311. package/dist/jsx/editor/blockAnchor.mjs +18 -0
  312. package/dist/jsx/editor/blockAnchor.mjs.map +1 -0
  313. package/dist/jsx/editor/blockAnchor.native.js +68 -0
  314. package/dist/jsx/editor/blockAnchor.native.js.map +1 -0
  315. package/dist/jsx/editor/codeBlockPreview.mjs +190 -0
  316. package/dist/jsx/editor/codeBlockPreview.mjs.map +1 -0
  317. package/dist/jsx/editor/codeBlockPreview.native.js +265 -0
  318. package/dist/jsx/editor/codeBlockPreview.native.js.map +1 -0
  319. package/dist/jsx/editor/editorStyles.mjs +203 -34
  320. package/dist/jsx/editor/editorStyles.mjs.map +1 -1
  321. package/dist/jsx/editor/editorStyles.native.js +203 -34
  322. package/dist/jsx/editor/editorStyles.native.js.map +1 -1
  323. package/dist/jsx/editor/emoji.mjs +88 -0
  324. package/dist/jsx/editor/emoji.mjs.map +1 -0
  325. package/dist/jsx/editor/emoji.native.js +184 -0
  326. package/dist/jsx/editor/emoji.native.js.map +1 -0
  327. package/dist/jsx/editor/lazyKatex.mjs +40 -0
  328. package/dist/jsx/editor/lazyKatex.mjs.map +1 -0
  329. package/dist/jsx/editor/lazyKatex.native.js +117 -0
  330. package/dist/jsx/editor/lazyKatex.native.js.map +1 -0
  331. package/dist/jsx/editor/markdown.mjs +179 -0
  332. package/dist/jsx/editor/markdown.mjs.map +1 -0
  333. package/dist/jsx/editor/markdown.native.js +278 -0
  334. package/dist/jsx/editor/markdown.native.js.map +1 -0
  335. package/dist/jsx/editor/mathematics.mjs +142 -0
  336. package/dist/jsx/editor/mathematics.mjs.map +1 -0
  337. package/dist/jsx/editor/mathematics.native.js +202 -0
  338. package/dist/jsx/editor/mathematics.native.js.map +1 -0
  339. package/dist/jsx/editor/media.mjs +113 -0
  340. package/dist/jsx/editor/media.mjs.map +1 -0
  341. package/dist/jsx/editor/media.native.js +172 -0
  342. package/dist/jsx/editor/media.native.js.map +1 -0
  343. package/dist/jsx/editor/mentions.mjs +37 -0
  344. package/dist/jsx/editor/mentions.mjs.map +1 -0
  345. package/dist/jsx/editor/mentions.native.js +84 -0
  346. package/dist/jsx/editor/mentions.native.js.map +1 -0
  347. package/dist/jsx/editor/pasteCleanup.mjs +57 -0
  348. package/dist/jsx/editor/pasteCleanup.mjs.map +1 -0
  349. package/dist/jsx/editor/pasteCleanup.native.js +175 -0
  350. package/dist/jsx/editor/pasteCleanup.native.js.map +1 -0
  351. package/dist/jsx/editor/suggestionPopup.mjs +268 -0
  352. package/dist/jsx/editor/suggestionPopup.mjs.map +1 -0
  353. package/dist/jsx/editor/suggestionPopup.native.js +327 -0
  354. package/dist/jsx/editor/suggestionPopup.native.js.map +1 -0
  355. package/dist/jsx/preview.mjs +236 -0
  356. package/dist/jsx/preview.mjs.map +1 -0
  357. package/dist/jsx/preview.native.js +294 -0
  358. package/dist/jsx/preview.native.js.map +1 -0
  359. package/dist/jsx/shared/t.mjs +17 -0
  360. package/dist/jsx/shared/t.mjs.map +1 -0
  361. package/dist/jsx/shared/t.native.js +56 -0
  362. package/dist/jsx/shared/t.native.js.map +1 -0
  363. package/dist/jsx/shared/url.mjs +10 -0
  364. package/dist/jsx/shared/url.mjs.map +1 -0
  365. package/dist/jsx/shared/url.native.js +38 -0
  366. package/dist/jsx/shared/url.native.js.map +1 -0
  367. package/dist/jsx/styled.mjs +13 -6
  368. package/dist/jsx/styled.mjs.map +1 -1
  369. package/dist/jsx/styled.native.js +13 -6
  370. package/dist/jsx/styled.native.js.map +1 -1
  371. package/dist/jsx/toolbar/BubbleToolbar.mjs +11 -9
  372. package/dist/jsx/toolbar/BubbleToolbar.mjs.map +1 -1
  373. package/dist/jsx/toolbar/BubbleToolbar.native.js +10 -8
  374. package/dist/jsx/toolbar/BubbleToolbar.native.js.map +1 -1
  375. package/dist/jsx/toolbar/CodeBlockBubble.mjs +60 -24
  376. package/dist/jsx/toolbar/CodeBlockBubble.mjs.map +1 -1
  377. package/dist/jsx/toolbar/CodeBlockBubble.native.js +71 -25
  378. package/dist/jsx/toolbar/CodeBlockBubble.native.js.map +1 -1
  379. package/dist/jsx/toolbar/ColorPicker.mjs +21 -56
  380. package/dist/jsx/toolbar/ColorPicker.mjs.map +1 -1
  381. package/dist/jsx/toolbar/ColorPicker.native.js +81 -179
  382. package/dist/jsx/toolbar/ColorPicker.native.js.map +1 -1
  383. package/dist/jsx/toolbar/FixedToolbar.mjs +34 -11
  384. package/dist/jsx/toolbar/FixedToolbar.mjs.map +1 -1
  385. package/dist/jsx/toolbar/FixedToolbar.native.js +46 -54
  386. package/dist/jsx/toolbar/FixedToolbar.native.js.map +1 -1
  387. package/dist/jsx/toolbar/HeadingPicker.mjs +34 -41
  388. package/dist/jsx/toolbar/HeadingPicker.mjs.map +1 -1
  389. package/dist/jsx/toolbar/HeadingPicker.native.js +61 -51
  390. package/dist/jsx/toolbar/HeadingPicker.native.js.map +1 -1
  391. package/dist/jsx/toolbar/ImageBubble.mjs +20 -43
  392. package/dist/jsx/toolbar/ImageBubble.mjs.map +1 -1
  393. package/dist/jsx/toolbar/ImageBubble.native.js +20 -43
  394. package/dist/jsx/toolbar/ImageBubble.native.js.map +1 -1
  395. package/dist/jsx/toolbar/ImageDialog.mjs +5 -4
  396. package/dist/jsx/toolbar/ImageDialog.mjs.map +1 -1
  397. package/dist/jsx/toolbar/ImageDialog.native.js +76 -65
  398. package/dist/jsx/toolbar/ImageDialog.native.js.map +1 -1
  399. package/dist/jsx/toolbar/LinkBubble.mjs +23 -70
  400. package/dist/jsx/toolbar/LinkBubble.mjs.map +1 -1
  401. package/dist/jsx/toolbar/LinkBubble.native.js +23 -70
  402. package/dist/jsx/toolbar/LinkBubble.native.js.map +1 -1
  403. package/dist/jsx/toolbar/LinkDialog.mjs +17 -16
  404. package/dist/jsx/toolbar/LinkDialog.mjs.map +1 -1
  405. package/dist/jsx/toolbar/LinkDialog.native.js +86 -83
  406. package/dist/jsx/toolbar/LinkDialog.native.js.map +1 -1
  407. package/dist/jsx/toolbar/ListPicker.mjs +33 -44
  408. package/dist/jsx/toolbar/ListPicker.mjs.map +1 -1
  409. package/dist/jsx/toolbar/ListPicker.native.js +43 -44
  410. package/dist/jsx/toolbar/ListPicker.native.js.map +1 -1
  411. package/dist/jsx/toolbar/MathBubble.mjs +134 -0
  412. package/dist/jsx/toolbar/MathBubble.mjs.map +1 -0
  413. package/dist/jsx/toolbar/MathBubble.native.js +169 -0
  414. package/dist/jsx/toolbar/MathBubble.native.js.map +1 -0
  415. package/dist/jsx/toolbar/MoreDropdown.mjs +50 -97
  416. package/dist/jsx/toolbar/MoreDropdown.mjs.map +1 -1
  417. package/dist/jsx/toolbar/MoreDropdown.native.js +73 -98
  418. package/dist/jsx/toolbar/MoreDropdown.native.js.map +1 -1
  419. package/dist/jsx/toolbar/StatusBar.mjs +19 -10
  420. package/dist/jsx/toolbar/StatusBar.mjs.map +1 -1
  421. package/dist/jsx/toolbar/StatusBar.native.js +19 -10
  422. package/dist/jsx/toolbar/StatusBar.native.js.map +1 -1
  423. package/dist/jsx/toolbar/TableBubble.mjs +77 -95
  424. package/dist/jsx/toolbar/TableBubble.mjs.map +1 -1
  425. package/dist/jsx/toolbar/TableBubble.native.js +73 -71
  426. package/dist/jsx/toolbar/TableBubble.native.js.map +1 -1
  427. package/dist/jsx/toolbar/ToolbarButton.mjs +87 -22
  428. package/dist/jsx/toolbar/ToolbarButton.mjs.map +1 -1
  429. package/dist/jsx/toolbar/ToolbarButton.native.js +14 -4
  430. package/dist/jsx/toolbar/ToolbarButton.native.js.map +1 -1
  431. package/dist/jsx/toolbar/icons.mjs +109 -469
  432. package/dist/jsx/toolbar/icons.mjs.map +1 -1
  433. package/dist/jsx/toolbar/shortcuts.mjs +73 -24
  434. package/dist/jsx/toolbar/shortcuts.mjs.map +1 -1
  435. package/dist/jsx/toolbar/shortcuts.native.js +73 -24
  436. package/dist/jsx/toolbar/shortcuts.native.js.map +1 -1
  437. package/dist/jsx/toolbar/useHorizontalScroll.mjs +25 -6
  438. package/dist/jsx/toolbar/useHorizontalScroll.mjs.map +1 -1
  439. package/dist/jsx/toolbar/useHorizontalScroll.native.js +25 -5
  440. package/dist/jsx/toolbar/useHorizontalScroll.native.js.map +1 -1
  441. package/dist/jsx/toolbar/useRovingFocus.mjs +55 -0
  442. package/dist/jsx/toolbar/useRovingFocus.mjs.map +1 -0
  443. package/dist/jsx/toolbar/useRovingFocus.native.js +113 -0
  444. package/dist/jsx/toolbar/useRovingFocus.native.js.map +1 -0
  445. package/dist/jsx/types.mjs.map +1 -1
  446. package/dist/jsx/types.native.js.map +1 -1
  447. package/package.json +28 -13
  448. package/src/RichEditor.native.tsx +451 -49
  449. package/src/RichEditor.stories.tsx +158 -0
  450. package/src/RichEditor.tsx +121 -7
  451. package/src/RichTextEditor/index.tsx +41 -3
  452. package/src/RichTextEditor/richTextEditor.spec.tsx +11 -4
  453. package/src/constants.ts +86 -24
  454. package/src/editor/BlockDragHandle.ts +30 -5
  455. package/src/editor/SlashCommands.tsx +228 -293
  456. package/src/editor/TentapEditor.native.tsx +68 -17
  457. package/src/editor/TiptapEditor.tsx +187 -22
  458. package/src/editor/blockAnchor.spec.ts +70 -0
  459. package/src/editor/blockAnchor.ts +42 -0
  460. package/src/editor/codeBlockPreview.spec.ts +144 -0
  461. package/src/editor/codeBlockPreview.ts +266 -0
  462. package/src/editor/css.d.ts +2 -0
  463. package/src/editor/details.spec.ts +48 -0
  464. package/src/editor/editorStyles.spec.ts +25 -0
  465. package/src/editor/editorStyles.ts +218 -34
  466. package/src/editor/emoji.spec.ts +88 -0
  467. package/src/editor/emoji.ts +147 -0
  468. package/src/editor/emojilib.d.ts +16 -0
  469. package/src/editor/lazyKatex.spec.ts +38 -0
  470. package/src/editor/lazyKatex.ts +68 -0
  471. package/src/editor/markdown.spec.ts +196 -0
  472. package/src/editor/markdown.ts +249 -0
  473. package/src/editor/mathematics.spec.ts +97 -0
  474. package/src/editor/mathematics.ts +179 -0
  475. package/src/editor/media.spec.ts +121 -0
  476. package/src/editor/media.ts +133 -0
  477. package/src/editor/mentions.spec.ts +41 -0
  478. package/src/editor/mentions.ts +55 -0
  479. package/src/editor/pasteCleanup.spec.ts +84 -0
  480. package/src/editor/pasteCleanup.ts +124 -0
  481. package/src/editor/suggestionPopup.spec.tsx +105 -0
  482. package/src/editor/suggestionPopup.tsx +414 -0
  483. package/src/editor/tiptapEditor.spec.tsx +15 -8
  484. package/src/exports.spec.ts +4 -2
  485. package/src/index.ts +7 -1
  486. package/src/integration.spec.tsx +38 -9
  487. package/src/preview.spec.ts +130 -0
  488. package/src/preview.ts +287 -0
  489. package/src/richEditor.spec.tsx +10 -3
  490. package/src/shared/t.ts +25 -0
  491. package/src/shared/url.ts +16 -0
  492. package/src/styled.ts +13 -6
  493. package/src/toolbar/BubbleToolbar.tsx +11 -8
  494. package/src/toolbar/CodeBlockBubble.tsx +66 -28
  495. package/src/toolbar/ColorPicker.native.tsx +126 -0
  496. package/src/toolbar/ColorPicker.tsx +23 -67
  497. package/src/toolbar/FixedToolbar.native.tsx +51 -51
  498. package/src/toolbar/FixedToolbar.tsx +54 -10
  499. package/src/toolbar/HeadingPicker.tsx +46 -38
  500. package/src/toolbar/ImageBubble.tsx +26 -44
  501. package/src/toolbar/ImageDialog.native.tsx +97 -0
  502. package/src/toolbar/ImageDialog.tsx +5 -4
  503. package/src/toolbar/LinkBubble.tsx +27 -64
  504. package/src/toolbar/LinkDialog.native.tsx +117 -0
  505. package/src/toolbar/LinkDialog.tsx +28 -24
  506. package/src/toolbar/ListPicker.tsx +47 -43
  507. package/src/toolbar/MathBubble.tsx +140 -0
  508. package/src/toolbar/MoreDropdown.tsx +53 -60
  509. package/src/toolbar/StatusBar.tsx +13 -8
  510. package/src/toolbar/TableBubble.tsx +82 -94
  511. package/src/toolbar/ToolbarButton.native.tsx +14 -4
  512. package/src/toolbar/ToolbarButton.tsx +98 -19
  513. package/src/toolbar/bubbleToolbar.spec.tsx +2 -1
  514. package/src/toolbar/fixedToolbar.spec.tsx +4 -2
  515. package/src/toolbar/icons.tsx +113 -323
  516. package/src/toolbar/shortcuts.ts +77 -24
  517. package/src/toolbar/toolbarPrimitives.spec.tsx +29 -1
  518. package/src/toolbar/toolbarSubComponents.spec.tsx +4 -2
  519. package/src/toolbar/useHorizontalScroll.spec.ts +67 -0
  520. package/src/toolbar/useHorizontalScroll.tsx +39 -12
  521. package/src/toolbar/useRovingFocus.spec.tsx +100 -0
  522. package/src/toolbar/useRovingFocus.ts +82 -0
  523. package/src/types.spec.ts +40 -1
  524. package/src/types.ts +28 -0
  525. package/types/RichEditor.d.ts +51 -0
  526. package/types/RichEditor.d.ts.map +1 -0
  527. package/types/RichEditor.native.d.ts +59 -0
  528. package/types/RichEditor.native.d.ts.map +1 -0
  529. package/types/RichTextEditor/index.d.ts +71 -0
  530. package/types/RichTextEditor/index.d.ts.map +1 -0
  531. package/types/constants.d.ts +49 -0
  532. package/types/constants.d.ts.map +1 -0
  533. package/types/context.d.ts +10 -0
  534. package/types/context.d.ts.map +1 -0
  535. package/types/editor/BlockDragHandle.d.ts +8 -0
  536. package/types/editor/BlockDragHandle.d.ts.map +1 -0
  537. package/types/editor/MarkdownPaste.d.ts +8 -0
  538. package/types/editor/MarkdownPaste.d.ts.map +1 -0
  539. package/types/editor/SlashCommands.d.ts +24 -0
  540. package/types/editor/SlashCommands.d.ts.map +1 -0
  541. package/types/editor/TentapEditor.native.d.ts +21 -0
  542. package/types/editor/TentapEditor.native.d.ts.map +1 -0
  543. package/types/editor/TiptapEditor.d.ts +24 -0
  544. package/types/editor/TiptapEditor.d.ts.map +1 -0
  545. package/types/editor/blockAnchor.d.ts +25 -0
  546. package/types/editor/blockAnchor.d.ts.map +1 -0
  547. package/types/editor/codeBlockPreview.d.ts +51 -0
  548. package/types/editor/codeBlockPreview.d.ts.map +1 -0
  549. package/types/editor/editorStyles.d.ts +25 -0
  550. package/types/editor/editorStyles.d.ts.map +1 -0
  551. package/types/editor/emoji.d.ts +45 -0
  552. package/types/editor/emoji.d.ts.map +1 -0
  553. package/types/editor/index.d.ts +11 -0
  554. package/types/editor/index.d.ts.map +1 -0
  555. package/types/editor/lazyKatex.d.ts +33 -0
  556. package/types/editor/lazyKatex.d.ts.map +1 -0
  557. package/types/editor/markdown.d.ts +24 -0
  558. package/types/editor/markdown.d.ts.map +1 -0
  559. package/types/editor/mathematics.d.ts +44 -0
  560. package/types/editor/mathematics.d.ts.map +1 -0
  561. package/types/editor/media.d.ts +32 -0
  562. package/types/editor/media.d.ts.map +1 -0
  563. package/types/editor/mentions.d.ts +15 -0
  564. package/types/editor/mentions.d.ts.map +1 -0
  565. package/types/editor/pasteCleanup.d.ts +24 -0
  566. package/types/editor/pasteCleanup.d.ts.map +1 -0
  567. package/types/editor/suggestionPopup.d.ts +113 -0
  568. package/types/editor/suggestionPopup.d.ts.map +1 -0
  569. package/types/editor/types.d.ts +80 -0
  570. package/types/editor/types.d.ts.map +1 -0
  571. package/types/editor/useEditorState.d.ts +19 -0
  572. package/types/editor/useEditorState.d.ts.map +1 -0
  573. package/types/index.d.ts +11 -0
  574. package/types/index.d.ts.map +1 -0
  575. package/types/preview.d.ts +44 -0
  576. package/types/preview.d.ts.map +1 -0
  577. package/types/shared/t.d.ts +10 -0
  578. package/types/shared/t.d.ts.map +1 -0
  579. package/types/shared/url.d.ts +9 -0
  580. package/types/shared/url.d.ts.map +1 -0
  581. package/types/styled.d.ts +40 -0
  582. package/types/styled.d.ts.map +1 -0
  583. package/types/toolbar/BubbleToolbar.d.ts +23 -0
  584. package/types/toolbar/BubbleToolbar.d.ts.map +1 -0
  585. package/types/toolbar/CodeBlockBubble.d.ts +10 -0
  586. package/types/toolbar/CodeBlockBubble.d.ts.map +1 -0
  587. package/types/toolbar/ColorPicker.d.ts +15 -0
  588. package/types/toolbar/ColorPicker.d.ts.map +1 -0
  589. package/types/toolbar/ColorPicker.native.d.ts +20 -0
  590. package/types/toolbar/ColorPicker.native.d.ts.map +1 -0
  591. package/types/toolbar/FixedToolbar.d.ts +32 -0
  592. package/types/toolbar/FixedToolbar.d.ts.map +1 -0
  593. package/types/toolbar/FixedToolbar.native.d.ts +30 -0
  594. package/types/toolbar/FixedToolbar.native.d.ts.map +1 -0
  595. package/types/toolbar/HeadingPicker.d.ts +14 -0
  596. package/types/toolbar/HeadingPicker.d.ts.map +1 -0
  597. package/types/toolbar/ImageBubble.d.ts +10 -0
  598. package/types/toolbar/ImageBubble.d.ts.map +1 -0
  599. package/types/toolbar/ImageDialog.d.ts +12 -0
  600. package/types/toolbar/ImageDialog.d.ts.map +1 -0
  601. package/types/toolbar/ImageDialog.native.d.ts +15 -0
  602. package/types/toolbar/ImageDialog.native.d.ts.map +1 -0
  603. package/types/toolbar/LinkBubble.d.ts +10 -0
  604. package/types/toolbar/LinkBubble.d.ts.map +1 -0
  605. package/types/toolbar/LinkDialog.d.ts +20 -0
  606. package/types/toolbar/LinkDialog.d.ts.map +1 -0
  607. package/types/toolbar/LinkDialog.native.d.ts +18 -0
  608. package/types/toolbar/LinkDialog.native.d.ts.map +1 -0
  609. package/types/toolbar/ListPicker.d.ts +14 -0
  610. package/types/toolbar/ListPicker.d.ts.map +1 -0
  611. package/types/toolbar/MathBubble.d.ts +11 -0
  612. package/types/toolbar/MathBubble.d.ts.map +1 -0
  613. package/types/toolbar/MoreDropdown.d.ts +13 -0
  614. package/types/toolbar/MoreDropdown.d.ts.map +1 -0
  615. package/types/toolbar/ResizeHandle.d.ts +11 -0
  616. package/types/toolbar/ResizeHandle.d.ts.map +1 -0
  617. package/types/toolbar/StatusBar.d.ts +11 -0
  618. package/types/toolbar/StatusBar.d.ts.map +1 -0
  619. package/types/toolbar/TableBubble.d.ts +10 -0
  620. package/types/toolbar/TableBubble.d.ts.map +1 -0
  621. package/types/toolbar/ToolbarButton.d.ts +35 -0
  622. package/types/toolbar/ToolbarButton.d.ts.map +1 -0
  623. package/types/toolbar/ToolbarButton.native.d.ts +30 -0
  624. package/types/toolbar/ToolbarButton.native.d.ts.map +1 -0
  625. package/types/toolbar/ToolbarGroup.d.ts +14 -0
  626. package/types/toolbar/ToolbarGroup.d.ts.map +1 -0
  627. package/types/toolbar/icons.d.ts +52 -0
  628. package/types/toolbar/icons.d.ts.map +1 -0
  629. package/types/toolbar/icons.native.d.ts +41 -0
  630. package/types/toolbar/icons.native.d.ts.map +1 -0
  631. package/types/toolbar/shortcuts.d.ts +34 -0
  632. package/types/toolbar/shortcuts.d.ts.map +1 -0
  633. package/types/toolbar/useHorizontalScroll.d.ts +43 -0
  634. package/types/toolbar/useHorizontalScroll.d.ts.map +1 -0
  635. package/types/toolbar/useRovingFocus.d.ts +10 -0
  636. package/types/toolbar/useRovingFocus.d.ts.map +1 -0
  637. package/types/types.d.ts +125 -0
  638. package/types/types.d.ts.map +1 -0
  639. package/dist/cjs/RichEditor.stories.cjs +0 -327
  640. package/dist/cjs/RichEditor.stories.native.js +0 -342
  641. package/dist/cjs/RichEditor.stories.native.js.map +0 -1
  642. package/dist/esm/RichEditor.stories.mjs +0 -291
  643. package/dist/esm/RichEditor.stories.mjs.map +0 -1
  644. package/dist/esm/RichEditor.stories.native.js +0 -303
  645. package/dist/esm/RichEditor.stories.native.js.map +0 -1
  646. package/dist/jsx/RichEditor.stories.mjs +0 -291
  647. package/dist/jsx/RichEditor.stories.mjs.map +0 -1
  648. package/dist/jsx/RichEditor.stories.native.js +0 -342
  649. package/dist/jsx/RichEditor.stories.native.js.map +0 -1
@@ -0,0 +1,68 @@
1
+ /**
2
+ * Lazy KaTeX renderer for `$...$` inline and `$$...$$` block math.
3
+ *
4
+ * Bundle discipline: KaTeX (~70 KB gz JS + CSS + fonts) never rides the
5
+ * editor chunk. Both the library and its stylesheet load through dynamic
6
+ * import on the first math render and are cached for the session. The
7
+ * stylesheet colors inherit `currentColor`, so dark schemes work without
8
+ * a separate dark CSS pass.
9
+ *
10
+ * The result contract is Axiom 6 friendly — invalid TeX returns
11
+ * `{ ok: false, error }` with KaTeX's parse message so callers can show
12
+ * the error instead of a blank node.
13
+ */
14
+
15
+ export type KatexRenderResult = { ok: true; html: string } | { ok: false; error: string };
16
+
17
+ type KatexModule = typeof import("katex").default;
18
+
19
+ let katexPromise: Promise<KatexModule> | null = null;
20
+
21
+ function loadKatex(): Promise<KatexModule> {
22
+ if (!katexPromise) {
23
+ katexPromise = Promise.all([
24
+ import("katex"),
25
+ // the stylesheet (fonts included) code-splits with this async chunk
26
+ import("katex/dist/katex.min.css"),
27
+ ]).then(([mod]) => (mod as any).default ?? mod);
28
+ }
29
+ return katexPromise;
30
+ }
31
+
32
+ /** Renders TeX to KaTeX HTML markup (display mode for `$$` blocks) */
33
+ export async function renderKatexHtml(
34
+ latex: string,
35
+ options: { displayMode?: boolean } = {},
36
+ ): Promise<KatexRenderResult> {
37
+ try {
38
+ const katex = await loadKatex();
39
+ const html = katex.renderToString(latex, {
40
+ displayMode: options.displayMode ?? false,
41
+ throwOnError: true,
42
+ strict: false,
43
+ });
44
+ return { ok: true, html };
45
+ } catch (err) {
46
+ return { ok: false, error: err instanceof Error ? err.message : String(err) };
47
+ }
48
+ }
49
+
50
+ /**
51
+ * Mounts KaTeX markup as real DOM nodes. KaTeX output is spans + MathML by
52
+ * construction; parsing inert and stripping executables is defense in
53
+ * depth, mirroring the mermaid mount helper.
54
+ */
55
+ export function mountKatexHtml(container: HTMLElement, html: string): void {
56
+ const doc = new DOMParser().parseFromString(html, "text/html");
57
+ for (const el of Array.from(doc.body.querySelectorAll("script, iframe, object, embed"))) {
58
+ el.remove();
59
+ }
60
+ container.replaceChildren(
61
+ ...Array.from(doc.body.childNodes).map((node) => document.importNode(node, true)),
62
+ );
63
+ }
64
+
65
+ /** Test seam: reset the cached library promise */
66
+ export function resetKatexForTesting(): void {
67
+ katexPromise = null;
68
+ }
@@ -0,0 +1,196 @@
1
+ import { describe, expect, it } from "vitest";
2
+ import { htmlToMarkdown, markdownToHtml } from "./markdown";
3
+
4
+ describe("htmlToMarkdown", () => {
5
+ it("converts headings, emphasis, and inline code to GFM", () => {
6
+ const md = htmlToMarkdown(
7
+ "<h1>Title</h1><p><strong>bold</strong> and <em>italic</em> and <code>code</code></p>",
8
+ );
9
+ expect(md).toContain("# Title");
10
+ expect(md).toContain("**bold**");
11
+ expect(md).toContain("_italic_");
12
+ expect(md).toContain("`code`");
13
+ });
14
+
15
+ it("converts strikethrough to ~~", () => {
16
+ expect(htmlToMarkdown("<p><s>gone</s></p>")).toContain("~~gone~~");
17
+ expect(htmlToMarkdown("<p><del>gone</del></p>")).toContain("~~gone~~");
18
+ });
19
+
20
+ it("converts fenced code blocks", () => {
21
+ const md = htmlToMarkdown('<pre><code class="language-js">const a = 1;</code></pre>');
22
+ expect(md).toContain("```");
23
+ expect(md).toContain("const a = 1;");
24
+ });
25
+
26
+ it("converts Tiptap task items to GFM checkboxes", () => {
27
+ const html =
28
+ '<ul data-type="taskList">' +
29
+ '<li data-type="taskItem" data-checked="true"><label><input type="checkbox" checked><span></span></label><div><p>done</p></div></li>' +
30
+ '<li data-type="taskItem" data-checked="false"><label><input type="checkbox"><span></span></label><div><p>todo</p></div></li>' +
31
+ "</ul>";
32
+ const md = htmlToMarkdown(html);
33
+ expect(md).toContain("- [x] done");
34
+ expect(md).toContain("- [ ] todo");
35
+ });
36
+
37
+ it("converts tables to GFM pipe tables", () => {
38
+ const html =
39
+ "<table><tr><th>Name</th><th>Role</th></tr><tr><td>Ada</td><td>Analyst</td></tr></table>";
40
+ const md = htmlToMarkdown(html);
41
+ expect(md).toContain("| Name | Role |");
42
+ expect(md).toContain("| --- | --- |");
43
+ expect(md).toContain("| Ada | Analyst |");
44
+ });
45
+
46
+ it("escapes pipes inside table cells", () => {
47
+ const md = htmlToMarkdown("<table><tr><th>A</th></tr><tr><td>x | y</td></tr></table>");
48
+ expect(md).toContain("x \\| y");
49
+ });
50
+
51
+ it("keeps marks markdown cannot express as inline HTML (lossless)", () => {
52
+ const md = htmlToMarkdown(
53
+ '<p><u>under</u> <sub>sub</sub> <sup>sup</sup> <mark>hi</mark> <span style="color: rgb(255, 0, 0)">red</span></p>',
54
+ );
55
+ expect(md).toContain("<u>under</u>");
56
+ expect(md).toContain("<sub>sub</sub>");
57
+ expect(md).toContain("<sup>sup</sup>");
58
+ expect(md).toContain("<mark>hi</mark>");
59
+ expect(md).toMatch(/<span style="color:\s*rgb\(255,\s*0,\s*0\)/);
60
+ });
61
+ });
62
+
63
+ describe("markdownToHtml", () => {
64
+ it("converts GFM to HTML", () => {
65
+ const html = markdownToHtml("# Title\n\n**bold** and ~~strike~~");
66
+ expect(html).toContain("<h1>Title</h1>");
67
+ expect(html).toContain("<strong>bold</strong>");
68
+ expect(html).toContain("<del>strike</del>");
69
+ });
70
+
71
+ it("upgrades GFM task lists to the Tiptap taskList schema", () => {
72
+ const html = markdownToHtml("- [x] done\n- [ ] todo");
73
+ expect(html).toContain('data-type="taskList"');
74
+ expect(html).toContain('data-type="taskItem"');
75
+ expect(html).toContain('data-checked="true"');
76
+ expect(html).toContain('data-checked="false"');
77
+ // marked's raw checkbox inputs are removed after the upgrade
78
+ expect(html).not.toContain("<input");
79
+ });
80
+
81
+ it("parses pipe tables", () => {
82
+ const html = markdownToHtml("| A | B |\n| --- | --- |\n| 1 | 2 |");
83
+ expect(html).toContain("<table>");
84
+ expect(html).toContain("<th>A</th>");
85
+ expect(html).toContain("<td>1</td>");
86
+ });
87
+ });
88
+
89
+ describe("math markdown (GitLab-flavored dollar math)", () => {
90
+ it("converts inline math spans to $...$", () => {
91
+ const md = htmlToMarkdown(
92
+ '<p>energy <span data-type="inline-math" data-latex="E=mc^2">E=mc^2</span> here</p>',
93
+ );
94
+ expect(md).toContain("$E=mc^2$");
95
+ });
96
+
97
+ it("converts math code blocks to $$ fences", () => {
98
+ const md = htmlToMarkdown('<pre><code class="language-math">\\frac{a}{b}</code></pre>');
99
+ expect(md).toContain("$$\n\\frac{a}{b}\n$$");
100
+ });
101
+
102
+ it("parses $...$ into inline math spans", () => {
103
+ const html = markdownToHtml("the mass $E=mc^2$ equation");
104
+ expect(html).toContain('data-type="inline-math"');
105
+ expect(html).toContain('data-latex="E=mc^2"');
106
+ });
107
+
108
+ it("parses $$ blocks (own-line and single-line) into math code blocks", () => {
109
+ expect(markdownToHtml("$$\n\\sqrt{x}\n$$")).toContain('<code class="language-math">');
110
+ expect(markdownToHtml("$$\\sqrt{x}$$")).toContain('<code class="language-math">');
111
+ });
112
+
113
+ it("parses ```math fences into the same math code block", () => {
114
+ expect(markdownToHtml("```math\n\\sqrt{x}\n```")).toContain('class="language-math"');
115
+ });
116
+
117
+ it("does not treat prices as math", () => {
118
+ const html = markdownToHtml("costs $5 and $10 total");
119
+ expect(html).not.toContain("inline-math");
120
+ expect(html).toContain("costs $5 and $10 total");
121
+ });
122
+
123
+ it("escapes HTML inside latex both directions", () => {
124
+ const html = markdownToHtml("$a<b$");
125
+ expect(html).toContain("a&lt;b");
126
+ expect(html).not.toContain("<b$");
127
+ });
128
+
129
+ it("round-trips inline and block math losslessly", () => {
130
+ const source =
131
+ '<p>inline <span data-type="inline-math" data-latex="x^2">x^2</span></p>' +
132
+ '<pre><code class="language-math">\\sum_{i=0}^n i</code></pre>';
133
+ const roundTripped = markdownToHtml(htmlToMarkdown(source));
134
+ expect(roundTripped).toContain('data-latex="x^2"');
135
+ expect(roundTripped).toContain('<code class="language-math">');
136
+ expect(roundTripped).toContain("\\sum_{i=0}^n i");
137
+ });
138
+ });
139
+
140
+ describe("mermaid markdown", () => {
141
+ it("round-trips mermaid fences losslessly", () => {
142
+ const source = '<pre><code class="language-mermaid">graph TD\n A--&gt;B</code></pre>';
143
+ const md = htmlToMarkdown(source);
144
+ expect(md).toContain("```mermaid");
145
+ expect(md).toContain("graph TD");
146
+ const roundTripped = markdownToHtml(md);
147
+ expect(roundTripped).toContain('class="language-mermaid"');
148
+ expect(roundTripped).toContain("A--&gt;B");
149
+ });
150
+ });
151
+
152
+ describe("details markdown (collapsible sections)", () => {
153
+ it("keeps <details> as raw HTML (GitLab behavior) and round-trips it", () => {
154
+ const source =
155
+ "<details><summary>Click me</summary>" +
156
+ '<div data-type="detailsContent"><p>hidden <strong>content</strong></p></div></details>';
157
+ const md = htmlToMarkdown(source);
158
+ expect(md).toContain("<details>");
159
+ expect(md).toContain("<summary>Click me</summary>");
160
+ const roundTripped = markdownToHtml(md);
161
+ expect(roundTripped).toContain("<details>");
162
+ expect(roundTripped).toContain("<summary>Click me</summary>");
163
+ expect(roundTripped).toContain("<strong>content</strong>");
164
+ });
165
+ });
166
+
167
+ describe("round-trip (rich -> markdown -> rich)", () => {
168
+ it("preserves headings, lists, tasks, quotes, and inline marks", () => {
169
+ const source =
170
+ "<h2>Notes</h2>" +
171
+ "<p><strong>bold</strong> <em>em</em> <s>strike</s> <code>code</code> <u>under</u></p>" +
172
+ "<ul><li><p>one</p></li><li><p>two</p></li></ul>" +
173
+ '<ul data-type="taskList"><li data-type="taskItem" data-checked="true"><label><input type="checkbox" checked><span></span></label><div><p>task</p></div></li></ul>' +
174
+ "<blockquote><p>quote</p></blockquote>";
175
+ const roundTripped = markdownToHtml(htmlToMarkdown(source));
176
+ expect(roundTripped).toContain("<h2>Notes</h2>");
177
+ expect(roundTripped).toContain("<strong>bold</strong>");
178
+ expect(roundTripped).toContain("<em>em</em>");
179
+ expect(roundTripped).toContain("<del>strike</del>");
180
+ expect(roundTripped).toContain("<code>code</code>");
181
+ expect(roundTripped).toContain("<u>under</u>");
182
+ // Tiptap emits loose lists (<li><p>…</p></li>); either form is fine
183
+ expect(roundTripped).toMatch(/<li>(<p>)?one(<\/p>)?\s*<\/li>/);
184
+ expect(roundTripped).toContain('data-type="taskItem"');
185
+ expect(roundTripped).toContain('data-checked="true"');
186
+ expect(roundTripped).toContain("<blockquote>");
187
+ });
188
+
189
+ it("preserves tables through the round trip", () => {
190
+ const source = "<table><tr><th>H</th></tr><tr><td>cell</td></tr></table>";
191
+ const roundTripped = markdownToHtml(htmlToMarkdown(source));
192
+ expect(roundTripped).toContain("<table>");
193
+ expect(roundTripped).toContain("<th>H</th>");
194
+ expect(roundTripped).toContain("<td>cell</td>");
195
+ });
196
+ });
@@ -0,0 +1,249 @@
1
+ /**
2
+ * Canonical HTML <-> Markdown conversion for the rich text editor (web).
3
+ *
4
+ * One implementation (LC-16) shared by the markdown source mode toggle and
5
+ * the markdown paste handler. GFM coverage beyond turndown's defaults:
6
+ * strikethrough, task lists (Tiptap's label-nested checkbox markup), and
7
+ * pipe tables. Marks with no markdown syntax (underline, sub/superscript,
8
+ * highlight, text color spans) survive as inline HTML so the
9
+ * rich -> markdown -> rich round-trip is lossless for every toolbar feature.
10
+ *
11
+ * GitLab-flavored extras (round-trip lossless):
12
+ * - `$x$` inline math <-> `<span data-type="inline-math" data-latex>`
13
+ * - `$$ ... $$` block math <-> code block with language "math"
14
+ * (``` math fences parse to the same node; `$$` is the canonical output)
15
+ * - ```mermaid fences <-> code block with language "mermaid" (turndown's
16
+ * fenced rule + marked's language classes handle this natively)
17
+ * - `<details>` collapsible sections stay raw HTML in markdown, exactly
18
+ * like GitLab renders them
19
+ */
20
+
21
+ import TurndownService from "turndown";
22
+ import { Marked } from "marked";
23
+
24
+ // ===========================================================================
25
+ // HTML -> Markdown (turndown + GFM rules)
26
+ // ===========================================================================
27
+
28
+ function cellMarkdown(cell: HTMLElement, inline: TurndownService): string {
29
+ const md = inline.turndown(cell.innerHTML || "");
30
+ // GFM cells are single-line: collapse block breaks and escape pipes
31
+ return md.replace(/\n+/g, " ").replace(/\|/g, "\\|").trim();
32
+ }
33
+
34
+ function createTurndown(): TurndownService {
35
+ const service = new TurndownService({
36
+ headingStyle: "atx",
37
+ codeBlockStyle: "fenced",
38
+ bulletListMarker: "-",
39
+ });
40
+
41
+ // Marks markdown cannot express stay as inline HTML (round-trip lossless):
42
+ // underline, sub/superscript, highlight, and color-carrying spans.
43
+ // Collapsible <details> sections are raw HTML in markdown (GitLab
44
+ // behavior) — kept whole, children included.
45
+ service.keep((node) => {
46
+ const name = node.nodeName;
47
+ if (name === "U" || name === "SUB" || name === "SUP" || name === "MARK") return true;
48
+ if (name === "DETAILS") return true;
49
+ if (name === "SPAN") {
50
+ const style = (node as HTMLElement).getAttribute("style") ?? "";
51
+ return style.includes("color");
52
+ }
53
+ return false;
54
+ });
55
+
56
+ service.addRule("strikethrough", {
57
+ filter: ["del", "s"],
58
+ replacement: (content) => `~~${content}~~`,
59
+ });
60
+
61
+ // Inline math node -> `$latex$` (GitLab-flavored markdown dollar math)
62
+ service.addRule("inlineMath", {
63
+ filter: (node) =>
64
+ node.nodeName === "SPAN" && (node as HTMLElement).getAttribute("data-type") === "inline-math",
65
+ replacement: (_content, node) => `$${(node as HTMLElement).getAttribute("data-latex") ?? ""}$`,
66
+ });
67
+
68
+ // Math code block -> `$$` delimited block (canonical GLFM display math)
69
+ service.addRule("mathBlock", {
70
+ filter: (node) =>
71
+ node.nodeName === "PRE" &&
72
+ (node.firstChild as HTMLElement | null)?.nodeName === "CODE" &&
73
+ ((node.firstChild as HTMLElement).getAttribute("class") ?? "").includes("language-math"),
74
+ replacement: (_content, node) => {
75
+ const code = (node.firstChild as HTMLElement).textContent ?? "";
76
+ return `\n\n$$\n${code.replace(/\n$/, "")}\n$$\n\n`;
77
+ },
78
+ });
79
+
80
+ // Tiptap task item: <li data-type="taskItem" data-checked="true">
81
+ // <label><input type="checkbox"><span></span></label><div><p>text</p></div>
82
+ service.addRule("taskListItem", {
83
+ filter: (node) =>
84
+ node.nodeName === "LI" && (node as HTMLElement).getAttribute("data-type") === "taskItem",
85
+ replacement: (content, node) => {
86
+ const checked = (node as HTMLElement).getAttribute("data-checked") === "true";
87
+ const text = content.replace(/^\s+|\s+$/g, "").replace(/\n{2,}/g, "\n");
88
+ return `- [${checked ? "x" : " "}] ${text}\n`;
89
+ },
90
+ });
91
+
92
+ // The checkbox control inside the task item label contributes no text
93
+ service.addRule("taskListCheckbox", {
94
+ filter: (node) =>
95
+ (node.nodeName === "INPUT" && (node as HTMLInputElement).type === "checkbox") ||
96
+ (node.nodeName === "LABEL" && node.parentElement?.getAttribute("data-type") === "taskItem"),
97
+ replacement: () => "",
98
+ });
99
+
100
+ // GFM pipe tables (simple grid: no colspan/rowspan)
101
+ service.addRule("table", {
102
+ filter: "table",
103
+ replacement: (_content, node) => {
104
+ const table = node as HTMLTableElement;
105
+ const rows = Array.from(table.querySelectorAll("tr"));
106
+ if (rows.length === 0) return "";
107
+ const inline = createInlineTurndown();
108
+ const grid = rows.map((row) =>
109
+ Array.from(row.querySelectorAll("th, td")).map((cell) =>
110
+ cellMarkdown(cell as HTMLElement, inline),
111
+ ),
112
+ );
113
+ const cols = Math.max(...grid.map((r) => r.length));
114
+ const pad = (r: string[]) => {
115
+ const filled = [...r];
116
+ while (filled.length < cols) filled.push("");
117
+ return filled;
118
+ };
119
+ const line = (cells: string[]) => `| ${pad(cells).join(" | ")} |`;
120
+ const header = line(grid[0]!);
121
+ const divider = `| ${Array.from({ length: cols }, () => "---").join(" | ")} |`;
122
+ const body = grid.slice(1).map(line);
123
+ return `\n\n${[header, divider, ...body].join("\n")}\n\n`;
124
+ },
125
+ });
126
+
127
+ return service;
128
+ }
129
+
130
+ /** Inline-only converter for table cells (tables cannot nest in GFM cells) */
131
+ function createInlineTurndown(): TurndownService {
132
+ const service = new TurndownService({ codeBlockStyle: "fenced" });
133
+ service.keep((node) => {
134
+ const name = node.nodeName;
135
+ if (name === "U" || name === "SUB" || name === "SUP" || name === "MARK") return true;
136
+ if (name === "SPAN")
137
+ return ((node as HTMLElement).getAttribute("style") ?? "").includes("color");
138
+ return false;
139
+ });
140
+ service.addRule("strikethrough", {
141
+ filter: ["del", "s"],
142
+ replacement: (content) => `~~${content}~~`,
143
+ });
144
+ return service;
145
+ }
146
+
147
+ let turndownSingleton: TurndownService | null = null;
148
+
149
+ /** Convert editor HTML to GFM markdown */
150
+ export function htmlToMarkdown(html: string): string {
151
+ if (!turndownSingleton) turndownSingleton = createTurndown();
152
+ return turndownSingleton.turndown(html);
153
+ }
154
+
155
+ // ===========================================================================
156
+ // Markdown -> HTML (marked + math extensions + Tiptap task list upgrade)
157
+ // ===========================================================================
158
+
159
+ function escapeHtml(value: string): string {
160
+ return value
161
+ .replace(/&/g, "&amp;")
162
+ .replace(/</g, "&lt;")
163
+ .replace(/>/g, "&gt;")
164
+ .replace(/"/g, "&quot;");
165
+ }
166
+
167
+ /**
168
+ * `$$ ... $$` display math -> math code block. Accepts the delimiters on
169
+ * their own lines (canonical GLFM) or a single `$$x$$` line; both re-enter
170
+ * the editor as a code block with language "math".
171
+ */
172
+ const blockMathExtension = {
173
+ name: "blockMath",
174
+ level: "block" as const,
175
+ start: (src: string) => src.match(/^\$\$/m)?.index,
176
+ tokenizer(src: string) {
177
+ const match =
178
+ src.match(/^\$\$[ \t]*\n([\s\S]*?)\n[ \t]*\$\$[ \t]*(?:\n+|$)/) ??
179
+ src.match(/^\$\$([^\n$]+?)\$\$[ \t]*(?:\n+|$)/);
180
+ if (!match) return undefined;
181
+ return { type: "blockMath", raw: match[0], latex: (match[1] ?? "").trim() };
182
+ },
183
+ renderer(token: { latex: string }) {
184
+ return `<pre><code class="language-math">${escapeHtml(token.latex)}</code></pre>\n`;
185
+ },
186
+ };
187
+
188
+ /**
189
+ * `$x^2$` inline math -> inline-math span. Content must not start or end
190
+ * with whitespace and cannot span lines, so prose like "$5 and $10" never
191
+ * false-positives (same heuristic GitLab/Pandoc use for dollar math).
192
+ */
193
+ const inlineMathExtension = {
194
+ name: "inlineMath",
195
+ level: "inline" as const,
196
+ start: (src: string) => src.indexOf("$"),
197
+ tokenizer(src: string) {
198
+ const match = src.match(/^\$([^$\n])\$/) ?? src.match(/^\$([^$\n \t][^$\n]*?[^$\n \t])\$/);
199
+ if (!match) return undefined;
200
+ return { type: "inlineMath", raw: match[0], latex: match[1] ?? "" };
201
+ },
202
+ renderer(token: { latex: string }) {
203
+ const escaped = escapeHtml(token.latex);
204
+ return `<span data-type="inline-math" data-latex="${escaped}">${escaped}</span>`;
205
+ },
206
+ };
207
+
208
+ let markedSingleton: Marked | null = null;
209
+
210
+ /** Local marked instance so math extensions never leak into the global */
211
+ function getMarked(): Marked {
212
+ if (!markedSingleton) {
213
+ markedSingleton = new Marked({ gfm: true });
214
+ markedSingleton.use({ extensions: [blockMathExtension, inlineMathExtension] });
215
+ }
216
+ return markedSingleton;
217
+ }
218
+
219
+ /**
220
+ * marked emits GFM task items as `<li><input type="checkbox" checked>`;
221
+ * Tiptap's TaskList/TaskItem parse `ul[data-type="taskList"] >
222
+ * li[data-type="taskItem"][data-checked]`. Upgrade in the DOM so the
223
+ * round-trip re-enters the editor as real task items.
224
+ */
225
+ function upgradeTaskLists(html: string): string {
226
+ if (typeof document === "undefined" || !html.includes("checkbox")) return html;
227
+ const doc = new DOMParser().parseFromString(html, "text/html");
228
+ for (const input of Array.from(
229
+ doc.querySelectorAll<HTMLInputElement>('li input[type="checkbox"]'),
230
+ )) {
231
+ const li = input.closest("li");
232
+ if (!li) continue;
233
+ li.setAttribute("data-type", "taskItem");
234
+ li.setAttribute(
235
+ "data-checked",
236
+ input.checked || input.hasAttribute("checked") ? "true" : "false",
237
+ );
238
+ input.remove();
239
+ const list = li.closest("ul, ol");
240
+ if (list) list.setAttribute("data-type", "taskList");
241
+ }
242
+ return doc.body.innerHTML;
243
+ }
244
+
245
+ /** Convert GFM markdown to HTML the Tiptap schema can ingest */
246
+ export function markdownToHtml(markdown: string): string {
247
+ const html = getMarked().parse(markdown, { async: false }) as string;
248
+ return upgradeTaskLists(html);
249
+ }
@@ -0,0 +1,97 @@
1
+ import { describe, expect, it } from "vitest";
2
+ import { Editor } from "@tiptap/core";
3
+ import StarterKit from "@tiptap/starter-kit";
4
+ import { INLINE_MATH_INPUT_RULE, InlineMath } from "./mathematics";
5
+
6
+ function createEditor(content = "<p></p>") {
7
+ return new Editor({
8
+ element: document.createElement("div"),
9
+ extensions: [StarterKit, InlineMath],
10
+ content,
11
+ });
12
+ }
13
+
14
+ async function waitFor(check: () => boolean, timeoutMs = 3000): Promise<void> {
15
+ const start = Date.now();
16
+ while (!check()) {
17
+ if (Date.now() - start > timeoutMs) throw new Error("waitFor timed out");
18
+ await new Promise((resolve) => setTimeout(resolve, 25));
19
+ }
20
+ }
21
+
22
+ describe("INLINE_MATH_INPUT_RULE", () => {
23
+ const matches = (text: string) => text.match(INLINE_MATH_INPUT_RULE);
24
+
25
+ it("matches dollar math at the end of typed text", () => {
26
+ const match = matches("energy $E=mc^2$");
27
+ expect(match?.[2]).toBe("E=mc^2");
28
+ const startOfLine = matches("$x^2$");
29
+ expect(startOfLine?.[2]).toBe("x^2");
30
+ const singleChar = matches("$x$");
31
+ expect(singleChar?.[2]).toBe("x");
32
+ });
33
+
34
+ it("rejects price-like text and padded content", () => {
35
+ expect(matches("costs $5 and $10")).toBeNull();
36
+ expect(matches("$ x$")).toBeNull();
37
+ expect(matches("$x $")).toBeNull();
38
+ expect(matches("$$")).toBeNull();
39
+ // `$$x$$` is block math, not inline
40
+ expect(matches("$$x$$")).toBeNull();
41
+ });
42
+ });
43
+
44
+ describe("InlineMath node", () => {
45
+ it("parses and serializes data-latex spans losslessly", () => {
46
+ const editor = createEditor(
47
+ '<p>see <span data-type="inline-math" data-latex="E=mc^2">E=mc^2</span></p>',
48
+ );
49
+ expect(editor.getHTML()).toContain('data-type="inline-math"');
50
+ expect(editor.getHTML()).toContain('data-latex="E=mc^2"');
51
+ editor.destroy();
52
+ });
53
+
54
+ it("insertInlineMath inserts and selects the node (bubble opens)", () => {
55
+ const editor = createEditor();
56
+ editor.chain().focus().insertInlineMath({ latex: "a+b" }).run();
57
+ expect(editor.isActive("inlineMath")).toBe(true);
58
+ expect(editor.getAttributes("inlineMath").latex).toBe("a+b");
59
+ editor.destroy();
60
+ });
61
+
62
+ it("updateInlineMath rewrites the selected node's latex", () => {
63
+ const editor = createEditor();
64
+ editor.chain().focus().insertInlineMath({ latex: "a" }).run();
65
+ expect(editor.commands.updateInlineMath({ latex: "b^2" })).toBe(true);
66
+ expect(editor.getAttributes("inlineMath").latex).toBe("b^2");
67
+ expect(editor.getHTML()).toContain('data-latex="b^2"');
68
+ editor.destroy();
69
+ });
70
+
71
+ it("updateInlineMath is a no-op without a selected math node", () => {
72
+ const editor = createEditor("<p>plain</p>");
73
+ expect(editor.commands.updateInlineMath({ latex: "x" })).toBe(false);
74
+ editor.destroy();
75
+ });
76
+
77
+ it("node view renders KaTeX markup for valid TeX", async () => {
78
+ const editor = createEditor('<p><span data-type="inline-math" data-latex="x^2">x^2</span></p>');
79
+ const chip = editor.view.dom.querySelector(".rt-math-inline");
80
+ expect(chip).not.toBeNull();
81
+ await waitFor(() => chip!.querySelector(".katex") !== null);
82
+ expect(chip!.getAttribute("aria-label")).toBe("x^2");
83
+ editor.destroy();
84
+ });
85
+
86
+ it("node view shows the error state for invalid TeX", async () => {
87
+ const editor = createEditor(
88
+ '<p><span data-type="inline-math" data-latex="\\nope{">x</span></p>',
89
+ );
90
+ const chip = editor.view.dom.querySelector(".rt-math-inline");
91
+ await waitFor(() => chip!.classList.contains("rt-math-error"));
92
+ // raw source stays visible; the parse error rides the title
93
+ expect(chip!.textContent).toBe("\\nope{");
94
+ expect(chip!.getAttribute("title")).toMatch(/parse error/i);
95
+ editor.destroy();
96
+ });
97
+ });