@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
@@ -2,7 +2,7 @@ import { Translate } from "../../i18n/index.js";
2
2
  import { Editor } from "@tiptap/core";
3
3
  import { Node as Node$1 } from "@tiptap/pm/model";
4
4
  //#region src/features/composites/outline.d.ts
5
- /** One Baustein of a document's outline. */
5
+ /** One Typed block of a document's outline. */
6
6
  export interface OutlineNode {
7
7
  /** Block ID, or `pos:<pos>` for a block without one yet; unique within the document. */
8
8
  key: string;
@@ -15,7 +15,7 @@ export interface OutlineNode {
15
15
  * text of its own body (`labelFromBody`), else the caller's `untitled`.
16
16
  */
17
17
  title: string;
18
- /** `title` is derived from the body, the Baustein itself has no title. */
18
+ /** `title` is derived from the body, the Typed block itself has no title. */
19
19
  labelFromBody: boolean;
20
20
  /** The composite has a description (the summary). */
21
21
  hasSummary: boolean;
@@ -23,16 +23,19 @@ export interface OutlineNode {
23
23
  basket: string | null;
24
24
  /** The title is hidden in the editor (`meta.titleHidden`). */
25
25
  titleHidden: boolean;
26
+ /** The Block is a Derived block whose original was deleted (the source-missing state of its Derivation). */
27
+ sourceMissing: boolean;
26
28
  children: OutlineNode[];
27
29
  }
28
30
  /**
29
31
  * The composites of `doc` as a tree (title, kind, summary flag). A composite without a title is labelled by its body
30
32
  * (`labelFromBody`: first heading, else the start of the first text; nested composites do not count) and only an empty
31
33
  * one gets `untitled` (the caller's translated „(ohne Titel)“). Composites of a kind in `hiddenKinds` are omitted and their visible descendants
32
- * take their place in the parent's list.
34
+ * take their place in the parent's list. With `capabilitiesOf` (the editor's block capabilities) a composite without the `basket` capability has no basket.
35
+ * `sourceMissing` marks a Derived block whose original is gone (`derivationOriginOf` against `documentId`, the open document).
33
36
  */
34
- export declare function compositeOutline(doc: Node$1, hiddenKinds: ReadonlySet<string>, untitled: string): OutlineNode[];
35
- /** Whether a block may move into a Baustein; `reason` is a short sentence for the UI (in the language of the `t` it was judged with) when it may not. */
37
+ export declare function compositeOutline(doc: Node$1, hiddenKinds: ReadonlySet<string>, untitled: string, capabilitiesOf?: (node: Node$1) => ReadonlySet<string>, documentId?: string | null): OutlineNode[];
38
+ /** Whether a block may move into a Typed block; `reason` is a short sentence for the UI (in the language of the `t` it was judged with) when it may not. */
36
39
  export type MoveVerdict = {
37
40
  ok: true;
38
41
  } | {
@@ -40,17 +43,17 @@ export type MoveVerdict = {
40
43
  reason: string;
41
44
  };
42
45
  /**
43
- * Whether block `id` may move into the Baustein `targetId` (`null` = the end of the document), with the reason when
44
- * not: a block is missing, the target is no Baustein, the target is the block itself or inside it, or the target's kind
45
- * does not accept the block's kind (`CompositeKind.accepts`). A block that is no Baustein may move into any Baustein,
46
- * unless it holds Bausteine of a refused kind; Bausteine nested inside a moved Baustein stay with it and are not
47
- * checked. Moving a block to the end of the Baustein it already sits in adds no nesting and is never refused for it.
46
+ * Whether block `id` may move into the Typed block `targetId` (`null` = the end of the document), with the reason when
47
+ * not: a block is missing, the target is no Typed block, the target is the block itself or inside it, or the target's Block type
48
+ * does not accept the block's Block type (`BlockType.accepts`). A block that is no Typed block may move into any Typed block,
49
+ * unless it holds Typed blocks of a refused Block type; Typed blocks nested inside a moved Typed block stay with it and are not
50
+ * checked. Moving a block to the end of the Typed block it already sits in adds no nesting and is never refused for it.
48
51
  */
49
52
  export declare function moveIntoVerdict(editor: Editor, id: string, targetId: string | null, t: Translate): MoveVerdict;
50
- /** Whether block `id` can move into the Baustein `targetId` (`null` = the end of the document); see `moveIntoVerdict`. */
53
+ /** Whether block `id` can move into the Typed block `targetId` (`null` = the end of the document); see `moveIntoVerdict`. */
51
54
  export declare function canMoveBlockInto(editor: Editor, id: string, targetId: string | null): boolean;
52
55
  /**
53
- * Moves block `id` to the end of the body of the Baustein `targetId` (`null` = the end of the document) in a single
56
+ * Moves block `id` to the end of the body of the Typed block `targetId` (`null` = the end of the document) in a single
54
57
  * transaction, i.e. one undo step. `false` when nothing moved: `moveIntoVerdict` refuses the move (or the editor
55
58
  * refused the transaction).
56
59
  */
@@ -1,7 +1,8 @@
1
1
  import { blockIdOf, findBlockById } from "../../core/schema/block-ids.js";
2
- import { kindAccepts } from "./kinds.js";
2
+ import { derivationOf, derivationOriginOf } from "../../core/derivation.js";
3
+ import { acceptsChild } from "./block-types.js";
3
4
  import { basketOf, titleHiddenOf } from "./baskets.js";
4
- import { compositeKindsOf } from "./nodes.js";
5
+ import { blockTypesOf } from "./nodes.js";
5
6
  import { nestingReason, outermostComposites } from "./accepted-children.js";
6
7
  //#region src/features/composites/outline.ts
7
8
  /** Longest label taken from a paragraph; longer text is cut and ends in an ellipsis. */
@@ -20,7 +21,7 @@ const clipLabel = (text) => {
20
21
  function scanBody(parent, from, found) {
21
22
  for (let i = from; i < parent.childCount && found.heading === null; i++) {
22
23
  const node = parent.child(i);
23
- if (node.type.name === "composite") continue;
24
+ if (node.type.name === "typedBlock") continue;
24
25
  if (node.isTextblock) {
25
26
  const text = node.textContent.trim();
26
27
  if (!text) continue;
@@ -42,14 +43,15 @@ function bodyLabel(composite) {
42
43
  * The composites of `doc` as a tree (title, kind, summary flag). A composite without a title is labelled by its body
43
44
  * (`labelFromBody`: first heading, else the start of the first text; nested composites do not count) and only an empty
44
45
  * one gets `untitled` (the caller's translated „(ohne Titel)“). Composites of a kind in `hiddenKinds` are omitted and their visible descendants
45
- * take their place in the parent's list.
46
+ * take their place in the parent's list. With `capabilitiesOf` (the editor's block capabilities) a composite without the `basket` capability has no basket.
47
+ * `sourceMissing` marks a Derived block whose original is gone (`derivationOriginOf` against `documentId`, the open document).
46
48
  */
47
- function compositeOutline(doc, hiddenKinds, untitled) {
49
+ function compositeOutline(doc, hiddenKinds, untitled, capabilitiesOf, documentId) {
48
50
  function collect(parent, start, into) {
49
51
  parent.forEach((node, offset) => {
50
52
  const pos = start + offset;
51
- if (node.type.name === "composite") {
52
- const kind = String(node.attrs.kind);
53
+ if (node.type.name === "typedBlock") {
54
+ const kind = String(node.attrs.blockType);
53
55
  const children = [];
54
56
  collect(node, pos + 1, children);
55
57
  if (hiddenKinds.has(kind)) {
@@ -67,8 +69,9 @@ function compositeOutline(doc, hiddenKinds, untitled) {
67
69
  title: ownTitle || derived || untitled,
68
70
  labelFromBody: derived !== null,
69
71
  hasSummary: (node.maybeChild(1)?.content.size ?? 0) > 0,
70
- basket: basketOf(node),
72
+ basket: capabilitiesOf && !capabilitiesOf(node).has("basket") ? null : basketOf(node),
71
73
  titleHidden: titleHiddenOf(node),
74
+ sourceMissing: derivationOf(node) !== null && derivationOriginOf(doc, pos, documentId)?.status === "missing",
72
75
  children
73
76
  });
74
77
  } else if (!node.isTextblock && !node.isLeaf) collect(node, pos + 1, into);
@@ -83,11 +86,11 @@ const refused = (reason) => ({
83
86
  reason
84
87
  });
85
88
  /**
86
- * Whether block `id` may move into the Baustein `targetId` (`null` = the end of the document), with the reason when
87
- * not: a block is missing, the target is no Baustein, the target is the block itself or inside it, or the target's kind
88
- * does not accept the block's kind (`CompositeKind.accepts`). A block that is no Baustein may move into any Baustein,
89
- * unless it holds Bausteine of a refused kind; Bausteine nested inside a moved Baustein stay with it and are not
90
- * checked. Moving a block to the end of the Baustein it already sits in adds no nesting and is never refused for it.
89
+ * Whether block `id` may move into the Typed block `targetId` (`null` = the end of the document), with the reason when
90
+ * not: a block is missing, the target is no Typed block, the target is the block itself or inside it, or the target's Block type
91
+ * does not accept the block's Block type (`BlockType.accepts`). A block that is no Typed block may move into any Typed block,
92
+ * unless it holds Typed blocks of a refused Block type; Typed blocks nested inside a moved Typed block stay with it and are not
93
+ * checked. Moving a block to the end of the Typed block it already sits in adds no nesting and is never refused for it.
91
94
  */
92
95
  function moveIntoVerdict(editor, id, targetId, t) {
93
96
  const { doc } = editor.state;
@@ -96,32 +99,32 @@ function moveIntoVerdict(editor, id, targetId, t) {
96
99
  if (targetId === null) return { ok: true };
97
100
  const target = findBlockById(doc, targetId);
98
101
  if (!target) return refused(t("composites.move.targetGone"));
99
- if (target.node.type.name !== "composite") return refused(t("composites.move.targetNotBlock"));
102
+ if (target.node.type.name !== "typedBlock") return refused(t("composites.move.targetNotBlock"));
100
103
  if (target.pos === block.pos) return refused(t("composites.move.intoSelf"));
101
104
  if (target.pos > block.pos && target.pos < block.pos + block.node.nodeSize) return refused(t("composites.move.intoOwn"));
102
105
  const $block = doc.resolve(block.pos);
103
106
  let parentPos = -1;
104
- for (let depth = $block.depth; depth > 0; depth--) if ($block.node(depth).type.name === "composite") {
107
+ for (let depth = $block.depth; depth > 0; depth--) if ($block.node(depth).type.name === "typedBlock") {
105
108
  parentPos = $block.before(depth);
106
109
  break;
107
110
  }
108
111
  if (parentPos === target.pos) return { ok: true };
109
- const kinds = compositeKindsOf(editor);
110
- const targetKind = String(target.node.attrs.kind);
112
+ const kinds = blockTypesOf(editor);
113
+ const targetKind = String(target.node.attrs.blockType);
111
114
  for (const child of outermostComposites(block.node)) {
112
- const childKind = String(child.attrs.kind);
113
- if (!kindAccepts(kinds, targetKind, childKind)) return refused(nestingReason(kinds, targetKind, childKind, t));
115
+ const childKind = String(child.attrs.blockType);
116
+ if (!acceptsChild(kinds, targetKind, childKind)) return refused(nestingReason(kinds, targetKind, childKind, t));
114
117
  }
115
118
  return { ok: true };
116
119
  }
117
120
  /** `canMoveBlockInto` reads only `ok`, so its verdict needs no text: the message keys stand in for the sentences. */
118
121
  const untranslated = (key) => key;
119
- /** Whether block `id` can move into the Baustein `targetId` (`null` = the end of the document); see `moveIntoVerdict`. */
122
+ /** Whether block `id` can move into the Typed block `targetId` (`null` = the end of the document); see `moveIntoVerdict`. */
120
123
  function canMoveBlockInto(editor, id, targetId) {
121
124
  return moveIntoVerdict(editor, id, targetId, untranslated).ok;
122
125
  }
123
126
  /**
124
- * Moves block `id` to the end of the body of the Baustein `targetId` (`null` = the end of the document) in a single
127
+ * Moves block `id` to the end of the body of the Typed block `targetId` (`null` = the end of the document) in a single
125
128
  * transaction, i.e. one undo step. `false` when nothing moved: `moveIntoVerdict` refuses the move (or the editor
126
129
  * refused the transaction).
127
130
  */
@@ -1 +1 @@
1
- {"version":3,"file":"outline.js","names":[],"sources":["../../../src/features/composites/outline.ts"],"sourcesContent":["import type { Editor } from '@tiptap/core'\nimport type { Node as PMNode } from '@tiptap/pm/model'\nimport { blockIdOf, findBlockById } from '../../core/schema'\nimport type { Translate } from '../../i18n'\nimport { nestingReason, outermostComposites } from './accepted-children'\nimport { basketOf, titleHiddenOf } from './baskets'\nimport { kindAccepts } from './kinds'\nimport { compositeKindsOf } from './nodes'\n\n/** One Baustein of a document's outline. */\nexport interface OutlineNode {\n /** Block ID, or `pos:<pos>` for a block without one yet; unique within the document. */\n key: string\n id: string | null\n /** Position of the composite in the document it was read from. */\n pos: number\n kind: string\n /**\n * The title; for a composite without one, the text of the first heading of its own body, else the start of the first\n * text of its own body (`labelFromBody`), else the caller's `untitled`.\n */\n title: string\n /** `title` is derived from the body, the Baustein itself has no title. */\n labelFromBody: boolean\n /** The composite has a description (the summary). */\n hasSummary: boolean\n /** Basket id (`meta.basket`), `null` without one. */\n basket: string | null\n /** The title is hidden in the editor (`meta.titleHidden`). */\n titleHidden: boolean\n children: OutlineNode[]\n}\n\n/** Longest label taken from a paragraph; longer text is cut and ends in an ellipsis. */\nconst BODY_LABEL_CHARS = 60\n\nconst clipLabel = (text: string) => {\n if (text.length <= BODY_LABEL_CHARS) return text\n let end = BODY_LABEL_CHARS\n const last = text.charCodeAt(end - 1)\n if (last >= 0xD800 && last <= 0xDBFF) end-- // do not cut a surrogate pair\n return `${text.slice(0, end).trimEnd()}…`\n}\n\n/**\n * Walks the blocks of a composite's own body (not the ones inside a nested composite) in order. The text of the first\n * heading ends the walk; `found.text` collects the first non-empty text block as the fallback.\n */\nfunction scanBody(parent: PMNode, from: number, found: { heading: string | null, text: string | null }): void {\n for (let i = from; i < parent.childCount && found.heading === null; i++) {\n const node = parent.child(i)\n if (node.type.name === 'composite') continue\n if (node.isTextblock) {\n const text = node.textContent.trim()\n if (!text) continue\n if (node.type.name === 'heading') found.heading = text\n else found.text ??= text.replace(/\\s+/g, ' ')\n }\n else if (!node.isLeaf) scanBody(node, 0, found)\n }\n}\n\n/** The label of a composite without a title: its first heading, else the start of its first text; `null` for an empty body. */\nfunction bodyLabel(composite: PMNode): string | null {\n const found = { heading: null as string | null, text: null as string | null }\n scanBody(composite, 3, found) // title, description and tags come first\n return found.heading ?? (found.text === null ? null : clipLabel(found.text))\n}\n\n/**\n * The composites of `doc` as a tree (title, kind, summary flag). A composite without a title is labelled by its body\n * (`labelFromBody`: first heading, else the start of the first text; nested composites do not count) and only an empty\n * one gets `untitled` (the caller's translated „(ohne Titel)“). Composites of a kind in `hiddenKinds` are omitted and their visible descendants\n * take their place in the parent's list.\n */\nexport function compositeOutline(doc: PMNode, hiddenKinds: ReadonlySet<string>, untitled: string): OutlineNode[] {\n function collect(parent: PMNode, start: number, into: OutlineNode[]) {\n parent.forEach((node, offset) => {\n const pos = start + offset\n if (node.type.name === 'composite') {\n const kind = String(node.attrs.kind)\n const children: OutlineNode[] = []\n collect(node, pos + 1, children)\n if (hiddenKinds.has(kind)) {\n into.push(...children)\n return\n }\n const id = blockIdOf(node)\n const ownTitle = node.firstChild?.textContent.trim() ?? ''\n const derived = ownTitle ? null : bodyLabel(node)\n into.push({\n key: id ?? `pos:${pos}`,\n id,\n pos,\n kind,\n title: ownTitle || derived || untitled,\n labelFromBody: derived !== null,\n hasSummary: (node.maybeChild(1)?.content.size ?? 0) > 0,\n basket: basketOf(node),\n titleHidden: titleHiddenOf(node),\n children,\n })\n }\n else if (!node.isTextblock && !node.isLeaf) {\n // Composites can sit in quotes or lists as well.\n collect(node, pos + 1, into)\n }\n })\n }\n const roots: OutlineNode[] = []\n collect(doc, 0, roots)\n return roots\n}\n\n/** Whether a block may move into a Baustein; `reason` is a short sentence for the UI (in the language of the `t` it was judged with) when it may not. */\nexport type MoveVerdict = { ok: true } | { ok: false, reason: string }\n\nconst refused = (reason: string): MoveVerdict => ({ ok: false, reason })\n\n/**\n * Whether block `id` may move into the Baustein `targetId` (`null` = the end of the document), with the reason when\n * not: a block is missing, the target is no Baustein, the target is the block itself or inside it, or the target's kind\n * does not accept the block's kind (`CompositeKind.accepts`). A block that is no Baustein may move into any Baustein,\n * unless it holds Bausteine of a refused kind; Bausteine nested inside a moved Baustein stay with it and are not\n * checked. Moving a block to the end of the Baustein it already sits in adds no nesting and is never refused for it.\n */\nexport function moveIntoVerdict(editor: Editor, id: string, targetId: string | null, t: Translate): MoveVerdict {\n const { doc } = editor.state\n const block = findBlockById(doc, id)\n if (!block) return refused(t('composites.move.blockGone'))\n if (targetId === null) return { ok: true }\n const target = findBlockById(doc, targetId)\n if (!target) return refused(t('composites.move.targetGone'))\n if (target.node.type.name !== 'composite') return refused(t('composites.move.targetNotBlock'))\n if (target.pos === block.pos) return refused(t('composites.move.intoSelf'))\n if (target.pos > block.pos && target.pos < block.pos + block.node.nodeSize) return refused(t('composites.move.intoOwn'))\n\n // The nearest Baustein around the block: when it is the target, the block only moves within it.\n const $block = doc.resolve(block.pos)\n let parentPos = -1\n for (let depth = $block.depth; depth > 0; depth--) {\n if ($block.node(depth).type.name === 'composite') {\n parentPos = $block.before(depth)\n break\n }\n }\n if (parentPos === target.pos) return { ok: true }\n\n const kinds = compositeKindsOf(editor)\n const targetKind = String(target.node.attrs.kind)\n for (const child of outermostComposites(block.node)) {\n const childKind = String(child.attrs.kind)\n if (!kindAccepts(kinds, targetKind, childKind)) return refused(nestingReason(kinds, targetKind, childKind, t))\n }\n return { ok: true }\n}\n\n/** `canMoveBlockInto` reads only `ok`, so its verdict needs no text: the message keys stand in for the sentences. */\nconst untranslated: Translate = key => key\n\n/** Whether block `id` can move into the Baustein `targetId` (`null` = the end of the document); see `moveIntoVerdict`. */\nexport function canMoveBlockInto(editor: Editor, id: string, targetId: string | null): boolean {\n return moveIntoVerdict(editor, id, targetId, untranslated).ok\n}\n\n/**\n * Moves block `id` to the end of the body of the Baustein `targetId` (`null` = the end of the document) in a single\n * transaction, i.e. one undo step. `false` when nothing moved: `moveIntoVerdict` refuses the move (or the editor\n * refused the transaction).\n */\nexport function moveBlockInto(editor: Editor, id: string, targetId: string | null): boolean {\n if (!canMoveBlockInto(editor, id, targetId)) return false\n const { doc, tr } = editor.state\n const block = findBlockById(doc, id)!\n const target = targetId === null ? null : findBlockById(doc, targetId)!\n // A composite's body is its last children, so its end is just before the composite's closing token.\n const insertPos = target ? target.pos + target.node.nodeSize - 1 : doc.content.size\n tr.delete(block.pos, block.pos + block.node.nodeSize)\n tr.insert(tr.mapping.map(insertPos), block.node)\n editor.view.dispatch(tr.scrollIntoView())\n return editor.state.doc !== doc\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"outline.js","names":[],"sources":["../../../src/features/composites/outline.ts"],"sourcesContent":["import type { Editor } from '@tiptap/core'\nimport type { Node as PMNode } from '@tiptap/pm/model'\nimport { derivationOf, derivationOriginOf } from '../../core/derivation'\nimport { blockIdOf, findBlockById } from '../../core/schema'\nimport type { Translate } from '../../i18n'\nimport { nestingReason, outermostComposites } from './accepted-children'\nimport { basketOf, titleHiddenOf } from './baskets'\nimport { acceptsChild } from './block-types'\nimport { blockTypesOf } from './nodes'\n\n/** One Typed block of a document's outline. */\nexport interface OutlineNode {\n /** Block ID, or `pos:<pos>` for a block without one yet; unique within the document. */\n key: string\n id: string | null\n /** Position of the composite in the document it was read from. */\n pos: number\n kind: string\n /**\n * The title; for a composite without one, the text of the first heading of its own body, else the start of the first\n * text of its own body (`labelFromBody`), else the caller's `untitled`.\n */\n title: string\n /** `title` is derived from the body, the Typed block itself has no title. */\n labelFromBody: boolean\n /** The composite has a description (the summary). */\n hasSummary: boolean\n /** Basket id (`meta.basket`), `null` without one. */\n basket: string | null\n /** The title is hidden in the editor (`meta.titleHidden`). */\n titleHidden: boolean\n /** The Block is a Derived block whose original was deleted (the source-missing state of its Derivation). */\n sourceMissing: boolean\n children: OutlineNode[]\n}\n\n/** Longest label taken from a paragraph; longer text is cut and ends in an ellipsis. */\nconst BODY_LABEL_CHARS = 60\n\nconst clipLabel = (text: string) => {\n if (text.length <= BODY_LABEL_CHARS) return text\n let end = BODY_LABEL_CHARS\n const last = text.charCodeAt(end - 1)\n if (last >= 0xD800 && last <= 0xDBFF) end-- // do not cut a surrogate pair\n return `${text.slice(0, end).trimEnd()}…`\n}\n\n/**\n * Walks the blocks of a composite's own body (not the ones inside a nested composite) in order. The text of the first\n * heading ends the walk; `found.text` collects the first non-empty text block as the fallback.\n */\nfunction scanBody(parent: PMNode, from: number, found: { heading: string | null, text: string | null }): void {\n for (let i = from; i < parent.childCount && found.heading === null; i++) {\n const node = parent.child(i)\n if (node.type.name === 'typedBlock') continue\n if (node.isTextblock) {\n const text = node.textContent.trim()\n if (!text) continue\n if (node.type.name === 'heading') found.heading = text\n else found.text ??= text.replace(/\\s+/g, ' ')\n }\n else if (!node.isLeaf) scanBody(node, 0, found)\n }\n}\n\n/** The label of a composite without a title: its first heading, else the start of its first text; `null` for an empty body. */\nfunction bodyLabel(composite: PMNode): string | null {\n const found = { heading: null as string | null, text: null as string | null }\n scanBody(composite, 3, found) // title, description and tags come first\n return found.heading ?? (found.text === null ? null : clipLabel(found.text))\n}\n\n/**\n * The composites of `doc` as a tree (title, kind, summary flag). A composite without a title is labelled by its body\n * (`labelFromBody`: first heading, else the start of the first text; nested composites do not count) and only an empty\n * one gets `untitled` (the caller's translated „(ohne Titel)“). Composites of a kind in `hiddenKinds` are omitted and their visible descendants\n * take their place in the parent's list. With `capabilitiesOf` (the editor's block capabilities) a composite without the `basket` capability has no basket.\n * `sourceMissing` marks a Derived block whose original is gone (`derivationOriginOf` against `documentId`, the open document).\n */\nexport function compositeOutline(doc: PMNode, hiddenKinds: ReadonlySet<string>, untitled: string, capabilitiesOf?: (node: PMNode) => ReadonlySet<string>, documentId?: string | null): OutlineNode[] {\n function collect(parent: PMNode, start: number, into: OutlineNode[]) {\n parent.forEach((node, offset) => {\n const pos = start + offset\n if (node.type.name === 'typedBlock') {\n const kind = String(node.attrs.blockType)\n const children: OutlineNode[] = []\n collect(node, pos + 1, children)\n if (hiddenKinds.has(kind)) {\n into.push(...children)\n return\n }\n const id = blockIdOf(node)\n const ownTitle = node.firstChild?.textContent.trim() ?? ''\n const derived = ownTitle ? null : bodyLabel(node)\n into.push({\n key: id ?? `pos:${pos}`,\n id,\n pos,\n kind,\n title: ownTitle || derived || untitled,\n labelFromBody: derived !== null,\n hasSummary: (node.maybeChild(1)?.content.size ?? 0) > 0,\n basket: capabilitiesOf && !capabilitiesOf(node).has('basket') ? null : basketOf(node),\n titleHidden: titleHiddenOf(node),\n sourceMissing: derivationOf(node) !== null && derivationOriginOf(doc, pos, documentId)?.status === 'missing',\n children,\n })\n }\n else if (!node.isTextblock && !node.isLeaf) {\n // Composites can sit in quotes or lists as well.\n collect(node, pos + 1, into)\n }\n })\n }\n const roots: OutlineNode[] = []\n collect(doc, 0, roots)\n return roots\n}\n\n/** Whether a block may move into a Typed block; `reason` is a short sentence for the UI (in the language of the `t` it was judged with) when it may not. */\nexport type MoveVerdict = { ok: true } | { ok: false, reason: string }\n\nconst refused = (reason: string): MoveVerdict => ({ ok: false, reason })\n\n/**\n * Whether block `id` may move into the Typed block `targetId` (`null` = the end of the document), with the reason when\n * not: a block is missing, the target is no Typed block, the target is the block itself or inside it, or the target's Block type\n * does not accept the block's Block type (`BlockType.accepts`). A block that is no Typed block may move into any Typed block,\n * unless it holds Typed blocks of a refused Block type; Typed blocks nested inside a moved Typed block stay with it and are not\n * checked. Moving a block to the end of the Typed block it already sits in adds no nesting and is never refused for it.\n */\nexport function moveIntoVerdict(editor: Editor, id: string, targetId: string | null, t: Translate): MoveVerdict {\n const { doc } = editor.state\n const block = findBlockById(doc, id)\n if (!block) return refused(t('composites.move.blockGone'))\n if (targetId === null) return { ok: true }\n const target = findBlockById(doc, targetId)\n if (!target) return refused(t('composites.move.targetGone'))\n if (target.node.type.name !== 'typedBlock') return refused(t('composites.move.targetNotBlock'))\n if (target.pos === block.pos) return refused(t('composites.move.intoSelf'))\n if (target.pos > block.pos && target.pos < block.pos + block.node.nodeSize) return refused(t('composites.move.intoOwn'))\n\n // The nearest Typed block around the block: when it is the target, the block only moves within it.\n const $block = doc.resolve(block.pos)\n let parentPos = -1\n for (let depth = $block.depth; depth > 0; depth--) {\n if ($block.node(depth).type.name === 'typedBlock') {\n parentPos = $block.before(depth)\n break\n }\n }\n if (parentPos === target.pos) return { ok: true }\n\n const kinds = blockTypesOf(editor)\n const targetKind = String(target.node.attrs.blockType)\n for (const child of outermostComposites(block.node)) {\n const childKind = String(child.attrs.blockType)\n if (!acceptsChild(kinds, targetKind, childKind)) return refused(nestingReason(kinds, targetKind, childKind, t))\n }\n return { ok: true }\n}\n\n/** `canMoveBlockInto` reads only `ok`, so its verdict needs no text: the message keys stand in for the sentences. */\nconst untranslated: Translate = key => key\n\n/** Whether block `id` can move into the Typed block `targetId` (`null` = the end of the document); see `moveIntoVerdict`. */\nexport function canMoveBlockInto(editor: Editor, id: string, targetId: string | null): boolean {\n return moveIntoVerdict(editor, id, targetId, untranslated).ok\n}\n\n/**\n * Moves block `id` to the end of the body of the Typed block `targetId` (`null` = the end of the document) in a single\n * transaction, i.e. one undo step. `false` when nothing moved: `moveIntoVerdict` refuses the move (or the editor\n * refused the transaction).\n */\nexport function moveBlockInto(editor: Editor, id: string, targetId: string | null): boolean {\n if (!canMoveBlockInto(editor, id, targetId)) return false\n const { doc, tr } = editor.state\n const block = findBlockById(doc, id)!\n const target = targetId === null ? null : findBlockById(doc, targetId)!\n // A composite's body is its last children, so its end is just before the composite's closing token.\n const insertPos = target ? target.pos + target.node.nodeSize - 1 : doc.content.size\n tr.delete(block.pos, block.pos + block.node.nodeSize)\n tr.insert(tr.mapping.map(insertPos), block.node)\n editor.view.dispatch(tr.scrollIntoView())\n return editor.state.doc !== doc\n}\n"],"mappings":"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"}
@@ -0,0 +1,51 @@
1
+ import { PropertyDefinition } from "../../core/properties.js";
2
+ import { BlockType } from "./block-types.js";
3
+ import { Editor } from "@tiptap/core";
4
+ import { Node as Node$1, ResolvedPos } from "@tiptap/pm/model";
5
+ //#region src/features/composites/properties.d.ts
6
+ /** Whether the node type has the `meta` attribute, where Block properties (and the bibliography, the basket, the derivation) are stored. This is what the `properties` capability's `appliesTo` asks of a node. */
7
+ export declare const carriesProperties: (node: Node$1) => boolean;
8
+ /** A block that carries property values, with the Property definitions its Block type declares and the values it holds. */
9
+ export interface BlockProperties {
10
+ /** Block ID, or `pos:<pos>` for a block without one yet; unique within the document. */
11
+ key: string;
12
+ id: string | null;
13
+ /** Position of the block when it was read; the write helpers re-resolve it, so a stale value is safe for blocks with an ID. */
14
+ pos: number;
15
+ /** The values, as stored: `meta`. */
16
+ meta: Record<string, unknown>;
17
+ /** The Property definitions of the block's Block type: empty without the `properties` capability; `bibliography` definitions drop out without the `bibliography` capability. */
18
+ definitions: readonly PropertyDefinition[];
19
+ }
20
+ /**
21
+ * The properties of `node` at `pos`, a node that carries property values (`carriesProperties`; its `meta` is read as the
22
+ * values). `capabilities` is what `capabilitiesOf` answers for the node; `blockTypes` are the editor's Block types.
23
+ */
24
+ export declare function blockPropertiesOf(node: Node$1, pos: number, blockTypes: readonly BlockType[], capabilities: ReadonlySet<string>): BlockProperties;
25
+ /**
26
+ * The properties of the innermost block around `$pos` that carries property values (`carriesProperties`), with its node; null
27
+ * when none does. A block of that kind whose type lacks the `properties` capability answers with no `definitions` rather than handing
28
+ * the caret to an outer block. `blockTypes` are the editor's Block types.
29
+ */
30
+ export declare function blockPropertiesAt(editor: Editor, $pos: ResolvedPos, blockTypes: readonly BlockType[]): {
31
+ node: Node$1;
32
+ properties: BlockProperties;
33
+ } | null;
34
+ /** The block `target` stands for in `doc` and that carries property values: by block ID, else (no ID yet) by its position. Positions are re-resolved on every call. */
35
+ export declare function propertyHostOf(doc: Node$1, target: Pick<BlockProperties, 'id' | 'pos'>): {
36
+ pos: number;
37
+ node: Node$1;
38
+ } | null;
39
+ /**
40
+ * `meta` with `value` stored under `definition.key`: a number property converts a numeric string, an empty value (`''`,
41
+ * `null`, `undefined`, `NaN`) removes the key. A `multiselect` property keeps the string entries of an array value and
42
+ * removes the key when none is left. Returns a new object; `meta` is not changed.
43
+ */
44
+ export declare function metaWithProperty(meta: Record<string, unknown>, definition: Pick<PropertyDefinition, 'key' | 'type'>, value: unknown): Record<string, unknown>;
45
+ /**
46
+ * Stores `value` under the property `key` of the block `target` stands for (see `metaWithProperty`), in one transaction; a key
47
+ * the block's `definitions` do not define is written as text. False when the block is gone or carries no property values.
48
+ */
49
+ export declare function setBlockProperty(editor: Editor, target: Pick<BlockProperties, 'id' | 'pos' | 'definitions'>, key: string, value: unknown): boolean;
50
+ //#endregion
51
+ //# sourceMappingURL=properties.d.ts.map
@@ -0,0 +1,89 @@
1
+ import { blockIdOf, findBlockById } from "../../core/schema/block-ids.js";
2
+ import { blockTypeIdOf, capabilitiesOf } from "../../core/capabilities.js";
3
+ import { blockTypeOf, propertiesOf } from "./block-types.js";
4
+ //#region src/features/composites/properties.ts
5
+ /** Whether the node type has the `meta` attribute, where Block properties (and the bibliography, the basket, the derivation) are stored. This is what the `properties` capability's `appliesTo` asks of a node. */
6
+ const carriesProperties = (node) => "meta" in (node.type.spec.attrs ?? {});
7
+ /**
8
+ * The properties of `node` at `pos`, a node that carries property values (`carriesProperties`; its `meta` is read as the
9
+ * values). `capabilities` is what `capabilitiesOf` answers for the node; `blockTypes` are the editor's Block types.
10
+ */
11
+ function blockPropertiesOf(node, pos, blockTypes, capabilities) {
12
+ const id = blockIdOf(node);
13
+ const typeId = blockTypeIdOf(node);
14
+ const definitions = typeId !== null && capabilities.has("properties") ? propertiesOf(blockTypeOf(blockTypes, typeId)).filter((field) => field.type !== "bibliography" || capabilities.has("bibliography")) : [];
15
+ return {
16
+ key: id ?? `pos:${pos}`,
17
+ id,
18
+ pos,
19
+ meta: node.attrs.meta ?? {},
20
+ definitions
21
+ };
22
+ }
23
+ /**
24
+ * The properties of the innermost block around `$pos` that carries property values (`carriesProperties`), with its node; null
25
+ * when none does. A block of that kind whose type lacks the `properties` capability answers with no `definitions` rather than handing
26
+ * the caret to an outer block. `blockTypes` are the editor's Block types.
27
+ */
28
+ function blockPropertiesAt(editor, $pos, blockTypes) {
29
+ for (let depth = $pos.depth; depth > 0; depth--) {
30
+ const node = $pos.node(depth);
31
+ if (carriesProperties(node)) return {
32
+ node,
33
+ properties: blockPropertiesOf(node, $pos.before(depth), blockTypes, capabilitiesOf(editor, node))
34
+ };
35
+ }
36
+ return null;
37
+ }
38
+ /** The block `target` stands for in `doc` and that carries property values: by block ID, else (no ID yet) by its position. Positions are re-resolved on every call. */
39
+ function propertyHostOf(doc, target) {
40
+ const found = target.id ? findBlockById(doc, target.id) : (() => {
41
+ const node = doc.nodeAt(target.pos);
42
+ return node ? {
43
+ pos: target.pos,
44
+ node
45
+ } : null;
46
+ })();
47
+ return found && carriesProperties(found.node) ? found : null;
48
+ }
49
+ /**
50
+ * `meta` with `value` stored under `definition.key`: a number property converts a numeric string, an empty value (`''`,
51
+ * `null`, `undefined`, `NaN`) removes the key. A `multiselect` property keeps the string entries of an array value and
52
+ * removes the key when none is left. Returns a new object; `meta` is not changed.
53
+ */
54
+ function metaWithProperty(meta, definition, value) {
55
+ const next = { ...meta };
56
+ if (definition.type === "multiselect") {
57
+ const chosen = Array.isArray(value) ? value.filter((item) => typeof item === "string") : [];
58
+ if (chosen.length) next[definition.key] = chosen;
59
+ else delete next[definition.key];
60
+ return next;
61
+ }
62
+ const stored = definition.type === "number" && typeof value === "string" && value !== "" ? Number(value) : value;
63
+ if (stored === "" || stored === null || stored === void 0 || Number.isNaN(stored)) delete next[definition.key];
64
+ else next[definition.key] = stored;
65
+ return next;
66
+ }
67
+ /**
68
+ * Stores `value` under the property `key` of the block `target` stands for (see `metaWithProperty`), in one transaction; a key
69
+ * the block's `definitions` do not define is written as text. False when the block is gone or carries no property values.
70
+ */
71
+ function setBlockProperty(editor, target, key, value) {
72
+ const definition = target.definitions.find((candidate) => candidate.key === key) ?? {
73
+ key,
74
+ type: "text"
75
+ };
76
+ return editor.commands.command(({ tr }) => {
77
+ const found = propertyHostOf(tr.doc, target);
78
+ if (!found) return false;
79
+ tr.setNodeMarkup(found.pos, void 0, {
80
+ ...found.node.attrs,
81
+ meta: metaWithProperty(found.node.attrs.meta ?? {}, definition, value)
82
+ });
83
+ return true;
84
+ });
85
+ }
86
+ //#endregion
87
+ export { blockPropertiesAt, blockPropertiesOf, carriesProperties, metaWithProperty, propertyHostOf, setBlockProperty };
88
+
89
+ //# sourceMappingURL=properties.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"properties.js","names":[],"sources":["../../../src/features/composites/properties.ts"],"sourcesContent":["// Vue-free: Block properties as one mechanism. A block carries property values when its node type has the `meta` attribute; the\n// `properties` capability (`capabilities.ts`) says which of its Property definitions a block's type declares. Reading, resolving\n// and writing the values never ask for a node type name, so every node type that gains a `meta` attribute is covered.\nimport type { Editor } from '@tiptap/core'\nimport type { Node as PMNode, ResolvedPos } from '@tiptap/pm/model'\nimport { blockTypeIdOf, capabilitiesOf } from '../../core/capabilities'\nimport type { PropertyDefinition } from '../../core/properties'\nimport { blockIdOf, findBlockById } from '../../core/schema'\nimport { type BlockType, blockTypeOf, propertiesOf } from './block-types'\n\n/** Whether the node type has the `meta` attribute, where Block properties (and the bibliography, the basket, the derivation) are stored. This is what the `properties` capability's `appliesTo` asks of a node. */\nexport const carriesProperties = (node: PMNode): boolean => 'meta' in (node.type.spec.attrs ?? {})\n\n/** A block that carries property values, with the Property definitions its Block type declares and the values it holds. */\nexport interface BlockProperties {\n /** Block ID, or `pos:<pos>` for a block without one yet; unique within the document. */\n key: string\n id: string | null\n /** Position of the block when it was read; the write helpers re-resolve it, so a stale value is safe for blocks with an ID. */\n pos: number\n /** The values, as stored: `meta`. */\n meta: Record<string, unknown>\n /** The Property definitions of the block's Block type: empty without the `properties` capability; `bibliography` definitions drop out without the `bibliography` capability. */\n definitions: readonly PropertyDefinition[]\n}\n\n/**\n * The properties of `node` at `pos`, a node that carries property values (`carriesProperties`; its `meta` is read as the\n * values). `capabilities` is what `capabilitiesOf` answers for the node; `blockTypes` are the editor's Block types.\n */\nexport function blockPropertiesOf(node: PMNode, pos: number, blockTypes: readonly BlockType[], capabilities: ReadonlySet<string>): BlockProperties {\n const id = blockIdOf(node)\n const typeId = blockTypeIdOf(node)\n const definitions = typeId !== null && capabilities.has('properties')\n ? propertiesOf(blockTypeOf(blockTypes, typeId)).filter(field => field.type !== 'bibliography' || capabilities.has('bibliography'))\n : []\n return { key: id ?? `pos:${pos}`, id, pos, meta: (node.attrs.meta ?? {}) as Record<string, unknown>, definitions }\n}\n\n/**\n * The properties of the innermost block around `$pos` that carries property values (`carriesProperties`), with its node; null\n * when none does. A block of that kind whose type lacks the `properties` capability answers with no `definitions` rather than handing\n * the caret to an outer block. `blockTypes` are the editor's Block types.\n */\nexport function blockPropertiesAt(editor: Editor, $pos: ResolvedPos, blockTypes: readonly BlockType[]): { node: PMNode, properties: BlockProperties } | null {\n for (let depth = $pos.depth; depth > 0; depth--) {\n const node = $pos.node(depth)\n if (carriesProperties(node)) return { node, properties: blockPropertiesOf(node, $pos.before(depth), blockTypes, capabilitiesOf(editor, node)) }\n }\n return null\n}\n\n/** The block `target` stands for in `doc` and that carries property values: by block ID, else (no ID yet) by its position. Positions are re-resolved on every call. */\nexport function propertyHostOf(doc: PMNode, target: Pick<BlockProperties, 'id' | 'pos'>): { pos: number, node: PMNode } | null {\n const found = target.id ? findBlockById(doc, target.id) : (() => {\n const node = doc.nodeAt(target.pos)\n return node ? { pos: target.pos, node } : null\n })()\n return found && carriesProperties(found.node) ? found : null\n}\n\n/**\n * `meta` with `value` stored under `definition.key`: a number property converts a numeric string, an empty value (`''`,\n * `null`, `undefined`, `NaN`) removes the key. A `multiselect` property keeps the string entries of an array value and\n * removes the key when none is left. Returns a new object; `meta` is not changed.\n */\nexport function metaWithProperty(meta: Record<string, unknown>, definition: Pick<PropertyDefinition, 'key' | 'type'>, value: unknown): Record<string, unknown> {\n const next = { ...meta }\n if (definition.type === 'multiselect') {\n const chosen = Array.isArray(value) ? value.filter((item): item is string => typeof item === 'string') : []\n if (chosen.length) next[definition.key] = chosen\n else delete next[definition.key]\n return next\n }\n const stored = definition.type === 'number' && typeof value === 'string' && value !== '' ? Number(value) : value\n if (stored === '' || stored === null || stored === undefined || Number.isNaN(stored)) delete next[definition.key]\n else next[definition.key] = stored\n return next\n}\n\n/**\n * Stores `value` under the property `key` of the block `target` stands for (see `metaWithProperty`), in one transaction; a key\n * the block's `definitions` do not define is written as text. False when the block is gone or carries no property values.\n */\nexport function setBlockProperty(editor: Editor, target: Pick<BlockProperties, 'id' | 'pos' | 'definitions'>, key: string, value: unknown): boolean {\n const definition = target.definitions.find(candidate => candidate.key === key) ?? { key, type: 'text' as const }\n return editor.commands.command(({ tr }) => {\n const found = propertyHostOf(tr.doc, target)\n if (!found) return false\n tr.setNodeMarkup(found.pos, undefined, { ...found.node.attrs, meta: metaWithProperty(found.node.attrs.meta ?? {}, definition, value) })\n return true\n })\n}\n"],"mappings":";;;;;AAWA,MAAa,qBAAqB,SAA0B,WAAW,KAAK,KAAK,KAAK,SAAS,CAAC;;;;;AAmBhG,SAAgB,kBAAkB,MAAc,KAAa,YAAkC,cAAoD;CACjJ,MAAM,KAAK,UAAU,IAAI;CACzB,MAAM,SAAS,cAAc,IAAI;CACjC,MAAM,cAAc,WAAW,QAAQ,aAAa,IAAI,YAAY,IAChE,aAAa,YAAY,YAAY,MAAM,CAAC,CAAC,CAAC,QAAO,UAAS,MAAM,SAAS,kBAAkB,aAAa,IAAI,cAAc,CAAC,IAC/H,CAAC;CACL,OAAO;EAAE,KAAK,MAAM,OAAO;EAAO;EAAI;EAAK,MAAO,KAAK,MAAM,QAAQ,CAAC;EAA+B;CAAY;AACnH;;;;;;AAOA,SAAgB,kBAAkB,QAAgB,MAAmB,YAAwF;CAC3J,KAAK,IAAI,QAAQ,KAAK,OAAO,QAAQ,GAAG,SAAS;EAC/C,MAAM,OAAO,KAAK,KAAK,KAAK;EAC5B,IAAI,kBAAkB,IAAI,GAAG,OAAO;GAAE;GAAM,YAAY,kBAAkB,MAAM,KAAK,OAAO,KAAK,GAAG,YAAY,eAAe,QAAQ,IAAI,CAAC;EAAE;CAChJ;CACA,OAAO;AACT;;AAGA,SAAgB,eAAe,KAAa,QAAmF;CAC7H,MAAM,QAAQ,OAAO,KAAK,cAAc,KAAK,OAAO,EAAE,WAAW;EAC/D,MAAM,OAAO,IAAI,OAAO,OAAO,GAAG;EAClC,OAAO,OAAO;GAAE,KAAK,OAAO;GAAK;EAAK,IAAI;CAC5C,EAAA,CAAG;CACH,OAAO,SAAS,kBAAkB,MAAM,IAAI,IAAI,QAAQ;AAC1D;;;;;;AAOA,SAAgB,iBAAiB,MAA+B,YAAsD,OAAyC;CAC7J,MAAM,OAAO,EAAE,GAAG,KAAK;CACvB,IAAI,WAAW,SAAS,eAAe;EACrC,MAAM,SAAS,MAAM,QAAQ,KAAK,IAAI,MAAM,QAAQ,SAAyB,OAAO,SAAS,QAAQ,IAAI,CAAC;EAC1G,IAAI,OAAO,QAAQ,KAAK,WAAW,OAAO;OACrC,OAAO,KAAK,WAAW;EAC5B,OAAO;CACT;CACA,MAAM,SAAS,WAAW,SAAS,YAAY,OAAO,UAAU,YAAY,UAAU,KAAK,OAAO,KAAK,IAAI;CAC3G,IAAI,WAAW,MAAM,WAAW,QAAQ,WAAW,KAAA,KAAa,OAAO,MAAM,MAAM,GAAG,OAAO,KAAK,WAAW;MACxG,KAAK,WAAW,OAAO;CAC5B,OAAO;AACT;;;;;AAMA,SAAgB,iBAAiB,QAAgB,QAA6D,KAAa,OAAyB;CAClJ,MAAM,aAAa,OAAO,YAAY,MAAK,cAAa,UAAU,QAAQ,GAAG,KAAK;EAAE;EAAK,MAAM;CAAgB;CAC/G,OAAO,OAAO,SAAS,SAAS,EAAE,SAAS;EACzC,MAAM,QAAQ,eAAe,GAAG,KAAK,MAAM;EAC3C,IAAI,CAAC,OAAO,OAAO;EACnB,GAAG,cAAc,MAAM,KAAK,KAAA,GAAW;GAAE,GAAG,MAAM,KAAK;GAAO,MAAM,iBAAiB,MAAM,KAAK,MAAM,QAAQ,CAAC,GAAG,YAAY,KAAK;EAAE,CAAC;EACtI,OAAO;CACT,CAAC;AACH"}
@@ -1,11 +1,11 @@
1
1
  import { bibtexOf, cslOf, cslTypeOptions } from "../bibliography.js";
2
+ import { propertyHostOf, setBlockProperty } from "../properties.js";
2
3
  import { useEditorI18n } from "../../../react/use-editor-i18n.js";
3
4
  import { Icon } from "../../../react/Icon.js";
4
5
  import { Button } from "../../../react/ui/button.js";
5
6
  import { Input } from "../../../react/ui/input.js";
6
7
  import { Textarea } from "../../../react/ui/textarea.js";
7
8
  import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from "../../../react/ui/select.js";
8
- import { compositeOfRow, setCompositeMetaField } from "../rows.js";
9
9
  import { bibFormOf, bibItemOf } from "../bibliography-form.js";
10
10
  import { useCallback, useEffect, useMemo, useRef, useState } from "react";
11
11
  import { jsx, jsxs } from "react/jsx-runtime";
@@ -51,7 +51,7 @@ const LINES = [
51
51
  /**
52
52
  * The structured editor of a `bibliography` field (CSL-JSON item, `meta.bib`): type, authors, year, container, volume,
53
53
  * issue, pages, publisher, DOI, ISBN, URL and abstract. Inputs keep a local draft; every commit (blur, Enter, choosing
54
- * a type, unmount, another row) writes the whole item through `setCompositeMetaField`. The title is the Baustein's and
54
+ * a type, unmount, another row) writes the whole item through `setBlockProperty`. The title is the Typed block's and
55
55
  * never stored.
56
56
  */
57
57
  function BibliographyEditor({ editor, row, field, disabled }) {
@@ -87,7 +87,7 @@ function BibliographyEditor({ editor, row, field, disabled }) {
87
87
  if (!dirty.current) return;
88
88
  dirty.current = false;
89
89
  const current = target.current;
90
- if (!current.editor.isDestroyed) setCompositeMetaField(current.editor, current.row, current.field.key, bibItemOf(formRef.current, current.stored));
90
+ if (!current.editor.isDestroyed) setBlockProperty(current.editor, current.row, current.field.key, bibItemOf(formRef.current, current.stored));
91
91
  }, []);
92
92
  useEffect(() => commit, [
93
93
  commit,
@@ -114,7 +114,7 @@ function BibliographyEditor({ editor, row, field, disabled }) {
114
114
  }
115
115
  async function copyBibtex() {
116
116
  commit();
117
- const node = compositeOfRow(editor.state.doc, row)?.node;
117
+ const node = propertyHostOf(editor.state.doc, row)?.node;
118
118
  const csl = node && cslOf(node);
119
119
  if (!csl) return;
120
120
  await navigator.clipboard.writeText(bibtexOf(csl));
@@ -124,7 +124,7 @@ function BibliographyEditor({ editor, row, field, disabled }) {
124
124
  const hasDoi = form.doi.trim() !== "" || typeof row.meta.doi === "string" && row.meta.doi.trim() !== "";
125
125
  function fetchByDoi() {
126
126
  commit();
127
- const found = compositeOfRow(editor.state.doc, row);
127
+ const found = propertyHostOf(editor.state.doc, row);
128
128
  if (found) editor.commands.fetchCompositeBibliography(found.pos);
129
129
  }
130
130
  const typeOptions = useMemo(() => cslTypeOptions(t), [t]);
@@ -1 +1 @@
1
- {"version":3,"file":"BibliographyEditor.js","names":[],"sources":["../../../../src/features/composites/react/BibliographyEditor.tsx"],"sourcesContent":["import type { Editor } from '@tiptap/core'\nimport { useCallback, useEffect, useMemo, useRef, useState } from 'react'\nimport { Icon } from '../../../react/Icon'\nimport { Button } from '../../../react/ui/button'\nimport { Input } from '../../../react/ui/input'\nimport { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from '../../../react/ui/select'\nimport { Textarea } from '../../../react/ui/textarea'\nimport { useEditorI18n } from '../../../react/use-editor-i18n'\nimport { bibtexOf, type CslItem, type CslType, cslOf, cslTypeOptions } from '../bibliography'\nimport { type BibForm, bibFormOf, bibItemOf } from '../bibliography-form'\nimport type { CompositeMetaField } from '../kinds'\nimport { compositeOfRow, type CompositeRow, setCompositeMetaField } from '../rows'\nimport '../bibliography-command'\n\nconst INPUT_CLASS = 'h-6 w-full px-2 text-xs md:text-xs'\nconst TEXTAREA_CLASS = 'max-h-[8.5rem] min-h-0 w-full px-2 py-1 text-xs md:text-xs'\n\nconst COUNTERS = [\n { key: 'volume', labelKey: 'composites.bib.field.volume' },\n { key: 'issue', labelKey: 'composites.bib.field.issue' },\n { key: 'page', labelKey: 'composites.bib.field.page' },\n] as const\nconst LINES = [\n { key: 'containerTitle', labelKey: 'composites.bib.field.containerTitle' },\n { key: 'publisher', labelKey: 'composites.bib.field.publisher' },\n { key: 'doi', labelKey: 'composites.bib.field.doi' },\n { key: 'isbn', labelKey: 'composites.bib.field.isbn' },\n { key: 'url', labelKey: 'composites.bib.field.url' },\n] as const\n\n/**\n * The structured editor of a `bibliography` field (CSL-JSON item, `meta.bib`): type, authors, year, container, volume,\n * issue, pages, publisher, DOI, ISBN, URL and abstract. Inputs keep a local draft; every commit (blur, Enter, choosing\n * a type, unmount, another row) writes the whole item through `setCompositeMetaField`. The title is the Baustein's and\n * never stored.\n */\nexport function BibliographyEditor({ editor, row, field, disabled }: {\n editor: Editor\n row: CompositeRow\n field: CompositeMetaField\n disabled?: boolean\n}) {\n const { t } = useEditorI18n()\n const value = row.meta[field.key] as Partial<CslItem> | null | undefined\n const stored = value && typeof value === 'object' && typeof value.type === 'string' ? value as CslItem : null\n const [form, setForm] = useState<BibForm>(() => bibFormOf(stored))\n const formRef = useRef(form)\n const dirty = useRef(false)\n const [copied, setCopied] = useState(false)\n // The latest props for the commit on unmount; updated after every render, so the cleanup of a changed `row.key` still sees the previous row.\n const target = useRef({ editor, row, field, stored })\n useEffect(() => {\n target.current = { editor, row, field, stored }\n })\n\n useEffect(() => {\n if (!dirty.current) {\n const next = bibFormOf(stored)\n formRef.current = next\n setForm(next)\n }\n }, [stored, row.key])\n\n const commit = useCallback(() => {\n if (!dirty.current) return\n dirty.current = false\n const current = target.current\n if (!current.editor.isDestroyed) setCompositeMetaField(current.editor, current.row, current.field.key, bibItemOf(formRef.current, current.stored))\n }, [])\n\n // Flush on unmount and when the editor is bound to another row.\n useEffect(() => commit, [commit, editor, row.key, field.key])\n\n useEffect(() => {\n if (!copied) return\n const timer = window.setTimeout(() => setCopied(false), 1500)\n return () => window.clearTimeout(timer)\n }, [copied])\n\n function onInput<K extends keyof BibForm>(key: K, next: BibForm[K]) {\n formRef.current = { ...formRef.current, [key]: next }\n setForm(formRef.current)\n dirty.current = true\n }\n\n function onType(next: string) {\n onInput('type', next as CslType)\n commit()\n }\n\n async function copyBibtex() {\n commit()\n const node = compositeOfRow(editor.state.doc, row)?.node\n const csl = node && cslOf(node)\n if (!csl) return\n await navigator.clipboard.writeText(bibtexOf(csl))\n setCopied(true)\n }\n\n // Registered by the AI integration (`composite-ai`); without it there is nothing to fetch with.\n const canFetch = typeof editor.commands.fetchCompositeBibliography === 'function'\n const hasDoi = form.doi.trim() !== '' || (typeof row.meta.doi === 'string' && row.meta.doi.trim() !== '')\n\n function fetchByDoi() {\n commit()\n const found = compositeOfRow(editor.state.doc, row)\n if (found) editor.commands.fetchCompositeBibliography(found.pos)\n }\n\n const typeOptions = useMemo(() => cslTypeOptions(t), [t])\n\n return (\n <div className=\"flex flex-col gap-1.5\">\n <Select value={form.type} onValueChange={onType} disabled={disabled}>\n <SelectTrigger size=\"sm\" className=\"w-full text-xs data-[size=sm]:h-6\" aria-label={t('composites.bib.field.type')}>\n <SelectValue />\n </SelectTrigger>\n <SelectContent>\n {typeOptions.map(option => (\n <SelectItem key={option.value} value={option.value}>{option.label}</SelectItem>\n ))}\n </SelectContent>\n </Select>\n <Textarea\n value={form.authors}\n placeholder={t('composites.bib.field.authorsHelp')}\n aria-label={t('composites.bib.field.authors')}\n disabled={disabled}\n rows={2}\n className={TEXTAREA_CLASS}\n onBlur={commit}\n onChange={event => onInput('authors', event.target.value)}\n />\n <div className=\"grid grid-cols-4 gap-1.5\">\n <Input\n value={form.year}\n type=\"number\"\n placeholder={t('composites.bib.field.year')}\n aria-label={t('composites.bib.field.year')}\n disabled={disabled}\n className={INPUT_CLASS}\n onBlur={commit}\n onKeyDown={(event) => {\n if (event.key === 'Enter') commit()\n }}\n onChange={event => onInput('year', event.target.value)}\n />\n {COUNTERS.map(input => (\n <Input\n key={input.key}\n value={form[input.key]}\n placeholder={t(input.labelKey)}\n aria-label={t(input.labelKey)}\n disabled={disabled}\n className={INPUT_CLASS}\n onBlur={commit}\n onKeyDown={(event) => {\n if (event.key === 'Enter') commit()\n }}\n onChange={event => onInput(input.key, event.target.value)}\n />\n ))}\n </div>\n {LINES.map(input => (\n <Input\n key={input.key}\n value={form[input.key]}\n placeholder={t(input.labelKey)}\n aria-label={t(input.labelKey)}\n disabled={disabled}\n className={INPUT_CLASS}\n onBlur={commit}\n onKeyDown={(event) => {\n if (event.key === 'Enter') commit()\n }}\n onChange={event => onInput(input.key, event.target.value)}\n />\n ))}\n <Textarea\n value={form.abstract}\n placeholder={t('composites.bib.field.abstract')}\n aria-label={t('composites.bib.field.abstract')}\n disabled={disabled}\n rows={2}\n className={TEXTAREA_CLASS}\n onBlur={commit}\n onChange={event => onInput('abstract', event.target.value)}\n />\n <div className=\"flex justify-end gap-1.5\">\n {canFetch && (\n <Button size=\"xs\" variant=\"ghost\" disabled={disabled || !hasDoi} onClick={fetchByDoi}>\n <Icon name=\"i-lucide-book-marked\" />\n {t('composites.bib.fetchDoi')}\n </Button>\n )}\n <Button size=\"xs\" variant=\"ghost\" disabled={!stored} onClick={() => void copyBibtex()}>\n <Icon name=\"i-lucide-copy\" />\n {copied ? t('composites.bib.copied') : t('composites.bib.copyBibtex')}\n </Button>\n </div>\n </div>\n )\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"BibliographyEditor.js","names":[],"sources":["../../../../src/features/composites/react/BibliographyEditor.tsx"],"sourcesContent":["import type { Editor } from '@tiptap/core'\nimport { useCallback, useEffect, useMemo, useRef, useState } from 'react'\nimport { Icon } from '../../../react/Icon'\nimport { Button } from '../../../react/ui/button'\nimport { Input } from '../../../react/ui/input'\nimport { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from '../../../react/ui/select'\nimport { Textarea } from '../../../react/ui/textarea'\nimport { useEditorI18n } from '../../../react/use-editor-i18n'\nimport { bibtexOf, type CslItem, type CslType, cslOf, cslTypeOptions } from '../bibliography'\nimport { type BibForm, bibFormOf, bibItemOf } from '../bibliography-form'\nimport type { PropertyDefinition } from '../../../core/properties'\nimport { type BlockProperties, propertyHostOf, setBlockProperty } from '../properties'\nimport '../bibliography-command'\n\nconst INPUT_CLASS = 'h-6 w-full px-2 text-xs md:text-xs'\nconst TEXTAREA_CLASS = 'max-h-[8.5rem] min-h-0 w-full px-2 py-1 text-xs md:text-xs'\n\nconst COUNTERS = [\n { key: 'volume', labelKey: 'composites.bib.field.volume' },\n { key: 'issue', labelKey: 'composites.bib.field.issue' },\n { key: 'page', labelKey: 'composites.bib.field.page' },\n] as const\nconst LINES = [\n { key: 'containerTitle', labelKey: 'composites.bib.field.containerTitle' },\n { key: 'publisher', labelKey: 'composites.bib.field.publisher' },\n { key: 'doi', labelKey: 'composites.bib.field.doi' },\n { key: 'isbn', labelKey: 'composites.bib.field.isbn' },\n { key: 'url', labelKey: 'composites.bib.field.url' },\n] as const\n\n/**\n * The structured editor of a `bibliography` field (CSL-JSON item, `meta.bib`): type, authors, year, container, volume,\n * issue, pages, publisher, DOI, ISBN, URL and abstract. Inputs keep a local draft; every commit (blur, Enter, choosing\n * a type, unmount, another row) writes the whole item through `setBlockProperty`. The title is the Typed block's and\n * never stored.\n */\nexport function BibliographyEditor({ editor, row, field, disabled }: {\n editor: Editor\n row: BlockProperties\n field: PropertyDefinition\n disabled?: boolean\n}) {\n const { t } = useEditorI18n()\n const value = row.meta[field.key] as Partial<CslItem> | null | undefined\n const stored = value && typeof value === 'object' && typeof value.type === 'string' ? value as CslItem : null\n const [form, setForm] = useState<BibForm>(() => bibFormOf(stored))\n const formRef = useRef(form)\n const dirty = useRef(false)\n const [copied, setCopied] = useState(false)\n // The latest props for the commit on unmount; updated after every render, so the cleanup of a changed `row.key` still sees the previous row.\n const target = useRef({ editor, row, field, stored })\n useEffect(() => {\n target.current = { editor, row, field, stored }\n })\n\n useEffect(() => {\n if (!dirty.current) {\n const next = bibFormOf(stored)\n formRef.current = next\n setForm(next)\n }\n }, [stored, row.key])\n\n const commit = useCallback(() => {\n if (!dirty.current) return\n dirty.current = false\n const current = target.current\n if (!current.editor.isDestroyed) setBlockProperty(current.editor, current.row, current.field.key, bibItemOf(formRef.current, current.stored))\n }, [])\n\n // Flush on unmount and when the editor is bound to another row.\n useEffect(() => commit, [commit, editor, row.key, field.key])\n\n useEffect(() => {\n if (!copied) return\n const timer = window.setTimeout(() => setCopied(false), 1500)\n return () => window.clearTimeout(timer)\n }, [copied])\n\n function onInput<K extends keyof BibForm>(key: K, next: BibForm[K]) {\n formRef.current = { ...formRef.current, [key]: next }\n setForm(formRef.current)\n dirty.current = true\n }\n\n function onType(next: string) {\n onInput('type', next as CslType)\n commit()\n }\n\n async function copyBibtex() {\n commit()\n const node = propertyHostOf(editor.state.doc, row)?.node\n const csl = node && cslOf(node)\n if (!csl) return\n await navigator.clipboard.writeText(bibtexOf(csl))\n setCopied(true)\n }\n\n // Registered by the AI integration (`composite-ai`); without it there is nothing to fetch with.\n const canFetch = typeof editor.commands.fetchCompositeBibliography === 'function'\n const hasDoi = form.doi.trim() !== '' || (typeof row.meta.doi === 'string' && row.meta.doi.trim() !== '')\n\n function fetchByDoi() {\n commit()\n const found = propertyHostOf(editor.state.doc, row)\n if (found) editor.commands.fetchCompositeBibliography(found.pos)\n }\n\n const typeOptions = useMemo(() => cslTypeOptions(t), [t])\n\n return (\n <div className=\"flex flex-col gap-1.5\">\n <Select value={form.type} onValueChange={onType} disabled={disabled}>\n <SelectTrigger size=\"sm\" className=\"w-full text-xs data-[size=sm]:h-6\" aria-label={t('composites.bib.field.type')}>\n <SelectValue />\n </SelectTrigger>\n <SelectContent>\n {typeOptions.map(option => (\n <SelectItem key={option.value} value={option.value}>{option.label}</SelectItem>\n ))}\n </SelectContent>\n </Select>\n <Textarea\n value={form.authors}\n placeholder={t('composites.bib.field.authorsHelp')}\n aria-label={t('composites.bib.field.authors')}\n disabled={disabled}\n rows={2}\n className={TEXTAREA_CLASS}\n onBlur={commit}\n onChange={event => onInput('authors', event.target.value)}\n />\n <div className=\"grid grid-cols-4 gap-1.5\">\n <Input\n value={form.year}\n type=\"number\"\n placeholder={t('composites.bib.field.year')}\n aria-label={t('composites.bib.field.year')}\n disabled={disabled}\n className={INPUT_CLASS}\n onBlur={commit}\n onKeyDown={(event) => {\n if (event.key === 'Enter') commit()\n }}\n onChange={event => onInput('year', event.target.value)}\n />\n {COUNTERS.map(input => (\n <Input\n key={input.key}\n value={form[input.key]}\n placeholder={t(input.labelKey)}\n aria-label={t(input.labelKey)}\n disabled={disabled}\n className={INPUT_CLASS}\n onBlur={commit}\n onKeyDown={(event) => {\n if (event.key === 'Enter') commit()\n }}\n onChange={event => onInput(input.key, event.target.value)}\n />\n ))}\n </div>\n {LINES.map(input => (\n <Input\n key={input.key}\n value={form[input.key]}\n placeholder={t(input.labelKey)}\n aria-label={t(input.labelKey)}\n disabled={disabled}\n className={INPUT_CLASS}\n onBlur={commit}\n onKeyDown={(event) => {\n if (event.key === 'Enter') commit()\n }}\n onChange={event => onInput(input.key, event.target.value)}\n />\n ))}\n <Textarea\n value={form.abstract}\n placeholder={t('composites.bib.field.abstract')}\n aria-label={t('composites.bib.field.abstract')}\n disabled={disabled}\n rows={2}\n className={TEXTAREA_CLASS}\n onBlur={commit}\n onChange={event => onInput('abstract', event.target.value)}\n />\n <div className=\"flex justify-end gap-1.5\">\n {canFetch && (\n <Button size=\"xs\" variant=\"ghost\" disabled={disabled || !hasDoi} onClick={fetchByDoi}>\n <Icon name=\"i-lucide-book-marked\" />\n {t('composites.bib.fetchDoi')}\n </Button>\n )}\n <Button size=\"xs\" variant=\"ghost\" disabled={!stored} onClick={() => void copyBibtex()}>\n <Icon name=\"i-lucide-copy\" />\n {copied ? t('composites.bib.copied') : t('composites.bib.copyBibtex')}\n </Button>\n </div>\n </div>\n )\n}\n"],"mappings":"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"}
@@ -9,8 +9,8 @@ import { jsx, jsxs } from "react/jsx-runtime";
9
9
  //#region src/features/composites/react/CompositeBasketMenu.tsx
10
10
  const OPTION = "flex w-full items-center gap-2 rounded-sm px-2 py-1.5 text-left text-sm text-foreground transition-colors duration-150 hover:bg-muted focus-visible:outline-2 focus-visible:-outline-offset-2 focus-visible:outline-primary";
11
11
  /**
12
- * Basket choice of a Baustein: the child (a button) opens a list of the editor's baskets (a dot in the basket's colour
13
- * and its label) and „Kein Korb“. The menu is a popover, not a dropdown menu: a dropdown item cannot show a dot in an
12
+ * Basket choice of a Typed block: the child (a button) opens a list of the editor's baskets (a dot in the basket's colour
13
+ * and its label) and a „none“ entry. The menu is a popover, not a dropdown menu: a dropdown item cannot show a dot in an
14
14
  * arbitrary CSS colour.
15
15
  */
16
16
  function CompositeBasketMenu({ editor, row, children }) {
@@ -1 +1 @@
1
- {"version":3,"file":"CompositeBasketMenu.js","names":[],"sources":["../../../../src/features/composites/react/CompositeBasketMenu.tsx"],"sourcesContent":["import type { Editor } from '@tiptap/core'\nimport { type ReactNode, useState } from 'react'\nimport { Icon } from '../../../react/Icon'\nimport { Popover, PopoverContent, PopoverTrigger } from '../../../react/ui/popover'\nimport { useEditorI18n } from '../../../react/use-editor-i18n'\nimport { basketOf } from '../baskets'\nimport { compositeBasketsOf } from '../nodes'\nimport { compositeOfRow, type CompositeRow } from '../rows'\n\nconst OPTION = 'flex w-full items-center gap-2 rounded-sm px-2 py-1.5 text-left text-sm text-foreground transition-colors duration-150 hover:bg-muted focus-visible:outline-2 focus-visible:-outline-offset-2 focus-visible:outline-primary'\n\n/**\n * Basket choice of a Baustein: the child (a button) opens a list of the editor's baskets (a dot in the basket's colour\n * and its label) and „Kein Korb“. The menu is a popover, not a dropdown menu: a dropdown item cannot show a dot in an\n * arbitrary CSS colour.\n */\nexport function CompositeBasketMenu({ editor, row, children }: { editor: Editor, row: CompositeRow, children: ReactNode }) {\n const { t } = useEditorI18n()\n const [open, setOpen] = useState(false)\n\n const current = basketOf(row)\n\n function choose(next: string | null) {\n setOpen(false)\n const found = compositeOfRow(editor.state.doc, row)\n if (found) editor.commands.setCompositeBasket(next, found.pos)\n }\n\n return (\n <Popover open={open} onOpenChange={setOpen}>\n <PopoverTrigger asChild>{children}</PopoverTrigger>\n <PopoverContent\n side=\"bottom\"\n align=\"start\"\n sideOffset={4}\n className=\"w-40 gap-0 p-1\"\n onCloseAutoFocus={event => event.preventDefault()}\n >\n <div role=\"menu\" aria-label={t('composites.basket.label')}>\n {compositeBasketsOf(editor).map(candidate => (\n <button\n key={candidate.id}\n type=\"button\"\n role=\"menuitemradio\"\n aria-checked={current === candidate.id}\n className={OPTION}\n onClick={() => choose(candidate.id)}\n >\n <span className=\"size-2.5 shrink-0 rounded-full\" style={{ backgroundColor: candidate.color }} />\n <span className=\"truncate\">{candidate.label}</span>\n {current === candidate.id && <Icon name=\"i-lucide-check\" className=\"ml-auto size-3.5 shrink-0\" />}\n </button>\n ))}\n <button type=\"button\" role=\"menuitemradio\" aria-checked={current === null} className={OPTION} onClick={() => choose(null)}>\n <Icon name=\"i-lucide-circle-dashed\" className=\"size-3 shrink-0 text-muted-foreground\" />\n <span className=\"truncate\">{t('composites.basket.none')}</span>\n {current === null && <Icon name=\"i-lucide-check\" className=\"ml-auto size-3.5 shrink-0\" />}\n </button>\n </div>\n </PopoverContent>\n </Popover>\n )\n}\n"],"mappings":";;;;;;;;;AASA,MAAM,SAAS;;;;;;AAOf,SAAgB,oBAAoB,EAAE,QAAQ,KAAK,YAAwE;CACzH,MAAM,EAAE,MAAM,cAAc;CAC5B,MAAM,CAAC,MAAM,WAAW,SAAS,KAAK;CAEtC,MAAM,UAAU,SAAS,GAAG;CAE5B,SAAS,OAAO,MAAqB;EACnC,QAAQ,KAAK;EACb,MAAM,QAAQ,eAAe,OAAO,MAAM,KAAK,GAAG;EAClD,IAAI,OAAO,OAAO,SAAS,mBAAmB,MAAM,MAAM,GAAG;CAC/D;CAEA,OACE,qBAAC,SAAD;EAAe;EAAM,cAAc;EAAnC,UAAA,CACE,oBAAC,gBAAD;GAAgB,SAAA;GAAS;EAAyB,CAAA,GAClD,oBAAC,gBAAD;GACE,MAAK;GACL,OAAM;GACN,YAAY;GACZ,WAAU;GACV,mBAAkB,UAAS,MAAM,eAAe;GAEhD,UAAA,qBAAC,OAAD;IAAK,MAAK;IAAO,cAAY,EAAE,yBAAyB;IAAxD,UAAA,CACG,mBAAmB,MAAM,CAAC,CAAC,KAAI,cAC9B,qBAAC,UAAD;KAEE,MAAK;KACL,MAAK;KACL,gBAAc,YAAY,UAAU;KACpC,WAAW;KACX,eAAe,OAAO,UAAU,EAAE;KANpC,UAAA;MAQE,oBAAC,QAAD;OAAM,WAAU;OAAiC,OAAO,EAAE,iBAAiB,UAAU,MAAM;MAAI,CAAA;MAC/F,oBAAC,QAAD;OAAM,WAAU;OAAY,UAAA,UAAU;MAAY,CAAA;MACjD,YAAY,UAAU,MAAM,oBAAC,MAAD;OAAM,MAAK;OAAiB,WAAU;MAA6B,CAAA;KAC1F;IAVD,GAAA,UAAU,EAUT,CACT,GACD,qBAAC,UAAD;KAAQ,MAAK;KAAS,MAAK;KAAgB,gBAAc,YAAY;KAAM,WAAW;KAAQ,eAAe,OAAO,IAAI;KAAxH,UAAA;MACE,oBAAC,MAAD;OAAM,MAAK;OAAyB,WAAU;MAAyC,CAAA;MACvF,oBAAC,QAAD;OAAM,WAAU;OAAY,UAAA,EAAE,wBAAwB;MAAQ,CAAA;MAC7D,YAAY,QAAQ,oBAAC,MAAD;OAAM,MAAK;OAAiB,WAAU;MAA6B,CAAA;KAClF;IACL,CAAA,CAAA;;EACS,CAAA,CACT;;AAEb"}
1
+ {"version":3,"file":"CompositeBasketMenu.js","names":[],"sources":["../../../../src/features/composites/react/CompositeBasketMenu.tsx"],"sourcesContent":["import type { Editor } from '@tiptap/core'\nimport { type ReactNode, useState } from 'react'\nimport { Icon } from '../../../react/Icon'\nimport { Popover, PopoverContent, PopoverTrigger } from '../../../react/ui/popover'\nimport { useEditorI18n } from '../../../react/use-editor-i18n'\nimport { basketOf } from '../baskets'\nimport { compositeBasketsOf } from '../nodes'\nimport { compositeOfRow, type CompositeRow } from '../rows'\n\nconst OPTION = 'flex w-full items-center gap-2 rounded-sm px-2 py-1.5 text-left text-sm text-foreground transition-colors duration-150 hover:bg-muted focus-visible:outline-2 focus-visible:-outline-offset-2 focus-visible:outline-primary'\n\n/**\n * Basket choice of a Typed block: the child (a button) opens a list of the editor's baskets (a dot in the basket's colour\n * and its label) and a „none“ entry. The menu is a popover, not a dropdown menu: a dropdown item cannot show a dot in an\n * arbitrary CSS colour.\n */\nexport function CompositeBasketMenu({ editor, row, children }: { editor: Editor, row: CompositeRow, children: ReactNode }) {\n const { t } = useEditorI18n()\n const [open, setOpen] = useState(false)\n\n const current = basketOf(row)\n\n function choose(next: string | null) {\n setOpen(false)\n const found = compositeOfRow(editor.state.doc, row)\n if (found) editor.commands.setCompositeBasket(next, found.pos)\n }\n\n return (\n <Popover open={open} onOpenChange={setOpen}>\n <PopoverTrigger asChild>{children}</PopoverTrigger>\n <PopoverContent\n side=\"bottom\"\n align=\"start\"\n sideOffset={4}\n className=\"w-40 gap-0 p-1\"\n onCloseAutoFocus={event => event.preventDefault()}\n >\n <div role=\"menu\" aria-label={t('composites.basket.label')}>\n {compositeBasketsOf(editor).map(candidate => (\n <button\n key={candidate.id}\n type=\"button\"\n role=\"menuitemradio\"\n aria-checked={current === candidate.id}\n className={OPTION}\n onClick={() => choose(candidate.id)}\n >\n <span className=\"size-2.5 shrink-0 rounded-full\" style={{ backgroundColor: candidate.color }} />\n <span className=\"truncate\">{candidate.label}</span>\n {current === candidate.id && <Icon name=\"i-lucide-check\" className=\"ml-auto size-3.5 shrink-0\" />}\n </button>\n ))}\n <button type=\"button\" role=\"menuitemradio\" aria-checked={current === null} className={OPTION} onClick={() => choose(null)}>\n <Icon name=\"i-lucide-circle-dashed\" className=\"size-3 shrink-0 text-muted-foreground\" />\n <span className=\"truncate\">{t('composites.basket.none')}</span>\n {current === null && <Icon name=\"i-lucide-check\" className=\"ml-auto size-3.5 shrink-0\" />}\n </button>\n </div>\n </PopoverContent>\n </Popover>\n )\n}\n"],"mappings":";;;;;;;;;AASA,MAAM,SAAS;;;;;;AAOf,SAAgB,oBAAoB,EAAE,QAAQ,KAAK,YAAwE;CACzH,MAAM,EAAE,MAAM,cAAc;CAC5B,MAAM,CAAC,MAAM,WAAW,SAAS,KAAK;CAEtC,MAAM,UAAU,SAAS,GAAG;CAE5B,SAAS,OAAO,MAAqB;EACnC,QAAQ,KAAK;EACb,MAAM,QAAQ,eAAe,OAAO,MAAM,KAAK,GAAG;EAClD,IAAI,OAAO,OAAO,SAAS,mBAAmB,MAAM,MAAM,GAAG;CAC/D;CAEA,OACE,qBAAC,SAAD;EAAe;EAAM,cAAc;EAAnC,UAAA,CACE,oBAAC,gBAAD;GAAgB,SAAA;GAAS;EAAyB,CAAA,GAClD,oBAAC,gBAAD;GACE,MAAK;GACL,OAAM;GACN,YAAY;GACZ,WAAU;GACV,mBAAkB,UAAS,MAAM,eAAe;GAEhD,UAAA,qBAAC,OAAD;IAAK,MAAK;IAAO,cAAY,EAAE,yBAAyB;IAAxD,UAAA,CACG,mBAAmB,MAAM,CAAC,CAAC,KAAI,cAC9B,qBAAC,UAAD;KAEE,MAAK;KACL,MAAK;KACL,gBAAc,YAAY,UAAU;KACpC,WAAW;KACX,eAAe,OAAO,UAAU,EAAE;KANpC,UAAA;MAQE,oBAAC,QAAD;OAAM,WAAU;OAAiC,OAAO,EAAE,iBAAiB,UAAU,MAAM;MAAI,CAAA;MAC/F,oBAAC,QAAD;OAAM,WAAU;OAAY,UAAA,UAAU;MAAY,CAAA;MACjD,YAAY,UAAU,MAAM,oBAAC,MAAD;OAAM,MAAK;OAAiB,WAAU;MAA6B,CAAA;KAC1F;IAVD,GAAA,UAAU,EAUT,CACT,GACD,qBAAC,UAAD;KAAQ,MAAK;KAAS,MAAK;KAAgB,gBAAc,YAAY;KAAM,WAAW;KAAQ,eAAe,OAAO,IAAI;KAAxH,UAAA;MACE,oBAAC,MAAD;OAAM,MAAK;OAAyB,WAAU;MAAyC,CAAA;MACvF,oBAAC,QAAD;OAAM,WAAU;OAAY,UAAA,EAAE,wBAAwB;MAAQ,CAAA;MAC7D,YAAY,QAAQ,oBAAC,MAAD;OAAM,MAAK;OAAiB,WAAU;MAA6B,CAAA;KAClF;IACL,CAAA,CAAA;;EACS,CAAA,CACT;;AAEb"}
@@ -5,7 +5,7 @@ import { Editor } from "@tiptap/core";
5
5
  * chip and one chip per tag (with a `+` chip to add tags), and on the front the kind icon. The icon is a button that
6
6
  * opens the details popover (kind with a confirmation before it changes, the kind's fields and the summary;
7
7
  * `CompositeDetails`) and, in an editable editor, the composite's drag handle: dragging it moves the composite
8
- * (`startBlockDrag`). With `blocks.kindIcon: 'hover'` it shows only while the composite is hovered, its popover is
8
+ * (`startBlockDrag`). With `blocks.blockTypeIcon: 'hover'` it shows only while the composite is hovered, its popover is
9
9
  * open or the icon has keyboard focus. Chips and popover also render in read-only editors, without edit affordances.
10
10
  * The node view's own description and tags rows are hidden by CSS; this overlay shows and edits them.
11
11
  */