UNPKG

@supunlakmal/hooks

Version:

A collection of reusable React hooks

86 lines 4.33 kB
import { useRef, useEffect, useState, useCallback } from 'react'; /** * Provides basic drag-and-drop event handling for an element. * Attaches necessary listeners and manages drag state. * * @param ref React ref object attached to the draggable element. * @param options Configuration options for the drag behavior. * @returns State indicating if the element is currently being dragged. */ export const useDrag = (ref, options = {}) => { const { setDraggableAttribute = true } = options; const [isDragging, setIsDragging] = useState(false); // Store options in refs to avoid re-running effects when they change const optionsRef = useRef(options); useEffect(() => { optionsRef.current = options; }, [options]); const handleDragStart = useCallback((event) => { var _a, _b, _c; const currentOptions = optionsRef.current; setIsDragging(true); if (event.dataTransfer) { event.dataTransfer.effectAllowed = currentOptions.dragEffect || 'move'; if (currentOptions.transferData !== undefined) { let dataString = null; try { if (typeof currentOptions.transferData === 'string') { dataString = currentOptions.transferData; } else { dataString = JSON.stringify(currentOptions.transferData); } event.dataTransfer.setData(currentOptions.dataFormat || 'text/plain', dataString); } catch (e) { console.error("useDrag: Failed to stringify transferData. Ensure it's serializable.", e); event.dataTransfer.setData(currentOptions.dataFormat || 'text/plain', '[Serialization Error]'); } } if (currentOptions.dragImage && event.dataTransfer.setDragImage) { event.dataTransfer.setDragImage(currentOptions.dragImage, ((_a = currentOptions.dragImageOffset) === null || _a === void 0 ? void 0 : _a.x) || 0, ((_b = currentOptions.dragImageOffset) === null || _b === void 0 ? void 0 : _b.y) || 0); } else if (currentOptions.dragImage === null) { // If explicitly null, try to use a minimal transparent image (browser support varies) const emptyImage = new Image(); emptyImage.src = 'data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7'; event.dataTransfer.setDragImage(emptyImage, 0, 0); } // Otherwise, use browser default drag image } (_c = currentOptions.onDragStart) === null || _c === void 0 ? void 0 : _c.call(currentOptions, event); }, []); // No dependencies, relies on optionsRef const handleDrag = useCallback((event) => { var _a, _b; (_b = (_a = optionsRef.current).onDrag) === null || _b === void 0 ? void 0 : _b.call(_a, event); // isDragging state is managed by dragstart/dragend }, []); // No dependencies, relies on optionsRef const handleDragEnd = useCallback((event) => { var _a, _b; setIsDragging(false); (_b = (_a = optionsRef.current).onDragEnd) === null || _b === void 0 ? void 0 : _b.call(_a, event); }, []); // No dependencies, relies on optionsRef useEffect(() => { const element = ref.current; if (!element) return; if (setDraggableAttribute) { element.setAttribute('draggable', 'true'); } element.addEventListener('dragstart', handleDragStart); element.addEventListener('drag', handleDrag); element.addEventListener('dragend', handleDragEnd); return () => { element.removeEventListener('dragstart', handleDragStart); element.removeEventListener('drag', handleDrag); element.removeEventListener('dragend', handleDragEnd); if (setDraggableAttribute) { // Reset draggable attribute on cleanup if we set it element.removeAttribute('draggable'); } }; }, [ref, setDraggableAttribute, handleDragStart, handleDrag, handleDragEnd]); return { isDragging }; }; //# sourceMappingURL=useDrag.js.map