@ecsplico/editor 3.5.1 → 4.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (583) hide show
  1. package/CHANGELOG.md +71 -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 -7
  268. package/dist/features/composites/merge.js +39 -12
  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 +1 -1
  374. package/dist/features/image-studio/components/ImageStudioDialog.js.map +1 -1
  375. package/dist/features/image-studio/components/ImageStudioDialog.vue.d.ts +1 -1
  376. package/dist/features/image-studio/components/ImageStudioView.js.map +1 -1
  377. package/dist/features/image-studio/feature.d.ts +1 -1
  378. package/dist/features/image-studio/feature.js +1 -1
  379. package/dist/features/image-studio/feature.js.map +1 -1
  380. package/dist/features/image-studio/node-core.d.ts +3 -3
  381. package/dist/features/image-studio/node-core.js +1 -1
  382. package/dist/features/image-studio/node-core.js.map +1 -1
  383. package/dist/features/image-studio/node-store.d.ts +1 -1
  384. package/dist/features/image-studio/node-store.js +1 -1
  385. package/dist/features/image-studio/node-store.js.map +1 -1
  386. package/dist/features/image-studio/react/ImageStudioDialog.d.ts +1 -1
  387. package/dist/features/image-studio/react/ImageStudioDialog.js +1 -1
  388. package/dist/features/image-studio/react/ImageStudioDialog.js.map +1 -1
  389. package/dist/features/image-studio/react/ImageStudioView.js +1 -1
  390. package/dist/features/image-studio/react/ImageStudioView.js.map +1 -1
  391. package/dist/features/image-studio/react/store.d.ts +3 -3
  392. package/dist/features/image-studio/react/store.js.map +1 -1
  393. package/dist/features/image-studio/react.d.ts +1 -1
  394. package/dist/features/image-studio/react.js +1 -1
  395. package/dist/features/image-studio/react.js.map +1 -1
  396. package/dist/features/image-studio/schema.d.ts +1 -1
  397. package/dist/features/image-studio/schema.js +1 -1
  398. package/dist/features/image-studio/schema.js.map +1 -1
  399. package/dist/features/image-studio/state.d.ts +3 -3
  400. package/dist/features/image-studio/state.js +2 -2
  401. package/dist/features/image-studio/state.js.map +1 -1
  402. package/dist/features/image-studio/store.d.ts +3 -3
  403. package/dist/features/image-studio/vue.d.ts +1 -1
  404. package/dist/features/image-studio/vue.js +1 -1
  405. package/dist/features/image-studio/vue.js.map +1 -1
  406. package/dist/features/media/index.js +1 -1
  407. package/dist/features/media/react/AudioRecorderModal.js +1 -1
  408. package/dist/features/media/react.js +1 -1
  409. package/dist/features/mentions/tag.js +2 -1
  410. package/dist/features/mentions/tag.js.map +1 -1
  411. package/dist/features/themes/components/SettingsAppearanceTab.js +1 -1
  412. package/dist/features/themes/components/SettingsAppearanceTab.js.map +1 -1
  413. package/dist/features/themes/feature.d.ts +1 -1
  414. package/dist/features/themes/feature.js.map +1 -1
  415. package/dist/features/themes/react/SettingsAppearanceTab.d.ts +1 -1
  416. package/dist/features/themes/react/SettingsAppearanceTab.js +1 -1
  417. package/dist/features/themes/react/SettingsAppearanceTab.js.map +1 -1
  418. package/dist/features/themes/theme-runtime.js +1 -1
  419. package/dist/features/themes/theme-runtime.js.map +1 -1
  420. package/dist/features/transcript/TranscriptSegmentView.js +1 -1
  421. package/dist/features/transcript/TranscriptSegmentView.js.map +1 -1
  422. package/dist/features/transcript/react/TranscriptSegmentView.js +1 -1
  423. package/dist/features/transcript/react/TranscriptSegmentView.js.map +1 -1
  424. package/dist/features/transcript/segment-node.js.map +1 -1
  425. package/dist/features/transfer/feature.js +1 -1
  426. package/dist/features/transfer/feature.js.map +1 -1
  427. package/dist/features/transfer/transforms.d.ts +4 -4
  428. package/dist/features/transfer/transforms.js +12 -12
  429. package/dist/features/transfer/transforms.js.map +1 -1
  430. package/dist/i18n/de/ai.js +4 -4
  431. package/dist/i18n/de/ai.js.map +1 -1
  432. package/dist/i18n/de/authors.js +1 -1
  433. package/dist/i18n/de/authors.js.map +1 -1
  434. package/dist/i18n/de/comments.js +1 -1
  435. package/dist/i18n/de/comments.js.map +1 -1
  436. package/dist/i18n/de/composites.js +62 -59
  437. package/dist/i18n/de/composites.js.map +1 -1
  438. package/dist/i18n/de/image-studio.js +2 -2
  439. package/dist/i18n/de/image-studio.js.map +1 -1
  440. package/dist/i18n/de/integrations.js +20 -20
  441. package/dist/i18n/de/integrations.js.map +1 -1
  442. package/dist/i18n/de/markdown.js +1 -1
  443. package/dist/i18n/de/markdown.js.map +1 -1
  444. package/dist/i18n/de/palette.js +1 -1
  445. package/dist/i18n/de/palette.js.map +1 -1
  446. package/dist/i18n/de/themes.js +3 -3
  447. package/dist/i18n/de/themes.js.map +1 -1
  448. package/dist/i18n/de/transfer.js +2 -2
  449. package/dist/i18n/de/transfer.js.map +1 -1
  450. package/dist/i18n/de/tree.js +6 -6
  451. package/dist/i18n/de/tree.js.map +1 -1
  452. package/dist/i18n/de.d.ts +101 -98
  453. package/dist/i18n/en/ai.js +2 -2
  454. package/dist/i18n/en/ai.js.map +1 -1
  455. package/dist/i18n/en/composites.js +64 -61
  456. package/dist/i18n/en/composites.js.map +1 -1
  457. package/dist/i18n/en/integrations.js +9 -9
  458. package/dist/i18n/en/integrations.js.map +1 -1
  459. package/dist/i18n/en/markdown.js +1 -1
  460. package/dist/i18n/en/markdown.js.map +1 -1
  461. package/dist/i18n/en/palette.js +1 -1
  462. package/dist/i18n/en/palette.js.map +1 -1
  463. package/dist/i18n/en/themes.js +4 -4
  464. package/dist/i18n/en/themes.js.map +1 -1
  465. package/dist/i18n/en/tree.js +5 -5
  466. package/dist/i18n/en/tree.js.map +1 -1
  467. package/dist/index.d.ts +4 -1
  468. package/dist/integrations/composite-ai/bibliography-fetch.d.ts +6 -6
  469. package/dist/integrations/composite-ai/bibliography-fetch.js +19 -19
  470. package/dist/integrations/composite-ai/bibliography-fetch.js.map +1 -1
  471. package/dist/integrations/composite-ai/composite-fill.d.ts +4 -4
  472. package/dist/integrations/composite-ai/composite-fill.js +5 -5
  473. package/dist/integrations/composite-ai/composite-fill.js.map +1 -1
  474. package/dist/integrations/composite-ai/composite-summary.d.ts +2 -2
  475. package/dist/integrations/composite-ai/composite-summary.js +5 -5
  476. package/dist/integrations/composite-ai/composite-summary.js.map +1 -1
  477. package/dist/integrations/composite-ai/derive.d.ts +17 -17
  478. package/dist/integrations/composite-ai/derive.js +27 -26
  479. package/dist/integrations/composite-ai/derive.js.map +1 -1
  480. package/dist/integrations/composite-ai/index.d.ts +14 -15
  481. package/dist/integrations/composite-ai/index.js +98 -77
  482. package/dist/integrations/composite-ai/index.js.map +1 -1
  483. package/dist/integrations/composite-ai/outline-sanitize.d.ts +1 -1
  484. package/dist/integrations/composite-ai/outline-sanitize.js +1 -1
  485. package/dist/integrations/composite-ai/outline-sanitize.js.map +1 -1
  486. package/dist/integrations/composite-ai/rendition.d.ts +9 -9
  487. package/dist/integrations/composite-ai/rendition.js +27 -27
  488. package/dist/integrations/composite-ai/rendition.js.map +1 -1
  489. package/dist/integrations/composite-ai/split.d.ts +8 -8
  490. package/dist/integrations/composite-ai/split.js +12 -12
  491. package/dist/integrations/composite-ai/split.js.map +1 -1
  492. package/dist/integrations/composite-ai/transfer-transforms.d.ts +2 -2
  493. package/dist/integrations/composite-ai/transfer-transforms.js +12 -12
  494. package/dist/integrations/composite-ai/transfer-transforms.js.map +1 -1
  495. package/dist/integrations/composite-media/index.d.ts +4 -3
  496. package/dist/integrations/composite-media/index.js +20 -14
  497. package/dist/integrations/composite-media/index.js.map +1 -1
  498. package/dist/markdown/MarkdownSurface.vue.d.ts +7 -7
  499. package/dist/markdown/document.js +1 -1
  500. package/dist/markdown/document.js.map +1 -1
  501. package/dist/nuxt/module.d.ts +30 -24
  502. package/dist/nuxt/module.js.map +1 -1
  503. package/dist/nuxt/runtime/server/plugins/editor-server.js +3 -2
  504. package/dist/nuxt/runtime/server/plugins/editor-server.js.map +1 -1
  505. package/dist/presets/compose.d.ts +6 -6
  506. package/dist/presets/compose.js +8 -5
  507. package/dist/presets/compose.js.map +1 -1
  508. package/dist/react/AdvancedEditor.d.ts +2 -2
  509. package/dist/react/AdvancedEditor.js +1 -1
  510. package/dist/react/AdvancedEditor.js.map +1 -1
  511. package/dist/react/compose.d.ts +1 -1
  512. package/dist/react/compose.js +2 -2
  513. package/dist/react/compose.js.map +1 -1
  514. package/dist/react/composed-surface.d.ts +5 -5
  515. package/dist/react/composed-surface.js +2 -2
  516. package/dist/react/composed-surface.js.map +1 -1
  517. package/dist/server/ai.d.ts +7 -7
  518. package/dist/server/ai.js +1 -1
  519. package/dist/server/ai.js.map +1 -1
  520. package/dist/server/auth.d.ts +1 -1
  521. package/dist/server/collab-state.d.ts +1 -1
  522. package/dist/server/collab-state.js.map +1 -1
  523. package/dist/server/collab.d.ts +4 -4
  524. package/dist/server/collab.js +22 -17
  525. package/dist/server/collab.js.map +1 -1
  526. package/dist/server/handlers/ai.d.ts +9 -6
  527. package/dist/server/handlers/ai.js +13 -17
  528. package/dist/server/handlers/ai.js.map +1 -1
  529. package/dist/server/handlers/context.d.ts +4 -0
  530. package/dist/server/handlers/context.js.map +1 -1
  531. package/dist/server/handlers/editor.d.ts +33 -32
  532. package/dist/server/handlers/editor.js +13 -8
  533. package/dist/server/handlers/editor.js.map +1 -1
  534. package/dist/server/handlers/images.d.ts +1 -1
  535. package/dist/server/handlers/images.js +1 -1
  536. package/dist/server/handlers/images.js.map +1 -1
  537. package/dist/server/host.d.ts +4 -0
  538. package/dist/server/host.js +10 -2
  539. package/dist/server/host.js.map +1 -1
  540. package/dist/server/index.d.ts +3 -3
  541. package/dist/server/ports.d.ts +8 -8
  542. package/dist/server/ports.js.map +1 -1
  543. package/dist/settings/index.d.ts +20 -19
  544. package/dist/settings/index.js +25 -24
  545. package/dist/settings/index.js.map +1 -1
  546. package/dist/settings/migrate.d.ts +18 -0
  547. package/dist/settings/migrate.js +46 -0
  548. package/dist/settings/migrate.js.map +1 -0
  549. package/dist/settings/values.d.ts +12 -12
  550. package/dist/settings/values.js +11 -11
  551. package/dist/settings/values.js.map +1 -1
  552. package/dist/styles/composites.css +10 -10
  553. package/dist/tree/DocumentTree.js +12 -5
  554. package/dist/tree/DocumentTree.js.map +1 -1
  555. package/dist/tree/drop-rules.js +5 -5
  556. package/dist/tree/drop-rules.js.map +1 -1
  557. package/dist/tree/react/DocumentTree.js +14 -5
  558. package/dist/tree/react/DocumentTree.js.map +1 -1
  559. package/dist/tree/tree-host.js +6 -6
  560. package/dist/tree/tree-host.js.map +1 -1
  561. package/dist/tree/tree-items.js +34 -28
  562. package/dist/tree/tree-items.js.map +1 -1
  563. package/dist/tree/tree-model.js +16 -16
  564. package/dist/tree/tree-model.js.map +1 -1
  565. package/dist/tree/tree-rows.js +2 -2
  566. package/dist/tree/tree-rows.js.map +1 -1
  567. package/dist/tree/tree-view-model.d.ts +2 -2
  568. package/dist/tree/tree-view-model.js.map +1 -1
  569. package/dist/vue/AdvancedEditor.js +2 -2
  570. package/dist/vue/AdvancedEditor.js.map +1 -1
  571. package/dist/vue/AdvancedEditor.vue.d.ts +10 -10
  572. package/dist/vue/SimpleEditor.vue.d.ts +4 -4
  573. package/dist/vue/components/EditorSurface.vue.d.ts +4 -4
  574. package/dist/vue/compose.d.ts +1 -1
  575. package/dist/vue/compose.js +2 -2
  576. package/dist/vue/compose.js.map +1 -1
  577. package/package.json +1 -1
  578. package/dist/features/composites/derivation.d.ts +0 -62
  579. package/dist/features/composites/derivation.js +0 -102
  580. package/dist/features/composites/derivation.js.map +0 -1
  581. package/dist/features/composites/kinds.d.ts +0 -83
  582. package/dist/features/composites/kinds.js +0 -285
  583. package/dist/features/composites/kinds.js.map +0 -1
