VUE

useDragDrop Composable

Simple drag and drop functionality with reactive drop zone state

Vue3ComposablesDragDropFileUploadDOM

Code

import { ref, onMounted, onUnmounted, type Ref } from 'vue';

export function useDragDrop(
  target: Ref<HTMLElement | null>,
  onDrop: (files: File[]) => void
) {
  const isDraggingOver = ref(false);
  const dragCounter = ref(0);

  // Prevent default browser behavior
  const handleDragEvents = (e: DragEvent) => {
    e.preventDefault();
    e.stopPropagation();
  };

  const handleDragEnter = (e: DragEvent) => {
    handleDragEvents(e);
    dragCounter.value++;
    isDraggingOver.value = true;
  };

  const handleDragLeave = (e: DragEvent) => {
    handleDragEvents(e);
    dragCounter.value--;
    __TOKEN_26__ (dragCounter.value === 0) {
      isDraggingOver.value = false;
    }
  };

  const handleDrop = (e: DragEvent) => {
    handleDragEvents(e);
    dragCounter.value = 0;
    isDraggingOver.value = false;

    __TOKEN_28__ (e.dataTransfer?.files && e.dataTransfer.files.length > 0) {
      const files = Array.__TOKEN_30__(e.dataTransfer.files);
      onDrop(files);
    }
  };

  onMounted(() => {
    __TOKEN_31__ (!target.value) return;

    const el = target.value;
    el.addEventListener('dragenter', handleDragEnter);
    el.addEventListener('dragover', handleDragEvents);
    el.addEventListener('dragleave', handleDragLeave);
    el.addEventListener('drop', handleDrop);
  });

  onUnmounted(() => {
    __TOKEN_34__ (!target.value) return;

    const el = target.value;
    el.removeEventListener('dragenter', handleDragEnter);
    el.removeEventListener('dragover', handleDragEvents);
    el.removeEventListener('dragleave', handleDragLeave);
    el.removeEventListener('drop', handleDrop);
  });

  return { isDraggingOver };
}

// Usage example
// const dropZoneRef = ref<HTMLElement | null>(null);
// const { isDraggingOver } = useDragDrop(dropZoneRef, (files) => {
//   console.log('Dropped files:', files);
//   // Handle file upload
// });