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 CHANGED
@@ -22,7 +22,7 @@ It is being actively maintained.
22
22
  - Rich animations (can be opted out of)
23
23
  - Touch support
24
24
  - Define what can be dropped where (dnd-zones optionally have a "type")
25
- - Scroll dnd-zones and/or the window horizontally or vertically by placing the dragged element next to the edge
25
+ - Scroll dnd-zones (of the relevant "type"), parent containers that contains them and/or the window horizontally or vertically by placing the dragged element next to the edge
26
26
  - Supports advanced use-cases such as various flavours of copy-on-drag and custom drag handles (see examples below)
27
27
  - Performant and small footprint (no external dependencies, no fluff code)
28
28
  - Fully accessible (beta) - keyboard support, aria attributes and assistive instructions for screen readers
@@ -82,7 +82,7 @@ npm install --save-dev svelte-dnd-action
82
82
  width: 50%;
83
83
  padding: 0.3em;
84
84
  border: 1px solid black;
85
- /* this will allow the dragged element to scroll the list */
85
+ /* this will allow the dragged element to scroll the list although starting in version 0.9.41 the lib would detect any scrollable parent*/
86
86
  overflow: scroll;
87
87
  height: 200px;
88
88
  }
@@ -207,7 +207,6 @@ If you want to implement your own custom screen-reader alerts, roles and instruc
207
207
  - Any data that should "survive" when the items are dragged around and dropped should be included in the `items` array that is passed in.
208
208
  - The host component must refresh the items that are passed in to the custom-action when receiving consider and finalize events (do not omit any handler).
209
209
  - FYI, the library assumes it is okay to add a temporary item to the items list in any of the dnd-zones while an element is dragged around.
210
- - If you want dragged items to be able to scroll the container, make sure the scroll-container (the element with overflow:scroll) is the dnd-zone (the element decorated with this custom action)
211
210
  - Svelte's built-in transitions might not play nice with this library. Luckily, it is an easy issue to work around. There are examples above.
212
211
 
213
212
  ### Overriding the item id key name
@@ -252,9 +251,11 @@ setDebugMode(true);
252
251
 
253
252
  ### Typescript
254
253
 
