@dxos/ui-editor 0.10.0 → 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
@@ -3,16 +3,24 @@
3
3
  //
4
4
 
5
5
  import { invertedEffects } from '@codemirror/commands';
6
- import { type ChangeDesc, type Extension, StateEffect, StateField, type Text } from '@codemirror/state';
6
+ import { getChunks } from '@codemirror/merge';
7
+ import {
8
+ type ChangeDesc,
9
+ EditorSelection,
10
+ type Extension,
11
+ StateEffect,
12
+ StateField,
13
+ type Text,
14
+ } from '@codemirror/state';
7
15
  import {
8
16
  type Command,
9
17
  Decoration,
10
18
  EditorView,
11
- type PluginValue,
12
19
  type Rect,
20
+ RectangleMarker,
13
21
  ViewPlugin,
14
- hoverTooltip,
15
22
  keymap,
23
+ layer,
16
24
  } from '@codemirror/view';
17
25
  import sortBy from 'lodash.sortby';
18
26
 
@@ -20,10 +28,219 @@ import { type CleanupFn, debounce } from '@dxos/async';
20
28
  import { log } from '@dxos/log';
21
29
  import { isNonNullable } from '@dxos/util';
22
30
 
23
- import { type Comment, type Range, type RenderCallback } from '../types';
24
- import { Cursor, singleValueFacet, wrapWithCatch } from '../util';
25
- import { markerMark, markerTheme } from './marker';
26
- import { documentId } from './selection';
31
+ import { type Comment, type Range } from '../../types';
32
+ import { Cursor, singleValueFacet, wrapWithCatch } from '../../util';
33
+ import { documentId } from '../state/selection';
34
+
35
+ //
36
+ // Options
37
+ //
38
+
39
+ export type CommentsOptions = {
40
+ /**
41
+ * Document id.
42
+ */
43
+ id: string;
44
+ /**
45
+ * Key shortcut to create a new thread.
46
+ */
47
+ key?: string;
48
+ /**
49
+ * Get the current comments.
50
+ */
51
+ getComments?: () => Comment[];
52
+ /**
53
+ * Subscribe to external comment updates.
54
+ */
55
+ subscribe?: (sink: () => void) => CleanupFn;
56
+ /**
57
+ * The branch under review; new comments are tagged with it (undefined = main/unbranched). Scopes
58
+ * a comment to the branch being reviewed so its visibility tracks the active diff.
59
+ */
60
+ reviewBranch?: string;
61
+ /**
62
+ * Prohibit creating new comments (e.g. on a per-user suggestion branch). Existing comments still
63
+ * render; the create command becomes a no-op.
64
+ */
65
+ readonly?: boolean;
66
+ /**
67
+ * Called to create a new thread and return the thread id.
68
+ */
69
+ onCreate?: (params: { cursor: string; from: number; location?: Rect | null; branch?: string }) => void;
70
+ /**
71
+ * Selection cut/deleted.
72
+ */
73
+ onDelete?: (params: { id: string }) => void;
74
+ /**
75
+ * Called when a comment is moved.
76
+ */
77
+ onUpdate?: (params: { id: string; cursor: string }) => void;
78
+ /**
79
+ * Called to notify which thread is currently closest to the cursor.
80
+ */
81
+ onSelect?: (state: CommentsState) => void;
82
+ /**
83
+ * Called when a comment is deliberately activated (clicked). Distinct from `onSelect` (passive
84
+ * cursor-proximity): a click is an explicit user intent, e.g. to reveal the thread in a companion.
85
+ * The editor-side selection/highlight is already applied by the time this fires.
86
+ */
87
+ onActivate?: (id: string) => void;
88
+ };
89
+
90
+ /**
91
+ * Comment threads.
92
+ * 1). Updates the EditorModel to store relative selections for a set of comments threads.
93
+ * Since the selections are relative, they do not need to be updated when the document is edited.
94
+ * 2). Implements a StateField to track absolute selections corresponding to the comments (i.e., when the document is edited).
95
+ * 3). Creates decoration marks to apply classes to each selection.
96
+ * 4). Tracks the current cursor position to:
97
+ * a). Update the decoration to show if the cursor is within a current selection.
98
+ * b). Calls a handler to indicate which is the closest selection (e.g., to update the thread sidebar).
99
+ * 5). Optionally, implements a hoverTooltip to show hints when creating a selection range.
100
+ */
101
+ export const comments = (options: CommentsOptions): Extension => {
102
+ const { key: shortcut = "meta-'" } = options;
103
+
104
+ const handleSelect = debounce((state: CommentsState) => options.onSelect?.(state), 200);
105
+
106
+ return [
107
+ optionsFacet.of(options),
108
+ options.id ? documentId.of(options.id) : undefined,
109
+ commentsState,
110
+ commentsDecorations,
111
+ commentsHighlightLayer,
112
+ handleCommentClick,
113
+ styles,
114
+
115
+ //
116
+ // External comment synchronization.
117
+ //
118
+ ViewPlugin.fromClass(
119
+ class {
120
+ private readonly unsubscribe: () => void;
121
+ constructor(view: EditorView) {
122
+ const { id } = options;
123
+ const updateComments = () => {
124
+ const comments = options.getComments?.() ?? [];
125
+ // Local `id` const so the truthiness narrowing survives into the microtask closure.
126
+ if (id && id === view.state.facet(documentId)) {
127
+ queueMicrotask(() => view.dispatch({ effects: setComments.of({ id, comments }) }));
128
+ }
129
+ };
130
+
131
+ this.unsubscribe = options.subscribe?.(updateComments) ?? (() => {});
132
+ // Prime the initial decoration pass: `subscribe` may not emit for an already-resolved source
133
+ // (e.g. an ECHO query whose results resolved before mount), so read once now that the source is
134
+ // subscribed. Owning this here means adapters never have to prime manually.
135
+ updateComments();
136
+ }
137
+
138
+ destroy = () => {
139
+ this.unsubscribe();
140
+ };
141
+ },
142
+ ),
143
+
144
+ //
145
+ // Keymap.
146
+ //
147
+ options.onCreate &&
148
+ keymap.of([
149
+ {
150
+ key: shortcut,
151
+ run: wrapWithCatch(createComment),
152
+ },
153
+ ]),
154
+
155
+ //
156
+ // Track deleted ranges and update ranges for decorations.
157
+ //
158
+ EditorView.updateListener.of(({ view, state, changes }) => {
159
+ let mod = false;
160
+ const { comments, ...value } = state.field(commentsState);
161
+ changes.iterChanges((from, to, from2, to2) => {
162
+ comments.forEach(({ comment, range }) => {
163
+ // Only comments with a cursor reach this state (setComments filters cursor-less ones).
164
+ if (!comment.cursor) {
165
+ return;
166
+ }
167
+
168
+ // Test if range deleted.
169
+ if (from2 === to2) {
170
+ const newRange = Cursor.getRangeFromCursor(view.state, comment.cursor);
171
+ if (!newRange || newRange.to - newRange.from === 0) {
172
+ options.onDelete?.({ id: comment.id });
173
+ }
174
+ }
175
+
176
+ // Update range.
177
+ if (from <= range.to) {
178
+ const newRange = Cursor.getRangeFromCursor(view.state, comment.cursor);
179
+ Object.assign(range, newRange);
180
+ mod = true;
181
+ }
182
+ });
183
+ });
184
+
185
+ if (mod) {
186
+ view.dispatch({ effects: setCommentState.of({ comments, ...value }) });
187
+ }
188
+ }),
189
+
190
+ //
191
+ // Track selection/proximity.
192
+ //
193
+ EditorView.updateListener.of(({ view, state, transactions }) => {
194
+ let min = Infinity;
195
+ const { selection: applied, comments } = state.field(commentsState);
196
+ const { current, closest } = applied;
197
+
198
+ const notify = (selection: SelectionState) =>
199
+ handleSelect({
200
+ selection,
201
+ id: state.facet(documentId),
202
+ comments: comments.map(({ comment, range }) => ({
203
+ comment,
204
+ range,
205
+ location: view.coordsAtPos(range.from),
206
+ })),
207
+ });
208
+
209
+ // An explicit `setSelection` is authoritative: selecting a thread in the comments companion sets
210
+ // `current` and moves the caret in one transaction, and the caret does not always land inside the
211
+ // tracked range — proximity would then clear the very selection that transaction just made. Report
212
+ // the applied selection so the app still learns which thread is current, but leave it as set.
213
+ if (transactions.some((tr) => tr.effects.some((effect) => effect.is(setSelection)))) {
214
+ notify(applied);
215
+ return;
216
+ }
217
+
218
+ const { head } = state.selection.main;
219
+ const selection: SelectionState = {};
220
+ comments.forEach(({ comment, range }) => {
221
+ if (head >= range.from && head <= range.to) {
222
+ selection.current = comment.id;
223
+ selection.closest = undefined;
224
+ }
225
+
226
+ if (!selection.current) {
227
+ const d = Math.min(Math.abs(head - range.from), Math.abs(head - range.to));
228
+ if (d < min) {
229
+ selection.closest = comment.id;
230
+ min = d;
231
+ }
232
+ }
233
+ });
234
+
235
+ if (selection.current !== current || selection.closest !== closest) {
236
+ view.dispatch({ effects: setSelection.of(selection) });
237
+ notify(selection);
238
+ }
239
+ }),
240
+
241
+ options.onUpdate && trackPastedComments(options.onUpdate),
242
+ ].filter(isNonNullable);
243
+ };
27
244
 
