svelte-dnd-action 0.9.39 → 0.9.41
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 +17 -15
- package/dist/index.d.ts +16 -5
- package/dist/index.js +213 -175
- package/dist/index.mjs +213 -175
- package/package.json +1 -1
- package/src/helpers/intersection.js +1 -21
- package/src/helpers/listUtil.js +0 -9
- package/src/helpers/multiScroller.js +74 -0
- package/src/helpers/observer.js +5 -7
- package/src/helpers/scroller.js +36 -2
- package/src/pointerAction.js +6 -5
- package/src/helpers/windowScroller.js +0 -48
package/dist/index.mjs
CHANGED
|
@@ -495,33 +495,13 @@ function calcDistanceBetweenCenters(elA, elB) {
|
|
|
495
495
|
|
|
496
496
|
/**
|
|
497
497
|
* @param {HTMLElement} el - the element to check
|
|
498
|
-
* @returns {boolean} - true if the element in its entirety is off
|
|
498
|
+
* @returns {boolean} - true if the element in its entirety is off-screen including the scrollable area (the normal dom events look at the mouse rather than the element)
|
|
499
499
|
*/
|
|
500
500
|
function isElementOffDocument(el) {
|
|
501
501
|
var rect = getAbsoluteRect(el);
|
|
502
502
|
return rect.right < 0 || rect.left > document.documentElement.scrollWidth || rect.bottom < 0 || rect.top > document.documentElement.scrollHeight;
|
|
503
503
|
}
|
|
504
504
|
|
|
505
|
-
/**
|
|
506
|
-
* If the point is inside the element returns its distances from the sides, otherwise returns null
|
|
507
|
-
* @param {Point} point
|
|
508
|
-
* @param {HTMLElement} el
|
|
509
|
-
* @return {null|{top: number, left: number, bottom: number, right: number}}
|
|
510
|
-
*/
|
|
511
|
-
function calcInnerDistancesBetweenPointAndSidesOfElement(point, el) {
|
|
512
|
-
var rect = getAbsoluteRect(el);
|
|
513
|
-
if (!isPointInsideRect(point, rect)) {
|
|
514
|
-
return null;
|
|
515
|
-
}
|
|
516
|
-
return {
|
|
517
|
-
top: point.y - rect.top,
|
|
518
|
-
bottom: rect.bottom - point.y,
|
|
519
|
-
left: point.x - rect.left,
|
|
520
|
-
// TODO - figure out what is so special about right (why the rect is too big)
|
|
521
|
-
right: Math.min(rect.right, document.documentElement.clientWidth) - point.x
|
|
522
|
-
};
|
|
523
|
-
}
|
|
524
|
-
|
|
525
505
|
var dzToShadowIndexToRect;
|
|
526
506
|
|
|
527
507
|
/**
|
|
@@ -535,17 +515,6 @@ function resetIndexesCache() {
|
|
|
535
515
|
}
|
|
536
516
|
resetIndexesCache();
|
|
537
517
|
|
|
538
|
-
/**
|
|
539
|
-
* Resets the cache that allows for smarter "would be index" resolution for a specific dropzone, should be called after the zone was scrolled
|
|
540
|
-
* @param {HTMLElement} dz
|
|
541
|
-
*/
|
|
542
|
-
function resetIndexesCacheForDz(dz) {
|
|
543
|
-
printDebug(function () {
|
|
544
|
-
return "resetting indexes cache for dz";
|
|
545
|
-
});
|
|
546
|
-
dzToShadowIndexToRect["delete"](dz);
|
|
547
|
-
}
|
|
548
|
-
|
|
549
518
|
/**
|
|
550
519
|
* Caches the coordinates of the shadow element when it's in a certain index in a certain dropzone.
|
|
551
520
|
* Helpful in order to determine "would be index" more effectively
|
|
@@ -628,102 +597,6 @@ function findWouldBeIndex(floatingAboveEl, collectionBelowEl) {
|
|
|
628
597
|
};
|
|
629
598
|
}
|
|
630
599
|
|
|
631
|
-
var SCROLL_ZONE_PX = 25;
|
|
632
|
-
function makeScroller() {
|
|
633
|
-
var scrollingInfo;
|
|
634
|
-
function resetScrolling() {
|
|
635
|
-
scrollingInfo = {
|
|
636
|
-
directionObj: undefined,
|
|
637
|
-
stepPx: 0
|
|
638
|
-
};
|
|
639
|
-
}
|
|
640
|
-
resetScrolling();
|
|
641
|
-
// directionObj {x: 0|1|-1, y:0|1|-1} - 1 means down in y and right in x
|
|
642
|
-
function scrollContainer(containerEl) {
|
|
643
|
-
var _scrollingInfo = scrollingInfo,
|
|
644
|
-
directionObj = _scrollingInfo.directionObj,
|
|
645
|
-
stepPx = _scrollingInfo.stepPx;
|
|
646
|
-
if (directionObj) {
|
|
647
|
-
containerEl.scrollBy(directionObj.x * stepPx, directionObj.y * stepPx);
|
|
648
|
-
window.requestAnimationFrame(function () {
|
|
649
|
-
return scrollContainer(containerEl);
|
|
650
|
-
});
|
|
651
|
-
}
|
|
652
|
-
}
|
|
653
|
-
function calcScrollStepPx(distancePx) {
|
|
654
|
-
return SCROLL_ZONE_PX - distancePx;
|
|
655
|
-
}
|
|
656
|
-
|
|
657
|
-
/**
|
|
658
|
-
* If the pointer is next to the sides of the element to scroll, will trigger scrolling
|
|
659
|
-
* Can be called repeatedly with updated pointer and elementToScroll values without issues
|
|
660
|
-
* @return {boolean} - true if scrolling was needed
|
|
661
|
-
*/
|
|
662
|
-
function scrollIfNeeded(pointer, elementToScroll) {
|
|
663
|
-
if (!elementToScroll) {
|
|
664
|
-
return false;
|
|
665
|
-
}
|
|
666
|
-
var distances = calcInnerDistancesBetweenPointAndSidesOfElement(pointer, elementToScroll);
|
|
667
|
-
if (distances === null) {
|
|
668
|
-
resetScrolling();
|
|
669
|
-
return false;
|
|
670
|
-
}
|
|
671
|
-
var isAlreadyScrolling = !!scrollingInfo.directionObj;
|
|
672
|
-
var scrollingVertically = false,
|
|
673
|
-
scrollingHorizontally = false;
|
|
674
|
-
// vertical
|
|
675
|
-
if (elementToScroll.scrollHeight > elementToScroll.clientHeight) {
|
|
676
|
-
if (distances.bottom < SCROLL_ZONE_PX) {
|
|
677
|
-
scrollingVertically = true;
|
|
678
|
-
scrollingInfo.directionObj = {
|
|
679
|
-
x: 0,
|
|
680
|
-
y: 1
|
|
681
|
-
};
|
|
682
|
-
scrollingInfo.stepPx = calcScrollStepPx(distances.bottom);
|
|
683
|
-
} else if (distances.top < SCROLL_ZONE_PX) {
|
|
684
|
-
scrollingVertically = true;
|
|
685
|
-
scrollingInfo.directionObj = {
|
|
686
|
-
x: 0,
|
|
687
|
-
y: -1
|
|
688
|
-
};
|
|
689
|
-
scrollingInfo.stepPx = calcScrollStepPx(distances.top);
|
|
690
|
-
}
|
|
691
|
-
if (!isAlreadyScrolling && scrollingVertically) {
|
|
692
|
-
scrollContainer(elementToScroll);
|
|
693
|
-
return true;
|
|
694
|
-
}
|
|
695
|
-
}
|
|
696
|
-
// horizontal
|
|
697
|
-
if (elementToScroll.scrollWidth > elementToScroll.clientWidth) {
|
|
698
|
-
if (distances.right < SCROLL_ZONE_PX) {
|
|
699
|
-
scrollingHorizontally = true;
|
|
700
|
-
scrollingInfo.directionObj = {
|
|
701
|
-
x: 1,
|
|
702
|
-
y: 0
|
|
703
|
-
};
|
|
704
|
-
scrollingInfo.stepPx = calcScrollStepPx(distances.right);
|
|
705
|
-
} else if (distances.left < SCROLL_ZONE_PX) {
|
|
706
|
-
scrollingHorizontally = true;
|
|
707
|
-
scrollingInfo.directionObj = {
|
|
708
|
-
x: -1,
|
|
709
|
-
y: 0
|
|
710
|
-
};
|
|
711
|
-
scrollingInfo.stepPx = calcScrollStepPx(distances.left);
|
|
712
|
-
}
|
|
713
|
-
if (!isAlreadyScrolling && scrollingHorizontally) {
|
|
714
|
-
scrollContainer(elementToScroll);
|
|
715
|
-
return true;
|
|
716
|
-
}
|
|
717
|
-
}
|
|
718
|
-
resetScrolling();
|
|
719
|
-
return false;
|
|
720
|
-
}
|
|
721
|
-
return {
|
|
722
|
-
scrollIfNeeded: scrollIfNeeded,
|
|
723
|
-
resetScrolling: resetScrolling
|
|
724
|
-
};
|
|
725
|
-
}
|
|
726
|
-
|
|
727
600
|
/**
|
|
728
601
|
* @param {Object} object
|
|
729
602
|
* @return {string}
|
|
@@ -789,9 +662,6 @@ function areArraysShallowEqualSameOrder(arrA, arrB) {
|
|
|
789
662
|
|
|
790
663
|
var INTERVAL_MS = 200;
|
|
791
664
|
var TOLERANCE_PX = 10;
|
|
792
|
-
var _makeScroller = makeScroller(),
|
|
793
|
-
scrollIfNeeded = _makeScroller.scrollIfNeeded,
|
|
794
|
-
resetScrolling = _makeScroller.resetScrolling;
|
|
795
665
|
var next;
|
|
796
666
|
|
|
797
667
|
/**
|
|
@@ -799,9 +669,11 @@ var next;
|
|
|
799
669
|
* @param {Set<HTMLElement>} dropZones
|
|
800
670
|
* @param {HTMLElement} draggedEl
|
|
801
671
|
* @param {number} [intervalMs = INTERVAL_MS]
|
|
672
|
+
* @param {MultiScroller} multiScroller
|
|
802
673
|
*/
|
|
803
674
|
function observe(draggedEl, dropZones) {
|
|
804
675
|
var intervalMs = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : INTERVAL_MS;
|
|
676
|
+
var multiScroller = arguments.length > 3 ? arguments[3] : undefined;
|
|
805
677
|
// initialization
|
|
806
678
|
var lastDropZoneFound;
|
|
807
679
|
var lastIndexFound;
|
|
@@ -817,7 +689,7 @@ function observe(draggedEl, dropZones) {
|
|
|
817
689
|
*/
|
|
818
690
|
function andNow() {
|
|
819
691
|
var currentCenterOfDragged = findCenterOfElement(draggedEl);
|
|
820
|
-
var scrolled =
|
|
692
|
+
var scrolled = multiScroller.multiScrollIfNeeded();
|
|
821
693
|
// we only want to make a new decision after the element was moved a bit to prevent flickering
|
|
822
694
|
if (!scrolled && lastCentrePositionOfDragged && Math.abs(lastCentrePositionOfDragged.x - currentCenterOfDragged.x) < TOLERANCE_PX && Math.abs(lastCentrePositionOfDragged.y - currentCenterOfDragged.y) < TOLERANCE_PX) {
|
|
823
695
|
next = window.setTimeout(andNow, intervalMs);
|
|
@@ -838,7 +710,7 @@ function observe(draggedEl, dropZones) {
|
|
|
838
710
|
try {
|
|
839
711
|
for (_iterator.s(); !(_step = _iterator.n()).done;) {
|
|
840
712
|
var dz = _step.value;
|
|
841
|
-
if (scrolled)
|
|
713
|
+
if (scrolled) resetIndexesCache();
|
|
842
714
|
var indexObj = findWouldBeIndex(draggedEl, dz);
|
|
843
715
|
if (indexObj === null) {
|
|
844
716
|
// it is not inside
|
|
@@ -883,61 +755,225 @@ function unobserve() {
|
|
|
883
755
|
return "unobserving";
|
|
884
756
|
});
|
|
885
757
|
clearTimeout(next);
|
|
886
|
-
resetScrolling();
|
|
887
758
|
resetIndexesCache();
|
|
888
759
|
}
|
|
889
760
|
|
|
890
|
-
var
|
|
891
|
-
var mousePosition;
|
|
761
|
+
var SCROLL_ZONE_PX = 30;
|
|
892
762
|
|
|
893
763
|
/**
|
|
894
|
-
*
|
|
895
|
-
*
|
|
896
|
-
* @param {{clientX: number, clientY: number}} e
|
|
764
|
+
* Will make a scroller that can scroll any element given to it in any direction
|
|
765
|
+
* @returns {{scrollIfNeeded: function(Point, HTMLElement): boolean, resetScrolling: function(void):void}}
|
|
897
766
|
*/
|
|
898
|
-
function
|
|
899
|
-
var
|
|
900
|
-
|
|
901
|
-
|
|
902
|
-
|
|
903
|
-
|
|
904
|
-
}
|
|
905
|
-
var _makeScroller$1 = makeScroller(),
|
|
906
|
-
scrollIfNeeded$1 = _makeScroller$1.scrollIfNeeded,
|
|
907
|
-
resetScrolling$1 = _makeScroller$1.resetScrolling;
|
|
908
|
-
var next$1;
|
|
909
|
-
function loop() {
|
|
910
|
-
if (mousePosition) {
|
|
911
|
-
var scrolled = scrollIfNeeded$1(mousePosition, document.documentElement);
|
|
912
|
-
if (scrolled) resetIndexesCache();
|
|
767
|
+
function makeScroller() {
|
|
768
|
+
var scrollingInfo;
|
|
769
|
+
function resetScrolling() {
|
|
770
|
+
scrollingInfo = {
|
|
771
|
+
directionObj: undefined,
|
|
772
|
+
stepPx: 0
|
|
773
|
+
};
|
|
913
774
|
}
|
|
914
|
-
|
|
775
|
+
resetScrolling();
|
|
776
|
+
// directionObj {x: 0|1|-1, y:0|1|-1} - 1 means down in y and right in x
|
|
777
|
+
function scrollContainer(containerEl) {
|
|
778
|
+
var _scrollingInfo = scrollingInfo,
|
|
779
|
+
directionObj = _scrollingInfo.directionObj,
|
|
780
|
+
stepPx = _scrollingInfo.stepPx;
|
|
781
|
+
if (directionObj) {
|
|
782
|
+
containerEl.scrollBy(directionObj.x * stepPx, directionObj.y * stepPx);
|
|
783
|
+
window.requestAnimationFrame(function () {
|
|
784
|
+
return scrollContainer(containerEl);
|
|
785
|
+
});
|
|
786
|
+
}
|
|
787
|
+
}
|
|
788
|
+
function calcScrollStepPx(distancePx) {
|
|
789
|
+
return SCROLL_ZONE_PX - distancePx;
|
|
790
|
+
}
|
|
791
|
+
|
|
792
|
+
/**
|
|
793
|
+
* @param {Point} pointer - the pointer will be used to decide in which direction to scroll
|
|
794
|
+
* @param {HTMLElement} elementToScroll - the scroll container
|
|
795
|
+
* If the pointer is next to the sides of the element to scroll, will trigger scrolling
|
|
796
|
+
* Can be called repeatedly with updated pointer and elementToScroll values without issues
|
|
797
|
+
* @return {boolean} - true if scrolling was needed
|
|
798
|
+
*/
|
|
799
|
+
function scrollIfNeeded(pointer, elementToScroll) {
|
|
800
|
+
if (!elementToScroll) {
|
|
801
|
+
return false;
|
|
802
|
+
}
|
|
803
|
+
var distances = calcInnerDistancesBetweenPointAndSidesOfElement(pointer, elementToScroll);
|
|
804
|
+
if (distances === null) {
|
|
805
|
+
resetScrolling();
|
|
806
|
+
return false;
|
|
807
|
+
}
|
|
808
|
+
var isAlreadyScrolling = !!scrollingInfo.directionObj;
|
|
809
|
+
var scrollingVertically = false,
|
|
810
|
+
scrollingHorizontally = false;
|
|
811
|
+
// vertical
|
|
812
|
+
if (elementToScroll.scrollHeight > elementToScroll.clientHeight) {
|
|
813
|
+
if (distances.bottom < SCROLL_ZONE_PX) {
|
|
814
|
+
scrollingVertically = true;
|
|
815
|
+
scrollingInfo.directionObj = {
|
|
816
|
+
x: 0,
|
|
817
|
+
y: 1
|
|
818
|
+
};
|
|
819
|
+
scrollingInfo.stepPx = calcScrollStepPx(distances.bottom);
|
|
820
|
+
} else if (distances.top < SCROLL_ZONE_PX) {
|
|
821
|
+
scrollingVertically = true;
|
|
822
|
+
scrollingInfo.directionObj = {
|
|
823
|
+
x: 0,
|
|
824
|
+
y: -1
|
|
825
|
+
};
|
|
826
|
+
scrollingInfo.stepPx = calcScrollStepPx(distances.top);
|
|
827
|
+
}
|
|
828
|
+
if (!isAlreadyScrolling && scrollingVertically) {
|
|
829
|
+
scrollContainer(elementToScroll);
|
|
830
|
+
return true;
|
|
831
|
+
}
|
|
832
|
+
}
|
|
833
|
+
// horizontal
|
|
834
|
+
if (elementToScroll.scrollWidth > elementToScroll.clientWidth) {
|
|
835
|
+
if (distances.right < SCROLL_ZONE_PX) {
|
|
836
|
+
scrollingHorizontally = true;
|
|
837
|
+
scrollingInfo.directionObj = {
|
|
838
|
+
x: 1,
|
|
839
|
+
y: 0
|
|
840
|
+
};
|
|
841
|
+
scrollingInfo.stepPx = calcScrollStepPx(distances.right);
|
|
842
|
+
} else if (distances.left < SCROLL_ZONE_PX) {
|
|
843
|
+
scrollingHorizontally = true;
|
|
844
|
+
scrollingInfo.directionObj = {
|
|
845
|
+
x: -1,
|
|
846
|
+
y: 0
|
|
847
|
+
};
|
|
848
|
+
scrollingInfo.stepPx = calcScrollStepPx(distances.left);
|
|
849
|
+
}
|
|
850
|
+
if (!isAlreadyScrolling && scrollingHorizontally) {
|
|
851
|
+
scrollContainer(elementToScroll);
|
|
852
|
+
return true;
|
|
853
|
+
}
|
|
854
|
+
}
|
|
855
|
+
resetScrolling();
|
|
856
|
+
return false;
|
|
857
|
+
}
|
|
858
|
+
return {
|
|
859
|
+
scrollIfNeeded: scrollIfNeeded,
|
|
860
|
+
resetScrolling: resetScrolling
|
|
861
|
+
};
|
|
915
862
|
}
|
|
916
863
|
|
|
917
864
|
/**
|
|
918
|
-
*
|
|
865
|
+
* If the point is inside the element returns its distances from the sides, otherwise returns null
|
|
866
|
+
* @param {Point} point
|
|
867
|
+
* @param {HTMLElement} el
|
|
868
|
+
* @return {null|{top: number, left: number, bottom: number, right: number}}
|
|
919
869
|
*/
|
|
920
|
-
function
|
|
921
|
-
|
|
922
|
-
|
|
923
|
-
|
|
924
|
-
|
|
925
|
-
|
|
926
|
-
|
|
870
|
+
function calcInnerDistancesBetweenPointAndSidesOfElement(point, el) {
|
|
871
|
+
// Even if the scrolling element is small it acts as a scroller for the viewport
|
|
872
|
+
var rect = el === document.scrollingElement ? {
|
|
873
|
+
top: 0,
|
|
874
|
+
bottom: window.innerHeight,
|
|
875
|
+
left: 0,
|
|
876
|
+
right: window.innerWidth
|
|
877
|
+
} : el.getBoundingClientRect();
|
|
878
|
+
if (!isPointInsideRect(point, rect)) {
|
|
879
|
+
return null;
|
|
880
|
+
}
|
|
881
|
+
return {
|
|
882
|
+
top: point.y - rect.top,
|
|
883
|
+
bottom: rect.bottom - point.y,
|
|
884
|
+
left: point.x - rect.left,
|
|
885
|
+
right: rect.right - point.x
|
|
886
|
+
};
|
|
927
887
|
}
|
|
928
888
|
|
|
929
889
|
/**
|
|
930
|
-
|
|
890
|
+
@typedef {Object} MultiScroller
|
|
891
|
+
@property {function():boolean} multiScrollIfNeeded - call this on every "tick" to scroll containers if needed, returns true if anything was scrolled
|
|
892
|
+
/**
|
|
893
|
+
* Creates a scroller than can scroll any of the provided containers or any of their scrollable parents (including the document's scrolling element)
|
|
894
|
+
* @param {HTMLElement[]} baseElementsForScrolling
|
|
895
|
+
* @param {function():Point} getPointerPosition
|
|
896
|
+
* @return {MultiScroller}
|
|
931
897
|
*/
|
|
932
|
-
function
|
|
898
|
+
function createMultiScroller() {
|
|
899
|
+
var baseElementsForScrolling = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : [];
|
|
900
|
+
var getPointerPosition = arguments.length > 1 ? arguments[1] : undefined;
|
|
933
901
|
printDebug(function () {
|
|
934
|
-
return "
|
|
902
|
+
return "creating multi-scroller";
|
|
903
|
+
});
|
|
904
|
+
var scrollingContainersSet = findRelevantScrollContainers(baseElementsForScrolling);
|
|
905
|
+
var scrollingContainersDeepToShallow = Array.from(scrollingContainersSet).sort(function (dz1, dz2) {
|
|
906
|
+
return getDepth(dz2) - getDepth(dz1);
|
|
935
907
|
});
|
|
936
|
-
|
|
937
|
-
|
|
938
|
-
|
|
939
|
-
|
|
940
|
-
|
|
908
|
+
var _makeScroller = makeScroller(),
|
|
909
|
+
scrollIfNeeded = _makeScroller.scrollIfNeeded;
|
|
910
|
+
|
|
911
|
+
/**
|
|
912
|
+
* @return {boolean} - was any container scrolled
|
|
913
|
+
*/
|
|
914
|
+
function tick() {
|
|
915
|
+
var mousePosition = getPointerPosition();
|
|
916
|
+
if (!mousePosition || !scrollingContainersDeepToShallow) {
|
|
917
|
+
return false;
|
|
918
|
+
}
|
|
919
|
+
var scrollContainersUnderCursor = scrollingContainersDeepToShallow.filter(function (el) {
|
|
920
|
+
return isPointInsideRect(mousePosition, el.getBoundingClientRect()) || el === document.scrollingElement;
|
|
921
|
+
});
|
|
922
|
+
for (var i = 0; i < scrollContainersUnderCursor.length; i++) {
|
|
923
|
+
var scrolled = scrollIfNeeded(mousePosition, scrollContainersUnderCursor[i]);
|
|
924
|
+
if (scrolled) {
|
|
925
|
+
return true;
|
|
926
|
+
}
|
|
927
|
+
}
|
|
928
|
+
return false;
|
|
929
|
+
}
|
|
930
|
+
return {
|
|
931
|
+
multiScrollIfNeeded: scrollingContainersSet.size > 0 ? tick : function () {
|
|
932
|
+
return false;
|
|
933
|
+
}
|
|
934
|
+
};
|
|
935
|
+
}
|
|
936
|
+
|
|
937
|
+
// internal utils
|
|
938
|
+
function findScrollableParents(element) {
|
|
939
|
+
if (!element) {
|
|
940
|
+
return [];
|
|
941
|
+
}
|
|
942
|
+
var scrollableContainers = [];
|
|
943
|
+
var parent = element;
|
|
944
|
+
while (parent) {
|
|
945
|
+
var _window$getComputedSt = window.getComputedStyle(parent),
|
|
946
|
+
overflow = _window$getComputedSt.overflow;
|
|
947
|
+
if (overflow.split(" ").some(function (o) {
|
|
948
|
+
return o.includes("auto") || o.includes("scroll");
|
|
949
|
+
})) {
|
|
950
|
+
scrollableContainers.push(parent);
|
|
951
|
+
}
|
|
952
|
+
parent = parent.parentElement;
|
|
953
|
+
}
|
|
954
|
+
return scrollableContainers;
|
|
955
|
+
}
|
|
956
|
+
function findRelevantScrollContainers(dropZones) {
|
|
957
|
+
var scrollingContainers = new Set();
|
|
958
|
+
var _iterator = _createForOfIteratorHelper(dropZones),
|
|
959
|
+
_step;
|
|
960
|
+
try {
|
|
961
|
+
for (_iterator.s(); !(_step = _iterator.n()).done;) {
|
|
962
|
+
var dz = _step.value;
|
|
963
|
+
findScrollableParents(dz).forEach(function (container) {
|
|
964
|
+
return scrollingContainers.add(container);
|
|
965
|
+
});
|
|
966
|
+
}
|
|
967
|
+
// The scrolling element might have overflow visible and still be scrollable
|
|
968
|
+
} catch (err) {
|
|
969
|
+
_iterator.e(err);
|
|
970
|
+
} finally {
|
|
971
|
+
_iterator.f();
|
|
972
|
+
}
|
|
973
|
+
if (document.scrollingElement.scrollHeight > document.scrollingElement.clientHeight || document.scrollingElement.scrollWidth > document.scrollingElement.clientHeight) {
|
|
974
|
+
scrollingContainers.add(document.scrollingElement);
|
|
975
|
+
}
|
|
976
|
+
return scrollingContainers;
|
|
941
977
|
}
|
|
942
978
|
|
|
943
979
|
/**
|
|
@@ -1286,7 +1322,6 @@ function watchDraggedElement() {
|
|
|
1286
1322
|
printDebug(function () {
|
|
1287
1323
|
return "watching dragged element";
|
|
1288
1324
|
});
|
|
1289
|
-
armWindowScroller();
|
|
1290
1325
|
var dropZones = typeToDropZones.get(draggedElType);
|
|
1291
1326
|
var _iterator = _createForOfIteratorHelper(dropZones),
|
|
1292
1327
|
_step;
|
|
@@ -1303,18 +1338,21 @@ function watchDraggedElement() {
|
|
|
1303
1338
|
_iterator.f();
|
|
1304
1339
|
}
|
|
1305
1340
|
window.addEventListener(DRAGGED_LEFT_DOCUMENT_EVENT_NAME, handleDrop);
|
|
1341
|
+
|
|
1306
1342
|
// it is important that we don't have an interval that is faster than the flip duration because it can cause elements to jump bach and forth
|
|
1307
1343
|
var setIntervalMs = Math.max.apply(Math, _toConsumableArray(Array.from(dropZones.keys()).map(function (dz) {
|
|
1308
1344
|
return dzToConfig.get(dz).dropAnimationDurationMs;
|
|
1309
1345
|
})));
|
|
1310
|
-
var observationIntervalMs = setIntervalMs === 0 ? DISABLED_OBSERVATION_INTERVAL_MS : Math.max(setIntervalMs, MIN_OBSERVATION_INTERVAL_MS); //if
|
|
1311
|
-
|
|
1346
|
+
var 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.
|
|
1347
|
+
var multiScroller = createMultiScroller(dropZones, function () {
|
|
1348
|
+
return currentMousePosition;
|
|
1349
|
+
});
|
|
1350
|
+
observe(draggedEl, dropZones, observationIntervalMs * 1.07, multiScroller);
|
|
1312
1351
|
}
|
|
1313
1352
|
function unWatchDraggedElement() {
|
|
1314
1353
|
printDebug(function () {
|
|
1315
1354
|
return "unwatching dragged element";
|
|
1316
1355
|
});
|
|
1317
|
-
disarmWindowScroller();
|
|
1318
1356
|
var dropZones = typeToDropZones.get(draggedElType);
|
|
1319
1357
|
var _iterator2 = _createForOfIteratorHelper(dropZones),
|
|
1320
1358
|
_step2;
|
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.
|
|
4
|
+
"version": "0.9.41",
|
|
5
5
|
"repository": {
|
|
6
6
|
"type": "git",
|
|
7
7
|
"url": "git+https://github.com/isaacHagoel/svelte-dnd-action.git"
|
|
@@ -150,29 +150,9 @@ export function calcDistanceBetweenCenters(elA, elB) {
|
|
|
150
150
|
|
|
151
151
|
/**
|
|
152
152
|
* @param {HTMLElement} el - the element to check
|
|
153
|
-
* @returns {boolean} - true if the element in its entirety is off
|
|
153
|
+
* @returns {boolean} - true if the element in its entirety is off-screen including the scrollable area (the normal dom events look at the mouse rather than the element)
|
|
154
154
|
*/
|
|
155
155
|
export function isElementOffDocument(el) {
|
|
156
156
|
const rect = getAbsoluteRect(el);
|
|
157
157
|
return rect.right < 0 || rect.left > document.documentElement.scrollWidth || rect.bottom < 0 || rect.top > document.documentElement.scrollHeight;
|
|
158
158
|
}
|
|
159
|
-
|
|
160
|
-
/**
|
|
161
|
-
* If the point is inside the element returns its distances from the sides, otherwise returns null
|
|
162
|
-
* @param {Point} point
|
|
163
|
-
* @param {HTMLElement} el
|
|
164
|
-
* @return {null|{top: number, left: number, bottom: number, right: number}}
|
|
165
|
-
*/
|
|
166
|
-
export function calcInnerDistancesBetweenPointAndSidesOfElement(point, el) {
|
|
167
|
-
const rect = getAbsoluteRect(el);
|
|
168
|
-
if (!isPointInsideRect(point, rect)) {
|
|
169
|
-
return null;
|
|
170
|
-
}
|
|
171
|
-
return {
|
|
172
|
-
top: point.y - rect.top,
|
|
173
|
-
bottom: rect.bottom - point.y,
|
|
174
|
-
left: point.x - rect.left,
|
|
175
|
-
// TODO - figure out what is so special about right (why the rect is too big)
|
|
176
|
-
right: Math.min(rect.right, document.documentElement.clientWidth) - point.x
|
|
177
|
-
};
|
|
178
|
-
}
|
package/src/helpers/listUtil.js
CHANGED
|
@@ -12,15 +12,6 @@ export function resetIndexesCache() {
|
|
|
12
12
|
}
|
|
13
13
|
resetIndexesCache();
|
|
14
14
|
|
|
15
|
-
/**
|
|
16
|
-
* Resets the cache that allows for smarter "would be index" resolution for a specific dropzone, should be called after the zone was scrolled
|
|
17
|
-
* @param {HTMLElement} dz
|
|
18
|
-
*/
|
|
19
|
-
export function resetIndexesCacheForDz(dz) {
|
|
20
|
-
printDebug(() => "resetting indexes cache for dz");
|
|
21
|
-
dzToShadowIndexToRect.delete(dz);
|
|
22
|
-
}
|
|
23
|
-
|
|
24
15
|
/**
|
|
25
16
|
* Caches the coordinates of the shadow element when it's in a certain index in a certain dropzone.
|
|
26
17
|
* Helpful in order to determine "would be index" more effectively
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
import {makeScroller} from "./scroller";
|
|
2
|
+
import {printDebug} from "../constants";
|
|
3
|
+
import {getDepth} from "./util";
|
|
4
|
+
import {isPointInsideRect} from "./intersection";
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
@typedef {Object} MultiScroller
|
|
8
|
+
@property {function():boolean} multiScrollIfNeeded - call this on every "tick" to scroll containers if needed, returns true if anything was scrolled
|
|
9
|
+
/**
|
|
10
|
+
* Creates a scroller than can scroll any of the provided containers or any of their scrollable parents (including the document's scrolling element)
|
|
11
|
+
* @param {HTMLElement[]} baseElementsForScrolling
|
|
12
|
+
* @param {function():Point} getPointerPosition
|
|
13
|
+
* @return {MultiScroller}
|
|
14
|
+
*/
|
|
15
|
+
export function createMultiScroller(baseElementsForScrolling = [], getPointerPosition) {
|
|
16
|
+
printDebug(() => "creating multi-scroller");
|
|
17
|
+
const scrollingContainersSet = findRelevantScrollContainers(baseElementsForScrolling);
|
|
18
|
+
const scrollingContainersDeepToShallow = Array.from(scrollingContainersSet).sort((dz1, dz2) => getDepth(dz2) - getDepth(dz1));
|
|
19
|
+
const {scrollIfNeeded} = makeScroller();
|
|
20
|
+
|
|
21
|
+
/**
|
|
22
|
+
* @return {boolean} - was any container scrolled
|
|
23
|
+
*/
|
|
24
|
+
function tick() {
|
|
25
|
+
const mousePosition = getPointerPosition();
|
|
26
|
+
if (!mousePosition || !scrollingContainersDeepToShallow) {
|
|
27
|
+
return false;
|
|
28
|
+
}
|
|
29
|
+
const scrollContainersUnderCursor = scrollingContainersDeepToShallow.filter(
|
|
30
|
+
el => isPointInsideRect(mousePosition, el.getBoundingClientRect()) || el === document.scrollingElement
|
|
31
|
+
);
|
|
32
|
+
for (let i = 0; i < scrollContainersUnderCursor.length; i++) {
|
|
33
|
+
const scrolled = scrollIfNeeded(mousePosition, scrollContainersUnderCursor[i]);
|
|
34
|
+
if (scrolled) {
|
|
35
|
+
return true;
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
return false;
|
|
39
|
+
}
|
|
40
|
+
return {
|
|
41
|
+
multiScrollIfNeeded: scrollingContainersSet.size > 0 ? tick : () => false
|
|
42
|
+
};
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
// internal utils
|
|
46
|
+
function findScrollableParents(element) {
|
|
47
|
+
if (!element) {
|
|
48
|
+
return [];
|
|
49
|
+
}
|
|
50
|
+
const scrollableContainers = [];
|
|
51
|
+
let parent = element;
|
|
52
|
+
while (parent) {
|
|
53
|
+
const {overflow} = window.getComputedStyle(parent);
|
|
54
|
+
if (overflow.split(" ").some(o => o.includes("auto") || o.includes("scroll"))) {
|
|
55
|
+
scrollableContainers.push(parent);
|
|
56
|
+
}
|
|
57
|
+
parent = parent.parentElement;
|
|
58
|
+
}
|
|
59
|
+
return scrollableContainers;
|
|
60
|
+
}
|
|
61
|
+
function findRelevantScrollContainers(dropZones) {
|
|
62
|
+
const scrollingContainers = new Set();
|
|
63
|
+
for (let dz of dropZones) {
|
|
64
|
+
findScrollableParents(dz).forEach(container => scrollingContainers.add(container));
|
|
65
|
+
}
|
|
66
|
+
// The scrolling element might have overflow visible and still be scrollable
|
|
67
|
+
if (
|
|
68
|
+
document.scrollingElement.scrollHeight > document.scrollingElement.clientHeight ||
|
|
69
|
+
document.scrollingElement.scrollWidth > document.scrollingElement.clientHeight
|
|
70
|
+
) {
|
|
71
|
+
scrollingContainers.add(document.scrollingElement);
|
|
72
|
+
}
|
|
73
|
+
return scrollingContainers;
|
|
74
|
+
}
|
package/src/helpers/observer.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {findWouldBeIndex, resetIndexesCache
|
|
1
|
+
import {findWouldBeIndex, resetIndexesCache} from "./listUtil";
|
|
2
2
|
import {findCenterOfElement, isElementOffDocument} from "./intersection";
|
|
3
3
|
import {
|
|
4
4
|
dispatchDraggedElementEnteredContainer,
|
|
@@ -7,13 +7,11 @@ import {
|
|
|
7
7
|
dispatchDraggedLeftDocument,
|
|
8
8
|
dispatchDraggedElementIsOverIndex
|
|
9
9
|
} from "./dispatcher";
|
|
10
|
-
import {makeScroller} from "./scroller";
|
|
11
10
|
import {getDepth} from "./util";
|
|
12
11
|
import {printDebug} from "../constants";
|
|
13
12
|
|
|
14
13
|
const INTERVAL_MS = 200;
|
|
15
14
|
const TOLERANCE_PX = 10;
|
|
16
|
-
const {scrollIfNeeded, resetScrolling} = makeScroller();
|
|
17
15
|
let next;
|
|
18
16
|
|
|
19
17
|
/**
|
|
@@ -21,8 +19,9 @@ let next;
|
|
|
21
19
|
* @param {Set<HTMLElement>} dropZones
|
|
22
20
|
* @param {HTMLElement} draggedEl
|
|
23
21
|
* @param {number} [intervalMs = INTERVAL_MS]
|
|
22
|
+
* @param {MultiScroller} multiScroller
|
|
24
23
|
*/
|
|
25
|
-
export function observe(draggedEl, dropZones, intervalMs = INTERVAL_MS) {
|
|
24
|
+
export function observe(draggedEl, dropZones, intervalMs = INTERVAL_MS, multiScroller) {
|
|
26
25
|
// initialization
|
|
27
26
|
let lastDropZoneFound;
|
|
28
27
|
let lastIndexFound;
|
|
@@ -36,7 +35,7 @@ export function observe(draggedEl, dropZones, intervalMs = INTERVAL_MS) {
|
|
|
36
35
|
*/
|
|
37
36
|
function andNow() {
|
|
38
37
|
const currentCenterOfDragged = findCenterOfElement(draggedEl);
|
|
39
|
-
const scrolled =
|
|
38
|
+
const scrolled = multiScroller.multiScrollIfNeeded();
|
|
40
39
|
// we only want to make a new decision after the element was moved a bit to prevent flickering
|
|
41
40
|
if (
|
|
42
41
|
!scrolled &&
|
|
@@ -57,7 +56,7 @@ export function observe(draggedEl, dropZones, intervalMs = INTERVAL_MS) {
|
|
|
57
56
|
// this is a simple algorithm, potential improvement: first look at lastDropZoneFound
|
|
58
57
|
let isDraggedInADropZone = false;
|
|
59
58
|
for (const dz of dropZonesFromDeepToShallow) {
|
|
60
|
-
if (scrolled)
|
|
59
|
+
if (scrolled) resetIndexesCache();
|
|
61
60
|
const indexObj = findWouldBeIndex(draggedEl, dz);
|
|
62
61
|
if (indexObj === null) {
|
|
63
62
|
// it is not inside
|
|
@@ -95,6 +94,5 @@ export function observe(draggedEl, dropZones, intervalMs = INTERVAL_MS) {
|
|
|
95
94
|
export function unobserve() {
|
|
96
95
|
printDebug(() => "unobserving");
|
|
97
96
|
clearTimeout(next);
|
|
98
|
-
resetScrolling();
|
|
99
97
|
resetIndexesCache();
|
|
100
98
|
}
|