@@ -11,8 +11,9 @@ export interface BlockUiUi<C> {
11
11
  * Block-level UI beside the editor content: the drag handle (upstream `@tiptap/extension-drag-handle`) with hover
12
12
  * targeting, and the actions of the targeted block (features' and host block actions, `BlockActionsOverlay`), on the
13
13
  * hover bar, the toolbar of the block holding the selection, or both (`BlockUiOptions.actions`; hover by default).
14
- * Also adds block-range selection (`NodeRange`: Mod+drag, Shift+↑/↓). Composite chrome (`editorChrome` nodes) targets its
15
- * parent block.
14
+ * Also adds block-range selection (`NodeRange`: Mod+drag, Shift+↑/↓). The target is the outermost block below the nearest
15
+ * block container (`outerBlockAt`): a list item or a quote paragraph targets its list or quote; composite chrome
16
+ * (`editorChrome` nodes) targets its parent block.
16
17
  *
17
18
  * Opt-in: the simple editor has none of it. Installing a binding also bundles the drag handle's transitive collaboration
18
19
  * support code (its upstream package imports `@tiptap/extension-collaboration` and `y-tiptap`), even without a live
@@ -4,8 +4,9 @@ import { NodeRange } from "@tiptap/extension-node-range";
4
4
  * Block-level UI beside the editor content: the drag handle (upstream `@tiptap/extension-drag-handle`) with hover
5
5
  * targeting, and the actions of the targeted block (features' and host block actions, `BlockActionsOverlay`), on the
6
6
  * hover bar, the toolbar of the block holding the selection, or both (`BlockUiOptions.actions`; hover by default).
7
- * Also adds block-range selection (`NodeRange`: Mod+drag, Shift+↑/↓). Composite chrome (`editorChrome` nodes) targets its
8
- * parent block.
7
+ * Also adds block-range selection (`NodeRange`: Mod+drag, Shift+↑/↓). The target is the outermost block below the nearest
8
+ * block container (`outerBlockAt`): a list item or a quote paragraph targets its list or quote; composite chrome
9
+ * (`editorChrome` nodes) targets its parent block.
9
10
  *
10
11
  * Opt-in: the simple editor has none of it. Installing a binding also bundles the drag handle's transitive collaboration
11
12
  * support code (its upstream package imports `@tiptap/extension-collaboration` and `y-tiptap`), even without a live
@@ -1 +1 @@
1
- {"version":3,"file":"feature.js","names":[],"sources":["../../../src/features/block-ui/feature.ts"],"sourcesContent":["import { NodeRange } from '@tiptap/extension-node-range'\nimport type { BlockUiOptions, EditorFeature } from '../../core'\n\n// The option types live in `core` (the editor entry carries them to the overlay); this is their public home.\nexport type { BlockActionSurface, BlockUiOptions } from '../../core'\n\n/** What a framework binding supplies to the block-ui feature. */\nexport interface BlockUiUi<C> {\n /** The block UI of an editor (drag handle, permanent handles, hover actions); mounted beside the editor content. */\n overlay: C\n}\n\n/**\n * Block-level UI beside the editor content: the drag handle (upstream `@tiptap/extension-drag-handle`) with hover\n * targeting, and the actions of the targeted block (features' and host block actions, `BlockActionsOverlay`), on the\n * hover bar, the toolbar of the block holding the selection, or both (`BlockUiOptions.actions`; hover by default).\n * Also adds block-range selection (`NodeRange`: Mod+drag, Shift+↑/↓). Composite chrome (`editorChrome` nodes) targets its\n * parent block.\n *\n * Opt-in: the simple editor has none of it. Installing a binding also bundles the drag handle's transitive collaboration\n * support code (its upstream package imports `@tiptap/extension-collaboration` and `y-tiptap`), even without a live\n * collaboration session.\n *\n * The overlay is a component type the surface mounts without props, so `options` reach it through `EditorFeature.blockUi`\n * and the editor entry (`editorEntryOf(editor)?.blockUi`).\n */\nexport function blockUiFeatureCore<C>(ui: BlockUiUi<C>, options: BlockUiOptions = {}): EditorFeature<C> {\n return {\n id: 'block-ui',\n dimension: 'interaction',\n extensions: () => [NodeRange],\n blockUi: options,\n overlays: [ui.overlay],\n }\n}\n"],"mappings":";;;;;;;;;;;;;;;;AA0BA,SAAgB,mBAAsB,IAAkB,UAA0B,CAAC,GAAqB;CACtG,OAAO;EACL,IAAI;EACJ,WAAW;EACX,kBAAkB,CAAC,SAAS;EAC5B,SAAS;EACT,UAAU,CAAC,GAAG,OAAO;CACvB;AACF"}
1
+ {"version":3,"file":"feature.js","names":[],"sources":["../../../src/features/block-ui/feature.ts"],"sourcesContent":["import { NodeRange } from '@tiptap/extension-node-range'\nimport type { BlockUiOptions, EditorFeature } from '../../core'\n\n// The option types live in `core` (the editor entry carries them to the overlay); this is their public home.\nexport type { BlockActionSurface, BlockUiOptions } from '../../core'\n\n/** What a framework binding supplies to the block-ui feature. */\nexport interface BlockUiUi<C> {\n /** The block UI of an editor (drag handle, permanent handles, hover actions); mounted beside the editor content. */\n overlay: C\n}\n\n/**\n * Block-level UI beside the editor content: the drag handle (upstream `@tiptap/extension-drag-handle`) with hover\n * targeting, and the actions of the targeted block (features' and host block actions, `BlockActionsOverlay`), on the\n * hover bar, the toolbar of the block holding the selection, or both (`BlockUiOptions.actions`; hover by default).\n * Also adds block-range selection (`NodeRange`: Mod+drag, Shift+↑/↓). The target is the outermost block below the nearest\n * block container (`outerBlockAt`): a list item or a quote paragraph targets its list or quote; composite chrome\n * (`editorChrome` nodes) targets its parent block.\n *\n * Opt-in: the simple editor has none of it. Installing a binding also bundles the drag handle's transitive collaboration\n * support code (its upstream package imports `@tiptap/extension-collaboration` and `y-tiptap`), even without a live\n * collaboration session.\n *\n * The overlay is a component type the surface mounts without props, so `options` reach it through `EditorFeature.blockUi`\n * and the editor entry (`editorEntryOf(editor)?.blockUi`).\n */\nexport function blockUiFeatureCore<C>(ui: BlockUiUi<C>, options: BlockUiOptions = {}): EditorFeature<C> {\n return {\n id: 'block-ui',\n dimension: 'interaction',\n extensions: () => [NodeRange],\n blockUi: options,\n overlays: [ui.overlay],\n }\n}\n"],"mappings":";;;;;;;;;;;;;;;;;AA2BA,SAAgB,mBAAsB,IAAkB,UAA0B,CAAC,GAAqB;CACtG,OAAO;EACL,IAAI;EACJ,WAAW;EACX,kBAAkB,CAAC,SAAS;EAC5B,SAAS;EACT,UAAU,CAAC,GAAG,OAAO;CACvB;AACF"}
@@ -1,23 +1,13 @@
1
- import { isChromeNode } from "../../core/schema/node-flags.js";
1
+ import { isBlockContainer, isChromeNode } from "../../core/schema/node-flags.js";
2
2
  //#region src/features/block-ui/handle-geometry.ts
3
- const LIST_ITEMS = ["listItem", "taskItem"];
4
- const TABLE_STRUCTURE = [
5
- "tableRow",
6
- "tableCell",
7
- "tableHeader"
8
- ];
9
3
  /** Whether a block shows its own kind icon (a composite's `.composite__toggle`): the icon is its drag handle, so it gets no standard one. */
10
- function hasKindIcon(dom) {
4
+ function hasBlockTypeIcon(dom) {
11
5
  return dom.querySelector(":scope > .composite__toggle") !== null;
12
6
  }
13
- function gutterShiftOf(node, dom) {
14
- const list = node.type.name === "listItem" ? dom.parentElement : null;
15
- return list ? dom.getBoundingClientRect().left - list.getBoundingClientRect().left : 0;
16
- }
17
- /** Left edge of the handle column of the block `node` rendered as `dom` (the block's own left edge when it has no handle). */
18
- function handleLeftOf(node, dom, handleWidth) {
7
+ /** Left edge of the handle column of the block rendered as `dom` (the block's own left edge when it has no handle). */
8
+ function handleLeftOf(dom, handleWidth) {
19
9
  const left = dom.getBoundingClientRect().left;
20
- return hasKindIcon(dom) ? left : left - handleWidth - gutterShiftOf(node, dom);
10
+ return hasBlockTypeIcon(dom) ? left : left - handleWidth;
21
11
  }
22
12
  function firstLineCenterShift(dom, referenceTop, handleHeight) {
23
13
  const textblock = dom.matches("p, h1, h2, h3, h4, h5, h6, pre") ? dom : dom.querySelector("p, h1, h2, h3, h4, h5, h6, pre");
@@ -27,19 +17,18 @@ function firstLineCenterShift(dom, referenceTop, handleHeight) {
27
17
  return textblock.getBoundingClientRect().top + Number.parseFloat(style.paddingTop) - referenceTop + (lineHeight - handleHeight) / 2;
28
18
  }
29
19
  /**
30
- * The blocks that get a permanent handle (`blocks.dragHandle: 'always'`): every block the hover handle can target, at any
31
- * depth, in document order. Not eligible, like for the hover handle: inline content, composite chrome (it stands for
32
- * its composite), table rows and cells, content of table headers, list wrappers (their items are), and the first block
33
- * of a list item (the item is). Blocks with a kind icon have the icon as their handle.
20
+ * The blocks that get a permanent handle (`blocks.dragHandle: 'always'`): every block the hover handle can target
21
+ * (`outerBlockRule`), at any depth, in document order: a block directly below a block container (the document or a
22
+ * Typed block's body). Not eligible: inline content, Typed block chrome (it stands for its Typed block), and everything
23
+ * inside a list, quote or table (the list, quote or table is the block). Blocks with a kind icon have the icon as their handle.
34
24
  */
35
25
  function handleBlocksOf(view) {
36
26
  const blocks = [];
37
- view.state.doc.descendants((node, pos, parent, index) => {
27
+ view.state.doc.descendants((node, pos, parent) => {
38
28
  if (node.isInline || isChromeNode(node)) return false;
39
29
  const dom = view.nodeDOM(pos);
40
30
  if (!(dom instanceof HTMLElement)) return;
41
- if (!(TABLE_STRUCTURE.includes(node.type.name) || parent !== null && parent.type.name === "tableHeader" || node.firstChild !== null && LIST_ITEMS.includes(node.firstChild.type.name) || index === 0 && parent !== null && LIST_ITEMS.includes(parent.type.name)) && !hasKindIcon(dom)) blocks.push({
42
- node,
31
+ if (parent !== null && isBlockContainer(parent) && !hasBlockTypeIcon(dom)) blocks.push({
43
32
  pos,
44
33
  dom
45
34
  });
@@ -47,6 +36,6 @@ function handleBlocksOf(view) {
47
36
  return blocks;
48
37
  }
49
38
  //#endregion
50
- export { firstLineCenterShift, gutterShiftOf, handleBlocksOf, handleLeftOf, hasKindIcon };
39
+ export { firstLineCenterShift, handleBlocksOf, handleLeftOf, hasBlockTypeIcon };
51
40
 
52
41
  //# sourceMappingURL=handle-geometry.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"handle-geometry.js","names":[],"sources":["../../../src/features/block-ui/handle-geometry.ts"],"sourcesContent":["import type { Node } from '@tiptap/pm/model'\nimport type { EditorView } from '@tiptap/pm/view'\nimport { isChromeNode } from '../../core/schema'\n\n// Where the drag handle sits and which blocks have one. Shared by the hover handle (`BlockUi`, upstream plugin) and the\n// permanent handles (`BlockHandles`), so both put the handle at the same place.\n\n/** Width and height of a handle: the hover handle's `size-6`. */\nexport const HANDLE_SIZE = 24\n\nconst LIST_ITEMS = ['listItem', 'taskItem']\nconst TABLE_STRUCTURE = ['tableRow', 'tableCell', 'tableHeader']\n\n/** Whether a block shows its own kind icon (a composite's `.composite__toggle`): the icon is its drag handle, so it gets no standard one. */\nexport function hasKindIcon(dom: HTMLElement): boolean {\n return dom.querySelector(':scope > .composite__toggle') !== null\n}\n\n// The handle's right edge sits on the block's left edge. A list item's marker sits in the list's left padding, exactly\n// where that puts the handle, so for list items the handle moves further left by the list's indent and lands left of\n// the bullet.\nexport function gutterShiftOf(node: Node, dom: HTMLElement): number {\n const list = node.type.name === 'listItem' ? dom.parentElement : null\n return list ? dom.getBoundingClientRect().left - list.getBoundingClientRect().left : 0\n}\n\n/** Left edge of the handle column of the block `node` rendered as `dom` (the block's own left edge when it has no handle). */\nexport function handleLeftOf(node: Node, dom: HTMLElement, handleWidth: number): number {\n const left = dom.getBoundingClientRect().left\n return hasKindIcon(dom) ? left : left - handleWidth - gutterShiftOf(node, dom)\n}\n\n// The plugin aligns the handle's top with the block's top, which sits above the middle of the block's first text line.\n// This shift puts the handle's centre on the centre of that line, counted from `referenceTop`.\nexport function firstLineCenterShift(dom: HTMLElement, referenceTop: number, handleHeight: number): number {\n const textblock = dom.matches('p, h1, h2, h3, h4, h5, h6, pre')\n ? dom\n : dom.querySelector<HTMLElement>('p, h1, h2, h3, h4, h5, h6, pre')\n if (!textblock) return 0\n const style = getComputedStyle(textblock)\n const lineHeight = Number.parseFloat(style.lineHeight) || Number.parseFloat(style.fontSize) * 1.2\n const lineTop = textblock.getBoundingClientRect().top + Number.parseFloat(style.paddingTop)\n return lineTop - referenceTop + (lineHeight - handleHeight) / 2\n}\n\n/**\n * The blocks that get a permanent handle (`blocks.dragHandle: 'always'`): every block the hover handle can target, at any\n * depth, in document order. Not eligible, like for the hover handle: inline content, composite chrome (it stands for\n * its composite), table rows and cells, content of table headers, list wrappers (their items are), and the first block\n * of a list item (the item is). Blocks with a kind icon have the icon as their handle.\n */\nexport function handleBlocksOf(view: EditorView): { node: Node, pos: number, dom: HTMLElement }[] {\n const blocks: { node: Node, pos: number, dom: HTMLElement }[] = []\n view.state.doc.descendants((node, pos, parent, index) => {\n if (node.isInline || isChromeNode(node)) return false\n const dom = view.nodeDOM(pos)\n if (!(dom instanceof HTMLElement)) return\n const structural = TABLE_STRUCTURE.includes(node.type.name)\n || (parent !== null && parent.type.name === 'tableHeader')\n || (node.firstChild !== null && LIST_ITEMS.includes(node.firstChild.type.name))\n || (index === 0 && parent !== null && LIST_ITEMS.includes(parent.type.name))\n if (!structural && !hasKindIcon(dom)) blocks.push({ node, pos, dom })\n })\n return blocks\n}\n"],"mappings":";;AAUA,MAAM,aAAa,CAAC,YAAY,UAAU;AAC1C,MAAM,kBAAkB;CAAC;CAAY;CAAa;AAAa;;AAG/D,SAAgB,YAAY,KAA2B;CACrD,OAAO,IAAI,cAAc,6BAA6B,MAAM;AAC9D;AAKA,SAAgB,cAAc,MAAY,KAA0B;CAClE,MAAM,OAAO,KAAK,KAAK,SAAS,aAAa,IAAI,gBAAgB;CACjE,OAAO,OAAO,IAAI,sBAAsB,CAAC,CAAC,OAAO,KAAK,sBAAsB,CAAC,CAAC,OAAO;AACvF;;AAGA,SAAgB,aAAa,MAAY,KAAkB,aAA6B;CACtF,MAAM,OAAO,IAAI,sBAAsB,CAAC,CAAC;CACzC,OAAO,YAAY,GAAG,IAAI,OAAO,OAAO,cAAc,cAAc,MAAM,GAAG;AAC/E;AAIA,SAAgB,qBAAqB,KAAkB,cAAsB,cAA8B;CACzG,MAAM,YAAY,IAAI,QAAQ,gCAAgC,IAC1D,MACA,IAAI,cAA2B,gCAAgC;CACnE,IAAI,CAAC,WAAW,OAAO;CACvB,MAAM,QAAQ,iBAAiB,SAAS;CACxC,MAAM,aAAa,OAAO,WAAW,MAAM,UAAU,KAAK,OAAO,WAAW,MAAM,QAAQ,IAAI;CAE9F,OADgB,UAAU,sBAAsB,CAAC,CAAC,MAAM,OAAO,WAAW,MAAM,UAAU,IACzE,gBAAgB,aAAa,gBAAgB;AAChE;;;;;;;AAQA,SAAgB,eAAe,MAAmE;CAChG,MAAM,SAA0D,CAAC;CACjE,KAAK,MAAM,IAAI,aAAa,MAAM,KAAK,QAAQ,UAAU;EACvD,IAAI,KAAK,YAAY,aAAa,IAAI,GAAG,OAAO;EAChD,MAAM,MAAM,KAAK,QAAQ,GAAG;EAC5B,IAAI,EAAE,eAAe,cAAc;EAKnC,IAAI,EAJe,gBAAgB,SAAS,KAAK,KAAK,IAAI,KACpD,WAAW,QAAQ,OAAO,KAAK,SAAS,iBACxC,KAAK,eAAe,QAAQ,WAAW,SAAS,KAAK,WAAW,KAAK,IAAI,KACzE,UAAU,KAAK,WAAW,QAAQ,WAAW,SAAS,OAAO,KAAK,IAAI,MACzD,CAAC,YAAY,GAAG,GAAG,OAAO,KAAK;GAAE;GAAM;GAAK;EAAI,CAAC;CACtE,CAAC;CACD,OAAO;AACT"}
1
+ {"version":3,"file":"handle-geometry.js","names":[],"sources":["../../../src/features/block-ui/handle-geometry.ts"],"sourcesContent":["import type { EditorView } from '@tiptap/pm/view'\nimport { isBlockContainer, isChromeNode } from '../../core/schema'\n\n// Where the drag handle sits and which blocks have one. Shared by the hover handle (`BlockUi`, upstream plugin) and the\n// permanent handles (`BlockHandles`), so both put the handle at the same place.\n\n/** Width and height of a handle: the hover handle's `size-6`. */\nexport const HANDLE_SIZE = 24\n\n/** Whether a block shows its own kind icon (a composite's `.composite__toggle`): the icon is its drag handle, so it gets no standard one. */\nexport function hasBlockTypeIcon(dom: HTMLElement): boolean {\n return dom.querySelector(':scope > .composite__toggle') !== null\n}\n\n/** Left edge of the handle column of the block rendered as `dom` (the block's own left edge when it has no handle). */\nexport function handleLeftOf(dom: HTMLElement, handleWidth: number): number {\n const left = dom.getBoundingClientRect().left\n return hasBlockTypeIcon(dom) ? left : left - handleWidth\n}\n\n// The plugin aligns the handle's top with the block's top, which sits above the middle of the block's first text line.\n// This shift puts the handle's centre on the centre of that line, counted from `referenceTop`.\nexport function firstLineCenterShift(dom: HTMLElement, referenceTop: number, handleHeight: number): number {\n const textblock = dom.matches('p, h1, h2, h3, h4, h5, h6, pre')\n ? dom\n : dom.querySelector<HTMLElement>('p, h1, h2, h3, h4, h5, h6, pre')\n if (!textblock) return 0\n const style = getComputedStyle(textblock)\n const lineHeight = Number.parseFloat(style.lineHeight) || Number.parseFloat(style.fontSize) * 1.2\n const lineTop = textblock.getBoundingClientRect().top + Number.parseFloat(style.paddingTop)\n return lineTop - referenceTop + (lineHeight - handleHeight) / 2\n}\n\n/**\n * The blocks that get a permanent handle (`blocks.dragHandle: 'always'`): every block the hover handle can target\n * (`outerBlockRule`), at any depth, in document order: a block directly below a block container (the document or a\n * Typed block's body). Not eligible: inline content, Typed block chrome (it stands for its Typed block), and everything\n * inside a list, quote or table (the list, quote or table is the block). Blocks with a kind icon have the icon as their handle.\n */\nexport function handleBlocksOf(view: EditorView): { pos: number, dom: HTMLElement }[] {\n const blocks: { pos: number, dom: HTMLElement }[] = []\n view.state.doc.descendants((node, pos, parent) => {\n if (node.isInline || isChromeNode(node)) return false\n const dom = view.nodeDOM(pos)\n if (!(dom instanceof HTMLElement)) return\n if (parent !== null && isBlockContainer(parent) && !hasBlockTypeIcon(dom)) blocks.push({ pos, dom })\n })\n return blocks\n}\n"],"mappings":";;;AAUA,SAAgB,iBAAiB,KAA2B;CAC1D,OAAO,IAAI,cAAc,6BAA6B,MAAM;AAC9D;;AAGA,SAAgB,aAAa,KAAkB,aAA6B;CAC1E,MAAM,OAAO,IAAI,sBAAsB,CAAC,CAAC;CACzC,OAAO,iBAAiB,GAAG,IAAI,OAAO,OAAO;AAC/C;AAIA,SAAgB,qBAAqB,KAAkB,cAAsB,cAA8B;CACzG,MAAM,YAAY,IAAI,QAAQ,gCAAgC,IAC1D,MACA,IAAI,cAA2B,gCAAgC;CACnE,IAAI,CAAC,WAAW,OAAO;CACvB,MAAM,QAAQ,iBAAiB,SAAS;CACxC,MAAM,aAAa,OAAO,WAAW,MAAM,UAAU,KAAK,OAAO,WAAW,MAAM,QAAQ,IAAI;CAE9F,OADgB,UAAU,sBAAsB,CAAC,CAAC,MAAM,OAAO,WAAW,MAAM,UAAU,IACzE,gBAAgB,aAAa,gBAAgB;AAChE;;;;;;;AAQA,SAAgB,eAAe,MAAuD;CACpF,MAAM,SAA8C,CAAC;CACrD,KAAK,MAAM,IAAI,aAAa,MAAM,KAAK,WAAW;EAChD,IAAI,KAAK,YAAY,aAAa,IAAI,GAAG,OAAO;EAChD,MAAM,MAAM,KAAK,QAAQ,GAAG;EAC5B,IAAI,EAAE,eAAe,cAAc;EACnC,IAAI,WAAW,QAAQ,iBAAiB,MAAM,KAAK,CAAC,iBAAiB,GAAG,GAAG,OAAO,KAAK;GAAE;GAAK;EAAI,CAAC;CACrG,CAAC;CACD,OAAO;AACT"}
@@ -1,4 +1,5 @@
1
1
  import { BlockActionSurface, BlockUiOptions } from "../../core/extension-points.js";
2
2
  import { BLOCK_CORNER_ATTR, BlockActionEntry, BlockCorner, actionSurfacesOf, blockActionsFor, blockCornerOf, effectiveTarget, sameBlock, selectedBlockOf } from "./block-actions.js";
3
+ import { outerBlockAt, outerBlocksAt, typedBlockAround } from "./block-target.js";
3
4
  import { BlockUiUi, blockUiFeatureCore } from "./feature.js";
4
- export { BLOCK_CORNER_ATTR, type BlockActionEntry, type BlockActionSurface, type BlockCorner, type BlockUiOptions, type BlockUiUi, actionSurfacesOf, blockActionsFor, blockCornerOf, blockUiFeatureCore, effectiveTarget, sameBlock, selectedBlockOf };
5
+ export { BLOCK_CORNER_ATTR, type BlockActionEntry, type BlockActionSurface, type BlockCorner, type BlockUiOptions, type BlockUiUi, actionSurfacesOf, blockActionsFor, blockCornerOf, blockUiFeatureCore, effectiveTarget, outerBlockAt, outerBlocksAt, sameBlock, selectedBlockOf, typedBlockAround };
@@ -1,3 +1,4 @@
1
1
  import { blockUiFeatureCore } from "./feature.js";
2
+ import { outerBlockAt, outerBlocksAt, typedBlockAround } from "./block-target.js";
2
3
  import { BLOCK_CORNER_ATTR, actionSurfacesOf, blockActionsFor, blockCornerOf, effectiveTarget, sameBlock, selectedBlockOf } from "./block-actions.js";
3
- export { BLOCK_CORNER_ATTR, actionSurfacesOf, blockActionsFor, blockCornerOf, blockUiFeatureCore, effectiveTarget, sameBlock, selectedBlockOf };
4
+ export { BLOCK_CORNER_ATTR, actionSurfacesOf, blockActionsFor, blockCornerOf, blockUiFeatureCore, effectiveTarget, outerBlockAt, outerBlocksAt, sameBlock, selectedBlockOf, typedBlockAround };
@@ -4,7 +4,7 @@ import { Editor } from "@tiptap/core";
4
4
  * The permanent drag handles (`blocks.dragHandle: 'always'`): one handle per block that the hover handle can target
5
5
  * (`handleBlocksOf`), each where the hover handle would sit for that block, dragging the block like the hover handle
6
6
  * does (`startBlockDrag`). Only blocks within a screen of the viewport get one. A nested block whose handle would cover
7
- * another handle on the same line (the first block of a quote, say) has none: its container's handle moves it. Hidden
7
+ * another handle on the same line (a nested block flush with its container, say) has none: its container's handle moves it. Hidden
8
8
  * while the editor is read-only. Positioned absolutely inside `host`, the `relative` element around the editor.
9
9
  */
10
10
  export declare function BlockHandles({ editor, host }: {
@@ -1,7 +1,7 @@
1
1
  import { startBlockDrag } from "../../../core/block-drag.js";
2
2
  import { cn } from "../../../react/ui/utils.js";
3
3
  import { Icon } from "../../../react/Icon.js";
4
- import { firstLineCenterShift, gutterShiftOf, handleBlocksOf } from "../handle-geometry.js";
4
+ import { firstLineCenterShift, handleBlocksOf } from "../handle-geometry.js";
5
5
  import { useEffect, useState } from "react";
6
6
  import { jsx } from "react/jsx-runtime";
7
7
  //#region src/features/block-ui/react/BlockHandles.tsx
@@ -9,7 +9,7 @@ import { jsx } from "react/jsx-runtime";
9
9
  * The permanent drag handles (`blocks.dragHandle: 'always'`): one handle per block that the hover handle can target
10
10
  * (`handleBlocksOf`), each where the hover handle would sit for that block, dragging the block like the hover handle
11
11
  * does (`startBlockDrag`). Only blocks within a screen of the viewport get one. A nested block whose handle would cover
12
- * another handle on the same line (the first block of a quote, say) has none: its container's handle moves it. Hidden
12
+ * another handle on the same line (a nested block flush with its container, say) has none: its container's handle moves it. Hidden
13
13
  * while the editor is read-only. Positioned absolutely inside `host`, the `relative` element around the editor.
14
14
  */
15
15
  function BlockHandles({ editor, host }) {
@@ -32,10 +32,10 @@ function BlockHandles({ editor, host }) {
32
32
  const originX = hostRect.left + host.clientLeft;
33
33
  const originY = hostRect.top + host.clientTop;
34
34
  const next = [];
35
- for (const { node, pos, dom } of handleBlocksOf(editor.view)) {
35
+ for (const { pos, dom } of handleBlocksOf(editor.view)) {
36
36
  const rect = dom.getBoundingClientRect();
37
37
  if (!rect.height || rect.bottom < -window.innerHeight || rect.top > 2 * window.innerHeight) continue;
38
- const left = rect.left - 24 - gutterShiftOf(node, dom) - originX;
38
+ const left = rect.left - 24 - originX;
39
39
  const top = rect.top + firstLineCenterShift(dom, rect.top, 24) - originY;
40
40
  if (!next.some((other) => Math.abs(top - other.top) < 12 && left < other.left + 24 && other.left < left + 24)) next.push({
41
41
  pos,
@@ -1 +1 @@
1
- {"version":3,"file":"BlockHandles.js","names":[],"sources":["../../../../src/features/block-ui/react/BlockHandles.tsx"],"sourcesContent":["import type { Editor } from '@tiptap/core'\nimport { type DragEvent, useEffect, useState } from 'react'\nimport { startBlockDrag } from '../../../core'\nimport { Icon } from '../../../react/Icon'\nimport { cn } from '../../../react/ui/utils'\nimport { firstLineCenterShift, gutterShiftOf, HANDLE_SIZE, handleBlocksOf } from '../handle-geometry'\n\ninterface Handle { pos: number, left: number, top: number }\n\n/**\n * The permanent drag handles (`blocks.dragHandle: 'always'`): one handle per block that the hover handle can target\n * (`handleBlocksOf`), each where the hover handle would sit for that block, dragging the block like the hover handle\n * does (`startBlockDrag`). Only blocks within a screen of the viewport get one. A nested block whose handle would cover\n * another handle on the same line (the first block of a quote, say) has none: its container's handle moves it. Hidden\n * while the editor is read-only. Positioned absolutely inside `host`, the `relative` element around the editor.\n */\nexport function BlockHandles({ editor, host }: { editor: Editor, host: HTMLElement }) {\n const [handles, setHandles] = useState<readonly Handle[]>([])\n // While a drag runs the handles let events through, so a drop over a handle's gutter still reaches the editor.\n const [dragging, setDragging] = useState(false)\n\n useEffect(() => {\n let raf = 0\n let wasEditable = false\n const schedule = () => {\n if (!raf) raf = requestAnimationFrame(measure)\n }\n\n function measure() {\n raf = 0\n wasEditable = !editor.isDestroyed && editor.isEditable\n if (!wasEditable || !editor.view.dom.getClientRects().length) {\n setHandles(previous => (previous.length ? [] : previous))\n return\n }\n const hostRect = host.getBoundingClientRect()\n const originX = hostRect.left + host.clientLeft\n const originY = hostRect.top + host.clientTop\n const next: Handle[] = []\n for (const { node, pos, dom } of handleBlocksOf(editor.view)) {\n const rect = dom.getBoundingClientRect()\n if (!rect.height || rect.bottom < -window.innerHeight || rect.top > 2 * window.innerHeight) continue\n const left = rect.left - HANDLE_SIZE - gutterShiftOf(node, dom) - originX\n const top = rect.top + firstLineCenterShift(dom, rect.top, HANDLE_SIZE) - originY\n const covered = next.some(other => Math.abs(top - other.top) < HANDLE_SIZE / 2 && left < other.left + HANDLE_SIZE && other.left < left + HANDLE_SIZE)\n if (!covered) next.push({ pos, left, top })\n }\n setHandles((previous) => {\n const changed = previous.length !== next.length || next.some((handle, index) => {\n const before = previous[index]\n return !before || handle.pos !== before.pos || handle.left !== before.left || handle.top !== before.top\n })\n return changed ? next : previous\n })\n }\n\n // Documents change layout through edits, the column through resizes; `EditorSurface` dispatches a transaction after\n // `setEditable`.\n const onTransaction = ({ transaction }: { transaction: { docChanged: boolean } }) => {\n if (transaction.docChanged || editor.isEditable !== wasEditable) schedule()\n }\n editor.on('transaction', onTransaction)\n window.addEventListener('resize', schedule)\n window.addEventListener('scroll', schedule, true)\n const resizeObserver = new ResizeObserver(schedule)\n resizeObserver.observe(editor.view.dom)\n schedule()\n return () => {\n editor.off('transaction', onTransaction)\n window.removeEventListener('resize', schedule)\n window.removeEventListener('scroll', schedule, true)\n resizeObserver.disconnect()\n if (raf) cancelAnimationFrame(raf)\n }\n }, [editor, host])\n\n function onDragStart(event: DragEvent<HTMLDivElement>, pos: number) {\n if (!startBlockDrag(editor, event.nativeEvent, pos)) {\n event.preventDefault()\n return\n }\n // Not inside `dragstart`: changing the source's styles there cancels the drag. The dropped block's handle may be\n // gone afterwards and send no `dragend`, so the document ends the drag.\n setTimeout(() => setDragging(true))\n const abort = new AbortController()\n const end = () => {\n setDragging(false)\n abort.abort()\n }\n document.addEventListener('drop', end, { signal: abort.signal })\n document.addEventListener('dragend', end, { signal: abort.signal })\n }\n\n return (\n <div className=\"absolute left-0 top-0 z-10 h-0 w-0\">\n {handles.map(handle => (\n <div\n key={handle.pos}\n draggable\n aria-hidden=\"true\"\n className={cn('absolute flex cursor-grab items-center justify-center rounded text-muted-foreground hover:bg-muted hover:text-foreground', dragging ? 'pointer-events-none' : 'pointer-events-auto')}\n style={{ left: `${handle.left}px`, top: `${handle.top}px`, width: `${HANDLE_SIZE}px`, height: `${HANDLE_SIZE}px` }}\n onDragStart={event => onDragStart(event, handle.pos)}\n >\n <Icon name=\"i-lucide-grip-vertical\" />\n </div>\n ))}\n </div>\n )\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"BlockHandles.js","names":[],"sources":["../../../../src/features/block-ui/react/BlockHandles.tsx"],"sourcesContent":["import type { Editor } from '@tiptap/core'\nimport { type DragEvent, useEffect, useState } from 'react'\nimport { startBlockDrag } from '../../../core'\nimport { Icon } from '../../../react/Icon'\nimport { cn } from '../../../react/ui/utils'\nimport { firstLineCenterShift, HANDLE_SIZE, handleBlocksOf } from '../handle-geometry'\n\ninterface Handle { pos: number, left: number, top: number }\n\n/**\n * The permanent drag handles (`blocks.dragHandle: 'always'`): one handle per block that the hover handle can target\n * (`handleBlocksOf`), each where the hover handle would sit for that block, dragging the block like the hover handle\n * does (`startBlockDrag`). Only blocks within a screen of the viewport get one. A nested block whose handle would cover\n * another handle on the same line (a nested block flush with its container, say) has none: its container's handle moves it. Hidden\n * while the editor is read-only. Positioned absolutely inside `host`, the `relative` element around the editor.\n */\nexport function BlockHandles({ editor, host }: { editor: Editor, host: HTMLElement }) {\n const [handles, setHandles] = useState<readonly Handle[]>([])\n // While a drag runs the handles let events through, so a drop over a handle's gutter still reaches the editor.\n const [dragging, setDragging] = useState(false)\n\n useEffect(() => {\n let raf = 0\n let wasEditable = false\n const schedule = () => {\n if (!raf) raf = requestAnimationFrame(measure)\n }\n\n function measure() {\n raf = 0\n wasEditable = !editor.isDestroyed && editor.isEditable\n if (!wasEditable || !editor.view.dom.getClientRects().length) {\n setHandles(previous => (previous.length ? [] : previous))\n return\n }\n const hostRect = host.getBoundingClientRect()\n const originX = hostRect.left + host.clientLeft\n const originY = hostRect.top + host.clientTop\n const next: Handle[] = []\n for (const { pos, dom } of handleBlocksOf(editor.view)) {\n const rect = dom.getBoundingClientRect()\n if (!rect.height || rect.bottom < -window.innerHeight || rect.top > 2 * window.innerHeight) continue\n const left = rect.left - HANDLE_SIZE - originX\n const top = rect.top + firstLineCenterShift(dom, rect.top, HANDLE_SIZE) - originY\n const covered = next.some(other => Math.abs(top - other.top) < HANDLE_SIZE / 2 && left < other.left + HANDLE_SIZE && other.left < left + HANDLE_SIZE)\n if (!covered) next.push({ pos, left, top })\n }\n setHandles((previous) => {\n const changed = previous.length !== next.length || next.some((handle, index) => {\n const before = previous[index]\n return !before || handle.pos !== before.pos || handle.left !== before.left || handle.top !== before.top\n })\n return changed ? next : previous\n })\n }\n\n // Documents change layout through edits, the column through resizes; `EditorSurface` dispatches a transaction after\n // `setEditable`.\n const onTransaction = ({ transaction }: { transaction: { docChanged: boolean } }) => {\n if (transaction.docChanged || editor.isEditable !== wasEditable) schedule()\n }\n editor.on('transaction', onTransaction)\n window.addEventListener('resize', schedule)\n window.addEventListener('scroll', schedule, true)\n const resizeObserver = new ResizeObserver(schedule)\n resizeObserver.observe(editor.view.dom)\n schedule()\n return () => {\n editor.off('transaction', onTransaction)\n window.removeEventListener('resize', schedule)\n window.removeEventListener('scroll', schedule, true)\n resizeObserver.disconnect()\n if (raf) cancelAnimationFrame(raf)\n }\n }, [editor, host])\n\n function onDragStart(event: DragEvent<HTMLDivElement>, pos: number) {\n if (!startBlockDrag(editor, event.nativeEvent, pos)) {\n event.preventDefault()\n return\n }\n // Not inside `dragstart`: changing the source's styles there cancels the drag. The dropped block's handle may be\n // gone afterwards and send no `dragend`, so the document ends the drag.\n setTimeout(() => setDragging(true))\n const abort = new AbortController()\n const end = () => {\n setDragging(false)\n abort.abort()\n }\n document.addEventListener('drop', end, { signal: abort.signal })\n document.addEventListener('dragend', end, { signal: abort.signal })\n }\n\n return (\n <div className=\"absolute left-0 top-0 z-10 h-0 w-0\">\n {handles.map(handle => (\n <div\n key={handle.pos}\n draggable\n aria-hidden=\"true\"\n className={cn('absolute flex cursor-grab items-center justify-center rounded text-muted-foreground hover:bg-muted hover:text-foreground', dragging ? 'pointer-events-none' : 'pointer-events-auto')}\n style={{ left: `${handle.left}px`, top: `${handle.top}px`, width: `${HANDLE_SIZE}px`, height: `${HANDLE_SIZE}px` }}\n onDragStart={event => onDragStart(event, handle.pos)}\n >\n <Icon name=\"i-lucide-grip-vertical\" />\n </div>\n ))}\n </div>\n )\n}\n"],"mappings":"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"}
@@ -1,9 +1,9 @@
1
1
  import { editorEntryOf } from "../../../core/editor-ui.js";
2
- import { isChromeNode } from "../../../core/schema/node-flags.js";
3
2
  import { cn } from "../../../react/ui/utils.js";
4
3
  import { Icon } from "../../../react/Icon.js";
5
4
  import { useEditorSettings } from "../../../react/settings.js";
6
- import { firstLineCenterShift, gutterShiftOf, handleLeftOf, hasKindIcon } from "../handle-geometry.js";
5
+ import { firstLineCenterShift, handleLeftOf, hasBlockTypeIcon } from "../handle-geometry.js";
6
+ import { outerBlockRule } from "../block-target.js";
7
7
  import { actionSurfacesOf, sameBlock, selectedBlockOf } from "../block-actions.js";
8
8
  import { BlockActionsOverlay } from "./BlockActionsOverlay.js";
9
9
  import { BlockHandles } from "./BlockHandles.js";
@@ -24,7 +24,7 @@ import { createPortal } from "react-dom";
24
24
  function BlockUi({ editor }) {
25
25
  const [host, setHost] = useState(null);
26
26
  const [hoverTarget, setHoverTarget] = useState(null);
27
- const [targetHasKindIcon, setTargetHasKindIcon] = useState(false);
27
+ const [targetHasBlockTypeIcon, setTargetHasBlockTypeIcon] = useState(false);
28
28
  const { settings } = useEditorSettings();
29
29
  const actions = editorEntryOf(editor)?.blockActions ?? [];
30
30
  const surfaces = actionSurfacesOf(editor);
@@ -44,9 +44,7 @@ function BlockUi({ editor }) {
44
44
  overlayHovered: false,
45
45
  clearTimer: void 0,
46
46
  pointer: null,
47
- dom: null,
48
- node: null,
49
- gutterShift: 0
47
+ dom: null
50
48
  }).current;
51
49
  const handleContent = useRef(null);
52
50
  const handleWidth = () => handleContent.current?.parentElement?.offsetWidth ?? 0;
@@ -88,7 +86,7 @@ function BlockUi({ editor }) {
88
86
  editor.view.dispatch(editor.state.tr.setMeta("hideDragHandle", true).setMeta("addToHistory", false));
89
87
  }, [editor]);
90
88
  const alwaysHandles = settings.blocks.dragHandle === "always";
91
- const hoverHandleHidden = alwaysHandles || targetHasKindIcon;
89
+ const hoverHandleHidden = alwaysHandles || targetHasBlockTypeIcon;
92
90
  const trackDragTarget = useCallback(({ node, pos }) => {
93
91
  if (node) {
94
92
  clearTimeout(track.clearTimer);
@@ -99,21 +97,13 @@ function BlockUi({ editor }) {
99
97
  } else scheduleHoverClear();
100
98
  const dom = node ? editor.view.nodeDOM(pos) : null;
101
99
  track.dom = dom instanceof HTMLElement ? dom : null;
102
- track.node = track.dom ? node : null;
103
- track.gutterShift = track.dom && track.node ? gutterShiftOf(track.node, track.dom) : 0;
104
- setTargetHasKindIcon(track.dom ? hasKindIcon(track.dom) : false);
100
+ setTargetHasBlockTypeIcon(track.dom ? hasBlockTypeIcon(track.dom) : false);
105
101
  }, [
106
102
  editor,
107
103
  track,
108
104
  scheduleHoverClear
109
105
  ]);
110
106
  const dragHandlePosition = useMemo(() => ({ middleware: [{
111
- name: "gutterShift",
112
- fn: ({ x, y }) => ({
113
- x: x - track.gutterShift,
114
- y
115
- })
116
- }, {
117
107
  name: "firstLineCenter",
118
108
  fn: ({ x, y, elements, rects }) => ({
119
109
  x,
@@ -122,33 +112,31 @@ function BlockUi({ editor }) {
122
112
  }] }), [track]);
123
113
  const dragHandleNested = useMemo(() => {
124
114
  const pointerReachesTarget = () => {
125
- const { pointer, node, dom } = track;
126
- if (!pointer || !node || !dom?.isConnected) return false;
115
+ const { pointer, dom } = track;
116
+ if (!pointer || !dom?.isConnected) return false;
127
117
  const rect = dom.getBoundingClientRect();
128
118
  const { x, y } = pointer;
129
- if (x < handleLeftOf(node, dom, handleWidth()) || x >= rect.right) return false;
119
+ if (x < handleLeftOf(dom, handleWidth()) || x >= rect.right) return false;
130
120
  if (y < (laidOutSibling(dom, "previous")?.bottom ?? rect.top)) return false;
131
121
  if (y >= (laidOutSibling(dom, "next")?.top ?? rect.bottom)) return false;
132
122
  return x < rect.left || y < rect.top || y >= rect.bottom;
133
123
  };
134
124
  return {
135
125
  edgeDetection: "none",
126
+ defaultRules: false,
136
127
  rules: [
137
- {
138
- id: "compositeChrome",
139
- evaluate: ({ node }) => isChromeNode(node) ? 1e3 : 0
140
- },
128
+ outerBlockRule,
141
129
  {
142
130
  id: "reachTarget",
143
131
  evaluate: () => pointerReachesTarget() ? 1e3 : 0
144
132
  },
145
133
  {
146
134
  id: "ownGutter",
147
- evaluate: ({ node, pos, depth, view }) => {
135
+ evaluate: ({ pos, depth, view }) => {
148
136
  const { pointer } = track;
149
137
  if (depth < 2 || !pointer) return 0;
150
138
  const dom = view.nodeDOM(pos);
151
- return dom instanceof HTMLElement && pointer.x < handleLeftOf(node, dom, handleWidth()) ? 1e3 : 0;
139
+ return dom instanceof HTMLElement && pointer.x < handleLeftOf(dom, handleWidth()) ? 1e3 : 0;
152
140
  }
153
141
  }
154
142
  ]
@@ -1 +1 @@
1
- {"version":3,"file":"BlockUi.js","names":[],"sources":["../../../../src/features/block-ui/react/BlockUi.tsx"],"sourcesContent":["import type { Editor } from '@tiptap/core'\nimport { DragHandle, type DragHandleProps } from '@tiptap/extension-drag-handle-react'\nimport type { Node } from '@tiptap/pm/model'\nimport { useCallback, useEffect, useMemo, useReducer, useRef, useState } from 'react'\nimport { createPortal } from 'react-dom'\nimport { type BlockTarget, editorEntryOf } from '../../../core'\nimport { isChromeNode } from '../../../core/schema'\nimport { Icon } from '../../../react/Icon'\nimport { useEditorSettings } from '../../../react/settings'\nimport { cn } from '../../../react/ui/utils'\nimport { firstLineCenterShift, gutterShiftOf, handleLeftOf, hasKindIcon } from '../handle-geometry'\nimport { actionSurfacesOf, sameBlock, selectedBlockOf } from '../block-actions'\nimport { BlockActionsOverlay } from './BlockActionsOverlay'\nimport { BlockHandles } from './BlockHandles'\n\n/**\n * Block UI of an editor: the drag handle on the left of the hovered block (hidden while the editor is read-only) and the\n * block actions (`BlockActionsOverlay`) at the editor's right edge. The actions are those the surface registered for\n * `editor` (features' block actions, then the host's), shown per `BlockUiOptions.actions`: on a hover bar for the block\n * the drag handle targets, on a persistent toolbar for the block holding the selection, both, or neither. When both\n * would show a bar on the same block, only the toolbar does. A block with a kind icon (a composite) gets no handle: its\n * icon drags it. With `blocks.dragHandle: 'always'` the hover handle is replaced by permanent handles on every eligible\n * block (`BlockHandles`). Mounted by the block-ui feature beside the editor.\n */\nexport function BlockUi({ editor }: { editor: Editor }) {\n // Hover actions target the drag handle's block. The plugin drops its target when the pointer leaves the editor (also\n // onto the overlay, which sits outside it) and on keydown; a short grace keeps the overlay while the pointer moves\n // onto it, and typing hides it at once.\n const [host, setHost] = useState<HTMLElement | null>(null)\n const [hoverTarget, setHoverTarget] = useState<BlockTarget | null>(null)\n const [targetHasKindIcon, setTargetHasKindIcon] = useState(false)\n const { settings } = useEditorSettings()\n // Read while rendering: the surface registers its entry after its overlays have mounted, and the overlay renders\n // again once a block is hovered.\n const actions = editorEntryOf(editor)?.blockActions ?? []\n const surfaces = actionSurfacesOf(editor)\n\n // The toolbar follows the selection: render on each transaction, but only while that surface exists (the options are\n // read when the transaction happens, the entry being registered after this component mounted).\n const [, rerender] = useReducer((count: number) => count + 1, 0)\n useEffect(() => {\n const onTransaction = () => { if (actionSurfacesOf(editor).toolbar) rerender() }\n editor.on('transaction', onTransaction)\n return () => { editor.off('transaction', onTransaction) }\n }, [editor])\n const selectedTarget = surfaces.toolbar ? selectedBlockOf(editor) : null\n // One bar per block: the toolbar wins where the hover bar would sit on the same block.\n const hoverBarTarget = hoverTarget && selectedTarget && sameBlock(editor, hoverTarget, selectedTarget) ? null : hoverTarget\n\n // Everything the plugin callbacks and the targeting rules below read while the pointer moves: not render state.\n const track = useRef({\n overlayHovered: false,\n clearTimer: undefined as number | undefined,\n pointer: null as { x: number, y: number } | null,\n dom: null as HTMLElement | null,\n node: null as Node | null,\n gutterShift: 0,\n }).current\n // The handle's content; its parent is the handle element the plugin positions (`handleWidth`).\n const handleContent = useRef<HTMLSpanElement>(null)\n const handleWidth = () => handleContent.current?.parentElement?.offsetWidth ?? 0\n\n const scheduleHoverClear = useCallback(() => {\n clearTimeout(track.clearTimer)\n track.clearTimer = window.setTimeout(() => {\n if (!track.overlayHovered) setHoverTarget(null)\n }, 200)\n }, [track])\n\n // The overlay is positioned inside the element that holds the editor content (`relative`); Tiptap's content component\n // has moved the editor DOM into it by the time this effect runs.\n useEffect(() => {\n if (editor.isDestroyed) return\n const dom = editor.view.dom\n setHost(dom.isConnected ? dom.parentElement : null)\n // Like the drag-handle plugin: a key pressed in the focused editor hides the actions.\n const onKeydown = () => {\n clearTimeout(track.clearTimer)\n setHoverTarget(null)\n }\n // Pointer position for the targeting rules below. The plugin evaluates them in a frame callback after the\n // mousemove, so this is the position they see.\n const onMousemove = (event: MouseEvent) => {\n track.pointer = { x: event.clientX, y: event.clientY }\n }\n dom.addEventListener('keydown', onKeydown)\n dom.addEventListener('mousemove', onMousemove)\n return () => {\n clearTimeout(track.clearTimer)\n dom.removeEventListener('keydown', onKeydown)\n dom.removeEventListener('mousemove', onMousemove)\n setHost(null)\n }\n }, [editor, track])\n\n const onOverlayHover = useCallback((hovered: boolean) => {\n track.overlayHovered = hovered\n if (!hovered) scheduleHoverClear()\n }, [track, scheduleHoverClear])\n\n // The drag-handle plugin hides the handle on dragend but keeps its current target. A dropped\n // nested node is the same node object, so hovering it again would not re-show the handle.\n // The plugin's `hideDragHandle` meta clears the target.\n const resetDragHandle = useCallback(() => {\n if (editor.isDestroyed) return\n editor.view.dispatch(editor.state.tr.setMeta('hideDragHandle', true).setMeta('addToHistory', false))\n }, [editor])\n\n // The plugin puts the handle's right edge on the target block's left edge (`gutterShiftOf`: list items move further\n // left). The hover handle is hidden where the block has a handle of its own: the kind icon of a composite, or, with\n // `blocks.dragHandle: 'always'`, the permanent handles. Hiding keeps its layout, which the targeting rules below measure.\n const alwaysHandles = settings.blocks.dragHandle === 'always'\n const hoverHandleHidden = alwaysHandles || targetHasKindIcon\n const trackDragTarget = useCallback(({ node, pos }: { node: Node | null, pos: number }) => {\n if (node) {\n clearTimeout(track.clearTimer)\n setHoverTarget({ node, pos })\n }\n else {\n scheduleHoverClear()\n }\n const dom = node ? editor.view.nodeDOM(pos) : null\n track.dom = dom instanceof HTMLElement ? dom : null\n track.node = track.dom ? node : null\n track.gutterShift = track.dom && track.node ? gutterShiftOf(track.node, track.dom) : 0\n setTargetHasKindIcon(track.dom ? hasKindIcon(track.dom) : false)\n }, [editor, track, scheduleHoverClear])\n\n // The plugin re-registers when its configuration changes: both objects below are made once and read `track`.\n const dragHandlePosition = useMemo<DragHandleProps['computePositionConfig']>(() => ({\n // The plugin aligns the handle's top with the block's top, which sits above the middle of the block's first text\n // line: `firstLineCenterShift` moves the handle's centre to that line's centre.\n middleware: [\n { name: 'gutterShift', fn: ({ x, y }) => ({ x: x - track.gutterShift, y }) },\n {\n name: 'firstLineCenter',\n fn: ({ x, y, elements, rects }) => ({\n x,\n y: track.dom ? y + firstLineCenterShift(track.dom, elements.reference.getBoundingClientRect().top, rects.floating.height) : y,\n }),\n },\n ],\n }), [track])\n\n // Targeting among nested blocks. `compositeChrome`: hovering a composite's title, description or tags row targets the\n // composite itself (a deduction of 1000, the base score, excludes a node). `reachTarget`: see `pointerReachesTarget`.\n // `ownGutter`: a nested block is targeted only from its handle column rightwards; further left its ancestors are, so\n // on any row the gutter is partitioned by the handle columns of the blocks nested there. The plugin's edge detection\n // is off: its left strip is this partition, its top strip would hand the handle to the parent on the block's first\n // line, where the handle sits.\n const dragHandleNested = useMemo<DragHandleProps['nested']>(() => {\n // Left of a block, ProseMirror resolves the pointer to the position before the block, so the plugin only considers\n // the block's ancestors there: the target's own handle column would hand the handle to its parent before the pointer\n // reaches it. This keeps the target while the pointer is between its handle and its box, over its whole height\n // including the gaps to its neighbours, and in those gaps themselves (which resolve to the parent as well). The rule\n // then excludes every candidate, and the plugin keeps its target when the detection yields none. Inside the target's\n // own box the rule is off, so its descendants are still targeted.\n const pointerReachesTarget = (): boolean => {\n const { pointer, node, dom } = track\n if (!pointer || !node || !dom?.isConnected) return false\n const rect = dom.getBoundingClientRect()\n const { x, y } = pointer\n if (x < handleLeftOf(node, dom, handleWidth()) || x >= rect.right) return false\n if (y < (laidOutSibling(dom, 'previous')?.bottom ?? rect.top)) return false\n if (y >= (laidOutSibling(dom, 'next')?.top ?? rect.bottom)) return false\n return x < rect.left || y < rect.top || y >= rect.bottom\n }\n return {\n edgeDetection: 'none',\n rules: [\n { id: 'compositeChrome', evaluate: ({ node }) => isChromeNode(node) ? 1000 : 0 },\n { id: 'reachTarget', evaluate: () => pointerReachesTarget() ? 1000 : 0 },\n {\n id: 'ownGutter',\n evaluate: ({ node, pos, depth, view }) => {\n const { pointer } = track\n if (depth < 2 || !pointer) return 0\n const dom = view.nodeDOM(pos)\n return dom instanceof HTMLElement && pointer.x < handleLeftOf(node, dom, handleWidth()) ? 1000 : 0\n },\n },\n ],\n }\n }, [track])\n\n return (\n <>\n {host && createPortal(\n <>\n {surfaces.hover && (\n <BlockActionsOverlay editor={editor} target={hoverBarTarget} host={host} actions={actions} surface=\"hover\" onHover={onOverlayHover} />\n )}\n {surfaces.toolbar && (\n <BlockActionsOverlay editor={editor} target={selectedTarget} host={host} actions={actions} surface=\"toolbar\" persistent />\n )}\n {alwaysHandles && <BlockHandles editor={editor} host={host} />}\n </>,\n host,\n )}\n <DragHandle\n editor={editor}\n onElementDragEnd={resetDragHandle}\n onNodeChange={trackDragTarget}\n computePositionConfig={dragHandlePosition}\n nested={dragHandleNested}\n className={cn(\n 'flex size-6 cursor-grab items-center justify-center rounded text-muted-foreground hover:bg-muted hover:text-foreground data-[dragging=true]:cursor-grabbing',\n hoverHandleHidden && 'invisible! pointer-events-none!',\n )}\n >\n <span ref={handleContent} className=\"contents\">\n <Icon name=\"i-lucide-grip-vertical\" />\n </span>\n </DragHandle>\n </>\n )\n}\n\n// Nearest sibling with a layout box (a composite's hidden description/tags rows have none).\nfunction laidOutSibling(dom: Element, side: 'previous' | 'next'): DOMRect | null {\n for (let element = dom[`${side}ElementSibling`]; element; element = element[`${side}ElementSibling`]) {\n const rect = element.getBoundingClientRect()\n if (rect.height > 0) return rect\n }\n return null\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"BlockUi.js","names":[],"sources":["../../../../src/features/block-ui/react/BlockUi.tsx"],"sourcesContent":["import type { Editor } from '@tiptap/core'\nimport { DragHandle, type DragHandleProps } from '@tiptap/extension-drag-handle-react'\nimport type { Node } from '@tiptap/pm/model'\nimport { useCallback, useEffect, useMemo, useReducer, useRef, useState } from 'react'\nimport { createPortal } from 'react-dom'\nimport { type BlockTarget, editorEntryOf } from '../../../core'\nimport { Icon } from '../../../react/Icon'\nimport { useEditorSettings } from '../../../react/settings'\nimport { cn } from '../../../react/ui/utils'\nimport { firstLineCenterShift, handleLeftOf, hasBlockTypeIcon } from '../handle-geometry'\nimport { outerBlockRule } from '../block-target'\nimport { actionSurfacesOf, sameBlock, selectedBlockOf } from '../block-actions'\nimport { BlockActionsOverlay } from './BlockActionsOverlay'\nimport { BlockHandles } from './BlockHandles'\n\n/**\n * Block UI of an editor: the drag handle on the left of the hovered block (hidden while the editor is read-only) and the\n * block actions (`BlockActionsOverlay`) at the editor's right edge. The actions are those the surface registered for\n * `editor` (features' block actions, then the host's), shown per `BlockUiOptions.actions`: on a hover bar for the block\n * the drag handle targets, on a persistent toolbar for the block holding the selection, both, or neither. When both\n * would show a bar on the same block, only the toolbar does. A block with a kind icon (a composite) gets no handle: its\n * icon drags it. With `blocks.dragHandle: 'always'` the hover handle is replaced by permanent handles on every eligible\n * block (`BlockHandles`). Mounted by the block-ui feature beside the editor.\n */\nexport function BlockUi({ editor }: { editor: Editor }) {\n // Hover actions target the drag handle's block. The plugin drops its target when the pointer leaves the editor (also\n // onto the overlay, which sits outside it) and on keydown; a short grace keeps the overlay while the pointer moves\n // onto it, and typing hides it at once.\n const [host, setHost] = useState<HTMLElement | null>(null)\n const [hoverTarget, setHoverTarget] = useState<BlockTarget | null>(null)\n const [targetHasBlockTypeIcon, setTargetHasBlockTypeIcon] = useState(false)\n const { settings } = useEditorSettings()\n // Read while rendering: the surface registers its entry after its overlays have mounted, and the overlay renders\n // again once a block is hovered.\n const actions = editorEntryOf(editor)?.blockActions ?? []\n const surfaces = actionSurfacesOf(editor)\n\n // The toolbar follows the selection: render on each transaction, but only while that surface exists (the options are\n // read when the transaction happens, the entry being registered after this component mounted).\n const [, rerender] = useReducer((count: number) => count + 1, 0)\n useEffect(() => {\n const onTransaction = () => { if (actionSurfacesOf(editor).toolbar) rerender() }\n editor.on('transaction', onTransaction)\n return () => { editor.off('transaction', onTransaction) }\n }, [editor])\n const selectedTarget = surfaces.toolbar ? selectedBlockOf(editor) : null\n // One bar per block: the toolbar wins where the hover bar would sit on the same block.\n const hoverBarTarget = hoverTarget && selectedTarget && sameBlock(editor, hoverTarget, selectedTarget) ? null : hoverTarget\n\n // Everything the plugin callbacks and the targeting rules below read while the pointer moves: not render state.\n const track = useRef({\n overlayHovered: false,\n clearTimer: undefined as number | undefined,\n pointer: null as { x: number, y: number } | null,\n dom: null as HTMLElement | null,\n }).current\n // The handle's content; its parent is the handle element the plugin positions (`handleWidth`).\n const handleContent = useRef<HTMLSpanElement>(null)\n const handleWidth = () => handleContent.current?.parentElement?.offsetWidth ?? 0\n\n const scheduleHoverClear = useCallback(() => {\n clearTimeout(track.clearTimer)\n track.clearTimer = window.setTimeout(() => {\n if (!track.overlayHovered) setHoverTarget(null)\n }, 200)\n }, [track])\n\n // The overlay is positioned inside the element that holds the editor content (`relative`); Tiptap's content component\n // has moved the editor DOM into it by the time this effect runs.\n useEffect(() => {\n if (editor.isDestroyed) return\n const dom = editor.view.dom\n setHost(dom.isConnected ? dom.parentElement : null)\n // Like the drag-handle plugin: a key pressed in the focused editor hides the actions.\n const onKeydown = () => {\n clearTimeout(track.clearTimer)\n setHoverTarget(null)\n }\n // Pointer position for the targeting rules below. The plugin evaluates them in a frame callback after the\n // mousemove, so this is the position they see.\n const onMousemove = (event: MouseEvent) => {\n track.pointer = { x: event.clientX, y: event.clientY }\n }\n dom.addEventListener('keydown', onKeydown)\n dom.addEventListener('mousemove', onMousemove)\n return () => {\n clearTimeout(track.clearTimer)\n dom.removeEventListener('keydown', onKeydown)\n dom.removeEventListener('mousemove', onMousemove)\n setHost(null)\n }\n }, [editor, track])\n\n const onOverlayHover = useCallback((hovered: boolean) => {\n track.overlayHovered = hovered\n if (!hovered) scheduleHoverClear()\n }, [track, scheduleHoverClear])\n\n // The drag-handle plugin hides the handle on dragend but keeps its current target. A dropped\n // nested node is the same node object, so hovering it again would not re-show the handle.\n // The plugin's `hideDragHandle` meta clears the target.\n const resetDragHandle = useCallback(() => {\n if (editor.isDestroyed) return\n editor.view.dispatch(editor.state.tr.setMeta('hideDragHandle', true).setMeta('addToHistory', false))\n }, [editor])\n\n // The plugin puts the handle's right edge on the target block's left edge. The hover handle is hidden where the block\n // has a handle of its own: the kind icon of a composite, or, with `blocks.dragHandle: 'always'`, the permanent\n // handles. Hiding keeps its layout, which the targeting rules below measure.\n const alwaysHandles = settings.blocks.dragHandle === 'always'\n const hoverHandleHidden = alwaysHandles || targetHasBlockTypeIcon\n const trackDragTarget = useCallback(({ node, pos }: { node: Node | null, pos: number }) => {\n if (node) {\n clearTimeout(track.clearTimer)\n setHoverTarget({ node, pos })\n }\n else {\n scheduleHoverClear()\n }\n const dom = node ? editor.view.nodeDOM(pos) : null\n track.dom = dom instanceof HTMLElement ? dom : null\n setTargetHasBlockTypeIcon(track.dom ? hasBlockTypeIcon(track.dom) : false)\n }, [editor, track, scheduleHoverClear])\n\n // The plugin re-registers when its configuration changes: both objects below are made once and read `track`.\n const dragHandlePosition = useMemo<DragHandleProps['computePositionConfig']>(() => ({\n // The plugin aligns the handle's top with the block's top, which sits above the middle of the block's first text\n // line: `firstLineCenterShift` moves the handle's centre to that line's centre.\n middleware: [\n {\n name: 'firstLineCenter',\n fn: ({ x, y, elements, rects }) => ({\n x,\n y: track.dom ? y + firstLineCenterShift(track.dom, elements.reference.getBoundingClientRect().top, rects.floating.height) : y,\n }),\n },\n ],\n }), [track])\n\n // Targeting among nested blocks, without the plugin's default rules (they target list items). `outerBlock` (a\n // deduction of 1000, the base score, excludes a node): only the blocks of `outerBlocksAt` the hovered position are\n // targets, so a list item or a quote paragraph targets its list or quote, and a Typed block's chrome its Typed block.\n // `reachTarget`: see `pointerReachesTarget`.\n // `ownGutter`: a nested block is targeted only from its handle column rightwards; further left its ancestors are, so\n // on any row the gutter is partitioned by the handle columns of the blocks nested there. The plugin's edge detection\n // is off: its left strip is this partition, its top strip would hand the handle to the parent on the block's first\n // line, where the handle sits.\n const dragHandleNested = useMemo<DragHandleProps['nested']>(() => {\n // Left of a block, ProseMirror resolves the pointer to the position before the block, so the plugin only considers\n // the block's ancestors there: the target's own handle column would hand the handle to its parent before the pointer\n // reaches it. This keeps the target while the pointer is between its handle and its box, over its whole height\n // including the gaps to its neighbours, and in those gaps themselves (which resolve to the parent as well). The rule\n // then excludes every candidate, and the plugin keeps its target when the detection yields none. Inside the target's\n // own box the rule is off, so its descendants are still targeted.\n const pointerReachesTarget = (): boolean => {\n const { pointer, dom } = track\n if (!pointer || !dom?.isConnected) return false\n const rect = dom.getBoundingClientRect()\n const { x, y } = pointer\n if (x < handleLeftOf(dom, handleWidth()) || x >= rect.right) return false\n if (y < (laidOutSibling(dom, 'previous')?.bottom ?? rect.top)) return false\n if (y >= (laidOutSibling(dom, 'next')?.top ?? rect.bottom)) return false\n return x < rect.left || y < rect.top || y >= rect.bottom\n }\n return {\n edgeDetection: 'none',\n defaultRules: false,\n rules: [\n outerBlockRule,\n { id: 'reachTarget', evaluate: () => pointerReachesTarget() ? 1000 : 0 },\n {\n id: 'ownGutter',\n evaluate: ({ pos, depth, view }) => {\n const { pointer } = track\n if (depth < 2 || !pointer) return 0\n const dom = view.nodeDOM(pos)\n return dom instanceof HTMLElement && pointer.x < handleLeftOf(dom, handleWidth()) ? 1000 : 0\n },\n },\n ],\n }\n }, [track])\n\n return (\n <>\n {host && createPortal(\n <>\n {surfaces.hover && (\n <BlockActionsOverlay editor={editor} target={hoverBarTarget} host={host} actions={actions} surface=\"hover\" onHover={onOverlayHover} />\n )}\n {surfaces.toolbar && (\n <BlockActionsOverlay editor={editor} target={selectedTarget} host={host} actions={actions} surface=\"toolbar\" persistent />\n )}\n {alwaysHandles && <BlockHandles editor={editor} host={host} />}\n </>,\n host,\n )}\n <DragHandle\n editor={editor}\n onElementDragEnd={resetDragHandle}\n onNodeChange={trackDragTarget}\n computePositionConfig={dragHandlePosition}\n nested={dragHandleNested}\n className={cn(\n 'flex size-6 cursor-grab items-center justify-center rounded text-muted-foreground hover:bg-muted hover:text-foreground data-[dragging=true]:cursor-grabbing',\n hoverHandleHidden && 'invisible! pointer-events-none!',\n )}\n >\n <span ref={handleContent} className=\"contents\">\n <Icon name=\"i-lucide-grip-vertical\" />\n </span>\n </DragHandle>\n </>\n )\n}\n\n// Nearest sibling with a layout box (a composite's hidden description/tags rows have none).\nfunction laidOutSibling(dom: Element, side: 'previous' | 'next'): DOMRect | null {\n for (let element = dom[`${side}ElementSibling`]; element; element = element[`${side}ElementSibling`]) {\n const rect = element.getBoundingClientRect()\n if (rect.height > 0) return rect\n }\n return null\n}\n"],"mappings":"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"}
@@ -1,5 +1,5 @@
1
- import { editorEntryOf } from "../../core/editor-ui.js";
2
1
  import { newBlockId } from "../../core/schema/block-ids.js";
2
+ import { editorEntryOf } from "../../core/editor-ui.js";
3
3
  import { createStore } from "../../core/store.js";
4
4
  import { anchorResolverOf, releaseRanges, resolveRange } from "../../core/doc-anchors.js";
5
5
  import { cancelCommentDraft, commentsDoc, commentsKey, commentsUser, setActiveComment, startCommentDraft } from "./comments-plugin.js";
@@ -1,6 +1,7 @@
1
1
  import { Translate } from "../../i18n/index.js";
2
2
  import { Notifier } from "../../core/notify.js";
3
3
  import "../../core/command-types.js";
4
+ import "./block-types.js";
4
5
  import { Extension } from "@tiptap/core";
5
6
  import { Node as Node$1 } from "@tiptap/pm/model";
6
7
  //#region src/features/composites/accepted-children.d.ts
@@ -11,11 +12,11 @@ export interface AcceptedChildrenOptions {
11
12
  t: Translate;
12
13
  }
13
14
  /**
14
- * Enforces the kinds' accepted children (`CompositeKind.accepts`) for every local edit at one place: a transaction that
15
- * leaves the document with more Bausteine nested in a Baustein that does not accept them than before is refused — block
16
- * drag, „In Baustein umwandeln“, paste, AI inserts and review acceptance, `moveBlockInto` — and the user is told why.
15
+ * Enforces the kinds' accepted children (`BlockType.accepts`) for every local edit at one place: a transaction that
16
+ * leaves the document with more Typed blocks nested in a Typed block that does not accept them than before is refused — block
17
+ * drag, „In Block umwandeln“, paste, AI inserts and review acceptance, `moveBlockInto` — and the user is told why.
17
18
  * Existing violations stay: transactions that add none (typing, undoing) pass, and so do collaboration replays, undo/redo
18
- * and loading a whole document. Client-only, no schema: kinds are read from the editor (`compositeKindsOf`).
19
+ * and loading a whole document. Client-only, no schema: kinds are read from the editor (`blockTypesOf`).
19
20
  */
20
21
  export declare const AcceptedChildren: Extension<AcceptedChildrenOptions, any>;
21
22
  //#endregion
@@ -1,6 +1,6 @@
1
1
  import { createTranslator } from "../../i18n/index.js";
2
- import { compositeKind, kindAccepts } from "./kinds.js";
3
- import { compositeKindsOf } from "./nodes.js";
2
+ import { acceptsChild, blockTypeOf } from "./block-types.js";
3
+ import { blockTypesOf } from "./nodes.js";
4
4
  import { Extension } from "@tiptap/core";
5
5
  import { Plugin, PluginKey } from "@tiptap/pm/state";
6
6
  import { AddMarkStep, AttrStep, RemoveMarkStep, ReplaceStep } from "@tiptap/pm/transform";
@@ -8,19 +8,19 @@ import { AddMarkStep, AttrStep, RemoveMarkStep, ReplaceStep } from "@tiptap/pm/t
8
8
  /** The short sentence for a refused nesting, naming both kinds by label (German: „Notiz nimmt keine Aufgabe auf.“). */
9
9
  function nestingReason(kinds, parent, child, t) {
10
10
  return t("composites.nesting.refused", {
11
- parent: compositeKind(kinds, parent).label,
12
- child: compositeKind(kinds, child).label
11
+ parent: blockTypeOf(kinds, parent).label,
12
+ child: blockTypeOf(kinds, child).label
13
13
  });
14
14
  }
15
15
  /**
16
- * The Bausteine of `node`'s subtree, outermost first: `node` itself when it is a Baustein, otherwise the Bausteine
17
- * directly inside it (not those nested in another Baustein).
16
+ * The Typed blocks of `node`'s subtree, outermost first: `node` itself when it is a Typed block, otherwise the Typed blocks
17
+ * directly inside it (not those nested in another Typed block).
18
18
  */
19
19
  function outermostComposites(node) {
20
- if (node.type.name === "composite") return [node];
20
+ if (node.type.name === "typedBlock") return [node];
21
21
  const found = [];
22
22
  node.descendants((child) => {
23
- if (child.type.name === "composite") {
23
+ if (child.type.name === "typedBlock") {
24
24
  found.push(child);
25
25
  return false;
26
26
  }
@@ -29,17 +29,17 @@ function outermostComposites(node) {
29
29
  return found;
30
30
  }
31
31
  /**
32
- * Every Baustein in `doc` whose nearest Baustein ancestor (quotes and lists in between do not count) does not accept
33
- * its kind, in document order. Top-level Bausteine have no parent and never violate.
32
+ * Every Typed block in `doc` whose nearest Typed block ancestor (quotes and lists in between do not count) does not accept
33
+ * its Block type, in document order. Top-level Typed blocks have no parent and never violate.
34
34
  */
35
35
  function nestingViolations(doc, kinds) {
36
36
  const found = [];
37
37
  function walk(node, parentKind) {
38
38
  node.forEach((child) => {
39
39
  if (child.isTextblock || child.isLeaf) return;
40
- if (child.type.name === "composite") {
41
- const kind = String(child.attrs.kind);
42
- if (parentKind !== null && !kindAccepts(kinds, parentKind, kind)) found.push({
40
+ if (child.type.name === "typedBlock") {
41
+ const kind = String(child.attrs.blockType);
42
+ if (parentKind !== null && !acceptsChild(kinds, parentKind, kind)) found.push({
43
43
  parent: parentKind,
44
44
  child: kind
45
45
  });
@@ -51,24 +51,24 @@ function nestingViolations(doc, kinds) {
51
51
  return found;
52
52
  }
53
53
  /**
54
- * The insert guard of the composites feature: a Baustein of kind `creates.attrs.kind` may be created only where the
55
- * nearest Baustein around the insertion point (`$parent` and outward; quotes and lists in between do not count)
56
- * accepts that kind, or where there is none. Uses `kindAccepts`, the rule `AcceptedChildren` enforces on transactions
54
+ * The insert guard of the composites feature: a Typed block of Block type `creates.attrs.blockType` may be created only where the
55
+ * nearest Typed block around the insertion point (`$parent` and outward; quotes and lists in between do not count)
56
+ * accepts that kind, or where there is none. Uses `acceptsChild`, the rule `AcceptedChildren` enforces on transactions
57
57
  * through `nestingViolations`, so the `/` menu and toolbar offer exactly what an edit would not be refused for.
58
58
  */
59
59
  const compositeInsertGuard = (editor, $parent, creates) => {
60
- const child = creates.attrs?.kind;
61
- if (creates.type !== "composite" || typeof child !== "string") return true;
60
+ const child = creates.attrs?.blockType;
61
+ if (creates.type !== "typedBlock" || typeof child !== "string") return true;
62
62
  for (let depth = $parent.depth; depth >= 0; depth--) {
63
63
  const node = $parent.node(depth);
64
- if (node.type.name === "composite") return kindAccepts(compositeKindsOf(editor), String(node.attrs.kind), child);
64
+ if (node.type.name === "typedBlock") return acceptsChild(blockTypesOf(editor), String(node.attrs.blockType), child);
65
65
  }
66
66
  return true;
67
67
  };
68
- /** A step that cannot change which Baustein sits in which: marks, text typed or deleted inside one textblock, attributes other than `kind`. */
68
+ /** A step that cannot change which Typed block sits in which: marks, text typed or deleted inside one textblock, attributes other than `blockType`. */
69
69
  function keepsNesting(step, before) {
70
70
  if (step instanceof AddMarkStep || step instanceof RemoveMarkStep) return true;
71
- if (step instanceof AttrStep) return step.attr !== "kind";
71
+ if (step instanceof AttrStep) return step.attr !== "blockType";
72
72
  if (step instanceof ReplaceStep) {
73
73
  const { slice } = step;
74
74
  if (slice.openStart !== 0 || slice.openEnd !== 0 || !slice.content.content.every((child) => child.isInline)) return false;
@@ -97,11 +97,11 @@ function addedViolation(before, after) {
97
97
  return after[0];
98
98
  }
99
99
  /**
100
- * Enforces the kinds' accepted children (`CompositeKind.accepts`) for every local edit at one place: a transaction that
101
- * leaves the document with more Bausteine nested in a Baustein that does not accept them than before is refused — block
102
- * drag, „In Baustein umwandeln“, paste, AI inserts and review acceptance, `moveBlockInto` — and the user is told why.
100
+ * Enforces the kinds' accepted children (`BlockType.accepts`) for every local edit at one place: a transaction that
101
+ * leaves the document with more Typed blocks nested in a Typed block that does not accept them than before is refused — block
102
+ * drag, „In Block umwandeln“, paste, AI inserts and review acceptance, `moveBlockInto` — and the user is told why.
103
103
  * Existing violations stay: transactions that add none (typing, undoing) pass, and so do collaboration replays, undo/redo
104
- * and loading a whole document. Client-only, no schema: kinds are read from the editor (`compositeKindsOf`).
104
+ * and loading a whole document. Client-only, no schema: kinds are read from the editor (`blockTypesOf`).
105
105
  */
106
106
  const AcceptedChildren = Extension.create({
107
107
  name: "acceptedChildren",
@@ -118,7 +118,7 @@ const AcceptedChildren = Extension.create({
118
118
  if (!tr.docChanged || isReplay(tr)) return true;
119
119
  if (tr.steps.some((step, index) => step instanceof ReplaceStep && step.from === 0 && step.to === tr.docs[index].content.size)) return true;
120
120
  if (tr.steps.every((step, index) => keepsNesting(step, tr.docs[index]))) return true;
121
- const kinds = compositeKindsOf(editor);
121
+ const kinds = blockTypesOf(editor);
122
122
  const before = nestingViolations(state.doc, kinds);
123
123
  const after = nestingViolations(tr.doc, kinds);
124
124
  if (after.length <= before.length) return true;