feat(useFileDialog): add MaybRef to multiple, accept, capture, reset, and directory
Before submitting the PR, please make sure you do the following
- [x] Read the Contributing Guidelines.
- [x] Read the Pull Request Guidelines.
- [x] Check that there isn't already a PR that solves the problem the same way to avoid creating a duplicate.
- [x] Provide a description in this PR that addresses what the PR is solving, or reference the issue that it solves (e.g.
fixes #123). - [x] Ideally, include relevant tests that fail without this PR but pass with it.
⚠️ Slowing down new functions
Warning: Slowing down new functions
As the VueUse audience continues to grow, we have been inundated with an overwhelming number of feature requests and pull requests. As a result, maintaining the project has become increasingly challenging and has stretched our capacity to its limits. As such, in the near future, we may need to slow down our acceptance of new features and prioritize the stability and quality of existing functions. Please note that new features for VueUse may not be accepted at this time. If you have any new ideas, we suggest that you first incorporate them into your own codebase, iterate on them to suit your needs, and assess their generalizability. If you strongly believe that your ideas are beneficial to the community, you may submit a pull request along with your use cases, and we would be happy to review and discuss them. Thank you for your understanding.
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 using ref. The alternative was to rerender the entire component to update the composable.
AMAZING LGTM!
If we add this as MaybeRef we should also consider what we want to do it the ref updates
@OrbisK Already taken care of, it adds toValue everywhere they are being used, which happens to be all in the open function.
@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. Is there anything else I should change?
@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 🚀
@ilyaliao @OrbisK Added the suggested changes, it should be good to go 🚀
@ilyaliao @OrbisK Added the suggested change, anything else I should add?
@vueuse/components
npm i https://pkg.pr.new/@vueuse/components@4813
@vueuse/core
npm i https://pkg.pr.new/@vueuse/core@4813
@vueuse/electron
npm i https://pkg.pr.new/@vueuse/electron@4813
@vueuse/firebase
npm i https://pkg.pr.new/@vueuse/firebase@4813
@vueuse/integrations
npm i https://pkg.pr.new/@vueuse/integrations@4813
@vueuse/math
npm i https://pkg.pr.new/@vueuse/math@4813
@vueuse/metadata
npm i https://pkg.pr.new/@vueuse/metadata@4813
@vueuse/nuxt
npm i https://pkg.pr.new/@vueuse/nuxt@4813
@vueuse/router
npm i https://pkg.pr.new/@vueuse/router@4813
@vueuse/rxjs
npm i https://pkg.pr.new/@vueuse/rxjs@4813
@vueuse/shared
npm i https://pkg.pr.new/@vueuse/shared@4813
commit: 8429ff1
Why not MaybeRefOrGetter?