UNPKG

@shopify/draggable

Version:

The JavaScript Drag & Drop library your grandparents warned you about.

1,736 lines (1,517 loc) 114 kB
(function (global, factory) { typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports) : typeof define === 'function' && define.amd ? define(['exports'], factory) : (global = typeof globalThis !== 'undefined' ? globalThis : global || self, factory(global.Draggable = {})); })(this, (function (exports) { 'use strict'; class AbstractEvent { constructor(data) { this._canceled = false; this.data = data; } get type() { return this.constructor.type; } get cancelable() { return this.constructor.cancelable; } cancel() { this._canceled = true; } canceled() { return this._canceled; } clone(data) { return new this.constructor({ ...this.data, ...data }); } } AbstractEvent.type = 'event'; AbstractEvent.cancelable = false; class AbstractPlugin { constructor(draggable) { this.draggable = draggable; } attach() { throw new Error('Not Implemented'); } detach() { throw new Error('Not Implemented'); } } const defaultDelay = { mouse: 0, drag: 0, touch: 100 }; class Sensor { constructor(containers = [], options = {}) { this.containers = [...containers]; this.options = { ...options }; this.dragging = false; this.currentContainer = null; this.originalSource = null; this.startEvent = null; this.delay = calcDelay(options.delay); } attach() { return this; } detach() { return this; } addContainer(...containers) { this.containers = [...this.containers, ...containers]; } removeContainer(...containers) { this.containers = this.containers.filter(container => !containers.includes(container)); } trigger(element, sensorEvent) { const event = document.createEvent('Event'); event.detail = sensorEvent; event.initEvent(sensorEvent.type, true, true); element.dispatchEvent(event); this.lastEvent = sensorEvent; return sensorEvent; } } function calcDelay(optionsDelay) { const delay = {}; if (optionsDelay === undefined) { return { ...defaultDelay }; } if (typeof optionsDelay === 'number') { for (const key in defaultDelay) { if (Object.prototype.hasOwnProperty.call(defaultDelay, key)) { delay[key] = optionsDelay; } } return delay; } for (const key in defaultDelay) { if (Object.prototype.hasOwnProperty.call(defaultDelay, key)) { if (optionsDelay[key] === undefined) { delay[key] = defaultDelay[key]; } else { delay[key] = optionsDelay[key]; } } } return delay; } function closest(node, value) { if (node == null) { return null; } function conditionFn(currentNode) { if (currentNode == null || value == null) { return false; } else if (isSelector(value)) { return Element.prototype.matches.call(currentNode, value); } else if (isNodeList(value)) { return [...value].includes(currentNode); } else if (isElement(value)) { return value === currentNode; } else if (isFunction(value)) { return value(currentNode); } else { return false; } } let current = node; do { current = current.correspondingUseElement || current.correspondingElement || current; if (conditionFn(current)) { return current; } current = current?.parentNode || null; } while (current != null && current !== document.body && current !== document); return null; } function isSelector(value) { return Boolean(typeof value === 'string'); } function isNodeList(value) { return Boolean(value instanceof NodeList || value instanceof Array); } function isElement(value) { return Boolean(value instanceof Node); } function isFunction(value) { return Boolean(typeof value === 'function'); } function AutoBind(originalMethod, { name, addInitializer }) { addInitializer(function () { this[name] = originalMethod.bind(this); }); } function requestNextAnimationFrame(callback) { return requestAnimationFrame(() => { requestAnimationFrame(callback); }); } function distance(x1, y1, x2, y2) { return Math.sqrt((x2 - x1) ** 2 + (y2 - y1) ** 2); } function touchCoords(event) { const { touches, changedTouches } = event; return touches && touches[0] || changedTouches && changedTouches[0]; } class SensorEvent extends AbstractEvent { get originalEvent() { return this.data.originalEvent; } get clientX() { return this.data.clientX; } get clientY() { return this.data.clientY; } get target() { return this.data.target; } get container() { return this.data.container; } get originalSource() { return this.data.originalSource; } get pressure() { return this.data.pressure; } } class DragStartSensorEvent extends SensorEvent {} DragStartSensorEvent.type = 'drag:start'; class DragMoveSensorEvent extends SensorEvent {} DragMoveSensorEvent.type = 'drag:move'; class DragStopSensorEvent extends SensorEvent {} DragStopSensorEvent.type = 'drag:stop'; class DragPressureSensorEvent extends SensorEvent {} DragPressureSensorEvent.type = 'drag:pressure'; const onContextMenuWhileDragging = Symbol('onContextMenuWhileDragging'); const onMouseDown$2 = Symbol('onMouseDown'); const onMouseMove$1 = Symbol('onMouseMove'); const onMouseUp$2 = Symbol('onMouseUp'); const startDrag$1 = Symbol('startDrag'); const onDistanceChange$1 = Symbol('onDistanceChange'); class MouseSensor extends Sensor { constructor(containers = [], options = {}) { super(containers, options); this.mouseDownTimeout = null; this.pageX = null; this.pageY = null; this[onContextMenuWhileDragging] = this[onContextMenuWhileDragging].bind(this); this[onMouseDown$2] = this[onMouseDown$2].bind(this); this[onMouseMove$1] = this[onMouseMove$1].bind(this); this[onMouseUp$2] = this[onMouseUp$2].bind(this); this[startDrag$1] = this[startDrag$1].bind(this); this[onDistanceChange$1] = this[onDistanceChange$1].bind(this); } attach() { document.addEventListener('mousedown', this[onMouseDown$2], true); } detach() { document.removeEventListener('mousedown', this[onMouseDown$2], true); } [onMouseDown$2](event) { if (event.button !== 0 || event.ctrlKey || event.metaKey) { return; } const container = closest(event.target, this.containers); if (!container) { return; } if (this.options.handle && event.target && !closest(event.target, this.options.handle)) { return; } const originalSource = closest(event.target, this.options.draggable); if (!originalSource) { return; } const { delay } = this; const { pageX, pageY } = event; Object.assign(this, { pageX, pageY }); this.onMouseDownAt = Date.now(); this.startEvent = event; this.currentContainer = container; this.originalSource = originalSource; document.addEventListener('mouseup', this[onMouseUp$2]); document.addEventListener('dragstart', preventNativeDragStart); document.addEventListener('mousemove', this[onDistanceChange$1]); this.mouseDownTimeout = window.setTimeout(() => { this[onDistanceChange$1]({ pageX: this.pageX, pageY: this.pageY }); }, delay.mouse); } [startDrag$1]() { const startEvent = this.startEvent; const container = this.currentContainer; const originalSource = this.originalSource; const dragStartEvent = new DragStartSensorEvent({ clientX: startEvent.clientX, clientY: startEvent.clientY, target: startEvent.target, container, originalSource, originalEvent: startEvent }); this.trigger(this.currentContainer, dragStartEvent); this.dragging = !dragStartEvent.canceled(); if (this.dragging) { document.addEventListener('contextmenu', this[onContextMenuWhileDragging], true); document.addEventListener('mousemove', this[onMouseMove$1]); } } [onDistanceChange$1](event) { const { pageX, pageY } = event; const { distance: distance$1 } = this.options; const { startEvent, delay } = this; Object.assign(this, { pageX, pageY }); if (!this.currentContainer) { return; } const timeElapsed = Date.now() - this.onMouseDownAt; const distanceTravelled = distance(startEvent.pageX, startEvent.pageY, pageX, pageY) || 0; clearTimeout(this.mouseDownTimeout); if (timeElapsed < delay.mouse) { document.removeEventListener('mousemove', this[onDistanceChange$1]); } else if (distanceTravelled >= distance$1) { document.removeEventListener('mousemove', this[onDistanceChange$1]); this[startDrag$1](); } } [onMouseMove$1](event) { if (!this.dragging) { return; } const target = document.elementFromPoint(event.clientX, event.clientY); const dragMoveEvent = new DragMoveSensorEvent({ clientX: event.clientX, clientY: event.clientY, target, container: this.currentContainer, originalEvent: event }); this.trigger(this.currentContainer, dragMoveEvent); } [onMouseUp$2](event) { clearTimeout(this.mouseDownTimeout); if (event.button !== 0) { return; } document.removeEventListener('mouseup', this[onMouseUp$2]); document.removeEventListener('dragstart', preventNativeDragStart); document.removeEventListener('mousemove', this[onDistanceChange$1]); if (!this.dragging) { return; } const target = document.elementFromPoint(event.clientX, event.clientY); const dragStopEvent = new DragStopSensorEvent({ clientX: event.clientX, clientY: event.clientY, target, container: this.currentContainer, originalEvent: event }); this.trigger(this.currentContainer, dragStopEvent); document.removeEventListener('contextmenu', this[onContextMenuWhileDragging], true); document.removeEventListener('mousemove', this[onMouseMove$1]); this.currentContainer = null; this.dragging = false; this.startEvent = null; } [onContextMenuWhileDragging](event) { event.preventDefault(); } } function preventNativeDragStart(event) { event.preventDefault(); } const onTouchStart = Symbol('onTouchStart'); const onTouchEnd = Symbol('onTouchEnd'); const onTouchMove = Symbol('onTouchMove'); const startDrag = Symbol('startDrag'); const onDistanceChange = Symbol('onDistanceChange'); let preventScrolling = false; window.addEventListener('touchmove', event => { if (!preventScrolling) { return; } event.preventDefault(); }, { passive: false }); class TouchSensor extends Sensor { constructor(containers = [], options = {}) { super(containers, options); this.currentScrollableParent = null; this.tapTimeout = null; this.touchMoved = false; this.pageX = null; this.pageY = null; this[onTouchStart] = this[onTouchStart].bind(this); this[onTouchEnd] = this[onTouchEnd].bind(this); this[onTouchMove] = this[onTouchMove].bind(this); this[startDrag] = this[startDrag].bind(this); this[onDistanceChange] = this[onDistanceChange].bind(this); } attach() { document.addEventListener('touchstart', this[onTouchStart]); } detach() { document.removeEventListener('touchstart', this[onTouchStart]); } [onTouchStart](event) { const container = closest(event.target, this.containers); if (!container) { return; } if (this.options.handle && event.target && !closest(event.target, this.options.handle)) { return; } const originalSource = closest(event.target, this.options.draggable); if (!originalSource) { return; } const { distance = 0 } = this.options; const { delay } = this; const { pageX, pageY } = touchCoords(event); Object.assign(this, { pageX, pageY }); this.onTouchStartAt = Date.now(); this.startEvent = event; this.currentContainer = container; this.originalSource = originalSource; document.addEventListener('touchend', this[onTouchEnd]); document.addEventListener('touchcancel', this[onTouchEnd]); document.addEventListener('touchmove', this[onDistanceChange]); container.addEventListener('contextmenu', onContextMenu); if (distance) { preventScrolling = true; } this.tapTimeout = window.setTimeout(() => { this[onDistanceChange]({ touches: [{ pageX: this.pageX, pageY: this.pageY }] }); }, delay.touch); } [startDrag]() { const startEvent = this.startEvent; const container = this.currentContainer; const touch = touchCoords(startEvent); const originalSource = this.originalSource; const dragStartEvent = new DragStartSensorEvent({ clientX: touch.pageX, clientY: touch.pageY, target: startEvent.target, container, originalSource, originalEvent: startEvent }); this.trigger(this.currentContainer, dragStartEvent); this.dragging = !dragStartEvent.canceled(); if (this.dragging) { document.addEventListener('touchmove', this[onTouchMove]); } preventScrolling = this.dragging; } [onDistanceChange](event) { const { distance: distance$1 } = this.options; const { startEvent, delay } = this; const start = touchCoords(startEvent); const current = touchCoords(event); const timeElapsed = Date.now() - this.onTouchStartAt; const distanceTravelled = distance(start.pageX, start.pageY, current.pageX, current.pageY); Object.assign(this, current); clearTimeout(this.tapTimeout); if (timeElapsed < delay.touch) { document.removeEventListener('touchmove', this[onDistanceChange]); } else if (distanceTravelled >= distance$1) { document.removeEventListener('touchmove', this[onDistanceChange]); this[startDrag](); } } [onTouchMove](event) { if (!this.dragging) { return; } const { pageX, pageY } = touchCoords(event); const target = document.elementFromPoint(pageX - window.scrollX, pageY - window.scrollY); const dragMoveEvent = new DragMoveSensorEvent({ clientX: pageX, clientY: pageY, target, container: this.currentContainer, originalEvent: event }); this.trigger(this.currentContainer, dragMoveEvent); } [onTouchEnd](event) { clearTimeout(this.tapTimeout); preventScrolling = false; document.removeEventListener('touchend', this[onTouchEnd]); document.removeEventListener('touchcancel', this[onTouchEnd]); document.removeEventListener('touchmove', this[onDistanceChange]); if (this.currentContainer) { this.currentContainer.removeEventListener('contextmenu', onContextMenu); } if (!this.dragging) { return; } document.removeEventListener('touchmove', this[onTouchMove]); const { pageX, pageY } = touchCoords(event); const target = document.elementFromPoint(pageX - window.scrollX, pageY - window.scrollY); event.preventDefault(); const dragStopEvent = new DragStopSensorEvent({ clientX: pageX, clientY: pageY, target, container: this.currentContainer, originalEvent: event }); this.trigger(this.currentContainer, dragStopEvent); this.currentContainer = null; this.dragging = false; this.startEvent = null; } } function onContextMenu(event) { event.preventDefault(); event.stopPropagation(); } const onMouseDown$1 = Symbol('onMouseDown'); const onMouseUp$1 = Symbol('onMouseUp'); const onDragStart$7 = Symbol('onDragStart'); const onDragOver$3 = Symbol('onDragOver'); const onDragEnd = Symbol('onDragEnd'); const onDrop = Symbol('onDrop'); const reset = Symbol('reset'); class DragSensor extends Sensor { constructor(containers = [], options = {}) { super(containers, options); this.mouseDownTimeout = null; this.draggableElement = null; this.nativeDraggableElement = null; this[onMouseDown$1] = this[onMouseDown$1].bind(this); this[onMouseUp$1] = this[onMouseUp$1].bind(this); this[onDragStart$7] = this[onDragStart$7].bind(this); this[onDragOver$3] = this[onDragOver$3].bind(this); this[onDragEnd] = this[onDragEnd].bind(this); this[onDrop] = this[onDrop].bind(this); } attach() { document.addEventListener('mousedown', this[onMouseDown$1], true); } detach() { document.removeEventListener('mousedown', this[onMouseDown$1], true); } [onDragStart$7](event) { event.dataTransfer.setData('text', ''); event.dataTransfer.effectAllowed = this.options.type; const target = document.elementFromPoint(event.clientX, event.clientY); const originalSource = this.draggableElement; if (!originalSource) { return; } const dragStartEvent = new DragStartSensorEvent({ clientX: event.clientX, clientY: event.clientY, target, originalSource, container: this.currentContainer, originalEvent: event }); setTimeout(() => { this.trigger(this.currentContainer, dragStartEvent); if (dragStartEvent.canceled()) { this.dragging = false; } else { this.dragging = true; } }, 0); } [onDragOver$3](event) { if (!this.dragging) { return; } const target = document.elementFromPoint(event.clientX, event.clientY); const container = this.currentContainer; const dragMoveEvent = new DragMoveSensorEvent({ clientX: event.clientX, clientY: event.clientY, target, container, originalEvent: event }); this.trigger(container, dragMoveEvent); if (!dragMoveEvent.canceled()) { event.preventDefault(); event.dataTransfer.dropEffect = this.options.type; } } [onDragEnd](event) { if (!this.dragging) { return; } document.removeEventListener('mouseup', this[onMouseUp$1], true); const target = document.elementFromPoint(event.clientX, event.clientY); const container = this.currentContainer; const dragStopEvent = new DragStopSensorEvent({ clientX: event.clientX, clientY: event.clientY, target, container, originalEvent: event }); this.trigger(container, dragStopEvent); this.dragging = false; this.startEvent = null; this[reset](); } [onDrop](event) { event.preventDefault(); } [onMouseDown$1](event) { if (event.target && (event.target.form || event.target.contenteditable)) { return; } const target = event.target; this.currentContainer = closest(target, this.containers); if (!this.currentContainer) { return; } if (this.options.handle && target && !closest(target, this.options.handle)) { return; } const originalSource = closest(target, this.options.draggable); if (!originalSource) { return; } const nativeDraggableElement = closest(event.target, element => element.draggable); if (nativeDraggableElement) { nativeDraggableElement.draggable = false; this.nativeDraggableElement = nativeDraggableElement; } document.addEventListener('mouseup', this[onMouseUp$1], true); document.addEventListener('dragstart', this[onDragStart$7], false); document.addEventListener('dragover', this[onDragOver$3], false); document.addEventListener('dragend', this[onDragEnd], false); document.addEventListener('drop', this[onDrop], false); this.startEvent = event; this.mouseDownTimeout = setTimeout(() => { originalSource.draggable = true; this.draggableElement = originalSource; }, this.delay.drag); } [onMouseUp$1]() { this[reset](); } [reset]() { clearTimeout(this.mouseDownTimeout); document.removeEventListener('mouseup', this[onMouseUp$1], true); document.removeEventListener('dragstart', this[onDragStart$7], false); document.removeEventListener('dragover', this[onDragOver$3], false); document.removeEventListener('dragend', this[onDragEnd], false); document.removeEventListener('drop', this[onDrop], false); if (this.nativeDraggableElement) { this.nativeDraggableElement.draggable = true; this.nativeDraggableElement = null; } if (this.draggableElement) { this.draggableElement.draggable = false; this.draggableElement = null; } } } const onMouseForceWillBegin = Symbol('onMouseForceWillBegin'); const onMouseForceDown = Symbol('onMouseForceDown'); const onMouseDown = Symbol('onMouseDown'); const onMouseForceChange = Symbol('onMouseForceChange'); const onMouseMove = Symbol('onMouseMove'); const onMouseUp = Symbol('onMouseUp'); const onMouseForceGlobalChange = Symbol('onMouseForceGlobalChange'); class ForceTouchSensor extends Sensor { constructor(containers = [], options = {}) { super(containers, options); this.mightDrag = false; this[onMouseForceWillBegin] = this[onMouseForceWillBegin].bind(this); this[onMouseForceDown] = this[onMouseForceDown].bind(this); this[onMouseDown] = this[onMouseDown].bind(this); this[onMouseForceChange] = this[onMouseForceChange].bind(this); this[onMouseMove] = this[onMouseMove].bind(this); this[onMouseUp] = this[onMouseUp].bind(this); } attach() { for (const container of this.containers) { container.addEventListener('webkitmouseforcewillbegin', this[onMouseForceWillBegin], false); container.addEventListener('webkitmouseforcedown', this[onMouseForceDown], false); container.addEventListener('mousedown', this[onMouseDown], true); container.addEventListener('webkitmouseforcechanged', this[onMouseForceChange], false); } document.addEventListener('mousemove', this[onMouseMove]); document.addEventListener('mouseup', this[onMouseUp]); } detach() { for (const container of this.containers) { container.removeEventListener('webkitmouseforcewillbegin', this[onMouseForceWillBegin], false); container.removeEventListener('webkitmouseforcedown', this[onMouseForceDown], false); container.removeEventListener('mousedown', this[onMouseDown], true); container.removeEventListener('webkitmouseforcechanged', this[onMouseForceChange], false); } document.removeEventListener('mousemove', this[onMouseMove]); document.removeEventListener('mouseup', this[onMouseUp]); } [onMouseForceWillBegin](event) { event.preventDefault(); this.mightDrag = true; } [onMouseForceDown](event) { if (this.dragging) { return; } const target = document.elementFromPoint(event.clientX, event.clientY); const container = event.currentTarget; if (this.options.handle && target && !closest(target, this.options.handle)) { return; } const originalSource = closest(target, this.options.draggable); if (!originalSource) { return; } const dragStartEvent = new DragStartSensorEvent({ clientX: event.clientX, clientY: event.clientY, target, container, originalSource, originalEvent: event }); this.trigger(container, dragStartEvent); this.currentContainer = container; this.dragging = !dragStartEvent.canceled(); this.mightDrag = false; } [onMouseUp](event) { if (!this.dragging) { return; } const dragStopEvent = new DragStopSensorEvent({ clientX: event.clientX, clientY: event.clientY, target: null, container: this.currentContainer, originalEvent: event }); this.trigger(this.currentContainer, dragStopEvent); this.currentContainer = null; this.dragging = false; this.mightDrag = false; } [onMouseDown](event) { if (!this.mightDrag) { return; } event.stopPropagation(); event.stopImmediatePropagation(); event.preventDefault(); } [onMouseMove](event) { if (!this.dragging) { return; } const target = document.elementFromPoint(event.clientX, event.clientY); const dragMoveEvent = new DragMoveSensorEvent({ clientX: event.clientX, clientY: event.clientY, target, container: this.currentContainer, originalEvent: event }); this.trigger(this.currentContainer, dragMoveEvent); } [onMouseForceChange](event) { if (this.dragging) { return; } const target = event.target; const container = event.currentTarget; const dragPressureEvent = new DragPressureSensorEvent({ pressure: event.webkitForce, clientX: event.clientX, clientY: event.clientY, target, container, originalEvent: event }); this.trigger(container, dragPressureEvent); } [onMouseForceGlobalChange](event) { if (!this.dragging) { return; } const target = event.target; const dragPressureEvent = new DragPressureSensorEvent({ pressure: event.webkitForce, clientX: event.clientX, clientY: event.clientY, target, container: this.currentContainer, originalEvent: event }); this.trigger(this.currentContainer, dragPressureEvent); } } var index$2 = /*#__PURE__*/Object.freeze({ __proto__: null, DragMoveSensorEvent: DragMoveSensorEvent, DragPressureSensorEvent: DragPressureSensorEvent, DragSensor: DragSensor, DragStartSensorEvent: DragStartSensorEvent, DragStopSensorEvent: DragStopSensorEvent, ForceTouchSensor: ForceTouchSensor, MouseSensor: MouseSensor, Sensor: Sensor, SensorEvent: SensorEvent, TouchSensor: TouchSensor }); class CollidableEvent extends AbstractEvent { constructor(data) { super(data); this.data = data; } get dragEvent() { return this.data.dragEvent; } } CollidableEvent.type = 'collidable'; class CollidableInEvent extends CollidableEvent { get collidingElement() { return this.data.collidingElement; } } CollidableInEvent.type = 'collidable:in'; class CollidableOutEvent extends CollidableEvent { get collidingElement() { return this.data.collidingElement; } } CollidableOutEvent.type = 'collidable:out'; const onDragMove$4 = Symbol('onDragMove'); const onDragStop$7 = Symbol('onDragStop'); const onRequestAnimationFrame = Symbol('onRequestAnimationFrame'); class Collidable extends AbstractPlugin { constructor(draggable) { super(draggable); this.currentlyCollidingElement = null; this.lastCollidingElement = null; this.currentAnimationFrame = null; this[onDragMove$4] = this[onDragMove$4].bind(this); this[onDragStop$7] = this[onDragStop$7].bind(this); this[onRequestAnimationFrame] = this[onRequestAnimationFrame].bind(this); } attach() { this.draggable.on('drag:move', this[onDragMove$4]).on('drag:stop', this[onDragStop$7]); } detach() { this.draggable.off('drag:move', this[onDragMove$4]).off('drag:stop', this[onDragStop$7]); } getCollidables() { const collidables = this.draggable.options.collidables; if (typeof collidables === 'string') { return Array.prototype.slice.call(document.querySelectorAll(collidables)); } else if (collidables instanceof NodeList || collidables instanceof Array) { return Array.prototype.slice.call(collidables); } else if (collidables instanceof HTMLElement) { return [collidables]; } else if (typeof collidables === 'function') { return collidables(); } else { return []; } } [onDragMove$4](event) { const target = event.sensorEvent.target; this.currentAnimationFrame = requestAnimationFrame(this[onRequestAnimationFrame](target)); if (this.currentlyCollidingElement) { event.cancel(); } const collidableInEvent = new CollidableInEvent({ dragEvent: event, collidingElement: this.currentlyCollidingElement }); const collidableOutEvent = new CollidableOutEvent({ dragEvent: event, collidingElement: this.lastCollidingElement }); const enteringCollidable = Boolean(this.currentlyCollidingElement && this.lastCollidingElement !== this.currentlyCollidingElement); const leavingCollidable = Boolean(!this.currentlyCollidingElement && this.lastCollidingElement); if (enteringCollidable) { if (this.lastCollidingElement) { this.draggable.trigger(collidableOutEvent); } this.draggable.trigger(collidableInEvent); } else if (leavingCollidable) { this.draggable.trigger(collidableOutEvent); } this.lastCollidingElement = this.currentlyCollidingElement; } [onDragStop$7](event) { const lastCollidingElement = this.currentlyCollidingElement || this.lastCollidingElement; const collidableOutEvent = new CollidableOutEvent({ dragEvent: event, collidingElement: lastCollidingElement }); if (lastCollidingElement) { this.draggable.trigger(collidableOutEvent); } this.lastCollidingElement = null; this.currentlyCollidingElement = null; } [onRequestAnimationFrame](target) { return () => { const collidables = this.getCollidables(); this.currentlyCollidingElement = closest(target, element => collidables.includes(element)); }; } } function createAddInitializerMethod(e, t) { return function (r) { assertNotFinished(t, "addInitializer"), assertCallable(r, "An initializer"), e.push(r); }; } function assertInstanceIfPrivate(e, t) { if (!e(t)) throw new TypeError("Attempted to access private element on non-instance"); } function memberDec(e, t, r, a, n, i, s, o, c, l, u) { var f; switch (i) { case 1: f = "accessor"; break; case 2: f = "method"; break; case 3: f = "getter"; break; case 4: f = "setter"; break; default: f = "field"; } var d, p, h = { kind: f, name: o ? "#" + r : r, static: s, private: o, metadata: u }, v = { v: !1 }; if (0 !== i && (h.addInitializer = createAddInitializerMethod(n, v)), o || 0 !== i && 2 !== i) { if (2 === i) d = function (e) { return assertInstanceIfPrivate(l, e), a.value; };else { var y = 0 === i || 1 === i; (y || 3 === i) && (d = o ? function (e) { return assertInstanceIfPrivate(l, e), a.get.call(e); } : function (e) { return a.get.call(e); }), (y || 4 === i) && (p = o ? function (e, t) { assertInstanceIfPrivate(l, e), a.set.call(e, t); } : function (e, t) { a.set.call(e, t); }); } } else d = function (e) { return e[r]; }, 0 === i && (p = function (e, t) { e[r] = t; }); var m = o ? l.bind() : function (e) { return r in e; }; h.access = d && p ? { get: d, set: p, has: m } : d ? { get: d, has: m } : { set: p, has: m }; try { return e.call(t, c, h); } finally { v.v = !0; } } function assertNotFinished(e, t) { if (e.v) throw new Error("attempted to call " + t + " after decoration was finished"); } function assertCallable(e, t) { if ("function" != typeof e) throw new TypeError(t + " must be a function"); } function assertValidReturnValue(e, t) { var r = typeof t; if (1 === e) { if ("object" !== r || null === t) throw new TypeError("accessor decorators must return an object with get, set, or init properties or void 0"); void 0 !== t.get && assertCallable(t.get, "accessor.get"), void 0 !== t.set && assertCallable(t.set, "accessor.set"), void 0 !== t.init && assertCallable(t.init, "accessor.init"); } else if ("function" !== r) { var a; throw a = 0 === e ? "field" : 5 === e ? "class" : "method", new TypeError(a + " decorators must return a function or void 0"); } } function curryThis1(e) { return function () { return e(this); }; } function curryThis2(e) { return function (t) { e(this, t); }; } function applyMemberDec(e, t, r, a, n, i, s, o, c, l, u) { var f, d, p, h, v, y, m = r[0]; a || Array.isArray(m) || (m = [m]), o ? f = 0 === i || 1 === i ? { get: curryThis1(r[3]), set: curryThis2(r[4]) } : 3 === i ? { get: r[3] } : 4 === i ? { set: r[3] } : { value: r[3] } : 0 !== i && (f = Object.getOwnPropertyDescriptor(t, n)), 1 === i ? p = { get: f.get, set: f.set } : 2 === i ? p = f.value : 3 === i ? p = f.get : 4 === i && (p = f.set); for (var g = a ? 2 : 1, b = m.length - 1; b >= 0; b -= g) { var I; if (void 0 !== (h = memberDec(m[b], a ? m[b - 1] : void 0, n, f, c, i, s, o, p, l, u))) assertValidReturnValue(i, h), 0 === i ? I = h : 1 === i ? (I = h.init, v = h.get || p.get, y = h.set || p.set, p = { get: v, set: y }) : p = h, void 0 !== I && (void 0 === d ? d = I : "function" == typeof d ? d = [d, I] : d.push(I)); } if (0 === i || 1 === i) { if (void 0 === d) d = function (e, t) { return t; };else if ("function" != typeof d) { var w = d; d = function (e, t) { for (var r = t, a = w.length - 1; a >= 0; a--) r = w[a].call(e, r); return r; }; } else { var M = d; d = function (e, t) { return M.call(e, t); }; } e.push(d); } 0 !== i && (1 === i ? (f.get = p.get, f.set = p.set) : 2 === i ? f.value = p : 3 === i ? f.get = p : 4 === i && (f.set = p), o ? 1 === i ? (e.push(function (e, t) { return p.get.call(e, t); }), e.push(function (e, t) { return p.set.call(e, t); })) : 2 === i ? e.push(p) : e.push(function (e, t) { return p.call(e, t); }) : Object.defineProperty(t, n, f)); } function applyMemberDecs(e, t, r, a) { for (var n, i, s, o = [], c = new Map(), l = new Map(), u = 0; u < t.length; u++) { var f = t[u]; if (Array.isArray(f)) { var d, p, h = f[1], v = f[2], y = f.length > 3, m = 16 & h, g = !!(8 & h), b = r; if (h &= 7, g ? (d = e, 0 !== h && (p = i = i || []), y && !s && (s = function (t) { return _checkInRHS(t) === e; }), b = s) : (d = e.prototype, 0 !== h && (p = n = n || [])), 0 !== h && !y) { var I = g ? l : c, w = I.get(v) || 0; if (!0 === w || 3 === w && 4 !== h || 4 === w && 3 !== h) throw new Error("Attempted to decorate a public method/accessor that has the same name as a previously decorated public method/accessor. This is not currently supported by the decorators plugin. Property name was: " + v); I.set(v, !(!w && h > 2) || h); } applyMemberDec(o, d, f, m, v, h, g, y, p, b, a); } } return pushInitializers(o, n), pushInitializers(o, i), o; } function pushInitializers(e, t) { t && e.push(function (e) { for (var r = 0; r < t.length; r++) t[r].call(e); return e; }); } function applyClassDecs(e, t, r, a) { if (t.length) { for (var n = [], i = e, s = e.name, o = r ? 2 : 1, c = t.length - 1; c >= 0; c -= o) { var l = { v: !1 }; try { var u = t[c].call(r ? t[c - 1] : void 0, i, { kind: "class", name: s, addInitializer: createAddInitializerMethod(n, l), metadata: a }); } finally { l.v = !0; } void 0 !== u && (assertValidReturnValue(5, u), i = u); } return [defineMetadata(i, a), function () { for (var e = 0; e < n.length; e++) n[e].call(i); }]; } } function defineMetadata(e, t) { return Object.defineProperty(e, Symbol.metadata || Symbol.for("Symbol.metadata"), { configurable: !0, enumerable: !0, value: t }); } function _applyDecs2305(e, t, r, a, n, i) { if (arguments.length >= 6) var s = i[Symbol.metadata || Symbol.for("Symbol.metadata")]; var o = Object.create(void 0 === s ? null : s), c = applyMemberDecs(e, t, n, o); return r.length || defineMetadata(e, o), { e: c, get c() { return applyClassDecs(e, r, a, o); } }; } function _checkInRHS(e) { if (Object(e) !== e) throw TypeError("right-hand side of 'in' should be an object, got " + (null !== e ? typeof e : "null")); return e; } class DragEvent extends AbstractEvent { constructor(data) { super(data); this.data = data; } get source() { return this.data.source; } get originalSource() { return this.data.originalSource; } get mirror() { return this.data.mirror; } get sourceContainer() { return this.data.sourceContainer; } get sensorEvent() { return this.data.sensorEvent; } get originalEvent() { if (this.sensorEvent) { return this.sensorEvent.originalEvent; } return null; } } DragEvent.type = 'drag'; class DragStartEvent extends DragEvent {} DragStartEvent.type = 'drag:start'; DragStartEvent.cancelable = true; class DragMoveEvent extends DragEvent {} DragMoveEvent.type = 'drag:move'; class DragOverEvent extends DragEvent { get overContainer() { return this.data.overContainer; } get over() { return this.data.over; } } DragOverEvent.type = 'drag:over'; DragOverEvent.cancelable = true; function isDragOverEvent(event) { return event.type === DragOverEvent.type; } class DragOutEvent extends DragEvent { get overContainer() { return this.data.overContainer; } get over() { return this.data.over; } } DragOutEvent.type = 'drag:out'; class DragOverContainerEvent extends DragEvent { get overContainer() { return this.data.overContainer; } } DragOverContainerEvent.type = 'drag:over:container'; class DragOutContainerEvent extends DragEvent { get overContainer() { return this.data.overContainer; } } DragOutContainerEvent.type = 'drag:out:container'; class DragPressureEvent extends DragEvent { get pressure() { return this.data.pressure; } } DragPressureEvent.type = 'drag:pressure'; class DragStopEvent extends DragEvent {} DragStopEvent.type = 'drag:stop'; DragStopEvent.cancelable = true; class DragStoppedEvent extends DragEvent {} DragStoppedEvent.type = 'drag:stopped'; var _initProto$1, _class$1; const defaultOptions$8 = {}; class ResizeMirror extends AbstractPlugin { constructor(draggable) { _initProto$1(super(draggable)); this.lastWidth = 0; this.lastHeight = 0; this.mirror = null; } attach() { this.draggable.on('mirror:created', this.onMirrorCreated).on('drag:over', this.onDragOver).on('drag:over:container', this.onDragOver); } detach() { this.draggable.off('mirror:created', this.onMirrorCreated).off('mirror:destroy', this.onMirrorDestroy).off('drag:over', this.onDragOver).off('drag:over:container', this.onDragOver); } getOptions() { return this.draggable.options.resizeMirror || {}; } onMirrorCreated({ mirror }) { this.mirror = mirror; } onMirrorDestroy() { this.mirror = null; } onDragOver(dragEvent) { this.resize(dragEvent); } resize(dragEvent) { requestAnimationFrame(() => { let over = null; const { overContainer } = dragEvent; if (this.mirror == null || this.mirror.parentNode == null) { return; } if (this.mirror.parentNode !== overContainer) { overContainer.appendChild(this.mirror); } if (isDragOverEvent(dragEvent)) { over = dragEvent.over; } const overElement = over || this.draggable.getDraggableElementsForContainer(overContainer)[0]; if (!overElement) { return; } requestNextAnimationFrame(() => { const overRect = overElement.getBoundingClientRect(); if (this.mirror == null || this.lastHeight === overRect.height && this.lastWidth === overRect.width) { return; } this.mirror.style.width = `${overRect.width}px`; this.mirror.style.height = `${overRect.height}px`; this.lastWidth = overRect.width; this.lastHeight = overRect.height; }); }); } } _class$1 = ResizeMirror; [_initProto$1] = _applyDecs2305(_class$1, [[AutoBind, 2, "onMirrorCreated"], [AutoBind, 2, "onMirrorDestroy"], [AutoBind, 2, "onDragOver"]], [], 0, void 0, AbstractPlugin).e; class SnapEvent extends AbstractEvent { get dragEvent() { return this.data.dragEvent; } get snappable() { return this.data.snappable; } } SnapEvent.type = 'snap'; class SnapInEvent extends SnapEvent {} SnapInEvent.type = 'snap:in'; SnapInEvent.cancelable = true; class SnapOutEvent extends SnapEvent {} SnapOutEvent.type = 'snap:out'; SnapOutEvent.cancelable = true; const onDragStart$6 = Symbol('onDragStart'); const onDragStop$6 = Symbol('onDragStop'); const onDragOver$2 = Symbol('onDragOver'); const onDragOut = Symbol('onDragOut'); const onMirrorCreated$1 = Symbol('onMirrorCreated'); const onMirrorDestroy = Symbol('onMirrorDestroy'); class Snappable extends AbstractPlugin { constructor(draggable) { super(draggable); this.firstSource = null; this.mirror = null; this[onDragStart$6] = this[onDragStart$6].bind(this); this[onDragStop$6] = this[onDragStop$6].bind(this); this[onDragOver$2] = this[onDragOver$2].bind(this); this[onDragOut] = this[onDragOut].bind(this); this[onMirrorCreated$1] = this[onMirrorCreated$1].bind(this); this[onMirrorDestroy] = this[onMirrorDestroy].bind(this); } attach() { this.draggable.on('drag:start', this[onDragStart$6]).on('drag:stop', this[onDragStop$6]).on('drag:over', this[onDragOver$2]).on('drag:out', this[onDragOut]).on('droppable:over', this[onDragOver$2]).on('droppable:out', this[onDragOut]).on('mirror:created', this[onMirrorCreated$1]).on('mirror:destroy', this[onMirrorDestroy]); } detach() { this.draggable.off('drag:start', this[onDragStart$6]).off('drag:stop', this[onDragStop$6]).off('drag:over', this[onDragOver$2]).off('drag:out', this[onDragOut]).off('droppable:over', this[onDragOver$2]).off('droppable:out', this[onDragOut]).off('mirror:created', this[onMirrorCreated$1]).off('mirror:destroy', this[onMirrorDestroy]); } [onDragStart$6](event) { if (event.canceled()) { return; } this.firstSource = event.source; } [onDragStop$6]() { this.firstSource = null; } [onDragOver$2](event) { if (event.canceled()) { return; } const source = event.source || event.dragEvent.source; if (source === this.firstSource) { this.firstSource = null; return; } const snapInEvent = new SnapInEvent({ dragEvent: event, snappable: event.over || event.droppable }); this.draggable.trigger(snapInEvent); if (snapInEvent.canceled()) { return; } if (this.mirror) { this.mirror.style.display = 'none'; } source.classList.remove(...this.draggable.getClassNamesFor('source:dragging')); source.classList.add(...this.draggable.getClassNamesFor('source:placed')); setTimeout(() => { source.classList.remove(...this.draggable.getClassNamesFor('source:placed')); }, this.draggable.options.placedTimeout); } [onDragOut](event) { if (event.canceled()) { return; } const source = event.source || event.dragEvent.source; const snapOutEvent = new SnapOutEvent({ dragEvent: event, snappable: event.over || event.droppable }); this.draggable.trigger(snapOutEvent); if (snapOutEvent.canceled()) { return; } if (this.mirror) { this.mirror.style.display = ''; } source.classList.add(...this.draggable.getClassNamesFor('source:dragging')); } [onMirrorCreated$1]({ mirror }) { this.mirror = mirror; } [onMirrorDestroy]() { this.mirror = null; } } var _initProto, _class; const defaultOptions$7 = { duration: 150, easingFunction: 'ease-in-out', horizontal: false }; class SwapAnimation extends AbstractPlugin { constructor(draggable) { _initProto(super(draggable)); this.options = { ...defaultOptions$7, ...this.getOptions() }; this.lastAnimationFrame = null; } attach() { this.draggable.on('sortable:sorted', this.onSortableSorted); } detach() { this.draggable.off('sortable:sorted', this.onSortableSorted); } getOptions() { return this.draggable.options.swapAnimation || {}; } onSortableSorted({ oldIndex, newIndex, dragEvent }) { const { source, over } = dragEvent; if (this.lastAnimationFrame) { cancelAnimationFrame(this.lastAnimationFrame); } this.lastAnimationFrame = requestAnimationFrame(() => { if (oldIndex >= newIndex) { animate$1(source, over, this.options); } else { animate$1(over, source, this.options); } }); } } _class = SwapAnimation; [_initProto] = _applyDecs2305(_class, [[AutoBind, 2, "onSortableSorted"]], [], 0, void 0, AbstractPlugin).e; function animate$1(from, to, { duration, easingFunction, horizontal }) { for (const element of [from, to]) { element.style.pointerEvents = 'none'; } if (horizontal) { const width = from.offsetWidth; from.style.transform = `translate3d(${width}px, 0, 0)`; to.style.transform = `translate3d(-${width}px, 0, 0)`; } else { const height = from.offsetHeight; from.style.transform = `translate3d(0, ${height}px, 0)`; to.style.transform = `translate3d(0, -${height}px, 0)`; } requestAnimationFrame(() => { for (const element of [from, to]) { element.addEventListener('transitionend', resetElementOnTransitionEnd$1); element.style.transition = `transform ${duration}ms ${easingFunction}`; element.style.transform = ''; } }); } function resetElementOnTransitionEnd$1(event) { if (event.target == null || !isHTMLElement(event.target)) { return; } event.target.style.transition = ''; event.target.style.pointerEvents = ''; event.target.removeEventListener('transitionend', resetElementOnTransitionEnd$1); } function isHTMLElement(eventTarget) { return Boolean('style' in eventTarget); } const onSortableSorted = Symbol('onSortableSorted'); const onSortableSort = Symbol('onSortableSort'); const defaultOptions$6 = { duration: 150, easingFunction: 'ease-in-out' }; class SortAnimation extends AbstractPlugin { constructor(draggable) { super(draggable); this.options = { ...defaultOptions$6, ...this.getOptions() }; this.lastAnimationFrame = null; this.lastElements = []; this[onSortableSorted] = this[onSortableSorted].bind(this); this[onSortableSort] = this[onSortableSort].bind(this); } attach() { this.draggable.on('sortable:sort', this[onSortableSort]); this.draggable.on('sortable:sorted', this[onSortableSorted]); } detach() { this.draggable.off('sortable:sort', this[onSortableSort]); this.draggable.off('sortable:sorted', this[onSortableSorted]); } getOptions() { return this.draggable.options.so