@voithos-labs/aragonite 0.10.4 → 0.10.7

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 (1021) hide show
  1. package/README.md +2 -2
  2. package/dist/a11y-strings.d.ts +11 -5
  3. package/dist/a11y-strings.js +60 -5
  4. package/dist/action-contracts.d.ts +242 -155
  5. package/dist/action-contracts.js +2 -2
  6. package/dist/active-editor.d.ts +3 -3
  7. package/dist/active-editor.js +8 -9
  8. package/dist/ambient/ambient-dom.d.ts +2 -5
  9. package/dist/ambient/ambient-dom.js +16 -62
  10. package/dist/assert.js +6 -5
  11. package/dist/block-component.d.ts +135 -109
  12. package/dist/block-component.js +30 -22
  13. package/dist/block-id.d.ts +6 -10
  14. package/dist/block-id.js +25 -14
  15. package/dist/bounded-memo.d.ts +5 -5
  16. package/dist/bounded-memo.js +6 -6
  17. package/dist/components/BlockDragHandle.svelte +12 -21
  18. package/dist/components/BlockHost.svelte +56 -134
  19. package/dist/components/BlockList.svelte +22 -19
  20. package/dist/components/DecorationOverlay.svelte +9 -10
  21. package/dist/components/DecorationOverlay.svelte.d.ts +2 -2
  22. package/dist/components/Editor.svelte +603 -1126
  23. package/dist/components/Editor.svelte.d.ts +9 -20
  24. package/dist/components/GapCaret.svelte +26 -59
  25. package/dist/components/SelectionOverlay.svelte +26 -51
  26. package/dist/components/SelectionOverlay.svelte.d.ts +5 -3
  27. package/dist/components/TailInsert.svelte +8 -55
  28. package/dist/components/TailInsert.svelte.d.ts +4 -6
  29. package/dist/components/block-content-selector.d.ts +11 -11
  30. package/dist/components/block-content-selector.js +11 -11
  31. package/dist/components/block-el-lookup.d.ts +6 -0
  32. package/dist/components/block-el-lookup.js +27 -0
  33. package/dist/components/blocks/BlockquoteBlock.svelte +3 -3
  34. package/dist/components/blocks/ThematicBreakBlock.svelte +22 -63
  35. package/dist/components/blocks/ThematicBreakBlock.svelte.d.ts +0 -2
  36. package/dist/components/blocks/code/CodeBlock.svelte +255 -276
  37. package/dist/components/blocks/code/CodeBlock.svelte.d.ts +2 -3
  38. package/dist/components/blocks/code/CodeBlockRail.svelte +72 -87
  39. package/dist/components/blocks/code/CodeBlockRail.svelte.d.ts +9 -4
  40. package/dist/components/blocks/code/code-beforeinput.d.ts +1 -1
  41. package/dist/components/blocks/code/code-bootstrap.d.ts +3 -5
  42. package/dist/components/blocks/code/code-bootstrap.js +29 -34
  43. package/dist/components/blocks/code/code-context-actions.js +5 -4
  44. package/dist/components/blocks/code/code-enter.js +2 -2
  45. package/dist/components/blocks/code/code-fence-boundary.d.ts +29 -46
  46. package/dist/components/blocks/code/code-fence-boundary.js +40 -66
  47. package/dist/components/blocks/code/code-fence-exit.d.ts +6 -11
  48. package/dist/components/blocks/code/code-fence-exit.js +24 -25
  49. package/dist/components/blocks/code/code-indent.d.ts +2 -2
  50. package/dist/components/blocks/code/code-indent.js +4 -7
  51. package/dist/components/blocks/code/code-languages.d.ts +16 -12
  52. package/dist/components/blocks/code/code-languages.js +57 -39
  53. package/dist/components/blocks/code/code-paste-surface.d.ts +3 -2
  54. package/dist/components/blocks/code/code-paste-surface.js +9 -18
  55. package/dist/components/blocks/code/code-renderer.d.ts +21 -5
  56. package/dist/components/blocks/code/code-renderer.js +90 -125
  57. package/dist/components/blocks/directive/DirectiveContainerBlock.svelte +5 -8
  58. package/dist/components/blocks/directive/activate-directives.d.ts +4 -4
  59. package/dist/components/blocks/directive/activate-directives.js +18 -13
  60. package/dist/components/blocks/editable-leaf.d.ts +50 -74
  61. package/dist/components/blocks/editable-leaf.js +141 -203
  62. package/dist/components/blocks/editable-surface.d.ts +96 -100
  63. package/dist/components/blocks/editable-surface.js +101 -109
  64. package/dist/components/blocks/list/ListBlock.svelte +45 -90
  65. package/dist/components/blocks/list/ListItemBlock.svelte +93 -147
  66. package/dist/components/blocks/list/ListItemBlock.svelte.d.ts +1 -0
  67. package/dist/components/blocks/list/task-checkbox.d.ts +5 -2
  68. package/dist/components/blocks/list/task-checkbox.js +12 -7
  69. package/dist/components/blocks/plain-text-backend.d.ts +4 -20
  70. package/dist/components/blocks/plain-text-backend.js +9 -43
  71. package/dist/components/blocks/surface-wiring.svelte.d.ts +8 -9
  72. package/dist/components/blocks/surface-wiring.svelte.js +15 -34
  73. package/dist/components/blocks/table/TableActionMenu.svelte +19 -18
  74. package/dist/components/blocks/table/TableActionMenu.svelte.d.ts +3 -1
  75. package/dist/components/blocks/table/TableBlock.svelte +100 -165
  76. package/dist/components/blocks/table/TableBlock.svelte.d.ts +3 -3
  77. package/dist/components/blocks/table/TableCellBlock.svelte +307 -385
  78. package/dist/components/blocks/table/TableCellBlock.svelte.d.ts +1 -0
  79. package/dist/components/blocks/table/TableRowBlock.svelte +60 -104
  80. package/dist/components/blocks/table/TableRowBlock.svelte.d.ts +0 -1
  81. package/dist/components/blocks/table/cell-keydown-plan.d.ts +4 -9
  82. package/dist/components/blocks/table/cell-keydown-plan.js +8 -12
  83. package/dist/components/blocks/table/cell-pointer.d.ts +18 -23
  84. package/dist/components/blocks/table/cell-pointer.js +49 -71
  85. package/dist/components/blocks/table/cell-render.d.ts +24 -29
  86. package/dist/components/blocks/table/cell-render.js +29 -31
  87. package/dist/components/blocks/table/selected-cells.d.ts +7 -7
  88. package/dist/components/blocks/table/selected-cells.js +9 -13
  89. package/dist/components/blocks/table/table-caret-at-point.d.ts +4 -4
  90. package/dist/components/blocks/table/table-caret-at-point.js +5 -5
  91. package/dist/components/blocks/table/table-cell-paste.d.ts +5 -11
  92. package/dist/components/blocks/table/table-cell-paste.js +27 -43
  93. package/dist/components/blocks/table/table-drag-hit-test.js +2 -1
  94. package/dist/components/blocks/table/table-menu-model.d.ts +4 -8
  95. package/dist/components/blocks/table/table-menu-model.js +6 -10
  96. package/dist/components/blocks/table/table-navigation.js +2 -2
  97. package/dist/components/blocks/text/TextEditableBlock.svelte +392 -310
  98. package/dist/components/blocks/text/TextEditableBlock.svelte.d.ts +2 -1
  99. package/dist/components/blocks/text/auto-pair-record.d.ts +23 -0
  100. package/dist/components/blocks/text/auto-pair-record.js +51 -0
  101. package/dist/components/blocks/text/click-snap-guard.d.ts +8 -6
  102. package/dist/components/blocks/text/click-snap-guard.js +10 -7
  103. package/dist/components/blocks/text/composition-seat.d.ts +17 -14
  104. package/dist/components/blocks/text/composition-seat.js +11 -11
  105. package/dist/components/blocks/text/construct-edge-delete.d.ts +20 -20
  106. package/dist/components/blocks/text/construct-edge-delete.js +50 -65
  107. package/dist/components/blocks/text/construct-reveal.d.ts +16 -21
  108. package/dist/components/blocks/text/construct-reveal.js +13 -14
  109. package/dist/components/blocks/text/delimiter-autopair.d.ts +51 -34
  110. package/dist/components/blocks/text/delimiter-autopair.js +87 -103
  111. package/dist/components/blocks/text/edge-policy-dispatch.d.ts +44 -46
  112. package/dist/components/blocks/text/edge-policy-dispatch.js +150 -181
  113. package/dist/components/blocks/text/edge-seat.d.ts +17 -26
  114. package/dist/components/blocks/text/edge-seat.js +43 -70
  115. package/dist/components/blocks/text/link-at-point.d.ts +9 -9
  116. package/dist/components/blocks/text/link-at-point.js +12 -15
  117. package/dist/components/blocks/text/live-join-seam.d.ts +6 -9
  118. package/dist/components/blocks/text/live-join-seam.js +75 -112
  119. package/dist/components/blocks/text/live-selection-edit.d.ts +14 -43
  120. package/dist/components/blocks/text/live-selection-edit.js +32 -108
  121. package/dist/components/blocks/text/live-split-rebalance.d.ts +9 -13
  122. package/dist/components/blocks/text/live-split-rebalance.js +50 -67
  123. package/dist/components/blocks/text/marker-completion.d.ts +7 -12
  124. package/dist/components/blocks/text/marker-completion.js +17 -10
  125. package/dist/components/blocks/text/pending-mark-insert.d.ts +11 -18
  126. package/dist/components/blocks/text/pending-mark-insert.js +30 -49
  127. package/dist/components/blocks/text/screen-diff.d.ts +5 -15
  128. package/dist/components/blocks/text/screen-diff.js +5 -19
  129. package/dist/components/blocks/text/text-clipboard.d.ts +23 -32
  130. package/dist/components/blocks/text/text-clipboard.js +27 -32
  131. package/dist/components/blocks/text/text-keydown.d.ts +20 -30
  132. package/dist/components/blocks/text/text-keydown.js +54 -51
  133. package/dist/components/blocks/text/text-render.d.ts +25 -35
  134. package/dist/components/blocks/text/text-render.js +82 -61
  135. package/dist/components/blocks/text/widget-adjacency.d.ts +9 -9
  136. package/dist/components/blocks/text/widget-adjacency.js +17 -17
  137. package/dist/components/blocks/text/widget-interaction.d.ts +67 -43
  138. package/dist/components/blocks/text/widget-interaction.js +212 -199
  139. package/dist/components/blocks/widget-portal.d.ts +20 -29
  140. package/dist/components/blocks/widget-portal.js +16 -14
  141. package/dist/components/built-in-blocks.d.ts +3 -4
  142. package/dist/components/built-in-blocks.js +17 -18
  143. package/dist/components/drag-handle.d.ts +12 -35
  144. package/dist/components/drag-handle.js +22 -68
  145. package/dist/components/editor-built-ins.d.ts +1 -0
  146. package/dist/components/editor-built-ins.js +16 -0
  147. package/dist/components/editor-root-clipboard.d.ts +6 -6
  148. package/dist/components/editor-root-clipboard.js +16 -27
  149. package/dist/components/editor-root-document-swap.d.ts +49 -0
  150. package/dist/components/editor-root-document-swap.js +54 -0
  151. package/dist/components/editor-root-focus.d.ts +5 -4
  152. package/dist/components/editor-root-focus.js +51 -22
  153. package/dist/components/editor-root-focused-surface.d.ts +35 -0
  154. package/dist/components/editor-root-focused-surface.js +65 -0
  155. package/dist/components/editor-root-geometry.d.ts +15 -24
  156. package/dist/components/editor-root-geometry.js +27 -31
  157. package/dist/components/editor-root-gestures.d.ts +39 -0
  158. package/dist/components/editor-root-gestures.js +189 -0
  159. package/dist/components/editor-root-keydown.d.ts +10 -25
  160. package/dist/components/editor-root-keydown.js +19 -43
  161. package/dist/components/editor-root-listeners.d.ts +22 -24
  162. package/dist/components/editor-root-listeners.js +49 -24
  163. package/dist/components/editor-root-menus.d.ts +51 -0
  164. package/dist/components/editor-root-menus.js +147 -0
  165. package/dist/components/editor-root-mode-flip.d.ts +16 -11
  166. package/dist/components/editor-root-mode-flip.js +36 -34
  167. package/dist/components/editor-root-scroll-host.d.ts +22 -0
  168. package/dist/components/editor-root-scroll-host.js +34 -0
  169. package/dist/components/editor-root-test-surface.d.ts +48 -0
  170. package/dist/components/editor-root-test-surface.js +6 -0
  171. package/dist/components/image/ImageOverlayHost.svelte +44 -35
  172. package/dist/components/image/ImageOverlayHost.svelte.d.ts +5 -6
  173. package/dist/components/image/ImageProperties.svelte +37 -41
  174. package/dist/components/image/ImageProperties.svelte.d.ts +9 -4
  175. package/dist/components/image/ImageResizeHandles.svelte +14 -26
  176. package/dist/components/image/image-crop.d.ts +5 -11
  177. package/dist/components/image/image-crop.js +5 -11
  178. package/dist/components/image/image-edit-commit.d.ts +19 -16
  179. package/dist/components/image/image-edit-commit.js +74 -38
  180. package/dist/components/image/image-resize.d.ts +2 -5
  181. package/dist/components/image/image-resize.js +3 -6
  182. package/dist/components/image/image-widget-editing.d.ts +3 -3
  183. package/dist/components/image/image-widget-editing.js +9 -9
  184. package/dist/components/image/widget-dom.d.ts +2 -3
  185. package/dist/components/image/widget-dom.js +19 -24
  186. package/dist/components/image/widget-selection-state.svelte.d.ts +10 -11
  187. package/dist/components/image/widget-selection-state.svelte.js +26 -19
  188. package/dist/components/kind-cue.svelte.d.ts +21 -0
  189. package/dist/components/kind-cue.svelte.js +35 -0
  190. package/dist/components/link-card/LinkCard.svelte +115 -64
  191. package/dist/components/link-card/LinkCard.svelte.d.ts +7 -5
  192. package/dist/components/link-card/LinkCardHost.svelte +42 -33
  193. package/dist/components/link-card/LinkCardHost.svelte.d.ts +10 -8
  194. package/dist/components/link-card/link-card-commit.d.ts +16 -19
  195. package/dist/components/link-card/link-card-commit.js +21 -30
  196. package/dist/components/link-card/link-card-entry.d.ts +13 -23
  197. package/dist/components/link-card/link-card-entry.js +16 -24
  198. package/dist/components/link-card/link-card-state.svelte.d.ts +17 -21
  199. package/dist/components/link-card/link-card-state.svelte.js +2 -2
  200. package/dist/components/lrd-map-gate.d.ts +4 -11
  201. package/dist/components/lrd-map-gate.js +5 -11
  202. package/dist/components/menu/BlockMenu.svelte +20 -81
  203. package/dist/components/menu/BlockMenu.svelte.d.ts +11 -9
  204. package/dist/components/menu/InlineMenuHost.svelte +191 -0
  205. package/dist/components/menu/InlineMenuHost.svelte.d.ts +13 -0
  206. package/dist/components/menu/MenuIcon.svelte +3 -103
  207. package/dist/components/menu/MenuIcon.svelte.d.ts +2 -44
  208. package/dist/components/menu/SelectionToolbar.svelte +30 -35
  209. package/dist/components/menu/SelectionToolbar.svelte.d.ts +3 -5
  210. package/dist/components/menu/clipboard-actions.d.ts +3 -4
  211. package/dist/components/menu/clipboard-actions.js +3 -4
  212. package/dist/components/menu/default-context-actions.d.ts +4 -13
  213. package/dist/components/menu/default-context-actions.js +49 -67
  214. package/dist/components/menu/flyout-placement.d.ts +2 -2
  215. package/dist/components/menu/flyout-placement.js +2 -2
  216. package/dist/components/menu/menu-presence.svelte.d.ts +12 -0
  217. package/dist/components/menu/menu-presence.svelte.js +19 -0
  218. package/dist/components/paste-image-arm.d.ts +6 -11
  219. package/dist/components/paste-image-arm.js +11 -18
  220. package/dist/components/portal.d.ts +2 -5
  221. package/dist/components/portal.js +4 -7
  222. package/dist/core/directive/activate.d.ts +4 -5
  223. package/dist/core/directive/activate.js +8 -9
  224. package/dist/core/directive/container-opener.js +13 -12
  225. package/dist/core/directive/grammar.d.ts +2 -5
  226. package/dist/core/directive/grammar.js +10 -10
  227. package/dist/core/directive/kinds.d.ts +4 -7
  228. package/dist/core/directive/kinds.js +14 -16
  229. package/dist/core/directive/registry.d.ts +12 -9
  230. package/dist/core/directive/registry.js +19 -20
  231. package/dist/core/directive/text-recognizer.d.ts +3 -2
  232. package/dist/core/directive/text-recognizer.js +5 -9
  233. package/dist/core/escapable.d.ts +1 -5
  234. package/dist/core/escapable.js +1 -5
  235. package/dist/core/inline/backticks.d.ts +3 -4
  236. package/dist/core/inline/backticks.js +3 -4
  237. package/dist/core/inline/character-refs.js +2 -1
  238. package/dist/core/inline/destination-bytes.d.ts +6 -3
  239. package/dist/core/inline/destination-bytes.js +50 -8
  240. package/dist/core/inline/entity-widget.d.ts +4 -3
  241. package/dist/core/inline/entity-widget.js +6 -6
  242. package/dist/core/inline/format-toggle.d.ts +22 -28
  243. package/dist/core/inline/format-toggle.js +97 -129
  244. package/dist/core/inline/html-entities.d.ts +2 -3
  245. package/dist/core/inline/html-entities.js +2 -3
  246. package/dist/core/inline/html-tag-grammar.js +6 -2
  247. package/dist/core/inline/image-dimensions.d.ts +2 -0
  248. package/dist/core/inline/image-dimensions.js +19 -2
  249. package/dist/core/inline/image-source-bytes.d.ts +11 -0
  250. package/dist/core/inline/image-source-bytes.js +71 -0
  251. package/dist/core/inline/index.d.ts +28 -21
  252. package/dist/core/inline/index.js +56 -34
  253. package/dist/core/inline/inline-cache.d.ts +12 -15
  254. package/dist/core/inline/inline-cache.js +11 -14
  255. package/dist/core/inline/inline-widgets.d.ts +54 -75
  256. package/dist/core/inline/inline-widgets.js +54 -62
  257. package/dist/core/inline/link-destination.d.ts +31 -0
  258. package/dist/core/inline/link-destination.js +129 -0
  259. package/dist/core/inline/link-reference-resolver.d.ts +8 -6
  260. package/dist/core/inline/link-reference-resolver.js +10 -6
  261. package/dist/core/inline/link-source-bytes.d.ts +31 -0
  262. package/dist/{components/blocks/text → core/inline}/link-source-bytes.js +43 -54
  263. package/dist/core/inline/live-edit/read-back.d.ts +29 -0
  264. package/dist/core/inline/live-edit/read-back.js +50 -0
  265. package/dist/core/inline/picture.d.ts +10 -0
  266. package/dist/core/inline/picture.js +40 -0
  267. package/dist/core/inline/scan/autolinks.d.ts +7 -8
  268. package/dist/core/inline/scan/autolinks.js +80 -59
  269. package/dist/core/inline/scan/brackets.d.ts +2 -2
  270. package/dist/core/inline/scan/brackets.js +6 -103
  271. package/dist/core/inline/scan/code-spans.d.ts +4 -0
  272. package/dist/core/inline/scan/code-spans.js +8 -0
  273. package/dist/core/inline/scan/emphasis.js +10 -14
  274. package/dist/core/inline/scan/index.d.ts +3 -1
  275. package/dist/core/inline/scan/index.js +32 -33
  276. package/dist/core/inline/scan/plugin-syntax.d.ts +28 -36
  277. package/dist/core/inline/scan/plugin-syntax.js +75 -89
  278. package/dist/core/inline/scan/scan-state.d.ts +2 -0
  279. package/dist/core/inline/scan/scan-state.js +1 -0
  280. package/dist/core/inline/scan/simple-nodes.d.ts +2 -5
  281. package/dist/core/inline/scan/simple-nodes.js +2 -5
  282. package/dist/core/inline/scan/triggers.d.ts +17 -0
  283. package/dist/core/inline/scan/triggers.js +26 -0
  284. package/dist/core/inline/scan/url.js +8 -10
  285. package/dist/core/inline/transparency.d.ts +2 -1
  286. package/dist/core/inline/transparency.js +31 -15
  287. package/dist/core/inline/visibility.d.ts +30 -49
  288. package/dist/core/inline/visibility.js +31 -49
  289. package/dist/core/inline/walk.d.ts +4 -10
  290. package/dist/core/inline/walk.js +4 -10
  291. package/dist/core/inline-render.d.ts +22 -27
  292. package/dist/core/inline-render.js +51 -60
  293. package/dist/core/lines.d.ts +67 -26
  294. package/dist/core/lines.js +164 -33
  295. package/dist/core/metadata-parity.d.ts +9 -0
  296. package/dist/core/metadata-parity.js +25 -0
  297. package/dist/core/node-views.d.ts +7 -6
  298. package/dist/core/node-views.js +5 -5
  299. package/dist/core/nodes.d.ts +34 -44
  300. package/dist/core/nodes.js +4 -12
  301. package/dist/core/parser.d.ts +27 -34
  302. package/dist/core/parser.js +53 -67
  303. package/dist/core/parsers/blockquote.d.ts +5 -8
  304. package/dist/core/parsers/blockquote.js +11 -10
  305. package/dist/core/parsers/built-in-openers.d.ts +2 -5
  306. package/dist/core/parsers/built-in-openers.js +5 -8
  307. package/dist/core/parsers/fence-syntax.d.ts +36 -7
  308. package/dist/core/parsers/fence-syntax.js +61 -11
  309. package/dist/core/parsers/fenced-code.d.ts +16 -0
  310. package/dist/core/parsers/fenced-code.js +16 -15
  311. package/dist/core/parsers/heading.d.ts +19 -2
  312. package/dist/core/parsers/heading.js +50 -2
  313. package/dist/core/parsers/html-block.d.ts +3 -6
  314. package/dist/core/parsers/html-block.js +10 -11
  315. package/dist/core/parsers/indented-code.d.ts +1 -1
  316. package/dist/core/parsers/indented-code.js +2 -8
  317. package/dist/core/parsers/link-reference.d.ts +5 -3
  318. package/dist/core/parsers/link-reference.js +116 -120
  319. package/dist/core/parsers/list.d.ts +12 -5
  320. package/dist/core/parsers/list.js +53 -36
  321. package/dist/core/parsers/paragraph.d.ts +3 -3
  322. package/dist/core/parsers/paragraph.js +14 -5
  323. package/dist/core/parsers/table-completion.d.ts +2 -5
  324. package/dist/core/parsers/table-completion.js +7 -10
  325. package/dist/core/parsers/table.d.ts +8 -8
  326. package/dist/core/parsers/table.js +23 -26
  327. package/dist/core/parsers/thematic-break.js +15 -14
  328. package/dist/core/paths.d.ts +13 -0
  329. package/dist/core/paths.js +31 -0
  330. package/dist/core/terminator-escalation.d.ts +0 -7
  331. package/dist/core/terminator-escalation.js +5 -8
  332. package/dist/core/url-policy.d.ts +2 -5
  333. package/dist/core/url-policy.js +8 -12
  334. package/dist/cursor/caret-memory.d.ts +34 -0
  335. package/dist/cursor/caret-memory.js +82 -0
  336. package/dist/cursor/coordinate-spaces.d.ts +26 -19
  337. package/dist/cursor/coordinate-spaces.js +32 -20
  338. package/dist/cursor/dom-walk.d.ts +7 -13
  339. package/dist/cursor/dom-walk.js +7 -13
  340. package/dist/cursor/edge-affinity.d.ts +7 -35
  341. package/dist/cursor/edge-affinity.js +13 -44
  342. package/dist/cursor/focused-caret.d.ts +6 -8
  343. package/dist/cursor/focused-caret.js +7 -16
  344. package/dist/cursor/height-model.d.ts +3 -3
  345. package/dist/cursor/height-model.js +5 -5
  346. package/dist/cursor/height-oracle.d.ts +10 -6
  347. package/dist/cursor/height-oracle.js +26 -74
  348. package/dist/cursor/observe-resize.d.ts +13 -0
  349. package/dist/cursor/observe-resize.js +43 -0
  350. package/dist/cursor/overlay-rects.d.ts +2 -5
  351. package/dist/cursor/overlay-rects.js +2 -5
  352. package/dist/cursor/overlay-remeasure.d.ts +6 -7
  353. package/dist/cursor/overlay-remeasure.js +10 -14
  354. package/dist/cursor/pending-marks.d.ts +7 -9
  355. package/dist/cursor/pending-marks.js +6 -27
  356. package/dist/cursor/point-offset.d.ts +16 -10
  357. package/dist/cursor/point-offset.js +60 -25
  358. package/dist/cursor/reveal-source.d.ts +7 -11
  359. package/dist/cursor/reveal-source.js +10 -18
  360. package/dist/cursor/scroll-ancestors.d.ts +9 -20
  361. package/dist/cursor/scroll-ancestors.js +14 -26
  362. package/dist/cursor/scroll-owner.d.ts +92 -0
  363. package/dist/cursor/scroll-owner.js +283 -0
  364. package/dist/cursor/scrollport.d.ts +14 -15
  365. package/dist/cursor/scrollport.js +7 -13
  366. package/dist/cursor/sticky-column.d.ts +6 -29
  367. package/dist/cursor/sticky-column.js +6 -49
  368. package/dist/cursor/sticky-measure.d.ts +14 -9
  369. package/dist/cursor/sticky-measure.js +99 -49
  370. package/dist/cursor/surface-backend.d.ts +41 -0
  371. package/dist/cursor/surface-backend.js +78 -0
  372. package/dist/cursor/typography-estimates.d.ts +3 -3
  373. package/dist/cursor/typography-estimates.js +3 -3
  374. package/dist/cursor/visual-lines.d.ts +25 -14
  375. package/dist/cursor/visual-lines.js +45 -46
  376. package/dist/cursor/widget-edge-snap.d.ts +10 -15
  377. package/dist/cursor/widget-edge-snap.js +13 -12
  378. package/dist/cursor/widget-offset.d.ts +110 -104
  379. package/dist/cursor/widget-offset.js +344 -179
  380. package/dist/debug/diagnostics-report.d.ts +6 -6
  381. package/dist/debug/diagnostics-report.js +5 -5
  382. package/dist/debug/dump-tree.js +2 -2
  383. package/dist/debug/editor-diagnostics.d.ts +15 -0
  384. package/dist/debug/editor-diagnostics.js +33 -0
  385. package/dist/debug/inspect.d.ts +2 -2
  386. package/dist/debug/inspect.js +4 -4
  387. package/dist/debug/interaction-trace.d.ts +14 -15
  388. package/dist/debug/interaction-trace.js +19 -20
  389. package/dist/debug/operations-log.d.ts +1 -1
  390. package/dist/debug/operations-log.js +1 -1
  391. package/dist/decorations/buckets.d.ts +6 -12
  392. package/dist/decorations/buckets.js +4 -11
  393. package/dist/decorations/decoration-state.svelte.d.ts +2 -3
  394. package/dist/decorations/decoration-state.svelte.js +24 -26
  395. package/dist/decorations/island-dom.d.ts +10 -18
  396. package/dist/decorations/island-dom.js +25 -50
  397. package/dist/decorations/reserved-attrs.d.ts +6 -8
  398. package/dist/decorations/reserved-attrs.js +30 -17
  399. package/dist/decorations/types.d.ts +6 -7
  400. package/dist/decorations/types.js +2 -1
  401. package/dist/decorations/use-block-decorations.svelte.d.ts +19 -0
  402. package/dist/decorations/use-block-decorations.svelte.js +71 -0
  403. package/dist/decorations/widget-dom.d.ts +3 -3
  404. package/dist/decorations/widget-dom.js +5 -5
  405. package/dist/dev-warn.d.ts +5 -2
  406. package/dist/dev-warn.js +16 -4
  407. package/dist/editor-actions/ancestry-folds.d.ts +9 -14
  408. package/dist/editor-actions/ancestry-folds.js +13 -18
  409. package/dist/editor-actions/block-edit-core.d.ts +49 -22
  410. package/dist/editor-actions/block-edit-core.js +279 -151
  411. package/dist/editor-actions/block-edit-scope.d.ts +63 -50
  412. package/dist/editor-actions/block-edit-scope.js +100 -48
  413. package/dist/editor-actions/block-edit.d.ts +2 -3
  414. package/dist/editor-actions/block-edit.js +14 -90
  415. package/dist/editor-actions/commit/history.d.ts +4 -4
  416. package/dist/editor-actions/commit/history.js +33 -34
  417. package/dist/editor-actions/commit/reading-write-gate.d.ts +18 -0
  418. package/dist/editor-actions/commit/reading-write-gate.js +56 -0
  419. package/dist/editor-actions/commit/text-batch.d.ts +7 -11
  420. package/dist/editor-actions/commit/text-batch.js +6 -7
  421. package/dist/editor-actions/commit/undo-controller.d.ts +6 -4
  422. package/dist/editor-actions/commit/undo-controller.js +346 -216
  423. package/dist/editor-actions/container-block-component.d.ts +32 -51
  424. package/dist/editor-actions/container-block-component.js +66 -92
  425. package/dist/editor-actions/container-edit.d.ts +4 -2
  426. package/dist/editor-actions/container-edit.js +14 -44
  427. package/dist/editor-actions/container-exit-overrides.d.ts +6 -4
  428. package/dist/editor-actions/container-exit-overrides.js +19 -21
  429. package/dist/editor-actions/deps.d.ts +25 -32
  430. package/dist/editor-actions/enter-completion.d.ts +12 -15
  431. package/dist/editor-actions/enter-completion.js +49 -51
  432. package/dist/editor-actions/focus/focus-dispatch.d.ts +24 -25
  433. package/dist/editor-actions/focus/focus-dispatch.js +28 -50
  434. package/dist/editor-actions/focus/focus-landing.d.ts +8 -11
  435. package/dist/editor-actions/focus/focus-landing.js +15 -14
  436. package/dist/editor-actions/focus/focus.d.ts +3 -2
  437. package/dist/editor-actions/focus/focus.js +42 -59
  438. package/dist/editor-actions/index.d.ts +4 -3
  439. package/dist/editor-actions/index.js +5 -4
  440. package/dist/editor-actions/inline-range-commit.d.ts +18 -16
  441. package/dist/editor-actions/inline-range-commit.js +45 -54
  442. package/dist/editor-actions/leaf-write.d.ts +11 -0
  443. package/dist/editor-actions/leaf-write.js +102 -0
  444. package/dist/editor-actions/list-context.d.ts +9 -10
  445. package/dist/editor-actions/list-context.js +115 -110
  446. package/dist/editor-actions/list-overrides.d.ts +13 -5
  447. package/dist/editor-actions/list-overrides.js +36 -12
  448. package/dist/editor-actions/merge-fallback.d.ts +10 -16
  449. package/dist/editor-actions/merge-fallback.js +11 -22
  450. package/dist/editor-actions/nested/container-actions.d.ts +37 -0
  451. package/dist/editor-actions/nested/container-actions.js +42 -0
  452. package/dist/editor-actions/nested/emptied-container.d.ts +5 -0
  453. package/dist/editor-actions/nested/emptied-container.js +5 -0
  454. package/dist/editor-actions/nested/nested-actions.d.ts +22 -25
  455. package/dist/editor-actions/nested/nested-actions.js +17 -15
  456. package/dist/editor-actions/nested/nested-block-edit.d.ts +3 -4
  457. package/dist/editor-actions/nested/nested-block-edit.js +40 -134
  458. package/dist/editor-actions/nested/nested-focus.d.ts +2 -3
  459. package/dist/editor-actions/nested/nested-focus.js +33 -21
  460. package/dist/editor-actions/paste-coordinator.d.ts +3 -2
  461. package/dist/editor-actions/paste-coordinator.js +17 -13
  462. package/dist/editor-actions/plugin/chrome-leaf.d.ts +11 -9
  463. package/dist/editor-actions/plugin/chrome-leaf.js +14 -13
  464. package/dist/editor-actions/plugin/container.d.ts +54 -82
  465. package/dist/editor-actions/plugin/container.js +105 -188
  466. package/dist/editor-actions/plugin/directive-container.d.ts +4 -4
  467. package/dist/editor-actions/plugin/directive-container.js +7 -8
  468. package/dist/editor-actions/reorder-action.d.ts +7 -12
  469. package/dist/editor-actions/reorder-action.js +32 -48
  470. package/dist/editor-actions/reorder-drag.d.ts +12 -8
  471. package/dist/editor-actions/reorder-drag.js +45 -41
  472. package/dist/editor-actions/replacement-focus.d.ts +13 -21
  473. package/dist/editor-actions/replacement-focus.js +32 -33
  474. package/dist/editor-actions/search-replace.js +71 -67
  475. package/dist/editor-actions/stored-caret.d.ts +7 -0
  476. package/dist/editor-actions/stored-caret.js +10 -0
  477. package/dist/editor-actions/table-context.d.ts +9 -11
  478. package/dist/editor-actions/table-context.js +70 -93
  479. package/dist/editor-actions/unwrap-strategies.d.ts +4 -5
  480. package/dist/editor-actions/unwrap-strategies.js +52 -63
  481. package/dist/editor-actions/whole-block-focus-surface.d.ts +19 -28
  482. package/dist/editor-actions/whole-block-focus-surface.js +43 -53
  483. package/dist/editor-events.d.ts +25 -29
  484. package/dist/editor-events.js +17 -28
  485. package/dist/editor-keys.d.ts +96 -104
  486. package/dist/editor-keys.js +11 -24
  487. package/dist/editor-props.d.ts +88 -71
  488. package/dist/editor-rects.d.ts +23 -34
  489. package/dist/editor-rects.js +9 -77
  490. package/dist/env.d.ts +6 -4
  491. package/dist/env.js +8 -4
  492. package/dist/index.d.ts +6 -2
  493. package/dist/index.js +5 -2
  494. package/dist/inline-menu/inline-menu-session.d.ts +37 -0
  495. package/dist/inline-menu/inline-menu-session.js +98 -0
  496. package/dist/inline-menu/inline-menu-state.svelte.d.ts +63 -0
  497. package/dist/inline-menu/inline-menu-state.svelte.js +409 -0
  498. package/dist/inline-menu/types.d.ts +77 -0
  499. package/dist/inline-menu/types.js +7 -0
  500. package/dist/invariants/child-id-parity.d.ts +23 -0
  501. package/dist/invariants/child-id-parity.js +39 -0
  502. package/dist/invariants/commit-paths.d.ts +4 -4
  503. package/dist/invariants/commit-paths.js +4 -4
  504. package/dist/invariants/commit-scope.d.ts +4 -4
  505. package/dist/invariants/commit-scope.js +9 -8
  506. package/dist/invariants/context-keys.d.ts +2 -5
  507. package/dist/invariants/context-keys.js +3 -6
  508. package/dist/invariants/descriptor.d.ts +2 -6
  509. package/dist/invariants/descriptor.js +2 -6
  510. package/dist/invariants/inline-transitions.d.ts +9 -16
  511. package/dist/invariants/inline-transitions.js +10 -18
  512. package/dist/invariants/install.d.ts +18 -27
  513. package/dist/invariants/install.js +29 -30
  514. package/dist/invariants/keeps-a-block.d.ts +7 -0
  515. package/dist/invariants/keeps-a-block.js +14 -0
  516. package/dist/invariants/landable-caret.d.ts +5 -7
  517. package/dist/invariants/landable-caret.js +8 -11
  518. package/dist/invariants/landing-focus-scroll.d.ts +7 -0
  519. package/dist/invariants/landing-focus-scroll.js +13 -0
  520. package/dist/invariants/landing-value.d.ts +13 -0
  521. package/dist/invariants/landing-value.js +27 -0
  522. package/dist/invariants/marker-css-parity.d.ts +5 -6
  523. package/dist/invariants/marker-css-parity.js +11 -12
  524. package/dist/invariants/measures-in-own-list.d.ts +6 -0
  525. package/dist/invariants/measures-in-own-list.js +13 -0
  526. package/dist/invariants/node-shape.d.ts +18 -37
  527. package/dist/invariants/node-shape.js +123 -79
  528. package/dist/invariants/open-tail.d.ts +7 -0
  529. package/dist/invariants/open-tail.js +45 -0
  530. package/dist/invariants/placement-ends-widget.d.ts +8 -0
  531. package/dist/invariants/placement-ends-widget.js +13 -0
  532. package/dist/invariants/registry.d.ts +27 -66
  533. package/dist/invariants/registry.js +61 -137
  534. package/dist/invariants/render-fidelity.d.ts +4 -4
  535. package/dist/invariants/render-fidelity.js +5 -5
  536. package/dist/invariants/selection-endpoints.d.ts +6 -7
  537. package/dist/invariants/selection-endpoints.js +18 -16
  538. package/dist/invariants/single-node-sink.d.ts +4 -5
  539. package/dist/invariants/single-node-sink.js +4 -5
  540. package/dist/invariants/snapshot-integrity.d.ts +5 -6
  541. package/dist/invariants/snapshot-integrity.js +1 -1
  542. package/dist/invariants/structural-descriptor.d.ts +6 -15
  543. package/dist/invariants/structural-descriptor.js +6 -15
  544. package/dist/menu-icons.d.ts +47 -0
  545. package/dist/menu-icons.js +113 -0
  546. package/dist/perf/instruments.d.ts +20 -5
  547. package/dist/perf/instruments.js +35 -15
  548. package/dist/perf/use-mount-gauge.svelte.js +4 -4
  549. package/dist/plugin.d.ts +37 -8
  550. package/dist/plugin.js +100 -77
  551. package/dist/plugins/admonitions/AdmonitionBlock.svelte +14 -11
  552. package/dist/plugins/admonitions/admonition-kind.js +12 -10
  553. package/dist/plugins/admonitions/convert-document.d.ts +5 -5
  554. package/dist/plugins/admonitions/convert-document.js +8 -7
  555. package/dist/plugins/admonitions/gh-alert.d.ts +8 -1
  556. package/dist/plugins/admonitions/gh-alert.js +21 -22
  557. package/dist/plugins/admonitions/github-alert-kind.d.ts +5 -7
  558. package/dist/plugins/admonitions/github-alert-kind.js +28 -37
  559. package/dist/plugins/admonitions/index.js +2 -2
  560. package/dist/plugins/admonitions/kinds.d.ts +1 -1
  561. package/dist/plugins/admonitions/register.js +11 -2
  562. package/dist/plugins/details/DetailsBlock.svelte +20 -20
  563. package/dist/plugins/details/details-disclosure.svelte.d.ts +5 -6
  564. package/dist/plugins/details/details-disclosure.svelte.js +6 -7
  565. package/dist/plugins/details/details-kind.d.ts +6 -7
  566. package/dist/plugins/details/details-kind.js +44 -59
  567. package/dist/plugins/emoji/emoji-recognizer.d.ts +4 -7
  568. package/dist/plugins/emoji/emoji-recognizer.js +7 -14
  569. package/dist/plugins/footnotes/FootnoteDefinition.svelte +33 -16
  570. package/dist/plugins/footnotes/FootnoteReference.svelte +39 -19
  571. package/dist/plugins/footnotes/constants.d.ts +2 -0
  572. package/dist/plugins/footnotes/constants.js +3 -0
  573. package/dist/plugins/footnotes/footnote-definition.d.ts +8 -6
  574. package/dist/plugins/footnotes/footnote-definition.js +69 -45
  575. package/dist/plugins/footnotes/footnote-lookup.d.ts +3 -3
  576. package/dist/plugins/footnotes/footnote-lookup.js +14 -26
  577. package/dist/plugins/footnotes/footnote-numbering.d.ts +11 -11
  578. package/dist/plugins/footnotes/footnote-numbering.js +22 -31
  579. package/dist/plugins/footnotes/footnote-reference.d.ts +4 -4
  580. package/dist/plugins/footnotes/footnote-reference.js +8 -13
  581. package/dist/plugins/footnotes/index.js +2 -3
  582. package/dist/plugins/highlight-occurrences/highlight-occurrences-plugin.d.ts +5 -8
  583. package/dist/plugins/highlight-occurrences/highlight-occurrences-plugin.js +8 -3
  584. package/dist/plugins/highlight-occurrences/occurrence-source.d.ts +10 -12
  585. package/dist/plugins/highlight-occurrences/occurrence-source.js +21 -18
  586. package/dist/plugins/highlight-occurrences/occurrences.d.ts +11 -11
  587. package/dist/plugins/highlight-occurrences/occurrences.js +14 -36
  588. package/dist/plugins/highlight-occurrences/word-char.d.ts +1 -0
  589. package/dist/plugins/highlight-occurrences/word-char.js +4 -0
  590. package/dist/plugins/latex/BlockMath.svelte +58 -75
  591. package/dist/plugins/latex/BlockMath.svelte.d.ts +2 -4
  592. package/dist/plugins/latex/MathInline.svelte +10 -9
  593. package/dist/plugins/latex/flanking.d.ts +1 -0
  594. package/dist/plugins/latex/flanking.js +3 -0
  595. package/dist/plugins/latex/index.d.ts +1 -1
  596. package/dist/plugins/latex/latex-kind.d.ts +4 -4
  597. package/dist/plugins/latex/latex-kind.js +78 -67
  598. package/dist/plugins/latex/math-completion.d.ts +1 -1
  599. package/dist/plugins/latex/math-completion.js +5 -8
  600. package/dist/plugins/latex/math-layout.d.ts +2 -8
  601. package/dist/plugins/latex/math-layout.js +0 -9
  602. package/dist/plugins/latex/math-renderer.d.ts +17 -20
  603. package/dist/plugins/latex/math-renderer.js +21 -38
  604. package/dist/plugins/latex/math-source.d.ts +4 -8
  605. package/dist/plugins/latex/math-source.js +36 -81
  606. package/dist/plugins/latex/register.d.ts +10 -11
  607. package/dist/plugins/latex/register.js +24 -10
  608. package/dist/plugins/latex/renderer.d.ts +9 -10
  609. package/dist/plugins/latex/renderer.js +9 -24
  610. package/dist/plugins/mermaid/MermaidBlock.svelte +51 -45
  611. package/dist/plugins/mermaid/index.js +1 -1
  612. package/dist/plugins/mermaid/mermaid-kind.d.ts +4 -7
  613. package/dist/plugins/mermaid/mermaid-kind.js +30 -47
  614. package/dist/plugins/mermaid/mermaid-renderer.d.ts +9 -16
  615. package/dist/plugins/mermaid/mermaid-renderer.js +12 -31
  616. package/dist/plugins/mermaid/register.d.ts +3 -3
  617. package/dist/plugins/mermaid/register.js +5 -5
  618. package/dist/plugins/mermaid/renderer.d.ts +5 -5
  619. package/dist/plugins/mermaid/renderer.js +8 -11
  620. package/dist/plugins/parrot/ParrotBlock.svelte +15 -6
  621. package/dist/plugins/parrot/ParrotBlock.svelte.d.ts +2 -2
  622. package/dist/plugins/parrot/parrot-plugin.js +3 -3
  623. package/dist/plugins/slash-commands/filter.d.ts +23 -0
  624. package/dist/plugins/slash-commands/filter.js +31 -0
  625. package/dist/plugins/slash-commands/index.d.ts +2 -0
  626. package/dist/plugins/slash-commands/index.js +2 -0
  627. package/dist/plugins/slash-commands/slash-commands-plugin.d.ts +12 -0
  628. package/dist/plugins/slash-commands/slash-commands-plugin.js +40 -0
  629. package/dist/plugins/slash-commands/slash-source.d.ts +36 -0
  630. package/dist/plugins/slash-commands/slash-source.js +108 -0
  631. package/dist/plugins/toc/TocBlock.svelte +23 -22
  632. package/dist/plugins/toc/TocBlock.svelte.d.ts +2 -3
  633. package/dist/plugins/toc/heading-outline.d.ts +7 -12
  634. package/dist/plugins/toc/heading-outline.js +22 -36
  635. package/dist/plugins/toc/navigation-queue.d.ts +2 -4
  636. package/dist/plugins/toc/toc-plugin.d.ts +5 -5
  637. package/dist/plugins/toc/toc-plugin.js +20 -13
  638. package/dist/presentation-mode.d.ts +15 -23
  639. package/dist/presentation-mode.js +19 -25
  640. package/dist/reactivity/block-list-state.svelte.d.ts +9 -11
  641. package/dist/reactivity/block-list-state.svelte.js +8 -9
  642. package/dist/reactivity/block-window.svelte.d.ts +12 -6
  643. package/dist/reactivity/block-window.svelte.js +44 -17
  644. package/dist/reactivity/child-list.d.ts +34 -0
  645. package/dist/reactivity/child-list.js +48 -0
  646. package/dist/reactivity/content-version.svelte.d.ts +4 -7
  647. package/dist/reactivity/content-version.svelte.js +3 -5
  648. package/dist/reactivity/hold-across.d.ts +39 -0
  649. package/dist/reactivity/hold-across.js +57 -0
  650. package/dist/reactivity/layout-state.svelte.d.ts +27 -0
  651. package/dist/reactivity/layout-state.svelte.js +51 -0
  652. package/dist/reactivity/list-tree.d.ts +39 -0
  653. package/dist/reactivity/list-tree.js +132 -0
  654. package/dist/reactivity/list-windowing.svelte.d.ts +50 -71
  655. package/dist/reactivity/list-windowing.svelte.js +141 -310
  656. package/dist/reactivity/measure-batch.d.ts +6 -8
  657. package/dist/reactivity/measure-batch.js +5 -6
  658. package/dist/reactivity/publish-ref.svelte.d.ts +16 -41
  659. package/dist/reactivity/publish-ref.svelte.js +21 -85
  660. package/dist/reactivity/scope-geometry.d.ts +6 -13
  661. package/dist/reactivity/scope-geometry.js +7 -14
  662. package/dist/reactivity/state-registry.d.ts +5 -5
  663. package/dist/reactivity/state-registry.js +11 -15
  664. package/dist/reactivity/use-container-windowing.svelte.d.ts +13 -26
  665. package/dist/reactivity/use-container-windowing.svelte.js +64 -74
  666. package/dist/reactivity/use-measured-child.svelte.d.ts +10 -0
  667. package/dist/reactivity/use-measured-child.svelte.js +41 -0
  668. package/dist/reactivity/use-window-floor.svelte.d.ts +2 -0
  669. package/dist/reactivity/use-window-floor.svelte.js +27 -0
  670. package/dist/reactivity/window-slice.d.ts +4 -4
  671. package/dist/reactivity/window-slice.js +0 -2
  672. package/dist/renderer-slot.d.ts +48 -0
  673. package/dist/renderer-slot.js +85 -0
  674. package/dist/scan-index.d.ts +4 -4
  675. package/dist/scan-index.js +4 -4
  676. package/dist/schema/block-commands.d.ts +69 -54
  677. package/dist/schema/block-commands.js +91 -104
  678. package/dist/schema/block-completions.d.ts +16 -19
  679. package/dist/schema/block-completions.js +25 -32
  680. package/dist/schema/block-component-registry.d.ts +13 -14
  681. package/dist/schema/block-component-registry.js +19 -17
  682. package/dist/schema/block-kind-descriptor.d.ts +234 -168
  683. package/dist/schema/block-kind-descriptor.js +151 -66
  684. package/dist/schema/block-openers.d.ts +48 -39
  685. package/dist/schema/block-openers.js +73 -83
  686. package/dist/schema/built-in-descriptors.d.ts +3 -5
  687. package/dist/schema/built-in-descriptors.js +96 -80
  688. package/dist/schema/child-spans.d.ts +12 -10
  689. package/dist/schema/child-spans.js +68 -34
  690. package/dist/schema/closure.d.ts +18 -16
  691. package/dist/schema/closure.js +24 -14
  692. package/dist/schema/command-id.d.ts +6 -8
  693. package/dist/schema/command-id.js +20 -25
  694. package/dist/schema/commands.d.ts +78 -84
  695. package/dist/schema/commands.js +152 -117
  696. package/dist/schema/container-raw.d.ts +51 -11
  697. package/dist/schema/container-raw.js +143 -14
  698. package/dist/schema/container-rebuilders.d.ts +17 -15
  699. package/dist/schema/container-rebuilders.js +30 -22
  700. package/dist/schema/context-actions.d.ts +25 -13
  701. package/dist/schema/context-actions.js +32 -17
  702. package/dist/schema/define-plugin-block.d.ts +8 -6
  703. package/dist/schema/define-plugin-block.js +6 -4
  704. package/dist/schema/fenced-code-raw.d.ts +30 -17
  705. package/dist/schema/fenced-code-raw.js +155 -107
  706. package/dist/schema/global-commands.d.ts +6 -6
  707. package/dist/schema/global-commands.js +14 -22
  708. package/dist/schema/height-estimates.d.ts +31 -0
  709. package/dist/schema/height-estimates.js +64 -0
  710. package/dist/schema/inline-construct-policy.d.ts +42 -55
  711. package/dist/schema/inline-construct-policy.js +36 -35
  712. package/dist/schema/insert-catalogue.d.ts +30 -0
  713. package/dist/schema/insert-catalogue.js +95 -0
  714. package/dist/schema/keybinding-overrides.d.ts +9 -11
  715. package/dist/schema/keybinding-overrides.js +1 -1
  716. package/dist/schema/keybindings.d.ts +15 -7
  717. package/dist/schema/keybindings.js +21 -9
  718. package/dist/schema/merge-rules.d.ts +5 -7
  719. package/dist/schema/merge-rules.js +7 -9
  720. package/dist/schema/opener-priorities.d.ts +4 -4
  721. package/dist/schema/opener-priorities.js +4 -4
  722. package/dist/schema/operations.d.ts +8 -10
  723. package/dist/schema/operations.js +3 -3
  724. package/dist/schema/page-role.d.ts +14 -0
  725. package/dist/schema/page-role.js +19 -0
  726. package/dist/schema/plugin-activation.d.ts +4 -6
  727. package/dist/schema/plugin-activation.js +12 -10
  728. package/dist/schema/plugin-editor-context.d.ts +25 -10
  729. package/dist/schema/plugin-editor-context.js +40 -9
  730. package/dist/schema/plugin-install.d.ts +49 -17
  731. package/dist/schema/plugin-install.js +51 -25
  732. package/dist/schema/plugin-kind.d.ts +12 -8
  733. package/dist/schema/plugin-kind.js +35 -42
  734. package/dist/schema/plugin-name.js +3 -3
  735. package/dist/schema/plugin-registry.d.ts +54 -0
  736. package/dist/schema/plugin-registry.js +70 -0
  737. package/dist/schema/reading.d.ts +23 -0
  738. package/dist/schema/reading.js +7 -0
  739. package/dist/schema/register-once.d.ts +3 -5
  740. package/dist/schema/register-once.js +7 -16
  741. package/dist/schema/registration-checks.d.ts +12 -16
  742. package/dist/schema/registration-checks.js +35 -51
  743. package/dist/schema/registration-pairs.d.ts +54 -0
  744. package/dist/schema/registration-pairs.js +48 -0
  745. package/dist/schema/registration-pending.d.ts +8 -12
  746. package/dist/schema/registration-pending.js +9 -9
  747. package/dist/schema/registry-reset.d.ts +8 -4
  748. package/dist/schema/registry-reset.js +13 -26
  749. package/dist/schema/registry-view.d.ts +25 -13
  750. package/dist/schema/registry-view.js +26 -20
  751. package/dist/schema/reserved-chords.d.ts +9 -10
  752. package/dist/schema/reserved-chords.js +63 -80
  753. package/dist/schema/reserved-chrome.d.ts +12 -11
  754. package/dist/schema/reserved-chrome.js +15 -11
  755. package/dist/schema/setext-raw.d.ts +13 -0
  756. package/dist/schema/setext-raw.js +33 -0
  757. package/dist/schema/stored-as.d.ts +20 -0
  758. package/dist/schema/stored-as.js +6 -0
  759. package/dist/schema/table-cell-raw.d.ts +18 -7
  760. package/dist/schema/table-cell-raw.js +28 -7
  761. package/dist/schema/whole-block-unit.d.ts +5 -4
  762. package/dist/schema/whole-block-unit.js +5 -4
  763. package/dist/search/document-scan.d.ts +3 -3
  764. package/dist/search/document-scan.js +2 -2
  765. package/dist/search/matcher.d.ts +1 -1
  766. package/dist/search/regex-executor.d.ts +5 -6
  767. package/dist/search/regex-executor.js +6 -8
  768. package/dist/search/replace.d.ts +2 -5
  769. package/dist/search/replace.js +2 -5
  770. package/dist/search/search-state.svelte.d.ts +5 -5
  771. package/dist/search/search-state.svelte.js +12 -16
  772. package/dist/selection/autoscroll.d.ts +6 -9
  773. package/dist/selection/block-hit-test.d.ts +16 -24
  774. package/dist/selection/block-hit-test.js +29 -22
  775. package/dist/selection/caret-doors.d.ts +15 -14
  776. package/dist/selection/caret-doors.js +37 -26
  777. package/dist/selection/caret-landing.d.ts +62 -0
  778. package/dist/selection/caret-landing.js +157 -0
  779. package/dist/selection/caret-restore.d.ts +17 -10
  780. package/dist/selection/caret-restore.js +10 -22
  781. package/dist/selection/caret-target.d.ts +30 -0
  782. package/dist/selection/caret-target.js +84 -0
  783. package/dist/selection/char-endpoint-snap.d.ts +6 -10
  784. package/dist/selection/char-endpoint-snap.js +8 -14
  785. package/dist/selection/clipboard-text.d.ts +5 -12
  786. package/dist/selection/clipboard-text.js +69 -172
  787. package/dist/selection/covered-block.d.ts +6 -8
  788. package/dist/selection/covered-block.js +8 -19
  789. package/dist/selection/cross-block/clipboard.d.ts +3 -2
  790. package/dist/selection/cross-block/clipboard.js +13 -4
  791. package/dist/selection/cross-block/dispatch.d.ts +47 -43
  792. package/dist/selection/cross-block/dispatch.js +12 -23
  793. package/dist/selection/cross-block/format-range.d.ts +18 -21
  794. package/dist/selection/cross-block/format-range.js +104 -103
  795. package/dist/selection/cross-block/format-toggle.d.ts +10 -15
  796. package/dist/selection/cross-block/format-toggle.js +28 -33
  797. package/dist/selection/cross-block/keydown.d.ts +4 -4
  798. package/dist/selection/cross-block/keydown.js +92 -125
  799. package/dist/selection/cross-block/ops.d.ts +19 -34
  800. package/dist/selection/cross-block/ops.js +110 -95
  801. package/dist/selection/cross-block/paste.d.ts +2 -3
  802. package/dist/selection/cross-block/paste.js +59 -96
  803. package/dist/selection/cross-block/pointer.d.ts +17 -15
  804. package/dist/selection/cross-block/pointer.js +74 -25
  805. package/dist/selection/cross-block/type-replace.d.ts +4 -6
  806. package/dist/selection/cross-block/type-replace.js +51 -134
  807. package/dist/selection/dead-space-caret.d.ts +19 -30
  808. package/dist/selection/dead-space-caret.js +70 -88
  809. package/dist/selection/drag-pointer.d.ts +7 -9
  810. package/dist/selection/drag-pointer.js +23 -33
  811. package/dist/selection/gap-caret.d.ts +17 -28
  812. package/dist/selection/gap-caret.js +14 -26
  813. package/dist/selection/grid-selection.d.ts +12 -0
  814. package/dist/selection/grid-selection.js +22 -0
  815. package/dist/selection/keyboard-extend.d.ts +27 -40
  816. package/dist/selection/keyboard-extend.js +94 -117
  817. package/dist/selection/multi-click.d.ts +13 -18
  818. package/dist/selection/multi-click.js +32 -38
  819. package/dist/selection/native-bridge.d.ts +29 -39
  820. package/dist/selection/native-bridge.js +78 -127
  821. package/dist/selection/nearest-block.d.ts +17 -12
  822. package/dist/selection/nearest-block.js +37 -18
  823. package/dist/selection/path-lookup.d.ts +25 -16
  824. package/dist/selection/path-lookup.js +101 -18
  825. package/dist/selection/path-math.d.ts +9 -11
  826. package/dist/selection/path-math.js +5 -7
  827. package/dist/selection/pointer-gesture.d.ts +5 -5
  828. package/dist/selection/pointer-gesture.js +5 -5
  829. package/dist/selection/pointer-session.d.ts +10 -16
  830. package/dist/selection/pointer-session.js +6 -7
  831. package/dist/selection/primitives.d.ts +64 -40
  832. package/dist/selection/primitives.js +57 -67
  833. package/dist/selection/range-coverage.d.ts +94 -0
  834. package/dist/selection/range-coverage.js +365 -0
  835. package/dist/selection/range-delete-ceremony.d.ts +28 -74
  836. package/dist/selection/range-delete-ceremony.js +100 -141
  837. package/dist/selection/range-delete-chrome.d.ts +20 -33
  838. package/dist/selection/range-delete-chrome.js +53 -78
  839. package/dist/selection/range-delete-table-coverage.d.ts +11 -25
  840. package/dist/selection/range-delete-table-coverage.js +42 -112
  841. package/dist/selection/range-delete-table.d.ts +14 -12
  842. package/dist/selection/range-delete-table.js +106 -310
  843. package/dist/selection/range-delete.d.ts +18 -23
  844. package/dist/selection/range-delete.js +83 -123
  845. package/dist/selection/round-trip-restore.d.ts +18 -0
  846. package/dist/selection/round-trip-restore.js +19 -0
  847. package/dist/selection/selection-announcer.d.ts +17 -0
  848. package/dist/selection/selection-announcer.js +25 -0
  849. package/dist/selection/selection-description.d.ts +4 -3
  850. package/dist/selection/selection-description.js +5 -4
  851. package/dist/selection/selection-drop.d.ts +34 -16
  852. package/dist/selection/selection-drop.js +159 -95
  853. package/dist/selection/selection-restore.d.ts +20 -33
  854. package/dist/selection/selection-restore.js +21 -44
  855. package/dist/selection/selection-state.svelte.d.ts +50 -42
  856. package/dist/selection/selection-state.svelte.js +144 -98
  857. package/dist/selection/shared-keydown.d.ts +22 -27
  858. package/dist/selection/shared-keydown.js +25 -45
  859. package/dist/selection/table-endpoint-snap.d.ts +17 -41
  860. package/dist/selection/table-endpoint-snap.js +54 -80
  861. package/dist/selection/table-rect-extend.d.ts +3 -6
  862. package/dist/selection/table-rect-extend.js +19 -14
  863. package/dist/styles/editor-theme.css +60 -53
  864. package/dist/styles/editor.css +201 -143
  865. package/dist/testing/conformance-core.d.ts +50 -18
  866. package/dist/testing/conformance-core.js +88 -50
  867. package/dist/testing/container-conformance.d.ts +48 -84
  868. package/dist/testing/container-conformance.js +159 -285
  869. package/dist/testing/headless-actions.d.ts +34 -19
  870. package/dist/testing/headless-actions.js +116 -65
  871. package/dist/testing/headless-block-list.svelte.d.ts +16 -0
  872. package/dist/testing/headless-block-list.svelte.js +22 -0
  873. package/dist/testing/inline-conformance.d.ts +15 -22
  874. package/dist/testing/inline-conformance.js +131 -148
  875. package/dist/testing/kind-conformance.d.ts +19 -24
  876. package/dist/testing/kind-conformance.js +204 -117
  877. package/dist/testing/kit-reading.d.ts +7 -0
  878. package/dist/testing/kit-reading.js +16 -0
  879. package/dist/testing/mount-dom-stubs.d.ts +4 -5
  880. package/dist/testing/mount-dom-stubs.js +8 -5
  881. package/dist/testing/parse-convergence.d.ts +10 -10
  882. package/dist/testing/parse-convergence.js +14 -49
  883. package/dist/testing.d.ts +13 -9
  884. package/dist/testing.js +28 -38
  885. package/dist/tree-operations/blockquote.d.ts +8 -14
  886. package/dist/tree-operations/blockquote.js +25 -45
  887. package/dist/tree-operations/chain-rebuild.d.ts +34 -25
  888. package/dist/tree-operations/chain-rebuild.js +115 -52
  889. package/dist/tree-operations/children.d.ts +5 -9
  890. package/dist/tree-operations/children.js +7 -11
  891. package/dist/tree-operations/cleanup.d.ts +6 -7
  892. package/dist/tree-operations/cleanup.js +14 -11
  893. package/dist/tree-operations/clone.js +5 -4
  894. package/dist/tree-operations/container-lift.d.ts +10 -5
  895. package/dist/tree-operations/container-lift.js +20 -14
  896. package/dist/tree-operations/container-offsets.d.ts +22 -0
  897. package/dist/tree-operations/container-offsets.js +89 -0
  898. package/dist/tree-operations/content-write.d.ts +52 -29
  899. package/dist/tree-operations/content-write.js +155 -110
  900. package/dist/tree-operations/index.d.ts +4 -4
  901. package/dist/tree-operations/index.js +4 -4
  902. package/dist/tree-operations/keep-one-block.d.ts +10 -0
  903. package/dist/tree-operations/keep-one-block.js +19 -0
  904. package/dist/tree-operations/leaf-range.d.ts +33 -0
  905. package/dist/tree-operations/leaf-range.js +67 -0
  906. package/dist/tree-operations/list/empty-check.d.ts +2 -3
  907. package/dist/tree-operations/list/empty-check.js +4 -4
  908. package/dist/tree-operations/list/exit-replacement.d.ts +4 -6
  909. package/dist/tree-operations/list/exit-replacement.js +4 -9
  910. package/dist/tree-operations/list/item-partition.d.ts +2 -2
  911. package/dist/tree-operations/list/item-partition.js +2 -2
  912. package/dist/tree-operations/list/list-builders.d.ts +18 -16
  913. package/dist/tree-operations/list/list-builders.js +59 -30
  914. package/dist/tree-operations/list/ordered-markers.d.ts +7 -16
  915. package/dist/tree-operations/list/ordered-markers.js +7 -16
  916. package/dist/tree-operations/list/reconcile-task.d.ts +16 -7
  917. package/dist/tree-operations/list/reconcile-task.js +80 -23
  918. package/dist/tree-operations/list/sublist-separator.d.ts +7 -7
  919. package/dist/tree-operations/list/sublist-separator.js +20 -27
  920. package/dist/tree-operations/list/task-paragraph.d.ts +25 -0
  921. package/dist/tree-operations/list/task-paragraph.js +54 -0
  922. package/dist/tree-operations/list/unwrap-merge.d.ts +8 -16
  923. package/dist/tree-operations/list/unwrap-merge.js +44 -79
  924. package/dist/tree-operations/node-ops.d.ts +30 -52
  925. package/dist/tree-operations/node-ops.js +152 -218
  926. package/dist/tree-operations/node-primitives.d.ts +44 -31
  927. package/dist/tree-operations/node-primitives.js +84 -60
  928. package/dist/tree-operations/open-tail.d.ts +25 -0
  929. package/dist/tree-operations/open-tail.js +100 -0
  930. package/dist/tree-operations/parse-block.d.ts +15 -2
  931. package/dist/tree-operations/parse-block.js +19 -4
  932. package/dist/tree-operations/paste/apply.d.ts +7 -8
  933. package/dist/tree-operations/paste/apply.js +33 -63
  934. package/dist/tree-operations/paste/body-write.d.ts +8 -6
  935. package/dist/tree-operations/paste/body-write.js +13 -14
  936. package/dist/tree-operations/paste/container-match.d.ts +7 -10
  937. package/dist/tree-operations/paste/container-match.js +76 -58
  938. package/dist/tree-operations/paste/container-paste.d.ts +3 -3
  939. package/dist/tree-operations/paste/container-paste.js +3 -3
  940. package/dist/tree-operations/paste/dispatch.d.ts +26 -29
  941. package/dist/tree-operations/paste/dispatch.js +68 -53
  942. package/dist/tree-operations/paste/focus-target.d.ts +11 -14
  943. package/dist/tree-operations/paste/focus-target.js +13 -18
  944. package/dist/tree-operations/paste/hooks.d.ts +7 -12
  945. package/dist/tree-operations/paste/hooks.js +49 -46
  946. package/dist/tree-operations/paste/line-ending.d.ts +11 -0
  947. package/dist/tree-operations/paste/line-ending.js +32 -0
  948. package/dist/tree-operations/paste/list-absorb.d.ts +8 -11
  949. package/dist/tree-operations/paste/list-absorb.js +17 -19
  950. package/dist/tree-operations/paste/list-break-out.d.ts +12 -11
  951. package/dist/tree-operations/paste/list-break-out.js +24 -32
  952. package/dist/tree-operations/paste/parent-scope.d.ts +8 -12
  953. package/dist/tree-operations/paste/parent-scope.js +9 -16
  954. package/dist/tree-operations/paste/paste-deps.d.ts +14 -9
  955. package/dist/tree-operations/paste/paste-replacement.d.ts +20 -3
  956. package/dist/tree-operations/paste/paste-replacement.js +73 -42
  957. package/dist/tree-operations/paste/paste-transforms.d.ts +5 -7
  958. package/dist/tree-operations/paste/paste-transforms.js +18 -27
  959. package/dist/tree-operations/paste/replacement-parse.d.ts +9 -7
  960. package/dist/tree-operations/paste/replacement-parse.js +12 -10
  961. package/dist/tree-operations/paste/strategy.d.ts +1 -1
  962. package/dist/tree-operations/paste/strategy.js +1 -1
  963. package/dist/tree-operations/paste/table-slice.js +15 -10
  964. package/dist/tree-operations/paste-surfaces.d.ts +18 -29
  965. package/dist/tree-operations/paste-surfaces.js +14 -10
  966. package/dist/tree-operations/path-mutate.d.ts +7 -8
  967. package/dist/tree-operations/path-mutate.js +4 -4
  968. package/dist/tree-operations/reorder-unit.d.ts +4 -5
  969. package/dist/tree-operations/reorder-unit.js +5 -6
  970. package/dist/tree-operations/reorder.d.ts +7 -9
  971. package/dist/tree-operations/reorder.js +39 -40
  972. package/dist/tree-operations/settle.d.ts +42 -53
  973. package/dist/tree-operations/settle.js +241 -162
  974. package/dist/tree-operations/sharing.d.ts +5 -5
  975. package/dist/tree-operations/splice-many.d.ts +5 -5
  976. package/dist/tree-operations/splice-many.js +5 -5
  977. package/dist/tree-operations/stored-as.d.ts +13 -0
  978. package/dist/tree-operations/stored-as.js +48 -0
  979. package/dist/tree-operations/structural-change.d.ts +11 -15
  980. package/dist/tree-operations/structural-change.js +10 -14
  981. package/dist/tree-operations/structural-suffix.d.ts +22 -0
  982. package/dist/tree-operations/structural-suffix.js +61 -0
  983. package/dist/tree-operations/sub-table-copy.d.ts +7 -0
  984. package/dist/tree-operations/sub-table-copy.js +40 -36
  985. package/dist/tree-operations/table-grid-clipboard.d.ts +2 -7
  986. package/dist/tree-operations/table-grid-clipboard.js +11 -36
  987. package/dist/tree-operations/table-mutations.d.ts +7 -3
  988. package/dist/tree-operations/table-mutations.js +45 -9
  989. package/dist/tree-operations/unshare.d.ts +11 -15
  990. package/dist/tree-operations/unshare.js +15 -17
  991. package/dist/undo/manager.js +1 -1
  992. package/dist/undo/types.d.ts +2 -2
  993. package/docs/guide/consumer-guide.md +327 -205
  994. package/docs/guide/directives.md +7 -7
  995. package/docs/guide/plugin-api.md +253 -185
  996. package/docs/guide/plugin-guide.md +332 -235
  997. package/docs/guide/plugin-testing.md +96 -82
  998. package/package.json +12 -16
  999. package/dist/ambient/ambient-cursor.d.ts +0 -41
  1000. package/dist/ambient/ambient-cursor.js +0 -120
  1001. package/dist/components/blocks/code/code-paste.d.ts +0 -24
  1002. package/dist/components/blocks/code/code-paste.js +0 -21
  1003. package/dist/components/blocks/table/cell-clipboard.d.ts +0 -33
  1004. package/dist/components/blocks/table/cell-clipboard.js +0 -67
  1005. package/dist/components/blocks/text/hidden-suffix.d.ts +0 -10
  1006. package/dist/components/blocks/text/hidden-suffix.js +0 -15
  1007. package/dist/components/blocks/text/link-source-bytes.d.ts +0 -37
  1008. package/dist/components/image/image-source-bytes.d.ts +0 -15
  1009. package/dist/components/image/image-source-bytes.js +0 -80
  1010. package/dist/cursor/content-offsets.d.ts +0 -29
  1011. package/dist/cursor/content-offsets.js +0 -151
  1012. package/dist/cursor/reveal-anchor.d.ts +0 -30
  1013. package/dist/cursor/reveal-anchor.js +0 -31
  1014. package/dist/cursor/scroll-hold.d.ts +0 -10
  1015. package/dist/cursor/scroll-hold.js +0 -22
  1016. package/dist/invariants/split-landing.d.ts +0 -8
  1017. package/dist/invariants/split-landing.js +0 -15
  1018. package/dist/tree-operations/list/terminator.d.ts +0 -17
  1019. package/dist/tree-operations/list/terminator.js +0 -60
  1020. package/dist/tree-operations/paste/replace-block-at-parent.d.ts +0 -31
  1021. package/dist/tree-operations/paste/replace-block-at-parent.js +0 -78
