UNPKG

@thisux/sveltednd

Version:

A lightweight, flexible drag and drop library for Svelte 5 applications.

94 lines (93 loc) 3.77 kB
import { dndState } from '../stores/dnd.svelte.js'; const DEFAULT_DRAGGING_CLASS = 'dragging'; export function draggable(node, options) { const draggingClass = (options.attributes?.draggingClass || DEFAULT_DRAGGING_CLASS).split(' '); let initialX; let initialY; function isInteractiveElement(target) { if (!options.interactive) return false; // Check if the target or its parents match any of the interactive selectors return options.interactive.some((selector) => target.matches(selector) || target.closest(selector)); } function handleDragStart(event) { if (options.disabled) return; dndState.isDragging = true; dndState.draggedItem = options.dragData; dndState.sourceContainer = options.container; dndState.targetContainer = null; if (event.dataTransfer) { event.dataTransfer.effectAllowed = 'move'; event.dataTransfer.setData('text/plain', JSON.stringify(options.dragData)); } node.classList.add(...draggingClass); options.callbacks?.onDragStart?.(dndState); // **Dispatch the custom event that bubbles up to the container** const customEvent = new CustomEvent('dragstart-on-container', { bubbles: true }); node.dispatchEvent(customEvent); } function handleDragEnd() { node.classList.remove(...draggingClass); options.callbacks?.onDragEnd?.(dndState); // Reset state dndState.isDragging = false; dndState.draggedItem = null; dndState.sourceContainer = ''; dndState.targetContainer = null; } function handlePointerDown(event) { if (options.disabled) return; // If the target is an interactive element, don't start dragging if (isInteractiveElement(event.target)) { return; } // Store initial pointer position initialX = event.clientX; initialY = event.clientY; dndState.isDragging = true; dndState.draggedItem = options.dragData; dndState.sourceContainer = options.container; dndState.targetContainer = null; node.setPointerCapture(event.pointerId); node.classList.add(...draggingClass); options.callbacks?.onDragStart?.(dndState); } function handlePointerMove(event) { if (!dndState.isDragging) return; // Optional: Update visual feedback or position } function handlePointerUp(event) { if (!dndState.isDragging) return; node.releasePointerCapture(event.pointerId); node.classList.remove(...draggingClass); options.callbacks?.onDragEnd?.(dndState); // Reset state dndState.isDragging = false; dndState.draggedItem = null; dndState.sourceContainer = ''; dndState.targetContainer = null; } node.draggable = !options.disabled; node.addEventListener('dragstart', handleDragStart); node.addEventListener('dragend', handleDragEnd); node.addEventListener('pointerdown', handlePointerDown); node.addEventListener('pointermove', handlePointerMove); node.addEventListener('pointerup', handlePointerUp); return { update(newOptions) { options = newOptions; node.draggable = !options.disabled; }, destroy() { node.removeEventListener('dragstart', handleDragStart); node.removeEventListener('dragend', handleDragEnd); node.removeEventListener('pointerdown', handlePointerDown); node.removeEventListener('pointermove', handlePointerMove); node.removeEventListener('pointerup', handlePointerUp); } }; }