UNPKG

@llamaindex/ui

Version:

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

321 lines (318 loc) 12.8 kB
import { Tooltip, TooltipTrigger, TooltipContent } from './chunk-LFNFTZZW.mjs'; import { Input } from './chunk-QMXCUFNI.mjs'; import { Button } from './chunk-JLPGK5XZ.mjs'; import { cn } from './chunk-MG2ARK3A.mjs'; import { jsx, jsxs, Fragment } from 'react/jsx-runtime'; import { File, Trash2, ChevronLeft, ChevronRight, Minus, Plus, RotateCcw, Download, Maximize } from 'lucide-react'; import { useState, useEffect } from 'react'; function BoundingBoxOverlay({ boundingBoxes, zoom, containerWidth, containerHeight, onBoundingBoxClick }) { if (containerWidth === 0 || containerHeight === 0) { return null; } return /* @__PURE__ */ jsx( "svg", { style: { position: "absolute", top: 0, left: 0, width: containerWidth * zoom, height: containerHeight * zoom, pointerEvents: "none" }, viewBox: `0 0 ${containerWidth} ${containerHeight}`, children: boundingBoxes.map((box) => /* @__PURE__ */ jsxs("g", { children: [ /* @__PURE__ */ jsx( "rect", { x: box.x, y: box.y, width: box.width, height: box.height, fill: box.color || "rgba(255, 0, 0, 0.2)", stroke: box.color || "red", strokeWidth: 2 / zoom, style: { pointerEvents: "auto", cursor: onBoundingBoxClick ? "pointer" : "default" }, onClick: () => onBoundingBoxClick == null ? void 0 : onBoundingBoxClick(box) } ), box.label && /* @__PURE__ */ jsx( "text", { x: box.x, y: box.y - 5, fill: box.color || "red", fontSize: 12 / zoom, fontWeight: "bold", children: box.label } ) ] }, box.id)) } ); } var FileToolbar = ({ fileName, onFullscreen, scale, onScaleChange, onReset, onRemove, onDownload, currentPage, totalPages, onPageChange, className, isOverlay = false }) => { var _a; const [pageInput, setPageInput] = useState( (_a = currentPage == null ? void 0 : currentPage.toString()) != null ? _a : "1" ); const [isEditing, setIsEditing] = useState(false); const [isHovered, setIsHovered] = useState(false); const showZoomControls = typeof scale === "number" && typeof onScaleChange === "function"; const showPageNavigation = typeof currentPage === "number" && typeof totalPages === "number" && typeof onPageChange === "function"; useEffect(() => { if (!isEditing && typeof currentPage === "number") { setPageInput(currentPage.toString()); } }, [currentPage, isEditing]); const handlePageInputChange = (value) => { setPageInput(value); setIsEditing(true); }; const handlePageInputSubmit = () => { if (!showPageNavigation || !totalPages || !currentPage || !onPageChange) { return; } const pageNumber = parseInt(pageInput); if (pageNumber >= 1 && pageNumber <= totalPages) { onPageChange(pageNumber); } else { setPageInput(currentPage.toString()); } setIsEditing(false); }; const handlePageInputKeyDown = (e) => { if (e.key === "Enter") { handlePageInputSubmit(); } }; const handlePageInputFocus = () => { setIsEditing(true); }; const handlePrevPage = () => { if (showPageNavigation && currentPage !== void 0 && totalPages !== void 0 && onPageChange && currentPage > 1) { onPageChange(currentPage - 1); } }; const handleNextPage = () => { if (showPageNavigation && currentPage !== void 0 && totalPages !== void 0 && onPageChange && currentPage < totalPages) { onPageChange(currentPage + 1); } }; const handleZoomIn = () => { if (showZoomControls && scale !== void 0 && onScaleChange) { onScaleChange(Math.min(scale + 0.25, 3)); } }; const handleZoomOut = () => { if (showZoomControls && scale !== void 0 && onScaleChange) { onScaleChange(Math.max(scale - 0.25, 0.5)); } }; const handleReset = () => { if (showZoomControls && onScaleChange) { onScaleChange(1); } if (onReset) { onReset(); } }; const hasControls = showPageNavigation || showZoomControls || onDownload || onFullscreen || onReset; return /* @__PURE__ */ jsxs( "div", { className: cn( "flex h-10 items-center justify-between gap-3 px-6 transition", isOverlay ? [ "absolute left-0 right-0 top-0 z-10 border-b bg-white/70", isHovered ? "opacity-100" : "opacity-20", "transition-opacity duration-300 ease-in-out" ] : "border-b bg-white", className ), onMouseEnter: () => isOverlay && setIsHovered(true), onMouseLeave: () => isOverlay && setIsHovered(false), children: [ /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2", children: [ fileName && /* @__PURE__ */ jsxs(Fragment, { children: [ /* @__PURE__ */ jsx(File, { className: "size-4" }), /* @__PURE__ */ jsx("span", { className: "text-xs text-muted-foreground", children: fileName }) ] }), onRemove && /* @__PURE__ */ jsxs(Tooltip, { children: [ /* @__PURE__ */ jsx(TooltipTrigger, { asChild: true, children: /* @__PURE__ */ jsx( Button, { variant: "ghost", size: "sm", onClick: onRemove, className: "size-6 p-0", children: /* @__PURE__ */ jsx(Trash2, { className: "size-4" }) } ) }), /* @__PURE__ */ jsx(TooltipContent, { children: "Remove file" }) ] }) ] }), hasControls && /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-3", children: [ showPageNavigation && /* @__PURE__ */ jsxs(Fragment, { children: [ /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-1", children: [ /* @__PURE__ */ jsxs(Tooltip, { children: [ /* @__PURE__ */ jsx(TooltipTrigger, { asChild: true, children: /* @__PURE__ */ jsx( Button, { variant: "ghost", size: "sm", onClick: handlePrevPage, disabled: currentPage === void 0 || currentPage <= 1, className: "size-6 p-0", children: /* @__PURE__ */ jsx(ChevronLeft, { className: "size-4" }) } ) }), /* @__PURE__ */ jsx(TooltipContent, { children: "Previous page" }) ] }), /* @__PURE__ */ jsxs("div", { className: "flex items-center justify-center gap-0.5", children: [ /* @__PURE__ */ jsx( Input, { type: "number", value: pageInput, onChange: (e) => handlePageInputChange(e.target.value), onFocus: handlePageInputFocus, onBlur: handlePageInputSubmit, onKeyDown: handlePageInputKeyDown, className: "size-6 px-1 text-center text-xs! rounded-sm [&::-webkit-outer-spin-button]:appearance-none [&::-webkit-inner-spin-button]:appearance-none [&::-webkit-inner-spin-button]:m-0 [&::-webkit-outer-spin-button]:m-0 [-moz-appearance:textfield] shadow-none border border-transparent hover:border-gray-300 focus:border-gray-500 focus:outline-none", min: 1, max: totalPages } ), /* @__PURE__ */ jsx("span", { className: "text-xs text-muted-foreground", children: "/" }), /* @__PURE__ */ jsx("span", { className: "flex items-center text-xs text-muted-foreground h-7 ml-1", children: totalPages }) ] }), /* @__PURE__ */ jsxs(Tooltip, { children: [ /* @__PURE__ */ jsx(TooltipTrigger, { asChild: true, children: /* @__PURE__ */ jsx( Button, { variant: "ghost", size: "sm", onClick: handleNextPage, disabled: currentPage === void 0 || totalPages === void 0 || currentPage >= totalPages, className: "size-6 p-0", children: /* @__PURE__ */ jsx(ChevronRight, { className: "size-4" }) } ) }), /* @__PURE__ */ jsx(TooltipContent, { children: "Next page" }) ] }) ] }), (showZoomControls || onDownload || onFullscreen || onReset) && /* @__PURE__ */ jsx("div", { className: "h-6 w-px bg-border" }) ] }), showZoomControls && /* @__PURE__ */ jsxs(Fragment, { children: [ /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-1", children: [ /* @__PURE__ */ jsxs(Tooltip, { children: [ /* @__PURE__ */ jsx(TooltipTrigger, { asChild: true, children: /* @__PURE__ */ jsx( Button, { variant: "ghost", size: "sm", onClick: handleZoomOut, disabled: scale !== void 0 && scale <= 0.5, className: "size-6 p-0", "aria-label": "Zoom Out", children: /* @__PURE__ */ jsx(Minus, { className: "size-4" }) } ) }), /* @__PURE__ */ jsx(TooltipContent, { children: "Zoom out" }) ] }), /* @__PURE__ */ jsxs("span", { className: "text-center text-xs text-muted-foreground", children: [ scale !== void 0 ? Math.round(scale * 100) : 0, "%" ] }), /* @__PURE__ */ jsxs(Tooltip, { children: [ /* @__PURE__ */ jsx(TooltipTrigger, { asChild: true, children: /* @__PURE__ */ jsx( Button, { variant: "ghost", size: "sm", onClick: handleZoomIn, disabled: scale !== void 0 && scale >= 3, className: "size-6 p-0", "aria-label": "Zoom In", children: /* @__PURE__ */ jsx(Plus, { className: "size-4" }) } ) }), /* @__PURE__ */ jsx(TooltipContent, { children: "Zoom in" }) ] }), /* @__PURE__ */ jsxs(Tooltip, { children: [ /* @__PURE__ */ jsx(TooltipTrigger, { asChild: true, children: /* @__PURE__ */ jsx( Button, { variant: "ghost", size: "sm", onClick: handleReset, className: "size-6 p-0", "aria-label": "Reset Zoom", children: /* @__PURE__ */ jsx(RotateCcw, { className: "size-4" }) } ) }), /* @__PURE__ */ jsx(TooltipContent, { children: "Reset zoom" }) ] }) ] }), (onDownload || onFullscreen) && /* @__PURE__ */ jsx("div", { className: "h-6 w-px bg-border" }) ] }), onDownload && /* @__PURE__ */ jsxs(Fragment, { children: [ /* @__PURE__ */ jsxs(Tooltip, { children: [ /* @__PURE__ */ jsx(TooltipTrigger, { asChild: true, children: /* @__PURE__ */ jsx( Button, { variant: "ghost", size: "sm", onClick: onDownload, className: "size-6 p-0", "aria-label": "Download PDF", children: /* @__PURE__ */ jsx(Download, { className: "size-4" }) } ) }), /* @__PURE__ */ jsx(TooltipContent, { children: "Download" }) ] }), onFullscreen && /* @__PURE__ */ jsx("div", { className: "h-6 w-px bg-border" }) ] }), onFullscreen && /* @__PURE__ */ jsxs(Tooltip, { children: [ /* @__PURE__ */ jsx(TooltipTrigger, { asChild: true, children: /* @__PURE__ */ jsx( Button, { variant: "ghost", size: "sm", onClick: onFullscreen, className: "size-6 p-0", "aria-label": "Fullscreen", children: /* @__PURE__ */ jsx(Maximize, { className: "size-4" }) } ) }), /* @__PURE__ */ jsx(TooltipContent, { children: "Fullscreen" }) ] }) ] }) ] } ); }; export { BoundingBoxOverlay, FileToolbar };