@@ -1,6 +1,9 @@
1
1
  <script lang="ts">
2
2
  import { getContext, tick, untrack } from 'svelte';
3
3
  import { CURSOR_START, type AmbientPrefix, type BlockComponent } from '../../../block-component';
4
+ import { readBlocks } from '../../../core/parser';
5
+ import { ambientHoldsTaskBox } from '../list/task-checkbox';
6
+ import { shownKind } from '../../../core/parsers/heading';
4
7
  import type { DocumentView, NodeView } from '../../../core/node-views';
5
8
  import type { EditorRects } from '../../../editor-rects';
6
9
  import { enterLinkCardAtCaret, linkCardTargetAt } from '../../link-card/link-card-entry';
@@ -15,13 +18,17 @@
15
18
  } from '../../../editor-keys';
16
19
  import type { IndexedDecoration } from '../../../decorations/buckets';
17
20
  import type { ReplaceDecoration, WidgetDecoration } from '../../../decorations/types';
18
- import { getContentRange, isProseKind } from '../../../core/inline';
21
+ import { getContentRange, isProseKind, structuralSuffix } from '../../../core/inline';
19
22
  import { devWarn } from '../../../dev-warn';
20
23
  import { resolvedInlineContent } from '../../../core/inline/inline-cache';
21
- import type { LinkReferenceResolver } from '../../../core/inline/link-reference-resolver';
22
24
  import { isInlineWidget } from '../../../core/inline/inline-widgets';
