svelte-dnd-action 0.9.68 → 0.9.69

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/README.md CHANGED
@@ -120,6 +120,7 @@ An options-object with the following attributes:
120
120
  | `transformDraggedElement` | Function | No | `() => {}` | A function that is invoked when the draggable element enters the dnd-zone or hover overs a new index in the current dnd-zone. <br />Signature:<br />function(element, data, index) {}<br />**element**: The dragged element. <br />**data**: The data of the item from the items array.<br />**index**: The index the dragged element will become in the new dnd-zone.<br /><br />This allows you to override properties on the dragged element, such as innerHTML to change how it displays. If what you are after is altering styles, do it to the children, not to the dragged element itself |
121
121
  | `autoAriaDisabled` | Boolean | No | `false` | Setting it to true will disable all the automatically added aria attributes and aria alerts (for example when the user starts/ stops dragging using the keyboard).<br /> **Use it only if you intend to implement your own custom instructions, roles and alerts.** In such a case, you might find the exported function `alertToScreenReader(string)` useful. |
122
122
  | `centreDraggedOnCursor` | Boolean | No | `false` | Setting it to true will cause elements from this dnd-zone to position their center on the cursor on drag start, effectively turning the cursor to the focal point that triggers all the dnd events (ex: entering another zone). Useful for dnd-zones with large items that can be dragged over small items. |
123
+ | `useCursorForDetection` | Boolean | No | `false` | Setting it to true will use the cursor position instead of the dragged element's center for drop zone detection. This improves accuracy when dragging large elements over small drop targets. Unlike `centreDraggedOnCursor`, this option does not reposition the dragged element. |
123
124
  | `dropAnimationDisabled` | Boolean | No | `false` | Setting it to true will disable the animation of the dropped element to its final place. |
124
125
  | `delayTouchStart` | Boolean \| Number | No | `false` | Prevents accidental drags on touch devices that should have been scrolls.
125
126
  • `true` – enable with sensible default (80 ms).
package/dist/index.d.ts CHANGED
@@ -64,6 +64,10 @@ export interface Options<T extends Item = Item> {
64
64
  * false/undefined => drag starts instantly (legacy behaviour)
65
65
  */
66
66
  delayTouchStart?: boolean | number;
67
+ /**
68
+ * Use cursor position instead of dragged element center for drop zone detection
69
+ */
70
+ useCursorForDetection?: boolean;
67
71
  }
68
72
 
69
73
  export interface DndZoneAttributes<T> {
package/dist/index.js CHANGED
@@ -480,25 +480,14 @@
480
480
  }
481
481
 
482
482
  /**
483
- * @param {HTMLElement} elA
484
- * @param {HTMLElement} elB
485
- * @return {boolean}
486
- */
487
- function isCenterOfAInsideB(elA, elB) {
488
- var centerOfA = findCenterOfElement(elA);
489
- var rectOfB = getAbsoluteRectNoTransforms(elB);
490
- return isPointInsideRect(centerOfA, rectOfB);
491
- }
492
-
493
- /**
494
- * @param {HTMLElement|ChildNode} elA
495
- * @param {HTMLElement|ChildNode} elB
483
+ * Calculate distance from a point to the center of an element
484
+ * @param {{x: number, y: number}} point
485
+ * @param {HTMLElement|ChildNode} el
496
486
  * @return {number}
497
487
  */
