@ecsplico/editor 2.1.1 → 3.0.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 (701) hide show
  1. package/CHANGELOG.md +74 -1
  2. package/README.md +39 -156
  3. package/dist/adapters/comments/drizzle.d.ts +1 -1
  4. package/dist/adapters/comments/{client.js → rest-model.js} +3 -3
  5. package/dist/adapters/comments/rest-model.js.map +1 -0
  6. package/dist/adapters/comments/types.d.ts +2 -2
  7. package/dist/adapters/document-state.d.ts +23 -0
  8. package/dist/adapters/document-state.js +66 -0
  9. package/dist/adapters/document-state.js.map +1 -0
  10. package/dist/adapters/documents.js +14 -11
  11. package/dist/adapters/documents.js.map +1 -1
  12. package/dist/adapters/drizzle.d.ts +2 -2
  13. package/dist/adapters/drizzle.js +97 -88
  14. package/dist/adapters/drizzle.js.map +1 -1
  15. package/dist/adapters/forge.d.ts +12 -7
  16. package/dist/adapters/forge.js +38 -45
  17. package/dist/adapters/forge.js.map +1 -1
  18. package/dist/adapters/http.d.ts +20 -0
  19. package/dist/adapters/http.js +68 -0
  20. package/dist/adapters/http.js.map +1 -0
  21. package/dist/adapters/index.d.ts +5 -5
  22. package/dist/adapters/json.d.ts +3 -3
  23. package/dist/adapters/json.js +58 -49
  24. package/dist/adapters/json.js.map +1 -1
  25. package/dist/adapters/memory.d.ts +21 -0
  26. package/dist/adapters/memory.js +53 -0
  27. package/dist/adapters/memory.js.map +1 -0
  28. package/dist/adapters/nitro.d.ts +23 -20
  29. package/dist/adapters/nitro.js +58 -163
  30. package/dist/adapters/nitro.js.map +1 -1
  31. package/dist/adapters/react.d.ts +55 -0
  32. package/dist/adapters/react.js +209 -0
  33. package/dist/adapters/react.js.map +1 -0
  34. package/dist/adapters/shared.d.ts +15 -21
  35. package/dist/adapters/shared.js +10 -8
  36. package/dist/adapters/shared.js.map +1 -1
  37. package/dist/adapters/vue.d.ts +15 -30
  38. package/dist/adapters/vue.js +36 -87
  39. package/dist/adapters/vue.js.map +1 -1
  40. package/dist/code/CodeSurface.vue.d.ts +3 -3
  41. package/dist/config/index.d.ts +105 -0
  42. package/dist/config/index.js +95 -0
  43. package/dist/config/index.js.map +1 -0
  44. package/dist/core/abilities.js +1 -0
  45. package/dist/core/abilities.js.map +1 -1
  46. package/dist/{adapters/routes.js → core/api-routes.js} +5 -3
  47. package/dist/core/api-routes.js.map +1 -0
  48. package/dist/core/backend-capability.d.ts +7 -0
  49. package/dist/core/backend-capability.js +17 -0
  50. package/dist/core/backend-capability.js.map +1 -0
  51. package/dist/core/backend-types.d.ts +245 -0
  52. package/dist/core/backend-types.js +17 -0
  53. package/dist/core/backend-types.js.map +1 -0
  54. package/dist/core/backend.d.ts +108 -0
  55. package/dist/core/backend.js +14 -0
  56. package/dist/core/backend.js.map +1 -0
  57. package/dist/core/block-convert.d.ts +7 -5
  58. package/dist/core/block-convert.js +28 -5
  59. package/dist/core/block-convert.js.map +1 -1
  60. package/dist/core/command-types.d.ts +89 -0
  61. package/dist/core/commands.d.ts +40 -0
  62. package/dist/core/commands.js +151 -0
  63. package/dist/core/commands.js.map +1 -0
  64. package/dist/core/context.d.ts +17 -20
  65. package/dist/core/context.js +24 -21
  66. package/dist/core/context.js.map +1 -1
  67. package/dist/core/core-feature.d.ts +22 -7
  68. package/dist/core/core-feature.js +51 -18
  69. package/dist/core/core-feature.js.map +1 -1
  70. package/dist/core/define-editor.d.ts +4 -3
  71. package/dist/core/define-editor.js +14 -7
  72. package/dist/core/define-editor.js.map +1 -1
  73. package/dist/core/document-markdown.js +12 -3
  74. package/dist/core/document-markdown.js.map +1 -1
  75. package/dist/core/editor-ui.d.ts +8 -1
  76. package/dist/core/editor-ui.js +9 -8
  77. package/dist/core/editor-ui.js.map +1 -1
  78. package/dist/core/extension-points.d.ts +3 -15
  79. package/dist/core/feature-context.d.ts +8 -7
  80. package/dist/core/feature-context.js +12 -11
  81. package/dist/core/feature-context.js.map +1 -1
  82. package/dist/core/feature.d.ts +35 -19
  83. package/dist/core/feature.js.map +1 -1
  84. package/dist/core/fences.d.ts +2 -1
  85. package/dist/core/fences.js +3 -2
  86. package/dist/core/fences.js.map +1 -1
  87. package/dist/core/fetch-error.d.ts +1 -1
  88. package/dist/core/fetch-error.js +3 -1
  89. package/dist/core/fetch-error.js.map +1 -1
  90. package/dist/core/hash.d.ts +5 -0
  91. package/dist/core/hash.js +11 -0
  92. package/dist/core/hash.js.map +1 -0
  93. package/dist/core/http-backend.d.ts +11 -0
  94. package/dist/core/http-backend.js +195 -0
  95. package/dist/core/http-backend.js.map +1 -0
  96. package/dist/core/index.d.ts +14 -9
  97. package/dist/core/index.js +12 -9
  98. package/dist/core/palette.d.ts +48 -0
  99. package/dist/core/palette.js +95 -0
  100. package/dist/core/palette.js.map +1 -0
  101. package/dist/core/schema/abilities.d.ts +2 -1
  102. package/dist/core/schema/abilities.js +5 -1
  103. package/dist/core/schema/abilities.js.map +1 -1
  104. package/dist/core/schema/index.d.ts +11 -5
  105. package/dist/core/schema/index.js +13 -8
  106. package/dist/core/schema/index.js.map +1 -1
  107. package/dist/core/schema/mark-flags.d.ts +8 -1
  108. package/dist/core/schema/of-features.d.ts +13 -0
  109. package/dist/core/schema/of-features.js +14 -0
  110. package/dist/core/schema/of-features.js.map +1 -0
  111. package/dist/core/slash.d.ts +8 -6
  112. package/dist/core/slash.js +24 -16
  113. package/dist/core/slash.js.map +1 -1
  114. package/dist/core/surface-session.js +13 -5
  115. package/dist/core/surface-session.js.map +1 -1
  116. package/dist/core/toolbar-items.d.ts +10 -4
  117. package/dist/core/toolbar-items.js +269 -195
  118. package/dist/core/toolbar-items.js.map +1 -1
  119. package/dist/core/util.js +11 -0
  120. package/dist/core/util.js.map +1 -0
  121. package/dist/document/DocumentSurface.d.ts +1 -1
  122. package/dist/document/DocumentSurface.vue.d.ts +3 -3
  123. package/dist/features/ai/agent-op-review.d.ts +1 -1
  124. package/dist/features/ai/agent-op-review.js +1 -1
  125. package/dist/features/ai/agent-ops.js +1 -1
  126. package/dist/features/ai/ai-apply.d.ts +2 -2
  127. package/dist/features/ai/ai-apply.js +1 -1
  128. package/dist/features/ai/ai-review.js +1 -1
  129. package/dist/features/ai/ai-sse.d.ts +6 -6
  130. package/dist/features/ai/ai-sse.js +20 -63
  131. package/dist/features/ai/ai-sse.js.map +1 -1
  132. package/dist/features/ai/assistant.d.ts +8 -7
  133. package/dist/features/ai/assistant.js +3 -3
  134. package/dist/features/ai/assistant.js.map +1 -1
  135. package/dist/features/ai/block-actions.d.ts +3 -2
  136. package/dist/features/ai/block-actions.js +3 -2
  137. package/dist/features/ai/block-actions.js.map +1 -1
  138. package/dist/features/ai/components/AiSelectionMenu.js +1 -1
  139. package/dist/features/ai/components/DocumentChatAnswer.js +1 -1
  140. package/dist/features/ai/components/DocumentChatOps.vue.d.ts +1 -1
  141. package/dist/features/ai/components/SettingsModelProfiles.js +8 -8
  142. package/dist/features/ai/components/SettingsModelProfiles.js.map +1 -1
  143. package/dist/features/ai/document-chat-model.d.ts +8 -7
  144. package/dist/features/ai/document-chat-model.js +5 -5
  145. package/dist/features/ai/document-chat-model.js.map +1 -1
  146. package/dist/features/ai/document-chat.js +1 -1
  147. package/dist/features/ai/feature.js +27 -14
  148. package/dist/features/ai/feature.js.map +1 -1
  149. package/dist/features/ai/ghost-autocomplete.d.ts +7 -6
  150. package/dist/features/ai/ghost-autocomplete.js +6 -9
  151. package/dist/features/ai/ghost-autocomplete.js.map +1 -1
  152. package/dist/features/ai/index.d.ts +4 -3
  153. package/dist/features/ai/index.js +10 -10
  154. package/dist/features/ai/model-profiles.d.ts +5 -4
  155. package/dist/features/ai/model-profiles.js +2 -2
  156. package/dist/features/ai/model-profiles.js.map +1 -1
  157. package/dist/features/ai/protocol/block-lines.js +1 -1
  158. package/dist/features/ai/protocol/block-lines.js.map +1 -1
  159. package/dist/features/ai/protocol/chat.js +4 -1
  160. package/dist/features/ai/protocol/chat.js.map +1 -1
  161. package/dist/features/ai/protocol/index.d.ts +3 -2
  162. package/dist/features/ai/protocol/models.d.ts +2 -16
  163. package/dist/features/ai/protocol/models.js.map +1 -1
  164. package/dist/features/ai/rate-limit.d.ts +1 -1
  165. package/dist/features/ai/rate-limit.js +3 -1
  166. package/dist/features/ai/rate-limit.js.map +1 -1
  167. package/dist/features/ai/react/AiSelectionMenu.js +2 -2
  168. package/dist/features/ai/react/AiSidebar.js +4 -4
  169. package/dist/features/ai/react/DocumentChatAnswer.js +1 -1
  170. package/dist/features/ai/react/DocumentChatOps.d.ts +1 -1
  171. package/dist/features/ai/react/DocumentChatOps.js +1 -1
  172. package/dist/features/ai/react/SettingsModelProfiles.js +8 -10
  173. package/dist/features/ai/react/SettingsModelProfiles.js.map +1 -1
  174. package/dist/features/ai/react/use-ai-assistant.d.ts +1 -1
  175. package/dist/features/ai/react/use-ai-assistant.js +3 -3
  176. package/dist/features/ai/react/use-ai-assistant.js.map +1 -1
  177. package/dist/features/ai/react/use-document-chat.js +2 -2
  178. package/dist/features/ai/react/use-document-chat.js.map +1 -1
  179. package/dist/features/ai/react/use-model-profiles.d.ts +2 -1
  180. package/dist/features/ai/selection-flow.d.ts +1 -1
  181. package/dist/features/ai/selection-flow.js +1 -1
  182. package/dist/features/ai/sidebar-flow.d.ts +1 -1
  183. package/dist/features/ai/sidebar-flow.js +1 -1
  184. package/dist/features/ai/use-ai-assistant.d.ts +1 -1
  185. package/dist/features/ai/use-ai-assistant.js +3 -3
  186. package/dist/features/ai/use-ai-assistant.js.map +1 -1
  187. package/dist/features/ai/use-document-chat.js +2 -2
  188. package/dist/features/ai/use-document-chat.js.map +1 -1
  189. package/dist/features/ai/use-model-profiles.d.ts +2 -1
  190. package/dist/features/authors/attribution.d.ts +1 -1
  191. package/dist/features/authors/feature.js +12 -11
  192. package/dist/features/authors/feature.js.map +1 -1
  193. package/dist/features/block-ui/block-actions.d.ts +22 -1
  194. package/dist/features/block-ui/block-actions.js +26 -2
  195. package/dist/features/block-ui/block-actions.js.map +1 -1
  196. package/dist/features/block-ui/components/BlockActionsOverlay.js +33 -4
  197. package/dist/features/block-ui/components/BlockActionsOverlay.js.map +1 -1
  198. package/dist/features/block-ui/components/BlockActionsOverlay.vue.d.ts +4 -0
  199. package/dist/features/block-ui/components/BlockUi.js +1 -1
  200. package/dist/features/block-ui/feature.js +1 -0
  201. package/dist/features/block-ui/feature.js.map +1 -1
  202. package/dist/features/block-ui/index.d.ts +2 -2
  203. package/dist/features/block-ui/index.js +2 -2
  204. package/dist/features/block-ui/react/BlockActionsOverlay.d.ts +4 -0
  205. package/dist/features/block-ui/react/BlockActionsOverlay.js +38 -12
  206. package/dist/features/block-ui/react/BlockActionsOverlay.js.map +1 -1
  207. package/dist/features/block-ui/react/BlockUi.js +1 -1
  208. package/dist/features/collab/anchor-resolver.js +1 -1
  209. package/dist/features/collab/feature.js +2 -0
  210. package/dist/features/collab/feature.js.map +1 -1
  211. package/dist/features/comments/components/CommentThreadView.vue.d.ts +2 -1
  212. package/dist/features/comments/feature.js +12 -11
  213. package/dist/features/comments/feature.js.map +1 -1
  214. package/dist/features/comments/index.d.ts +3 -2
  215. package/dist/features/comments/index.js +1 -1
  216. package/dist/features/comments/margin-layout.d.ts +3 -2
  217. package/dist/features/comments/model.d.ts +3 -67
  218. package/dist/features/comments/model.js +2 -2
  219. package/dist/features/comments/model.js.map +1 -1
  220. package/dist/features/comments/react/CommentThreadView.d.ts +3 -2
  221. package/dist/features/comments/react/use-comments.d.ts +2 -1
  222. package/dist/features/comments/react.d.ts +1 -1
  223. package/dist/features/comments/schema.d.ts +2 -52
  224. package/dist/features/comments/schema.js.map +1 -1
  225. package/dist/features/comments/snapshot-equality.js.map +1 -1
  226. package/dist/features/comments/use-comments.d.ts +3 -2
  227. package/dist/features/comments/vue.d.ts +1 -1
  228. package/dist/features/composites/accepted-children.d.ts +1 -0
  229. package/dist/features/composites/accepted-children.js +16 -1
  230. package/dist/features/composites/accepted-children.js.map +1 -1
  231. package/dist/features/composites/ai-brief.js +31 -0
  232. package/dist/features/composites/ai-brief.js.map +1 -1
  233. package/dist/features/composites/bibliography-command.d.ts +11 -0
  234. package/dist/features/composites/bibliography-form.js +90 -0
  235. package/dist/features/composites/bibliography-form.js.map +1 -0
  236. package/dist/features/composites/bibliography.d.ts +33 -0
  237. package/dist/features/composites/bibliography.js +120 -0
  238. package/dist/features/composites/bibliography.js.map +1 -0
  239. package/dist/features/composites/components/BibliographyEditor.js +261 -0
  240. package/dist/features/composites/components/BibliographyEditor.js.map +1 -0
  241. package/dist/features/composites/components/CompositeChrome.js +75 -26
  242. package/dist/features/composites/components/CompositeChrome.js.map +1 -1
  243. package/dist/features/composites/components/CompositeDetails.js +46 -11
  244. package/dist/features/composites/components/CompositeDetails.js.map +1 -1
  245. package/dist/features/composites/components/CompositeDetails.vue.d.ts +2 -1
  246. package/dist/features/composites/components/CompositeFieldEditor.js +37 -4
  247. package/dist/features/composites/components/CompositeFieldEditor.js.map +1 -1
  248. package/dist/features/composites/components/CompositeInspector.js +17 -5
  249. package/dist/features/composites/components/CompositeInspector.js.map +1 -1
  250. package/dist/features/composites/components/CompositeTable.js +13 -4
  251. package/dist/features/composites/components/CompositeTable.js.map +1 -1
  252. package/dist/features/composites/components/CompositeTagsEditor.js +1 -1
  253. package/dist/features/composites/components/CompositeView.js +11 -1
  254. package/dist/features/composites/components/CompositeView.js.map +1 -1
  255. package/dist/features/composites/components/DerivationBadge.js +103 -0
  256. package/dist/features/composites/components/DerivationBadge.js.map +1 -0
  257. package/dist/features/composites/components/ReferenceFieldSelect.js +60 -0
  258. package/dist/features/composites/components/ReferenceFieldSelect.js.map +1 -0
  259. package/dist/features/composites/components/ReferenceView.js +122 -0
  260. package/dist/features/composites/components/ReferenceView.js.map +1 -0
  261. package/dist/features/composites/components/ReferenceView.vue.d.ts +96 -0
  262. package/dist/features/composites/components/SettingsEditingTab.js +1 -1
  263. package/dist/features/composites/convert.js +2 -2
  264. package/dist/features/composites/convert.js.map +1 -1
  265. package/dist/features/composites/derivation.d.ts +61 -0
  266. package/dist/features/composites/derivation.js +98 -0
  267. package/dist/features/composites/derivation.js.map +1 -0
  268. package/dist/features/composites/derived-chrome.js +69 -0
  269. package/dist/features/composites/derived-chrome.js.map +1 -0
  270. package/dist/features/composites/feature.js +159 -109
  271. package/dist/features/composites/feature.js.map +1 -1
  272. package/dist/features/composites/fences.d.ts +4 -3
  273. package/dist/features/composites/fences.js +51 -7
  274. package/dist/features/composites/fences.js.map +1 -1
  275. package/dist/features/composites/index.d.ts +12 -3
  276. package/dist/features/composites/index.js +15 -6
  277. package/dist/features/composites/inspector-model.d.ts +4 -1
  278. package/dist/features/composites/inspector-model.js +8 -4
  279. package/dist/features/composites/inspector-model.js.map +1 -1
  280. package/dist/features/composites/kinds.d.ts +8 -1
  281. package/dist/features/composites/kinds.js +145 -6
  282. package/dist/features/composites/kinds.js.map +1 -1
  283. package/dist/features/composites/legacy.d.ts +4 -1
  284. package/dist/features/composites/legacy.js +56 -1
  285. package/dist/features/composites/legacy.js.map +1 -1
  286. package/dist/features/composites/meta-display.js +40 -1
  287. package/dist/features/composites/meta-display.js.map +1 -1
  288. package/dist/features/composites/meta-keys.d.ts +7 -0
  289. package/dist/features/composites/meta-keys.js +21 -0
  290. package/dist/features/composites/meta-keys.js.map +1 -0
  291. package/dist/features/composites/node-views.d.ts +6 -3
  292. package/dist/features/composites/node-views.js +7 -3
  293. package/dist/features/composites/node-views.js.map +1 -1
  294. package/dist/features/composites/nodes.d.ts +6 -1
  295. package/dist/features/composites/nodes.js +33 -7
  296. package/dist/features/composites/nodes.js.map +1 -1
  297. package/dist/features/composites/react/BibliographyEditor.js +229 -0
  298. package/dist/features/composites/react/BibliographyEditor.js.map +1 -0
  299. package/dist/features/composites/react/CompositeChrome.js +65 -17
  300. package/dist/features/composites/react/CompositeChrome.js.map +1 -1
  301. package/dist/features/composites/react/CompositeDetails.d.ts +2 -1
  302. package/dist/features/composites/react/CompositeDetails.js +45 -6
  303. package/dist/features/composites/react/CompositeDetails.js.map +1 -1
  304. package/dist/features/composites/react/CompositeFieldEditor.d.ts +1 -1
  305. package/dist/features/composites/react/CompositeFieldEditor.js +24 -1
  306. package/dist/features/composites/react/CompositeFieldEditor.js.map +1 -1
  307. package/dist/features/composites/react/CompositeInspector.js +11 -5
  308. package/dist/features/composites/react/CompositeInspector.js.map +1 -1
  309. package/dist/features/composites/react/CompositeStatusMenu.js +1 -1
  310. package/dist/features/composites/react/CompositeSummaryEditor.js +1 -1
  311. package/dist/features/composites/react/CompositeTable.js +16 -2
  312. package/dist/features/composites/react/CompositeTable.js.map +1 -1
  313. package/dist/features/composites/react/CompositeTagsEditor.js +2 -2
  314. package/dist/features/composites/react/CompositeView.js +6 -1
  315. package/dist/features/composites/react/CompositeView.js.map +1 -1
  316. package/dist/features/composites/react/DerivationBadge.js +116 -0
  317. package/dist/features/composites/react/DerivationBadge.js.map +1 -0
  318. package/dist/features/composites/react/ReferenceFieldSelect.js +52 -0
  319. package/dist/features/composites/react/ReferenceFieldSelect.js.map +1 -0
  320. package/dist/features/composites/react/ReferenceView.d.ts +11 -0
  321. package/dist/features/composites/react/ReferenceView.js +115 -0
  322. package/dist/features/composites/react/ReferenceView.js.map +1 -0
  323. package/dist/features/composites/react/SettingsEditingTab.js +2 -2
  324. package/dist/features/composites/react.d.ts +2 -1
  325. package/dist/features/composites/react.js +7 -3
  326. package/dist/features/composites/react.js.map +1 -1
  327. package/dist/features/composites/reference-ai.js +16 -0
  328. package/dist/features/composites/reference-ai.js.map +1 -0
  329. package/dist/features/composites/reference-label.d.ts +19 -0
  330. package/dist/features/composites/reference-label.js +58 -0
  331. package/dist/features/composites/reference-label.js.map +1 -0
  332. package/dist/features/composites/reference-suggestion.d.ts +10 -0
  333. package/dist/features/composites/reference-suggestion.js +41 -0
  334. package/dist/features/composites/reference-suggestion.js.map +1 -0
  335. package/dist/features/composites/reference-text.d.ts +18 -0
  336. package/dist/features/composites/reference-text.js +89 -0
  337. package/dist/features/composites/reference-text.js.map +1 -0
  338. package/dist/features/composites/reference.d.ts +44 -0
  339. package/dist/features/composites/reference.js +148 -0
  340. package/dist/features/composites/reference.js.map +1 -0
  341. package/dist/features/composites/reveal-source.d.ts +32 -0
  342. package/dist/features/composites/reveal-source.js +89 -0
  343. package/dist/features/composites/reveal-source.js.map +1 -0
  344. package/dist/features/composites/rows.d.ts +21 -2
  345. package/dist/features/composites/rows.js +63 -9
  346. package/dist/features/composites/rows.js.map +1 -1
  347. package/dist/features/composites/schema.d.ts +9 -3
  348. package/dist/features/composites/schema.js +11 -4
  349. package/dist/features/composites/schema.js.map +1 -1
  350. package/dist/features/composites/table-model.js +12 -21
  351. package/dist/features/composites/table-model.js.map +1 -1
  352. package/dist/features/composites/vue.d.ts +3 -2
  353. package/dist/features/composites/vue.js +8 -4
  354. package/dist/features/composites/vue.js.map +1 -1
  355. package/dist/features/media/assets.d.ts +2 -0
  356. package/dist/features/media/assets.js +3 -2
  357. package/dist/features/media/assets.js.map +1 -1
  358. package/dist/features/media/components/FileView.js +13 -4
  359. package/dist/features/media/components/FileView.js.map +1 -1
  360. package/dist/features/media/feature.d.ts +3 -3
  361. package/dist/features/media/feature.js +21 -28
  362. package/dist/features/media/feature.js.map +1 -1
  363. package/dist/features/media/file-import.js +2 -2
  364. package/dist/features/media/file-import.js.map +1 -1
  365. package/dist/features/media/index.d.ts +2 -2
  366. package/dist/features/media/index.js +2 -2
  367. package/dist/features/media/react/FileView.js +19 -2
  368. package/dist/features/media/react/FileView.js.map +1 -1
  369. package/dist/features/media/schema.d.ts +8 -0
  370. package/dist/features/media/schema.js +126 -11
  371. package/dist/features/media/schema.js.map +1 -1
  372. package/dist/features/media/upload.d.ts +16 -14
  373. package/dist/features/media/upload.js +13 -19
  374. package/dist/features/media/upload.js.map +1 -1
  375. package/dist/features/mentions/index.d.ts +4 -3
  376. package/dist/features/mentions/index.js +4 -1
  377. package/dist/features/mentions/index.js.map +1 -1
  378. package/dist/features/mentions/mention-text.d.ts +1 -1
  379. package/dist/features/mentions/mention-text.js.map +1 -1
  380. package/dist/features/mentions/mention.d.ts +0 -6
  381. package/dist/features/mentions/mention.js.map +1 -1
  382. package/dist/features/mentions/metadata-defaults.d.ts +2 -2
  383. package/dist/features/mentions/metadata-defaults.js +3 -9
  384. package/dist/features/mentions/metadata-defaults.js.map +1 -1
  385. package/dist/features/mentions/schema.d.ts +2 -1
  386. package/dist/features/mentions/schema.js.map +1 -1
  387. package/dist/features/tables/feature.d.ts +2 -1
  388. package/dist/features/tables/feature.js +90 -70
  389. package/dist/features/tables/feature.js.map +1 -1
  390. package/dist/features/themes/components/SettingsAppearanceTab.js +6 -9
  391. package/dist/features/themes/components/SettingsAppearanceTab.js.map +1 -1
  392. package/dist/features/themes/feature.js +2 -0
  393. package/dist/features/themes/feature.js.map +1 -1
  394. package/dist/features/themes/index.d.ts +2 -1
  395. package/dist/features/themes/react/SettingsAppearanceTab.js +7 -10
  396. package/dist/features/themes/react/SettingsAppearanceTab.js.map +1 -1
  397. package/dist/features/themes/schema.d.ts +2 -6
  398. package/dist/features/themes/schema.js.map +1 -1
  399. package/dist/features/themes/theme-runtime.d.ts +1 -1
  400. package/dist/features/themes/theme-runtime.js +4 -2
  401. package/dist/features/themes/theme-runtime.js.map +1 -1
  402. package/dist/features/transcript/TranscriptSegmentView.js +48 -28
  403. package/dist/features/transcript/TranscriptSegmentView.js.map +1 -1
  404. package/dist/features/transcript/feature.js +21 -19
  405. package/dist/features/transcript/feature.js.map +1 -1
  406. package/dist/features/transcript/react/TranscriptSegmentView.js +55 -36
  407. package/dist/features/transcript/react/TranscriptSegmentView.js.map +1 -1
  408. package/dist/features/transcript/segment-node.d.ts +2 -0
  409. package/dist/features/transcript/segment-node.js +35 -7
  410. package/dist/features/transcript/segment-node.js.map +1 -1
  411. package/dist/i18n/de/composites.js +91 -1
  412. package/dist/i18n/de/composites.js.map +1 -1
  413. package/dist/i18n/de/integrations.js +49 -8
  414. package/dist/i18n/de/integrations.js.map +1 -1
  415. package/dist/i18n/de/media.js +0 -1
  416. package/dist/i18n/de/media.js.map +1 -1
  417. package/dist/i18n/de/palette.js +22 -0
  418. package/dist/i18n/de/palette.js.map +1 -0
  419. package/dist/i18n/de/tables.js +0 -1
  420. package/dist/i18n/de/tables.js.map +1 -1
  421. package/dist/i18n/de/transcript.js +2 -1
  422. package/dist/i18n/de/transcript.js.map +1 -1
  423. package/dist/i18n/de/tree.js +3 -0
  424. package/dist/i18n/de/tree.js.map +1 -1
  425. package/dist/i18n/de.d.ts +157 -11
  426. package/dist/i18n/de.js +3 -1
  427. package/dist/i18n/de.js.map +1 -1
  428. package/dist/i18n/en/composites.js +89 -1
  429. package/dist/i18n/en/composites.js.map +1 -1
  430. package/dist/i18n/en/integrations.js +49 -8
  431. package/dist/i18n/en/integrations.js.map +1 -1
  432. package/dist/i18n/en/media.js +0 -1
  433. package/dist/i18n/en/media.js.map +1 -1
  434. package/dist/i18n/en/palette.js +22 -0
  435. package/dist/i18n/en/palette.js.map +1 -0
  436. package/dist/i18n/en/tables.js +0 -1
  437. package/dist/i18n/en/tables.js.map +1 -1
  438. package/dist/i18n/en/transcript.js +2 -1
  439. package/dist/i18n/en/transcript.js.map +1 -1
  440. package/dist/i18n/en/tree.js +3 -0
  441. package/dist/i18n/en/tree.js.map +1 -1
  442. package/dist/i18n/en.js +3 -1
  443. package/dist/i18n/en.js.map +1 -1
  444. package/dist/index.d.ts +4 -3
  445. package/dist/integrations/composite-ai/bibliography-fetch.d.ts +31 -0
  446. package/dist/integrations/composite-ai/bibliography-fetch.js +159 -0
  447. package/dist/integrations/composite-ai/bibliography-fetch.js.map +1 -0
  448. package/dist/integrations/composite-ai/composite-fill.d.ts +30 -8
  449. package/dist/integrations/composite-ai/composite-fill.js +97 -56
  450. package/dist/integrations/composite-ai/composite-fill.js.map +1 -1
  451. package/dist/integrations/composite-ai/composite-summary.d.ts +4 -12
  452. package/dist/integrations/composite-ai/composite-summary.js +7 -26
  453. package/dist/integrations/composite-ai/composite-summary.js.map +1 -1
  454. package/dist/integrations/composite-ai/derive.d.ts +29 -0
  455. package/dist/integrations/composite-ai/derive.js +173 -0
  456. package/dist/integrations/composite-ai/derive.js.map +1 -0
  457. package/dist/integrations/composite-ai/index.d.ts +11 -7
  458. package/dist/integrations/composite-ai/index.js +72 -14
  459. package/dist/integrations/composite-ai/index.js.map +1 -1
  460. package/dist/integrations/composite-ai/rendition.d.ts +45 -0
  461. package/dist/integrations/composite-ai/rendition.js +314 -0
  462. package/dist/integrations/composite-ai/rendition.js.map +1 -0
  463. package/dist/integrations/composite-media/index.d.ts +7 -5
  464. package/dist/integrations/composite-media/index.js +86 -13
  465. package/dist/integrations/composite-media/index.js.map +1 -1
  466. package/dist/integrations/transcript-ai/index.d.ts +1 -1
  467. package/dist/integrations/transcript-ai/index.js +5 -2
  468. package/dist/integrations/transcript-ai/index.js.map +1 -1
  469. package/dist/integrations/transcript-ai/protocol.d.ts +2 -12
  470. package/dist/integrations/transcript-ai/protocol.js +0 -2
  471. package/dist/integrations/transcript-ai/protocol.js.map +1 -1
  472. package/dist/integrations/transcript-ai/transcript-cleanup.d.ts +5 -5
  473. package/dist/integrations/transcript-ai/transcript-cleanup.js +7 -10
  474. package/dist/integrations/transcript-ai/transcript-cleanup.js.map +1 -1
  475. package/dist/markdown/MarkdownSurface.vue.d.ts +10 -9
  476. package/dist/markdown/MarkdownSurface2.js +3 -6
  477. package/dist/markdown/MarkdownSurface2.js.map +1 -1
  478. package/dist/markdown/document.js +1 -1
  479. package/dist/markdown/source-mode.d.ts +1 -1
  480. package/dist/nuxt/module.d.ts +1402 -54
  481. package/dist/nuxt/module.js +6 -49
  482. package/dist/nuxt/module.js.map +1 -1
  483. package/dist/nuxt/runtime/install-context.d.ts +7 -3
  484. package/dist/nuxt/runtime/install-context.js +14 -8
  485. package/dist/nuxt/runtime/install-context.js.map +1 -1
  486. package/dist/nuxt/runtime/plugins/editor-context-nuxt-ui.client.ts +2 -2
  487. package/dist/nuxt/runtime/server/plugins/editor-server.js +20 -12
  488. package/dist/nuxt/runtime/server/plugins/editor-server.js.map +1 -1
  489. package/dist/presets/compose.d.ts +94 -0
  490. package/dist/presets/compose.js +164 -0
  491. package/dist/presets/compose.js.map +1 -0
  492. package/dist/react/AdvancedEditor.d.ts +15 -15
  493. package/dist/react/AdvancedEditor.js +15 -13
  494. package/dist/react/AdvancedEditor.js.map +1 -1
  495. package/dist/react/EditorCommandPalette.d.ts +13 -0
  496. package/dist/react/EditorCommandPalette.js +118 -0
  497. package/dist/react/EditorCommandPalette.js.map +1 -0
  498. package/dist/react/EditorSettingsModal.d.ts +5 -5
  499. package/dist/react/EditorSettingsModal.js +7 -4
  500. package/dist/react/EditorSettingsModal.js.map +1 -1
  501. package/dist/react/EditorSettingsPanel.d.ts +7 -7
  502. package/dist/react/EditorSettingsPanel.js +8 -5
  503. package/dist/react/EditorSettingsPanel.js.map +1 -1
  504. package/dist/react/EditorSurface.d.ts +7 -7
  505. package/dist/react/EditorSurface.js +10 -6
  506. package/dist/react/EditorSurface.js.map +1 -1
  507. package/dist/react/EditorToolbar.d.ts +4 -6
  508. package/dist/react/EditorToolbar.js +29 -37
  509. package/dist/react/EditorToolbar.js.map +1 -1
  510. package/dist/react/SimpleEditor.d.ts +22 -23
  511. package/dist/react/SimpleEditor.js +21 -7
  512. package/dist/react/SimpleEditor.js.map +1 -1
  513. package/dist/react/advanced.d.ts +4 -3
  514. package/dist/react/advanced.js +2 -2
  515. package/dist/react/compose.d.ts +20 -0
  516. package/dist/react/compose.js +49 -0
  517. package/dist/react/compose.js.map +1 -0
  518. package/dist/react/composed-surface.d.ts +39 -0
  519. package/dist/react/composed-surface.js +71 -0
  520. package/dist/react/composed-surface.js.map +1 -0
  521. package/dist/react/context.js +6 -2
  522. package/dist/react/context.js.map +1 -1
  523. package/dist/react/index.d.ts +2 -1
  524. package/dist/react/index.js +2 -1
  525. package/dist/react/key-labels.js +15 -0
  526. package/dist/react/key-labels.js.map +1 -0
  527. package/dist/react/settings.d.ts +1 -1
  528. package/dist/react/simple.d.ts +2 -2
  529. package/dist/react/ui/command.js +36 -1
  530. package/dist/react/ui/command.js.map +1 -1
  531. package/dist/schema/advanced.d.ts +6 -6
  532. package/dist/schema/advanced.js +26 -29
  533. package/dist/schema/advanced.js.map +1 -1
  534. package/dist/server/ai.d.ts +5 -16
  535. package/dist/server/ai.js.map +1 -1
  536. package/dist/server/auth.d.ts +9 -0
  537. package/dist/server/collab-state.d.ts +1 -1
  538. package/dist/server/collab-state.js.map +1 -1
  539. package/dist/server/collab.d.ts +13 -13
  540. package/dist/server/collab.js +34 -18
  541. package/dist/server/collab.js.map +1 -1
  542. package/dist/server/crossref.js +78 -0
  543. package/dist/server/crossref.js.map +1 -0
  544. package/dist/server/errors.d.ts +1 -1
  545. package/dist/server/errors.js +1 -1
  546. package/dist/server/errors.js.map +1 -1
  547. package/dist/server/extract.js +308 -0
  548. package/dist/server/extract.js.map +1 -0
  549. package/dist/{nuxt/runtime/server/utils/editor-route.js → server/h3.js} +8 -16
  550. package/dist/server/h3.js.map +1 -0
  551. package/dist/server/handlers/ai.d.ts +30 -9
  552. package/dist/server/handlers/ai.js +170 -36
  553. package/dist/server/handlers/ai.js.map +1 -1
  554. package/dist/server/handlers/context.d.ts +12 -5
  555. package/dist/server/handlers/context.js +10 -4
  556. package/dist/server/handlers/context.js.map +1 -1
  557. package/dist/server/handlers/editor.d.ts +19 -13
  558. package/dist/server/handlers/editor.js +49 -38
  559. package/dist/server/handlers/editor.js.map +1 -1
  560. package/dist/server/handlers/index.d.ts +4 -4
  561. package/dist/server/handlers/index.js +4 -4
  562. package/dist/server/host.d.ts +16 -25
  563. package/dist/server/host.js +58 -41
  564. package/dist/server/host.js.map +1 -1
  565. package/dist/server/index.d.ts +6 -4
  566. package/dist/server/index.js +3 -2
  567. package/dist/server/pdf.js +97 -0
  568. package/dist/server/pdf.js.map +1 -0
  569. package/dist/server/{adapter.d.ts → ports.d.ts} +81 -30
  570. package/dist/server/ports.js +29 -0
  571. package/dist/server/ports.js.map +1 -0
  572. package/dist/server/routes.js +144 -0
  573. package/dist/server/routes.js.map +1 -0
  574. package/dist/settings/index.d.ts +1 -1
  575. package/dist/settings/index.js.map +1 -1
  576. package/dist/styles/composites.css +25 -0
  577. package/dist/tree/DocumentTree.js +56 -29
  578. package/dist/tree/DocumentTree.js.map +1 -1
  579. package/dist/tree/react/DocumentTree.js +23 -0
  580. package/dist/tree/react/DocumentTree.js.map +1 -1
  581. package/dist/tree/tree-host.js +1 -1
  582. package/dist/vue/AdvancedEditor.js +30 -9
  583. package/dist/vue/AdvancedEditor.js.map +1 -1
  584. package/dist/vue/AdvancedEditor.vue.d.ts +32 -12
  585. package/dist/vue/SimpleEditor.js +62 -16
  586. package/dist/vue/SimpleEditor.js.map +1 -1
  587. package/dist/vue/SimpleEditor.vue.d.ts +37 -7
  588. package/dist/vue/advanced.d.ts +3 -2
  589. package/dist/vue/advanced.js +2 -2
  590. package/dist/vue/components/EditorCommandPalette.js +91 -0
  591. package/dist/vue/components/EditorCommandPalette.js.map +1 -0
  592. package/dist/vue/components/EditorCommandPalette.vue.d.ts +15 -0
  593. package/dist/vue/components/EditorSettingsModal.js +10 -6
  594. package/dist/vue/components/EditorSettingsModal.js.map +1 -1
  595. package/dist/vue/components/EditorSettingsModal.vue.d.ts +4 -4
  596. package/dist/vue/components/EditorSettingsPanel.js +10 -6
  597. package/dist/vue/components/EditorSettingsPanel.js.map +1 -1
  598. package/dist/vue/components/EditorSettingsPanel.vue.d.ts +6 -6
  599. package/dist/vue/components/EditorSurface.js +11 -6
  600. package/dist/vue/components/EditorSurface.js.map +1 -1
  601. package/dist/vue/components/EditorSurface.vue.d.ts +11 -11
  602. package/dist/vue/components/EditorToolbar.js +41 -49
  603. package/dist/vue/components/EditorToolbar.js.map +1 -1
  604. package/dist/vue/components/EditorToolbar.vue.d.ts +2 -4
  605. package/dist/vue/compose.d.ts +17 -0
  606. package/dist/vue/compose.js +51 -0
  607. package/dist/vue/compose.js.map +1 -0
  608. package/dist/vue/context-key.d.ts +6 -0
  609. package/dist/vue/context-key.js +6 -0
  610. package/dist/vue/context-key.js.map +1 -0
  611. package/dist/vue/context.d.ts +8 -6
  612. package/dist/vue/context.js +6 -5
  613. package/dist/vue/context.js.map +1 -1
  614. package/dist/vue/index.d.ts +10 -8
  615. package/dist/vue/index.js +10 -8
  616. package/dist/vue/kit/index.d.ts +2 -2
  617. package/dist/vue/kit/nuxt-ui.js +23 -0
  618. package/dist/vue/kit/nuxt-ui.js.map +1 -1
  619. package/dist/vue/kit/types.d.ts +40 -1
  620. package/package.json +30 -16
  621. package/dist/adapters/comments/client.d.ts +0 -64
  622. package/dist/adapters/comments/client.js.map +0 -1
  623. package/dist/adapters/routes.js.map +0 -1
  624. package/dist/core/toolbar.d.ts +0 -74
  625. package/dist/core/toolbar.js +0 -45
  626. package/dist/core/toolbar.js.map +0 -1
  627. package/dist/integrations/composite-ai/document-transcribe.d.ts +0 -14
  628. package/dist/integrations/composite-ai/document-transcribe.js +0 -89
  629. package/dist/integrations/composite-ai/document-transcribe.js.map +0 -1
  630. package/dist/nuxt/runtime/server/api/ai/chat.post.d.ts +0 -5
  631. package/dist/nuxt/runtime/server/api/ai/chat.post.js +0 -8
  632. package/dist/nuxt/runtime/server/api/ai/chat.post.js.map +0 -1
  633. package/dist/nuxt/runtime/server/api/ai/complete.post.d.ts +0 -5
  634. package/dist/nuxt/runtime/server/api/ai/complete.post.js +0 -8
  635. package/dist/nuxt/runtime/server/api/ai/complete.post.js.map +0 -1
  636. package/dist/nuxt/runtime/server/api/ai/generate.post.d.ts +0 -5
  637. package/dist/nuxt/runtime/server/api/ai/generate.post.js +0 -8
  638. package/dist/nuxt/runtime/server/api/ai/generate.post.js.map +0 -1
  639. package/dist/nuxt/runtime/server/api/ai/models.get.d.ts +0 -5
  640. package/dist/nuxt/runtime/server/api/ai/models.get.js +0 -8
  641. package/dist/nuxt/runtime/server/api/ai/models.get.js.map +0 -1
  642. package/dist/nuxt/runtime/server/api/ai/transcribe.post.d.ts +0 -5
  643. package/dist/nuxt/runtime/server/api/ai/transcribe.post.js +0 -8
  644. package/dist/nuxt/runtime/server/api/ai/transcribe.post.js.map +0 -1
  645. package/dist/nuxt/runtime/server/api/ai/transcript-cleanup.post.d.ts +0 -5
  646. package/dist/nuxt/runtime/server/api/ai/transcript-cleanup.post.js +0 -8
  647. package/dist/nuxt/runtime/server/api/ai/transcript-cleanup.post.js.map +0 -1
  648. package/dist/nuxt/runtime/server/api/editor/assets/[id]/[name].get.d.ts +0 -5
  649. package/dist/nuxt/runtime/server/api/editor/assets/[id]/[name].get.js +0 -8
  650. package/dist/nuxt/runtime/server/api/editor/assets/[id]/[name].get.js.map +0 -1
  651. package/dist/nuxt/runtime/server/api/editor/assets/[id].post.d.ts +0 -5
  652. package/dist/nuxt/runtime/server/api/editor/assets/[id].post.js +0 -8
  653. package/dist/nuxt/runtime/server/api/editor/assets/[id].post.js.map +0 -1
  654. package/dist/nuxt/runtime/server/api/editor/settings.get.d.ts +0 -5
  655. package/dist/nuxt/runtime/server/api/editor/settings.get.js +0 -8
  656. package/dist/nuxt/runtime/server/api/editor/settings.get.js.map +0 -1
  657. package/dist/nuxt/runtime/server/api/editor/settings.put.d.ts +0 -5
  658. package/dist/nuxt/runtime/server/api/editor/settings.put.js +0 -8
  659. package/dist/nuxt/runtime/server/api/editor/settings.put.js.map +0 -1
  660. package/dist/nuxt/runtime/server/api/editor/tags.get.d.ts +0 -5
  661. package/dist/nuxt/runtime/server/api/editor/tags.get.js +0 -8
  662. package/dist/nuxt/runtime/server/api/editor/tags.get.js.map +0 -1
  663. package/dist/nuxt/runtime/server/api/editor/themes/[id].delete.d.ts +0 -5
  664. package/dist/nuxt/runtime/server/api/editor/themes/[id].delete.js +0 -8
  665. package/dist/nuxt/runtime/server/api/editor/themes/[id].delete.js.map +0 -1
  666. package/dist/nuxt/runtime/server/api/editor/themes/[id].get.d.ts +0 -5
  667. package/dist/nuxt/runtime/server/api/editor/themes/[id].get.js +0 -8
  668. package/dist/nuxt/runtime/server/api/editor/themes/[id].get.js.map +0 -1
  669. package/dist/nuxt/runtime/server/api/editor/themes/index.get.d.ts +0 -5
  670. package/dist/nuxt/runtime/server/api/editor/themes/index.get.js +0 -8
  671. package/dist/nuxt/runtime/server/api/editor/themes/index.get.js.map +0 -1
  672. package/dist/nuxt/runtime/server/api/editor/themes/index.post.d.ts +0 -5
  673. package/dist/nuxt/runtime/server/api/editor/themes/index.post.js +0 -8
  674. package/dist/nuxt/runtime/server/api/editor/themes/index.post.js.map +0 -1
  675. package/dist/nuxt/runtime/server/api/editor/users.get.d.ts +0 -5
  676. package/dist/nuxt/runtime/server/api/editor/users.get.js +0 -8
  677. package/dist/nuxt/runtime/server/api/editor/users.get.js.map +0 -1
  678. package/dist/nuxt/runtime/server/plugins/collab.d.ts +0 -5
  679. package/dist/nuxt/runtime/server/plugins/collab.js +0 -10
  680. package/dist/nuxt/runtime/server/plugins/collab.js.map +0 -1
  681. package/dist/nuxt/runtime/server/routes/collab/[id].d.ts +0 -5
  682. package/dist/nuxt/runtime/server/routes/collab/[id].js +0 -35
  683. package/dist/nuxt/runtime/server/routes/collab/[id].js.map +0 -1
  684. package/dist/nuxt/runtime/server/utils/editor-route.d.ts +0 -11
  685. package/dist/nuxt/runtime/server/utils/editor-route.js.map +0 -1
  686. package/dist/presets/advanced.d.ts +0 -33
  687. package/dist/presets/advanced.js +0 -50
  688. package/dist/presets/advanced.js.map +0 -1
  689. package/dist/presets/simple.d.ts +0 -9
  690. package/dist/presets/simple.js +0 -12
  691. package/dist/presets/simple.js.map +0 -1
  692. package/dist/react/advanced-preset.d.ts +0 -11
  693. package/dist/react/advanced-preset.js +0 -31
  694. package/dist/react/advanced-preset.js.map +0 -1
  695. package/dist/vue/advanced-preset.d.ts +0 -13
  696. package/dist/vue/advanced-preset.js +0 -33
  697. package/dist/vue/advanced-preset.js.map +0 -1
  698. package/docs/extending.md +0 -538
  699. package/docs/integration.md +0 -630
  700. package/docs/llms.md +0 -383
  701. package/docs/usage.md +0 -1076