23
- import { trimTrailingLineEnding, trailingLineEnding } from '../../../core/lines';
24
- import { hasSelection as hasSelectionHelper } from '../../../cursor/content-offsets';
25
+ import {
26
+ documentLineEnding,
27
+ trimTrailingLineEnding,
28
+ trailingLineEnding
29
+ } from '../../../core/lines';
30
+ import { caretIsInTextContent, seatIsInTextContent } from './click-snap-guard';
31
+ import { caretSeatInElement } from '../../../cursor/point-offset';
25
32
  import { FALLBACK_CONTENT_WIDTH } from '../../../cursor/typography-estimates';
26
33
  import {
27
34
  createInlineFormatActiveMemo,
@@ -44,14 +51,15 @@
44
51
  import { createTextClipboard } from './text-clipboard';
45
52
  import { createTextRender } from './text-render';
46
53
  import { createWidgetInteraction } from './widget-interaction';
47
- import { createEdgePolicyDispatch, keepsBlockKind } from './edge-policy-dispatch';
48
- import { hidesStructuralSuffix } from './hidden-suffix';
49
- import { applyLiveRangeEdit, resolveSelectionEdit } from './live-selection-edit';
54
+ import { createEdgePolicyDispatch } from './edge-policy-dispatch';
55
+ import { keepsKindAt } from '../../../core/inline/live-edit/read-back';
56
+ import { storedAsAt } from '../../../tree-operations/stored-as';
57
+ import { applyLiveRangeEdit } from './live-selection-edit';
58
+ import { replaceRangeInLeaf } from '../../../tree-operations/leaf-range';
50
59
  import { applyDelimiterAutoPair } from './delimiter-autopair';
51
60
  import { createCompositionSeat } from './composition-seat';
52
61
  import { createConstructReveal } from './construct-reveal';
53
62
  import { assertInvariant } from '../../../assert';
54
- import { paintsFocusedMarkers } from '../../../presentation-mode';
55
63
  import { widgetElByStart } from './widget-adjacency';
56
64
  import {
57
65
  caretLandableBounds,
@@ -59,29 +67,24 @@
59
67
  handleSharedBeforeInput
60
68
  } from '../../../selection/shared-keydown';
61
69
  import {
70
+ editableSurfaceAttributes,
62
71
  createEditableSurface,
63
72
  consumePendingRestore,
64
73
  withKeydownVerdict
65
74
  } from '../editable-surface';
66
75
  import { wireSurfaceContexts, useParkFocusOnUnmount } from '../surface-wiring.svelte';
67
76
  import {
68
- domTextOffsetAtNode,
69
77
  landableStartAbutsIsland,
70
- rawTextOfNode,
71
- createRangeAtDomTextOffsets,
78
+ markerPrefixOf,
79
+ rawOffsetAt,
80
+ rawTextOfContent,
72
81
  revealsNoMarkers,
73
82
  screenVisibilityOf,
74
- selectionFocusWalkOffset
83
+ rawSelectionFocus
75
84
  } from '../../../cursor/widget-offset';
76
- import { ambientSpanOf } from '../../../ambient/ambient-dom';
77
- import {
78
- asRawOffset,
79
- toClampedRawOffset,
80
- toDomTextOffset
81
- } from '../../../cursor/coordinate-spaces';
82
- import { createAmbientCursorIO } from '../../../ambient/ambient-cursor';
85
+ import { asRawOffset } from '../../../cursor/coordinate-spaces';
86
+ import { createSurfaceBackend } from '../../../cursor/surface-backend';
83
87
  import { type CommandId } from '../../../schema/commands';
84
- import { reorderRunCommand } from '../../../editor-actions/reorder-action';
85
88
  import { planTypedCompletion } from '../../../editor-actions/enter-completion';
86
89
  import {
87
90
  perfEnabled,
@@ -107,19 +110,18 @@
107
110
  myPath?: number[];
108
111
  blockClass?: string;
109
112
  ambientPrefix?: AmbientPrefix;
110
- // Accepted for BlockComponentProps parity: this surface reads the doc from the
111
- // document facet, and binding would shadow the global `document`.
113
+ // Accepted so the props match `BlockComponentProps`: this block reads the document
114
+ // from its own context, and binding here would shadow the global `document`.
112
115
  document?: DocumentView;
113
- // The surface itself navigates through the editor; this is forwarded to inline
114
- // widgets whose own gesture jumps elsewhere in the document.
116
+ // Passed on to inline widgets whose own gesture jumps elsewhere in the document.
115
117
  rects?: EditorRects;
116
118
  } = $props();
117
119
 
118
120
  const ambientPrefixText = $derived(
119
121
  typeof ambientPrefix === 'string' ? ambientPrefix : ambientPrefix.text
120
122
  );
121
- // The hanging indent is the prefix's painted width: its text width by default, or what a
122
- // prefix painting itself as chrome (the task box) declares.
123
+ // The hanging indent is how wide the prefix draws: its text width by default, or what a
124
+ // prefix that draws itself, such as the task checkbox, declares.
123
125
  const ambientIndent = $derived(
124
126
  (typeof ambientPrefix === 'string' ? undefined : ambientPrefix.indent) ??
125
127
  `${ambientPrefixText.length}ch`
@@ -131,46 +133,52 @@
131
133
  focusActions,
132
134
  controller,
133
135
  pasteCoordinator,
134
- stickyColumn,
135
- edgeAffinity,
136
+ caretMemory,
136
137
  selection,
137
138
  getDoc,
138
139
  getEditorRoot,
139
- grammar,
140
140
  activePlugins,
141
141
  events: editorEvents,
142
- linkRef
142
+ reading
143
143
  } = wiring.deps;
144
+ const { grammar } = reading;
145
+ // A block with no line ending of its own is the document's last line; a write gives it the
146
+ // document's.
147
+ const documentEnding = () => documentLineEnding(getDoc());
148
+ const blockEnding = () => trailingLineEnding(node.raw, documentEnding());
149
+ // Made per gesture, never derived: a derived value would subscribe the block to the tree.
150
+ const storedAs = () => storedAsAt(getDoc(), myPath, reading);
144
151
  // Present inside a list item, whose ListItemBlock owns Tab-as-indent.
145
152
  const listContext = getContext(LIST_CONTEXT_KEY);
146
153
  const {
147
- reorder,
148
- pendingMarks,
154
+ autoPairs,
149
155
  widgetSelection,
150
156
  linkCard,
151
- decorations: decorationEngine
157
+ inlineMenuCombobox,
158
+ decorations: decorationEngine,
159
+ kindCue
152
160
  } = getContext<EditorServices>(EDITOR_SERVICES_KEY);
161
+ const ownPairs = autoPairs.forBlock();
162
+
153
163
  const {
154
164
  resolveImageUrl,
155
165
  resolveLinkUrl,
156
166
  imageLoadPolicy,
157
167
  brokenImageUrls: brokenUrlCache,
158
- presentationMode: getPresentationMode,
159
168
  theme: getTheme,
160
169
  onPasteImage
161
170
  } = getContext<EditorPolicies>(EDITOR_POLICIES_KEY);
162
171
  const { contentVersion: getContentVersion } = getContext<EditorDoc>(EDITOR_DOC_KEY);
163
- const presentationMode = $derived(getPresentationMode?.() ?? 'source');
164
- const readOnly = $derived(presentationMode === 'reading');
172
+ const readOnly = $derived(reading.mode() === 'reading');
173
+ const combobox = $derived(inlineMenuCombobox(myPath));
165
174
 
166
- /** The card's query for this surface, the cell's shape: `range` is the live selection at both
167
- * the chord's arm and the pressed read, since prose owns no wrap policy of its own. */
175
+ /** What the link card is asked about here, the same shape a table cell passes: `range` is the
176
+ * live selection both when the chord runs and when the pressed state is read. */
168
177
  const linkCardQuery = (contentEl: HTMLElement, range: { start: number; end: number } | null) => ({
169
178
  contentEl,
170
179
  block: node,
171
180
  path: myPath,
172
- linkRef,
173
- mode: presentationMode,
181
+ reading,
174
182
  selection: range,
175
183
  crossBlockRange: selection.isCrossBlock
176
184
  });
@@ -182,84 +190,85 @@
182
190
  });
