@tiptap/extension-drag-handle 2.24.2 → 3.0.0-beta.10

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 (37) hide show
  1. package/LICENSE.md +21 -0
  2. package/dist/index.cjs +463 -457
  3. package/dist/index.cjs.map +1 -1
  4. package/dist/index.d.cts +68 -0
  5. package/dist/index.d.ts +68 -5
  6. package/dist/index.js +441 -450
  7. package/dist/index.js.map +1 -1
  8. package/package.json +20 -18
  9. package/src/drag-handle-plugin.ts +233 -236
  10. package/src/drag-handle.ts +42 -28
  11. package/src/helpers/dragHandler.ts +8 -8
  12. package/src/helpers/findNextElementFromCursor.ts +3 -5
  13. package/src/helpers/getInnerCoords.ts +3 -7
  14. package/src/helpers/getOuterNode.ts +1 -1
  15. package/dist/drag-handle-plugin.d.ts +0 -20
  16. package/dist/drag-handle-plugin.d.ts.map +0 -1
  17. package/dist/drag-handle.d.ts +0 -44
  18. package/dist/drag-handle.d.ts.map +0 -1
  19. package/dist/helpers/cloneElement.d.ts +0 -2
  20. package/dist/helpers/cloneElement.d.ts.map +0 -1
  21. package/dist/helpers/dragHandler.d.ts +0 -3
  22. package/dist/helpers/dragHandler.d.ts.map +0 -1
  23. package/dist/helpers/findNextElementFromCursor.d.ts +0 -14
  24. package/dist/helpers/findNextElementFromCursor.d.ts.map +0 -1
  25. package/dist/helpers/getComputedStyle.d.ts +0 -2
  26. package/dist/helpers/getComputedStyle.d.ts.map +0 -1
  27. package/dist/helpers/getInnerCoords.d.ts +0 -6
  28. package/dist/helpers/getInnerCoords.d.ts.map +0 -1
  29. package/dist/helpers/getOuterNode.d.ts +0 -4
  30. package/dist/helpers/getOuterNode.d.ts.map +0 -1
  31. package/dist/helpers/minMax.d.ts +0 -2
  32. package/dist/helpers/minMax.d.ts.map +0 -1
  33. package/dist/helpers/removeNode.d.ts +0 -2
  34. package/dist/helpers/removeNode.d.ts.map +0 -1
  35. package/dist/index.d.ts.map +0 -1
  36. package/dist/index.umd.js +0 -499
  37. package/dist/index.umd.js.map +0 -1
package/dist/index.cjs CHANGED
@@ -1,504 +1,510 @@
1
- 'use strict';
1
+ "use strict";
2
+ var __defProp = Object.defineProperty;
3
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
+ var __getOwnPropNames = Object.getOwnPropertyNames;
5
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
6
+ var __export = (target, all) => {
7
+ for (var name in all)
8
+ __defProp(target, name, { get: all[name], enumerable: true });
9
+ };
10
+ var __copyProps = (to, from, except, desc) => {
11
+ if (from && typeof from === "object" || typeof from === "function") {
12
+ for (let key of __getOwnPropNames(from))
13
+ if (!__hasOwnProp.call(to, key) && key !== except)
14
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
15
+ }
16
+ return to;
17
+ };
18
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
2
19
 
3
- Object.defineProperty(exports, '__esModule', { value: true });
20
+ // src/index.ts
21
+ var index_exports = {};
22
+ __export(index_exports, {
23
+ DragHandle: () => DragHandle,
24
+ DragHandlePlugin: () => DragHandlePlugin,
25
+ default: () => index_default,
26
+ defaultComputePositionConfig: () => defaultComputePositionConfig,
27
+ dragHandlePluginDefaultKey: () => dragHandlePluginDefaultKey
28
+ });
29
+ module.exports = __toCommonJS(index_exports);
4
30
 
5
- var core = require('@tiptap/core');
6
- var extensionCollaboration = require('@tiptap/extension-collaboration');
7
- var state = require('@tiptap/pm/state');
8
- var tippy = require('tippy.js');
9
- var yProsemirror = require('y-prosemirror');
10
- var extensionNodeRange = require('@tiptap/extension-node-range');
31
+ // src/drag-handle.ts
32
+ var import_core = require("@tiptap/core");
11
33
 
12
- function _interopDefaultCompat (e) { return e && typeof e === 'object' && 'default' in e ? e : { default: e }; }
34
+ // src/drag-handle-plugin.ts
35
+ var import_dom = require("@floating-ui/dom");
36
+ var import_extension_collaboration = require("@tiptap/extension-collaboration");
37
+ var import_state = require("@tiptap/pm/state");
38
+ var import_y_tiptap = require("@tiptap/y-tiptap");
13
39
 
14
- var tippy__default = /*#__PURE__*/_interopDefaultCompat(tippy);
40
+ // src/helpers/dragHandler.ts
41
+ var import_extension_node_range = require("@tiptap/extension-node-range");
15
42
 
43
+ // src/helpers/cloneElement.ts
16
44
  function getCSSText(element) {
17
- let value = '';
18
- const style = getComputedStyle(element);
19
- for (let i = 0; i < style.length; i += 1) {
20
- value += `${style[i]}:${style.getPropertyValue(style[i])};`;
21
- }
22
- return value;
45
+ let value = "";
46
+ const style = getComputedStyle(element);
47
+ for (let i = 0; i < style.length; i += 1) {
48
+ value += `${style[i]}:${style.getPropertyValue(style[i])};`;
49
+ }
50
+ return value;
23
51
  }
