@dxos/ui-editor 0.9.1-staging.ee54ba693a → 0.11.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (551) hide show
  1. package/dist/lib/chunk-diff.mjs +935 -0
  2. package/dist/lib/chunk-diff.mjs.map +1 -0
  3. package/dist/lib/headless.mjs +2 -0
  4. package/dist/lib/index.mjs +9937 -0
  5. package/dist/lib/index.mjs.map +1 -0
  6. package/dist/lib/types.mjs +18 -0
  7. package/dist/lib/types.mjs.map +1 -0
  8. package/dist/types/src/extensions/{bookmarks.d.ts → behavior/bookmarks.d.ts} +3 -0
  9. package/dist/types/src/extensions/behavior/bookmarks.d.ts.map +1 -0
  10. package/dist/types/src/extensions/behavior/dnd.d.ts.map +1 -0
  11. package/dist/types/src/extensions/behavior/index.d.ts +6 -0
  12. package/dist/types/src/extensions/behavior/index.d.ts.map +1 -0
  13. package/dist/types/src/extensions/{listener.d.ts → behavior/listener.d.ts} +3 -0
  14. package/dist/types/src/extensions/behavior/listener.d.ts.map +1 -0
  15. package/dist/types/src/extensions/{spacing.d.ts → behavior/spacing.d.ts} +3 -0
  16. package/dist/types/src/extensions/behavior/spacing.d.ts.map +1 -0
  17. package/dist/types/src/extensions/behavior/submit.d.ts.map +1 -0
  18. package/dist/types/src/extensions/collab/automerge/automerge.d.ts.map +1 -0
  19. package/dist/types/src/extensions/collab/automerge/automerge.test.d.ts.map +1 -0
  20. package/dist/types/src/extensions/{automerge → collab/automerge}/cursor.d.ts +1 -1
  21. package/dist/types/src/extensions/collab/automerge/cursor.d.ts.map +1 -0
  22. package/dist/types/src/extensions/{automerge → collab/automerge}/defs.d.ts +3 -1
  23. package/dist/types/src/extensions/collab/automerge/defs.d.ts.map +1 -0
  24. package/dist/types/src/extensions/collab/automerge/index.d.ts +3 -0
  25. package/dist/types/src/extensions/collab/automerge/index.d.ts.map +1 -0
  26. package/dist/types/src/extensions/collab/automerge/sync.d.ts.map +1 -0
  27. package/dist/types/src/extensions/{automerge → collab/automerge}/update-automerge.d.ts +4 -0
  28. package/dist/types/src/extensions/collab/automerge/update-automerge.d.ts.map +1 -0
  29. package/dist/types/src/extensions/{automerge → collab/automerge}/update-codemirror.d.ts +4 -0
  30. package/dist/types/src/extensions/collab/automerge/update-codemirror.d.ts.map +1 -0
  31. package/dist/types/src/extensions/collab/awareness/awareness-provider.d.ts.map +1 -0
  32. package/dist/types/src/extensions/{awareness → collab/awareness}/awareness.d.ts +4 -1
  33. package/dist/types/src/extensions/collab/awareness/awareness.d.ts.map +1 -0
  34. package/dist/types/src/extensions/collab/awareness/index.d.ts.map +1 -0
  35. package/dist/types/src/extensions/collab/index.d.ts +3 -0
  36. package/dist/types/src/extensions/collab/index.d.ts.map +1 -0
  37. package/dist/types/src/extensions/completion/autocomplete.d.ts.map +1 -0
  38. package/dist/types/src/extensions/{autocomplete → completion}/index.d.ts +1 -0
  39. package/dist/types/src/extensions/completion/index.d.ts.map +1 -0
  40. package/dist/types/src/extensions/{autocomplete → completion}/match.d.ts +2 -2
  41. package/dist/types/src/extensions/completion/match.d.ts.map +1 -0
  42. package/dist/types/src/extensions/{mention.d.ts → completion/mention.d.ts} +3 -0
  43. package/dist/types/src/extensions/completion/mention.d.ts.map +1 -0
  44. package/dist/types/src/extensions/completion/placeholder.d.ts.map +1 -0
  45. package/dist/types/src/extensions/{autocomplete → completion}/typeahead.d.ts +2 -2
  46. package/dist/types/src/extensions/completion/typeahead.d.ts.map +1 -0
  47. package/dist/types/src/extensions/{factories.d.ts → core/factories.d.ts} +23 -2
  48. package/dist/types/src/extensions/core/factories.d.ts.map +1 -0
  49. package/dist/types/src/extensions/core/factories.test.d.ts.map +1 -0
  50. package/dist/types/src/extensions/core/index.d.ts +3 -0
  51. package/dist/types/src/extensions/core/index.d.ts.map +1 -0
  52. package/dist/types/src/extensions/{modes.d.ts → core/modes.d.ts} +3 -0
  53. package/dist/types/src/extensions/core/modes.d.ts.map +1 -0
  54. package/dist/types/src/extensions/{debug.d.ts → debug/debug.d.ts} +3 -0
  55. package/dist/types/src/extensions/debug/debug.d.ts.map +1 -0
  56. package/dist/types/src/extensions/debug/index.d.ts +2 -0
  57. package/dist/types/src/extensions/debug/index.d.ts.map +1 -0
  58. package/dist/types/src/extensions/{annotations.d.ts → decoration/annotations.d.ts} +1 -1
  59. package/dist/types/src/extensions/decoration/annotations.d.ts.map +1 -0
  60. package/dist/types/src/extensions/decoration/assistant.d.ts +27 -0
  61. package/dist/types/src/extensions/decoration/assistant.d.ts.map +1 -0
  62. package/dist/types/src/extensions/decoration/fader.d.ts.map +1 -0
  63. package/dist/types/src/extensions/decoration/hashtag.d.ts +6 -0
  64. package/dist/types/src/extensions/decoration/hashtag.d.ts.map +1 -0
  65. package/dist/types/src/extensions/decoration/index.d.ts +8 -0
  66. package/dist/types/src/extensions/decoration/index.d.ts.map +1 -0
  67. package/dist/types/src/extensions/decoration/marker.d.ts.map +1 -0
  68. package/dist/types/src/extensions/{pos.d.ts → decoration/pos.d.ts} +40 -14
  69. package/dist/types/src/extensions/decoration/pos.d.ts.map +1 -0
  70. package/dist/types/src/extensions/decoration/pos.test.d.ts.map +1 -0
  71. package/dist/types/src/extensions/{replacer.d.ts → decoration/replacer.d.ts} +8 -8
  72. package/dist/types/src/extensions/decoration/replacer.d.ts.map +1 -0
  73. package/dist/types/src/extensions/decoration/replacer.test.d.ts.map +1 -0
  74. package/dist/types/src/extensions/{blast.d.ts → demo/blast.d.ts} +3 -0
  75. package/dist/types/src/extensions/demo/blast.d.ts.map +1 -0
  76. package/dist/types/src/extensions/demo/index.d.ts +3 -0
  77. package/dist/types/src/extensions/demo/index.d.ts.map +1 -0
  78. package/dist/types/src/extensions/demo/snippets.d.ts.map +1 -0
  79. package/dist/types/src/extensions/index.d.ts +10 -33
  80. package/dist/types/src/extensions/index.d.ts.map +1 -1
  81. package/dist/types/src/extensions/language/index.d.ts +5 -0
  82. package/dist/types/src/extensions/language/index.d.ts.map +1 -0
  83. package/dist/types/src/extensions/language/json/index.d.ts +2 -0
  84. package/dist/types/src/extensions/language/json/index.d.ts.map +1 -0
  85. package/dist/types/src/extensions/language/json/json.d.ts +12 -0
  86. package/dist/types/src/extensions/language/json/json.d.ts.map +1 -0
  87. package/dist/types/src/extensions/language/markdown/action.d.ts.map +1 -0
  88. package/dist/types/src/extensions/language/markdown/bundle.d.ts.map +1 -0
  89. package/dist/types/src/extensions/{markdown → language/markdown}/changes.d.ts +1 -1
  90. package/dist/types/src/extensions/language/markdown/changes.d.ts.map +1 -0
  91. package/dist/types/src/extensions/language/markdown/changes.test.d.ts.map +1 -0
  92. package/dist/types/src/extensions/{markdown → language/markdown}/debug.d.ts +3 -0
  93. package/dist/types/src/extensions/language/markdown/debug.d.ts.map +1 -0
  94. package/dist/types/src/extensions/{markdown → language/markdown}/decorate.d.ts +5 -1
  95. package/dist/types/src/extensions/language/markdown/decorate.d.ts.map +1 -0
  96. package/dist/types/src/extensions/{markdown → language/markdown}/formatting.d.ts +11 -2
  97. package/dist/types/src/extensions/language/markdown/formatting.d.ts.map +1 -0
  98. package/dist/types/src/extensions/language/markdown/formatting.test.d.ts.map +1 -0
  99. package/dist/types/src/extensions/{markdown → language/markdown}/highlight.d.ts +16 -12
  100. package/dist/types/src/extensions/language/markdown/highlight.d.ts.map +1 -0
  101. package/dist/types/src/extensions/language/markdown/image.d.ts.map +1 -0
  102. package/dist/types/src/extensions/language/markdown/image.test.d.ts.map +1 -0
  103. package/dist/types/src/extensions/language/markdown/index.d.ts.map +1 -0
  104. package/dist/types/src/extensions/language/markdown/link.d.ts +25 -0
  105. package/dist/types/src/extensions/language/markdown/link.d.ts.map +1 -0
  106. package/dist/types/src/extensions/language/markdown/link.test.d.ts +2 -0
  107. package/dist/types/src/extensions/language/markdown/link.test.d.ts.map +1 -0
  108. package/dist/types/src/extensions/language/markdown/parser.test.d.ts.map +1 -0
  109. package/dist/types/src/extensions/{markdown → language/markdown}/styles.d.ts +3 -0
  110. package/dist/types/src/extensions/language/markdown/styles.d.ts.map +1 -0
  111. package/dist/types/src/extensions/language/markdown/table.d.ts.map +1 -0
  112. package/dist/types/src/extensions/language/mermaid/index.d.ts +2 -0
  113. package/dist/types/src/extensions/language/mermaid/index.d.ts.map +1 -0
  114. package/dist/types/src/extensions/language/mermaid/mermaid.d.ts +18 -0
  115. package/dist/types/src/extensions/language/mermaid/mermaid.d.ts.map +1 -0
  116. package/dist/types/src/extensions/language/xml/extended-markdown.d.ts.map +1 -0
  117. package/dist/types/src/extensions/language/xml/extended-markdown.test.d.ts.map +1 -0
  118. package/dist/types/src/extensions/language/xml/index.d.ts.map +1 -0
  119. package/dist/types/src/extensions/language/xml/stub.d.ts +76 -0
  120. package/dist/types/src/extensions/language/xml/stub.d.ts.map +1 -0
  121. package/dist/types/src/extensions/language/xml/widgets/anchor.d.ts.map +1 -0
  122. package/dist/types/src/extensions/language/xml/widgets/index.d.ts.map +1 -0
  123. package/dist/types/src/extensions/language/xml/xml-block-decoration.d.ts +48 -0
  124. package/dist/types/src/extensions/language/xml/xml-block-decoration.d.ts.map +1 -0
  125. package/dist/types/src/extensions/language/xml/xml-formatting.d.ts.map +1 -0
  126. package/dist/types/src/extensions/{tags → language/xml}/xml-tags.d.ts +12 -1
  127. package/dist/types/src/extensions/language/xml/xml-tags.d.ts.map +1 -0
  128. package/dist/types/src/extensions/language/xml/xml-tags.test.d.ts +2 -0
  129. package/dist/types/src/extensions/language/xml/xml-tags.test.d.ts.map +1 -0
  130. package/dist/types/src/extensions/language/xml/xml-util.d.ts.map +1 -0
  131. package/dist/types/src/extensions/language/xml/xml-util.test.d.ts.map +1 -0
  132. package/dist/types/src/extensions/review/change-bar.d.ts +29 -0
  133. package/dist/types/src/extensions/review/change-bar.d.ts.map +1 -0
  134. package/dist/types/src/extensions/{comments.d.ts → review/comments.d.ts} +56 -38
  135. package/dist/types/src/extensions/review/comments.d.ts.map +1 -0
  136. package/dist/types/src/extensions/review/comments.test.d.ts +2 -0
  137. package/dist/types/src/extensions/review/comments.test.d.ts.map +1 -0
  138. package/dist/types/src/extensions/review/diff.d.ts +131 -0
  139. package/dist/types/src/extensions/review/diff.d.ts.map +1 -0
  140. package/dist/types/src/extensions/review/diff.test.d.ts +2 -0
  141. package/dist/types/src/extensions/review/diff.test.d.ts.map +1 -0
  142. package/dist/types/src/extensions/review/index.d.ts +7 -0
  143. package/dist/types/src/extensions/review/index.d.ts.map +1 -0
  144. package/dist/types/src/extensions/review/suggest.d.ts +89 -0
  145. package/dist/types/src/extensions/review/suggest.d.ts.map +1 -0
  146. package/dist/types/src/extensions/review/suggest.test.d.ts +2 -0
  147. package/dist/types/src/extensions/review/suggest.test.d.ts.map +1 -0
  148. package/dist/types/src/extensions/review/suggestions-overlay.d.ts +25 -0
  149. package/dist/types/src/extensions/review/suggestions-overlay.d.ts.map +1 -0
  150. package/dist/types/src/extensions/review/suggestions-overlay.test.d.ts +2 -0
  151. package/dist/types/src/extensions/review/suggestions-overlay.test.d.ts.map +1 -0
  152. package/dist/types/src/extensions/review/track-changes.d.ts +27 -0
  153. package/dist/types/src/extensions/review/track-changes.d.ts.map +1 -0
  154. package/dist/types/src/extensions/review/track-changes.test.d.ts +2 -0
  155. package/dist/types/src/extensions/review/track-changes.test.d.ts.map +1 -0
  156. package/dist/types/src/extensions/{busy.d.ts → state/busy.d.ts} +1 -0
  157. package/dist/types/src/extensions/state/busy.d.ts.map +1 -0
  158. package/dist/types/src/extensions/{focus.d.ts → state/focus.d.ts} +4 -0
  159. package/dist/types/src/extensions/state/focus.d.ts.map +1 -0
  160. package/dist/types/src/extensions/state/index.d.ts +5 -0
  161. package/dist/types/src/extensions/state/index.d.ts.map +1 -0
  162. package/dist/types/src/extensions/state/modal.d.ts.map +1 -0
  163. package/dist/types/src/extensions/{selection.d.ts → state/selection.d.ts} +1 -1
  164. package/dist/types/src/extensions/state/selection.d.ts.map +1 -0
  165. package/dist/types/src/extensions/state/selection.test.d.ts.map +1 -0
  166. package/dist/types/src/extensions/streaming/index.d.ts +4 -0
  167. package/dist/types/src/extensions/streaming/index.d.ts.map +1 -0
  168. package/dist/types/src/extensions/streaming/pending/index.d.ts.map +1 -0
  169. package/dist/types/src/extensions/streaming/pending/pending-text-stream.d.ts.map +1 -0
  170. package/dist/types/src/extensions/streaming/pending/pending-text-stream.test.d.ts.map +1 -0
  171. package/dist/types/src/extensions/{pending → streaming/pending}/pending-text.d.ts +1 -0
  172. package/dist/types/src/extensions/streaming/pending/pending-text.d.ts.map +1 -0
  173. package/dist/types/src/extensions/streaming/pending/pending-text.test.d.ts.map +1 -0
  174. package/dist/types/src/extensions/streaming/scrolling/auto-scroll.d.ts.map +1 -0
  175. package/dist/types/src/extensions/streaming/scrolling/crawler.d.ts.map +1 -0
  176. package/dist/types/src/extensions/streaming/scrolling/index.d.ts.map +1 -0
  177. package/dist/types/src/extensions/streaming/scrolling/scroll-past-end.d.ts +4 -0
  178. package/dist/types/src/extensions/streaming/scrolling/scroll-past-end.d.ts.map +1 -0
  179. package/dist/types/src/extensions/streaming/scrolling/scrollbar-autohide.d.ts.map +1 -0
  180. package/dist/types/src/extensions/streaming/scrolling/scroller.d.ts.map +1 -0
  181. package/dist/types/src/extensions/{typewriter.d.ts → streaming/typewriter.d.ts} +12 -12
  182. package/dist/types/src/extensions/streaming/typewriter.d.ts.map +1 -0
  183. package/dist/types/src/extensions/streaming/typewriter.test.d.ts.map +1 -0
  184. package/dist/types/src/extensions/structure/blocks/blocks.d.ts +52 -0
  185. package/dist/types/src/extensions/structure/blocks/blocks.d.ts.map +1 -0
  186. package/dist/types/src/extensions/structure/blocks/blocks.test.d.ts +2 -0
  187. package/dist/types/src/extensions/structure/blocks/blocks.test.d.ts.map +1 -0
  188. package/dist/types/src/extensions/structure/blocks/drag.d.ts +57 -0
  189. package/dist/types/src/extensions/structure/blocks/drag.d.ts.map +1 -0
  190. package/dist/types/src/extensions/structure/blocks/index.d.ts +5 -0
  191. package/dist/types/src/extensions/structure/blocks/index.d.ts.map +1 -0
  192. package/dist/types/src/extensions/structure/blocks/selection.d.ts +47 -0
  193. package/dist/types/src/extensions/structure/blocks/selection.d.ts.map +1 -0
  194. package/dist/types/src/extensions/structure/blocks/selection.test.d.ts +2 -0
  195. package/dist/types/src/extensions/structure/blocks/selection.test.d.ts.map +1 -0
  196. package/dist/types/src/extensions/structure/blocks/types.d.ts +17 -0
  197. package/dist/types/src/extensions/structure/blocks/types.d.ts.map +1 -0
  198. package/dist/types/src/extensions/structure/folding/folding.d.ts.map +1 -0
  199. package/dist/types/src/extensions/structure/folding/index.d.ts +3 -0
  200. package/dist/types/src/extensions/structure/folding/index.d.ts.map +1 -0
  201. package/dist/types/src/extensions/structure/folding/turns.d.ts +55 -0
  202. package/dist/types/src/extensions/structure/folding/turns.d.ts.map +1 -0
  203. package/dist/types/src/extensions/structure/folding/turns.test.d.ts +2 -0
  204. package/dist/types/src/extensions/structure/folding/turns.test.d.ts.map +1 -0
  205. package/dist/types/src/extensions/structure/index.d.ts +4 -0
  206. package/dist/types/src/extensions/structure/index.d.ts.map +1 -0
  207. package/dist/types/src/extensions/structure/outliner/commands.d.ts +31 -0
  208. package/dist/types/src/extensions/structure/outliner/commands.d.ts.map +1 -0
  209. package/dist/types/src/extensions/structure/outliner/dnd.d.ts +43 -0
  210. package/dist/types/src/extensions/structure/outliner/dnd.d.ts.map +1 -0
  211. package/dist/types/src/extensions/structure/outliner/dnd.test.d.ts +2 -0
  212. package/dist/types/src/extensions/structure/outliner/dnd.test.d.ts.map +1 -0
  213. package/dist/types/src/extensions/structure/outliner/editor.d.ts.map +1 -0
  214. package/dist/types/src/extensions/structure/outliner/editor.test.d.ts.map +1 -0
  215. package/dist/types/src/extensions/{outliner → structure/outliner}/index.d.ts +1 -0
  216. package/dist/types/src/extensions/structure/outliner/index.d.ts.map +1 -0
  217. package/dist/types/src/extensions/{outliner → structure/outliner}/menu.d.ts +1 -0
  218. package/dist/types/src/extensions/structure/outliner/menu.d.ts.map +1 -0
  219. package/dist/types/src/extensions/structure/outliner/outliner.d.ts.map +1 -0
  220. package/dist/types/src/extensions/structure/outliner/outliner.test.d.ts.map +1 -0
  221. package/dist/types/src/extensions/{outliner → structure/outliner}/tree.d.ts +1 -1
  222. package/dist/types/src/extensions/structure/outliner/tree.d.ts.map +1 -0
  223. package/dist/types/src/extensions/structure/outliner/tree.test.d.ts.map +1 -0
  224. package/dist/types/src/headless.d.ts +4 -0
  225. package/dist/types/src/headless.d.ts.map +1 -0
  226. package/dist/types/src/styles/theme.d.ts +1 -1
  227. package/dist/types/src/styles/theme.d.ts.map +1 -1
  228. package/dist/types/src/util/util.d.ts +2 -0
  229. package/dist/types/src/util/util.d.ts.map +1 -1
  230. package/dist/types/tsconfig.tsbuildinfo +1 -1
  231. package/package.json +48 -42
  232. package/src/defaults.ts +1 -1
  233. package/src/extensions/{bookmarks.ts → behavior/bookmarks.ts} +24 -14
  234. package/src/extensions/behavior/index.ts +9 -0
  235. package/src/extensions/{listener.ts → behavior/listener.ts} +4 -1
  236. package/src/extensions/{spacing.ts → behavior/spacing.ts} +8 -2
  237. package/src/extensions/{submit.ts → behavior/submit.ts} +2 -10
  238. package/src/extensions/{automerge → collab/automerge}/automerge.test.tsx +4 -4
  239. package/src/extensions/{automerge → collab/automerge}/automerge.ts +7 -4
  240. package/src/extensions/{automerge → collab/automerge}/cursor.ts +1 -1
  241. package/src/extensions/{automerge → collab/automerge}/defs.ts +4 -1
  242. package/src/extensions/{automerge → collab/automerge}/index.ts +1 -0
  243. package/src/extensions/{automerge → collab/automerge}/sync.ts +1 -2
  244. package/src/extensions/{automerge → collab/automerge}/update-automerge.ts +4 -0
  245. package/src/extensions/{automerge → collab/automerge}/update-codemirror.ts +5 -1
  246. package/src/extensions/{awareness → collab/awareness}/awareness-provider.ts +3 -4
  247. package/src/extensions/{awareness → collab/awareness}/awareness.ts +19 -16
  248. package/src/extensions/collab/index.ts +6 -0
  249. package/src/extensions/{autocomplete → completion}/autocomplete.ts +7 -5
  250. package/src/extensions/{autocomplete → completion}/index.ts +2 -1
  251. package/src/extensions/{autocomplete → completion}/match.ts +2 -2
  252. package/src/extensions/{mention.ts → completion/mention.ts} +3 -0
  253. package/src/extensions/{autocomplete → completion}/placeholder.ts +1 -1
  254. package/src/extensions/completion/typeahead.ts +97 -0
  255. package/src/extensions/{factories.ts → core/factories.ts} +35 -13
  256. package/src/extensions/core/index.ts +6 -0
  257. package/src/extensions/{modes.ts → core/modes.ts} +4 -1
  258. package/src/extensions/{debug.ts → debug/debug.ts} +3 -0
  259. package/src/extensions/debug/index.ts +5 -0
  260. package/src/extensions/{annotations.ts → decoration/annotations.ts} +12 -10
  261. package/src/extensions/decoration/assistant.ts +225 -0
  262. package/src/extensions/{fader.ts → decoration/fader.ts} +17 -19
  263. package/src/extensions/{hashtag.ts → decoration/hashtag.ts} +35 -28
  264. package/src/extensions/decoration/index.ts +11 -0
  265. package/src/extensions/{marker.ts → decoration/marker.ts} +18 -18
  266. package/src/extensions/{pos.test.ts → decoration/pos.test.ts} +57 -1
  267. package/src/extensions/{pos.ts → decoration/pos.ts} +165 -31
  268. package/src/extensions/{blast.ts → demo/blast.ts} +3 -0
  269. package/src/extensions/demo/index.ts +6 -0
  270. package/src/extensions/{snippets.ts → demo/snippets.ts} +5 -1
  271. package/src/extensions/index.ts +10 -33
  272. package/src/extensions/language/index.ts +8 -0
  273. package/src/extensions/language/json/index.ts +5 -0
  274. package/src/extensions/{json.ts → language/json/json.ts} +11 -6
  275. package/src/extensions/{markdown → language/markdown}/action.ts +1 -1
  276. package/src/extensions/{markdown → language/markdown}/bundle.ts +7 -1
  277. package/src/extensions/{markdown → language/markdown}/changes.test.ts +2 -2
  278. package/src/extensions/{markdown → language/markdown}/changes.ts +2 -2
  279. package/src/extensions/{markdown → language/markdown}/debug.ts +3 -0
  280. package/src/extensions/{markdown → language/markdown}/decorate.ts +96 -85
  281. package/src/extensions/{markdown → language/markdown}/formatting.test.ts +88 -1
  282. package/src/extensions/{markdown → language/markdown}/formatting.ts +193 -74
  283. package/src/extensions/{markdown → language/markdown}/highlight.ts +42 -41
  284. package/src/extensions/{markdown → language/markdown}/image.test.ts +1 -1
  285. package/src/extensions/{markdown → language/markdown}/image.ts +6 -6
  286. package/src/extensions/language/markdown/link.test.ts +58 -0
  287. package/src/extensions/language/markdown/link.ts +109 -0
  288. package/src/extensions/{markdown → language/markdown}/parser.test.ts +0 -28
  289. package/src/extensions/{markdown → language/markdown}/styles.ts +38 -7
  290. package/src/extensions/{markdown → language/markdown}/table.ts +5 -5
  291. package/src/extensions/language/mermaid/index.ts +5 -0
  292. package/src/extensions/language/mermaid/mermaid.ts +44 -0
  293. package/src/extensions/{tags → language/xml}/DESIGN.md +3 -3
  294. package/src/extensions/{tags → language/xml}/extended-markdown.test.ts +2 -1
  295. package/src/extensions/{tags → language/xml}/extended-markdown.ts +2 -4
  296. package/src/extensions/language/xml/stub.ts +233 -0
  297. package/src/extensions/language/xml/xml-block-decoration.ts +165 -0
  298. package/src/extensions/{tags → language/xml}/xml-formatting.ts +54 -38
  299. package/src/extensions/language/xml/xml-tags.test.ts +588 -0
  300. package/src/extensions/{tags → language/xml}/xml-tags.ts +165 -66
  301. package/src/extensions/{tags → language/xml}/xml-util.test.ts +2 -2
  302. package/src/extensions/review/change-bar.ts +94 -0
  303. package/src/extensions/review/comments.test.ts +72 -0
  304. package/src/extensions/{comments.ts → review/comments.ts} +395 -267
  305. package/src/extensions/review/diff.test.ts +405 -0
  306. package/src/extensions/review/diff.ts +502 -0
  307. package/src/extensions/review/index.ts +10 -0
  308. package/src/extensions/review/suggest.test.ts +170 -0
  309. package/src/extensions/review/suggest.ts +512 -0
  310. package/src/extensions/review/suggestions-overlay.test.ts +58 -0
  311. package/src/extensions/review/suggestions-overlay.ts +50 -0
  312. package/src/extensions/review/track-changes.test.ts +101 -0
  313. package/src/extensions/review/track-changes.ts +215 -0
  314. package/src/extensions/{busy.ts → state/busy.ts} +1 -0
  315. package/src/extensions/{focus.ts → state/focus.ts} +4 -0
  316. package/src/extensions/state/index.ts +8 -0
  317. package/src/extensions/{selection.ts → state/selection.ts} +3 -3
  318. package/src/extensions/streaming/index.ts +7 -0
  319. package/src/extensions/{pending → streaming/pending}/pending-text-stream.ts +10 -3
  320. package/src/extensions/{pending → streaming/pending}/pending-text.test.ts +1 -1
  321. package/src/extensions/{pending → streaming/pending}/pending-text.ts +20 -19
  322. package/src/extensions/{scrolling → streaming/scrolling}/auto-scroll.ts +9 -6
  323. package/src/extensions/{scrolling → streaming/scrolling}/scroll-past-end.ts +1 -0
  324. package/src/extensions/{scrolling → streaming/scrolling}/scrollbar-autohide.ts +13 -11
  325. package/src/extensions/{typewriter.ts → streaming/typewriter.ts} +46 -47
  326. package/src/extensions/structure/blocks/DESIGN.md +134 -0
  327. package/src/extensions/structure/blocks/blocks.test.ts +147 -0
  328. package/src/extensions/structure/blocks/blocks.ts +219 -0
  329. package/src/extensions/structure/blocks/drag.ts +996 -0
  330. package/src/extensions/structure/blocks/index.ts +8 -0
  331. package/src/extensions/structure/blocks/selection.test.ts +56 -0
  332. package/src/extensions/structure/blocks/selection.ts +279 -0
  333. package/src/extensions/structure/blocks/types.ts +22 -0
  334. package/src/extensions/{folding.ts → structure/folding/folding.ts} +12 -10
  335. package/src/extensions/structure/folding/index.ts +6 -0
  336. package/src/extensions/structure/folding/turns.test.ts +72 -0
  337. package/src/extensions/structure/folding/turns.ts +209 -0
  338. package/src/extensions/structure/index.ts +7 -0
  339. package/src/extensions/structure/outliner/DESIGN.md +183 -0
  340. package/src/extensions/structure/outliner/SPEC.mdl +305 -0
  341. package/src/extensions/{outliner → structure/outliner}/commands.ts +125 -42
  342. package/src/extensions/structure/outliner/dnd.test.ts +142 -0
  343. package/src/extensions/structure/outliner/dnd.ts +375 -0
  344. package/src/extensions/structure/outliner/editor.test.ts +85 -0
  345. package/src/extensions/{outliner → structure/outliner}/editor.ts +14 -9
  346. package/src/extensions/{outliner → structure/outliner}/index.ts +1 -0
  347. package/src/extensions/{outliner → structure/outliner}/menu.ts +48 -25
  348. package/src/extensions/structure/outliner/outliner.test.ts +193 -0
  349. package/src/extensions/structure/outliner/outliner.ts +183 -0
  350. package/src/extensions/{outliner → structure/outliner}/tree.test.ts +2 -2
  351. package/src/extensions/{outliner → structure/outliner}/tree.ts +1 -1
  352. package/src/headless.ts +13 -0
  353. package/src/styles/theme.ts +3 -1
  354. package/src/util/util.ts +3 -0
  355. package/dist/lib/browser/index.mjs +0 -9594
  356. package/dist/lib/browser/index.mjs.map +0 -7
  357. package/dist/lib/browser/meta.json +0 -1
  358. package/dist/lib/browser/types/index.mjs +0 -33
  359. package/dist/lib/browser/types/index.mjs.map +0 -7
  360. package/dist/lib/node-esm/index.mjs +0 -9596
  361. package/dist/lib/node-esm/index.mjs.map +0 -7
  362. package/dist/lib/node-esm/meta.json +0 -1
  363. package/dist/lib/node-esm/types/index.mjs +0 -35
  364. package/dist/lib/node-esm/types/index.mjs.map +0 -7
  365. package/dist/types/src/extensions/annotations.d.ts.map +0 -1
  366. package/dist/types/src/extensions/autocomplete/autocomplete.d.ts.map +0 -1
  367. package/dist/types/src/extensions/autocomplete/index.d.ts.map +0 -1
  368. package/dist/types/src/extensions/autocomplete/match.d.ts.map +0 -1
  369. package/dist/types/src/extensions/autocomplete/placeholder.d.ts.map +0 -1
  370. package/dist/types/src/extensions/autocomplete/typeahead.d.ts.map +0 -1
  371. package/dist/types/src/extensions/automerge/automerge.d.ts.map +0 -1
  372. package/dist/types/src/extensions/automerge/automerge.test.d.ts.map +0 -1
  373. package/dist/types/src/extensions/automerge/cursor.d.ts.map +0 -1
  374. package/dist/types/src/extensions/automerge/defs.d.ts.map +0 -1
  375. package/dist/types/src/extensions/automerge/index.d.ts +0 -2
  376. package/dist/types/src/extensions/automerge/index.d.ts.map +0 -1
  377. package/dist/types/src/extensions/automerge/sync.d.ts.map +0 -1
  378. package/dist/types/src/extensions/automerge/update-automerge.d.ts.map +0 -1
  379. package/dist/types/src/extensions/automerge/update-codemirror.d.ts.map +0 -1
  380. package/dist/types/src/extensions/awareness/awareness-provider.d.ts.map +0 -1
  381. package/dist/types/src/extensions/awareness/awareness.d.ts.map +0 -1
  382. package/dist/types/src/extensions/awareness/index.d.ts.map +0 -1
  383. package/dist/types/src/extensions/blast.d.ts.map +0 -1
  384. package/dist/types/src/extensions/blocks.d.ts +0 -2
  385. package/dist/types/src/extensions/blocks.d.ts.map +0 -1
  386. package/dist/types/src/extensions/bookmarks.d.ts.map +0 -1
  387. package/dist/types/src/extensions/busy.d.ts.map +0 -1
  388. package/dist/types/src/extensions/comments.d.ts.map +0 -1
  389. package/dist/types/src/extensions/debug.d.ts.map +0 -1
  390. package/dist/types/src/extensions/dnd.d.ts.map +0 -1
  391. package/dist/types/src/extensions/factories.d.ts.map +0 -1
  392. package/dist/types/src/extensions/factories.test.d.ts.map +0 -1
  393. package/dist/types/src/extensions/fader.d.ts.map +0 -1
  394. package/dist/types/src/extensions/focus.d.ts.map +0 -1
  395. package/dist/types/src/extensions/folding.d.ts.map +0 -1
  396. package/dist/types/src/extensions/hashtag.d.ts +0 -3
  397. package/dist/types/src/extensions/hashtag.d.ts.map +0 -1
  398. package/dist/types/src/extensions/json.d.ts +0 -7
  399. package/dist/types/src/extensions/json.d.ts.map +0 -1
  400. package/dist/types/src/extensions/listener.d.ts.map +0 -1
  401. package/dist/types/src/extensions/markdown/action.d.ts.map +0 -1
  402. package/dist/types/src/extensions/markdown/bundle.d.ts.map +0 -1
  403. package/dist/types/src/extensions/markdown/changes.d.ts.map +0 -1
  404. package/dist/types/src/extensions/markdown/changes.test.d.ts.map +0 -1
  405. package/dist/types/src/extensions/markdown/debug.d.ts.map +0 -1
  406. package/dist/types/src/extensions/markdown/decorate.d.ts.map +0 -1
  407. package/dist/types/src/extensions/markdown/formatting.d.ts.map +0 -1
  408. package/dist/types/src/extensions/markdown/formatting.test.d.ts.map +0 -1
  409. package/dist/types/src/extensions/markdown/highlight.d.ts.map +0 -1
  410. package/dist/types/src/extensions/markdown/image.d.ts.map +0 -1
  411. package/dist/types/src/extensions/markdown/image.test.d.ts.map +0 -1
  412. package/dist/types/src/extensions/markdown/index.d.ts.map +0 -1
  413. package/dist/types/src/extensions/markdown/link.d.ts +0 -7
  414. package/dist/types/src/extensions/markdown/link.d.ts.map +0 -1
  415. package/dist/types/src/extensions/markdown/parser.test.d.ts.map +0 -1
  416. package/dist/types/src/extensions/markdown/styles.d.ts.map +0 -1
  417. package/dist/types/src/extensions/markdown/table.d.ts.map +0 -1
  418. package/dist/types/src/extensions/marker.d.ts.map +0 -1
  419. package/dist/types/src/extensions/mention.d.ts.map +0 -1
  420. package/dist/types/src/extensions/modal.d.ts.map +0 -1
  421. package/dist/types/src/extensions/modes.d.ts.map +0 -1
  422. package/dist/types/src/extensions/outliner/commands.d.ts +0 -10
  423. package/dist/types/src/extensions/outliner/commands.d.ts.map +0 -1
  424. package/dist/types/src/extensions/outliner/editor.d.ts.map +0 -1
  425. package/dist/types/src/extensions/outliner/editor.test.d.ts.map +0 -1
  426. package/dist/types/src/extensions/outliner/index.d.ts.map +0 -1
  427. package/dist/types/src/extensions/outliner/menu.d.ts.map +0 -1
  428. package/dist/types/src/extensions/outliner/outliner.d.ts.map +0 -1
  429. package/dist/types/src/extensions/outliner/outliner.test.d.ts.map +0 -1
  430. package/dist/types/src/extensions/outliner/selection.d.ts +0 -12
  431. package/dist/types/src/extensions/outliner/selection.d.ts.map +0 -1
  432. package/dist/types/src/extensions/outliner/tree.d.ts.map +0 -1
  433. package/dist/types/src/extensions/outliner/tree.test.d.ts.map +0 -1
  434. package/dist/types/src/extensions/pending/index.d.ts.map +0 -1
  435. package/dist/types/src/extensions/pending/pending-text-stream.d.ts.map +0 -1
  436. package/dist/types/src/extensions/pending/pending-text-stream.test.d.ts.map +0 -1
  437. package/dist/types/src/extensions/pending/pending-text.d.ts.map +0 -1
  438. package/dist/types/src/extensions/pending/pending-text.test.d.ts.map +0 -1
  439. package/dist/types/src/extensions/pos.d.ts.map +0 -1
  440. package/dist/types/src/extensions/pos.test.d.ts.map +0 -1
  441. package/dist/types/src/extensions/replacer.d.ts.map +0 -1
  442. package/dist/types/src/extensions/replacer.test.d.ts.map +0 -1
  443. package/dist/types/src/extensions/scrolling/auto-scroll.d.ts.map +0 -1
  444. package/dist/types/src/extensions/scrolling/crawler.d.ts.map +0 -1
  445. package/dist/types/src/extensions/scrolling/index.d.ts.map +0 -1
  446. package/dist/types/src/extensions/scrolling/scroll-past-end.d.ts +0 -3
  447. package/dist/types/src/extensions/scrolling/scroll-past-end.d.ts.map +0 -1
  448. package/dist/types/src/extensions/scrolling/scrollbar-autohide.d.ts.map +0 -1
  449. package/dist/types/src/extensions/scrolling/scroller.d.ts.map +0 -1
  450. package/dist/types/src/extensions/selection.d.ts.map +0 -1
  451. package/dist/types/src/extensions/selection.test.d.ts.map +0 -1
  452. package/dist/types/src/extensions/snippets.d.ts.map +0 -1
  453. package/dist/types/src/extensions/spacing.d.ts.map +0 -1
  454. package/dist/types/src/extensions/state.d.ts +0 -2
  455. package/dist/types/src/extensions/state.d.ts.map +0 -1
  456. package/dist/types/src/extensions/submit.d.ts.map +0 -1
  457. package/dist/types/src/extensions/tags/extended-markdown.d.ts.map +0 -1
  458. package/dist/types/src/extensions/tags/extended-markdown.test.d.ts.map +0 -1
  459. package/dist/types/src/extensions/tags/index.d.ts.map +0 -1
  460. package/dist/types/src/extensions/tags/stub.d.ts +0 -35
  461. package/dist/types/src/extensions/tags/stub.d.ts.map +0 -1
  462. package/dist/types/src/extensions/tags/widgets/anchor.d.ts.map +0 -1
  463. package/dist/types/src/extensions/tags/widgets/index.d.ts.map +0 -1
  464. package/dist/types/src/extensions/tags/xml-block-decoration.d.ts +0 -31
  465. package/dist/types/src/extensions/tags/xml-block-decoration.d.ts.map +0 -1
  466. package/dist/types/src/extensions/tags/xml-formatting.d.ts.map +0 -1
  467. package/dist/types/src/extensions/tags/xml-tags.d.ts.map +0 -1
  468. package/dist/types/src/extensions/tags/xml-util.d.ts.map +0 -1
  469. package/dist/types/src/extensions/tags/xml-util.test.d.ts.map +0 -1
  470. package/dist/types/src/extensions/typewriter.d.ts.map +0 -1
  471. package/dist/types/src/extensions/typewriter.test.d.ts.map +0 -1
  472. package/src/extensions/autocomplete/typeahead.ts +0 -87
  473. package/src/extensions/blocks.ts +0 -131
  474. package/src/extensions/markdown/link.ts +0 -49
  475. package/src/extensions/outliner/editor.test.ts +0 -33
  476. package/src/extensions/outliner/outliner.test.ts +0 -99
  477. package/src/extensions/outliner/outliner.ts +0 -166
  478. package/src/extensions/outliner/selection.ts +0 -50
  479. package/src/extensions/state.ts +0 -7
  480. package/src/extensions/tags/stub.ts +0 -80
  481. package/src/extensions/tags/xml-block-decoration.ts +0 -123
  482. package/dist/types/src/extensions/{dnd.d.ts → behavior/dnd.d.ts} +0 -0
  483. package/dist/types/src/extensions/{submit.d.ts → behavior/submit.d.ts} +0 -0
  484. package/dist/types/src/extensions/{automerge → collab/automerge}/automerge.d.ts +0 -0
  485. package/dist/types/src/extensions/{automerge → collab/automerge}/automerge.test.d.ts +0 -0
  486. package/dist/types/src/extensions/{automerge → collab/automerge}/sync.d.ts +0 -0
  487. package/dist/types/src/extensions/{awareness → collab/awareness}/awareness-provider.d.ts +0 -0
  488. package/dist/types/src/extensions/{awareness → collab/awareness}/index.d.ts +0 -0
  489. package/dist/types/src/extensions/{autocomplete → completion}/autocomplete.d.ts +0 -0
  490. package/dist/types/src/extensions/{autocomplete → completion}/placeholder.d.ts +0 -0
  491. package/dist/types/src/extensions/{factories.test.d.ts → core/factories.test.d.ts} +0 -0
  492. package/dist/types/src/extensions/{fader.d.ts → decoration/fader.d.ts} +0 -0
  493. package/dist/types/src/extensions/{marker.d.ts → decoration/marker.d.ts} +0 -0
  494. package/dist/types/src/extensions/{pos.test.d.ts → decoration/pos.test.d.ts} +0 -0
  495. package/dist/types/src/extensions/{replacer.test.d.ts → decoration/replacer.test.d.ts} +0 -0
  496. package/dist/types/src/extensions/{snippets.d.ts → demo/snippets.d.ts} +0 -0
  497. package/dist/types/src/extensions/{markdown → language/markdown}/action.d.ts +0 -0
  498. package/dist/types/src/extensions/{markdown → language/markdown}/bundle.d.ts +0 -0
  499. package/dist/types/src/extensions/{markdown → language/markdown}/changes.test.d.ts +0 -0
  500. package/dist/types/src/extensions/{markdown → language/markdown}/formatting.test.d.ts +0 -0
  501. package/dist/types/src/extensions/{markdown → language/markdown}/image.d.ts +0 -0
  502. package/dist/types/src/extensions/{markdown → language/markdown}/image.test.d.ts +0 -0
  503. package/dist/types/src/extensions/{markdown → language/markdown}/index.d.ts +0 -0
  504. package/dist/types/src/extensions/{markdown → language/markdown}/parser.test.d.ts +0 -0
  505. package/dist/types/src/extensions/{markdown → language/markdown}/table.d.ts +0 -0
  506. package/dist/types/src/extensions/{tags → language/xml}/extended-markdown.d.ts +0 -0
  507. package/dist/types/src/extensions/{tags → language/xml}/extended-markdown.test.d.ts +0 -0
  508. package/dist/types/src/extensions/{tags → language/xml}/index.d.ts +0 -0
  509. package/dist/types/src/extensions/{tags → language/xml}/widgets/anchor.d.ts +0 -0
  510. package/dist/types/src/extensions/{tags → language/xml}/widgets/index.d.ts +0 -0
  511. package/dist/types/src/extensions/{tags → language/xml}/xml-formatting.d.ts +0 -0
  512. package/dist/types/src/extensions/{tags → language/xml}/xml-util.d.ts +0 -0
  513. package/dist/types/src/extensions/{tags → language/xml}/xml-util.test.d.ts +0 -0
  514. package/dist/types/src/extensions/{modal.d.ts → state/modal.d.ts} +0 -0
  515. package/dist/types/src/extensions/{selection.test.d.ts → state/selection.test.d.ts} +0 -0
  516. package/dist/types/src/extensions/{pending → streaming/pending}/index.d.ts +0 -0
  517. package/dist/types/src/extensions/{pending → streaming/pending}/pending-text-stream.d.ts +0 -0
  518. package/dist/types/src/extensions/{pending → streaming/pending}/pending-text-stream.test.d.ts +0 -0
  519. package/dist/types/src/extensions/{pending → streaming/pending}/pending-text.test.d.ts +0 -0
  520. package/dist/types/src/extensions/{scrolling → streaming/scrolling}/auto-scroll.d.ts +0 -0
  521. package/dist/types/src/extensions/{scrolling → streaming/scrolling}/crawler.d.ts +0 -0
  522. package/dist/types/src/extensions/{scrolling → streaming/scrolling}/index.d.ts +0 -0
  523. package/dist/types/src/extensions/{scrolling → streaming/scrolling}/scrollbar-autohide.d.ts +0 -0
  524. package/dist/types/src/extensions/{scrolling → streaming/scrolling}/scroller.d.ts +0 -0
  525. package/dist/types/src/extensions/{typewriter.test.d.ts → streaming/typewriter.test.d.ts} +0 -0
  526. package/dist/types/src/extensions/{folding.d.ts → structure/folding/folding.d.ts} +0 -0
  527. package/dist/types/src/extensions/{outliner → structure/outliner}/editor.d.ts +0 -0
  528. package/dist/types/src/extensions/{outliner → structure/outliner}/editor.test.d.ts +0 -0
  529. package/dist/types/src/extensions/{outliner → structure/outliner}/outliner.d.ts +0 -0
  530. package/dist/types/src/extensions/{outliner → structure/outliner}/outliner.test.d.ts +0 -0
  531. package/dist/types/src/extensions/{outliner → structure/outliner}/tree.test.d.ts +0 -0
  532. package/src/extensions/{dnd.ts → behavior/dnd.ts} +29 -29
  533. package/src/extensions/{awareness → collab/awareness}/index.ts +0 -0
  534. package/src/extensions/{factories.test.ts → core/factories.test.ts} +0 -0
  535. package/src/extensions/{replacer.test.ts → decoration/replacer.test.ts} +0 -0
  536. package/src/extensions/{replacer.ts → decoration/replacer.ts} +25 -25
  537. /package/src/extensions/{markdown → language/markdown}/index.ts +0 -0
  538. /package/src/extensions/{tags → language/xml}/index.ts +0 -0
  539. /package/src/extensions/{tags → language/xml}/testing/text.md +0 -0
  540. /package/src/extensions/{tags → language/xml}/testing/text.txt +0 -0
  541. /package/src/extensions/{tags → language/xml}/widgets/anchor.ts +0 -0
  542. /package/src/extensions/{tags → language/xml}/widgets/index.ts +0 -0
  543. /package/src/extensions/{tags → language/xml}/xml-util.ts +0 -0
  544. /package/src/extensions/{modal.ts → state/modal.ts} +0 -0
  545. /package/src/extensions/{selection.test.ts → state/selection.test.ts} +0 -0
  546. /package/src/extensions/{pending → streaming/pending}/index.ts +0 -0
  547. /package/src/extensions/{pending → streaming/pending}/pending-text-stream.test.ts +0 -0
  548. /package/src/extensions/{scrolling → streaming/scrolling}/crawler.ts +0 -0
  549. /package/src/extensions/{scrolling → streaming/scrolling}/index.ts +0 -0
  550. /package/src/extensions/{scrolling → streaming/scrolling}/scroller.ts +0 -0
  551. /package/src/extensions/{typewriter.test.ts → streaming/typewriter.test.ts} +0 -0
