stylescape
Version:
Stylescape is a visual identity framework developed by Scape Agency.
186 lines • 7.52 kB
JavaScript
export class DragAndDropManager {
constructor(draggableSelector, options = {}) {
this.draggables = new Set();
this.dropZones = new Set();
this.currentDragged = null;
this.handleDragStart = (event) => {
const target = event.currentTarget;
this.currentDragged = target;
target.classList.add(this.options.draggingClass);
target.setAttribute("aria-grabbed", "true");
if (event.dataTransfer) {
event.dataTransfer.effectAllowed = this.options.effectAllowed;
event.dataTransfer.setData(this.options.dataFormat, target.id || "dragged");
}
this.options.onDragStart(target, event);
};
this.handleDragEnd = (event) => {
const target = event.currentTarget;
target.classList.remove(this.options.draggingClass);
target.setAttribute("aria-grabbed", "false");
this.dropZones.forEach((zone) => {
zone.classList.remove(this.options.dragOverClass);
});
this.options.onDragEnd(target, event);
this.currentDragged = null;
};
this.handleDragOver = (event) => {
const target = event.currentTarget;
const result = this.options.onDragOver(target, event);
if (result !== false) {
event.preventDefault();
if (event.dataTransfer) {
event.dataTransfer.dropEffect = "move";
}
}
};
this.handleDragEnter = (event) => {
const target = event.currentTarget;
target.classList.add(this.options.dragOverClass);
};
this.handleDragLeave = (event) => {
const target = event.currentTarget;
const relatedTarget = event.relatedTarget;
if (!target.contains(relatedTarget)) {
target.classList.remove(this.options.dragOverClass);
}
};
this.handleDrop = (event) => {
event.preventDefault();
const dropZone = event.currentTarget;
dropZone.classList.remove(this.options.dragOverClass);
if (this.currentDragged) {
if (!this.options.allowCrossContainer) {
const originalParent = this.currentDragged.parentElement;
if (originalParent !== dropZone) {
return;
}
}
this.options.onDrop(this.currentDragged, dropZone, event);
}
};
this.options = {
draggingClass: options.draggingClass ?? "ss-dragging",
dragOverClass: options.dragOverClass ?? "ss-drag-over",
dropZoneSelector: options.dropZoneSelector ?? "[data-ss='dropzone']",
allowCrossContainer: options.allowCrossContainer ?? true,
effectAllowed: options.effectAllowed ?? "move",
dataFormat: options.dataFormat ?? "text/plain",
onDragStart: options.onDragStart ?? (() => { }),
onDragEnd: options.onDragEnd ?? (() => { }),
onDrop: options.onDrop ?? (() => { }),
onDragOver: options.onDragOver ?? (() => true),
handleSelector: options.handleSelector ?? "",
};
this.initDraggables(draggableSelector);
this.initDropZones();
}
addDraggable(element) {
this.setupDraggable(element);
this.draggables.add(element);
}
removeDraggable(element) {
this.teardownDraggable(element);
this.draggables.delete(element);
}
addDropZone(element) {
this.setupDropZone(element);
this.dropZones.add(element);
}
removeDropZone(element) {
this.teardownDropZone(element);
this.dropZones.delete(element);
}
getDragged() {
return this.currentDragged;
}
setDraggable(element, enabled) {
element.setAttribute("draggable", String(enabled));
element.setAttribute("aria-grabbed", String(enabled && this.currentDragged === element));
}
destroy() {
this.draggables.forEach((el) => this.teardownDraggable(el));
this.dropZones.forEach((el) => this.teardownDropZone(el));
this.draggables.clear();
this.dropZones.clear();
this.currentDragged = null;
}
static initDraggables() {
const managers = [];
const draggables = document.querySelectorAll('[data-ss="draggable"]');
draggables.forEach((el) => {
const handle = el.dataset.ssDraggableHandle;
const manager = new DragAndDropManager(el, {
handleSelector: handle,
});
managers.push(manager);
});
return managers;
}
initDraggables(selector) {
let elements;
if (typeof selector === "string") {
elements = Array.from(document.querySelectorAll(selector));
}
else if (Array.isArray(selector)) {
elements = selector;
}
else {
elements = [selector];
}
elements.forEach((el) => {
this.setupDraggable(el);
this.draggables.add(el);
});
}
initDropZones() {
const zones = document.querySelectorAll(this.options.dropZoneSelector);
zones.forEach((zone) => {
this.setupDropZone(zone);
this.dropZones.add(zone);
});
}
setupDraggable(element) {
element.setAttribute("draggable", "true");
element.setAttribute("role", "listitem");
element.setAttribute("aria-grabbed", "false");
if (this.options.handleSelector) {
const handle = element.querySelector(this.options.handleSelector);
if (handle) {
handle.style.cursor = "grab";
element.setAttribute("draggable", "false");
handle.addEventListener("mousedown", () => {
element.setAttribute("draggable", "true");
});
handle.addEventListener("mouseup", () => {
element.setAttribute("draggable", "false");
});
}
}
element.addEventListener("dragstart", this.handleDragStart);
element.addEventListener("dragend", this.handleDragEnd);
}
teardownDraggable(element) {
element.removeAttribute("draggable");
element.removeAttribute("aria-grabbed");
element.removeEventListener("dragstart", this.handleDragStart);
element.removeEventListener("dragend", this.handleDragEnd);
}
setupDropZone(element) {
element.setAttribute("role", "list");
element.setAttribute("aria-dropeffect", "move");
element.addEventListener("dragover", this.handleDragOver);
element.addEventListener("dragenter", this.handleDragEnter);
element.addEventListener("dragleave", this.handleDragLeave);
element.addEventListener("drop", this.handleDrop);
}
teardownDropZone(element) {
element.removeAttribute("aria-dropeffect");
element.removeEventListener("dragover", this.handleDragOver);
element.removeEventListener("dragenter", this.handleDragEnter);
element.removeEventListener("dragleave", this.handleDragLeave);
element.removeEventListener("drop", this.handleDrop);
}
}
export default DragAndDropManager;
//# sourceMappingURL=DragAndDropManager.js.map