UNPKG

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