vue.jsvuejs3vue-componentvueuse

Why useDropZone not working with dataTypes: ['image/*']?


I using Vue 3. Why useDropZone from VueUse 10.9.0 (latest version) can't handle dataTypes: ['image/*'] ? I want to implement loading a single image by drag and drop and/or (user-defined) selection. When setting dataTypes: ['image/*'] drag and drop stops working. If you specify dataTypes: ['image/png'], drag and drop works, but only for png images. I need support for all image formats as in 'image/*'.

I don't understand something or VueUse didn't implement support for 'image/*' in useDropZone ?

My full vue code:

<script setup lang="ts">
import { ref } from 'vue'
import { useDropZone} from '@vueuse/core'

const imageFilesData = ref<{ name: string, size: number, type: string, lastModified: number }[]>([])

function onImageDrop(files: File[] | null) {
    imageFilesData.value = []
    if (files) {
        imageFilesData.value = files.map(file => ({
            name: file.name,
            size: file.size,
            type: file.type,
            lastModified: file.lastModified,
        }))
    }
}

const imageDropZoneRef = ref<HTMLElement>()


const { isOverDropZone: isOverImageDropZone } = useDropZone(imageDropZoneRef, {dataTypes: ['image/*'], onDrop: onImageDrop })
</script>

<template>
    <div class="flex flex-col gap-2">
        <div class="w-full h-auto relative">
            <p>Drop files on to drop zones</p>
            <div grid="~ cols-2 gap-2">
                <div
                    ref="imageDropZoneRef"
                    class="flex flex-col w-full min-h-[200px] h-auto bg-gray justify-center items-center mt-6 rounded"
                >
                    <div class="font-bold mb-2">
                        Image DropZone
                    </div>
                    <div>
                        isOverDropZone:
                        <span :class="isOverImageDropZone ? 'text-green-600 shadow-1' : 'text-red-600 shadow-1'">{{ isOverImageDropZone }}</span>
                    </div>
                    <div class="flex flex-wrap justify-center items-center">
                        <div v-for="(file, index) in imageFilesData" :key="index" class="w-[200px] bg-gray-200 m-2 p-6">
                            <p>Name: {{ file.name }}</p>
                            <p>Size: {{ file.size }}</p>
                            <p>Type: {{ file.type }}</p>
                            <p>Last modified: {{ file.lastModified }}</p>
                        </div>
                    </div>
                </div>
            </div>
        </div>
    </div>
</template>

Solution

  • The source code shows the dropzone does a comparison of the data type being dragged against the dataTypes array in your dropzone options, so wildcards aren't going to work.

    You can, however, provide a function to the dataTypes option which will let you provide custom filter logic.

    // returns true if data type starts with "image", otherwise returns false
    function isImage(types: readonly string[]) {
      return !types.some(type => !type.startsWith('image'))
    }
    
    const { isOverDropZone: isOverImageDropZone } = useDropZone(imageDropZoneRef, {
      dataTypes: isImage,
      onDrop: onImageDrop
    })