@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
JavaScript
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 };