183
191
  }
184
192
  };
185
- // A constant fallback keeps an empty island set out of the render key.
193
+ // A shared constant keeps an empty decoration list out of the render key.
186
194
  const NO_ISLANDS: IndexedDecoration<WidgetDecoration | ReplaceDecoration>[] = [];
187
195
  let el: HTMLDivElement | undefined = $state();
188
196
  let composing = $state(false);
189
- // A revealed widget source is ephemeral DOM, so onInput and IME compositionend skip
190
- // the per-keystroke CST commit and the block commits once on reveal exit.
197
+ // A widget's shown source lives only in the DOM, so `onInput` and IME `compositionend`
198
+ // skip the per-keystroke CST commit and the block commits once when it is hidden.
191
199
  let revealing = $state(false);
192
200
  /** Cursor offset to restore after the next $effect render. Null = don't touch cursor. */
193
201
  let pendingCursorOffset = $state<number | null>(null);
194
- // Captured before each edit; keydown fires before the DOM changes.
195
- let preEditOffset = 0;
196
- // Survives the click→keydown gap when Chromium clears the caret at CE=false-adjacent
197
- // positions. Reactive so the snap-caret overlay sees changes.
202
+ // Survives the click-to-keydown gap when Chromium clears the caret beside a non-editable
203
+ // widget. Reactive so the snap-caret overlay sees changes.
198
204
  let lastSnapTargetOffset = $state<number | null>(null);
