@dxos/ui-editor 0.10.0 → 0.11.1

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
@@ -2,7 +2,7 @@
2
2
  // Copyright 2025 DXOS.org
3
3
  //
4
4
 
5
- import { syntaxTree } from '@codemirror/language';
5
+ import { syntaxTree, syntaxTreeAvailable } from '@codemirror/language';
6
6
  import { type EditorState, type Extension, Prec, RangeSetBuilder, StateEffect, StateField } from '@codemirror/state';
7
7
  import {
8
8
  Decoration,
@@ -17,9 +17,9 @@ import { type FunctionComponent } from 'react';
17
17
 
18
18
  import { log } from '@dxos/log';
19
19
 
20
- import { type Range } from '../../types';
21
- import { decorationSetToArray } from '../../util';
22
- import { crawlerLineEffect } from '../scrolling';
20
+ import { type Range } from '../../../types';
21
+ import { decorationSetToArray, escapeRegExpSource } from '../../../util';
22
+ import { crawlerLineEffect } from '../../streaming/scrolling';
23
23
  import { StubWidget, type XmlWidgetNotifier } from './stub';
24
24
  import { nodeToJson } from './xml-util';
25
25
 
@@ -52,10 +52,10 @@ export type XmlEventHandler<TEvent = any> = (event: TEvent) => void;
52
52
  */
53
53
  export type XmlWidgetProps<TProps = any, TContext = any> = TProps & {
54
54
  _tag: string;
55
+ view?: EditorView;
55
56
  range: { from: number; to: number };
56
57
  children?: any[];
57
58
  context?: TContext;
58
- view?: EditorView;
59
59
  onEvent?: XmlEventHandler;
60
60
  };
61
61
 
@@ -104,6 +104,13 @@ export type XmlWidgetDef = {
104
104
  * Block widgets are created for Image nodes; inline widgets for Link nodes.
105
105
  */
106
106
  urlSchemes?: string[];
107
+
108
+ /**
109
+ * Reserved block height (px) derived from the widget's props (e.g. parsed from the image label),
110
+ * used to size the placeholder and CodeMirror's viewport estimate before the React content mounts.
111
+ * Only meaningful for block widgets.
112
+ */
113
+ estimatedHeight?: (props: XmlWidgetProps) => number | undefined;
107
114
  };
108
115
 
109
116
  export type XmlWidgetRegistry = Record<string, XmlWidgetDef>;
@@ -117,9 +124,6 @@ export const getXmlTextChild = (children: any[]): string | null => {
117
124
  const xmlWidgetId = (explicit: unknown, fallback: string): string =>
118
125
  typeof explicit === 'string' && explicit.length > 0 ? explicit : fallback;
119
126
 
120
- /** Escapes a string for safe embedding in RegExp source (tag names from the registry). */
121
- const escapeRegExpSource = (value: string) => value.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
122
-
123
127
  /**
124
128
  * Update context.
125
129
  */
@@ -130,6 +134,12 @@ export const xmlTagContextEffect = StateEffect.define<any>();
130
134
  */
131
135
  export const xmlTagResetEffect = StateEffect.define();
132
136
 
137
+ /**
138
+ * Force a full decoration rebuild without a document change — dispatched once background parsing of a
139
+ * long document completes, so blocks past the initial parse window are decorated without needing an edit.
140
+ */
141
+ export const xmlTagRebuildEffect = StateEffect.define();
142
+
133
143
  /**
134
144
  * Update widget.
135
145
  */
@@ -153,6 +163,44 @@ export type XmlWidgetState = {
153
163
 
154
164
  export type { XmlWidgetNotifier };
155
165
 
166
+ export type XmlTagsOptions = {
167
+ /** Tag registry. */
168
+ registry?: XmlWidgetRegistry;
169
+
170
+ /** Tags to bookmark for navigation. */
171
+ bookmarks?: string[];
172
+
173
+ /** Called when widgets are mounted or unmounted. */
174
+ setWidgets?: (widgets: XmlWidgetState[]) => void;
175
+ };
176
+
177
+ /**
178
+ * Implements custom XML tags via CodeMirror-native Widgets and portaled React/Solid components.
179
+ *
180
+ * Basic mechanism:
181
+ * - Decorations are created from XML tags that matched the provided Widget registry.
182
+ * - Native widgets are rendered inline.
183
+ * - React/Solid widgets are rendered in portals outside of the editor via the StubWidget.
184
+ * - Widget state can be update via effects.
185
+ * - NOTE: Widget state may be updated BEFORE the widget is mounted.
186
+ */
187
+ export const xmlTags = ({ registry, setWidgets, bookmarks }: XmlTagsOptions = {}): Extension => {
188
+ const debug = registry ? Object.values(registry).some((def) => def.debug) : false;
189
+ const notifier = createWidgetMap(setWidgets, debug);
190
+ const widgetDecorationsField = createWidgetDecorationsField(registry, notifier);
191
+
192
+ return [
193
+ widgetContextStateField,
194
+ widgetStateMapStateField,
195
+ widgetDecorationsField,
196
+ createWidgetUpdatePlugin(widgetDecorationsField, notifier),
197
+ createParseCompletionPlugin(),
198
+ createNavigationEffectPlugin(widgetDecorationsField, bookmarks),
199
+ bookmarks?.length ? Prec.highest(keyHandlers) : [],
200
+ debug ? createScrollJumpMonitor() : [],
201
+ ];
202
+ };
203
+
156
204
  /**
157
205
  * Context state.
158
206
  */
@@ -175,76 +223,115 @@ const widgetContextStateField = StateField.define<any>({
175
223
  const widgetStateMapStateField = StateField.define<XmlWidgetStateMap>({
176
224
  create: () => ({}),
177
225
  update: (map, tr) => {
226
+ // Reduce over every effect: a transaction may carry several updates (or a reset followed by them),
227
+ // and returning on the first would silently drop the rest.
228
+ let next = map;
178
229
  for (const effect of tr.effects) {
179
230
  if (effect.is(xmlTagResetEffect)) {
180
- return {};
181
- }
182
-
183
- if (effect.is(xmlTagUpdateEffect)) {
231
+ next = {};
232
+ } else if (effect.is(xmlTagUpdateEffect)) {
184
233
  // Update accumulated widget props by id.
185
234
  const { id, value } = effect.value;
186
235
  log('widget updated', { id, value });
187
- const state = typeof value === 'function' ? value(map[id]) : value;
188
- return { ...map, [id]: state };
236
+ next = { ...next, [id]: typeof value === 'function' ? value(next[id]) : value };
189
237
  }
190
238
  }
191
239
 
192
- return map;
240
+ return next;
193
241
  },
194
242
  });
195
243
 
196
- export type XmlTagsOptions = {
197
- /** Tag registry. */
198
- registry?: XmlWidgetRegistry;
199
-
200
- /** Tags to bookmark for navigation. */
201
- bookmarks?: string[];
244
+ /**
245
+ * Debug-only: flag large single-event scroll deltas (the "jump") so they can be correlated with the
246
+ * widget lifecycle trace. A smooth user scroll produces small per-event deltas; a jump-to-top is one
247
+ * big negative delta to near-zero.
248
+ */
249
+ const createScrollJumpMonitor = () => {
250
+ let last = -1;
251
+ return EditorView.domEventHandlers({
252
+ scroll: (_event, view) => {
253
+ const top = view.scrollDOM.scrollTop;
254
+ if (last >= 0 && Math.abs(top - last) > 600) {
255
+ log.warn('xml-tags: scroll jump', {
256
+ from: Math.round(last),
257
+ to: Math.round(top),
258
+ delta: Math.round(top - last),
259
+ });
260
+ }
261
+ last = top;
262
+ },
263
+ });
264
+ };
202
265
 
203
- /** Called when widgets are mounted or unmounted. */
204
- setWidgets?: (widgets: XmlWidgetState[]) => void;
266
+ /**
267
+ * Re-decorate once the whole document has parsed. `StateField.create` (and incremental rebuilds) only
268
+ * see the syntax tree parsed so far, so a block past CodeMirror's initial background-parse window is
269
+ * not decorated until some later transaction — previously it appeared only after the first edit. This
270
+ * dispatches a one-shot rebuild when the full tree becomes available (re-armed on each edit).
271
+ */
272
+ const createParseCompletionPlugin = () => {
273
+ let rebuiltForLength = -1;
274
+ return EditorView.updateListener.of((update) => {
275
+ if (update.docChanged) {
276
+ rebuiltForLength = -1;
277
+ }
278
+ const length = update.state.doc.length;
279
+ if (rebuiltForLength !== length && syntaxTreeAvailable(update.state, length)) {
280
+ rebuiltForLength = length;
281
+ // Defer: cannot dispatch during an update.
282
+ queueMicrotask(() => update.view.dispatch({ effects: xmlTagRebuildEffect.of(null) }));
283
+ }
284
+ });
205
285
  };
206
286
 
207
287
  /**
208
- * Implements custom XML tags via CodeMirror-native Widgets and portaled React/Solid components.
288
+ * Re-applies the accumulated widget state at mount time.
209
289
  *
210
- * Basic mechanism:
211
- * - Decorations are created from XML tags that matched the provided Widget registry.
212
- * - Native widgets are rendered inline.
213
- * - React/Solid widgets are rendered in portals outside of the editor via the StubWidget.
214
- * - Widget state can be update via effects.
215
- * - NOTE: Widget state may be updated BEFORE the widget is mounted.
290
+ * A widget's props are baked when its decoration is built, but state can be dispatched before the
291
+ * widget mounts — rehydration after a document reset targets widgets that are still outside
292
+ * CodeMirror's viewport, and `xmlTagUpdateEffect` alone rebuilds no decorations. Such a widget would
293
+ * otherwise mount with the stale props it was built with, since `StubWidget.eq` (id equality) stops a
294
+ * later rebuild from replacing the instance.
216
295
  */
217
- export const xmlTags = ({ registry, setWidgets, bookmarks }: XmlTagsOptions = {}): Extension => {
218
- const notifier = createWidgetMap(setWidgets);
219
- const widgetDecorationsField = createWidgetDecorationsField(registry, notifier);
220
-
221
- return [
222
- widgetContextStateField,
223
- widgetStateMapStateField,
224
- widgetDecorationsField,
225
- createWidgetUpdatePlugin(widgetDecorationsField, notifier),
226
- createNavigationEffectPlugin(widgetDecorationsField, bookmarks),
227
- bookmarks?.length ? Prec.highest(keyHandlers) : [],
228
- ];
296
+ const withCurrentWidgetState = (state: XmlWidgetState): XmlWidgetState => {
297
+ const view: EditorView | undefined = state.props?.view;
298
+ const widgetState = view?.state.field(widgetStateMapStateField, false)?.[state.id];
299
+ return widgetState ? { ...state, props: { ...state.props, ...widgetState } } : state;
229
300
  };
230
301
 
231
302
  /**
232
303
  * Manages the collection of widgets.
233
304
  */
234
- const createWidgetMap = (setWidgets?: (widgets: XmlWidgetState[]) => void): XmlWidgetNotifier => {
305
+ const createWidgetMap = (setWidgets?: (widgets: XmlWidgetState[]) => void, debug = false): XmlWidgetNotifier => {
235
306
  const widgets = new Map<string, XmlWidgetState>();
236
307
 
237
308
  // TODO(burdon): Batch updates?
238
309
  const notifier = {
239
- mounted: (state: XmlWidgetState) => {
240
- log('widget mounted', { id: state.id, tag: state.props._tag });
310
+ mounted: (rawState: XmlWidgetState) => {
311
+ const state = withCurrentWidgetState(rawState);
312
+ const isNew = !widgets.has(state.id);
241
313
  widgets.set(state.id, state);
314
+ // Only a genuinely new id changes the portal set (blank-frame culprit); re-parents just re-notify.
315
+ if (debug && isNew) {
316
+ log.info('widget-map: mounted', { id: state.id, count: widgets.size });
317
+ }
318
+ setWidgets?.([...widgets.values()]);
319
+ },
320
+ updated: (id: string, widgetState: any) => {
321
+ const current = widgets.get(id);
322
+ if (!current || !widgetState) {
323
+ return;
324
+ }
325
+
326
+ widgets.set(id, { ...current, props: { ...current.props, ...widgetState } });
242
327
  setWidgets?.([...widgets.values()]);
243
328
  },
244
329
  unmounted: (id: string) => {
245
- const state = widgets.get(id);
246
- log('widget unmounted', { id, tag: state?.props._tag });
247
330
  widgets.delete(id);
331
+ // A cull drops the portal for a frame before it re-mounts — this is the blank-space window.
332
+ if (debug) {
333
+ log.info('widget-map: unmounted', { id, count: widgets.size });
334
+ }
248
335
  setWidgets?.([...widgets.values()]);
249
336
  },
250
337
  reconcile: (liveIds: Set<string>) => {
@@ -256,6 +343,9 @@ const createWidgetMap = (setWidgets?: (widgets: XmlWidgetState[]) => void): XmlW
256
343
  }
257
344
  }
258
345
  if (changed) {
346
+ if (debug) {
347
+ log.info('widget-map: reconcile pruned', { live: [...liveIds], count: widgets.size });
348
+ }
259
349
  setWidgets?.([...widgets.values()]);
260
350
  }
261
351
  },
@@ -382,22 +472,11 @@ const createWidgetUpdatePlugin = (
382
472
  notifier.reconcile(liveIds);
383
473
  }
384
474
 
385
- // Check for widget update effects and re-render widgets.
475
+ // Re-render widgets whose state changed. Widgets not yet mounted pick their state up at mount
476
+ // time instead (see `withCurrentWidgetState`).
386
477
  for (const effect of update.transactions.flatMap((tr) => tr.effects)) {
387
478
  if (effect.is(xmlTagUpdateEffect)) {
388
- const widgetState = widgetStateMap[effect.value.id];
389
-
390
- // Find and render widget.
391
- for (const range of decorationSetToArray(decorations)) {
392
- const deco = range.value;
393
- const widget = deco?.spec?.widget;
394
-
395
- // NOTE: If the widget has not yet been mounted, then the root will be null.
396
- if (widget && widget instanceof StubWidget && widget.id === effect.value.id && widget.root) {
397
- const props = { ...widget.props, ...widgetState };
398
- notifier.mounted({ id: widget.id, props, root: widget.root, Component: widget.Component });
399
- }
400
- }
479
+ notifier.updated(effect.value.id, widgetStateMap[effect.value.id]);
401
480
  }
402
481
  }
403
482
  }
@@ -435,6 +514,16 @@ const createWidgetDecorationsField = (registry: XmlWidgetRegistry = {}, notifier
435
514
  }
436
515
  return { from: 0, decorations: Decoration.none };
437
516
  }
517
+ // Full rebuild once background parsing has advanced (no document change).
518
+ if (effect.is(xmlTagRebuildEffect)) {
519
+ return buildDecorations(tr.state, { from: 0, to: tr.state.doc.length }, registry, notifier, urlSchemeMap);
520
+ }
521
+ // Widget props capture the context at build time and `StubWidget.eq` compares ids, so a context
522
+ // set after the first build would otherwise never reach a widget — leaving its callbacks bound to
523
+ // `undefined` for the life of the document.
524
+ if (effect.is(xmlTagContextEffect)) {
525
+ return buildDecorations(tr.state, { from: 0, to: tr.state.doc.length }, registry, notifier, urlSchemeMap);
526
+ }
438
527
  }
439
528
 
440
529
  if (tr.docChanged) {
@@ -499,6 +588,11 @@ const buildDecorations = (
499
588
  let last = range.from;
500
589
  let streamingFrom: number | undefined;
501
590
 
591
+ // Per-dxn occurrence counter for position-independent url-scheme widget ids. Keying on document
592
+ // position would change the id on every keystroke above the widget (full rebuild), remounting the
593
+ // portal and flashing the embed; occurrence order is stable because edits above force a full rebuild.
594
+ const dxnOccurrences = new Map<string, number>();
595
+
502
596
  tree.iterate({
503
597
  from: range.from,
504
598
  to: range.to,
@@ -532,11 +626,13 @@ const buildDecorations = (
532
626
  ...widgetState,
533
627
  } satisfies XmlWidgetProps;
534
628
 
535
- // Create widget.
629
+ // Create widget. Known-height block widgets get their reserved height so StubWidget's
630
+ // fixed-height keep-alive applies to Component element tags too, not just url-scheme widgets.
631
+ const blockHeight = block ? def.estimatedHeight?.(props) : undefined;
536
632
  const widget: WidgetType | undefined = factory
537
633
  ? (factory(props) ?? undefined)
538
634
  : Component
539
- ? new StubWidget(widgetId, Component, props, notifier, false, !!block)
635
+ ? new StubWidget(widgetId, Component, props, notifier, false, !!block, blockHeight, def.debug)
540
636
  : undefined;
541
637
 
542
638
  // Add decoration.
@@ -589,7 +685,9 @@ const buildDecorations = (
589
685
  const [tag, def] = matched;
590
686
  const label = state.sliceDoc(markNodes[0].to, markNodes[1].from);
591
687
  const nodeRange = { from: node.node.from, to: node.node.to };
592
- const widgetId = `cm-url-${node.from}-${dxn}`;
688
+ const occurrence = dxnOccurrences.get(dxn) ?? 0;
689
+ dxnOccurrences.set(dxn, occurrence + 1);
690
+ const widgetId = `cm-url-${dxn}-${occurrence}`;
593
691
  const widgetState = widgetStateMap[widgetId];
594
692
  const props: XmlWidgetProps = {
595
693
  id: widgetId,
@@ -602,10 +700,11 @@ const buildDecorations = (
602
700
  suggest: isBlock,
603
701
  ...widgetState,
604
702
  };
703
+ const blockHeight = isBlock ? def.estimatedHeight?.(props) : undefined;
605
704
  const widget: WidgetType | undefined = def.factory
606
705
  ? (def.factory(props) ?? undefined)
607
706
  : def.Component
608
- ? new StubWidget(widgetId, def.Component, props, notifier, false, isBlock)
707
+ ? new StubWidget(widgetId, def.Component, props, notifier, false, isBlock, blockHeight, def.debug)
609
708
  : undefined;
610
709
  if (widget) {
611
710
  builder.add(
@@ -667,7 +766,7 @@ const buildDecorations = (
667
766
  const widget: WidgetType | undefined = def.factory
668
767
  ? (def.factory(mergedProps) ?? undefined)
669
768
  : def.Component
670
- ? new StubWidget(widgetId, def.Component, mergedProps, notifier, true)
769
+ ? new StubWidget(widgetId, def.Component, mergedProps, notifier, true, undefined, undefined, def.debug)
671
770
  : undefined;
672
771
 
673
772
  if (widget) {
@@ -10,7 +10,7 @@ import { trim } from '@dxos/util';
10
10
 
11
11
  import { extendedMarkdown } from './extended-markdown';
12
12
  import TEXT from './testing/text.md?raw';
13
- import { xmlTags } from './xml-tags';
13
+ import { type XmlWidgetRegistry, xmlTags } from './xml-tags';
14
14
  import { type Tag, nodeToJson } from './xml-util';
15
15
 
16
16
  type ParsedElement = Tag & {
@@ -22,7 +22,7 @@ type ParsedElement = Tag & {
22
22
  * Helper to extract all parsed XML elements from a document.
23
23
  * Checks completeness by verifying the Element node has a CloseTag child.
24
24
  */
25
- const parseElements = (doc: string, registry: Record<string, any> = {}): ParsedElement[] => {
25
+ const parseElements = (doc: string, registry: XmlWidgetRegistry = {}): ParsedElement[] => {
26
26
  const state = EditorState.create({
27
27
  doc,
28
28
  extensions: [extendedMarkdown({ registry }), xmlTags({ registry })],
@@ -0,0 +1,94 @@
1
+ //
2
+ // Copyright 2026 DXOS.org
3
+ //
4
+
5
+ import { type EditorState, type Extension, Facet, RangeSet } from '@codemirror/state';
6
+ import { EditorView, GutterMarker, gutter } from '@codemirror/view';
7
+
8
+ /**
9
+ * A change-bar gutter marker: a vertical bar tinted with the author's colour. Full line height by
10
+ * default; `rows` caps it to that many text rows (in `lh` units) — a BLOCK-insert proposal renders
11
+ * as a widget occupying the top rows of its host line, and the bar must cover the proposal's rows
12
+ * without tinting the host line's own text below it.
13
+ */
14
+ export class ChangeBarMarker extends GutterMarker {
15
+ #colour: string;
16
+ #rows?: number;
17
+ #offsetRows?: number;
18
+
19
+ constructor(colour: string, rows?: number, offsetRows?: number) {
20
+ super();
21
+ this.#colour = colour;
22
+ this.#rows = rows;
23
+ this.#offsetRows = offsetRows;
24
+ }
25
+
26
+ override eq(other: ChangeBarMarker): boolean {
27
+ return other.#colour === this.#colour && other.#rows === this.#rows && other.#offsetRows === this.#offsetRows;
28
+ }
29
+
30
+ override toDOM(): HTMLElement {
31
+ const bar = document.createElement('div');
32
+ bar.className = 'cm-change-bar';
33
+ // Attribution colour is per-author (dynamic); the bar geometry lives in the theme class.
34
+ bar.style.background = this.#colour;
35
+ if (this.#rows !== undefined) {
36
+ bar.style.height = `calc(${this.#rows}lh)`;
37
+ }
38
+ // A proposal that STARTS with a newline renders its text below the break; shift the bar with it.
39
+ if (this.#offsetRows) {
40
+ bar.style.marginTop = `calc(${this.#offsetRows}lh)`;
41
+ }
42
+ return bar;
43
+ }
44
+ }
45
+
46
+ /**
47
+ * Per-line change-bar markers for one suggestion source, derived from editor state. Contributed by the
48
+ * suggestion extensions (`trackChanges`, `suggestions`) so each can colour its own lines by author.
49
+ */
50
+ export type ChangeBarProvider = (state: EditorState) => RangeSet<GutterMarker>;
51
+
52
+ const changeBarTheme = EditorView.baseTheme({
53
+ '& .cm-change-bar-gutter': {
54
+ width: '3px',
55
+ paddingInline: '1px',
56
+ },
57
+ '& .cm-change-bar': {
58
+ width: '3px',
59
+ height: '100%',
60
+ borderRadius: '1px',
61
+ },
62
+ });
63
+
64
+ /**
65
+ * Providers of per-line change bars. `enables` adds the single shared gutter (+ theme) once when any
66
+ * provider is present — identical extension instances dedupe — so own edits (`trackChanges`) and foreign
67
+ * suggestions (`suggestions`) share one bar column rather than stacking separate gutters. The gutter is
68
+ * built inside `enables` so its `markers` can read this same facet.
69
+ */
70
+ const changeBarProviders = Facet.define<ChangeBarProvider>({
71
+ enables: (self) => [
72
+ gutter({
73
+ class: 'cm-change-bar-gutter',
74
+ // Merge every contributor's per-line markers into the shared gutter (sorted so co-located markers
75
+ // from different sources interleave rather than throw).
76
+ markers: (view) => {
77
+ const sets = view.state.facet(self).map((provider) => provider(view.state));
78
+ return sets.length ? RangeSet.join(sets) : RangeSet.empty;
79
+ },
80
+ }),
81
+ changeBarTheme,
82
+ ],
83
+ });
84
+
85
+ /** Contribute per-line change bars to the shared author-coloured gutter (see {@link ChangeBarMarker}). */
86
+ export const changeBars = (provider: ChangeBarProvider): Extension => changeBarProviders.of(provider);
87
+
88
+ /**
89
+ * Keeps the change-bar column mounted with no markers. Hosts that toggle review overlays install this
90
+ * once alongside their compartments, so entering/leaving Suggesting reconfigures marker providers
91
+ * inside an existing gutter instead of adding and removing the column — which shifted the text and
92
+ * flickered on every mode switch.
93
+ */
94
+ export const changeBarGutter: Extension = changeBarProviders.of(() => RangeSet.empty);
@@ -0,0 +1,72 @@
1
+ //
2
+ // Copyright 2026 DXOS.org
3
+ //
4
+
5
+ import { EditorView } from '@codemirror/view';
6
+ import { describe, test } from 'vitest';
7
+
8
+ import { comments, createComment } from './comments';
9
+
10
+ describe('createComment', () => {
11
+ test('collapses the selection to its start after creating a comment', ({ expect }) => {
12
+ const created: { cursor: string; from: number }[] = [];
13
+ const view = new EditorView({
14
+ doc: 'The quick brown fox jumps over the lazy dog.',
15
+ extensions: [comments({ id: 'test', onCreate: ({ cursor, from }) => created.push({ cursor, from }) })],
16
+ });
17
+
18
+ // Select "quick".
19
+ view.dispatch({ selection: { anchor: 4, head: 9 } });
20
+ const result = createComment(view);
21
+
22
+ expect(result).to.eq(true);
23
+ expect(created).to.have.length(1);
24
+ // The text selection is collapsed to the start of the commented range.
25
+ expect(view.state.selection.main.empty).to.eq(true);
26
+ expect(view.state.selection.main.head).to.eq(4);
27
+
28
+ view.destroy();
29
+ });
30
+
31
+ test('expands a bare cursor to the word under it', ({ expect }) => {
32
+ const created: { from: number }[] = [];
33
+ const view = new EditorView({
34
+ doc: 'The quick brown fox.',
35
+ extensions: [comments({ id: 'test', onCreate: ({ from }) => created.push({ from }) })],
36
+ });
37
+
38
+ // Cursor inside "quick", no range: the comment expands to the whole word.
39
+ view.dispatch({ selection: { anchor: 6 } });
40
+ expect(createComment(view)).to.eq(true);
41
+ expect(created).to.have.length(1);
42
+ expect(created[0].from).to.eq(4);
43
+
44
+ view.destroy();
45
+ });
46
+
47
+ test('is a no-op when there is no word or range under the caret', ({ expect }) => {
48
+ const view = new EditorView({
49
+ doc: ' ',
50
+ extensions: [comments({ id: 'test', onCreate: () => {} })],
51
+ });
52
+
53
+ view.dispatch({ selection: { anchor: 1 } });
54
+ expect(createComment(view)).to.eq(false);
55
+
56
+ view.destroy();
57
+ });
58
+
59
+ test('is prohibited when readonly (e.g. a suggestion branch)', ({ expect }) => {
60
+ const created: unknown[] = [];
61
+ const view = new EditorView({
62
+ doc: 'The quick brown fox.',
63
+ extensions: [comments({ id: 'test', readonly: true, onCreate: () => created.push(1) })],
64
+ });
65
+
66
+ view.dispatch({ selection: { anchor: 4, head: 9 } });
67
+ expect(createComment(view)).to.eq(false);
68
+ expect(created).to.have.length(0);
69
+
70
+ view.destroy();
71
+ });
72
+ });