@ecsplico/editor 3.6.0 → 4.1.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 (593) hide show
  1. package/CHANGELOG.md +73 -0
  2. package/dist/adapters/direct-ai.d.ts +4 -4
  3. package/dist/adapters/direct-ai.js +2 -2
  4. package/dist/adapters/direct-ai.js.map +1 -1
  5. package/dist/adapters/document-state.d.ts +1 -1
  6. package/dist/adapters/document-state.js.map +1 -1
  7. package/dist/adapters/forge.d.ts +2 -2
  8. package/dist/adapters/forge.js.map +1 -1
  9. package/dist/adapters/nitro.d.ts +11 -3
  10. package/dist/adapters/nitro.js +3 -1
  11. package/dist/adapters/nitro.js.map +1 -1
  12. package/dist/adapters/shared.d.ts +6 -6
  13. package/dist/adapters/shared.js.map +1 -1
  14. package/dist/code/CodeSurface.vue.d.ts +3 -3
  15. package/dist/config/index.d.ts +14 -14
  16. package/dist/config/index.js +8 -8
  17. package/dist/config/index.js.map +1 -1
  18. package/dist/core/backend-types.d.ts +3 -3
  19. package/dist/core/backend-types.js.map +1 -1
  20. package/dist/core/backend.d.ts +4 -4
  21. package/dist/core/backend.js.map +1 -1
  22. package/dist/core/block-convert.d.ts +1 -1
  23. package/dist/core/block-convert.js +5 -5
  24. package/dist/core/block-convert.js.map +1 -1
  25. package/dist/core/block-transfer.d.ts +8 -4
  26. package/dist/core/block-transfer.js +23 -14
  27. package/dist/core/block-transfer.js.map +1 -1
  28. package/dist/core/capabilities.d.ts +113 -0
  29. package/dist/core/capabilities.js +155 -0
  30. package/dist/core/capabilities.js.map +1 -0
  31. package/dist/core/command-types.d.ts +1 -1
  32. package/dist/core/context.js.map +1 -1
  33. package/dist/core/convert.d.ts +5 -5
  34. package/dist/core/convert.js +5 -5
  35. package/dist/core/convert.js.map +1 -1
  36. package/dist/core/core-feature.js +1 -1
  37. package/dist/core/define-editor.d.ts +2 -2
  38. package/dist/core/define-editor.js +34 -6
  39. package/dist/core/define-editor.js.map +1 -1
  40. package/dist/core/derivation.d.ts +119 -0
  41. package/dist/core/derivation.js +187 -0
  42. package/dist/core/derivation.js.map +1 -0
  43. package/dist/core/derive.d.ts +61 -0
  44. package/dist/core/derive.js +69 -0
  45. package/dist/core/derive.js.map +1 -0
  46. package/dist/core/extension-points.d.ts +16 -0
  47. package/dist/core/feature-context.d.ts +5 -1
  48. package/dist/core/feature-context.js +10 -3
  49. package/dist/core/feature-context.js.map +1 -1
  50. package/dist/core/feature.d.ts +41 -19
  51. package/dist/core/feature.js.map +1 -1
  52. package/dist/core/fences.js +1 -1
  53. package/dist/core/fences.js.map +1 -1
  54. package/dist/core/index.d.ts +6 -2
  55. package/dist/core/index.js +5 -1
  56. package/dist/core/pipeline.d.ts +14 -5
  57. package/dist/core/pipeline.js +19 -7
  58. package/dist/core/pipeline.js.map +1 -1
  59. package/dist/core/properties.d.ts +22 -0
  60. package/dist/core/properties.js +17 -0
  61. package/dist/core/properties.js.map +1 -0
  62. package/dist/core/schema/block-ids.js +5 -5
  63. package/dist/core/schema/block-ids.js.map +1 -1
  64. package/dist/core/schema/index.d.ts +2 -1
  65. package/dist/core/schema/index.js +2 -1
  66. package/dist/core/schema/index.js.map +1 -1
  67. package/dist/core/schema/opaque-fence.d.ts +4 -4
  68. package/dist/core/schema/opaque-fence.js +7 -7
  69. package/dist/core/schema/opaque-fence.js.map +1 -1
  70. package/dist/core/schema/persisted-names.d.ts +58 -0
  71. package/dist/core/schema/persisted-names.js +96 -0
  72. package/dist/core/schema/persisted-names.js.map +1 -0
  73. package/dist/core/toolbar-items.js +1 -1
  74. package/dist/core/toolbar-items.js.map +1 -1
  75. package/dist/core/util.js +5 -1
  76. package/dist/core/util.js.map +1 -1
  77. package/dist/document/DocumentSurface.vue.d.ts +3 -3
  78. package/dist/features/ai/agent-ops.js +1 -1
  79. package/dist/features/ai/ai-review.js +1 -1
  80. package/dist/features/ai/assistant.d.ts +4 -4
  81. package/dist/features/ai/assistant.js +1 -1
  82. package/dist/features/ai/assistant.js.map +1 -1
  83. package/dist/features/ai/components/AiSelectionMenu.js +1 -1
  84. package/dist/features/ai/components/AiSelectionMenu.js.map +1 -1
  85. package/dist/features/ai/components/ModelQuickSwitch.js +7 -7
  86. package/dist/features/ai/components/ModelQuickSwitch.js.map +1 -1
  87. package/dist/features/ai/components/ModelQuickSwitch.vue.d.ts +4 -4
  88. package/dist/features/ai/components/SettingsAiTab.js +8 -8
  89. package/dist/features/ai/components/SettingsAiTab.js.map +1 -1
  90. package/dist/features/ai/components/SettingsModelProfiles.js +1 -1
  91. package/dist/features/ai/components/SettingsModelProfiles.js.map +1 -1
  92. package/dist/features/ai/document-chat-model.d.ts +2 -2
  93. package/dist/features/ai/document-chat-model.js +5 -5
  94. package/dist/features/ai/document-chat-model.js.map +1 -1
  95. package/dist/features/ai/document-chat.js +2 -2
  96. package/dist/features/ai/document-chat.js.map +1 -1
  97. package/dist/features/ai/feature.d.ts +2 -2
  98. package/dist/features/ai/feature.js +2 -2
  99. package/dist/features/ai/feature.js.map +1 -1
  100. package/dist/features/ai/ghost-autocomplete.d.ts +4 -4
  101. package/dist/features/ai/ghost-autocomplete.js +1 -1
  102. package/dist/features/ai/ghost-autocomplete.js.map +1 -1
  103. package/dist/features/ai/index.d.ts +3 -3
  104. package/dist/features/ai/index.js +2 -2
  105. package/dist/features/ai/model-profiles.d.ts +9 -9
  106. package/dist/features/ai/model-profiles.js +13 -13
  107. package/dist/features/ai/model-profiles.js.map +1 -1
  108. package/dist/features/ai/protocol/agent-ops.d.ts +2 -2
  109. package/dist/features/ai/protocol/agent-ops.js +1 -1
  110. package/dist/features/ai/protocol/agent-ops.js.map +1 -1
  111. package/dist/features/ai/protocol/block-lines.d.ts +7 -7
  112. package/dist/features/ai/protocol/block-lines.js +10 -10
  113. package/dist/features/ai/protocol/block-lines.js.map +1 -1
  114. package/dist/features/ai/protocol/chat.d.ts +5 -5
  115. package/dist/features/ai/protocol/chat.js +12 -12
  116. package/dist/features/ai/protocol/chat.js.map +1 -1
  117. package/dist/features/ai/protocol/generate.d.ts +1 -1
  118. package/dist/features/ai/protocol/generate.js +1 -1
  119. package/dist/features/ai/protocol/generate.js.map +1 -1
  120. package/dist/features/ai/protocol/index.d.ts +3 -3
  121. package/dist/features/ai/protocol/index.js +2 -2
  122. package/dist/features/ai/protocol/models.d.ts +3 -3
  123. package/dist/features/ai/protocol/models.js +3 -3
  124. package/dist/features/ai/protocol/models.js.map +1 -1
  125. package/dist/features/ai/protocol/schemas.d.ts +1 -1
  126. package/dist/features/ai/protocol/schemas.js +1 -1
  127. package/dist/features/ai/protocol/schemas.js.map +1 -1
  128. package/dist/features/ai/protocol/tasks.d.ts +5 -5
  129. package/dist/features/ai/protocol/tasks.js +12 -12
  130. package/dist/features/ai/protocol/tasks.js.map +1 -1
  131. package/dist/features/ai/react/AiSelectionMenu.js.map +1 -1
  132. package/dist/features/ai/react/ModelQuickSwitch.d.ts +4 -4
  133. package/dist/features/ai/react/ModelQuickSwitch.js +6 -6
  134. package/dist/features/ai/react/ModelQuickSwitch.js.map +1 -1
  135. package/dist/features/ai/react/SettingsAiTab.d.ts +1 -1
  136. package/dist/features/ai/react/SettingsAiTab.js +8 -8
  137. package/dist/features/ai/react/SettingsAiTab.js.map +1 -1
  138. package/dist/features/ai/react/SettingsModelProfiles.d.ts +1 -1
  139. package/dist/features/ai/react/SettingsModelProfiles.js +1 -1
  140. package/dist/features/ai/react/SettingsModelProfiles.js.map +1 -1
  141. package/dist/features/ai/react/use-ai-assistant.d.ts +1 -1
  142. package/dist/features/ai/react/use-ai-assistant.js +1 -1
  143. package/dist/features/ai/react/use-ai-assistant.js.map +1 -1
  144. package/dist/features/ai/react/use-model-profiles.d.ts +5 -5
  145. package/dist/features/ai/react/use-model-profiles.js +2 -2
  146. package/dist/features/ai/react/use-model-profiles.js.map +1 -1
  147. package/dist/features/ai/use-ai-assistant.d.ts +1 -1
  148. package/dist/features/ai/use-ai-assistant.js +1 -1
  149. package/dist/features/ai/use-ai-assistant.js.map +1 -1
  150. package/dist/features/ai/use-model-profiles.d.ts +4 -4
  151. package/dist/features/ai/use-model-profiles.js +2 -2
  152. package/dist/features/ai/use-model-profiles.js.map +1 -1
  153. package/dist/features/block-ui/block-actions.d.ts +8 -4
  154. package/dist/features/block-ui/block-actions.js +38 -22
  155. package/dist/features/block-ui/block-actions.js.map +1 -1
  156. package/dist/features/block-ui/block-target.d.ts +29 -0
  157. package/dist/features/block-ui/block-target.js +63 -0
  158. package/dist/features/block-ui/block-target.js.map +1 -0
  159. package/dist/features/block-ui/components/BlockHandles.js +3 -3
  160. package/dist/features/block-ui/components/BlockHandles.js.map +1 -1
  161. package/dist/features/block-ui/components/BlockUi.js +11 -23
  162. package/dist/features/block-ui/components/BlockUi.js.map +1 -1
  163. package/dist/features/block-ui/feature.d.ts +3 -2
  164. package/dist/features/block-ui/feature.js +3 -2
  165. package/dist/features/block-ui/feature.js.map +1 -1
  166. package/dist/features/block-ui/handle-geometry.js +12 -23
  167. package/dist/features/block-ui/handle-geometry.js.map +1 -1
  168. package/dist/features/block-ui/index.d.ts +2 -1
  169. package/dist/features/block-ui/index.js +2 -1
  170. package/dist/features/block-ui/react/BlockHandles.d.ts +1 -1
  171. package/dist/features/block-ui/react/BlockHandles.js +4 -4
  172. package/dist/features/block-ui/react/BlockHandles.js.map +1 -1
  173. package/dist/features/block-ui/react/BlockUi.js +13 -25
  174. package/dist/features/block-ui/react/BlockUi.js.map +1 -1
  175. package/dist/features/comments/model.js +1 -1
  176. package/dist/features/composites/accepted-children.d.ts +5 -4
  177. package/dist/features/composites/accepted-children.js +26 -26
  178. package/dist/features/composites/accepted-children.js.map +1 -1
  179. package/dist/features/composites/ai-brief.d.ts +4 -4
  180. package/dist/features/composites/ai-brief.js +14 -12
  181. package/dist/features/composites/ai-brief.js.map +1 -1
  182. package/dist/features/composites/anchors.d.ts +1 -1
  183. package/dist/features/composites/anchors.js.map +1 -1
  184. package/dist/features/composites/baskets.d.ts +1 -1
  185. package/dist/features/composites/baskets.js.map +1 -1
  186. package/dist/features/composites/bibliography-command.d.ts +1 -1
  187. package/dist/features/composites/bibliography-form.js +1 -1
  188. package/dist/features/composites/bibliography-form.js.map +1 -1
  189. package/dist/features/composites/bibliography.js.map +1 -1
  190. package/dist/features/composites/block-types-json.d.ts +38 -0
  191. package/dist/features/composites/block-types-json.js +122 -0
  192. package/dist/features/composites/block-types-json.js.map +1 -0
  193. package/dist/features/composites/block-types.d.ts +119 -0
  194. package/dist/features/composites/block-types.js +343 -0
  195. package/dist/features/composites/block-types.js.map +1 -0
  196. package/dist/features/composites/capabilities.js +109 -0
  197. package/dist/features/composites/capabilities.js.map +1 -0
  198. package/dist/features/composites/components/BibliographyEditor.js +5 -5
  199. package/dist/features/composites/components/BibliographyEditor.js.map +1 -1
  200. package/dist/features/composites/components/CompositeBasketMenu.js +2 -2
  201. package/dist/features/composites/components/CompositeBasketMenu.js.map +1 -1
  202. package/dist/features/composites/components/CompositeChrome.js +18 -8
  203. package/dist/features/composites/components/CompositeChrome.js.map +1 -1
  204. package/dist/features/composites/components/CompositeChrome.vue.d.ts +1 -1
  205. package/dist/features/composites/components/CompositeDetails.js +11 -10
  206. package/dist/features/composites/components/CompositeDetails.js.map +1 -1
  207. package/dist/features/composites/components/CompositeDetails.vue.d.ts +1 -1
  208. package/dist/features/composites/components/CompositeFieldEditor.js +7 -7
  209. package/dist/features/composites/components/CompositeFieldEditor.js.map +1 -1
  210. package/dist/features/composites/components/CompositeFieldEditor.vue.d.ts +5 -5
  211. package/dist/features/composites/components/CompositeInspector.js +136 -113
  212. package/dist/features/composites/components/CompositeInspector.js.map +1 -1
  213. package/dist/features/composites/components/CompositeInspector.vue.d.ts +3 -3
  214. package/dist/features/composites/components/CompositeStatusMenu.js +2 -2
  215. package/dist/features/composites/components/CompositeStatusMenu.js.map +1 -1
  216. package/dist/features/composites/components/CompositeSummaryEditor.js +1 -1
  217. package/dist/features/composites/components/CompositeSummaryEditor.js.map +1 -1
  218. package/dist/features/composites/components/CompositeSummaryEditor.vue.d.ts +1 -1
  219. package/dist/features/composites/components/CompositeTable.js +2 -2
  220. package/dist/features/composites/components/CompositeTable.js.map +1 -1
  221. package/dist/features/composites/components/CompositeTagsEditor.js +1 -1
  222. package/dist/features/composites/components/CompositeTagsEditor.js.map +1 -1
  223. package/dist/features/composites/components/CompositeTagsEditor.vue.d.ts +1 -1
  224. package/dist/features/composites/components/CompositeView.js +19 -17
  225. package/dist/features/composites/components/CompositeView.js.map +1 -1
  226. package/dist/features/composites/components/DerivationBadge.js +15 -6
  227. package/dist/features/composites/components/DerivationBadge.js.map +1 -1
  228. package/dist/features/composites/components/FocusChip.js +1 -1
  229. package/dist/features/composites/components/FocusChip.js.map +1 -1
  230. package/dist/features/composites/components/FocusChip.vue.d.ts +1 -1
  231. package/dist/features/composites/components/ReferenceFieldSelect.js +3 -3
  232. package/dist/features/composites/components/ReferenceFieldSelect.js.map +1 -1
  233. package/dist/features/composites/components/ReferenceView.js +1 -1
  234. package/dist/features/composites/components/ReferenceView.js.map +1 -1
  235. package/dist/features/composites/components/SettingsEditingTab.js +18 -18
  236. package/dist/features/composites/components/SettingsEditingTab.js.map +1 -1
  237. package/dist/features/composites/components/SettingsEditingTab.vue.d.ts +3 -3
  238. package/dist/features/composites/convert.d.ts +4 -4
  239. package/dist/features/composites/convert.js +27 -28
  240. package/dist/features/composites/convert.js.map +1 -1
  241. package/dist/features/composites/derived-chrome.js +34 -28
  242. package/dist/features/composites/derived-chrome.js.map +1 -1
  243. package/dist/features/composites/editing-settings-keys.js +6 -6
  244. package/dist/features/composites/editing-settings-keys.js.map +1 -1
  245. package/dist/features/composites/feature.d.ts +10 -10
  246. package/dist/features/composites/feature.js +58 -46
  247. package/dist/features/composites/feature.js.map +1 -1
  248. package/dist/features/composites/fences.d.ts +3 -3
  249. package/dist/features/composites/fences.js +18 -13
  250. package/dist/features/composites/fences.js.map +1 -1
  251. package/dist/features/composites/focus.d.ts +10 -10
  252. package/dist/features/composites/focus.js +11 -11
  253. package/dist/features/composites/focus.js.map +1 -1
  254. package/dist/features/composites/heading-composites.d.ts +5 -5
  255. package/dist/features/composites/heading-composites.js +13 -16
  256. package/dist/features/composites/heading-composites.js.map +1 -1
  257. package/dist/features/composites/index.d.ts +20 -18
  258. package/dist/features/composites/index.js +9 -7
  259. package/dist/features/composites/inspector-model.d.ts +45 -22
  260. package/dist/features/composites/inspector-model.js +53 -14
  261. package/dist/features/composites/inspector-model.js.map +1 -1
  262. package/dist/features/composites/legacy.d.ts +5 -4
  263. package/dist/features/composites/legacy.js +16 -23
  264. package/dist/features/composites/legacy.js.map +1 -1
  265. package/dist/features/composites/markdown-export.js +3 -3
  266. package/dist/features/composites/markdown-export.js.map +1 -1
  267. package/dist/features/composites/merge.d.ts +8 -8
  268. package/dist/features/composites/merge.js +23 -22
  269. package/dist/features/composites/merge.js.map +1 -1
  270. package/dist/features/composites/meta-display.js +5 -5
  271. package/dist/features/composites/meta-display.js.map +1 -1
  272. package/dist/features/composites/meta-keys.d.ts +5 -5
  273. package/dist/features/composites/meta-keys.js +8 -8
  274. package/dist/features/composites/meta-keys.js.map +1 -1
  275. package/dist/features/composites/node-views.d.ts +3 -3
  276. package/dist/features/composites/node-views.js +2 -2
  277. package/dist/features/composites/node-views.js.map +1 -1
  278. package/dist/features/composites/nodes.d.ts +13 -13
  279. package/dist/features/composites/nodes.js +100 -77
  280. package/dist/features/composites/nodes.js.map +1 -1
  281. package/dist/features/composites/outline.d.ts +15 -12
  282. package/dist/features/composites/outline.js +24 -21
  283. package/dist/features/composites/outline.js.map +1 -1
  284. package/dist/features/composites/properties.d.ts +51 -0
  285. package/dist/features/composites/properties.js +89 -0
  286. package/dist/features/composites/properties.js.map +1 -0
  287. package/dist/features/composites/react/BibliographyEditor.js +5 -5
  288. package/dist/features/composites/react/BibliographyEditor.js.map +1 -1
  289. package/dist/features/composites/react/CompositeBasketMenu.js +2 -2
  290. package/dist/features/composites/react/CompositeBasketMenu.js.map +1 -1
  291. package/dist/features/composites/react/CompositeChrome.d.ts +1 -1
  292. package/dist/features/composites/react/CompositeChrome.js +15 -6
  293. package/dist/features/composites/react/CompositeChrome.js.map +1 -1
  294. package/dist/features/composites/react/CompositeDetails.d.ts +1 -1
  295. package/dist/features/composites/react/CompositeDetails.js +11 -10
  296. package/dist/features/composites/react/CompositeDetails.js.map +1 -1
  297. package/dist/features/composites/react/CompositeFieldEditor.d.ts +5 -5
  298. package/dist/features/composites/react/CompositeFieldEditor.js +6 -6
  299. package/dist/features/composites/react/CompositeFieldEditor.js.map +1 -1
  300. package/dist/features/composites/react/CompositeInspector.d.ts +3 -3
  301. package/dist/features/composites/react/CompositeInspector.js +142 -128
  302. package/dist/features/composites/react/CompositeInspector.js.map +1 -1
  303. package/dist/features/composites/react/CompositeStatusMenu.js +2 -2
  304. package/dist/features/composites/react/CompositeStatusMenu.js.map +1 -1
  305. package/dist/features/composites/react/CompositeSummaryEditor.d.ts +1 -1
  306. package/dist/features/composites/react/CompositeSummaryEditor.js +1 -1
  307. package/dist/features/composites/react/CompositeSummaryEditor.js.map +1 -1
  308. package/dist/features/composites/react/CompositeTable.d.ts +1 -1
  309. package/dist/features/composites/react/CompositeTable.js +3 -3
  310. package/dist/features/composites/react/CompositeTable.js.map +1 -1
  311. package/dist/features/composites/react/CompositeTagsEditor.d.ts +1 -1
  312. package/dist/features/composites/react/CompositeTagsEditor.js +1 -1
  313. package/dist/features/composites/react/CompositeTagsEditor.js.map +1 -1
  314. package/dist/features/composites/react/CompositeView.js +17 -15
  315. package/dist/features/composites/react/CompositeView.js.map +1 -1
  316. package/dist/features/composites/react/DerivationBadge.js +13 -4
  317. package/dist/features/composites/react/DerivationBadge.js.map +1 -1
  318. package/dist/features/composites/react/FocusChip.d.ts +1 -1
  319. package/dist/features/composites/react/FocusChip.js +1 -1
  320. package/dist/features/composites/react/FocusChip.js.map +1 -1
  321. package/dist/features/composites/react/ReferenceFieldSelect.js +3 -3
  322. package/dist/features/composites/react/ReferenceFieldSelect.js.map +1 -1
  323. package/dist/features/composites/react/ReferenceView.d.ts +1 -1
  324. package/dist/features/composites/react/ReferenceView.js +1 -1
  325. package/dist/features/composites/react/ReferenceView.js.map +1 -1
  326. package/dist/features/composites/react/SettingsEditingTab.d.ts +4 -4
  327. package/dist/features/composites/react/SettingsEditingTab.js +20 -20
  328. package/dist/features/composites/react/SettingsEditingTab.js.map +1 -1
  329. package/dist/features/composites/react.js +1 -1
  330. package/dist/features/composites/react.js.map +1 -1
  331. package/dist/features/composites/reference-ai.js +1 -1
  332. package/dist/features/composites/reference-ai.js.map +1 -1
  333. package/dist/features/composites/reference-label.d.ts +3 -3
  334. package/dist/features/composites/reference-label.js +6 -6
  335. package/dist/features/composites/reference-label.js.map +1 -1
  336. package/dist/features/composites/reference-suggestion.d.ts +1 -1
  337. package/dist/features/composites/reference-suggestion.js +3 -3
  338. package/dist/features/composites/reference-suggestion.js.map +1 -1
  339. package/dist/features/composites/reference-text.d.ts +2 -2
  340. package/dist/features/composites/reference-text.js +4 -4
  341. package/dist/features/composites/reference-text.js.map +1 -1
  342. package/dist/features/composites/reference.d.ts +3 -3
  343. package/dist/features/composites/reference.js +1 -1
  344. package/dist/features/composites/reference.js.map +1 -1
  345. package/dist/features/composites/reveal-source.d.ts +3 -3
  346. package/dist/features/composites/reveal-source.js +6 -6
  347. package/dist/features/composites/reveal-source.js.map +1 -1
  348. package/dist/features/composites/rows-model.d.ts +2 -2
  349. package/dist/features/composites/rows-model.js +4 -3
  350. package/dist/features/composites/rows-model.js.map +1 -1
  351. package/dist/features/composites/rows.d.ts +16 -28
  352. package/dist/features/composites/rows.js +20 -54
  353. package/dist/features/composites/rows.js.map +1 -1
  354. package/dist/features/composites/schema.d.ts +12 -11
  355. package/dist/features/composites/schema.js +10 -9
  356. package/dist/features/composites/schema.js.map +1 -1
  357. package/dist/features/composites/source.d.ts +20 -0
  358. package/dist/features/composites/source.js +40 -0
  359. package/dist/features/composites/source.js.map +1 -0
  360. package/dist/features/composites/split.d.ts +11 -11
  361. package/dist/features/composites/split.js +20 -20
  362. package/dist/features/composites/split.js.map +1 -1
  363. package/dist/features/composites/structure-mode.js +3 -3
  364. package/dist/features/composites/structure-mode.js.map +1 -1
  365. package/dist/features/composites/table-model.js +2 -2
  366. package/dist/features/composites/table-model.js.map +1 -1
  367. package/dist/features/composites/use-composite-inspector.js +3 -1
  368. package/dist/features/composites/use-composite-inspector.js.map +1 -1
  369. package/dist/features/composites/use-composite-rows.d.ts +2 -2
  370. package/dist/features/composites/use-composite-rows.js.map +1 -1
  371. package/dist/features/composites/vue.js +1 -1
  372. package/dist/features/composites/vue.js.map +1 -1
  373. package/dist/features/image-studio/components/ImageStudioDialog.js +150 -87
  374. package/dist/features/image-studio/components/ImageStudioDialog.js.map +1 -1
  375. package/dist/features/image-studio/components/ImageStudioDialog.vue.d.ts +5 -1
  376. package/dist/features/image-studio/components/ImageStudioLibraryPanel.js +186 -0
  377. package/dist/features/image-studio/components/ImageStudioLibraryPanel.js.map +1 -0
  378. package/dist/features/image-studio/components/ImageStudioLibraryTile.js +134 -0
  379. package/dist/features/image-studio/components/ImageStudioLibraryTile.js.map +1 -0
  380. package/dist/features/image-studio/components/ImageStudioView.js.map +1 -1
  381. package/dist/features/image-studio/feature.d.ts +1 -1
  382. package/dist/features/image-studio/feature.js +1 -1
  383. package/dist/features/image-studio/feature.js.map +1 -1
  384. package/dist/features/image-studio/index.d.ts +3 -2
  385. package/dist/features/image-studio/index.js +2 -2
  386. package/dist/features/image-studio/library.d.ts +35 -0
  387. package/dist/features/image-studio/node-core.d.ts +3 -3
  388. package/dist/features/image-studio/node-core.js +1 -1
  389. package/dist/features/image-studio/node-core.js.map +1 -1
  390. package/dist/features/image-studio/node-store.d.ts +1 -1
  391. package/dist/features/image-studio/node-store.js +1 -1
  392. package/dist/features/image-studio/node-store.js.map +1 -1
  393. package/dist/features/image-studio/react/ImageStudioDialog.d.ts +1 -1
  394. package/dist/features/image-studio/react/ImageStudioDialog.js +46 -5
  395. package/dist/features/image-studio/react/ImageStudioDialog.js.map +1 -1
  396. package/dist/features/image-studio/react/ImageStudioLibraryPanel.js +141 -0
  397. package/dist/features/image-studio/react/ImageStudioLibraryPanel.js.map +1 -0
  398. package/dist/features/image-studio/react/ImageStudioLibraryTile.js +105 -0
  399. package/dist/features/image-studio/react/ImageStudioLibraryTile.js.map +1 -0
  400. package/dist/features/image-studio/react/ImageStudioView.js +1 -1
  401. package/dist/features/image-studio/react/ImageStudioView.js.map +1 -1
  402. package/dist/features/image-studio/react/store.d.ts +8 -3
  403. package/dist/features/image-studio/react/store.js.map +1 -1
  404. package/dist/features/image-studio/react.d.ts +4 -3
  405. package/dist/features/image-studio/react.js +3 -3
  406. package/dist/features/image-studio/react.js.map +1 -1
  407. package/dist/features/image-studio/schema.d.ts +1 -1
  408. package/dist/features/image-studio/schema.js +1 -1
  409. package/dist/features/image-studio/schema.js.map +1 -1
  410. package/dist/features/image-studio/state.d.ts +8 -3
  411. package/dist/features/image-studio/state.js +11 -3
  412. package/dist/features/image-studio/state.js.map +1 -1
  413. package/dist/features/image-studio/store.d.ts +8 -3
  414. package/dist/features/image-studio/vue.d.ts +4 -3
  415. package/dist/features/image-studio/vue.js +3 -3
  416. package/dist/features/image-studio/vue.js.map +1 -1
  417. package/dist/features/mentions/tag.js +2 -1
  418. package/dist/features/mentions/tag.js.map +1 -1
  419. package/dist/features/themes/components/SettingsAppearanceTab.js +1 -1
  420. package/dist/features/themes/components/SettingsAppearanceTab.js.map +1 -1
  421. package/dist/features/themes/feature.d.ts +1 -1
  422. package/dist/features/themes/feature.js.map +1 -1
  423. package/dist/features/themes/react/SettingsAppearanceTab.d.ts +1 -1
  424. package/dist/features/themes/react/SettingsAppearanceTab.js +1 -1
  425. package/dist/features/themes/react/SettingsAppearanceTab.js.map +1 -1
  426. package/dist/features/themes/theme-runtime.js +1 -1
  427. package/dist/features/themes/theme-runtime.js.map +1 -1
  428. package/dist/features/transcript/TranscriptSegmentView.js +1 -1
  429. package/dist/features/transcript/TranscriptSegmentView.js.map +1 -1
  430. package/dist/features/transcript/react/TranscriptSegmentView.js +1 -1
  431. package/dist/features/transcript/react/TranscriptSegmentView.js.map +1 -1
  432. package/dist/features/transcript/segment-node.js.map +1 -1
  433. package/dist/features/transfer/feature.js +1 -1
  434. package/dist/features/transfer/feature.js.map +1 -1
  435. package/dist/features/transfer/transforms.d.ts +4 -4
  436. package/dist/features/transfer/transforms.js +12 -12
  437. package/dist/features/transfer/transforms.js.map +1 -1
  438. package/dist/i18n/de/ai.js +4 -4
  439. package/dist/i18n/de/ai.js.map +1 -1
  440. package/dist/i18n/de/authors.js +1 -1
  441. package/dist/i18n/de/authors.js.map +1 -1
  442. package/dist/i18n/de/comments.js +1 -1
  443. package/dist/i18n/de/comments.js.map +1 -1
  444. package/dist/i18n/de/composites.js +62 -59
  445. package/dist/i18n/de/composites.js.map +1 -1
  446. package/dist/i18n/de/image-studio.js +11 -2
  447. package/dist/i18n/de/image-studio.js.map +1 -1
  448. package/dist/i18n/de/integrations.js +20 -20
  449. package/dist/i18n/de/integrations.js.map +1 -1
  450. package/dist/i18n/de/markdown.js +1 -1
  451. package/dist/i18n/de/markdown.js.map +1 -1
  452. package/dist/i18n/de/palette.js +1 -1
  453. package/dist/i18n/de/palette.js.map +1 -1
  454. package/dist/i18n/de/themes.js +3 -3
  455. package/dist/i18n/de/themes.js.map +1 -1
  456. package/dist/i18n/de/transfer.js +2 -2
  457. package/dist/i18n/de/transfer.js.map +1 -1
  458. package/dist/i18n/de/tree.js +6 -6
  459. package/dist/i18n/de/tree.js.map +1 -1
  460. package/dist/i18n/de.d.ts +110 -98
  461. package/dist/i18n/en/ai.js +2 -2
  462. package/dist/i18n/en/ai.js.map +1 -1
  463. package/dist/i18n/en/composites.js +64 -61
  464. package/dist/i18n/en/composites.js.map +1 -1
  465. package/dist/i18n/en/image-studio.js +9 -0
  466. package/dist/i18n/en/image-studio.js.map +1 -1
  467. package/dist/i18n/en/integrations.js +9 -9
  468. package/dist/i18n/en/integrations.js.map +1 -1
  469. package/dist/i18n/en/markdown.js +1 -1
  470. package/dist/i18n/en/markdown.js.map +1 -1
  471. package/dist/i18n/en/palette.js +1 -1
  472. package/dist/i18n/en/palette.js.map +1 -1
  473. package/dist/i18n/en/themes.js +4 -4
  474. package/dist/i18n/en/themes.js.map +1 -1
  475. package/dist/i18n/en/tree.js +5 -5
  476. package/dist/i18n/en/tree.js.map +1 -1
  477. package/dist/index.d.ts +4 -1
  478. package/dist/integrations/composite-ai/bibliography-fetch.d.ts +6 -6
  479. package/dist/integrations/composite-ai/bibliography-fetch.js +19 -19
  480. package/dist/integrations/composite-ai/bibliography-fetch.js.map +1 -1
  481. package/dist/integrations/composite-ai/composite-fill.d.ts +4 -4
  482. package/dist/integrations/composite-ai/composite-fill.js +5 -5
  483. package/dist/integrations/composite-ai/composite-fill.js.map +1 -1
  484. package/dist/integrations/composite-ai/composite-summary.d.ts +2 -2
  485. package/dist/integrations/composite-ai/composite-summary.js +5 -5
  486. package/dist/integrations/composite-ai/composite-summary.js.map +1 -1
  487. package/dist/integrations/composite-ai/derive.d.ts +17 -17
  488. package/dist/integrations/composite-ai/derive.js +27 -26
  489. package/dist/integrations/composite-ai/derive.js.map +1 -1
  490. package/dist/integrations/composite-ai/index.d.ts +14 -15
  491. package/dist/integrations/composite-ai/index.js +98 -77
  492. package/dist/integrations/composite-ai/index.js.map +1 -1
  493. package/dist/integrations/composite-ai/outline-sanitize.d.ts +1 -1
  494. package/dist/integrations/composite-ai/outline-sanitize.js +1 -1
  495. package/dist/integrations/composite-ai/outline-sanitize.js.map +1 -1
  496. package/dist/integrations/composite-ai/rendition.d.ts +9 -9
  497. package/dist/integrations/composite-ai/rendition.js +27 -27
  498. package/dist/integrations/composite-ai/rendition.js.map +1 -1
  499. package/dist/integrations/composite-ai/split.d.ts +8 -8
  500. package/dist/integrations/composite-ai/split.js +12 -12
  501. package/dist/integrations/composite-ai/split.js.map +1 -1
  502. package/dist/integrations/composite-ai/transfer-transforms.d.ts +2 -2
  503. package/dist/integrations/composite-ai/transfer-transforms.js +11 -11
  504. package/dist/integrations/composite-ai/transfer-transforms.js.map +1 -1
  505. package/dist/integrations/composite-media/index.d.ts +4 -3
  506. package/dist/integrations/composite-media/index.js +20 -14
  507. package/dist/integrations/composite-media/index.js.map +1 -1
  508. package/dist/markdown/MarkdownSurface.vue.d.ts +7 -7
  509. package/dist/markdown/document.js +1 -1
  510. package/dist/markdown/document.js.map +1 -1
  511. package/dist/nuxt/module.d.ts +48 -24
  512. package/dist/nuxt/module.js.map +1 -1
  513. package/dist/nuxt/runtime/server/plugins/editor-server.js +3 -2
  514. package/dist/nuxt/runtime/server/plugins/editor-server.js.map +1 -1
  515. package/dist/presets/compose.d.ts +6 -6
  516. package/dist/presets/compose.js +7 -4
  517. package/dist/presets/compose.js.map +1 -1
  518. package/dist/react/AdvancedEditor.d.ts +2 -2
  519. package/dist/react/AdvancedEditor.js +1 -1
  520. package/dist/react/AdvancedEditor.js.map +1 -1
  521. package/dist/react/compose.d.ts +1 -1
  522. package/dist/react/compose.js +1 -1
  523. package/dist/react/compose.js.map +1 -1
  524. package/dist/react/composed-surface.d.ts +5 -5
  525. package/dist/react/composed-surface.js +2 -2
  526. package/dist/react/composed-surface.js.map +1 -1
  527. package/dist/server/ai.d.ts +7 -7
  528. package/dist/server/ai.js +1 -1
  529. package/dist/server/ai.js.map +1 -1
  530. package/dist/server/auth.d.ts +1 -1
  531. package/dist/server/collab-state.d.ts +1 -1
  532. package/dist/server/collab-state.js.map +1 -1
  533. package/dist/server/collab.d.ts +4 -4
  534. package/dist/server/collab.js +22 -17
  535. package/dist/server/collab.js.map +1 -1
  536. package/dist/server/handlers/ai.d.ts +9 -6
  537. package/dist/server/handlers/ai.js +13 -17
  538. package/dist/server/handlers/ai.js.map +1 -1
  539. package/dist/server/handlers/context.d.ts +4 -0
  540. package/dist/server/handlers/context.js.map +1 -1
  541. package/dist/server/handlers/editor.d.ts +33 -32
  542. package/dist/server/handlers/editor.js +13 -8
  543. package/dist/server/handlers/editor.js.map +1 -1
  544. package/dist/server/handlers/images.d.ts +1 -1
  545. package/dist/server/handlers/images.js +1 -1
  546. package/dist/server/handlers/images.js.map +1 -1
  547. package/dist/server/host.d.ts +4 -0
  548. package/dist/server/host.js +10 -2
  549. package/dist/server/host.js.map +1 -1
  550. package/dist/server/index.d.ts +3 -3
  551. package/dist/server/ports.d.ts +8 -8
  552. package/dist/server/ports.js.map +1 -1
  553. package/dist/settings/index.d.ts +20 -19
  554. package/dist/settings/index.js +25 -24
  555. package/dist/settings/index.js.map +1 -1
  556. package/dist/settings/migrate.d.ts +18 -0
  557. package/dist/settings/migrate.js +46 -0
  558. package/dist/settings/migrate.js.map +1 -0
  559. package/dist/settings/values.d.ts +12 -12
  560. package/dist/settings/values.js +11 -11
  561. package/dist/settings/values.js.map +1 -1
  562. package/dist/styles/composites.css +10 -10
  563. package/dist/tree/DocumentTree.js +12 -5
  564. package/dist/tree/DocumentTree.js.map +1 -1
  565. package/dist/tree/drop-rules.js +5 -5
  566. package/dist/tree/drop-rules.js.map +1 -1
  567. package/dist/tree/react/DocumentTree.js +14 -5
  568. package/dist/tree/react/DocumentTree.js.map +1 -1
  569. package/dist/tree/tree-host.js +5 -5
  570. package/dist/tree/tree-host.js.map +1 -1
  571. package/dist/tree/tree-items.js +34 -28
  572. package/dist/tree/tree-items.js.map +1 -1
  573. package/dist/tree/tree-model.js +16 -16
  574. package/dist/tree/tree-model.js.map +1 -1
  575. package/dist/tree/tree-rows.js +2 -2
  576. package/dist/tree/tree-rows.js.map +1 -1
  577. package/dist/tree/tree-view-model.d.ts +2 -2
  578. package/dist/tree/tree-view-model.js.map +1 -1
  579. package/dist/vue/AdvancedEditor.js +2 -2
  580. package/dist/vue/AdvancedEditor.js.map +1 -1
  581. package/dist/vue/AdvancedEditor.vue.d.ts +10 -10
  582. package/dist/vue/SimpleEditor.vue.d.ts +4 -4
  583. package/dist/vue/components/EditorSurface.vue.d.ts +4 -4
  584. package/dist/vue/compose.d.ts +1 -1
  585. package/dist/vue/compose.js +1 -1
  586. package/dist/vue/compose.js.map +1 -1
  587. package/package.json +1 -1
  588. package/dist/features/composites/derivation.d.ts +0 -62
  589. package/dist/features/composites/derivation.js +0 -102
  590. package/dist/features/composites/derivation.js.map +0 -1
  591. package/dist/features/composites/kinds.d.ts +0 -89
  592. package/dist/features/composites/kinds.js +0 -285
  593. package/dist/features/composites/kinds.js.map +0 -1
