@tiptap/extension-drag-handle 3.27.0 → 3.27.2
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/dist/index.cjs +126 -68
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +126 -68
- package/dist/index.js.map +1 -1
- package/package.json +14 -14
- package/src/drag-handle-plugin.ts +59 -39
- package/src/helpers/cloneElement.ts +3 -2
- package/src/helpers/dragHandler.ts +19 -1
- package/src/helpers/findNextElementFromCursor.ts +57 -13
- package/src/helpers/nodeRangeDrop.ts +47 -0
package/dist/index.js
CHANGED
|
@@ -20,7 +20,7 @@ import { NodeSelection } from "@tiptap/pm/state";
|
|
|
20
20
|
function getCSSText(element, properties) {
|
|
21
21
|
const style = getComputedStyle(element);
|
|
22
22
|
if (properties) {
|
|
23
|
-
return properties.
|
|
23
|
+
return properties.map((property) => property.trim()).filter((property) => property.length > 0).map((property) => `${property}:${style.getPropertyValue(property)};`).join("");
|
|
24
24
|
}
|
|
25
25
|
let value = "";
|
|
26
26
|
for (let i = 0; i < style.length; i += 1) {
|
|
@@ -278,28 +278,41 @@ function findBestDragTarget(view, coords, options) {
|
|
|
278
278
|
|
|
279
279
|
// src/helpers/findNextElementFromCursor.ts
|
|
280
280
|
function findClosestTopLevelBlock(element, view) {
|
|
281
|
+
var _a;
|
|
281
282
|
let current = element;
|
|
282
283
|
while ((current == null ? void 0 : current.parentElement) && current.parentElement !== view.dom) {
|
|
283
284
|
current = current.parentElement;
|
|
284
285
|
}
|
|
285
|
-
|
|
286
|
+
if ((current == null ? void 0 : current.parentElement) !== view.dom) {
|
|
287
|
+
return void 0;
|
|
288
|
+
}
|
|
289
|
+
if (!((_a = current.pmViewDesc) == null ? void 0 : _a.node)) {
|
|
290
|
+
return void 0;
|
|
291
|
+
}
|
|
292
|
+
return current;
|
|
286
293
|
}
|
|
287
294
|
function isValidRect(rect) {
|
|
288
295
|
return Number.isFinite(rect.top) && Number.isFinite(rect.bottom) && Number.isFinite(rect.left) && Number.isFinite(rect.right) && rect.width > 0 && rect.height > 0;
|
|
289
296
|
}
|
|
297
|
+
function edgeBlockRect(container, edge) {
|
|
298
|
+
let current = edge === "first" ? container.firstElementChild : container.lastElementChild;
|
|
299
|
+
while (current) {
|
|
300
|
+
const rect = current.getBoundingClientRect();
|
|
301
|
+
if (isValidRect(rect)) {
|
|
302
|
+
return rect;
|
|
303
|
+
}
|
|
304
|
+
current = edge === "first" ? current.nextElementSibling : current.previousElementSibling;
|
|
305
|
+
}
|
|
306
|
+
return null;
|
|
307
|
+
}
|
|
290
308
|
function clampToContent(view, x, y, inset = 5) {
|
|
291
309
|
if (!Number.isFinite(x) || !Number.isFinite(y)) {
|
|
292
310
|
return null;
|
|
293
311
|
}
|
|
294
312
|
const container = view.dom;
|
|
295
|
-
const
|
|
296
|
-
const
|
|
297
|
-
if (!
|
|
298
|
-
return null;
|
|
299
|
-
}
|
|
300
|
-
const topRect = firstBlock.getBoundingClientRect();
|
|
301
|
-
const botRect = lastBlock.getBoundingClientRect();
|
|
302
|
-
if (!isValidRect(topRect) || !isValidRect(botRect)) {
|
|
313
|
+
const topRect = edgeBlockRect(container, "first");
|
|
314
|
+
const botRect = edgeBlockRect(container, "last");
|
|
315
|
+
if (!topRect || !botRect) {
|
|
303
316
|
return null;
|
|
304
317
|
}
|
|
305
318
|
const clampedY = Math.min(Math.max(topRect.top + inset, y), botRect.bottom - inset);
|
|
@@ -425,6 +438,15 @@ function removeNode(node) {
|
|
|
425
438
|
function getDragImageOffset(direction, wrapperWidth) {
|
|
426
439
|
return direction === "rtl" ? wrapperWidth : 0;
|
|
427
440
|
}
|
|
441
|
+
function shouldResetMargin(dragImageProperties) {
|
|
442
|
+
if (!dragImageProperties) {
|
|
443
|
+
return true;
|
|
444
|
+
}
|
|
445
|
+
return !dragImageProperties.some((property) => {
|
|
446
|
+
const p = property.trim().toLowerCase();
|
|
447
|
+
return p === "margin" || p.startsWith("margin-");
|
|
448
|
+
});
|
|
449
|
+
}
|
|
428
450
|
function getDragHandleRanges(event, editor, nestedOptions, dragContext) {
|
|
429
451
|
const { doc } = editor.view.state;
|
|
430
452
|
if ((nestedOptions == null ? void 0 : nestedOptions.enabled) && (dragContext == null ? void 0 : dragContext.node) && dragContext.pos >= 0) {
|
|
@@ -486,13 +508,16 @@ function dragHandler(event, editor, nestedOptions, dragContext, dragImagePropert
|
|
|
486
508
|
selection = NodeRangeSelection.create(view.state.doc, from, to);
|
|
487
509
|
slice = selection.content();
|
|
488
510
|
}
|
|
511
|
+
const resetMargin = shouldResetMargin(dragImageProperties);
|
|
489
512
|
ranges.forEach((range) => {
|
|
490
513
|
const element = getDraggedBlockElement(view, range.$from.pos);
|
|
491
514
|
if (!element) {
|
|
492
515
|
return;
|
|
493
516
|
}
|
|
494
517
|
const clonedElement = cloneElement(element, dragImageProperties);
|
|
495
|
-
|
|
518
|
+
if (resetMargin) {
|
|
519
|
+
clonedElement.style.margin = "0";
|
|
520
|
+
}
|
|
496
521
|
wrapper.append(clonedElement);
|
|
497
522
|
});
|
|
498
523
|
wrapper.style.position = "absolute";
|
|
@@ -520,8 +545,56 @@ function dragHandler(event, editor, nestedOptions, dragContext, dragImagePropert
|
|
|
520
545
|
document.addEventListener("dragend", cleanupDragPreview);
|
|
521
546
|
}
|
|
522
547
|
|
|
548
|
+
// src/helpers/getOuterNode.ts
|
|
549
|
+
var getOuterNodePos = (doc, pos) => {
|
|
550
|
+
const resolvedPos = doc.resolve(pos);
|
|
551
|
+
const { depth } = resolvedPos;
|
|
552
|
+
if (depth === 0) {
|
|
553
|
+
return pos;
|
|
554
|
+
}
|
|
555
|
+
const a = resolvedPos.pos - resolvedPos.parentOffset;
|
|
556
|
+
return a - 1;
|
|
557
|
+
};
|
|
558
|
+
var getOuterNode = (doc, pos) => {
|
|
559
|
+
const node = doc.nodeAt(pos);
|
|
560
|
+
const resolvedPos = doc.resolve(pos);
|
|
561
|
+
let { depth } = resolvedPos;
|
|
562
|
+
let parent = node;
|
|
563
|
+
while (depth > 0) {
|
|
564
|
+
const currentNode = resolvedPos.node(depth);
|
|
565
|
+
depth -= 1;
|
|
566
|
+
if (depth === 0) {
|
|
567
|
+
parent = currentNode;
|
|
568
|
+
}
|
|
569
|
+
}
|
|
570
|
+
return parent;
|
|
571
|
+
};
|
|
572
|
+
|
|
523
573
|
// src/helpers/nodeRangeDrop.ts
|
|
524
574
|
import { isNodeRangeSelection, NodeRangeSelection as NodeRangeSelection2 } from "@tiptap/extension-node-range";
|
|
575
|
+
function mapPendingRestoreAnchor(pendingRestore, tr, options) {
|
|
576
|
+
if (!tr.docChanged) {
|
|
577
|
+
return pendingRestore;
|
|
578
|
+
}
|
|
579
|
+
if (options.isChangeOrigin && pendingRestore.relativeAnchorPos != null) {
|
|
580
|
+
const newPos = options.getAbsolutePos(pendingRestore.relativeAnchorPos);
|
|
581
|
+
if (!Number.isFinite(newPos) || newPos <= 0) {
|
|
582
|
+
return null;
|
|
583
|
+
}
|
|
584
|
+
return {
|
|
585
|
+
...pendingRestore,
|
|
586
|
+
anchorPos: newPos
|
|
587
|
+
};
|
|
588
|
+
}
|
|
589
|
+
const mappedResult = tr.mapping.mapResult(pendingRestore.anchorPos, 1);
|
|
590
|
+
if (mappedResult.deleted) {
|
|
591
|
+
return null;
|
|
592
|
+
}
|
|
593
|
+
return {
|
|
594
|
+
...pendingRestore,
|
|
595
|
+
anchorPos: mappedResult.pos
|
|
596
|
+
};
|
|
597
|
+
}
|
|
525
598
|
function sumNodeSizes(parent, from, to) {
|
|
526
599
|
let size = 0;
|
|
527
600
|
for (let i = from; i < to; i += 1) {
|
|
@@ -568,31 +641,6 @@ function createDroppedNodeRangeSelection(doc, anchorPos, nodeCount, depth) {
|
|
|
568
641
|
}
|
|
569
642
|
}
|
|
570
643
|
|
|
571
|
-
// src/helpers/getOuterNode.ts
|
|
572
|
-
var getOuterNodePos = (doc, pos) => {
|
|
573
|
-
const resolvedPos = doc.resolve(pos);
|
|
574
|
-
const { depth } = resolvedPos;
|
|
575
|
-
if (depth === 0) {
|
|
576
|
-
return pos;
|
|
577
|
-
}
|
|
578
|
-
const a = resolvedPos.pos - resolvedPos.parentOffset;
|
|
579
|
-
return a - 1;
|
|
580
|
-
};
|
|
581
|
-
var getOuterNode = (doc, pos) => {
|
|
582
|
-
const node = doc.nodeAt(pos);
|
|
583
|
-
const resolvedPos = doc.resolve(pos);
|
|
584
|
-
let { depth } = resolvedPos;
|
|
585
|
-
let parent = node;
|
|
586
|
-
while (depth > 0) {
|
|
587
|
-
const currentNode = resolvedPos.node(depth);
|
|
588
|
-
depth -= 1;
|
|
589
|
-
if (depth === 0) {
|
|
590
|
-
parent = currentNode;
|
|
591
|
-
}
|
|
592
|
-
}
|
|
593
|
-
return parent;
|
|
594
|
-
};
|
|
595
|
-
|
|
596
644
|
// src/drag-handle-plugin.ts
|
|
597
645
|
var getRelativePos = (state, absolutePos) => {
|
|
598
646
|
const ystate = ySyncPluginKey.getState(state);
|
|
@@ -642,10 +690,40 @@ var DragHandlePlugin = ({
|
|
|
642
690
|
let currentNodePos = -1;
|
|
643
691
|
let currentNodeRelPos;
|
|
644
692
|
let rafId = null;
|
|
645
|
-
let restoreRafId = null;
|
|
646
693
|
let pendingMouseCoords = null;
|
|
647
694
|
let activeDragRange = null;
|
|
648
695
|
let pendingRestore = null;
|
|
696
|
+
function clearDragRangeState() {
|
|
697
|
+
activeDragRange = null;
|
|
698
|
+
pendingRestore = null;
|
|
699
|
+
}
|
|
700
|
+
function remapPendingRestore(tr, state) {
|
|
701
|
+
if (!pendingRestore) {
|
|
702
|
+
return;
|
|
703
|
+
}
|
|
704
|
+
pendingRestore = mapPendingRestoreAnchor(pendingRestore, tr, {
|
|
705
|
+
isChangeOrigin: isChangeOrigin(tr),
|
|
706
|
+
getAbsolutePos: (relativePos) => getAbsolutePos(state, relativePos)
|
|
707
|
+
});
|
|
708
|
+
}
|
|
709
|
+
function buildRestoreTransaction(state) {
|
|
710
|
+
if (!pendingRestore) {
|
|
711
|
+
return null;
|
|
712
|
+
}
|
|
713
|
+
const nodeRangeSelection = createDroppedNodeRangeSelection(
|
|
714
|
+
state.doc,
|
|
715
|
+
pendingRestore.anchorPos,
|
|
716
|
+
pendingRestore.nodeCount,
|
|
717
|
+
pendingRestore.depth
|
|
718
|
+
);
|
|
719
|
+
if (!nodeRangeSelection) {
|
|
720
|
+
pendingRestore = null;
|
|
721
|
+
activeDragRange = null;
|
|
722
|
+
return null;
|
|
723
|
+
}
|
|
724
|
+
clearDragRangeState();
|
|
725
|
+
return state.tr.setSelection(nodeRangeSelection);
|
|
726
|
+
}
|
|
649
727
|
function hideHandle() {
|
|
650
728
|
if (!element) {
|
|
651
729
|
return;
|
|
@@ -704,17 +782,6 @@ var DragHandlePlugin = ({
|
|
|
704
782
|
element.dataset.dragging = "false";
|
|
705
783
|
}
|
|
706
784
|
}
|
|
707
|
-
function restoreNodeRangeSelection({ nodeCount, depth, anchorPos }) {
|
|
708
|
-
const nodeRangeSelection = createDroppedNodeRangeSelection(
|
|
709
|
-
editor.state.doc,
|
|
710
|
-
anchorPos,
|
|
711
|
-
nodeCount,
|
|
712
|
-
depth
|
|
713
|
-
);
|
|
714
|
-
if (nodeRangeSelection) {
|
|
715
|
-
editor.view.dispatch(editor.state.tr.setSelection(nodeRangeSelection));
|
|
716
|
-
}
|
|
717
|
-
}
|
|
718
785
|
function onDrop(e) {
|
|
719
786
|
if (!e.target || !editor.view.dom.contains(e.target)) {
|
|
720
787
|
return;
|
|
@@ -731,17 +798,14 @@ var DragHandlePlugin = ({
|
|
|
731
798
|
if (!activeDragRange || editor.view.state.selection.empty) {
|
|
732
799
|
return;
|
|
733
800
|
}
|
|
801
|
+
const anchorPos = editor.state.selection.from;
|
|
802
|
+
const relativeAnchorPos = getRelativePos(editor.state, anchorPos);
|
|
734
803
|
pendingRestore = {
|
|
735
804
|
...activeDragRange,
|
|
736
|
-
anchorPos
|
|
805
|
+
anchorPos,
|
|
806
|
+
relativeAnchorPos: relativeAnchorPos != null ? relativeAnchorPos : void 0
|
|
737
807
|
};
|
|
738
|
-
|
|
739
|
-
restoreRafId = null;
|
|
740
|
-
if (pendingRestore) {
|
|
741
|
-
restoreNodeRangeSelection(pendingRestore);
|
|
742
|
-
pendingRestore = null;
|
|
743
|
-
}
|
|
744
|
-
});
|
|
808
|
+
editor.view.dispatch(editor.state.tr.setMeta("addToHistory", false));
|
|
745
809
|
}
|
|
746
810
|
function cleanup() {
|
|
747
811
|
element.removeEventListener("dragstart", onDragStart);
|
|
@@ -752,10 +816,7 @@ var DragHandlePlugin = ({
|
|
|
752
816
|
rafId = null;
|
|
753
817
|
pendingMouseCoords = null;
|
|
754
818
|
}
|
|
755
|
-
|
|
756
|
-
cancelAnimationFrame(restoreRafId);
|
|
757
|
-
restoreRafId = null;
|
|
758
|
-
}
|
|
819
|
+
clearDragRangeState();
|
|
759
820
|
}
|
|
760
821
|
wrapper.appendChild(element);
|
|
761
822
|
return {
|
|
@@ -769,14 +830,7 @@ var DragHandlePlugin = ({
|
|
|
769
830
|
return { locked: false };
|
|
770
831
|
},
|
|
771
832
|
apply(tr, value, _oldState, state) {
|
|
772
|
-
|
|
773
|
-
const mappedResult = tr.mapping.mapResult(pendingRestore.anchorPos, 1);
|
|
774
|
-
if (mappedResult.deleted) {
|
|
775
|
-
pendingRestore = null;
|
|
776
|
-
} else {
|
|
777
|
-
pendingRestore.anchorPos = mappedResult.pos;
|
|
778
|
-
}
|
|
779
|
-
}
|
|
833
|
+
remapPendingRestore(tr, state);
|
|
780
834
|
const isLocked = tr.getMeta("lockDragHandle");
|
|
781
835
|
const hideDragHandle = tr.getMeta("hideDragHandle");
|
|
782
836
|
if (isLocked !== void 0) {
|
|
@@ -807,6 +861,9 @@ var DragHandlePlugin = ({
|
|
|
807
861
|
return value;
|
|
808
862
|
}
|
|
809
863
|
},
|
|
864
|
+
appendTransaction(_transactions, _oldState, newState) {
|
|
865
|
+
return buildRestoreTransaction(newState);
|
|
866
|
+
},
|
|
810
867
|
view: (view) => {
|
|
811
868
|
var _a;
|
|
812
869
|
element.draggable = true;
|
|
@@ -817,6 +874,7 @@ var DragHandlePlugin = ({
|
|
|
817
874
|
wrapper.style.position = "absolute";
|
|
818
875
|
wrapper.style.top = "0";
|
|
819
876
|
wrapper.style.left = "0";
|
|
877
|
+
wrapper.style.zIndex = "10";
|
|
820
878
|
element.addEventListener("dragstart", onDragStart);
|
|
821
879
|
element.addEventListener("dragend", onDragEnd);
|
|
822
880
|
document.addEventListener("drop", onDrop);
|