UNPKG

@llamaindex/ui

Version:

A comprehensive UI component library built with React, TypeScript, and Tailwind CSS for LlamaIndex applications

832 lines (827 loc) 31.2 kB
import { Dialog, DialogTrigger, DialogContent, DialogHeader, DialogTitle, DialogFooter } from './chunk-ICIG4S2N.mjs'; import { Progress } from './chunk-KRVDHZW4.mjs'; import { Input } from './chunk-A734CEDD.mjs'; import { Button } from './chunk-KPGB4IWL.mjs'; import { __spreadProps, __spreadValues } from './chunk-JD6AELXS.mjs'; import { useState, useCallback } from 'react'; import { ChevronDown, X, Loader2, Upload } from 'lucide-react'; import { uploadFileApiV1FilesPost, readFileContentApiV1FilesIdContentGet } from 'llama-cloud-services/api'; import { jsxs, jsx, Fragment } from 'react/jsx-runtime'; // src/file-uploader/file-utils.ts var FileType = /* @__PURE__ */ ((FileType3) => { FileType3["JPEG"] = "jpeg"; FileType3["JPG"] = "jpg"; FileType3["PNG"] = "png"; FileType3["WEBP"] = "webp"; FileType3["PDF"] = "pdf"; FileType3["DOC"] = "doc"; FileType3["DOCX"] = "docx"; FileType3["XLS"] = "xls"; FileType3["XLSX"] = "xlsx"; FileType3["PPT"] = "ppt"; FileType3["PPTX"] = "pptx"; FileType3["TXT"] = "txt"; FileType3["CSV"] = "csv"; FileType3["JSON"] = "json"; FileType3["XML"] = "xml"; FileType3["HTML"] = "html"; FileType3["CSS"] = "css"; FileType3["JS"] = "js"; FileType3["TS"] = "ts"; FileType3["MD"] = "md"; return FileType3; })(FileType || {}); var FILE_TYPE_DEFINITIONS = { ["jpeg" /* JPEG */]: { extensions: ["jpg", "jpeg"], mimeTypes: ["image/jpeg", "image/jpg"], displayName: "JPEG Image", category: "image" }, ["jpg" /* JPG */]: { extensions: ["jpg", "jpeg"], mimeTypes: ["image/jpeg", "image/jpg"], displayName: "JPG Image", category: "image" }, ["png" /* PNG */]: { extensions: ["png"], mimeTypes: ["image/png"], displayName: "PNG Image", category: "image" }, ["webp" /* WEBP */]: { extensions: ["webp"], mimeTypes: ["image/webp"], displayName: "WebP Image", category: "image" }, ["pdf" /* PDF */]: { extensions: ["pdf"], mimeTypes: ["application/pdf"], displayName: "PDF Document", category: "document" }, ["doc" /* DOC */]: { extensions: ["doc"], mimeTypes: ["application/msword"], displayName: "Word Document", category: "document" }, ["docx" /* DOCX */]: { extensions: ["docx"], mimeTypes: [ "application/vnd.openxmlformats-officedocument.wordprocessingml.document" ], displayName: "Word Document", category: "document" }, ["xls" /* XLS */]: { extensions: ["xls"], mimeTypes: ["application/vnd.ms-excel"], displayName: "Excel Spreadsheet", category: "document" }, ["xlsx" /* XLSX */]: { extensions: ["xlsx"], mimeTypes: [ "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet" ], displayName: "Excel Spreadsheet", category: "document" }, ["ppt" /* PPT */]: { extensions: ["ppt"], mimeTypes: ["application/vnd.ms-powerpoint"], displayName: "PowerPoint Presentation", category: "document" }, ["pptx" /* PPTX */]: { extensions: ["pptx"], mimeTypes: [ "application/vnd.openxmlformats-officedocument.presentationml.presentation" ], displayName: "PowerPoint Presentation", category: "document" }, ["txt" /* TXT */]: { extensions: ["txt"], mimeTypes: ["text/plain"], displayName: "Text File", category: "text" }, ["csv" /* CSV */]: { extensions: ["csv"], mimeTypes: ["text/csv"], displayName: "CSV File", category: "text" }, ["json" /* JSON */]: { extensions: ["json"], mimeTypes: ["application/json"], displayName: "JSON File", category: "text" }, ["xml" /* XML */]: { extensions: ["xml"], mimeTypes: ["application/xml", "text/xml"], displayName: "XML File", category: "text" }, ["html" /* HTML */]: { extensions: ["html", "htm"], mimeTypes: ["text/html"], displayName: "HTML File", category: "text" }, ["css" /* CSS */]: { extensions: ["css"], mimeTypes: ["text/css"], displayName: "CSS File", category: "text" }, ["js" /* JS */]: { extensions: ["js"], mimeTypes: ["application/javascript", "text/javascript"], displayName: "JavaScript File", category: "text" }, ["ts" /* TS */]: { extensions: ["ts"], mimeTypes: ["application/typescript", "text/typescript"], displayName: "TypeScript File", category: "text" }, ["md" /* MD */]: { extensions: ["md", "markdown"], mimeTypes: ["text/markdown"], displayName: "Markdown File", category: "text" } }; var FILE_TYPE_GROUPS = { IMAGES: ["jpeg" /* JPEG */, "jpg" /* JPG */, "png" /* PNG */, "webp" /* WEBP */], DOCUMENTS: [ "pdf" /* PDF */, "doc" /* DOC */, "docx" /* DOCX */, "xls" /* XLS */, "xlsx" /* XLSX */, "ppt" /* PPT */, "pptx" /* PPTX */ ], TEXT: [ "txt" /* TXT */, "csv" /* CSV */, "json" /* JSON */, "xml" /* XML */, "html" /* HTML */, "css" /* CSS */, "js" /* JS */, "ts" /* TS */, "md" /* MD */ ], SPREADSHEETS: ["xls" /* XLS */, "xlsx" /* XLSX */, "csv" /* CSV */], PRESENTATIONS: ["ppt" /* PPT */, "pptx" /* PPTX */], COMMON_IMAGES: ["jpeg" /* JPEG */, "jpg" /* JPG */, "png" /* PNG */, "webp" /* WEBP */], OFFICE_DOCS: [ "pdf" /* PDF */, "doc" /* DOC */, "docx" /* DOCX */, "xls" /* XLS */, "xlsx" /* XLSX */, "ppt" /* PPT */, "pptx" /* PPTX */ ] }; var getFileTypeDefinition = (fileType) => { return FILE_TYPE_DEFINITIONS[fileType]; }; var getFileExtensions = (fileType) => { return FILE_TYPE_DEFINITIONS[fileType].extensions; }; var getFileMimeTypes = (fileType) => { return FILE_TYPE_DEFINITIONS[fileType].mimeTypes; }; var isFileTypeMatch = (file, fileType) => { var _a; const definition = FILE_TYPE_DEFINITIONS[fileType]; const fileExtension = (_a = file.name.split(".").pop()) == null ? void 0 : _a.toLowerCase(); const extensionMatch = fileExtension && definition.extensions.includes(fileExtension); const mimeTypeMatch = definition.mimeTypes.includes(file.type); return extensionMatch || mimeTypeMatch; }; var validateFile = (file, allowedFileTypes = [], maxFileSizeBytes = 10 * 1e3 * 1e3) => { if (file.size > maxFileSizeBytes) { return `File size exceeds ${Math.round(maxFileSizeBytes / 1e3 / 1e3)}MB limit`; } if (allowedFileTypes.length > 0) { const isValidType = allowedFileTypes.some((fileType) => { return isFileTypeMatch(file, fileType); }); if (!isValidType) { const allowedTypeNames = allowedFileTypes.map((fileType) => { return FILE_TYPE_DEFINITIONS[fileType].displayName; }); return `File type not allowed. Allowed types: ${allowedTypeNames.join(", ")}`; } } return null; }; var getFileTypesByCategory = (category) => { return Object.entries(FILE_TYPE_DEFINITIONS).filter(([, definition]) => definition.category === category).map(([fileType]) => fileType); }; var createFileTypeValidator = (allowedTypes, maxSizeBytes = 10 * 1e3 * 1e3) => { return (file) => validateFile(file, allowedTypes, maxSizeBytes); }; var formatFileSize = (bytes) => { if (bytes === 0) return "0 Bytes"; const k = 1e3; const sizes = ["Bytes", "KB", "MB", "GB"]; const i = Math.floor(Math.log(bytes) / Math.log(k)); return parseFloat((bytes / Math.pow(k, i)).toFixed(2)) + " " + sizes[i]; }; var isFileApiSupported = () => { return typeof File !== "undefined" && typeof FileReader !== "undefined"; }; var isCryptoSupported = () => { return typeof crypto !== "undefined" && typeof crypto.subtle !== "undefined"; }; function useFileUpload({ onProgress, onUploadStart, onUploadComplete, onUploadError } = {}) { const [isUploading, setIsUploading] = useState(false); const uploadAndReturn = async (file) => { setIsUploading(true); onUploadStart == null ? void 0 : onUploadStart(file); try { const response = await uploadFileApiV1FilesPost({ body: { upload_file: file } }); if (response.error) { throw response.error; } const fileId = response.data.id; onProgress == null ? void 0 : onProgress(file, 10); const contentResponse = await readFileContentApiV1FilesIdContentGet({ path: { id: fileId } }); if (contentResponse.error) { throw contentResponse.error; } const fileUrl = contentResponse.data.url; onProgress == null ? void 0 : onProgress(file, 80); const fileData = { file, fileId, url: fileUrl }; onProgress == null ? void 0 : onProgress(file, 100); onUploadComplete == null ? void 0 : onUploadComplete(file); return { success: true, data: fileData, error: null }; } catch (error) { console.error("Upload error:", error); const errorMessage = error instanceof Error ? error.message : "Upload failed"; onUploadError == null ? void 0 : onUploadError(file, errorMessage); return { success: false, data: null, error }; } finally { setIsUploading(false); } }; return { isUploading, uploadAndReturn }; } // src/file-uploader/upload-progress-utils.ts var PROGRESS_THRESHOLD = 3; function getDisplayModes(fileCount) { return { showOverallProgress: fileCount > PROGRESS_THRESHOLD, isCompact: fileCount > PROGRESS_THRESHOLD }; } function addUploadToQueue(uploads, file) { const newUpload = { file, progress: 0, status: "uploading" }; const filtered = uploads.filter((upload) => upload.file.name !== file.name); return [...filtered, newUpload]; } function updateFileProgress(uploads, file, progress) { return uploads.map( (upload) => upload.file.name === file.name ? __spreadProps(__spreadValues({}, upload), { progress: Math.min(progress, 100) }) : upload ); } function completeFileUpload(uploads, file) { return uploads.map( (upload) => upload.file.name === file.name ? __spreadProps(__spreadValues({}, upload), { progress: 100, status: "completed" }) : upload ); } function failFileUpload(uploads, file, error) { return uploads.map( (upload) => upload.file.name === file.name ? __spreadProps(__spreadValues({}, upload), { status: "error", error }) : upload ); } function removeFileUpload(uploads, file) { return uploads.filter((upload) => upload.file.name !== file.name); } function calculateUploadStats(uploads) { return { total: uploads.length, uploading: uploads.filter((f) => f.status === "uploading").length, completed: uploads.filter((f) => f.status === "completed").length, failed: uploads.filter((f) => f.status === "error").length, canceled: uploads.filter((f) => f.status === "canceled").length, totalProgress: uploads.length > 0 ? Math.round( uploads.reduce((sum, f) => sum + f.progress, 0) / uploads.length ) : 0 }; } function hasActiveUploads(uploads) { return uploads.length > 0; } function getVisibleFiles(uploads, showAll, maxVisible = 5) { const shouldShowViewMore = uploads.length > maxVisible; const filesToShow = showAll ? uploads : uploads.slice(0, maxVisible); return { filesToShow, shouldShowViewMore }; } // src/file-uploader/use-upload-progress.ts function useUploadProgress() { const [uploadProgressFiles, setUploadProgressFiles] = useState([]); const [isVisible, setIsVisible] = useState(false); const startUpload = useCallback((file) => { setUploadProgressFiles((prev) => addUploadToQueue(prev, file)); setIsVisible(true); }, []); const updateProgress = useCallback((file, progress) => { setUploadProgressFiles((prev) => updateFileProgress(prev, file, progress)); }, []); const completeUpload = useCallback((file) => { setUploadProgressFiles((prev) => { const updated = completeFileUpload(prev, file); const allComplete = updated.every( (f) => f.status === "completed" || f.status === "error" ); if (allComplete) { setTimeout(() => { setUploadProgressFiles([]); setIsVisible(false); }, 1e4); } return updated; }); }, []); const failUpload = useCallback((file, error) => { setUploadProgressFiles((prev) => failFileUpload(prev, file, error)); }, []); const removeUpload = useCallback((file) => { setUploadProgressFiles((prev) => removeFileUpload(prev, file)); }, []); const clearAllUploads = useCallback(() => { setUploadProgressFiles([]); setIsVisible(false); }, []); const hideProgress = useCallback(() => { setIsVisible(false); }, []); const hasUploads = hasActiveUploads(uploadProgressFiles); if (!hasUploads && isVisible) { setIsVisible(false); } return { uploadProgressFiles, startUpload, updateProgress, completeUpload, failUpload, removeUpload, clearAllUploads, isVisible: isVisible && hasUploads, hideProgress }; } function UploadProgress({ files, onClose }) { const [isCollapsed, setIsCollapsed] = useState(false); const [showAll, setShowAll] = useState(false); if (files.length === 0) return null; const stats = calculateUploadStats(files); const { showOverallProgress, isCompact } = getDisplayModes(files.length); const maxVisible = 5; const { filesToShow, shouldShowViewMore } = getVisibleFiles( files, showAll, maxVisible ); return /* @__PURE__ */ jsxs("div", { className: "fixed bottom-4 right-4 z-50 w-80 bg-background border rounded-lg shadow-lg", children: [ /* @__PURE__ */ jsxs("div", { className: `p-4 ${showOverallProgress ? "border-b" : ""}`, children: [ /* @__PURE__ */ jsxs("div", { className: "flex items-center justify-between mb-2", children: [ /* @__PURE__ */ jsx("h3", { className: "font-semibold text-sm", children: showOverallProgress ? `Uploading Files (${stats.completed}/${stats.total})` : files.length === 1 ? "Uploading File" : "Uploading Files" }), /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-1", children: [ showOverallProgress && /* @__PURE__ */ jsx( Button, { variant: "ghost", size: "sm", className: "h-6 w-6 p-0", onClick: () => setIsCollapsed(!isCollapsed), children: /* @__PURE__ */ jsx( ChevronDown, { className: `h-4 w-4 transition-transform duration-200 ease-in-out ${isCollapsed ? "rotate-180" : "rotate-0"}` } ) } ), /* @__PURE__ */ jsx( Button, { variant: "ghost", size: "sm", className: "h-6 w-6 p-0", onClick: onClose, children: /* @__PURE__ */ jsx(X, { className: "h-4 w-4" }) } ) ] }) ] }), showOverallProgress && /* @__PURE__ */ jsxs(Fragment, { children: [ /* @__PURE__ */ jsx( Progress, { value: stats.totalProgress, className: `h-2 mb-2 ${stats.uploading === 0 && stats.completed > 0 ? "[&>[data-slot=progress-indicator]]:bg-green-500" : ""}` } ), /* @__PURE__ */ jsxs("div", { className: "flex items-center justify-between text-xs text-muted-foreground", children: [ /* @__PURE__ */ jsxs("span", { children: [ stats.completed > 0 && `${stats.completed} completed`, stats.uploading > 0 && `, ${stats.uploading} uploading`, stats.failed > 0 && `, ${stats.failed} failed` ] }), /* @__PURE__ */ jsxs("span", { children: [ stats.totalProgress, "%" ] }) ] }) ] }) ] }), (!showOverallProgress || !isCollapsed) && /* @__PURE__ */ jsxs("div", { className: `${showOverallProgress ? "p-4" : "px-4 pb-4"}`, children: [ /* @__PURE__ */ jsx("div", { className: "space-y-3", children: filesToShow.map((fileProgress, index) => /* @__PURE__ */ jsx( FileProgressItem, { fileProgress, isCompact }, `${fileProgress.file.name}-${index}` )) }), shouldShowViewMore && /* @__PURE__ */ jsx("div", { className: "pt-2 border-t mt-3", children: /* @__PURE__ */ jsxs( Button, { variant: "ghost", size: "sm", className: "w-full h-6 text-xs transition-all duration-200 hover:bg-accent", onClick: () => setShowAll(!showAll), children: [ /* @__PURE__ */ jsx( ChevronDown, { className: `h-3 w-3 mr-1 transition-transform duration-200 ${showAll ? "rotate-180" : "rotate-0"}` } ), showAll ? "Show Less" : `View ${files.length - maxVisible} More Files` ] } ) }) ] }) ] }); } function FileProgressItem({ fileProgress, isCompact = false }) { const { file, progress, status, error } = fileProgress; if (isCompact) { return /* @__PURE__ */ jsxs("div", { className: "space-y-1", children: [ /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2 text-xs", children: [ /* @__PURE__ */ jsx( "div", { className: `w-2 h-2 rounded-full flex-shrink-0 ${status === "error" ? "bg-destructive" : status === "completed" ? "bg-green-500" : status === "canceled" ? "bg-muted-foreground" : "bg-primary animate-pulse"}` } ), /* @__PURE__ */ jsx("span", { className: "font-medium truncate flex-1", title: file.name, children: file.name }), /* @__PURE__ */ jsx("span", { className: "text-muted-foreground", children: status === "completed" ? "\u2713" : status === "canceled" ? "\u2715" : `${Math.round(progress)}%` }) ] }), status === "error" && error && /* @__PURE__ */ jsx("div", { className: "text-xs text-destructive pl-4", children: error }), status === "canceled" && /* @__PURE__ */ jsx("div", { className: "text-xs text-muted-foreground pl-4", children: "Canceled" }) ] }); } return /* @__PURE__ */ jsxs("div", { className: "space-y-2", children: [ /* @__PURE__ */ jsxs("div", { className: "flex items-center justify-between text-sm", children: [ /* @__PURE__ */ jsx("span", { className: "font-medium truncate flex-1", title: file.name, children: file.name }), /* @__PURE__ */ jsx("span", { className: "text-muted-foreground ml-2", children: formatFileSize(file.size) }) ] }), /* @__PURE__ */ jsxs("div", { className: "space-y-1", children: [ /* @__PURE__ */ jsx( Progress, { value: Math.min(progress, 100), className: `h-2 transition-all duration-300 ${status === "error" ? "[&>[data-slot=progress-indicator]]:bg-destructive" : status === "completed" ? "[&>[data-slot=progress-indicator]]:bg-green-500" : status === "canceled" ? "[&>[data-slot=progress-indicator]]:bg-muted-foreground" : ""}` } ), /* @__PURE__ */ jsx("div", { className: "flex items-center justify-between text-xs", children: /* @__PURE__ */ jsx( "span", { className: `${status === "error" ? "text-destructive" : status === "completed" ? "text-green-600" : status === "canceled" ? "text-muted-foreground" : "text-muted-foreground"}`, children: status === "error" && error ? error : status === "completed" ? "Completed" : status === "canceled" ? "Canceled" : `${Math.round(progress)}%` } ) }) ] }) ] }); } function FileUploader({ title, description, inputFields, allowedFileTypes = [], maxFileSizeBytes = 100 * 1024 * 1024, // 100MB default multiple = false, onSuccess, trigger, isProcessing = false }) { const [isOpen, setIsOpen] = useState(false); const [fieldValues, setFieldValues] = useState({}); const [selectedFiles, setSelectedFiles] = useState([]); const [dragActive, setDragActive] = useState(false); const [fieldErrors, setFieldErrors] = useState({}); const modalTitle = title || (multiple ? "Upload Files" : "Upload File"); const modalDescription = description || (multiple ? "Upload files and fill in the required information" : "Upload a file and fill in the required information"); const uploadProgress = useUploadProgress(); const { uploadAndReturn } = useFileUpload({ onUploadStart: uploadProgress.startUpload, onProgress: uploadProgress.updateProgress, onUploadComplete: uploadProgress.completeUpload, onUploadError: uploadProgress.failUpload }); const handleClose = () => { setIsOpen(false); setFieldValues({}); setSelectedFiles([]); setDragActive(false); setFieldErrors({}); }; const handleFieldChange = (key, value) => { setFieldValues((prev) => __spreadProps(__spreadValues({}, prev), { [key]: value })); if (fieldErrors[key]) { setFieldErrors((prev) => __spreadProps(__spreadValues({}, prev), { [key]: "" })); } }; const validateFields = () => { const errors = {}; inputFields == null ? void 0 : inputFields.forEach((field) => { const value = fieldValues[field.key] || ""; if (field.required && !value.trim()) { errors[field.key] = `${field.label} is required`; return; } if (field.validation && value.trim()) { const validationError = field.validation(value.trim()); if (validationError) { errors[field.key] = validationError; } } }); setFieldErrors(errors); return Object.keys(errors).length === 0; }; const handleFileSelect = (newFiles) => { const validFiles = []; newFiles.forEach((file) => { const validationError = validateFile( file, allowedFileTypes, maxFileSizeBytes ); if (!validationError) { validFiles.push(file); } }); if (validFiles.length > 0) { if (multiple) { setSelectedFiles((prev) => [...prev, ...validFiles]); } else { setSelectedFiles(validFiles.slice(0, 1)); } } }; const handleDragEnter = (e) => { e.preventDefault(); e.stopPropagation(); setDragActive(true); }; const handleDragLeave = (e) => { e.preventDefault(); e.stopPropagation(); setDragActive(false); }; const handleDragOver = (e) => { e.preventDefault(); e.stopPropagation(); }; const handleDrop = (e) => { e.preventDefault(); e.stopPropagation(); setDragActive(false); const files = Array.from(e.dataTransfer.files); if (files.length > 0) { handleFileSelect(files); } }; const handleFileInputChange = (e) => { const files = e.target.files; if (files && files.length > 0) { handleFileSelect(Array.from(files)); } }; const handleUpload = async () => { if (selectedFiles.length === 0) { return; } if (!validateFields()) { return; } handleClose(); try { const uploadPromises = selectedFiles.map((file) => uploadAndReturn(file)); const results = await Promise.all(uploadPromises); const successfulData = results.filter((result) => result.success && result.data).map((result) => result.data); if (successfulData.length > 0) { await onSuccess(successfulData, fieldValues); } } catch (e) { } }; const removeFile = (fileToRemove) => { setSelectedFiles((prev) => prev.filter((file) => file !== fileToRemove)); }; const canSubmit = () => { if (!inputFields) return true; if (inputFields.length === 0) return true; if (selectedFiles.length === 0) return false; return inputFields.every( (field) => !field.required || fieldValues[field.key] && fieldValues[field.key].trim() ); }; return /* @__PURE__ */ jsxs(Fragment, { children: [ /* @__PURE__ */ jsxs(Dialog, { open: isOpen, onOpenChange: setIsOpen, children: [ /* @__PURE__ */ jsx(DialogTrigger, { asChild: true, children: trigger || /* @__PURE__ */ jsxs(Button, { className: "cursor-pointer", disabled: isProcessing, children: [ isProcessing && /* @__PURE__ */ jsx(Loader2, { className: "h-4 w-4 animate-spin mr-2" }), /* @__PURE__ */ jsx(Upload, { className: "h-4 w-4" }), multiple ? "Upload Files" : "Upload File" ] }) }), /* @__PURE__ */ jsxs(DialogContent, { className: "sm:max-w-md", children: [ /* @__PURE__ */ jsxs(DialogHeader, { children: [ /* @__PURE__ */ jsx(DialogTitle, { children: modalTitle }), /* @__PURE__ */ jsx("p", { className: "text-sm text-muted-foreground", children: modalDescription }) ] }), /* @__PURE__ */ jsxs("div", { className: "space-y-4 overflow-hidden", children: [ inputFields == null ? void 0 : inputFields.map((field) => /* @__PURE__ */ jsxs("div", { className: "space-y-2", children: [ /* @__PURE__ */ jsxs("label", { htmlFor: field.key, className: "text-sm font-medium", children: [ field.label, field.required && /* @__PURE__ */ jsx("span", { className: "text-destructive ml-1", children: "*" }) ] }), /* @__PURE__ */ jsx( Input, { id: field.key, value: fieldValues[field.key] || "", onChange: (e) => handleFieldChange(field.key, e.target.value), placeholder: field.placeholder, className: fieldErrors[field.key] ? "border-destructive" : "" } ), fieldErrors[field.key] && /* @__PURE__ */ jsx("p", { className: "text-sm text-destructive", children: fieldErrors[field.key] }) ] }, field.key)), /* @__PURE__ */ jsxs("div", { className: "space-y-2", children: [ /* @__PURE__ */ jsxs("label", { className: "text-sm font-medium", children: [ multiple ? "Files" : "File", " ", /* @__PURE__ */ jsx("span", { className: "text-destructive ml-1", children: "*" }) ] }), /* @__PURE__ */ jsxs( "div", { className: `border border-dashed rounded-lg p-4 text-center transition-colors cursor-pointer ${dragActive ? "border-primary bg-primary/5" : "border-muted-foreground/30 hover:border-primary/60"}`, onDragEnter: handleDragEnter, onDragLeave: handleDragLeave, onDragOver: handleDragOver, onDrop: handleDrop, onClick: () => { var _a; return (_a = document.getElementById("file-upload")) == null ? void 0 : _a.click(); }, children: [ selectedFiles.length > 0 ? /* @__PURE__ */ jsxs("div", { className: "space-y-2", children: [ selectedFiles.map((file, index) => /* @__PURE__ */ jsxs( "div", { className: "flex items-center justify-between bg-muted/30 px-3 py-2 rounded", children: [ /* @__PURE__ */ jsxs("div", { className: "flex items-center space-x-2 min-w-0 flex-1", children: [ /* @__PURE__ */ jsx(Upload, { className: "h-3 w-3 text-muted-foreground flex-shrink-0" }), /* @__PURE__ */ jsx("span", { className: "text-sm font-medium truncate", children: file.name }), /* @__PURE__ */ jsxs("span", { className: "text-xs text-muted-foreground flex-shrink-0", children: [ "(", Math.round(file.size / 1e3), "KB)" ] }) ] }), /* @__PURE__ */ jsx( Button, { variant: "ghost", size: "sm", className: "h-6 w-6 p-0 flex-shrink-0", onClick: (e) => { e.stopPropagation(); removeFile(file); }, children: /* @__PURE__ */ jsx(X, { className: "h-3 w-3" }) } ) ] }, `${file.name}-${index}` )), multiple && /* @__PURE__ */ jsx("div", { className: "text-xs text-muted-foreground pt-2 mt-3 border-t border-muted-foreground/20", children: "Click to add more files or drag and drop" }) ] }) : /* @__PURE__ */ jsxs("div", { className: "space-y-3", children: [ /* @__PURE__ */ jsx(Upload, { className: "h-6 w-6 text-muted-foreground mx-auto" }), /* @__PURE__ */ jsxs("div", { children: [ /* @__PURE__ */ jsxs("div", { className: "text-sm font-medium", children: [ "Click to upload", multiple ? " files" : "" ] }), /* @__PURE__ */ jsx("div", { className: "text-xs text-muted-foreground mt-1", children: "or drag and drop" }) ] }), allowedFileTypes.length > 0 && /* @__PURE__ */ jsxs("p", { className: "text-xs text-muted-foreground", children: [ "Supported: ", allowedFileTypes.join(", ") ] }), /* @__PURE__ */ jsxs("p", { className: "text-xs text-muted-foreground", children: [ "Max size: ", Math.round(maxFileSizeBytes / 1e3 / 1e3), "MB" ] }) ] }), /* @__PURE__ */ jsx( "input", { type: "file", className: "sr-only", id: "file-upload", onChange: handleFileInputChange, accept: allowedFileTypes.join(","), multiple } ) ] } ) ] }) ] }), /* @__PURE__ */ jsxs(DialogFooter, { children: [ /* @__PURE__ */ jsx(Button, { variant: "outline", onClick: handleClose, children: "Cancel" }), /* @__PURE__ */ jsx(Button, { onClick: handleUpload, disabled: !canSubmit, children: selectedFiles.length > 1 ? `Upload ${selectedFiles.length} Files & Process` : "Upload & Process" }) ] }) ] }) ] }), /* @__PURE__ */ jsx( UploadProgress, { files: uploadProgress.uploadProgressFiles, onClose: uploadProgress.clearAllUploads } ) ] }); } export { FILE_TYPE_GROUPS, FileType, FileUploader, UploadProgress, createFileTypeValidator, formatFileSize, getFileExtensions, getFileMimeTypes, getFileTypeDefinition, getFileTypesByCategory, isCryptoSupported, isFileApiSupported, isFileTypeMatch, useFileUpload, useUploadProgress, validateFile };