498
- function calcDistanceBetweenCenters(elA, elB) {
499
- var centerOfA = findCenterOfElement(elA);
500
- var centerOfB = findCenterOfElement(elB);
501
- return calcDistance(centerOfA, centerOfB);
488
+ function calcDistanceFromPointToCenter(point, el) {
489
+ var centerOfEl = findCenterOfElement(el);
490
+ return calcDistance(point, centerOfEl);
502
491
  }
503
492
 
504
493
  /**
@@ -637,12 +626,13 @@
637
626
  */
638
627
  /**
639
628
  * Find the index for the dragged element in the list it is dragged over
640
- * @param {HTMLElement} floatingAboveEl
629
+ * @param {{x: number, y: number}} referencePoint - The reference point for detection (cursor position or element center)
641
630
  * @param {HTMLElement} collectionBelowEl
642
631
  * @returns {Index|null} - if the element is over the container the Index object otherwise null
643
632
  */
644
- function findWouldBeIndex(floatingAboveEl, collectionBelowEl) {
645
- if (!isCenterOfAInsideB(floatingAboveEl, collectionBelowEl)) {
633
+ function findWouldBeIndex(referencePoint, collectionBelowEl) {
634
+ var collectionRect = getAbsoluteRectNoTransforms(collectionBelowEl);
635
+ if (!isPointInsideRect(referencePoint, collectionRect)) {
646
636
  return null;
647
637
  }
648
638
  var children = collectionBelowEl.children;
@@ -658,10 +648,11 @@
658
648
  // the search could be more efficient but keeping it simple for now
659
649
  // a possible improvement: pass in the lastIndex it was found in and check there first, then expand from there
660
650
  for (var i = 0; i < children.length; i++) {
661
- if (isCenterOfAInsideB(floatingAboveEl, children[i])) {
651
+ var childRect = getAbsoluteRectNoTransforms(children[i]);
652
+ if (isPointInsideRect(referencePoint, childRect)) {
662
653
  var cachedShadowRect = dzToShadowIndexToRect.has(collectionBelowEl) && dzToShadowIndexToRect.get(collectionBelowEl).get(i);
663
654
  if (cachedShadowRect) {
664
- if (!isPointInsideRect(findCenterOfElement(floatingAboveEl), cachedShadowRect)) {
655
+ if (!isPointInsideRect(referencePoint, cachedShadowRect)) {
665
656
  return {
666
657
  index: shadowElIndex,
667
658
  isProximityBased: false
@@ -680,7 +671,7 @@
680
671
  var indexOfMin = undefined;
681
672
  // we are checking all of them because we don't know whether we are dealing with a horizontal or vertical container and where the floating element entered from
682
673
  for (var _i = 0; _i < children.length; _i++) {
683
- var distance = calcDistanceBetweenCenters(floatingAboveEl, children[_i]);
674
+ var distance = calcDistanceFromPointToCenter(referencePoint, children[_i]);
684
675
  if (distance < minDistanceSoFar) {
685
676
  minDistanceSoFar = distance;
686
677
  indexOfMin = _i;
@@ -705,7 +696,7 @@
705
696
  phantom.style.visibility = "hidden";
706
697
  phantom.style.pointerEvents = "none";
707
698
  collectionBelowEl.appendChild(phantom);
708
- var phantomDistance = calcDistanceBetweenCenters(floatingAboveEl, phantom);
699
+ var phantomDistance = calcDistanceFromPointToCenter(referencePoint, phantom);
709
700
  if (phantomDistance < minDistanceSoFar) {
710
701
  indexOfMin = originalLen; // index of phantom slot in original list
711
702
  }
@@ -791,10 +782,12 @@
791
782
  * @param {HTMLElement} draggedEl
792
783
  * @param {number} [intervalMs = INTERVAL_MS]
793
784
  * @param {MultiScroller} multiScroller
785
+ * @param {function(): {x: number, y: number}} getReferencePoint - Function that returns the reference point for detection (cursor or element center)
794
786
  */
795
787
  function observe(draggedEl, dropZones) {
796
788
  var intervalMs = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : INTERVAL_MS;
797
789
  var multiScroller = arguments.length > 3 ? arguments[3] : undefined;
790
+ var getReferencePoint = arguments.length > 4 ? arguments[4] : undefined;
798
791
  // initialization
799
792
  var lastDropZoneFound;
800
793
  var lastIndexFound;
@@ -809,10 +802,10 @@
809
802
  * The main function in this module. Tracks where everything is/ should be a take the actions
810
803
  */
811
804
  function andNow() {
812
- var currentCenterOfDragged = findCenterOfElement(draggedEl);
805
+ var referencePoint = getReferencePoint();
813
806
  var scrolled = multiScroller.multiScrollIfNeeded();
814
807
  // we only want to make a new decision after the element was moved a bit to prevent flickering
815
- if (!scrolled && lastCentrePositionOfDragged && Math.abs(lastCentrePositionOfDragged.x - currentCenterOfDragged.x) < TOLERANCE_PX && Math.abs(lastCentrePositionOfDragged.y - currentCenterOfDragged.y) < TOLERANCE_PX) {
808
+ if (!scrolled && lastCentrePositionOfDragged && Math.abs(lastCentrePositionOfDragged.x - referencePoint.x) < TOLERANCE_PX && Math.abs(lastCentrePositionOfDragged.y - referencePoint.y) < TOLERANCE_PX) {
816
809
  next = window.setTimeout(andNow, intervalMs);
817
810
  return;
818
811
  }
@@ -823,7 +816,7 @@
823
816
  dispatchDraggedLeftDocument(draggedEl);
824
817
  return;
825
818
  }
826
- lastCentrePositionOfDragged = currentCenterOfDragged;
819
+ lastCentrePositionOfDragged = referencePoint;
827
820
  // this is a simple algorithm, potential improvement: first look at lastDropZoneFound
828
821
  var isDraggedInADropZone = false;
829
822
  var _iterator = _createForOfIteratorHelper(dropZonesFromDeepToShallow),
@@ -832,7 +825,7 @@
832
825
  for (_iterator.s(); !(_step = _iterator.n()).done;) {
833
826
  var dz = _step.value;
834
827
  if (scrolled) resetIndexesCache();
835
- var indexObj = findWouldBeIndex(draggedEl, dz);
828
+ var indexObj = findWouldBeIndex(referencePoint, dz);
836
829
  if (indexObj === null) {
837
830
  // it is not inside
838
831
  continue;
@@ -1419,6 +1412,7 @@
1419
1412
  var multiScroller;
1420
1413
  var touchDragHoldTimer;
1421
1414
  var touchHoldElapsed = false;
1415
+ var useCursorForDetectionActive = false;
1422
1416
 
1423
1417
  // a map from type to a set of drop-zones
1424
1418
  var typeToDropZones$1 = new Map();
@@ -1478,7 +1472,16 @@
1478
1472
  multiScroller = createMultiScroller(dropZones, function () {
1479
1473
  return currentMousePosition;
1480
1474
  });
1481
- observe(draggedEl, dropZones, observationIntervalMs * 1.07, multiScroller);
1475
+ // Returns reference point in document coordinates - either cursor position or element center
1476
+ var getReferencePoint = useCursorForDetectionActive ? function () {
1477
+ return {
1478
+ x: currentMousePosition.x + window.scrollX,
1479
+ y: currentMousePosition.y + window.scrollY
1480
+ };
1481
+ } : function () {
1482
+ return findCenterOfElement(draggedEl);
1483
+ };
1484
+ observe(draggedEl, dropZones, observationIntervalMs * 1.07, multiScroller, getReferencePoint);
1482
1485
  }
1483
1486
  function unWatchDraggedElement() {
1484
1487
  printDebug(function () {
@@ -1764,6 +1767,7 @@
1764
1767
  }
1765
1768
  touchDragHoldTimer = undefined;
1766
1769
  touchHoldElapsed = false;
1770
+ useCursorForDetectionActive = false;
1767
1771
  if (scheduledForRemovalAfterDrop.length) {
1768
1772
  printDebug(function () {
1769
1773
  return ["will destroy zones that were removed during drag", scheduledForRemovalAfterDrop];
@@ -1790,6 +1794,7 @@
1790
1794
  dropTargetClasses: [],
1791
1795
  transformDraggedElement: function transformDraggedElement() {},
1792
1796
  centreDraggedOnCursor: false,
1797
+ useCursorForDetection: false,
1793
1798
  dropAnimationDisabled: false,
1794
1799
  delayTouchStartMs: 0
1795
1800
  };
@@ -1935,11 +1940,13 @@
1935
1940
  var originDropZoneRoot = rootNode.body || rootNode;
1936
1941
  var originalItems = config.items,
1937
1942
  type = config.type,
1938
- centreDraggedOnCursor = config.centreDraggedOnCursor;
1943
+ centreDraggedOnCursor = config.centreDraggedOnCursor,
1944
+ useCursorForDetection = config.useCursorForDetection;
1939
1945
  var items = _toConsumableArray(originalItems);
1940
1946
  draggedElData = items[currentIdx];
1941
1947
  draggedElType = type;
1942
1948
  shadowElData = createShadowElData(draggedElData);
1949
+ useCursorForDetectionActive = useCursorForDetection;
1943
1950
 
1944
1951
  // creating the draggable element
1945
1952
  draggedEl = createDraggedElementFrom(originalDragTarget, centreDraggedOnCursor && currentMousePosition);
@@ -2014,6 +2021,8 @@
2014
2021
  transformDraggedElement = _ref2$transformDragge === void 0 ? function () {} : _ref2$transformDragge,
2015
2022
  _ref2$centreDraggedOn = _ref2.centreDraggedOnCursor,
2016
2023
  centreDraggedOnCursor = _ref2$centreDraggedOn === void 0 ? false : _ref2$centreDraggedOn,
2024
+ _ref2$useCursorForDet = _ref2.useCursorForDetection,
2025
+ useCursorForDetection = _ref2$useCursorForDet === void 0 ? false : _ref2$useCursorForDet,
2017
2026
  _ref2$dropAnimationDi = _ref2.dropAnimationDisabled,
2018
2027
  dropAnimationDisabled = _ref2$dropAnimationDi === void 0 ? false : _ref2$dropAnimationDi,
2019
2028
  _ref2$delayTouchStart = _ref2.delayTouchStart,
@@ -2035,6 +2044,7 @@
2035
2044
  config.morphDisabled = morphDisabled;
2036
2045
  config.transformDraggedElement = transformDraggedElement;
2037
2046
  config.centreDraggedOnCursor = centreDraggedOnCursor;
2047
+ config.useCursorForDetection = useCursorForDetection;
2038
2048
  config.dropAnimationDisabled = dropAnimationDisabled;
2039
2049
 
2040
2050
  // realtime update for dropTargetStyle
@@ -2626,7 +2636,7 @@
2626
2636
  return handles;
2627
2637
  }
2628
2638
 
2629
- var _excluded = ["items", "flipDurationMs", "type", "dragDisabled", "morphDisabled", "dropFromOthersDisabled", "zoneTabIndex", "zoneItemTabIndex", "dropTargetStyle", "dropTargetClasses", "transformDraggedElement", "autoAriaDisabled", "centreDraggedOnCursor", "delayTouchStart", "dropAnimationDisabled"];
2639
+ var _excluded = ["items", "flipDurationMs", "type", "dragDisabled", "morphDisabled", "dropFromOthersDisabled", "zoneTabIndex", "zoneItemTabIndex", "dropTargetStyle", "dropTargetClasses", "transformDraggedElement", "autoAriaDisabled", "centreDraggedOnCursor", "useCursorForDetection", "delayTouchStart", "dropAnimationDisabled"];
2630
2640
 
2631
2641
  /**
2632
2642
  * A custom action to turn any container to a dnd zone and all of its direct children to draggables
@@ -2700,6 +2710,7 @@
2700
2710
  options.transformDraggedElement;
2701
2711
  options.autoAriaDisabled;
2702
2712
  options.centreDraggedOnCursor;
2713
+ options.useCursorForDetection;
2703
2714
  var delayTouchStart = options.delayTouchStart;
2704
2715
  options.dropAnimationDisabled;
2705
2716
  var rest = _objectWithoutProperties(options, _excluded);
package/dist/index.mjs CHANGED
@@ -474,25 +474,14 @@ function findCenterOfElement(el) {
474
474
  }
475
475
 
476
476
  /**
477
- * @param {HTMLElement} elA
478
- * @param {HTMLElement} elB
479
- * @return {boolean}
480
- */
481
- function isCenterOfAInsideB(elA, elB) {
482
- var centerOfA = findCenterOfElement(elA);
483
- var rectOfB = getAbsoluteRectNoTransforms(elB);
484
- return isPointInsideRect(centerOfA, rectOfB);
485
- }
486
-
487
- /**
488
- * @param {HTMLElement|ChildNode} elA
489
- * @param {HTMLElement|ChildNode} elB
477
+ * Calculate distance from a point to the center of an element
478
+ * @param {{x: number, y: number}} point
479
+ * @param {HTMLElement|ChildNode} el
490
480
  * @return {number}
491
481
  */
492
- function calcDistanceBetweenCenters(elA, elB) {
493
- var centerOfA = findCenterOfElement(elA);
494
- var centerOfB = findCenterOfElement(elB);
495
- return calcDistance(centerOfA, centerOfB);
482
+ function calcDistanceFromPointToCenter(point, el) {
483
+ var centerOfEl = findCenterOfElement(el);
484
+ return calcDistance(point, centerOfEl);
496
485
  }
497
486
 
498
487
  /**
@@ -631,12 +620,13 @@ function cacheShadowRect(dz) {
631
620
  */
632
621
  /**
633
622
  * Find the index for the dragged element in the list it is dragged over
634
- * @param {HTMLElement} floatingAboveEl
623
+ * @param {{x: number, y: number}} referencePoint - The reference point for detection (cursor position or element center)
635
624
  * @param {HTMLElement} collectionBelowEl
636
625
  * @returns {Index|null} - if the element is over the container the Index object otherwise null
637
626
  */
638
- function findWouldBeIndex(floatingAboveEl, collectionBelowEl) {
639
- if (!isCenterOfAInsideB(floatingAboveEl, collectionBelowEl)) {
627
+ function findWouldBeIndex(referencePoint, collectionBelowEl) {
628
+ var collectionRect = getAbsoluteRectNoTransforms(collectionBelowEl);
629
+ if (!isPointInsideRect(referencePoint, collectionRect)) {
640
630
  return null;
641
631
  }
642
632
  var children = collectionBelowEl.children;
@@ -652,10 +642,11 @@ function findWouldBeIndex(floatingAboveEl, collectionBelowEl) {
652
642
  // the search could be more efficient but keeping it simple for now
653
643
  // a possible improvement: pass in the lastIndex it was found in and check there first, then expand from there
654
644
  for (var i = 0; i < children.length; i++) {
655
- if (isCenterOfAInsideB(floatingAboveEl, children[i])) {
645
+ var childRect = getAbsoluteRectNoTransforms(children[i]);
646
+ if (isPointInsideRect(referencePoint, childRect)) {
656
647
  var cachedShadowRect = dzToShadowIndexToRect.has(collectionBelowEl) && dzToShadowIndexToRect.get(collectionBelowEl).get(i);
657
648
  if (cachedShadowRect) {
658
- if (!isPointInsideRect(findCenterOfElement(floatingAboveEl), cachedShadowRect)) {
649
+ if (!isPointInsideRect(referencePoint, cachedShadowRect)) {
659
650
  return {
660
651
  index: shadowElIndex,
661
652
  isProximityBased: false
@@ -674,7 +665,7 @@ function findWouldBeIndex(floatingAboveEl, collectionBelowEl) {
674
665
  var indexOfMin = undefined;
675
666
  // we are checking all of them because we don't know whether we are dealing with a horizontal or vertical container and where the floating element entered from
676
667
  for (var _i = 0; _i < children.length; _i++) {
677
- var distance = calcDistanceBetweenCenters(floatingAboveEl, children[_i]);
668
+ var distance = calcDistanceFromPointToCenter(referencePoint, children[_i]);
678
669
  if (distance < minDistanceSoFar) {
679
670
  minDistanceSoFar = distance;
680
671
  indexOfMin = _i;
@@ -699,7 +690,7 @@ function findWouldBeIndex(floatingAboveEl, collectionBelowEl) {
699
690
  phantom.style.visibility = "hidden";
700
691
  phantom.style.pointerEvents = "none";
701
692
  collectionBelowEl.appendChild(phantom);
702
- var phantomDistance = calcDistanceBetweenCenters(floatingAboveEl, phantom);
693
+ var phantomDistance = calcDistanceFromPointToCenter(referencePoint, phantom);
703
694
  if (phantomDistance < minDistanceSoFar) {
704
695
  indexOfMin = originalLen; // index of phantom slot in original list
705
696
  }
@@ -785,10 +776,12 @@ var next;
785
776
  * @param {HTMLElement} draggedEl
786
777
  * @param {number} [intervalMs = INTERVAL_MS]
787
778
  * @param {MultiScroller} multiScroller
779
+ * @param {function(): {x: number, y: number}} getReferencePoint - Function that returns the reference point for detection (cursor or element center)
788
780
  */
789
781
  function observe(draggedEl, dropZones) {
790
782
  var intervalMs = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : INTERVAL_MS;
791
783
  var multiScroller = arguments.length > 3 ? arguments[3] : undefined;
784
+ var getReferencePoint = arguments.length > 4 ? arguments[4] : undefined;
792
785
  // initialization
793
786
  var lastDropZoneFound;
794
787
  var lastIndexFound;
@@ -803,10 +796,10 @@ function observe(draggedEl, dropZones) {
803
796
  * The main function in this module. Tracks where everything is/ should be a take the actions
804
797
  */
805
798
  function andNow() {
806
- var currentCenterOfDragged = findCenterOfElement(draggedEl);
799
+ var referencePoint = getReferencePoint();
807
800
  var scrolled = multiScroller.multiScrollIfNeeded();
808
801
  // we only want to make a new decision after the element was moved a bit to prevent flickering
809
- if (!scrolled && lastCentrePositionOfDragged && Math.abs(lastCentrePositionOfDragged.x - currentCenterOfDragged.x) < TOLERANCE_PX && Math.abs(lastCentrePositionOfDragged.y - currentCenterOfDragged.y) < TOLERANCE_PX) {
802
+ if (!scrolled && lastCentrePositionOfDragged && Math.abs(lastCentrePositionOfDragged.x - referencePoint.x) < TOLERANCE_PX && Math.abs(lastCentrePositionOfDragged.y - referencePoint.y) < TOLERANCE_PX) {
810
803
  next = window.setTimeout(andNow, intervalMs);
811
804
  return;
812
805
  }
@@ -817,7 +810,7 @@ function observe(draggedEl, dropZones) {
817
810
  dispatchDraggedLeftDocument(draggedEl);
818
811
  return;
819
812
  }
820
- lastCentrePositionOfDragged = currentCenterOfDragged;
813
+ lastCentrePositionOfDragged = referencePoint;
821
814
  // this is a simple algorithm, potential improvement: first look at lastDropZoneFound
822
815
  var isDraggedInADropZone = false;
823
816
  var _iterator = _createForOfIteratorHelper(dropZonesFromDeepToShallow),
@@ -826,7 +819,7 @@ function observe(draggedEl, dropZones) {
826
819
  for (_iterator.s(); !(_step = _iterator.n()).done;) {
827
820
  var dz = _step.value;
828
821
  if (scrolled) resetIndexesCache();
829
- var indexObj = findWouldBeIndex(draggedEl, dz);
822
+ var indexObj = findWouldBeIndex(referencePoint, dz);
830
823
  if (indexObj === null) {
831
824
  // it is not inside
832
825
  continue;
@@ -1413,6 +1406,7 @@ var scheduledForRemovalAfterDrop = [];
1413
1406
  var multiScroller;
1414
1407
  var touchDragHoldTimer;
1415
1408
  var touchHoldElapsed = false;
1409
+ var useCursorForDetectionActive = false;
1416
1410
 
1417
1411
  // a map from type to a set of drop-zones
1418
1412
  var typeToDropZones$1 = new Map();
@@ -1472,7 +1466,16 @@ function watchDraggedElement() {
1472
1466
  multiScroller = createMultiScroller(dropZones, function () {
1473
1467
  return currentMousePosition;
1474
1468
  });
1475
- observe(draggedEl, dropZones, observationIntervalMs * 1.07, multiScroller);
1469
+ // Returns reference point in document coordinates - either cursor position or element center
1470
+ var getReferencePoint = useCursorForDetectionActive ? function () {
1471
+ return {
1472
+ x: currentMousePosition.x + window.scrollX,
1473
+ y: currentMousePosition.y + window.scrollY
1474
+ };
1475
+ } : function () {
1476
+ return findCenterOfElement(draggedEl);
1477
+ };
1478
+ observe(draggedEl, dropZones, observationIntervalMs * 1.07, multiScroller, getReferencePoint);
1476
1479
  }
1477
1480
  function unWatchDraggedElement() {
1478
1481
  printDebug(function () {
@@ -1758,6 +1761,7 @@ function cleanupPostDrop() {
1758
1761
  }
1759
1762
  touchDragHoldTimer = undefined;
1760
1763
  touchHoldElapsed = false;
1764
+ useCursorForDetectionActive = false;
1761
1765
  if (scheduledForRemovalAfterDrop.length) {
1762
1766
  printDebug(function () {
1763
1767
  return ["will destroy zones that were removed during drag", scheduledForRemovalAfterDrop];
@@ -1784,6 +1788,7 @@ function dndzone$2(node, options) {
1784
1788
  dropTargetClasses: [],
1785
1789
  transformDraggedElement: function transformDraggedElement() {},
1786
1790
  centreDraggedOnCursor: false,
1791
+ useCursorForDetection: false,
1787
1792
  dropAnimationDisabled: false,
1788
1793
  delayTouchStartMs: 0
1789
1794
  };
@@ -1929,11 +1934,13 @@ function dndzone$2(node, options) {
1929
1934
  var originDropZoneRoot = rootNode.body || rootNode;
1930
1935
  var originalItems = config.items,
1931
1936
  type = config.type,
1932
- centreDraggedOnCursor = config.centreDraggedOnCursor;
1937
+ centreDraggedOnCursor = config.centreDraggedOnCursor,
1938
+ useCursorForDetection = config.useCursorForDetection;
1933
1939
  var items = _toConsumableArray(originalItems);
1934
1940
  draggedElData = items[currentIdx];
1935
1941
  draggedElType = type;
1936
1942
  shadowElData = createShadowElData(draggedElData);
1943
+ useCursorForDetectionActive = useCursorForDetection;
1937
1944
 
1938
1945
  // creating the draggable element
1939
1946
  draggedEl = createDraggedElementFrom(originalDragTarget, centreDraggedOnCursor && currentMousePosition);
@@ -2008,6 +2015,8 @@ function dndzone$2(node, options) {
2008
2015
  transformDraggedElement = _ref2$transformDragge === void 0 ? function () {} : _ref2$transformDragge,
2009
2016
  _ref2$centreDraggedOn = _ref2.centreDraggedOnCursor,
2010
2017
  centreDraggedOnCursor = _ref2$centreDraggedOn === void 0 ? false : _ref2$centreDraggedOn,
2018
+ _ref2$useCursorForDet = _ref2.useCursorForDetection,
2019
+ useCursorForDetection = _ref2$useCursorForDet === void 0 ? false : _ref2$useCursorForDet,
2011
2020
  _ref2$dropAnimationDi = _ref2.dropAnimationDisabled,
2012
2021
  dropAnimationDisabled = _ref2$dropAnimationDi === void 0 ? false : _ref2$dropAnimationDi,
2013
2022
  _ref2$delayTouchStart = _ref2.delayTouchStart,
@@ -2029,6 +2038,7 @@ function dndzone$2(node, options) {
2029
2038
  config.morphDisabled = morphDisabled;
2030
2039
  config.transformDraggedElement = transformDraggedElement;
2031
2040
  config.centreDraggedOnCursor = centreDraggedOnCursor;
2041
+ config.useCursorForDetection = useCursorForDetection;
2032
2042
  config.dropAnimationDisabled = dropAnimationDisabled;
2033
2043
 
2034
2044
  // realtime update for dropTargetStyle
@@ -2620,7 +2630,7 @@ function dndzone$1(node, options) {
2620
2630
  return handles;
2621
2631
  }
2622
2632
 
2623
- var _excluded = ["items", "flipDurationMs", "type", "dragDisabled", "morphDisabled", "dropFromOthersDisabled", "zoneTabIndex", "zoneItemTabIndex", "dropTargetStyle", "dropTargetClasses", "transformDraggedElement", "autoAriaDisabled", "centreDraggedOnCursor", "delayTouchStart", "dropAnimationDisabled"];
2633
+ var _excluded = ["items", "flipDurationMs", "type", "dragDisabled", "morphDisabled", "dropFromOthersDisabled", "zoneTabIndex", "zoneItemTabIndex", "dropTargetStyle", "dropTargetClasses", "transformDraggedElement", "autoAriaDisabled", "centreDraggedOnCursor", "useCursorForDetection", "delayTouchStart", "dropAnimationDisabled"];
2624
2634
 
2625
2635
  /**
2626
2636
  * A custom action to turn any container to a dnd zone and all of its direct children to draggables
@@ -2694,6 +2704,7 @@ function validateOptions(options) {
2694
2704
  options.transformDraggedElement;
2695
2705
  options.autoAriaDisabled;
2696
2706
  options.centreDraggedOnCursor;
2707
+ options.useCursorForDetection;
2697
2708
  var delayTouchStart = options.delayTouchStart;
2698
2709
  options.dropAnimationDisabled;
2699
2710
  var rest = _objectWithoutProperties(options, _excluded);
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "svelte-dnd-action",
3
3
  "description": "*An awesome drag and drop library for Svelte 3 and 4 (not using the browser's built-in dnd, thanks god): Rich animations, nested containers, touch support and more *",
4
- "version": "0.9.68",
4
+ "version": "0.9.69",
5
5
  "repository": {
6
6
  "type": "git",
7
7
  "url": "git+https://github.com/isaacHagoel/svelte-dnd-action.git"
package/src/action.js CHANGED
@@ -77,6 +77,7 @@ function validateOptions(options) {
77
77
  transformDraggedElement,
78
78
  autoAriaDisabled,
79
79
  centreDraggedOnCursor,
80
+ useCursorForDetection,
80
81
  delayTouchStart,
81
82
  dropAnimationDisabled,
82
83
  ...rest
@@ -128,25 +128,14 @@ export function findCenterOfElement(el) {
128
128
  }
129
129
 
130
130
  /**
131
- * @param {HTMLElement} elA
132
- * @param {HTMLElement} elB
133
- * @return {boolean}
134
- */
135
- export function isCenterOfAInsideB(elA, elB) {
136
- const centerOfA = findCenterOfElement(elA);
137
- const rectOfB = getAbsoluteRectNoTransforms(elB);
138
- return isPointInsideRect(centerOfA, rectOfB);
139
- }
140
-
141
- /**
142
- * @param {HTMLElement|ChildNode} elA
143
- * @param {HTMLElement|ChildNode} elB
131
+ * Calculate distance from a point to the center of an element
132
+ * @param {{x: number, y: number}} point
133
+ * @param {HTMLElement|ChildNode} el
144
134
  * @return {number}
145
135
  */
146
- export function calcDistanceBetweenCenters(elA, elB) {
147
- const centerOfA = findCenterOfElement(elA);
148
- const centerOfB = findCenterOfElement(elB);
149
- return calcDistance(centerOfA, centerOfB);
136
+ export function calcDistanceFromPointToCenter(point, el) {
137
+ const centerOfEl = findCenterOfElement(el);
138
+ return calcDistance(point, centerOfEl);
150
139
  }
151
140
 
152
141
  /**
@@ -1,4 +1,4 @@
1
- import {isCenterOfAInsideB, calcDistanceBetweenCenters, getAbsoluteRectNoTransforms, isPointInsideRect, findCenterOfElement} from "./intersection";
1
+ import {getAbsoluteRectNoTransforms, isPointInsideRect, calcDistanceFromPointToCenter} from "./intersection";
2
2
  import {printDebug, SHADOW_ELEMENT_ATTRIBUTE_NAME} from "../constants";
3
3
 
4
4
  let dzToShadowIndexToRect;
@@ -37,14 +37,16 @@ function cacheShadowRect(dz) {
37
37
  */
38
38
  /**
39
39
  * Find the index for the dragged element in the list it is dragged over
40
- * @param {HTMLElement} floatingAboveEl
40
+ * @param {{x: number, y: number}} referencePoint - The reference point for detection (cursor position or element center)
41
41
  * @param {HTMLElement} collectionBelowEl
42
42
  * @returns {Index|null} - if the element is over the container the Index object otherwise null
43
43
  */
44
- export function findWouldBeIndex(floatingAboveEl, collectionBelowEl) {
45
- if (!isCenterOfAInsideB(floatingAboveEl, collectionBelowEl)) {
44
+ export function findWouldBeIndex(referencePoint, collectionBelowEl) {
45
+ const collectionRect = getAbsoluteRectNoTransforms(collectionBelowEl);
46
+ if (!isPointInsideRect(referencePoint, collectionRect)) {
46
47
  return null;
47
48
  }
49
+
48
50
  const children = collectionBelowEl.children;
49
51
  // the container is empty, floating element should be the first
50
52
  if (children.length === 0) {
@@ -55,10 +57,11 @@ export function findWouldBeIndex(floatingAboveEl, collectionBelowEl) {
55
57
  // the search could be more efficient but keeping it simple for now
56
58
  // a possible improvement: pass in the lastIndex it was found in and check there first, then expand from there
57
59
  for (let i = 0; i < children.length; i++) {
58
- if (isCenterOfAInsideB(floatingAboveEl, children[i])) {
60
+ const childRect = getAbsoluteRectNoTransforms(children[i]);
61
+ if (isPointInsideRect(referencePoint, childRect)) {
59
62
  const cachedShadowRect = dzToShadowIndexToRect.has(collectionBelowEl) && dzToShadowIndexToRect.get(collectionBelowEl).get(i);
60
63
  if (cachedShadowRect) {
61
- if (!isPointInsideRect(findCenterOfElement(floatingAboveEl), cachedShadowRect)) {
64
+ if (!isPointInsideRect(referencePoint, cachedShadowRect)) {
62
65
  return {index: shadowElIndex, isProximityBased: false};
63
66
  }
64
67
  }
@@ -71,7 +74,7 @@ export function findWouldBeIndex(floatingAboveEl, collectionBelowEl) {
71
74
  let indexOfMin = undefined;
72
75
  // we are checking all of them because we don't know whether we are dealing with a horizontal or vertical container and where the floating element entered from
73
76
  for (let i = 0; i < children.length; i++) {
74
- const distance = calcDistanceBetweenCenters(floatingAboveEl, children[i]);
77
+ const distance = calcDistanceFromPointToCenter(referencePoint, children[i]);
75
78
  if (distance < minDistanceSoFar) {
76
79
  minDistanceSoFar = distance;
77
80
  indexOfMin = i;
@@ -97,7 +100,7 @@ export function findWouldBeIndex(floatingAboveEl, collectionBelowEl) {
97
100
  phantom.style.pointerEvents = "none";
98
101
  collectionBelowEl.appendChild(phantom);
99
102
 
100
- const phantomDistance = calcDistanceBetweenCenters(floatingAboveEl, phantom);
103
+ const phantomDistance = calcDistanceFromPointToCenter(referencePoint, phantom);
101
104
  if (phantomDistance < minDistanceSoFar) {
102
105
  indexOfMin = originalLen; // index of phantom slot in original list
103
106
  }
@@ -1,5 +1,5 @@
1
1
  import {findWouldBeIndex, resetIndexesCache} from "./listUtil";
2
- import {findCenterOfElement, isElementOffDocument} from "./intersection";
2
+ import {isElementOffDocument} from "./intersection";
3
3
  import {
4
4
  dispatchDraggedElementEnteredContainer,
5
5
  dispatchDraggedElementLeftContainerForAnother,
@@ -20,8 +20,9 @@ let next;
20
20
  * @param {HTMLElement} draggedEl
21
21
  * @param {number} [intervalMs = INTERVAL_MS]
22
22
  * @param {MultiScroller} multiScroller
23
+ * @param {function(): {x: number, y: number}} getReferencePoint - Function that returns the reference point for detection (cursor or element center)
23
24
  */
24
- export function observe(draggedEl, dropZones, intervalMs = INTERVAL_MS, multiScroller) {
25
+ export function observe(draggedEl, dropZones, intervalMs = INTERVAL_MS, multiScroller, getReferencePoint) {
25
26
  // initialization
26
27
  let lastDropZoneFound;
27
28
  let lastIndexFound;
@@ -34,14 +35,14 @@ export function observe(draggedEl, dropZones, intervalMs = INTERVAL_MS, multiScr
34
35
  * The main function in this module. Tracks where everything is/ should be a take the actions
35
36
  */
36
37
  function andNow() {
37
- const currentCenterOfDragged = findCenterOfElement(draggedEl);
38
+ const referencePoint = getReferencePoint();
38
39
  const scrolled = multiScroller.multiScrollIfNeeded();
39
40
  // we only want to make a new decision after the element was moved a bit to prevent flickering
40
41
  if (
41
42
  !scrolled &&
42
43
  lastCentrePositionOfDragged &&
43
- Math.abs(lastCentrePositionOfDragged.x - currentCenterOfDragged.x) < TOLERANCE_PX &&
44
- Math.abs(lastCentrePositionOfDragged.y - currentCenterOfDragged.y) < TOLERANCE_PX
44
+ Math.abs(lastCentrePositionOfDragged.x - referencePoint.x) < TOLERANCE_PX &&
45
+ Math.abs(lastCentrePositionOfDragged.y - referencePoint.y) < TOLERANCE_PX
45
46
  ) {
46
47
  next = window.setTimeout(andNow, intervalMs);
47
48
  return;
@@ -52,12 +53,12 @@ export function observe(draggedEl, dropZones, intervalMs = INTERVAL_MS, multiScr
52
53
  return;
53
54
  }
54
55
 
55
- lastCentrePositionOfDragged = currentCenterOfDragged;
56
+ lastCentrePositionOfDragged = referencePoint;
56
57
  // this is a simple algorithm, potential improvement: first look at lastDropZoneFound
57
58
  let isDraggedInADropZone = false;
58
59
  for (const dz of dropZonesFromDeepToShallow) {
59
60
  if (scrolled) resetIndexesCache();
60
- const indexObj = findWouldBeIndex(draggedEl, dz);
61
+ const indexObj = findWouldBeIndex(referencePoint, dz);
61
62
  if (indexObj === null) {
62
63
  // it is not inside
63
64
  continue;
@@ -33,7 +33,7 @@ import {
33
33
  DRAGGED_OVER_INDEX_EVENT_NAME
34
34
  } from "./helpers/dispatcher";
35
35
  import {areArraysShallowEqualSameOrder, areObjectsShallowEqual, toString} from "./helpers/util";
36
- import {getBoundingRectNoTransforms} from "./helpers/intersection";
36
+ import {getBoundingRectNoTransforms, findCenterOfElement} from "./helpers/intersection";
37
37
 
38
38
  const DEFAULT_DROP_ZONE_TYPE = "--any--";
39
39
  const MIN_OBSERVATION_INTERVAL_MS = 100;
@@ -63,6 +63,7 @@ let scheduledForRemovalAfterDrop = [];
63
63
  let multiScroller;
64
64
  let touchDragHoldTimer;
65
65
  let touchHoldElapsed = false;
66
+ let useCursorForDetectionActive = false;
66
67
 
67
68
  // a map from type to a set of drop-zones
68
69
  const typeToDropZones = new Map();
@@ -106,7 +107,14 @@ function watchDraggedElement() {
106
107
  const setIntervalMs = Math.max(...Array.from(dropZones.keys()).map(dz => dzToConfig.get(dz).dropAnimationDurationMs));
107
108
  const observationIntervalMs = setIntervalMs === 0 ? DISABLED_OBSERVATION_INTERVAL_MS : Math.max(setIntervalMs, MIN_OBSERVATION_INTERVAL_MS); // if setIntervalMs is 0 it goes to 20, otherwise it is max between it and min observation.
108
109
  multiScroller = createMultiScroller(dropZones, () => currentMousePosition);
109
- observe(draggedEl, dropZones, observationIntervalMs * 1.07, multiScroller);
110
+ // Returns reference point in document coordinates - either cursor position or element center
111
+ const getReferencePoint = useCursorForDetectionActive
112
+ ? () => ({
113
+ x: currentMousePosition.x + window.scrollX,
114
+ y: currentMousePosition.y + window.scrollY
115
+ })
116
+ : () => findCenterOfElement(draggedEl);
117
+ observe(draggedEl, dropZones, observationIntervalMs * 1.07, multiScroller, getReferencePoint);
110
118
  }
111
119
  function unWatchDraggedElement() {
112
120
  printDebug(() => "unwatching dragged element");
@@ -339,6 +347,7 @@ function cleanupPostDrop() {
339
347
  }
340
348
  touchDragHoldTimer = undefined;
341
349
  touchHoldElapsed = false;
350
+ useCursorForDetectionActive = false;
342
351
  if (scheduledForRemovalAfterDrop.length) {
343
352
  printDebug(() => ["will destroy zones that were removed during drag", scheduledForRemovalAfterDrop]);
344
353
  scheduledForRemovalAfterDrop.forEach(({dz, destroy}) => {
@@ -362,6 +371,7 @@ export function dndzone(node, options) {
362
371
  dropTargetClasses: [],
363
372
  transformDraggedElement: () => {},
364
373
  centreDraggedOnCursor: false,
374
+ useCursorForDetection: false,
365
375
  dropAnimationDisabled: false,
366
376
  delayTouchStartMs: 0
367
377
  };
@@ -489,11 +499,12 @@ export function dndzone(node, options) {
489
499
  /** @type {ShadowRoot | HTMLDocument | Element } */
490
500
  const rootNode = originDropZone.closest("dialog") || originDropZone.closest("[popover]") || originDropZone.getRootNode();
491
501
  const originDropZoneRoot = rootNode.body || rootNode;
492
- const {items: originalItems, type, centreDraggedOnCursor} = config;
502
+ const {items: originalItems, type, centreDraggedOnCursor, useCursorForDetection} = config;
493
503
  const items = [...originalItems];
494
504
  draggedElData = items[currentIdx];
495
505
  draggedElType = type;
496
506
  shadowElData = createShadowElData(draggedElData);
507
+ useCursorForDetectionActive = useCursorForDetection;
497
508
 
498
509
  // creating the draggable element
499
510
  draggedEl = createDraggedElementFrom(originalDragTarget, centreDraggedOnCursor && currentMousePosition);
@@ -546,6 +557,7 @@ export function dndzone(node, options) {
546
557
  dropTargetClasses = [],
547
558
  transformDraggedElement = () => {},
548
559
  centreDraggedOnCursor = false,
560
+ useCursorForDetection = false,
549
561
  dropAnimationDisabled = false,
550
562
  delayTouchStart: delayTouchStartOpt = false
551
563
  }) {
@@ -568,6 +580,7 @@ export function dndzone(node, options) {
568
580
  config.morphDisabled = morphDisabled;
569
581
  config.transformDraggedElement = transformDraggedElement;
570
582
  config.centreDraggedOnCursor = centreDraggedOnCursor;
583
+ config.useCursorForDetection = useCursorForDetection;
571
584
  config.dropAnimationDisabled = dropAnimationDisabled;
572
585
 
573
586
  // realtime update for dropTargetStyle