@ecsplico/editor 2.1.2 → 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 (692) hide show
  1. package/CHANGELOG.md +68 -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/config/index.d.ts +105 -0
  41. package/dist/config/index.js +95 -0
  42. package/dist/config/index.js.map +1 -0
  43. package/dist/core/abilities.js +1 -0
  44. package/dist/core/abilities.js.map +1 -1
  45. package/dist/{adapters/routes.js → core/api-routes.js} +5 -3
  46. package/dist/core/api-routes.js.map +1 -0
  47. package/dist/core/backend-capability.d.ts +7 -0
  48. package/dist/core/backend-capability.js +17 -0
  49. package/dist/core/backend-capability.js.map +1 -0
  50. package/dist/core/backend-types.d.ts +245 -0
  51. package/dist/core/backend-types.js +17 -0
  52. package/dist/core/backend-types.js.map +1 -0
  53. package/dist/core/backend.d.ts +108 -0
  54. package/dist/core/backend.js +14 -0
  55. package/dist/core/backend.js.map +1 -0
  56. package/dist/core/block-convert.d.ts +7 -5
  57. package/dist/core/block-convert.js +28 -5
  58. package/dist/core/block-convert.js.map +1 -1
  59. package/dist/core/command-types.d.ts +89 -0
  60. package/dist/core/commands.d.ts +40 -0
  61. package/dist/core/commands.js +151 -0
  62. package/dist/core/commands.js.map +1 -0
  63. package/dist/core/context.d.ts +17 -20
  64. package/dist/core/context.js +24 -21
  65. package/dist/core/context.js.map +1 -1
  66. package/dist/core/core-feature.d.ts +22 -7
  67. package/dist/core/core-feature.js +51 -18
  68. package/dist/core/core-feature.js.map +1 -1
  69. package/dist/core/define-editor.d.ts +4 -3
  70. package/dist/core/define-editor.js +14 -7
  71. package/dist/core/define-editor.js.map +1 -1
  72. package/dist/core/document-markdown.js +12 -3
  73. package/dist/core/document-markdown.js.map +1 -1
  74. package/dist/core/editor-ui.d.ts +8 -1
  75. package/dist/core/editor-ui.js +9 -8
  76. package/dist/core/editor-ui.js.map +1 -1
  77. package/dist/core/extension-points.d.ts +3 -15
  78. package/dist/core/feature-context.d.ts +8 -7
  79. package/dist/core/feature-context.js +12 -11
  80. package/dist/core/feature-context.js.map +1 -1
  81. package/dist/core/feature.d.ts +35 -19
  82. package/dist/core/feature.js.map +1 -1
  83. package/dist/core/fences.d.ts +2 -1
  84. package/dist/core/fences.js +3 -2
  85. package/dist/core/fences.js.map +1 -1
  86. package/dist/core/fetch-error.d.ts +1 -1
  87. package/dist/core/fetch-error.js +3 -1
  88. package/dist/core/fetch-error.js.map +1 -1
  89. package/dist/core/hash.d.ts +5 -0
  90. package/dist/core/hash.js +11 -0
  91. package/dist/core/hash.js.map +1 -0
  92. package/dist/core/http-backend.d.ts +11 -0
  93. package/dist/core/http-backend.js +195 -0
  94. package/dist/core/http-backend.js.map +1 -0
  95. package/dist/core/index.d.ts +14 -9
  96. package/dist/core/index.js +12 -9
  97. package/dist/core/palette.d.ts +48 -0
  98. package/dist/core/palette.js +95 -0
  99. package/dist/core/palette.js.map +1 -0
  100. package/dist/core/schema/abilities.d.ts +2 -1
  101. package/dist/core/schema/abilities.js +5 -1
  102. package/dist/core/schema/abilities.js.map +1 -1
  103. package/dist/core/schema/index.d.ts +11 -5
  104. package/dist/core/schema/index.js +13 -8
  105. package/dist/core/schema/index.js.map +1 -1
  106. package/dist/core/schema/mark-flags.d.ts +8 -1
  107. package/dist/core/schema/of-features.d.ts +13 -0
  108. package/dist/core/schema/of-features.js +14 -0
  109. package/dist/core/schema/of-features.js.map +1 -0
  110. package/dist/core/slash.d.ts +8 -6
  111. package/dist/core/slash.js +24 -16
  112. package/dist/core/slash.js.map +1 -1
  113. package/dist/core/surface-session.js +13 -5
  114. package/dist/core/surface-session.js.map +1 -1
  115. package/dist/core/toolbar-items.d.ts +10 -4
  116. package/dist/core/toolbar-items.js +269 -195
  117. package/dist/core/toolbar-items.js.map +1 -1
  118. package/dist/core/util.js +11 -0
  119. package/dist/core/util.js.map +1 -0
  120. package/dist/document/DocumentSurface.d.ts +1 -1
  121. package/dist/features/ai/agent-op-review.d.ts +1 -1
  122. package/dist/features/ai/agent-op-review.js +1 -1
  123. package/dist/features/ai/agent-ops.js +1 -1
  124. package/dist/features/ai/ai-apply.d.ts +2 -2
  125. package/dist/features/ai/ai-apply.js +1 -1
  126. package/dist/features/ai/ai-review.js +1 -1
  127. package/dist/features/ai/ai-sse.d.ts +6 -6
  128. package/dist/features/ai/ai-sse.js +20 -63
  129. package/dist/features/ai/ai-sse.js.map +1 -1
  130. package/dist/features/ai/assistant.d.ts +8 -7
  131. package/dist/features/ai/assistant.js +3 -3
  132. package/dist/features/ai/assistant.js.map +1 -1
  133. package/dist/features/ai/block-actions.d.ts +3 -2
  134. package/dist/features/ai/block-actions.js +3 -2
  135. package/dist/features/ai/block-actions.js.map +1 -1
  136. package/dist/features/ai/components/AiSelectionMenu.js +1 -1
  137. package/dist/features/ai/components/DocumentChatAnswer.js +1 -1
  138. package/dist/features/ai/components/DocumentChatOps.vue.d.ts +1 -1
  139. package/dist/features/ai/components/SettingsModelProfiles.js +8 -8
  140. package/dist/features/ai/components/SettingsModelProfiles.js.map +1 -1
  141. package/dist/features/ai/document-chat-model.d.ts +8 -7
  142. package/dist/features/ai/document-chat-model.js +5 -5
  143. package/dist/features/ai/document-chat-model.js.map +1 -1
  144. package/dist/features/ai/document-chat.js +1 -1
  145. package/dist/features/ai/feature.js +27 -14
  146. package/dist/features/ai/feature.js.map +1 -1
  147. package/dist/features/ai/ghost-autocomplete.d.ts +7 -6
  148. package/dist/features/ai/ghost-autocomplete.js +6 -9
  149. package/dist/features/ai/ghost-autocomplete.js.map +1 -1
  150. package/dist/features/ai/index.d.ts +4 -3
  151. package/dist/features/ai/index.js +10 -10
  152. package/dist/features/ai/model-profiles.d.ts +5 -4
  153. package/dist/features/ai/model-profiles.js +2 -2
  154. package/dist/features/ai/model-profiles.js.map +1 -1
  155. package/dist/features/ai/protocol/block-lines.js +1 -1
  156. package/dist/features/ai/protocol/block-lines.js.map +1 -1
  157. package/dist/features/ai/protocol/chat.js +4 -1
  158. package/dist/features/ai/protocol/chat.js.map +1 -1
  159. package/dist/features/ai/protocol/index.d.ts +3 -2
  160. package/dist/features/ai/protocol/models.d.ts +2 -16
  161. package/dist/features/ai/protocol/models.js.map +1 -1
  162. package/dist/features/ai/rate-limit.d.ts +1 -1
  163. package/dist/features/ai/rate-limit.js +3 -1
  164. package/dist/features/ai/rate-limit.js.map +1 -1
  165. package/dist/features/ai/react/AiSelectionMenu.js +2 -2
  166. package/dist/features/ai/react/AiSidebar.js +4 -4
  167. package/dist/features/ai/react/DocumentChatAnswer.js +1 -1
  168. package/dist/features/ai/react/DocumentChatOps.d.ts +1 -1
  169. package/dist/features/ai/react/DocumentChatOps.js +1 -1
  170. package/dist/features/ai/react/SettingsModelProfiles.js +8 -10
  171. package/dist/features/ai/react/SettingsModelProfiles.js.map +1 -1
  172. package/dist/features/ai/react/use-ai-assistant.d.ts +1 -1
  173. package/dist/features/ai/react/use-ai-assistant.js +3 -3
  174. package/dist/features/ai/react/use-ai-assistant.js.map +1 -1
  175. package/dist/features/ai/react/use-document-chat.js +2 -2
  176. package/dist/features/ai/react/use-document-chat.js.map +1 -1
  177. package/dist/features/ai/react/use-model-profiles.d.ts +2 -1
  178. package/dist/features/ai/selection-flow.d.ts +1 -1
  179. package/dist/features/ai/selection-flow.js +1 -1
  180. package/dist/features/ai/sidebar-flow.d.ts +1 -1
  181. package/dist/features/ai/sidebar-flow.js +1 -1
  182. package/dist/features/ai/use-ai-assistant.d.ts +1 -1
  183. package/dist/features/ai/use-ai-assistant.js +3 -3
  184. package/dist/features/ai/use-ai-assistant.js.map +1 -1
  185. package/dist/features/ai/use-document-chat.js +2 -2
  186. package/dist/features/ai/use-document-chat.js.map +1 -1
  187. package/dist/features/ai/use-model-profiles.d.ts +2 -1
  188. package/dist/features/authors/attribution.d.ts +1 -1
  189. package/dist/features/authors/feature.js +12 -11
  190. package/dist/features/authors/feature.js.map +1 -1
  191. package/dist/features/block-ui/block-actions.d.ts +1 -1
  192. package/dist/features/block-ui/block-actions.js +1 -1
  193. package/dist/features/block-ui/block-actions.js.map +1 -1
  194. package/dist/features/block-ui/components/BlockUi.js +1 -1
  195. package/dist/features/block-ui/feature.js +1 -0
  196. package/dist/features/block-ui/feature.js.map +1 -1
  197. package/dist/features/block-ui/react/BlockUi.js +1 -1
  198. package/dist/features/collab/anchor-resolver.js +1 -1
  199. package/dist/features/collab/feature.js +2 -0
  200. package/dist/features/collab/feature.js.map +1 -1
  201. package/dist/features/comments/components/CommentThreadView.vue.d.ts +2 -1
  202. package/dist/features/comments/feature.js +12 -11
  203. package/dist/features/comments/feature.js.map +1 -1
  204. package/dist/features/comments/index.d.ts +3 -2
  205. package/dist/features/comments/index.js +1 -1
  206. package/dist/features/comments/margin-layout.d.ts +3 -2
  207. package/dist/features/comments/model.d.ts +3 -67
  208. package/dist/features/comments/model.js +2 -2
  209. package/dist/features/comments/model.js.map +1 -1
  210. package/dist/features/comments/react/CommentThreadView.d.ts +3 -2
  211. package/dist/features/comments/react/use-comments.d.ts +2 -1
  212. package/dist/features/comments/react.d.ts +1 -1
  213. package/dist/features/comments/schema.d.ts +2 -52
  214. package/dist/features/comments/schema.js.map +1 -1
  215. package/dist/features/comments/snapshot-equality.js.map +1 -1
  216. package/dist/features/comments/use-comments.d.ts +3 -2
  217. package/dist/features/comments/vue.d.ts +1 -1
  218. package/dist/features/composites/accepted-children.d.ts +1 -0
  219. package/dist/features/composites/accepted-children.js +16 -1
  220. package/dist/features/composites/accepted-children.js.map +1 -1
  221. package/dist/features/composites/ai-brief.js +31 -0
  222. package/dist/features/composites/ai-brief.js.map +1 -1
  223. package/dist/features/composites/bibliography-command.d.ts +11 -0
  224. package/dist/features/composites/bibliography-form.js +90 -0
  225. package/dist/features/composites/bibliography-form.js.map +1 -0
  226. package/dist/features/composites/bibliography.d.ts +33 -0
  227. package/dist/features/composites/bibliography.js +120 -0
  228. package/dist/features/composites/bibliography.js.map +1 -0
  229. package/dist/features/composites/components/BibliographyEditor.js +261 -0
  230. package/dist/features/composites/components/BibliographyEditor.js.map +1 -0
  231. package/dist/features/composites/components/CompositeChrome.js +75 -26
  232. package/dist/features/composites/components/CompositeChrome.js.map +1 -1
  233. package/dist/features/composites/components/CompositeDetails.js +46 -11
  234. package/dist/features/composites/components/CompositeDetails.js.map +1 -1
  235. package/dist/features/composites/components/CompositeDetails.vue.d.ts +2 -1
  236. package/dist/features/composites/components/CompositeFieldEditor.js +37 -4
  237. package/dist/features/composites/components/CompositeFieldEditor.js.map +1 -1
  238. package/dist/features/composites/components/CompositeInspector.js +17 -5
  239. package/dist/features/composites/components/CompositeInspector.js.map +1 -1
  240. package/dist/features/composites/components/CompositeTable.js +13 -4
  241. package/dist/features/composites/components/CompositeTable.js.map +1 -1
  242. package/dist/features/composites/components/CompositeTagsEditor.js +1 -1
  243. package/dist/features/composites/components/CompositeView.js +11 -1
  244. package/dist/features/composites/components/CompositeView.js.map +1 -1
  245. package/dist/features/composites/components/DerivationBadge.js +103 -0
  246. package/dist/features/composites/components/DerivationBadge.js.map +1 -0
  247. package/dist/features/composites/components/ReferenceFieldSelect.js +60 -0
  248. package/dist/features/composites/components/ReferenceFieldSelect.js.map +1 -0
  249. package/dist/features/composites/components/ReferenceView.js +122 -0
  250. package/dist/features/composites/components/ReferenceView.js.map +1 -0
  251. package/dist/features/composites/components/ReferenceView.vue.d.ts +96 -0
  252. package/dist/features/composites/components/SettingsEditingTab.js +1 -1
  253. package/dist/features/composites/convert.js +2 -2
  254. package/dist/features/composites/convert.js.map +1 -1
  255. package/dist/features/composites/derivation.d.ts +61 -0
  256. package/dist/features/composites/derivation.js +98 -0
  257. package/dist/features/composites/derivation.js.map +1 -0
  258. package/dist/features/composites/derived-chrome.js +69 -0
  259. package/dist/features/composites/derived-chrome.js.map +1 -0
  260. package/dist/features/composites/feature.js +159 -109
  261. package/dist/features/composites/feature.js.map +1 -1
  262. package/dist/features/composites/fences.d.ts +4 -3
  263. package/dist/features/composites/fences.js +51 -7
  264. package/dist/features/composites/fences.js.map +1 -1
  265. package/dist/features/composites/index.d.ts +12 -3
  266. package/dist/features/composites/index.js +15 -6
  267. package/dist/features/composites/inspector-model.d.ts +4 -1
  268. package/dist/features/composites/inspector-model.js +8 -4
  269. package/dist/features/composites/inspector-model.js.map +1 -1
  270. package/dist/features/composites/kinds.d.ts +8 -1
  271. package/dist/features/composites/kinds.js +145 -6
  272. package/dist/features/composites/kinds.js.map +1 -1
  273. package/dist/features/composites/legacy.d.ts +4 -1
  274. package/dist/features/composites/legacy.js +56 -1
  275. package/dist/features/composites/legacy.js.map +1 -1
  276. package/dist/features/composites/meta-display.js +40 -1
  277. package/dist/features/composites/meta-display.js.map +1 -1
  278. package/dist/features/composites/meta-keys.d.ts +7 -0
  279. package/dist/features/composites/meta-keys.js +21 -0
  280. package/dist/features/composites/meta-keys.js.map +1 -0
  281. package/dist/features/composites/node-views.d.ts +6 -3
  282. package/dist/features/composites/node-views.js +7 -3
  283. package/dist/features/composites/node-views.js.map +1 -1
  284. package/dist/features/composites/nodes.d.ts +6 -1
  285. package/dist/features/composites/nodes.js +33 -7
  286. package/dist/features/composites/nodes.js.map +1 -1
  287. package/dist/features/composites/react/BibliographyEditor.js +229 -0
  288. package/dist/features/composites/react/BibliographyEditor.js.map +1 -0
  289. package/dist/features/composites/react/CompositeChrome.js +65 -17
  290. package/dist/features/composites/react/CompositeChrome.js.map +1 -1
  291. package/dist/features/composites/react/CompositeDetails.d.ts +2 -1
  292. package/dist/features/composites/react/CompositeDetails.js +45 -6
  293. package/dist/features/composites/react/CompositeDetails.js.map +1 -1
  294. package/dist/features/composites/react/CompositeFieldEditor.d.ts +1 -1
  295. package/dist/features/composites/react/CompositeFieldEditor.js +24 -1
  296. package/dist/features/composites/react/CompositeFieldEditor.js.map +1 -1
  297. package/dist/features/composites/react/CompositeInspector.js +11 -5
  298. package/dist/features/composites/react/CompositeInspector.js.map +1 -1
  299. package/dist/features/composites/react/CompositeStatusMenu.js +1 -1
  300. package/dist/features/composites/react/CompositeSummaryEditor.js +1 -1
  301. package/dist/features/composites/react/CompositeTable.js +16 -2
  302. package/dist/features/composites/react/CompositeTable.js.map +1 -1
  303. package/dist/features/composites/react/CompositeTagsEditor.js +2 -2
  304. package/dist/features/composites/react/CompositeView.js +6 -1
  305. package/dist/features/composites/react/CompositeView.js.map +1 -1
  306. package/dist/features/composites/react/DerivationBadge.js +116 -0
  307. package/dist/features/composites/react/DerivationBadge.js.map +1 -0
  308. package/dist/features/composites/react/ReferenceFieldSelect.js +52 -0
  309. package/dist/features/composites/react/ReferenceFieldSelect.js.map +1 -0
  310. package/dist/features/composites/react/ReferenceView.d.ts +11 -0
  311. package/dist/features/composites/react/ReferenceView.js +115 -0
  312. package/dist/features/composites/react/ReferenceView.js.map +1 -0
  313. package/dist/features/composites/react/SettingsEditingTab.js +2 -2
  314. package/dist/features/composites/react.d.ts +2 -1
  315. package/dist/features/composites/react.js +7 -3
  316. package/dist/features/composites/react.js.map +1 -1
  317. package/dist/features/composites/reference-ai.js +16 -0
  318. package/dist/features/composites/reference-ai.js.map +1 -0
  319. package/dist/features/composites/reference-label.d.ts +19 -0
  320. package/dist/features/composites/reference-label.js +58 -0
  321. package/dist/features/composites/reference-label.js.map +1 -0
  322. package/dist/features/composites/reference-suggestion.d.ts +10 -0
  323. package/dist/features/composites/reference-suggestion.js +41 -0
  324. package/dist/features/composites/reference-suggestion.js.map +1 -0
  325. package/dist/features/composites/reference-text.d.ts +18 -0
  326. package/dist/features/composites/reference-text.js +89 -0
  327. package/dist/features/composites/reference-text.js.map +1 -0
  328. package/dist/features/composites/reference.d.ts +44 -0
  329. package/dist/features/composites/reference.js +148 -0
  330. package/dist/features/composites/reference.js.map +1 -0
  331. package/dist/features/composites/reveal-source.d.ts +32 -0
  332. package/dist/features/composites/reveal-source.js +89 -0
  333. package/dist/features/composites/reveal-source.js.map +1 -0
  334. package/dist/features/composites/rows.d.ts +21 -2
  335. package/dist/features/composites/rows.js +63 -9
  336. package/dist/features/composites/rows.js.map +1 -1
  337. package/dist/features/composites/schema.d.ts +9 -3
  338. package/dist/features/composites/schema.js +11 -4
  339. package/dist/features/composites/schema.js.map +1 -1
  340. package/dist/features/composites/table-model.js +12 -21
  341. package/dist/features/composites/table-model.js.map +1 -1
  342. package/dist/features/composites/vue.d.ts +3 -2
  343. package/dist/features/composites/vue.js +8 -4
  344. package/dist/features/composites/vue.js.map +1 -1
  345. package/dist/features/media/assets.d.ts +2 -0
  346. package/dist/features/media/assets.js +3 -2
  347. package/dist/features/media/assets.js.map +1 -1
  348. package/dist/features/media/components/FileView.js +13 -4
  349. package/dist/features/media/components/FileView.js.map +1 -1
  350. package/dist/features/media/feature.d.ts +3 -3
  351. package/dist/features/media/feature.js +21 -28
  352. package/dist/features/media/feature.js.map +1 -1
  353. package/dist/features/media/file-import.js +2 -2
  354. package/dist/features/media/file-import.js.map +1 -1
  355. package/dist/features/media/index.d.ts +2 -2
  356. package/dist/features/media/index.js +2 -2
  357. package/dist/features/media/react/FileView.js +19 -2
  358. package/dist/features/media/react/FileView.js.map +1 -1
  359. package/dist/features/media/schema.d.ts +8 -0
  360. package/dist/features/media/schema.js +126 -11
  361. package/dist/features/media/schema.js.map +1 -1
  362. package/dist/features/media/upload.d.ts +16 -14
  363. package/dist/features/media/upload.js +13 -19
  364. package/dist/features/media/upload.js.map +1 -1
  365. package/dist/features/mentions/index.d.ts +4 -3
  366. package/dist/features/mentions/index.js +4 -1
  367. package/dist/features/mentions/index.js.map +1 -1
  368. package/dist/features/mentions/mention-text.d.ts +1 -1
  369. package/dist/features/mentions/mention-text.js.map +1 -1
  370. package/dist/features/mentions/mention.d.ts +0 -6
  371. package/dist/features/mentions/mention.js.map +1 -1
  372. package/dist/features/mentions/metadata-defaults.d.ts +2 -2
  373. package/dist/features/mentions/metadata-defaults.js +3 -9
  374. package/dist/features/mentions/metadata-defaults.js.map +1 -1
  375. package/dist/features/mentions/schema.d.ts +2 -1
  376. package/dist/features/mentions/schema.js.map +1 -1
  377. package/dist/features/tables/feature.d.ts +2 -1
  378. package/dist/features/tables/feature.js +90 -70
  379. package/dist/features/tables/feature.js.map +1 -1
  380. package/dist/features/themes/components/SettingsAppearanceTab.js +6 -9
  381. package/dist/features/themes/components/SettingsAppearanceTab.js.map +1 -1
  382. package/dist/features/themes/feature.js +2 -0
  383. package/dist/features/themes/feature.js.map +1 -1
  384. package/dist/features/themes/index.d.ts +2 -1
  385. package/dist/features/themes/react/SettingsAppearanceTab.js +7 -10
  386. package/dist/features/themes/react/SettingsAppearanceTab.js.map +1 -1
  387. package/dist/features/themes/schema.d.ts +2 -6
  388. package/dist/features/themes/schema.js.map +1 -1
  389. package/dist/features/themes/theme-runtime.d.ts +1 -1
  390. package/dist/features/themes/theme-runtime.js +4 -2
  391. package/dist/features/themes/theme-runtime.js.map +1 -1
  392. package/dist/features/transcript/TranscriptSegmentView.js +48 -28
  393. package/dist/features/transcript/TranscriptSegmentView.js.map +1 -1
  394. package/dist/features/transcript/feature.js +21 -19
  395. package/dist/features/transcript/feature.js.map +1 -1
  396. package/dist/features/transcript/react/TranscriptSegmentView.js +55 -36
  397. package/dist/features/transcript/react/TranscriptSegmentView.js.map +1 -1
  398. package/dist/features/transcript/segment-node.d.ts +2 -0
  399. package/dist/features/transcript/segment-node.js +35 -7
  400. package/dist/features/transcript/segment-node.js.map +1 -1
  401. package/dist/i18n/de/composites.js +91 -1
  402. package/dist/i18n/de/composites.js.map +1 -1
  403. package/dist/i18n/de/integrations.js +49 -8
  404. package/dist/i18n/de/integrations.js.map +1 -1
  405. package/dist/i18n/de/media.js +0 -1
  406. package/dist/i18n/de/media.js.map +1 -1
  407. package/dist/i18n/de/palette.js +22 -0
  408. package/dist/i18n/de/palette.js.map +1 -0
  409. package/dist/i18n/de/tables.js +0 -1
  410. package/dist/i18n/de/tables.js.map +1 -1
  411. package/dist/i18n/de/transcript.js +2 -1
  412. package/dist/i18n/de/transcript.js.map +1 -1
  413. package/dist/i18n/de/tree.js +3 -0
  414. package/dist/i18n/de/tree.js.map +1 -1
  415. package/dist/i18n/de.d.ts +157 -11
  416. package/dist/i18n/de.js +3 -1
  417. package/dist/i18n/de.js.map +1 -1
  418. package/dist/i18n/en/composites.js +89 -1
  419. package/dist/i18n/en/composites.js.map +1 -1
  420. package/dist/i18n/en/integrations.js +49 -8
  421. package/dist/i18n/en/integrations.js.map +1 -1
  422. package/dist/i18n/en/media.js +0 -1
  423. package/dist/i18n/en/media.js.map +1 -1
  424. package/dist/i18n/en/palette.js +22 -0
  425. package/dist/i18n/en/palette.js.map +1 -0
  426. package/dist/i18n/en/tables.js +0 -1
  427. package/dist/i18n/en/tables.js.map +1 -1
  428. package/dist/i18n/en/transcript.js +2 -1
  429. package/dist/i18n/en/transcript.js.map +1 -1
  430. package/dist/i18n/en/tree.js +3 -0
  431. package/dist/i18n/en/tree.js.map +1 -1
  432. package/dist/i18n/en.js +3 -1
  433. package/dist/i18n/en.js.map +1 -1
  434. package/dist/index.d.ts +4 -3
  435. package/dist/integrations/composite-ai/bibliography-fetch.d.ts +31 -0
  436. package/dist/integrations/composite-ai/bibliography-fetch.js +159 -0
  437. package/dist/integrations/composite-ai/bibliography-fetch.js.map +1 -0
  438. package/dist/integrations/composite-ai/composite-fill.d.ts +30 -8
  439. package/dist/integrations/composite-ai/composite-fill.js +97 -56
  440. package/dist/integrations/composite-ai/composite-fill.js.map +1 -1
  441. package/dist/integrations/composite-ai/composite-summary.d.ts +4 -12
  442. package/dist/integrations/composite-ai/composite-summary.js +7 -26
  443. package/dist/integrations/composite-ai/composite-summary.js.map +1 -1
  444. package/dist/integrations/composite-ai/derive.d.ts +29 -0
  445. package/dist/integrations/composite-ai/derive.js +173 -0
  446. package/dist/integrations/composite-ai/derive.js.map +1 -0
  447. package/dist/integrations/composite-ai/index.d.ts +11 -7
  448. package/dist/integrations/composite-ai/index.js +72 -14
  449. package/dist/integrations/composite-ai/index.js.map +1 -1
  450. package/dist/integrations/composite-ai/rendition.d.ts +45 -0
  451. package/dist/integrations/composite-ai/rendition.js +314 -0
  452. package/dist/integrations/composite-ai/rendition.js.map +1 -0
  453. package/dist/integrations/composite-media/index.d.ts +7 -5
  454. package/dist/integrations/composite-media/index.js +86 -13
  455. package/dist/integrations/composite-media/index.js.map +1 -1
  456. package/dist/integrations/transcript-ai/index.d.ts +1 -1
  457. package/dist/integrations/transcript-ai/index.js +5 -2
  458. package/dist/integrations/transcript-ai/index.js.map +1 -1
  459. package/dist/integrations/transcript-ai/protocol.d.ts +2 -12
  460. package/dist/integrations/transcript-ai/protocol.js +0 -2
  461. package/dist/integrations/transcript-ai/protocol.js.map +1 -1
  462. package/dist/integrations/transcript-ai/transcript-cleanup.d.ts +5 -5
  463. package/dist/integrations/transcript-ai/transcript-cleanup.js +7 -10
  464. package/dist/integrations/transcript-ai/transcript-cleanup.js.map +1 -1
  465. package/dist/markdown/MarkdownSurface.vue.d.ts +6 -5
  466. package/dist/markdown/MarkdownSurface2.js +3 -6
  467. package/dist/markdown/MarkdownSurface2.js.map +1 -1
  468. package/dist/markdown/document.js +1 -1
  469. package/dist/markdown/source-mode.d.ts +1 -1
  470. package/dist/nuxt/module.d.ts +1402 -54
  471. package/dist/nuxt/module.js +6 -49
  472. package/dist/nuxt/module.js.map +1 -1
  473. package/dist/nuxt/runtime/install-context.d.ts +7 -3
  474. package/dist/nuxt/runtime/install-context.js +14 -8
  475. package/dist/nuxt/runtime/install-context.js.map +1 -1
  476. package/dist/nuxt/runtime/plugins/editor-context-nuxt-ui.client.ts +2 -2
  477. package/dist/nuxt/runtime/server/plugins/editor-server.js +20 -12
  478. package/dist/nuxt/runtime/server/plugins/editor-server.js.map +1 -1
  479. package/dist/presets/compose.d.ts +94 -0
  480. package/dist/presets/compose.js +164 -0
  481. package/dist/presets/compose.js.map +1 -0
  482. package/dist/react/AdvancedEditor.d.ts +15 -15
  483. package/dist/react/AdvancedEditor.js +15 -13
  484. package/dist/react/AdvancedEditor.js.map +1 -1
  485. package/dist/react/EditorCommandPalette.d.ts +13 -0
  486. package/dist/react/EditorCommandPalette.js +118 -0
  487. package/dist/react/EditorCommandPalette.js.map +1 -0
  488. package/dist/react/EditorSettingsModal.d.ts +5 -5
  489. package/dist/react/EditorSettingsModal.js +7 -4
  490. package/dist/react/EditorSettingsModal.js.map +1 -1
  491. package/dist/react/EditorSettingsPanel.d.ts +7 -7
  492. package/dist/react/EditorSettingsPanel.js +8 -5
  493. package/dist/react/EditorSettingsPanel.js.map +1 -1
  494. package/dist/react/EditorSurface.d.ts +7 -7
  495. package/dist/react/EditorSurface.js +10 -6
  496. package/dist/react/EditorSurface.js.map +1 -1
  497. package/dist/react/EditorToolbar.d.ts +4 -6
  498. package/dist/react/EditorToolbar.js +29 -37
  499. package/dist/react/EditorToolbar.js.map +1 -1
  500. package/dist/react/SimpleEditor.d.ts +22 -23
  501. package/dist/react/SimpleEditor.js +21 -7
  502. package/dist/react/SimpleEditor.js.map +1 -1
  503. package/dist/react/advanced.d.ts +4 -3
  504. package/dist/react/advanced.js +2 -2
  505. package/dist/react/compose.d.ts +20 -0
  506. package/dist/react/compose.js +49 -0
  507. package/dist/react/compose.js.map +1 -0
  508. package/dist/react/composed-surface.d.ts +39 -0
  509. package/dist/react/composed-surface.js +71 -0
  510. package/dist/react/composed-surface.js.map +1 -0
  511. package/dist/react/context.js +6 -2
  512. package/dist/react/context.js.map +1 -1
  513. package/dist/react/index.d.ts +2 -1
  514. package/dist/react/index.js +2 -1
  515. package/dist/react/key-labels.js +15 -0
  516. package/dist/react/key-labels.js.map +1 -0
  517. package/dist/react/settings.d.ts +1 -1
  518. package/dist/react/simple.d.ts +2 -2
  519. package/dist/react/ui/command.js +36 -1
  520. package/dist/react/ui/command.js.map +1 -1
  521. package/dist/schema/advanced.d.ts +6 -6
  522. package/dist/schema/advanced.js +26 -29
  523. package/dist/schema/advanced.js.map +1 -1
  524. package/dist/server/ai.d.ts +5 -16
  525. package/dist/server/ai.js.map +1 -1
  526. package/dist/server/auth.d.ts +9 -0
  527. package/dist/server/collab-state.d.ts +1 -1
  528. package/dist/server/collab-state.js.map +1 -1
  529. package/dist/server/collab.d.ts +13 -13
  530. package/dist/server/collab.js +34 -18
  531. package/dist/server/collab.js.map +1 -1
  532. package/dist/server/crossref.js +78 -0
  533. package/dist/server/crossref.js.map +1 -0
  534. package/dist/server/errors.d.ts +1 -1
  535. package/dist/server/errors.js +1 -1
  536. package/dist/server/errors.js.map +1 -1
  537. package/dist/server/extract.js +308 -0
  538. package/dist/server/extract.js.map +1 -0
  539. package/dist/{nuxt/runtime/server/utils/editor-route.js → server/h3.js} +8 -16
  540. package/dist/server/h3.js.map +1 -0
  541. package/dist/server/handlers/ai.d.ts +30 -9
  542. package/dist/server/handlers/ai.js +170 -36
  543. package/dist/server/handlers/ai.js.map +1 -1
  544. package/dist/server/handlers/context.d.ts +12 -5
  545. package/dist/server/handlers/context.js +10 -4
  546. package/dist/server/handlers/context.js.map +1 -1
  547. package/dist/server/handlers/editor.d.ts +19 -13
  548. package/dist/server/handlers/editor.js +49 -38
  549. package/dist/server/handlers/editor.js.map +1 -1
  550. package/dist/server/handlers/index.d.ts +4 -4
  551. package/dist/server/handlers/index.js +4 -4
  552. package/dist/server/host.d.ts +16 -25
  553. package/dist/server/host.js +58 -41
  554. package/dist/server/host.js.map +1 -1
  555. package/dist/server/index.d.ts +6 -4
  556. package/dist/server/index.js +3 -2
  557. package/dist/server/pdf.js +97 -0
  558. package/dist/server/pdf.js.map +1 -0
  559. package/dist/server/{adapter.d.ts → ports.d.ts} +81 -30
  560. package/dist/server/ports.js +29 -0
  561. package/dist/server/ports.js.map +1 -0
  562. package/dist/server/routes.js +144 -0
  563. package/dist/server/routes.js.map +1 -0
  564. package/dist/settings/index.d.ts +1 -1
  565. package/dist/settings/index.js.map +1 -1
  566. package/dist/styles/composites.css +25 -0
  567. package/dist/tree/DocumentTree.js +56 -29
  568. package/dist/tree/DocumentTree.js.map +1 -1
  569. package/dist/tree/react/DocumentTree.js +23 -0
  570. package/dist/tree/react/DocumentTree.js.map +1 -1
  571. package/dist/tree/tree-host.js +2 -2
  572. package/dist/tree/tree-items.js +1 -1
  573. package/dist/vue/AdvancedEditor.js +30 -9
  574. package/dist/vue/AdvancedEditor.js.map +1 -1
  575. package/dist/vue/AdvancedEditor.vue.d.ts +28 -8
  576. package/dist/vue/SimpleEditor.js +62 -16
  577. package/dist/vue/SimpleEditor.js.map +1 -1
  578. package/dist/vue/SimpleEditor.vue.d.ts +37 -7
  579. package/dist/vue/advanced.d.ts +3 -2
  580. package/dist/vue/advanced.js +2 -2
  581. package/dist/vue/components/EditorCommandPalette.js +91 -0
  582. package/dist/vue/components/EditorCommandPalette.js.map +1 -0
  583. package/dist/vue/components/EditorCommandPalette.vue.d.ts +15 -0
  584. package/dist/vue/components/EditorSettingsModal.js +10 -6
  585. package/dist/vue/components/EditorSettingsModal.js.map +1 -1
  586. package/dist/vue/components/EditorSettingsModal.vue.d.ts +4 -4
  587. package/dist/vue/components/EditorSettingsPanel.js +10 -6
  588. package/dist/vue/components/EditorSettingsPanel.js.map +1 -1
  589. package/dist/vue/components/EditorSettingsPanel.vue.d.ts +6 -6
  590. package/dist/vue/components/EditorSurface.js +11 -6
  591. package/dist/vue/components/EditorSurface.js.map +1 -1
  592. package/dist/vue/components/EditorSurface.vue.d.ts +7 -7
  593. package/dist/vue/components/EditorToolbar.js +41 -49
  594. package/dist/vue/components/EditorToolbar.js.map +1 -1
  595. package/dist/vue/components/EditorToolbar.vue.d.ts +2 -4
  596. package/dist/vue/compose.d.ts +17 -0
  597. package/dist/vue/compose.js +51 -0
  598. package/dist/vue/compose.js.map +1 -0
  599. package/dist/vue/context-key.d.ts +6 -0
  600. package/dist/vue/context-key.js +6 -0
  601. package/dist/vue/context-key.js.map +1 -0
  602. package/dist/vue/context.d.ts +8 -6
  603. package/dist/vue/context.js +6 -5
  604. package/dist/vue/context.js.map +1 -1
  605. package/dist/vue/index.d.ts +10 -8
  606. package/dist/vue/index.js +10 -8
  607. package/dist/vue/kit/index.d.ts +2 -2
  608. package/dist/vue/kit/nuxt-ui.js +23 -0
  609. package/dist/vue/kit/nuxt-ui.js.map +1 -1
  610. package/dist/vue/kit/types.d.ts +40 -1
  611. package/package.json +30 -16
  612. package/dist/adapters/comments/client.d.ts +0 -64
  613. package/dist/adapters/comments/client.js.map +0 -1
  614. package/dist/adapters/routes.js.map +0 -1
  615. package/dist/core/toolbar.d.ts +0 -74
  616. package/dist/core/toolbar.js +0 -45
  617. package/dist/core/toolbar.js.map +0 -1
  618. package/dist/integrations/composite-ai/document-transcribe.d.ts +0 -14
  619. package/dist/integrations/composite-ai/document-transcribe.js +0 -89
  620. package/dist/integrations/composite-ai/document-transcribe.js.map +0 -1
  621. package/dist/nuxt/runtime/server/api/ai/chat.post.d.ts +0 -5
  622. package/dist/nuxt/runtime/server/api/ai/chat.post.js +0 -8
  623. package/dist/nuxt/runtime/server/api/ai/chat.post.js.map +0 -1
  624. package/dist/nuxt/runtime/server/api/ai/complete.post.d.ts +0 -5
  625. package/dist/nuxt/runtime/server/api/ai/complete.post.js +0 -8
  626. package/dist/nuxt/runtime/server/api/ai/complete.post.js.map +0 -1
  627. package/dist/nuxt/runtime/server/api/ai/generate.post.d.ts +0 -5
  628. package/dist/nuxt/runtime/server/api/ai/generate.post.js +0 -8
  629. package/dist/nuxt/runtime/server/api/ai/generate.post.js.map +0 -1
  630. package/dist/nuxt/runtime/server/api/ai/models.get.d.ts +0 -5
  631. package/dist/nuxt/runtime/server/api/ai/models.get.js +0 -8
  632. package/dist/nuxt/runtime/server/api/ai/models.get.js.map +0 -1
  633. package/dist/nuxt/runtime/server/api/ai/transcribe.post.d.ts +0 -5
  634. package/dist/nuxt/runtime/server/api/ai/transcribe.post.js +0 -8
  635. package/dist/nuxt/runtime/server/api/ai/transcribe.post.js.map +0 -1
  636. package/dist/nuxt/runtime/server/api/ai/transcript-cleanup.post.d.ts +0 -5
  637. package/dist/nuxt/runtime/server/api/ai/transcript-cleanup.post.js +0 -8
  638. package/dist/nuxt/runtime/server/api/ai/transcript-cleanup.post.js.map +0 -1
  639. package/dist/nuxt/runtime/server/api/editor/assets/[id]/[name].get.d.ts +0 -5
  640. package/dist/nuxt/runtime/server/api/editor/assets/[id]/[name].get.js +0 -8
  641. package/dist/nuxt/runtime/server/api/editor/assets/[id]/[name].get.js.map +0 -1
  642. package/dist/nuxt/runtime/server/api/editor/assets/[id].post.d.ts +0 -5
  643. package/dist/nuxt/runtime/server/api/editor/assets/[id].post.js +0 -8
  644. package/dist/nuxt/runtime/server/api/editor/assets/[id].post.js.map +0 -1
  645. package/dist/nuxt/runtime/server/api/editor/settings.get.d.ts +0 -5
  646. package/dist/nuxt/runtime/server/api/editor/settings.get.js +0 -8
  647. package/dist/nuxt/runtime/server/api/editor/settings.get.js.map +0 -1
  648. package/dist/nuxt/runtime/server/api/editor/settings.put.d.ts +0 -5
  649. package/dist/nuxt/runtime/server/api/editor/settings.put.js +0 -8
  650. package/dist/nuxt/runtime/server/api/editor/settings.put.js.map +0 -1
  651. package/dist/nuxt/runtime/server/api/editor/tags.get.d.ts +0 -5
  652. package/dist/nuxt/runtime/server/api/editor/tags.get.js +0 -8
  653. package/dist/nuxt/runtime/server/api/editor/tags.get.js.map +0 -1
  654. package/dist/nuxt/runtime/server/api/editor/themes/[id].delete.d.ts +0 -5
  655. package/dist/nuxt/runtime/server/api/editor/themes/[id].delete.js +0 -8
  656. package/dist/nuxt/runtime/server/api/editor/themes/[id].delete.js.map +0 -1
  657. package/dist/nuxt/runtime/server/api/editor/themes/[id].get.d.ts +0 -5
  658. package/dist/nuxt/runtime/server/api/editor/themes/[id].get.js +0 -8
  659. package/dist/nuxt/runtime/server/api/editor/themes/[id].get.js.map +0 -1
  660. package/dist/nuxt/runtime/server/api/editor/themes/index.get.d.ts +0 -5
  661. package/dist/nuxt/runtime/server/api/editor/themes/index.get.js +0 -8
  662. package/dist/nuxt/runtime/server/api/editor/themes/index.get.js.map +0 -1
  663. package/dist/nuxt/runtime/server/api/editor/themes/index.post.d.ts +0 -5
  664. package/dist/nuxt/runtime/server/api/editor/themes/index.post.js +0 -8
  665. package/dist/nuxt/runtime/server/api/editor/themes/index.post.js.map +0 -1
  666. package/dist/nuxt/runtime/server/api/editor/users.get.d.ts +0 -5
  667. package/dist/nuxt/runtime/server/api/editor/users.get.js +0 -8
  668. package/dist/nuxt/runtime/server/api/editor/users.get.js.map +0 -1
  669. package/dist/nuxt/runtime/server/plugins/collab.d.ts +0 -5
  670. package/dist/nuxt/runtime/server/plugins/collab.js +0 -10
  671. package/dist/nuxt/runtime/server/plugins/collab.js.map +0 -1
  672. package/dist/nuxt/runtime/server/routes/collab/[id].d.ts +0 -5
  673. package/dist/nuxt/runtime/server/routes/collab/[id].js +0 -35
  674. package/dist/nuxt/runtime/server/routes/collab/[id].js.map +0 -1
  675. package/dist/nuxt/runtime/server/utils/editor-route.d.ts +0 -11
  676. package/dist/nuxt/runtime/server/utils/editor-route.js.map +0 -1
  677. package/dist/presets/advanced.d.ts +0 -33
  678. package/dist/presets/advanced.js +0 -50
  679. package/dist/presets/advanced.js.map +0 -1
  680. package/dist/presets/simple.d.ts +0 -9
  681. package/dist/presets/simple.js +0 -12
  682. package/dist/presets/simple.js.map +0 -1
  683. package/dist/react/advanced-preset.d.ts +0 -11
  684. package/dist/react/advanced-preset.js +0 -31
  685. package/dist/react/advanced-preset.js.map +0 -1
  686. package/dist/vue/advanced-preset.d.ts +0 -13
  687. package/dist/vue/advanced-preset.js +0 -33
  688. package/dist/vue/advanced-preset.js.map +0 -1
  689. package/docs/extending.md +0 -538
  690. package/docs/integration.md +0 -632
  691. package/docs/llms.md +0 -383
  692. package/docs/usage.md +0 -1076
