import Button from "../layout/Button"; import Stack from "../layout/Stack"; import { FileArchive, FilePlus2, X } from "lucide-react"; import React, { ComponentProps, DetailedHTMLProps, ReactNode } from "react"; import Card from "../elements/Card"; import Span from "../layout/Span"; import Center from "../layout/Center"; import { FileInputToBase64FunctionReturn } from "../utils/form/fileInputToBase64"; import { twMerge } from "tailwind-merge"; import fileInputToBase64 from "../utils/form/fileInputToBase64"; import Row from "../layout/Row"; import Input from "./Input"; import Loading from "../elements/Loading"; type ImageUploadProps = DetailedHTMLProps< React.HTMLAttributes, HTMLDivElement > & { onChangeHandler?: ( fileData: FileInputToBase64FunctionReturn | undefined ) => any; onClear?: () => void; fileInputProps?: DetailedHTMLProps< React.InputHTMLAttributes, HTMLInputElement >; placeHolderWrapper?: DetailedHTMLProps< React.HTMLAttributes, HTMLDivElement >; previewImageWrapperProps?: DetailedHTMLProps< React.HTMLAttributes, HTMLDivElement >; previewImageProps?: DetailedHTMLProps< React.ImgHTMLAttributes, HTMLImageElement >; label?: string | ReactNode; disablePreview?: boolean; allowedRegex?: RegExp; externalSetFile?: React.Dispatch< React.SetStateAction >; externalSetFiles?: React.Dispatch< React.SetStateAction >; existingFile?: FileInputToBase64FunctionReturn; existingFileUrl?: string; icon?: ReactNode; labelSpanProps?: ComponentProps; loading?: boolean; multiple?: boolean; }; /** * @note use the `onChangeHandler` prop to grab the parsed base64 image object */ export default function FileUpload({ onChangeHandler, fileInputProps, placeHolderWrapper, previewImageWrapperProps, previewImageProps, label, disablePreview, allowedRegex, externalSetFile, externalSetFiles, existingFile, existingFileUrl, icon, labelSpanProps, loading, multiple, onClear, ...props }: ImageUploadProps) { const [file, setFile] = React.useState< FileInputToBase64FunctionReturn | undefined >(existingFile); const [fileUrl, setFileUrl] = React.useState( existingFileUrl ); const [fileDraggedOver, setFileDraggedOver] = React.useState(false); const inputRef = React.useRef(null); React.useEffect(() => { if (existingFileUrl) { setFileUrl(existingFileUrl); } }, [existingFileUrl]); React.useEffect(() => { if (existingFile) { setFile(existingFile); } }, [existingFile]); return ( { if (multiple) { (async () => { const files = e.target.files; if (!files?.[0]) return; let filesArr: FileInputToBase64FunctionReturn[] = []; for (let i = 0; i < files.length; i++) { const file = files[i]; const fileObj = await fileInputToBase64({ inputFile: file, }); filesArr.push(fileObj); } externalSetFiles?.(filesArr); })(); } else { const inputFile = e.target.files?.[0]; if (!inputFile) return; fileInputToBase64({ inputFile, allowedRegex }).then( (res) => { setFile(res); externalSetFile?.(res); onChangeHandler?.(res); fileInputProps?.onChange?.(e); } ); } }} ref={inputRef as any} /> {loading ? (
) : file ? ( {disablePreview ? ( Image Uploaded! ) : file.fileType?.match(/image/i) ? ( ) : ( {file.file?.name || file.fileName} {file.fileType} )} { setFile({ ...file, fileName: e.target.value }); externalSetFile?.({ ...file, fileName: e.target.value, }); }} /> ) : fileUrl ? ( {disablePreview ? ( Image Uploaded! ) : fileUrl.match(/\.pdf$|\.txt$/) ? ( {fileUrl} ) : ( )} ) : ( { inputRef.current?.click(); placeHolderWrapper?.onClick?.(e); }} onDragOver={(e) => { e.preventDefault(); setFileDraggedOver(true); }} onDragLeave={(e) => { setFileDraggedOver(false); }} onDrop={(e) => { e.preventDefault(); setFileDraggedOver(false); let inputFile: File | null = null; if (e.dataTransfer.items) { [...e.dataTransfer.items].forEach((item, i) => { if (inputFile) return; if (item.kind === "file") { const file = item.getAsFile(); inputFile = file; } }); } else { inputFile = e.dataTransfer.files?.[0]; } if (!inputFile) return; fileInputToBase64({ inputFile, allowedRegex }).then( (res) => { setFile(res); externalSetFile?.(res); onChangeHandler?.(res); } ); }} {...placeHolderWrapper} >
{icon || } {label || "Click to Upload File"}
)}
); }