28
245
  //
29
246
  // State management.
@@ -55,6 +272,7 @@ const setCommentState = StateEffect.define<CommentsState>();
55
272
  /**
56
273
  * State field (reducer) that tracks comment ranges.
57
274
  * The ranges are tracked as Automerge cursors from which the absolute indexed ranges can be computed.
275
+ * Included by {@link comments}; exported for direct state reads.
58
276
  */
59
277
  export const commentsState = StateField.define<CommentsState>({
60
278
  create: (state) => ({
@@ -97,19 +315,8 @@ export const commentsState = StateField.define<CommentsState>({
97
315
  },
98
316
  });
99
317
 
100
- /**
101
- * NOTE: Matches search.
102
- */
103
- // Surface/box-shadow come from the shared `markerTheme`, tinted by the mark's `data-hue`; the comment
104
- // just adds the pointer affordance.
105
- const styles = EditorView.theme({
106
- '.cm-comment > span': {
107
- cursor: 'pointer',
108
- },
109
- });
110
-
111
318
  const createCommentMark = (id: string, isCurrent: boolean) =>
112
- markerMark(isCurrent ? 'orange' : 'teal', {
319
+ Decoration.mark({
113
320
  class: 'cm-comment',
114
321
  attributes: {
115
322
  'data-testid': 'cm-comment',
@@ -119,7 +326,8 @@ const createCommentMark = (id: string, isCurrent: boolean) =>
119
326
  });
120
327
 
121
328
  /**
122
- * Decorate ranges.
329
+ * Transparent inline marks that carry `data-comment-id` for click routing (see `handleCommentClick`).
330
+ * The colour comes from `commentsHighlightLayer`.
123
331
  */
124
332
  const commentsDecorations = EditorView.decorations.compute([commentsState], (state) => {
125
333
  const {
@@ -146,32 +354,87 @@ const commentsDecorations = EditorView.decorations.compute([commentsState], (sta
146
354
  return Decoration.set(decorations);
147
355
  });
148
356
 
149
- export const commentClickedEffect = StateEffect.define<string>();
357
+ /**
358
+ * Selection-style highlight: draws each comment range as a layer of rectangle markers below the text.
359
+ * `RectangleMarker.forRange` extends wrapped (non-final) lines to the line edge, so a multi-line comment
360
+ * reads as one continuous block rather than ragged per-word inline backgrounds.
361
+ */
362
+ const commentsHighlightLayer = layer({
363
+ above: false,
364
+ class: 'cm-commentsHighlightLayer',
365
+ update: (update) =>
366
+ update.docChanged ||
367
+ update.viewportChanged ||
368
+ update.geometryChanged ||
369
+ update.selectionSet ||
370
+ update.transactions.some((tr) =>
371
+ tr.effects.some((effect) => effect.is(setSelection) || effect.is(setComments) || effect.is(setCommentState)),
372
+ ),
373
+ markers: (view) => {
374
+ const {
375
+ selection: { current },
376
+ comments,
377
+ } = view.state.field(commentsState);
378
+
379
+ return sortBy(comments ?? [], (comment) => comment.range.from).flatMap((comment) => {
380
+ const { from, to } = comment.range;
381
+ if (from >= to) {
382
+ return [];
383
+ }
384
+
385
+ const className =
386
+ comment.comment.id === current ? 'cm-comment-highlight cm-comment-highlight-current' : 'cm-comment-highlight';
387
+ const range = EditorSelection.range(from, to);
388
+ const markers = RectangleMarker.forRange(view, className, range);
389
+ // A single rectangle means the comment fits on one visual line — round its corners.
390
+ return markers.length === 1
391
+ ? RectangleMarker.forRange(view, `${className} cm-comment-highlight-single`, range)
392
+ : markers;
393
+ });
394
+ },
395
+ });
150
396
 
151
397
  const handleCommentClick = EditorView.domEventHandlers({
152
398
  click: (event, view) => {
153
- let target = event.target as HTMLElement;
154
- const editorRoot = view.dom;
155
-
156
- // Traverse up the DOM tree looking for an element with data-comment-id
157
- // Stop if we reach the editor root or find the comment id
158
- while (target && target !== editorRoot && !target.hasAttribute('data-comment-id')) {
159
- target = target.parentElement as HTMLElement;
399
+ const id = commentIdAtClick(event, view);
400
+ if (!id) {
401
+ return false;
160
402
  }
161
403
 
162
- // Check if we found a comment id and are still within the editor
163
- if (target && target !== editorRoot) {
164
- const commentId = target.getAttribute('data-comment-id');
165
- if (commentId) {
166
- view.dispatch({ effects: commentClickedEffect.of(commentId) });
167
- return true;
168
- }
169
- }
170
-
171
- return false;
404
+ // Select the clicked thread in the editor (moves the caret into the range so the proximity tracker
405
+ // keeps it current) and notify the app for deliberate-click behaviour (e.g. reveal in a companion).
406
+ scrollCommentIntoView(view, id);
407
+ view.state.facet(optionsFacet).onActivate?.(id);
408
+ return true;
172
409
  },
173
410
  });
174
411
 
412
+ /**
413
+ * Resolve the comment id under a click. Prefers the DOM target (a direct hit on the `.cm-comment`
414
+ * span), then falls back to a document-position hit-test: the highlight-layer rectangles
415
+ * (pointer-events: none) sit over the text, so a click often lands on the `.cm-line` (an ancestor of
416
+ * the span) and an upward target walk would miss it.
417
+ */
418
+ const commentIdAtClick = (event: MouseEvent, view: EditorView): string | undefined => {
419
+ let target = event.target as HTMLElement | null;
420
+ const editorRoot = view.dom;
421
+ while (target && target !== editorRoot && !target.hasAttribute?.('data-comment-id')) {
422
+ target = target.parentElement;
423
+ }
424
+ const domId = target && target !== editorRoot ? target.getAttribute('data-comment-id') : null;
425
+ if (domId) {
426
+ return domId;
427
+ }
428
+
429
+ const pos = view.posAtCoords({ x: event.clientX, y: event.clientY });
430
+ if (pos != null) {
431
+ const commentState = view.state.field(commentsState, false);
432
+ return commentState?.comments.find(({ range }) => pos >= range.from && pos <= range.to)?.comment.id;
433
+ }
434
+
435
+ return undefined;
436
+ };
437
+
175
438
  //
176
439
  // Cut-and-paste.
177
440
  //
@@ -290,218 +553,65 @@ const mapTrackedComment = (comment: TrackedComment, changes: ChangeDesc) => ({
290
553
  * These are attached to undone/redone transactions in the editor for the purpose of restoring comments
291
554
  * that were deleted by the original changes.
292
555
  */
293
- const restoreCommentEffect = StateEffect.define<TrackedComment>({ map: mapTrackedComment });
556
+ const restoreCommentEffect = StateEffect.define<TrackedComment>({
557
+ map: mapTrackedComment,
558
+ });
559
+
560
+ const optionsFacet = singleValueFacet<CommentsOptions>();
294
561
 
295
562
  /**
296
563
  * Create comment thread action.
297
564
  */
298
565
  export const createComment: Command = (view) => {
299
566
  const options = view.state.facet(optionsFacet);
300
- const { from, to } = view.state.selection.main;
301
- if (from === to) {
567
+ // Comment creation is prohibited on this surface (e.g. a suggestion branch).
568
+ if (options.readonly) {
302
569
  return false;
303
570
  }
304
571
 
305
- // Don't allow selection at end of document.
306
- if (to === view.state.doc.length) {
307
- view.dispatch({
308
- changes: {
309
- from: to,
310
- insert: '\n',
311
- },
312
- });
572
+ let { from, to } = view.state.selection.main;
573
+
574
+ // Snap to the largest logical region so commenting never depends on a precise selection. Inside a
575
+ // (unified) diff hunk the comment covers the whole changed hunk (a bare cursor in the hunk is
576
+ // enough); otherwise, with no selection, it expands to the word under the cursor. The diff case
577
+ // takes precedence so a comment on a change visibly covers it.
578
+ const merge = getChunks(view.state);
579
+ const chunk = merge?.chunks.find((candidate) => candidate.fromB <= to && candidate.endB >= from);
580
+ if (chunk) {
581
+ from = chunk.fromB;
582
+ to = Math.min(chunk.endB, view.state.doc.length);
583
+ } else if (from === to) {
584
+ const word = view.state.wordAt(from);
585
+ if (word) {
586
+ from = word.from;
587
+ to = word.to;
588
+ }
589
+ }
590
+
591
+ // Exclude trailing newlines so the anchor stays within content and never reaches the document end.
592
+ // Anchoring at the very end previously required inserting a newline to stabilise the end cursor — a
593
+ // visible, unwanted mutation; the end cursor instead associates with the preceding character.
594
+ while (to > from && view.state.doc.sliceString(to - 1, to) === '\n') {
595
+ to--;
596
+ }
597
+
598
+ if (from === to) {
599
+ return false;
313
600
  }
314
601
 
315
602
  const cursor = Cursor.getCursorFromRange(view.state, { from, to });
316
603
  if (cursor) {
317
- // Create thread via callback.
318
- options.onCreate?.({ cursor, from, location: view.coordsAtPos(from) });
604
+ // Collapse the text selection now that the range is captured by the comment (the caret stays within
605
+ // the new comment, keeping it the current thread).
606
+ view.dispatch({ selection: { anchor: from } });
607
+ // Create thread via callback; branch-tag it with the branch under review (undefined = main).
608
+ options.onCreate?.({ cursor, from, location: view.coordsAtPos(from), branch: options.reviewBranch });
319
609
  return true;
320
610
  }
321
611
 
322
612
  return false;
323
613
  };
324
614
 
325
- //
326
- // Options
327
- //
328
-
329
- export type CommentsOptions = {
330
- /**
331
- * Document id.
332
- */
333
- id?: string;
334
- /**
335
- * Key shortcut to create a new thread.
336
- */
337
- key?: string;
338
- /**
339
- * Called to render tooltip.
340
- */
341
- renderTooltip?: RenderCallback<{ shortcut: string }>;
342
- /**
343
- * Called to create a new thread and return the thread id.
344
- */
345
- onCreate?: (params: { cursor: string; from: number; location?: Rect | null }) => void;
346
- /**
347
- * Selection cut/deleted.
348
- */
349
- onDelete?: (params: { id: string }) => void;
350
- /**
351
- * Called when a comment is moved.
352
- */
353
- onUpdate?: (params: { id: string; cursor: string }) => void;
354
- /**
355
- * Called to notify which thread is currently closest to the cursor.
356
- */
357
- onSelect?: (state: CommentsState) => void;
358
- };
359
-
360
- const optionsFacet = singleValueFacet<CommentsOptions>();
361
-
362
- /**
363
- * Comment threads.
364
- * 1). Updates the EditorModel to store relative selections for a set of comments threads.
365
- * Since the selections are relative, they do not need to be updated when the document is edited.
366
- * 2). Implements a StateField to track absolute selections corresponding to the comments (i.e., when the document is edited).
367
- * 3). Creates decoration marks to apply classes to each selection.
368
- * 4). Tracks the current cursor position to:
369
- * a). Update the decoration to show if the cursor is within a current selection.
370
- * b). Calls a handler to indicate which is the closest selection (e.g., to update the thread sidebar).
371
- * 5). Optionally, implements a hoverTooltip to show hints when creating a selection range.
372
- */
373
- export const comments = (options: CommentsOptions = {}): Extension => {
374
- const { key: shortcut = "meta-'" } = options;
375
-
376
- const handleSelect = debounce((state: CommentsState) => options.onSelect?.(state), 200);
377
-
378
- return [
379
- optionsFacet.of(options),
380
- options.id ? documentId.of(options.id) : undefined,
381
- commentsState,
382
- commentsDecorations,
383
- handleCommentClick,
384
- markerTheme(),
385
- styles,
386
-
387
- //
388
- // Keymap.
389
- //
390
- options.onCreate &&
391
- keymap.of([
392
- {
393
- key: shortcut,
394
- run: wrapWithCatch(createComment),
395
- },
396
- ]),
397
-
398
- //
399
- // Hover tooltip (for key shortcut hints, etc.)
400
- // TODO(burdon): Factor out to generic hints extension for current selection/line.
401
- //
402
- options.renderTooltip &&
403
- hoverTooltip(
404
- (view, pos) => {
405
- const selection = view.state.selection.main;
406
- if (selection && pos >= selection.from && pos <= selection.to) {
407
- return {
408
- pos: selection.from,
409
- end: selection.to,
410
- above: true,
411
- create: () => {
412
- const el = document.createElement('div');
413
- options.renderTooltip!(el, { shortcut }, view);
414
- return { dom: el, offset: { x: 0, y: 8 } };
415
- },
416
- };
417
- }
418
-
419
- return null;
420
- },
421
- {
422
- // TODO(burdon): Hide on change triggered immediately?
423
- // hideOnChange: true,
424
- hoverTime: 1_000,
425
- },
426
- ),
427
-
428
- //
429
- // Track deleted ranges and update ranges for decorations.
430
- //
431
- EditorView.updateListener.of(({ view, state, changes }) => {
432
- let mod = false;
433
- const { comments, ...value } = state.field(commentsState);
434
- changes.iterChanges((from, to, from2, to2) => {
435
- comments.forEach(({ comment, range }) => {
436
- // Test if range deleted.
437
- if (from2 === to2) {
438
- const newRange = Cursor.getRangeFromCursor(view.state, comment.cursor!);
439
- if (!newRange || newRange.to - newRange.from === 0) {
440
- options.onDelete?.({ id: comment.id });
441
- }
442
- }
443
-
444
- // Update range.
445
- if (from <= range.to) {
446
- const newRange = Cursor.getRangeFromCursor(view.state, comment.cursor!);
447
- Object.assign(range, newRange);
448
- mod = true;
449
- }
450
- });
451
- });
452
-
453
- if (mod) {
454
- view.dispatch({ effects: setCommentState.of({ comments, ...value }) });
455
- }
456
- }),
457
-
458
- //
459
- // Track selection/proximity.
460
- //
461
- EditorView.updateListener.of(({ view, state }) => {
462
- let min = Infinity;
463
- const {
464
- selection: { current, closest },
465
- comments,
466
- } = state.field(commentsState);
467
-
468
- const { head } = state.selection.main;
469
- const selection: SelectionState = {};
470
- comments.forEach(({ comment, range }) => {
471
- if (head >= range.from && head <= range.to) {
472
- selection.current = comment.id;
473
- selection.closest = undefined;
474
- }
475
-
476
- if (!selection.current) {
477
- const d = Math.min(Math.abs(head - range.from), Math.abs(head - range.to));
478
- if (d < min) {
479
- selection.closest = comment.id;
480
- min = d;
481
- }
482
- }
483
- });
484
-
485
- if (selection.current !== current || selection.closest !== closest) {
486
- view.dispatch({ effects: setSelection.of(selection) });
487
-
488
- // Update callback.
489
- handleSelect({
490
- selection,
491
- id: state.facet(documentId),
492
- comments: comments.map(({ comment, range }) => ({
493
- comment,
494
- range,
495
- location: view.coordsAtPos(range.from),
496
- })),
497
- });
498
- }
499
- }),
500
-
501
- options.onUpdate && trackPastedComments(options.onUpdate),
502
- ].filter(isNonNullable);
503
- };
504
-
505
615
  //
506
616
  // Utils.
507
617
  //
@@ -532,7 +642,7 @@ export type ScrollThreadOptions = {
532
642
  * Scroll the comment thread with the given id into view (if not already entirely
533
643
  * visible) and mark it the current comment so the editor highlights it.
534
644
  */
535
- export const scrollThreadIntoView = (
645
+ export const scrollCommentIntoView = (
536
646
  view: EditorView,
537
647
  id: string,
538
648
  { y = 'center', yMargin }: ScrollThreadOptions = {},
@@ -548,7 +658,9 @@ export const scrollThreadIntoView = (
548
658
  }
549
659
 
550
660
  const { from, to } = view.state.selection.main;
551
- const needsSelectionUpdate = from !== range.from || to !== range.from;
661
+ // Never collapse a live selection: an attention change in the comments companion can land while the
662
+ // user is selecting text, and moving the caret would silently retarget the comment they create next.
663
+ const needsSelectionUpdate = from === to && from !== range.from;
552
664
  view.dispatch({
553
665
  selection: needsSelectionUpdate ? { anchor: range.from } : undefined,
554
666
  effects: [
@@ -560,38 +672,54 @@ export const scrollThreadIntoView = (
560
672
  };
561
673
 
562
674
  /**
563
- * Manages external comment synchronization for the editor.
564
- * This class subscribes to external comment updates and applies them to the editor view.
675
+ * NOTE: Matches search.
565
676
  */
566
- class ExternalCommentSync implements PluginValue {
567
- private readonly unsubscribe: () => void;
568
-
569
- constructor(view: EditorView, id: string, subscribe: (sink: () => void) => CleanupFn, getComments: () => Comment[]) {
570
- const updateComments = () => {
571
- const comments = getComments();
572
- if (id === view.state.facet(documentId)) {
573
- queueMicrotask(() => view.dispatch({ effects: setComments.of({ id, comments }) }));
574
- }
575
- };
576
-
577
- this.unsubscribe = subscribe(updateComments);
578
- }
579
-
580
- destroy = () => {
581
- this.unsubscribe();
582
- };
583
- }
584
-
585
- // TODO(burdon): Needs comment.
586
- export const createExternalCommentSync = (
587
- id: string,
588
- subscribe: (sink: () => void) => CleanupFn,
589
- getComments: () => Comment[],
590
- ): Extension =>
591
- ViewPlugin.fromClass(
592
- class {
593
- constructor(view: EditorView) {
594
- return new ExternalCommentSync(view, id, subscribe, getComments);
595
- }
596
- },
597
- );
677
+ // The visible highlight is drawn by `commentsHighlightLayer` (below) as a layer of rectangle markers,
678
+ // so — like a text selection — it fills wrapped lines to the line edge instead of stopping at the last
679
+ // glyph. The inline `cm-comment` mark is now transparent and exists only to carry `data-comment-id`
680
+ // (click routing) and the pointer affordance. No `border-radius`: the per-line rectangles abut, so
681
+ // rounding each would pinch the interior edges into notches on a multi-line comment.
682
+ const styles = EditorView.theme({
683
+ // The layer only paints the background; text colour comes from the inline mark, which wraps exactly
684
+ // the comment text. `!important` and the descendant selector win over markdown syntax-highlight tokens
685
+ // nested inside the range.
686
+ '.cm-comment, .cm-comment *': {
687
+ color: 'var(--color-teal-fg) !important',
688
+ },
689
+ '.cm-comment[data-current="1"], .cm-comment[data-current="1"] *': {
690
+ color: 'var(--color-orange-fg) !important',
691
+ },
692
+ '.cm-comment': {
693
+ cursor: 'pointer',
694
+ },
695
+ // Layer wrapper: sit behind the text and never swallow clicks meant for the `cm-comment` mark.
696
+ '.cm-commentsHighlightLayer': {
697
+ pointerEvents: 'none',
698
+ },
699
+ // `box-shadow` with a 1px spread extends the block 1px on every side in the same colour — visual
700
+ // padding without changing layout. Vertically adjacent line rectangles paint into each other's gap
701
+ // with the same colour, so a multi-line comment stays seamless.
702
+ // 2px horizontal breathing room around the text: `padding-inline` widens the background box and the
703
+ // compensating negative `margin-inline` keeps it aligned to the text; `content-box` makes the padding
704
+ // grow the box (rather than shrink the content) so the fill and border-radius extend with it.
705
+ // `pointer-events: none` on the rectangles themselves (not only the layer wrapper) so a click over a
706
+ // comment passes through to the `.cm-comment` mark's `data-comment-id` (and reaches `handleCommentClick`)
707
+ // instead of landing on a highlight rectangle that carries no id.
708
+ '.cm-comment-highlight': {
709
+ backgroundColor: 'var(--color-teal-bg)',
710
+ boxShadow: '0 0 0 1px var(--color-teal-bg)',
711
+ boxSizing: 'content-box',
712
+ marginInline: '-2px',
713
+ paddingInline: '2px',
714
+ pointerEvents: 'none',
715
+ },
716
+ '.cm-comment-highlight-current': {
717
+ backgroundColor: 'var(--color-orange-bg)',
718
+ boxShadow: '0 0 0 1px var(--color-orange-bg)',
719
+ },
720
+ // Only round a comment that occupies a single visual line: a multi-line comment is drawn as several
721
+ // abutting rectangles, so rounding each would notch the interior edges.
722
+ '.cm-comment-highlight-single': {
723
+ borderRadius: '0.25rem',
724
+ },
725
+ });