/** * PDF rendering substrate — react-pdf + react-zoom-pan-pinch. * * Replaces the previous tile-fetch + canvas approach with Mozilla's * pdf.js renderer (via wojtekmaj/react-pdf) wrapped in a battle- * tested pan/zoom controller. This gives Acrobat-grade interactions: * one-finger pan, pinch-zoom, double-tap zoom, momentum scroll on * iOS Safari — all without the custom touch routing the old * implementation kept losing to mobile browser quirks. * * The substrate is geometry-pure: it renders a single PDF page at * a fixed internal resolution and lets the host position any number * of overlay children on top via the `overlay` slot. Overlays render * INSIDE the TransformComponent so they scale/pan with the page — * no per-overlay zoom math needed. */ import type { ReactNode } from "react"; import type { ThemeTokens } from "../plugin/services"; export { defaultPdfjsWorkerSrc } from "./pdfjsWorker"; /** * Page anchoring within the stage. ``"center"`` centers the page; * ``"left"`` pins it to the top-left. Shared by {@link PdfSubstrateProps} * and `LensPDFProps` so the union + default stay in lockstep. * * @public */ export type StageAlign = "center" | "left"; export interface PdfSubstrateProps { /** Source PDF — URL string, File, or { url, ... } object. Mirrors * react-pdf's `Document.file` prop type. */ file: string | File | { url: string; }; /** 1-indexed page number to display. */ pageNumber: number; /** Current zoom percentage (e.g., 80 = 80%). Drives the * TransformWrapper's CSS transform; the underlying canvas is * rendered at RENDER_SCALE regardless. */ zoom: number; /** Fires when the user pinches / double-taps / wheels — reports * the new percentage so the host's zoom slider stays in sync. */ onZoomChange?: (zoomPercent: number) => void; /** Fires once react-pdf has parsed the document. */ onDocumentLoad?: (info: { numPages: number; }) => void; /** Fires when a page has fully rendered (canvas drawn + text * layer placed) — host uses this to mount overlays at the * right time. */ onPageRender?: (info: { pageNumber: number; /** Rendered page width in CSS px (canvas + text layer width). */ width: number; /** Rendered page height in CSS px. */ height: number; /** PDF page dimensions in points. */ widthPts: number; heightPts: number; }) => void; /** Children rendered inside the TransformComponent on top of the * PDF page. Use absolute positioning relative to the page (the * parent has `position: relative` with `width=renderedWidth`, * `height=renderedHeight`). All overlays scale + pan with the * page automatically. */ overlay?: ReactNode; /** Theme tokens for the loading / error states. */ tokens: ThemeTokens; /** When true, suppress the TransformWrapper's pan + pinch — useful * while an annotation / measurement tool needs exclusive touch * input. */ panEnabled?: boolean; pinchEnabled?: boolean; /** Optional className on the wrapper div. */ className?: string; /** * Host-provided loading state. Replaces the built-in * `LensLoadingSkeleton` for both the document-fetch and the * per-page render phases. When unset, defaults to a branded * page-shaped skeleton with a shimmer sweep. * * Pass a static React node for a fully custom loading screen, or * pass `} />` to * keep the default look with a brand logo on top. */ loadingPlaceholder?: ReactNode; /** * Milliseconds before the "load taking too long" error fires. * Only applies when `file` is a URL string (blob: or http(s):). * Default: 30 000. */ loadTimeoutMs?: number; /** * Bounding box (PDF points, ``[x0, y0, x1, y1]``, origin lower-left) * to frame on screen — typically the union of a selected finding's * bbox + regions. ``null`` leaves the current pan/zoom untouched. */ focusRect?: readonly [number, number, number, number] | null; /** * Identity of the focus request (e.g. the selected finding id). The * substrate re-frames only when this value changes, so unrelated * re-renders — or the user manually panning/zooming — don't yank the * view back to the finding. The rect contents are also compared, so * an in-place geometry update on the same id (e.g. live preflight * enriching a finding's regions) still re-frames. */ focusKey?: string | number | null; /** * Lower / upper zoom bounds (transform scale, 1 = 100%). Defaults * align the TransformWrapper's pan/pinch limits with the * `computeFitScale` clamp the focus effect uses, so a fit can * never ask for a scale the wrapper won't apply. Bump `maxScale` * for hosts that want deeper zoom on signage / high-DPI imagery. * Defaults: ``0.25`` / ``4``. */ minScale?: number; maxScale?: number; /** * Anchoring of the page within the stage. ``"center"`` (default) * centers it; ``"left"`` pins the page to the top-left so it opens * flush against the stage's top-left edge. Mobile always pins * top-left regardless (the page is usually wider than a phone * viewport); this prop extends that behaviour to desktop. */ stageAlign?: StageAlign; /** * Override the react-pdf pdf.js worker URL. When set (and running in * the browser), it replaces `pdfjs.GlobalWorkerOptions.workerSrc` * before `` mounts, so the worker spins up from a * self-hosted file instead of the unpkg default. Must match * react-pdf's bundled pdfjs major (see {@link defaultPdfjsWorkerSrc}). * When unset, the module-load default (unpkg, or a real URL a host * set before importing lens-pdf) is used. */ workerSrc?: string; } export interface LensLoadingSkeletonProps { /** Theme tokens for backgrounds + borders + text. */ tokens: ThemeTokens; /** Bottom-row caption — e.g. "Loading PDF…", "Rendering page 3…", * or a host-branded "Crunching your file" string. */ label?: string; /** * Optional brand logo or icon rendered above the page-shaped * placeholder. Pass an ``, ``, or any React node. * Sized to ~32px tall by default — wrap in a styled span for * larger logos. */ logo?: ReactNode; /** Spinner accent colour. Defaults to `tokens.fg`. */ accentColor?: string; } /** * Branded loading state — a page-shaped skeleton with a shimmer * sweep + brand label. Much friendlier than the plain "Loading PDF…" * text the bare react-pdf prop slot used to render. Uses a US Letter * aspect ratio (8.5:11) since most demo PDFs are letter or close. * * Exported so hosts can mount it directly or wrap it. For a full * custom loading state, pass `loadingPlaceholder` on `` * instead. */ export declare function LensLoadingSkeleton({ tokens, label, logo, accentColor, }: LensLoadingSkeletonProps): import("react").JSX.Element; export declare function PdfSubstrate({ file, pageNumber, zoom, onZoomChange, onDocumentLoad, onPageRender, overlay, tokens, panEnabled, pinchEnabled, className, loadingPlaceholder, loadTimeoutMs, focusRect, focusKey, minScale, maxScale, stageAlign, workerSrc, }: PdfSubstrateProps): import("react").JSX.Element; //# sourceMappingURL=PdfSubstrate.d.ts.map