@@ -0,0 +1,134 @@
1
+ # Block selection, drag, and clipboard
2
+
3
+ Design for gutter-driven block selection in the editor: select whole blocks
4
+ (paragraphs, list items, headings, …), drag them to reorder, and cut/copy/paste
5
+ them. The machinery is **document-agnostic** — markdown top-level blocks and
6
+ outliner task lines are both just "documents" that supply the same operations.
7
+
8
+ ## Concept
9
+
10
+ A **block selection** is an ordered set of whole blocks, distinct from
11
+ CodeMirror's text selection. It drives which gutter drag handle is shown, what a
12
+ drag moves, and what cut/copy/paste act on. When empty, the editor behaves
13
+ exactly as before (text-selection cut/copy/paste, single-block drag from the
14
+ cursor's block).
15
+
16
+ ## Operations contract
17
+
18
+ Both documents provide the same options bag; nothing below is markdown-specific.
19
+
20
+ ```ts
21
+ type Block = { from: number; to: number };
22
+
23
+ type BlockOps = {
24
+ // Blocks in document order; ranges non-overlapping. Memoized per state.
25
+ getBlocks: (state: EditorState) => Block[];
26
+ // Move the blocks at `sourceIndices` to the slot before `dropIndex` (end when
27
+ // dropIndex === blocks.length), preserving their relative order, as one edit.
28
+ moveBlocks: (view, sourceIndices: number[], dropIndex: number) => void;
29
+ // Serialize blocks to text for the clipboard (markdown joins with a blank line;
30
+ // the outliner joins with newlines).
31
+ serialize: (state, blocks: Block[]) => string;
32
+ // Remove the blocks (with separators) and, when text is non-null, insert it at
33
+ // the first removed slot — one edit. null = cut (delete), non-null = paste.
34
+ replaceBlocks: (view, indices: number[], text: string | null) => void;
35
+ };
36
+ ```
37
+
38
+ Single-block drag is just `moveBlocks(view, [i], drop)`.
39
+
40
+ ## State
41
+
42
+ ```ts
43
+ // Block anchors (each block's `from`), sorted. Positions — not indices — so they
44
+ // survive edits: `update` maps each anchor through `tr.changes` (no filtering).
45
+ const blockSelectionField: StateField<readonly number[]>;
46
+ const setBlockSelection = StateEffect<readonly number[]>(); // replace
47
+ const toggleBlockSelection = StateEffect<number>(); // add/remove one
48
+ ```
49
+
50
+ - `getSelectedBlocks(state)` — resolves anchors to `{ block, index }` in order,
51
+ dropping anchors that no longer identify a block start.
52
+ - The set is **cleared** on a non-shift `mousedown` in the content (a plain text
53
+ click); keyboard caret moves keep it so it can be extended.
54
+
55
+ ## Feature design
56
+
57
+ ### 1 · Handle only on the active block
58
+
59
+ `gutter.markers` emits **one** handle (not one per block), at:
60
+
61
+ - the top-most block in the selection set, if non-empty (feature 4); else
62
+ - the block containing `state.selection.main.head`.
63
+
64
+ Recompute on selection/set change: `lineMarkerChange: u => u.selectionSet ||
65
+ hasEffect(u, setBlockSelection, toggleBlock)`.
66
+
67
+ ### 2 · Click handle → toggle the block
68
+
69
+ The gutter `mousedown` is split arm → move → up:
70
+
71
+ - **mousedown**: ignore non-primary button; record block + start point; do not
72
+ drag yet.
73
+ - **move > 4px**: begin the real drag.
74
+ - **mouseup without moving** = click:
75
+ - move the caret to the block start and **collapse** any text selection
76
+ (answer 3);
77
+ - plain: `setBlockSelection([block])`; if it was already the sole selection,
78
+ clear to `[]` (answer 1);
79
+ - `shift`: `toggleBlock(block)` — add/remove, keep the rest (feature 3).
80
+
81
+ ### 4 · Handle on first selected block
82
+
83
+ Covered by (1)'s priority: with a non-empty set the grip sits on the top-most
84
+ selected block, always giving the group a grab point.
85
+
86
+ ### 5 · Drag moves the whole selection
87
+
88
+ On drag begin: if the grabbed block ∈ set and `|set| > 1`, drag the **set**; else
89
+ drag just the grabbed block. `moveBlocks` extracts the selected blocks in document
90
+ order, deletes them (with separators), and re-inserts them joined at the drop slot
91
+ — they land contiguous there, order preserved, one undo step. The drop index
92
+ skips the moving blocks (can't drop inside the group). The floating preview stacks
93
+ the selected blocks; the placeholder height is their combined height.
94
+
95
+ ### 6 · Cut / copy / paste
96
+
97
+ `EditorView.domEventHandlers({ copy, cut, paste })`, active only when the set is
98
+ non-empty (else fall through to native text behavior). Mod-C/X/V route through
99
+ these same DOM events, so no extra keymap.
100
+
101
+ - **copy**: `serialize` the set → `clipboardData`; `preventDefault`; keep the set.
102
+ - **cut**: copy + `removeBlocks`; clear the set.
103
+ - **paste**: `insertBlocks` the clipboard text, **replacing** the selection
104
+ (answer 2); if the set is empty, native paste at the caret.
105
+
106
+ ## Cross-cutting
107
+
108
+ - **Abort on `docChanged`**: the drag plugin's `update()` cancels an in-flight
109
+ drag when a concurrent/collaborative edit lands (stale indices would otherwise
110
+ resolve against a changed doc on drop).
111
+ - **Primary button only** for drag/click.
112
+ - **Highlight**: selected blocks get a `cm-blockSelected` border/background
113
+ (accent-tinted), drawn in a below-text layer by its own extension
114
+ (`createBlockSelectionHighlight`) so the visual travels with the drag grip
115
+ independently of the selection state/clipboard.
116
+
117
+ ## Module layout
118
+
119
+ - `selection.ts` — the field + effects and `getSelectedBlocks`;
120
+ `createBlockSelectionHighlight(getBlocks)` (the highlight layer); and
121
+ `createBlockSelection(ops)` (clipboard `domEventHandlers` + clear-on-text-press).
122
+ Exports the module-level `blockSelectionField` (deduped by CM if included twice).
123
+ - `drag.ts` — `createBlockDrag(ops)`: gutter + drag, reads `blockSelectionField`
124
+ for handle placement and multi-block drag; click/shift-click dispatch selection
125
+ effects.
126
+ - `blocks.ts` — markdown `BlockOps` (findBlocks, moveBlocks, serialize,
127
+ replaceBlocks); public `blockSelectionHighlight()`, `blockSelection()`,
128
+ `blockDrag()`; `blocks()` composes highlight + selection + drag.
129
+ - `outliner/dnd.ts` — outliner `BlockOps` over the item tree.
130
+
131
+ ## Non-goals (this pass)
132
+
133
+ - Rectangular/column selection, cross-document drag, nested-block reparenting on
134
+ drop (outliner drop keeps the existing re-indent behavior).
@@ -0,0 +1,147 @@
1
+ //
2
+ // Copyright 2026 DXOS.org
3
+ //
4
+
5
+ import { markdown, markdownLanguage } from '@codemirror/lang-markdown';
6
+ import { ensureSyntaxTree } from '@codemirror/language';
7
+ import { EditorState, type TransactionSpec } from '@codemirror/state';
8
+ import { describe, test } from 'vitest';
9
+
10
+ import { invariant } from '@dxos/invariant';
11
+
12
+ import { findBlocks, moveBlocksSpec, replaceBlocksSpec } from './blocks';
13
+ import { blockSelectionField } from './selection';
14
+
15
+ const extensions = [markdown({ base: markdownLanguage }), blockSelectionField];
16
+
17
+ // `findBlocks` walks the syntax tree, and CodeMirror's initial parse is budgeted in wall-clock time —
18
+ // on a loaded CI runner it can expire having parsed almost nothing, collapsing the document to a single
19
+ // block. Parse to the end before asserting so the tests measure `findBlocks`, not the parse scheduler.
20
+ const parsed = (state: EditorState): EditorState => {
21
+ ensureSyntaxTree(state, state.doc.length, 10_000);
22
+ return state;
23
+ };
24
+
25
+ const create = (doc: string) => parsed(EditorState.create({ doc, extensions }));
26
+
27
+ describe('findBlocks', () => {
28
+ test('splits into top-level blocks', ({ expect }) => {
29
+ const state = create('# Heading\n\npara\n\n- a\n- b');
30
+ const blocks = findBlocks(state);
31
+ expect(blocks.length).to.eq(3);
32
+ expect(state.doc.sliceString(blocks[0].from, blocks[0].to)).to.eq('# Heading');
33
+ expect(state.doc.sliceString(blocks[1].from, blocks[1].to)).to.eq('para');
34
+ // A list is a single block.
35
+ expect(state.doc.sliceString(blocks[2].from, blocks[2].to)).to.eq('- a\n- b');
36
+ });
37
+ });
38
+
39
+ describe('moveBlocksSpec', () => {
40
+ test('moves a block before another and puts the caret at its end', ({ expect }) => {
41
+ const state = create('A\n\nB\n\nC');
42
+ const next = apply(state, moveBlocksSpec(state, [0], 2));
43
+ expect(next.doc.toString()).to.eq('B\n\nA\n\nC');
44
+ // The caret is at the end of the moved block — not the block that took its old slot.
45
+ expect(charBeforeCaret(next)).to.eq('A');
46
+ const moved = findBlocks(next)[1];
47
+ expect(next.selection.main.head).to.eq(moved.to);
48
+ });
49
+
50
+ test('moves a block to the end', ({ expect }) => {
51
+ const state = create('A\n\nB\n\nC');
52
+ const next = apply(state, moveBlocksSpec(state, [0], 3));
53
+ expect(next.doc.toString()).to.eq('B\n\nC\n\nA');
54
+ expect(next.selection.main.head).to.eq(next.doc.length);
55
+ });
56
+
57
+ test('moves the last block without orphaning its separator', ({ expect }) => {
58
+ const state = create('A\n\nB\n\nC');
59
+ const next = apply(state, moveBlocksSpec(state, [2], 0));
60
+ expect(next.doc.toString()).to.eq('C\n\nA\n\nB');
61
+ });
62
+
63
+ test('moves multiple contiguous blocks as a group', ({ expect }) => {
64
+ const state = create('A\n\nB\n\nC\n\nD');
65
+ const next = apply(state, moveBlocksSpec(state, [0, 1], 4));
66
+ expect(next.doc.toString()).to.eq('C\n\nD\n\nA\n\nB');
67
+ });
68
+
69
+ test('moves multiple non-contiguous blocks, preserving order', ({ expect }) => {
70
+ const state = create('A\n\nB\n\nC\n\nD');
71
+ const next = apply(state, moveBlocksSpec(state, [0, 2], 4));
72
+ expect(next.doc.toString()).to.eq('B\n\nD\n\nA\n\nC');
73
+ });
74
+
75
+ test('keeps the moved blocks selected after the drop', ({ expect }) => {
76
+ const state = create('A\n\nB\n\nC\n\nD');
77
+ // A single block dropped before another.
78
+ expect(selectedText(apply(state, moveBlocksSpec(state, [1], 3)))).to.deep.eq(['B']);
79
+ // Multiple non-contiguous blocks moved to the end stay selected, in document order.
80
+ expect(selectedText(apply(state, moveBlocksSpec(state, [0, 2], 4)))).to.deep.eq(['A', 'C']);
81
+ });
82
+
83
+ test('is a no-op when dropping onto a source block', ({ expect }) => {
84
+ const state = create('A\n\nB\n\nC');
85
+ expect(moveBlocksSpec(state, [0], 0)).to.eq(null);
86
+ expect(moveBlocksSpec(state, [1], 1)).to.eq(null);
87
+ });
88
+
89
+ test('is a no-op for empty sources', ({ expect }) => {
90
+ const state = create('A\n\nB');
91
+ expect(moveBlocksSpec(state, [], 1)).to.eq(null);
92
+ });
93
+ });
94
+
95
+ describe('replaceBlocksSpec', () => {
96
+ test('cut deletes the block and its separator', ({ expect }) => {
97
+ const state = create('A\n\nB\n\nC');
98
+ const next = apply(state, replaceBlocksSpec(state, [1], null));
99
+ expect(next.doc.toString()).to.eq('A\n\nC');
100
+ });
101
+
102
+ test('cut removes the last block without orphaning its separator', ({ expect }) => {
103
+ const state = create('A\n\nB\n\nC');
104
+ const next = apply(state, replaceBlocksSpec(state, [2], null));
105
+ expect(next.doc.toString()).to.eq('A\n\nB');
106
+ });
107
+
108
+ test('cut removes multiple blocks', ({ expect }) => {
109
+ const state = create('A\n\nB\n\nC\n\nD');
110
+ const next = apply(state, replaceBlocksSpec(state, [1, 2], null));
111
+ expect(next.doc.toString()).to.eq('A\n\nD');
112
+ });
113
+
114
+ test('paste replaces the selected block with block(s)', ({ expect }) => {
115
+ const state = create('A\n\nB\n\nC');
116
+ const next = apply(state, replaceBlocksSpec(state, [1], 'X\n\nY'));
117
+ expect(next.doc.toString()).to.eq('A\n\nX\n\nY\n\nC');
118
+ });
119
+
120
+ test('is a no-op for empty indices', ({ expect }) => {
121
+ const state = create('A\n\nB');
122
+ expect(replaceBlocksSpec(state, [], 'X')).to.eq(null);
123
+ });
124
+ });
125
+
126
+ // The blocks selected in a state, as their source strings.
127
+ const selectedText = (state: EditorState): string[] => {
128
+ const anchors = state.field(blockSelectionField);
129
+ const byFrom = new Map(findBlocks(state).map((block) => [block.from, block]));
130
+ return anchors.map((anchor) => {
131
+ const block = byFrom.get(anchor);
132
+ invariant(block, `no block at anchor ${anchor}`);
133
+ return state.doc.sliceString(block.from, block.to);
134
+ });
135
+ };
136
+
137
+ // Applies a (non-null) transaction spec and returns the resulting state.
138
+ const apply = (state: EditorState, spec: TransactionSpec | null): EditorState => {
139
+ invariant(spec, 'expected a transaction spec');
140
+ return parsed(state.update(spec).state);
141
+ };
142
+
143
+ // The character at the caret's left, so tests can assert the caret lands at the end of a moved block.
144
+ const charBeforeCaret = (state: EditorState) => {
145
+ const head = state.selection.main.head;
146
+ return state.doc.sliceString(head - 1, head);
147
+ };
@@ -0,0 +1,219 @@
1
+ //
2
+ // Copyright 2026 DXOS.org
3
+ //
4
+
5
+ import { syntaxTree } from '@codemirror/language';
6
+ import { type EditorState, type Extension, type TransactionSpec } from '@codemirror/state';
7
+ import { type EditorView } from '@codemirror/view';
8
+
9
+ import { createBlockDrag } from './drag';
10
+ import { type BlockOps, createBlockSelection, createBlockSelectionHighlight, setBlockSelection } from './selection';
11
+ import { type Block } from './types';
12
+
13
+ export type BlockOptions = {
14
+ /**
15
+ * Pin the drag preview to the block's left edge so it only tracks vertically (default `true`).
16
+ * When `false`, the preview follows the pointer on both axes.
17
+ */
18
+ clampX?: boolean;
19
+ };
20
+
21
+ /**
22
+ * Whole-block editing over the top-level markdown blocks: click/shift-click the gutter grip to select,
23
+ * drag-to-reorder, cut/copy/paste, with a border/background behind the selection. Composes
24
+ * `blockSelectionHighlight` (the box behind selected blocks), `blockSelection` (selection state and
25
+ * clipboard), and `blockDrag` (the gutter grip that populates the selection and drag-to-move). The grip
26
+ * lives in `blockDrag` and drives the selection, so these are used together (or via this `blocks()`).
27
+ */
28
+ export const blocks = ({ clampX }: BlockOptions = {}): Extension => [
29
+ blockSelectionHighlight(),
30
+ blockSelection(),
31
+ blockDrag({ clampX }),
32
+ ];
33
+
34
+ /**
35
+ * Draws a border/background box behind each selected top-level markdown block. See
36
+ * `createBlockSelectionHighlight`.
37
+ */
38
+ export const blockSelectionHighlight = (): Extension => createBlockSelectionHighlight(findBlocks);
39
+
40
+ /**
41
+ * Whole-block selection state and block cut/copy/paste over the top-level markdown blocks. The gutter
42
+ * grip gesture that populates the selection is provided by `blockDrag` and the highlight by
43
+ * `blockSelectionHighlight`, so pair them (or use `blocks()`, which composes them). See
44
+ * `createBlockSelection`.
45
+ */
46
+ export const blockSelection = (): Extension => createBlockSelection(markdownBlockOps);
47
+
48
+ /**
49
+ * Adds a gutter drag grip to the active markdown block and moves the block (or the whole block
50
+ * selection) on drop. See `createBlockDrag`.
51
+ */
52
+ export const blockDrag = ({ clampX }: Pick<BlockOptions, 'clampX'> = {}): Extension =>
53
+ createBlockDrag({ getBlocks: findBlocks, moveBlocks, clampX });
54
+
55
+ /**
56
+ * Top-level markdown blocks (headings, paragraphs, lists, blockquotes, fenced code, …) from the
57
+ * syntax tree, so a list or code fence moves and boxes as a single unit. Memoized per state — the
58
+ * highlight layer, the gutter, and the drag plugin all query it on the same state.
59
+ */
60
+ const blockCache = new WeakMap<EditorState, Block[]>();
61
+
62
+ export const findBlocks = (state: EditorState): Block[] => {
63
+ const cached = blockCache.get(state);
64
+ if (cached) {
65
+ return cached;
66
+ }
67
+
68
+ const blocks: Block[] = [];
69
+ const cursor = syntaxTree(state).topNode.cursor();
70
+ if (cursor.firstChild()) {
71
+ do {
72
+ if (cursor.to > cursor.from) {
73
+ blocks.push({ from: cursor.from, to: cursor.to });
74
+ }
75
+ } while (cursor.nextSibling());
76
+ }
77
+
78
+ blockCache.set(state, blocks);
79
+ return blocks;
80
+ };
81
+
82
+ // Merges sorted ranges, combining any that overlap or touch.
83
+ const mergeRanges = (ranges: { from: number; to: number }[]): { from: number; to: number }[] => {
84
+ const sorted = [...ranges].sort((a, b) => a.from - b.from);
85
+ const merged: { from: number; to: number }[] = [];
86
+ for (const range of sorted) {
87
+ const last = merged.at(-1);
88
+ if (last && range.from <= last.to) {
89
+ last.to = Math.max(last.to, range.to);
90
+ } else {
91
+ merged.push({ ...range });
92
+ }
93
+ }
94
+ return merged;
95
+ };
96
+
97
+ // Delete ranges for the given blocks: each block plus its blank-line separator (the one below it, down to
98
+ // the next block; for the last block the one above it instead, so no trailing blank is orphaned), merged
99
+ // so adjacent selections form one range.
100
+ const deleteRanges = (state: EditorState, blocks: Block[], indices: number[]): { from: number; to: number }[] => {
101
+ const count = blocks.length;
102
+ return mergeRanges(
103
+ indices.map((index) => ({
104
+ from: index === count - 1 && index > 0 ? blocks[index - 1].to : blocks[index].from,
105
+ to: index + 1 < count ? blocks[index + 1].from : state.doc.length,
106
+ })),
107
+ );
108
+ };
109
+
110
+ /**
111
+ * Transaction that moves the blocks at `sourceIndices` to the slot before `dropIndex` (the end of the
112
+ * document when `dropIndex === blocks.length`), preserving their relative order and blank-line
113
+ * separation, as a single undo step. Places the caret at the end of the moved content and clears the
114
+ * block selection. Returns `null` for a no-op (empty/invalid sources, or a drop inside the moved region).
115
+ * Pure — exported for tests.
116
+ */
117
+ export const moveBlocksSpec = (
118
+ state: EditorState,
119
+ sourceIndices: number[],
120
+ dropIndex: number,
121
+ ): TransactionSpec | null => {
122
+ const blocks = findBlocks(state);
123
+ const count = blocks.length;
124
+ const sources = [...new Set(sourceIndices)].filter((index) => index >= 0 && index < count).sort((a, b) => a - b);
125
+ // Dropping onto a selected block is a no-op.
126
+ if (sources.length === 0 || sources.includes(dropIndex)) {
127
+ return null;
128
+ }
129
+
130
+ const text = sources.map((index) => state.doc.sliceString(blocks[index].from, blocks[index].to)).join('\n\n');
131
+ const deletes = deleteRanges(state, blocks, sources);
132
+ const insertAt = dropIndex < count ? blocks[dropIndex].from : state.doc.length;
133
+ // Dropping inside the removed region is a no-op.
134
+ if (deletes.some((range) => insertAt > range.from && insertAt < range.to)) {
135
+ return null;
136
+ }
137
+
138
+ const insert = dropIndex < count ? `${text}\n\n` : `\n\n${text}`;
139
+ const changes = [...deletes.map((range) => ({ from: range.from, to: range.to })), { from: insertAt, insert }];
140
+ // The inserted text starts where `insertAt` maps to (dropping any deletes before it), then `text` sits
141
+ // at its start (or after the `\n\n` prefix when appending).
142
+ const changeSet = state.changes(changes);
143
+ const textStart = changeSet.mapPos(insertAt, -1) + (dropIndex < count ? 0 : 2);
144
+ // Keep the moved blocks selected: their new anchors are the start of each block within the inserted
145
+ // text, joined by `\n\n` (block length + 2). The caret lands at the end of the moved content.
146
+ const anchors: number[] = [];
147
+ let anchor = textStart;
148
+ for (const index of sources) {
149
+ anchors.push(anchor);
150
+ anchor += blocks[index].to - blocks[index].from + 2;
151
+ }
152
+ const caret = textStart + text.length;
153
+ return {
154
+ changes,
155
+ selection: { anchor: Math.min(caret, changeSet.newLength) },
156
+ effects: setBlockSelection.of(anchors),
157
+ userEvent: 'move.block',
158
+ };
159
+ };
160
+
161
+ const moveBlocks = (view: EditorView, sourceIndices: number[], dropIndex: number): void => {
162
+ const spec = moveBlocksSpec(view.state, sourceIndices, dropIndex);
163
+ if (spec) {
164
+ view.dispatch(spec);
165
+ }
166
+ };
167
+
168
+ /**
169
+ * Transaction that removes the blocks at `indices` and, when `text` is non-null, inserts it as block(s)
170
+ * at the first removed slot — a single edit. `null` is a pure delete (cut); non-null is a replace
171
+ * (paste). Returns `null` for a no-op. Pure — exported for tests.
172
+ */
173
+ export const replaceBlocksSpec = (
174
+ state: EditorState,
175
+ indices: number[],
176
+ text: string | null,
177
+ ): TransactionSpec | null => {
178
+ const blocks = findBlocks(state);
179
+ const count = blocks.length;
180
+ const sources = [...new Set(indices)].filter((index) => index >= 0 && index < count).sort((a, b) => a - b);
181
+ if (sources.length === 0) {
182
+ return null;
183
+ }
184
+
185
+ const deletes = deleteRanges(state, blocks, sources);
186
+ const changes: { from: number; to: number; insert?: string }[] = deletes.map((range) => ({
187
+ from: range.from,
188
+ to: range.to,
189
+ }));
190
+ let anchor = deletes[0].from;
191
+ if (text != null && text.length > 0) {
192
+ // Replace the first removed range with the pasted text (keeping a trailing blank unless at doc end).
193
+ const insert = deletes[0].to >= state.doc.length ? text : `${text}\n\n`;
194
+ changes[0] = { from: deletes[0].from, to: deletes[0].to, insert };
195
+ anchor = deletes[0].from + text.length;
196
+ }
197
+
198
+ const changeSet = state.changes(changes);
199
+ return {
200
+ changes,
201
+ selection: { anchor: Math.min(anchor, changeSet.newLength) },
202
+ effects: setBlockSelection.of([]),
203
+ userEvent: text == null ? 'delete.block' : 'input.paste',
204
+ };
205
+ };
206
+
207
+ const replaceBlocks = (view: EditorView, indices: number[], text: string | null): void => {
208
+ const spec = replaceBlocksSpec(view.state, indices, text);
209
+ if (spec) {
210
+ view.dispatch(spec);
211
+ }
212
+ };
213
+
214
+ export const markdownBlockOps: BlockOps = {
215
+ getBlocks: findBlocks,
216
+ moveBlocks,
217
+ serialize: (state, blocks) => blocks.map((block) => state.doc.sliceString(block.from, block.to)).join('\n\n'),
218
+ replaceBlocks,
219
+ };