205
+ /** Counted up on every `armSnapTarget` call, so setting the offset already held still repaints:
206
+ * Svelte coalesces a null-then-same-value write into no change at all. */
207
+ let snapEpoch = $state(0);
208
+
209
+ function armSnapTarget(offset: number | null): void {
210
+ lastSnapTargetOffset = offset;
211
+ snapEpoch++;
212
+ }
213
+ // Beside a non-editable widget Chromium paints a taller caret for the length of the press.
214
+ // Reactive, so the synthetic caret can hide it as the press lands rather than after the click.
215
+ let pressSeatedBesideIsland = $state(false);
216
+ let pressPending = false;
199
217
 
200
- // One funnel for every pending-cursor write, tagged so the interaction trace names
201
- // which gesture set the restore; the render effect owns the consume half.
218
+ // The one place a pending cursor is written, tagged so the interaction trace names
219
+ // which gesture set the restore; the render effect reads and clears it.
202
220
  function setPendingCursorOffset(offset: number | null, source: string): void {
203
221
  tracePendingCursorSet(source, offset);
204
222
  pendingCursorOffset = offset;
205
223
  }
206
224
 
207
- const ambientLength = $derived(ambientPrefixText.length);
208
-
209
- const cursor = createAmbientCursorIO({
225
+ const cursor = createSurfaceBackend({
210
226
  getEl: () => el ?? null,
211
- getAmbientLength: () => ambientLength,
212
227
  getSnapTarget: () => lastSnapTargetOffset
213
228
  });
214
229
 
215
230
  const editableSurface = createEditableSurface({
216
231
  ...wiring.deps,
217
232
  getEl: () => el ?? null,
218
- getAmbientLength: () => ambientLength,
219
233
  isInputSuppressed: () => revealing,
220
- backend: {
221
- getRaw: () => cursor.getRaw(),
222
- setRaw: (offset) => cursor.setRaw(offset),
223
- buildRange: (start, end) =>
224
- createRangeAtDomTextOffsets(
225
- el!,
226
- toDomTextOffset(start, ambientLength),
227
- toDomTextOffset(end, ambientLength)
228
- )
229
- },
234
+ backend: cursor,
230
235
  getMyPath: () => myPath,
231
236
  getIndex: () => index,
232
237
  getComposing: () => composing,
233
238
  setComposing: (value) => {
234
239
  composing = value;
235
240
  },
236
- getPreEditOffset: () => preEditOffset,
237
- setPreEditOffset: (offset) => {
238
- preEditOffset = offset;
239
- },
240
241
  setPendingCursor: (offset) => setPendingCursorOffset(offset, 'surface'),
241
- getPresentationMode: () => presentationMode,
242
- getFocusOffset: () => (el ? selectionFocusWalkOffset(el, ambientLength) : null),
243
- getTextLen: () => liveDisplayLength(),
242
+ getFocusOffset: () => (el ? rawSelectionFocus(el) : null),
243
+ getTextLen: () => caretReach(),
244
244
  readText: () => readRawText(),
245
245
  relocateComposedText: (after, composedAt) => compositionSeat.relocate(after, composedAt),
246
246
  commitInput: (text, preEdit, saved) => {
247
- const committed = text + trailingLineEnding(node.raw);
248
- void blockEdit.updateBlockContent(index, committed, preEdit, saved);
249
- // An enclosing container may rewrite these bytes on the way in, so the caret
250
- // restore reads the image of the write, not the offset the keystroke produced.
251
- return blockEdit.mapCommittedOffset?.(committed, saved);
247
+ // Typed text is the one write whose kind change the block names (`kind-cue.svelte.ts`).
248
+ const before = shownKind(node);
249
+ const write = blockEdit.updateBlockContent(
250
+ index,
251
+ text + blockEnding(),
252
+ 'authored',
253
+ preEdit,
254
+ saved
255
+ );
256
+ void kindCue.afterTypedWrite(write, myPath, before);
257
+ return write.admitted ? write.caret : null;
252
258
  },
253
259
  inputPrelude: () => {
254
260
  markKeystrokeStart();
255
- lastSnapTargetOffset = null;
256
- }
261
+ armSnapTarget(null);
262
+ },
263
+ handleBeforeInput: onBeforeInput
257
264
  });
258
265
 
259
266
  const crossBlock = editableSurface.crossBlock;
260
267
  const sharedCtx = editableSurface.sharedCtx;
261
268
 
262
269
  const widgetInteraction = createWidgetInteraction({
270
+ getLineEnding: documentEnding,
271
+ storedAs,
263
272
  get node() {
264
273
  return node;
265
274
  },
@@ -270,14 +279,13 @@
270
279
  return myPath;
271
280
  },
272
281
  getEl: () => el ?? null,
273
- getAmbientLength: () => ambientLength,
274
282
  getEditorContentWidth: () => getEditorRoot()?.clientWidth ?? FALLBACK_CONTENT_WIDTH,
275
283
  cursor,
276
284
  widgetSelection,
277
285
  blockEdit,
278
286
  focusActions,
279
287
  setSnapTarget: (offset) => {
280
- lastSnapTargetOffset = offset;
288
+ armSnapTarget(offset);
281
289
  },
282
290
  setPendingCursor: (offset) => setPendingCursorOffset(offset, 'widget'),
283
291
  readRawText: () => readRawText(),
@@ -285,15 +293,15 @@
285
293
  revealing = value;
286
294
  },
287
295
  isCrossBlock: () => selection.isCrossBlock,
288
- getPresentationMode: () => presentationMode,
289
- get linkRef() {
290
- return linkRef;
296
+ get reading() {
297
+ return reading;
291
298
  }
292
299
  });
