@ecsplico/editor 3.1.0 → 3.2.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 (270) hide show
  1. package/CHANGELOG.md +41 -0
  2. package/dist/adapters/direct-ai.d.ts +36 -0
  3. package/dist/adapters/direct-ai.js +169 -0
  4. package/dist/adapters/direct-ai.js.map +1 -0
  5. package/dist/adapters/memory.js.map +1 -1
  6. package/dist/code/CodeSurface.vue.d.ts +2 -2
  7. package/dist/core/block-drag.js +3 -0
  8. package/dist/core/block-drag.js.map +1 -1
  9. package/dist/core/block-transfer.d.ts +44 -0
  10. package/dist/core/block-transfer.js +68 -0
  11. package/dist/core/block-transfer.js.map +1 -0
  12. package/dist/core/commands.js +5 -0
  13. package/dist/core/commands.js.map +1 -1
  14. package/dist/core/core-feature.d.ts +4 -1
  15. package/dist/core/core-feature.js +8 -3
  16. package/dist/core/core-feature.js.map +1 -1
  17. package/dist/core/editor-ui.d.ts +3 -1
  18. package/dist/core/editor-ui.js.map +1 -1
  19. package/dist/core/extension-points.d.ts +17 -1
  20. package/dist/core/feature.d.ts +6 -1
  21. package/dist/core/feature.js.map +1 -1
  22. package/dist/core/index.d.ts +4 -2
  23. package/dist/core/index.js +3 -2
  24. package/dist/core/schema/index.d.ts +24 -3
  25. package/dist/core/schema/index.js +21 -4
  26. package/dist/core/schema/index.js.map +1 -1
  27. package/dist/core/surface-session.js +3 -1
  28. package/dist/core/surface-session.js.map +1 -1
  29. package/dist/core/toolbar-items.js +1 -1
  30. package/dist/core/toolbar-items.js.map +1 -1
  31. package/dist/document/DocumentSurface.vue.d.ts +2 -2
  32. package/dist/features/ai/agent-op-review.js +1 -1
  33. package/dist/features/ai/agent-ops.js +2 -2
  34. package/dist/features/ai/ai-apply.js +1 -1
  35. package/dist/features/ai/assistant.js +1 -1
  36. package/dist/features/ai/components/AiSelectionMenu.js +2 -2
  37. package/dist/features/ai/components/AiSidebar.js +2 -2
  38. package/dist/features/ai/components/SettingsAiTab.js +1 -1
  39. package/dist/features/ai/components/SettingsModelProfiles.js +1 -1
  40. package/dist/features/ai/document-chat-model.js +1 -1
  41. package/dist/features/ai/document-chat.js +2 -2
  42. package/dist/features/ai/ghost-autocomplete.js +1 -1
  43. package/dist/features/ai/index.d.ts +4 -3
  44. package/dist/features/ai/index.js +6 -5
  45. package/dist/features/ai/protocol/complete.d.ts +19 -0
  46. package/dist/features/ai/protocol/complete.js +27 -1
  47. package/dist/features/ai/protocol/complete.js.map +1 -1
  48. package/dist/features/ai/protocol/generate.d.ts +95 -0
  49. package/dist/features/ai/protocol/generate.js +58 -0
  50. package/dist/features/ai/protocol/generate.js.map +1 -0
  51. package/dist/features/ai/protocol/index.d.ts +4 -3
  52. package/dist/features/ai/protocol/index.js +6 -5
  53. package/dist/features/ai/protocol/tasks.d.ts +3 -1
  54. package/dist/features/ai/protocol/tasks.js +74 -2
  55. package/dist/features/ai/protocol/tasks.js.map +1 -1
  56. package/dist/features/ai/react/AiSelectionMenu.js +2 -2
  57. package/dist/features/ai/react/AiSidebar.js +2 -2
  58. package/dist/features/ai/react/SettingsAiTab.js +1 -1
  59. package/dist/features/ai/react/SettingsModelProfiles.js +1 -1
  60. package/dist/features/ai/selection-flow.js +1 -1
  61. package/dist/features/ai/sidebar-flow.js +1 -1
  62. package/dist/features/block-ui/block-actions.d.ts +19 -3
  63. package/dist/features/block-ui/block-actions.js +49 -3
  64. package/dist/features/block-ui/block-actions.js.map +1 -1
  65. package/dist/features/block-ui/components/BlockActionsOverlay.js +24 -13
  66. package/dist/features/block-ui/components/BlockActionsOverlay.js.map +1 -1
  67. package/dist/features/block-ui/components/BlockActionsOverlay.vue.d.ts +12 -5
  68. package/dist/features/block-ui/components/BlockUi.js +52 -20
  69. package/dist/features/block-ui/components/BlockUi.js.map +1 -1
  70. package/dist/features/block-ui/components/BlockUi.vue.d.ts +6 -4
  71. package/dist/features/block-ui/feature.d.ts +8 -2
  72. package/dist/features/block-ui/feature.js +7 -2
  73. package/dist/features/block-ui/feature.js.map +1 -1
  74. package/dist/features/block-ui/index.d.ts +3 -2
  75. package/dist/features/block-ui/index.js +2 -2
  76. package/dist/features/block-ui/react/BlockActionsOverlay.d.ts +14 -7
  77. package/dist/features/block-ui/react/BlockActionsOverlay.js +25 -13
  78. package/dist/features/block-ui/react/BlockActionsOverlay.js.map +1 -1
  79. package/dist/features/block-ui/react/BlockUi.d.ts +6 -4
  80. package/dist/features/block-ui/react/BlockUi.js +43 -15
  81. package/dist/features/block-ui/react/BlockUi.js.map +1 -1
  82. package/dist/features/block-ui/react.d.ts +4 -2
  83. package/dist/features/block-ui/react.js +3 -3
  84. package/dist/features/block-ui/react.js.map +1 -1
  85. package/dist/features/block-ui/vue.d.ts +4 -2
  86. package/dist/features/block-ui/vue.js +3 -3
  87. package/dist/features/block-ui/vue.js.map +1 -1
  88. package/dist/features/composites/baskets.d.ts +27 -0
  89. package/dist/features/composites/baskets.js +46 -0
  90. package/dist/features/composites/baskets.js.map +1 -0
  91. package/dist/features/composites/components/CompositeBasketMenu.js +97 -0
  92. package/dist/features/composites/components/CompositeBasketMenu.js.map +1 -0
  93. package/dist/features/composites/components/CompositeChrome.js +79 -23
  94. package/dist/features/composites/components/CompositeChrome.js.map +1 -1
  95. package/dist/features/composites/components/CompositeFieldEditor.js +1 -0
  96. package/dist/features/composites/components/CompositeFieldEditor.js.map +1 -1
  97. package/dist/features/composites/components/CompositeView.js +17 -2
  98. package/dist/features/composites/components/CompositeView.js.map +1 -1
  99. package/dist/features/composites/components/DerivationBadge.js +12 -3
  100. package/dist/features/composites/components/DerivationBadge.js.map +1 -1
  101. package/dist/features/composites/components/FocusChip.js +53 -0
  102. package/dist/features/composites/components/FocusChip.js.map +1 -0
  103. package/dist/features/composites/components/FocusChip.vue.d.ts +14 -0
  104. package/dist/features/composites/components/SettingsEditingTab.js +40 -4
  105. package/dist/features/composites/components/SettingsEditingTab.js.map +1 -1
  106. package/dist/features/composites/derivation.d.ts +2 -1
  107. package/dist/features/composites/derivation.js +5 -1
  108. package/dist/features/composites/derivation.js.map +1 -1
  109. package/dist/features/composites/derived-chrome.js +13 -3
  110. package/dist/features/composites/derived-chrome.js.map +1 -1
  111. package/dist/features/composites/feature.d.ts +7 -1
  112. package/dist/features/composites/feature.js +96 -23
  113. package/dist/features/composites/feature.js.map +1 -1
  114. package/dist/features/composites/focus.d.ts +38 -0
  115. package/dist/features/composites/focus.js +86 -0
  116. package/dist/features/composites/focus.js.map +1 -0
  117. package/dist/features/composites/index.d.ts +6 -3
  118. package/dist/features/composites/index.js +6 -3
  119. package/dist/features/composites/meta-keys.d.ts +4 -0
  120. package/dist/features/composites/meta-keys.js +8 -4
  121. package/dist/features/composites/meta-keys.js.map +1 -1
  122. package/dist/features/composites/nodes.d.ts +14 -2
  123. package/dist/features/composites/nodes.js +61 -5
  124. package/dist/features/composites/nodes.js.map +1 -1
  125. package/dist/features/composites/outline.d.ts +4 -0
  126. package/dist/features/composites/outline.js +3 -0
  127. package/dist/features/composites/outline.js.map +1 -1
  128. package/dist/features/composites/react/CompositeBasketMenu.js +88 -0
  129. package/dist/features/composites/react/CompositeBasketMenu.js.map +1 -0
  130. package/dist/features/composites/react/CompositeChrome.js +52 -4
  131. package/dist/features/composites/react/CompositeChrome.js.map +1 -1
  132. package/dist/features/composites/react/CompositeView.js +12 -2
  133. package/dist/features/composites/react/CompositeView.js.map +1 -1
  134. package/dist/features/composites/react/DerivationBadge.js +10 -1
  135. package/dist/features/composites/react/DerivationBadge.js.map +1 -1
  136. package/dist/features/composites/react/FocusChip.d.ts +11 -0
  137. package/dist/features/composites/react/FocusChip.js +50 -0
  138. package/dist/features/composites/react/FocusChip.js.map +1 -0
  139. package/dist/features/composites/react/SettingsEditingTab.js +36 -1
  140. package/dist/features/composites/react/SettingsEditingTab.js.map +1 -1
  141. package/dist/features/composites/react.d.ts +2 -1
  142. package/dist/features/composites/react.js +3 -1
  143. package/dist/features/composites/react.js.map +1 -1
  144. package/dist/features/composites/schema.d.ts +5 -3
  145. package/dist/features/composites/schema.js +8 -4
  146. package/dist/features/composites/schema.js.map +1 -1
  147. package/dist/features/composites/split.d.ts +62 -0
  148. package/dist/features/composites/split.js +172 -0
  149. package/dist/features/composites/split.js.map +1 -0
  150. package/dist/features/composites/vue.d.ts +4 -3
  151. package/dist/features/composites/vue.js +7 -5
  152. package/dist/features/composites/vue.js.map +1 -1
  153. package/dist/features/media/index.js +1 -1
  154. package/dist/features/media/react/AudioRecorderModal.js +1 -1
  155. package/dist/features/media/react.js +1 -1
  156. package/dist/features/transfer/components/TransferMenu.js +93 -0
  157. package/dist/features/transfer/components/TransferMenu.js.map +1 -0
  158. package/dist/features/transfer/components/TransferMenu.vue.d.ts +15 -0
  159. package/dist/features/transfer/feature.d.ts +76 -0
  160. package/dist/features/transfer/feature.js +169 -0
  161. package/dist/features/transfer/feature.js.map +1 -0
  162. package/dist/features/transfer/index.d.ts +3 -0
  163. package/dist/features/transfer/index.js +3 -0
  164. package/dist/features/transfer/react/TransferMenu.d.ts +12 -0
  165. package/dist/features/transfer/react/TransferMenu.js +71 -0
  166. package/dist/features/transfer/react/TransferMenu.js.map +1 -0
  167. package/dist/features/transfer/react.d.ts +10 -0
  168. package/dist/features/transfer/react.js +11 -0
  169. package/dist/features/transfer/react.js.map +1 -0
  170. package/dist/features/transfer/transforms.d.ts +83 -0
  171. package/dist/features/transfer/transforms.js +137 -0
  172. package/dist/features/transfer/transforms.js.map +1 -0
  173. package/dist/features/transfer/vue.d.ts +9 -0
  174. package/dist/features/transfer/vue.js +11 -0
  175. package/dist/features/transfer/vue.js.map +1 -0
  176. package/dist/i18n/de/ai.js +4 -0
  177. package/dist/i18n/de/ai.js.map +1 -1
  178. package/dist/i18n/de/composites.js +20 -1
  179. package/dist/i18n/de/composites.js.map +1 -1
  180. package/dist/i18n/de/integrations.js +16 -0
  181. package/dist/i18n/de/integrations.js.map +1 -1
  182. package/dist/i18n/de/transfer.js +17 -0
  183. package/dist/i18n/de/transfer.js.map +1 -0
  184. package/dist/i18n/de/tree.js +6 -0
  185. package/dist/i18n/de/tree.js.map +1 -1
  186. package/dist/i18n/de.d.ts +55 -0
  187. package/dist/i18n/de.js +3 -1
  188. package/dist/i18n/de.js.map +1 -1
  189. package/dist/i18n/en/ai.js +4 -0
  190. package/dist/i18n/en/ai.js.map +1 -1
  191. package/dist/i18n/en/composites.js +20 -1
  192. package/dist/i18n/en/composites.js.map +1 -1
  193. package/dist/i18n/en/integrations.js +16 -0
  194. package/dist/i18n/en/integrations.js.map +1 -1
  195. package/dist/i18n/en/transfer.js +17 -0
  196. package/dist/i18n/en/transfer.js.map +1 -0
  197. package/dist/i18n/en/tree.js +6 -0
  198. package/dist/i18n/en/tree.js.map +1 -1
  199. package/dist/i18n/en.js +3 -1
  200. package/dist/i18n/en.js.map +1 -1
  201. package/dist/integrations/composite-ai/composite-fill.js +1 -1
  202. package/dist/integrations/composite-ai/composite-summary.js +1 -1
  203. package/dist/integrations/composite-ai/derive.d.ts +21 -0
  204. package/dist/integrations/composite-ai/derive.js +69 -47
  205. package/dist/integrations/composite-ai/derive.js.map +1 -1
  206. package/dist/integrations/composite-ai/index.d.ts +8 -3
  207. package/dist/integrations/composite-ai/index.js +50 -4
  208. package/dist/integrations/composite-ai/index.js.map +1 -1
  209. package/dist/integrations/composite-ai/outline-sanitize.d.ts +48 -0
  210. package/dist/integrations/composite-ai/outline-sanitize.js +175 -0
  211. package/dist/integrations/composite-ai/outline-sanitize.js.map +1 -0
  212. package/dist/integrations/composite-ai/split.d.ts +44 -0
  213. package/dist/integrations/composite-ai/split.js +187 -0
  214. package/dist/integrations/composite-ai/split.js.map +1 -0
  215. package/dist/integrations/composite-ai/transfer-transforms.d.ts +27 -0
  216. package/dist/integrations/composite-ai/transfer-transforms.js +153 -0
  217. package/dist/integrations/composite-ai/transfer-transforms.js.map +1 -0
  218. package/dist/integrations/transcript-ai/protocol.d.ts +13 -0
  219. package/dist/integrations/transcript-ai/protocol.js +49 -1
  220. package/dist/integrations/transcript-ai/protocol.js.map +1 -1
  221. package/dist/integrations/transcript-ai/transcript-cleanup.js +1 -1
  222. package/dist/markdown/MarkdownSurface.vue.d.ts +6 -6
  223. package/dist/nuxt/module.d.ts +110 -0
  224. package/dist/presets/compose.d.ts +24 -8
  225. package/dist/presets/compose.js +117 -58
  226. package/dist/presets/compose.js.map +1 -1
  227. package/dist/react/compose.js +6 -2
  228. package/dist/react/compose.js.map +1 -1
  229. package/dist/react/composed-surface.d.ts +9 -0
  230. package/dist/react/composed-surface.js +4 -1
  231. package/dist/react/composed-surface.js.map +1 -1
  232. package/dist/server/ai.d.ts +2 -5
  233. package/dist/server/ai.js.map +1 -1
  234. package/dist/server/handlers/ai.d.ts +7 -78
  235. package/dist/server/handlers/ai.js +30 -94
  236. package/dist/server/handlers/ai.js.map +1 -1
  237. package/dist/server/handlers/editor.d.ts +1 -0
  238. package/dist/server/handlers/index.d.ts +3 -1
  239. package/dist/server/handlers/index.js +3 -1
  240. package/dist/server/index.d.ts +2 -1
  241. package/dist/settings/index.d.ts +8 -0
  242. package/dist/settings/index.js +16 -4
  243. package/dist/settings/index.js.map +1 -1
  244. package/dist/styles/composites.css +32 -0
  245. package/dist/tree/DocumentTree.js +229 -78
  246. package/dist/tree/DocumentTree.js.map +1 -1
  247. package/dist/tree/drop-rules.js +8 -0
  248. package/dist/tree/drop-rules.js.map +1 -1
  249. package/dist/tree/react/DocumentTree.js +152 -31
  250. package/dist/tree/react/DocumentTree.js.map +1 -1
  251. package/dist/tree/tree-host.js +30 -1
  252. package/dist/tree/tree-host.js.map +1 -1
  253. package/dist/tree/tree-items.js +52 -5
  254. package/dist/tree/tree-items.js.map +1 -1
  255. package/dist/tree/tree-model.js +113 -10
  256. package/dist/tree/tree-model.js.map +1 -1
  257. package/dist/tree/tree-rows.js +20 -7
  258. package/dist/tree/tree-rows.js.map +1 -1
  259. package/dist/tree/tree-view-model.d.ts +5 -0
  260. package/dist/tree/tree-view-model.js +13 -0
  261. package/dist/tree/tree-view-model.js.map +1 -1
  262. package/dist/vue/AdvancedEditor.js +6 -0
  263. package/dist/vue/AdvancedEditor.js.map +1 -1
  264. package/dist/vue/AdvancedEditor.vue.d.ts +13 -5
  265. package/dist/vue/SimpleEditor.vue.d.ts +4 -4
  266. package/dist/vue/components/EditorSurface.vue.d.ts +4 -4
  267. package/dist/vue/compose.js +6 -2
  268. package/dist/vue/compose.js.map +1 -1
  269. package/dist/vue/kit/types.d.ts +2 -0
  270. package/package.json +21 -1