@@ -1,8 +1,9 @@
1
1
  import { TYPE_ABILITIES } from "./schema/abilities.js";
2
2
  import { abilitiesAt } from "./abilities.js";
3
+ import { conversionsOf } from "./pipeline.js";
4
+ import { guardsAccept } from "./commands.js";
3
5
  import { isBlockContainer, isChromeNode } from "./schema/node-flags.js";
4
6
  import { convertCoreBlocks, convertTargetId, coreConversionTargets, isCoreTarget, parseCoreTarget } from "./convert.js";
5
- import { conversionsOf } from "./pipeline.js";
6
7
  import { Extension } from "@tiptap/core";
7
8
  import { Selection } from "@tiptap/pm/state";
8
9
  import { Fragment } from "@tiptap/pm/model";
@@ -120,17 +121,37 @@ function blockConversion(providers, state, $start, target) {
120
121
  if ($end.parent !== parent || !parent.canReplace($start.index(), $end.index(), Fragment.from(conversion.blocks))) return null;
121
122
  return conversion;
122
123
  }
124
+ /** The node a conversion into `target` creates, as the insert guards see it (`Creates`). */
125
+ function createdBy(target) {
126
+ switch (target.type) {
127
+ case "heading": return {
128
+ type: "heading",
129
+ attrs: { level: target.level }
130
+ };
131
+ case "composite": return {
132
+ type: "composite",
133
+ attrs: { kind: target.kind }
134
+ };
135
+ case "custom": return {
136
+ type: target.id,
137
+ ...target.attrs && { attrs: target.attrs }
138
+ };
139
+ default: return { type: target.type };
140
+ }
141
+ }
123
142
  /**
124
143
  * Client-only, no schema: the `convertBlockTo` command over the preset's conversion providers — the „Umwandeln in …“
125
- * block action and the toolbar's conversion groups. One transaction, so one undo step.
144
+ * block action and the toolbar's conversion groups. One transaction, so one undo step. The target must pass the same
145
+ * insert guards as creating that node there (`guardsAccept`): a Baustein kind its parent does not accept is refused.
126
146
  */
