svelte-dnd-action
Version:
*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 *
1,447 lines (1,380 loc) • 104 kB
JavaScript
function ownKeys(object, enumerableOnly) {
var keys = Object.keys(object);
if (Object.getOwnPropertySymbols) {
var symbols = Object.getOwnPropertySymbols(object);
enumerableOnly && (symbols = symbols.filter(function (sym) {
return Object.getOwnPropertyDescriptor(object, sym).enumerable;
})), keys.push.apply(keys, symbols);
}
return keys;
}
function _objectSpread2(target) {
for (var i = 1; i < arguments.length; i++) {
var source = null != arguments[i] ? arguments[i] : {};
i % 2 ? ownKeys(Object(source), !0).forEach(function (key) {
_defineProperty(target, key, source[key]);
}) : Object.getOwnPropertyDescriptors ? Object.defineProperties(target, Object.getOwnPropertyDescriptors(source)) : ownKeys(Object(source)).forEach(function (key) {
Object.defineProperty(target, key, Object.getOwnPropertyDescriptor(source, key));
});
}
return target;
}
function _typeof(obj) {
"@babel/helpers - typeof";
return _typeof = "function" == typeof Symbol && "symbol" == typeof Symbol.iterator ? function (obj) {
return typeof obj;
} : function (obj) {
return obj && "function" == typeof Symbol && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj;
}, _typeof(obj);
}
function _defineProperty(obj, key, value) {
if (key in obj) {
Object.defineProperty(obj, key, {
value: value,
enumerable: true,
configurable: true,
writable: true
});
} else {
obj[key] = value;
}
return obj;
}
function _objectWithoutPropertiesLoose(source, excluded) {
if (source == null) return {};
var target = {};
var sourceKeys = Object.keys(source);
var key, i;
for (i = 0; i < sourceKeys.length; i++) {
key = sourceKeys[i];
if (excluded.indexOf(key) >= 0) continue;
target[key] = source[key];
}
return target;
}
function _objectWithoutProperties(source, excluded) {
if (source == null) return {};
var target = _objectWithoutPropertiesLoose(source, excluded);
var key, i;
if (Object.getOwnPropertySymbols) {
var sourceSymbolKeys = Object.getOwnPropertySymbols(source);
for (i = 0; i < sourceSymbolKeys.length; i++) {
key = sourceSymbolKeys[i];
if (excluded.indexOf(key) >= 0) continue;
if (!Object.prototype.propertyIsEnumerable.call(source, key)) continue;
target[key] = source[key];
}
}
return target;
}
function _slicedToArray(arr, i) {
return _arrayWithHoles(arr) || _iterableToArrayLimit(arr, i) || _unsupportedIterableToArray(arr, i) || _nonIterableRest();
}
function _toConsumableArray(arr) {
return _arrayWithoutHoles(arr) || _iterableToArray(arr) || _unsupportedIterableToArray(arr) || _nonIterableSpread();
}
function _arrayWithoutHoles(arr) {
if (Array.isArray(arr)) return _arrayLikeToArray(arr);
}
function _arrayWithHoles(arr) {
if (Array.isArray(arr)) return arr;
}
function _iterableToArray(iter) {
if (typeof Symbol !== "undefined" && iter[Symbol.iterator] != null || iter["@@iterator"] != null) return Array.from(iter);
}
function _iterableToArrayLimit(arr, i) {
var _i = arr == null ? null : typeof Symbol !== "undefined" && arr[Symbol.iterator] || arr["@@iterator"];
if (_i == null) return;
var _arr = [];
var _n = true;
var _d = false;
var _s, _e;
try {
for (_i = _i.call(arr); !(_n = (_s = _i.next()).done); _n = true) {
_arr.push(_s.value);
if (i && _arr.length === i) break;
}
} catch (err) {
_d = true;
_e = err;
} finally {
try {
if (!_n && _i["return"] != null) _i["return"]();
} finally {
if (_d) throw _e;
}
}
return _arr;
}
function _unsupportedIterableToArray(o, minLen) {
if (!o) return;
if (typeof o === "string") return _arrayLikeToArray(o, minLen);
var n = Object.prototype.toString.call(o).slice(8, -1);
if (n === "Object" && o.constructor) n = o.constructor.name;
if (n === "Map" || n === "Set") return Array.from(o);
if (n === "Arguments" || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n)) return _arrayLikeToArray(o, minLen);
}
function _arrayLikeToArray(arr, len) {
if (len == null || len > arr.length) len = arr.length;
for (var i = 0, arr2 = new Array(len); i < len; i++) arr2[i] = arr[i];
return arr2;
}
function _nonIterableSpread() {
throw new TypeError("Invalid attempt to spread non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.");
}
function _nonIterableRest() {
throw new TypeError("Invalid attempt to destructure non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.");
}
function _createForOfIteratorHelper(o, allowArrayLike) {
var it = typeof Symbol !== "undefined" && o[Symbol.iterator] || o["@@iterator"];
if (!it) {
if (Array.isArray(o) || (it = _unsupportedIterableToArray(o)) || allowArrayLike && o && typeof o.length === "number") {
if (it) o = it;
var i = 0;
var F = function () {};
return {
s: F,
n: function () {
if (i >= o.length) return {
done: true
};
return {
done: false,
value: o[i++]
};
},
e: function (e) {
throw e;
},
f: F
};
}
throw new TypeError("Invalid attempt to iterate non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.");
}
var normalCompletion = true,
didErr = false,
err;
return {
s: function () {
it = it.call(o);
},
n: function () {
var step = it.next();
normalCompletion = step.done;
return step;
},
e: function (e) {
didErr = true;
err = e;
},
f: function () {
try {
if (!normalCompletion && it.return != null) it.return();
} finally {
if (didErr) throw err;
}
}
};
}
// external events
var FINALIZE_EVENT_NAME = "finalize";
var CONSIDER_EVENT_NAME = "consider";
/**
* @typedef {Object} Info
* @property {string} trigger
* @property {string} id
* @property {string} source
* @param {Node} el
* @param {Array} items
* @param {Info} info
*/
function dispatchFinalizeEvent(el, items, info) {
el.dispatchEvent(new CustomEvent(FINALIZE_EVENT_NAME, {
detail: {
items: items,
info: info
}
}));
}
/**
* Dispatches a consider event
* @param {Node} el
* @param {Array} items
* @param {Info} info
*/
function dispatchConsiderEvent(el, items, info) {
el.dispatchEvent(new CustomEvent(CONSIDER_EVENT_NAME, {
detail: {
items: items,
info: info
}
}));
}
// internal events
var DRAGGED_ENTERED_EVENT_NAME = "draggedEntered";
var DRAGGED_LEFT_EVENT_NAME = "draggedLeft";
var DRAGGED_OVER_INDEX_EVENT_NAME = "draggedOverIndex";
var DRAGGED_LEFT_DOCUMENT_EVENT_NAME = "draggedLeftDocument";
var DRAGGED_LEFT_TYPES = {
LEFT_FOR_ANOTHER: "leftForAnother",
OUTSIDE_OF_ANY: "outsideOfAny"
};
function dispatchDraggedElementEnteredContainer(containerEl, indexObj, draggedEl) {
containerEl.dispatchEvent(new CustomEvent(DRAGGED_ENTERED_EVENT_NAME, {
detail: {
indexObj: indexObj,
draggedEl: draggedEl
}
}));
}
/**
* @param containerEl - the dropzone the element left
* @param draggedEl - the dragged element
* @param theOtherDz - the new dropzone the element entered
*/
function dispatchDraggedElementLeftContainerForAnother(containerEl, draggedEl, theOtherDz) {
containerEl.dispatchEvent(new CustomEvent(DRAGGED_LEFT_EVENT_NAME, {
detail: {
draggedEl: draggedEl,
type: DRAGGED_LEFT_TYPES.LEFT_FOR_ANOTHER,
theOtherDz: theOtherDz
}
}));
}
function dispatchDraggedElementLeftContainerForNone(containerEl, draggedEl) {
containerEl.dispatchEvent(new CustomEvent(DRAGGED_LEFT_EVENT_NAME, {
detail: {
draggedEl: draggedEl,
type: DRAGGED_LEFT_TYPES.OUTSIDE_OF_ANY
}
}));
}
function dispatchDraggedElementIsOverIndex(containerEl, indexObj, draggedEl) {
containerEl.dispatchEvent(new CustomEvent(DRAGGED_OVER_INDEX_EVENT_NAME, {
detail: {
indexObj: indexObj,
draggedEl: draggedEl
}
}));
}
function dispatchDraggedLeftDocument(draggedEl) {
window.dispatchEvent(new CustomEvent(DRAGGED_LEFT_DOCUMENT_EVENT_NAME, {
detail: {
draggedEl: draggedEl
}
}));
}
var TRIGGERS = {
DRAG_STARTED: "dragStarted",
DRAGGED_ENTERED: DRAGGED_ENTERED_EVENT_NAME,
DRAGGED_ENTERED_ANOTHER: "dragEnteredAnother",
DRAGGED_OVER_INDEX: DRAGGED_OVER_INDEX_EVENT_NAME,
DRAGGED_LEFT: DRAGGED_LEFT_EVENT_NAME,
DRAGGED_LEFT_ALL: "draggedLeftAll",
DROPPED_INTO_ZONE: "droppedIntoZone",
DROPPED_INTO_ANOTHER: "droppedIntoAnother",
DROPPED_OUTSIDE_OF_ANY: "droppedOutsideOfAny",
DRAG_STOPPED: "dragStopped"
};
var SOURCES = {
POINTER: "pointer",
KEYBOARD: "keyboard"
};
var SHADOW_ITEM_MARKER_PROPERTY_NAME = "isDndShadowItem";
var SHADOW_ELEMENT_ATTRIBUTE_NAME = "data-is-dnd-shadow-item-internal";
var SHADOW_ELEMENT_HINT_ATTRIBUTE_NAME = "data-is-dnd-shadow-item-hint";
var SHADOW_PLACEHOLDER_ITEM_ID = "id:dnd-shadow-placeholder-0000";
var DRAGGED_ELEMENT_ID = "dnd-action-dragged-el";
var ITEM_ID_KEY = "id";
var activeDndZoneCount = 0;
function incrementActiveDropZoneCount() {
activeDndZoneCount++;
}
function decrementActiveDropZoneCount() {
if (activeDndZoneCount === 0) {
throw new Error("Bug! trying to decrement when there are no dropzones");
}
activeDndZoneCount--;
}
/**
* Allows using another key instead of "id" in the items data. This is global and applies to all dndzones.
* Has to be called when there are no rendered dndzones whatsoever.
* @param {String} newKeyName
* @throws {Error} if it was called when there are rendered dndzones or if it is given the wrong type (not a string)
*/
function overrideItemIdKeyNameBeforeInitialisingDndZones(newKeyName) {
if (activeDndZoneCount > 0) {
throw new Error("can only override the id key before initialising any dndzone");
}
if (typeof newKeyName !== "string") {
throw new Error("item id key has to be a string");
}
printDebug(function () {
return ["overriding item id key name", newKeyName];
});
ITEM_ID_KEY = newKeyName;
}
var isOnServer = typeof window === "undefined";
var printDebug = function printDebug() {};
/**
* Allows the user to show/hide console debug output
* * @param {boolean} isDebug
*/
function setDebugMode(isDebug) {
if (isDebug) {
printDebug = function printDebug(generateMessage) {
var logFunction = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : console.debug;
var message = generateMessage();
if (Array.isArray(message)) {
logFunction.apply(void 0, _toConsumableArray(message));
} else {
logFunction(message);
}
};
} else {
printDebug = function printDebug() {};
}
}
// This is based off https://stackoverflow.com/questions/27745438/how-to-compute-getboundingclientrect-without-considering-transforms/57876601#57876601
// It removes the transforms that are potentially applied by the flip animations
/**
* Gets the bounding rect but removes transforms (ex: flip animation)
* @param {HTMLElement} el
* @param {boolean} [onlyVisible] - use the visible rect defaults to true
* @return {{top: number, left: number, bottom: number, right: number}}
*/
function getBoundingRectNoTransforms(el) {
var onlyVisible = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : true;
var ta;
var rect = onlyVisible ? getVisibleRectRecursive(el) : el.getBoundingClientRect();
var style = getComputedStyle(el);
var tx = style.transform;
if (tx) {
var sx, sy, dx, dy;
if (tx.startsWith("matrix3d(")) {
ta = tx.slice(9, -1).split(/, /);
sx = +ta[0];
sy = +ta[5];
dx = +ta[12];
dy = +ta[13];
} else if (tx.startsWith("matrix(")) {
ta = tx.slice(7, -1).split(/, /);
sx = +ta[0];
sy = +ta[3];
dx = +ta[4];
dy = +ta[5];
} else {
return rect;
}
var to = style.transformOrigin;
var x = rect.x - dx - (1 - sx) * parseFloat(to);
var y = rect.y - dy - (1 - sy) * parseFloat(to.slice(to.indexOf(" ") + 1));
var w = sx ? rect.width / sx : el.offsetWidth;
var h = sy ? rect.height / sy : el.offsetHeight;
return {
x: x,
y: y,
width: w,
height: h,
top: y,
right: x + w,
bottom: y + h,
left: x
};
} else {
return rect;
}
}
/**
* Gets the absolute bounding rect (accounts for the window's scroll position and removes transforms)
* @param {HTMLElement} el
* @return {{top: number, left: number, bottom: number, right: number}}
*/
function getAbsoluteRectNoTransforms(el) {
var rect = getBoundingRectNoTransforms(el);
return {
top: rect.top + window.scrollY,
bottom: rect.bottom + window.scrollY,
left: rect.left + window.scrollX,
right: rect.right + window.scrollX
};
}
/**
* Gets the absolute bounding rect (accounts for the window's scroll position)
* @param {HTMLElement} el
* @return {{top: number, left: number, bottom: number, right: number}}
*/
function getAbsoluteRect(el) {
var rect = el.getBoundingClientRect();
return {
top: rect.top + window.scrollY,
bottom: rect.bottom + window.scrollY,
left: rect.left + window.scrollX,
right: rect.right + window.scrollX
};
}
/**
* finds the center :)
* @typedef {Object} Rect
* @property {number} top
* @property {number} bottom
* @property {number} left
* @property {number} right
* @param {Rect} rect
* @return {{x: number, y: number}}
*/
function findCenter(rect) {
return {
x: (rect.left + rect.right) / 2,
y: (rect.top + rect.bottom) / 2
};
}
/**
* @typedef {Object} Point
* @property {number} x
* @property {number} y
* @param {Point} pointA
* @param {Point} pointB
* @return {number}
*/
function calcDistance(pointA, pointB) {
return Math.sqrt(Math.pow(pointA.x - pointB.x, 2) + Math.pow(pointA.y - pointB.y, 2));
}
/**
* @param {Point} point
* @param {Rect} rect
* @return {boolean|boolean}
*/
function isPointInsideRect(point, rect) {
return point.y <= rect.bottom && point.y >= rect.top && point.x >= rect.left && point.x <= rect.right;
}
/**
* find the absolute coordinates of the center of a dom element
* @param el {HTMLElement}
* @returns {{x: number, y: number}}
*/
function findCenterOfElement(el) {
return findCenter(getAbsoluteRect(el));
}
/**
* @param {HTMLElement} elA
* @param {HTMLElement} elB
* @return {boolean}
*/
function isCenterOfAInsideB(elA, elB) {
var centerOfA = findCenterOfElement(elA);
var rectOfB = getAbsoluteRectNoTransforms(elB);
return isPointInsideRect(centerOfA, rectOfB);
}
/**
* @param {HTMLElement|ChildNode} elA
* @param {HTMLElement|ChildNode} elB
* @return {number}
*/
function calcDistanceBetweenCenters(elA, elB) {
var centerOfA = findCenterOfElement(elA);
var centerOfB = findCenterOfElement(elB);
return calcDistance(centerOfA, centerOfB);
}
/**
* @param {HTMLElement} el - the element to check
* @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)
*/
function isElementOffDocument(el) {
var rect = getAbsoluteRect(el);
return rect.right < 0 || rect.left > document.documentElement.scrollWidth || rect.bottom < 0 || rect.top > document.documentElement.scrollHeight;
}
function getVisibleRectRecursive(element) {
var rect = element.getBoundingClientRect();
var visibleRect = {
top: rect.top,
bottom: rect.bottom,
left: rect.left,
right: rect.right
};
// Traverse up the DOM hierarchy, checking for scrollable ancestors
var parent = element.parentElement;
while (parent && parent !== document.body) {
var parentRect = parent.getBoundingClientRect();
// Check if the parent has a scrollable overflow
var overflowY = window.getComputedStyle(parent).overflowY;
var overflowX = window.getComputedStyle(parent).overflowX;
var isScrollableY = overflowY === "scroll" || overflowY === "auto";
var isScrollableX = overflowX === "scroll" || overflowX === "auto";
// Constrain the visible area to the parent's visible area
if (isScrollableY) {
visibleRect.top = Math.max(visibleRect.top, parentRect.top);
visibleRect.bottom = Math.min(visibleRect.bottom, parentRect.bottom);
}
if (isScrollableX) {
visibleRect.left = Math.max(visibleRect.left, parentRect.left);
visibleRect.right = Math.min(visibleRect.right, parentRect.right);
}
parent = parent.parentElement;
}
// Finally, constrain the visible rect to the viewport
visibleRect.top = Math.max(visibleRect.top, 0);
visibleRect.bottom = Math.min(visibleRect.bottom, window.innerHeight);
visibleRect.left = Math.max(visibleRect.left, 0);
visibleRect.right = Math.min(visibleRect.right, window.innerWidth);
// Return the visible rectangle, ensuring that all values are valid
return {
top: visibleRect.top,
bottom: visibleRect.bottom,
left: visibleRect.left,
right: visibleRect.right,
width: Math.max(0, visibleRect.right - visibleRect.left),
height: Math.max(0, visibleRect.bottom - visibleRect.top)
};
}
var dzToShadowIndexToRect;
/**
* Resets the cache that allows for smarter "would be index" resolution. Should be called after every drag operation
*/
function resetIndexesCache() {
printDebug(function () {
return "resetting indexes cache";
});
dzToShadowIndexToRect = new Map();
}
resetIndexesCache();
/**
* Caches the coordinates of the shadow element when it's in a certain index in a certain dropzone.
* Helpful in order to determine "would be index" more effectively
* @param {HTMLElement} dz
* @return {number} - the shadow element index
*/
function cacheShadowRect(dz) {
var shadowElIndex = Array.from(dz.children).findIndex(function (child) {
return child.getAttribute(SHADOW_ELEMENT_ATTRIBUTE_NAME);
});
if (shadowElIndex >= 0) {
if (!dzToShadowIndexToRect.has(dz)) {
dzToShadowIndexToRect.set(dz, new Map());
}
dzToShadowIndexToRect.get(dz).set(shadowElIndex, getAbsoluteRectNoTransforms(dz.children[shadowElIndex]));
return shadowElIndex;
}
return undefined;
}
/**
* @typedef {Object} Index
* @property {number} index - the would be index
* @property {boolean} isProximityBased - false if the element is actually over the index, true if it is not over it but this index is the closest
*/
/**
* Find the index for the dragged element in the list it is dragged over
* @param {HTMLElement} floatingAboveEl
* @param {HTMLElement} collectionBelowEl
* @returns {Index|null} - if the element is over the container the Index object otherwise null
*/
function findWouldBeIndex(floatingAboveEl, collectionBelowEl) {
if (!isCenterOfAInsideB(floatingAboveEl, collectionBelowEl)) {
return null;
}
var children = collectionBelowEl.children;
// the container is empty, floating element should be the first
if (children.length === 0) {
return {
index: 0,
isProximityBased: true
};
}
var shadowElIndex = cacheShadowRect(collectionBelowEl);
// the search could be more efficient but keeping it simple for now
// a possible improvement: pass in the lastIndex it was found in and check there first, then expand from there
for (var i = 0; i < children.length; i++) {
if (isCenterOfAInsideB(floatingAboveEl, children[i])) {
var cachedShadowRect = dzToShadowIndexToRect.has(collectionBelowEl) && dzToShadowIndexToRect.get(collectionBelowEl).get(i);
if (cachedShadowRect) {
if (!isPointInsideRect(findCenterOfElement(floatingAboveEl), cachedShadowRect)) {
return {
index: shadowElIndex,
isProximityBased: false
};
}
}
return {
index: i,
isProximityBased: false
};
}
}
// this can happen if there is space around the children so the floating element has
//entered the container but not any of the children, in this case we will find the nearest child
var minDistanceSoFar = Number.MAX_VALUE;
var indexOfMin = undefined;
// 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
for (var _i = 0; _i < children.length; _i++) {
var distance = calcDistanceBetweenCenters(floatingAboveEl, children[_i]);
if (distance < minDistanceSoFar) {
minDistanceSoFar = distance;
indexOfMin = _i;
}
}
// -------- Phantom slot check --------
// Regardless of layout (simple vertical list, flex-wrap, grid, floats …) the
// visually closest drop target can be *after* the current last **real** child.
// In simple layouts the would be index from the existing children would always be the last index
// but in more complex layouts (flex-wrap, grid, floats …) it can be any index.
// The problem is we can't predict where an additional element would be rendered in the general case,
// We therefore create a temporary, invisible clone of that last element, let
// the browser position it, measure the distance, and remove it immediately
// (same task → no paint). This leaves `children` back in its original state
// before we exit the function, so existing index-caching logic and shadow-
// element bookkeeping continue to work unchanged.
if (children.length > 0) {
var originalLen = children.length; // before we append the phantom
var template = children[originalLen - 1];
var phantom = template.cloneNode(false); // shallow clone is enough for size
phantom.style.visibility = "hidden";
phantom.style.pointerEvents = "none";
collectionBelowEl.appendChild(phantom);
var phantomDistance = calcDistanceBetweenCenters(floatingAboveEl, phantom);
if (phantomDistance < minDistanceSoFar) {
indexOfMin = originalLen; // index of phantom slot in original list
}
collectionBelowEl.removeChild(phantom);
}
return {
index: indexOfMin,
isProximityBased: true
};
}
/**
* @param {Object} object
* @return {string}
*/
function toString(object) {
return JSON.stringify(object, null, 2);
}
/**
* Finds the depth of the given node in the DOM tree
* @param {HTMLElement} node
* @return {number} - the depth of the node
*/
function getDepth(node) {
if (!node) {
throw new Error("cannot get depth of a falsy node");
}
return _getDepth(node, 0);
}
function _getDepth(node) {
var countSoFar = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 0;
if (!node.parentElement) {
return countSoFar - 1;
}
return _getDepth(node.parentElement, countSoFar + 1);
}
/**
* A simple util to shallow compare objects quickly, it doesn't validate the arguments so pass objects in
* @param {Object} objA
* @param {Object} objB
* @return {boolean} - true if objA and objB are shallow equal
*/
function areObjectsShallowEqual(objA, objB) {
if (Object.keys(objA).length !== Object.keys(objB).length) {
return false;
}
for (var keyA in objA) {
if (!{}.hasOwnProperty.call(objB, keyA) || objB[keyA] !== objA[keyA]) {
return false;
}
}
return true;
}
/**
* Shallow compares two arrays
* @param arrA
* @param arrB
* @return {boolean} - whether the arrays are shallow equal
*/
function areArraysShallowEqualSameOrder(arrA, arrB) {
if (arrA.length !== arrB.length) {
return false;
}
for (var i = 0; i < arrA.length; i++) {
if (arrA[i] !== arrB[i]) {
return false;
}
}
return true;
}
var INTERVAL_MS = 200;
var TOLERANCE_PX = 10;
var next;
/**
* Tracks the dragged elements and performs the side effects when it is dragged over a drop zone (basically dispatching custom-events scrolling)
* @param {Set<HTMLElement>} dropZones
* @param {HTMLElement} draggedEl
* @param {number} [intervalMs = INTERVAL_MS]
* @param {MultiScroller} multiScroller
*/
function observe(draggedEl, dropZones) {
var intervalMs = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : INTERVAL_MS;
var multiScroller = arguments.length > 3 ? arguments[3] : undefined;
// initialization
var lastDropZoneFound;
var lastIndexFound;
var lastIsDraggedInADropZone = false;
var lastCentrePositionOfDragged;
// We are sorting to make sure that in case of nested zones of the same type the one "on top" is considered first
var dropZonesFromDeepToShallow = Array.from(dropZones).sort(function (dz1, dz2) {
return getDepth(dz2) - getDepth(dz1);
});
/**
* The main function in this module. Tracks where everything is/ should be a take the actions
*/
function andNow() {
var currentCenterOfDragged = findCenterOfElement(draggedEl);
var scrolled = multiScroller.multiScrollIfNeeded();
// we only want to make a new decision after the element was moved a bit to prevent flickering
if (!scrolled && lastCentrePositionOfDragged && Math.abs(lastCentrePositionOfDragged.x - currentCenterOfDragged.x) < TOLERANCE_PX && Math.abs(lastCentrePositionOfDragged.y - currentCenterOfDragged.y) < TOLERANCE_PX) {
next = window.setTimeout(andNow, intervalMs);
return;
}
if (isElementOffDocument(draggedEl)) {
printDebug(function () {
return "off document";
});
dispatchDraggedLeftDocument(draggedEl);
return;
}
lastCentrePositionOfDragged = currentCenterOfDragged;
// this is a simple algorithm, potential improvement: first look at lastDropZoneFound
var isDraggedInADropZone = false;
var _iterator = _createForOfIteratorHelper(dropZonesFromDeepToShallow),
_step;
try {
for (_iterator.s(); !(_step = _iterator.n()).done;) {
var dz = _step.value;
if (scrolled) resetIndexesCache();
var indexObj = findWouldBeIndex(draggedEl, dz);
if (indexObj === null) {
// it is not inside
continue;
}
var index = indexObj.index;
isDraggedInADropZone = true;
// the element is over a container
if (dz !== lastDropZoneFound) {
lastDropZoneFound && dispatchDraggedElementLeftContainerForAnother(lastDropZoneFound, draggedEl, dz);
dispatchDraggedElementEnteredContainer(dz, indexObj, draggedEl);
lastDropZoneFound = dz;
} else if (index !== lastIndexFound) {
dispatchDraggedElementIsOverIndex(dz, indexObj, draggedEl);
lastIndexFound = index;
}
// we handle looping with the 'continue' statement above
break;
}
// the first time the dragged element is not in any dropzone we need to notify the last dropzone it was in
} catch (err) {
_iterator.e(err);
} finally {
_iterator.f();
}
if (!isDraggedInADropZone && lastIsDraggedInADropZone && lastDropZoneFound) {
dispatchDraggedElementLeftContainerForNone(lastDropZoneFound, draggedEl);
lastDropZoneFound = undefined;
lastIndexFound = undefined;
lastIsDraggedInADropZone = false;
} else {
lastIsDraggedInADropZone = true;
}
next = window.setTimeout(andNow, intervalMs);
}
andNow();
}
// assumption - we can only observe one dragged element at a time, this could be changed in the future
function unobserve() {
printDebug(function () {
return "unobserving";
});
clearTimeout(next);
resetIndexesCache();
}
var SCROLL_ZONE_PX = 30;
/**
* Will make a scroller that can scroll any element given to it in any direction
* @returns {{scrollIfNeeded: function(Point, HTMLElement): boolean, resetScrolling: function(void):void}}
*/
function makeScroller() {
var scrollingInfo;
function resetScrolling() {
scrollingInfo = {
directionObj: undefined,
stepPx: 0
};
}
resetScrolling();
// directionObj {x: 0|1|-1, y:0|1|-1} - 1 means down in y and right in x
function scrollContainer(containerEl) {
var _scrollingInfo = scrollingInfo,
directionObj = _scrollingInfo.directionObj,
stepPx = _scrollingInfo.stepPx;
if (directionObj) {
containerEl.scrollBy(directionObj.x * stepPx, directionObj.y * stepPx);
window.requestAnimationFrame(function () {
return scrollContainer(containerEl);
});
}
}
function calcScrollStepPx(distancePx) {
return SCROLL_ZONE_PX - distancePx;
}
/**
* @param {Point} pointer - the pointer will be used to decide in which direction to scroll
* @param {HTMLElement} elementToScroll - the scroll container
* If the pointer is next to the sides of the element to scroll, will trigger scrolling
* Can be called repeatedly with updated pointer and elementToScroll values without issues
* @return {boolean} - true if scrolling was needed
*/
function scrollIfNeeded(pointer, elementToScroll) {
if (!elementToScroll) {
return false;
}
var distances = calcInnerDistancesBetweenPointAndSidesOfElement(pointer, elementToScroll);
var isAlreadyScrolling = !!scrollingInfo.directionObj;
if (distances === null) {
if (isAlreadyScrolling) resetScrolling();
return false;
}
var scrollingVertically = false,
scrollingHorizontally = false;
// vertical
if (elementToScroll.scrollHeight > elementToScroll.clientHeight) {
if (distances.bottom < SCROLL_ZONE_PX) {
scrollingVertically = true;
scrollingInfo.directionObj = {
x: 0,
y: 1
};
scrollingInfo.stepPx = calcScrollStepPx(distances.bottom);
} else if (distances.top < SCROLL_ZONE_PX) {
scrollingVertically = true;
scrollingInfo.directionObj = {
x: 0,
y: -1
};
scrollingInfo.stepPx = calcScrollStepPx(distances.top);
}
if (!isAlreadyScrolling && scrollingVertically) {
scrollContainer(elementToScroll);
return true;
}
}
// horizontal
if (elementToScroll.scrollWidth > elementToScroll.clientWidth) {
if (distances.right < SCROLL_ZONE_PX) {
scrollingHorizontally = true;
scrollingInfo.directionObj = {
x: 1,
y: 0
};
scrollingInfo.stepPx = calcScrollStepPx(distances.right);
} else if (distances.left < SCROLL_ZONE_PX) {
scrollingHorizontally = true;
scrollingInfo.directionObj = {
x: -1,
y: 0
};
scrollingInfo.stepPx = calcScrollStepPx(distances.left);
}
if (!isAlreadyScrolling && scrollingHorizontally) {
scrollContainer(elementToScroll);
return true;
}
}
resetScrolling();
return false;
}
return {
scrollIfNeeded: scrollIfNeeded,
resetScrolling: resetScrolling
};
}
/**
* If the point is inside the element returns its distances from the sides, otherwise returns null
* @param {Point} point
* @param {HTMLElement} el
* @return {null|{top: number, left: number, bottom: number, right: number}}
*/
function calcInnerDistancesBetweenPointAndSidesOfElement(point, el) {
// Even if the scrolling element is small it acts as a scroller for the viewport
var rect = el === document.scrollingElement ? {
top: 0,
bottom: window.innerHeight,
left: 0,
right: window.innerWidth
} : el.getBoundingClientRect();
if (!isPointInsideRect(point, rect)) {
return null;
}
return {
top: point.y - rect.top,
bottom: rect.bottom - point.y,
left: point.x - rect.left,
right: rect.right - point.x
};
}
/**
@typedef {Object} MultiScroller
@property {function():boolean} multiScrollIfNeeded - call this on every "tick" to scroll containers if needed, returns true if anything was scrolled
/**
* Creates a scroller than can scroll any of the provided containers or any of their scrollable parents (including the document's scrolling element)
* @param {HTMLElement[]} baseElementsForScrolling
* @param {function():Point} getPointerPosition
* @return {MultiScroller}
*/
function createMultiScroller() {
var baseElementsForScrolling = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : [];
var getPointerPosition = arguments.length > 1 ? arguments[1] : undefined;
printDebug(function () {
return "creating multi-scroller";
});
var scrollingContainersSet = findRelevantScrollContainers(baseElementsForScrolling);
var scrollingContainersDeepToShallow = Array.from(scrollingContainersSet).sort(function (dz1, dz2) {
return getDepth(dz2) - getDepth(dz1);
});
var _makeScroller = makeScroller(),
scrollIfNeeded = _makeScroller.scrollIfNeeded,
resetScrolling = _makeScroller.resetScrolling;
/**
* @return {boolean} - was any container scrolled
*/
function tick() {
var mousePosition = getPointerPosition();
if (!mousePosition || !scrollingContainersDeepToShallow) {
return false;
}
var scrollContainersUnderCursor = scrollingContainersDeepToShallow.filter(function (el) {
return isPointInsideRect(mousePosition, el.getBoundingClientRect()) || el === document.scrollingElement;
});
for (var i = 0; i < scrollContainersUnderCursor.length; i++) {
var scrolled = scrollIfNeeded(mousePosition, scrollContainersUnderCursor[i]);
if (scrolled) {
return true;
}
}
return false;
}
return {
multiScrollIfNeeded: scrollingContainersSet.size > 0 ? tick : function () {
return false;
},
destroy: function destroy() {
return resetScrolling();
}
};
}
// internal utils
function findScrollableParents(element) {
if (!element) {
return [];
}
var scrollableContainers = [];
var parent = element;
while (parent) {
var _window$getComputedSt = window.getComputedStyle(parent),
overflow = _window$getComputedSt.overflow;
if (overflow.split(" ").some(function (o) {
return o.includes("auto") || o.includes("scroll");
})) {
scrollableContainers.push(parent);
}
parent = parent.parentElement;
}
return scrollableContainers;
}
function findRelevantScrollContainers(dropZones) {
var scrollingContainers = new Set();
var _iterator = _createForOfIteratorHelper(dropZones),
_step;
try {
for (_iterator.s(); !(_step = _iterator.n()).done;) {
var dz = _step.value;
findScrollableParents(dz).forEach(function (container) {
return scrollingContainers.add(container);
});
}
// The scrolling element might have overflow visible and still be scrollable
} catch (err) {
_iterator.e(err);
} finally {
_iterator.f();
}
if (document.scrollingElement.scrollHeight > document.scrollingElement.clientHeight || document.scrollingElement.scrollWidth > document.scrollingElement.clientHeight) {
scrollingContainers.add(document.scrollingElement);
}
return scrollingContainers;
}
/**
* Fixes svelte issue when cloning node containing (or being) <select> which will loose it's value.
* Since svelte manages select value internally.
* @see https://github.com/sveltejs/svelte/issues/6717
* @see https://github.com/isaacHagoel/svelte-dnd-action/issues/306
*
* @param {HTMLElement} el
* @returns
*/
function svelteNodeClone(el) {
var cloned = el.cloneNode(true);
var values = [];
var elIsSelect = el.tagName === "SELECT";
var selects = elIsSelect ? [el] : _toConsumableArray(el.querySelectorAll("select"));
var _iterator = _createForOfIteratorHelper(selects),
_step;
try {
for (_iterator.s(); !(_step = _iterator.n()).done;) {
var _select = _step.value;
values.push(_select.value);
}
} catch (err) {
_iterator.e(err);
} finally {
_iterator.f();
}
if (selects.length > 0) {
var clonedSelects = elIsSelect ? [cloned] : _toConsumableArray(cloned.querySelectorAll("select"));
for (var i = 0; i < clonedSelects.length; i++) {
var select = clonedSelects[i];
var value = values[i];
var optionEl = select.querySelector("option[value=\"".concat(value, "\""));
if (optionEl) {
optionEl.setAttribute("selected", true);
}
}
}
var elIsCanvas = el.tagName === "CANVAS";
var canvases = elIsCanvas ? [el] : _toConsumableArray(el.querySelectorAll("canvas"));
if (canvases.length > 0) {
var clonedCanvases = elIsCanvas ? [cloned] : _toConsumableArray(cloned.querySelectorAll("canvas"));
for (var _i = 0; _i < clonedCanvases.length; _i++) {
var canvas = canvases[_i];
var clonedCanvas = clonedCanvases[_i];
clonedCanvas.width = canvas.width;
clonedCanvas.height = canvas.height;
if (canvas.width > 0 && canvas.height > 0) {
clonedCanvas.getContext("2d").drawImage(canvas, 0, 0);
}
}
}
return cloned;
}
/**
* @type {{USE_COMPUTED_STYLE_INSTEAD_OF_BOUNDING_RECT: string}}
*/
var FEATURE_FLAG_NAMES = Object.freeze({
// This flag exists as a workaround for issue 454 (basically a browser bug) - seems like these rect values take time to update when in grid layout. Setting it to true can cause strange behaviour in the REPL for non-grid zones, see issue 470
USE_COMPUTED_STYLE_INSTEAD_OF_BOUNDING_RECT: "USE_COMPUTED_STYLE_INSTEAD_OF_BOUNDING_RECT"
});
var featureFlagsMap = _defineProperty({}, FEATURE_FLAG_NAMES.USE_COMPUTED_STYLE_INSTEAD_OF_BOUNDING_RECT, false);
/**
* @param {FEATURE_FLAG_NAMES} flagName
* @param {boolean} flagValue
*/
function setFeatureFlag(flagName, flagValue) {
if (!FEATURE_FLAG_NAMES[flagName]) throw new Error("Can't set non existing feature flag ".concat(flagName, "! Supported flags: ").concat(Object.keys(FEATURE_FLAG_NAMES)));
featureFlagsMap[flagName] = !!flagValue;
}
/**
*
* @param {FEATURE_FLAG_NAMES} flagName
* @return {boolean}
*/
function getFeatureFlag(flagName) {
if (!FEATURE_FLAG_NAMES[flagName]) throw new Error("Can't get non existing feature flag ".concat(flagName, "! Supported flags: ").concat(Object.keys(FEATURE_FLAG_NAMES)));
return featureFlagsMap[flagName];
}
var TRANSITION_DURATION_SECONDS = 0.2;
/**
* private helper function - creates a transition string for a property
* @param {string} property
* @return {string} - the transition string
*/
function trs(property) {
return "".concat(property, " ").concat(TRANSITION_DURATION_SECONDS, "s ease");
}
/**
* clones the given element and applies proper styles and transitions to the dragged element
* @param {HTMLElement} originalElement
* @param {Point} [positionCenterOnXY]
* @return {Node} - the cloned, styled element
*/
function createDraggedElementFrom(originalElement, positionCenterOnXY) {
var rect = originalElement.getBoundingClientRect();
var draggedEl = svelteNodeClone(originalElement);
copyStylesFromTo(originalElement, draggedEl);
draggedEl.id = DRAGGED_ELEMENT_ID;
draggedEl.style.position = "fixed";
var elTopPx = rect.top;
var elLeftPx = rect.left;
draggedEl.style.top = "".concat(elTopPx, "px");
draggedEl.style.left = "".concat(elLeftPx, "px");
if (positionCenterOnXY) {
var center = findCenter(rect);
elTopPx -= center.y - positionCenterOnXY.y;
elLeftPx -= center.x - positionCenterOnXY.x;
window.setTimeout(function () {
draggedEl.style.top = "".concat(elTopPx, "px");
draggedEl.style.left = "".concat(elLeftPx, "px");
}, 0);
}
draggedEl.style.margin = "0";
// we can't have relative or automatic height and width or it will break the illusion
draggedEl.style.boxSizing = "border-box";
draggedEl.style.height = "".concat(rect.height, "px");
draggedEl.style.width = "".concat(rect.width, "px");
draggedEl.style.transition = "".concat(trs("top"), ", ").concat(trs("left"), ", ").concat(trs("background-color"), ", ").concat(trs("opacity"), ", ").concat(trs("color"), " ");
// this is a workaround for a strange browser bug that causes the right border to disappear when all the transitions are added at the same time
window.setTimeout(function () {
return draggedEl.style.transition += ", ".concat(trs("width"), ", ").concat(trs("height"));
}, 0);
draggedEl.style.zIndex = "9999";
draggedEl.style.cursor = "grabbing";
return draggedEl;
}
/**
* styles the dragged element to a 'dropped' state
* @param {HTMLElement} draggedEl
*/
function moveDraggedElementToWasDroppedState(draggedEl) {
draggedEl.style.cursor = "grab";
}
/**
* Morphs the dragged element style, maintains the mouse pointer within the element
* @param {HTMLElement} draggedEl
* @param {HTMLElement} copyFromEl - the element the dragged element should look like, typically the shadow element
* @param {number} currentMouseX
* @param {number} currentMouseY
*/
function morphDraggedElementToBeLike(draggedEl, copyFromEl, currentMouseX, currentMouseY) {
copyStylesFromTo(copyFromEl, draggedEl);
var newRect = copyFromEl.getBoundingClientRect();
var draggedElRect = draggedEl.getBoundingClientRect();
var widthChange = newRect.width - draggedElRect.width;
var heightChange = newRect.height - draggedElRect.height;
if (widthChange || heightChange) {
var relativeDistanceOfMousePointerFromDraggedSides = {
left: (currentMouseX - draggedElRect.left) / draggedElRect.width,
top: (currentMouseY - draggedElRect.top) / draggedElRect.height
};
if (!getFeatureFlag(FEATURE_FLAG_NAMES.USE_COMPUTED_STYLE_INSTEAD_OF_BOUNDING_RECT)) {
draggedEl.style.height = "".concat(newRect.height, "px");
draggedEl.style.width = "".concat(newRect.width, "px");
}
draggedEl.style.left = "".concat(parseFloat(draggedEl.style.left) - relativeDistanceOfMousePointerFromDraggedSides.left * widthChange, "px");
draggedEl.style.top = "".concat(parseFloat(draggedEl.style.top) - relativeDistanceOfMousePointerFromDraggedSides.top * heightChange, "px");
}
}
/**
* @param {HTMLElement} copyFromEl
* @param {HTMLElement} copyToEl
*/
function copyStylesFromTo(copyFromEl, copyToEl) {
var computedStyle = window.getComputedStyle(copyFromEl);
Array.from(computedStyle).filter(function (s) {
return s.startsWith("background") || s.startsWith("padding") || s.startsWith("font") || s.startsWith("text") || s.startsWith("align") || s.startsWith("justify") || s.startsWith("display") || s.startsWith("flex") || s.startsWith("border") || s === "opacity" || s === "color" || s === "list-style-type" ||
// copying with and height to make up for rect update timing issues in some browsers
getFeatureFlag(FEATURE_FLAG_NAMES.USE_COMPUTED_STYLE_INSTEAD_OF_BOUNDING_RECT) && (s === "width" || s === "height");
}).forEach(function (s) {
return copyToEl.style.setProperty(s, computedStyle.getPropertyValue(s), computedStyle.getPropertyPriority(s));
});
}
/**
* makes the element compatible with being draggable
* @param {HTMLElement} draggableEl
* @param {boolean} dragDisabled
*/
function styleDraggable(draggableEl, dragDisabled) {
draggableEl.draggable = false;
draggableEl.ondragstart = function () {
return false;
};
if (!dragDisabled) {
draggableEl.style.userSelect = "none";
draggableEl.style.WebkitUserSelect = "none";
draggableEl.style.cursor = "grab";
} else {
draggableEl.style.userSelect = "";
draggableEl.style.WebkitUserSelect = "";
draggableEl.style.cursor = "";
}
}
/**
* Hides the provided element so that it can stay in the dom without interrupting
* @param {HTMLElement} dragTarget
*/
function hideElement(dragTarget) {
dragTarget.style.display = "none";
dragTarget.style.position = "fixed";
dragTarget.style.zIndex = "-5";
}
/**
* styles the shadow element
* @param {HTMLElement} shadowEl
*/
function decorateShadowEl(shadowEl) {
shadowEl.style.visibility = "hidden";
shadowEl.setAttribute(SHADOW_ELEMENT_ATTRIBUTE_NAME, "true");
}
/**
* undo the styles the shadow element
* @param {HTMLElement} shadowEl
*/
function unDecorateShadowElement(shadowEl) {
shadowEl.style.visibility = "";
shadowEl.removeAttribute(SHADOW_ELEMENT_ATTRIBUTE_NAME);
}
/**
* will mark the given dropzones as visually active
* @param {Array<HTMLElement>} dropZones
* @param {Function} getStyles - maps a dropzone to a styles object (so the styles can be removed)
* @param {Function} getClasses - maps a dropzone to a classList
*/
function styleActiveDropZones(dropZones) {
var getStyles = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : function () {};
var getClasses = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : function () {
return [];
};
dropZones.forEach(function (dz) {
var styles = getStyles(dz);
Object.keys(styles).forEach(function (style) {
dz.style[style] = styles[style];
});
getClasses(dz).forEach(function (c) {
return dz.classList.add(c);
});
});
}
/**
* will remove the 'active' styling from given dropzones
* @param {Array<HTMLElement>} dropZones
* @param {Function} getStyles - maps a dropzone to a styles object
* @param {Function} getClasses - maps a dropzone to a classList
*/
function styleInactiveDropZones(dropZones) {
var getStyles = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : function () {};
var getClasses = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : function () {
return [];
};
dropZones.forEach(function (dz) {
var styles = getStyles(dz);
Object.keys(styles).forEach(function (style) {
dz.style[style] = "";
});
getClasses(dz).forEach(function (c) {
return dz.classList.contains(c) && dz.classList.remove(c);
});
});
}
/**
* will prevent the provided element from shrinking by setting its minWidth and minHeight to the current width and height values
* @param {HTMLElement} el
* @return {function(): void} - run this function to undo the operation and restore the original values
*/
function preventShrinking(el) {
var originalMinHeight = el.style.minHeight;
el.style.minHeight = window.getComputedStyle(el).getPropertyValue("height");
var originalMinWidth = el.style.minWidth;
el.style.minWidth = window.getComputedStyle(el).getPropertyValue("width");
return function undo() {
el.style.minHeight = originalMinHeight;
el.style.minWidth = originalMinWidth;
};
}
var DEFAULT_DROP_ZONE_TYPE$1 = "--any--";
var MIN_OBSERVATION_INTERVAL_MS = 100;
var DISABLED_OBSERVATION_INTERVAL_MS = 20;
var MIN_MOVEMENT_BEFORE_DRAG_START_PX = 3;
var DEFAULT_TOUCH_DELAY_MS = 80;
var DEFAULT_DROP_TARGET_STYLE$1 = {
outline: "rgba(255, 255, 102, 0.7) solid 2px"
};
var ORIGINAL_DRAGGED_ITEM_MARKER_ATTRIBUTE = "data-is-dnd-original-dragged-item";
var originalDragTarget;
var draggedEl;
var draggedElData;
var draggedElType;
var originDropZone;
var originIndex;
var shadowElData;
var shadowElDropZone;
var dragStartMousePosition;
var currentMousePosition;
var isWorkingOnPreviousDrag = false;
var finalizingPreviousDrag = false;
var unlockOriginDzMinDimensions;
var isDraggedOutsideOfAnyDz = false;
var scheduledForRemovalAfterDrop = [];
var multiScroller;
var touchDragHoldTimer;
var touchHoldElapsed = false;
// a map from type to a set of drop-zones
var typeToDropZones$1 = new Map();
// important - this is needed because otherwise the config that would be used for everyone is the config of the element that created the event listeners
var dzToConfig$1 = new Map();
// this is needed in order to be able to cleanup old listeners and avoid stale closures issues (as the listener is defined within each zone)
var elToMouseDownListener = new WeakMap();
/* drop-zones registration management */
function registerDropZone$1(dropZoneEl, type) {
printDebug(function () {
return "registering drop-zone if absent";
});
if (!typeToDropZones$1.has(type)) {
typeToDropZones$1.set(type, new Set());
}
if (!typeToDropZones$1.get(type).has(dropZoneEl)) {
typeToDropZones$1.get(type).add(dropZoneEl);
incrementActiveDropZoneCount();
}
}
function unregisterDropZone$1(dropZoneEl, type) {
typeToDropZones$1.get(type)["delete"](dropZoneEl);
decrementActiveDropZoneCount();
if (typeToDropZones$1.get(type).size === 0) {
typeToDropZones$1["delete"](type);
}
}
/* functions to manage observing the dragged element and trigger custom drag-events */
function watchDraggedElement() {
printDebug(function () {
return "watching dragged element";
});
var dropZones = typeToDropZones$1.get(draggedElType);
var _iterator = _createForOfIteratorHelper(dropZones),
_step;
try {
for (_iterator.s(); !(_step = _iterator.n()).done;) {
var dz = _step.value;
dz.addEventListener(DRAGGED_ENTERED_EVENT_NAME, handleDraggedEntered);
dz.addEventListener(DRAGGED_LEFT_EVENT_NAME, handleDraggedLeft);
dz.addEventListener(DRAGGED_OVER_INDEX_EVENT_NAME, handleDraggedIsOverIndex);
}
} catch (err) {
_iterator.e(err);
} finally {
_iterator.f();
}
window.addEventListener(DRAGGED_LEFT_DOCUMENT_EVENT_NAME, handleDrop$1);
// 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
var setIntervalMs = Math.max.apply(Math, _toConsumableArray(Array.from(dropZones.keys()).map(function (dz) {
return dzToConfig$1.get(dz).dropAnimationDurationMs;
})));
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.
multiScroller = createMultiScroller(dropZones, function () {
return currentMousePosition;
});
observe(draggedEl, dropZones, observationIntervalMs * 1.07, multiScroller);
}
function unWatchDraggedElement() {
printDebug(function () {
return "unwatching dragged element";
});
var dropZones = typeToDropZones$1.get(draggedElType);
var _iterator2 = _createForOfIteratorHelper(dropZones),
_step2;
try {
for (_iterator2.s(); !(_step2 = _iterator2.n()).done;) {
var dz = _step2.value