phormat 0.0.5

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 (489) hide show
  1. package/README.md +102 -0
  2. package/dist/assets/example-test.svelte +228 -0
  3. package/dist/debug/JsonDebug.svelte +19 -0
  4. package/dist/debug/JsonDebug.svelte.d.ts +6 -0
  5. package/dist/debug/JsonDebugNode.svelte +138 -0
  6. package/dist/debug/JsonDebugNode.svelte.d.ts +11 -0
  7. package/dist/demo/documentLifecycle.d.ts +57 -0
  8. package/dist/demo/documentLifecycle.js +196 -0
  9. package/dist/demo/index.d.ts +2 -0
  10. package/dist/demo/index.js +2 -0
  11. package/dist/editor/BlockEditor.svelte +112 -0
  12. package/dist/editor/BlockEditor.svelte.d.ts +7 -0
  13. package/dist/editor/BlockRow.svelte +76 -0
  14. package/dist/editor/BlockRow.svelte.d.ts +20 -0
  15. package/dist/editor/Editor.svelte +103 -0
  16. package/dist/editor/Editor.svelte.d.ts +7 -0
  17. package/dist/editor/MarkdownEditor.svelte.d.ts +160 -0
  18. package/dist/editor/MarkdownEditor.svelte.js +1119 -0
  19. package/dist/editor/NestedRowChrome.svelte +160 -0
  20. package/dist/editor/NestedRowChrome.svelte.d.ts +20 -0
  21. package/dist/editor/PhormatEditor.svelte +206 -0
  22. package/dist/editor/PhormatEditor.svelte.d.ts +26 -0
  23. package/dist/editor/RawMarkdownPanel.svelte +39 -0
  24. package/dist/editor/RawMarkdownPanel.svelte.d.ts +6 -0
  25. package/dist/editor/block-specs/BlockSpecMissing.svelte +12 -0
  26. package/dist/editor/block-specs/BlockSpecMissing.svelte.d.ts +7 -0
  27. package/dist/editor/block-specs/blockquote/BlockquoteRenderer.svelte +32 -0
  28. package/dist/editor/block-specs/blockquote/BlockquoteRenderer.svelte.d.ts +21 -0
  29. package/dist/editor/block-specs/blockquote/commands.d.ts +2 -0
  30. package/dist/editor/block-specs/blockquote/commands.js +65 -0
  31. package/dist/editor/block-specs/blockquote/index.d.ts +6 -0
  32. package/dist/editor/block-specs/blockquote/index.js +5 -0
  33. package/dist/editor/block-specs/blockquote/inlineSecondPass.d.ts +6 -0
  34. package/dist/editor/block-specs/blockquote/inlineSecondPass.js +35 -0
  35. package/dist/editor/block-specs/blockquote/parse.d.ts +16 -0
  36. package/dist/editor/block-specs/blockquote/parse.js +188 -0
  37. package/dist/editor/block-specs/blockquote/reconcile.d.ts +2 -0
  38. package/dist/editor/block-specs/blockquote/reconcile.js +9 -0
  39. package/dist/editor/block-specs/blockquote/serialize.d.ts +6 -0
  40. package/dist/editor/block-specs/blockquote/serialize.js +55 -0
  41. package/dist/editor/block-specs/blockquote/types.d.ts +20 -0
  42. package/dist/editor/block-specs/blockquote/types.js +1 -0
  43. package/dist/editor/block-specs/blockquoteSpec.d.ts +4 -0
  44. package/dist/editor/block-specs/blockquoteSpec.js +37 -0
  45. package/dist/editor/block-specs/callout/CalloutRenderer.svelte +38 -0
  46. package/dist/editor/block-specs/callout/CalloutRenderer.svelte.d.ts +21 -0
  47. package/dist/editor/block-specs/callout/CalloutTypeIcon.svelte +14 -0
  48. package/dist/editor/block-specs/callout/CalloutTypeIcon.svelte.d.ts +7 -0
  49. package/dist/editor/block-specs/callout/commands.d.ts +2 -0
  50. package/dist/editor/block-specs/callout/commands.js +65 -0
  51. package/dist/editor/block-specs/callout/icons.d.ts +10 -0
  52. package/dist/editor/block-specs/callout/icons.js +52 -0
  53. package/dist/editor/block-specs/callout/index.d.ts +9 -0
  54. package/dist/editor/block-specs/callout/index.js +7 -0
  55. package/dist/editor/block-specs/callout/inlineSecondPass.d.ts +6 -0
  56. package/dist/editor/block-specs/callout/inlineSecondPass.js +9 -0
  57. package/dist/editor/block-specs/callout/parse.d.ts +9 -0
  58. package/dist/editor/block-specs/callout/parse.js +83 -0
  59. package/dist/editor/block-specs/callout/parseBody.d.ts +6 -0
  60. package/dist/editor/block-specs/callout/parseBody.js +290 -0
  61. package/dist/editor/block-specs/callout/reconcile.d.ts +2 -0
  62. package/dist/editor/block-specs/callout/reconcile.js +8 -0
  63. package/dist/editor/block-specs/callout/serialize.d.ts +5 -0
  64. package/dist/editor/block-specs/callout/serialize.js +65 -0
  65. package/dist/editor/block-specs/callout/types.d.ts +7 -0
  66. package/dist/editor/block-specs/callout/types.js +1 -0
  67. package/dist/editor/block-specs/calloutSpec.d.ts +2 -0
  68. package/dist/editor/block-specs/calloutSpec.js +23 -0
  69. package/dist/editor/block-specs/codeFence/CodeFenceRenderer.svelte +18 -0
  70. package/dist/editor/block-specs/codeFence/CodeFenceRenderer.svelte.d.ts +21 -0
  71. package/dist/editor/block-specs/codeFence/commands.d.ts +2 -0
  72. package/dist/editor/block-specs/codeFence/commands.js +1 -0
  73. package/dist/editor/block-specs/codeFence/index.d.ts +5 -0
  74. package/dist/editor/block-specs/codeFence/index.js +4 -0
  75. package/dist/editor/block-specs/codeFence/inlineSecondPass.d.ts +3 -0
  76. package/dist/editor/block-specs/codeFence/inlineSecondPass.js +5 -0
  77. package/dist/editor/block-specs/codeFence/reconcile.d.ts +2 -0
  78. package/dist/editor/block-specs/codeFence/reconcile.js +5 -0
  79. package/dist/editor/block-specs/codeFence/serialize.d.ts +2 -0
  80. package/dist/editor/block-specs/codeFence/serialize.js +8 -0
  81. package/dist/editor/block-specs/codeFence/types.d.ts +6 -0
  82. package/dist/editor/block-specs/codeFence/types.js +1 -0
  83. package/dist/editor/block-specs/codeFenceSpec.d.ts +2 -0
  84. package/dist/editor/block-specs/codeFenceSpec.js +23 -0
  85. package/dist/editor/block-specs/columns/ColumnsRenderer.svelte +18 -0
  86. package/dist/editor/block-specs/columns/ColumnsRenderer.svelte.d.ts +21 -0
  87. package/dist/editor/block-specs/columns/EditableColumns.svelte +16 -0
  88. package/dist/editor/block-specs/columns/EditableColumns.svelte.d.ts +4 -0
  89. package/dist/editor/block-specs/columns/commands.d.ts +2 -0
  90. package/dist/editor/block-specs/columns/commands.js +1 -0
  91. package/dist/editor/block-specs/columns/index.d.ts +6 -0
  92. package/dist/editor/block-specs/columns/index.js +5 -0
  93. package/dist/editor/block-specs/columns/inlineSecondPass.d.ts +3 -0
  94. package/dist/editor/block-specs/columns/inlineSecondPass.js +5 -0
  95. package/dist/editor/block-specs/columns/parse.d.ts +20 -0
  96. package/dist/editor/block-specs/columns/parse.js +111 -0
  97. package/dist/editor/block-specs/columns/reconcile.d.ts +2 -0
  98. package/dist/editor/block-specs/columns/reconcile.js +6 -0
  99. package/dist/editor/block-specs/columns/serialize.d.ts +2 -0
  100. package/dist/editor/block-specs/columns/serialize.js +16 -0
  101. package/dist/editor/block-specs/columns/types.d.ts +4 -0
  102. package/dist/editor/block-specs/columns/types.js +1 -0
  103. package/dist/editor/block-specs/columnsSpec.d.ts +2 -0
  104. package/dist/editor/block-specs/columnsSpec.js +24 -0
  105. package/dist/editor/block-specs/heading/HeaderRenderer.svelte +30 -0
  106. package/dist/editor/block-specs/heading/HeaderRenderer.svelte.d.ts +21 -0
  107. package/dist/editor/block-specs/heading/commands.d.ts +2 -0
  108. package/dist/editor/block-specs/heading/commands.js +41 -0
  109. package/dist/editor/block-specs/heading/edit.d.ts +10 -0
  110. package/dist/editor/block-specs/heading/edit.js +33 -0
  111. package/dist/editor/block-specs/heading/index.d.ts +7 -0
  112. package/dist/editor/block-specs/heading/index.js +6 -0
  113. package/dist/editor/block-specs/heading/inlineSecondPass.d.ts +4 -0
  114. package/dist/editor/block-specs/heading/inlineSecondPass.js +20 -0
  115. package/dist/editor/block-specs/heading/parse.d.ts +5 -0
  116. package/dist/editor/block-specs/heading/parse.js +18 -0
  117. package/dist/editor/block-specs/heading/reconcile.d.ts +2 -0
  118. package/dist/editor/block-specs/heading/reconcile.js +8 -0
  119. package/dist/editor/block-specs/heading/serialize.d.ts +2 -0
  120. package/dist/editor/block-specs/heading/serialize.js +9 -0
  121. package/dist/editor/block-specs/heading/types.d.ts +5 -0
  122. package/dist/editor/block-specs/heading/types.js +1 -0
  123. package/dist/editor/block-specs/headingSpec.d.ts +2 -0
  124. package/dist/editor/block-specs/headingSpec.js +28 -0
  125. package/dist/editor/block-specs/horizontalRule/HorizontalRuleRenderer.svelte +15 -0
  126. package/dist/editor/block-specs/horizontalRule/HorizontalRuleRenderer.svelte.d.ts +21 -0
  127. package/dist/editor/block-specs/horizontalRule/commands.d.ts +2 -0
  128. package/dist/editor/block-specs/horizontalRule/commands.js +1 -0
  129. package/dist/editor/block-specs/horizontalRule/index.d.ts +6 -0
  130. package/dist/editor/block-specs/horizontalRule/index.js +5 -0
  131. package/dist/editor/block-specs/horizontalRule/inlineSecondPass.d.ts +3 -0
  132. package/dist/editor/block-specs/horizontalRule/inlineSecondPass.js +5 -0
  133. package/dist/editor/block-specs/horizontalRule/parse.d.ts +2 -0
  134. package/dist/editor/block-specs/horizontalRule/parse.js +15 -0
  135. package/dist/editor/block-specs/horizontalRule/reconcile.d.ts +2 -0
  136. package/dist/editor/block-specs/horizontalRule/reconcile.js +5 -0
  137. package/dist/editor/block-specs/horizontalRule/serialize.d.ts +2 -0
  138. package/dist/editor/block-specs/horizontalRule/serialize.js +3 -0
  139. package/dist/editor/block-specs/horizontalRule/types.d.ts +3 -0
  140. package/dist/editor/block-specs/horizontalRule/types.js +1 -0
  141. package/dist/editor/block-specs/horizontalRuleSpec.d.ts +2 -0
  142. package/dist/editor/block-specs/horizontalRuleSpec.js +24 -0
  143. package/dist/editor/block-specs/list/ListRenderer.svelte +70 -0
  144. package/dist/editor/block-specs/list/ListRenderer.svelte.d.ts +21 -0
  145. package/dist/editor/block-specs/list/commands.d.ts +2 -0
  146. package/dist/editor/block-specs/list/commands.js +65 -0
  147. package/dist/editor/block-specs/list/index.d.ts +6 -0
  148. package/dist/editor/block-specs/list/index.js +5 -0
  149. package/dist/editor/block-specs/list/inlineSecondPass.d.ts +6 -0
  150. package/dist/editor/block-specs/list/inlineSecondPass.js +78 -0
  151. package/dist/editor/block-specs/list/parse.d.ts +11 -0
  152. package/dist/editor/block-specs/list/parse.js +312 -0
  153. package/dist/editor/block-specs/list/reconcile.d.ts +2 -0
  154. package/dist/editor/block-specs/list/reconcile.js +6 -0
  155. package/dist/editor/block-specs/list/serialize.d.ts +4 -0
  156. package/dist/editor/block-specs/list/serialize.js +83 -0
  157. package/dist/editor/block-specs/list/types.d.ts +27 -0
  158. package/dist/editor/block-specs/list/types.js +1 -0
  159. package/dist/editor/block-specs/listSpec.d.ts +4 -0
  160. package/dist/editor/block-specs/listSpec.js +24 -0
  161. package/dist/editor/block-specs/paragraph/ParagraphRenderer.svelte +22 -0
  162. package/dist/editor/block-specs/paragraph/ParagraphRenderer.svelte.d.ts +21 -0
  163. package/dist/editor/block-specs/paragraph/commands.d.ts +2 -0
  164. package/dist/editor/block-specs/paragraph/commands.js +41 -0
  165. package/dist/editor/block-specs/paragraph/edit.d.ts +10 -0
  166. package/dist/editor/block-specs/paragraph/edit.js +69 -0
  167. package/dist/editor/block-specs/paragraph/index.d.ts +7 -0
  168. package/dist/editor/block-specs/paragraph/index.js +6 -0
  169. package/dist/editor/block-specs/paragraph/inlineSecondPass.d.ts +3 -0
  170. package/dist/editor/block-specs/paragraph/inlineSecondPass.js +25 -0
  171. package/dist/editor/block-specs/paragraph/parse.d.ts +9 -0
  172. package/dist/editor/block-specs/paragraph/parse.js +76 -0
  173. package/dist/editor/block-specs/paragraph/reconcile.d.ts +2 -0
  174. package/dist/editor/block-specs/paragraph/reconcile.js +9 -0
  175. package/dist/editor/block-specs/paragraph/serialize.d.ts +4 -0
  176. package/dist/editor/block-specs/paragraph/serialize.js +39 -0
  177. package/dist/editor/block-specs/paragraph/types.d.ts +10 -0
  178. package/dist/editor/block-specs/paragraph/types.js +1 -0
  179. package/dist/editor/block-specs/paragraphSpec.d.ts +2 -0
  180. package/dist/editor/block-specs/paragraphSpec.js +24 -0
  181. package/dist/editor/block-specs/registry.d.ts +10 -0
  182. package/dist/editor/block-specs/registry.js +34 -0
  183. package/dist/editor/block-specs/table/TableRenderer.svelte +53 -0
  184. package/dist/editor/block-specs/table/TableRenderer.svelte.d.ts +21 -0
  185. package/dist/editor/block-specs/table/commands.d.ts +2 -0
  186. package/dist/editor/block-specs/table/commands.js +1 -0
  187. package/dist/editor/block-specs/table/edit.d.ts +10 -0
  188. package/dist/editor/block-specs/table/edit.js +127 -0
  189. package/dist/editor/block-specs/table/editCommands.d.ts +18 -0
  190. package/dist/editor/block-specs/table/editCommands.js +87 -0
  191. package/dist/editor/block-specs/table/index.d.ts +8 -0
  192. package/dist/editor/block-specs/table/index.js +6 -0
  193. package/dist/editor/block-specs/table/inlineSecondPass.d.ts +3 -0
  194. package/dist/editor/block-specs/table/inlineSecondPass.js +22 -0
  195. package/dist/editor/block-specs/table/parse.d.ts +17 -0
  196. package/dist/editor/block-specs/table/parse.js +181 -0
  197. package/dist/editor/block-specs/table/reconcile.d.ts +2 -0
  198. package/dist/editor/block-specs/table/reconcile.js +6 -0
  199. package/dist/editor/block-specs/table/serialize.d.ts +3 -0
  200. package/dist/editor/block-specs/table/serialize.js +32 -0
  201. package/dist/editor/block-specs/table/types.d.ts +11 -0
  202. package/dist/editor/block-specs/table/types.js +1 -0
  203. package/dist/editor/block-specs/tableSpec.d.ts +2 -0
  204. package/dist/editor/block-specs/tableSpec.js +25 -0
  205. package/dist/editor/block-specs/toc/EditableToc.svelte +16 -0
  206. package/dist/editor/block-specs/toc/EditableToc.svelte.d.ts +4 -0
  207. package/dist/editor/block-specs/toc/TocRenderer.svelte +22 -0
  208. package/dist/editor/block-specs/toc/TocRenderer.svelte.d.ts +21 -0
  209. package/dist/editor/block-specs/toc/commands.d.ts +2 -0
  210. package/dist/editor/block-specs/toc/commands.js +1 -0
  211. package/dist/editor/block-specs/toc/index.d.ts +6 -0
  212. package/dist/editor/block-specs/toc/index.js +5 -0
  213. package/dist/editor/block-specs/toc/inlineSecondPass.d.ts +3 -0
  214. package/dist/editor/block-specs/toc/inlineSecondPass.js +5 -0
  215. package/dist/editor/block-specs/toc/parse.d.ts +10 -0
  216. package/dist/editor/block-specs/toc/parse.js +43 -0
  217. package/dist/editor/block-specs/toc/reconcile.d.ts +2 -0
  218. package/dist/editor/block-specs/toc/reconcile.js +5 -0
  219. package/dist/editor/block-specs/toc/serialize.d.ts +2 -0
  220. package/dist/editor/block-specs/toc/serialize.js +6 -0
  221. package/dist/editor/block-specs/toc/types.d.ts +8 -0
  222. package/dist/editor/block-specs/toc/types.js +1 -0
  223. package/dist/editor/block-specs/tocSpec.d.ts +2 -0
  224. package/dist/editor/block-specs/tocSpec.js +24 -0
  225. package/dist/editor/block-specs/toggle/ToggleRenderer.svelte +19 -0
  226. package/dist/editor/block-specs/toggle/ToggleRenderer.svelte.d.ts +21 -0
  227. package/dist/editor/block-specs/toggle/commands.d.ts +2 -0
  228. package/dist/editor/block-specs/toggle/commands.js +1 -0
  229. package/dist/editor/block-specs/toggle/index.d.ts +7 -0
  230. package/dist/editor/block-specs/toggle/index.js +5 -0
  231. package/dist/editor/block-specs/toggle/inlineSecondPass.d.ts +3 -0
  232. package/dist/editor/block-specs/toggle/inlineSecondPass.js +5 -0
  233. package/dist/editor/block-specs/toggle/parse.d.ts +9 -0
  234. package/dist/editor/block-specs/toggle/parse.js +78 -0
  235. package/dist/editor/block-specs/toggle/reconcile.d.ts +2 -0
  236. package/dist/editor/block-specs/toggle/reconcile.js +6 -0
  237. package/dist/editor/block-specs/toggle/serialize.d.ts +4 -0
  238. package/dist/editor/block-specs/toggle/serialize.js +13 -0
  239. package/dist/editor/block-specs/toggle/types.d.ts +5 -0
  240. package/dist/editor/block-specs/toggle/types.js +1 -0
  241. package/dist/editor/block-specs/toggleSpec.d.ts +2 -0
  242. package/dist/editor/block-specs/toggleSpec.js +24 -0
  243. package/dist/editor/block-specs/types.d.ts +26 -0
  244. package/dist/editor/block-specs/types.js +1 -0
  245. package/dist/editor/blocks/EditableBlockquote.svelte +52 -0
  246. package/dist/editor/blocks/EditableBlockquote.svelte.d.ts +10 -0
  247. package/dist/editor/blocks/EditableBlockquoteNodes.svelte +134 -0
  248. package/dist/editor/blocks/EditableBlockquoteNodes.svelte.d.ts +14 -0
  249. package/dist/editor/blocks/EditableBlockquoteParagraph.svelte +44 -0
  250. package/dist/editor/blocks/EditableBlockquoteParagraph.svelte.d.ts +12 -0
  251. package/dist/editor/blocks/EditableCallout.svelte +182 -0
  252. package/dist/editor/blocks/EditableCallout.svelte.d.ts +11 -0
  253. package/dist/editor/blocks/EditableCalloutListItemRow.svelte +169 -0
  254. package/dist/editor/blocks/EditableCalloutListItemRow.svelte.d.ts +15 -0
  255. package/dist/editor/blocks/EditableCalloutNodes.svelte +91 -0
  256. package/dist/editor/blocks/EditableCalloutNodes.svelte.d.ts +13 -0
  257. package/dist/editor/blocks/EditableCalloutParagraph.svelte +39 -0
  258. package/dist/editor/blocks/EditableCalloutParagraph.svelte.d.ts +12 -0
  259. package/dist/editor/blocks/EditableCodeBlock.svelte +43 -0
  260. package/dist/editor/blocks/EditableCodeBlock.svelte.d.ts +10 -0
  261. package/dist/editor/blocks/EditableHeading.svelte +161 -0
  262. package/dist/editor/blocks/EditableHeading.svelte.d.ts +10 -0
  263. package/dist/editor/blocks/EditableHorizontalRule.svelte +20 -0
  264. package/dist/editor/blocks/EditableHorizontalRule.svelte.d.ts +10 -0
  265. package/dist/editor/blocks/EditableInlineSurface.svelte +423 -0
  266. package/dist/editor/blocks/EditableInlineSurface.svelte.d.ts +26 -0
  267. package/dist/editor/blocks/EditableList.svelte +77 -0
  268. package/dist/editor/blocks/EditableList.svelte.d.ts +17 -0
  269. package/dist/editor/blocks/EditableListItemRow.svelte +231 -0
  270. package/dist/editor/blocks/EditableListItemRow.svelte.d.ts +19 -0
  271. package/dist/editor/blocks/EditableParagraph.svelte +208 -0
  272. package/dist/editor/blocks/EditableParagraph.svelte.d.ts +10 -0
  273. package/dist/editor/blocks/EditableParagraphNodes.svelte +89 -0
  274. package/dist/editor/blocks/EditableParagraphNodes.svelte.d.ts +15 -0
  275. package/dist/editor/blocks/EditableTable.svelte +83 -0
  276. package/dist/editor/blocks/EditableTable.svelte.d.ts +10 -0
  277. package/dist/editor/blocks/EditableTableCell.svelte +89 -0
  278. package/dist/editor/blocks/EditableTableCell.svelte.d.ts +15 -0
  279. package/dist/editor/blocks/EditableToggle.svelte +94 -0
  280. package/dist/editor/blocks/EditableToggle.svelte.d.ts +10 -0
  281. package/dist/editor/commandMenu.d.ts +18 -0
  282. package/dist/editor/commandMenu.js +83 -0
  283. package/dist/editor/commandRegistry.d.ts +48 -0
  284. package/dist/editor/commandRegistry.js +133 -0
  285. package/dist/editor/context/assetBaseUrl.d.ts +6 -0
  286. package/dist/editor/context/assetBaseUrl.js +20 -0
  287. package/dist/editor/dom/editorHistoryKeydown.d.ts +6 -0
  288. package/dist/editor/dom/editorHistoryKeydown.js +31 -0
  289. package/dist/editor/dom/plainEnterKeydown.d.ts +12 -0
  290. package/dist/editor/dom/plainEnterKeydown.js +53 -0
  291. package/dist/editor/dom/plaintextCaret.d.ts +12 -0
  292. package/dist/editor/dom/plaintextCaret.js +61 -0
  293. package/dist/editor/dom/syncDocumentSelectionFocus.d.ts +17 -0
  294. package/dist/editor/dom/syncDocumentSelectionFocus.js +56 -0
  295. package/dist/editor/draftPersistence.d.ts +27 -0
  296. package/dist/editor/draftPersistence.js +83 -0
  297. package/dist/editor/editorHistoryHandle.d.ts +16 -0
  298. package/dist/editor/editorHistoryHandle.js +22 -0
  299. package/dist/editor/inlineChrome/InlineChromeCoordinator.svelte +174 -0
  300. package/dist/editor/inlineChrome/InlineChromeCoordinator.svelte.d.ts +8 -0
  301. package/dist/editor/inlineChrome/InlineFormattingToolbar.svelte +181 -0
  302. package/dist/editor/inlineChrome/InlineFormattingToolbar.svelte.d.ts +3 -0
  303. package/dist/editor/inlineChrome/inlineChromeActions.d.ts +17 -0
  304. package/dist/editor/inlineChrome/inlineChromeActions.js +148 -0
  305. package/dist/editor/inlineChrome/inlineChromeState.svelte.d.ts +23 -0
  306. package/dist/editor/inlineChrome/inlineChromeState.svelte.js +21 -0
  307. package/dist/editor/inlineChrome/inlineToolbarIcons.d.ts +14 -0
  308. package/dist/editor/inlineChrome/inlineToolbarIcons.js +14 -0
  309. package/dist/editor/inlineChrome/inlineWrapActive.d.ts +3 -0
  310. package/dist/editor/inlineChrome/inlineWrapActive.js +19 -0
  311. package/dist/editor/inlineChrome/selectionRect.d.ts +2 -0
  312. package/dist/editor/inlineChrome/selectionRect.js +23 -0
  313. package/dist/editor/model/blockEditCommands.d.ts +73 -0
  314. package/dist/editor/model/blockEditCommands.js +719 -0
  315. package/dist/editor/model/blockTree.d.ts +39 -0
  316. package/dist/editor/model/blockTree.js +185 -0
  317. package/dist/editor/model/blockTreeDrop.d.ts +9 -0
  318. package/dist/editor/model/blockTreeDrop.js +295 -0
  319. package/dist/editor/model/blockTreeMutations.d.ts +10 -0
  320. package/dist/editor/model/blockTreeMutations.js +68 -0
  321. package/dist/editor/model/calloutEditCommands.d.ts +39 -0
  322. package/dist/editor/model/calloutEditCommands.js +305 -0
  323. package/dist/editor/model/documentSelection.d.ts +8 -0
  324. package/dist/editor/model/documentSelection.js +56 -0
  325. package/dist/editor/model/documentSelectionFromSource.d.ts +3 -0
  326. package/dist/editor/model/documentSelectionFromSource.js +45 -0
  327. package/dist/editor/model/documentToRenderBlocks.d.ts +3 -0
  328. package/dist/editor/model/documentToRenderBlocks.js +13 -0
  329. package/dist/editor/model/editorPipeline.bench.d.ts +1 -0
  330. package/dist/editor/model/editorPipeline.bench.js +27 -0
  331. package/dist/editor/model/editorTransactions.d.ts +20 -0
  332. package/dist/editor/model/editorTransactions.js +68 -0
  333. package/dist/editor/model/emptyParagraph.d.ts +11 -0
  334. package/dist/editor/model/emptyParagraph.js +25 -0
  335. package/dist/editor/model/enterCommands.d.ts +16 -0
  336. package/dist/editor/model/enterCommands.js +288 -0
  337. package/dist/editor/model/extensionSyntaxWarnings.d.ts +29 -0
  338. package/dist/editor/model/extensionSyntaxWarnings.js +122 -0
  339. package/dist/editor/model/findBlockAtSourceOffset.d.ts +3 -0
  340. package/dist/editor/model/findBlockAtSourceOffset.js +20 -0
  341. package/dist/editor/model/fixtures/serialization-fidelity/reorder-gaps.svelte +4 -0
  342. package/dist/editor/model/focusOutcome.d.ts +25 -0
  343. package/dist/editor/model/focusOutcome.js +1 -0
  344. package/dist/editor/model/incrementalReparse.d.ts +16 -0
  345. package/dist/editor/model/incrementalReparse.js +111 -0
  346. package/dist/editor/model/index.d.ts +22 -0
  347. package/dist/editor/model/index.js +19 -0
  348. package/dist/editor/model/inlineDraftCommit.d.ts +17 -0
  349. package/dist/editor/model/inlineDraftCommit.js +187 -0
  350. package/dist/editor/model/inlineDraftMerge.d.ts +8 -0
  351. package/dist/editor/model/inlineDraftMerge.js +81 -0
  352. package/dist/editor/model/inlineEditCommands.d.ts +28 -0
  353. package/dist/editor/model/inlineEditCommands.js +581 -0
  354. package/dist/editor/model/inlinePlain.d.ts +3 -0
  355. package/dist/editor/model/inlinePlain.js +28 -0
  356. package/dist/editor/model/inlineSecondPass.d.ts +4 -0
  357. package/dist/editor/model/inlineSecondPass.js +47 -0
  358. package/dist/editor/model/line-utils.d.ts +14 -0
  359. package/dist/editor/model/line-utils.js +38 -0
  360. package/dist/editor/model/listEditCommands.d.ts +56 -0
  361. package/dist/editor/model/listEditCommands.js +299 -0
  362. package/dist/editor/model/nestedContainerTransactions.d.ts +36 -0
  363. package/dist/editor/model/nestedContainerTransactions.js +336 -0
  364. package/dist/editor/model/parseMarkdownDocument.d.ts +2 -0
  365. package/dist/editor/model/parseMarkdownDocument.js +324 -0
  366. package/dist/editor/model/quoteEditCommands.d.ts +39 -0
  367. package/dist/editor/model/quoteEditCommands.js +323 -0
  368. package/dist/editor/model/reconcileBlockIds.d.ts +9 -0
  369. package/dist/editor/model/reconcileBlockIds.js +297 -0
  370. package/dist/editor/model/reparseOptions.d.ts +12 -0
  371. package/dist/editor/model/reparseOptions.js +1 -0
  372. package/dist/editor/model/resolveEnterPlainSnapshot.d.ts +6 -0
  373. package/dist/editor/model/resolveEnterPlainSnapshot.js +23 -0
  374. package/dist/editor/model/richInlines.d.ts +16 -0
  375. package/dist/editor/model/richInlines.js +494 -0
  376. package/dist/editor/model/serializeInlineNodes.d.ts +3 -0
  377. package/dist/editor/model/serializeInlineNodes.js +45 -0
  378. package/dist/editor/model/serializeMarkdownDocument.d.ts +30 -0
  379. package/dist/editor/model/serializeMarkdownDocument.js +150 -0
  380. package/dist/editor/model/structureParseWarnings.d.ts +10 -0
  381. package/dist/editor/model/structureParseWarnings.js +60 -0
  382. package/dist/editor/model/syntheticInlineRanges.d.ts +3 -0
  383. package/dist/editor/model/syntheticInlineRanges.js +36 -0
  384. package/dist/editor/model/types.d.ts +185 -0
  385. package/dist/editor/model/types.js +26 -0
  386. package/dist/editor/plugins/autolinks/AutolinkRenderer.svelte +20 -0
  387. package/dist/editor/plugins/autolinks/AutolinkRenderer.svelte.d.ts +21 -0
  388. package/dist/editor/plugins/autolinks/index.d.ts +2 -0
  389. package/dist/editor/plugins/autolinks/index.js +4 -0
  390. package/dist/editor/plugins/autolinks/parse-autolinks.d.ts +2 -0
  391. package/dist/editor/plugins/autolinks/parse-autolinks.js +68 -0
  392. package/dist/editor/plugins/autolinks/types.d.ts +6 -0
  393. package/dist/editor/plugins/autolinks/types.js +1 -0
  394. package/dist/editor/plugins/emphasis/EmphasisRenderer.svelte +15 -0
  395. package/dist/editor/plugins/emphasis/EmphasisRenderer.svelte.d.ts +21 -0
  396. package/dist/editor/plugins/emphasis/index.d.ts +2 -0
  397. package/dist/editor/plugins/emphasis/index.js +4 -0
  398. package/dist/editor/plugins/emphasis/parse-emphasis.d.ts +2 -0
  399. package/dist/editor/plugins/emphasis/parse-emphasis.js +188 -0
  400. package/dist/editor/plugins/emphasis/types.d.ts +24 -0
  401. package/dist/editor/plugins/emphasis/types.js +1 -0
  402. package/dist/editor/plugins/escaping/EscapingRenderer.svelte +18 -0
  403. package/dist/editor/plugins/escaping/EscapingRenderer.svelte.d.ts +21 -0
  404. package/dist/editor/plugins/escaping/index.d.ts +2 -0
  405. package/dist/editor/plugins/escaping/index.js +4 -0
  406. package/dist/editor/plugins/escaping/parse-escaping.d.ts +6 -0
  407. package/dist/editor/plugins/escaping/parse-escaping.js +26 -0
  408. package/dist/editor/plugins/escaping/types.d.ts +10 -0
  409. package/dist/editor/plugins/escaping/types.js +1 -0
  410. package/dist/editor/plugins/extended-task-list/ExtendedTaskListRenderer.svelte +25 -0
  411. package/dist/editor/plugins/extended-task-list/ExtendedTaskListRenderer.svelte.d.ts +21 -0
  412. package/dist/editor/plugins/extended-task-list/index.d.ts +2 -0
  413. package/dist/editor/plugins/extended-task-list/index.js +4 -0
  414. package/dist/editor/plugins/extended-task-list/parse-extended-task-list.d.ts +2 -0
  415. package/dist/editor/plugins/extended-task-list/parse-extended-task-list.js +35 -0
  416. package/dist/editor/plugins/extended-task-list/types.d.ts +6 -0
  417. package/dist/editor/plugins/extended-task-list/types.js +1 -0
  418. package/dist/editor/plugins/highlight/HighlightRenderer.svelte +16 -0
  419. package/dist/editor/plugins/highlight/HighlightRenderer.svelte.d.ts +21 -0
  420. package/dist/editor/plugins/highlight/index.d.ts +2 -0
  421. package/dist/editor/plugins/highlight/index.js +4 -0
  422. package/dist/editor/plugins/highlight/parse-highlights.d.ts +4 -0
  423. package/dist/editor/plugins/highlight/parse-highlights.js +49 -0
  424. package/dist/editor/plugins/highlight/types.d.ts +6 -0
  425. package/dist/editor/plugins/highlight/types.js +1 -0
  426. package/dist/editor/plugins/index.d.ts +1 -0
  427. package/dist/editor/plugins/index.js +1 -0
  428. package/dist/editor/plugins/links-images/LinksImagesRenderer.svelte +53 -0
  429. package/dist/editor/plugins/links-images/LinksImagesRenderer.svelte.d.ts +21 -0
  430. package/dist/editor/plugins/links-images/index.d.ts +2 -0
  431. package/dist/editor/plugins/links-images/index.js +4 -0
  432. package/dist/editor/plugins/links-images/parse-image-layout.d.ts +28 -0
  433. package/dist/editor/plugins/links-images/parse-image-layout.js +147 -0
  434. package/dist/editor/plugins/links-images/parse-links-images.d.ts +25 -0
  435. package/dist/editor/plugins/links-images/parse-links-images.js +236 -0
  436. package/dist/editor/plugins/links-images/resolve-asset-url.d.ts +5 -0
  437. package/dist/editor/plugins/links-images/resolve-asset-url.js +21 -0
  438. package/dist/editor/plugins/links-images/types.d.ts +11 -0
  439. package/dist/editor/plugins/links-images/types.js +1 -0
  440. package/dist/editor/plugins/mention/MentionRenderer.svelte +18 -0
  441. package/dist/editor/plugins/mention/MentionRenderer.svelte.d.ts +21 -0
  442. package/dist/editor/plugins/mention/index.d.ts +2 -0
  443. package/dist/editor/plugins/mention/index.js +4 -0
  444. package/dist/editor/plugins/mention/parse-mentions.d.ts +2 -0
  445. package/dist/editor/plugins/mention/parse-mentions.js +54 -0
  446. package/dist/editor/plugins/mention/types.d.ts +14 -0
  447. package/dist/editor/plugins/mention/types.js +1 -0
  448. package/dist/editor/plugins/raw-text/RawTextRenderer.svelte +19 -0
  449. package/dist/editor/plugins/raw-text/RawTextRenderer.svelte.d.ts +21 -0
  450. package/dist/editor/plugins/raw-text/index.d.ts +2 -0
  451. package/dist/editor/plugins/raw-text/index.js +4 -0
  452. package/dist/editor/plugins/raw-text/types.d.ts +4 -0
  453. package/dist/editor/plugins/raw-text/types.js +1 -0
  454. package/dist/editor/plugins/shared/InlineNodes.svelte +113 -0
  455. package/dist/editor/plugins/shared/InlineNodes.svelte.d.ts +21 -0
  456. package/dist/editor/plugins/shared/InlineNodesEdit.svelte +78 -0
  457. package/dist/editor/plugins/shared/InlineNodesEdit.svelte.d.ts +21 -0
  458. package/dist/editor/plugins/strikethrough/StrikethroughRenderer.svelte +9 -0
  459. package/dist/editor/plugins/strikethrough/StrikethroughRenderer.svelte.d.ts +21 -0
  460. package/dist/editor/plugins/strikethrough/index.d.ts +2 -0
  461. package/dist/editor/plugins/strikethrough/index.js +4 -0
  462. package/dist/editor/plugins/strikethrough/parse-strikethrough.d.ts +3 -0
  463. package/dist/editor/plugins/strikethrough/parse-strikethrough.js +38 -0
  464. package/dist/editor/plugins/strikethrough/types.d.ts +4 -0
  465. package/dist/editor/plugins/strikethrough/types.js +1 -0
  466. package/dist/editor/plugins/synced-block/SyncedBlockRenderer.svelte +16 -0
  467. package/dist/editor/plugins/synced-block/SyncedBlockRenderer.svelte.d.ts +21 -0
  468. package/dist/editor/plugins/synced-block/index.d.ts +2 -0
  469. package/dist/editor/plugins/synced-block/index.js +4 -0
  470. package/dist/editor/plugins/synced-block/parse-synced-blocks.d.ts +2 -0
  471. package/dist/editor/plugins/synced-block/parse-synced-blocks.js +15 -0
  472. package/dist/editor/plugins/synced-block/types.d.ts +4 -0
  473. package/dist/editor/plugins/synced-block/types.js +1 -0
  474. package/dist/editor/plugins/types.d.ts +19 -0
  475. package/dist/editor/plugins/types.js +1 -0
  476. package/dist/editor/plugins/wiki-link/WikiLinkRenderer.svelte +15 -0
  477. package/dist/editor/plugins/wiki-link/WikiLinkRenderer.svelte.d.ts +21 -0
  478. package/dist/editor/plugins/wiki-link/index.d.ts +2 -0
  479. package/dist/editor/plugins/wiki-link/index.js +4 -0
  480. package/dist/editor/plugins/wiki-link/parse-wiki-links.d.ts +2 -0
  481. package/dist/editor/plugins/wiki-link/parse-wiki-links.js +30 -0
  482. package/dist/editor/plugins/wiki-link/types.d.ts +8 -0
  483. package/dist/editor/plugins/wiki-link/types.js +1 -0
  484. package/dist/editor/taskCheckboxStates.d.ts +5 -0
  485. package/dist/editor/taskCheckboxStates.js +28 -0
  486. package/dist/index.d.ts +6 -0
  487. package/dist/index.js +9 -0
  488. package/dist/styles/index.css +6 -0
  489. package/package.json +84 -0