293
300
 
294
- // After widgetInteraction, whose fold seam a clipboard mutation runs before it
301
+ // After `widgetInteraction`, because a clipboard edit hides a shown source before it
295
302
  // touches the CST.
296
303
  const clipboardHandlers = createTextClipboard({
304
+ storedAs,
297
305
  get node() {
298
306
  return node;
299
307
  },
@@ -307,11 +315,9 @@
307
315
  caret: editableSurface.caret,
308
316
  crossBlock,
309
317
  selection,
310
- stickyColumn,
311
- edgeAffinity,
318
+ caretMemory,
312
319
  blockEdit,
313
320
  pasteCoordinator,
314
- grammar,
315
321
  activePlugins,
316
322
  getDoc,
317
323
  widgetSelection,
@@ -321,31 +327,28 @@
321
327
  isReadOnly: () => readOnly,
322
328
  foldRevealBeforeMutation: () => widgetInteraction.foldRevealBeforeMutation(),
323
329
  isRevealing: () => widgetInteraction.isRevealing(),
324
- getPresentationMode: () => presentationMode,
325
- getAmbientPrefix: () => ambientPrefixText,
326
330
  readRevealedText: () => readRawText(),
327
- get linkRef() {
328
- return linkRef;
331
+ get reading() {
332
+ return reading;
329
333
  }
330
334
  });
331
335
 
332
- // preview-inline's marker reveal: CSS class flips only, no keys intercepted.
336
+ // Showing markers in preview-inline mode: CSS classes only, no keys intercepted.
333
337
  const constructReveal = createConstructReveal({
334
338
  get node() {
335
339
  return node;
336
340
  },
337
- get linkRef() {
338
- return linkRef;
341
+ get reading() {
342
+ return reading;
339
343
  },
340
344
  getEl: () => el ?? null,
341
- getAmbientLength: () => ambientLength,
342
- getPresentationMode: () => presentationMode,
343
345
  isCrossBlock: () => selection.isCrossBlock
344
346
  });
345
347
 
346
- // The one caret-edge dispatch (G4.12); entry execution stays at
348
+ // Every caret-edge key goes through this one dispatch (G4.12); entering a widget stays in
347
349
  // `widgetInteraction.enterWidget`.
348
350
  const edgeDispatch = createEdgePolicyDispatch({
351
+ getLineEnding: documentEnding,
349
352
  get node() {
350
353
  return node;
351
354
  },
@@ -355,51 +358,45 @@
355
358
  get containerParent() {
356
359
  return blockNodeAt(getDoc(), myPath.slice(0, -1));
357
360
  },
358
- get linkRef() {
359
- return linkRef;
361
+ get reading() {
362
+ return reading;
360
363
  },
361
364
  getEl: () => el ?? null,
362
- getAmbientLength: () => ambientLength,
363
- getAmbientPrefix: () => ambientPrefixText,
365
+ storedAs,
364
366
  hasIslands: () =>
365
367
  decorationEngine ? decorationEngine.islandsForPath(myPath).length > 0 : false,
366
368
  getRawSelection: () => cursor.getRawSelection(),
367
369
  blockEdit,
368
370
  setPendingCursor: (offset, source) => setPendingCursorOffset(offset, source),
369
371
  setSnapTarget: (offset) => {
370
- lastSnapTargetOffset = offset;
372
+ armSnapTarget(offset);
371
373
  },
372
374
  isRevealing: () => widgetInteraction.isRevealing(),
373
375
  enterWidget: (widget, fromTrailingEdge) =>
374
376
  widgetInteraction.enterWidget(widget, fromTrailingEdge),
375
377
  isReading: () => readOnly,
376
- getEdgeAffinity: () => edgeAffinity.get(),
377
- noteOutside: edgeAffinity.noteExtreme,
378
- pendingMarks,
379
- installedAs: 'block'
378
+ getEdgeAffinity: caretMemory.side,
379
+ noteOutside: caretMemory.noteExtreme,
380
+ pendingMarks: caretMemory.pendingMarks,
381
+ ownPairs
380
382
  });
381
383
 
382
- // The same seat the keydown dispatch takes, for the one insertion a keydown cannot reach.
384
+ // The same placement rules the keydown dispatch uses, for the one insertion it cannot reach.
383
385
  const compositionSeat = createCompositionSeat({
384
386
  getDisplayText: () => getDisplayText(),
385
- getInlines: () => resolvedInlineContent(node, linkRef),
386
- getAffinity: () => edgeAffinity.get(),
387
+ getInlines: () => resolvedInlineContent(node, reading),
388
+ reading,
389
+ getAffinity: caretMemory.side,
387
390
  getScreen: () => screenVisibilityOf(el ?? null),
388
- consumePendingMarks: () => pendingMarks.consume(),
389
- restorePendingMarks: (marks) => pendingMarks.restore(marks),
391
+ consumePendingMarks: caretMemory.pendingMarks.consume,
392
+ restorePendingMarks: caretMemory.pendingMarks.restore,
390
393
  getRawSelection: () => cursor.getRawSelection(),
391
- // The same join seam `handleLiveSelectionEdit` takes, in the display bytes the seat's
392
- // contract returns (commitInput re-appends the trailing line ending).
394
+ // The in-leaf range replace `handleLiveSelectionEdit` uses, in the displayed bytes this
395
+ // returns (`commitInput` re-appends the trailing line ending).
393
396
  resolveRangeEdit: (range, typed) => {
394
- const edit = resolveSelectionEdit(
395
- node,
396
- range,
397
- typed,
398
- presentationMode,
399
- linkRef,
400
- ambientPrefixText
401
- );
402
- return edit && { raw: trimTrailingLineEnding(edit.raw), caret: edit.caret };
397
+ const edit = replaceRangeInLeaf(node, range, typed, storedAs());
398
+ if (edit.matchesBrowserEdit) return null;
399
+ return { raw: trimTrailingLineEnding(edit.raw), caret: edit.caret };
403
400
  }
404
401
  });
405
402
 
@@ -422,19 +419,11 @@
422
419
  get imageLoadPolicy() {
423
420
  return imageLoadPolicy();
424
421
  },
425
- get presentationMode() {
426
- return presentationMode;
427
- },
422
+ reading,
428
423
  getTheme,
429
424
  getDocument: () => getDoc(),
430
425
  getContentVersion,
431
426
  navigateTo: (path) => rects?.navigateTo(path) ?? Promise.resolve(false),
432
- get linkResolver(): LinkReferenceResolver | undefined {
433
- return linkRef?.current;
434
- },
435
- get linkStamp(): string {
436
- return String(linkRef?.epoch ?? 0);
437
- },
438
427
  get islands() {
439
428
  return decorationEngine ? decorationEngine.islandsForPath(myPath) : NO_ISLANDS;
440
429
  },
@@ -473,31 +462,29 @@
473
462
  widgetInteraction.snapClickToWidgetEdge(clientX, clientY);
474
463
  }
475
464
 
476
- /** The display length the CARET walks — the DOM's while a reveal is open, since the
477
- * CST hasn't seen that edit. Against a stale `node.raw`, an edited reveal at the
478
- * block's end traps the caret: no press reads as "at the boundary". */
479
- function liveDisplayLength(): number {
480
- return widgetInteraction.isRevealing() ? readRawText().length : getDisplayText().length;
465
+ /** The length the caret counts against: the DOM's while a source is shown, since the CST has
466
+ * not seen that edit. */
467
+ function caretReach(): number {
468
+ if (widgetInteraction.isRevealing()) return readRawText().length;
469
+ return getDisplayText().length;
481
470
  }
482
471
 
483
- /** The offsets a caret can reach here, from the one home the arrow exits already read: a mode
484
- * that paints no marker puts the block's own bytes out of reach, so every block-edge gate
485
- * moves in to what the DOM can land rather than testing 0 / length. */
472
+ /** The offsets a caret can reach here, as the arrow exits read them: a mode that draws no marker
473
+ * puts the block's own marker bytes out of reach, so 0 and the length are wrong there. */
486
474
  function caretBounds(): { start: number; end: number } {
487
- return el ? caretLandableBounds(sharedCtx, el) : { start: 0, end: liveDisplayLength() };
475
+ return el ? caretLandableBounds(sharedCtx, el) : { start: 0, end: caretReach() };
488
476
  }
489
477
 
490
- /** The structural bytes this press gives up before any merge — a declared kind's, in a mode
491
- * that paints none of them. Null everywhere else, and the cascade takes the press. */
478
+ /** The structural bytes this key gives up before any merge: a declared kind's, in a mode
479
+ * that draws none of them. Null everywhere else, and the merge below takes the key. */
492
480
  function demoteBeforeMerge(offset: number): TextEditResult | null {
493
481
  if (!el || !revealsNoMarkers(el)) return null;
494
482
  if (tryGetBlockKindDescriptor(node.kind)?.contentStartBackspace !== 'demote-first') return null;
495
483
  return demoteToParagraph(node.raw, getContentRange(node), offset);
496
484
  }
497
485
 
498
- /** One arm per command this block owns, split so the reveal fold sits between the
499
- * halves: `applies` reads only the DOM and survives a fold, `perform` reads `node.raw`
500
- * and is valid only after one. `offset`/`selected` are closed over: the fold moves them. */
486
+ /** Split so hiding a shown source fits between the halves: `applies` reads only the DOM, and
487
+ * `perform` reads `node.raw`, valid only after the source is hidden. */
501
488
  function blockCommand(
502
489
  id: CommandId,
503
490
  arg: unknown,
@@ -512,9 +499,20 @@
512
499
  return always(() => blockEdit.descendToBody(index));
513
500
  case 'block.hardBreak':
514
501
  return always(() => {
515
- const { newRaw, caretOffset } = insertHardBreak(node.raw, offset);
516
- blockEdit.updateBlockContent(index, newRaw, offset);
517
- setPendingCursorOffset(caretOffset, 'hard-break');
502
+ const { newRaw, caretOffset } = insertHardBreak(
503
+ node.raw,
504
+ offset,
505
+ documentEnding(),
506
+ getContentRange(node)
507
+ );
508
+ const write = blockEdit.updateBlockContent(
509
+ index,
510
+ newRaw,
511
+ 'authored',
512
+ offset,
513
+ caretOffset
514
+ );
515
+ if (write.admitted) setPendingCursorOffset(write.caret, 'hard-break');
518
516
  });
519
517
  case 'block.insertTab':
520
518
  return {
@@ -523,65 +521,78 @@
523
521
  // A literal tab, because the browser default moves focus out of the editor.
524
522
  perform: () => {
525
523
  const { newRaw, caretOffset } = insertLiteralTab(node.raw, offset);
526
- blockEdit.updateBlockContent(index, newRaw, offset);
527
- setPendingCursorOffset(caretOffset, 'insert-tab');
524
+ // The key types its own character, so its kind change is named as typing's is.
525
+ const before = shownKind(node);
526
+ const write = blockEdit.updateBlockContent(
527
+ index,
528
+ newRaw,
529
+ 'authored',
530
+ offset,
531
+ caretOffset
532
+ );
533
+ void kindCue.afterTypedWrite(write, myPath, before);
534
+ if (write.admitted) setPendingCursorOffset(write.caret, 'insert-tab');
528
535
  }
529
536
  };
530
537
  case 'block.mergePrev':
531
538
  return {
532
- // At-or-before, not equal: a caret door can still park on an offset the walk
533
- // canonicalizes forward, and a strict test would make the press a dead key there.
534
- applies: () => offset <= caretBounds().start && !hasSelectionHelper(),
539
+ // At or before, not equal: a caret can still be placed at an offset the DOM
540
+ // traversal moves forward, and a strict test would make the key do nothing.
541
+ applies: () => offset <= caretBounds().start && cursor.getRawSelection() === null,
535
542
  perform: () => {
536
543
  const demoted = demoteBeforeMerge(offset);
537
544
  if (!demoted) return void blockEdit.mergeWithPrevious(index);
538
- // A command is not typing: the demote is its own undo step, so one Ctrl+Z puts
539
- // the heading back whole rather than unwinding the burst around it.
540
- controller.isolateUndoEntry(() =>
541
- blockEdit.updateBlockContent(index, demoted.newRaw, offset, demoted.caretOffset)
545
+ const write = blockEdit.updateBlockContent(
546
+ index,
547
+ demoted.newRaw,
548
+ 'literal',
549
+ offset,
550
+ demoted.caretOffset
542
551
  );
543
- setPendingCursorOffset(demoted.caretOffset, 'demote');
552
+ if (write.admitted) setPendingCursorOffset(write.caret, 'demote');
544
553
  }
545
554
  };
546
555
  case 'block.mergeNext':
547
556
  return {
548
- // A block whose own structure sits AFTER its content cannot absorb the next one
549
- // without surfacing it (live-mode.md § 4.5). The keydown dispatch consumes that press; this is
550
- // the same rule for the callers that never pass through it.
551
- applies: () =>
552
- offset >= caretBounds().end &&
553
- !hasSelectionHelper() &&
554
- !hidesStructuralSuffix(el ?? null, node, liveDisplayLength()),
557
+ applies: () => offset >= caretBounds().end && cursor.getRawSelection() === null,
555
558
  perform: () => void blockEdit.mergeWithNext(index)
556
559
  };
557
560
  case 'link.openCard':
558
- // Consumed wherever the keymap binds it, entry or not: `reservedChords()` reports
559
- // Mod+K as the editor's, and handing an unentered press back fires the browser
560
- // default the host was told not to expect (Ctrl+K kills to end of line here).
561
+ // Consumed whether or not a card opens: `reservedChords()` reports Mod+K as the editor's,
562
+ // and the browser default (Ctrl+K kills a line) would surprise the host.
561
563
  return always(enterLinkCard);
562
564
  case 'heading.cycle':
563
565
  return {
564
- // A heading marks PROSE. The raw-editable kinds bind this keymap too, and there
566
+ // A heading marks prose. The raw-editable kinds bind this keymap too, and there
565
567
  // an ATX prefix is content: it would destroy a link reference definition.
566
568
  applies: () => isProseKind(node.kind),
567
569
  perform: () => {
568
- // `arg` is untrusted `unknown` from the widened keybinding channel: an
569
- // out-of-range value would throw a RangeError inside `repeat`, so fall
570
- // back to the strip behavior.
570
+ // `arg` comes untrusted from the keybinding channel, and an out-of-range level
571
+ // would throw inside `repeat`, so it falls back to stripping the heading.
571
572
  const level = typeof arg === 'number' && arg >= 0 && arg <= 6 ? arg : 0;
572
573
  const cycled = cycleHeading(node.raw, getContentRange(node), level, offset);
573
574
  if (!cycled) return;
574
- blockEdit.updateBlockContent(index, cycled.newRaw, offset, cycled.caretOffset);
575
- setPendingCursorOffset(cycled.caretOffset, 'heading-cycle');
575
+ // Text after a task box is the to-do's own text, so a written `# ` would stay
576
+ // text there; replacing the block makes the heading and gives the box up.
577
+ if (ambientHoldsTaskBox(ambientPrefix)) {
578
+ const heading = readBlocks(cycled.newRaw, { grammar, scope: 'fragment' }).children;
579
+ const focus = { replacementIndex: 0, offset: cycled.caretOffset };
580
+ void blockEdit.replaceBlock(index, heading, focus, { snapshotOffset: offset });
581
+ return;
582
+ }
583
+ const write = blockEdit.updateBlockContent(
584
+ index,
585
+ cycled.newRaw,
586
+ 'literal',
587
+ offset,
588
+ cycled.caretOffset
589
+ );
590
+ if (write.admitted) setPendingCursorOffset(write.caret, 'heading-cycle');
576
591
  }
577
592
  };
578
- case 'block.moveUp':
579
- case 'block.moveDown':
580
- // Through `always`, not a bare opener line: every perform here rides the reveal fold.
581
- return always(() => void reorderRunCommand(id, reorder, () => myPath));
582
593
  default: {
583
- // The format chords are rows, not arms: a construct that declares a mark names the
584
- // command that toggles it, so a new markable kind costs a row here and nothing else.
594
+ // The format chords come from the policy table: a construct that declares a mark names
595
+ // the command that toggles it, so a new markable kind needs no branch here.
585
596
  const marked = inlineMarkForCommand(id);
586
597
  return marked === null
587
598
  ? null
@@ -591,53 +602,53 @@
591
602
  }
592
603
 
593
604
  export function runCommand(id: CommandId, arg?: unknown): boolean {
594
- // Read live: cross-block dispatch arrives with no preceding onKeyDown, so
595
- // `preEditOffset` would be stale here.
605
+ // Read live: a command dispatched from another block arrives with no input event here.
596
606
  const offset = cursor.getRaw() ?? 0;
597
607
  const command = blockCommand(id, arg, offset, cursor.getRawSelection());
598
608
  if (!command || !command.applies()) return false;
599
- if (!widgetInteraction.isRevealing()) {
600
- performBlockCommand(id, command.perform);
601
- return true;
602
- }
603
- // A live reveal holds this block's bytes in ephemeral DOM, so every `perform` would
604
- // splice the pre-reveal source: fold, settle, then act. The fold is handed the user's
605
- // offset, valid because the committed text IS the DOM text it was measured against.
606
- const fold = widgetInteraction.foldRevealBeforeMutation(offset);
607
- void (fold?.settled ?? tick()).then(() => performBlockCommand(id, command.perform));
609
+ afterSourceCommit(() => performBlockCommand(id, command.perform), offset);
608
610
  return true;
609
611
  }
610
612
 
613
+ // A shown source holds this block's edit in the DOM only, so a command waits for it to be
614
+ // written; the user's offset stays valid, since the written text is the DOM text.
615
+ export function afterSourceCommit(run: () => void, offset = cursor.getRaw() ?? 0): void {
616
+ if (!widgetInteraction.isRevealing()) return run();
617
+ const fold = widgetInteraction.foldRevealBeforeMutation(offset);
618
+ void (fold?.settled ?? tick()).then(run);
619
+ }
620
+
611
621
  // A toolbar asks once per button on every selection change, so the buttons share the parse.
612
622
  const formatActive = createInlineFormatActiveMemo();
613
623
 
614
- // The pressed-state read: the same display, content and selection the toggle itself takes,
615
- // and for the card the same construct its own entry resolves.
624
+ // Whether a button shows as pressed: the same displayed text, content and selection the
625
+ // toggle itself uses, and for the card the same construct its own entry resolves.
616
626
  export function isCommandActive(id: CommandId): boolean {
617
627
  const marked = inlineMarkForCommand(id);
618
628
  if (!marked) {
619
- // Both surfaces spell the id, as their run arms do: a registry for one command is premature.
629
+ // The link card is the one pressed state no mark policy answers.
620
630
  if (id !== 'link.openCard' || !el) return false;
621
631
  return linkCardTargetAt(linkCardQuery(el, cursor.getRawSelection())) !== null;
622
632
  }
623
633
  const caret = cursor.getRaw() ?? 0;
624
634
  const selection = cursor.getRawSelection() ?? { start: caret, end: caret };
625
635
  return formatActive(
626
- { display: getDisplayText(), content: getContentRange(node), selection },
636
+ { display: getDisplayText(), content: getContentRange(node), selection, reading },
627
637
  marked.kind
628
638
  );
629
639
  }
630
640
 
631
- // No arm reached through here mutates while a reveal is open (G1.26): a fire means a
632
- // `runCommand` branch that skipped the fold. It guards the arms, not every entry path.
633
- // TODO(#35): funnel the fold at every mutation entry path, not just the command arms.
641
+ // A command never writes while a source is shown, so a failure means a `runCommand` branch
642
+ // skipped hiding it (G1.26). TODO: hide a shown source at the other entry paths that write.
634
643
  function performBlockCommand(id: CommandId, perform: () => void): void {
635
644
  assertInvariant('reveal-transition', () =>
636
645
  widgetInteraction.isRevealing()
637
646
  ? { code: 'command-during-reveal', message: `${id} mutated the block with a reveal open` }
638
647
  : null
639
648
  );
640
- perform();
649
+ // A command is not typing: its bytes are their own undo step, so one Ctrl+Z undoes the
650
+ // command alone rather than the burst of typing around it.
651
+ controller.isolateUndoEntry(perform);
641
652
  }
642
653
 
643
654
  void ({
@@ -652,7 +663,8 @@
652
663
  claimRootClipboard,
653
664
  insertMarkdown,
654
665
  snapCaretToPoint,
655
- runCommand
666
+ runCommand,
667
+ afterSourceCommit
656
668
  } satisfies BlockComponent);
657
669
 
658
670
  // ── Content sync ──────────────────────────────────────────────────────
@@ -670,8 +682,8 @@
670
682
  }
671
683
 
672
684
  const t0 = perfEnabled() ? performance.now() : 0;
673
- // With a pending restore armed, the consume below overwrites the selection, so the
674
- // render's own caret walk would be dead work.
685
+ // With a restore pending, the code below overwrites the selection, so the render's
686
+ // own caret capture would be wasted.
675
687
  textRender.render({
676
688
  forceRebuild: pendingCursorOffset !== null,
677
689
  carryCaret: pendingCursorOffset === null
@@ -679,18 +691,17 @@
679
691
  if (perfEnabled()) recordBlockRender(performance.now() - t0, myPath);
680
692
 
681
693
  if (pendingCursorOffset !== null) {
682
- // Only while this block still owns focus: a blur-commit also arms a pending
683
- // offset, and restoring would yank the selection back into the blurred block.
684
- // The clear runs regardless, so a skipped restore is dropped, never re-armed.
694
+ // Restored only while this block has focus: a commit on blur also sets a pending offset,
695
+ // and restoring it would pull the selection back. Cleared either way.
685
696
  const applied = consumePendingRestore(el ?? null, pendingCursorOffset, (offset) => {
686
- if (!widgetInteraction.revealInterior(offset)) cursor.setRaw(asRawOffset(offset));
697
+ if (!widgetInteraction.revealInterior(offset))
698
+ cursor.setRaw(asRawOffset(offset), { clamp: 'exact' });
687
699
  });
688
700
  tracePendingCursorConsume(pendingCursorOffset, applied);
689
701
  pendingCursorOffset = null;
690
702
  }
691
- // A rebuild mints fresh spans with no reveal class, so re-apply before paint or
692
- // typing inside a revealed construct folds for one frame per keystroke. Untracked,
693
- // because the caret chain must never join this effect's dependencies.
703
+ // A rebuild makes spans with no marker class, so the shown markers are re-applied before paint.
704
+ // Untracked, so the caret's reads never join this effect's dependencies.
694
705
  untrack(() => {
695
706
  if (!composing) constructReveal.update(true);
696
707
  });
@@ -699,30 +710,50 @@
699
710
 
700
711
  useParkFocusOnUnmount(() => el ?? null, getEditorRoot);
701
712
 
702
- // Asymmetric: clears only. The synthetic indicator is click-intent, armed nowhere but
703
- // `snapClickToWidgetEdge`, so a caret reaching a boundary by other means never sets it.
713
+ // Only clears: the snap target means "the click meant this", and only `snapClickToWidgetEdge`
714
+ // sets it.
704
715
  function clearSnapTargetIfMoved(root: HTMLElement): void {
705
716
  if (lastSnapTargetOffset === null) return;
706
717
  const sel = window.getSelection();
718
+ // With no range there is nothing to compare the snap target against, and this function only
719
+ // clears: the gestures that move the caret elsewhere clear it through their own handlers.
707
720
  if (!sel || sel.rangeCount === 0) return;
708
721
  const range = sel.getRangeAt(0);
709
722
  if (!root.contains(range.startContainer)) {
710
- lastSnapTargetOffset = null;
723
+ armSnapTarget(null);
711
724
  return;
712
725
  }
713
- const content = domTextOffsetAtNode(root, range.startContainer, range.startOffset);
714
- const off = toClampedRawOffset(content, ambientLength);
715
- if (off !== lastSnapTargetOffset) lastSnapTargetOffset = null;
726
+ const off = rawOffsetAt(root, range.startContainer, range.startOffset);
727
+ if (off !== lastSnapTargetOffset) armSnapTarget(null);
716
728
  }
717
729
 
718
- // One listener drives the block's whole selection cadence. The snap clearer runs even
719
- // during composition — an IME caret move still invalidates a click-intent snap — while
720
- // the reveal machines are composition-gated like onInput.
730
+ /** Whether the press left the browser's caret at an element-level offset in this block, the
731
+ * position Chromium paints at the line box's height rather than at the text's. */
732
+ function notePressSeat(root: HTMLElement): void {
733
+ if (!pressPending) return;
734
+ const sel = window.getSelection();
735
+ const seated =
736
+ !!sel &&
737
+ sel.isCollapsed &&
738
+ sel.rangeCount > 0 &&
739
+ root.contains(sel.getRangeAt(0).startContainer) &&
740
+ !caretIsInTextContent(root, sel);
741
+ if (seated !== pressSeatedBesideIsland) pressSeatedBesideIsland = seated;
742
+ }
743
+
744
+ function endPress(): void {
745
+ pressPending = false;
746
+ if (pressSeatedBesideIsland) pressSeatedBesideIsland = false;
747
+ }
748
+
749
+ // The snap target is cleared even during composition, since an IME caret move invalidates it;
750
+ // the source and marker updates skip composition as `onInput` does.
721
751
  $effect(() => {
722
752
  const root = el;
723
753
  if (!root) return;
724
754
  const handler = () => {
725
755
  clearSnapTargetIfMoved(root);
756
+ notePressSeat(root);
726
757
  if (composing) return;
727
758
  widgetInteraction.foldRevealIfSelectionEscaped();
728
759
  constructReveal.update();
@@ -733,46 +764,68 @@
733
764
 
734
765
  $effect(() => {
735
766
  if (!el) return;
767
+ // Read so that setting the offset already held still repaints and clears the other blocks.
768
+ void snapEpoch;
736
769
  for (const w of el.querySelectorAll('.md-snap-after, .md-snap-before')) {
737
770
  w.classList.remove('md-snap-after', 'md-snap-before');
738
771
  }
739
- // The synthetic caret stands in for one Chromium renders unreliably beside a
740
- // contenteditable=false island, and "unreliably" cuts both ways — nothing can ask
741
- // whether it painted, so darkening the native one is the only guarantee available.
772
+ // Chromium draws its caret unreliably beside a non-editable widget and nothing can ask
773
+ // whether it did, so the editor hides it and draws its own.
742
774
  el.classList.remove('md-snap-caret-active');
743
- if (lastSnapTargetOffset === null) return;
775
+ // Hidden from the press, not from the click, so a press beside a widget does not show the
776
+ // browser's caret first and the synthetic one after it.
777
+ if (pressSeatedBesideIsland) el.classList.add('md-snap-caret-active');
778
+ // A cross-block range owns the caret's position wherever its endpoints landed, so no block
779
+ // paints one of its own under it, however the range was entered.
780
+ if (lastSnapTargetOffset === null || selection.isCrossBlock) return;
744
781
  const off = lastSnapTargetOffset;
745
- for (const inline of resolvedInlineContent(node, linkRef)) {
746
- if (!isInlineWidget(inline, node.raw)) continue;
782
+ for (const inline of resolvedInlineContent(node, reading)) {
783
+ if (!isInlineWidget(inline, node.raw, grammar)) continue;
747
784
  if (inline.end !== off && inline.start !== off) continue;
748
785
  const widget = widgetElByStart(el, inline.start);
749
786
  if (widget) {
787
+ sweepOtherBlocksSnap();
750
788
  widget.classList.add(inline.end === off ? 'md-snap-after' : 'md-snap-before');
751
789
  el.classList.add('md-snap-caret-active');
790
+ // One caret is one position, so one widget in the document carries the paint (G1.39).
791
+ assertInvariant('snap-caret-unique', () => {
792
+ const root = getEditorRoot();
793
+ const painted = root?.querySelectorAll('.md-snap-after, .md-snap-before').length ?? 1;
794
+ return painted > 1
795
+ ? {
796
+ code: 'snap-caret-not-unique',
797
+ message: `${painted} synthetic carets painted at once; one caret is one position`
798
+ }
799
+ : null;
800
+ });
752
801
  }
753
802
  return;
754
803
  }
755
804
  });
756
805
 
806
+ /** A block painting its synthetic caret clears every other block's: one that unmounts with the
807
+ * caret inside never hears the change that clears its own. */
808
+ function sweepOtherBlocksSnap(): void {
809
+ const root = getEditorRoot();
810
+ if (!root || !el) return;
811
+ for (const stale of root.querySelectorAll('.md-snap-after, .md-snap-before')) {
812
+ if (!el.contains(stale)) stale.classList.remove('md-snap-after', 'md-snap-before');
813
+ }
814
+ for (const block of root.querySelectorAll('.md-snap-caret-active')) {
815
+ if (block !== el) block.classList.remove('md-snap-caret-active');
816
+ }
817
+ }
818
+
757
819
  // ── Event Handlers ──────────────────────────────────────────────────
758
820
 
759
821
  const onInput = editableSurface.onInput;
760
822
 
761
- // Walk children rather than reading textContent, so stray text nodes Chromium inserts
762
- // around the marker span don't pollute the raw.
763
823
  function readRawText(): string {
764
- if (!el) return '';
765
- const ambient = ambientLength > 0 ? ambientSpanOf(el) : null;
766
- let out = '';
767
- for (const child of Array.from(el.childNodes)) {
768
- if (child === ambient) continue;
769
- out += rawTextOfNode(child, node.raw);
770
- }
771
- return out;
824
+ return el ? rawTextOfContent(el, node.raw, structuralSuffix(node)) : '';
772
825
  }
773
826
 
774
- // Captured before the surface's own handler: its cross-block half clears the affinity, and
775
- // the first mid-composition `input` re-arms it to the typed side.
827
+ // Captured before the shared handler: its cross-block half clears the arrival side, and the
828
+ // first `input` during the composition resets that side to the typed one.
776
829
  function onCompositionStart(): void {
777
830
  compositionSeat.noteStart();
778
831
  editableSurface.onCompositionStart();
@@ -786,75 +839,72 @@
786
839
  async function onKeyDown(e: KeyboardEvent): Promise<void> {
787
840
  if (composing || editableSurface.isDetached()) return;
788
841
 
789
- preEditOffset = cursor.getRaw() ?? 0;
790
-
791
- // Reveal-only backstop, before any default runs: rapid arrows outrun the async
792
- // selectionchange reveal, and a step against folded markers skips their bytes.
842
+ // Shows markers only, before any default runs: fast arrows outrun the async
843
+ // `selectionchange` update, and a step against still-hidden markers skips their bytes.
793
844
  constructReveal.prepareForKeydown(e);
794
845
 
795
- // Escape cancels a revealed source back to rendered; every other key edits the
796
- // source natively or reaches the command seam below, which folds before mutating.
846
+ // Escape cancels a shown source back to its rendered form; every other key edits the
847
+ // source in the DOM or reaches the commands below, which hide it before writing.
797
848
  if ((await widgetInteraction.handleRevealingKeydown(e)) || editableSurface.isDetached()) return;
798
849
 
799
- // Before handleSharedKeydown: selecting cleared the native range, so the shared
800
- // ArrowLeft boundary branch would read offset 0 and move focus to a block that
801
- // isn't there.
850
+ // Before `handleSharedKeydown`: selecting cleared the browser range, so the shared
851
+ // ArrowLeft branch would read offset 0.
802
852
  if ((await widgetInteraction.handleSelectedWidgetKeydown(e)) || editableSurface.isDetached())
803
853
  return;
804
854
 
805
- // The native default, with user-select:none on the widget, collapses the selection
855
+ // The browser default, with `user-select: none` on the widget, collapses the selection
806
856
  // instead of stepping past it.
807
857
  if (widgetInteraction.handleShiftArrowIntoWidget(e)) return;
808
858
 
809
859
  if ((await handleSharedKeydown(e, sharedCtx)) || editableSurface.isDetached()) return;
810
860
 
811
- // Every caret-edge construct routes through this one dispatch, keeping native
812
- // contenteditable from corrupting the atomic bytes each stands for.
861
+ // Every caret-edge construct goes through this one dispatch, keeping contenteditable
862
+ // from corrupting the atomic bytes each stands for.
813
863
  if (edgeDispatch.handleKeydown(e, cursor.getRaw())) return;
814
864
 
815
- // Native Home lands at DOM 0, before the marker span — or past a leading island no text
816
- // node fronts; the user wants the block's start. Through the sentinel door,
817
- // not a raw-0 DOM write: the landable clamp applies.
865
+ // The browser's Home lands before the marker span or past a leading widget. `CURSOR_START`
866
+ // rather than offset 0, so the clamp still applies.
818
867
  if (
819
868
  e.key === 'Home' &&
820
869
  !e.shiftKey &&
821
870
  el &&
822
- (ambientLength > 0 || landableStartAbutsIsland(el))
871
+ (markerPrefixOf(el) !== null || landableStartAbutsIsland(el))
823
872
  ) {
824
873
  e.preventDefault();
825
874
  focus(CURSOR_START);
826
875
  return;
827
876
  }
828
877
 
829
- if (wiring.dispatchChord(e, { kind: node.kind, runCommand })) return;
878
+ const target = { kind: node.kind, runCommand, getPath: () => myPath, afterSourceCommit };
879
+ if (wiring.dispatchChord(e, target)) return;
830
880
  }
831
881
 
832
882
  const onKeyDownTraced = withKeydownVerdict(onKeyDown);
833
883
 
834
- /**
835
- * A native ranged edit inside ONE block, in a mode that paints no delimiter: the engine would
836
- * write the runs the range crossed literally, so the edit goes through the join seam instead.
837
- * Declines wherever that seam has nothing to clean, leaving the engine its grapheme and IME
838
- * behavior.
839
- */
884
+ /** A range edit in a mode that draws no delimiter goes through the join rules, since the browser
885
+ * would leave the crossed markers behind. Elsewhere the browser keeps its own edit. */
840
886
  function handleLiveSelectionEdit(e: InputEvent): boolean {
841
887
  return applyLiveRangeEdit(
842
888
  e,
843
889
  node,
844
890
  cursor,
845
- presentationMode,
846
- linkRef,
847
- ambientPrefixText,
891
+ storedAs(),
848
892
  widgetInteraction.isRevealing,
849
893
  (edit) => {
850
- void blockEdit.updateBlockContent(index, edit.raw, edit.range.start, edit.caret);
851
- setPendingCursorOffset(edit.caret, 'live-selection-edit');
894
+ const write = blockEdit.updateBlockContent(
895
+ index,
896
+ edit.raw,
897
+ 'authored',
898
+ edit.range.start,
899
+ edit.caret
900
+ );
901
+ if (write.admitted) setPendingCursorOffset(write.caret, 'live-selection-edit');
852
902
  }
853
903
  );
854
904
  }
855
905
 
856
- // The write takes the ranged edit's road above, so the surface repaints once with the caret
857
- // inside the pair. During a reveal the caret indexes the DOM text, which has outrun `node.raw`.
906
+ // The write takes the same path as the range edit above, so the block repaints once with the
907
+ // caret inside the pair. While a source is shown the caret counts into the DOM text instead.
858
908
  function handleDelimiterAutoPair(e: InputEvent): boolean {
859
909
  return applyDelimiterAutoPair(e, {
860
910
  text: () => (widgetInteraction.isRevealing() ? readRawText() : getDisplayText()),
@@ -863,15 +913,18 @@
863
913
  hasSelection: () => cursor.getRawSelection() !== null,
864
914
  isRevealing: widgetInteraction.isRevealing,
865
915
  foldReveal: () => widgetInteraction.foldRevealBeforeMutation(),
866
- markersPaint: () => paintsFocusedMarkers(presentationMode),
867
- setCaret: (offset) => cursor.setRaw(asRawOffset(offset)),
868
- seatOutside: edgeAffinity.noteExtreme,
869
- completesLine: (caret) => planTypedCompletion(node, caret) !== null,
870
- keepsBlockKind: (text) => keepsBlockKind(node, text),
916
+ setCaret: (offset) => cursor.setRaw(asRawOffset(offset), { clamp: 'exact' }),
917
+ seatOutside: caretMemory.noteExtreme,
918
+ completesLine: (caret) =>
919
+ planTypedCompletion(node, caret, grammar, documentEnding()) !== null,
920
+ // Each auto-pair caller asks this itself until the caret-edge key table gives it one caller.
921
+ keepsKind: (line) => keepsKindAt(node, line, storedAs()),
922
+ reading,
923
+ ownPairs,
871
924
  write: (text, caretBefore, caretAfter) => {
872
- const raw = text + trailingLineEnding(node.raw);
873
- void blockEdit.updateBlockContent(index, raw, caretBefore, caretAfter);
874
- setPendingCursorOffset(caretAfter, 'delimiter-autopair');
925
+ const raw = text + blockEnding();
926
+ const write = blockEdit.updateBlockContent(index, raw, 'authored', caretBefore, caretAfter);
927
+ if (write.admitted) setPendingCursorOffset(write.caret, 'delimiter-autopair');
875
928
  }
876
929
  });
877
930
  }
@@ -880,111 +933,140 @@
880
933
  if (await handleSharedBeforeInput(e, sharedCtx)) return;
881
934
  if (handleLiveSelectionEdit(e)) return;
882
935
  if (handleDelimiterAutoPair(e)) return;
883
- // Soft-keyboard/IME insertLineBreak slipped past onKeyDown — swallow; Shift+Enter there owns hard breaks.
936
+ // An `insertLineBreak` from a soft keyboard or IME got past `onKeyDown`: consume it, since
937
+ // Shift+Enter is what makes a hard break.
884
938
  if (e.inputType === 'insertLineBreak') {
885
939
  e.preventDefault();
886
940
  return;
887
941
  }
888
942
  }
889
943
 
890
- // A click past a widget drops the caret outside the contenteditable, with no text-node
891
- // anchor, so onClick snaps to the nearest widget edge from this point. Y is
892
- // load-bearing: a column-aligned click on another visual line must not reveal.
944
+ // `onClick` snaps from the press point to the nearest widget edge. Y is kept too: a click at
945
+ // the same column on another visual line must not open a source.
893
946
  let lastClickClientX: number | null = null;
894
947
  let lastClickClientY: number | null = null;
895
948
 
949
+ /** The browser starts no drag from a non-editable inline widget, so the editor paints the range
950
+ * itself from the widget's edge on the press's side. */
951
+ function islandPress(e: PointerEvent): { paintSameBlock: boolean; anchorOffset?: number } {
952
+ if (!el || e.button !== 0 || e.shiftKey) return { paintSameBlock: false };
953
+ const anchorOffset = widgetInteraction.islandDragAnchor(e.clientX, e.clientY);
954
+ if (anchorOffset === null) return { paintSameBlock: false };
955
+ return { paintSameBlock: true, anchorOffset };
956
+ }
957
+
896
958
  function onPointerDown(e: PointerEvent): void {
897
- if (crossBlock.handlePointerDown(e)) return;
959
+ if (crossBlock.handlePointerDown(e, islandPress(e))) return;
898
960
  lastClickClientX = e.clientX;
899
961
  lastClickClientY = e.clientY;
900
- lastSnapTargetOffset = null;
901
- // A press on a reveal-source widget is an owned gesture: suppressing the browser's
902
- // caret default leaves the reveal as the only selection writer until it places.
962
+ armSnapTarget(null);
963
+ // Only a primary press ends in a click; a context-menu press would keep the caret hidden.
964
+ pressPending = e.button === 0;
965
+ // Read now, not at the `selectionchange` that follows: that event can arrive after a frame
966
+ // has already painted the native caret. Level with a line, where a padding press lands.
967
+ const seat = pressPending && el ? caretSeatInElement(el, e.clientX, e.clientY) : null;
968
+ pressSeatedBesideIsland =
969
+ !!seat && !!el && el.contains(seat.node) && !seatIsInTextContent(el, seat.node);
970
+ // A click on a widget that can show its source is this editor's gesture: cancelling the
971
+ // browser's caret default leaves that code as the only writer of the selection.
903
972
  if (widgetInteraction.isPointOnRevealWidget(e.clientX, e.clientY)) e.preventDefault();
904
973
  }
905
974
 
906
975
  function onBlur(e: FocusEvent): void {
907
976
  if (el && e.relatedTarget && el.contains(e.relatedTarget as Node)) return;
908
- // Persist a revealed source edit before the caret is gone.
977
+ // Save an edit to a shown source before the caret is gone.
909
978
  widgetInteraction.commitRevealOnBlur();
910
- lastSnapTargetOffset = null;
979
+ armSnapTarget(null);
980
+ endPress();
911
981
  demoteEmptyHeadingOnBlur();
912
982
  }
913
983
 
914
984
  function demoteEmptyHeadingOnBlur(): void {
915
985
  if (readOnly || node.kind !== 'heading' || editableSurface.isDetached()) return;
916
986
  const demoted = demoteEmptyAtxHeading(node.raw, getContentRange(node));
917
- if (demoted) void blockEdit.updateBlockContent(index, demoted.newRaw, 0);
987
+ if (demoted) void blockEdit.updateBlockContent(index, demoted.newRaw, 'literal', 0);
918
988
  }
919
989
 
920
990
  function onClick(e: MouseEvent): void {
921
991
  // An inline widget's own handler runs first, and a jump it starts can unmount this
922
- // surface before the click reaches it; nothing below addresses a block that is gone.
992
+ // block before the click reaches it; nothing below applies to a block that is gone.
923
993
  if (!el) return;
924
994
  const x = lastClickClientX;
925
995
  const y = lastClickClientY;
926
996
  lastClickClientX = null;
927
997
  lastClickClientY = null;
928
- cursor.clampOutOfAmbient();
998
+ cursor.clampOutOfMarkerPrefix();
929
999
  widgetInteraction.snapClickToWidgetEdge(x, y, {
930
1000
  modified: e.ctrlKey || e.metaKey,
931
- clickCount: e.detail
1001
+ clickCount: e.detail,
1002
+ // A release that travelled ends a drag rather than a click: showing the source there
1003
+ // would unmount the widget the drag just painted a range across.
1004
+ moved:
1005
+ x !== null && y !== null && (Math.abs(e.clientX - x) > 3 || Math.abs(e.clientY - y) > 3)
932
1006
  });
1007
+ // The click has decided: from here the snap target hides the browser's caret, or nothing does.
1008
+ endPress();
933
1009
  }
934
1010
 
935
1011
  // ── Formatting shortcuts ────────────────────────────────────────────
936
1012
 
937
- // `range` is what the COMMAND read before it ran, and must not be re-read: a fold on
938
- // the way in parks a caret that collapses the live selection, so the chord would find
939
- // nothing to toggle. A collapsed range is the caret contract, not a bail.
1013
+ // `range` was read before the command ran and must not be read again: hiding a shown source
1014
+ // collapses the live selection.
940
1015
  function toggleFormat(format: InlineMarkKind, range: { start: number; end: number }): void {
941
1016
  if (!el) return;
942
1017
 
943
- // A surface painting no delimiter would hold the byte-pair strategy's abandoned `****` as
944
- // invisible garbage the user can see the effect of but not explain: pend the mark and let
945
- // the next insertion carry it instead (live-mode.md § 4.3). The preview rungs reveal the
946
- // block the caret is in, so they show the pair and take the byte path.
947
- if (!paintsFocusedMarkers(presentationMode) && range.start === range.end) {
1018
+ // Where the markers stay hidden, an empty `****` would be invisible bytes, so the mark waits
1019
+ // for the next insertion (`docs/design/live-mode.md` § 4.3).
1020
+ if (reading.hidesDelimitersAtCaret() && range.start === range.end) {
948
1021
  // The insertion that spends the mark starts its own undo entry, so it is never
949
- // folded into the burst the chord interrupted.
1022
+ // merged into the burst the chord interrupted.
950
1023
  controller.flushDebouncedCheckpoint();
951
- pendingMarks.toggle(format);
1024
+ caretMemory.pendingMarks.toggle(format);
952
1025
  return;
953
1026
  }
954
1027
 
955
1028
  const toggled = toggleInlineFormat(
956
- { display: getDisplayText(), content: getContentRange(node), selection: range },
957
- format,
958
- presentationMode
1029
+ {
1030
+ display: getDisplayText(),
1031
+ content: getContentRange(node),
1032
+ selection: range,
1033
+ reading
1034
+ },
1035
+ format
959
1036
  );
960
1037
  if (!toggled) return;
961
1038
  const { newDisplay, newSelStart, newSelEnd } = toggled;
962
1039
 
963
- // A command is not typing: the toggle's bytes are their own undo step in every mode.
964
- controller.isolateUndoEntry(() =>
965
- blockEdit.updateBlockContent(index, newDisplay + trailingLineEnding(node.raw), newSelStart)
1040
+ const write = blockEdit.updateBlockContent(
1041
+ index,
1042
+ newDisplay + blockEnding(),
1043
+ 'literal',
1044
+ range.start,
1045
+ newSelStart
966
1046
  );
1047
+ if (!write.admitted) return;
967
1048
 
968
1049
  tick().then(() => {
969
- setSelection(newSelStart, newSelEnd);
1050
+ setSelection(write.caret, write.storedOffset(newSelEnd));
970
1051
  });
971
1052
  }
972
1053
  </script>
973
1054
 
974
- <!-- Reading mode flips contenteditable off, killing the whole browser-edit-path class
975
- structurally. tabindex/role are independent, so focus and arrow traversal stay. -->
1055
+ <!-- Reading mode turns contenteditable off, ruling out every browser edit; tabindex keeps focus
1056
+ and arrow traversal. Both roles the spread sets are interactive, which the compiler cannot see. -->
1057
+ <!-- svelte-ignore a11y_no_noninteractive_tabindex -->
976
1058
  <div
977
1059
  bind:this={el}
978
1060
  tabindex="0"
979
1061
  class="text-editable-block {blockClass}"
980
1062
  contenteditable={readOnly ? 'false' : 'true'}
981
1063
  aria-readonly={readOnly ? 'true' : undefined}
982
- role="textbox"
983
- style:text-indent={ambientPrefixText ? `-${ambientIndent}` : null}
1064
+ {...editableSurfaceAttributes(node, combobox)}
1065
+ style:text-indent={ambientPrefixText ? `calc(-1 * ${ambientIndent})` : null}
984
1066
  style:padding-left={ambientPrefixText ? ambientIndent : null}
985
1067
  oninput={onInput}
986
1068
  onkeydown={onKeyDownTraced}
987
- onbeforeinput={onBeforeInput}
1069
+ onbeforeinput={editableSurface.onBeforeInput}
988
1070
  oncopy={clipboardHandlers.onCopy}
989
1071
  oncut={clipboardHandlers.onCut}
990
1072
  onpaste={clipboardHandlers.onPaste}