UNPKG

stylescape

Version:

Stylescape is a visual identity framework developed by Scape Agency.

186 lines 7.52 kB
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