Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(VFileUpload): add new component #19667

Open
wants to merge 16 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions packages/docs/src/data/nav.json
Original file line number Diff line number Diff line change
Expand Up @@ -237,6 +237,10 @@
"title": "date-inputs",
"subfolder": "components"
},
{
"title": "file-upload",
"subfolder": "components"
},
{
"title": "number-inputs",
"subfolder": "components"
Expand Down
8 changes: 8 additions & 0 deletions packages/docs/src/examples/v-file-upload/prop-content.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
<template>
<v-file-upload
browse-text="Local Filesystem"
divider-text="or choose locally"
icon="mdi-upload"
title="Drag and Drop Here"
></v-file-upload>
</template>
19 changes: 19 additions & 0 deletions packages/docs/src/examples/v-file-upload/prop-density.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
<template>
<div class="text-center pa-2 mb-2">
<v-btn-toggle v-model="density" density="comfortable" border divided rounded>
<v-btn value="default">Default</v-btn>

<v-btn value="comfortable">Comfortable</v-btn>

<v-btn value="compact">Compact</v-btn>
</v-btn-toggle>
</div>

<v-file-upload :density="density"></v-file-upload>
</template>

<script setup>
import { shallowRef } from 'vue'

const density = shallowRef('default')
</script>
3 changes: 3 additions & 0 deletions packages/docs/src/examples/v-file-upload/prop-disabled.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
<template>
<v-file-upload disabled></v-file-upload>
</template>
3 changes: 3 additions & 0 deletions packages/docs/src/examples/v-file-upload/prop-scrim.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
<template>
<v-file-upload scrim="primary"></v-file-upload>
</template>
26 changes: 26 additions & 0 deletions packages/docs/src/examples/v-file-upload/slot-item.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
<template>
<v-file-upload
v-model="model"
clearable
multiple
show-size
>
<template v-slot:item="{ props: itemProps }">
<v-file-upload-item v-bind="itemProps" lines="one" nav>
<template v-slot:prepend>
<v-avatar size="32" rounded></v-avatar>
</template>

<template v-slot:clear="{ props: clearProps }">
<v-btn color="primary" v-bind="clearProps"></v-btn>
</template>
</v-file-upload-item>
</template>
</v-file-upload>
</template>

<script setup>
import { shallowRef } from 'vue'

const model = shallowRef(null)
</script>
48 changes: 48 additions & 0 deletions packages/docs/src/examples/v-file-upload/usage.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
<template>
<ExamplesUsageExample
v-model="model"
:code="code"
:name="name"
:options="options"
>
<div>
<v-file-upload v-bind="props"></v-file-upload>
</div>

<template v-slot:configuration>
<v-text-field v-model="title" label="Title"></v-text-field>

<v-checkbox v-model="disabled" label="Disabled"></v-checkbox>

<v-checkbox v-model="clear" label="Clearable"></v-checkbox>
</template>
</ExamplesUsageExample>
</template>

<script setup>
const name = 'v-file-upload'
const model = ref('default')
const options = ['comfortable', 'compact']
const clear = ref(false)
const counter = ref(false)
const disabled = ref(false)
const title = ref()
const props = computed(() => {
return {
clearable: clear.value || undefined,
counter: counter.value || undefined,
disabled: disabled.value || undefined,
density: model.value,
title: title.value || undefined,
variant: model.value === 'default' ? undefined : model.value,
}
})

const slots = computed(() => {
return ``
})

const code = computed(() => {
return `<${name}${propsToString(props.value)}>${slots.value}</${name}>`
})
</script>
99 changes: 99 additions & 0 deletions packages/docs/src/pages/en/components/file-upload.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,99 @@
---
emphasized: true
meta:
title: File upload
description: The file upload component is a drag and drop area for uploading files.
keywords: file uploading, file upload, file drag and drop, file drop area, file dropzone, file upload component
related:
- /components/buttons/
- /components/file-inputs/
- /components/sheets/
features:
report: true
label: 'C: VFileUpload'
github: '/labs/VFileUpload/'
---

# File upload

<PageFeatures />

::: warning

This feature requires [v3.7.3](/getting-started/release-notes/?version=v3.7.3)

:::

## Installation

Labs components require a manual import and installation of the component.

```js { resource="src/plugins/vuetify.js" }
import { VFileUpload } from 'vuetify/labs/VFileUpload'

export default createVuetify({
components: {
VFileUpload,
},
})
```

## Usage

The `v-file-upload` component is a drag and drop area for uploading files. It can be customized with slots and has support for density and multiple styles.

<ExamplesUsage name="v-file-upload" />

<PromotedEntry />

## API

| Component | Description |
| - | - |
| [v-file-upload](/api/v-file-upload/) | Primary Component |
| [v-file-upload-item](/api/v-file-upload-item/) | Item Component |
| [v-file-input](/api/v-file-input/) | File input component |

<ApiInline hide-links />

## Guide

The v-file-upload component is a more visual counterpart to the [v-file-input](/components/file-inputs/) component. It provides a drag and drop area for files, and can be customized with slots.

### Props

Utilize various properties to customize the look and feel of the `v-file-upload` component.

#### Density

The **density** prop is used to control the vertical space the upload takes up.

<ExamplesExample file="v-file-upload/prop-density" />

#### Content

Use the **browse-text**, **divider-text**, **icon**, **title**, or **subtitle** props to customize the text displayed in the component.

<ExamplesExample file="v-file-upload/prop-content" />

#### Disabled

The **disabled** property reduces the opacity of the component and prevents interaction.

<ExamplesExample file="v-file-upload/prop-disabled" />

#### Scrim

The **scrim** property allows you to set a colored scrim when hovering over the component with files.

<ExamplesExample file="v-file-upload/prop-scrim" />

### Slots

The `v-file-upload` component has several slots that can be used to customize the component.

#### Item

The **item** slot is used to customize the appearance of the file item.

<ExamplesExample file="v-file-upload/slot-item" />
1 change: 1 addition & 0 deletions packages/vuetify/src/iconsets/mdi.ts
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@ const aliases: IconAliases = {
treeviewCollapse: 'mdi-menu-down',
treeviewExpand: 'mdi-menu-right',
eyeDropper: 'mdi-eyedropper',
upload: 'mdi-cloud-upload',
}

const mdi: IconSet = {
Expand Down
75 changes: 75 additions & 0 deletions packages/vuetify/src/labs/VFileUpload/VFileUpload.sass
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
@use '../../styles/tools'
@use '../../styles/settings'
@use './variables' as *

@include tools.layer('components')
.v-file-upload
padding: $file-upload-padding
flex-direction: column
justify-content: center
align-items: center
position: relative

&.v-sheet
display: flex
border-radius: 4px
border-style: dashed
border-width: 2px

&.v-file-upload--density-compact
padding: 32px 0
flex-direction: row
gap: 1rem

.v-overlay__scrim
pointer-events: none

&--disabled
pointer-events: none
opacity: var(--v-disabled-opacity)

&--dragging
> *
pointer-events: none

&--clickable
cursor: pointer

input[type="file"]
left: 0
opacity: 0
position: absolute
cursor: pointer
top: 0
z-index: -1

.v-file-upload-title
font-size: $file-upload-title-font-size
font-weight: 600

.v-file-upload-icon
opacity: var(--v-medium-emphasis-opacity)
font-size: $file-upload-icon-font-size
margin-bottom: $file-upload-icon-margin-bottom

.v-file-upload--density-comfortable &
font-size: $file-upload-icon-font-size - .5rem
margin-bottom: $file-upload-icon-margin-bottom - .5rem

.v-file-upload--density-compact &
font-size: $file-upload-icon-font-size - 1rem
margin-bottom: $file-upload-icon-margin-bottom - 1rem

.v-file-upload-divider
align-items: center
display: flex
margin: $file-upload-divider-margin
justify-content: center
width: 100%

.v-file-upload-items
margin: $file-upload-items-margin

.v-file-upload-item
&:not(:first-child)
margin-top: 8px
Loading