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/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
|
-
|
|
254
|
+
#### Setup (Optional)
|
|
256
255
|
|
|
257
|
-
|
|
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
|
-
|
|
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`.
|
|
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
|
-
>
|
|
289
|
-
>
|
|
290
|
-
>
|
|
291
|
-
>
|
|
292
|
-
>
|
|
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:
|
|
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
|
|
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 =
|
|
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)
|
|
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
|
|
897
|
-
var mousePosition;
|
|
767
|
+
var SCROLL_ZONE_PX = 30;
|
|
898
768
|
|
|
899
769
|
/**
|
|
900
|
-
*
|
|
901
|
-
*
|
|
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
|
|
905
|
-
var
|
|
906
|
-
|
|
907
|
-
|
|
908
|
-
|
|
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
|
-
|
|
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
|
-
*
|
|
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
|
|
927
|
-
|
|
928
|
-
|
|
929
|
-
|
|
930
|
-
|
|
931
|
-
|
|
932
|
-
|
|
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
|
-
|
|
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
|
|
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 "
|
|
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
|
-
|
|
943
|
-
|
|
944
|
-
|
|
945
|
-
|
|
946
|
-
|
|
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
|
|
1317
|
-
|
|
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;
|