Skip to content

Commit

Permalink
feat(useDropZone): new function (#1610)
Browse files Browse the repository at this point in the history
Co-authored-by: Anthony Fu <anthonyfu117@hotmail.com>
  • Loading branch information
Julien Martin and antfu committed May 31, 2022
1 parent 900317f commit d64070e
Show file tree
Hide file tree
Showing 4 changed files with 118 additions and 0 deletions.
1 change: 1 addition & 0 deletions packages/core/index.ts
Expand Up @@ -32,6 +32,7 @@ export * from './useDevicesList'
export * from './useDisplayMedia'
export * from './useDocumentVisibility'
export * from './useDraggable'
export * from './useDropZone'
export * from './useElementBounding'
export * from './useElementByPoint'
export * from './useElementHover'
Expand Down
42 changes: 42 additions & 0 deletions packages/core/useDropZone/demo.vue
@@ -0,0 +1,42 @@
<script setup lang="ts">
import { ref } from 'vue'
import { useDropZone } from '@vueuse/core'
const filesData = ref<{ name: string; size: number; type: string; lastModified: number }[]>([])
function onDrop(files: File[] | null) {
filesData.value = []
if (files) {
filesData.value = files.map(file => ({
name: file.name,
size: file.size,
type: file.type,
lastModified: file.lastModified,
}))
}
}
const dropZoneRef = ref<HTMLElement | null>(null)
const { isOverDropZone } = useDropZone(dropZoneRef, onDrop)
</script>

<template>
<div class="flex">
<div class="w-full h-auto relative">
<p>Drop files into dropZone</p>
<img src="/favicon.ico" alt="Drop me">

<div ref="dropZoneRef" class="flex flex-col w-full min-h-200px h-auto bg-gray-400/10 justify-center items-center mt-6">
<div> isOverDropZone: <BooleanDisplay :value="isOverDropZone" /></div>
<div class="flex flex-wrap justify-center items-center">
<div v-for="(file, index) in filesData" :key="index" class="w-200px bg-black-200/10 ma-2 pa-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>
</template>
29 changes: 29 additions & 0 deletions packages/core/useDropZone/index.md
@@ -0,0 +1,29 @@
---
category: Elements
---

# useDropZone

Create an zone where files can be dropped.

## Usage

```html
<script setup lang="ts">
import { useDropZone } from '@vueuse/core'
const dropZoneRef = ref(null)
function onDrop(dropZoneRef, files: File[] | null) {
// Trigger an event when file(s) is drop on zone
}
const { isOverDropZone } = useDropZone(dropZoneRef, onDrop)
</script>

<template>
<div ref="dropZoneRef">
Drop files here
</div>
</template>
```
46 changes: 46 additions & 0 deletions packages/core/useDropZone/index.ts
@@ -0,0 +1,46 @@
import { ref } from 'vue-demi'
import type { Ref } from 'vue-demi'
import type { MaybeRef } from '@vueuse/shared'
import { isClient } from '@vueuse/shared'
import { useEventListener } from '../useEventListener'

export interface UseDropZoneReturn {
isOverDropZone: Ref<boolean>
}

export function useDropZone(target: MaybeRef<HTMLElement | null>, onDrop: (files: File[] | null) => void): UseDropZoneReturn {
const isOverDropZone = ref(false)
let counter = 0

if (isClient) {
useEventListener<DragEvent>(target, 'dragenter', (event) => {
event.preventDefault()
counter += 1
isOverDropZone.value = true
})
useEventListener<DragEvent>(target, 'dragover', (event) => {
event.preventDefault()
})
useEventListener<DragEvent>(target, 'dragleave', (event) => {
event.preventDefault()
counter -= 1
if (counter === 0)
isOverDropZone.value = false
})
useEventListener<DragEvent>(target, 'drop', (event) => {
event.preventDefault()
counter = 0
isOverDropZone.value = false
const files = Array.from(event.dataTransfer?.files ?? [])
if (files.length === 0) {
onDrop(null)
return
}
onDrop(files)
})
}

return {
isOverDropZone,
}
}

0 comments on commit d64070e

Please sign in to comment.