@blockslides/extension-drag-handle 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,84 @@
1
+ import { ComputePositionConfig, VirtualElement } from '@floating-ui/dom';
2
+ import { Extension, Editor } from '@blockslides/core';
3
+ import { Node } from '@blockslides/pm/model';
4
+ import { PluginKey, Plugin } from '@blockslides/pm/state';
5
+
6
+ declare const defaultComputePositionConfig: ComputePositionConfig;
7
+ interface DragHandleOptions {
8
+ /**
9
+ * Renders an element that is positioned with the floating-ui/dom package
10
+ */
11
+ render(): HTMLElement;
12
+ /**
13
+ * Configuration for position computation of the drag handle
14
+ * using the floating-ui/dom package
15
+ */
16
+ computePositionConfig?: ComputePositionConfig;
17
+ /**
18
+ * A function that returns the virtual element for the drag handle.
19
+ * This is useful when the menu needs to be positioned relative to a specific DOM element.
20
+ */
21
+ getReferencedVirtualElement?: () => VirtualElement | null;
22
+ /**
23
+ * Locks the draghandle in place and visibility
24
+ */
25
+ locked?: boolean;
26
+ /**
27
+ * Returns a node or null when a node is hovered over
28
+ */
29
+ onNodeChange?: (options: {
30
+ node: Node | null;
31
+ editor: Editor;
32
+ }) => void;
33
+ /**
34
+ * The callback function that will be called when drag start.
35
+ */
36
+ onElementDragStart?: (e: DragEvent) => void;
37
+ /**
38
+ * The callback function that will be called when drag end.
39
+ */
40
+ onElementDragEnd?: (e: DragEvent) => void;
41
+ }
42
+ declare module '@blockslides/core' {
43
+ interface Commands<ReturnType> {
44
+ dragHandle: {
45
+ /**
46
+ * Locks the draghandle in place and visibility
47
+ */
48
+ lockDragHandle: () => ReturnType;
49
+ /**
50
+ * Unlocks the draghandle
51
+ */
52
+ unlockDragHandle: () => ReturnType;
53
+ /**
54
+ * Toggle draghandle lock state
55
+ */
56
+ toggleDragHandle: () => ReturnType;
57
+ };
58
+ }
59
+ }
60
+ declare const DragHandle: Extension<DragHandleOptions, any>;
61
+
62
+ interface DragHandlePluginProps {
63
+ pluginKey?: PluginKey | string;
64
+ editor: Editor;
65
+ element: HTMLElement;
66
+ onNodeChange?: (data: {
67
+ editor: Editor;
68
+ node: Node | null;
69
+ pos: number;
70
+ }) => void;
71
+ onElementDragStart?: (e: DragEvent) => void;
72
+ onElementDragEnd?: (e: DragEvent) => void;
73
+ computePositionConfig?: ComputePositionConfig;
74
+ getReferencedVirtualElement?: () => VirtualElement | null;
75
+ }
76
+ declare const dragHandlePluginDefaultKey: PluginKey<any>;
77
+ declare const DragHandlePlugin: ({ pluginKey, element, editor, computePositionConfig, getReferencedVirtualElement, onNodeChange, onElementDragStart, onElementDragEnd, }: DragHandlePluginProps) => {
78
+ unbind(): void;
79
+ plugin: Plugin<{
80
+ locked: boolean;
81
+ }>;
82
+ };
83
+
84
+ export { DragHandle, type DragHandleOptions, DragHandlePlugin, type DragHandlePluginProps, DragHandle as default, defaultComputePositionConfig, dragHandlePluginDefaultKey };
@@ -0,0 +1,84 @@
1
+ import { ComputePositionConfig, VirtualElement } from '@floating-ui/dom';
2
+ import { Extension, Editor } from '@blockslides/core';
3
+ import { Node } from '@blockslides/pm/model';
4
+ import { PluginKey, Plugin } from '@blockslides/pm/state';
5
+
6
+ declare const defaultComputePositionConfig: ComputePositionConfig;
7
+ interface DragHandleOptions {
8
+ /**
9
+ * Renders an element that is positioned with the floating-ui/dom package
10
+ */
11
+ render(): HTMLElement;
12
+ /**
13
+ * Configuration for position computation of the drag handle
14
+ * using the floating-ui/dom package
15
+ */
16
+ computePositionConfig?: ComputePositionConfig;
17
+ /**
18
+ * A function that returns the virtual element for the drag handle.
19
+ * This is useful when the menu needs to be positioned relative to a specific DOM element.
20
+ */
21
+ getReferencedVirtualElement?: () => VirtualElement | null;
22
+ /**
23
+ * Locks the draghandle in place and visibility
24
+ */
25
+ locked?: boolean;
26
+ /**
27
+ * Returns a node or null when a node is hovered over
28
+ */
29
+ onNodeChange?: (options: {
30
+ node: Node | null;
31
+ editor: Editor;
32
+ }) => void;
33
+ /**
34
+ * The callback function that will be called when drag start.
35
+ */
36
+ onElementDragStart?: (e: DragEvent) => void;
37
+ /**
38
+ * The callback function that will be called when drag end.
39
+ */
40
+ onElementDragEnd?: (e: DragEvent) => void;
41
+ }
42
+ declare module '@blockslides/core' {
43
+ interface Commands<ReturnType> {
44
+ dragHandle: {
45
+ /**
46
+ * Locks the draghandle in place and visibility
47
+ */
48
+ lockDragHandle: () => ReturnType;
49
+ /**
50
+ * Unlocks the draghandle
51
+ */
52
+ unlockDragHandle: () => ReturnType;
53
+ /**
54
+ * Toggle draghandle lock state
55
+ */
56
+ toggleDragHandle: () => ReturnType;
57
+ };
58
+ }
59
+ }
60
+ declare const DragHandle: Extension<DragHandleOptions, any>;
61
+
62
+ interface DragHandlePluginProps {
63
+ pluginKey?: PluginKey | string;
64
+ editor: Editor;
65
+ element: HTMLElement;
66
+ onNodeChange?: (data: {
67
+ editor: Editor;
68
+ node: Node | null;
69
+ pos: number;
70
+ }) => void;
71
+ onElementDragStart?: (e: DragEvent) => void;
72
+ onElementDragEnd?: (e: DragEvent) => void;
73
+ computePositionConfig?: ComputePositionConfig;
74
+ getReferencedVirtualElement?: () => VirtualElement | null;
75
+ }
76
+ declare const dragHandlePluginDefaultKey: PluginKey<any>;
77
+ declare const DragHandlePlugin: ({ pluginKey, element, editor, computePositionConfig, getReferencedVirtualElement, onNodeChange, onElementDragStart, onElementDragEnd, }: DragHandlePluginProps) => {
78
+ unbind(): void;
79
+ plugin: Plugin<{
80
+ locked: boolean;
81
+ }>;
82
+ };
83
+
84
+ export { DragHandle, type DragHandleOptions, DragHandlePlugin, type DragHandlePluginProps, DragHandle as default, defaultComputePositionConfig, dragHandlePluginDefaultKey };
package/dist/index.js ADDED
@@ -0,0 +1,542 @@
1
+ // src/drag-handle.ts
2
+ import { Extension } from "@blockslides/core";
3
+
4
+ // src/drag-handle-plugin.ts
5
+ import { computePosition } from "@floating-ui/dom";
6
+ import { Plugin, PluginKey } from "@blockslides/pm/state";
7
+
8
+ // src/helpers/dragHandler.ts
9
+ import { getSelectionRanges, NodeRangeSelection } from "@blockslides/extension-node-range";
10
+
11
+ // src/helpers/cloneElement.ts
12
+ function getCSSText(element) {
13
+ let value = "";
14
+ const style = getComputedStyle(element);
15
+ for (let i = 0; i < style.length; i += 1) {
16
+ value += `${style[i]}:${style.getPropertyValue(style[i])};`;
17
+ }
18
+ return value;
19
+ }
20
+ function cloneElement(node) {
21
+ const clonedNode = node.cloneNode(true);
22
+ const sourceElements = [node, ...Array.from(node.getElementsByTagName("*"))];
23
+ const targetElements = [clonedNode, ...Array.from(clonedNode.getElementsByTagName("*"))];
24
+ sourceElements.forEach((sourceElement, index) => {
25
+ targetElements[index].style.cssText = getCSSText(sourceElement);
26
+ });
27
+ return clonedNode;
28
+ }
29
+
30
+ // src/helpers/findNextElementFromCursor.ts
31
+ function findClosestTopLevelBlock(element, view) {
32
+ let current = element;
33
+ while ((current == null ? void 0 : current.parentElement) && current.parentElement !== view.dom) {
34
+ current = current.parentElement;
35
+ }
36
+ return (current == null ? void 0 : current.parentElement) === view.dom ? current : void 0;
37
+ }
38
+ function clampToContent(view, x, y, inset = 5) {
39
+ const container = view.dom;
40
+ const firstBlock = container.firstElementChild;
41
+ const lastBlock = container.lastElementChild;
42
+ if (!firstBlock || !lastBlock) {
43
+ return { x, y };
44
+ }
45
+ const topRect = firstBlock.getBoundingClientRect();
46
+ const botRect = lastBlock.getBoundingClientRect();
47
+ const clampedY = Math.min(Math.max(topRect.top + inset, y), botRect.bottom - inset);
48
+ const epsilon = 0.5;
49
+ const sameLeft = Math.abs(topRect.left - botRect.left) < epsilon;
50
+ const sameRight = Math.abs(topRect.right - botRect.right) < epsilon;
51
+ let rowRect = topRect;
52
+ if (sameLeft && sameRight) {
53
+ rowRect = topRect;
54
+ } else {
55
+ }
56
+ const clampedX = Math.min(Math.max(rowRect.left + inset, x), rowRect.right - inset);
57
+ return { x: clampedX, y: clampedY };
58
+ }
59
+ var findElementNextToCoords = (options) => {
60
+ const { x, y, editor } = options;
61
+ const { view, state } = editor;
62
+ const { x: clampedX, y: clampedY } = clampToContent(view, x, y, 5);
63
+ const elements = view.root.elementsFromPoint(clampedX, clampedY);
64
+ let block;
65
+ Array.prototype.some.call(elements, (el) => {
66
+ if (!view.dom.contains(el)) {
67
+ return false;
68
+ }
69
+ const candidate = findClosestTopLevelBlock(el, view);
70
+ if (candidate) {
71
+ block = candidate;
72
+ return true;
73
+ }
74
+ return false;
75
+ });
76
+ if (!block) {
77
+ return { resultElement: null, resultNode: null, pos: null };
78
+ }
79
+ let pos;
80
+ try {
81
+ pos = view.posAtDOM(block, 0);
82
+ } catch {
83
+ return { resultElement: null, resultNode: null, pos: null };
84
+ }
85
+ const node = state.doc.nodeAt(pos);
86
+ if (!node) {
87
+ const resolvedPos = state.doc.resolve(pos);
88
+ const parent = resolvedPos.parent;
89
+ return {
90
+ resultElement: block,
91
+ resultNode: parent,
92
+ pos: resolvedPos.start()
93
+ };
94
+ }
95
+ return {
96
+ resultElement: block,
97
+ resultNode: node,
98
+ pos
99
+ };
100
+ };
101
+
102
+ // src/helpers/getComputedStyle.ts
103
+ function getComputedStyle2(node, property) {
104
+ const style = window.getComputedStyle(node);
105
+ return style[property];
106
+ }
107
+
108
+ // src/helpers/minMax.ts
109
+ function minMax(value = 0, min = 0, max = 0) {
110
+ return Math.min(Math.max(value, min), max);
111
+ }
112
+
113
+ // src/helpers/getInnerCoords.ts
114
+ function getInnerCoords(view, x, y) {
115
+ const paddingLeft = parseInt(getComputedStyle2(view.dom, "paddingLeft"), 10);
116
+ const paddingRight = parseInt(getComputedStyle2(view.dom, "paddingRight"), 10);
117
+ const borderLeft = parseInt(getComputedStyle2(view.dom, "borderLeftWidth"), 10);
118
+ const borderRight = parseInt(getComputedStyle2(view.dom, "borderLeftWidth"), 10);
119
+ const bounds = view.dom.getBoundingClientRect();
120
+ const coords = {
121
+ left: minMax(x, bounds.left + paddingLeft + borderLeft, bounds.right - paddingRight - borderRight),
122
+ top: y
123
+ };
124
+ return coords;
125
+ }
126
+
127
+ // src/helpers/removeNode.ts
128
+ function removeNode(node) {
129
+ var _a;
130
+ (_a = node.parentNode) == null ? void 0 : _a.removeChild(node);
131
+ }
132
+
133
+ // src/helpers/dragHandler.ts
134
+ function getDragHandleRanges(event, editor) {
135
+ const { doc } = editor.view.state;
136
+ const result = findElementNextToCoords({
137
+ editor,
138
+ x: event.clientX,
139
+ y: event.clientY,
140
+ direction: "right"
141
+ });
142
+ if (!result.resultNode || result.pos === null) {
143
+ return [];
144
+ }
145
+ const x = event.clientX;
146
+ const coords = getInnerCoords(editor.view, x, event.clientY);
147
+ const posAtCoords = editor.view.posAtCoords(coords);
148
+ if (!posAtCoords) {
149
+ return [];
150
+ }
151
+ const { pos } = posAtCoords;
152
+ const nodeAt = doc.resolve(pos).parent;
153
+ if (!nodeAt) {
154
+ return [];
155
+ }
156
+ const $from = doc.resolve(result.pos);
157
+ const $to = doc.resolve(result.pos + 1);
158
+ return getSelectionRanges($from, $to, 0);
159
+ }
160
+ function dragHandler(event, editor) {
161
+ const { view } = editor;
162
+ if (!event.dataTransfer) {
163
+ return;
164
+ }
165
+ const { empty, $from, $to } = view.state.selection;
166
+ const dragHandleRanges = getDragHandleRanges(event, editor);
167
+ const selectionRanges = getSelectionRanges($from, $to, 0);
168
+ const isDragHandleWithinSelection = selectionRanges.some((range) => {
169
+ return dragHandleRanges.find((dragHandleRange) => {
170
+ return dragHandleRange.$from === range.$from && dragHandleRange.$to === range.$to;
171
+ });
172
+ });
173
+ const ranges = empty || !isDragHandleWithinSelection ? dragHandleRanges : selectionRanges;
174
+ if (!ranges.length) {
175
+ return;
176
+ }
177
+ const { tr } = view.state;
178
+ const wrapper = document.createElement("div");
179
+ const from = ranges[0].$from.pos;
180
+ const to = ranges[ranges.length - 1].$to.pos;
181
+ const selection = NodeRangeSelection.create(view.state.doc, from, to);
182
+ const slice = selection.content();
183
+ ranges.forEach((range) => {
184
+ const element = view.nodeDOM(range.$from.pos);
185
+ const clonedElement = cloneElement(element);
186
+ wrapper.append(clonedElement);
187
+ });
188
+ wrapper.style.position = "absolute";
189
+ wrapper.style.top = "-10000px";
190
+ document.body.append(wrapper);
191
+ event.dataTransfer.clearData();
192
+ event.dataTransfer.setDragImage(wrapper, 0, 0);
193
+ view.dragging = { slice, move: true };
194
+ tr.setSelection(selection);
195
+ view.dispatch(tr);
196
+ document.addEventListener("drop", () => removeNode(wrapper), { once: true });
197
+ }
198
+
199
+ // src/helpers/getOuterNode.ts
200
+ var getOuterNodePos = (doc, pos) => {
201
+ const resolvedPos = doc.resolve(pos);
202
+ const { depth } = resolvedPos;
203
+ if (depth === 0) {
204
+ return pos;
205
+ }
206
+ const a = resolvedPos.pos - resolvedPos.parentOffset;
207
+ return a - 1;
208
+ };
209
+ var getOuterNode = (doc, pos) => {
210
+ const node = doc.nodeAt(pos);
211
+ const resolvedPos = doc.resolve(pos);
212
+ let { depth } = resolvedPos;
213
+ let parent = node;
214
+ while (depth > 0) {
215
+ const currentNode = resolvedPos.node(depth);
216
+ depth -= 1;
217
+ if (depth === 0) {
218
+ parent = currentNode;
219
+ }
220
+ }
221
+ return parent;
222
+ };
223
+
224
+ // src/drag-handle-plugin.ts
225
+ var getOuterDomNode = (view, domNode) => {
226
+ let tmpDomNode = domNode;
227
+ while (tmpDomNode == null ? void 0 : tmpDomNode.parentNode) {
228
+ if (tmpDomNode.parentNode === view.dom) {
229
+ break;
230
+ }
231
+ tmpDomNode = tmpDomNode.parentNode;
232
+ }
233
+ return tmpDomNode;
234
+ };
235
+ var dragHandlePluginDefaultKey = new PluginKey("dragHandle");
236
+ var DragHandlePlugin = ({
237
+ pluginKey = dragHandlePluginDefaultKey,
238
+ element,
239
+ editor,
240
+ computePositionConfig,
241
+ getReferencedVirtualElement,
242
+ onNodeChange,
243
+ onElementDragStart,
244
+ onElementDragEnd
245
+ }) => {
246
+ const wrapper = document.createElement("div");
247
+ let locked = false;
248
+ let currentNode = null;
249
+ let currentNodePos = -1;
250
+ let rafId = null;
251
+ let pendingMouseCoords = null;
252
+ function hideHandle() {
253
+ if (!element) {
254
+ return;
255
+ }
256
+ element.style.visibility = "hidden";
257
+ element.style.pointerEvents = "none";
258
+ }
259
+ function showHandle() {
260
+ if (!element) {
261
+ return;
262
+ }
263
+ if (!editor.isEditable) {
264
+ hideHandle();
265
+ return;
266
+ }
267
+ element.style.visibility = "";
268
+ element.style.pointerEvents = "auto";
269
+ }
270
+ function repositionDragHandle(dom) {
271
+ const virtualElement = (getReferencedVirtualElement == null ? void 0 : getReferencedVirtualElement()) || {
272
+ getBoundingClientRect: () => dom.getBoundingClientRect()
273
+ };
274
+ computePosition(virtualElement, element, computePositionConfig).then((val) => {
275
+ Object.assign(element.style, {
276
+ position: val.strategy,
277
+ left: `${val.x}px`,
278
+ top: `${val.y}px`
279
+ });
280
+ });
281
+ }
282
+ function onDragStart(e) {
283
+ onElementDragStart == null ? void 0 : onElementDragStart(e);
284
+ dragHandler(e, editor);
285
+ if (element) {
286
+ element.dataset.dragging = "true";
287
+ }
288
+ setTimeout(() => {
289
+ if (element) {
290
+ element.style.pointerEvents = "none";
291
+ }
292
+ }, 0);
293
+ }
294
+ function onDragEnd(e) {
295
+ onElementDragEnd == null ? void 0 : onElementDragEnd(e);
296
+ hideHandle();
297
+ if (element) {
298
+ element.style.pointerEvents = "auto";
299
+ element.dataset.dragging = "false";
300
+ }
301
+ }
302
+ element.addEventListener("dragstart", onDragStart);
303
+ element.addEventListener("dragend", onDragEnd);
304
+ wrapper.appendChild(element);
305
+ return {
306
+ unbind() {
307
+ element.removeEventListener("dragstart", onDragStart);
308
+ element.removeEventListener("dragend", onDragEnd);
309
+ if (rafId) {
310
+ cancelAnimationFrame(rafId);
311
+ rafId = null;
312
+ pendingMouseCoords = null;
313
+ }
314
+ },
315
+ plugin: new Plugin({
316
+ key: typeof pluginKey === "string" ? new PluginKey(pluginKey) : pluginKey,
317
+ state: {
318
+ init() {
319
+ return { locked: false };
320
+ },
321
+ apply(tr, value, _oldState, state) {
322
+ const isLocked = tr.getMeta("lockDragHandle");
323
+ const hideDragHandle = tr.getMeta("hideDragHandle");
324
+ if (isLocked !== void 0) {
325
+ locked = isLocked;
326
+ }
327
+ if (hideDragHandle) {
328
+ hideHandle();
329
+ locked = false;
330
+ currentNode = null;
331
+ currentNodePos = -1;
332
+ onNodeChange == null ? void 0 : onNodeChange({ editor, node: null, pos: -1 });
333
+ return value;
334
+ }
335
+ if (tr.docChanged && currentNodePos !== -1 && element) {
336
+ const newPos = tr.mapping.map(currentNodePos);
337
+ if (newPos !== currentNodePos) {
338
+ currentNodePos = newPos;
339
+ }
340
+ }
341
+ return value;
342
+ }
343
+ },
344
+ view: (view) => {
345
+ var _a;
346
+ element.draggable = true;
347
+ element.style.pointerEvents = "auto";
348
+ element.dataset.dragging = "false";
349
+ (_a = editor.view.dom.parentElement) == null ? void 0 : _a.appendChild(wrapper);
350
+ wrapper.style.pointerEvents = "none";
351
+ wrapper.style.position = "absolute";
352
+ wrapper.style.top = "0";
353
+ wrapper.style.left = "0";
354
+ return {
355
+ update(_, oldState) {
356
+ if (!element) {
357
+ return;
358
+ }
359
+ if (!editor.isEditable) {
360
+ hideHandle();
361
+ return;
362
+ }
363
+ if (locked) {
364
+ element.draggable = false;
365
+ } else {
366
+ element.draggable = true;
367
+ }
368
+ if (view.state.doc.eq(oldState.doc) || currentNodePos === -1) {
369
+ return;
370
+ }
371
+ let domNode = view.nodeDOM(currentNodePos);
372
+ domNode = getOuterDomNode(view, domNode);
373
+ if (domNode === view.dom) {
374
+ return;
375
+ }
376
+ if ((domNode == null ? void 0 : domNode.nodeType) !== 1) {
377
+ return;
378
+ }
379
+ const domNodePos = view.posAtDOM(domNode, 0);
380
+ const outerNode = getOuterNode(editor.state.doc, domNodePos);
381
+ const outerNodePos = getOuterNodePos(editor.state.doc, domNodePos);
382
+ currentNode = outerNode;
383
+ currentNodePos = outerNodePos;
384
+ onNodeChange == null ? void 0 : onNodeChange({ editor, node: currentNode, pos: currentNodePos });
385
+ repositionDragHandle(domNode);
386
+ },
387
+ // TODO: Kills even on hot reload
388
+ destroy() {
389
+ if (rafId) {
390
+ cancelAnimationFrame(rafId);
391
+ rafId = null;
392
+ pendingMouseCoords = null;
393
+ }
394
+ if (element) {
395
+ removeNode(wrapper);
396
+ }
397
+ }
398
+ };
399
+ },
400
+ props: {
401
+ handleDOMEvents: {
402
+ keydown(view) {
403
+ if (!element || locked) {
404
+ return false;
405
+ }
406
+ if (view.hasFocus()) {
407
+ hideHandle();
408
+ currentNode = null;
409
+ currentNodePos = -1;
410
+ onNodeChange == null ? void 0 : onNodeChange({ editor, node: null, pos: -1 });
411
+ return false;
412
+ }
413
+ return false;
414
+ },
415
+ mouseleave(_view, e) {
416
+ if (locked) {
417
+ return false;
418
+ }
419
+ if (e.target && !wrapper.contains(e.relatedTarget)) {
420
+ hideHandle();
421
+ currentNode = null;
422
+ currentNodePos = -1;
423
+ onNodeChange == null ? void 0 : onNodeChange({ editor, node: null, pos: -1 });
424
+ }
425
+ return false;
426
+ },
427
+ mousemove(view, e) {
428
+ if (!element || locked) {
429
+ return false;
430
+ }
431
+ pendingMouseCoords = { x: e.clientX, y: e.clientY };
432
+ if (rafId) {
433
+ return false;
434
+ }
435
+ rafId = requestAnimationFrame(() => {
436
+ rafId = null;
437
+ if (!pendingMouseCoords) {
438
+ return;
439
+ }
440
+ const { x, y } = pendingMouseCoords;
441
+ pendingMouseCoords = null;
442
+ const nodeData = findElementNextToCoords({
443
+ x,
444
+ y,
445
+ direction: "right",
446
+ editor
447
+ });
448
+ if (!nodeData.resultElement) {
449
+ return;
450
+ }
451
+ let domNode = nodeData.resultElement;
452
+ domNode = getOuterDomNode(view, domNode);
453
+ if (domNode === view.dom) {
454
+ return;
455
+ }
456
+ if ((domNode == null ? void 0 : domNode.nodeType) !== 1) {
457
+ return;
458
+ }
459
+ const domNodePos = view.posAtDOM(domNode, 0);
460
+ const outerNode = getOuterNode(editor.state.doc, domNodePos);
461
+ if (outerNode !== currentNode) {
462
+ const outerNodePos = getOuterNodePos(editor.state.doc, domNodePos);
463
+ currentNode = outerNode;
464
+ currentNodePos = outerNodePos;
465
+ onNodeChange == null ? void 0 : onNodeChange({ editor, node: currentNode, pos: currentNodePos });
466
+ repositionDragHandle(domNode);
467
+ showHandle();
468
+ }
469
+ });
470
+ return false;
471
+ }
472
+ }
473
+ }
474
+ })
475
+ };
476
+ };
477
+
478
+ // src/drag-handle.ts
479
+ var defaultComputePositionConfig = {
480
+ placement: "left-start",
481
+ strategy: "absolute"
482
+ };
483
+ var DragHandle = Extension.create({
484
+ name: "dragHandle",
485
+ addOptions() {
486
+ return {
487
+ render() {
488
+ const element = document.createElement("div");
489
+ element.classList.add("drag-handle");
490
+ return element;
491
+ },
492
+ computePositionConfig: {},
493
+ locked: false,
494
+ onNodeChange: () => {
495
+ return null;
496
+ },
497
+ onElementDragStart: void 0,
498
+ onElementDragEnd: void 0
499
+ };
500
+ },
501
+ addCommands() {
502
+ return {
503
+ lockDragHandle: () => ({ editor }) => {
504
+ this.options.locked = true;
505
+ return editor.commands.setMeta("lockDragHandle", this.options.locked);
506
+ },
507
+ unlockDragHandle: () => ({ editor }) => {
508
+ this.options.locked = false;
509
+ return editor.commands.setMeta("lockDragHandle", this.options.locked);
510
+ },
511
+ toggleDragHandle: () => ({ editor }) => {
512
+ this.options.locked = !this.options.locked;
513
+ return editor.commands.setMeta("lockDragHandle", this.options.locked);
514
+ }
515
+ };
516
+ },
517
+ addProseMirrorPlugins() {
518
+ const element = this.options.render();
519
+ return [
520
+ DragHandlePlugin({
521
+ computePositionConfig: { ...defaultComputePositionConfig, ...this.options.computePositionConfig },
522
+ getReferencedVirtualElement: this.options.getReferencedVirtualElement,
523
+ element,
524
+ editor: this.editor,
525
+ onNodeChange: this.options.onNodeChange,
526
+ onElementDragStart: this.options.onElementDragStart,
527
+ onElementDragEnd: this.options.onElementDragEnd
528
+ }).plugin
529
+ ];
530
+ }
531
+ });
532
+
533
+ // src/index.ts
534
+ var index_default = DragHandle;
535
+ export {
536
+ DragHandle,
537
+ DragHandlePlugin,
538
+ index_default as default,
539
+ defaultComputePositionConfig,
540
+ dragHandlePluginDefaultKey
541
+ };
542
+ //# sourceMappingURL=index.js.map