@@ -0,0 +1,93 @@
1
+ import { useUiKit } from "../../../vue/kit/use-ui-kit.js";
2
+ import { useEditorI18n } from "../../../vue/use-editor-i18n.js";
3
+ import { useStoreRef } from "../../../vue/store-ref.js";
4
+ import { Fragment, computed, createBlock, createCommentVNode, createElementBlock, createElementVNode, defineComponent, normalizeStyle, onBeforeUnmount, openBlock, ref, renderList, toDisplayString, unref, watch } from "vue";
5
+ //#region src/features/transfer/components/TransferMenu.vue
6
+ const _hoisted_1 = ["aria-label"];
7
+ const _hoisted_2 = { class: "px-2 py-1 text-xs text-[var(--sk-muted)]" };
8
+ /**
9
+ * The transform menu of a Shift-drop (mounted by the transfer feature): opens at the drop point while a drop waits in
10
+ * `editor.storage.blockDropTarget.pending`, lists the transforms available for it and runs the one picked. Escape or a
11
+ * click elsewhere cancels the drop.
12
+ */
13
+ const ITEM_HEIGHT = 32;
14
+ const MENU_WIDTH = 240;
15
+ const EDGE = 8;
16
+ const _sfc_main = /*@__PURE__*/ defineComponent({
17
+ __name: "TransferMenu",
18
+ props: { editor: {} },
19
+ setup(__props) {
20
+ const props = __props;
21
+ const { Button: UButton } = useUiKit();
22
+ const { t } = useEditorI18n();
23
+ const storage = props.editor.storage.blockDropTarget;
24
+ const pending = useStoreRef(storage.pending);
25
+ const transforms = computed(() => pending.value ? storage.available(pending.value) : []);
26
+ const label = (transform) => transform.labelKey ? t(transform.labelKey) : transform.label;
27
+ /** The menu's top-left corner: at the drop point, kept inside the viewport. */
28
+ const style = computed(() => {
29
+ const drop = pending.value;
30
+ if (!drop) return {};
31
+ const height = transforms.value.length * ITEM_HEIGHT + ITEM_HEIGHT + 16;
32
+ const left = Math.max(EDGE, Math.min(drop.x, window.innerWidth - MENU_WIDTH - EDGE));
33
+ const top = Math.max(EDGE, Math.min(drop.y, window.innerHeight - height - EDGE));
34
+ return {
35
+ left: `${left}px`,
36
+ top: `${top}px`,
37
+ width: `${MENU_WIDTH}px`
38
+ };
39
+ });
40
+ const root = ref(null);
41
+ const cancel = () => props.editor.commands.cancelTransfer();
42
+ const onKey = (event) => {
43
+ if (event.key !== "Escape") return;
44
+ event.preventDefault();
45
+ cancel();
46
+ };
47
+ const onPointerDown = (event) => {
48
+ if (!root.value?.contains(event.target)) cancel();
49
+ };
50
+ const listen = (on) => {
51
+ if (on) {
52
+ document.addEventListener("keydown", onKey, true);
53
+ document.addEventListener("pointerdown", onPointerDown, true);
54
+ } else {
55
+ document.removeEventListener("keydown", onKey, true);
56
+ document.removeEventListener("pointerdown", onPointerDown, true);
57
+ }
58
+ };
59
+ watch(() => pending.value !== null, listen, { immediate: true });
60
+ onBeforeUnmount(() => listen(false));
61
+ return (_ctx, _cache) => {
62
+ return unref(pending) ? (openBlock(), createElementBlock("div", {
63
+ key: 0,
64
+ ref_key: "root",
65
+ ref: root,
66
+ class: "fixed z-50 rounded-lg border border-[var(--sk-border)] bg-[var(--sk-bg)] p-1 shadow-lg",
67
+ style: normalizeStyle(style.value),
68
+ role: "menu",
69
+ "aria-label": unref(t)("transfer.menu.title")
70
+ }, [createElementVNode("p", _hoisted_2, toDisplayString(unref(t)("transfer.menu.title")), 1), (openBlock(true), createElementBlock(Fragment, null, renderList(transforms.value, (transform) => {
71
+ return openBlock(), createBlock(unref(UButton), {
72
+ key: transform.id,
73
+ class: "w-full justify-start",
74
+ size: "sm",
75
+ color: "neutral",
76
+ variant: "ghost",
77
+ role: "menuitem",
78
+ icon: transform.icon,
79
+ label: label(transform),
80
+ onClick: ($event) => unref(storage).run(transform.id, unref(pending))
81
+ }, null, 8, [
82
+ "icon",
83
+ "label",
84
+ "onClick"
85
+ ]);
86
+ }), 128))], 12, _hoisted_1)) : createCommentVNode("v-if", true);
87
+ };
88
+ }
89
+ });
90
+ //#endregion
91
+ export { _sfc_main as default };
92
+
93
+ //# sourceMappingURL=TransferMenu.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"TransferMenu.js","names":["_unref","_openBlock","_createElementBlock","_normalizeStyle","_createElementVNode","_toDisplayString","_Fragment","_renderList","_createBlock","_createCommentVNode"],"sources":["../../../../src/features/transfer/components/TransferMenu.vue"],"sourcesContent":["<script setup lang=\"ts\">\nimport type { Editor } from '@tiptap/vue-3'\nimport { computed, onBeforeUnmount, ref, watch } from 'vue'\nimport { useStoreRef } from '../../../vue/store-ref'\nimport { useUiKit } from '../../../vue/kit/use-ui-kit'\nimport { useEditorI18n } from '../../../vue/use-editor-i18n'\nimport type { BlockTransform } from '../transforms'\n\n/**\n * The transform menu of a Shift-drop (mounted by the transfer feature): opens at the drop point while a drop waits in\n * `editor.storage.blockDropTarget.pending`, lists the transforms available for it and runs the one picked. Escape or a\n * click elsewhere cancels the drop.\n */\nconst props = defineProps<{ editor: Editor }>()\n\nconst { Button: UButton } = useUiKit()\nconst { t } = useEditorI18n()\n\nconst storage = props.editor.storage.blockDropTarget!\nconst pending = useStoreRef(storage.pending)\n\nconst ITEM_HEIGHT = 32\nconst MENU_WIDTH = 240\nconst EDGE = 8\n\nconst transforms = computed<BlockTransform[]>(() => (pending.value ? storage.available(pending.value) : []))\nconst label = (transform: BlockTransform) => (transform.labelKey ? t(transform.labelKey) : transform.label)\n\n/** The menu's top-left corner: at the drop point, kept inside the viewport. */\nconst style = computed(() => {\n const drop = pending.value\n if (!drop) return {}\n const height = transforms.value.length * ITEM_HEIGHT + ITEM_HEIGHT + 2 * EDGE\n const left = Math.max(EDGE, Math.min(drop.x, window.innerWidth - MENU_WIDTH - EDGE))\n const top = Math.max(EDGE, Math.min(drop.y, window.innerHeight - height - EDGE))\n return { left: `${left}px`, top: `${top}px`, width: `${MENU_WIDTH}px` }\n})\n\nconst root = ref<HTMLElement | null>(null)\nconst cancel = () => props.editor.commands.cancelTransfer()\nconst onKey = (event: KeyboardEvent) => {\n if (event.key !== 'Escape') return\n event.preventDefault()\n cancel()\n}\nconst onPointerDown = (event: PointerEvent) => {\n if (!root.value?.contains(event.target as Node)) cancel()\n}\nconst listen = (on: boolean) => {\n if (on) {\n document.addEventListener('keydown', onKey, true)\n document.addEventListener('pointerdown', onPointerDown, true)\n }\n else {\n document.removeEventListener('keydown', onKey, true)\n document.removeEventListener('pointerdown', onPointerDown, true)\n }\n}\nwatch(() => pending.value !== null, listen, { immediate: true })\nonBeforeUnmount(() => listen(false))\n</script>\n\n<template>\n <div\n v-if=\"pending\"\n ref=\"root\"\n class=\"fixed z-50 rounded-lg border border-[var(--sk-border)] bg-[var(--sk-bg)] p-1 shadow-lg\"\n :style=\"style\"\n role=\"menu\"\n :aria-label=\"t('transfer.menu.title')\"\n >\n <p class=\"px-2 py-1 text-xs text-[var(--sk-muted)]\">{{ t('transfer.menu.title') }}</p>\n <UButton\n v-for=\"transform in transforms\"\n :key=\"transform.id\"\n class=\"w-full justify-start\"\n size=\"sm\"\n color=\"neutral\"\n variant=\"ghost\"\n role=\"menuitem\"\n :icon=\"transform.icon\"\n :label=\"label(transform)\"\n @click=\"storage.run(transform.id, pending)\"\n />\n </div>\n</template>\n"],"mappings":";;;;;;;;;;;;AAqBA,MAAM,cAAc;AACpB,MAAM,aAAa;AACnB,MAAM,OAAO;;;;;EAVb,MAAM,QAAQ;EAEd,MAAM,EAAE,QAAQ,YAAY,SAAS;EACrC,MAAM,EAAE,MAAM,cAAc;EAE5B,MAAM,UAAU,MAAM,OAAO,QAAQ;EACrC,MAAM,UAAU,YAAY,QAAQ,OAAO;EAM3C,MAAM,aAAa,eAAkC,QAAQ,QAAQ,QAAQ,UAAU,QAAQ,KAAK,IAAI,CAAC,CAAE;EAC3G,MAAM,SAAS,cAA+B,UAAU,WAAW,EAAE,UAAU,QAAQ,IAAI,UAAU;;EAGrG,MAAM,QAAQ,eAAe;GAC3B,MAAM,OAAO,QAAQ;GACrB,IAAI,CAAC,MAAM,OAAO,CAAC;GACnB,MAAM,SAAS,WAAW,MAAM,SAAS,cAAc,cAAc;GACrE,MAAM,OAAO,KAAK,IAAI,MAAM,KAAK,IAAI,KAAK,GAAG,OAAO,aAAa,aAAa,IAAI,CAAC;GACnF,MAAM,MAAM,KAAK,IAAI,MAAM,KAAK,IAAI,KAAK,GAAG,OAAO,cAAc,SAAS,IAAI,CAAC;GAC/E,OAAO;IAAE,MAAM,GAAG,KAAK;IAAK,KAAK,GAAG,IAAI;IAAK,OAAO,GAAG,WAAW;GAAI;EACxE,CAAC;EAED,MAAM,OAAO,IAAwB,IAAI;EACzC,MAAM,eAAe,MAAM,OAAO,SAAS,eAAe;EAC1D,MAAM,SAAS,UAAyB;GACtC,IAAI,MAAM,QAAQ,UAAU;GAC5B,MAAM,eAAe;GACrB,OAAO;EACT;EACA,MAAM,iBAAiB,UAAwB;GAC7C,IAAI,CAAC,KAAK,OAAO,SAAS,MAAM,MAAc,GAAG,OAAO;EAC1D;EACA,MAAM,UAAU,OAAgB;GAC9B,IAAI,IAAI;IACN,SAAS,iBAAiB,WAAW,OAAO,IAAI;IAChD,SAAS,iBAAiB,eAAe,eAAe,IAAI;GAC9D,OACK;IACH,SAAS,oBAAoB,WAAW,OAAO,IAAI;IACnD,SAAS,oBAAoB,eAAe,eAAe,IAAI;GACjE;EACF;EACA,YAAY,QAAQ,UAAU,MAAM,QAAQ,EAAE,WAAW,KAAK,CAAC;EAC/D,sBAAsB,OAAO,KAAK,CAAC;;GAKzB,OAAAA,MAAA,OAAA,KADRC,UAAA,GAAAC,mBAqBM,OAAA;;IAnBA,SAAA;IAAJ,KAAI;IACJ,OAAM;IACL,OAAKC,eAAE,MAAA,KAAK;IACb,MAAK;IACJ,cAAYH,MAAA,CAAA,CAAC,CAAA,qBAAA;GAEd,GAAA,CAAAI,mBAAsF,KAAtF,YAAsFC,gBAA/BL,MAAA,CAAA,CAAC,CAAA,qBAAA,CAAA,GAAA,CAAA,IACxDC,UAAA,IAAA,GAAAC,mBAWEI,UAAA,MAAAC,WAVoB,WAAA,QAAb,cAAS;IADlB,OAAAN,UAAA,GAAAO,YAWER,MAAA,OAAA,GAAA;KATC,KAAK,UAAU;KAChB,OAAM;KACN,MAAK;KACL,OAAM;KACN,SAAQ;KACR,MAAK;KACJ,MAAM,UAAU;KAChB,OAAO,MAAM,SAAS;KACtB,UAAK,WAAEA,MAAA,OAAA,CAAO,CAAC,IAAI,UAAU,IAAIA,MAAA,OAAA,CAAO"}
@@ -0,0 +1,15 @@
1
+ import { Editor } from "@tiptap/vue-3";
2
+ //#region src/features/transfer/components/TransferMenu.vue.d.ts
3
+ /**
4
+ * The transform menu of a Shift-drop (mounted by the transfer feature): opens at the drop point while a drop waits in
5
+ * `editor.storage.blockDropTarget.pending`, lists the transforms available for it and runs the one picked. Escape or a
6
+ * click elsewhere cancels the drop.
7
+ */
8
+ type __VLS_Props = {
9
+ editor: Editor;
10
+ };
11
+ declare const __VLS_export: import("vue").DefineComponent<__VLS_Props, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {}, string, import("vue").PublicProps, Readonly<__VLS_Props> & Readonly<{}>, {}, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
12
+ declare const _default: typeof __VLS_export;
13
+ //#endregion
14
+ export { _default as default };
15
+ //# sourceMappingURL=TransferMenu.vue.d.ts.map
@@ -0,0 +1,76 @@
1
+ import { Store } from "../../core/store.js";
2
+ import { EditorFeature } from "../../core/feature.js";
3
+ import { BlockTransfer } from "../../core/block-transfer.js";
4
+ import "../../core/index.js";
5
+ import { BlockTransform } from "./transforms.js";
6
+ import { Node } from "@tiptap/pm/model";
7
+ //#region src/features/transfer/feature.d.ts
8
+ /** One drop of a block: the dragged block, where it lands (document position), whether the transform menu opens first and where it opens (viewport pixels). */
9
+ export interface TransferDrop {
10
+ payload: BlockTransfer;
11
+ pos: number;
12
+ /** `true`: the menu opens at (`x`, `y`) and the user picks the transform; `false`: the default transform runs. */
13
+ menu: boolean;
14
+ x: number;
15
+ y: number;
16
+ }
17
+ /** A drop waiting for the user to pick a transform from the menu (`TransferDrop` with `menu` on). */
18
+ export type PendingDrop = TransferDrop;
19
+ export interface BlockDropTargetStorage {
20
+ /** The drop the transform menu is open for; `null` while no menu is open. */
21
+ pending: Store<PendingDrop | null>;
22
+ /** The transforms the menu offers for `drop` (those whose `available` says yes). */
23
+ available: (drop: PendingDrop) => BlockTransform[];
24
+ /** Closes the menu and runs the transform `id` for `drop` (a refused insert shows its notice). */
25
+ run: (id: string, drop: PendingDrop) => Promise<void>;
26
+ }
27
+ declare module '@tiptap/core' {
28
+ interface Storage {
29
+ /** Absent in an editor without the transfer feature. */
30
+ blockDropTarget?: BlockDropTargetStorage;
31
+ }
32
+ interface Commands<ReturnType> {
33
+ blockTransfer: {
34
+ /**
35
+ * Puts the block of `payload` into the document at `pos` (a position where a block may be inserted): with `menu`
36
+ * the transform menu opens at (`x`, `y`) and the transform the user picks runs, else the default transform runs.
37
+ * Refuses a drop of a block onto its own position in the same document (notice). Used by the document tree's drop executor.
38
+ */
39
+ transferBlock: (options: {
40
+ payload: BlockTransfer;
41
+ pos: number;
42
+ menu: boolean;
43
+ x?: number;
44
+ y?: number;
45
+ }) => ReturnType;
46
+ /** Closes the transform menu without inserting anything. */
47
+ cancelTransfer: () => ReturnType;
48
+ };
49
+ }
50
+ }
51
+ /**
52
+ * Whether dropping `payload` at `pos` of `doc` lands inside the very block it was dragged from: the payload names a
53
+ * block of this document (same `documentId`, a block with that id exists) and `pos` is strictly inside it.
54
+ */
55
+ export declare function isSelfDrop(doc: Node, documentId: string | null | undefined, payload: BlockTransfer, pos: number): boolean;
56
+ /** Options of `transferFeature`. */
57
+ export interface TransferFeatureOptions {
58
+ /** The transforms the menu offers and a drop can run; default `[copyTransform]` (`composeEditor` adds the AI transforms of `@ecsplico/editor/integrations/composite-ai` when `ai` is on). A host list replaces the default (add built-ins explicitly). */
59
+ transforms?: readonly BlockTransform[];
60
+ /** Id of the transform a plain drop (no Shift) runs; default `copy`. */
61
+ defaultTransform?: string;
62
+ }
63
+ /** What a framework binding supplies to `transferFeatureCore`. */
64
+ export interface TransferUi<C> {
65
+ /** The transform menu (receives `{ editor }`), mounted as an overlay. */
66
+ menu: C;
67
+ }
68
+ /**
69
+ * Block transfer between editor surfaces and document trees (the framework-free part of `transferFeature`): a block
70
+ * dragged out of another surface lands as a copy with fresh ids and a `meta.derivation` pointing at its source, or,
71
+ * with Shift held at the drop, as the result of a transform picked from a menu (the copy, and the AI transforms a host or `composeEditor` adds).
72
+ * Insert guards apply; the commands `transferBlock` and `cancelTransfer` serve the document tree's drops.
73
+ */
74
+ export declare function transferFeatureCore<C>(ui: TransferUi<C>, options?: TransferFeatureOptions): EditorFeature<C>;
75
+ //#endregion
76
+ //# sourceMappingURL=feature.d.ts.map
@@ -0,0 +1,169 @@
1
+ import { findBlockById } from "../../core/schema/block-ids.js";
2
+ import { readBlockTransfer } from "../../core/block-transfer.js";
3
+ import { createStore } from "../../core/store.js";
4
+ import { DEFAULT_TRANSFORMS, availableTransforms, runTransform } from "./transforms.js";
5
+ import { Extension } from "@tiptap/core";
6
+ import { Plugin, PluginKey } from "@tiptap/pm/state";
7
+ import { Fragment, Slice } from "@tiptap/pm/model";
8
+ import { dropPoint } from "@tiptap/pm/transform";
9
+ //#region src/features/transfer/feature.ts
10
+ /**
11
+ * Whether dropping `payload` at `pos` of `doc` lands inside the very block it was dragged from: the payload names a
12
+ * block of this document (same `documentId`, a block with that id exists) and `pos` is strictly inside it.
13
+ */
14
+ function isSelfDrop(doc, documentId, payload, pos) {
15
+ if (!payload.blockId || (payload.documentId ?? null) !== (documentId ?? null)) return false;
16
+ const found = findBlockById(doc, payload.blockId);
17
+ return !!found && pos > found.pos && pos < found.pos + found.node.nodeSize;
18
+ }
19
+ /**
20
+ * The shared tail of a drop (DOM drop and `transferBlock`): refuses a self-drop, else opens the menu (`menu`) or runs
21
+ * the default transform.
22
+ */
23
+ function dropBlock(env, documentId, defaultId, pending, drop) {
24
+ const { payload, pos } = drop;
25
+ pending.set(null);
26
+ if (isSelfDrop(env.editor.state.doc, documentId, payload, pos)) {
27
+ env.notify({
28
+ kind: "warning",
29
+ title: env.t("transfer.selfDrop")
30
+ });
31
+ return;
32
+ }
33
+ if (drop.menu) pending.set(drop);
34
+ else queueMicrotask(() => {
35
+ runTransform(env, defaultId, payload, pos);
36
+ });
37
+ }
38
+ const blockDropTargetKey = new PluginKey("blockDropTarget");
39
+ /**
40
+ * The slice dropping `payload` would insert, for `dropPoint`; `null` when this schema cannot hold the block. It is closed
41
+ * (`openStart` and `openEnd` 0): an open slice would let `dropPoint` return a position inside a paragraph, where the
42
+ * Baustein cannot be inserted.
43
+ */
44
+ function sliceOf(editor, payload) {
45
+ try {
46
+ return new Slice(Fragment.from(editor.schema.nodeFromJSON(payload.json)), 0, 0);
47
+ } catch {
48
+ return null;
49
+ }
50
+ }
51
+ /**
52
+ * Takes blocks dragged out of another editor surface or document tree (`BLOCK_MIME`): a plain drop runs the default
53
+ * transform, Shift opens the transform menu at the drop point. A drag that started in this editor stays ProseMirror's
54
+ * native move. Also the commands `transferBlock` and `cancelTransfer`.
55
+ */
56
+ function blockDropTarget(ctx, transforms, defaultId) {
57
+ const envOf = (editor) => ({
58
+ editor,
59
+ transforms,
60
+ ai: ctx.backend.ai,
61
+ app: ctx.app,
62
+ notify: ctx.notify,
63
+ t: ctx.t
64
+ });
65
+ let created;
66
+ const editorOf = () => {
67
+ if (!created) throw new Error("blockDropTarget: the editor is not created yet");
68
+ return created;
69
+ };
70
+ return Extension.create({
71
+ name: "blockDropTarget",
72
+ onBeforeCreate() {
73
+ created = this.editor;
74
+ },
75
+ addStorage() {
76
+ const pending = createStore(null);
77
+ return {
78
+ pending,
79
+ available: ({ payload, pos }) => availableTransforms(envOf(editorOf()), payload, pos),
80
+ run: async (id, { payload, pos }) => {
81
+ pending.set(null);
82
+ await runTransform(envOf(editorOf()), id, payload, pos);
83
+ }
84
+ };
85
+ },
86
+ addCommands() {
87
+ return {
88
+ transferBlock: ({ payload, pos, menu, x = 0, y = 0 }) => ({ editor, dispatch }) => {
89
+ if (!dispatch) return true;
90
+ dropBlock(envOf(editor), ctx.documentId ?? null, defaultId, this.storage.pending, {
91
+ payload,
92
+ pos: Math.min(Math.max(pos, 0), editor.state.doc.content.size),
93
+ menu,
94
+ x,
95
+ y
96
+ });
97
+ return true;
98
+ },
99
+ cancelTransfer: () => () => {
100
+ this.storage.pending.set(null);
101
+ return true;
102
+ }
103
+ };
104
+ },
105
+ addProseMirrorPlugins() {
106
+ const editor = this.editor;
107
+ return [new Plugin({
108
+ key: blockDropTargetKey,
109
+ props: {
110
+ handleDOMEvents: { dragover: (view, event) => {
111
+ if (view.dragging || !view.editable || !event.dataTransfer?.types.includes("application/x-tip-block")) return false;
112
+ event.preventDefault();
113
+ event.dataTransfer.dropEffect = "copy";
114
+ return false;
115
+ } },
116
+ handleDrop: (view, event) => {
117
+ if (view.dragging || !view.editable || !event.dataTransfer) return false;
118
+ const payload = readBlockTransfer(event.dataTransfer);
119
+ if (!payload) return false;
120
+ event.preventDefault();
121
+ const env = envOf(editor);
122
+ const slice = sliceOf(editor, payload);
123
+ if (!slice) {
124
+ env.notify({
125
+ kind: "warning",
126
+ title: env.t("transfer.refused")
127
+ });
128
+ return true;
129
+ }
130
+ const at = view.posAtCoords({
131
+ left: event.clientX,
132
+ top: event.clientY
133
+ })?.pos ?? view.state.doc.content.size;
134
+ const pos = dropPoint(view.state.doc, at, slice) ?? view.state.doc.content.size;
135
+ dropBlock(env, ctx.documentId ?? null, defaultId, this.storage.pending, {
136
+ payload,
137
+ pos,
138
+ menu: event.shiftKey,
139
+ x: event.clientX,
140
+ y: event.clientY
141
+ });
142
+ return true;
143
+ }
144
+ }
145
+ })];
146
+ }
147
+ });
148
+ }
149
+ /**
150
+ * Block transfer between editor surfaces and document trees (the framework-free part of `transferFeature`): a block
151
+ * dragged out of another surface lands as a copy with fresh ids and a `meta.derivation` pointing at its source, or,
152
+ * with Shift held at the drop, as the result of a transform picked from a menu (the copy, and the AI transforms a host or `composeEditor` adds).
153
+ * Insert guards apply; the commands `transferBlock` and `cancelTransfer` serve the document tree's drops.
154
+ */
155
+ function transferFeatureCore(ui, options = {}) {
156
+ const transforms = options.transforms ?? DEFAULT_TRANSFORMS;
157
+ const defaultId = options.defaultTransform ?? "copy";
158
+ return {
159
+ id: "transfer",
160
+ dimension: "interaction",
161
+ requires: ["composites"],
162
+ extensions: (ctx) => [blockDropTarget(ctx, transforms, defaultId)],
163
+ overlays: [ui.menu]
164
+ };
165
+ }
166
+ //#endregion
167
+ export { isSelfDrop, transferFeatureCore };
168
+
169
+ //# sourceMappingURL=feature.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"feature.js","names":[],"sources":["../../../src/features/transfer/feature.ts"],"sourcesContent":["import { type AnyExtension, type Editor, Extension } from '@tiptap/core'\nimport { Fragment, type Node as PMNode, Slice } from '@tiptap/pm/model'\nimport { Plugin, PluginKey } from '@tiptap/pm/state'\nimport { dropPoint } from '@tiptap/pm/transform'\nimport { BLOCK_MIME, type BlockTransfer, readBlockTransfer } from '../../core'\nimport type { EditorFeature, FeatureContext } from '../../core/feature'\nimport { findBlockById } from '../../core/schema'\nimport { createStore, type Store } from '../../core/store'\nimport { availableTransforms, type BlockTransform, DEFAULT_TRANSFORMS, runTransform, type TransferEnv } from './transforms'\n\n/** One drop of a block: the dragged block, where it lands (document position), whether the transform menu opens first and where it opens (viewport pixels). */\nexport interface TransferDrop {\n payload: BlockTransfer\n pos: number\n /** `true`: the menu opens at (`x`, `y`) and the user picks the transform; `false`: the default transform runs. */\n menu: boolean\n x: number\n y: number\n}\n\n/** A drop waiting for the user to pick a transform from the menu (`TransferDrop` with `menu` on). */\nexport type PendingDrop = TransferDrop\n\nexport interface BlockDropTargetStorage {\n /** The drop the transform menu is open for; `null` while no menu is open. */\n pending: Store<PendingDrop | null>\n /** The transforms the menu offers for `drop` (those whose `available` says yes). */\n available: (drop: PendingDrop) => BlockTransform[]\n /** Closes the menu and runs the transform `id` for `drop` (a refused insert shows its notice). */\n run: (id: string, drop: PendingDrop) => Promise<void>\n}\n\ndeclare module '@tiptap/core' {\n interface Storage {\n /** Absent in an editor without the transfer feature. */\n blockDropTarget?: BlockDropTargetStorage\n }\n interface Commands<ReturnType> {\n blockTransfer: {\n /**\n * Puts the block of `payload` into the document at `pos` (a position where a block may be inserted): with `menu`\n * the transform menu opens at (`x`, `y`) and the transform the user picks runs, else the default transform runs.\n * Refuses a drop of a block onto its own position in the same document (notice). Used by the document tree's drop executor.\n */\n transferBlock: (options: { payload: BlockTransfer, pos: number, menu: boolean, x?: number, y?: number }) => ReturnType\n /** Closes the transform menu without inserting anything. */\n cancelTransfer: () => ReturnType\n }\n }\n}\n\n/**\n * Whether dropping `payload` at `pos` of `doc` lands inside the very block it was dragged from: the payload names a\n * block of this document (same `documentId`, a block with that id exists) and `pos` is strictly inside it.\n */\nexport function isSelfDrop(doc: PMNode, documentId: string | null | undefined, payload: BlockTransfer, pos: number): boolean {\n if (!payload.blockId || (payload.documentId ?? null) !== (documentId ?? null)) return false\n const found = findBlockById(doc, payload.blockId)\n return !!found && pos > found.pos && pos < found.pos + found.node.nodeSize\n}\n\n/**\n * The shared tail of a drop (DOM drop and `transferBlock`): refuses a self-drop, else opens the menu (`menu`) or runs\n * the default transform.\n */\nfunction dropBlock(env: TransferEnv, documentId: string | null, defaultId: string, pending: Store<PendingDrop | null>, drop: TransferDrop): void {\n const { payload, pos } = drop\n pending.set(null)\n if (isSelfDrop(env.editor.state.doc, documentId, payload, pos)) {\n env.notify({ kind: 'warning', title: env.t('transfer.selfDrop') })\n return\n }\n if (drop.menu) pending.set(drop)\n // The transform dispatches its own transaction, which must not collide with the one a tiptap command still holds (the command's transaction is dispatched after it returns).\n else queueMicrotask(() => { void runTransform(env, defaultId, payload, pos) })\n}\n\nconst blockDropTargetKey = new PluginKey('blockDropTarget')\n\n/**\n * The slice dropping `payload` would insert, for `dropPoint`; `null` when this schema cannot hold the block. It is closed\n * (`openStart` and `openEnd` 0): an open slice would let `dropPoint` return a position inside a paragraph, where the\n * Baustein cannot be inserted.\n */\nfunction sliceOf(editor: Editor, payload: BlockTransfer): Slice | null {\n try {\n return new Slice(Fragment.from(editor.schema.nodeFromJSON(payload.json)), 0, 0)\n }\n catch {\n return null\n }\n}\n\n/**\n * Takes blocks dragged out of another editor surface or document tree (`BLOCK_MIME`): a plain drop runs the default\n * transform, Shift opens the transform menu at the drop point. A drag that started in this editor stays ProseMirror's\n * native move. Also the commands `transferBlock` and `cancelTransfer`.\n */\nfunction blockDropTarget(ctx: FeatureContext, transforms: readonly BlockTransform[], defaultId: string): AnyExtension {\n const envOf = (editor: Editor): TransferEnv => ({ editor, transforms, ai: ctx.backend.ai, app: ctx.app, notify: ctx.notify, t: ctx.t })\n // The storage is built before the editor exists (`addStorage` has no `this.editor`); `onBeforeCreate` hands it over.\n let created: Editor | undefined\n const editorOf = (): Editor => {\n if (!created) throw new Error('blockDropTarget: the editor is not created yet')\n return created\n }\n return Extension.create<unknown, BlockDropTargetStorage>({\n name: 'blockDropTarget',\n onBeforeCreate() {\n created = this.editor\n },\n addStorage() {\n const pending = createStore<PendingDrop | null>(null)\n return {\n pending,\n available: ({ payload, pos }) => availableTransforms(envOf(editorOf()), payload, pos),\n run: async (id, { payload, pos }) => {\n pending.set(null)\n await runTransform(envOf(editorOf()), id, payload, pos)\n },\n }\n },\n addCommands() {\n return {\n transferBlock: ({ payload, pos, menu, x = 0, y = 0 }) => ({ editor, dispatch }) => {\n if (!dispatch) return true\n dropBlock(envOf(editor), ctx.documentId ?? null, defaultId, this.storage.pending, { payload, pos: Math.min(Math.max(pos, 0), editor.state.doc.content.size), menu, x, y })\n return true\n },\n cancelTransfer: () => () => {\n this.storage.pending.set(null)\n return true\n },\n }\n },\n addProseMirrorPlugins() {\n const editor = this.editor\n return [new Plugin({\n key: blockDropTargetKey,\n props: {\n handleDOMEvents: {\n dragover: (view, event) => {\n if (view.dragging || !view.editable || !event.dataTransfer?.types.includes(BLOCK_MIME)) return false\n event.preventDefault()\n event.dataTransfer.dropEffect = 'copy'\n return false\n },\n },\n handleDrop: (view, event) => {\n if (view.dragging || !view.editable || !event.dataTransfer) return false\n const payload = readBlockTransfer(event.dataTransfer)\n if (!payload) return false\n event.preventDefault()\n const env = envOf(editor)\n const slice = sliceOf(editor, payload)\n if (!slice) {\n env.notify({ kind: 'warning', title: env.t('transfer.refused') })\n return true\n }\n const at = view.posAtCoords({ left: event.clientX, top: event.clientY })?.pos ?? view.state.doc.content.size\n const pos = dropPoint(view.state.doc, at, slice) ?? view.state.doc.content.size\n dropBlock(env, ctx.documentId ?? null, defaultId, this.storage.pending, { payload, pos, menu: event.shiftKey, x: event.clientX, y: event.clientY })\n return true\n },\n },\n })]\n },\n })\n}\n\n/** Options of `transferFeature`. */\nexport interface TransferFeatureOptions {\n /** The transforms the menu offers and a drop can run; default `[copyTransform]` (`composeEditor` adds the AI transforms of `@ecsplico/editor/integrations/composite-ai` when `ai` is on). A host list replaces the default (add built-ins explicitly). */\n transforms?: readonly BlockTransform[]\n /** Id of the transform a plain drop (no Shift) runs; default `copy`. */\n defaultTransform?: string\n}\n\n/** What a framework binding supplies to `transferFeatureCore`. */\nexport interface TransferUi<C> {\n /** The transform menu (receives `{ editor }`), mounted as an overlay. */\n menu: C\n}\n\n/**\n * Block transfer between editor surfaces and document trees (the framework-free part of `transferFeature`): a block\n * dragged out of another surface lands as a copy with fresh ids and a `meta.derivation` pointing at its source, or,\n * with Shift held at the drop, as the result of a transform picked from a menu (the copy, and the AI transforms a host or `composeEditor` adds).\n * Insert guards apply; the commands `transferBlock` and `cancelTransfer` serve the document tree's drops.\n */\nexport function transferFeatureCore<C>(ui: TransferUi<C>, options: TransferFeatureOptions = {}): EditorFeature<C> {\n const transforms = options.transforms ?? DEFAULT_TRANSFORMS\n const defaultId = options.defaultTransform ?? 'copy'\n return {\n id: 'transfer',\n dimension: 'interaction',\n requires: ['composites'],\n extensions: ctx => [blockDropTarget(ctx, transforms, defaultId)],\n overlays: [ui.menu],\n }\n}\n"],"mappings":"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"}
@@ -0,0 +1,3 @@
1
+ import { BlockTransform, DEFAULT_TRANSFORMS, TransferEnv, TransformContext, availableTransforms, copyTransform, createsOf, runTransform, transferKindOf, transferSourceHash, transformContextOf, withFreshBlockIds } from "./transforms.js";
2
+ import { BlockDropTargetStorage, PendingDrop, TransferDrop, TransferFeatureOptions, TransferUi, isSelfDrop, transferFeatureCore } from "./feature.js";
3
+ export { type BlockDropTargetStorage, type BlockTransform, DEFAULT_TRANSFORMS, type PendingDrop, type TransferDrop, type TransferEnv, type TransferFeatureOptions, type TransferUi, type TransformContext, availableTransforms, copyTransform, createsOf, isSelfDrop, runTransform, transferFeatureCore, transferKindOf, transferSourceHash, transformContextOf, withFreshBlockIds };
@@ -0,0 +1,3 @@
1
+ import { DEFAULT_TRANSFORMS, availableTransforms, copyTransform, createsOf, runTransform, transferKindOf, transferSourceHash, transformContextOf, withFreshBlockIds } from "./transforms.js";
2
+ import { isSelfDrop, transferFeatureCore } from "./feature.js";
3
+ export { DEFAULT_TRANSFORMS, availableTransforms, copyTransform, createsOf, isSelfDrop, runTransform, transferFeatureCore, transferKindOf, transferSourceHash, transformContextOf, withFreshBlockIds };
@@ -0,0 +1,12 @@
1
+ import { Editor } from "@tiptap/core";
2
+ //#region src/features/transfer/react/TransferMenu.d.ts
3
+ /**
4
+ * The transform menu of a Shift-drop (mounted by the transfer feature): opens at the drop point while a drop waits in
5
+ * `editor.storage.blockDropTarget.pending`, lists the transforms available for it and runs the one picked. Escape or a
6
+ * click elsewhere cancels the drop.
7
+ */
8
+ export declare function TransferMenu({ editor }: {
9
+ editor: Editor;
10
+ }): import("react").JSX.Element | null;
11
+ //#endregion
12
+ //# sourceMappingURL=TransferMenu.d.ts.map
@@ -0,0 +1,71 @@
1
+ import { useEditorI18n } from "../../../react/use-editor-i18n.js";
2
+ import { Icon } from "../../../react/Icon.js";
3
+ import { useStore } from "../../../react/use-store.js";
4
+ import { Button } from "../../../react/ui/button.js";
5
+ import { useEffect, useRef } from "react";
6
+ import { jsx, jsxs } from "react/jsx-runtime";
7
+ //#region src/features/transfer/react/TransferMenu.tsx
8
+ const ITEM_HEIGHT = 32;
9
+ const MENU_WIDTH = 240;
10
+ const EDGE = 8;
11
+ /**
12
+ * The transform menu of a Shift-drop (mounted by the transfer feature): opens at the drop point while a drop waits in
13
+ * `editor.storage.blockDropTarget.pending`, lists the transforms available for it and runs the one picked. Escape or a
14
+ * click elsewhere cancels the drop.
15
+ */
16
+ function TransferMenu({ editor }) {
17
+ const { t } = useEditorI18n();
18
+ const storage = editor.storage.blockDropTarget;
19
+ const pending = useStore(storage.pending);
20
+ const root = useRef(null);
21
+ const open = pending !== null;
22
+ useEffect(() => {
23
+ if (!open) return;
24
+ const cancel = () => editor.commands.cancelTransfer();
25
+ const onKey = (event) => {
26
+ if (event.key !== "Escape") return;
27
+ event.preventDefault();
28
+ cancel();
29
+ };
30
+ const onPointerDown = (event) => {
31
+ if (!root.current?.contains(event.target)) cancel();
32
+ };
33
+ document.addEventListener("keydown", onKey, true);
34
+ document.addEventListener("pointerdown", onPointerDown, true);
35
+ return () => {
36
+ document.removeEventListener("keydown", onKey, true);
37
+ document.removeEventListener("pointerdown", onPointerDown, true);
38
+ };
39
+ }, [open, editor]);
40
+ if (!pending) return null;
41
+ const transforms = storage.available(pending);
42
+ const height = transforms.length * ITEM_HEIGHT + ITEM_HEIGHT + 16;
43
+ const left = Math.max(EDGE, Math.min(pending.x, window.innerWidth - MENU_WIDTH - EDGE));
44
+ const top = Math.max(EDGE, Math.min(pending.y, window.innerHeight - height - EDGE));
45
+ return /* @__PURE__ */ jsxs("div", {
46
+ ref: root,
47
+ className: "fixed z-50 rounded-lg border border-border bg-popover p-1 text-popover-foreground shadow-lg",
48
+ style: {
49
+ left,
50
+ top,
51
+ width: MENU_WIDTH
52
+ },
53
+ role: "menu",
54
+ "aria-label": t("transfer.menu.title"),
55
+ children: [/* @__PURE__ */ jsx("p", {
56
+ className: "px-2 py-1 text-xs text-muted-foreground",
57
+ children: t("transfer.menu.title")
58
+ }), transforms.map((transform) => /* @__PURE__ */ jsxs(Button, {
59
+ variant: "ghost",
60
+ size: "sm",
61
+ className: "w-full justify-start",
62
+ role: "menuitem",
63
+ onClick: () => void storage.run(transform.id, pending),
64
+ children: [/* @__PURE__ */ jsx(Icon, { name: transform.icon }), transform.labelKey ? t(transform.labelKey) : transform.label]
65
+ }, transform.id))]
66
+ });
67
+ }
68
+ //#endregion
69
+ export { TransferMenu };
70
+
71
+ //# sourceMappingURL=TransferMenu.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"TransferMenu.js","names":[],"sources":["../../../../src/features/transfer/react/TransferMenu.tsx"],"sourcesContent":["import type { Editor } from '@tiptap/core'\nimport { useEffect, useRef } from 'react'\nimport { Icon } from '../../../react/Icon'\nimport { Button } from '../../../react/ui/button'\nimport { useStore } from '../../../react/use-store'\nimport { useEditorI18n } from '../../../react/use-editor-i18n'\nimport type { BlockTransform } from '../transforms'\n\nconst ITEM_HEIGHT = 32\nconst MENU_WIDTH = 240\nconst EDGE = 8\n\n/**\n * The transform menu of a Shift-drop (mounted by the transfer feature): opens at the drop point while a drop waits in\n * `editor.storage.blockDropTarget.pending`, lists the transforms available for it and runs the one picked. Escape or a\n * click elsewhere cancels the drop.\n */\nexport function TransferMenu({ editor }: { editor: Editor }) {\n const { t } = useEditorI18n()\n const storage = editor.storage.blockDropTarget!\n const pending = useStore(storage.pending)\n const root = useRef<HTMLDivElement>(null)\n const open = pending !== null\n\n useEffect(() => {\n if (!open) return\n const cancel = () => editor.commands.cancelTransfer()\n const onKey = (event: KeyboardEvent) => {\n if (event.key !== 'Escape') return\n event.preventDefault()\n cancel()\n }\n const onPointerDown = (event: PointerEvent) => {\n if (!root.current?.contains(event.target as Node)) cancel()\n }\n document.addEventListener('keydown', onKey, true)\n document.addEventListener('pointerdown', onPointerDown, true)\n return () => {\n document.removeEventListener('keydown', onKey, true)\n document.removeEventListener('pointerdown', onPointerDown, true)\n }\n }, [open, editor])\n\n if (!pending) return null\n const transforms: BlockTransform[] = storage.available(pending)\n const height = transforms.length * ITEM_HEIGHT + ITEM_HEIGHT + 2 * EDGE\n const left = Math.max(EDGE, Math.min(pending.x, window.innerWidth - MENU_WIDTH - EDGE))\n const top = Math.max(EDGE, Math.min(pending.y, window.innerHeight - height - EDGE))\n return (\n <div\n ref={root}\n className=\"fixed z-50 rounded-lg border border-border bg-popover p-1 text-popover-foreground shadow-lg\"\n style={{ left, top, width: MENU_WIDTH }}\n role=\"menu\"\n aria-label={t('transfer.menu.title')}\n >\n <p className=\"px-2 py-1 text-xs text-muted-foreground\">{t('transfer.menu.title')}</p>\n {transforms.map(transform => (\n <Button key={transform.id} variant=\"ghost\" size=\"sm\" className=\"w-full justify-start\" role=\"menuitem\" onClick={() => void storage.run(transform.id, pending)}>\n <Icon name={transform.icon} />\n {transform.labelKey ? t(transform.labelKey) : transform.label}\n </Button>\n ))}\n </div>\n )\n}\n"],"mappings":";;;;;;;AAQA,MAAM,cAAc;AACpB,MAAM,aAAa;AACnB,MAAM,OAAO;;;;;;AAOb,SAAgB,aAAa,EAAE,UAA8B;CAC3D,MAAM,EAAE,MAAM,cAAc;CAC5B,MAAM,UAAU,OAAO,QAAQ;CAC/B,MAAM,UAAU,SAAS,QAAQ,OAAO;CACxC,MAAM,OAAO,OAAuB,IAAI;CACxC,MAAM,OAAO,YAAY;CAEzB,gBAAgB;EACd,IAAI,CAAC,MAAM;EACX,MAAM,eAAe,OAAO,SAAS,eAAe;EACpD,MAAM,SAAS,UAAyB;GACtC,IAAI,MAAM,QAAQ,UAAU;GAC5B,MAAM,eAAe;GACrB,OAAO;EACT;EACA,MAAM,iBAAiB,UAAwB;GAC7C,IAAI,CAAC,KAAK,SAAS,SAAS,MAAM,MAAc,GAAG,OAAO;EAC5D;EACA,SAAS,iBAAiB,WAAW,OAAO,IAAI;EAChD,SAAS,iBAAiB,eAAe,eAAe,IAAI;EAC5D,aAAa;GACX,SAAS,oBAAoB,WAAW,OAAO,IAAI;GACnD,SAAS,oBAAoB,eAAe,eAAe,IAAI;EACjE;CACF,GAAG,CAAC,MAAM,MAAM,CAAC;CAEjB,IAAI,CAAC,SAAS,OAAO;CACrB,MAAM,aAA+B,QAAQ,UAAU,OAAO;CAC9D,MAAM,SAAS,WAAW,SAAS,cAAc,cAAc;CAC/D,MAAM,OAAO,KAAK,IAAI,MAAM,KAAK,IAAI,QAAQ,GAAG,OAAO,aAAa,aAAa,IAAI,CAAC;CACtF,MAAM,MAAM,KAAK,IAAI,MAAM,KAAK,IAAI,QAAQ,GAAG,OAAO,cAAc,SAAS,IAAI,CAAC;CAClF,OACE,qBAAC,OAAD;EACE,KAAK;EACL,WAAU;EACV,OAAO;GAAE;GAAM;GAAK,OAAO;EAAW;EACtC,MAAK;EACL,cAAY,EAAE,qBAAqB;EALrC,UAAA,CAOE,oBAAC,KAAD;GAAG,WAAU;GAA2C,UAAA,EAAE,qBAAqB;EAAK,CAAA,GACnF,WAAW,KAAI,cACd,qBAAC,QAAD;GAA2B,SAAQ;GAAQ,MAAK;GAAK,WAAU;GAAuB,MAAK;GAAW,eAAe,KAAK,QAAQ,IAAI,UAAU,IAAI,OAAO;GAA3J,UAAA,CACE,oBAAC,MAAD,EAAM,MAAM,UAAU,KAAO,CAAA,GAC5B,UAAU,WAAW,EAAE,UAAU,QAAQ,IAAI,UAAU,KAClD;EAHK,GAAA,UAAU,EAGf,CACT,CACE;;AAET"}
@@ -0,0 +1,10 @@
1
+ import { ReactFeature } from "../../react/EditorSurface.js";
2
+ import "../../react/index.js";
3
+ import { TransferFeatureOptions } from "./feature.js";
4
+ import { TransferMenu } from "./react/TransferMenu.js";
5
+ //#region src/features/transfer/react.d.ts
6
+ /** The React transfer feature (shadcn): see `transferFeatureCore`. */
7
+ export declare function transferFeature(options?: TransferFeatureOptions): ReactFeature;
8
+ //#endregion
9
+ export { TransferMenu };
10
+ //# sourceMappingURL=react.d.ts.map
@@ -0,0 +1,11 @@
1
+ import { transferFeatureCore } from "./feature.js";
2
+ import { TransferMenu } from "./react/TransferMenu.js";
3
+ //#region src/features/transfer/react.ts
4
+ /** The React transfer feature (shadcn): see `transferFeatureCore`. */
5
+ function transferFeature(options = {}) {
6
+ return transferFeatureCore({ menu: TransferMenu }, options);
7
+ }
8
+ //#endregion
9
+ export { TransferMenu, transferFeature };
10
+
11
+ //# sourceMappingURL=react.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"react.js","names":[],"sources":["../../../src/features/transfer/react.ts"],"sourcesContent":["import type { Editor } from '@tiptap/core'\nimport type { ComponentType } from 'react'\nimport type { ReactFeature } from '../../react'\nimport { type TransferFeatureOptions, transferFeatureCore } from './feature'\nimport { TransferMenu } from './react/TransferMenu'\n\nexport { TransferMenu } from './react/TransferMenu'\n\n/** The React transfer feature (shadcn): see `transferFeatureCore`. */\nexport function transferFeature(options: TransferFeatureOptions = {}): ReactFeature {\n return transferFeatureCore<ComponentType<{ editor: Editor }>>({ menu: TransferMenu }, options)\n}\n"],"mappings":";;;;AASA,SAAgB,gBAAgB,UAAkC,CAAC,GAAiB;CAClF,OAAO,oBAAuD,EAAE,MAAM,aAAa,GAAG,OAAO;AAC/F"}
@@ -0,0 +1,83 @@
1
+ import { MessageKey, Translate } from "../../i18n/index.js";
2
+ import { EditorBackend } from "../../core/backend.js";
3
+ import { Notifier } from "../../core/notify.js";
4
+ import { EditorContext } from "../../core/context.js";
5
+ import { Creates } from "../../core/command-types.js";
6
+ import { BlockTransfer } from "../../core/block-transfer.js";
7
+ import "../../core/index.js";
8
+ import { Editor, JSONContent } from "@tiptap/core";
9
+ //#region src/features/transfer/transforms.d.ts
10
+ /** What a transform works with: the target editor, the dragged block, where it lands and the app services. */
11
+ export interface TransformContext {
12
+ editor: Editor;
13
+ payload: BlockTransfer;
14
+ /** Document position the result is inserted at (a valid drop point of `editor.state.doc`). */
15
+ pos: number;
16
+ /** The app's AI backend; absent when the app has none. */
17
+ ai: EditorBackend['ai'] | undefined;
18
+ /** The app context the editor belongs to; transforms that need app services (the AI model profiles) read them from it. */
19
+ app: EditorContext;
20
+ notify: Notifier;
21
+ t: Translate;
22
+ }
23
+ /** One way to put a dragged block into a surface: offered by the transform menu and run by a plain drop (the default transform). */
24
+ export interface BlockTransform {
25
+ id: string;
26
+ /** Menu text; shown as is unless `labelKey` is set. */
27
+ label: string;
28
+ /** Message key of the label: the menu renders it in the editor's language instead of `label`. */
29
+ labelKey?: MessageKey;
30
+ /** Iconify name (`i-lucide-…`). */
31
+ icon: string;
32
+ /** Absent = always available. */
33
+ available?: (ctx: TransformContext) => boolean;
34
+ /**
35
+ * What `run` inserts at `ctx.pos`, so the insert guards and the target's content rules are checked before `run`; a
36
+ * refused insert shows the warning „lässt sich nicht einfügen“ and runs nothing. Absent: the transform `copy` is
37
+ * checked as inserting the dragged block itself, every other transform checks itself.
38
+ */
39
+ creates?: (ctx: TransformContext) => Creates | null;
40
+ run: (ctx: TransformContext) => Promise<void>;
41
+ }
42
+ /** `json` with a fresh block id on every block that carries one (recursively); other nodes and attributes stay. */
43
+ export declare function withFreshBlockIds(editor: Editor, json: JSONContent): JSONContent;
44
+ /** The `Creates` a node of `json` stands for in the insert guards. */
45
+ export declare const createsOf: (json: JSONContent) => Creates;
46
+ /**
47
+ * The hash a derivation of the dragged block records as `inputHash`: the Markdown of a Baustein's body (the same text
48
+ * `derivationState` hashes for a source in the open document), else of the whole block. Without a Markdown serializer the
49
+ * hash of the payload's Markdown.
50
+ */
51
+ export declare function transferSourceHash(editor: Editor, payload: BlockTransfer): string;
52
+ /** The kind of Baustein the AI transforms insert: the setting `blocks.defaultKind` when the editor offers it, else its first kind. */
53
+ export declare function transferKindOf(editor: Editor): string;
54
+ /**
55
+ * „Kopie einfügen“: inserts the dragged block with fresh block ids (the block and every block inside it). A Baustein
56
+ * that has a block id records its source in `meta.derivation` (`from: { block, document }`, method `copy`, the source
57
+ * Markdown as `inputHash`, the hash of the copy's body as `outputHash`, so the badge shows „bearbeitet“ once the copy is edited).
58
+ */
59
+ export declare const copyTransform: BlockTransform;
60
+ /** The transforms `transferFeature` offers unless the host passes its own list: the copy. The AI transforms (`summaryTransform`, `bulletsTransform`) live in `@ecsplico/editor/integrations/composite-ai`; `composeEditor` adds them when `ai` is on. */
61
+ export declare const DEFAULT_TRANSFORMS: readonly BlockTransform[];
62
+ /** What `runTransform` needs: the editor, the transform list and the app services. */
63
+ export interface TransferEnv {
64
+ editor: Editor;
65
+ transforms: readonly BlockTransform[];
66
+ ai: EditorBackend['ai'] | undefined;
67
+ app: EditorContext;
68
+ notify: Notifier;
69
+ t: Translate;
70
+ }
71
+ /** The context a transform of `env` gets for dropping `payload` at `pos` (clamped into the document). */
72
+ export declare function transformContextOf(env: TransferEnv, payload: BlockTransfer, pos: number): TransformContext;
73
+ /** The transforms of `env` available for dropping `payload` at `pos`, in list order. */
74
+ export declare function availableTransforms(env: TransferEnv, payload: BlockTransfer, pos: number): BlockTransform[];
75
+ /**
76
+ * Runs the transform `id` of `env` for dropping `payload` at `pos`. Nothing runs for an unknown or unavailable
77
+ * transform. What the transform inserts (`BlockTransform.creates`) must pass the insert guards below `pos`'s parent and
78
+ * the parent's content rules, else the warning „Hier lässt sich der Baustein nicht einfügen“ is shown and the document stays
79
+ * unchanged. The transform's own failure is its own to report; this never throws for a refusal.
80
+ */
81
+ export declare function runTransform(env: TransferEnv, id: string, payload: BlockTransfer, pos: number): Promise<void>;
82
+ //#endregion
83
+ //# sourceMappingURL=transforms.d.ts.map