127
147
  const BlockConvert = Extension.create({
128
148
  name: "blockConvert",
129
149
  addCommands() {
130
150
  return { convertBlockTo: (target, pos) => ({ editor, state, tr, dispatch }) => {
131
151
  const $start = blockStart(state, pos);
132
- const conversion = $start && blockConversion(conversionsOf(editor), state, $start, target);
133
- if (!conversion) return false;
152
+ if (!$start) return false;
153
+ const conversion = blockConversion(conversionsOf(editor), state, $start, target);
154
+ if (!conversion || !guardsAccept(editor, state.doc.resolve($start.start()), createdBy(target))) return false;
134
155
  if (dispatch) {
135
156
  tr.replaceWith(conversion.from, conversion.to, conversion.blocks);
136
157
  const $first = tr.doc.resolve(conversion.from);
@@ -142,7 +163,8 @@ const BlockConvert = Extension.create({
142
163
  });
143
164
  /**
144
165
  * „Umwandeln in …“ entries for the block `target`: the targets the providers offer whose type the block's container
145
- * allows (`TYPE_ABILITIES`), one separated group per provider in feature order. A list item stands for its list.
166
+ * allows (`TYPE_ABILITIES`), one separated group per provider in feature order; targets the block cannot be converted
167
+ * to right now are disabled. A list item stands for its list.
146
168
  */
147
169
  function convertMenuItems(editor, target, t) {
148
170
  let { node, pos } = target;
@@ -155,6 +177,7 @@ function convertMenuItems(editor, target, t) {
155
177
  const abilities = abilitiesAt(editor, pos);
156
178
  return conversionTargetGroups(providers, editor, node).map((targets) => targets.filter((to) => !TYPE_ABILITIES[to.type] || abilities.has(TYPE_ABILITIES[to.type])).map((to) => ({
157
179
  ...conversionLabel(providers, to, t),
180
+ disabled: !editor.can().convertBlockTo(to, pos),
158
181
  onSelect: () => editor.chain().focus().convertBlockTo(to, pos).run()
159
182
  }))).filter((items) => items.length > 0).flatMap((items, index) => index ? [{ type: "separator" }, ...items] : items);
160
183
  }
@@ -1 +1 @@
1
- {"version":3,"file":"block-convert.js","names":[],"sources":["../../src/core/block-convert.ts"],"sourcesContent":["import { type Editor, Extension } from '@tiptap/core'\nimport { Fragment, type Node as PMNode, type ResolvedPos } from '@tiptap/pm/model'\nimport { type EditorState, Selection } from '@tiptap/pm/state'\nimport { abilitiesAt } from './abilities'\nimport { type ConvertTarget, convertCoreBlocks, convertTargetId, coreConversionTargets, isCoreTarget, parseCoreTarget } from './convert'\nimport type { BlockTarget } from './extension-points'\nimport type { ConversionProvider } from './feature'\nimport type { MessageKey, Translate } from '../i18n'\nimport { conversionsOf } from './pipeline'\nimport { isBlockContainer, isChromeNode } from './schema/node-flags'\nimport { TYPE_ABILITIES } from './schema/abilities'\nimport type { MenuItem } from './toolbar'\n\ndeclare module '@tiptap/core' {\n interface Commands<ReturnType> {\n blockConvert: {\n /**\n * Convert the block at `pos` (default: the caret's block in the document or another block container; a chrome\n * node stands for its parent) into `target`. False when the conversion changes nothing or is impossible there.\n */\n convertBlockTo: (target: ConvertTarget, pos?: number) => ReturnType\n }\n }\n}\n\nconst CORE_LABELS: Record<string, { key: MessageKey, icon: string }> = {\n paragraph: { key: 'block.paragraph', icon: 'i-lucide-pilcrow' },\n bulletList: { key: 'block.bulletList', icon: 'i-lucide-list' },\n orderedList: { key: 'block.orderedList', icon: 'i-lucide-list-ordered' },\n blockquote: { key: 'block.blockquote', icon: 'i-lucide-text-quote' },\n codeBlock: { key: 'block.codeBlock', icon: 'i-lucide-square-code' },\n}\n\n/**\n * The standard conversions: paragraphs, headings, lists, quotes and code blocks into each other. Declines every other\n * target, so features that add targets (speaker segments, composites) own them in their own providers.\n */\nexport const coreConversions: ConversionProvider = {\n targets: (_editor, node) => coreConversionTargets(node),\n parseTarget: parseCoreTarget,\n label: (target, t) => {\n if (target.type === 'heading') return { label: t('block.heading', { level: target.level }), icon: `i-lucide-heading-${target.level}` }\n const core = isCoreTarget(target) ? CORE_LABELS[target.type] : undefined\n return core ? { label: t(core.key), icon: core.icon } : null\n },\n convert: (state, $start, target) => {\n const node = $start.nodeAfter\n if (!node) return null\n const blocks = convertCoreBlocks(state.schema, [node], target)\n return blocks ? { from: $start.pos, to: $start.pos + node.nodeSize, blocks } : null\n },\n}\n\n/** The provider that owns `target`: the first, in feature order, that parses its id. */\nexport function targetOwner(providers: readonly ConversionProvider[], target: ConvertTarget): ConversionProvider | undefined {\n const id = convertTargetId(target)\n return providers.find(provider => provider.parseTarget(id) !== null)\n}\n\n/** The target `id` names, by its owner; null when no provider knows it. */\nexport function parseConversionTarget(providers: readonly ConversionProvider[], id: string): ConvertTarget | null {\n for (const provider of providers) {\n const target = provider.parseTarget(id)\n if (target) return target\n }\n return null\n}\n\n/** Label (in the language of `t`) and icon of `target`, from its owner. */\nexport function conversionLabel(providers: readonly ConversionProvider[], target: ConvertTarget, t: Translate): { label: string, icon: string } {\n const label = targetOwner(providers, target)?.label(target, t)\n if (!label) throw new Error(`@ecsplico/editor: no conversion provider owns the target \"${convertTargetId(target)}\"`)\n return label\n}\n\n/** The targets offered for `node` per provider, in feature order; a target id offered twice is an error. */\nexport function conversionTargetGroups(providers: readonly ConversionProvider[], editor: Editor, node: PMNode): ConvertTarget[][] {\n const offered = new Set<string>()\n return providers.map(provider => provider.targets(editor, node).filter((target) => {\n const id = convertTargetId(target)\n if (offered.has(id)) throw new Error(`@ecsplico/editor: the conversion target \"${id}\" is advertised by more than one provider`)\n offered.add(id)\n return true\n }))\n}\n\n/** The `$pos` right in front of the block to convert; a chrome node stands for its parent block. */\nfunction blockStart(state: EditorState, pos: number | undefined): ResolvedPos | null {\n let $start: ResolvedPos\n if (pos === undefined) {\n // The caret's block whose parent is a block container (the document, a composite).\n const { $head } = state.selection\n let depth = $head.depth\n while (depth > 0 && !isBlockContainer($head.node(depth - 1))) depth--\n if (depth === 0) return null\n $start = state.doc.resolve($head.before(depth))\n }\n else {\n if (pos < 0 || pos >= state.doc.content.size) return null\n $start = state.doc.resolve(pos)\n }\n const node = $start.nodeAfter\n if (!node) return null\n return isChromeNode(node) ? state.doc.resolve($start.before()) : $start\n}\n\n/**\n * The conversion of the block right after `$start` into `target`: the range it replaces and the converted blocks.\n * A provider claiming the source block (`handlesSource`) executes; otherwise the target's owner does. Null when the\n * conversion changes nothing or the result does not fit there (`parent.canReplace`). Shared by `convertBlockTo` and\n * the chat's `convert` op.\n */\nexport function blockConversion(providers: readonly ConversionProvider[], state: EditorState, $start: ResolvedPos, target: ConvertTarget): { from: number, to: number, blocks: PMNode[] } | null {\n const node = $start.nodeAfter\n if (!node) return null\n const provider = providers.find(candidate => candidate.handlesSource?.(node)) ?? targetOwner(providers, target)\n const conversion = provider?.convert(state, $start, target)\n if (!conversion) return null\n const parent = $start.parent\n const $end = state.doc.resolve(conversion.to)\n if ($end.parent !== parent || !parent.canReplace($start.index(), $end.index(), Fragment.from(conversion.blocks))) return null\n return conversion\n}\n\n/**\n * Client-only, no schema: the `convertBlockTo` command over the preset's conversion providers — the „Umwandeln in …“\n * block action and the toolbar's conversion groups. One transaction, so one undo step.\n */\nexport const BlockConvert = Extension.create({\n name: 'blockConvert',\n\n addCommands() {\n return {\n convertBlockTo: (target, pos) => ({ editor, state, tr, dispatch }) => {\n const $start = blockStart(state, pos)\n const conversion = $start && blockConversion(conversionsOf(editor), state, $start, target)\n if (!conversion) return false\n if (dispatch) {\n tr.replaceWith(conversion.from, conversion.to, conversion.blocks)\n const $first = tr.doc.resolve(conversion.from)\n tr.setSelection(Selection.findFrom($first, 1, true) ?? Selection.near($first)).scrollIntoView()\n }\n return true\n },\n }\n },\n})\n\n/**\n * „Umwandeln in …“ entries for the block `target`: the targets the providers offer whose type the block's container\n * allows (`TYPE_ABILITIES`), one separated group per provider in feature order. A list item stands for its list.\n */\nexport function convertMenuItems(editor: Editor, target: BlockTarget, t: Translate): MenuItem[] {\n let { node, pos } = target\n if (node.type.name === 'listItem') {\n const $item = editor.state.doc.resolve(pos)\n node = $item.parent\n pos = $item.before()\n }\n const providers = conversionsOf(editor)\n const abilities = abilitiesAt(editor, pos)\n const groups = conversionTargetGroups(providers, editor, node)\n .map(targets => targets\n .filter(to => !TYPE_ABILITIES[to.type] || abilities.has(TYPE_ABILITIES[to.type]!))\n .map((to): MenuItem => ({\n ...conversionLabel(providers, to, t),\n onSelect: () => editor.chain().focus().convertBlockTo(to, pos).run(),\n })))\n .filter(items => items.length > 0)\n return groups.flatMap((items, index) => index ? [{ type: 'separator' } as const, ...items] : items)\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"block-convert.js","names":[],"sources":["../../src/core/block-convert.ts"],"sourcesContent":["import { type Editor, Extension } from '@tiptap/core'\nimport { Fragment, type Node as PMNode, type ResolvedPos } from '@tiptap/pm/model'\nimport { type EditorState, Selection } from '@tiptap/pm/state'\nimport { abilitiesAt } from './abilities'\nimport type { Creates, MenuItem } from './command-types'\nimport { guardsAccept } from './commands'\nimport { type ConvertTarget, convertCoreBlocks, convertTargetId, coreConversionTargets, isCoreTarget, parseCoreTarget } from './convert'\nimport type { BlockTarget } from './extension-points'\nimport type { ConversionProvider } from './feature'\nimport type { MessageKey, Translate } from '../i18n'\nimport { conversionsOf } from './pipeline'\nimport { isBlockContainer, isChromeNode } from './schema/node-flags'\nimport { TYPE_ABILITIES } from './schema/abilities'\n\ndeclare module '@tiptap/core' {\n interface Commands<ReturnType> {\n blockConvert: {\n /**\n * Convert the block at `pos` (default: the caret's block in the document or another block container; a chrome\n * node stands for its parent) into `target`. False when the conversion changes nothing or is impossible there.\n */\n convertBlockTo: (target: ConvertTarget, pos?: number) => ReturnType\n }\n }\n}\n\nconst CORE_LABELS: Record<string, { key: MessageKey, icon: string }> = {\n paragraph: { key: 'block.paragraph', icon: 'i-lucide-pilcrow' },\n bulletList: { key: 'block.bulletList', icon: 'i-lucide-list' },\n orderedList: { key: 'block.orderedList', icon: 'i-lucide-list-ordered' },\n blockquote: { key: 'block.blockquote', icon: 'i-lucide-text-quote' },\n codeBlock: { key: 'block.codeBlock', icon: 'i-lucide-square-code' },\n}\n\n/**\n * The standard conversions: paragraphs, headings, lists, quotes and code blocks into each other. Declines every other\n * target, so features that add targets (speaker segments, composites) own them in their own providers.\n */\nexport const coreConversions: ConversionProvider = {\n targets: (_editor, node) => coreConversionTargets(node),\n parseTarget: parseCoreTarget,\n label: (target, t) => {\n if (target.type === 'heading') return { label: t('block.heading', { level: target.level }), icon: `i-lucide-heading-${target.level}` }\n const core = isCoreTarget(target) ? CORE_LABELS[target.type] : undefined\n return core ? { label: t(core.key), icon: core.icon } : null\n },\n convert: (state, $start, target) => {\n const node = $start.nodeAfter\n if (!node) return null\n const blocks = convertCoreBlocks(state.schema, [node], target)\n return blocks ? { from: $start.pos, to: $start.pos + node.nodeSize, blocks } : null\n },\n}\n\n/** The provider that owns `target`: the first, in feature order, that parses its id. */\nexport function targetOwner(providers: readonly ConversionProvider[], target: ConvertTarget): ConversionProvider | undefined {\n const id = convertTargetId(target)\n return providers.find(provider => provider.parseTarget(id) !== null)\n}\n\n/** The target `id` names, by its owner; null when no provider knows it. */\nexport function parseConversionTarget(providers: readonly ConversionProvider[], id: string): ConvertTarget | null {\n for (const provider of providers) {\n const target = provider.parseTarget(id)\n if (target) return target\n }\n return null\n}\n\n/** Label (in the language of `t`) and icon of `target`, from its owner. */\nexport function conversionLabel(providers: readonly ConversionProvider[], target: ConvertTarget, t: Translate): { label: string, icon: string } {\n const label = targetOwner(providers, target)?.label(target, t)\n if (!label) throw new Error(`@ecsplico/editor: no conversion provider owns the target \"${convertTargetId(target)}\"`)\n return label\n}\n\n/** The targets offered for `node` per provider, in feature order; a target id offered twice is an error. */\nexport function conversionTargetGroups(providers: readonly ConversionProvider[], editor: Editor, node: PMNode): ConvertTarget[][] {\n const offered = new Set<string>()\n return providers.map(provider => provider.targets(editor, node).filter((target) => {\n const id = convertTargetId(target)\n if (offered.has(id)) throw new Error(`@ecsplico/editor: the conversion target \"${id}\" is advertised by more than one provider`)\n offered.add(id)\n return true\n }))\n}\n\n/** The `$pos` right in front of the block to convert; a chrome node stands for its parent block. */\nfunction blockStart(state: EditorState, pos: number | undefined): ResolvedPos | null {\n let $start: ResolvedPos\n if (pos === undefined) {\n // The caret's block whose parent is a block container (the document, a composite).\n const { $head } = state.selection\n let depth = $head.depth\n while (depth > 0 && !isBlockContainer($head.node(depth - 1))) depth--\n if (depth === 0) return null\n $start = state.doc.resolve($head.before(depth))\n }\n else {\n if (pos < 0 || pos >= state.doc.content.size) return null\n $start = state.doc.resolve(pos)\n }\n const node = $start.nodeAfter\n if (!node) return null\n return isChromeNode(node) ? state.doc.resolve($start.before()) : $start\n}\n\n/**\n * The conversion of the block right after `$start` into `target`: the range it replaces and the converted blocks.\n * A provider claiming the source block (`handlesSource`) executes; otherwise the target's owner does. Null when the\n * conversion changes nothing or the result does not fit there (`parent.canReplace`). Shared by `convertBlockTo` and\n * the chat's `convert` op.\n */\nexport function blockConversion(providers: readonly ConversionProvider[], state: EditorState, $start: ResolvedPos, target: ConvertTarget): { from: number, to: number, blocks: PMNode[] } | null {\n const node = $start.nodeAfter\n if (!node) return null\n const provider = providers.find(candidate => candidate.handlesSource?.(node)) ?? targetOwner(providers, target)\n const conversion = provider?.convert(state, $start, target)\n if (!conversion) return null\n const parent = $start.parent\n const $end = state.doc.resolve(conversion.to)\n if ($end.parent !== parent || !parent.canReplace($start.index(), $end.index(), Fragment.from(conversion.blocks))) return null\n return conversion\n}\n\n/** The node a conversion into `target` creates, as the insert guards see it (`Creates`). */\nfunction createdBy(target: ConvertTarget): Creates {\n switch (target.type) {\n case 'heading': return { type: 'heading', attrs: { level: target.level } }\n case 'composite': return { type: 'composite', attrs: { kind: target.kind } }\n case 'custom': return { type: target.id, ...(target.attrs && { attrs: target.attrs }) }\n default: return { type: target.type }\n }\n}\n\n/**\n * Client-only, no schema: the `convertBlockTo` command over the preset's conversion providers — the „Umwandeln in …“\n * block action and the toolbar's conversion groups. One transaction, so one undo step. The target must pass the same\n * insert guards as creating that node there (`guardsAccept`): a Baustein kind its parent does not accept is refused.\n */\nexport const BlockConvert = Extension.create({\n name: 'blockConvert',\n\n addCommands() {\n return {\n convertBlockTo: (target, pos) => ({ editor, state, tr, dispatch }) => {\n const $start = blockStart(state, pos)\n if (!$start) return false\n const conversion = blockConversion(conversionsOf(editor), state, $start, target)\n if (!conversion || !guardsAccept(editor, state.doc.resolve($start.start()), createdBy(target))) return false\n if (dispatch) {\n tr.replaceWith(conversion.from, conversion.to, conversion.blocks)\n const $first = tr.doc.resolve(conversion.from)\n tr.setSelection(Selection.findFrom($first, 1, true) ?? Selection.near($first)).scrollIntoView()\n }\n return true\n },\n }\n },\n})\n\n/**\n * „Umwandeln in …“ entries for the block `target`: the targets the providers offer whose type the block's container\n * allows (`TYPE_ABILITIES`), one separated group per provider in feature order; targets the block cannot be converted\n * to right now are disabled. A list item stands for its list.\n */\nexport function convertMenuItems(editor: Editor, target: BlockTarget, t: Translate): MenuItem[] {\n let { node, pos } = target\n if (node.type.name === 'listItem') {\n const $item = editor.state.doc.resolve(pos)\n node = $item.parent\n pos = $item.before()\n }\n const providers = conversionsOf(editor)\n const abilities = abilitiesAt(editor, pos)\n const groups = conversionTargetGroups(providers, editor, node)\n .map(targets => targets\n .filter(to => !TYPE_ABILITIES[to.type] || abilities.has(TYPE_ABILITIES[to.type]!))\n .map((to): MenuItem => ({\n ...conversionLabel(providers, to, t),\n disabled: !editor.can().convertBlockTo(to, pos),\n onSelect: () => editor.chain().focus().convertBlockTo(to, pos).run(),\n })))\n .filter(items => items.length > 0)\n return groups.flatMap((items, index) => index ? [{ type: 'separator' } as const, ...items] : items)\n}\n"],"mappings":"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"}
@@ -0,0 +1,89 @@
1
+ import { MessageKey } from "../i18n/index.js";
2
+ import { Ability } from "./schema/abilities.js";
3
+ import { Editor } from "@tiptap/core";
4
+ import { ResolvedPos } from "@tiptap/pm/model";
5
+ //#region src/core/command-types.d.ts
6
+ /** One row of a dropdown a command or block action opens; the framework layer renders it. */
7
+ export interface MenuItem {
8
+ type?: 'label' | 'separator';
9
+ label?: string;
10
+ description?: string;
11
+ /** Iconify name, e.g. `i-lucide-heading-1`. */
12
+ icon?: string;
13
+ disabled?: boolean;
14
+ onSelect?: () => void;
15
+ }
16
+ /** The node a command inserts at the caret; enables the schema and accepted-children fit check. */
17
+ export interface Creates {
18
+ type: string;
19
+ attrs?: Record<string, unknown>;
20
+ }
21
+ export interface CommandBase {
22
+ /** Unique among the commands of one editor (host commands included). */
23
+ id: string;
24
+ /** Tooltip, aria-label and `/` menu text. */
25
+ label: string;
26
+ /** Iconify name, e.g. `i-lucide-bold`. */
27
+ icon: string;
28
+ /** Shortcut keys shown in the tooltip, e.g. `['meta', 'b']`. */
29
+ kbds?: string[];
30
+ /** Ability the command needs at the caret (toolbar: at the selection); an active toggle never needs it. Unset: ungated. */
31
+ ability?: Ability;
32
+ /** The node the command inserts; the command is enabled only where `canCreateAt` says it fits (schema and registered insert guards). */
33
+ creates?: Creates;
34
+ /** Further structural check (`editor.can()` style); with `creates`, both must hold. Default: always. */
35
+ can?: (editor: Editor) => boolean;
36
+ /** Whether the command is on at the caret (toggle style). An active command is always enabled. */
37
+ active?: (editor: Editor) => boolean;
38
+ /** Hides the command everywhere; evaluated only with a live editor. */
39
+ visible?: (editor: Editor) => boolean;
40
+ /** Toolbar placement: the group (declared by a feature's `toolbarGroups`) and the position within it. Default: none. */
41
+ toolbar?: {
42
+ group: string;
43
+ order?: number;
44
+ } | false;
45
+ /** `/` menu placement (`run` commands only): `id` is what is typed after `/` (default: the command id). Default: none. */
46
+ slash?: {
47
+ id?: string;
48
+ } | false;
49
+ /** Listed by the ⌘K palette. Default: true for `run` and `menu` commands, false for `component` commands. */
50
+ palette?: boolean;
51
+ }
52
+ /**
53
+ * `run` on click or pick, `menu` (a dropdown of the items it returns), or `component`: a toolbar component that renders
54
+ * the whole button itself (own popover, badge or state) and receives `{ editor }`; `ability`, `active` and `can` are not
55
+ * applied to it, and it never has a `slash` placement.
56
+ */
57
+ export type CommandDef<C = unknown> = CommandBase & ({
58
+ run: (editor: Editor) => void;
59
+ } | {
60
+ menu: (editor: Editor) => MenuItem[];
61
+ } | {
62
+ component: C;
63
+ });
64
+ /** A visually joined set of toolbar buttons; features declare the groups their commands name. */
65
+ export interface ToolbarGroupDef {
66
+ id: string;
67
+ /** Position among the groups (ascending, stable). */
68
+ order?: number;
69
+ /** Catalog key of the group's heading in the ⌘K palette (default: the group id). */
70
+ labelKey?: MessageKey;
71
+ /** Hides the group; evaluated only with a live editor. */
72
+ visible?: (editor: Editor) => boolean;
73
+ }
74
+ /** A toolbar group with the commands placed in it, in `toolbar.order`. */
75
+ export interface PlacedToolbarGroup<C = unknown> extends ToolbarGroupDef {
76
+ items: CommandDef<C>[];
77
+ }
78
+ /**
79
+ * Checks whether `creates` may be inserted into the ancestor that `canCreateAt` found: `$parent.parent` is the node
80
+ * that would receive it. Features contribute guards (`EditorFeature.insertGuards`), e.g. the accepted children of a Baustein.
81
+ */
82
+ export type InsertGuard = (editor: Editor, $parent: ResolvedPos, creates: Creates) => boolean;
83
+ export interface CommandState {
84
+ visible: boolean;
85
+ enabled: boolean;
86
+ active: boolean;
87
+ }
88
+ //#endregion
89
+ //# sourceMappingURL=command-types.d.ts.map
@@ -0,0 +1,40 @@
1
+ import { CommandBase, CommandDef, CommandState, Creates, InsertGuard, MenuItem, PlacedToolbarGroup, ToolbarGroupDef } from "./command-types.js";
2
+ import { EditorPreset, FeatureContext } from "./feature.js";
3
+ import { ChainedCommands, Editor } from "@tiptap/core";
4
+ import { ResolvedPos } from "@tiptap/pm/model";
5
+ //#region src/core/commands.d.ts
6
+ /**
7
+ * A command over a command chain: `run` focuses the editor and executes `command`; the command is disabled while
8
+ * `can()` says it is structurally impossible (also an empty undo history). With `creates`, `commandState` additionally
9
+ * requires the node to fit at the caret.
10
+ */
11
+ export declare function command(def: Omit<CommandBase, 'can'> & {
12
+ command: (chain: ChainedCommands) => ChainedCommands;
13
+ }): CommandDef<never>;
14
+ /**
15
+ * Whether every registered insert guard accepts `creates` below the ancestor `$parent` stands for (`$parent.parent` is the
16
+ * node that would receive it). The one rule behind both creation (`canCreateAt`) and conversion targets (`convertBlockTo`).
17
+ */
18
+ export declare function guardsAccept(editor: Editor, $parent: ResolvedPos, creates: Creates): boolean;
19
+ /**
20
+ * Whether a node like `creates` may be inserted at `$pos`: walks from the caret's depth outward to the first ancestor
21
+ * whose content accepts the type at the caret's index, then every registered insert guard must accept it there.
22
+ */
23
+ export declare function canCreateAt(editor: Editor, $pos: ResolvedPos, creates: Creates): boolean;
24
+ /**
25
+ * The state of `cmd` for the toolbar (`'selection'`: abilities of the selection) or the `/` menu (`'caret'`). `$at`
26
+ * replaces the caret position (the `/` plugin evaluates inside a transaction's `apply`, where `editor.state` is still
27
+ * the old state); `can` hooks always read `editor.state`.
28
+ */
29
+ export declare function commandState(editor: Editor, cmd: CommandDef, at: 'selection' | 'caret', $at?: ResolvedPos): CommandState;
30
+ /** The commands of the preset's features in feature order. Throws when two commands share an id. */
31
+ export declare function commandsOf<C>(preset: EditorPreset<C>, ctx: FeatureContext): CommandDef<C>[];
32
+ /**
33
+ * The toolbar of `preset`: the groups features declare (`toolbarGroups`) with every command that has a `toolbar`
34
+ * placement, groups and commands sorted by `order` (stable). Throws when a command names a group no feature declares
35
+ * or two commands share an id.
36
+ */
37
+ export declare function toolbarOf<C>(preset: EditorPreset<C>, ctx: FeatureContext): PlacedToolbarGroup<C>[];
38
+ //#endregion
39
+ export type { CommandBase, CommandDef, CommandState, Creates, InsertGuard, MenuItem, PlacedToolbarGroup, ToolbarGroupDef };
40
+ //# sourceMappingURL=commands.d.ts.map
@@ -0,0 +1,151 @@
1
+ import { abilitiesAt, abilitiesAtSelection } from "./abilities.js";
2
+ import { byOrder, fail } from "./util.js";
3
+ import { contributions } from "./define-editor.js";
4
+ import { editorEntryOf } from "./editor-ui.js";
5
+ //#region src/core/commands.ts
6
+ const guardCache = /* @__PURE__ */ new WeakMap();
7
+ function guardsOf(editor) {
8
+ const entry = editorEntryOf(editor);
9
+ if (!entry) return [];
10
+ let guards = guardCache.get(entry);
11
+ if (!guards) {
12
+ guards = contributions(entry.preset, "insertGuards").flatMap((factory) => factory(entry.ctx));
13
+ guardCache.set(entry, guards);
14
+ }
15
+ return guards;
16
+ }
17
+ /**
18
+ * A command over a command chain: `run` focuses the editor and executes `command`; the command is disabled while
19
+ * `can()` says it is structurally impossible (also an empty undo history). With `creates`, `commandState` additionally
20
+ * requires the node to fit at the caret.
21
+ */
22
+ function command(def) {
23
+ const { command: chainOf, ...rest } = def;
24
+ return {
25
+ ...rest,
26
+ can: (editor) => chainOf(editor.can().chain()).run(),
27
+ run: (editor) => {
28
+ chainOf(editor.chain().focus()).run();
29
+ }
30
+ };
31
+ }
32
+ /**
33
+ * Whether every registered insert guard accepts `creates` below the ancestor `$parent` stands for (`$parent.parent` is the
34
+ * node that would receive it). The one rule behind both creation (`canCreateAt`) and conversion targets (`convertBlockTo`).
35
+ */
36
+ function guardsAccept(editor, $parent, creates) {
37
+ return guardsOf(editor).every((guard) => guard(editor, $parent, creates));
38
+ }
39
+ /**
40
+ * Whether a node like `creates` may be inserted at `$pos`: walks from the caret's depth outward to the first ancestor
41
+ * whose content accepts the type at the caret's index, then every registered insert guard must accept it there.
42
+ */
43
+ function canCreateAt(editor, $pos, creates) {
44
+ const type = editor.schema.nodes[creates.type];
45
+ if (!type) return false;
46
+ for (let depth = $pos.depth; depth >= 0; depth--) {
47
+ const index = $pos.index(depth);
48
+ if (!$pos.node(depth).canReplaceWith(index, index, type)) continue;
49
+ return guardsAccept(editor, $pos.doc.resolve($pos.start(depth)), creates);
50
+ }
51
+ return false;
52
+ }
53
+ /**
54
+ * The state of `cmd` for the toolbar (`'selection'`: abilities of the selection) or the `/` menu (`'caret'`). `$at`
55
+ * replaces the caret position (the `/` plugin evaluates inside a transaction's `apply`, where `editor.state` is still
56
+ * the old state); `can` hooks always read `editor.state`.
57
+ */
58
+ function commandState(editor, cmd, at, $at) {
59
+ const visible = cmd.visible?.(editor) ?? true;
60
+ if ("component" in cmd) return {
61
+ visible,
62
+ enabled: true,
63
+ active: false
64
+ };
65
+ const active = cmd.active?.(editor) ?? false;
66
+ if (active) return {
67
+ visible,
68
+ enabled: true,
69
+ active
70
+ };
71
+ const $from = $at ?? editor.state.selection.$from;
72
+ if (cmd.ability) {
73
+ if (!(at === "selection" && !$at ? abilitiesAtSelection(editor) : abilitiesAt(editor, $from)).has(cmd.ability)) return {
74
+ visible,
75
+ enabled: false,
76
+ active
77
+ };
78
+ }
79
+ return {
80
+ visible,
81
+ enabled: (!cmd.can || cmd.can(editor)) && (!cmd.creates || canCreateAt(editor, $from, cmd.creates)),
82
+ active
83
+ };
84
+ }
85
+ /** The commands of the preset's features in feature order. Throws when two commands share an id. */
86
+ function commandsOf(preset, ctx) {
87
+ return collect(preset, ctx).commands;
88
+ }
89
+ const ownerOfCommand = /* @__PURE__ */ new WeakMap();
90
+ /**
91
+ * Throws when two of `commands` share an id (`CommandBase.id` is unique per editor), naming the declaring features;
92
+ * a command without a known feature is the host's.
93
+ */
94
+ function assertUniqueCommandIds(commands) {
95
+ const seen = /* @__PURE__ */ new Map();
96
+ for (const cmd of commands) {
97
+ const first = seen.get(cmd.id);
98
+ if (first) fail(`command "${cmd.id}" is declared by "${ownerOfCommand.get(first) ?? "host"}" and "${ownerOfCommand.get(cmd) ?? "host"}"`);
99
+ seen.set(cmd.id, cmd);
100
+ }
101
+ }
102
+ /**
103
+ * Places `commands` into their toolbar `groups` (every declared group, also empty ones, sorted by `order`; a group's
104
+ * commands sorted by `toolbar.order`, stable). `unplaced` receives each command that has no group to go to: no `toolbar`
105
+ * placement, or one naming a group that is not declared; what that means is the caller's policy.
106
+ */
107
+ function placeInGroups(groups, commands, unplaced) {
108
+ const placed = /* @__PURE__ */ new Map();
109
+ for (const group of groups) placed.set(group.id, {
110
+ ...group,
111
+ items: []
112
+ });
113
+ for (const cmd of commands) {
114
+ const group = cmd.toolbar ? placed.get(cmd.toolbar.group) : void 0;
115
+ if (group) group.items.push(cmd);
116
+ else unplaced(cmd);
117
+ }
118
+ return [...placed.values()].sort(byOrder).map((group) => ({
119
+ ...group,
120
+ items: [...group.items].sort((a, b) => byOrder(a.toolbar || {}, b.toolbar || {}))
121
+ }));
122
+ }
123
+ /** The toolbar groups the features of `preset` declare, in feature order. */
124
+ const toolbarGroupsOf = (preset) => preset.features.flatMap((feature) => feature.toolbarGroups ?? []);
125
+ /**
126
+ * The toolbar of `preset`: the groups features declare (`toolbarGroups`) with every command that has a `toolbar`
127
+ * placement, groups and commands sorted by `order` (stable). Throws when a command names a group no feature declares
128
+ * or two commands share an id.
129
+ */
130
+ function toolbarOf(preset, ctx) {
131
+ const { commands, groups } = collect(preset, ctx);
132
+ return placeInGroups(groups, commands, (cmd) => {
133
+ if (cmd.toolbar) fail(`command "${cmd.id}" of "${ownerOfCommand.get(cmd) ?? "?"}" names toolbar group "${cmd.toolbar.group}" that no feature declares`);
134
+ });
135
+ }
136
+ function collect(preset, ctx) {
137
+ const commands = [];
138
+ for (const feature of preset.features) for (const cmd of feature.commands?.(ctx) ?? []) {
139
+ commands.push(cmd);
140
+ ownerOfCommand.set(cmd, feature.id);
141
+ }
142
+ assertUniqueCommandIds(commands);
143
+ return {
144
+ commands,
145
+ groups: toolbarGroupsOf(preset)
146
+ };
147
+ }
148
+ //#endregion
149
+ export { assertUniqueCommandIds, canCreateAt, command, commandState, commandsOf, guardsAccept, placeInGroups, toolbarGroupsOf, toolbarOf };
150
+
151
+ //# sourceMappingURL=commands.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"commands.js","names":[],"sources":["../../src/core/commands.ts"],"sourcesContent":["import type { ChainedCommands, Editor } from '@tiptap/core'\nimport type { ResolvedPos } from '@tiptap/pm/model'\nimport { abilitiesAt, abilitiesAtSelection } from './abilities'\nimport { contributions } from './define-editor'\nimport { type EditorEntry, editorEntryOf } from './editor-ui'\nimport type { EditorPreset, FeatureContext } from './feature'\nimport type { CommandBase, CommandDef, CommandState, Creates, InsertGuard, PlacedToolbarGroup, ToolbarGroupDef } from './command-types'\nimport { byOrder, fail } from './util'\n\nexport type { CommandBase, CommandDef, CommandState, Creates, InsertGuard, MenuItem, PlacedToolbarGroup, ToolbarGroupDef } from './command-types'\n\n// The guards of an editor are the `insertGuards` of the features of the preset its surface registered\n// (`registerEditor`): looked up by the raw editor instance, built once per entry. An editor without an entry\n// (a headless test editor) has none. Callers holding a framework proxy of the editor pass the raw instance.\nconst guardCache = new WeakMap<EditorEntry, readonly InsertGuard[]>()\n\nfunction guardsOf(editor: Editor): readonly InsertGuard[] {\n const entry = editorEntryOf(editor)\n if (!entry) return []\n let guards = guardCache.get(entry)\n if (!guards) {\n guards = contributions(entry.preset, 'insertGuards').flatMap(factory => factory(entry.ctx))\n guardCache.set(entry, guards)\n }\n return guards\n}\n\n/**\n * A command over a command chain: `run` focuses the editor and executes `command`; the command is disabled while\n * `can()` says it is structurally impossible (also an empty undo history). With `creates`, `commandState` additionally\n * requires the node to fit at the caret.\n */\nexport function command(def: Omit<CommandBase, 'can'> & { command: (chain: ChainedCommands) => ChainedCommands }): CommandDef<never> {\n const { command: chainOf, ...rest } = def\n return {\n ...rest,\n can: editor => chainOf(editor.can().chain()).run(),\n run: (editor) => { chainOf(editor.chain().focus()).run() },\n }\n}\n\n/**\n * Whether every registered insert guard accepts `creates` below the ancestor `$parent` stands for (`$parent.parent` is the\n * node that would receive it). The one rule behind both creation (`canCreateAt`) and conversion targets (`convertBlockTo`).\n */\nexport function guardsAccept(editor: Editor, $parent: ResolvedPos, creates: Creates): boolean {\n return guardsOf(editor).every(guard => guard(editor, $parent, creates))\n}\n\n/**\n * Whether a node like `creates` may be inserted at `$pos`: walks from the caret's depth outward to the first ancestor\n * whose content accepts the type at the caret's index, then every registered insert guard must accept it there.\n */\nexport function canCreateAt(editor: Editor, $pos: ResolvedPos, creates: Creates): boolean {\n const type = editor.schema.nodes[creates.type]\n if (!type) return false\n for (let depth = $pos.depth; depth >= 0; depth--) {\n const index = $pos.index(depth)\n if (!$pos.node(depth).canReplaceWith(index, index, type)) continue\n return guardsAccept(editor, $pos.doc.resolve($pos.start(depth)), creates)\n }\n return false\n}\n\n/**\n * The state of `cmd` for the toolbar (`'selection'`: abilities of the selection) or the `/` menu (`'caret'`). `$at`\n * replaces the caret position (the `/` plugin evaluates inside a transaction's `apply`, where `editor.state` is still\n * the old state); `can` hooks always read `editor.state`.\n */\nexport function commandState(editor: Editor, cmd: CommandDef, at: 'selection' | 'caret', $at?: ResolvedPos): CommandState {\n const visible = cmd.visible?.(editor) ?? true\n if ('component' in cmd) return { visible, enabled: true, active: false }\n const active = cmd.active?.(editor) ?? false\n if (active) return { visible, enabled: true, active }\n const $from = $at ?? editor.state.selection.$from\n if (cmd.ability) {\n const abilities = at === 'selection' && !$at ? abilitiesAtSelection(editor) : abilitiesAt(editor, $from)\n if (!abilities.has(cmd.ability)) return { visible, enabled: false, active }\n }\n const fits = (!cmd.can || cmd.can(editor)) && (!cmd.creates || canCreateAt(editor, $from, cmd.creates))\n return { visible, enabled: fits, active }\n}\n\n/** The commands of the preset's features in feature order. Throws when two commands share an id. */\nexport function commandsOf<C>(preset: EditorPreset<C>, ctx: FeatureContext): CommandDef<C>[] {\n return collect(preset, ctx).commands\n}\n\n// The feature each command came from, for error messages; commands of the host's `commands` transformer have none.\nconst ownerOfCommand = new WeakMap<object, string>()\n\n/**\n * Throws when two of `commands` share an id (`CommandBase.id` is unique per editor), naming the declaring features;\n * a command without a known feature is the host's.\n */\nexport function assertUniqueCommandIds<C>(commands: readonly CommandDef<C>[]): void {\n const seen = new Map<string, CommandDef<C>>()\n for (const cmd of commands) {\n const first = seen.get(cmd.id)\n if (first) fail(`command \"${cmd.id}\" is declared by \"${ownerOfCommand.get(first) ?? 'host'}\" and \"${ownerOfCommand.get(cmd) ?? 'host'}\"`)\n seen.set(cmd.id, cmd)\n }\n}\n\n/**\n * Places `commands` into their toolbar `groups` (every declared group, also empty ones, sorted by `order`; a group's\n * commands sorted by `toolbar.order`, stable). `unplaced` receives each command that has no group to go to: no `toolbar`\n * placement, or one naming a group that is not declared; what that means is the caller's policy.\n */\nexport function placeInGroups<C>(groups: readonly ToolbarGroupDef[], commands: readonly CommandDef<C>[], unplaced: (cmd: CommandDef<C>) => void): PlacedToolbarGroup<C>[] {\n const placed = new Map<string, PlacedToolbarGroup<C>>()\n // `defineEditor` guarantees every group id is declared once.\n for (const group of groups) placed.set(group.id, { ...group, items: [] })\n for (const cmd of commands) {\n const group = cmd.toolbar ? placed.get(cmd.toolbar.group) : undefined\n if (group) group.items.push(cmd)\n else unplaced(cmd)\n }\n return [...placed.values()]\n .sort(byOrder)\n .map(group => ({ ...group, items: [...group.items].sort((a, b) => byOrder(a.toolbar || {}, b.toolbar || {})) }))\n}\n\n/** The toolbar groups the features of `preset` declare, in feature order. */\nexport const toolbarGroupsOf = <C>(preset: EditorPreset<C>): ToolbarGroupDef[] => preset.features.flatMap(feature => feature.toolbarGroups ?? [])\n\n/**\n * The toolbar of `preset`: the groups features declare (`toolbarGroups`) with every command that has a `toolbar`\n * placement, groups and commands sorted by `order` (stable). Throws when a command names a group no feature declares\n * or two commands share an id.\n */\nexport function toolbarOf<C>(preset: EditorPreset<C>, ctx: FeatureContext): PlacedToolbarGroup<C>[] {\n const { commands, groups } = collect(preset, ctx)\n return placeInGroups(groups, commands, (cmd) => {\n if (cmd.toolbar) fail(`command \"${cmd.id}\" of \"${ownerOfCommand.get(cmd) ?? '?'}\" names toolbar group \"${cmd.toolbar.group}\" that no feature declares`)\n })\n}\n\nfunction collect<C>(preset: EditorPreset<C>, ctx: FeatureContext) {\n const commands: CommandDef<C>[] = []\n for (const feature of preset.features) {\n for (const cmd of feature.commands?.(ctx) ?? []) {\n commands.push(cmd)\n ownerOfCommand.set(cmd, feature.id)\n }\n }\n assertUniqueCommandIds(commands)\n return { commands, groups: toolbarGroupsOf(preset) }\n}\n"],"mappings":"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"}
@@ -1,22 +1,19 @@
1
+ import { ReadonlyStore, Store } from "./store.js";
1
2
  import { Locale, Messages, Translate } from "../i18n/index.js";
2
- import { ModelSlot } from "../settings/values.js";
3
3
  import { EditorSettings } from "../settings/index.js";
4
+ import { EditorBackend } from "./backend.js";
5
+ import { EditorPublicConfig } from "../config/index.js";
4
6
  import { Notifier } from "./notify.js";
5
- import { ReadonlyStore, Store } from "./store.js";
6
- import { $Fetch } from "ofetch";
7
7
  //#region src/core/context.d.ts
8
- /** Inert public AI configuration (set by the Nuxt client plugin); only the AI feature reads it. */
9
- export interface EditorAiConfig {
10
- slots: Record<ModelSlot, string>;
11
- transcription: boolean;
12
- }
8
+ /** Inert public AI configuration (set by the Nuxt client plugin); only the AI feature reads it. Defined with the public config view. */
9
+ export type EditorAiConfig = EditorPublicConfig['ai'];
13
10
  export interface EditorContextOptions {
14
- /** HTTP client of every feature request (default: ofetch). */
15
- fetch?: $Fetch;
16
- settings?: {
17
- /** Keep the settings per account through `GET`/`PUT /api/editor/settings`; default false (this browser only). */
18
- remote?: boolean;
19
- };
11
+ /**
12
+ * Where documents, uploads, mention lookups, settings, themes and AI come from (default: the HTTP routes of the Nuxt
13
+ * module over the platform `fetch`, `createFetchBackend`). A backend that offers `settings` keeps the settings per
14
+ * account (`backend.settings`); without it they stay in this browser.
15
+ */
16
+ backend?: EditorBackend;
20
17
  ai?: EditorAiConfig;
21
18
  /** Shows app-level notices (e.g. model profiles); default: dropped (`silentNotifier`). */
22
19
  notify?: Notifier;
@@ -38,7 +35,7 @@ export interface EditorContext {
38
35
  * login page).
39
36
  */
40
37
  load: () => void;
41
- fetch: $Fetch;
38
+ backend: EditorBackend;
42
39
  ai: EditorAiConfig | undefined;
43
40
  /** Notices of app-level models; surfaces hand features their own `FeatureContext.notify`. */
44
41
  notify: Notifier;
@@ -50,13 +47,13 @@ export interface EditorContext {
50
47
  dispose: () => void;
51
48
  }
52
49
  /**
53
- * The editor context of an app: the settings shared by all editors of the app, and the HTTP client. Framework-free;
50
+ * The editor context of an app: the settings shared by all editors of the app, and the backend. Framework-free;
54
51
  * the Vue layer installs it with `app.use(createEditor())`, the React layer provides it through
55
52
  * `EditorContextProvider`. The settings are read from localStorage right away (client only) and every change is
56
- * written back. With `settings.remote`, `GET /api/editor/settings` (on `load()`, which the settings hooks call) answers:
57
- * `200` replaces them with the user's account settings (`synced`), `204` (the host's adapter keeps no settings), `401`
58
- * or a network error keep the local ones; once synced every change is also sent to the server (`PUT`, debounced).
59
- * Subscription and timer stop with `dispose()`.
53
+ * written back. With a backend that offers `settings`, `backend.settings.load()` (on `load()`, which
54
+ * the settings hooks call) answers: the user's account settings replace them (`synced`), `null` (the account has none
55
+ * yet) makes the account take this browser's, a refusal (`401`, `501`) or a network error keeps the local ones; once
56
+ * synced every change is also sent to the backend (`save`, debounced). Subscription and timer stop with `dispose()`.
60
57
  */
61
58
  export declare function createEditorContext(options?: EditorContextOptions): EditorContext;
62
59
  //#endregion
@@ -1,8 +1,9 @@
1
+ import { BackendError } from "./backend.js";
1
2
  import { createTranslator } from "../i18n/index.js";
2
3
  import { parseEditorSettings } from "../settings/index.js";
4
+ import { createFetchBackend } from "./http-backend.js";
3
5
  import { silentNotifier } from "./notify.js";
4
6
  import { createStore } from "./store.js";
5
- import { ofetch } from "ofetch";
6
7
  //#region src/core/context.ts
7
8
  const STORAGE_KEY = "tiptap-editor:settings";
8
9
  /** Pause after the last change before the settings are sent to the server (ms). */
@@ -20,19 +21,20 @@ function writeLocal(settings) {
20
21
  } catch {}
21
22
  }
22
23
  /**
23
- * The editor context of an app: the settings shared by all editors of the app, and the HTTP client. Framework-free;
24
+ * The editor context of an app: the settings shared by all editors of the app, and the backend. Framework-free;
24
25
  * the Vue layer installs it with `app.use(createEditor())`, the React layer provides it through
25
26
  * `EditorContextProvider`. The settings are read from localStorage right away (client only) and every change is
26
- * written back. With `settings.remote`, `GET /api/editor/settings` (on `load()`, which the settings hooks call) answers:
27
- * `200` replaces them with the user's account settings (`synced`), `204` (the host's adapter keeps no settings), `401`
28
- * or a network error keep the local ones; once synced every change is also sent to the server (`PUT`, debounced).
29
- * Subscription and timer stop with `dispose()`.
27
+ * written back. With a backend that offers `settings`, `backend.settings.load()` (on `load()`, which
28
+ * the settings hooks call) answers: the user's account settings replace them (`synced`), `null` (the account has none
29
+ * yet) makes the account take this browser's, a refusal (`401`, `501`) or a network error keeps the local ones; once
30
+ * synced every change is also sent to the backend (`save`, debounced). Subscription and timer stop with `dispose()`.
30
31
  */
31
32
  function createEditorContext(options = {}) {
32
- const fetcher = options.fetch ?? ofetch;
33
- const remoteMode = options.settings?.remote === true;
33
+ const backend = options.backend ?? createFetchBackend();
34
+ let remoteStore = backend.settings;
35
+ const remoteMode = remoteStore !== void 0;
34
36
  const settings = createStore(parseEditorSettings(null));
35
- const ready = createStore(!remoteMode);
37
+ const ready = createStore(!remoteMode && backend.ready === void 0);
36
38
  const synced = createStore(false);
37
39
  let loading = false;
38
40
  let loadRemote = () => {};
@@ -49,13 +51,14 @@ function createEditorContext(options = {}) {
49
51
  ready,
50
52
  synced,
51
53
  load,
52
- fetch: fetcher,
54
+ backend,
53
55
  ai: options.ai,
54
56
  notify: options.notify ?? silentNotifier,
55
57
  locale,
56
58
  t,
57
59
  dispose: () => dispose()
58
60
  };
61
+ if (!remoteMode) backend.ready?.then(() => ready.set(true));
59
62
  if (!("window" in globalThis)) return context;
60
63
  settings.set(readLocal());
61
64
  writeLocal(settings.get());
@@ -68,13 +71,10 @@ function createEditorContext(options = {}) {
68
71
  timer = setTimeout(() => {
69
72
  const json = JSON.stringify(value);
70
73
  if (json === remote) return;
71
- fetcher("/api/editor/settings", {
72
- method: "PUT",
73
- body: value
74
- }).then(() => {
74
+ remoteStore?.save(value).then(() => {
75
75
  remote = json;
76
76
  }).catch((error) => {
77
- if (error?.statusCode !== 501) console.warn(`tiptap-editor: ${t("settings.saveFailed")}`, error);
77
+ if (!(error instanceof BackendError && (error.status === 501 || error.status === 404))) console.warn(`tiptap-editor: ${t("settings.saveFailed")}`, error);
78
78
  });
79
79
  }, PUT_DEBOUNCE);
80
80
  }
@@ -87,16 +87,19 @@ function createEditorContext(options = {}) {
87
87
  clearTimeout(timer);
88
88
  unsubscribe();
89
89
  };
90
- if (!remoteMode) return context;
91
- loadRemote = () => fetcher.raw("/api/editor/settings").then((response) => {
92
- if (!active || response.status !== 200) return;
90
+ if (!remoteStore) return context;
91
+ loadRemote = () => Promise.resolve(backend.ready).then(() => {
92
+ remoteStore = backend.settings;
93
+ return remoteStore?.load();
94
+ }).then((stored) => {
95
+ if (!active || !remoteStore) return;
93
96
  synced.set(true);
94
- if (response._data) {
95
- settings.set(parseEditorSettings(response._data));
97
+ if (stored) {
98
+ settings.set(parseEditorSettings(stored));
96
99
  remote = JSON.stringify(settings.get());
97
100
  } else push(settings.get());
98
101
  }).catch((error) => {
99
- console.warn(`tiptap-editor: ${t("settings.loadFailed")}`, error);
102
+ if (!(error instanceof BackendError && (error.status === 501 || error.status === 404))) console.warn(`tiptap-editor: ${t("settings.loadFailed")}`, error);
100
103
  }).finally(() => {
101
104
  ready.set(true);
102
105
  });