@@ -0,0 +1,113 @@
1
+ import { ZodType } from "zod";
2
+ import { Editor } from "@tiptap/core";
3
+ import { Node as Node$1 } from "@tiptap/pm/model";
4
+ //#region src/core/capabilities.d.ts
5
+ /** One capability a Block type lists, with the config the capability's `configSchema` validates. Plain JSON. */
6
+ export interface BlockTypeCapability {
7
+ id: string;
8
+ config?: unknown;
9
+ }
10
+ /** What the capability registry knows of a Block type: its id and the capabilities it lists. The public `BlockType` extends it with presentation. */
11
+ export interface BlockTypeData {
12
+ id: string;
13
+ capabilities: readonly BlockTypeCapability[];
14
+ }
15
+ /** What a capability predicate may read besides the node. */
16
+ export interface CapabilityContext {
17
+ /** The id of the node's Block type: its persisted `attrs.blockType`; null for a node without one. */
18
+ blockTypeId: string | null;
19
+ /** The Block type of `node` among the editor's Block types; null for a node without one, an id no Block type defines, or an editor without Block types. */
20
+ blockTypeOf: (node: Node$1) => BlockTypeData | null;
21
+ /** The config the Block type of `node` gives `capability`; undefined when the type does not list it or lists it without config. */
22
+ configOf: <C = unknown>(node: Node$1, capability: string) => C | undefined;
23
+ }
24
+ /** The config `type` gives capability `id`; undefined when there is no `type` (`ctx.blockTypeOf(node)` found none), it does not list the capability or lists it without config. */
25
+ export declare const blockTypeConfigOf: <C = unknown>(type: BlockTypeData | null | undefined, id: string) => C | undefined;
26
+ /** Whether `type` lists capability `id`: the `appliesTo` of a capability a Block type opts into is `listsCapability(ctx.blockTypeOf(node), id)`. False without a `type`. */
27
+ export declare const listsCapability: (type: BlockTypeData | null | undefined, id: string) => boolean;
28
+ /**
29
+ * A descriptor a Feature declares through `EditorFeature.blockCapabilities`: whether a block has the capability, where its
30
+ * data lives and how to read it. It never installs schema, extensions, node views or settings; the Feature that owns the mechanism does.
31
+ */
32
+ export interface BlockCapability {
33
+ /** Unique across the preset (`container`, `title` are built in); a `BlockAction.requires` entry and a Block type's `capabilities` name it. */
34
+ id: string;
35
+ /**
36
+ * Whether `node` has the capability. The result is memoised per node type and Block type id (`capabilitiesOf`), so it may
37
+ * read only the node type (its spec and flags), `ctx.blockTypeId` and the Block type's config (`ctx.configOf`), never other
38
+ * attributes or the content; a capability that must read node attributes sets `perNode`.
39
+ */
40
+ appliesTo: (node: Node$1, ctx: CapabilityContext) => boolean;
41
+ /**
42
+ * `appliesTo` reads attributes of the node itself (`derived`: `meta.derivation` is present), so it runs for every node instead of
43
+ * once per node type and Block type id. Keep such predicates to a constant-time attribute check.
44
+ */
45
+ perNode?: boolean;
46
+ /** Validates the config a Block type gives the capability. Absent: the capability takes no config and a Block type may not give one. */
47
+ configSchema?: ZodType;
48
+ /**
49
+ * The current contents or value of the capability in `node` (the source media child, the basket id, the bibliography
50
+ * record); null when the block has none. Called only for blocks that have the capability; not memoised.
51
+ */
52
+ read?: (node: Node$1, ctx: CapabilityContext) => unknown;
53
+ /** Where the capability's data lives, so conversion, Markdown and copy can treat it uniformly. Descriptive only. */
54
+ storage?: {
55
+ /** Keys of the node's `meta` attribute. */
56
+ metaKeys?: readonly string[];
57
+ /** Node type names of the children that hold the data. */
58
+ childTypes?: readonly string[];
59
+ };
60
+ }
61
+ /** The structural capabilities every editor has, derived from existing node flags. A Feature may not declare these ids. */
62
+ export declare const BUILT_IN_BLOCK_CAPABILITIES: readonly BlockCapability[];
63
+ /** The merged capabilities of a preset: the declarations, shared by every editor created from it. */
64
+ export interface CapabilityRegistry {
65
+ /** Built-in capabilities first, then the Features' in feature order. */
66
+ readonly capabilities: readonly BlockCapability[];
67
+ has: (id: string) => boolean;
68
+ get: (id: string) => BlockCapability | undefined;
69
+ }
70
+ export declare function createCapabilityRegistry(capabilities: readonly BlockCapability[]): CapabilityRegistry;
71
+ /** The per-editor answer to "which capabilities does this block have". It depends on the editor's Block types, so it is not shared between editors. */
72
+ export interface CapabilityIndex {
73
+ readonly registry: CapabilityRegistry;
74
+ /** Ids of the capabilities `node` has; one predicate run per capability for each node type and Block type id, kept for the index's life. */
75
+ of: (node: Node$1) => ReadonlySet<string>;
76
+ /** `read` of capability `id` for `node`; null when the block lacks the capability or it has no value. */
77
+ read: <Data = unknown>(node: Node$1, id: string) => Data | null;
78
+ /** The config the Block type of `node` gives capability `id`; undefined when absent. */
79
+ configOf: <C = unknown>(node: Node$1, id: string) => C | undefined;
80
+ }
81
+ /** Id of the Block type of `node` (its `attrs.blockType`), or null. */
82
+ export declare const blockTypeIdOf: (node: Node$1) => string | null;
83
+ /** `blockTypes` is read at call time, so an editor whose Block types are set after the index exists sees them. */
84
+ export declare function createCapabilityIndex(registry: CapabilityRegistry, blockTypes?: () => readonly BlockTypeData[]): CapabilityIndex;
85
+ /** One problem in the capabilities a Block type lists. `path` is where in the capability's config it is (empty: the capability entry itself). */
86
+ export interface CapabilityIssue {
87
+ capability: string;
88
+ path: string;
89
+ message: string;
90
+ }
91
+ /**
92
+ * The problems of the capabilities `type` lists, none when it is valid: every capability is declared by a Feature (or built in),
93
+ * listed once, and its config passes the capability's `configSchema` (a capability without one takes no config). The one rule set
94
+ * behind `validateBlockTypes` (throws on the first) and `parseBlockTypes` (collects them for the whole file).
95
+ */
96
+ export declare function capabilityIssues(registry: CapabilityRegistry, type: BlockTypeData): CapabilityIssue[];
97
+ /**
98
+ * Checks the Block types against the registry: ids are unique and `capabilityIssues` finds nothing in any type. Throws
99
+ * naming the Block type and capability; `defineEditor` runs it for the Block types of the Features when an editor is created.
100
+ */
101
+ export declare function validateBlockTypes(registry: CapabilityRegistry, blockTypes: readonly BlockTypeData[]): void;
102
+ /** The capability index of `editor`: its preset's capabilities over its own Block types (the built-in capabilities and no Block types for an editor without a preset). */
103
+ export declare function capabilityIndexOf(editor: Editor): CapabilityIndex;
104
+ /** The capabilities `node` has in `editor`'s preset (memoised per node type and Block type id). */
105
+ export declare const capabilitiesOf: (editor: Editor, node: Node$1) => ReadonlySet<string>;
106
+ /** The contents or value capability `id` reads from `node` (`BlockCapability.read`); null when the block lacks the capability or holds nothing for it. */
107
+ export declare const capabilityDataOf: <Data = unknown>(editor: Editor, node: Node$1, id: string) => Data | null;
108
+ /** The config the Block type of `node` gives capability `id` in `editor`; undefined when the type does not list it or gives no config. */
109
+ export declare const capabilityConfigOf: <C = unknown>(editor: Editor, node: Node$1, id: string) => C | undefined;
110
+ /** The capabilities of the block at `pos` (the position right before it); empty when there is no node there (also outside the document). */
111
+ export declare function capabilitiesAt(editor: Editor, pos: number): ReadonlySet<string>;
112
+ //#endregion
113
+ //# sourceMappingURL=capabilities.d.ts.map
@@ -0,0 +1,155 @@
1
+ import { isBlockContainer } from "./schema/node-flags.js";
2
+ import { fail as fail$1, nodeAtPos, pathText } from "./util.js";
3
+ import { z } from "zod";
4
+ //#region src/core/capabilities.ts
5
+ const fail = (message) => fail$1(message, "blockTypes");
6
+ /** The config `type` gives capability `id`; undefined when there is no `type` (`ctx.blockTypeOf(node)` found none), it does not list the capability or lists it without config. */
7
+ const blockTypeConfigOf = (type, id) => type?.capabilities.find((entry) => entry.id === id)?.config;
8
+ /** Whether `type` lists capability `id`: the `appliesTo` of a capability a Block type opts into is `listsCapability(ctx.blockTypeOf(node), id)`. False without a `type`. */
9
+ const listsCapability = (type, id) => type?.capabilities.some((entry) => entry.id === id) ?? false;
10
+ /** The structural capabilities every editor has, derived from existing node flags. A Feature may not declare these ids. */
11
+ const BUILT_IN_BLOCK_CAPABILITIES = [{
12
+ id: "container",
13
+ appliesTo: (node) => isBlockContainer(node),
14
+ configSchema: z.strictObject({
15
+ accepts: z.union([z.literal("all"), z.array(z.string())]).optional(),
16
+ nestedAfterContent: z.boolean().optional(),
17
+ root: z.boolean().optional()
18
+ })
19
+ }, {
20
+ id: "title",
21
+ appliesTo: (node) => node.type.contentMatch.defaultType?.spec.editorChrome === true
22
+ }];
23
+ function createCapabilityRegistry(capabilities) {
24
+ const byId = new Map(capabilities.map((capability) => [capability.id, capability]));
25
+ return {
26
+ capabilities,
27
+ has: (id) => byId.has(id),
28
+ get: (id) => byId.get(id)
29
+ };
30
+ }
31
+ /** Id of the Block type of `node` (its `attrs.blockType`), or null. */
32
+ const blockTypeIdOf = (node) => typeof node.attrs.blockType === "string" ? node.attrs.blockType : null;
33
+ /** `blockTypes` is read at call time, so an editor whose Block types are set after the index exists sees them. */
34
+ function createCapabilityIndex(registry, blockTypes = () => []) {
35
+ const memo = /* @__PURE__ */ new WeakMap();
36
+ const perNode = registry.capabilities.filter((capability) => capability.perNode);
37
+ const contextOf = (node) => {
38
+ const blockTypeId = blockTypeIdOf(node);
39
+ const blockTypeOf = (target) => {
40
+ const id = blockTypeIdOf(target);
41
+ return id === null ? null : blockTypes().find((type) => type.id === id) ?? null;
42
+ };
43
+ return {
44
+ blockTypeId,
45
+ blockTypeOf,
46
+ configOf: (target, capability) => blockTypeConfigOf(blockTypeOf(target), capability)
47
+ };
48
+ };
49
+ const of = (node) => {
50
+ let byBlockType = memo.get(node.type);
51
+ if (!byBlockType) memo.set(node.type, byBlockType = /* @__PURE__ */ new Map());
52
+ const blockTypeId = blockTypeIdOf(node);
53
+ let found = byBlockType.get(blockTypeId);
54
+ if (!found) {
55
+ const ctx = contextOf(node);
56
+ byBlockType.set(blockTypeId, found = new Set(registry.capabilities.filter((capability) => !capability.perNode && capability.appliesTo(node, ctx)).map((capability) => capability.id)));
57
+ }
58
+ if (!perNode.length) return found;
59
+ const ctx = contextOf(node);
60
+ const extra = perNode.filter((capability) => capability.appliesTo(node, ctx));
61
+ return extra.length ? /* @__PURE__ */ new Set([...found, ...extra.map((capability) => capability.id)]) : found;
62
+ };
63
+ return {
64
+ registry,
65
+ of,
66
+ read: (node, id) => {
67
+ if (!of(node).has(id)) return null;
68
+ return registry.get(id)?.read?.(node, contextOf(node)) ?? null;
69
+ },
70
+ configOf: (node, id) => contextOf(node).configOf(node, id)
71
+ };
72
+ }
73
+ /**
74
+ * The problems of the capabilities `type` lists, none when it is valid: every capability is declared by a Feature (or built in),
75
+ * listed once, and its config passes the capability's `configSchema` (a capability without one takes no config). The one rule set
76
+ * behind `validateBlockTypes` (throws on the first) and `parseBlockTypes` (collects them for the whole file).
77
+ */
78
+ function capabilityIssues(registry, type) {
79
+ const issues = [];
80
+ const listed = /* @__PURE__ */ new Set();
81
+ for (const { id, config } of type.capabilities) {
82
+ const capability = registry.get(id);
83
+ if (!capability) {
84
+ issues.push({
85
+ capability: id,
86
+ path: "",
87
+ message: `unknown capability; no feature declares it (known: ${registry.capabilities.map((known) => known.id).join(", ")})`
88
+ });
89
+ continue;
90
+ }
91
+ if (listed.has(id)) {
92
+ issues.push({
93
+ capability: id,
94
+ path: "",
95
+ message: "listed twice"
96
+ });
97
+ continue;
98
+ }
99
+ listed.add(id);
100
+ if (!capability.configSchema) {
101
+ if (config !== void 0) issues.push({
102
+ capability: id,
103
+ path: "",
104
+ message: "the capability takes no config"
105
+ });
106
+ continue;
107
+ }
108
+ const checked = capability.configSchema.safeParse(config ?? {});
109
+ if (!checked.success) for (const issue of checked.error.issues) issues.push({
110
+ capability: id,
111
+ path: pathText(issue.path),
112
+ message: issue.message
113
+ });
114
+ }
115
+ return issues;
116
+ }
117
+ /**
118
+ * Checks the Block types against the registry: ids are unique and `capabilityIssues` finds nothing in any type. Throws
119
+ * naming the Block type and capability; `defineEditor` runs it for the Block types of the Features when an editor is created.
120
+ */
121
+ function validateBlockTypes(registry, blockTypes) {
122
+ const seen = /* @__PURE__ */ new Set();
123
+ for (const type of blockTypes) {
124
+ if (seen.has(type.id)) fail(`the Block type "${type.id}" is defined twice`);
125
+ seen.add(type.id);
126
+ const [issue] = capabilityIssues(registry, type);
127
+ if (issue) fail(`the Block type "${type.id}", capability "${issue.capability}"${issue.path ? `, config ${issue.path}` : ""}: ${issue.message}`);
128
+ }
129
+ }
130
+ const BUILT_IN_REGISTRY = createCapabilityRegistry(BUILT_IN_BLOCK_CAPABILITIES);
131
+ const INDEXES = /* @__PURE__ */ new WeakMap();
132
+ /** The capability index of `editor`: its preset's capabilities over its own Block types (the built-in capabilities and no Block types for an editor without a preset). */
133
+ function capabilityIndexOf(editor) {
134
+ let index = INDEXES.get(editor);
135
+ if (!index) {
136
+ const preset = editor.storage.editorPreset;
137
+ INDEXES.set(editor, index = createCapabilityIndex(preset?.capabilities ?? BUILT_IN_REGISTRY, () => preset?.blockTypes?.(editor) ?? []));
138
+ }
139
+ return index;
140
+ }
141
+ /** The capabilities `node` has in `editor`'s preset (memoised per node type and Block type id). */
142
+ const capabilitiesOf = (editor, node) => capabilityIndexOf(editor).of(node);
143
+ /** The contents or value capability `id` reads from `node` (`BlockCapability.read`); null when the block lacks the capability or holds nothing for it. */
144
+ const capabilityDataOf = (editor, node, id) => capabilityIndexOf(editor).read(node, id);
145
+ /** The config the Block type of `node` gives capability `id` in `editor`; undefined when the type does not list it or gives no config. */
146
+ const capabilityConfigOf = (editor, node, id) => capabilityIndexOf(editor).configOf(node, id);
147
+ /** The capabilities of the block at `pos` (the position right before it); empty when there is no node there (also outside the document). */
148
+ function capabilitiesAt(editor, pos) {
149
+ const node = nodeAtPos(editor.state.doc, pos);
150
+ return node ? capabilitiesOf(editor, node) : /* @__PURE__ */ new Set();
151
+ }
152
+ //#endregion
153
+ export { BUILT_IN_BLOCK_CAPABILITIES, blockTypeConfigOf, blockTypeIdOf, capabilitiesAt, capabilitiesOf, capabilityConfigOf, capabilityDataOf, capabilityIndexOf, capabilityIssues, createCapabilityIndex, createCapabilityRegistry, listsCapability, validateBlockTypes };
154
+
155
+ //# sourceMappingURL=capabilities.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"capabilities.js","names":["failWith"],"sources":["../../src/core/capabilities.ts"],"sourcesContent":["import type { Editor } from '@tiptap/core'\nimport type { Node as PMNode, NodeType } from '@tiptap/pm/model'\nimport { z, type ZodType } from 'zod'\nimport { isBlockContainer } from './schema/node-flags'\nimport { fail as failWith, nodeAtPos, pathText } from './util'\n// The `editorPreset` storage augmentation of `Storage`, read by `capabilityIndexOf`.\nimport type {} from './pipeline'\n\n// Framework-free and server-importable. A block capability describes what a block is (\"has a container body\", \"has\n// a title row\", \"may keep a source\"); an ability (`./schema/abilities`) says what the user may do. Capabilities describe,\n// abilities permit. A capability is type-level: \"this Block type supports X\". What a block actually holds (its source\n// child, its basket, its bibliography record) is Block contents or a Block property, read through `read`, never `appliesTo`.\n\nconst fail = (message: string): never => failWith(message, 'blockTypes')\n\n/** One capability a Block type lists, with the config the capability's `configSchema` validates. Plain JSON. */\nexport interface BlockTypeCapability {\n id: string\n config?: unknown\n}\n\n/** What the capability registry knows of a Block type: its id and the capabilities it lists. The public `BlockType` extends it with presentation. */\nexport interface BlockTypeData {\n id: string\n capabilities: readonly BlockTypeCapability[]\n}\n\n/** What a capability predicate may read besides the node. */\nexport interface CapabilityContext {\n /** The id of the node's Block type: its persisted `attrs.blockType`; null for a node without one. */\n blockTypeId: string | null\n /** The Block type of `node` among the editor's Block types; null for a node without one, an id no Block type defines, or an editor without Block types. */\n blockTypeOf: (node: PMNode) => BlockTypeData | null\n /** The config the Block type of `node` gives `capability`; undefined when the type does not list it or lists it without config. */\n configOf: <C = unknown>(node: PMNode, capability: string) => C | undefined\n}\n\n/** The config `type` gives capability `id`; undefined when there is no `type` (`ctx.blockTypeOf(node)` found none), it does not list the capability or lists it without config. */\nexport const blockTypeConfigOf = <C = unknown>(type: BlockTypeData | null | undefined, id: string): C | undefined =>\n type?.capabilities.find(entry => entry.id === id)?.config as C | undefined\n\n/** Whether `type` lists capability `id`: the `appliesTo` of a capability a Block type opts into is `listsCapability(ctx.blockTypeOf(node), id)`. False without a `type`. */\nexport const listsCapability = (type: BlockTypeData | null | undefined, id: string): boolean =>\n type?.capabilities.some(entry => entry.id === id) ?? false\n\n/**\n * A descriptor a Feature declares through `EditorFeature.blockCapabilities`: whether a block has the capability, where its\n * data lives and how to read it. It never installs schema, extensions, node views or settings; the Feature that owns the mechanism does.\n */\nexport interface BlockCapability {\n /** Unique across the preset (`container`, `title` are built in); a `BlockAction.requires` entry and a Block type's `capabilities` name it. */\n id: string\n /**\n * Whether `node` has the capability. The result is memoised per node type and Block type id (`capabilitiesOf`), so it may\n * read only the node type (its spec and flags), `ctx.blockTypeId` and the Block type's config (`ctx.configOf`), never other\n * attributes or the content; a capability that must read node attributes sets `perNode`.\n */\n appliesTo: (node: PMNode, ctx: CapabilityContext) => boolean\n /**\n * `appliesTo` reads attributes of the node itself (`derived`: `meta.derivation` is present), so it runs for every node instead of\n * once per node type and Block type id. Keep such predicates to a constant-time attribute check.\n */\n perNode?: boolean\n /** Validates the config a Block type gives the capability. Absent: the capability takes no config and a Block type may not give one. */\n configSchema?: ZodType\n /**\n * The current contents or value of the capability in `node` (the source media child, the basket id, the bibliography\n * record); null when the block has none. Called only for blocks that have the capability; not memoised.\n */\n read?: (node: PMNode, ctx: CapabilityContext) => unknown\n /** Where the capability's data lives, so conversion, Markdown and copy can treat it uniformly. Descriptive only. */\n storage?: {\n /** Keys of the node's `meta` attribute. */\n metaKeys?: readonly string[]\n /** Node type names of the children that hold the data. */\n childTypes?: readonly string[]\n }\n}\n\n/** The structural capabilities every editor has, derived from existing node flags. A Feature may not declare these ids. */\nexport const BUILT_IN_BLOCK_CAPABILITIES: readonly BlockCapability[] = [\n // `editorBlockContainer`: the node holds Blocks of its own (`doc`, a Typed block). Config `accepts`: the Block types it accepts as\n // nested Typed blocks; `nestedAfterContent`: nested Typed blocks follow the own content, also after a merge; `root`: the Block type\n // stands for the file of a document tree (the store's document rows), so the tree takes it as the root's kind.\n {\n id: 'container',\n appliesTo: node => isBlockContainer(node),\n configSchema: z.strictObject({ accepts: z.union([z.literal('all'), z.array(z.string())]).optional(), nestedAfterContent: z.boolean().optional(), root: z.boolean().optional() }),\n },\n // The node type's content starts with chrome (`editorChrome`): the title row of a Typed block. Read from the type, not\n // the content, so the memo per node type stays correct.\n { id: 'title', appliesTo: node => node.type.contentMatch.defaultType?.spec.editorChrome === true },\n]\n\n/** The merged capabilities of a preset: the declarations, shared by every editor created from it. */\nexport interface CapabilityRegistry {\n /** Built-in capabilities first, then the Features' in feature order. */\n readonly capabilities: readonly BlockCapability[]\n has: (id: string) => boolean\n get: (id: string) => BlockCapability | undefined\n}\n\nexport function createCapabilityRegistry(capabilities: readonly BlockCapability[]): CapabilityRegistry {\n const byId = new Map(capabilities.map(capability => [capability.id, capability]))\n return { capabilities, has: id => byId.has(id), get: id => byId.get(id) }\n}\n\n/** The per-editor answer to \"which capabilities does this block have\". It depends on the editor's Block types, so it is not shared between editors. */\nexport interface CapabilityIndex {\n readonly registry: CapabilityRegistry\n /** Ids of the capabilities `node` has; one predicate run per capability for each node type and Block type id, kept for the index's life. */\n of: (node: PMNode) => ReadonlySet<string>\n /** `read` of capability `id` for `node`; null when the block lacks the capability or it has no value. */\n read: <Data = unknown>(node: PMNode, id: string) => Data | null\n /** The config the Block type of `node` gives capability `id`; undefined when absent. */\n configOf: <C = unknown>(node: PMNode, id: string) => C | undefined\n}\n\n/** Id of the Block type of `node` (its `attrs.blockType`), or null. */\nexport const blockTypeIdOf = (node: PMNode): string | null => typeof node.attrs.blockType === 'string' ? node.attrs.blockType : null\n\n/** `blockTypes` is read at call time, so an editor whose Block types are set after the index exists sees them. */\nexport function createCapabilityIndex(registry: CapabilityRegistry, blockTypes: () => readonly BlockTypeData[] = () => []): CapabilityIndex {\n const memo = new WeakMap<NodeType, Map<string | null, ReadonlySet<string>>>()\n const perNode = registry.capabilities.filter(capability => capability.perNode)\n const contextOf = (node: PMNode): CapabilityContext => {\n const blockTypeId = blockTypeIdOf(node)\n const blockTypeOf = (target: PMNode): BlockTypeData | null => {\n const id = blockTypeIdOf(target)\n return id === null ? null : blockTypes().find(type => type.id === id) ?? null\n }\n return {\n blockTypeId,\n blockTypeOf,\n configOf: <C>(target: PMNode, capability: string) => blockTypeConfigOf<C>(blockTypeOf(target), capability),\n }\n }\n const of = (node: PMNode): ReadonlySet<string> => {\n let byBlockType = memo.get(node.type)\n if (!byBlockType) memo.set(node.type, byBlockType = new Map())\n const blockTypeId = blockTypeIdOf(node)\n let found = byBlockType.get(blockTypeId)\n if (!found) {\n const ctx = contextOf(node)\n byBlockType.set(blockTypeId, found = new Set(registry.capabilities.filter(capability => !capability.perNode && capability.appliesTo(node, ctx)).map(capability => capability.id)))\n }\n if (!perNode.length) return found\n const ctx = contextOf(node)\n const extra = perNode.filter(capability => capability.appliesTo(node, ctx))\n return extra.length ? new Set([...found, ...extra.map(capability => capability.id)]) : found\n }\n return {\n registry,\n of,\n read: <Data>(node: PMNode, id: string) => {\n if (!of(node).has(id)) return null\n return (registry.get(id)?.read?.(node, contextOf(node)) ?? null) as Data | null\n },\n configOf: <C>(node: PMNode, id: string) => contextOf(node).configOf<C>(node, id),\n }\n}\n\n/** One problem in the capabilities a Block type lists. `path` is where in the capability's config it is (empty: the capability entry itself). */\nexport interface CapabilityIssue {\n capability: string\n path: string\n message: string\n}\n\n// i18n-ignore-start: developer-facing errors of a Block type list\n/**\n * The problems of the capabilities `type` lists, none when it is valid: every capability is declared by a Feature (or built in),\n * listed once, and its config passes the capability's `configSchema` (a capability without one takes no config). The one rule set\n * behind `validateBlockTypes` (throws on the first) and `parseBlockTypes` (collects them for the whole file).\n */\nexport function capabilityIssues(registry: CapabilityRegistry, type: BlockTypeData): CapabilityIssue[] {\n const issues: CapabilityIssue[] = []\n const listed = new Set<string>()\n for (const { id, config } of type.capabilities) {\n const capability = registry.get(id)\n if (!capability) {\n issues.push({ capability: id, path: '', message: `unknown capability; no feature declares it (known: ${registry.capabilities.map(known => known.id).join(', ')})` })\n continue\n }\n if (listed.has(id)) {\n issues.push({ capability: id, path: '', message: 'listed twice' })\n continue\n }\n listed.add(id)\n if (!capability.configSchema) {\n if (config !== undefined) issues.push({ capability: id, path: '', message: 'the capability takes no config' })\n continue\n }\n const checked = capability.configSchema.safeParse(config ?? {})\n if (!checked.success) for (const issue of checked.error.issues) issues.push({ capability: id, path: pathText(issue.path), message: issue.message })\n }\n return issues\n}\n\n/**\n * Checks the Block types against the registry: ids are unique and `capabilityIssues` finds nothing in any type. Throws\n * naming the Block type and capability; `defineEditor` runs it for the Block types of the Features when an editor is created.\n */\nexport function validateBlockTypes(registry: CapabilityRegistry, blockTypes: readonly BlockTypeData[]): void {\n const seen = new Set<string>()\n for (const type of blockTypes) {\n if (seen.has(type.id)) fail(`the Block type \"${type.id}\" is defined twice`)\n seen.add(type.id)\n const [issue] = capabilityIssues(registry, type)\n if (issue) fail(`the Block type \"${type.id}\", capability \"${issue.capability}\"${issue.path ? `, config ${issue.path}` : ''}: ${issue.message}`)\n }\n}\n// i18n-ignore-end\n\nconst BUILT_IN_REGISTRY = createCapabilityRegistry(BUILT_IN_BLOCK_CAPABILITIES)\nconst INDEXES = new WeakMap<Editor, CapabilityIndex>()\n\n/** The capability index of `editor`: its preset's capabilities over its own Block types (the built-in capabilities and no Block types for an editor without a preset). */\nexport function capabilityIndexOf(editor: Editor): CapabilityIndex {\n let index = INDEXES.get(editor)\n if (!index) {\n const preset = editor.storage.editorPreset\n INDEXES.set(editor, index = createCapabilityIndex(preset?.capabilities ?? BUILT_IN_REGISTRY, () => preset?.blockTypes?.(editor) ?? []))\n }\n return index\n}\n\n/** The capabilities `node` has in `editor`'s preset (memoised per node type and Block type id). */\nexport const capabilitiesOf = (editor: Editor, node: PMNode): ReadonlySet<string> => capabilityIndexOf(editor).of(node)\n\n/** The contents or value capability `id` reads from `node` (`BlockCapability.read`); null when the block lacks the capability or holds nothing for it. */\nexport const capabilityDataOf = <Data = unknown>(editor: Editor, node: PMNode, id: string): Data | null => capabilityIndexOf(editor).read<Data>(node, id)\n\n/** The config the Block type of `node` gives capability `id` in `editor`; undefined when the type does not list it or gives no config. */\nexport const capabilityConfigOf = <C = unknown>(editor: Editor, node: PMNode, id: string): C | undefined => capabilityIndexOf(editor).configOf<C>(node, id)\n\n/** The capabilities of the block at `pos` (the position right before it); empty when there is no node there (also outside the document). */\nexport function capabilitiesAt(editor: Editor, pos: number): ReadonlySet<string> {\n const node = nodeAtPos(editor.state.doc, pos)\n return node ? capabilitiesOf(editor, node) : new Set()\n}\n"],"mappings":";;;;AAaA,MAAM,QAAQ,YAA2BA,OAAS,SAAS,YAAY;;AAyBvE,MAAa,qBAAkC,MAAwC,OACrF,MAAM,aAAa,MAAK,UAAS,MAAM,OAAO,EAAE,CAAC,EAAE;;AAGrD,MAAa,mBAAmB,MAAwC,OACtE,MAAM,aAAa,MAAK,UAAS,MAAM,OAAO,EAAE,KAAK;;AAqCvD,MAAa,8BAA0D,CAIrE;CACE,IAAI;CACJ,YAAW,SAAQ,iBAAiB,IAAI;CACxC,cAAc,EAAE,aAAa;EAAE,SAAS,EAAE,MAAM,CAAC,EAAE,QAAQ,KAAK,GAAG,EAAE,MAAM,EAAE,OAAO,CAAC,CAAC,CAAC,CAAC,CAAC,SAAS;EAAG,oBAAoB,EAAE,QAAQ,CAAC,CAAC,SAAS;EAAG,MAAM,EAAE,QAAQ,CAAC,CAAC,SAAS;CAAE,CAAC;AACjL,GAGA;CAAE,IAAI;CAAS,YAAW,SAAQ,KAAK,KAAK,aAAa,aAAa,KAAK,iBAAiB;AAAK,CACnG;AAUA,SAAgB,yBAAyB,cAA8D;CACrG,MAAM,OAAO,IAAI,IAAI,aAAa,KAAI,eAAc,CAAC,WAAW,IAAI,UAAU,CAAC,CAAC;CAChF,OAAO;EAAE;EAAc,MAAK,OAAM,KAAK,IAAI,EAAE;EAAG,MAAK,OAAM,KAAK,IAAI,EAAE;CAAE;AAC1E;;AAcA,MAAa,iBAAiB,SAAgC,OAAO,KAAK,MAAM,cAAc,WAAW,KAAK,MAAM,YAAY;;AAGhI,SAAgB,sBAAsB,UAA8B,mBAAmD,CAAC,GAAoB;CAC1I,MAAM,uBAAO,IAAI,QAA2D;CAC5E,MAAM,UAAU,SAAS,aAAa,QAAO,eAAc,WAAW,OAAO;CAC7E,MAAM,aAAa,SAAoC;EACrD,MAAM,cAAc,cAAc,IAAI;EACtC,MAAM,eAAe,WAAyC;GAC5D,MAAM,KAAK,cAAc,MAAM;GAC/B,OAAO,OAAO,OAAO,OAAO,WAAW,CAAC,CAAC,MAAK,SAAQ,KAAK,OAAO,EAAE,KAAK;EAC3E;EACA,OAAO;GACL;GACA;GACA,WAAc,QAAgB,eAAuB,kBAAqB,YAAY,MAAM,GAAG,UAAU;EAC3G;CACF;CACA,MAAM,MAAM,SAAsC;EAChD,IAAI,cAAc,KAAK,IAAI,KAAK,IAAI;EACpC,IAAI,CAAC,aAAa,KAAK,IAAI,KAAK,MAAM,8BAAc,IAAI,IAAI,CAAC;EAC7D,MAAM,cAAc,cAAc,IAAI;EACtC,IAAI,QAAQ,YAAY,IAAI,WAAW;EACvC,IAAI,CAAC,OAAO;GACV,MAAM,MAAM,UAAU,IAAI;GAC1B,YAAY,IAAI,aAAa,QAAQ,IAAI,IAAI,SAAS,aAAa,QAAO,eAAc,CAAC,WAAW,WAAW,WAAW,UAAU,MAAM,GAAG,CAAC,CAAC,CAAC,KAAI,eAAc,WAAW,EAAE,CAAC,CAAC;EACnL;EACA,IAAI,CAAC,QAAQ,QAAQ,OAAO;EAC5B,MAAM,MAAM,UAAU,IAAI;EAC1B,MAAM,QAAQ,QAAQ,QAAO,eAAc,WAAW,UAAU,MAAM,GAAG,CAAC;EAC1E,OAAO,MAAM,yBAAS,IAAI,IAAI,CAAC,GAAG,OAAO,GAAG,MAAM,KAAI,eAAc,WAAW,EAAE,CAAC,CAAC,IAAI;CACzF;CACA,OAAO;EACL;EACA;EACA,OAAa,MAAc,OAAe;GACxC,IAAI,CAAC,GAAG,IAAI,CAAC,CAAC,IAAI,EAAE,GAAG,OAAO;GAC9B,OAAQ,SAAS,IAAI,EAAE,CAAC,EAAE,OAAO,MAAM,UAAU,IAAI,CAAC,KAAK;EAC7D;EACA,WAAc,MAAc,OAAe,UAAU,IAAI,CAAC,CAAC,SAAY,MAAM,EAAE;CACjF;AACF;;;;;;AAeA,SAAgB,iBAAiB,UAA8B,MAAwC;CACrG,MAAM,SAA4B,CAAC;CACnC,MAAM,yBAAS,IAAI,IAAY;CAC/B,KAAK,MAAM,EAAE,IAAI,YAAY,KAAK,cAAc;EAC9C,MAAM,aAAa,SAAS,IAAI,EAAE;EAClC,IAAI,CAAC,YAAY;GACf,OAAO,KAAK;IAAE,YAAY;IAAI,MAAM;IAAI,SAAS,sDAAsD,SAAS,aAAa,KAAI,UAAS,MAAM,EAAE,CAAC,CAAC,KAAK,IAAI,EAAE;GAAG,CAAC;GACnK;EACF;EACA,IAAI,OAAO,IAAI,EAAE,GAAG;GAClB,OAAO,KAAK;IAAE,YAAY;IAAI,MAAM;IAAI,SAAS;GAAe,CAAC;GACjE;EACF;EACA,OAAO,IAAI,EAAE;EACb,IAAI,CAAC,WAAW,cAAc;GAC5B,IAAI,WAAW,KAAA,GAAW,OAAO,KAAK;IAAE,YAAY;IAAI,MAAM;IAAI,SAAS;GAAiC,CAAC;GAC7G;EACF;EACA,MAAM,UAAU,WAAW,aAAa,UAAU,UAAU,CAAC,CAAC;EAC9D,IAAI,CAAC,QAAQ,SAAS,KAAK,MAAM,SAAS,QAAQ,MAAM,QAAQ,OAAO,KAAK;GAAE,YAAY;GAAI,MAAM,SAAS,MAAM,IAAI;GAAG,SAAS,MAAM;EAAQ,CAAC;CACpJ;CACA,OAAO;AACT;;;;;AAMA,SAAgB,mBAAmB,UAA8B,YAA4C;CAC3G,MAAM,uBAAO,IAAI,IAAY;CAC7B,KAAK,MAAM,QAAQ,YAAY;EAC7B,IAAI,KAAK,IAAI,KAAK,EAAE,GAAG,KAAK,mBAAmB,KAAK,GAAG,mBAAmB;EAC1E,KAAK,IAAI,KAAK,EAAE;EAChB,MAAM,CAAC,SAAS,iBAAiB,UAAU,IAAI;EAC/C,IAAI,OAAO,KAAK,mBAAmB,KAAK,GAAG,iBAAiB,MAAM,WAAW,GAAG,MAAM,OAAO,YAAY,MAAM,SAAS,GAAG,IAAI,MAAM,SAAS;CAChJ;AACF;AAGA,MAAM,oBAAoB,yBAAyB,2BAA2B;AAC9E,MAAM,0BAAU,IAAI,QAAiC;;AAGrD,SAAgB,kBAAkB,QAAiC;CACjE,IAAI,QAAQ,QAAQ,IAAI,MAAM;CAC9B,IAAI,CAAC,OAAO;EACV,MAAM,SAAS,OAAO,QAAQ;EAC9B,QAAQ,IAAI,QAAQ,QAAQ,sBAAsB,QAAQ,gBAAgB,yBAAyB,QAAQ,aAAa,MAAM,KAAK,CAAC,CAAC,CAAC;CACxI;CACA,OAAO;AACT;;AAGA,MAAa,kBAAkB,QAAgB,SAAsC,kBAAkB,MAAM,CAAC,CAAC,GAAG,IAAI;;AAGtH,MAAa,oBAAoC,QAAgB,MAAc,OAA4B,kBAAkB,MAAM,CAAC,CAAC,KAAW,MAAM,EAAE;;AAGxJ,MAAa,sBAAmC,QAAgB,MAAc,OAA8B,kBAAkB,MAAM,CAAC,CAAC,SAAY,MAAM,EAAE;;AAG1J,SAAgB,eAAe,QAAgB,KAAkC;CAC/E,MAAM,OAAO,UAAU,OAAO,MAAM,KAAK,GAAG;CAC5C,OAAO,OAAO,eAAe,QAAQ,IAAI,oBAAI,IAAI,IAAI;AACvD"}
@@ -78,7 +78,7 @@ export interface PlacedToolbarGroup<C = unknown> extends ToolbarGroupDef {
78
78
  }