@@ -0,0 +1,1119 @@
1
+ import { applyInlineSecondPass, applyInlineWrap, applyStructuralMarkdownShortcut, applyEditorTransaction, clampSelection, convertHeadingLevel, convertHeadingToParagraph, convertParagraphToHeading, deleteBlockTransaction, documentBlocksToRenderBlocks, duplicateBlockTransaction, EDITOR_HISTORY_LIMIT, findEditorBlockById, findEditorBlockIdAtSourceOffset, mergeWithPreviousBlock, moveBlockDown, moveBlockToIndex as reorderBlockToIndexInDocument, moveBlockUp, parseMarkdownDocument, paragraphBlockToPlainText, paragraphDisplayPlain, reconcileBlockIds, replaceBlockMarkdownSlice, replaceSourceRange, FULL_REPARSE, tryIncrementalReparse, tryRemapDocumentSelectionBlockId, documentSelectionFromSourceOffset, updateBlockPlainText, applyListItemInlineWrapTransaction, applyQuoteParagraphInlineWrapTransaction, deleteListItemTransaction, deleteQuoteParagraphTransaction, duplicateListItemTransaction, duplicateQuoteParagraphTransaction, blockTreeDropTransaction, tabReparentBlockTransaction, listRegionStructMutation, moveListItemSiblingTransaction, moveQuoteParagraphSiblingTransaction, quoteParagraphReorderTransaction, quoteStructMutationTransaction, calloutDocumentStructMutation, deleteCalloutChildTransaction, duplicateCalloutChildTransaction, moveCalloutChildSiblingTransaction, siblingFocusIdForCalloutDelete, siblingFocusIdForListDelete, siblingFocusIdForQuoteDelete, buildEmptyParagraphInsertTransaction, insertEmptyParagraphRelative } from './model';
2
+ import { isDisplayEmptyParagraph, isSoleEmptyParagraphDocument, normalizeEmptySource } from './model/emptyParagraph';
3
+ import { sourceLineAndCharacterCount } from './model/line-utils';
4
+ import { appendTableColumnInDocument, appendTableRowInDocument, commitTableCellInlineDraft, convertBlockToTable, navigateTableCellInDocument } from './block-specs/table/editCommands';
5
+ import { buildEnterCommand } from './model/enterCommands';
6
+ import { ensureCalloutEmptyBodyTransaction } from './model/calloutEditCommands';
7
+ import { findListItemPath, resolveListItem, setListItemBodyPlain } from './model/listEditCommands';
8
+ import { commitBlockquoteBodyInlineDraft, commitBlockquoteParagraphInlineDraft, commitCalloutListItemInlineDraft, commitCalloutOpenerDraft, commitCalloutParagraphInlineDraft, commitHeadingInlineDraft, commitParagraphInlineDraft } from './model/inlineDraftCommit';
9
+ import { cloneInlineNodeDeep } from './model/inlineEditCommands';
10
+ import { findBlockLocation, blockAtSiblingOffset } from './model/blockTree';
11
+ import { serializeListItem } from './block-specs/list/serialize';
12
+ import { SvelteSet } from 'svelte/reactivity';
13
+ export class MarkdownEditor {
14
+ #source = $state('');
15
+ #fileName = $state(null);
16
+ #document = $state.raw({ source: '', fileName: null, blocks: [] });
17
+ #blocks = $state.raw([]);
18
+ #isLoading = $state(false);
19
+ #error = $state(null);
20
+ #selection = $state.raw({ anchor: 0, focus: 0 });
21
+ #lastSavedSource = $state('');
22
+ #undoStack = [];
23
+ #redoStack = [];
24
+ /** Block index being edited with coalesced undo; null when not in a plain-text session. */
25
+ #typingSessionBlockIndex = null;
26
+ /** Last plain selection inside a paragraph/heading surface (for inline commands). */
27
+ #inlinePlainFocus = null;
28
+ /** Leaf-block caret/range from editable surfaces that emit document selection. */
29
+ #documentSelection = $state.raw(null);
30
+ /** One-shot focus target after structural Enter/split; cleared once applied. */
31
+ #pendingFocusBlockId = $state.raw(null);
32
+ #pendingFocusTableCell = $state.raw(null);
33
+ #tableCellNavGuard = false;
34
+ /** Suppresses stale blur cleanup while a remounted surface restores focus. */
35
+ #pendingFocusBlurGuardId = null;
36
+ /** Suppress one plain-input commit on this block after Enter (browser may still insert a line break). */
37
+ #plainInputSuppressBlockId = null;
38
+ #reparseDepth = 0;
39
+ #sourceLineCount = $state(0);
40
+ #sourceCharacterCount = $state(0);
41
+ /** Top-level block ids edited this session; drives {@link serializeMarkdownDocumentPreserving}. */
42
+ #dirtyBlockIds = new SvelteSet();
43
+ #readonly = $state(false);
44
+ #suppressSourceNotify = false;
45
+ #sourceChangeListeners = new Set();
46
+ get source() {
47
+ return this.#source;
48
+ }
49
+ set source(value) {
50
+ this.#source = value;
51
+ this.#reparse(value, this.#fileName);
52
+ }
53
+ get fileName() {
54
+ return this.#fileName;
55
+ }
56
+ set fileName(value) {
57
+ this.#fileName = value;
58
+ this.#reparse(this.#source, value);
59
+ }
60
+ get document() {
61
+ return this.#document;
62
+ }
63
+ get blocks() {
64
+ return this.#blocks;
65
+ }
66
+ constructor() {
67
+ this.#applySourceAndSelection(normalizeEmptySource(''), { anchor: 0, focus: 0 });
68
+ }
69
+ get isLoading() {
70
+ return this.#isLoading;
71
+ }
72
+ get error() {
73
+ return this.#error;
74
+ }
75
+ get selection() {
76
+ return this.#selection;
77
+ }
78
+ get documentSelection() {
79
+ return this.#documentSelection;
80
+ }
81
+ get isReparsing() {
82
+ return this.#reparseDepth > 0;
83
+ }
84
+ /** Whether a post-structural focus restore is pending for this block (suppress stale blur cleanup). */
85
+ isPendingFocusTarget(blockId) {
86
+ return this.#pendingFocusBlurGuardId === blockId;
87
+ }
88
+ get sourceLineCount() {
89
+ return this.#sourceLineCount;
90
+ }
91
+ get sourceCharacterCount() {
92
+ return this.#sourceCharacterCount;
93
+ }
94
+ get dirty() {
95
+ return this.#source !== this.#lastSavedSource;
96
+ }
97
+ /** Stable ids of top-level blocks touched by edits (cleared on load, draft restore, undo/redo). Used with `serializeMarkdownDocumentPreserving`. */
98
+ get dirtyBlockIds() {
99
+ return new SvelteSet([...this.#dirtyBlockIds]);
100
+ }
101
+ isBlockDirty(id) {
102
+ return this.#dirtyBlockIds.has(id);
103
+ }
104
+ get readonly() {
105
+ return this.#readonly;
106
+ }
107
+ setReadonly(value) {
108
+ this.#readonly = value;
109
+ }
110
+ get canUndo() {
111
+ return this.#undoStack.length > 0;
112
+ }
113
+ get canRedo() {
114
+ return this.#redoStack.length > 0;
115
+ }
116
+ markSaved() {
117
+ this.#lastSavedSource = this.#source;
118
+ }
119
+ /** Replace document source — used by controlled embedders and demo file load. */
120
+ setSource(source, opts) {
121
+ const { fileName, resetHistory = true, syncBaseline = true, selection = { anchor: 0, focus: 0 } } = opts ?? {};
122
+ this.#error = null;
123
+ if (resetHistory) {
124
+ this.#undoStack = [];
125
+ this.#redoStack = [];
126
+ this.#typingSessionBlockIndex = null;
127
+ this.#dirtyBlockIds.clear();
128
+ }
129
+ if (fileName !== undefined) {
130
+ this.#fileName = fileName;
131
+ }
132
+ if (syncBaseline) {
133
+ this.#lastSavedSource = source;
134
+ }
135
+ this.#suppressSourceNotify = true;
136
+ try {
137
+ this.#applySourceAndSelection(normalizeEmptySource(source), selection);
138
+ }
139
+ finally {
140
+ this.#suppressSourceNotify = false;
141
+ }
142
+ }
143
+ /** Subscribe to source mutations (not fired during silent {@link setSource}). Returns unsubscribe. */
144
+ onSourceChange(listener) {
145
+ this.#sourceChangeListeners.add(listener);
146
+ return () => {
147
+ this.#sourceChangeListeners.delete(listener);
148
+ };
149
+ }
150
+ commitSourceEdit(result, dirtyBlockIndices, focusAfter) {
151
+ if (this.#readonly)
152
+ return false;
153
+ if (!result.ok) {
154
+ this.#error = result.error;
155
+ return false;
156
+ }
157
+ this.#error = null;
158
+ this.#undoStack.push(this.#captureHistorySnapshot());
159
+ if (this.#undoStack.length > EDITOR_HISTORY_LIMIT) {
160
+ this.#undoStack.shift();
161
+ }
162
+ this.#redoStack = [];
163
+ this.#typingSessionBlockIndex = null;
164
+ if (dirtyBlockIndices?.length) {
165
+ this.#markDirtyByBlockIndices(dirtyBlockIndices);
166
+ }
167
+ this.#applySourceAndSelection(result.source, result.selection, { focusAfter });
168
+ return true;
169
+ }
170
+ /** Apply a built transaction through the same undo/history path as {@link commitSourceEdit}. */
171
+ commitTransaction(transaction, dirtyBlockIndices, focusAfter) {
172
+ const applied = applyEditorTransaction(this.#source, transaction);
173
+ return this.commitSourceEdit(applied, dirtyBlockIndices, focusAfter);
174
+ }
175
+ undo() {
176
+ if (this.#readonly)
177
+ return false;
178
+ const snap = this.#undoStack.pop();
179
+ if (!snap)
180
+ return false;
181
+ this.#redoStack.push(this.#captureHistorySnapshot());
182
+ this.#error = null;
183
+ this.#typingSessionBlockIndex = null;
184
+ this.#dirtyBlockIds.clear();
185
+ this.#restoreHistorySnapshot(snap);
186
+ return true;
187
+ }
188
+ redo() {
189
+ if (this.#readonly)
190
+ return false;
191
+ const snap = this.#redoStack.pop();
192
+ if (!snap)
193
+ return false;
194
+ this.#undoStack.push(this.#captureHistorySnapshot());
195
+ this.#error = null;
196
+ this.#typingSessionBlockIndex = null;
197
+ this.#dirtyBlockIds.clear();
198
+ this.#restoreHistorySnapshot(snap);
199
+ return true;
200
+ }
201
+ /** One undo step per focused plain-text session (paragraph / heading body). */
202
+ beginPlainEditSession(blockIndex) {
203
+ if (this.#readonly)
204
+ return;
205
+ if (this.#typingSessionBlockIndex === blockIndex)
206
+ return;
207
+ this.#typingSessionBlockIndex = blockIndex;
208
+ this.#undoStack.push(this.#captureHistorySnapshot());
209
+ if (this.#undoStack.length > EDITOR_HISTORY_LIMIT) {
210
+ this.#undoStack.shift();
211
+ }
212
+ this.#redoStack = [];
213
+ }
214
+ commitPlainEditSession() {
215
+ this.#typingSessionBlockIndex = null;
216
+ }
217
+ silentUpdateBlockPlain(blockIndex, plainText, kind, selectionPlainOffset) {
218
+ const r = updateBlockPlainText(this.#source, this.#document, blockIndex, plainText, kind, selectionPlainOffset);
219
+ if (!r.ok) {
220
+ this.#error = r.error;
221
+ return false;
222
+ }
223
+ this.#markDirtyByBlockIndices([blockIndex]);
224
+ this.#error = null;
225
+ this.#source = r.source;
226
+ this.#selection = clampSelection(r.selection, r.source.length);
227
+ this.#reparse(r.source, this.#fileName);
228
+ this.#emitSourceChange();
229
+ return true;
230
+ }
231
+ commitParagraphInlineDraftAt(blockIndex, inlines, plainCaret) {
232
+ const r = commitParagraphInlineDraft(this.#source, this.#document, blockIndex, inlines, plainCaret);
233
+ if (!r.ok) {
234
+ this.#error = r.error;
235
+ return false;
236
+ }
237
+ this.#markDirtyByBlockIndices([blockIndex]);
238
+ this.#error = null;
239
+ this.#source = r.source;
240
+ this.#selection = clampSelection(r.selection, r.source.length);
241
+ this.#reparse(r.source, this.#fileName, {
242
+ kind: 'inlineDraftCommit',
243
+ blockIndex,
244
+ expectedType: 'paragraph'
245
+ });
246
+ this.#emitSourceChange();
247
+ return true;
248
+ }
249
+ commitHeadingInlineDraftAt(blockIndex, inlines, plainCaret) {
250
+ const r = commitHeadingInlineDraft(this.#source, this.#document, blockIndex, inlines, plainCaret);
251
+ if (!r.ok) {
252
+ this.#error = r.error;
253
+ return false;
254
+ }
255
+ this.#markDirtyByBlockIndices([blockIndex]);
256
+ this.#error = null;
257
+ this.#source = r.source;
258
+ this.#selection = clampSelection(r.selection, r.source.length);
259
+ this.#reparse(r.source, this.#fileName, {
260
+ kind: 'inlineDraftCommit',
261
+ blockIndex,
262
+ expectedType: 'heading'
263
+ });
264
+ this.#emitSourceChange();
265
+ return true;
266
+ }
267
+ commitTableCellInlineDraftAt(blockIndex, row, col, inlines, plainCaret) {
268
+ const block = this.#document.blocks[blockIndex];
269
+ const blockId = block?.id;
270
+ const r = commitTableCellInlineDraft(this.#source, this.#document, blockIndex, row, col, inlines, plainCaret);
271
+ if (!r.ok) {
272
+ this.#error = r.error;
273
+ return false;
274
+ }
275
+ this.#markDirtyByBlockIndices([blockIndex]);
276
+ this.#error = null;
277
+ this.#source = r.source;
278
+ this.#selection = clampSelection(r.selection, r.source.length);
279
+ if (blockId) {
280
+ this.#documentSelection = {
281
+ blockId,
282
+ tableCell: { row, col },
283
+ plain: { start: plainCaret, end: plainCaret }
284
+ };
285
+ }
286
+ this.#reparse(r.source, this.#fileName, {
287
+ kind: 'inlineDraftCommit',
288
+ blockIndex,
289
+ expectedType: 'table'
290
+ });
291
+ this.#emitSourceChange();
292
+ return true;
293
+ }
294
+ navigateTableCellAt(blockIndex, from, to, inlines, plainCaret) {
295
+ const block = this.#document.blocks[blockIndex];
296
+ const blockId = block?.id;
297
+ this.#tableCellNavGuard = true;
298
+ this.commitPlainEditSession();
299
+ const r = navigateTableCellInDocument(this.#source, this.#document, blockIndex, from, to, inlines, plainCaret);
300
+ if (!r.ok) {
301
+ this.#tableCellNavGuard = false;
302
+ this.#error = r.error;
303
+ return false;
304
+ }
305
+ if (!('focusCell' in r) || !('focusPlain' in r))
306
+ return false;
307
+ const ok = this.commitSourceEdit(r, [blockIndex], blockId
308
+ ? {
309
+ mode: 'blockId',
310
+ blockId,
311
+ tableCell: r.focusCell,
312
+ plain: { start: r.focusPlain, end: r.focusPlain }
313
+ }
314
+ : undefined);
315
+ queueMicrotask(() => {
316
+ this.#tableCellNavGuard = false;
317
+ });
318
+ return ok;
319
+ }
320
+ appendTableRowAt(blockIndex) {
321
+ this.commitPlainEditSession();
322
+ const block = this.#document.blocks[blockIndex];
323
+ const blockId = block?.id;
324
+ const r = appendTableRowInDocument(this.#source, this.#document, blockIndex);
325
+ if (!r.ok) {
326
+ this.#error = r.error;
327
+ return false;
328
+ }
329
+ if (!('focusCell' in r))
330
+ return false;
331
+ return this.commitSourceEdit(r, [blockIndex], blockId
332
+ ? {
333
+ mode: 'blockId',
334
+ blockId,
335
+ tableCell: r.focusCell,
336
+ plain: { start: 0, end: 0 }
337
+ }
338
+ : undefined);
339
+ }
340
+ appendTableColumnAt(blockIndex) {
341
+ this.commitPlainEditSession();
342
+ const block = this.#document.blocks[blockIndex];
343
+ const blockId = block?.id;
344
+ const r = appendTableColumnInDocument(this.#source, this.#document, blockIndex);
345
+ if (!r.ok) {
346
+ this.#error = r.error;
347
+ return false;
348
+ }
349
+ if (!('focusCell' in r))
350
+ return false;
351
+ return this.commitSourceEdit(r, [blockIndex], blockId
352
+ ? {
353
+ mode: 'blockId',
354
+ blockId,
355
+ tableCell: r.focusCell,
356
+ plain: { start: 0, end: 0 }
357
+ }
358
+ : undefined);
359
+ }
360
+ convertBlockToTableAt(blockIndex) {
361
+ this.commitPlainEditSession();
362
+ const blockId = this.#document.blocks[blockIndex]?.id;
363
+ const r = convertBlockToTable(this.#source, this.#document, blockIndex);
364
+ if (!r.ok) {
365
+ this.#error = r.error;
366
+ return false;
367
+ }
368
+ return this.commitSourceEdit(r, [blockIndex], blockId
369
+ ? {
370
+ mode: 'blockId',
371
+ blockId,
372
+ tableCell: { row: -1, col: 0 },
373
+ plain: { start: 0, end: 0 }
374
+ }
375
+ : undefined);
376
+ }
377
+ commitListItemInlineDraftAt(blockIndex, itemId, inlines, _plainCaret) {
378
+ void _plainCaret;
379
+ const loc = findBlockLocation(this.#document.blocks, itemId);
380
+ if (!loc || loc.block.type !== 'listItem')
381
+ return false;
382
+ loc.block.inlines = inlines.map(cloneInlineNodeDeep);
383
+ if (loc.parent === null) {
384
+ return this.silentReplaceBlockMarkdown(blockIndex, serializeListItem(loc.block, this.#source));
385
+ }
386
+ const top = this.#document.blocks[blockIndex];
387
+ if (top?.type === 'callout') {
388
+ return this.applyCalloutStructMutation(blockIndex, itemId, (blocks) => {
389
+ const inner = findBlockLocation(blocks, itemId);
390
+ if (!inner || inner.block.type !== 'listItem')
391
+ return null;
392
+ inner.block.inlines = inlines.map(cloneInlineNodeDeep);
393
+ return blocks;
394
+ });
395
+ }
396
+ return this.applyListStructMutation(blockIndex, itemId, (blocks) => {
397
+ const inner = findBlockLocation(blocks, itemId);
398
+ if (!inner || inner.block.type !== 'listItem')
399
+ return null;
400
+ inner.block.inlines = inlines.map(cloneInlineNodeDeep);
401
+ return blocks;
402
+ });
403
+ }
404
+ commitBlockquoteBodyInlineDraftAt(topBlockIndex, quoteBlockId, inlines, _plainCaret) {
405
+ void _plainCaret;
406
+ const top = this.#document.blocks[topBlockIndex];
407
+ if (!top || top.type !== 'blockquote')
408
+ return false;
409
+ const r = commitBlockquoteBodyInlineDraft(this.#source, top, quoteBlockId, inlines);
410
+ if (!r.ok) {
411
+ this.#error = r.error;
412
+ return false;
413
+ }
414
+ this.#markDirtyByBlockIndices([topBlockIndex]);
415
+ this.#error = null;
416
+ this.#source = r.source;
417
+ this.#selection = clampSelection(r.selection, r.source.length);
418
+ this.#reparse(r.source, this.#fileName);
419
+ this.#emitSourceChange();
420
+ return true;
421
+ }
422
+ commitBlockquoteParagraphInlineDraftAt(topBlockIndex, paragraphId, inlines, _plainCaret) {
423
+ void _plainCaret;
424
+ const top = this.#document.blocks[topBlockIndex];
425
+ if (!top || top.type !== 'blockquote')
426
+ return false;
427
+ const r = commitBlockquoteParagraphInlineDraft(this.#source, top, paragraphId, inlines);
428
+ if (!r.ok) {
429
+ this.#error = r.error;
430
+ return false;
431
+ }
432
+ this.#markDirtyByBlockIndices([topBlockIndex]);
433
+ this.#error = null;
434
+ this.#source = r.source;
435
+ this.#selection = clampSelection(r.selection, r.source.length);
436
+ this.#reparse(r.source, this.#fileName);
437
+ this.#emitSourceChange();
438
+ return true;
439
+ }
440
+ commitCalloutOpenerDraftAt(topBlockIndex, calloutId, data) {
441
+ const top = this.#document.blocks[topBlockIndex];
442
+ if (!top || top.type !== 'callout')
443
+ return false;
444
+ const r = commitCalloutOpenerDraft(this.#source, top, calloutId, data);
445
+ if (!r.ok) {
446
+ this.#error = r.error;
447
+ return false;
448
+ }
449
+ this.#markDirtyByBlockIndices([topBlockIndex]);
450
+ this.#error = null;
451
+ this.#source = r.source;
452
+ this.#selection = clampSelection(r.selection, r.source.length);
453
+ this.#reparse(r.source, this.#fileName);
454
+ this.#emitSourceChange();
455
+ return true;
456
+ }
457
+ commitCalloutParagraphInlineDraftAt(topBlockIndex, paragraphId, inlines, _plainCaret) {
458
+ void _plainCaret;
459
+ const top = this.#document.blocks[topBlockIndex];
460
+ if (!top || top.type !== 'callout')
461
+ return false;
462
+ const r = commitCalloutParagraphInlineDraft(this.#source, top, paragraphId, inlines);
463
+ if (!r.ok) {
464
+ this.#error = r.error;
465
+ return false;
466
+ }
467
+ this.#markDirtyByBlockIndices([topBlockIndex]);
468
+ this.#error = null;
469
+ this.#source = r.source;
470
+ this.#selection = clampSelection(r.selection, r.source.length);
471
+ this.#reparse(r.source, this.#fileName);
472
+ this.#emitSourceChange();
473
+ return true;
474
+ }
475
+ commitCalloutListItemInlineDraftAt(topBlockIndex, itemId, inlines, _plainCaret) {
476
+ void _plainCaret;
477
+ const top = this.#document.blocks[topBlockIndex];
478
+ if (!top || top.type !== 'callout')
479
+ return false;
480
+ const r = commitCalloutListItemInlineDraft(this.#source, top, itemId, inlines);
481
+ if (!r.ok) {
482
+ this.#error = r.error;
483
+ return false;
484
+ }
485
+ this.#markDirtyByBlockIndices([topBlockIndex]);
486
+ this.#error = null;
487
+ this.#source = r.source;
488
+ this.#selection = clampSelection(r.selection, r.source.length);
489
+ this.#reparse(r.source, this.#fileName);
490
+ this.#emitSourceChange();
491
+ return true;
492
+ }
493
+ /** Ensure an imported opener-only callout has a real empty body line in source. */
494
+ ensureCalloutEmptyBodyAt(blockIndex) {
495
+ const top = this.#document.blocks[blockIndex];
496
+ if (!top || top.type !== 'callout')
497
+ return false;
498
+ if ((top.children?.length ?? 0) > 0)
499
+ return true;
500
+ const built = ensureCalloutEmptyBodyTransaction(this.#source, this.#document, blockIndex);
501
+ if (!built.ok)
502
+ return false;
503
+ return this.commitTransaction(built.transaction, [blockIndex], {
504
+ mode: 'sourceOffset',
505
+ offset: built.transaction.selection.anchor
506
+ });
507
+ }
508
+ updateBlockPlain(blockIndex, plainText, kind, selectionPlainOffset) {
509
+ return this.commitSourceEdit(updateBlockPlainText(this.#source, this.#document, blockIndex, plainText, kind, selectionPlainOffset), [blockIndex]);
510
+ }
511
+ /** @deprecated Use {@link tryStructuralMarkdownShortcut}. */
512
+ maybeApplyParagraphShortcut(blockIndex, plainText) {
513
+ this.tryStructuralMarkdownShortcut(blockIndex, plainText);
514
+ }
515
+ /** Sole public Enter API — dispatches by block type, commits via transactions, sets post-split focus. */
516
+ enterAt({ blockId, plainOffset, plainText }) {
517
+ this.commitPlainEditSession();
518
+ this.#plainInputSuppressBlockId = blockId;
519
+ const outcome = buildEnterCommand(this.#source, this.#document, blockId, plainOffset, plainText);
520
+ if (!outcome.ok) {
521
+ this.#plainInputSuppressBlockId = null;
522
+ this.#error = outcome.error;
523
+ return false;
524
+ }
525
+ this.#error = null;
526
+ const ok = this.commitTransaction(outcome.transaction, [outcome.dirtyTopLevelIndex], outcome.focus);
527
+ queueMicrotask(() => {
528
+ if (this.#plainInputSuppressBlockId === blockId) {
529
+ this.#plainInputSuppressBlockId = null;
530
+ }
531
+ });
532
+ return ok;
533
+ }
534
+ shouldSuppressPlainInputForBlock(blockId) {
535
+ return this.#plainInputSuppressBlockId === blockId;
536
+ }
537
+ shouldSkipTableCellBlurCommit() {
538
+ return this.#tableCellNavGuard;
539
+ }
540
+ /** Set post-command caret: resolves to {@link DocumentSelection} + one-shot pending focus. */
541
+ setFocusOutcome(target) {
542
+ this.#applyFocusOutcome(target);
543
+ }
544
+ mergeWithPrevious(blockIndex) {
545
+ const b = this.#document.blocks[blockIndex];
546
+ if (isSoleEmptyParagraphDocument(this.#document) &&
547
+ b?.type === 'paragraph' &&
548
+ isDisplayEmptyParagraph(b)) {
549
+ return true;
550
+ }
551
+ this.commitPlainEditSession();
552
+ const r = mergeWithPreviousBlock(this.#source, this.#document, blockIndex);
553
+ if (!r.ok)
554
+ return false;
555
+ return this.commitSourceEdit(r, [blockIndex - 1, blockIndex], r.focusAfter);
556
+ }
557
+ /** Line-start `#` / `-` / `1.` shortcut when the pattern is complete (Space, Enter, or blur). */
558
+ tryStructuralMarkdownShortcut(blockIndex, plainText) {
559
+ this.commitPlainEditSession();
560
+ const r = applyStructuralMarkdownShortcut(this.#source, this.#document, blockIndex, plainText);
561
+ if (!r.ok)
562
+ return false;
563
+ return this.commitSourceEdit(r, [blockIndex], r.focusAfter);
564
+ }
565
+ insertEmptyParagraph(blockIndex, after) {
566
+ this.commitPlainEditSession();
567
+ if (this.#document.blocks.length === 0) {
568
+ const edit = insertEmptyParagraphRelative(this.#source, this.#document, 0, after);
569
+ return this.commitSourceEdit(edit, []);
570
+ }
571
+ const edit = insertEmptyParagraphRelative(this.#source, this.#document, blockIndex, after);
572
+ return this.commitSourceEdit(edit, [blockIndex]);
573
+ }
574
+ deleteBlockAt(blockIndex) {
575
+ const b = this.#document.blocks[blockIndex];
576
+ if (isSoleEmptyParagraphDocument(this.#document) &&
577
+ b?.type === 'paragraph' &&
578
+ isDisplayEmptyParagraph(b)) {
579
+ return true;
580
+ }
581
+ this.commitPlainEditSession();
582
+ const built = deleteBlockTransaction(this.#source, this.#document, blockIndex);
583
+ if (!built.ok) {
584
+ this.#error = built.error;
585
+ return false;
586
+ }
587
+ return this.commitTransaction(built.transaction, [blockIndex]);
588
+ }
589
+ /** Replace one block’s source slice (code fences, lists, blockquotes). */
590
+ replaceBlockMarkdown(blockIndex, markdown) {
591
+ this.commitPlainEditSession();
592
+ const r = replaceBlockMarkdownSlice(this.#source, this.#document, blockIndex, markdown);
593
+ if (!r.ok)
594
+ return false;
595
+ return this.commitSourceEdit(r, [blockIndex]);
596
+ }
597
+ /** Coalesced list/blockquote/code edits within {@link beginPlainEditSession} (no undo frame per keystroke). */
598
+ silentReplaceBlockMarkdown(blockIndex, markdown) {
599
+ const r = replaceBlockMarkdownSlice(this.#source, this.#document, blockIndex, markdown);
600
+ if (!r.ok) {
601
+ this.#error = r.error;
602
+ return false;
603
+ }
604
+ this.#markDirtyByBlockIndices([blockIndex]);
605
+ this.#error = null;
606
+ this.#source = r.source;
607
+ this.#selection = clampSelection(r.selection, r.source.length);
608
+ this.#reparse(r.source, this.#fileName);
609
+ this.#emitSourceChange();
610
+ return true;
611
+ }
612
+ applyInlineWrapAt(blockIndex, plainStart, plainEnd, kind, linkHref) {
613
+ this.commitPlainEditSession();
614
+ const r = applyInlineWrap(this.#source, this.#document, blockIndex, plainStart, plainEnd, kind, linkHref);
615
+ if (!r.ok) {
616
+ this.#error = r.error;
617
+ return false;
618
+ }
619
+ this.#error = null;
620
+ return this.commitSourceEdit(r, [blockIndex]);
621
+ }
622
+ duplicateBlockAt(blockIndex) {
623
+ this.commitPlainEditSession();
624
+ const built = duplicateBlockTransaction(this.#source, this.#document, blockIndex);
625
+ if (!built.ok) {
626
+ this.#error = built.error;
627
+ return false;
628
+ }
629
+ this.#error = null;
630
+ return this.commitTransaction(built.transaction, [blockIndex]);
631
+ }
632
+ moveBlockUpAt(blockIndex) {
633
+ this.commitPlainEditSession();
634
+ const r = moveBlockUp(this.#source, this.#document, blockIndex);
635
+ if (!r.ok)
636
+ return false;
637
+ return this.commitSourceEdit(r, [blockIndex - 1, blockIndex]);
638
+ }
639
+ moveBlockDownAt(blockIndex) {
640
+ this.commitPlainEditSession();
641
+ const r = moveBlockDown(this.#source, this.#document, blockIndex);
642
+ if (!r.ok)
643
+ return false;
644
+ return this.commitSourceEdit(r, [blockIndex, blockIndex + 1]);
645
+ }
646
+ moveBlockToIndex(fromIndex, toIndex) {
647
+ this.commitPlainEditSession();
648
+ const lo = Math.min(fromIndex, toIndex);
649
+ const hi = Math.max(fromIndex, toIndex);
650
+ const affected = Array.from({ length: hi - lo + 1 }, (_, k) => lo + k);
651
+ const r = reorderBlockToIndexInDocument(this.#source, this.#document, fromIndex, toIndex);
652
+ if (!r.ok)
653
+ return false;
654
+ return this.commitSourceEdit(r, affected);
655
+ }
656
+ convertParagraphToHeadingAt(blockIndex, level) {
657
+ this.commitPlainEditSession();
658
+ const block = this.#document.blocks[blockIndex];
659
+ const r = convertParagraphToHeading(this.#source, this.#document, blockIndex, level);
660
+ if (!r.ok)
661
+ return false;
662
+ const plainLength = block?.type === 'paragraph'
663
+ ? paragraphBlockToPlainText(block.data).trimEnd().length
664
+ : 0;
665
+ return this.commitSourceEdit(r, [blockIndex], {
666
+ mode: 'sourceOffset',
667
+ offset: block?.sourceRange.start ?? 0,
668
+ plain: { start: plainLength, end: plainLength }
669
+ });
670
+ }
671
+ convertParagraphToBulletListAt(blockIndex) {
672
+ this.commitPlainEditSession();
673
+ const block = this.#document.blocks[blockIndex];
674
+ if (!block || block.type !== 'paragraph')
675
+ return false;
676
+ const plain = paragraphBlockToPlainText(block.data).trimEnd();
677
+ const markdown = `- ${plain}`;
678
+ const r = replaceBlockMarkdownSlice(this.#source, this.#document, blockIndex, markdown);
679
+ if (!r.ok)
680
+ return false;
681
+ return this.commitSourceEdit(r, [blockIndex], {
682
+ mode: 'sourceOffset',
683
+ offset: block.sourceRange.start,
684
+ plain: { start: plain.length, end: plain.length }
685
+ });
686
+ }
687
+ convertHeadingToParagraphAt(blockIndex) {
688
+ this.commitPlainEditSession();
689
+ const r = convertHeadingToParagraph(this.#source, this.#document, blockIndex);
690
+ if (!r.ok)
691
+ return false;
692
+ return this.commitSourceEdit(r, [blockIndex]);
693
+ }
694
+ convertHeadingLevelAt(blockIndex, level) {
695
+ this.commitPlainEditSession();
696
+ const r = convertHeadingLevel(this.#source, this.#document, blockIndex, level);
697
+ if (!r.ok)
698
+ return false;
699
+ return this.commitSourceEdit(r, [blockIndex]);
700
+ }
701
+ setSelection(sel) {
702
+ this.#selection = clampSelection(sel, this.#source.length);
703
+ }
704
+ setDocumentSelection(sel) {
705
+ this.#documentSelection = sel;
706
+ }
707
+ /**
708
+ * Caret/selection updates from a focused surface (selectionchange, keyup, input).
709
+ * Ignored while reparsing or another block owns {@link #pendingFocusBlockId}.
710
+ */
711
+ emitDocumentSelection(sel) {
712
+ if (this.#reparseDepth > 0)
713
+ return;
714
+ if (!this.#selectionAllowedForPending(sel))
715
+ return;
716
+ this.setDocumentSelection(sel);
717
+ }
718
+ /** Focus moved to this surface; ignored while reparsing or another block owns post-split focus. */
719
+ claimDocumentSelection(sel) {
720
+ if (this.#reparseDepth > 0)
721
+ return;
722
+ if (!this.#selectionAllowedForPending(sel))
723
+ return;
724
+ this.setDocumentSelection(sel);
725
+ }
726
+ /** Whether this block (and optional table cell) should receive one-shot programmatic focus. */
727
+ takePendingFocusForBlock(blockId, tableCell, surfaceBlockType) {
728
+ if (this.#pendingFocusBlockId !== blockId)
729
+ return false;
730
+ const pendingCell = this.#pendingFocusTableCell;
731
+ if (pendingCell) {
732
+ if (!tableCell || pendingCell.row !== tableCell.row || pendingCell.col !== tableCell.col) {
733
+ return false;
734
+ }
735
+ }
736
+ else if (tableCell) {
737
+ return false;
738
+ }
739
+ if (surfaceBlockType) {
740
+ const block = findEditorBlockById(this.#document.blocks, blockId);
741
+ if (!block || block.type !== surfaceBlockType)
742
+ return false;
743
+ }
744
+ this.#pendingFocusBlockId = null;
745
+ this.#pendingFocusTableCell = null;
746
+ return true;
747
+ }
748
+ clearDocumentSelection(blockId) {
749
+ if (this.#pendingFocusBlurGuardId === blockId)
750
+ return;
751
+ if (this.#documentSelection?.blockId === blockId) {
752
+ this.#documentSelection = null;
753
+ }
754
+ }
755
+ registerInlinePlainFocus(blockIndex, start, end) {
756
+ this.#inlinePlainFocus = { blockIndex, start, end };
757
+ }
758
+ clearInlinePlainFocus(blockIndex) {
759
+ if (this.#inlinePlainFocus?.blockIndex === blockIndex)
760
+ this.#inlinePlainFocus = null;
761
+ }
762
+ getInlinePlainFocus(blockIndex) {
763
+ const block = this.#document.blocks[blockIndex];
764
+ const docSel = this.#documentSelection;
765
+ if (block && docSel?.plain && docSel.blockId === block.id) {
766
+ return { start: docSel.plain.start, end: docSel.plain.end };
767
+ }
768
+ const f = this.#inlinePlainFocus;
769
+ if (!f || f.blockIndex !== blockIndex)
770
+ return null;
771
+ return { start: f.start, end: f.end };
772
+ }
773
+ getDocumentSelectionPlain(blockId) {
774
+ const sel = this.#documentSelection;
775
+ if (!sel || sel.blockId !== blockId || !sel.plain)
776
+ return null;
777
+ return { start: sel.plain.start, end: sel.plain.end };
778
+ }
779
+ #commitNestedStructural(built, blockIndex, opts = {}) {
780
+ if (!built.ok) {
781
+ this.#error = built.error;
782
+ return false;
783
+ }
784
+ const prevPlain = opts.preserveBlockId && this.#documentSelection?.blockId === opts.preserveBlockId
785
+ ? this.#documentSelection.plain
786
+ : undefined;
787
+ this.commitPlainEditSession();
788
+ this.#error = null;
789
+ const focusAfter = this.#focusOutcomeForNestedStructural(opts, prevPlain);
790
+ return this.commitTransaction(built.transaction, [blockIndex], focusAfter);
791
+ }
792
+ moveListItemSiblingAt(blockIndex, itemId, direction) {
793
+ return this.#commitNestedStructural(moveListItemSiblingTransaction(this.#source, this.#document, blockIndex, itemId, direction), blockIndex, { preserveBlockId: itemId });
794
+ }
795
+ blockTreeDropAt(draggedId, targetId, placement) {
796
+ const loc = findBlockLocation(this.#document.blocks, draggedId);
797
+ const blockIndex = loc?.topLevelIndex ?? 0;
798
+ return this.#commitNestedStructural(blockTreeDropTransaction(this.#source, this.#document, draggedId, targetId, placement), blockIndex, { preserveBlockId: draggedId });
799
+ }
800
+ applyBlockTreeTabReparent(blockId, shift, focusPlain) {
801
+ const loc = findBlockLocation(this.#document.blocks, blockId);
802
+ if (!loc)
803
+ return false;
804
+ const built = tabReparentBlockTransaction(this.#source, this.#document, blockId, shift);
805
+ if (!built.ok)
806
+ return false;
807
+ return this.#commitNestedStructural(built, loc.topLevelIndex, {
808
+ focusBlockId: blockId,
809
+ focusPlain: focusPlain ?? { start: 0, end: 0 }
810
+ });
811
+ }
812
+ listItemTreeDropAt(blockIndex, draggedId, targetId, placement) {
813
+ return this.blockTreeDropAt(draggedId, targetId, placement);
814
+ }
815
+ deleteListItemAt(blockIndex, itemId) {
816
+ const focusId = siblingFocusIdForListDelete(this.#document.blocks, itemId);
817
+ return this.#commitNestedStructural(deleteListItemTransaction(this.#source, this.#document, blockIndex, itemId, focusId), blockIndex, focusId ? { focusBlockId: focusId, focusPlain: { start: 0, end: 0 } } : {});
818
+ }
819
+ applyListStructMutation(blockIndex, itemId, mutate, opts) {
820
+ const caretBlockId = opts?.focusBlockId ?? opts?.preserveBlockId ?? itemId;
821
+ return this.#commitNestedStructural(listRegionStructMutation(this.#source, this.#document, itemId, mutate, `list-struct:${itemId}`, caretBlockId), blockIndex, opts?.focusBlockId
822
+ ? {
823
+ focusBlockId: opts.focusBlockId,
824
+ focusPlain: opts.focusPlain ?? { start: 0, end: 0 }
825
+ }
826
+ : { preserveBlockId: opts?.preserveBlockId ?? itemId });
827
+ }
828
+ applyQuoteStructMutation(blockIndex, quoteBlockId, mutate, opts) {
829
+ const caretBlockId = opts?.focusBlockId ?? quoteBlockId;
830
+ return this.#commitNestedStructural(quoteStructMutationTransaction(this.#source, this.#document, blockIndex, quoteBlockId, mutate, `quote-struct:${quoteBlockId}`, caretBlockId), blockIndex, opts?.focusBlockId
831
+ ? { focusBlockId: opts.focusBlockId, focusPlain: { start: 0, end: 0 } }
832
+ : { preserveBlockId: quoteBlockId });
833
+ }
834
+ updateListItemBodyAt(blockIndex, itemId, plain) {
835
+ const loc = findBlockLocation(this.#document.blocks, itemId);
836
+ if (!loc || loc.block.type !== 'listItem')
837
+ return false;
838
+ if (loc.parent === null) {
839
+ setListItemBodyPlain(loc.block, plain);
840
+ return this.silentReplaceBlockMarkdown(blockIndex, serializeListItem(loc.block, this.#source));
841
+ }
842
+ return this.applyListStructMutation(blockIndex, itemId, (blocks) => {
843
+ const inner = findBlockLocation(blocks, itemId);
844
+ if (!inner || inner.block.type !== 'listItem')
845
+ return null;
846
+ setListItemBodyPlain(inner.block, plain);
847
+ return blocks;
848
+ });
849
+ }
850
+ duplicateListItemAt(blockIndex, itemId) {
851
+ const built = duplicateListItemTransaction(this.#source, this.#document, blockIndex, itemId);
852
+ if (!built.ok) {
853
+ this.#error = built.error;
854
+ return false;
855
+ }
856
+ this.commitPlainEditSession();
857
+ this.#error = null;
858
+ const ok = this.commitTransaction(built.transaction, [blockIndex]);
859
+ if (!ok)
860
+ return false;
861
+ const path = findListItemPath(this.#document.blocks, itemId);
862
+ if (path) {
863
+ const nav = resolveListItem(this.#document.blocks, path);
864
+ const dup = nav?.siblings[nav.itemIndex + 1];
865
+ if (dup) {
866
+ this.setFocusOutcome({ mode: 'blockId', blockId: dup.id });
867
+ }
868
+ }
869
+ return true;
870
+ }
871
+ moveQuoteParagraphSiblingAt(blockIndex, paragraphId, direction) {
872
+ return this.#commitNestedStructural(moveQuoteParagraphSiblingTransaction(this.#source, this.#document, blockIndex, paragraphId, direction), blockIndex, { preserveBlockId: paragraphId });
873
+ }
874
+ quoteParagraphReorderAt(blockIndex, quotePath, fromIndex, toIndex, paragraphId) {
875
+ return this.#commitNestedStructural(quoteParagraphReorderTransaction(this.#source, this.#document, blockIndex, quotePath, fromIndex, toIndex, paragraphId), blockIndex, { preserveBlockId: paragraphId });
876
+ }
877
+ deleteQuoteParagraphAt(blockIndex, paragraphId) {
878
+ const block = this.#document.blocks[blockIndex];
879
+ const focusId = block?.type === 'blockquote' ? siblingFocusIdForQuoteDelete(block, paragraphId) : undefined;
880
+ return this.#commitNestedStructural(deleteQuoteParagraphTransaction(this.#source, this.#document, blockIndex, paragraphId, focusId), blockIndex, focusId ? { focusBlockId: focusId, focusPlain: { start: 0, end: 0 } } : {});
881
+ }
882
+ duplicateQuoteParagraphAt(blockIndex, paragraphId) {
883
+ const built = duplicateQuoteParagraphTransaction(this.#source, this.#document, blockIndex, paragraphId);
884
+ if (!built.ok) {
885
+ this.#error = built.error;
886
+ return false;
887
+ }
888
+ this.commitPlainEditSession();
889
+ this.#error = null;
890
+ const ok = this.commitTransaction(built.transaction, [blockIndex]);
891
+ if (!ok)
892
+ return false;
893
+ return true;
894
+ }
895
+ moveCalloutChildSiblingAt(blockIndex, childId, direction) {
896
+ return this.#commitNestedStructural(moveCalloutChildSiblingTransaction(this.#source, this.#document, blockIndex, childId, direction), blockIndex, { preserveBlockId: childId });
897
+ }
898
+ calloutBodyTreeDropAt(blockIndex, draggedId, targetId, placement) {
899
+ return this.blockTreeDropAt(draggedId, targetId, placement);
900
+ }
901
+ deleteCalloutChildAt(blockIndex, childId) {
902
+ const block = this.#document.blocks[blockIndex];
903
+ const focusId = block?.type === 'callout' ? siblingFocusIdForCalloutDelete(block, childId) : undefined;
904
+ return this.#commitNestedStructural(deleteCalloutChildTransaction(this.#source, this.#document, blockIndex, childId, focusId), blockIndex, focusId ? { focusBlockId: focusId, focusPlain: { start: 0, end: 0 } } : {});
905
+ }
906
+ duplicateCalloutChildAt(blockIndex, childId) {
907
+ const built = duplicateCalloutChildTransaction(this.#source, this.#document, blockIndex, childId);
908
+ if (!built.ok) {
909
+ this.#error = built.error;
910
+ return false;
911
+ }
912
+ this.commitPlainEditSession();
913
+ this.#error = null;
914
+ return this.commitTransaction(built.transaction, [blockIndex]);
915
+ }
916
+ applyCalloutStructMutation(blockIndex, anchorBlockId, mutate, opts) {
917
+ const caretBlockId = opts?.focusBlockId ?? opts?.preserveBlockId ?? anchorBlockId;
918
+ return this.#commitNestedStructural(calloutDocumentStructMutation(this.#source, this.#document, blockIndex, anchorBlockId, mutate, `callout-struct:${anchorBlockId}`, caretBlockId), blockIndex, opts?.focusBlockId
919
+ ? {
920
+ focusBlockId: opts.focusBlockId,
921
+ focusPlain: opts.focusPlain ?? { start: 0, end: 0 }
922
+ }
923
+ : { preserveBlockId: opts?.preserveBlockId ?? anchorBlockId });
924
+ }
925
+ applyInlineWrapOnNestedRow(blockIndex, rowBlockId, plainStart, plainEnd, kind, linkHref) {
926
+ this.commitPlainEditSession();
927
+ const block = this.#document.blocks[blockIndex];
928
+ if (!block)
929
+ return false;
930
+ const built = block.type === 'listItem'
931
+ ? applyListItemInlineWrapTransaction(this.#source, this.#document, blockIndex, rowBlockId, plainStart, plainEnd, kind, linkHref)
932
+ : block.type === 'blockquote'
933
+ ? applyQuoteParagraphInlineWrapTransaction(this.#source, this.#document, blockIndex, rowBlockId, plainStart, plainEnd, kind, linkHref)
934
+ : { ok: false, error: 'Unsupported container block.' };
935
+ return this.#commitNestedStructural(built, blockIndex, {
936
+ preserveBlockId: rowBlockId,
937
+ focusPlain: { start: plainEnd, end: plainEnd }
938
+ });
939
+ }
940
+ #captureHistorySnapshot() {
941
+ const docSel = this.#documentSelection;
942
+ return {
943
+ source: this.#source,
944
+ selection: { ...this.#selection },
945
+ documentSelection: docSel
946
+ ? {
947
+ blockId: docSel.blockId,
948
+ plain: docSel.plain ? { ...docSel.plain } : undefined,
949
+ tableCell: docSel.tableCell ? { ...docSel.tableCell } : undefined
950
+ }
951
+ : null
952
+ };
953
+ }
954
+ #restoreHistorySnapshot(snap) {
955
+ const selection = clampSelection(snap.selection, snap.source.length);
956
+ const focusAfter = snap.documentSelection
957
+ ? {
958
+ mode: 'blockId',
959
+ blockId: snap.documentSelection.blockId,
960
+ plain: snap.documentSelection.plain ?? { start: 0, end: 0 },
961
+ tableCell: snap.documentSelection.tableCell
962
+ }
963
+ : undefined;
964
+ this.#applySourceAndSelection(snap.source, selection, { focusAfter });
965
+ if (snap.documentSelection)
966
+ return;
967
+ const derived = documentSelectionFromSourceOffset(this.#document.blocks, snap.source, selection);
968
+ if (derived) {
969
+ this.setFocusOutcome({
970
+ mode: 'blockId',
971
+ blockId: derived.blockId,
972
+ plain: derived.plain ?? { start: 0, end: 0 }
973
+ });
974
+ }
975
+ }
976
+ #focusOutcomeForNestedStructural(opts, prevPlain) {
977
+ if (opts.focusBlockId) {
978
+ return {
979
+ mode: 'blockId',
980
+ blockId: opts.focusBlockId,
981
+ plain: opts.focusPlain ?? { start: 0, end: 0 }
982
+ };
983
+ }
984
+ if (opts.preserveBlockId && findEditorBlockById(this.#document.blocks, opts.preserveBlockId)) {
985
+ const plain = opts.focusPlain ?? prevPlain;
986
+ if (plain) {
987
+ return { mode: 'blockId', blockId: opts.preserveBlockId, plain };
988
+ }
989
+ }
990
+ return undefined;
991
+ }
992
+ #armPostStructuralFocus(blockId, plain, tableCell) {
993
+ this.#documentSelection = { blockId, plain, tableCell };
994
+ this.#pendingFocusBlockId = blockId;
995
+ this.#pendingFocusTableCell = tableCell ?? null;
996
+ this.#pendingFocusBlurGuardId = blockId;
997
+ queueMicrotask(() => {
998
+ if (this.#pendingFocusBlurGuardId === blockId) {
999
+ this.#pendingFocusBlurGuardId = null;
1000
+ }
1001
+ });
1002
+ }
1003
+ #applyFocusOutcome(target) {
1004
+ const plain = target.plain ?? { start: 0, end: 0 };
1005
+ if (target.mode === 'blockId') {
1006
+ this.#armPostStructuralFocus(target.blockId, plain, target.tableCell);
1007
+ return;
1008
+ }
1009
+ if (target.mode === 'siblingOffset') {
1010
+ const block = blockAtSiblingOffset(this.#document.blocks, target.anchorBlockId, target.offset);
1011
+ if (block) {
1012
+ this.#armPostStructuralFocus(block.id, plain);
1013
+ }
1014
+ return;
1015
+ }
1016
+ const targetId = findEditorBlockIdAtSourceOffset(this.#document.blocks, target.offset);
1017
+ if (targetId) {
1018
+ this.#armPostStructuralFocus(targetId, plain);
1019
+ }
1020
+ }
1021
+ #emitSourceChange() {
1022
+ if (this.#suppressSourceNotify)
1023
+ return;
1024
+ for (const listener of this.#sourceChangeListeners) {
1025
+ listener(this.#source);
1026
+ }
1027
+ }
1028
+ #applySourceAndSelection(source, selection, opts) {
1029
+ const normalized = normalizeEmptySource(source);
1030
+ this.#source = normalized;
1031
+ this.#selection = clampSelection(selection, normalized.length);
1032
+ if (opts?.focusAfter?.mode === 'blockId') {
1033
+ this.#pendingFocusBlurGuardId = opts.focusAfter.blockId;
1034
+ }
1035
+ this.#reparse(normalized, this.#fileName);
1036
+ if (opts?.focusAfter) {
1037
+ this.#applyFocusOutcome(opts.focusAfter);
1038
+ }
1039
+ this.#emitSourceChange();
1040
+ }
1041
+ #reparse(source, fileName, opts = FULL_REPARSE) {
1042
+ this.#reparseDepth++;
1043
+ try {
1044
+ const prevBlocks = this.#document.blocks;
1045
+ const prevReal = prevBlocks.filter((b) => !b.sourceRange.synthetic);
1046
+ let nextReal;
1047
+ let docSource = normalizeEmptySource(source);
1048
+ let docFileName = fileName;
1049
+ if (opts.kind === 'inlineDraftCommit') {
1050
+ const incremental = tryIncrementalReparse(docSource, fileName, this.#document, opts.blockIndex, opts.expectedType);
1051
+ if (incremental.ok) {
1052
+ nextReal = incremental.document.blocks.filter((b) => !b.sourceRange.synthetic);
1053
+ docSource = normalizeEmptySource(incremental.document.source);
1054
+ docFileName = incremental.document.fileName;
1055
+ }
1056
+ else {
1057
+ const docParsed = applyInlineSecondPass(parseMarkdownDocument(docSource, fileName));
1058
+ nextReal = reconcileBlockIds(prevReal, docParsed.blocks);
1059
+ }
1060
+ }
1061
+ else {
1062
+ const docParsed = applyInlineSecondPass(parseMarkdownDocument(docSource, fileName));
1063
+ nextReal = reconcileBlockIds(prevReal, docParsed.blocks);
1064
+ }
1065
+ this.#document = { source: docSource, fileName: docFileName, blocks: nextReal };
1066
+ this.#blocks = documentBlocksToRenderBlocks(nextReal);
1067
+ this.#pruneDirtyBlockIds(nextReal);
1068
+ this.#restoreDocumentSelection(prevBlocks, nextReal);
1069
+ const stats = sourceLineAndCharacterCount(docSource);
1070
+ this.#sourceLineCount = stats.lineCount;
1071
+ this.#sourceCharacterCount = stats.characterCount;
1072
+ }
1073
+ finally {
1074
+ this.#reparseDepth--;
1075
+ }
1076
+ }
1077
+ #restoreDocumentSelection(prevBlocks, nextBlocks) {
1078
+ const sel = this.#documentSelection;
1079
+ if (!sel)
1080
+ return;
1081
+ if (findEditorBlockById(nextBlocks, sel.blockId))
1082
+ return;
1083
+ const remapped = tryRemapDocumentSelectionBlockId(prevBlocks, nextBlocks, sel.blockId);
1084
+ if (remapped) {
1085
+ this.#documentSelection = { ...sel, blockId: remapped };
1086
+ }
1087
+ else {
1088
+ this.#documentSelection = null;
1089
+ }
1090
+ }
1091
+ #selectionAllowedForPending(sel) {
1092
+ if (!this.#pendingFocusBlockId)
1093
+ return true;
1094
+ if (this.#pendingFocusBlockId !== sel.blockId)
1095
+ return false;
1096
+ const pendingCell = this.#pendingFocusTableCell;
1097
+ if (!pendingCell)
1098
+ return true;
1099
+ if (!sel.tableCell)
1100
+ return false;
1101
+ return pendingCell.row === sel.tableCell.row && pendingCell.col === sel.tableCell.col;
1102
+ }
1103
+ #markDirtyByBlockIndices(indices) {
1104
+ const blocks = this.#document.blocks;
1105
+ for (const i of indices) {
1106
+ const b = blocks[i];
1107
+ if (b && b.sourceRange.start >= 0 && !b.sourceRange.synthetic) {
1108
+ this.#dirtyBlockIds.add(b.id);
1109
+ }
1110
+ }
1111
+ }
1112
+ #pruneDirtyBlockIds(merged) {
1113
+ const valid = new SvelteSet(merged.map((b) => b.id));
1114
+ for (const id of this.#dirtyBlockIds) {
1115
+ if (!valid.has(id))
1116
+ this.#dirtyBlockIds.delete(id);
1117
+ }
1118
+ }
1119
+ }