@shopify/draggable
Version:
The JavaScript Drag & Drop library your grandparents warned you about.
172 lines (150 loc) • 5.21 kB
JavaScript
'use strict';
Object.defineProperty(exports, '__esModule', { value: true });
var closest = require('../../../shared/utils/closest/closest.cjs');
var Sensor = require('../Sensor/Sensor.cjs');
var SensorEvent = require('../SensorEvent/SensorEvent.cjs');
const onMouseDown = Symbol('onMouseDown');
const onMouseUp = Symbol('onMouseUp');
const onDragStart = Symbol('onDragStart');
const onDragOver = Symbol('onDragOver');
const onDragEnd = Symbol('onDragEnd');
const onDrop = Symbol('onDrop');
const reset = Symbol('reset');
class DragSensor extends Sensor.default {
constructor(containers = [], options = {}) {
super(containers, options);
this.mouseDownTimeout = null;
this.draggableElement = null;
this.nativeDraggableElement = null;
this[onMouseDown] = this[onMouseDown].bind(this);
this[onMouseUp] = this[onMouseUp].bind(this);
this[onDragStart] = this[onDragStart].bind(this);
this[onDragOver] = this[onDragOver].bind(this);
this[onDragEnd] = this[onDragEnd].bind(this);
this[onDrop] = this[onDrop].bind(this);
}
attach() {
document.addEventListener('mousedown', this[onMouseDown], true);
}
detach() {
document.removeEventListener('mousedown', this[onMouseDown], true);
}
[onDragStart](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 SensorEvent.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](event) {
if (!this.dragging) {
return;
}
const target = document.elementFromPoint(event.clientX, event.clientY);
const container = this.currentContainer;
const dragMoveEvent = new SensorEvent.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], true);
const target = document.elementFromPoint(event.clientX, event.clientY);
const container = this.currentContainer;
const dragStopEvent = new SensorEvent.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](event) {
if (event.target && (event.target.form || event.target.contenteditable)) {
return;
}
const target = event.target;
this.currentContainer = closest.default(target, this.containers);
if (!this.currentContainer) {
return;
}
if (this.options.handle && target && !closest.default(target, this.options.handle)) {
return;
}
const originalSource = closest.default(target, this.options.draggable);
if (!originalSource) {
return;
}
const nativeDraggableElement = closest.default(event.target, element => element.draggable);
if (nativeDraggableElement) {
nativeDraggableElement.draggable = false;
this.nativeDraggableElement = nativeDraggableElement;
}
document.addEventListener('mouseup', this[onMouseUp], true);
document.addEventListener('dragstart', this[onDragStart], false);
document.addEventListener('dragover', this[onDragOver], 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]() {
this[reset]();
}
[reset]() {
clearTimeout(this.mouseDownTimeout);
document.removeEventListener('mouseup', this[onMouseUp], true);
document.removeEventListener('dragstart', this[onDragStart], false);
document.removeEventListener('dragover', this[onDragOver], 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;
}
}
}
exports.default = DragSensor;