79
79
  /**
80
80
  * Checks whether `creates` may be inserted into the ancestor that `canCreateAt` found: `$parent.parent` is the node
81
- * that would receive it. Features contribute guards (`EditorFeature.insertGuards`), e.g. the accepted children of a Baustein.
81
+ * that would receive it. Features contribute guards (`EditorFeature.insertGuards`), e.g. the accepted children of a Typed block.
82
82
  */
83
83
  export type InsertGuard = (editor: Editor, $parent: ResolvedPos, creates: Creates) => boolean;
84
84
  /**
@@ -1 +1 @@
1
- {"version":3,"file":"context.js","names":[],"sources":["../../src/core/context.ts"],"sourcesContent":["import type { EditorPublicConfig } from '../config'\nimport { createTranslator, DEFAULT_LOCALE, type Locale, type Messages, type Translate } from '../i18n'\nimport { type EditorSettings, parseEditorSettings } from '../settings'\nimport { BackendError, type EditorBackend } from './backend'\nimport { createFetchBackend } from './http-backend'\nimport { type Notifier, silentNotifier } from './notify'\nimport { createStore, type ReadonlyStore, type Store } from './store'\n\nconst STORAGE_KEY = 'tiptap-editor:settings'\n/** Pause after the last change before the settings are sent to the server (ms). */\nconst PUT_DEBOUNCE = 500\n\n/** Inert public AI configuration (set by the Nuxt client plugin); only the AI feature reads it. Defined with the public config view. */\nexport type EditorAiConfig = EditorPublicConfig['ai']\n\nexport interface EditorContextOptions {\n /**\n * Where documents, uploads, mention lookups, settings, themes and AI come from (default: the HTTP routes of the Nuxt\n * module over the platform `fetch`, `createFetchBackend`). A backend that offers `settings` keeps the settings per\n * account (`backend.settings`); without it they stay in this browser.\n */\n backend?: EditorBackend\n ai?: EditorAiConfig\n /** Shows app-level notices (e.g. model profiles); default: dropped (`silentNotifier`). */\n notify?: Notifier\n /** Language of every string the editor renders (toolbar, slash menu, settings, AI, notices); default `'de'`. Fixed for the life of the context. */\n locale?: Locale\n /** Overrides of single messages by key (`{ 'toolbar.bold': 'Strong' }`); the rest comes from the catalog of `locale`. */\n messages?: Partial<Messages>\n}\n\n/** What `createEditorContext` returns: shared by all editors of an app. One per app: there is no process-global state. */\nexport interface EditorContext {\n settings: Store<EditorSettings>\n /** True once the stored settings are usable: immediately in local mode, after the server answered in remote mode. */\n ready: ReadonlyStore<boolean>\n /** True once the account's settings from the server are in effect (always false in local mode). */\n synced: ReadonlyStore<boolean>\n /**\n * Starts the account-settings load of remote mode (idempotent, no-op in local mode). The framework layers'\n * settings hooks call it, so the server is asked only once an editor-side component needs the settings (not on a\n * login page).\n */\n load: () => void\n backend: EditorBackend\n ai: EditorAiConfig | undefined\n /** Notices of app-level models; surfaces hand features their own `FeatureContext.notify`. */\n notify: Notifier\n /** The language of the editor's strings (`options.locale`, default `'de'`). */\n locale: Locale\n /** Renders a message of the catalog (with the host's `messages` applied): `t('toolbar.bold')`, `t('ai.run', { task })`. */\n t: Translate\n /** Stops the persistence (store subscription and pending server write); call when the app goes away. */\n dispose: () => void\n}\n\nfunction readLocal(): EditorSettings {\n try {\n // Also migrates the flat `{ headingConversionScope }` of the per-browser settings before version 1.\n return parseEditorSettings(JSON.parse(localStorage.getItem(STORAGE_KEY) ?? 'null'))\n }\n catch {\n // Unreadable or corrupt (or no) storage: the defaults.\n return parseEditorSettings(null)\n }\n}\n\nfunction writeLocal(settings: EditorSettings) {\n try {\n localStorage.setItem(STORAGE_KEY, JSON.stringify(settings))\n }\n catch {\n // Storage unavailable (e.g. privacy mode): the settings last for this session only.\n }\n}\n\n/**\n * The editor context of an app: the settings shared by all editors of the app, and the backend. Framework-free;\n * the Vue layer installs it with `app.use(createEditor())`, the React layer provides it through\n * `EditorContextProvider`. The settings are read from localStorage right away (client only) and every change is\n * written back. With a backend that offers `settings`, `backend.settings.load()` (on `load()`, which\n * the settings hooks call) answers: the user's account settings replace them (`synced`), `null` (the account has none\n * yet) makes the account take this browser's, a refusal (`401`, `501`) or a network error keeps the local ones; once\n * synced every change is also sent to the backend (`save`, debounced). Subscription and timer stop with `dispose()`.\n */\nexport function createEditorContext(options: EditorContextOptions = {}): EditorContext {\n const backend = options.backend ?? createFetchBackend()\n // `let`: a probing backend (`backend.ready`) may drop `settings` before the first load.\n let remoteStore = backend.settings\n const remoteMode = remoteStore !== undefined\n const settings = createStore<EditorSettings>(parseEditorSettings(null))\n const ready = createStore(!remoteMode && backend.ready === undefined)\n const synced = createStore(false)\n let loading = false\n let loadRemote = () => {}\n const load = () => {\n if (loading) return\n loading = true\n loadRemote()\n }\n let dispose = () => {}\n const locale = options.locale ?? DEFAULT_LOCALE\n const t = createTranslator(locale, options.messages)\n const context: EditorContext = { settings, ready, synced, load, backend, ai: options.ai, notify: options.notify ?? silentNotifier, locale, t, dispose: () => dispose() }\n // Local mode: ready once the backend knows its capabilities (remote mode: after the settings load, which waits for it).\n if (!remoteMode) void backend.ready?.then(() => ready.set(true))\n // No browser storage (server render): defaults, nothing to persist.\n if (!('window' in globalThis)) return context\n\n settings.set(readLocal())\n writeLocal(settings.get())\n\n /** JSON of the settings the server holds, so values that came from it are not sent back. */\n let remote = ''\n let timer: ReturnType<typeof setTimeout> | undefined\n let active = true\n function push(value: EditorSettings) {\n clearTimeout(timer)\n timer = setTimeout(() => {\n const json = JSON.stringify(value)\n if (json === remote) return\n remoteStore?.save(value)\n .then(() => { remote = json })\n .catch((error: unknown) => {\n // 501/404: the host serves no settings (no `settings` port, so no route); nothing to report.\n if (!(error instanceof BackendError && (error.status === 501 || error.status === 404))) {\n console.warn(`tiptap-editor: ${t('settings.saveFailed')}`, error)\n }\n })\n }, PUT_DEBOUNCE)\n }\n\n const unsubscribe = settings.subscribe((value) => {\n writeLocal(value)\n if (synced.get()) push(value)\n })\n dispose = () => {\n active = false\n clearTimeout(timer)\n unsubscribe()\n }\n\n if (!remoteStore) return context\n loadRemote = () => Promise.resolve(backend.ready)\n .then(() => {\n remoteStore = backend.settings\n return remoteStore?.load()\n })\n .then((stored) => {\n // The probe dropped `settings` (the server keeps none): the account has no settings, the local ones stay.\n if (!active || !remoteStore) return\n synced.set(true)\n if (stored) {\n settings.set(parseEditorSettings(stored))\n remote = JSON.stringify(settings.get())\n }\n // The account has no settings yet: it takes this browser's.\n else push(settings.get())\n })\n .catch((error: unknown) => {\n // 501/404: the host serves no settings; the local ones stay and there is nothing to report.\n if (!(error instanceof BackendError && (error.status === 501 || error.status === 404))) {\n console.warn(`tiptap-editor: ${t('settings.loadFailed')}`, error)\n }\n })\n .finally(() => { ready.set(true) })\n return context\n}\n"],"mappings":";;;;;;;AAQA,MAAM,cAAc;;AAEpB,MAAM,eAAe;AA8CrB,SAAS,YAA4B;CACnC,IAAI;EAEF,OAAO,oBAAoB,KAAK,MAAM,aAAa,QAAQ,WAAW,KAAK,MAAM,CAAC;CACpF,QACM;EAEJ,OAAO,oBAAoB,IAAI;CACjC;AACF;AAEA,SAAS,WAAW,UAA0B;CAC5C,IAAI;EACF,aAAa,QAAQ,aAAa,KAAK,UAAU,QAAQ,CAAC;CAC5D,QACM,CAEN;AACF;;;;;;;;;;AAWA,SAAgB,oBAAoB,UAAgC,CAAC,GAAkB;CACrF,MAAM,UAAU,QAAQ,WAAW,mBAAmB;CAEtD,IAAI,cAAc,QAAQ;CAC1B,MAAM,aAAa,gBAAgB,KAAA;CACnC,MAAM,WAAW,YAA4B,oBAAoB,IAAI,CAAC;CACtE,MAAM,QAAQ,YAAY,CAAC,cAAc,QAAQ,UAAU,KAAA,CAAS;CACpE,MAAM,SAAS,YAAY,KAAK;CAChC,IAAI,UAAU;CACd,IAAI,mBAAmB,CAAC;CACxB,MAAM,aAAa;EACjB,IAAI,SAAS;EACb,UAAU;EACV,WAAW;CACb;CACA,IAAI,gBAAgB,CAAC;CACrB,MAAM,SAAS,QAAQ,UAAA;CACvB,MAAM,IAAI,iBAAiB,QAAQ,QAAQ,QAAQ;CACnD,MAAM,UAAyB;EAAE;EAAU;EAAO;EAAQ;EAAM;EAAS,IAAI,QAAQ;EAAI,QAAQ,QAAQ,UAAU;EAAgB;EAAQ;EAAG,eAAe,QAAQ;CAAE;CAEvK,IAAI,CAAC,YAAY,QAAa,OAAO,WAAW,MAAM,IAAI,IAAI,CAAC;CAE/D,IAAI,EAAE,YAAY,aAAa,OAAO;CAEtC,SAAS,IAAI,UAAU,CAAC;CACxB,WAAW,SAAS,IAAI,CAAC;;CAGzB,IAAI,SAAS;CACb,IAAI;CACJ,IAAI,SAAS;CACb,SAAS,KAAK,OAAuB;EACnC,aAAa,KAAK;EAClB,QAAQ,iBAAiB;GACvB,MAAM,OAAO,KAAK,UAAU,KAAK;GACjC,IAAI,SAAS,QAAQ;GACrB,aAAa,KAAK,KAAK,CAAC,CACrB,WAAW;IAAE,SAAS;GAAK,CAAC,CAAC,CAC7B,OAAO,UAAmB;IAEzB,IAAI,EAAE,iBAAiB,iBAAiB,MAAM,WAAW,OAAO,MAAM,WAAW,OAC/E,QAAQ,KAAK,kBAAkB,EAAE,qBAAqB,KAAK,KAAK;GAEpE,CAAC;EACL,GAAG,YAAY;CACjB;CAEA,MAAM,cAAc,SAAS,WAAW,UAAU;EAChD,WAAW,KAAK;EAChB,IAAI,OAAO,IAAI,GAAG,KAAK,KAAK;CAC9B,CAAC;CACD,gBAAgB;EACd,SAAS;EACT,aAAa,KAAK;EAClB,YAAY;CACd;CAEA,IAAI,CAAC,aAAa,OAAO;CACzB,mBAAmB,QAAQ,QAAQ,QAAQ,KAAK,CAAC,CAC9C,WAAW;EACV,cAAc,QAAQ;EACtB,OAAO,aAAa,KAAK;CAC3B,CAAC,CAAC,CACD,MAAM,WAAW;EAEhB,IAAI,CAAC,UAAU,CAAC,aAAa;EAC7B,OAAO,IAAI,IAAI;EACf,IAAI,QAAQ;GACV,SAAS,IAAI,oBAAoB,MAAM,CAAC;GACxC,SAAS,KAAK,UAAU,SAAS,IAAI,CAAC;EACxC,OAEK,KAAK,SAAS,IAAI,CAAC;CAC1B,CAAC,CAAC,CACD,OAAO,UAAmB;EAEzB,IAAI,EAAE,iBAAiB,iBAAiB,MAAM,WAAW,OAAO,MAAM,WAAW,OAC/E,QAAQ,KAAK,kBAAkB,EAAE,qBAAqB,KAAK,KAAK;CAEpE,CAAC,CAAC,CACD,cAAc;EAAE,MAAM,IAAI,IAAI;CAAE,CAAC;CACpC,OAAO;AACT"}
1
+ {"version":3,"file":"context.js","names":[],"sources":["../../src/core/context.ts"],"sourcesContent":["import type { EditorPublicConfig } from '../config'\nimport { createTranslator, DEFAULT_LOCALE, type Locale, type Messages, type Translate } from '../i18n'\nimport { type EditorSettings, parseEditorSettings } from '../settings'\nimport { BackendError, type EditorBackend } from './backend'\nimport { createFetchBackend } from './http-backend'\nimport { type Notifier, silentNotifier } from './notify'\nimport { createStore, type ReadonlyStore, type Store } from './store'\n\nconst STORAGE_KEY = 'tiptap-editor:settings'\n/** Pause after the last change before the settings are sent to the server (ms). */\nconst PUT_DEBOUNCE = 500\n\n/** Inert public AI configuration (set by the Nuxt client plugin); only the AI feature reads it. Defined with the public config view. */\nexport type EditorAiConfig = EditorPublicConfig['ai']\n\nexport interface EditorContextOptions {\n /**\n * Where documents, uploads, mention lookups, settings, themes and AI come from (default: the HTTP routes of the Nuxt\n * module over the platform `fetch`, `createFetchBackend`). A backend that offers `settings` keeps the settings per\n * account (`backend.settings`); without it they stay in this browser.\n */\n backend?: EditorBackend\n ai?: EditorAiConfig\n /** Shows app-level notices (e.g. model profiles); default: dropped (`silentNotifier`). */\n notify?: Notifier\n /** Language of every string the editor renders (toolbar, slash menu, settings, AI, notices); default `'de'`. Fixed for the life of the context. */\n locale?: Locale\n /** Overrides of single messages by key (`{ 'toolbar.bold': 'Strong' }`); the rest comes from the catalog of `locale`. */\n messages?: Partial<Messages>\n}\n\n/** What `createEditorContext` returns: shared by all editors of an app. One per app: there is no process-global state. */\nexport interface EditorContext {\n settings: Store<EditorSettings>\n /** True once the stored settings are usable: immediately in local mode, after the server answered in remote mode. */\n ready: ReadonlyStore<boolean>\n /** True once the account's settings from the server are in effect (always false in local mode). */\n synced: ReadonlyStore<boolean>\n /**\n * Starts the account-settings load of remote mode (idempotent, no-op in local mode). The framework layers'\n * settings hooks call it, so the server is asked only once an editor-side component needs the settings (not on a\n * login page).\n */\n load: () => void\n backend: EditorBackend\n ai: EditorAiConfig | undefined\n /** Notices of app-level models; surfaces hand features their own `FeatureContext.notify`. */\n notify: Notifier\n /** The language of the editor's strings (`options.locale`, default `'de'`). */\n locale: Locale\n /** Renders a message of the catalog (with the host's `messages` applied): `t('toolbar.bold')`, `t('ai.run', { task })`. */\n t: Translate\n /** Stops the persistence (store subscription and pending server write); call when the app goes away. */\n dispose: () => void\n}\n\nfunction readLocal(): EditorSettings {\n try {\n // Also migrates the flat `{ headingConversionScope }` of the per-browser settings before version 1 and the key\n // names before version 2; `createEditorContext` writes the result back right away, so an older record is rewritten once.\n return parseEditorSettings(JSON.parse(localStorage.getItem(STORAGE_KEY) ?? 'null'))\n }\n catch {\n // Unreadable or corrupt (or no) storage: the defaults.\n return parseEditorSettings(null)\n }\n}\n\nfunction writeLocal(settings: EditorSettings) {\n try {\n localStorage.setItem(STORAGE_KEY, JSON.stringify(settings))\n }\n catch {\n // Storage unavailable (e.g. privacy mode): the settings last for this session only.\n }\n}\n\n/**\n * The editor context of an app: the settings shared by all editors of the app, and the backend. Framework-free;\n * the Vue layer installs it with `app.use(createEditor())`, the React layer provides it through\n * `EditorContextProvider`. The settings are read from localStorage right away (client only) and every change is\n * written back. With a backend that offers `settings`, `backend.settings.load()` (on `load()`, which\n * the settings hooks call) answers: the user's account settings replace them (`synced`), `null` (the account has none\n * yet) makes the account take this browser's, a refusal (`401`, `501`) or a network error keeps the local ones; once\n * synced every change is also sent to the backend (`save`, debounced). Subscription and timer stop with `dispose()`.\n */\nexport function createEditorContext(options: EditorContextOptions = {}): EditorContext {\n const backend = options.backend ?? createFetchBackend()\n // `let`: a probing backend (`backend.ready`) may drop `settings` before the first load.\n let remoteStore = backend.settings\n const remoteMode = remoteStore !== undefined\n const settings = createStore<EditorSettings>(parseEditorSettings(null))\n const ready = createStore(!remoteMode && backend.ready === undefined)\n const synced = createStore(false)\n let loading = false\n let loadRemote = () => {}\n const load = () => {\n if (loading) return\n loading = true\n loadRemote()\n }\n let dispose = () => {}\n const locale = options.locale ?? DEFAULT_LOCALE\n const t = createTranslator(locale, options.messages)\n const context: EditorContext = { settings, ready, synced, load, backend, ai: options.ai, notify: options.notify ?? silentNotifier, locale, t, dispose: () => dispose() }\n // Local mode: ready once the backend knows its capabilities (remote mode: after the settings load, which waits for it).\n if (!remoteMode) void backend.ready?.then(() => ready.set(true))\n // No browser storage (server render): defaults, nothing to persist.\n if (!('window' in globalThis)) return context\n\n settings.set(readLocal())\n writeLocal(settings.get())\n\n /** JSON of the settings the server holds, so values that came from it are not sent back. */\n let remote = ''\n let timer: ReturnType<typeof setTimeout> | undefined\n let active = true\n function push(value: EditorSettings) {\n clearTimeout(timer)\n timer = setTimeout(() => {\n const json = JSON.stringify(value)\n if (json === remote) return\n remoteStore?.save(value)\n .then(() => { remote = json })\n .catch((error: unknown) => {\n // 501/404: the host serves no settings (no `settings` port, so no route); nothing to report.\n if (!(error instanceof BackendError && (error.status === 501 || error.status === 404))) {\n console.warn(`tiptap-editor: ${t('settings.saveFailed')}`, error)\n }\n })\n }, PUT_DEBOUNCE)\n }\n\n const unsubscribe = settings.subscribe((value) => {\n writeLocal(value)\n if (synced.get()) push(value)\n })\n dispose = () => {\n active = false\n clearTimeout(timer)\n unsubscribe()\n }\n\n if (!remoteStore) return context\n loadRemote = () => Promise.resolve(backend.ready)\n .then(() => {\n remoteStore = backend.settings\n return remoteStore?.load()\n })\n .then((stored) => {\n // The probe dropped `settings` (the server keeps none): the account has no settings, the local ones stay.\n if (!active || !remoteStore) return\n synced.set(true)\n if (stored) {\n settings.set(parseEditorSettings(stored))\n remote = JSON.stringify(settings.get())\n }\n // The account has no settings yet: it takes this browser's.\n else push(settings.get())\n })\n .catch((error: unknown) => {\n // 501/404: the host serves no settings; the local ones stay and there is nothing to report.\n if (!(error instanceof BackendError && (error.status === 501 || error.status === 404))) {\n console.warn(`tiptap-editor: ${t('settings.loadFailed')}`, error)\n }\n })\n .finally(() => { ready.set(true) })\n return context\n}\n"],"mappings":";;;;;;;AAQA,MAAM,cAAc;;AAEpB,MAAM,eAAe;AA8CrB,SAAS,YAA4B;CACnC,IAAI;EAGF,OAAO,oBAAoB,KAAK,MAAM,aAAa,QAAQ,WAAW,KAAK,MAAM,CAAC;CACpF,QACM;EAEJ,OAAO,oBAAoB,IAAI;CACjC;AACF;AAEA,SAAS,WAAW,UAA0B;CAC5C,IAAI;EACF,aAAa,QAAQ,aAAa,KAAK,UAAU,QAAQ,CAAC;CAC5D,QACM,CAEN;AACF;;;;;;;;;;AAWA,SAAgB,oBAAoB,UAAgC,CAAC,GAAkB;CACrF,MAAM,UAAU,QAAQ,WAAW,mBAAmB;CAEtD,IAAI,cAAc,QAAQ;CAC1B,MAAM,aAAa,gBAAgB,KAAA;CACnC,MAAM,WAAW,YAA4B,oBAAoB,IAAI,CAAC;CACtE,MAAM,QAAQ,YAAY,CAAC,cAAc,QAAQ,UAAU,KAAA,CAAS;CACpE,MAAM,SAAS,YAAY,KAAK;CAChC,IAAI,UAAU;CACd,IAAI,mBAAmB,CAAC;CACxB,MAAM,aAAa;EACjB,IAAI,SAAS;EACb,UAAU;EACV,WAAW;CACb;CACA,IAAI,gBAAgB,CAAC;CACrB,MAAM,SAAS,QAAQ,UAAA;CACvB,MAAM,IAAI,iBAAiB,QAAQ,QAAQ,QAAQ;CACnD,MAAM,UAAyB;EAAE;EAAU;EAAO;EAAQ;EAAM;EAAS,IAAI,QAAQ;EAAI,QAAQ,QAAQ,UAAU;EAAgB;EAAQ;EAAG,eAAe,QAAQ;CAAE;CAEvK,IAAI,CAAC,YAAY,QAAa,OAAO,WAAW,MAAM,IAAI,IAAI,CAAC;CAE/D,IAAI,EAAE,YAAY,aAAa,OAAO;CAEtC,SAAS,IAAI,UAAU,CAAC;CACxB,WAAW,SAAS,IAAI,CAAC;;CAGzB,IAAI,SAAS;CACb,IAAI;CACJ,IAAI,SAAS;CACb,SAAS,KAAK,OAAuB;EACnC,aAAa,KAAK;EAClB,QAAQ,iBAAiB;GACvB,MAAM,OAAO,KAAK,UAAU,KAAK;GACjC,IAAI,SAAS,QAAQ;GACrB,aAAa,KAAK,KAAK,CAAC,CACrB,WAAW;IAAE,SAAS;GAAK,CAAC,CAAC,CAC7B,OAAO,UAAmB;IAEzB,IAAI,EAAE,iBAAiB,iBAAiB,MAAM,WAAW,OAAO,MAAM,WAAW,OAC/E,QAAQ,KAAK,kBAAkB,EAAE,qBAAqB,KAAK,KAAK;GAEpE,CAAC;EACL,GAAG,YAAY;CACjB;CAEA,MAAM,cAAc,SAAS,WAAW,UAAU;EAChD,WAAW,KAAK;EAChB,IAAI,OAAO,IAAI,GAAG,KAAK,KAAK;CAC9B,CAAC;CACD,gBAAgB;EACd,SAAS;EACT,aAAa,KAAK;EAClB,YAAY;CACd;CAEA,IAAI,CAAC,aAAa,OAAO;CACzB,mBAAmB,QAAQ,QAAQ,QAAQ,KAAK,CAAC,CAC9C,WAAW;EACV,cAAc,QAAQ;EACtB,OAAO,aAAa,KAAK;CAC3B,CAAC,CAAC,CACD,MAAM,WAAW;EAEhB,IAAI,CAAC,UAAU,CAAC,aAAa;EAC7B,OAAO,IAAI,IAAI;EACf,IAAI,QAAQ;GACV,SAAS,IAAI,oBAAoB,MAAM,CAAC;GACxC,SAAS,KAAK,UAAU,SAAS,IAAI,CAAC;EACxC,OAEK,KAAK,SAAS,IAAI,CAAC;CAC1B,CAAC,CAAC,CACD,OAAO,UAAmB;EAEzB,IAAI,EAAE,iBAAiB,iBAAiB,MAAM,WAAW,OAAO,MAAM,WAAW,OAC/E,QAAQ,KAAK,kBAAkB,EAAE,qBAAqB,KAAK,KAAK;CAEpE,CAAC,CAAC,CACD,cAAc;EAAE,MAAM,IAAI,IAAI;CAAE,CAAC;CACpC,OAAO;AACT"}
@@ -17,8 +17,8 @@ export type ConvertTarget = {
17
17
  } | {
18
18
  type: 'transcriptSegment';
19
19
  } | {
20
- type: 'composite';
21
- kind: string;
20
+ type: 'typedBlock';
21
+ blockType: string;
22
22
  } |
23
23
  /** A host block: `id` is both the target id and the node type name; `attrs` must match for the node to be the current target. */
24
24
  {
@@ -31,14 +31,14 @@ type CoreTarget = Extract<ConvertTarget, {
31
31
  }>;
32
32
  /** Ids of the targets of the core provider. */
33
33
  export declare const CORE_TARGET_IDS: readonly ["paragraph", "heading1", "heading2", "heading3", "bulletList", "orderedList", "blockquote", "codeBlock"];
34
- /** `'heading2'`, `'composite:task'`, a custom target's id, else the target's type. */
34
+ /** `'heading2'`, `'typedBlock:task'`, a custom target's id, else the target's type. */
35
35
  export declare function convertTargetId(target: ConvertTarget): string;
36
36
  /** The target of a `CORE_TARGET_IDS` entry; null for anything else. */
37
37
  export declare function parseCoreTarget(id: string): CoreTarget | null;
38
38
  export declare const isCoreTarget: (target: ConvertTarget) => target is CoreTarget;
39
- /** `node` already is `target` (same heading level, same composite kind, same custom type and attrs). */
39
+ /** `node` already is `target` (same heading level, same Block type, same custom type and attrs). */
40
40
  export declare function isCurrentTarget(node: Node, target: ConvertTarget): boolean;
41
- /** A textblock of the document body (not a block's chrome such as a composite title). */
41
+ /** A textblock of the document body (not a block's chrome such as a Typed block's title). */
42
42
  export declare const isTextblockNode: (node: Node) => boolean;
43
43
  export declare const isListNode: (node: Node) => boolean;
44
44
  export declare const isQuoteNode: (node: Node) => boolean;
@@ -22,10 +22,10 @@ const CORE_TARGET_TYPES = {
22
22
  blockquote: true,
23
23
  codeBlock: true
24
24
  };
25
- /** `'heading2'`, `'composite:task'`, a custom target's id, else the target's type. */
25
+ /** `'heading2'`, `'typedBlock:task'`, a custom target's id, else the target's type. */
26
26
  function convertTargetId(target) {
27
27
  if (target.type === "heading") return `heading${target.level}`;
28
- if (target.type === "composite") return `composite:${target.kind}`;
28
+ if (target.type === "typedBlock") return `typedBlock:${target.blockType}`;
29
29
  if (target.type === "custom") return target.id;
30
30
  return target.type;
31
31
  }
@@ -40,12 +40,12 @@ function parseCoreTarget(id) {
40
40
  return { type: known };
41
41
  }
42
42
  const isCoreTarget = (target) => CORE_TARGET_TYPES[target.type] === true;
43
- /** `node` already is `target` (same heading level, same composite kind, same custom type and attrs). */
43
+ /** `node` already is `target` (same heading level, same Block type, same custom type and attrs). */
44
44
  function isCurrentTarget(node, target) {
45
45
  if (target.type === "custom") return node.type.name === target.id && Object.entries(target.attrs ?? {}).every(([key, value]) => node.attrs[key] === value);
46
46
  if (node.type.name !== target.type) return false;
47
47
  if (target.type === "heading") return node.attrs.level === target.level;
48
- if (target.type === "composite") return node.attrs.kind === target.kind;
48
+ if (target.type === "typedBlock") return node.attrs.blockType === target.blockType;
49
49
  return true;
50
50
  }
51
51
  const LISTS = {
@@ -53,7 +53,7 @@ const LISTS = {
53
53
  orderedList: true
54
54
  };
55
55
  const CODE_BLOCK = "codeBlock";
56
- /** A textblock of the document body (not a block's chrome such as a composite title). */
56
+ /** A textblock of the document body (not a block's chrome such as a Typed block's title). */
57
57
  const isTextblockNode = (node) => node.isTextblock && !isChromeNode(node);
58
58
  const isListNode = (node) => LISTS[node.type.name] === true;
59
59
  const isQuoteNode = (node) => node.type.name === "blockquote";
@@ -1 +1 @@
1
- {"version":3,"file":"convert.js","names":[],"sources":["../../src/core/convert.ts"],"sourcesContent":["import { getText, getTextSerializersFromSchema } from '@tiptap/core'\nimport { Fragment, type Node as PMNode, type Schema } from '@tiptap/pm/model'\nimport { BLOCK_ID_ATTR } from './schema/block-ids'\nimport { isBlockContainer, isChromeNode, isEditorBlock } from './schema/node-flags'\n\n// Vue-free and server-importable: the generic block conversion engine behind „Umwandeln in …“ and the toolbar. It\n// converts paragraphs, headings, code blocks, lists and quotes into each other. Features whose blocks take part\n// (composites, speaker segments) own those conversions as `ConversionProvider`s and reuse this engine for the shared\n// parts (see `ForeignBlocks`, `createConverter`, `finishConversion`).\n\n/** A block type blocks can be converted into. Inert: composite, speaker and custom targets are interpreted by their providers. */\nexport type ConvertTarget =\n | { type: 'paragraph' } | { type: 'heading', level: 1 | 2 | 3 | 4 | 5 | 6 } | { type: 'bulletList' } | { type: 'orderedList' }\n | { type: 'blockquote' } | { type: 'codeBlock' } | { type: 'transcriptSegment' } | { type: 'composite', kind: string }\n /** A host block: `id` is both the target id and the node type name; `attrs` must match for the node to be the current target. */\n | { type: 'custom', id: string, attrs?: Record<string, unknown> }\n\ntype CoreTarget = Extract<ConvertTarget, { type: 'paragraph' | 'heading' | 'bulletList' | 'orderedList' | 'blockquote' | 'codeBlock' }>\n\n/** Ids of the targets of the core provider. */\nexport const CORE_TARGET_IDS = ['paragraph', 'heading1', 'heading2', 'heading3', 'bulletList', 'orderedList', 'blockquote', 'codeBlock'] as const\n\nconst CORE_TARGET_TYPES: Record<string, true> = { paragraph: true, heading: true, bulletList: true, orderedList: true, blockquote: true, codeBlock: true }\n\n/** `'heading2'`, `'composite:task'`, a custom target's id, else the target's type. */\nexport function convertTargetId(target: ConvertTarget): string {\n if (target.type === 'heading') return `heading${target.level}`\n if (target.type === 'composite') return `composite:${target.kind}`\n if (target.type === 'custom') return target.id\n return target.type\n}\n\n/** The target of a `CORE_TARGET_IDS` entry; null for anything else. */\nexport function parseCoreTarget(id: string): CoreTarget | null {\n const known = CORE_TARGET_IDS.find(targetId => targetId === id)\n if (!known) return null\n if (known === 'heading1' || known === 'heading2' || known === 'heading3') return { type: 'heading', level: Number(known.slice(-1)) as 1 | 2 | 3 }\n return { type: known }\n}\n\nexport const isCoreTarget = (target: ConvertTarget): target is CoreTarget => CORE_TARGET_TYPES[target.type] === true\n\n/** `node` already is `target` (same heading level, same composite kind, same custom type and attrs). */\nexport function isCurrentTarget(node: PMNode, target: ConvertTarget): boolean {\n if (target.type === 'custom') return node.type.name === target.id && Object.entries(target.attrs ?? {}).every(([key, value]) => node.attrs[key] === value)\n if (node.type.name !== target.type) return false\n if (target.type === 'heading') return node.attrs.level === target.level\n if (target.type === 'composite') return node.attrs.kind === target.kind\n return true\n}\n\nconst LISTS: Record<string, true> = { bulletList: true, orderedList: true }\nconst CODE_BLOCK = 'codeBlock'\n\n/** A textblock of the document body (not a block's chrome such as a composite title). */\nexport const isTextblockNode = (node: PMNode) => node.isTextblock && !isChromeNode(node)\nexport const isListNode = (node: PMNode) => LISTS[node.type.name] === true\nexport const isQuoteNode = (node: PMNode) => node.type.name === 'blockquote'\n/** A host block holding blocks (a callout): an editor block that is no textblock, leaf, block container, list or quote. */\nexport const isWrapperBlock = (node: PMNode) =>\n isEditorBlock(node) && !node.isTextblock && !node.isLeaf && !isBlockContainer(node) && !isListNode(node) && !isQuoteNode(node)\n/** Blocks the core engine converts by itself. */\nexport const isCoreSource = (node: PMNode) => isTextblockNode(node) || isListNode(node) || isQuoteNode(node)\n\nexport function childrenOf(node: PMNode, from = 0): PMNode[] {\n const children: PMNode[] = []\n node.forEach((child, _offset, index) => {\n if (index >= from) children.push(child)\n })\n return children\n}\n\n/** Targets offered for `node` in menus: every core target its schema has except its current type; none for other blocks. */\nexport function coreConversionTargets(node: PMNode): ConvertTarget[] {\n if (!isCoreSource(node)) return []\n const targets: ConvertTarget[] = [\n { type: 'paragraph' }, { type: 'heading', level: 1 }, { type: 'heading', level: 2 }, { type: 'heading', level: 3 },\n { type: 'bulletList' }, { type: 'orderedList' }, { type: 'blockquote' }, { type: 'codeBlock' },\n ]\n const { nodes } = node.type.schema\n return targets.filter(target => nodes[target.type] && !isCurrentTarget(node, target))\n}\n\n/** A textblock type to retype blocks into; `variant` lists the attributes that tell variants of one type apart (a heading's level). */\nexport interface TextblockSpec {\n type: string\n attrs?: Record<string, unknown>\n variant?: readonly string[]\n}\n\n/** The spec of a textblock core target. */\nexport function textblockSpecOf(target: Extract<CoreTarget, { type: 'paragraph' | 'heading' | 'codeBlock' }>): TextblockSpec {\n return target.type === 'heading' ? { type: 'heading', attrs: { level: target.level }, variant: ['level'] } : { type: target.type }\n}\n\n/** Blocks of a feature (composites) that unwrap into plain blocks when converted into core targets. */\nexport interface ForeignBlocks {\n is: (node: PMNode) => boolean\n /**\n * `node` as plain blocks. `keepEmptyTitle`: keep an empty first block. `headingLevel`: the node becomes a heading of\n * that level, so nested foreign blocks become sub-headings.\n */\n unwrap: (node: PMNode, keepEmptyTitle: boolean, headingLevel?: number) => PMNode[]\n}\n\nexport interface Converter {\n /** Inline content of a textblock for a block of `type`: plain text for code blocks; elsewhere code lines become hard breaks. */\n inline: (node: PMNode, type: string) => Fragment\n /** `node` retyped to a textblock; keeps its own id. The node itself when it already is the target. */\n textblock: (node: PMNode, to: TextblockSpec) => PMNode\n toTextblocks: (nodes: PMNode[], to: TextblockSpec) => PMNode[]\n /** One list of `type` (`bulletList`, `orderedList`) with an item per textblock; lists contribute their items. */\n toList: (nodes: PMNode[], type: string) => PMNode[]\n toQuote: (nodes: PMNode[]) => PMNode[]\n}\n\n/** The conversion rules between textblocks, lists and quotes, over `schema`. Foreign blocks unwrap through `foreign`. */\nexport function createConverter(schema: Schema, foreign?: ForeignBlocks): Converter {\n const n = schema.nodes\n const paragraph = n.paragraph!\n const listItem = n.listItem!\n const textSerializers = getTextSerializersFromSchema(schema)\n const paragraphSpec: TextblockSpec = { type: 'paragraph' }\n\n function inline(node: PMNode, type: string): Fragment {\n if (type === CODE_BLOCK) {\n const text = getText(node, { textSerializers })\n return text ? Fragment.from(schema.text(text)) : Fragment.empty\n }\n const hardBreak = n.hardBreak\n if (node.type.name !== CODE_BLOCK || !hardBreak) return node.content\n const parts: PMNode[] = []\n node.textContent.split('\\n').forEach((line, index) => {\n if (index) parts.push(hardBreak.create())\n if (line) parts.push(schema.text(line))\n })\n return Fragment.from(parts)\n }\n\n function textblock(node: PMNode, to: TextblockSpec): PMNode {\n if (node.type.name === to.type && (to.variant ?? []).every(key => node.attrs[key] === to.attrs?.[key])) return node\n const attrs: Record<string, unknown> = { [BLOCK_ID_ATTR]: node.attrs[BLOCK_ID_ATTR] ?? null, ...to.attrs }\n return n[to.type]!.create(attrs, inline(node, to.type))\n }\n\n /** A list as textblocks: one per item from its first paragraph, nested lists depth-first, other item blocks as they are. */\n function flattenList(list: PMNode, to: TextblockSpec): PMNode[] {\n return childrenOf(list).flatMap(item => childrenOf(item).flatMap((child, index) => {\n if (isListNode(child)) return flattenList(child, to)\n return index === 0 && isTextblockNode(child) ? [textblock(child, to)] : [child]\n }))\n }\n\n /** Content of a quote or list made from `node`: textblocks as paragraphs, quotes and foreign blocks unwrapped. */\n function containerBlocks(node: PMNode): PMNode[] {\n if (isTextblockNode(node)) return [textblock(node, paragraphSpec)]\n if (isQuoteNode(node)) return childrenOf(node)\n if (foreign?.is(node)) return foreign.unwrap(node, false)\n return [node]\n }\n\n /** List items of `blocks`: one per textblock (as paragraph), the items of lists; other blocks join the item before them. */\n function listItems(blocks: PMNode[]): PMNode[] {\n const items: PMNode[] = []\n for (const block of blocks) {\n if (isTextblockNode(block)) items.push(listItem.create(null, textblock(block, paragraphSpec)))\n else if (isListNode(block)) items.push(...childrenOf(block))\n else {\n const last = items.pop()\n items.push(last ? last.copy(last.content.addToEnd(block)) : listItem.create(null, [paragraph.create(), block]))\n }\n }\n return items\n }\n\n function toTextblocks(nodes: PMNode[], to: TextblockSpec): PMNode[] {\n return nodes.flatMap((node) => {\n if (isTextblockNode(node)) return [textblock(node, to)]\n if (isListNode(node)) return flattenList(node, to)\n if (isQuoteNode(node)) return childrenOf(node).map(child => isTextblockNode(child) ? textblock(child, to) : child)\n const headingLevel = to.type === 'heading' ? Number(to.attrs?.level) : undefined\n const [title, ...rest] = foreign!.unwrap(node, true, headingLevel)\n return [textblock(title!, to), ...rest]\n })\n }\n\n return {\n inline,\n textblock,\n toTextblocks,\n toList: (nodes, type) => [n[type]!.create(null, listItems(nodes.flatMap(containerBlocks)))],\n toQuote: nodes => [n.blockquote!.create(null, nodes.flatMap(containerBlocks))],\n }\n}\n\n/** `node` without the id `id` anywhere in it (itself included); the same node when it does not carry it. */\nfunction withoutId(node: PMNode, id: string): PMNode {\n let found = node.attrs[BLOCK_ID_ATTR] === id\n if (!found) {\n node.descendants((child) => {\n if (child.attrs[BLOCK_ID_ATTR] === id) found = true\n return !found\n })\n }\n if (!found) return node\n const attrs = node.attrs[BLOCK_ID_ATTR] === id ? { ...node.attrs, [BLOCK_ID_ATTR]: null } : node.attrs\n return node.type.create(attrs, childrenOf(node).map(child => withoutId(child, id)), node.marks)\n}\n\n/** The first block takes `id` (the first input block's) and no other block keeps it; unchanged when there is no id. */\nfunction withFirstId(blocks: PMNode[], id: unknown): PMNode[] {\n const [head, ...rest] = blocks\n if (!head || typeof id !== 'string' || !id || !(BLOCK_ID_ATTR in head.attrs)) return blocks\n const own = withoutId(head, id)\n return [own.type.create({ ...own.attrs, [BLOCK_ID_ATTR]: id }, own.content, own.marks), ...rest.map(block => withoutId(block, id))]\n}\n\n/**\n * Finalizes a conversion of `nodes` into `output`: ids (the first output block takes the first input block's id,\n * blocks carried over keep theirs, new ones get none), then null when nothing changed or a block violates the schema.\n */\nexport function finishConversion(nodes: PMNode[], output: PMNode[]): PMNode[] | null {\n const result = withFirstId(output, nodes[0]?.attrs[BLOCK_ID_ATTR])\n if (Fragment.from(result).eq(Fragment.from(nodes))) return null\n try {\n for (const block of result) block.check()\n }\n catch {\n return null\n }\n return result\n}\n\n/**\n * Blocks `nodes` (siblings) converted to a core `target`: textblocks retype, lists flatten into one block per item,\n * quotes unwrap, textblocks wrap into one list item / paragraph each. Null when the target is not a core target, a node\n * is not a core source, nothing changes or the result does not fit the schema.\n */\nexport function convertCoreBlocks(schema: Schema, nodes: PMNode[], target: ConvertTarget): PMNode[] | null {\n const first = nodes[0]\n if (!first || !isCoreTarget(target) || !schema.nodes[target.type]) return null\n if (!nodes.every(isCoreSource)) return null\n if (nodes.length === 1 && isCurrentTarget(first, target)) return null\n const converter = createConverter(schema)\n let output: PMNode[]\n switch (target.type) {\n case 'bulletList':\n case 'orderedList':\n output = converter.toList(nodes, target.type)\n break\n case 'blockquote':\n output = converter.toQuote(nodes)\n break\n default:\n output = converter.toTextblocks(nodes, textblockSpecOf(target))\n }\n return finishConversion(nodes, output)\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"convert.js","names":[],"sources":["../../src/core/convert.ts"],"sourcesContent":["import { getText, getTextSerializersFromSchema } from '@tiptap/core'\nimport { Fragment, type Node as PMNode, type Schema } from '@tiptap/pm/model'\nimport { BLOCK_ID_ATTR } from './schema/block-ids'\nimport { isBlockContainer, isChromeNode, isEditorBlock } from './schema/node-flags'\n\n// Vue-free and server-importable: the generic block conversion engine behind „Umwandeln in …“ and the toolbar. It\n// converts paragraphs, headings, code blocks, lists and quotes into each other. Features whose blocks take part\n// (composites, speaker segments) own those conversions as `ConversionProvider`s and reuse this engine for the shared\n// parts (see `ForeignBlocks`, `createConverter`, `finishConversion`).\n\n/** A block type blocks can be converted into. Inert: composite, speaker and custom targets are interpreted by their providers. */\nexport type ConvertTarget =\n | { type: 'paragraph' } | { type: 'heading', level: 1 | 2 | 3 | 4 | 5 | 6 } | { type: 'bulletList' } | { type: 'orderedList' }\n | { type: 'blockquote' } | { type: 'codeBlock' } | { type: 'transcriptSegment' } | { type: 'typedBlock', blockType: string }\n /** A host block: `id` is both the target id and the node type name; `attrs` must match for the node to be the current target. */\n | { type: 'custom', id: string, attrs?: Record<string, unknown> }\n\ntype CoreTarget = Extract<ConvertTarget, { type: 'paragraph' | 'heading' | 'bulletList' | 'orderedList' | 'blockquote' | 'codeBlock' }>\n\n/** Ids of the targets of the core provider. */\nexport const CORE_TARGET_IDS = ['paragraph', 'heading1', 'heading2', 'heading3', 'bulletList', 'orderedList', 'blockquote', 'codeBlock'] as const\n\nconst CORE_TARGET_TYPES: Record<string, true> = { paragraph: true, heading: true, bulletList: true, orderedList: true, blockquote: true, codeBlock: true }\n\n/** `'heading2'`, `'typedBlock:task'`, a custom target's id, else the target's type. */\nexport function convertTargetId(target: ConvertTarget): string {\n if (target.type === 'heading') return `heading${target.level}`\n if (target.type === 'typedBlock') return `typedBlock:${target.blockType}`\n if (target.type === 'custom') return target.id\n return target.type\n}\n\n/** The target of a `CORE_TARGET_IDS` entry; null for anything else. */\nexport function parseCoreTarget(id: string): CoreTarget | null {\n const known = CORE_TARGET_IDS.find(targetId => targetId === id)\n if (!known) return null\n if (known === 'heading1' || known === 'heading2' || known === 'heading3') return { type: 'heading', level: Number(known.slice(-1)) as 1 | 2 | 3 }\n return { type: known }\n}\n\nexport const isCoreTarget = (target: ConvertTarget): target is CoreTarget => CORE_TARGET_TYPES[target.type] === true\n\n/** `node` already is `target` (same heading level, same Block type, same custom type and attrs). */\nexport function isCurrentTarget(node: PMNode, target: ConvertTarget): boolean {\n if (target.type === 'custom') return node.type.name === target.id && Object.entries(target.attrs ?? {}).every(([key, value]) => node.attrs[key] === value)\n if (node.type.name !== target.type) return false\n if (target.type === 'heading') return node.attrs.level === target.level\n if (target.type === 'typedBlock') return node.attrs.blockType === target.blockType\n return true\n}\n\nconst LISTS: Record<string, true> = { bulletList: true, orderedList: true }\nconst CODE_BLOCK = 'codeBlock'\n\n/** A textblock of the document body (not a block's chrome such as a Typed block's title). */\nexport const isTextblockNode = (node: PMNode) => node.isTextblock && !isChromeNode(node)\nexport const isListNode = (node: PMNode) => LISTS[node.type.name] === true\nexport const isQuoteNode = (node: PMNode) => node.type.name === 'blockquote'\n/** A host block holding blocks (a callout): an editor block that is no textblock, leaf, block container, list or quote. */\nexport const isWrapperBlock = (node: PMNode) =>\n isEditorBlock(node) && !node.isTextblock && !node.isLeaf && !isBlockContainer(node) && !isListNode(node) && !isQuoteNode(node)\n/** Blocks the core engine converts by itself. */\nexport const isCoreSource = (node: PMNode) => isTextblockNode(node) || isListNode(node) || isQuoteNode(node)\n\nexport function childrenOf(node: PMNode, from = 0): PMNode[] {\n const children: PMNode[] = []\n node.forEach((child, _offset, index) => {\n if (index >= from) children.push(child)\n })\n return children\n}\n\n/** Targets offered for `node` in menus: every core target its schema has except its current type; none for other blocks. */\nexport function coreConversionTargets(node: PMNode): ConvertTarget[] {\n if (!isCoreSource(node)) return []\n const targets: ConvertTarget[] = [\n { type: 'paragraph' }, { type: 'heading', level: 1 }, { type: 'heading', level: 2 }, { type: 'heading', level: 3 },\n { type: 'bulletList' }, { type: 'orderedList' }, { type: 'blockquote' }, { type: 'codeBlock' },\n ]\n const { nodes } = node.type.schema\n return targets.filter(target => nodes[target.type] && !isCurrentTarget(node, target))\n}\n\n/** A textblock type to retype blocks into; `variant` lists the attributes that tell variants of one type apart (a heading's level). */\nexport interface TextblockSpec {\n type: string\n attrs?: Record<string, unknown>\n variant?: readonly string[]\n}\n\n/** The spec of a textblock core target. */\nexport function textblockSpecOf(target: Extract<CoreTarget, { type: 'paragraph' | 'heading' | 'codeBlock' }>): TextblockSpec {\n return target.type === 'heading' ? { type: 'heading', attrs: { level: target.level }, variant: ['level'] } : { type: target.type }\n}\n\n/** Blocks of a feature (composites) that unwrap into plain blocks when converted into core targets. */\nexport interface ForeignBlocks {\n is: (node: PMNode) => boolean\n /**\n * `node` as plain blocks. `keepEmptyTitle`: keep an empty first block. `headingLevel`: the node becomes a heading of\n * that level, so nested foreign blocks become sub-headings.\n */\n unwrap: (node: PMNode, keepEmptyTitle: boolean, headingLevel?: number) => PMNode[]\n}\n\nexport interface Converter {\n /** Inline content of a textblock for a block of `type`: plain text for code blocks; elsewhere code lines become hard breaks. */\n inline: (node: PMNode, type: string) => Fragment\n /** `node` retyped to a textblock; keeps its own id. The node itself when it already is the target. */\n textblock: (node: PMNode, to: TextblockSpec) => PMNode\n toTextblocks: (nodes: PMNode[], to: TextblockSpec) => PMNode[]\n /** One list of `type` (`bulletList`, `orderedList`) with an item per textblock; lists contribute their items. */\n toList: (nodes: PMNode[], type: string) => PMNode[]\n toQuote: (nodes: PMNode[]) => PMNode[]\n}\n\n/** The conversion rules between textblocks, lists and quotes, over `schema`. Foreign blocks unwrap through `foreign`. */\nexport function createConverter(schema: Schema, foreign?: ForeignBlocks): Converter {\n const n = schema.nodes\n const paragraph = n.paragraph!\n const listItem = n.listItem!\n const textSerializers = getTextSerializersFromSchema(schema)\n const paragraphSpec: TextblockSpec = { type: 'paragraph' }\n\n function inline(node: PMNode, type: string): Fragment {\n if (type === CODE_BLOCK) {\n const text = getText(node, { textSerializers })\n return text ? Fragment.from(schema.text(text)) : Fragment.empty\n }\n const hardBreak = n.hardBreak\n if (node.type.name !== CODE_BLOCK || !hardBreak) return node.content\n const parts: PMNode[] = []\n node.textContent.split('\\n').forEach((line, index) => {\n if (index) parts.push(hardBreak.create())\n if (line) parts.push(schema.text(line))\n })\n return Fragment.from(parts)\n }\n\n function textblock(node: PMNode, to: TextblockSpec): PMNode {\n if (node.type.name === to.type && (to.variant ?? []).every(key => node.attrs[key] === to.attrs?.[key])) return node\n const attrs: Record<string, unknown> = { [BLOCK_ID_ATTR]: node.attrs[BLOCK_ID_ATTR] ?? null, ...to.attrs }\n return n[to.type]!.create(attrs, inline(node, to.type))\n }\n\n /** A list as textblocks: one per item from its first paragraph, nested lists depth-first, other item blocks as they are. */\n function flattenList(list: PMNode, to: TextblockSpec): PMNode[] {\n return childrenOf(list).flatMap(item => childrenOf(item).flatMap((child, index) => {\n if (isListNode(child)) return flattenList(child, to)\n return index === 0 && isTextblockNode(child) ? [textblock(child, to)] : [child]\n }))\n }\n\n /** Content of a quote or list made from `node`: textblocks as paragraphs, quotes and foreign blocks unwrapped. */\n function containerBlocks(node: PMNode): PMNode[] {\n if (isTextblockNode(node)) return [textblock(node, paragraphSpec)]\n if (isQuoteNode(node)) return childrenOf(node)\n if (foreign?.is(node)) return foreign.unwrap(node, false)\n return [node]\n }\n\n /** List items of `blocks`: one per textblock (as paragraph), the items of lists; other blocks join the item before them. */\n function listItems(blocks: PMNode[]): PMNode[] {\n const items: PMNode[] = []\n for (const block of blocks) {\n if (isTextblockNode(block)) items.push(listItem.create(null, textblock(block, paragraphSpec)))\n else if (isListNode(block)) items.push(...childrenOf(block))\n else {\n const last = items.pop()\n items.push(last ? last.copy(last.content.addToEnd(block)) : listItem.create(null, [paragraph.create(), block]))\n }\n }\n return items\n }\n\n function toTextblocks(nodes: PMNode[], to: TextblockSpec): PMNode[] {\n return nodes.flatMap((node) => {\n if (isTextblockNode(node)) return [textblock(node, to)]\n if (isListNode(node)) return flattenList(node, to)\n if (isQuoteNode(node)) return childrenOf(node).map(child => isTextblockNode(child) ? textblock(child, to) : child)\n const headingLevel = to.type === 'heading' ? Number(to.attrs?.level) : undefined\n const [title, ...rest] = foreign!.unwrap(node, true, headingLevel)\n return [textblock(title!, to), ...rest]\n })\n }\n\n return {\n inline,\n textblock,\n toTextblocks,\n toList: (nodes, type) => [n[type]!.create(null, listItems(nodes.flatMap(containerBlocks)))],\n toQuote: nodes => [n.blockquote!.create(null, nodes.flatMap(containerBlocks))],\n }\n}\n\n/** `node` without the id `id` anywhere in it (itself included); the same node when it does not carry it. */\nfunction withoutId(node: PMNode, id: string): PMNode {\n let found = node.attrs[BLOCK_ID_ATTR] === id\n if (!found) {\n node.descendants((child) => {\n if (child.attrs[BLOCK_ID_ATTR] === id) found = true\n return !found\n })\n }\n if (!found) return node\n const attrs = node.attrs[BLOCK_ID_ATTR] === id ? { ...node.attrs, [BLOCK_ID_ATTR]: null } : node.attrs\n return node.type.create(attrs, childrenOf(node).map(child => withoutId(child, id)), node.marks)\n}\n\n/** The first block takes `id` (the first input block's) and no other block keeps it; unchanged when there is no id. */\nfunction withFirstId(blocks: PMNode[], id: unknown): PMNode[] {\n const [head, ...rest] = blocks\n if (!head || typeof id !== 'string' || !id || !(BLOCK_ID_ATTR in head.attrs)) return blocks\n const own = withoutId(head, id)\n return [own.type.create({ ...own.attrs, [BLOCK_ID_ATTR]: id }, own.content, own.marks), ...rest.map(block => withoutId(block, id))]\n}\n\n/**\n * Finalizes a conversion of `nodes` into `output`: ids (the first output block takes the first input block's id,\n * blocks carried over keep theirs, new ones get none), then null when nothing changed or a block violates the schema.\n */\nexport function finishConversion(nodes: PMNode[], output: PMNode[]): PMNode[] | null {\n const result = withFirstId(output, nodes[0]?.attrs[BLOCK_ID_ATTR])\n if (Fragment.from(result).eq(Fragment.from(nodes))) return null\n try {\n for (const block of result) block.check()\n }\n catch {\n return null\n }\n return result\n}\n\n/**\n * Blocks `nodes` (siblings) converted to a core `target`: textblocks retype, lists flatten into one block per item,\n * quotes unwrap, textblocks wrap into one list item / paragraph each. Null when the target is not a core target, a node\n * is not a core source, nothing changes or the result does not fit the schema.\n */\nexport function convertCoreBlocks(schema: Schema, nodes: PMNode[], target: ConvertTarget): PMNode[] | null {\n const first = nodes[0]\n if (!first || !isCoreTarget(target) || !schema.nodes[target.type]) return null\n if (!nodes.every(isCoreSource)) return null\n if (nodes.length === 1 && isCurrentTarget(first, target)) return null\n const converter = createConverter(schema)\n let output: PMNode[]\n switch (target.type) {\n case 'bulletList':\n case 'orderedList':\n output = converter.toList(nodes, target.type)\n break\n case 'blockquote':\n output = converter.toQuote(nodes)\n break\n default:\n output = converter.toTextblocks(nodes, textblockSpecOf(target))\n }\n return finishConversion(nodes, output)\n}\n"],"mappings":"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"}
@@ -1,8 +1,8 @@
1
1
  import { ABILITY } from "./schema/abilities.js";
2
2
  import { Abilities } from "./abilities.js";
3
- import { Metadata } from "./metadata.js";
4
3
  import { BlockId } from "./schema/block-ids.js";
5
4
  import { NodeFlags } from "./schema/node-flags.js";
5
+ import { Metadata } from "./metadata.js";
6
6
  import { BlockConvert, convertMenuItems, coreConversions } from "./block-convert.js";
7
7
  import { BlockTransferStorage } from "./block-transfer.js";
8
8
  import { BlockFlash } from "./block-flash.js";
@@ -4,9 +4,9 @@ import { EditorFeature, EditorPreset, SettingsTab } from "./feature.js";
4
4
  /**
5
5
  * Validates `features` and resolves their pipeline and conversion providers. Keeps the given order; neither
6
6
  * deduplicates nor installs missing dependencies. Throws on duplicate ids, a `requires` entry that is not installed,
7
- * a toolbar group declared by two features (`toolbarGroups`) and a singleton hook (`parseMarkdown`, `segment`, `structure`, `wrapImport`, `migrateContent`, `anchorResolver`,
7
+ * a toolbar group declared by two features (`toolbarGroups`), a block capability declared twice or with a built-in id (`blockCapabilities`), a derive method declared twice, with neither `run` nor `menu` or requiring an undeclared capability (`deriveMethods`) and a singleton hook (`parseMarkdown`, `segment`, `structure`, `wrapImport`, `migrateContent`, `anchorResolver`,
8
8
  * `formatAiResult`) contributed twice. A command naming a toolbar group no feature declares needs the feature context
9
- * to build the commands: `toolbarOf` throws it. `normalize` hooks chain left to right. `aiContext` contributions merge (`kinds` and `blocks`
9
+ * to build the commands: `toolbarOf` throws it. `normalize` hooks chain left to right. `aiContext` contributions merge (`blockTypes` and `blocks`
10
10
  * concatenated in feature order, `structure` from one feature only); their conflicts surface when the merged `aiContext` reads the editor.
11
11
  * `aiBlockData` contributions are additive too: they run in parallel per block and their data concatenate in feature order.
12
12
  */