@@ -1,6 +1,7 @@
1
1
  import { AuthorIdentity } from "../../../core/feature.js";
2
+ import { CommentThread } from "../../../core/backend-types.js";
2
3
  import "../../../core/index.js";
3
- import { CommentThread } from "../schema.js";
4
+ import "../schema.js";
4
5
  import { CommentsStore } from "../use-comments.js";
5
6
  //#region src/features/comments/components/CommentThreadView.vue.d.ts
6
7
  /**
@@ -1,5 +1,5 @@
1
- import { CommentMark } from "./schema.js";
2
1
  import { Comments, commentsKey } from "./comments-plugin.js";
2
+ import { CommentMark, commentsSchemaExtensions } from "./schema.js";
3
3
  import { provideCommentsModel } from "./model.js";
4
4
  import { commentsShortcuts } from "./shortcuts.js";
5
5
  import { Extension } from "@tiptap/core";
@@ -19,6 +19,8 @@ function commentsFeatureCore(ui, options = {}) {
19
19
  const { model: factory } = options;
20
20
  return {
21
21
  id: "comments",
22
+ dimension: "interaction",
23
+ schemaExtensions: commentsSchemaExtensions,
22
24
  requires: factory ? [] : ["collab"],
23
25
  extensions: (ctx) => {
24
26
  if (!factory) return [
@@ -38,16 +40,15 @@ function commentsFeatureCore(ui, options = {}) {
38
40
  commentsShortcuts(ctx)
39
41
  ];
40
42
  },
41
- toolbar: (ctx) => [{
42
- id: "collaboration",
43
- order: 1010,
44
- items: [{
45
- id: "comments",
46
- order: 10,
47
- icon: "i-lucide-message-square-text",
48
- label: ctx.t("comments.title"),
49
- component: ui.toolbarButton
50
- }]
43
+ commands: (ctx) => [{
44
+ id: "comments",
45
+ toolbar: {
46
+ group: "collaboration",
47
+ order: 10
48
+ },
49
+ icon: "i-lucide-message-square-text",
50
+ label: ctx.t("comments.title"),
51
+ component: ui.toolbarButton
51
52
  }],
52
53
  overlays: [ui.overlay],
53
54
  settingsTabs: (ctx) => [{
@@ -1 +1 @@
1
- {"version":3,"file":"feature.js","names":[],"sources":["../../../src/features/comments/feature.ts"],"sourcesContent":["import { type AnyExtension, type Editor, Extension } from '@tiptap/core'\nimport type { EditorFeature } from '../../core'\nimport { Comments, type CommentsMeta, commentsKey } from './comments-plugin'\nimport { type CommentsModelFactory, type CommentsSnapshot, provideCommentsModel } from './model'\nimport { CommentMark } from './schema'\nimport { commentsShortcuts } from './shortcuts'\n\n/** What a framework binding supplies to the comments feature. */\nexport interface CommentsUi<C> {\n /** The toolbar entry: the margin toggle or the list menu, by the user's comments layout. */\n toolbarButton: C\n /** Mounted beside the editor content: the selection bubble, the inline popover and the layout glue. */\n overlay: C\n /** The „Kommentare“ settings tab component of the framework. */\n settingsTab: C\n}\n\n/** Options of `commentsFeatureCore`. */\nexport interface CommentsFeatureOptions {\n /**\n * Backs the comments with the host's own model (REST threads, a database) instead of the document's Y.Doc: the feature\n * then requires no `collab` feature, the `Comments` plugin reads the user from the model, gets the thread ids\n * (`known`/`hidden`) and the text ranges from its snapshot, and the framework `useComments` hooks use the model of\n * the surface (`commentsModelOf(ctx)`) instead of `createCommentsModel`. The factory runs once for the plugin and once\n * per `useComments` consumer, so a model that shares state between them keeps it outside the factory. The model\n * itself drives the active thread and the draft through the `comments-plugin` helpers.\n */\n model?: CommentsModelFactory\n}\n\n/**\n * Google-Docs-style comments on a collaborative document: select text, „Kommentar“ in the selection bubble, others\n * reply, anyone resolves or reopens a thread. Threads live in the Y.Doc (a `Y.Map` named `comments`, `createCommentsModel`), so\n * they sync live and persist with the document; the text range is the `comment` mark, highlighted by the `Comments`\n * plugin from the thread state. The user chooses per setting (`editing.commentsLayout`) between the margin column\n * (`CommentsMargin`, which the host places in the editor's scroll container and shows while the surface's\n * `commentsOpen` model is true; Mod-Shift-m or the toolbar button toggle it, and it excludes the AI sidebar) and the\n * inline popover plus the toolbar's list. Needs a collaborative surface with a `collaboration.user`: without one the\n * UI says so and nothing can be written (the schema mark stays registered, so stored comment marks round-trip). With\n * `options.model` the threads live wherever the host's model keeps them and no collaboration is needed.\n */\nexport function commentsFeatureCore<C>(ui: CommentsUi<C>, options: CommentsFeatureOptions = {}): EditorFeature<C> {\n const { model: factory } = options\n return {\n id: 'comments',\n requires: factory ? [] : ['collab'],\n extensions: (ctx) => {\n if (!factory) {\n return [\n CommentMark,\n Comments.configure({\n user: () => ctx.collaboration?.user ?? null,\n doc: () => ctx.collaboration?.ydoc ?? null,\n }),\n commentsShortcuts(ctx),\n ]\n }\n provideCommentsModel(ctx, factory)\n const { configured, bridge } = modelExtensions(factory, ctx.getEditor)\n return [CommentMark, configured, bridge, commentsShortcuts(ctx)]\n },\n toolbar: ctx => [{\n id: 'collaboration',\n order: 1010,\n items: [{ id: 'comments', order: 10, icon: 'i-lucide-message-square-text', label: ctx.t('comments.title'), component: ui.toolbarButton }],\n }],\n overlays: [ui.overlay],\n settingsTabs: ctx => [{ id: 'comments', label: ctx.t('comments.tab'), icon: 'i-lucide-message-square-text', component: ui.settingsTab }],\n }\n}\n\n/**\n * The `Comments` plugin and its feed for a host model: the plugin reads user, availability and `canComment` from the\n * model's snapshot; the bridge extension refreshes the model once the editor exists, mirrors the snapshot's thread ids\n * and ranges into the plugin state (queued, never from inside a transaction) and disposes the model with the editor.\n */\nfunction modelExtensions(factory: CommentsModelFactory, getEditor: Parameters<CommentsModelFactory>[0]): { configured: AnyExtension, bridge: AnyExtension } {\n let created: Editor | undefined\n const model = factory(() => created ?? getEditor())\n const snapshot = () => model.state.get()\n\n let stop: (() => void) | undefined\n let queued = false\n // What the plugin was last told, to skip no-op dispatches and to apply the deactivation rule.\n let told: CommentsSnapshot['threads'] | undefined\n let toldRanges: CommentsSnapshot['ranges'] | undefined\n\n function push() {\n queued = false\n const editor = created\n const value = editor && !editor.isDestroyed ? commentsKey.getState(editor.state) : undefined\n if (!editor || !value) return\n const { threads, ranges } = snapshot()\n if (threads === told && ranges === toldRanges) return\n const known = new Set(threads.map(t => t.id))\n const hidden = new Set(threads.filter(t => t.resolved).map(t => t.id))\n const meta: CommentsMeta = { known, hidden, modelRanges: ranges }\n const before = value.active ? told?.find(t => t.id === value.active) : undefined\n if (value.active && before && !before.resolved && (!known.has(value.active) || hidden.has(value.active))) meta.active = null\n told = threads\n toldRanges = ranges\n editor.view.dispatch(editor.state.tr.setMeta(commentsKey, meta).setMeta('addToHistory', false))\n }\n\n function queue() {\n if (queued) return\n queued = true\n queueMicrotask(push)\n }\n\n return {\n configured: Comments.configure({\n user: () => snapshot().user,\n doc: () => null,\n available: () => snapshot().available,\n canComment: () => snapshot().canComment,\n }),\n bridge: Extension.create({\n name: 'commentsModelBridge',\n onCreate() {\n created = this.editor\n model.refresh()\n stop = model.state.subscribe(queue)\n queue()\n },\n onDestroy() {\n stop?.()\n stop = undefined\n model.dispose()\n created = undefined\n told = undefined\n toldRanges = undefined\n },\n }),\n }\n}\n"],"mappings":";;;;;;;;;;;;;;;;;AAyCA,SAAgB,oBAAuB,IAAmB,UAAkC,CAAC,GAAqB;CAChH,MAAM,EAAE,OAAO,YAAY;CAC3B,OAAO;EACL,IAAI;EACJ,UAAU,UAAU,CAAC,IAAI,CAAC,QAAQ;EAClC,aAAa,QAAQ;GACnB,IAAI,CAAC,SACH,OAAO;IACL;IACA,SAAS,UAAU;KACjB,YAAY,IAAI,eAAe,QAAQ;KACvC,WAAW,IAAI,eAAe,QAAQ;IACxC,CAAC;IACD,kBAAkB,GAAG;GACvB;GAEF,qBAAqB,KAAK,OAAO;GACjC,MAAM,EAAE,YAAY,WAAW,gBAAgB,SAAS,IAAI,SAAS;GACrE,OAAO;IAAC;IAAa;IAAY;IAAQ,kBAAkB,GAAG;GAAC;EACjE;EACA,UAAS,QAAO,CAAC;GACf,IAAI;GACJ,OAAO;GACP,OAAO,CAAC;IAAE,IAAI;IAAY,OAAO;IAAI,MAAM;IAAgC,OAAO,IAAI,EAAE,gBAAgB;IAAG,WAAW,GAAG;GAAc,CAAC;EAC1I,CAAC;EACD,UAAU,CAAC,GAAG,OAAO;EACrB,eAAc,QAAO,CAAC;GAAE,IAAI;GAAY,OAAO,IAAI,EAAE,cAAc;GAAG,MAAM;GAAgC,WAAW,GAAG;EAAY,CAAC;CACzI;AACF;;;;;;AAOA,SAAS,gBAAgB,SAA+B,WAAoG;CAC1J,IAAI;CACJ,MAAM,QAAQ,cAAc,WAAW,UAAU,CAAC;CAClD,MAAM,iBAAiB,MAAM,MAAM,IAAI;CAEvC,IAAI;CACJ,IAAI,SAAS;CAEb,IAAI;CACJ,IAAI;CAEJ,SAAS,OAAO;EACd,SAAS;EACT,MAAM,SAAS;EACf,MAAM,QAAQ,UAAU,CAAC,OAAO,cAAc,YAAY,SAAS,OAAO,KAAK,IAAI,KAAA;EACnF,IAAI,CAAC,UAAU,CAAC,OAAO;EACvB,MAAM,EAAE,SAAS,WAAW,SAAS;EACrC,IAAI,YAAY,QAAQ,WAAW,YAAY;EAC/C,MAAM,QAAQ,IAAI,IAAI,QAAQ,KAAI,MAAK,EAAE,EAAE,CAAC;EAC5C,MAAM,SAAS,IAAI,IAAI,QAAQ,QAAO,MAAK,EAAE,QAAQ,CAAC,CAAC,KAAI,MAAK,EAAE,EAAE,CAAC;EACrE,MAAM,OAAqB;GAAE;GAAO;GAAQ,aAAa;EAAO;EAChE,MAAM,SAAS,MAAM,SAAS,MAAM,MAAK,MAAK,EAAE,OAAO,MAAM,MAAM,IAAI,KAAA;EACvE,IAAI,MAAM,UAAU,UAAU,CAAC,OAAO,aAAa,CAAC,MAAM,IAAI,MAAM,MAAM,KAAK,OAAO,IAAI,MAAM,MAAM,IAAI,KAAK,SAAS;EACxH,OAAO;EACP,aAAa;EACb,OAAO,KAAK,SAAS,OAAO,MAAM,GAAG,QAAQ,aAAa,IAAI,CAAC,CAAC,QAAQ,gBAAgB,KAAK,CAAC;CAChG;CAEA,SAAS,QAAQ;EACf,IAAI,QAAQ;EACZ,SAAS;EACT,eAAe,IAAI;CACrB;CAEA,OAAO;EACL,YAAY,SAAS,UAAU;GAC7B,YAAY,SAAS,CAAC,CAAC;GACvB,WAAW;GACX,iBAAiB,SAAS,CAAC,CAAC;GAC5B,kBAAkB,SAAS,CAAC,CAAC;EAC/B,CAAC;EACD,QAAQ,UAAU,OAAO;GACvB,MAAM;GACN,WAAW;IACT,UAAU,KAAK;IACf,MAAM,QAAQ;IACd,OAAO,MAAM,MAAM,UAAU,KAAK;IAClC,MAAM;GACR;GACA,YAAY;IACV,OAAO;IACP,OAAO,KAAA;IACP,MAAM,QAAQ;IACd,UAAU,KAAA;IACV,OAAO,KAAA;IACP,aAAa,KAAA;GACf;EACF,CAAC;CACH;AACF"}
1
+ {"version":3,"file":"feature.js","names":[],"sources":["../../../src/features/comments/feature.ts"],"sourcesContent":["import { type AnyExtension, type Editor, Extension } from '@tiptap/core'\nimport type { EditorFeature } from '../../core'\nimport { Comments, type CommentsMeta, commentsKey } from './comments-plugin'\nimport { type CommentsModelFactory, type CommentsSnapshot, provideCommentsModel } from './model'\nimport { CommentMark, commentsSchemaExtensions } from './schema'\nimport { commentsShortcuts } from './shortcuts'\n\n/** What a framework binding supplies to the comments feature. */\nexport interface CommentsUi<C> {\n /** The toolbar entry: the margin toggle or the list menu, by the user's comments layout. */\n toolbarButton: C\n /** Mounted beside the editor content: the selection bubble, the inline popover and the layout glue. */\n overlay: C\n /** The „Kommentare“ settings tab component of the framework. */\n settingsTab: C\n}\n\n/** Options of `commentsFeatureCore`. */\nexport interface CommentsFeatureOptions {\n /**\n * Backs the comments with the host's own model (REST threads, a database) instead of the document's Y.Doc: the feature\n * then requires no `collab` feature, the `Comments` plugin reads the user from the model, gets the thread ids\n * (`known`/`hidden`) and the text ranges from its snapshot, and the framework `useComments` hooks use the model of\n * the surface (`commentsModelOf(ctx)`) instead of `createCommentsModel`. The factory runs once for the plugin and once\n * per `useComments` consumer, so a model that shares state between them keeps it outside the factory. The model\n * itself drives the active thread and the draft through the `comments-plugin` helpers.\n */\n model?: CommentsModelFactory\n}\n\n/**\n * Google-Docs-style comments on a collaborative document: select text, „Kommentar“ in the selection bubble, others\n * reply, anyone resolves or reopens a thread. Threads live in the Y.Doc (a `Y.Map` named `comments`, `createCommentsModel`), so\n * they sync live and persist with the document; the text range is the `comment` mark, highlighted by the `Comments`\n * plugin from the thread state. The user chooses per setting (`editing.commentsLayout`) between the margin column\n * (`CommentsMargin`, which the host places in the editor's scroll container and shows while the surface's\n * `commentsOpen` model is true; Mod-Shift-m or the toolbar button toggle it, and it excludes the AI sidebar) and the\n * inline popover plus the toolbar's list. Needs a collaborative surface with a `collaboration.user`: without one the\n * UI says so and nothing can be written (the schema mark stays registered, so stored comment marks round-trip). With\n * `options.model` the threads live wherever the host's model keeps them and no collaboration is needed.\n */\nexport function commentsFeatureCore<C>(ui: CommentsUi<C>, options: CommentsFeatureOptions = {}): EditorFeature<C> {\n const { model: factory } = options\n return {\n id: 'comments',\n dimension: 'interaction',\n schemaExtensions: commentsSchemaExtensions,\n requires: factory ? [] : ['collab'],\n extensions: (ctx) => {\n if (!factory) {\n return [\n CommentMark,\n Comments.configure({\n user: () => ctx.collaboration?.user ?? null,\n doc: () => ctx.collaboration?.ydoc ?? null,\n }),\n commentsShortcuts(ctx),\n ]\n }\n provideCommentsModel(ctx, factory)\n const { configured, bridge } = modelExtensions(factory, ctx.getEditor)\n return [CommentMark, configured, bridge, commentsShortcuts(ctx)]\n },\n commands: ctx => [\n { id: 'comments', toolbar: { group: 'collaboration', order: 10 }, icon: 'i-lucide-message-square-text', label: ctx.t('comments.title'), component: ui.toolbarButton },\n ],\n overlays: [ui.overlay],\n settingsTabs: ctx => [{ id: 'comments', label: ctx.t('comments.tab'), icon: 'i-lucide-message-square-text', component: ui.settingsTab }],\n }\n}\n\n/**\n * The `Comments` plugin and its feed for a host model: the plugin reads user, availability and `canComment` from the\n * model's snapshot; the bridge extension refreshes the model once the editor exists, mirrors the snapshot's thread ids\n * and ranges into the plugin state (queued, never from inside a transaction) and disposes the model with the editor.\n */\nfunction modelExtensions(factory: CommentsModelFactory, getEditor: Parameters<CommentsModelFactory>[0]): { configured: AnyExtension, bridge: AnyExtension } {\n let created: Editor | undefined\n const model = factory(() => created ?? getEditor())\n const snapshot = () => model.state.get()\n\n let stop: (() => void) | undefined\n let queued = false\n // What the plugin was last told, to skip no-op dispatches and to apply the deactivation rule.\n let told: CommentsSnapshot['threads'] | undefined\n let toldRanges: CommentsSnapshot['ranges'] | undefined\n\n function push() {\n queued = false\n const editor = created\n const value = editor && !editor.isDestroyed ? commentsKey.getState(editor.state) : undefined\n if (!editor || !value) return\n const { threads, ranges } = snapshot()\n if (threads === told && ranges === toldRanges) return\n const known = new Set(threads.map(t => t.id))\n const hidden = new Set(threads.filter(t => t.resolved).map(t => t.id))\n const meta: CommentsMeta = { known, hidden, modelRanges: ranges }\n const before = value.active ? told?.find(t => t.id === value.active) : undefined\n if (value.active && before && !before.resolved && (!known.has(value.active) || hidden.has(value.active))) meta.active = null\n told = threads\n toldRanges = ranges\n editor.view.dispatch(editor.state.tr.setMeta(commentsKey, meta).setMeta('addToHistory', false))\n }\n\n function queue() {\n if (queued) return\n queued = true\n queueMicrotask(push)\n }\n\n return {\n configured: Comments.configure({\n user: () => snapshot().user,\n doc: () => null,\n available: () => snapshot().available,\n canComment: () => snapshot().canComment,\n }),\n bridge: Extension.create({\n name: 'commentsModelBridge',\n onCreate() {\n created = this.editor\n model.refresh()\n stop = model.state.subscribe(queue)\n queue()\n },\n onDestroy() {\n stop?.()\n stop = undefined\n model.dispose()\n created = undefined\n told = undefined\n toldRanges = undefined\n },\n }),\n }\n}\n"],"mappings":";;;;;;;;;;;;;;;;;AAyCA,SAAgB,oBAAuB,IAAmB,UAAkC,CAAC,GAAqB;CAChH,MAAM,EAAE,OAAO,YAAY;CAC3B,OAAO;EACL,IAAI;EACJ,WAAW;EACX,kBAAkB;EAClB,UAAU,UAAU,CAAC,IAAI,CAAC,QAAQ;EAClC,aAAa,QAAQ;GACnB,IAAI,CAAC,SACH,OAAO;IACL;IACA,SAAS,UAAU;KACjB,YAAY,IAAI,eAAe,QAAQ;KACvC,WAAW,IAAI,eAAe,QAAQ;IACxC,CAAC;IACD,kBAAkB,GAAG;GACvB;GAEF,qBAAqB,KAAK,OAAO;GACjC,MAAM,EAAE,YAAY,WAAW,gBAAgB,SAAS,IAAI,SAAS;GACrE,OAAO;IAAC;IAAa;IAAY;IAAQ,kBAAkB,GAAG;GAAC;EACjE;EACA,WAAU,QAAO,CACf;GAAE,IAAI;GAAY,SAAS;IAAE,OAAO;IAAiB,OAAO;GAAG;GAAG,MAAM;GAAgC,OAAO,IAAI,EAAE,gBAAgB;GAAG,WAAW,GAAG;EAAc,CACtK;EACA,UAAU,CAAC,GAAG,OAAO;EACrB,eAAc,QAAO,CAAC;GAAE,IAAI;GAAY,OAAO,IAAI,EAAE,cAAc;GAAG,MAAM;GAAgC,WAAW,GAAG;EAAY,CAAC;CACzI;AACF;;;;;;AAOA,SAAS,gBAAgB,SAA+B,WAAoG;CAC1J,IAAI;CACJ,MAAM,QAAQ,cAAc,WAAW,UAAU,CAAC;CAClD,MAAM,iBAAiB,MAAM,MAAM,IAAI;CAEvC,IAAI;CACJ,IAAI,SAAS;CAEb,IAAI;CACJ,IAAI;CAEJ,SAAS,OAAO;EACd,SAAS;EACT,MAAM,SAAS;EACf,MAAM,QAAQ,UAAU,CAAC,OAAO,cAAc,YAAY,SAAS,OAAO,KAAK,IAAI,KAAA;EACnF,IAAI,CAAC,UAAU,CAAC,OAAO;EACvB,MAAM,EAAE,SAAS,WAAW,SAAS;EACrC,IAAI,YAAY,QAAQ,WAAW,YAAY;EAC/C,MAAM,QAAQ,IAAI,IAAI,QAAQ,KAAI,MAAK,EAAE,EAAE,CAAC;EAC5C,MAAM,SAAS,IAAI,IAAI,QAAQ,QAAO,MAAK,EAAE,QAAQ,CAAC,CAAC,KAAI,MAAK,EAAE,EAAE,CAAC;EACrE,MAAM,OAAqB;GAAE;GAAO;GAAQ,aAAa;EAAO;EAChE,MAAM,SAAS,MAAM,SAAS,MAAM,MAAK,MAAK,EAAE,OAAO,MAAM,MAAM,IAAI,KAAA;EACvE,IAAI,MAAM,UAAU,UAAU,CAAC,OAAO,aAAa,CAAC,MAAM,IAAI,MAAM,MAAM,KAAK,OAAO,IAAI,MAAM,MAAM,IAAI,KAAK,SAAS;EACxH,OAAO;EACP,aAAa;EACb,OAAO,KAAK,SAAS,OAAO,MAAM,GAAG,QAAQ,aAAa,IAAI,CAAC,CAAC,QAAQ,gBAAgB,KAAK,CAAC;CAChG;CAEA,SAAS,QAAQ;EACf,IAAI,QAAQ;EACZ,SAAS;EACT,eAAe,IAAI;CACrB;CAEA,OAAO;EACL,YAAY,SAAS,UAAU;GAC7B,YAAY,SAAS,CAAC,CAAC;GACvB,WAAW;GACX,iBAAiB,SAAS,CAAC,CAAC;GAC5B,kBAAkB,SAAS,CAAC,CAAC;EAC/B,CAAC;EACD,QAAQ,UAAU,OAAO;GACvB,MAAM;GACN,WAAW;IACT,UAAU,KAAK;IACf,MAAM,QAAQ;IACd,OAAO,MAAM,MAAM,UAAU,KAAK;IAClC,MAAM;GACR;GACA,YAAY;IACV,OAAO;IACP,OAAO,KAAA;IACP,MAAM,QAAQ;IACd,UAAU,KAAA;IACV,OAAO,KAAA;IACP,aAAa,KAAA;GACf;EACF,CAAC;CACH;AACF"}
@@ -1,8 +1,9 @@
1
1
  import { COMMENTS_LAYOUTS, CommentsLayout } from "../../settings/values.js";
2
- import { COMMENTS_FIELD, COMMENT_LIMITS, CommentAnchor, CommentAuthor, CommentMark, CommentReply, CommentThread, commentsSchemaExtensions } from "./schema.js";
3
- import { CommentsActions, CommentsModel, CommentsModelFactory, CommentsSnapshot, DocRange, commentsModelOf, createCommentsModel, createEditorCommentsModel } from "./model.js";
2
+ import { CommentAnchor, CommentAuthor, CommentReply, CommentThread, CommentsActions, CommentsModel, CommentsSnapshot, DocRange } from "../../core/backend-types.js";
3
+ import { CommentsModelFactory, commentsModelOf, createCommentsModel, createEditorCommentsModel } from "./model.js";
4
4
  import { CommentsFeatureOptions, CommentsUi, commentsFeatureCore } from "./feature.js";
5
5
  import { Comments, CommentsMeta, CommentsOptions, CommentsState, cancelCommentDraft, commentsAvailable, commentsCanComment, commentsDoc, commentsKey, commentsState, commentsUser, setActiveComment, startCommentDraft } from "./comments-plugin.js";
6
+ import { COMMENTS_FIELD, COMMENT_LIMITS, CommentMark, commentsSchemaExtensions } from "./schema.js";
6
7
  import { DRAFT_CARD, MARGIN_GAP, MarginCard, MarginEntry, MarginLayout, layoutMargin, marginCards } from "./margin-layout.js";
7
8
  import { MarginController, MarginSource, MarginState, createMarginController } from "./margin-controller.js";
8
9
  export { COMMENTS_FIELD, COMMENTS_LAYOUTS, COMMENT_LIMITS, type CommentAnchor, type CommentAuthor, CommentMark, type CommentReply, type CommentThread, Comments, type CommentsActions, type CommentsFeatureOptions, type CommentsLayout, type CommentsMeta, type CommentsModel, type CommentsModelFactory, type CommentsOptions, type CommentsSnapshot, type CommentsState, type CommentsUi, DRAFT_CARD, type DocRange, MARGIN_GAP, type MarginCard, type MarginController, type MarginEntry, type MarginLayout, type MarginSource, type MarginState, cancelCommentDraft, commentsAvailable, commentsCanComment, commentsDoc, commentsFeatureCore, commentsKey, commentsModelOf, commentsSchemaExtensions, commentsState, commentsUser, createCommentsModel, createEditorCommentsModel, createMarginController, layoutMargin, marginCards, setActiveComment, startCommentDraft };
@@ -1,6 +1,6 @@
1
1
  import { COMMENTS_LAYOUTS } from "../../settings/values.js";
2
- import { COMMENTS_FIELD, COMMENT_LIMITS, CommentMark, commentsSchemaExtensions } from "./schema.js";
3
2
  import { Comments, cancelCommentDraft, commentsAvailable, commentsCanComment, commentsDoc, commentsKey, commentsState, commentsUser, setActiveComment, startCommentDraft } from "./comments-plugin.js";
3
+ import { COMMENTS_FIELD, COMMENT_LIMITS, CommentMark, commentsSchemaExtensions } from "./schema.js";
4
4
  import { commentsModelOf, createCommentsModel, createEditorCommentsModel } from "./model.js";
5
5
  import { commentsFeatureCore } from "./feature.js";
6
6
  import { DRAFT_CARD, MARGIN_GAP, layoutMargin, marginCards } from "./margin-layout.js";
@@ -1,5 +1,6 @@
1
- import { CommentThread } from "./schema.js";
2
- import { DocRange } from "./model.js";
1
+ import { CommentThread, DocRange } from "../../core/backend-types.js";
2
+ import "./model.js";
3
+ import "./schema.js";
3
4
  //#region src/features/comments/margin-layout.d.ts
4
5
  /** Vertical gap between two cards of the comments margin, in px. */
5
6
  export declare const MARGIN_GAP = 8;
@@ -1,73 +1,8 @@
1
- import { ReadonlyStore } from "../../core/store.js";
2
- import { AuthorIdentity, FeatureContext } from "../../core/feature.js";
1
+ import { FeatureContext } from "../../core/feature.js";
2
+ import { CommentsActions, CommentsModel, CommentsSnapshot, DocRange } from "../../core/backend-types.js";
3
3
  import "../../core/index.js";
4
- import { CommentThread } from "./schema.js";
5
4
  import { Editor } from "@tiptap/core";
6
5
  //#region src/features/comments/model.d.ts
7
- export type DocRange = {
8
- from: number;
9
- to: number;
10
- };
11
- /** What a comments UI renders: replaced (a new object) whenever any part of it changes, so a store subscriber re-renders only then. */
12
- export interface CommentsSnapshot {
13
- /** Comments need a collaborative editor whose `Comments` extension has a user (a host model decides for itself). */
14
- available: boolean;
15
- /**
16
- * Whether the user may compose a comment now: the default model says `available` and the editor is editable, a host
17
- * model may allow readers of a read-only document to comment.
18
- */
19
- canComment: boolean;
20
- user: AuthorIdentity | null;
21
- /** Plain snapshots of all threads in the Y.Doc, replaced on every change. */
22
- threads: readonly CommentThread[];
23
- /** Current text range per thread id (threads without one are orphans). */
24
- ranges: ReadonlyMap<string, DocRange>;
25
- /**
26
- * Where the text of an orphaned open thread was: the document position of the deletion point, resolved from the
27
- * thread's stored anchor (so it is the same place for every collaborator and follows edits). Absent for orphans
28
- * without a usable anchor (threads from before anchors, or whose block is gone for good).
29
- */
30
- orphanAt: ReadonlyMap<string, number>;
31
- active: string | null;
32
- /** Current range of the draft a new comment is being written for. */
33
- draft: DocRange | null;
34
- /** The draft's text as the new thread will keep it (`quote`). */
35
- draftQuote: string;
36
- /** Unresolved threads in document order, orphans last; resolved ones newest first. */
37
- open: readonly CommentThread[];
38
- resolved: readonly CommentThread[];
39
- }
40
- /** The mutations of the comments of one editor; no-ops without collaboration or a user. */
41
- export interface CommentsActions {
42
- /** Creates a thread on the draft range; its id, or null without a (non-empty) draft or text. */
43
- add: (text: string) => string | null;
44
- reply: (threadId: string, text: string) => void;
45
- /** Changes the text of the user's own thread (`replyId` null) or reply. */
46
- edit: (threadId: string, replyId: string | null, text: string) => void;
47
- /** Resolves or reopens a thread (anyone may). */
48
- setResolved: (threadId: string, resolved: boolean) => void;
49
- /** Deletes the user's own thread with its marks / the user's own reply. */
50
- remove: (threadId: string) => void;
51
- removeReply: (threadId: string, replyId: string) => void;
52
- /** Activates a thread (`null`: none); `reveal` selects and scrolls to its text. */
53
- activate: (id: string | null, options?: {
54
- reveal?: boolean;
55
- }) => void;
56
- /** Starts a comment on the current selection (the layout shows the composer while `draft` is set). */
57
- startDraft: () => void;
58
- cancelDraft: () => void;
59
- }
60
- /**
61
- * The comments of one editor, framework-free: `state` is the observable snapshot, `refresh()` brings it up to date
62
- * (the framework hook calls it when the editor it watches changes; the model itself listens to that editor's
63
- * transactions from then on), `dispose()` detaches the editor and Y.Doc listeners and may be followed by `refresh()` again
64
- * (StrictMode mounts twice).
65
- */
66
- export interface CommentsModel extends CommentsActions {
67
- readonly state: ReadonlyStore<CommentsSnapshot>;
68
- refresh: () => void;
69
- dispose: () => void;
70
- }
71
6
  /**
72
7
  * The comment threads of a collaborative editor, stored in its Y.Doc (`COMMENTS_FIELD`, one nested `Y.Map` per thread,
73
8
  * replies in a nested `Y.Array`), so they sync live with the document and persist with its Yjs state. Keeps the
@@ -92,4 +27,5 @@ export declare function commentsModelOf(ctx: FeatureContext): CommentsModelFacto
92
27
  */
93
28
  export declare function createEditorCommentsModel(getEditor: () => Editor | undefined): CommentsModel;
94
29
  //#endregion
30
+ export type { CommentsActions, CommentsModel, CommentsSnapshot, DocRange };
95
31
  //# sourceMappingURL=model.d.ts.map
@@ -1,9 +1,9 @@
1
+ import { editorEntryOf } from "../../core/editor-ui.js";
1
2
  import { newBlockId } from "../../core/schema/block-ids.js";
2
3
  import { createStore } from "../../core/store.js";
3
4
  import { anchorResolverOf, releaseRanges, resolveRange } from "../../core/doc-anchors.js";
4
- import { editorEntryOf } from "../../core/editor-ui.js";
5
- import { COMMENTS_FIELD, COMMENT_LIMITS } from "./schema.js";
6
5
  import { cancelCommentDraft, commentsDoc, commentsKey, commentsUser, setActiveComment, startCommentDraft } from "./comments-plugin.js";
6
+ import { COMMENTS_FIELD, COMMENT_LIMITS } from "./schema.js";
7
7
  import { EMPTY_SNAPSHOT, NO_POSITIONS, NO_RANGES, NO_THREADS, sameOrphanAt, sameRange, sameRanges, sameUser } from "./snapshot-equality.js";
8
8
  import { captureThreadAnchor, resolveThreadAnchor } from "./thread-anchor.js";
9
9
  import * as Y from "yjs";
@@ -1 +1 @@
1
- {"version":3,"file":"model.js","names":[],"sources":["../../../src/features/comments/model.ts"],"sourcesContent":["import type { Editor } from '@tiptap/core'\nimport * as Y from 'yjs'\nimport type { AuthorIdentity, FeatureContext } from '../../core'\nimport { anchorResolverOf, editorEntryOf, releaseRanges, resolveRange } from '../../core'\nimport { newBlockId } from '../../core/schema'\nimport { createStore, type ReadonlyStore } from '../../core/store'\nimport { cancelCommentDraft, commentsDoc, commentsKey, type CommentsMeta, commentsUser, setActiveComment, startCommentDraft } from './comments-plugin'\nimport { COMMENT_LIMITS, COMMENTS_FIELD, type CommentAnchor, type CommentReply, type CommentThread } from './schema'\nimport { EMPTY_SNAPSHOT, NO_POSITIONS, NO_RANGES, NO_THREADS, sameOrphanAt, sameRange, sameRanges, sameUser } from './snapshot-equality'\nimport { captureThreadAnchor, resolveThreadAnchor } from './thread-anchor'\n\nexport type DocRange = { from: number, to: number }\n\n/** What a comments UI renders: replaced (a new object) whenever any part of it changes, so a store subscriber re-renders only then. */\nexport interface CommentsSnapshot {\n /** Comments need a collaborative editor whose `Comments` extension has a user (a host model decides for itself). */\n available: boolean\n /**\n * Whether the user may compose a comment now: the default model says `available` and the editor is editable, a host\n * model may allow readers of a read-only document to comment.\n */\n canComment: boolean\n user: AuthorIdentity | null\n /** Plain snapshots of all threads in the Y.Doc, replaced on every change. */\n threads: readonly CommentThread[]\n /** Current text range per thread id (threads without one are orphans). */\n ranges: ReadonlyMap<string, DocRange>\n /**\n * Where the text of an orphaned open thread was: the document position of the deletion point, resolved from the\n * thread's stored anchor (so it is the same place for every collaborator and follows edits). Absent for orphans\n * without a usable anchor (threads from before anchors, or whose block is gone for good).\n */\n orphanAt: ReadonlyMap<string, number>\n active: string | null\n /** Current range of the draft a new comment is being written for. */\n draft: DocRange | null\n /** The draft's text as the new thread will keep it (`quote`). */\n draftQuote: string\n /** Unresolved threads in document order, orphans last; resolved ones newest first. */\n open: readonly CommentThread[]\n resolved: readonly CommentThread[]\n}\n\n/** The mutations of the comments of one editor; no-ops without collaboration or a user. */\nexport interface CommentsActions {\n /** Creates a thread on the draft range; its id, or null without a (non-empty) draft or text. */\n add: (text: string) => string | null\n reply: (threadId: string, text: string) => void\n /** Changes the text of the user's own thread (`replyId` null) or reply. */\n edit: (threadId: string, replyId: string | null, text: string) => void\n /** Resolves or reopens a thread (anyone may). */\n setResolved: (threadId: string, resolved: boolean) => void\n /** Deletes the user's own thread with its marks / the user's own reply. */\n remove: (threadId: string) => void\n removeReply: (threadId: string, replyId: string) => void\n /** Activates a thread (`null`: none); `reveal` selects and scrolls to its text. */\n activate: (id: string | null, options?: { reveal?: boolean }) => void\n /** Starts a comment on the current selection (the layout shows the composer while `draft` is set). */\n startDraft: () => void\n cancelDraft: () => void\n}\n\n/**\n * The comments of one editor, framework-free: `state` is the observable snapshot, `refresh()` brings it up to date\n * (the framework hook calls it when the editor it watches changes; the model itself listens to that editor's\n * transactions from then on), `dispose()` detaches the editor and Y.Doc listeners and may be followed by `refresh()` again\n * (StrictMode mounts twice).\n */\nexport interface CommentsModel extends CommentsActions {\n readonly state: ReadonlyStore<CommentsSnapshot>\n refresh: () => void\n dispose: () => void\n}\n\n/** A thread's `Y.Map` as plain data; `replies` converted explicitly so it is always a plain array. */\nfunction snapshotOf(thread: Y.Map<unknown>): CommentThread {\n const replies = thread.get('replies')\n return { ...(thread.toJSON() as CommentThread), replies: replies instanceof Y.Array ? replies.toArray() as CommentReply[] : [] }\n}\n\n/**\n * The comment threads of a collaborative editor, stored in its Y.Doc (`COMMENTS_FIELD`, one nested `Y.Map` per thread,\n * replies in a nested `Y.Array`), so they sync live with the document and persist with its Yjs state. Keeps the\n * `Comments` plugin's `known`/`hidden` thread ids in step with the store (highlights), exposes the plugin's ranges,\n * active thread and draft, and the mutations. Mutations are no-ops without collaboration or user; editing and\n * deleting are limited to the user's own comments and replies (a client-side rule: the Y.Doc itself has no ACL).\n * `getEditor` names the editor to work on (it may change over time and may return a destroyed or no editor).\n * Each thread also keeps `anchor` (a Yjs relative position of its text's start, see `CommentAnchor`): `orphanAt` resolves\n * it for the threads whose text is gone. Threads from before anchors get theirs written once they are seen with a range.\n */\nexport function createCommentsModel(getEditor: () => Editor | undefined): CommentsModel {\n const store = createStore<CommentsSnapshot>(EMPTY_SNAPSHOT)\n\n const current = () => {\n const instance = getEditor()\n return instance && !instance.isDestroyed ? instance : undefined\n }\n\n // The editor whose transactions are followed, and the Y.Map of threads observed.\n let bound: Editor | undefined\n let observed: { doc: Y.Doc, map: Y.Map<unknown> } | undefined\n let threads: readonly CommentThread[] = NO_THREADS\n let syncQueued = false\n // The thread list the plugin was last told about, for the deactivation rule.\n let told: readonly CommentThread[] = NO_THREADS\n // Threads already tried for an anchor (written, or not capturable), so a failed capture is not repeated on every change.\n const anchorTried = new Set<string>()\n let healQueued = false\n\n function unobserve() {\n observed?.map.unobserveDeep(onThreadsChanged)\n observed = undefined\n }\n\n function onThreadsChanged() {\n if (!observed) return\n threads = [...observed.map.values()].filter((t): t is Y.Map<unknown> => t instanceof Y.Map).map(snapshotOf)\n recompute()\n queueSync()\n }\n\n function onTransaction() {\n recompute()\n }\n\n function unbind() {\n bound?.off('transaction', onTransaction)\n // `setEditable` emits `update` only, and `canComment` follows `isEditable`.\n bound?.off('update', onTransaction)\n bound = undefined\n }\n\n /** The snapshot of the editor's current state; the previous object when nothing changed. */\n function recompute() {\n const instance = current()\n if (!instance) {\n store.set(EMPTY_SNAPSHOT)\n return\n }\n const previous = store.get()\n const ydoc = commentsDoc(instance)\n const user = commentsUser(instance)\n const plugin = commentsKey.getState(instance.state)\n const ranges = plugin?.ranges ?? NO_RANGES\n const orphanAt = orphanPositions(instance, ranges)\n const active = plugin?.active ?? null\n const anchor = plugin?.draft\n const draft = anchor ? resolveRange(instance.state, anchor) : null\n const draftQuote = draft ? instance.state.doc.textBetween(draft.from, draft.to, ' ').slice(0, COMMENT_LIMITS.quote) : ''\n const available = !!ydoc && !!user\n const canComment = available && instance.isEditable\n\n const sameThreads = threads === previous.threads\n const sameRangeMap = sameRanges(ranges, previous.ranges)\n const sameOrphanMap = sameOrphanAt(orphanAt, previous.orphanAt)\n if (\n available === previous.available && canComment === previous.canComment && sameUser(user, previous.user) && sameThreads && sameRangeMap && sameOrphanMap\n && active === previous.active && sameRange(draft, previous.draft) && draftQuote === previous.draftQuote\n ) return\n\n const kept = sameThreads && sameRangeMap\n const open = kept\n ? previous.open\n : threads\n .filter(t => !t.resolved)\n .sort((a, b) => (ranges.get(a.id)?.from ?? Infinity) - (ranges.get(b.id)?.from ?? Infinity) || a.createdAt.localeCompare(b.createdAt))\n const resolved = sameThreads\n ? previous.resolved\n : threads.filter(t => t.resolved).sort((a, b) => b.createdAt.localeCompare(a.createdAt))\n store.set({\n available,\n canComment,\n user,\n threads,\n ranges: sameRangeMap ? previous.ranges : ranges,\n orphanAt: sameOrphanMap ? previous.orphanAt : orphanAt,\n active,\n draft: sameRange(draft, previous.draft) ? previous.draft : draft,\n draftQuote,\n open,\n resolved,\n })\n if (available) queueHeal()\n }\n\n /** Where each unresolved thread without a text range was, from its anchor; empty without a Yjs session. */\n function orphanPositions(instance: Editor, ranges: ReadonlyMap<string, DocRange>): ReadonlyMap<string, number> {\n const resolver = anchorResolverOf(instance)\n if (!resolver) return NO_POSITIONS\n const size = instance.state.doc.content.size\n let found: Map<string, number> | undefined\n for (const thread of threads) {\n if (thread.resolved || ranges.has(thread.id) || !thread.anchor) continue\n const position = resolveThreadAnchor(instance.state, resolver, thread.anchor)\n if (position !== null && position <= size) (found ??= new Map()).set(thread.id, position)\n }\n return found ?? NO_POSITIONS\n }\n\n // Threads from before anchors get theirs once they are seen with their text in the document (any client with a user\n // writes it; the positions are equivalent, so concurrent writes agree). Queued: not written from inside a Yjs\n // observer or a transaction listener.\n function queueHeal() {\n if (healQueued || !threads.some(t => !t.anchor && !anchorTried.has(t.id))) return\n healQueued = true\n queueMicrotask(() => {\n healQueued = false\n healAnchors()\n })\n }\n\n function healAnchors() {\n const ctx = writable()\n const resolver = ctx && anchorResolverOf(ctx.editor)\n if (!ctx || !resolver || ctx.editor !== bound) return\n const { ranges } = store.get()\n const written: [Y.Map<unknown>, CommentAnchor][] = []\n for (const { id, anchor } of threads) {\n const range = ranges.get(id)\n if (anchor || anchorTried.has(id) || !range) continue\n anchorTried.add(id)\n const thread = threadMap(ctx.map, id)\n const captured = thread && captureThreadAnchor(ctx.editor.state, resolver, range)\n if (thread && captured) written.push([thread, captured])\n }\n if (written.length) ctx.ydoc.transact(() => written.forEach(([thread, captured]) => thread.set('anchor', captured)))\n }\n\n // Highlights appear and disappear on every client as threads arrive, get resolved or deleted. The active thread\n // stays highlighted even when resolved (a resolved thread activated from its card), so a thread that turns resolved\n // or disappears while active is deactivated here, on every client, not only on the one that resolved or deleted it.\n // Queued (not dispatched from inside the Yjs observer or a transaction listener).\n function queueSync() {\n if (syncQueued) return\n syncQueued = true\n queueMicrotask(() => {\n syncQueued = false\n syncPlugin()\n })\n }\n\n function syncPlugin() {\n const instance = current()\n if (!instance || instance !== bound) return\n const value = commentsKey.getState(instance.state)\n if (!value) return\n const known = new Set(threads.map(t => t.id))\n const hidden = new Set(threads.filter(t => t.resolved).map(t => t.id))\n const meta: CommentsMeta = { known, hidden }\n const before = value.active ? told.find(t => t.id === value.active) : undefined\n if (value.active && before && !before.resolved && (!known.has(value.active) || hidden.has(value.active))) meta.active = null\n told = threads\n instance.view.dispatch(instance.state.tr.setMeta(commentsKey, meta).setMeta('addToHistory', false))\n }\n\n /** Follows the editor `getEditor` names now, and the Y.Doc of its collaboration session. */\n function refresh() {\n const instance = current()\n if (instance !== bound) {\n unbind()\n unobserve()\n bound = instance\n threads = NO_THREADS\n told = NO_THREADS\n anchorTried.clear()\n instance?.on('transaction', onTransaction)\n instance?.on('update', onTransaction)\n // The new editor's plugin knows no threads yet.\n queueSync()\n }\n const ydoc = instance ? commentsDoc(instance) : null\n if ((observed?.doc ?? null) !== ydoc) {\n unobserve()\n if (ydoc) {\n const map = ydoc.getMap<unknown>(COMMENTS_FIELD)\n observed = { doc: ydoc, map }\n map.observeDeep(onThreadsChanged)\n threads = [...map.values()].filter((t): t is Y.Map<unknown> => t instanceof Y.Map).map(snapshotOf)\n }\n else {\n threads = NO_THREADS\n }\n queueSync()\n }\n recompute()\n }\n\n function dispose() {\n unbind()\n unobserve()\n threads = NO_THREADS\n told = NO_THREADS\n anchorTried.clear()\n store.set(EMPTY_SNAPSHOT)\n }\n\n /** Editor, thread map and user while comments are available; null otherwise. */\n function writable() {\n const instance = current()\n const ydoc = instance && commentsDoc(instance)\n const author = instance && commentsUser(instance)\n if (!instance || !ydoc || !author) return null\n return { editor: instance, ydoc, map: ydoc.getMap<unknown>(COMMENTS_FIELD), user: { id: author.id, name: author.name, color: author.color } }\n }\n\n /** Trimmed and cut to the limit; '' when nothing is left. */\n const clean = (text: string) => text.trim().slice(0, COMMENT_LIMITS.text)\n\n function threadMap(map: Y.Map<unknown>, threadId: string): Y.Map<unknown> | null {\n const thread = map.get(threadId)\n return thread instanceof Y.Map ? thread : null\n }\n\n function repliesOf(thread: Y.Map<unknown>): Y.Array<CommentReply> | null {\n const replies = thread.get('replies')\n return replies instanceof Y.Array ? replies as Y.Array<CommentReply> : null\n }\n\n function add(text: string): string | null {\n const ctx = writable()\n const body = clean(text)\n const anchor = ctx && commentsKey.getState(ctx.editor.state)?.draft\n const range = ctx && anchor ? resolveRange(ctx.editor.state, anchor) : null\n const type = ctx?.editor.schema.marks.comment\n if (!ctx || !anchor || !range || range.from >= range.to || !body || !type) return null\n const id = newBlockId()\n const { state } = ctx.editor\n const resolver = anchorResolverOf(ctx.editor)\n const threadAnchor = resolver ? captureThreadAnchor(state, resolver, range) : null\n const quote = state.doc.textBetween(range.from, range.to, ' ').slice(0, COMMENT_LIMITS.quote)\n const tr = state.tr.addMark(range.from, range.to, type.create({ id }))\n // Text that takes no marks (code block, inline code): no thread that would start out without a range.\n if (!tr.docChanged) return null\n // Not undoable: the mark is the thread's anchor, not an edit of the text.\n const meta: CommentsMeta = { draft: null, active: id }\n ctx.editor.view.dispatch(tr.setMeta(commentsKey, meta).setMeta('addToHistory', false))\n releaseRanges(ctx.editor, [anchor])\n const thread = new Y.Map<unknown>()\n thread.set('id', id)\n thread.set('author', ctx.user)\n thread.set('text', body)\n thread.set('createdAt', new Date().toISOString())\n thread.set('quote', quote)\n thread.set('resolved', false)\n if (threadAnchor) thread.set('anchor', threadAnchor)\n thread.set('replies', new Y.Array<CommentReply>())\n ctx.map.set(id, thread)\n return id\n }\n\n function reply(threadId: string, text: string): void {\n const ctx = writable()\n const body = clean(text)\n const thread = ctx && threadMap(ctx.map, threadId)\n const replies = thread && repliesOf(thread)\n if (!ctx || !replies || !body) return\n replies.push([{ id: newBlockId(), author: ctx.user, text: body, createdAt: new Date().toISOString() }])\n }\n\n function edit(threadId: string, replyId: string | null, text: string): void {\n const ctx = writable()\n const body = clean(text)\n const thread = ctx && threadMap(ctx.map, threadId)\n if (!ctx || !thread || !body) return\n const now = new Date().toISOString()\n if (replyId === null) {\n if ((thread.get('author') as CommentThread['author'] | undefined)?.id !== ctx.user.id || thread.get('text') === body) return\n ctx.ydoc.transact(() => {\n thread.set('text', body)\n thread.set('editedAt', now)\n })\n return\n }\n const replies = repliesOf(thread)\n const index = replies ? replies.toArray().findIndex(r => r.id === replyId) : -1\n const previous = replies && index >= 0 ? replies.get(index) : undefined\n if (!replies || !previous || previous.author.id !== ctx.user.id || previous.text === body) return\n ctx.ydoc.transact(() => {\n replies.delete(index, 1)\n replies.insert(index, [{ ...previous, text: body, editedAt: now }])\n })\n }\n\n function setResolved(threadId: string, value: boolean): void {\n const ctx = writable()\n const thread = ctx && threadMap(ctx.map, threadId)\n if (!ctx || !thread) return\n thread.set('resolved', value)\n if (value && commentsKey.getState(ctx.editor.state)?.active === threadId) setActiveComment(ctx.editor, null)\n }\n\n function remove(threadId: string): void {\n const ctx = writable()\n const thread = ctx && threadMap(ctx.map, threadId)\n if (!ctx || !thread || (thread.get('author') as CommentThread['author'] | undefined)?.id !== ctx.user.id) return\n const { state } = ctx.editor\n const tr = state.tr\n state.doc.descendants((node, pos) => {\n if (!node.isText) return\n const mark = node.marks.find(m => m.type.name === 'comment' && m.attrs.id === threadId)\n if (mark) tr.removeMark(pos, pos + node.nodeSize, mark)\n })\n if (commentsKey.getState(state)?.active === threadId) tr.setMeta(commentsKey, { active: null } satisfies CommentsMeta)\n if (tr.docChanged || tr.getMeta(commentsKey)) ctx.editor.view.dispatch(tr.setMeta('addToHistory', false))\n ctx.map.delete(threadId)\n }\n\n function removeReply(threadId: string, replyId: string): void {\n const ctx = writable()\n const thread = ctx && threadMap(ctx.map, threadId)\n const replies = thread && repliesOf(thread)\n if (!ctx || !replies) return\n const index = replies.toArray().findIndex(r => r.id === replyId)\n if (index >= 0 && replies.get(index).author.id === ctx.user.id) replies.delete(index, 1)\n }\n\n function activate(id: string | null, options: { reveal?: boolean } = {}): void {\n const instance = current()\n if (instance) setActiveComment(instance, id, options)\n }\n\n function startDraft(): void {\n const ctx = writable()\n if (ctx) startCommentDraft(ctx.editor)\n }\n\n function cancelDraft(): void {\n const instance = current()\n if (instance) cancelCommentDraft(instance)\n }\n\n return { state: store, refresh, dispose, add, reply, edit, setResolved, remove, removeReply, activate, startDraft, cancelDraft }\n}\n\n/** Creates the comments model of one editor, as a host supplies it to `commentsFeatureCore`. */\nexport type CommentsModelFactory = (getEditor: () => Editor | undefined) => CommentsModel\n\n// The host's model factory per surface context, set by the comments feature while the surface builds its extensions.\nconst modelFactories = new WeakMap<FeatureContext, CommentsModelFactory>()\n\n/** Registers the host model factory of `ctx` (the comments feature does this; hosts pass `model` to the feature). */\nexport function provideCommentsModel(ctx: FeatureContext, factory: CommentsModelFactory): void {\n modelFactories.set(ctx, factory)\n}\n\n/** The host model factory the comments feature of `ctx` was configured with; undefined for the default Y.Doc model. */\nexport function commentsModelOf(ctx: FeatureContext): CommentsModelFactory | undefined {\n return modelFactories.get(ctx)\n}\n\n/**\n * The comments model the framework hooks (`useComments`) use: the model of the surface `getEditor` belongs to\n * (`commentsModelOf` of its feature context: the host's `model` factory) and `createCommentsModel` for every other\n * editor. It follows the editor over time: when the editor changes to one of a surface with another model, the inner\n * model is replaced (disposed, created, refreshed) and `state` carries on with the new one. The factory runs once per\n * consumer of this function, so a host model that must share state across them keeps it outside the factory.\n */\nexport function createEditorCommentsModel(getEditor: () => Editor | undefined): CommentsModel {\n const store = createStore<CommentsSnapshot>(EMPTY_SNAPSHOT)\n let inner: { model: CommentsModel, factory: CommentsModelFactory, stop: () => void } | undefined\n\n function release() {\n inner?.stop()\n inner?.model.dispose()\n inner = undefined\n }\n\n /** The inner model for the editor now; a replacement when its surface brings another factory. */\n function current(): CommentsModel {\n const entry = editorEntryOf(getEditor())\n const factory = (entry && commentsModelOf(entry.ctx)) ?? createCommentsModel\n if (inner?.factory !== factory) {\n release()\n const model = factory(getEditor)\n inner = { model, factory, stop: model.state.subscribe(snapshot => store.set(snapshot)) }\n store.set(model.state.get())\n }\n return inner!.model\n }\n\n return {\n state: store,\n refresh: () => current().refresh(),\n dispose: () => {\n release()\n store.set(EMPTY_SNAPSHOT)\n },\n add: text => current().add(text),\n reply: (threadId, text) => current().reply(threadId, text),\n edit: (threadId, replyId, text) => current().edit(threadId, replyId, text),\n setResolved: (threadId, resolved) => current().setResolved(threadId, resolved),\n remove: threadId => current().remove(threadId),\n removeReply: (threadId, replyId) => current().removeReply(threadId, replyId),\n activate: (id, options) => current().activate(id, options),\n startDraft: () => current().startDraft(),\n cancelDraft: () => current().cancelDraft(),\n }\n}\n"],"mappings":";;;;;;;;;;;AA2EA,SAAS,WAAW,QAAuC;CACzD,MAAM,UAAU,OAAO,IAAI,SAAS;CACpC,OAAO;EAAE,GAAI,OAAO,OAAO;EAAqB,SAAS,mBAAmB,EAAE,QAAQ,QAAQ,QAAQ,IAAsB,CAAC;CAAE;AACjI;;;;;;;;;;;AAYA,SAAgB,oBAAoB,WAAoD;CACtF,MAAM,QAAQ,YAA8B,cAAc;CAE1D,MAAM,gBAAgB;EACpB,MAAM,WAAW,UAAU;EAC3B,OAAO,YAAY,CAAC,SAAS,cAAc,WAAW,KAAA;CACxD;CAGA,IAAI;CACJ,IAAI;CACJ,IAAI,UAAoC;CACxC,IAAI,aAAa;CAEjB,IAAI,OAAiC;CAErC,MAAM,8BAAc,IAAI,IAAY;CACpC,IAAI,aAAa;CAEjB,SAAS,YAAY;EACnB,UAAU,IAAI,cAAc,gBAAgB;EAC5C,WAAW,KAAA;CACb;CAEA,SAAS,mBAAmB;EAC1B,IAAI,CAAC,UAAU;EACf,UAAU,CAAC,GAAG,SAAS,IAAI,OAAO,CAAC,CAAC,CAAC,QAAQ,MAA2B,aAAa,EAAE,GAAG,CAAC,CAAC,IAAI,UAAU;EAC1G,UAAU;EACV,UAAU;CACZ;CAEA,SAAS,gBAAgB;EACvB,UAAU;CACZ;CAEA,SAAS,SAAS;EAChB,OAAO,IAAI,eAAe,aAAa;EAEvC,OAAO,IAAI,UAAU,aAAa;EAClC,QAAQ,KAAA;CACV;;CAGA,SAAS,YAAY;EACnB,MAAM,WAAW,QAAQ;EACzB,IAAI,CAAC,UAAU;GACb,MAAM,IAAI,cAAc;GACxB;EACF;EACA,MAAM,WAAW,MAAM,IAAI;EAC3B,MAAM,OAAO,YAAY,QAAQ;EACjC,MAAM,OAAO,aAAa,QAAQ;EAClC,MAAM,SAAS,YAAY,SAAS,SAAS,KAAK;EAClD,MAAM,SAAS,QAAQ,UAAU;EACjC,MAAM,WAAW,gBAAgB,UAAU,MAAM;EACjD,MAAM,SAAS,QAAQ,UAAU;EACjC,MAAM,SAAS,QAAQ;EACvB,MAAM,QAAQ,SAAS,aAAa,SAAS,OAAO,MAAM,IAAI;EAC9D,MAAM,aAAa,QAAQ,SAAS,MAAM,IAAI,YAAY,MAAM,MAAM,MAAM,IAAI,GAAG,CAAC,CAAC,MAAM,GAAG,eAAe,KAAK,IAAI;EACtH,MAAM,YAAY,CAAC,CAAC,QAAQ,CAAC,CAAC;EAC9B,MAAM,aAAa,aAAa,SAAS;EAEzC,MAAM,cAAc,YAAY,SAAS;EACzC,MAAM,eAAe,WAAW,QAAQ,SAAS,MAAM;EACvD,MAAM,gBAAgB,aAAa,UAAU,SAAS,QAAQ;EAC9D,IACE,cAAc,SAAS,aAAa,eAAe,SAAS,cAAc,SAAS,MAAM,SAAS,IAAI,KAAK,eAAe,gBAAgB,iBACvI,WAAW,SAAS,UAAU,UAAU,OAAO,SAAS,KAAK,KAAK,eAAe,SAAS,YAC7F;EAGF,MAAM,OADO,eAAe,eAExB,SAAS,OACT,QACG,QAAO,MAAK,CAAC,EAAE,QAAQ,CAAC,CACxB,MAAM,GAAG,OAAO,OAAO,IAAI,EAAE,EAAE,CAAC,EAAE,QAAQ,aAAa,OAAO,IAAI,EAAE,EAAE,CAAC,EAAE,QAAQ,aAAa,EAAE,UAAU,cAAc,EAAE,SAAS,CAAC;EAC3I,MAAM,WAAW,cACb,SAAS,WACT,QAAQ,QAAO,MAAK,EAAE,QAAQ,CAAC,CAAC,MAAM,GAAG,MAAM,EAAE,UAAU,cAAc,EAAE,SAAS,CAAC;EACzF,MAAM,IAAI;GACR;GACA;GACA;GACA;GACA,QAAQ,eAAe,SAAS,SAAS;GACzC,UAAU,gBAAgB,SAAS,WAAW;GAC9C;GACA,OAAO,UAAU,OAAO,SAAS,KAAK,IAAI,SAAS,QAAQ;GAC3D;GACA;GACA;EACF,CAAC;EACD,IAAI,WAAW,UAAU;CAC3B;;CAGA,SAAS,gBAAgB,UAAkB,QAAoE;EAC7G,MAAM,WAAW,iBAAiB,QAAQ;EAC1C,IAAI,CAAC,UAAU,OAAO;EACtB,MAAM,OAAO,SAAS,MAAM,IAAI,QAAQ;EACxC,IAAI;EACJ,KAAK,MAAM,UAAU,SAAS;GAC5B,IAAI,OAAO,YAAY,OAAO,IAAI,OAAO,EAAE,KAAK,CAAC,OAAO,QAAQ;GAChE,MAAM,WAAW,oBAAoB,SAAS,OAAO,UAAU,OAAO,MAAM;GAC5E,IAAI,aAAa,QAAQ,YAAY,MAAM,CAAC,0BAAU,IAAI,IAAI,EAAA,CAAG,IAAI,OAAO,IAAI,QAAQ;EAC1F;EACA,OAAO,SAAS;CAClB;CAKA,SAAS,YAAY;EACnB,IAAI,cAAc,CAAC,QAAQ,MAAK,MAAK,CAAC,EAAE,UAAU,CAAC,YAAY,IAAI,EAAE,EAAE,CAAC,GAAG;EAC3E,aAAa;EACb,qBAAqB;GACnB,aAAa;GACb,YAAY;EACd,CAAC;CACH;CAEA,SAAS,cAAc;EACrB,MAAM,MAAM,SAAS;EACrB,MAAM,WAAW,OAAO,iBAAiB,IAAI,MAAM;EACnD,IAAI,CAAC,OAAO,CAAC,YAAY,IAAI,WAAW,OAAO;EAC/C,MAAM,EAAE,WAAW,MAAM,IAAI;EAC7B,MAAM,UAA6C,CAAC;EACpD,KAAK,MAAM,EAAE,IAAI,YAAY,SAAS;GACpC,MAAM,QAAQ,OAAO,IAAI,EAAE;GAC3B,IAAI,UAAU,YAAY,IAAI,EAAE,KAAK,CAAC,OAAO;GAC7C,YAAY,IAAI,EAAE;GAClB,MAAM,SAAS,UAAU,IAAI,KAAK,EAAE;GACpC,MAAM,WAAW,UAAU,oBAAoB,IAAI,OAAO,OAAO,UAAU,KAAK;GAChF,IAAI,UAAU,UAAU,QAAQ,KAAK,CAAC,QAAQ,QAAQ,CAAC;EACzD;EACA,IAAI,QAAQ,QAAQ,IAAI,KAAK,eAAe,QAAQ,SAAS,CAAC,QAAQ,cAAc,OAAO,IAAI,UAAU,QAAQ,CAAC,CAAC;CACrH;CAMA,SAAS,YAAY;EACnB,IAAI,YAAY;EAChB,aAAa;EACb,qBAAqB;GACnB,aAAa;GACb,WAAW;EACb,CAAC;CACH;CAEA,SAAS,aAAa;EACpB,MAAM,WAAW,QAAQ;EACzB,IAAI,CAAC,YAAY,aAAa,OAAO;EACrC,MAAM,QAAQ,YAAY,SAAS,SAAS,KAAK;EACjD,IAAI,CAAC,OAAO;EACZ,MAAM,QAAQ,IAAI,IAAI,QAAQ,KAAI,MAAK,EAAE,EAAE,CAAC;EAC5C,MAAM,SAAS,IAAI,IAAI,QAAQ,QAAO,MAAK,EAAE,QAAQ,CAAC,CAAC,KAAI,MAAK,EAAE,EAAE,CAAC;EACrE,MAAM,OAAqB;GAAE;GAAO;EAAO;EAC3C,MAAM,SAAS,MAAM,SAAS,KAAK,MAAK,MAAK,EAAE,OAAO,MAAM,MAAM,IAAI,KAAA;EACtE,IAAI,MAAM,UAAU,UAAU,CAAC,OAAO,aAAa,CAAC,MAAM,IAAI,MAAM,MAAM,KAAK,OAAO,IAAI,MAAM,MAAM,IAAI,KAAK,SAAS;EACxH,OAAO;EACP,SAAS,KAAK,SAAS,SAAS,MAAM,GAAG,QAAQ,aAAa,IAAI,CAAC,CAAC,QAAQ,gBAAgB,KAAK,CAAC;CACpG;;CAGA,SAAS,UAAU;EACjB,MAAM,WAAW,QAAQ;EACzB,IAAI,aAAa,OAAO;GACtB,OAAO;GACP,UAAU;GACV,QAAQ;GACR,UAAU;GACV,OAAO;GACP,YAAY,MAAM;GAClB,UAAU,GAAG,eAAe,aAAa;GACzC,UAAU,GAAG,UAAU,aAAa;GAEpC,UAAU;EACZ;EACA,MAAM,OAAO,WAAW,YAAY,QAAQ,IAAI;EAChD,KAAK,UAAU,OAAO,UAAU,MAAM;GACpC,UAAU;GACV,IAAI,MAAM;IACR,MAAM,MAAM,KAAK,OAAgB,cAAc;IAC/C,WAAW;KAAE,KAAK;KAAM;IAAI;IAC5B,IAAI,YAAY,gBAAgB;IAChC,UAAU,CAAC,GAAG,IAAI,OAAO,CAAC,CAAC,CAAC,QAAQ,MAA2B,aAAa,EAAE,GAAG,CAAC,CAAC,IAAI,UAAU;GACnG,OAEE,UAAU;GAEZ,UAAU;EACZ;EACA,UAAU;CACZ;CAEA,SAAS,UAAU;EACjB,OAAO;EACP,UAAU;EACV,UAAU;EACV,OAAO;EACP,YAAY,MAAM;EAClB,MAAM,IAAI,cAAc;CAC1B;;CAGA,SAAS,WAAW;EAClB,MAAM,WAAW,QAAQ;EACzB,MAAM,OAAO,YAAY,YAAY,QAAQ;EAC7C,MAAM,SAAS,YAAY,aAAa,QAAQ;EAChD,IAAI,CAAC,YAAY,CAAC,QAAQ,CAAC,QAAQ,OAAO;EAC1C,OAAO;GAAE,QAAQ;GAAU;GAAM,KAAK,KAAK,OAAgB,cAAc;GAAG,MAAM;IAAE,IAAI,OAAO;IAAI,MAAM,OAAO;IAAM,OAAO,OAAO;GAAM;EAAE;CAC9I;;CAGA,MAAM,SAAS,SAAiB,KAAK,KAAK,CAAC,CAAC,MAAM,GAAG,eAAe,IAAI;CAExE,SAAS,UAAU,KAAqB,UAAyC;EAC/E,MAAM,SAAS,IAAI,IAAI,QAAQ;EAC/B,OAAO,kBAAkB,EAAE,MAAM,SAAS;CAC5C;CAEA,SAAS,UAAU,QAAsD;EACvE,MAAM,UAAU,OAAO,IAAI,SAAS;EACpC,OAAO,mBAAmB,EAAE,QAAQ,UAAmC;CACzE;CAEA,SAAS,IAAI,MAA6B;EACxC,MAAM,MAAM,SAAS;EACrB,MAAM,OAAO,MAAM,IAAI;EACvB,MAAM,SAAS,OAAO,YAAY,SAAS,IAAI,OAAO,KAAK,CAAC,EAAE;EAC9D,MAAM,QAAQ,OAAO,SAAS,aAAa,IAAI,OAAO,OAAO,MAAM,IAAI;EACvE,MAAM,OAAO,KAAK,OAAO,OAAO,MAAM;EACtC,IAAI,CAAC,OAAO,CAAC,UAAU,CAAC,SAAS,MAAM,QAAQ,MAAM,MAAM,CAAC,QAAQ,CAAC,MAAM,OAAO;EAClF,MAAM,KAAK,WAAW;EACtB,MAAM,EAAE,UAAU,IAAI;EACtB,MAAM,WAAW,iBAAiB,IAAI,MAAM;EAC5C,MAAM,eAAe,WAAW,oBAAoB,OAAO,UAAU,KAAK,IAAI;EAC9E,MAAM,QAAQ,MAAM,IAAI,YAAY,MAAM,MAAM,MAAM,IAAI,GAAG,CAAC,CAAC,MAAM,GAAG,eAAe,KAAK;EAC5F,MAAM,KAAK,MAAM,GAAG,QAAQ,MAAM,MAAM,MAAM,IAAI,KAAK,OAAO,EAAE,GAAG,CAAC,CAAC;EAErE,IAAI,CAAC,GAAG,YAAY,OAAO;EAE3B,MAAM,OAAqB;GAAE,OAAO;GAAM,QAAQ;EAAG;EACrD,IAAI,OAAO,KAAK,SAAS,GAAG,QAAQ,aAAa,IAAI,CAAC,CAAC,QAAQ,gBAAgB,KAAK,CAAC;EACrF,cAAc,IAAI,QAAQ,CAAC,MAAM,CAAC;EAClC,MAAM,SAAS,IAAI,EAAE,IAAa;EAClC,OAAO,IAAI,MAAM,EAAE;EACnB,OAAO,IAAI,UAAU,IAAI,IAAI;EAC7B,OAAO,IAAI,QAAQ,IAAI;EACvB,OAAO,IAAI,8BAAa,IAAI,KAAK,EAAA,CAAE,YAAY,CAAC;EAChD,OAAO,IAAI,SAAS,KAAK;EACzB,OAAO,IAAI,YAAY,KAAK;EAC5B,IAAI,cAAc,OAAO,IAAI,UAAU,YAAY;EACnD,OAAO,IAAI,WAAW,IAAI,EAAE,MAAoB,CAAC;EACjD,IAAI,IAAI,IAAI,IAAI,MAAM;EACtB,OAAO;CACT;CAEA,SAAS,MAAM,UAAkB,MAAoB;EACnD,MAAM,MAAM,SAAS;EACrB,MAAM,OAAO,MAAM,IAAI;EACvB,MAAM,SAAS,OAAO,UAAU,IAAI,KAAK,QAAQ;EACjD,MAAM,UAAU,UAAU,UAAU,MAAM;EAC1C,IAAI,CAAC,OAAO,CAAC,WAAW,CAAC,MAAM;EAC/B,QAAQ,KAAK,CAAC;GAAE,IAAI,WAAW;GAAG,QAAQ,IAAI;GAAM,MAAM;GAAM,4BAAW,IAAI,KAAK,EAAA,CAAE,YAAY;EAAE,CAAC,CAAC;CACxG;CAEA,SAAS,KAAK,UAAkB,SAAwB,MAAoB;EAC1E,MAAM,MAAM,SAAS;EACrB,MAAM,OAAO,MAAM,IAAI;EACvB,MAAM,SAAS,OAAO,UAAU,IAAI,KAAK,QAAQ;EACjD,IAAI,CAAC,OAAO,CAAC,UAAU,CAAC,MAAM;EAC9B,MAAM,uBAAM,IAAI,KAAK,EAAA,CAAE,YAAY;EACnC,IAAI,YAAY,MAAM;GACpB,IAAK,OAAO,IAAI,QAAQ,CAAC,EAA0C,OAAO,IAAI,KAAK,MAAM,OAAO,IAAI,MAAM,MAAM,MAAM;GACtH,IAAI,KAAK,eAAe;IACtB,OAAO,IAAI,QAAQ,IAAI;IACvB,OAAO,IAAI,YAAY,GAAG;GAC5B,CAAC;GACD;EACF;EACA,MAAM,UAAU,UAAU,MAAM;EAChC,MAAM,QAAQ,UAAU,QAAQ,QAAQ,CAAC,CAAC,WAAU,MAAK,EAAE,OAAO,OAAO,IAAI;EAC7E,MAAM,WAAW,WAAW,SAAS,IAAI,QAAQ,IAAI,KAAK,IAAI,KAAA;EAC9D,IAAI,CAAC,WAAW,CAAC,YAAY,SAAS,OAAO,OAAO,IAAI,KAAK,MAAM,SAAS,SAAS,MAAM;EAC3F,IAAI,KAAK,eAAe;GACtB,QAAQ,OAAO,OAAO,CAAC;GACvB,QAAQ,OAAO,OAAO,CAAC;IAAE,GAAG;IAAU,MAAM;IAAM,UAAU;GAAI,CAAC,CAAC;EACpE,CAAC;CACH;CAEA,SAAS,YAAY,UAAkB,OAAsB;EAC3D,MAAM,MAAM,SAAS;EACrB,MAAM,SAAS,OAAO,UAAU,IAAI,KAAK,QAAQ;EACjD,IAAI,CAAC,OAAO,CAAC,QAAQ;EACrB,OAAO,IAAI,YAAY,KAAK;EAC5B,IAAI,SAAS,YAAY,SAAS,IAAI,OAAO,KAAK,CAAC,EAAE,WAAW,UAAU,iBAAiB,IAAI,QAAQ,IAAI;CAC7G;CAEA,SAAS,OAAO,UAAwB;EACtC,MAAM,MAAM,SAAS;EACrB,MAAM,SAAS,OAAO,UAAU,IAAI,KAAK,QAAQ;EACjD,IAAI,CAAC,OAAO,CAAC,UAAW,OAAO,IAAI,QAAQ,CAAC,EAA0C,OAAO,IAAI,KAAK,IAAI;EAC1G,MAAM,EAAE,UAAU,IAAI;EACtB,MAAM,KAAK,MAAM;EACjB,MAAM,IAAI,aAAa,MAAM,QAAQ;GACnC,IAAI,CAAC,KAAK,QAAQ;GAClB,MAAM,OAAO,KAAK,MAAM,MAAK,MAAK,EAAE,KAAK,SAAS,aAAa,EAAE,MAAM,OAAO,QAAQ;GACtF,IAAI,MAAM,GAAG,WAAW,KAAK,MAAM,KAAK,UAAU,IAAI;EACxD,CAAC;EACD,IAAI,YAAY,SAAS,KAAK,CAAC,EAAE,WAAW,UAAU,GAAG,QAAQ,aAAa,EAAE,QAAQ,KAAK,CAAwB;EACrH,IAAI,GAAG,cAAc,GAAG,QAAQ,WAAW,GAAG,IAAI,OAAO,KAAK,SAAS,GAAG,QAAQ,gBAAgB,KAAK,CAAC;EACxG,IAAI,IAAI,OAAO,QAAQ;CACzB;CAEA,SAAS,YAAY,UAAkB,SAAuB;EAC5D,MAAM,MAAM,SAAS;EACrB,MAAM,SAAS,OAAO,UAAU,IAAI,KAAK,QAAQ;EACjD,MAAM,UAAU,UAAU,UAAU,MAAM;EAC1C,IAAI,CAAC,OAAO,CAAC,SAAS;EACtB,MAAM,QAAQ,QAAQ,QAAQ,CAAC,CAAC,WAAU,MAAK,EAAE,OAAO,OAAO;EAC/D,IAAI,SAAS,KAAK,QAAQ,IAAI,KAAK,CAAC,CAAC,OAAO,OAAO,IAAI,KAAK,IAAI,QAAQ,OAAO,OAAO,CAAC;CACzF;CAEA,SAAS,SAAS,IAAmB,UAAgC,CAAC,GAAS;EAC7E,MAAM,WAAW,QAAQ;EACzB,IAAI,UAAU,iBAAiB,UAAU,IAAI,OAAO;CACtD;CAEA,SAAS,aAAmB;EAC1B,MAAM,MAAM,SAAS;EACrB,IAAI,KAAK,kBAAkB,IAAI,MAAM;CACvC;CAEA,SAAS,cAAoB;EAC3B,MAAM,WAAW,QAAQ;EACzB,IAAI,UAAU,mBAAmB,QAAQ;CAC3C;CAEA,OAAO;EAAE,OAAO;EAAO;EAAS;EAAS;EAAK;EAAO;EAAM;EAAa;EAAQ;EAAa;EAAU;EAAY;CAAY;AACjI;AAMA,MAAM,iCAAiB,IAAI,QAA8C;;AAGzE,SAAgB,qBAAqB,KAAqB,SAAqC;CAC7F,eAAe,IAAI,KAAK,OAAO;AACjC;;AAGA,SAAgB,gBAAgB,KAAuD;CACrF,OAAO,eAAe,IAAI,GAAG;AAC/B;;;;;;;;AASA,SAAgB,0BAA0B,WAAoD;CAC5F,MAAM,QAAQ,YAA8B,cAAc;CAC1D,IAAI;CAEJ,SAAS,UAAU;EACjB,OAAO,KAAK;EACZ,OAAO,MAAM,QAAQ;EACrB,QAAQ,KAAA;CACV;;CAGA,SAAS,UAAyB;EAChC,MAAM,QAAQ,cAAc,UAAU,CAAC;EACvC,MAAM,WAAW,SAAS,gBAAgB,MAAM,GAAG,MAAM;EACzD,IAAI,OAAO,YAAY,SAAS;GAC9B,QAAQ;GACR,MAAM,QAAQ,QAAQ,SAAS;GAC/B,QAAQ;IAAE;IAAO;IAAS,MAAM,MAAM,MAAM,WAAU,aAAY,MAAM,IAAI,QAAQ,CAAC;GAAE;GACvF,MAAM,IAAI,MAAM,MAAM,IAAI,CAAC;EAC7B;EACA,OAAO,MAAO;CAChB;CAEA,OAAO;EACL,OAAO;EACP,eAAe,QAAQ,CAAC,CAAC,QAAQ;EACjC,eAAe;GACb,QAAQ;GACR,MAAM,IAAI,cAAc;EAC1B;EACA,MAAK,SAAQ,QAAQ,CAAC,CAAC,IAAI,IAAI;EAC/B,QAAQ,UAAU,SAAS,QAAQ,CAAC,CAAC,MAAM,UAAU,IAAI;EACzD,OAAO,UAAU,SAAS,SAAS,QAAQ,CAAC,CAAC,KAAK,UAAU,SAAS,IAAI;EACzE,cAAc,UAAU,aAAa,QAAQ,CAAC,CAAC,YAAY,UAAU,QAAQ;EAC7E,SAAQ,aAAY,QAAQ,CAAC,CAAC,OAAO,QAAQ;EAC7C,cAAc,UAAU,YAAY,QAAQ,CAAC,CAAC,YAAY,UAAU,OAAO;EAC3E,WAAW,IAAI,YAAY,QAAQ,CAAC,CAAC,SAAS,IAAI,OAAO;EACzD,kBAAkB,QAAQ,CAAC,CAAC,WAAW;EACvC,mBAAmB,QAAQ,CAAC,CAAC,YAAY;CAC3C;AACF"}
1
+ {"version":3,"file":"model.js","names":[],"sources":["../../../src/features/comments/model.ts"],"sourcesContent":["import type { Editor } from '@tiptap/core'\nimport * as Y from 'yjs'\nimport type { FeatureContext } from '../../core'\nimport type { CommentsModel, CommentsSnapshot, DocRange } from '../../core/backend-types'\nimport { anchorResolverOf, editorEntryOf, releaseRanges, resolveRange } from '../../core'\nimport { newBlockId } from '../../core/schema'\nimport { createStore } from '../../core/store'\nimport { cancelCommentDraft, commentsDoc, commentsKey, type CommentsMeta, commentsUser, setActiveComment, startCommentDraft } from './comments-plugin'\nimport { COMMENT_LIMITS, COMMENTS_FIELD, type CommentAnchor, type CommentReply, type CommentThread } from './schema'\nimport { EMPTY_SNAPSHOT, NO_POSITIONS, NO_RANGES, NO_THREADS, sameOrphanAt, sameRange, sameRanges, sameUser } from './snapshot-equality'\nimport { captureThreadAnchor, resolveThreadAnchor } from './thread-anchor'\n\nexport type { CommentsActions, CommentsModel, CommentsSnapshot, DocRange } from '../../core/backend-types'\n\n/** A thread's `Y.Map` as plain data; `replies` converted explicitly so it is always a plain array. */\nfunction snapshotOf(thread: Y.Map<unknown>): CommentThread {\n const replies = thread.get('replies')\n return { ...(thread.toJSON() as CommentThread), replies: replies instanceof Y.Array ? replies.toArray() as CommentReply[] : [] }\n}\n\n/**\n * The comment threads of a collaborative editor, stored in its Y.Doc (`COMMENTS_FIELD`, one nested `Y.Map` per thread,\n * replies in a nested `Y.Array`), so they sync live with the document and persist with its Yjs state. Keeps the\n * `Comments` plugin's `known`/`hidden` thread ids in step with the store (highlights), exposes the plugin's ranges,\n * active thread and draft, and the mutations. Mutations are no-ops without collaboration or user; editing and\n * deleting are limited to the user's own comments and replies (a client-side rule: the Y.Doc itself has no ACL).\n * `getEditor` names the editor to work on (it may change over time and may return a destroyed or no editor).\n * Each thread also keeps `anchor` (a Yjs relative position of its text's start, see `CommentAnchor`): `orphanAt` resolves\n * it for the threads whose text is gone. Threads from before anchors get theirs written once they are seen with a range.\n */\nexport function createCommentsModel(getEditor: () => Editor | undefined): CommentsModel {\n const store = createStore<CommentsSnapshot>(EMPTY_SNAPSHOT)\n\n const current = () => {\n const instance = getEditor()\n return instance && !instance.isDestroyed ? instance : undefined\n }\n\n // The editor whose transactions are followed, and the Y.Map of threads observed.\n let bound: Editor | undefined\n let observed: { doc: Y.Doc, map: Y.Map<unknown> } | undefined\n let threads: readonly CommentThread[] = NO_THREADS\n let syncQueued = false\n // The thread list the plugin was last told about, for the deactivation rule.\n let told: readonly CommentThread[] = NO_THREADS\n // Threads already tried for an anchor (written, or not capturable), so a failed capture is not repeated on every change.\n const anchorTried = new Set<string>()\n let healQueued = false\n\n function unobserve() {\n observed?.map.unobserveDeep(onThreadsChanged)\n observed = undefined\n }\n\n function onThreadsChanged() {\n if (!observed) return\n threads = [...observed.map.values()].filter((t): t is Y.Map<unknown> => t instanceof Y.Map).map(snapshotOf)\n recompute()\n queueSync()\n }\n\n function onTransaction() {\n recompute()\n }\n\n function unbind() {\n bound?.off('transaction', onTransaction)\n // `setEditable` emits `update` only, and `canComment` follows `isEditable`.\n bound?.off('update', onTransaction)\n bound = undefined\n }\n\n /** The snapshot of the editor's current state; the previous object when nothing changed. */\n function recompute() {\n const instance = current()\n if (!instance) {\n store.set(EMPTY_SNAPSHOT)\n return\n }\n const previous = store.get()\n const ydoc = commentsDoc(instance)\n const user = commentsUser(instance)\n const plugin = commentsKey.getState(instance.state)\n const ranges = plugin?.ranges ?? NO_RANGES\n const orphanAt = orphanPositions(instance, ranges)\n const active = plugin?.active ?? null\n const anchor = plugin?.draft\n const draft = anchor ? resolveRange(instance.state, anchor) : null\n const draftQuote = draft ? instance.state.doc.textBetween(draft.from, draft.to, ' ').slice(0, COMMENT_LIMITS.quote) : ''\n const available = !!ydoc && !!user\n const canComment = available && instance.isEditable\n\n const sameThreads = threads === previous.threads\n const sameRangeMap = sameRanges(ranges, previous.ranges)\n const sameOrphanMap = sameOrphanAt(orphanAt, previous.orphanAt)\n if (\n available === previous.available && canComment === previous.canComment && sameUser(user, previous.user) && sameThreads && sameRangeMap && sameOrphanMap\n && active === previous.active && sameRange(draft, previous.draft) && draftQuote === previous.draftQuote\n ) return\n\n const kept = sameThreads && sameRangeMap\n const open = kept\n ? previous.open\n : threads\n .filter(t => !t.resolved)\n .sort((a, b) => (ranges.get(a.id)?.from ?? Infinity) - (ranges.get(b.id)?.from ?? Infinity) || a.createdAt.localeCompare(b.createdAt))\n const resolved = sameThreads\n ? previous.resolved\n : threads.filter(t => t.resolved).sort((a, b) => b.createdAt.localeCompare(a.createdAt))\n store.set({\n available,\n canComment,\n user,\n threads,\n ranges: sameRangeMap ? previous.ranges : ranges,\n orphanAt: sameOrphanMap ? previous.orphanAt : orphanAt,\n active,\n draft: sameRange(draft, previous.draft) ? previous.draft : draft,\n draftQuote,\n open,\n resolved,\n })\n if (available) queueHeal()\n }\n\n /** Where each unresolved thread without a text range was, from its anchor; empty without a Yjs session. */\n function orphanPositions(instance: Editor, ranges: ReadonlyMap<string, DocRange>): ReadonlyMap<string, number> {\n const resolver = anchorResolverOf(instance)\n if (!resolver) return NO_POSITIONS\n const size = instance.state.doc.content.size\n let found: Map<string, number> | undefined\n for (const thread of threads) {\n if (thread.resolved || ranges.has(thread.id) || !thread.anchor) continue\n const position = resolveThreadAnchor(instance.state, resolver, thread.anchor)\n if (position !== null && position <= size) (found ??= new Map()).set(thread.id, position)\n }\n return found ?? NO_POSITIONS\n }\n\n // Threads from before anchors get theirs once they are seen with their text in the document (any client with a user\n // writes it; the positions are equivalent, so concurrent writes agree). Queued: not written from inside a Yjs\n // observer or a transaction listener.\n function queueHeal() {\n if (healQueued || !threads.some(t => !t.anchor && !anchorTried.has(t.id))) return\n healQueued = true\n queueMicrotask(() => {\n healQueued = false\n healAnchors()\n })\n }\n\n function healAnchors() {\n const ctx = writable()\n const resolver = ctx && anchorResolverOf(ctx.editor)\n if (!ctx || !resolver || ctx.editor !== bound) return\n const { ranges } = store.get()\n const written: [Y.Map<unknown>, CommentAnchor][] = []\n for (const { id, anchor } of threads) {\n const range = ranges.get(id)\n if (anchor || anchorTried.has(id) || !range) continue\n anchorTried.add(id)\n const thread = threadMap(ctx.map, id)\n const captured = thread && captureThreadAnchor(ctx.editor.state, resolver, range)\n if (thread && captured) written.push([thread, captured])\n }\n if (written.length) ctx.ydoc.transact(() => written.forEach(([thread, captured]) => thread.set('anchor', captured)))\n }\n\n // Highlights appear and disappear on every client as threads arrive, get resolved or deleted. The active thread\n // stays highlighted even when resolved (a resolved thread activated from its card), so a thread that turns resolved\n // or disappears while active is deactivated here, on every client, not only on the one that resolved or deleted it.\n // Queued (not dispatched from inside the Yjs observer or a transaction listener).\n function queueSync() {\n if (syncQueued) return\n syncQueued = true\n queueMicrotask(() => {\n syncQueued = false\n syncPlugin()\n })\n }\n\n function syncPlugin() {\n const instance = current()\n if (!instance || instance !== bound) return\n const value = commentsKey.getState(instance.state)\n if (!value) return\n const known = new Set(threads.map(t => t.id))\n const hidden = new Set(threads.filter(t => t.resolved).map(t => t.id))\n const meta: CommentsMeta = { known, hidden }\n const before = value.active ? told.find(t => t.id === value.active) : undefined\n if (value.active && before && !before.resolved && (!known.has(value.active) || hidden.has(value.active))) meta.active = null\n told = threads\n instance.view.dispatch(instance.state.tr.setMeta(commentsKey, meta).setMeta('addToHistory', false))\n }\n\n /** Follows the editor `getEditor` names now, and the Y.Doc of its collaboration session. */\n function refresh() {\n const instance = current()\n if (instance !== bound) {\n unbind()\n unobserve()\n bound = instance\n threads = NO_THREADS\n told = NO_THREADS\n anchorTried.clear()\n instance?.on('transaction', onTransaction)\n instance?.on('update', onTransaction)\n // The new editor's plugin knows no threads yet.\n queueSync()\n }\n const ydoc = instance ? commentsDoc(instance) : null\n if ((observed?.doc ?? null) !== ydoc) {\n unobserve()\n if (ydoc) {\n const map = ydoc.getMap<unknown>(COMMENTS_FIELD)\n observed = { doc: ydoc, map }\n map.observeDeep(onThreadsChanged)\n threads = [...map.values()].filter((t): t is Y.Map<unknown> => t instanceof Y.Map).map(snapshotOf)\n }\n else {\n threads = NO_THREADS\n }\n queueSync()\n }\n recompute()\n }\n\n function dispose() {\n unbind()\n unobserve()\n threads = NO_THREADS\n told = NO_THREADS\n anchorTried.clear()\n store.set(EMPTY_SNAPSHOT)\n }\n\n /** Editor, thread map and user while comments are available; null otherwise. */\n function writable() {\n const instance = current()\n const ydoc = instance && commentsDoc(instance)\n const author = instance && commentsUser(instance)\n if (!instance || !ydoc || !author) return null\n return { editor: instance, ydoc, map: ydoc.getMap<unknown>(COMMENTS_FIELD), user: { id: author.id, name: author.name, color: author.color } }\n }\n\n /** Trimmed and cut to the limit; '' when nothing is left. */\n const clean = (text: string) => text.trim().slice(0, COMMENT_LIMITS.text)\n\n function threadMap(map: Y.Map<unknown>, threadId: string): Y.Map<unknown> | null {\n const thread = map.get(threadId)\n return thread instanceof Y.Map ? thread : null\n }\n\n function repliesOf(thread: Y.Map<unknown>): Y.Array<CommentReply> | null {\n const replies = thread.get('replies')\n return replies instanceof Y.Array ? replies as Y.Array<CommentReply> : null\n }\n\n function add(text: string): string | null {\n const ctx = writable()\n const body = clean(text)\n const anchor = ctx && commentsKey.getState(ctx.editor.state)?.draft\n const range = ctx && anchor ? resolveRange(ctx.editor.state, anchor) : null\n const type = ctx?.editor.schema.marks.comment\n if (!ctx || !anchor || !range || range.from >= range.to || !body || !type) return null\n const id = newBlockId()\n const { state } = ctx.editor\n const resolver = anchorResolverOf(ctx.editor)\n const threadAnchor = resolver ? captureThreadAnchor(state, resolver, range) : null\n const quote = state.doc.textBetween(range.from, range.to, ' ').slice(0, COMMENT_LIMITS.quote)\n const tr = state.tr.addMark(range.from, range.to, type.create({ id }))\n // Text that takes no marks (code block, inline code): no thread that would start out without a range.\n if (!tr.docChanged) return null\n // Not undoable: the mark is the thread's anchor, not an edit of the text.\n const meta: CommentsMeta = { draft: null, active: id }\n ctx.editor.view.dispatch(tr.setMeta(commentsKey, meta).setMeta('addToHistory', false))\n releaseRanges(ctx.editor, [anchor])\n const thread = new Y.Map<unknown>()\n thread.set('id', id)\n thread.set('author', ctx.user)\n thread.set('text', body)\n thread.set('createdAt', new Date().toISOString())\n thread.set('quote', quote)\n thread.set('resolved', false)\n if (threadAnchor) thread.set('anchor', threadAnchor)\n thread.set('replies', new Y.Array<CommentReply>())\n ctx.map.set(id, thread)\n return id\n }\n\n function reply(threadId: string, text: string): void {\n const ctx = writable()\n const body = clean(text)\n const thread = ctx && threadMap(ctx.map, threadId)\n const replies = thread && repliesOf(thread)\n if (!ctx || !replies || !body) return\n replies.push([{ id: newBlockId(), author: ctx.user, text: body, createdAt: new Date().toISOString() }])\n }\n\n function edit(threadId: string, replyId: string | null, text: string): void {\n const ctx = writable()\n const body = clean(text)\n const thread = ctx && threadMap(ctx.map, threadId)\n if (!ctx || !thread || !body) return\n const now = new Date().toISOString()\n if (replyId === null) {\n if ((thread.get('author') as CommentThread['author'] | undefined)?.id !== ctx.user.id || thread.get('text') === body) return\n ctx.ydoc.transact(() => {\n thread.set('text', body)\n thread.set('editedAt', now)\n })\n return\n }\n const replies = repliesOf(thread)\n const index = replies ? replies.toArray().findIndex(r => r.id === replyId) : -1\n const previous = replies && index >= 0 ? replies.get(index) : undefined\n if (!replies || !previous || previous.author.id !== ctx.user.id || previous.text === body) return\n ctx.ydoc.transact(() => {\n replies.delete(index, 1)\n replies.insert(index, [{ ...previous, text: body, editedAt: now }])\n })\n }\n\n function setResolved(threadId: string, value: boolean): void {\n const ctx = writable()\n const thread = ctx && threadMap(ctx.map, threadId)\n if (!ctx || !thread) return\n thread.set('resolved', value)\n if (value && commentsKey.getState(ctx.editor.state)?.active === threadId) setActiveComment(ctx.editor, null)\n }\n\n function remove(threadId: string): void {\n const ctx = writable()\n const thread = ctx && threadMap(ctx.map, threadId)\n if (!ctx || !thread || (thread.get('author') as CommentThread['author'] | undefined)?.id !== ctx.user.id) return\n const { state } = ctx.editor\n const tr = state.tr\n state.doc.descendants((node, pos) => {\n if (!node.isText) return\n const mark = node.marks.find(m => m.type.name === 'comment' && m.attrs.id === threadId)\n if (mark) tr.removeMark(pos, pos + node.nodeSize, mark)\n })\n if (commentsKey.getState(state)?.active === threadId) tr.setMeta(commentsKey, { active: null } satisfies CommentsMeta)\n if (tr.docChanged || tr.getMeta(commentsKey)) ctx.editor.view.dispatch(tr.setMeta('addToHistory', false))\n ctx.map.delete(threadId)\n }\n\n function removeReply(threadId: string, replyId: string): void {\n const ctx = writable()\n const thread = ctx && threadMap(ctx.map, threadId)\n const replies = thread && repliesOf(thread)\n if (!ctx || !replies) return\n const index = replies.toArray().findIndex(r => r.id === replyId)\n if (index >= 0 && replies.get(index).author.id === ctx.user.id) replies.delete(index, 1)\n }\n\n function activate(id: string | null, options: { reveal?: boolean } = {}): void {\n const instance = current()\n if (instance) setActiveComment(instance, id, options)\n }\n\n function startDraft(): void {\n const ctx = writable()\n if (ctx) startCommentDraft(ctx.editor)\n }\n\n function cancelDraft(): void {\n const instance = current()\n if (instance) cancelCommentDraft(instance)\n }\n\n return { state: store, refresh, dispose, add, reply, edit, setResolved, remove, removeReply, activate, startDraft, cancelDraft }\n}\n\n/** Creates the comments model of one editor, as a host supplies it to `commentsFeatureCore`. */\nexport type CommentsModelFactory = (getEditor: () => Editor | undefined) => CommentsModel\n\n// The host's model factory per surface context, set by the comments feature while the surface builds its extensions.\nconst modelFactories = new WeakMap<FeatureContext, CommentsModelFactory>()\n\n/** Registers the host model factory of `ctx` (the comments feature does this; hosts pass `model` to the feature). */\nexport function provideCommentsModel(ctx: FeatureContext, factory: CommentsModelFactory): void {\n modelFactories.set(ctx, factory)\n}\n\n/** The host model factory the comments feature of `ctx` was configured with; undefined for the default Y.Doc model. */\nexport function commentsModelOf(ctx: FeatureContext): CommentsModelFactory | undefined {\n return modelFactories.get(ctx)\n}\n\n/**\n * The comments model the framework hooks (`useComments`) use: the model of the surface `getEditor` belongs to\n * (`commentsModelOf` of its feature context: the host's `model` factory) and `createCommentsModel` for every other\n * editor. It follows the editor over time: when the editor changes to one of a surface with another model, the inner\n * model is replaced (disposed, created, refreshed) and `state` carries on with the new one. The factory runs once per\n * consumer of this function, so a host model that must share state across them keeps it outside the factory.\n */\nexport function createEditorCommentsModel(getEditor: () => Editor | undefined): CommentsModel {\n const store = createStore<CommentsSnapshot>(EMPTY_SNAPSHOT)\n let inner: { model: CommentsModel, factory: CommentsModelFactory, stop: () => void } | undefined\n\n function release() {\n inner?.stop()\n inner?.model.dispose()\n inner = undefined\n }\n\n /** The inner model for the editor now; a replacement when its surface brings another factory. */\n function current(): CommentsModel {\n const entry = editorEntryOf(getEditor())\n const factory = (entry && commentsModelOf(entry.ctx)) ?? createCommentsModel\n if (inner?.factory !== factory) {\n release()\n const model = factory(getEditor)\n inner = { model, factory, stop: model.state.subscribe(snapshot => store.set(snapshot)) }\n store.set(model.state.get())\n }\n return inner!.model\n }\n\n return {\n state: store,\n refresh: () => current().refresh(),\n dispose: () => {\n release()\n store.set(EMPTY_SNAPSHOT)\n },\n add: text => current().add(text),\n reply: (threadId, text) => current().reply(threadId, text),\n edit: (threadId, replyId, text) => current().edit(threadId, replyId, text),\n setResolved: (threadId, resolved) => current().setResolved(threadId, resolved),\n remove: threadId => current().remove(threadId),\n removeReply: (threadId, replyId) => current().removeReply(threadId, replyId),\n activate: (id, options) => current().activate(id, options),\n startDraft: () => current().startDraft(),\n cancelDraft: () => current().cancelDraft(),\n }\n}\n"],"mappings":"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"}
@@ -1,7 +1,8 @@
1
1
  import { AuthorIdentity } from "../../../core/feature.js";
2
+ import { CommentThread, CommentsActions } from "../../../core/backend-types.js";
2
3
  import "../../../core/index.js";
3
- import { CommentThread } from "../schema.js";
4
- import { CommentsActions } from "../model.js";
4
+ import "../model.js";
5
+ import "../schema.js";
5
6
  //#region src/features/comments/react/CommentThreadView.d.ts
6
7
  /**
7
8
  * One comment thread as a card: root comment (with the commented text, or „Textstelle gelöscht“ for an orphan),
@@ -1,4 +1,5 @@
1
- import { CommentsActions, CommentsSnapshot } from "../model.js";
1
+ import { CommentsActions, CommentsSnapshot } from "../../../core/backend-types.js";
2
+ import "../model.js";
2
3
  import { Editor } from "@tiptap/core";
3
4
  //#region src/features/comments/react/use-comments.d.ts
4
5
  /** What `useComments` returns; layouts pass it on to `CommentThreadView`. */
@@ -1,6 +1,6 @@
1
- import { CommentsFeatureOptions } from "./feature.js";
2
1
  import { ReactFeature } from "../../react/EditorSurface.js";
3
2
  import "../../react/index.js";
3
+ import { CommentsFeatureOptions } from "./feature.js";
4
4
  import { CommentBubble } from "./react/CommentBubble.js";
5
5
  import { CommentComposer } from "./react/CommentComposer.js";
6
6
  import { CommentsListMenu } from "./react/CommentsListMenu.js";
@@ -1,5 +1,5 @@
1
1
  import { COMMENTS_LAYOUTS, CommentsLayout } from "../../settings/values.js";
2
- import { AuthorIdentity } from "../../core/feature.js";
2
+ import { CommentAnchor, CommentAuthor, CommentReply, CommentThread } from "../../core/backend-types.js";
3
3
  import "../../core/schema/mark-flags.js";
4
4
  import { AnyExtension, Mark } from "@tiptap/core";
5
5
  //#region src/features/comments/schema.d.ts
@@ -10,56 +10,6 @@ export declare const COMMENT_LIMITS: {
10
10
  readonly text: 5000;
11
11
  readonly quote: 200;
12
12
  };
13
- /** Who wrote a comment or reply: the writing user's identity, copied in when writing. */
14
- export type CommentAuthor = AuthorIdentity;
15
- export interface CommentReply {
16
- id: string;
17
- author: CommentAuthor;
18
- text: string;
19
- /** ISO timestamps; `editedAt` once the author changed the text. */
20
- createdAt: string;
21
- editedAt?: string;
22
- }
23
- /**
24
- * Where a thread's text starts, as the JSON form of a Yjs relative position (`Y.relativePositionToJSON`): bound to the
25
- * first commented character, so it keeps pointing at the place after that text was deleted (and moves with the text
26
- * around it). Stored in the thread's `Y.Map` under `anchor`, so every collaborator resolves the same place.
27
- */
28
- export interface CommentAnchor {
29
- type?: {
30
- client: number;
31
- clock: number;
32
- };
33
- tname?: string;
34
- item?: {
35
- client: number;
36
- clock: number;
37
- };
38
- assoc?: number;
39
- }
40
- /**
41
- * A comment thread: the root comment plus its replies. Stored as a nested `Y.Map` in `ydoc.getMap(COMMENTS_FIELD)`
42
- * (replies as a nested `Y.Array`), so concurrent replies and edits of different users merge. Its text range is the
43
- * `comment` mark with the thread's `id`.
44
- */
45
- export interface CommentThread {
46
- id: string;
47
- author: CommentAuthor;
48
- text: string;
49
- createdAt: string;
50
- editedAt?: string;
51
- /** The commented text when the thread was created, cut to `COMMENT_LIMITS.quote`. */
52
- quote: string;
53
- /** Resolved threads are kept, without highlight, until reopened. */
54
- resolved: boolean;
55
- /**
56
- * Start of the commented text as a Yjs relative position, written when the thread is created (older threads get it
57
- * once they are seen with their text still in the document). Tells where an orphaned thread's text was. Absent on threads
58
- * not yet seen with a range, and when the position could not be captured.
59
- */
60
- anchor?: CommentAnchor;
61
- replies: CommentReply[];
62
- }
63
13
  /**
64
14
  * Anchors a comment thread to text (attribute `id` = the thread's id). Storage only: the visible highlight is a
65
15
  * client-side decoration driven by the thread's state (`Comments` extension). `excludes: ''` lets the marks of
@@ -70,5 +20,5 @@ export declare const CommentMark: Mark<any, any>;
70
20
  /** The comment mark of the document schema. */
71
21
  export declare const commentsSchemaExtensions: () => AnyExtension[];
72
22
  //#endregion
73
- export { COMMENTS_LAYOUTS, type CommentsLayout };
23
+ export { COMMENTS_LAYOUTS, type CommentAnchor, type CommentAuthor, type CommentReply, type CommentThread, type CommentsLayout };
74
24
  //# sourceMappingURL=schema.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"schema.js","names":[],"sources":["../../../src/features/comments/schema.ts"],"sourcesContent":["import { type AnyExtension, Mark, mergeAttributes } from '@tiptap/core'\nimport type { AuthorIdentity } from '../../core/feature'\nimport '../../core/schema/mark-flags'\n\n// Vue-free and server-importable (`@ecsplico/editor/comments/schema`): the comment mark that anchors a thread to\n// text, the thread data model and the limits. The Y.Map store, the highlights and the UI live in the feature.\n\nexport { COMMENTS_LAYOUTS, type CommentsLayout } from '../../settings/values'\n\n/** Name of the `Y.Map` holding the comment threads in the Y.Doc, beside the document's 'default' XmlFragment. */\nexport const COMMENTS_FIELD = 'comments'\n\n/** Maximum lengths of a comment's or reply's text and of the quoted text a thread keeps of its range. */\nexport const COMMENT_LIMITS = { text: 5000, quote: 200 } as const\n\n/** Who wrote a comment or reply: the writing user's identity, copied in when writing. */\nexport type CommentAuthor = AuthorIdentity\n\nexport interface CommentReply {\n id: string\n author: CommentAuthor\n text: string\n /** ISO timestamps; `editedAt` once the author changed the text. */\n createdAt: string\n editedAt?: string\n}\n\n/**\n * Where a thread's text starts, as the JSON form of a Yjs relative position (`Y.relativePositionToJSON`): bound to the\n * first commented character, so it keeps pointing at the place after that text was deleted (and moves with the text\n * around it). Stored in the thread's `Y.Map` under `anchor`, so every collaborator resolves the same place.\n */\nexport interface CommentAnchor {\n type?: { client: number, clock: number }\n tname?: string\n item?: { client: number, clock: number }\n assoc?: number\n}\n\n/**\n * A comment thread: the root comment plus its replies. Stored as a nested `Y.Map` in `ydoc.getMap(COMMENTS_FIELD)`\n * (replies as a nested `Y.Array`), so concurrent replies and edits of different users merge. Its text range is the\n * `comment` mark with the thread's `id`.\n */\nexport interface CommentThread {\n id: string\n author: CommentAuthor\n text: string\n createdAt: string\n editedAt?: string\n /** The commented text when the thread was created, cut to `COMMENT_LIMITS.quote`. */\n quote: string\n /** Resolved threads are kept, without highlight, until reopened. */\n resolved: boolean\n /**\n * Start of the commented text as a Yjs relative position, written when the thread is created (older threads get it\n * once they are seen with their text still in the document). Tells where an orphaned thread's text was. Absent on threads\n * not yet seen with a range, and when the position could not be captured.\n */\n anchor?: CommentAnchor\n replies: CommentReply[]\n}\n\n/**\n * Anchors a comment thread to text (attribute `id` = the thread's id). Storage only: the visible highlight is a\n * client-side decoration driven by the thread's state (`Comments` extension). `excludes: ''` lets the marks of\n * overlapping threads coexist on the same text; `inclusive: false` keeps text typed at the end of a range outside it.\n * No Markdown form (`markdownInvisible`).\n */\nexport const CommentMark = Mark.create({\n name: 'comment',\n excludes: '',\n inclusive: false,\n markdownInvisible: true,\n addAttributes() {\n return {\n id: {\n default: null,\n parseHTML: el => el.getAttribute('data-comment-id'),\n renderHTML: attrs => ({ 'data-comment-id': attrs.id }),\n },\n }\n },\n parseHTML: () => [{ tag: 'span[data-comment-id]' }],\n renderHTML: ({ HTMLAttributes }) => ['span', mergeAttributes(HTMLAttributes, { class: 'comment' }), 0],\n})\n\n/** The comment mark of the document schema. */\nexport const commentsSchemaExtensions = (): AnyExtension[] => [CommentMark]\n"],"mappings":";;;;AAUA,MAAa,iBAAiB;;AAG9B,MAAa,iBAAiB;CAAE,MAAM;CAAM,OAAO;AAAI;;;;;;;AAwDvD,MAAa,cAAc,KAAK,OAAO;CACrC,MAAM;CACN,UAAU;CACV,WAAW;CACX,mBAAmB;CACnB,gBAAgB;EACd,OAAO,EACL,IAAI;GACF,SAAS;GACT,YAAW,OAAM,GAAG,aAAa,iBAAiB;GAClD,aAAY,WAAU,EAAE,mBAAmB,MAAM,GAAG;EACtD,EACF;CACF;CACA,iBAAiB,CAAC,EAAE,KAAK,wBAAwB,CAAC;CAClD,aAAa,EAAE,qBAAqB;EAAC;EAAQ,gBAAgB,gBAAgB,EAAE,OAAO,UAAU,CAAC;EAAG;CAAC;AACvG,CAAC;;AAGD,MAAa,iCAAiD,CAAC,WAAW"}
1
+ {"version":3,"file":"schema.js","names":[],"sources":["../../../src/features/comments/schema.ts"],"sourcesContent":["import { type AnyExtension, Mark, mergeAttributes } from '@tiptap/core'\nimport '../../core/schema/mark-flags'\n\n// Vue-free and server-importable (`@ecsplico/editor/comments/schema`): the comment mark that anchors a thread to\n// text, the thread data model and the limits. The Y.Map store, the highlights and the UI live in the feature.\n\nexport { COMMENTS_LAYOUTS, type CommentsLayout } from '../../settings/values'\n\n/** Name of the `Y.Map` holding the comment threads in the Y.Doc, beside the document's 'default' XmlFragment. */\nexport const COMMENTS_FIELD = 'comments'\n\n/** Maximum lengths of a comment's or reply's text and of the quoted text a thread keeps of its range. */\nexport const COMMENT_LIMITS = { text: 5000, quote: 200 } as const\n\n// The thread data model (`CommentThread`, its replies, author and anchor) is core's, because `EditorBackend.comments`\n// returns a model of them; this entry exports the types as before.\nexport type { CommentAnchor, CommentAuthor, CommentReply, CommentThread } from '../../core/backend-types'\n\n/**\n * Anchors a comment thread to text (attribute `id` = the thread's id). Storage only: the visible highlight is a\n * client-side decoration driven by the thread's state (`Comments` extension). `excludes: ''` lets the marks of\n * overlapping threads coexist on the same text; `inclusive: false` keeps text typed at the end of a range outside it.\n * No Markdown form (`markdownInvisible`).\n */\nexport const CommentMark = Mark.create({\n name: 'comment',\n excludes: '',\n inclusive: false,\n markdownInvisible: true,\n addAttributes() {\n return {\n id: {\n default: null,\n parseHTML: el => el.getAttribute('data-comment-id'),\n renderHTML: attrs => ({ 'data-comment-id': attrs.id }),\n },\n }\n },\n parseHTML: () => [{ tag: 'span[data-comment-id]' }],\n renderHTML: ({ HTMLAttributes }) => ['span', mergeAttributes(HTMLAttributes, { class: 'comment' }), 0],\n})\n\n/** The comment mark of the document schema. */\nexport const commentsSchemaExtensions = (): AnyExtension[] => [CommentMark]\n"],"mappings":";;;;AASA,MAAa,iBAAiB;;AAG9B,MAAa,iBAAiB;CAAE,MAAM;CAAM,OAAO;AAAI;;;;;;;AAYvD,MAAa,cAAc,KAAK,OAAO;CACrC,MAAM;CACN,UAAU;CACV,WAAW;CACX,mBAAmB;CACnB,gBAAgB;EACd,OAAO,EACL,IAAI;GACF,SAAS;GACT,YAAW,OAAM,GAAG,aAAa,iBAAiB;GAClD,aAAY,WAAU,EAAE,mBAAmB,MAAM,GAAG;EACtD,EACF;CACF;CACA,iBAAiB,CAAC,EAAE,KAAK,wBAAwB,CAAC;CAClD,aAAa,EAAE,qBAAqB;EAAC;EAAQ,gBAAgB,gBAAgB,EAAE,OAAO,UAAU,CAAC;EAAG;CAAC;AACvG,CAAC;;AAGD,MAAa,iCAAiD,CAAC,WAAW"}
@@ -1 +1 @@
1
- {"version":3,"file":"snapshot-equality.js","names":[],"sources":["../../../src/features/comments/snapshot-equality.ts"],"sourcesContent":["import type { AuthorIdentity } from '../../core'\nimport type { CommentsSnapshot, DocRange } from './model'\nimport type { CommentThread } from './schema'\n\n// What both comments models (the Y.Doc one in `./model` and the REST one in `adapters/comments/client`) need to hand\n// out a snapshot that keeps its identity while nothing in it changed. Type-only imports: this module stays free of `yjs`.\n\nexport const NO_RANGES: ReadonlyMap<string, DocRange> = new Map()\nexport const NO_THREADS: readonly CommentThread[] = []\nexport const NO_POSITIONS: ReadonlyMap<string, number> = new Map()\n\n/** The snapshot of an editor that has no comments (yet). */\nexport const EMPTY_SNAPSHOT: CommentsSnapshot = {\n available: false,\n canComment: false,\n user: null,\n threads: NO_THREADS,\n ranges: NO_RANGES,\n orphanAt: NO_POSITIONS,\n active: null,\n draft: null,\n draftQuote: '',\n open: NO_THREADS,\n resolved: NO_THREADS,\n}\n\nexport function sameRange(a: DocRange | null, b: DocRange | null): boolean {\n return a === b || (!!a && !!b && a.from === b.from && a.to === b.to)\n}\n\nexport function sameRanges(a: ReadonlyMap<string, DocRange>, b: ReadonlyMap<string, DocRange>): boolean {\n if (a === b) return true\n if (a.size !== b.size) return false\n for (const [id, range] of a) {\n if (!sameRange(range, b.get(id) ?? null)) return false\n }\n return true\n}\n\nexport function sameOrphanAt(a: ReadonlyMap<string, number>, b: ReadonlyMap<string, number>): boolean {\n if (a === b) return true\n if (a.size !== b.size) return false\n for (const [id, position] of a) {\n if (b.get(id) !== position) return false\n }\n return true\n}\n\nexport function sameUser(a: AuthorIdentity | null, b: AuthorIdentity | null): boolean {\n return a === b || (!!a && !!b && a.id === b.id && a.name === b.name && a.color === b.color)\n}\n"],"mappings":";AAOA,MAAa,4BAA2C,IAAI,IAAI;AAChE,MAAa,aAAuC,CAAC;AACrD,MAAa,+BAA4C,IAAI,IAAI;;AAGjE,MAAa,iBAAmC;CAC9C,WAAW;CACX,YAAY;CACZ,MAAM;CACN,SAAS;CACT,QAAQ;CACR,UAAU;CACV,QAAQ;CACR,OAAO;CACP,YAAY;CACZ,MAAM;CACN,UAAU;AACZ;AAEA,SAAgB,UAAU,GAAoB,GAA6B;CACzE,OAAO,MAAM,KAAM,CAAC,CAAC,KAAK,CAAC,CAAC,KAAK,EAAE,SAAS,EAAE,QAAQ,EAAE,OAAO,EAAE;AACnE;AAEA,SAAgB,WAAW,GAAkC,GAA2C;CACtG,IAAI,MAAM,GAAG,OAAO;CACpB,IAAI,EAAE,SAAS,EAAE,MAAM,OAAO;CAC9B,KAAK,MAAM,CAAC,IAAI,UAAU,GACxB,IAAI,CAAC,UAAU,OAAO,EAAE,IAAI,EAAE,KAAK,IAAI,GAAG,OAAO;CAEnD,OAAO;AACT;AAEA,SAAgB,aAAa,GAAgC,GAAyC;CACpG,IAAI,MAAM,GAAG,OAAO;CACpB,IAAI,EAAE,SAAS,EAAE,MAAM,OAAO;CAC9B,KAAK,MAAM,CAAC,IAAI,aAAa,GAC3B,IAAI,EAAE,IAAI,EAAE,MAAM,UAAU,OAAO;CAErC,OAAO;AACT;AAEA,SAAgB,SAAS,GAA0B,GAAmC;CACpF,OAAO,MAAM,KAAM,CAAC,CAAC,KAAK,CAAC,CAAC,KAAK,EAAE,OAAO,EAAE,MAAM,EAAE,SAAS,EAAE,QAAQ,EAAE,UAAU,EAAE;AACvF"}
1
+ {"version":3,"file":"snapshot-equality.js","names":[],"sources":["../../../src/features/comments/snapshot-equality.ts"],"sourcesContent":["import type { AuthorIdentity } from '../../core'\nimport type { CommentsSnapshot, DocRange } from './model'\nimport type { CommentThread } from './schema'\n\n// What both comments models (the Y.Doc one in `./model` and the REST one in `adapters/comments/rest-model`) need to hand\n// out a snapshot that keeps its identity while nothing in it changed. Type-only imports: this module stays free of `yjs`.\n\nexport const NO_RANGES: ReadonlyMap<string, DocRange> = new Map()\nexport const NO_THREADS: readonly CommentThread[] = []\nexport const NO_POSITIONS: ReadonlyMap<string, number> = new Map()\n\n/** The snapshot of an editor that has no comments (yet). */\nexport const EMPTY_SNAPSHOT: CommentsSnapshot = {\n available: false,\n canComment: false,\n user: null,\n threads: NO_THREADS,\n ranges: NO_RANGES,\n orphanAt: NO_POSITIONS,\n active: null,\n draft: null,\n draftQuote: '',\n open: NO_THREADS,\n resolved: NO_THREADS,\n}\n\nexport function sameRange(a: DocRange | null, b: DocRange | null): boolean {\n return a === b || (!!a && !!b && a.from === b.from && a.to === b.to)\n}\n\nexport function sameRanges(a: ReadonlyMap<string, DocRange>, b: ReadonlyMap<string, DocRange>): boolean {\n if (a === b) return true\n if (a.size !== b.size) return false\n for (const [id, range] of a) {\n if (!sameRange(range, b.get(id) ?? null)) return false\n }\n return true\n}\n\nexport function sameOrphanAt(a: ReadonlyMap<string, number>, b: ReadonlyMap<string, number>): boolean {\n if (a === b) return true\n if (a.size !== b.size) return false\n for (const [id, position] of a) {\n if (b.get(id) !== position) return false\n }\n return true\n}\n\nexport function sameUser(a: AuthorIdentity | null, b: AuthorIdentity | null): boolean {\n return a === b || (!!a && !!b && a.id === b.id && a.name === b.name && a.color === b.color)\n}\n"],"mappings":";AAOA,MAAa,4BAA2C,IAAI,IAAI;AAChE,MAAa,aAAuC,CAAC;AACrD,MAAa,+BAA4C,IAAI,IAAI;;AAGjE,MAAa,iBAAmC;CAC9C,WAAW;CACX,YAAY;CACZ,MAAM;CACN,SAAS;CACT,QAAQ;CACR,UAAU;CACV,QAAQ;CACR,OAAO;CACP,YAAY;CACZ,MAAM;CACN,UAAU;AACZ;AAEA,SAAgB,UAAU,GAAoB,GAA6B;CACzE,OAAO,MAAM,KAAM,CAAC,CAAC,KAAK,CAAC,CAAC,KAAK,EAAE,SAAS,EAAE,QAAQ,EAAE,OAAO,EAAE;AACnE;AAEA,SAAgB,WAAW,GAAkC,GAA2C;CACtG,IAAI,MAAM,GAAG,OAAO;CACpB,IAAI,EAAE,SAAS,EAAE,MAAM,OAAO;CAC9B,KAAK,MAAM,CAAC,IAAI,UAAU,GACxB,IAAI,CAAC,UAAU,OAAO,EAAE,IAAI,EAAE,KAAK,IAAI,GAAG,OAAO;CAEnD,OAAO;AACT;AAEA,SAAgB,aAAa,GAAgC,GAAyC;CACpG,IAAI,MAAM,GAAG,OAAO;CACpB,IAAI,EAAE,SAAS,EAAE,MAAM,OAAO;CAC9B,KAAK,MAAM,CAAC,IAAI,aAAa,GAC3B,IAAI,EAAE,IAAI,EAAE,MAAM,UAAU,OAAO;CAErC,OAAO;AACT;AAEA,SAAgB,SAAS,GAA0B,GAAmC;CACpF,OAAO,MAAM,KAAM,CAAC,CAAC,KAAK,CAAC,CAAC,KAAK,EAAE,OAAO,EAAE,MAAM,EAAE,SAAS,EAAE,QAAQ,EAAE,UAAU,EAAE;AACvF"}
@@ -1,7 +1,8 @@
1
1
  import { AuthorIdentity } from "../../core/feature.js";
2
+ import { CommentThread, CommentsActions, DocRange } from "../../core/backend-types.js";
2
3
  import "../../core/index.js";
3
- import { CommentThread } from "./schema.js";
4
- import { CommentsActions, DocRange } from "./model.js";
4
+ import "./model.js";
5
+ import "./schema.js";
5
6
  import { Editor } from "@tiptap/core";
6
7
  import { ComputedRef, MaybeRefOrGetter, Ref } from "vue";
7
8
  //#region src/features/comments/use-comments.d.ts
@@ -1,5 +1,5 @@
1
- import { CommentsFeatureOptions } from "./feature.js";
2
1
  import { VueFeature } from "../../vue/index.js";
2
+ import { CommentsFeatureOptions } from "./feature.js";
3
3
  import _default from "./components/CommentBubble.vue.js";
4
4
  import _default$1 from "./components/CommentComposer.vue.js";
5
5
  import _default$3 from "./components/CommentsListMenu.vue.js";
@@ -1,5 +1,6 @@
1
1
  import { Translate } from "../../i18n/index.js";
2
2
  import { Notifier } from "../../core/notify.js";
3
+ import "../../core/command-types.js";
3
4
  import { Extension } from "@tiptap/core";
4
5
  import { Node as Node$1 } from "@tiptap/pm/model";
5
6
  //#region src/features/composites/accepted-children.d.ts
@@ -50,6 +50,21 @@ function nestingViolations(doc, kinds) {
50
50
  walk(doc, null);
51
51
  return found;
52
52
  }
53
+ /**
54
+ * The insert guard of the composites feature: a Baustein of kind `creates.attrs.kind` may be created only where the
55
+ * nearest Baustein around the insertion point (`$parent` and outward; quotes and lists in between do not count)
56
+ * accepts that kind, or where there is none. Uses `kindAccepts`, the rule `AcceptedChildren` enforces on transactions
57
+ * through `nestingViolations`, so the `/` menu and toolbar offer exactly what an edit would not be refused for.
58
+ */
59
+ const compositeInsertGuard = (editor, $parent, creates) => {
60
+ const child = creates.attrs?.kind;
61
+ if (creates.type !== "composite" || typeof child !== "string") return true;
62
+ for (let depth = $parent.depth; depth >= 0; depth--) {
63
+ const node = $parent.node(depth);
64
+ if (node.type.name === "composite") return kindAccepts(compositeKindsOf(editor), String(node.attrs.kind), child);
65
+ }
66
+ return true;
67
+ };
53
68
  /** A step that cannot change which Baustein sits in which: marks, text typed or deleted inside one textblock, attributes other than `kind`. */
54
69
  function keepsNesting(step, before) {
55
70
  if (step instanceof AddMarkStep || step instanceof RemoveMarkStep) return true;
@@ -121,6 +136,6 @@ const AcceptedChildren = Extension.create({
121
136
  }
122
137
  });
123
138
  //#endregion
124
- export { AcceptedChildren, nestingReason, nestingViolations, outermostComposites };
139
+ export { AcceptedChildren, compositeInsertGuard, nestingReason, nestingViolations, outermostComposites };
125
140
 
126
141
  //# sourceMappingURL=accepted-children.js.map