Also mark selection

This commit is contained in:
Manav Rathi 2025-02-20 12:46:54 +05:30
parent 957c333cf3
commit 77d16e275d
No known key found for this signature in database
2 changed files with 52 additions and 28 deletions

View File

@ -228,35 +228,61 @@ export const Upload: React.FC<UploadProps> = ({
const uploaderNameRef = useRef<string>(null);
const isDragAndDrop = useRef(false);
/**
* `true` if we've activated one hidden {@link Inputs} that allow the user
* to select items, and haven't heard back from the browser as to the
* selection (or cancellation).
*
* [Note: Showing an activity indicator during upload item selection]
*
* When selecting a large number of items (100K+), the browser can take
* significant time (10s+) before it hands back control to us. The
* {@link isInputPending} state tracks this intermediate state, and we use
* it to show an activity indicator to let that the user know that their
* selection is still being processed.
*/
const [isInputPending, setIsInputPending] = useState(false);
/**
* Files that were selected by the user in the last activation of one of the
* hidden {@link Inputs}.
*/
const [selectedInputFiles, setSelectedInputFiles] = useState<File[]>([]);
const handleInputSelect = useCallback((files: File[]) => {
setIsInputPending(false);
setSelectedInputFiles(files);
}, []);
const handleInputCancel = useCallback(() => {
console.log("cancel");
setIsInputPending(false);
}, []);
const {
getInputProps: getFileSelectorInputProps,
openSelector: openFileSelector,
selectedFiles: fileSelectorFiles,
} = useFileInput({
directory: false,
onSelect: handleInputSelect,
onCancel: handleInputCancel,
});
const {
getInputProps: getFolderSelectorInputProps,
openSelector: openFolderSelector,
selectedFiles: folderSelectorFiles,
} = useFileInput({
directory: true,
onSelect: handleInputSelect,
onCancel: handleInputCancel,
});
const {
getInputProps: getZipFileSelectorInputProps,
openSelector: openZipFileSelector,
selectedFiles: fileSelectorZipFiles,
} = useFileInput({
directory: false,
accept: ".zip",
onSelect: handleInputSelect,
onCancel: handleInputCancel,
});
@ -346,15 +372,9 @@ export const Upload: React.FC<UploadProps> = ({
switch (selectedUploadType.current) {
case "files":
files = fileSelectorFiles;
break;
case "folders":
files = folderSelectorFiles;
break;
case "zips":
files = fileSelectorZipFiles;
files = selectedInputFiles;
break;
default:
@ -373,12 +393,7 @@ export const Upload: React.FC<UploadProps> = ({
} else {
setWebFiles(files);
}
}, [
dragAndDropFiles,
fileSelectorFiles,
folderSelectorFiles,
fileSelectorZipFiles,
]);
}, [selectedInputFiles, dragAndDropFiles]);
// Trigger an upload when any of the dependencies change.
useEffect(() => {
@ -739,6 +754,7 @@ export const Upload: React.FC<UploadProps> = ({
const handleUploadTypeSelect = (type: UploadType) => {
selectedUploadType.current = type;
setIsInputPending(true);
switch (type) {
case "files":
openFileSelector();

View File

@ -1,4 +1,4 @@
import { useCallback, useEffect, useRef, useState } from "react";
import { useCallback, useEffect, useRef } from "react";
interface UseFileInputParams {
/**
@ -14,6 +14,17 @@ interface UseFileInputParams {
* https://developer.mozilla.org/en-US/docs/Web/HTML/Attributes/accept).
*/
accept?: string;
/**
* A callback that is invoked when the user selects files.
*
* It will be passed the list of {@link File}s that the user selected.
*
* This will be a list even if the user selected directories - in that case,
* it will be the recursive list of files within this directory.
*
* If the user selected no items, then {@link onCancel} will be invoked.
*/
onSelect: (selectedFiles: File[]) => void;
/**
* A callback that is invoked when the user cancels on the file / directory
* dialog.
@ -33,13 +44,6 @@ interface UseFileInputResult {
* A function that can be called to open the select file / directory dialog.
*/
openSelector: () => void;
/**
* The list of {@link File}s that the user selected.
*
* This will be a list even if the user selected directories - in that case,
* it will be the recursive list of files within this directory.
*/
selectedFiles: File[];
}
/**
@ -55,9 +59,9 @@ interface UseFileInputResult {
export const useFileInput = ({
directory,
accept,
onSelect,
onCancel,
}: UseFileInputParams): UseFileInputResult => {
const [selectedFiles, setSelectedFiles] = useState<File[]>([]);
const inputRef = useRef<HTMLInputElement | undefined>(undefined);
useEffect(() => {
@ -80,7 +84,11 @@ export const useFileInput = ({
event,
) => {
const files = event.target.files;
if (files) setSelectedFiles([...files]);
if (files?.length) {
onSelect([...files]);
} else {
onCancel();
}
};
// [Note: webkitRelativePath]
@ -111,5 +119,5 @@ export const useFileInput = ({
[directoryOpts, accept, handleChange],
);
return { getInputProps, openSelector, selectedFiles };
return { getInputProps, openSelector };
};