255
- If you are using Typescript, you will need to add the following block to your `global.d.ts` (at least until [this svelte issue](https://github.com/sveltejs/language-tools/issues/431) is resolved):
254
+ #### Setup (Optional)
256
255
 
257
- #### Svelte 3 or below
256
+ TypeScript support has been added since version 0.9.40 and you do not need to set up any custom typings. However, in case you are using some older version or face some types issue, you will need to add the following block to your `global.d.ts` (at least until [this svelte issue](https://github.com/sveltejs/language-tools/issues/431) is resolved):
257
+
258
+ ##### Svelte 3 or below
258
259
 
259
260
  ```typescript
260
261
  declare type Item = import("svelte-dnd-action").Item;
@@ -267,7 +268,7 @@ declare namespace svelte.JSX {
267
268
  }
268
269
  ```
269
270
 
270
- #### Svelte 4:
271
+ ##### Svelte 4:
271
272
 
272
273
  ```typescript
273
274
  declare type Item = import("svelte-dnd-action").Item;
@@ -282,17 +283,18 @@ declare namespace svelteHTML {
282
283
 
283
284
  You may need to edit `tsconfig.json` to include `global.d.ts` if it doesn't already: "include": ["src/**/*", "global.d.ts"].
284
285
 
285
- > Note: If you are using Sveltekit you should use `svelte.config.js` to modify the generated `tsconfig.json` rather than adding the `include` element to the root `tsconfig.json`. Adding `include` to the root file will cause issues because it will [override](https://www.typescriptlang.org/tsconfig#extends) the `include` array defined in `.svelte-kit/tsconfig.json`. Example:
286
+ > Note: If you are using Sveltekit you should use `svelte.config.js` to modify the generated `tsconfig.json` rather than adding the `include` element to the root `tsconfig.json`. Adding `include` to the root file will cause issues because it will [override](https://www.typescriptlang.org/tsconfig#extends) the `include` array defined in `.svelte-kit/tsconfig.json`. Example:
287
+ >
286
288
  > ```javascript
287
289
  > const config = {
288
- > kit: {
289
- > typescript: {
290
- > config(config) {
291
- > // This path is relative to the ".svelte-kit" folder
292
- > config.include.push('../global.d.ts');
293
- > },
294
- > },
295
- > },
290
+ > kit: {
291
+ > typescript: {
292
+ > config(config) {
293
+ > // This path is relative to the ".svelte-kit" folder
294
+ > config.include.push("../global.d.ts");
295
+ > }
296
+ > }
297
+ > }
296
298
  > };
297
299
  > ```
298
300
 
package/dist/index.d.ts CHANGED
@@ -1,14 +1,18 @@
1
+ import type {ActionReturn} from "svelte/action";
2
+
1
3
  /**
2
4
  * A custom action to turn any container to a dnd zone and all of its direct children to draggables
3
5
  * Supports mouse, touch and keyboard interactions.
4
6
  * Dispatches two events that the container is expected to react to by modifying its list of items,
5
7
  * which will then feed back in to this action via the update function
6
8
  */
7
- export declare function dndzone(
9
+ export declare function dndzone<T extends Item>(node: HTMLElement, options: Options<T>): ActionReturn<Options<T>, DndZoneAttributes<T>>;
10
+
11
+ export declare function dndzone<T extends Item>(
8
12
  node: HTMLElement,
9
- options: Options
13
+ options: Options<T>
10
14
  ): {
11
- update: (newOptions: Options) => void;
15
+ update: (newOptions: Options<T>) => void;
12
16
  destroy: () => void;
13
17
  };
14
18
 
@@ -19,8 +23,8 @@ export type TransformDraggedElementFunction = (
19
23
  ) => void;
20
24
 
21
25
  export declare type Item = Record<string, any>;
22
- export interface Options {
23
- items: Item[]; // the list of items that was used to generate the children of the given node
26
+ export interface Options<T extends Item = Item> {
27
+ items: T[]; // the list of items that was used to generate the children of the given node
24
28
  type?: string; // the type of the dnd zone. children dragged from here can only be dropped in other zones of the same type, defaults to a base type
25
29
  flipDurationMs?: number; // if the list animated using flip (recommended), specifies the flip duration such that everything syncs with it without conflict
26
30
  dragDisabled?: boolean;
@@ -35,6 +39,13 @@ export interface Options {
35
39
  centreDraggedOnCursor?: boolean;
36
40
  }
37
41
 
42
+ export interface DndZoneAttributes<T> {
43
+ "on:consider"?: (e: CustomEvent<DndEvent<T>>) => void;
44
+ "on:finalize"?: (e: CustomEvent<DndEvent<T>>) => void;
45
+ onconsider?: (e: CustomEvent<DndEvent<T>>) => void;
46
+ onfinalize?: (e: CustomEvent<DndEvent<T>>) => void;
47
+ }
48
+
38
49
  /**
39
50
  * Will make the screen reader alert the provided text to the user
40
51
  */
package/dist/index.js CHANGED
@@ -501,33 +501,13 @@
501
501
 
502
502
  /**
503
503
  * @param {HTMLElement} el - the element to check
504
- * @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)
504
+ * @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)
505
505
  */
506
506
  function isElementOffDocument(el) {
507
507
  var rect = getAbsoluteRect(el);
508
508
  return rect.right < 0 || rect.left > document.documentElement.scrollWidth || rect.bottom < 0 || rect.top > document.documentElement.scrollHeight;
509
509
  }
510
510
 
511
- /**
512
- * If the point is inside the element returns its distances from the sides, otherwise returns null
513
- * @param {Point} point
514
- * @param {HTMLElement} el
515
- * @return {null|{top: number, left: number, bottom: number, right: number}}
516
- */
517
- function calcInnerDistancesBetweenPointAndSidesOfElement(point, el) {
518
- var rect = getAbsoluteRect(el);
519
- if (!isPointInsideRect(point, rect)) {
520
- return null;
521
- }
522
- return {
523
- top: point.y - rect.top,
524
- bottom: rect.bottom - point.y,
525
- left: point.x - rect.left,
526
- // TODO - figure out what is so special about right (why the rect is too big)
527
- right: Math.min(rect.right, document.documentElement.clientWidth) - point.x
528
- };
529
- }
530
-
531
511
  var dzToShadowIndexToRect;
532
512
 
533
513
  /**
@@ -541,17 +521,6 @@
541
521
  }
542
522
  resetIndexesCache();
543
523
 
544
- /**
545
- * Resets the cache that allows for smarter "would be index" resolution for a specific dropzone, should be called after the zone was scrolled
546
- * @param {HTMLElement} dz
547
- */
548
- function resetIndexesCacheForDz(dz) {
549
- printDebug(function () {
550
- return "resetting indexes cache for dz";
551
- });
552
- dzToShadowIndexToRect["delete"](dz);
553
- }
554
-
555
524
  /**
556
525
  * Caches the coordinates of the shadow element when it's in a certain index in a certain dropzone.
557
526
  * Helpful in order to determine "would be index" more effectively
@@ -634,102 +603,6 @@
634
603
  };
635
604
  }
636
605
 
637
- var SCROLL_ZONE_PX = 25;
638
- function makeScroller() {
639
- var scrollingInfo;
640
- function resetScrolling() {
641
- scrollingInfo = {
642
- directionObj: undefined,
643
- stepPx: 0
644
- };
645
- }
646
- resetScrolling();
647
- // directionObj {x: 0|1|-1, y:0|1|-1} - 1 means down in y and right in x
648
- function scrollContainer(containerEl) {
649
- var _scrollingInfo = scrollingInfo,
650
- directionObj = _scrollingInfo.directionObj,
651
- stepPx = _scrollingInfo.stepPx;
652
- if (directionObj) {
653
- containerEl.scrollBy(directionObj.x * stepPx, directionObj.y * stepPx);
654
- window.requestAnimationFrame(function () {
655
- return scrollContainer(containerEl);
656
- });
657
- }
658
- }
659
- function calcScrollStepPx(distancePx) {
660
- return SCROLL_ZONE_PX - distancePx;
661
- }
662
-
663
- /**
664
- * If the pointer is next to the sides of the element to scroll, will trigger scrolling
665
- * Can be called repeatedly with updated pointer and elementToScroll values without issues
666
- * @return {boolean} - true if scrolling was needed
667
- */
668
- function scrollIfNeeded(pointer, elementToScroll) {
669
- if (!elementToScroll) {
670
- return false;
671
- }
672
- var distances = calcInnerDistancesBetweenPointAndSidesOfElement(pointer, elementToScroll);
673
- if (distances === null) {
674
- resetScrolling();
675
- return false;
676
- }
677
- var isAlreadyScrolling = !!scrollingInfo.directionObj;
678
- var scrollingVertically = false,
679
- scrollingHorizontally = false;
680
- // vertical
681
- if (elementToScroll.scrollHeight > elementToScroll.clientHeight) {
682
- if (distances.bottom < SCROLL_ZONE_PX) {
683
- scrollingVertically = true;
684
- scrollingInfo.directionObj = {
685
- x: 0,
686
- y: 1
687
- };
688
- scrollingInfo.stepPx = calcScrollStepPx(distances.bottom);
689
- } else if (distances.top < SCROLL_ZONE_PX) {
690
- scrollingVertically = true;
691
- scrollingInfo.directionObj = {
692
- x: 0,
693
- y: -1
694
- };
695
- scrollingInfo.stepPx = calcScrollStepPx(distances.top);
696
- }
697
- if (!isAlreadyScrolling && scrollingVertically) {
698
- scrollContainer(elementToScroll);
699
- return true;
700
- }
701
- }
702
- // horizontal
703
- if (elementToScroll.scrollWidth > elementToScroll.clientWidth) {
704
- if (distances.right < SCROLL_ZONE_PX) {
705
- scrollingHorizontally = true;
706
- scrollingInfo.directionObj = {
707
- x: 1,
708
- y: 0
709
- };
710
- scrollingInfo.stepPx = calcScrollStepPx(distances.right);
711
- } else if (distances.left < SCROLL_ZONE_PX) {
712
- scrollingHorizontally = true;
713
- scrollingInfo.directionObj = {
714
- x: -1,
715
- y: 0
716
- };
717
- scrollingInfo.stepPx = calcScrollStepPx(distances.left);
718
- }
719
- if (!isAlreadyScrolling && scrollingHorizontally) {
720
- scrollContainer(elementToScroll);
721
- return true;
722
- }
723
- }
724
- resetScrolling();
725
- return false;
726
- }
727
- return {
728
- scrollIfNeeded: scrollIfNeeded,
729
- resetScrolling: resetScrolling
730
- };
731
- }
732
-
733
606
  /**
734
607
  * @param {Object} object
735
608
  * @return {string}
@@ -795,9 +668,6 @@
795
668
 
796
669
  var INTERVAL_MS = 200;
797
670
  var TOLERANCE_PX = 10;
798
- var _makeScroller = makeScroller(),
799
- scrollIfNeeded = _makeScroller.scrollIfNeeded,
800
- resetScrolling = _makeScroller.resetScrolling;
801
671
  var next;
802
672
 
803
673
  /**
@@ -805,9 +675,11 @@
805
675
  * @param {Set<HTMLElement>} dropZones
806
676
  * @param {HTMLElement} draggedEl
807
677
  * @param {number} [intervalMs = INTERVAL_MS]
678
+ * @param {MultiScroller} multiScroller
808
679
  */
809
680
  function observe(draggedEl, dropZones) {
810
681
  var intervalMs = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : INTERVAL_MS;
682
+ var multiScroller = arguments.length > 3 ? arguments[3] : undefined;
811
683
  // initialization
812
684
  var lastDropZoneFound;
813
685
  var lastIndexFound;
@@ -823,7 +695,7 @@
823
695
  */
824
696
  function andNow() {
825
697
  var currentCenterOfDragged = findCenterOfElement(draggedEl);
826
- var scrolled = scrollIfNeeded(currentCenterOfDragged, lastDropZoneFound);
698
+ var scrolled = multiScroller.multiScrollIfNeeded();
827
699
  // we only want to make a new decision after the element was moved a bit to prevent flickering
828
700
  if (!scrolled && lastCentrePositionOfDragged && Math.abs(lastCentrePositionOfDragged.x - currentCenterOfDragged.x) < TOLERANCE_PX && Math.abs(lastCentrePositionOfDragged.y - currentCenterOfDragged.y) < TOLERANCE_PX) {
829
701
  next = window.setTimeout(andNow, intervalMs);
@@ -844,7 +716,7 @@
844
716
  try {
845
717
  for (_iterator.s(); !(_step = _iterator.n()).done;) {
846
718
  var dz = _step.value;
847
- if (scrolled) resetIndexesCacheForDz(lastDropZoneFound);
719
+ if (scrolled) resetIndexesCache();
848
720
  var indexObj = findWouldBeIndex(draggedEl, dz);
849
721
  if (indexObj === null) {
850
722
  // it is not inside
@@ -889,61 +761,225 @@
889
761
  return "unobserving";
890
762
  });
891
763
  clearTimeout(next);
892
- resetScrolling();
893
764
  resetIndexesCache();
894
765
  }
895
766
 
896
- var INTERVAL_MS$1 = 300;
897
- var mousePosition;
767
+ var SCROLL_ZONE_PX = 30;
898
768
 
899
769
  /**
900
- * Do not use this! it is visible for testing only until we get over the issue Cypress not triggering the mousemove listeners
901
- * // TODO - make private (remove export)
902
- * @param {{clientX: number, clientY: number}} e
770
+ * Will make a scroller that can scroll any element given to it in any direction
771
+ * @returns {{scrollIfNeeded: function(Point, HTMLElement): boolean, resetScrolling: function(void):void}}
903
772
  */
904
- function updateMousePosition(e) {
905
- var c = e.touches ? e.touches[0] : e;
906
- mousePosition = {
907
- x: c.clientX,
908
- y: c.clientY
909
- };
910
- }
911
- var _makeScroller$1 = makeScroller(),
912
- scrollIfNeeded$1 = _makeScroller$1.scrollIfNeeded,
913
- resetScrolling$1 = _makeScroller$1.resetScrolling;
914
- var next$1;
915
- function loop() {
916
- if (mousePosition) {
917
- var scrolled = scrollIfNeeded$1(mousePosition, document.documentElement);
918
- if (scrolled) resetIndexesCache();
773
+ function makeScroller() {
774
+ var scrollingInfo;
775
+ function resetScrolling() {
776
+ scrollingInfo = {
777
+ directionObj: undefined,
778
+ stepPx: 0
779
+ };
919
780
  }
920
- next$1 = window.setTimeout(loop, INTERVAL_MS$1);
781
+ resetScrolling();
782
+ // directionObj {x: 0|1|-1, y:0|1|-1} - 1 means down in y and right in x
783
+ function scrollContainer(containerEl) {
784
+ var _scrollingInfo = scrollingInfo,
785
+ directionObj = _scrollingInfo.directionObj,
786
+ stepPx = _scrollingInfo.stepPx;
787
+ if (directionObj) {
788
+ containerEl.scrollBy(directionObj.x * stepPx, directionObj.y * stepPx);
789
+ window.requestAnimationFrame(function () {
790
+ return scrollContainer(containerEl);
791
+ });
792
+ }
793
+ }
794
+ function calcScrollStepPx(distancePx) {
795
+ return SCROLL_ZONE_PX - distancePx;
796
+ }
797
+
798
+ /**
799
+ * @param {Point} pointer - the pointer will be used to decide in which direction to scroll
800
+ * @param {HTMLElement} elementToScroll - the scroll container
801
+ * If the pointer is next to the sides of the element to scroll, will trigger scrolling
802
+ * Can be called repeatedly with updated pointer and elementToScroll values without issues
803
+ * @return {boolean} - true if scrolling was needed
804
+ */
805
+ function scrollIfNeeded(pointer, elementToScroll) {
806
+ if (!elementToScroll) {
807
+ return false;
808
+ }
809
+ var distances = calcInnerDistancesBetweenPointAndSidesOfElement(pointer, elementToScroll);
810
+ if (distances === null) {
811
+ resetScrolling();
812
+ return false;
813
+ }
814
+ var isAlreadyScrolling = !!scrollingInfo.directionObj;
815
+ var scrollingVertically = false,
816
+ scrollingHorizontally = false;
817
+ // vertical
818
+ if (elementToScroll.scrollHeight > elementToScroll.clientHeight) {
819
+ if (distances.bottom < SCROLL_ZONE_PX) {
820
+ scrollingVertically = true;
821
+ scrollingInfo.directionObj = {
822
+ x: 0,
823
+ y: 1
824
+ };
825
+ scrollingInfo.stepPx = calcScrollStepPx(distances.bottom);
826
+ } else if (distances.top < SCROLL_ZONE_PX) {
827
+ scrollingVertically = true;
828
+ scrollingInfo.directionObj = {
829
+ x: 0,
830
+ y: -1
831
+ };
832
+ scrollingInfo.stepPx = calcScrollStepPx(distances.top);
833
+ }
834
+ if (!isAlreadyScrolling && scrollingVertically) {
835
+ scrollContainer(elementToScroll);
836
+ return true;
837
+ }
838
+ }
839
+ // horizontal
840
+ if (elementToScroll.scrollWidth > elementToScroll.clientWidth) {
841
+ if (distances.right < SCROLL_ZONE_PX) {
842
+ scrollingHorizontally = true;
843
+ scrollingInfo.directionObj = {
844
+ x: 1,
845
+ y: 0
846
+ };
847
+ scrollingInfo.stepPx = calcScrollStepPx(distances.right);
848
+ } else if (distances.left < SCROLL_ZONE_PX) {
849
+ scrollingHorizontally = true;
850
+ scrollingInfo.directionObj = {
851
+ x: -1,
852
+ y: 0
853
+ };
854
+ scrollingInfo.stepPx = calcScrollStepPx(distances.left);
855
+ }
856
+ if (!isAlreadyScrolling && scrollingHorizontally) {
857
+ scrollContainer(elementToScroll);
858
+ return true;
859
+ }
860
+ }
861
+ resetScrolling();
862
+ return false;
863
+ }
864
+ return {
865
+ scrollIfNeeded: scrollIfNeeded,
866
+ resetScrolling: resetScrolling
867
+ };
921
868
  }
922
869
 
923
870
  /**
924
- * will start watching the mouse pointer and scroll the window if it goes next to the edges
871
+ * If the point is inside the element returns its distances from the sides, otherwise returns null
872
+ * @param {Point} point
873
+ * @param {HTMLElement} el
874
+ * @return {null|{top: number, left: number, bottom: number, right: number}}
925
875
  */
926
- function armWindowScroller() {
927
- printDebug(function () {
928
- return "arming window scroller";
929
- });
930
- window.addEventListener("mousemove", updateMousePosition);
931
- window.addEventListener("touchmove", updateMousePosition);
932
- loop();
876
+ function calcInnerDistancesBetweenPointAndSidesOfElement(point, el) {
877
+ // Even if the scrolling element is small it acts as a scroller for the viewport
878
+ var rect = el === document.scrollingElement ? {
879
+ top: 0,
880
+ bottom: window.innerHeight,
881
+ left: 0,
882
+ right: window.innerWidth
883
+ } : el.getBoundingClientRect();
884
+ if (!isPointInsideRect(point, rect)) {
885
+ return null;
886
+ }
887
+ return {
888
+ top: point.y - rect.top,
889
+ bottom: rect.bottom - point.y,
890
+ left: point.x - rect.left,
891
+ right: rect.right - point.x
892
+ };
933
893
  }
934
894
 
935
895
  /**
936
- * will stop watching the mouse pointer and won't scroll the window anymore
896
+ @typedef {Object} MultiScroller
897
+ @property {function():boolean} multiScrollIfNeeded - call this on every "tick" to scroll containers if needed, returns true if anything was scrolled
898
+ /**
899
+ * Creates a scroller than can scroll any of the provided containers or any of their scrollable parents (including the document's scrolling element)
900
+ * @param {HTMLElement[]} baseElementsForScrolling
901
+ * @param {function():Point} getPointerPosition
902
+ * @return {MultiScroller}
937
903
  */
938
- function disarmWindowScroller() {
904
+ function createMultiScroller() {
905
+ var baseElementsForScrolling = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : [];
906
+ var getPointerPosition = arguments.length > 1 ? arguments[1] : undefined;
939
907
  printDebug(function () {
940
- return "disarming window scroller";
908
+ return "creating multi-scroller";
909
+ });
910
+ var scrollingContainersSet = findRelevantScrollContainers(baseElementsForScrolling);
911
+ var scrollingContainersDeepToShallow = Array.from(scrollingContainersSet).sort(function (dz1, dz2) {
912
+ return getDepth(dz2) - getDepth(dz1);
941
913
  });
942
- window.removeEventListener("mousemove", updateMousePosition);
943
- window.removeEventListener("touchmove", updateMousePosition);
944
- mousePosition = undefined;
945
- window.clearTimeout(next$1);
946
- resetScrolling$1();
914
+ var _makeScroller = makeScroller(),
915
+ scrollIfNeeded = _makeScroller.scrollIfNeeded;
916
+
917
+ /**
918
+ * @return {boolean} - was any container scrolled
919
+ */
920
+ function tick() {
921
+ var mousePosition = getPointerPosition();
922
+ if (!mousePosition || !scrollingContainersDeepToShallow) {
923
+ return false;
924
+ }
925
+ var scrollContainersUnderCursor = scrollingContainersDeepToShallow.filter(function (el) {
926
+ return isPointInsideRect(mousePosition, el.getBoundingClientRect()) || el === document.scrollingElement;
927
+ });
928
+ for (var i = 0; i < scrollContainersUnderCursor.length; i++) {
929
+ var scrolled = scrollIfNeeded(mousePosition, scrollContainersUnderCursor[i]);
930
+ if (scrolled) {
931
+ return true;
932
+ }
933
+ }
934
+ return false;
935
+ }
936
+ return {
937
+ multiScrollIfNeeded: scrollingContainersSet.size > 0 ? tick : function () {
938
+ return false;
939
+ }
940
+ };
941
+ }
942
+
943
+ // internal utils
944
+ function findScrollableParents(element) {
945
+ if (!element) {
946
+ return [];
947
+ }
948
+ var scrollableContainers = [];
949
+ var parent = element;
950
+ while (parent) {
951
+ var _window$getComputedSt = window.getComputedStyle(parent),
952
+ overflow = _window$getComputedSt.overflow;
953
+ if (overflow.split(" ").some(function (o) {
954
+ return o.includes("auto") || o.includes("scroll");
955
+ })) {
956
+ scrollableContainers.push(parent);
957
+ }
958
+ parent = parent.parentElement;
959
+ }
960
+ return scrollableContainers;
961
+ }
962
+ function findRelevantScrollContainers(dropZones) {
963
+ var scrollingContainers = new Set();
964
+ var _iterator = _createForOfIteratorHelper(dropZones),
965
+ _step;
966
+ try {
967
+ for (_iterator.s(); !(_step = _iterator.n()).done;) {
968
+ var dz = _step.value;
969
+ findScrollableParents(dz).forEach(function (container) {
970
+ return scrollingContainers.add(container);
971
+ });
972
+ }
973
+ // The scrolling element might have overflow visible and still be scrollable
974
+ } catch (err) {
975
+ _iterator.e(err);
976
+ } finally {
977
+ _iterator.f();
978
+ }
979
+ if (document.scrollingElement.scrollHeight > document.scrollingElement.clientHeight || document.scrollingElement.scrollWidth > document.scrollingElement.clientHeight) {
980
+ scrollingContainers.add(document.scrollingElement);
981
+ }
982
+ return scrollingContainers;
947
983
  }
948
984
 
949
985
  /**
@@ -1292,7 +1328,6 @@
1292
1328
  printDebug(function () {
1293
1329
  return "watching dragged element";
1294
1330
  });
1295
- armWindowScroller();
1296
1331
  var dropZones = typeToDropZones.get(draggedElType);
1297
1332
  var _iterator = _createForOfIteratorHelper(dropZones),
1298
1333
  _step;
@@ -1309,18 +1344,21 @@
1309
1344
  _iterator.f();
1310
1345
  }
1311
1346
  window.addEventListener(DRAGGED_LEFT_DOCUMENT_EVENT_NAME, handleDrop);
1347
+
1312
1348
  // 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
1313
1349
  var setIntervalMs = Math.max.apply(Math, _toConsumableArray(Array.from(dropZones.keys()).map(function (dz) {
1314
1350
  return dzToConfig.get(dz).dropAnimationDurationMs;
1315
1351
  })));
1316
- 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.
1317
- observe(draggedEl, dropZones, observationIntervalMs * 1.07);
1352
+ 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.
1353
+ var multiScroller = createMultiScroller(dropZones, function () {
1354
+ return currentMousePosition;
1355
+ });
1356
+ observe(draggedEl, dropZones, observationIntervalMs * 1.07, multiScroller);
1318
1357
  }
1319
1358
  function unWatchDraggedElement() {
1320
1359
  printDebug(function () {
1321
1360
  return "unwatching dragged element";
1322
1361
  });
1323
- disarmWindowScroller();
1324
1362
  var dropZones = typeToDropZones.get(draggedElType);
1325
1363
  var _iterator2 = _createForOfIteratorHelper(dropZones),
1326
1364
  _step2;