@shopify/draggable
Version:
The JavaScript Drag & Drop library your grandparents warned you about.
119 lines (103 loc) • 2.9 kB
JavaScript
import { AbstractPlugin } from '../../shared/AbstractPlugin/AbstractPlugin.mjs';
const onSortableSorted = Symbol('onSortableSorted');
const onSortableSort = Symbol('onSortableSort');
const defaultOptions = {
duration: 150,
easingFunction: 'ease-in-out'
};
class SortAnimation extends AbstractPlugin {
constructor(draggable) {
super(draggable);
this.options = {
...defaultOptions,
...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.sortAnimation || {};
}
[onSortableSort]({
dragEvent
}) {
const {
sourceContainer
} = dragEvent;
const elements = this.draggable.getDraggableElementsForContainer(sourceContainer);
this.lastElements = Array.from(elements).map(el => {
return {
domEl: el,
offsetTop: el.offsetTop,
offsetLeft: el.offsetLeft
};
});
}
[onSortableSorted]({
oldIndex,
newIndex
}) {
if (oldIndex === newIndex) {
return;
}
const effectedElements = [];
let start;
let end;
let num;
if (oldIndex > newIndex) {
start = newIndex;
end = oldIndex - 1;
num = 1;
} else {
start = oldIndex + 1;
end = newIndex;
num = -1;
}
for (let i = start; i <= end; i++) {
const from = this.lastElements[i];
const to = this.lastElements[i + num];
effectedElements.push({
from,
to
});
}
cancelAnimationFrame(this.lastAnimationFrame);
this.lastAnimationFrame = requestAnimationFrame(() => {
effectedElements.forEach(element => animate(element, this.options));
});
}
}
function animate({
from,
to
}, {
duration,
easingFunction
}) {
const domEl = from.domEl;
const x = from.offsetLeft - to.offsetLeft;
const y = from.offsetTop - to.offsetTop;
domEl.style.pointerEvents = 'none';
domEl.style.transform = `translate3d(${x}px, ${y}px, 0)`;
requestAnimationFrame(() => {
domEl.addEventListener('transitionend', resetElementOnTransitionEnd);
domEl.style.transition = `transform ${duration}ms ${easingFunction}`;
domEl.style.transform = '';
});
}
function resetElementOnTransitionEnd(event) {
event.target.style.transition = '';
event.target.style.pointerEvents = '';
event.target.removeEventListener('transitionend', resetElementOnTransitionEnd);
}
export { SortAnimation as default, defaultOptions };