@shopify/draggable
Version:
The JavaScript Drag & Drop library your grandparents warned you about.
1,736 lines (1,517 loc) • 114 kB
JavaScript
(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