@llamaindex/ui
Version:
A comprehensive UI component library built with React, TypeScript, and Tailwind CSS for LlamaIndex applications
217 lines (214 loc) • 7.5 kB
JavaScript
import { FileToolbar, BoundingBoxOverlay } from './chunk-BXXOJHA2.mjs';
import { PdfPreview } from './chunk-LB2R4VLK.mjs';
import { Card } from './chunk-BYCYB6AC.mjs';
import { Button } from './chunk-JLPGK5XZ.mjs';
import { cn } from './chunk-MG2ARK3A.mjs';
import { __objRest, __spreadValues } from './chunk-4AMAFZLZ.mjs';
import { useState, useEffect, useRef } from 'react';
import { jsx, jsxs } from 'react/jsx-runtime';
import { getFileApiV1FilesIdGet, readFileContentApiV1FilesIdContentGet } from 'llama-cloud-services/api';
import { Clock, XCircle, File, Trash2 } from 'lucide-react';
function ImagePreview({
src,
boundingBoxes = [],
onBoundingBoxClick,
onImageLoad
}) {
const imgRef = useRef(null);
const [imageDimensions, setImageDimensions] = useState({
width: 0,
height: 0
});
const handleImageLoad = () => {
if (imgRef.current) {
const { naturalWidth, naturalHeight } = imgRef.current;
setImageDimensions({ width: naturalWidth, height: naturalHeight });
onImageLoad == null ? void 0 : onImageLoad({ width: naturalWidth, height: naturalHeight });
}
};
return /* @__PURE__ */ jsxs(
"div",
{
style: {
position: "relative",
display: "inline-block",
border: "1px solid #eee"
},
children: [
/* @__PURE__ */ jsx(
"img",
{
ref: imgRef,
src,
alt: "Preview",
onLoad: handleImageLoad,
style: {
maxWidth: "100%",
height: "auto"
}
}
),
/* @__PURE__ */ jsx(
BoundingBoxOverlay,
{
boundingBoxes,
zoom: 1,
containerWidth: imageDimensions.width,
containerHeight: imageDimensions.height,
onBoundingBoxClick
}
)
]
}
);
}
function useFileData(fileId, mockData) {
const [data, setData] = useState(null);
const [loading, setLoading] = useState(true);
const [error, setError] = useState(null);
useEffect(() => {
const fetchFileData = async () => {
var _a, _b, _c;
if (!fileId) {
setLoading(false);
return;
}
if (mockData) {
setData(mockData);
setLoading(false);
return;
}
setLoading(true);
setError(null);
try {
const getFilePromise = getFileApiV1FilesIdGet({
headers: {
"Content-Type": "application/json"
},
path: {
id: fileId
}
});
const getFileContentPromise = readFileContentApiV1FilesIdContentGet({
headers: {
"Content-Type": "application/json"
},
path: {
id: fileId
}
});
const fileResponse = await getFilePromise;
const contentResponse = await getFileContentPromise;
const fileType = (_a = fileResponse.data) == null ? void 0 : _a.file_type;
const url = (_b = contentResponse.data) == null ? void 0 : _b.url;
setData({
url,
name: (_c = fileResponse.data) == null ? void 0 : _c.name,
type: fileType || void 0
});
} catch (err) {
console.error("Error fetching file data:", err);
setError(
err instanceof Error ? err.message : "Failed to load file data"
);
} finally {
setLoading(false);
}
};
fetchFileData();
}, [fileId, mockData]);
return { data, loading, error };
}
function getFileType(fileType) {
if (!fileType) return "unsupported";
const type = fileType.toLowerCase();
if (type.includes("image/") || type.includes("png") || type.includes("jpg") || type.includes("jpeg") || type.includes("gif") || type.includes("webp")) {
return "image";
}
if (type.includes("pdf")) {
return "pdf";
}
return "unsupported";
}
function FilePreview({
onBoundingBoxClick,
highlight,
fileId,
mockData
}) {
const { data, loading, error } = useFileData(fileId || "", mockData);
const fileName = (data == null ? void 0 : data.name) || "";
const fileType = getFileType(data == null ? void 0 : data.type) || "unsupported";
if (loading) {
return /* @__PURE__ */ jsx(Card, { children: /* @__PURE__ */ jsx("div", { className: "flex h-32 items-center justify-center", children: /* @__PURE__ */ jsxs("div", { className: "text-center", children: [
/* @__PURE__ */ jsx(Clock, { className: "h-8 w-8 animate-spin mx-auto mb-2" }),
/* @__PURE__ */ jsx("div", { className: "text-sm text-muted-foreground", children: "Loading file..." })
] }) }) });
}
if (error) {
return /* @__PURE__ */ jsx(Card, { children: /* @__PURE__ */ jsx("div", { className: "flex h-32 items-center justify-center", children: /* @__PURE__ */ jsxs("div", { className: "text-center", children: [
/* @__PURE__ */ jsx(XCircle, { className: "h-8 w-8 text-red-500 mx-auto mb-2" }),
/* @__PURE__ */ jsxs("div", { className: "text-sm text-muted-foreground", children: [
"Error loading file: ",
error
] })
] }) }) });
}
if (fileType === "unsupported") {
return /* @__PURE__ */ jsx(Card, { children: /* @__PURE__ */ jsx("div", { className: "p-4", children: /* @__PURE__ */ jsxs("p", { className: "text-sm text-muted-foreground", children: [
"Unsupported file type: ",
fileName
] }) }) });
}
if (fileType === "image") {
return /* @__PURE__ */ jsx("div", { className: "flex flex-col gap-6", children: /* @__PURE__ */ jsx(
ImagePreview,
{
src: (data == null ? void 0 : data.url) || "",
boundingBoxes: [],
onBoundingBoxClick: (box) => onBoundingBoxClick == null ? void 0 : onBoundingBoxClick(box, 1)
}
) });
}
if (fileType === "pdf") {
return /* @__PURE__ */ jsx(
PdfPreview,
{
url: (data == null ? void 0 : data.url) || "",
highlights: highlight ? [highlight] : void 0
}
);
}
return null;
}
var PdfNavigator = (props) => {
if (process.env.NODE_ENV !== "production") {
console.warn(
"PdfNavigator is deprecated. Use FileToolbar from @llamaindex/ui/document-preview directly instead."
);
}
const { fileName, onRemove, className } = props;
const toolbarProps = props.isLoading === true ? null : (() => {
const _a = props, { fileName: fileName2, onRemove: onRemove2, className: className2, isLoading } = _a, rest = __objRest(_a, ["fileName", "onRemove", "className", "isLoading"]);
return rest;
})();
return /* @__PURE__ */ jsx("div", { className: cn("sticky top-0 w-full z-50 text-xs", className), children: /* @__PURE__ */ jsxs("div", { className: "bg-white border px-6 flex items-center justify-between gap-3 h-10", children: [
/* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2", children: [
/* @__PURE__ */ jsx(File, { className: "size-4" }),
/* @__PURE__ */ jsx("span", { className: "text-xs text-muted-foreground", children: fileName }),
onRemove && /* @__PURE__ */ jsx(
Button,
{
variant: "ghost",
size: "sm",
onClick: onRemove,
className: "size-6 p-0",
title: "Remove PDF",
children: /* @__PURE__ */ jsx(Trash2, { className: "size-4" })
}
)
] }),
toolbarProps && /* @__PURE__ */ jsx(FileToolbar, __spreadValues({}, toolbarProps))
] }) });
};
export { FilePreview, PdfNavigator, useFileData };