24
52
  function cloneElement(node) {
25
- const clonedNode = node.cloneNode(true);
26
- const sourceElements = [node, ...Array.from(node.getElementsByTagName('*'))];
27
- const targetElements = [clonedNode, ...Array.from(clonedNode.getElementsByTagName('*'))];
28
- sourceElements.forEach((sourceElement, index) => {
29
- targetElements[index].style.cssText = getCSSText(sourceElement);
30
- });
31
- return clonedNode;
53
+ const clonedNode = node.cloneNode(true);
54
+ const sourceElements = [node, ...Array.from(node.getElementsByTagName("*"))];
55
+ const targetElements = [clonedNode, ...Array.from(clonedNode.getElementsByTagName("*"))];
56
+ sourceElements.forEach((sourceElement, index) => {
57
+ targetElements[index].style.cssText = getCSSText(sourceElement);
58
+ });
59
+ return clonedNode;
32
60
  }
33
61
 
34
- const findElementNextToCoords = (options) => {
35
- const { x, y, direction, editor, } = options;
36
- let resultElement = null;
37
- let resultNode = null;
38
- let pos = null;
39
- let currentX = x;
40
- while (resultNode === null && currentX < window.innerWidth && currentX > 0) {
41
- const allElements = document.elementsFromPoint(currentX, y);
42
- const prosemirrorIndex = allElements.findIndex(element => element.classList.contains('ProseMirror'));
43
- const filteredElements = allElements.slice(0, prosemirrorIndex);
44
- if (filteredElements.length > 0) {
45
- const target = filteredElements[0];
46
- resultElement = target;
47
- pos = editor.view.posAtDOM(target, 0);
48
- if (pos >= 0) {
49
- resultNode = editor.state.doc.nodeAt(Math.max(pos - 1, 0));
50
- if (resultNode === null || resultNode === void 0 ? void 0 : resultNode.isText) {
51
- resultNode = editor.state.doc.nodeAt(Math.max(pos - 1, 0));
52
- }
53
- if (!resultNode) {
54
- resultNode = editor.state.doc.nodeAt(Math.max(pos, 0));
55
- }
56
- break;
57
- }
58
- }
59
- if (direction === 'left') {
60
- currentX -= 1;
62
+ // src/helpers/findNextElementFromCursor.ts
63
+ var findElementNextToCoords = (options) => {
64
+ const { x, y, direction, editor } = options;
65
+ let resultElement = null;
66
+ let resultNode = null;
67
+ let pos = null;
68
+ let currentX = x;
69
+ while (resultNode === null && currentX < window.innerWidth && currentX > 0) {
70
+ const allElements = document.elementsFromPoint(currentX, y);
71
+ const prosemirrorIndex = allElements.findIndex((element) => element.classList.contains("ProseMirror"));
72
+ const filteredElements = allElements.slice(0, prosemirrorIndex);
73
+ if (filteredElements.length > 0) {
74
+ const target = filteredElements[0];
75
+ resultElement = target;
76
+ pos = editor.view.posAtDOM(target, 0);
77
+ if (pos >= 0) {
78
+ resultNode = editor.state.doc.nodeAt(Math.max(pos - 1, 0));
79
+ if (resultNode == null ? void 0 : resultNode.isText) {
80
+ resultNode = editor.state.doc.nodeAt(Math.max(pos - 1, 0));
61
81
  }
62
- else {
63
- currentX += 1;
82
+ if (!resultNode) {
83
+ resultNode = editor.state.doc.nodeAt(Math.max(pos, 0));
64
84
  }
85
+ break;
86
+ }
65
87
  }
66
- return { resultElement, resultNode, pos: pos !== null && pos !== void 0 ? pos : null };
88
+ if (direction === "left") {
89
+ currentX -= 1;
90
+ } else {
91
+ currentX += 1;
92
+ }
93
+ }
94
+ return { resultElement, resultNode, pos: pos != null ? pos : null };
67
95
  };
68
96
 
69
- function getComputedStyle$1(node, property) {
70
- const style = window.getComputedStyle(node);
71
- return style[property];
97
+ // src/helpers/getComputedStyle.ts
98
+ function getComputedStyle2(node, property) {
99
+ const style = window.getComputedStyle(node);
100
+ return style[property];
72
101
  }
73
102
 
103
+ // src/helpers/minMax.ts
74
104
  function minMax(value = 0, min = 0, max = 0) {
75
- return Math.min(Math.max(value, min), max);
105
+ return Math.min(Math.max(value, min), max);
76
106
  }
77
107
 
108
+ // src/helpers/getInnerCoords.ts
78
109
  function getInnerCoords(view, x, y) {
79
- const paddingLeft = parseInt(getComputedStyle$1(view.dom, 'paddingLeft'), 10);
80
- const paddingRight = parseInt(getComputedStyle$1(view.dom, 'paddingRight'), 10);
81
- const borderLeft = parseInt(getComputedStyle$1(view.dom, 'borderLeftWidth'), 10);
82
- const borderRight = parseInt(getComputedStyle$1(view.dom, 'borderLeftWidth'), 10);
83
- const bounds = view.dom.getBoundingClientRect();
84
- const coords = {
85
- left: minMax(x, bounds.left + paddingLeft + borderLeft, bounds.right - paddingRight - borderRight),
86
- top: y,
87
- };
88
- return coords;
110
+ const paddingLeft = parseInt(getComputedStyle2(view.dom, "paddingLeft"), 10);
111
+ const paddingRight = parseInt(getComputedStyle2(view.dom, "paddingRight"), 10);
112
+ const borderLeft = parseInt(getComputedStyle2(view.dom, "borderLeftWidth"), 10);
113
+ const borderRight = parseInt(getComputedStyle2(view.dom, "borderLeftWidth"), 10);
114
+ const bounds = view.dom.getBoundingClientRect();
115
+ const coords = {
116
+ left: minMax(x, bounds.left + paddingLeft + borderLeft, bounds.right - paddingRight - borderRight),
117
+ top: y
118
+ };
119
+ return coords;
89
120
  }
90
121
 
122
+ // src/helpers/removeNode.ts
91
123
  function removeNode(node) {
92
- var _a;
93
- (_a = node.parentNode) === null || _a === void 0 ? void 0 : _a.removeChild(node);
124
+ var _a;
125
+ (_a = node.parentNode) == null ? void 0 : _a.removeChild(node);
94
126
  }
95
127
 
128
+ // src/helpers/dragHandler.ts
96
129
  function getDragHandleRanges(event, editor) {
97
- const { doc } = editor.view.state;
98
- const result = findElementNextToCoords({
99
- editor, x: event.clientX, y: event.clientY, direction: 'right',
100
- });
101
- if (!result.resultNode || result.pos === null) {
102
- return [];
103
- }
104
- const x = event.clientX;
105
- // @ts-ignore
106
- const coords = getInnerCoords(editor.view, x, event.clientY);
107
- const posAtCoords = editor.view.posAtCoords(coords);
108
- if (!posAtCoords) {
109
- return [];
110
- }
111
- const { pos } = posAtCoords;
112
- const nodeAt = doc.resolve(pos).parent;
113
- if (!nodeAt) {
114
- return [];
115
- }
116
- const $from = doc.resolve(result.pos);
117
- const $to = doc.resolve(result.pos + 1);
118
- return extensionNodeRange.getSelectionRanges($from, $to, 0);
130
+ const { doc } = editor.view.state;
131
+ const result = findElementNextToCoords({
132
+ editor,
133
+ x: event.clientX,
134
+ y: event.clientY,
135
+ direction: "right"
136
+ });
137
+ if (!result.resultNode || result.pos === null) {
138
+ return [];
139
+ }
140
+ const x = event.clientX;
141
+ const coords = getInnerCoords(editor.view, x, event.clientY);
142
+ const posAtCoords = editor.view.posAtCoords(coords);
143
+ if (!posAtCoords) {
144
+ return [];
145
+ }
146
+ const { pos } = posAtCoords;
147
+ const nodeAt = doc.resolve(pos).parent;
148
+ if (!nodeAt) {
149
+ return [];
150
+ }
151
+ const $from = doc.resolve(result.pos);
152
+ const $to = doc.resolve(result.pos + 1);
153
+ return (0, import_extension_node_range.getSelectionRanges)($from, $to, 0);
119
154
  }
120
155
  function dragHandler(event, editor) {
121
- const { view } = editor;
122
- if (!event.dataTransfer) {
123
- return;
124
- }
125
- const { empty, $from, $to } = view.state.selection;
126
- const dragHandleRanges = getDragHandleRanges(event, editor);
127
- const selectionRanges = extensionNodeRange.getSelectionRanges($from, $to, 0);
128
- const isDragHandleWithinSelection = selectionRanges.some(range => {
129
- return dragHandleRanges.find(dragHandleRange => {
130
- return dragHandleRange.$from === range.$from
131
- && dragHandleRange.$to === range.$to;
132
- });
133
- });
134
- const ranges = empty || !isDragHandleWithinSelection
135
- ? dragHandleRanges
136
- : selectionRanges;
137
- if (!ranges.length) {
138
- return;
139
- }
140
- const { tr } = view.state;
141
- const wrapper = document.createElement('div');
142
- const from = ranges[0].$from.pos;
143
- const to = ranges[ranges.length - 1].$to.pos;
144
- const selection = extensionNodeRange.NodeRangeSelection.create(view.state.doc, from, to);
145
- const slice = selection.content();
146
- ranges.forEach(range => {
147
- const element = view.nodeDOM(range.$from.pos);
148
- const clonedElement = cloneElement(element);
149
- wrapper.append(clonedElement);
156
+ const { view } = editor;
157
+ if (!event.dataTransfer) {
158
+ return;
159
+ }
160
+ const { empty, $from, $to } = view.state.selection;
161
+ const dragHandleRanges = getDragHandleRanges(event, editor);
162
+ const selectionRanges = (0, import_extension_node_range.getSelectionRanges)($from, $to, 0);
163
+ const isDragHandleWithinSelection = selectionRanges.some((range) => {
164
+ return dragHandleRanges.find((dragHandleRange) => {
165
+ return dragHandleRange.$from === range.$from && dragHandleRange.$to === range.$to;
150
166
  });
151
- wrapper.style.position = 'absolute';
152
- wrapper.style.top = '-10000px';
153
- document.body.append(wrapper);
154
- event.dataTransfer.clearData();
155
- event.dataTransfer.setDragImage(wrapper, 0, 0);
156
- // tell ProseMirror the dragged content
157
- view.dragging = { slice, move: true };
158
- tr.setSelection(selection);
159
- view.dispatch(tr);
160
- // clean up
161
- document.addEventListener('drop', () => removeNode(wrapper), { once: true });
167
+ });
168
+ const ranges = empty || !isDragHandleWithinSelection ? dragHandleRanges : selectionRanges;
169
+ if (!ranges.length) {
170
+ return;
171
+ }
172
+ const { tr } = view.state;
173
+ const wrapper = document.createElement("div");
174
+ const from = ranges[0].$from.pos;
175
+ const to = ranges[ranges.length - 1].$to.pos;
176
+ const selection = import_extension_node_range.NodeRangeSelection.create(view.state.doc, from, to);
177
+ const slice = selection.content();
178
+ ranges.forEach((range) => {
179
+ const element = view.nodeDOM(range.$from.pos);
180
+ const clonedElement = cloneElement(element);
181
+ wrapper.append(clonedElement);
182
+ });
183
+ wrapper.style.position = "absolute";
184
+ wrapper.style.top = "-10000px";
185
+ document.body.append(wrapper);
186
+ event.dataTransfer.clearData();
187
+ event.dataTransfer.setDragImage(wrapper, 0, 0);
188
+ view.dragging = { slice, move: true };
189
+ tr.setSelection(selection);
190
+ view.dispatch(tr);
191
+ document.addEventListener("drop", () => removeNode(wrapper), { once: true });
162
192
  }
163
193
 
164
- const getOuterNodePos = (doc, pos) => {
165
- const resolvedPos = doc.resolve(pos);
166
- const { depth } = resolvedPos;
167
- if (depth === 0) {
168
- return pos;
169
- }
170
- const a = resolvedPos.pos - resolvedPos.parentOffset;
171
- return a - 1;
194
+ // src/helpers/getOuterNode.ts
195
+ var getOuterNodePos = (doc, pos) => {
196
+ const resolvedPos = doc.resolve(pos);
197
+ const { depth } = resolvedPos;
198
+ if (depth === 0) {
199
+ return pos;
200
+ }
201
+ const a = resolvedPos.pos - resolvedPos.parentOffset;
202
+ return a - 1;
172
203
  };
173
- const getOuterNode = (doc, pos) => {
174
- const node = doc.nodeAt(pos);
175
- const resolvedPos = doc.resolve(pos);
176
- let { depth } = resolvedPos;
177
- let parent = node;
178
- while (depth > 0) {
179
- const currentNode = resolvedPos.node(depth);
180
- depth -= 1;
181
- if (depth === 0) {
182
- parent = currentNode;
183
- }
204
+ var getOuterNode = (doc, pos) => {
205
+ const node = doc.nodeAt(pos);
206
+ const resolvedPos = doc.resolve(pos);
207
+ let { depth } = resolvedPos;
208
+ let parent = node;
209
+ while (depth > 0) {
210
+ const currentNode = resolvedPos.node(depth);
211
+ depth -= 1;
212
+ if (depth === 0) {
213
+ parent = currentNode;
184
214
  }
185
- return parent;
215
+ }
216
+ return parent;
186
217
  };
187
218
 
188
- const getRelativePos = (state, absolutePos) => {
189
- const ystate = yProsemirror.ySyncPluginKey.getState(state);
190
- if (!ystate) {
191
- return null;
192
- }
193
- return yProsemirror.absolutePositionToRelativePosition(absolutePos, ystate.type, ystate.binding.mapping);
219
+ // src/drag-handle-plugin.ts
220
+ var getRelativePos = (state, absolutePos) => {
221
+ const ystate = import_y_tiptap.ySyncPluginKey.getState(state);
222
+ if (!ystate) {
223
+ return null;
224
+ }
225
+ return (0, import_y_tiptap.absolutePositionToRelativePosition)(absolutePos, ystate.type, ystate.binding.mapping);
194
226
  };
195
- const getAbsolutePos = (state, relativePos) => {
196
- const ystate = yProsemirror.ySyncPluginKey.getState(state);
197
- if (!ystate) {
198
- return -1;
199
- }
200
- return yProsemirror.relativePositionToAbsolutePosition(ystate.doc, ystate.type, relativePos, ystate.binding.mapping) || 0;
227
+ var getAbsolutePos = (state, relativePos) => {
228
+ const ystate = import_y_tiptap.ySyncPluginKey.getState(state);
229
+ if (!ystate) {
230
+ return -1;
231
+ }
232
+ return (0, import_y_tiptap.relativePositionToAbsolutePosition)(ystate.doc, ystate.type, relativePos, ystate.binding.mapping) || 0;
201
233
  };
202
- const getOuterDomNode = (view, domNode) => {
203
- let tmpDomNode = domNode;
204
- // Traverse to top level node.
205
- while (tmpDomNode && tmpDomNode.parentNode) {
206
- if (tmpDomNode.parentNode === view.dom) {
207
- break;
208
- }
209
- tmpDomNode = tmpDomNode.parentNode;
234
+ var getOuterDomNode = (view, domNode) => {
235
+ let tmpDomNode = domNode;
236
+ while (tmpDomNode == null ? void 0 : tmpDomNode.parentNode) {
237
+ if (tmpDomNode.parentNode === view.dom) {
238
+ break;
210
239
  }
211
- return tmpDomNode;
240
+ tmpDomNode = tmpDomNode.parentNode;
241
+ }
242
+ return tmpDomNode;
212
243
  };
213
- const dragHandlePluginDefaultKey = new state.PluginKey('dragHandle');
214
- const DragHandlePlugin = ({ pluginKey = dragHandlePluginDefaultKey, element, editor, tippyOptions, onNodeChange, }) => {
215
- const wrapper = document.createElement('div');
216
- let popup = null;
217
- let locked = false;
218
- let currentNode = null;
219
- let currentNodePos = -1;
220
- let currentNodeRelPos;
221
- element.addEventListener('dragstart', e => {
222
- // Push this to the end of the event cue
223
- // Fixes bug where incorrect drag pos is returned if drag handle has position: absolute
224
- // @ts-ignore
225
- dragHandler(e, editor);
226
- setTimeout(() => {
244
+ var dragHandlePluginDefaultKey = new import_state.PluginKey("dragHandle");
245
+ var DragHandlePlugin = ({
246
+ pluginKey = dragHandlePluginDefaultKey,
247
+ element,
248
+ editor,
249
+ computePositionConfig,
250
+ onNodeChange
251
+ }) => {
252
+ const wrapper = document.createElement("div");
253
+ let locked = false;
254
+ let currentNode = null;
255
+ let currentNodePos = -1;
256
+ let currentNodeRelPos;
257
+ function hideHandle() {
258
+ if (!element) {
259
+ return;
260
+ }
261
+ element.style.visibility = "hidden";
262
+ element.style.pointerEvents = "none";
263
+ }
264
+ function showHandle() {
265
+ if (!element) {
266
+ return;
267
+ }
268
+ if (!editor.isEditable) {
269
+ hideHandle();
270
+ return;
271
+ }
272
+ element.style.visibility = "";
273
+ element.style.pointerEvents = "auto";
274
+ }
275
+ function repositionDragHandle(dom) {
276
+ const virtualElement = {
277
+ getBoundingClientRect: () => dom.getBoundingClientRect()
278
+ };
279
+ (0, import_dom.computePosition)(virtualElement, element, computePositionConfig).then((val) => {
280
+ Object.assign(element.style, {
281
+ position: val.strategy,
282
+ left: `${val.x}px`,
283
+ top: `${val.y}px`
284
+ });
285
+ });
286
+ }
287
+ function onDragStart(e) {
288
+ dragHandler(e, editor);
289
+ setTimeout(() => {
290
+ if (element) {
291
+ element.style.pointerEvents = "none";
292
+ }
293
+ }, 0);
294
+ }
295
+ function onDragEnd() {
296
+ hideHandle();
297
+ if (element) {
298
+ element.style.pointerEvents = "auto";
299
+ }
300
+ }
301
+ element.addEventListener("dragstart", onDragStart);
302
+ element.addEventListener("dragend", onDragEnd);
303
+ wrapper.appendChild(element);
304
+ return {
305
+ unbind() {
306
+ element.removeEventListener("dragstart", onDragStart);
307
+ element.removeEventListener("dragend", onDragEnd);
308
+ },
309
+ plugin: new import_state.Plugin({
310
+ key: typeof pluginKey === "string" ? new import_state.PluginKey(pluginKey) : pluginKey,
311
+ state: {
312
+ init() {
313
+ return { locked: false };
314
+ },
315
+ apply(tr, value, _oldState, state) {
316
+ const isLocked = tr.getMeta("lockDragHandle");
317
+ const hideDragHandle = tr.getMeta("hideDragHandle");
318
+ if (isLocked !== void 0) {
319
+ locked = isLocked;
320
+ }
321
+ if (hideDragHandle) {
322
+ hideHandle();
323
+ locked = false;
324
+ currentNode = null;
325
+ currentNodePos = -1;
326
+ onNodeChange == null ? void 0 : onNodeChange({ editor, node: null, pos: -1 });
327
+ return value;
328
+ }
329
+ if (tr.docChanged && currentNodePos !== -1 && element) {
330
+ if ((0, import_extension_collaboration.isChangeOrigin)(tr)) {
331
+ const newPos = getAbsolutePos(state, currentNodeRelPos);
332
+ if (newPos !== currentNodePos) {
333
+ currentNodePos = newPos;
334
+ }
335
+ } else {
336
+ const newPos = tr.mapping.map(currentNodePos);
337
+ if (newPos !== currentNodePos) {
338
+ currentNodePos = newPos;
339
+ currentNodeRelPos = getRelativePos(state, currentNodePos);
340
+ }
341
+ }
342
+ }
343
+ return value;
344
+ }
345
+ },
346
+ view: (view) => {
347
+ var _a;
348
+ element.draggable = true;
349
+ element.style.pointerEvents = "auto";
350
+ (_a = editor.view.dom.parentElement) == null ? void 0 : _a.appendChild(wrapper);
351
+ wrapper.style.pointerEvents = "none";
352
+ wrapper.style.position = "absolute";
353
+ wrapper.style.top = "0";
354
+ wrapper.style.left = "0";
355
+ return {
356
+ update(_, oldState) {
357
+ if (!element) {
358
+ return;
359
+ }
360
+ if (!editor.isEditable) {
361
+ hideHandle();
362
+ return;
363
+ }
364
+ if (locked) {
365
+ element.draggable = false;
366
+ } else {
367
+ element.draggable = true;
368
+ }
369
+ if (view.state.doc.eq(oldState.doc) || currentNodePos === -1) {
370
+ return;
371
+ }
372
+ let domNode = view.nodeDOM(currentNodePos);
373
+ domNode = getOuterDomNode(view, domNode);
374
+ if (domNode === view.dom) {
375
+ return;
376
+ }
377
+ if ((domNode == null ? void 0 : domNode.nodeType) !== 1) {
378
+ return;
379
+ }
380
+ const domNodePos = view.posAtDOM(domNode, 0);
381
+ const outerNode = getOuterNode(editor.state.doc, domNodePos);
382
+ const outerNodePos = getOuterNodePos(editor.state.doc, domNodePos);
383
+ currentNode = outerNode;
384
+ currentNodePos = outerNodePos;
385
+ currentNodeRelPos = getRelativePos(view.state, currentNodePos);
386
+ onNodeChange == null ? void 0 : onNodeChange({ editor, node: currentNode, pos: currentNodePos });
387
+ repositionDragHandle(domNode);
388
+ },
389
+ // TODO: Kills even on hot reload
390
+ destroy() {
227
391
  if (element) {
228
- element.style.pointerEvents = 'none';
392
+ removeNode(wrapper);
229
393
  }
230
- }, 0);
231
- });
232
- element.addEventListener('dragend', () => {
233
- if (element) {
234
- element.style.pointerEvents = 'auto';
394
+ }
395
+ };
396
+ },
397
+ props: {
398
+ handleDOMEvents: {
399
+ mouseleave(_view, e) {
400
+ if (locked) {
401
+ return false;
402
+ }
403
+ if (e.target && !wrapper.contains(e.relatedTarget)) {
404
+ hideHandle();
405
+ currentNode = null;
406
+ currentNodePos = -1;
407
+ onNodeChange == null ? void 0 : onNodeChange({ editor, node: null, pos: -1 });
408
+ }
409
+ return false;
410
+ },
411
+ mousemove(view, e) {
412
+ if (!element || locked) {
413
+ return false;
414
+ }
415
+ const nodeData = findElementNextToCoords({
416
+ x: e.clientX,
417
+ y: e.clientY,
418
+ direction: "right",
419
+ editor
420
+ });
421
+ if (!nodeData.resultElement) {
422
+ return false;
423
+ }
424
+ let domNode = nodeData.resultElement;
425
+ domNode = getOuterDomNode(view, domNode);
426
+ if (domNode === view.dom) {
427
+ return false;
428
+ }
429
+ if ((domNode == null ? void 0 : domNode.nodeType) !== 1) {
430
+ return false;
431
+ }
432
+ const domNodePos = view.posAtDOM(domNode, 0);
433
+ const outerNode = getOuterNode(editor.state.doc, domNodePos);
434
+ if (outerNode !== currentNode) {
435
+ const outerNodePos = getOuterNodePos(editor.state.doc, domNodePos);
436
+ currentNode = outerNode;
437
+ currentNodePos = outerNodePos;
438
+ currentNodeRelPos = getRelativePos(view.state, currentNodePos);
439
+ onNodeChange == null ? void 0 : onNodeChange({ editor, node: currentNode, pos: currentNodePos });
440
+ repositionDragHandle(domNode);
441
+ showHandle();
442
+ }
443
+ return false;
444
+ }
235
445
  }
236
- });
237
- return new state.Plugin({
238
- key: typeof pluginKey === 'string' ? new state.PluginKey(pluginKey) : pluginKey,
239
- state: {
240
- init() {
241
- return { locked: false };
242
- },
243
- apply(tr, value, oldState, state) {
244
- const isLocked = tr.getMeta('lockDragHandle');
245
- const hideDragHandle = tr.getMeta('hideDragHandle');
246
- if (isLocked !== undefined) {
247
- locked = isLocked;
248
- }
249
- if (hideDragHandle && popup) {
250
- popup.hide();
251
- locked = false;
252
- currentNode = null;
253
- currentNodePos = -1;
254
- onNodeChange === null || onNodeChange === void 0 ? void 0 : onNodeChange({ editor, node: null, pos: -1 });
255
- return value;
256
- }
257
- // Something has changed and drag handler is visible…
258
- if (tr.docChanged && currentNodePos !== -1 && element && popup) {
259
- // Yjs replaces the entire document on every incoming change and needs a special handling.
260
- // If change comes from another user …
261
- if (extensionCollaboration.isChangeOrigin(tr)) {
262
- // https://discuss.yjs.dev/t/y-prosemirror-mapping-a-single-relative-position-when-doc-changes/851/3
263
- const newPos = getAbsolutePos(state, currentNodeRelPos);
264
- if (newPos !== currentNodePos) {
265
- // Set the new position for our current node.
266
- currentNodePos = newPos;
267
- // We will get the outer node with data and position in views update method.
268
- }
269
- }
270
- else {
271
- // … otherwise use ProseMirror mapping to update the position.
272
- const newPos = tr.mapping.map(currentNodePos);
273
- if (newPos !== currentNodePos) {
274
- // TODO: Remove
275
- // console.log('Position has changed …', { old: currentNodePos, new: newPos }, tr);
276
- // Set the new position for our current node.
277
- currentNodePos = newPos;
278
- // Memorize relative position to retrieve absolute position in case of collaboration
279
- currentNodeRelPos = getRelativePos(state, currentNodePos);
280
- // We will get the outer node with data and position in views update method.
281
- }
282
- }
283
- }
284
- return value;
285
- },
286
- },
287
- view: view => {
288
- var _a;
289
- element.draggable = true;
290
- element.style.pointerEvents = 'auto';
291
- (_a = editor.view.dom.parentElement) === null || _a === void 0 ? void 0 : _a.appendChild(wrapper);
292
- wrapper.appendChild(element);
293
- wrapper.style.pointerEvents = 'none';
294
- wrapper.style.position = 'absolute';
295
- wrapper.style.top = '0';
296
- wrapper.style.left = '0';
297
- return {
298
- update(_, oldState) {
299
- if (!element) {
300
- return;
301
- }
302
- if (!editor.isEditable) {
303
- popup === null || popup === void 0 ? void 0 : popup.destroy();
304
- popup = null;
305
- return;
306
- }
307
- if (!popup) {
308
- popup = tippy__default.default(view.dom, {
309
- getReferenceClientRect: null,
310
- interactive: true,
311
- trigger: 'manual',
312
- placement: 'left-start',
313
- hideOnClick: false,
314
- duration: 100,
315
- popperOptions: {
316
- modifiers: [
317
- { name: 'flip', enabled: false },
318
- {
319
- name: 'preventOverflow',
320
- options: {
321
- rootBoundary: 'document',
322
- mainAxis: false,
323
- },
324
- },
325
- ],
326
- },
327
- ...tippyOptions,
328
- appendTo: wrapper,
329
- content: element,
330
- });
331
- }
332
- // Prevent element being draggend while being open.
333
- if (locked) {
334
- element.draggable = false;
335
- }
336
- else {
337
- element.draggable = true;
338
- }
339
- // Do not close on updates (e.g. changing padding of a section or collaboration events)
340
- // popup?.hide();
341
- // Recalculate popup position if doc has changend and drag handler is visible.
342
- if (view.state.doc.eq(oldState.doc) || currentNodePos === -1) {
343
- return;
344
- }
345
- // Get domNode from (new) position.
346
- let domNode = view.nodeDOM(currentNodePos);
347
- // Since old element could have been wrapped, we need to find
348
- // the outer node and take its position and node data.
349
- domNode = getOuterDomNode(view, domNode);
350
- // Skip if domNode is editor dom.
351
- if (domNode === view.dom) {
352
- return;
353
- }
354
- // We only want `Element`.
355
- if ((domNode === null || domNode === void 0 ? void 0 : domNode.nodeType) !== 1) {
356
- return;
357
- }
358
- const domNodePos = view.posAtDOM(domNode, 0);
359
- const outerNode = getOuterNode(editor.state.doc, domNodePos);
360
- const outerNodePos = getOuterNodePos(editor.state.doc, domNodePos); // TODO: needed?
361
- currentNode = outerNode;
362
- currentNodePos = outerNodePos;
363
- // Memorize relative position to retrieve absolute position in case of collaboration
364
- currentNodeRelPos = getRelativePos(view.state, currentNodePos);
365
- // TODO: Remove
366
- // console.log('View has updated: callback with new data and repositioning of popup …', {
367
- // domNode,
368
- // currentNodePos,
369
- // currentNode,
370
- // rect: (domNode as Element).getBoundingClientRect(),
371
- // });
372
- onNodeChange === null || onNodeChange === void 0 ? void 0 : onNodeChange({ editor, node: currentNode, pos: currentNodePos });
373
- // Update Tippys getReferenceClientRect since domNode might have changed.
374
- popup.setProps({
375
- getReferenceClientRect: () => domNode.getBoundingClientRect(),
376
- });
377
- },
378
- // TODO: Kills even on hot reload
379
- destroy() {
380
- popup === null || popup === void 0 ? void 0 : popup.destroy();
381
- if (element) {
382
- removeNode(wrapper);
383
- }
384
- },
385
- };
386
- },
387
- props: {
388
- handleDOMEvents: {
389
- mouseleave(_view, e) {
390
- // Do not hide open popup on mouseleave.
391
- if (locked) {
392
- return false;
393
- }
394
- // If e.target is not inside the wrapper, hide.
395
- if (e.target && !wrapper.contains(e.relatedTarget)) {
396
- popup === null || popup === void 0 ? void 0 : popup.hide();
397
- currentNode = null;
398
- currentNodePos = -1;
399
- onNodeChange === null || onNodeChange === void 0 ? void 0 : onNodeChange({ editor, node: null, pos: -1 });
400
- }
401
- return false;
402
- },
403
- mousemove(view, e) {
404
- // Do not continue if popup is not initialized or open.
405
- if (!element || !popup || locked) {
406
- return false;
407
- }
408
- const nodeData = findElementNextToCoords({
409
- x: e.clientX,
410
- y: e.clientY,
411
- direction: 'right',
412
- editor,
413
- });
414
- // Skip if there is no node next to coords
415
- if (!nodeData.resultElement) {
416
- return false;
417
- }
418
- let domNode = nodeData.resultElement;
419
- domNode = getOuterDomNode(view, domNode);
420
- // Skip if domNode is editor dom.
421
- if (domNode === view.dom) {
422
- return false;
423
- }
424
- // We only want `Element`.
425
- if ((domNode === null || domNode === void 0 ? void 0 : domNode.nodeType) !== 1) {
426
- return false;
427
- }
428
- const domNodePos = view.posAtDOM(domNode, 0);
429
- const outerNode = getOuterNode(editor.state.doc, domNodePos);
430
- if (outerNode !== currentNode) {
431
- const outerNodePos = getOuterNodePos(editor.state.doc, domNodePos);
432
- currentNode = outerNode;
433
- currentNodePos = outerNodePos;
434
- // Memorize relative position to retrieve absolute position in case of collaboration
435
- currentNodeRelPos = getRelativePos(view.state, currentNodePos);
436
- // TODO: Remove
437
- // console.log('Mousemove with changed node / node data …', {
438
- // domNode,
439
- // currentNodePos,
440
- // currentNode,
441
- // rect: (domNode as Element).getBoundingClientRect(),
442
- // });
443
- onNodeChange === null || onNodeChange === void 0 ? void 0 : onNodeChange({ editor, node: currentNode, pos: currentNodePos });
444
- // Set nodes clientRect.
445
- popup.setProps({
446
- getReferenceClientRect: () => domNode.getBoundingClientRect(),
447
- });
448
- popup.show();
449
- }
450
- return false;
451
- },
452
- },
453
- },
454
- });
446
+ }
447
+ })
448
+ };
455
449
  };
456
450
 
457
- const DragHandle = core.Extension.create({
458
- name: 'dragHandle',
459
- addOptions() {
460
- return {
461
- render() {
462
- const element = document.createElement('div');
463
- element.classList.add('drag-handle');
464
- return element;
465
- },
466
- tippyOptions: {},
467
- locked: false,
468
- onNodeChange: () => { return null; },
469
- };
470
- },
471
- addCommands() {
472
- return {
473
- lockDragHandle: () => ({ editor }) => {
474
- this.options.locked = true;
475
- return editor.commands.setMeta('lockDragHandle', this.options.locked);
476
- },
477
- unlockDragHandle: () => ({ editor }) => {
478
- this.options.locked = false;
479
- return editor.commands.setMeta('lockDragHandle', this.options.locked);
480
- },
481
- toggleDragHandle: () => ({ editor }) => {
482
- this.options.locked = !this.options.locked;
483
- return editor.commands.setMeta('lockDragHandle', this.options.locked);
484
- },
485
- };
486
- },
487
- addProseMirrorPlugins() {
488
- const element = this.options.render();
489
- return [
490
- DragHandlePlugin({
491
- tippyOptions: this.options.tippyOptions,
492
- element,
493
- editor: this.editor,
494
- onNodeChange: this.options.onNodeChange,
495
- }),
496
- ];
497
- },
451
+ // src/drag-handle.ts
452
+ var defaultComputePositionConfig = {
453
+ placement: "left-start",
454
+ strategy: "absolute"
455
+ };
456
+ var DragHandle = import_core.Extension.create({
457
+ name: "dragHandle",
458
+ addOptions() {
459
+ return {
460
+ render() {
461
+ const element = document.createElement("div");
462
+ element.classList.add("drag-handle");
463
+ return element;
464
+ },
465
+ computePositionConfig: {},
466
+ locked: false,
467
+ onNodeChange: () => {
468
+ return null;
469
+ }
470
+ };
471
+ },
472
+ addCommands() {
473
+ return {
474
+ lockDragHandle: () => ({ editor }) => {
475
+ this.options.locked = true;
476
+ return editor.commands.setMeta("lockDragHandle", this.options.locked);
477
+ },
478
+ unlockDragHandle: () => ({ editor }) => {
479
+ this.options.locked = false;
480
+ return editor.commands.setMeta("lockDragHandle", this.options.locked);
481
+ },
482
+ toggleDragHandle: () => ({ editor }) => {
483
+ this.options.locked = !this.options.locked;
484
+ return editor.commands.setMeta("lockDragHandle", this.options.locked);
485
+ }
486
+ };
487
+ },
488
+ addProseMirrorPlugins() {
489
+ const element = this.options.render();
490
+ return [
491
+ DragHandlePlugin({
492
+ computePositionConfig: { ...defaultComputePositionConfig, ...this.options.computePositionConfig },
493
+ element,
494
+ editor: this.editor,
495
+ onNodeChange: this.options.onNodeChange
496
+ }).plugin
497
+ ];
498
+ }
498
499
  });
499
500
 
500
- exports.DragHandle = DragHandle;
501
- exports.DragHandlePlugin = DragHandlePlugin;
502
- exports.default = DragHandle;
503
- exports.dragHandlePluginDefaultKey = dragHandlePluginDefaultKey;
504
- //# sourceMappingURL=index.cjs.map
501
+ // src/index.ts
502
+ var index_default = DragHandle;
503
+ // Annotate the CommonJS export names for ESM import in node:
504
+ 0 && (module.exports = {
505
+ DragHandle,
506
+ DragHandlePlugin,
507
+ defaultComputePositionConfig,
508
+ dragHandlePluginDefaultKey
509
+ });
510
+ //# sourceMappingURL=index.cjs.map