-
-
Notifications
You must be signed in to change notification settings - Fork 2.7k
feat(useFileDialog): add MaybRef to multiple, accept, capture, reset, and directory #4813
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
base: main
Are you sure you want to change the base?
feat(useFileDialog): add MaybRef to multiple, accept, capture, reset, and directory #4813
Conversation
AMAZING LGTM! |
If we add this as |
@OrbisK Already taken care of, it adds |
@hunterwilhelm this is true, but we are not reacting if the ref value changes |
@OrbisK I see! I changed it so the refs update the element properties when the refs change, including the input element param. |
@OrbisK Any chance we can see this merged? |
Can someone confirm that this is working on mac/safari? |
@OrbisK Just tested it on Safari on Mac and Safari on iPhone, all the features work perfectly. I wrote a UI for each test. Full test with a UI<script setup lang="ts">
import { useFileDialog } from '@vueuse/core'
import { shallowRef } from 'vue'
// 1. Basic usage (default)
const {
files: filesDefault,
open: openDefault,
reset: resetDefault,
onCancel: onCancelDefault,
onChange: onChangeDefault,
} = useFileDialog()
onChangeDefault((files) => {
// do something with files
})
onCancelDefault(() => {
// do something on cancel
})
// 2. Initial files as Array<File>
const initialFilesArr = shallowRef<File[]>([new File(['baz'], 'baz.txt', { type: 'text/plain' })])
const {
files: filesArr,
open: openArr,
reset: resetArr,
} = useFileDialog({ initialFiles: initialFilesArr.value })
// 3. Initial files as FileList (simulate with DataTransfer)
const initialFilesList = shallowRef<FileList | undefined>(undefined)
if (typeof window !== 'undefined') {
const dt = new DataTransfer()
dt.items.add(new File(['foo'], 'foo.txt', { type: 'text/plain' }))
dt.items.add(new File(['bar'], 'bar.txt', { type: 'text/plain' }))
initialFilesList.value = dt.files
}
const {
files: filesList,
open: openList,
reset: resetList,
} = useFileDialog({ initialFiles: initialFilesList.value })
// 4. Custom input element
const customInput = shallowRef<HTMLInputElement | undefined>(undefined)
const {
open: openCustomInput,
files: filesCustomInput,
} = useFileDialog({ input: customInput.value })
// 5. Input as template ref (shallowRef)
const inputRef = shallowRef<HTMLInputElement>()
const {
open: openInputRef,
files: filesInputRef,
} = useFileDialog({ input: inputRef.value })
// 6. Multiple as ref
const multipleRef = shallowRef(true)
const {
open: openMultiple,
files: filesMultiple,
} = useFileDialog({ multiple: multipleRef })
// 7. Accept as ref
const acceptRef = shallowRef('image/*')
const {
open: openAccept,
files: filesAccept,
} = useFileDialog({ accept: acceptRef })
// 8. Directory as ref
const directoryRef = shallowRef(false)
const {
open: openDirectory,
files: filesDirectory,
} = useFileDialog({ directory: directoryRef })
// 9. Reset as ref
const resetOptRef = shallowRef(false)
const {
open: openResetOpt,
files: filesResetOpt,
} = useFileDialog({ reset: resetOptRef })
// 10. Capture as ref
const captureRef = shallowRef('user')
const {
open: openCapture,
files: filesCapture,
} = useFileDialog({ capture: captureRef })
// Helper for showing file names
function fileNames(files: FileList | File[] | null) {
if (!files)
return 'None'
const arr = Array.from(files)
return arr.map(f => f.name).join(', ')
}
</script>
<template>
<h2>1. Default</h2>
<button type="button" @click="openDefault()">
Choose files
</button>
<button type="button" :disabled="!filesDefault" @click="resetDefault()">
Reset
</button>
<div v-if="filesDefault">
<p>You have selected: <b>{{ `${filesDefault.length} ${filesDefault.length === 1 ? 'file' : 'files'}` }}</b></p>
<ul>
<li v-for="file of filesDefault" :key="file.name">
{{ file.name }}
</li>
</ul>
</div>
<h2>2. Initial files as Array<File></h2>
<button type="button" @click="openArr()">
Choose files
</button>
<button type="button" :disabled="!filesArr" @click="resetArr()">
Reset
</button>
<div v-if="filesArr">
<p>Selected: {{ fileNames(filesArr) }}</p>
</div>
<h2>3. Initial files as FileList</h2>
<button type="button" @click="openList()">
Choose files
</button>
<button type="button" :disabled="!filesList" @click="resetList()">
Reset
</button>
<div v-if="filesList">
<p>Selected: {{ fileNames(filesList) }}</p>
</div>
<h2>4. Custom input element</h2>
<input ref="customInput" type="file" style="display:none">
<button type="button" @click="openCustomInput()">
Choose files (custom input)
</button>
<div v-if="filesCustomInput">
<p>Selected: {{ fileNames(filesCustomInput) }}</p>
</div>
<h2>5. Input as template ref (shallowRef)</h2>
<input ref="inputRef" type="file" style="display:none">
<button type="button" @click="openInputRef()">
Choose files (inputRef)
</button>
<div v-if="filesInputRef">
<p>Selected: {{ fileNames(filesInputRef) }}</p>
</div>
<h2>6. Multiple as ref</h2>
<button type="button" @click="openMultiple()">
Choose files (multiple: {{ multipleRef }})
</button>
<button @click="multipleRef = !multipleRef">
Toggle multiple
</button>
<div v-if="filesMultiple">
<p>Selected: {{ fileNames(filesMultiple) }}</p>
</div>
<h2>7. Accept as ref</h2>
<button type="button" @click="openAccept()">
Choose files (accept: {{ acceptRef }})
</button>
<button @click="acceptRef = acceptRef === 'image/*' ? 'video/*' : 'image/*'">
Toggle accept
</button>
<div v-if="filesAccept">
<p>Selected: {{ fileNames(filesAccept) }}</p>
</div>
<h2>8. Directory as ref</h2>
<button type="button" @click="openDirectory()">
Choose files (directory: {{ directoryRef }})
</button>
<button @click="directoryRef = !directoryRef">
Toggle directory
</button>
<div v-if="filesDirectory">
<p>Selected: {{ fileNames(filesDirectory) }}</p>
</div>
<h2>9. Reset as ref</h2>
<button type="button" @click="openResetOpt()">
Choose files (reset: {{ resetOptRef }})
</button>
<button @click="resetOptRef = !resetOptRef">
Toggle reset
</button>
<div v-if="filesResetOpt">
<p>Selected: {{ fileNames(filesResetOpt) }}</p>
</div>
<h2>10. Capture as ref</h2>
<button type="button" @click="openCapture()">
Choose files (capture: {{ captureRef }})
</button>
<button @click="captureRef = captureRef === 'user' ? 'environment' : 'user'">
Toggle capture
</button>
<div v-if="filesCapture">
<p>Selected: {{ fileNames(filesCapture) }}</p>
</div>
</template> |
@OrbisK Thanks for approving 🚀 |
Before submitting the PR, please make sure you do the following
fixes #123
).Description
Fixes #4812
add MaybRef to multiple, accept, capture, reset, and directory
Additional context
These 5 parameters are only used upon invocation of
open
, so they can be easily updated usingref
. The alternative was to rerender the entire component to update the composable.