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