@kingtech/react-pdf-viewer 0.0.0-stage → 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (45) hide show
  1. package/CHANGELOG.md +29 -0
  2. package/LICENSE +21 -0
  3. package/NOTICE +14 -0
  4. package/README.md +67 -2
  5. package/dist/PdfViewer.d.ts +23 -0
  6. package/dist/components/ContinuousPages.d.ts +23 -0
  7. package/dist/components/ErrorView.d.ts +10 -0
  8. package/dist/components/LoadingView.d.ts +6 -0
  9. package/dist/components/PageInput.d.ts +11 -0
  10. package/dist/components/PasswordPrompt.d.ts +10 -0
  11. package/dist/components/PdfPageCanvas.d.ts +53 -0
  12. package/dist/components/SearchBar.d.ts +18 -0
  13. package/dist/components/Thumbnails.d.ts +16 -0
  14. package/dist/components/Toolbar.d.ts +30 -0
  15. package/dist/components/ToolbarButton.d.ts +15 -0
  16. package/dist/components/ToolbarMenu.d.ts +25 -0
  17. package/dist/components/icons.d.ts +60 -0
  18. package/dist/core/download.d.ts +4 -0
  19. package/dist/core/env.d.ts +2 -0
  20. package/dist/core/errors.d.ts +19 -0
  21. package/dist/core/fileName.d.ts +10 -0
  22. package/dist/core/geometry.d.ts +25 -0
  23. package/dist/core/linkService.d.ts +29 -0
  24. package/dist/core/loadSource.d.ts +22 -0
  25. package/dist/core/pdfjs.d.ts +80 -0
  26. package/dist/core/print.d.ts +16 -0
  27. package/dist/core/scale.d.ts +26 -0
  28. package/dist/core/search.d.ts +36 -0
  29. package/dist/hooks/useControllableState.d.ts +19 -0
  30. package/dist/hooks/useDevicePixelRatio.d.ts +2 -0
  31. package/dist/hooks/useDocumentSearch.d.ts +13 -0
  32. package/dist/hooks/useElementSize.d.ts +13 -0
  33. package/dist/hooks/useFullscreen.d.ts +18 -0
  34. package/dist/hooks/useIsomorphicLayoutEffect.d.ts +3 -0
  35. package/dist/hooks/useKeyboardShortcuts.d.ts +18 -0
  36. package/dist/hooks/useMediaQuery.d.ts +2 -0
  37. package/dist/hooks/usePageRenderer.d.ts +74 -0
  38. package/dist/hooks/usePdfDocument.d.ts +31 -0
  39. package/dist/index.d.ts +10 -0
  40. package/dist/index.js +2290 -0
  41. package/dist/index.js.map +1 -0
  42. package/dist/labels.d.ts +64 -0
  43. package/dist/styles.css +2 -0
  44. package/dist/types.d.ts +324 -0
  45. package/package.json +95 -4
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","names":[],"sources":["../src/core/geometry.ts","../src/components/ContinuousPages.tsx","../src/components/icons.tsx","../src/components/ErrorView.tsx","../src/components/LoadingView.tsx","../src/components/PageInput.tsx","../src/components/PasswordPrompt.tsx","../src/core/errors.ts","../src/core/linkService.ts","../src/core/env.ts","../src/core/pdfjs.ts","../src/core/search.ts","../src/hooks/useDevicePixelRatio.ts","../src/hooks/useIsomorphicLayoutEffect.ts","../src/hooks/usePageRenderer.ts","../src/components/PdfPageCanvas.tsx","../src/components/SearchBar.tsx","../src/components/Thumbnails.tsx","../src/core/scale.ts","../src/labels.ts","../src/components/ToolbarButton.tsx","../src/components/ToolbarMenu.tsx","../src/components/Toolbar.tsx","../src/core/download.ts","../src/core/fileName.ts","../src/core/print.ts","../src/hooks/useControllableState.ts","../src/hooks/useDocumentSearch.ts","../src/hooks/useElementSize.ts","../src/hooks/useFullscreen.ts","../src/hooks/useKeyboardShortcuts.ts","../src/hooks/useMediaQuery.ts","../src/core/loadSource.ts","../src/hooks/usePdfDocument.ts","../src/PdfViewer.tsx"],"sourcesContent":["import type { Rotation } from '../types.js';\n\n/** Default canvas pixel budget: 4096², the iOS Safari limit. */\nexport const DEFAULT_MAX_CANVAS_PIXELS = 16_777_216;\n\n// Largest canvas side accepted by every supported browser.\nconst MAX_CANVAS_DIMENSION = 32_767;\n\n/** Clamps a 1-based page number to `[1, numPages]`. */\nexport function clampPage(page: number, numPages: number): number {\n const rounded = Number.isFinite(page) ? Math.round(page) : 1;\n return Math.min(Math.max(rounded, 1), Math.max(numPages, 1));\n}\n\n/** Snaps any angle to the nearest quarter turn in `[0, 360)`. */\nexport function normalizeRotation(degrees: number): Rotation {\n const quarter = Math.round(degrees / 90);\n return ((((quarter % 4) + 4) % 4) * 90) as Rotation;\n}\n\n/** Page rotation actually rendered: the page's intrinsic `/Rotate` plus the user rotation. */\nexport function effectiveRotation(intrinsic: number, user: number): Rotation {\n return normalizeRotation(intrinsic + user);\n}\n\n/**\n * Canvas backing-store multiplier: the device pixel ratio, reduced when the canvas would exceed\n * `maxCanvasPixels` or the largest side browsers accept. Resolution degrades; CSS size does not.\n */\nexport function getOutputScale(\n cssWidth: number,\n cssHeight: number,\n devicePixelRatio: number,\n maxCanvasPixels: number,\n): number {\n let scale = Number.isFinite(devicePixelRatio) && devicePixelRatio > 0 ? devicePixelRatio : 1;\n const area = cssWidth * cssHeight;\n if (area <= 0) {\n return scale;\n }\n if (maxCanvasPixels > 0) {\n scale = Math.min(scale, Math.sqrt(maxCanvasPixels / area));\n }\n return Math.min(scale, MAX_CANVAS_DIMENSION / Math.max(cssWidth, cssHeight));\n}\n\n/** Constrains the rendered page to a box. */\nexport interface FitOptions {\n /** Available width in CSS pixels, including the page's border and padding. */\n width?: number | undefined;\n /** Available height in CSS pixels, including the page's border and padding. */\n height?: number | undefined;\n /** When `true` the page is scaled to fill the box; otherwise it only ever shrinks. */\n upscale?: boolean | undefined;\n}\n\n/** Scale that satisfies `fit` for a page whose size at scale 1 is `baseWidth × baseHeight`. */\nexport function fitScale(\n requested: number,\n baseWidth: number,\n baseHeight: number,\n fit: FitOptions | undefined,\n): number {\n if (!fit) {\n return requested;\n }\n const ratios: number[] = [];\n if (fit.width !== undefined && fit.width > 0 && baseWidth > 0) {\n ratios.push(fit.width / baseWidth);\n }\n if (fit.height !== undefined && fit.height > 0 && baseHeight > 0) {\n ratios.push(fit.height / baseHeight);\n }\n if (ratios.length === 0) {\n return requested;\n }\n const fitted = Math.min(...ratios);\n return fit.upscale ? fitted : Math.min(requested, fitted);\n}\n","import { memo, useEffect, useLayoutEffect, useRef, useState, type ReactNode } from 'react';\nimport type { PDFDocumentProxy } from 'pdfjs-dist';\nimport { effectiveRotation, fitScale, type FitOptions } from '../core/geometry.js';\nimport type { Rotation } from '../types.js';\n\ninterface Size {\n width: number;\n height: number;\n}\n\n/** Page border width on both sides together (see `.rpv-page`). */\nconst PAGE_CHROME = 2;\nconst DEFAULT_SIZE: Size = { width: 612, height: 792 };\n\n/** Scrolls `scroller` so `slot` sits at the top of its content box. */\nfunction scrollToSlot(scroller: HTMLElement, slot: HTMLElement) {\n const padding = Number.parseFloat(getComputedStyle(scroller).paddingTop) || 0;\n scroller.scrollTop = slot.offsetTop - padding;\n}\n\ninterface ContinuousPagesProps {\n document: PDFDocumentProxy;\n numPages: number;\n /** Current page; the list scrolls to it unless the change came from scrolling. */\n page: number;\n /** Reports the most visible page while the user scrolls. */\n onVisiblePageChange: (page: number) => void;\n scale: number;\n rotation: Rotation;\n fit: FitOptions | undefined;\n /** The scroll container. */\n scroller: HTMLElement | null;\n /** Renders one page at an explicit scale. */\n renderPage: (page: number, scale: number) => ReactNode;\n}\n\n/** Loads every page's size at scale 1 progressively (fetching a page does not render it). */\nfunction usePageSizes(pdf: PDFDocumentProxy, numPages: number, rotation: Rotation) {\n const [state, setState] = useState<{ key: object; sizes: (Size | undefined)[] }>({\n key: pdf,\n sizes: [],\n });\n useEffect(() => {\n let cancelled = false;\n const sizes: (Size | undefined)[] = [];\n void (async () => {\n for (let index = 0; index < numPages && !cancelled; index++) {\n try {\n const page = await pdf.getPage(index + 1);\n const viewport = page.getViewport({\n scale: 1,\n rotation: effectiveRotation(page.rotate, rotation),\n });\n sizes[index] = { width: viewport.width, height: viewport.height };\n } catch {\n sizes[index] = undefined;\n }\n if (!cancelled && (index === 0 || index % 16 === 15 || index === numPages - 1)) {\n setState({ key: pdf, sizes: [...sizes] });\n }\n }\n })();\n return () => {\n cancelled = true;\n };\n }, [pdf, numPages, rotation]);\n return state.key === pdf ? state.sizes : [];\n}\n\nfunction ContinuousPagesImpl({\n document,\n numPages,\n page,\n onVisiblePageChange,\n scale,\n rotation,\n fit,\n scroller,\n renderPage,\n}: ContinuousPagesProps) {\n const sizes = usePageSizes(document, numPages, rotation);\n const fallback = sizes.find(Boolean) ?? DEFAULT_SIZE;\n const slots = useRef(new Map<number, HTMLDivElement>());\n const [visible, setVisible] = useState<readonly number[]>([page]);\n const reported = useRef(page);\n const scrolledOnce = useRef(false);\n const reportRef = useRef(onVisiblePageChange);\n useLayoutEffect(() => {\n reportRef.current = onVisiblePageChange;\n });\n\n // Track which pages intersect the scroll container; only those (±1) get a canvas.\n useEffect(() => {\n if (!scroller || typeof IntersectionObserver === 'undefined') return;\n const ratios = new Map<number, number>();\n const observer = new IntersectionObserver(\n (entries) => {\n for (const entry of entries) {\n const pageNumber = Number((entry.target as HTMLElement).dataset['page']);\n if (entry.isIntersecting) ratios.set(pageNumber, entry.intersectionRatio);\n else ratios.delete(pageNumber);\n }\n const inView = [...ratios.keys()].sort((a, b) => a - b);\n if (inView.length === 0) return;\n setVisible((current) =>\n current.length === inView.length && current.every((value, i) => value === inView[i])\n ? current\n : inView,\n );\n let best = inView[0] ?? 1;\n for (const candidate of inView) {\n if ((ratios.get(candidate) ?? 0) > (ratios.get(best) ?? 0)) best = candidate;\n }\n if (best !== reported.current) {\n reported.current = best;\n reportRef.current(best);\n }\n },\n { root: scroller, threshold: [0, 0.1, 0.25, 0.5, 0.75, 1] },\n );\n for (const slot of slots.current.values()) observer.observe(slot);\n return () => observer.disconnect();\n }, [scroller, numPages]);\n\n // Scroll to the page when navigation did not come from scrolling (buttons, keys, links, API).\n useLayoutEffect(() => {\n const slot = slots.current.get(page);\n if (!scroller || !slot) return;\n if (scrolledOnce.current && page === reported.current) return;\n scrolledOnce.current = true;\n reported.current = page;\n scrollToSlot(scroller, slot);\n }, [page, scroller]);\n\n const mounted = new Set<number>();\n if (typeof IntersectionObserver === 'undefined') {\n for (let n = Math.max(1, page - 1); n <= Math.min(numPages, page + 1); n++) mounted.add(n);\n } else {\n const first = Math.min(...visible);\n const last = Math.max(...visible);\n for (let n = Math.max(1, first - 1); n <= Math.min(numPages, last + 1); n++) mounted.add(n);\n }\n\n const fitBox =\n fit === undefined\n ? undefined\n : {\n width: fit.width === undefined ? undefined : fit.width - PAGE_CHROME,\n height: fit.height === undefined ? undefined : fit.height - PAGE_CHROME,\n upscale: fit.upscale,\n };\n\n return (\n <div className=\"rpv-pages\">\n {Array.from({ length: numPages }, (_, index) => {\n const pageNumber = index + 1;\n const size = sizes[index] ?? fallback;\n const pageScale = fitScale(scale, size.width, size.height, fitBox);\n return (\n <div\n key={pageNumber}\n ref={(node) => {\n if (node) slots.current.set(pageNumber, node);\n else slots.current.delete(pageNumber);\n }}\n className=\"rpv-page-slot\"\n data-page={pageNumber}\n style={{\n width: `${size.width * pageScale + PAGE_CHROME}px`,\n height: `${size.height * pageScale + PAGE_CHROME}px`,\n }}\n >\n {mounted.has(pageNumber) ? renderPage(pageNumber, pageScale) : null}\n </div>\n );\n })}\n </div>\n );\n}\n\n/** Vertically scrolling pages; only the visible pages ±1 are rendered. */\nexport const ContinuousPages = memo(ContinuousPagesImpl);\n","// Material Icons paths (Apache License 2.0, Google). See NOTICE.\n\nfunction createIcon(path: string, displayName: string) {\n function Icon() {\n return (\n <svg className=\"rpv-icon\" viewBox=\"0 0 24 24\" aria-hidden=\"true\" focusable=\"false\">\n <path d={path} />\n </svg>\n );\n }\n Icon.displayName = displayName;\n return Icon;\n}\n\nconst MAGNIFIER =\n 'M15.5 14h-.79l-.28-.27C15.41 12.59 16 11.11 16 9.5 16 5.91 13.09 3 9.5 3S3 5.91 3 9.5 5.91 16 9.5 16c1.61 0 3.09-.59 4.23-1.57l.27.28v.79l5 4.99L20.49 19l-4.99-5zm-6 0C7.01 14 5 11.99 5 9.5S7.01 5 9.5 5 14 7.01 14 9.5 11.99 14 9.5 14z';\n\nexport const ZoomOutIcon = createIcon(`${MAGNIFIER}M7 9h5v1H7z`, 'ZoomOutIcon');\nexport const ZoomInIcon = createIcon(`${MAGNIFIER}m2.5-4h-2v2H9v-2H7V9h2V7h1v2h2v1z`, 'ZoomInIcon');\nexport const NavigateBeforeIcon = createIcon(\n 'M15.41 7.41 14 6l-6 6 6 6 1.41-1.41L10.83 12z',\n 'NavigateBeforeIcon',\n);\nexport const NavigateNextIcon = createIcon(\n 'M10 6 8.59 7.41 13.17 12l-4.58 4.59L10 18l6-6z',\n 'NavigateNextIcon',\n);\nexport const FullscreenIcon = createIcon(\n 'M7 14H5v5h5v-2H7v-3zm-2-4h2V7h3V5H5v5zm12 7h-3v2h5v-5h-2v3zM14 5v2h3v3h2V5h-5z',\n 'FullscreenIcon',\n);\nexport const FullscreenExitIcon = createIcon(\n 'M5 16h3v3h2v-5H5v2zm3-8H5v2h5V5H8v3zm6 11h2v-3h3v-2h-5v5zm2-11V5h-2v5h5V8h-3z',\n 'FullscreenExitIcon',\n);\nexport const RotateRightIcon = createIcon(\n 'M15.55 5.55 11 1v3.07C7.06 4.56 4 7.92 4 12s3.05 7.44 7 7.93v-2.02c-2.84-.48-5-2.94-5-5.91s2.16-5.43 5-5.91V10l4.55-4.45zM19.93 11c-.17-1.39-.72-2.73-1.62-3.89l-1.42 1.42c.54.75.88 1.6 1.02 2.47h2.02zM13 17.9v2.02c1.39-.17 2.74-.71 3.9-1.61l-1.44-1.44c-.75.54-1.59.89-2.46 1.03zm3.89-2.42 1.42 1.41c.9-1.16 1.45-2.5 1.62-3.89h-2.02c-.14.87-.48 1.72-1.02 2.48z',\n 'RotateRightIcon',\n);\nexport const DownloadIcon = createIcon('M5 20h14v-2H5v2zM19 9h-4V3H9v6H5l7 7 7-7z', 'DownloadIcon');\nexport const PrintIcon = createIcon(\n 'M19 8H5c-1.66 0-3 1.34-3 3v6h4v4h12v-4h4v-6c0-1.66-1.34-3-3-3zm-3 11H8v-5h8v5zm3-7c-.55 0-1-.45-1-1s.45-1 1-1 1 .45 1 1-.45 1-1 1zm-1-9H6v4h12V3z',\n 'PrintIcon',\n);\nexport const ErrorOutlineIcon = createIcon(\n 'M11 15h2v2h-2zm0-8h2v6h-2zm.99-5C6.47 2 2 6.48 2 12s4.47 10 9.99 10C17.52 22 22 17.52 22 12S17.52 2 11.99 2zM12 20c-4.42 0-8-3.58-8-8s3.58-8 8-8 8 3.58 8 8-3.58 8-8 8z',\n 'ErrorOutlineIcon',\n);\nexport const SearchIcon = createIcon(MAGNIFIER, 'SearchIcon');\nexport const ExpandLessIcon = createIcon(\n 'm12 8-6 6 1.41 1.41L12 10.83l4.59 4.58L18 14z',\n 'ExpandLessIcon',\n);\nexport const ExpandMoreIcon = createIcon(\n 'M16.59 8.59 12 13.17 7.41 8.59 6 10l6 6 6-6z',\n 'ExpandMoreIcon',\n);\nexport const MoreVertIcon = createIcon(\n 'M12 8c1.1 0 2-.9 2-2s-.9-2-2-2-2 .9-2 2 .9 2 2 2zm0 2c-1.1 0-2 .9-2 2s.9 2 2 2 2-.9 2-2-.9-2-2-2zm0 6c-1.1 0-2 .9-2 2s.9 2 2 2 2-.9 2-2-.9-2-2-2z',\n 'MoreVertIcon',\n);\nexport const RestartIcon = createIcon(\n 'M12 5V2L8 6l4 4V7c3.31 0 6 2.69 6 6 0 2.97-2.17 5.43-5 5.91v2.02c3.95-.49 7-3.85 7-7.93 0-4.42-3.58-8-8-8zm-6 8c0-1.65.67-3.15 1.76-4.24L6.34 7.34C4.9 8.79 4 10.79 4 13c0 4.08 3.05 7.44 7 7.93v-2.02c-2.83-.48-5-2.94-5-5.91z',\n 'RestartIcon',\n);\n","import { ErrorOutlineIcon } from './icons.js';\n\ninterface ErrorViewProps {\n message: string;\n retryLabel: string;\n onRetry?: (() => void) | undefined;\n /** `document` fills a 400px area; `page` sits inside the page box. */\n variant?: 'document' | 'page' | undefined;\n}\n\n/** Red error alert with an optional Retry button. */\nexport function ErrorView({ message, retryLabel, onRetry, variant = 'document' }: ErrorViewProps) {\n return (\n <div className={variant === 'page' ? 'rpv-error rpv-error--page' : 'rpv-error'}>\n <div className=\"rpv-alert\" role=\"alert\">\n <span className=\"rpv-alert__icon\">\n <ErrorOutlineIcon />\n </span>\n <div className=\"rpv-alert__message\">{message}</div>\n </div>\n {onRetry && (\n <button type=\"button\" className=\"rpv-text-button\" onClick={onRetry}>\n {retryLabel}\n </button>\n )}\n </div>\n );\n}\n","/** Indeterminate circular spinner. */\nexport function Spinner() {\n return (\n <span className=\"rpv-spinner\" aria-hidden=\"true\">\n <svg viewBox=\"22 22 44 44\" focusable=\"false\">\n <circle cx=\"44\" cy=\"44\" r=\"20.2\" fill=\"none\" strokeWidth=\"3.6\" />\n </svg>\n </span>\n );\n}\n\n/** Centered spinner with a status text, shown while the document loads. */\nexport function LoadingView({ label }: { label: string }) {\n return (\n <div className=\"rpv-loading\" role=\"status\">\n <Spinner />\n <p className=\"rpv-loading__text\">{label}</p>\n </div>\n );\n}\n","import { useState, type CSSProperties } from 'react';\nimport type { LabelContext } from '../labels.js';\n\ninterface PageInputProps {\n page: number;\n numPages: number;\n label: string;\n context: LabelContext;\n onCommit: (page: number) => void;\n}\n\n/** Editable page number (`Enter` or blur commits, `Esc` reverts) followed by the page count. */\nexport function PageInput({ page, numPages, label, context, onCommit }: PageInputProps) {\n const [draft, setDraft] = useState<string | null>(null);\n\n const commit = () => {\n if (draft === null) return;\n const value = Number.parseInt(draft, 10);\n setDraft(null);\n if (Number.isFinite(value)) onCommit(value);\n };\n\n return (\n <>\n <input\n className=\"rpv-page-input\"\n type=\"text\"\n inputMode=\"numeric\"\n autoComplete=\"off\"\n aria-label={label}\n size={Math.max(2, String(numPages).length)}\n style={{ '--rpv-page-input-chars': Math.max(2, String(numPages).length) } as CSSProperties}\n disabled={numPages === 0}\n value={draft ?? (numPages > 0 ? context.formatNumber(page) : '0')}\n onChange={(event) => setDraft(event.target.value)}\n onFocus={(event) => event.target.select()}\n onBlur={commit}\n onKeyDown={(event) => {\n if (event.key === 'Enter') {\n event.preventDefault();\n commit();\n } else if (event.key === 'Escape') {\n setDraft(null);\n }\n }}\n />\n <span aria-hidden=\"true\">/ {context.formatNumber(numPages)}</span>\n </>\n );\n}\n","import { useEffect, useId, useRef, useState, type FormEvent } from 'react';\nimport type { PdfViewerLabels } from '../labels.js';\n\ninterface PasswordPromptProps {\n labels: PdfViewerLabels;\n /** The previous attempt was wrong. */\n incorrect: boolean;\n onSubmit: (password: string) => void;\n}\n\n/** Built-in password form for encrypted documents. */\nexport function PasswordPrompt({ labels, incorrect, onSubmit }: PasswordPromptProps) {\n const inputId = useId();\n const titleId = useId();\n const errorId = useId();\n const inputRef = useRef<HTMLInputElement>(null);\n const [value, setValue] = useState('');\n\n useEffect(() => {\n inputRef.current?.focus();\n }, [incorrect]);\n\n const submit = (event: FormEvent) => {\n event.preventDefault();\n onSubmit(value);\n setValue('');\n };\n\n return (\n <form className=\"rpv-password\" aria-labelledby={titleId} onSubmit={submit}>\n <p id={titleId} className=\"rpv-password__title\">\n {labels.passwordPrompt}\n </p>\n {incorrect && (\n <p id={errorId} className=\"rpv-password__error\" role=\"alert\">\n {labels.passwordIncorrect}\n </p>\n )}\n <label htmlFor={inputId}>{labels.passwordLabel}</label>\n <input\n ref={inputRef}\n id={inputId}\n type=\"password\"\n autoComplete=\"current-password\"\n value={value}\n aria-invalid={incorrect || undefined}\n aria-describedby={incorrect ? errorId : undefined}\n onChange={(event) => setValue(event.target.value)}\n />\n <button type=\"submit\" className=\"rpv-text-button\">\n {labels.passwordSubmit}\n </button>\n </form>\n );\n}\n","import type { PdfViewerError, PdfViewerErrorCode } from '../types.js';\n\nconst DEFAULT_MESSAGES: Record<PdfViewerErrorCode, string> = {\n PDFJS_LOAD_FAILED: 'Failed to load the PDF.js library',\n NETWORK_ERROR: 'Could not load the PDF. Check your connection and try again.',\n HTTP_ERROR: 'Failed to fetch PDF document',\n INVALID_PDF: 'Invalid or corrupted PDF file',\n PASSWORD_REQUIRED: 'This document is password protected',\n INCORRECT_PASSWORD: 'Incorrect password',\n RENDER_FAILED: 'Failed to render PDF page',\n DOWNLOAD_FAILED: 'Failed to download PDF',\n PRINT_FAILED: 'Failed to print PDF',\n UNKNOWN: 'Failed to load PDF document',\n};\n\n// pdfjs-dist `PasswordResponses.INCORRECT_PASSWORD`.\nconst PDFJS_INCORRECT_PASSWORD = 2;\n\ninterface ErrorDetails {\n status?: number | undefined;\n cause?: unknown;\n}\n\nclass ViewerError extends Error implements PdfViewerError {\n declare readonly code: PdfViewerErrorCode;\n declare readonly status?: number;\n\n constructor(code: PdfViewerErrorCode, message: string, details: ErrorDetails) {\n super(message, details.cause === undefined ? undefined : { cause: details.cause });\n this.name = 'PdfViewerError';\n this.code = code;\n if (details.status !== undefined) {\n this.status = details.status;\n }\n }\n}\n\n/** Creates a {@link PdfViewerError}. `message` defaults to a generic text for the code. */\nexport function createPdfViewerError(\n code: PdfViewerErrorCode,\n message?: string,\n details: ErrorDetails = {},\n): PdfViewerError {\n return new ViewerError(code, message || DEFAULT_MESSAGES[code], details);\n}\n\n/** Type guard for errors created by the viewer. */\nexport function isPdfViewerError(value: unknown): value is PdfViewerError {\n return value instanceof ViewerError;\n}\n\nfunction readProperty(value: unknown, key: string): unknown {\n return typeof value === 'object' && value !== null\n ? (value as Record<string, unknown>)[key]\n : undefined;\n}\n\n/** True for fetch aborts and PDF.js loading-task aborts. */\nexport function isAbortError(error: unknown): boolean {\n const name = readProperty(error, 'name');\n return name === 'AbortError' || name === 'AbortException';\n}\n\n/** True for PDF.js render cancellations, which are a normal outcome. */\nexport function isRenderCancelled(error: unknown): boolean {\n return readProperty(error, 'name') === 'RenderingCancelledException';\n}\n\n/**\n * Maps anything thrown by the loading or rendering pipeline to a {@link PdfViewerError}.\n * PDF.js exceptions are recognized by `name`, so this works with any `pdfjs-dist` build.\n */\nexport function toPdfViewerError(error: unknown, fallback: PdfViewerErrorCode): PdfViewerError {\n if (isPdfViewerError(error)) {\n return error;\n }\n\n let code = fallback;\n let status: number | undefined;\n switch (readProperty(error, 'name')) {\n case 'PasswordException':\n code =\n readProperty(error, 'code') === PDFJS_INCORRECT_PASSWORD\n ? 'INCORRECT_PASSWORD'\n : 'PASSWORD_REQUIRED';\n break;\n case 'InvalidPDFException':\n code = 'INVALID_PDF';\n break;\n case 'ResponseException': {\n code = 'HTTP_ERROR';\n const rawStatus = readProperty(error, 'status');\n status = typeof rawStatus === 'number' ? rawStatus : undefined;\n break;\n }\n }\n\n const rawMessage = readProperty(error, 'message');\n const message =\n typeof rawMessage === 'string' && rawMessage\n ? rawMessage\n : typeof error === 'string'\n ? error\n : undefined;\n\n return createPdfViewerError(code, message, { status, cause: error });\n}\n","import type { PDFDocumentProxy } from 'pdfjs-dist';\n\ntype RefProxy = Parameters<PDFDocumentProxy['getPageIndex']>[0];\n\n/** Navigation callbacks the link service needs from the viewer. */\nexport interface LinkNavigation {\n /** Go to a 1-based page. */\n goToPage: (page: number) => void;\n /** Current 1-based page (for named actions such as NextPage). */\n getPage: () => number;\n}\n\n/**\n * The subset of PDF.js's `PDFLinkService` that `AnnotationLayer` uses for links. External links\n * open in a new tab with `rel=\"noopener noreferrer\"`; internal links navigate the viewer.\n * (PDF.js only passes URLs with safe protocols through to `addLinkAttributes`.)\n */\nexport function createLinkService(pdf: PDFDocumentProxy, navigation: LinkNavigation) {\n const resolvePage = async (destination: unknown): Promise<number | null> => {\n const explicit =\n typeof destination === 'string' ? await pdf.getDestination(destination) : destination;\n if (!Array.isArray(explicit) || explicit.length === 0) return null;\n const [target] = explicit as unknown[];\n if (typeof target === 'object' && target !== null) {\n try {\n return (await pdf.getPageIndex(target as RefProxy)) + 1;\n } catch {\n return null;\n }\n }\n return typeof target === 'number' && Number.isInteger(target) ? target + 1 : null;\n };\n\n return {\n externalLinkEnabled: true,\n isInPresentationMode: false,\n eventBus: { on: () => undefined, off: () => undefined, dispatch: () => undefined },\n addLinkAttributes(link: HTMLAnchorElement, url: string) {\n link.href = url;\n link.target = '_blank';\n link.rel = 'noopener noreferrer nofollow';\n link.title = url;\n },\n getDestinationHash: () => '#',\n getAnchorUrl: () => '#',\n goToDestination(destination: unknown) {\n // A destination that cannot be resolved (malformed, or the document is gone) does nothing.\n resolvePage(destination).then(\n (page) => {\n if (page !== null) navigation.goToPage(page);\n },\n () => undefined,\n );\n },\n goToPage(page: number) {\n navigation.goToPage(page);\n },\n executeNamedAction(action: string) {\n const current = navigation.getPage();\n const target: Record<string, number> = {\n FirstPage: 1,\n LastPage: pdf.numPages,\n NextPage: current + 1,\n PrevPage: current - 1,\n };\n const page = target[action];\n if (page !== undefined) navigation.goToPage(page);\n },\n executeSetOCGState: () => undefined,\n };\n}\n","// Bundlers statically replace `process.env.NODE_ENV`; where nothing defines `process`, the access\n// throws and we treat the environment as production.\ndeclare const process: { readonly env: { readonly NODE_ENV?: string } };\n\n/** True unless the consumer's bundler marks the build as production. */\nexport function isDevelopment(): boolean {\n try {\n return process.env.NODE_ENV !== 'production';\n } catch {\n return false;\n }\n}\n","import type * as PdfJsNamespace from 'pdfjs-dist';\nimport type { PdfJsDocumentOptions } from '../types.js';\nimport { isDevelopment } from './env.js';\nimport { createPdfViewerError } from './errors.js';\n\n/** The `pdfjs-dist` module namespace. */\nexport type PdfJsModule = typeof PdfJsNamespace;\n\n/**\n * Global PDF.js configuration. Every field is optional; unset asset URLs default to the jsDelivr\n * CDN copy of the **exact installed** `pdfjs-dist` version. Self-hosting is recommended for\n * production (see the README).\n */\nexport interface PdfJsConfig {\n /**\n * Returns the `pdfjs-dist` module. Use it to select the legacy build\n * (`() => import('pdfjs-dist/legacy/build/pdf.mjs')`) or a pre-loaded instance.\n *\n * @defaultValue `() => import('pdfjs-dist')`\n */\n loader?: () => Promise<PdfJsModule>;\n /**\n * Worker script URL (e.g. from `import workerSrc from 'pdfjs-dist/build/pdf.worker.min.mjs?url'`).\n * A worker already set on `GlobalWorkerOptions` is respected.\n *\n * @defaultValue the jsDelivr worker for the installed version\n */\n workerSrc?: string;\n /** A ready `Worker` running the PDF.js worker script. Takes precedence over `workerSrc`. */\n workerPort?: Worker;\n /**\n * Base URL of the CMap files, with a trailing slash.\n *\n * @defaultValue jsDelivr `cmaps/` for the installed version\n */\n cMapUrl?: string;\n /** Whether the CMaps are binary-packed. Default `true`. */\n cMapPacked?: boolean;\n /**\n * Base URL of the standard font data, with a trailing slash.\n *\n * @defaultValue jsDelivr `standard_fonts/` for the installed version\n */\n standardFontDataUrl?: string;\n /**\n * Base URL of the WebAssembly decoders, with a trailing slash.\n *\n * @defaultValue jsDelivr `wasm/` for the installed version\n */\n wasmUrl?: string;\n /**\n * Base URL of the ICC color profiles, with a trailing slash.\n *\n * @defaultValue jsDelivr `iccs/` for the installed version\n */\n iccUrl?: string;\n /**\n * Forwarded to `getDocument` for builds that still support it. Default `false` (defense in depth\n * against CVE-2024-4367; `pdfjs-dist` 5+ removed eval-based font compilation entirely).\n */\n isEvalSupported?: boolean;\n}\n\nlet config: PdfJsConfig = {};\nlet modulePromise: Promise<PdfJsModule> | null = null;\nlet cdnNoticeShown = false;\n\nconst defaultLoader = (): Promise<PdfJsModule> => import('pdfjs-dist');\n\nconst cdnBase = (version: string): string => `https://cdn.jsdelivr.net/npm/pdfjs-dist@${version}/`;\n\nfunction showCdnNotice(): void {\n if (cdnNoticeShown || !isDevelopment()) {\n return;\n }\n cdnNoticeShown = true;\n console.info(\n '[react-pdf-viewer] Loading PDF.js worker/assets from cdn.jsdelivr.net. ' +\n 'Self-host them with configurePdfJs() for production (see the package README).',\n );\n}\n\nfunction applyWorkerOptions(lib: PdfJsModule): void {\n const options = lib.GlobalWorkerOptions;\n if (config.workerPort) {\n options.workerPort = config.workerPort;\n } else if (config.workerSrc) {\n options.workerSrc = config.workerSrc;\n } else if (!options.workerSrc && !options.workerPort) {\n // Respect a worker the application configured itself; otherwise match the installed version.\n options.workerSrc = `${cdnBase(lib.version)}build/pdf.worker.min.mjs`;\n showCdnNotice();\n }\n}\n\n/**\n * Configures PDF.js for every viewer instance. Call it once at startup, before the first viewer\n * mounts. Calls merge with previous configuration.\n *\n * @example\n * ```ts\n * import workerSrc from 'pdfjs-dist/build/pdf.worker.min.mjs?url';\n * configurePdfJs({ workerSrc, cMapUrl: '/pdfjs/cmaps/', standardFontDataUrl: '/pdfjs/standard_fonts/' });\n * ```\n */\nexport function configurePdfJs(next: PdfJsConfig): void {\n const loaderChanged = next.loader !== undefined && next.loader !== config.loader;\n config = { ...config, ...next };\n if (loaderChanged) {\n modulePromise = null;\n } else if (modulePromise && (next.workerSrc !== undefined || next.workerPort !== undefined)) {\n modulePromise.then(applyWorkerOptions).catch(() => undefined);\n }\n}\n\n/** Resets configuration and the cached module. Test-only; not part of the public API. */\nexport function resetPdfJs(): void {\n config = {};\n modulePromise = null;\n cdnNoticeShown = false;\n}\n\n/**\n * Loads `pdfjs-dist` once and shares the result between all instances. A failed load is not\n * cached, so a later call (e.g. `reload()`) retries. Rejects with a `PDFJS_LOAD_FAILED` error.\n */\nexport function loadPdfJs(): Promise<PdfJsModule> {\n if (modulePromise) {\n return modulePromise;\n }\n const loader = config.loader ?? defaultLoader;\n const promise: Promise<PdfJsModule> = Promise.resolve()\n .then(loader)\n .then(\n (lib) => {\n applyWorkerOptions(lib);\n return lib;\n },\n (cause: unknown) => {\n if (modulePromise === promise) {\n modulePromise = null;\n }\n throw createPdfViewerError('PDFJS_LOAD_FAILED', undefined, { cause });\n },\n );\n modulePromise = promise;\n return promise;\n}\n\n/** `getDocument` options every load receives: asset URLs and security defaults. */\nexport function getDocumentDefaults(\n lib: PdfJsModule,\n): PdfJsDocumentOptions & { isEvalSupported: boolean } {\n const base = cdnBase(lib.version);\n if (!config.cMapUrl || !config.standardFontDataUrl || !config.wasmUrl || !config.iccUrl) {\n showCdnNotice();\n }\n return {\n cMapUrl: config.cMapUrl ?? `${base}cmaps/`,\n cMapPacked: config.cMapPacked ?? true,\n standardFontDataUrl: config.standardFontDataUrl ?? `${base}standard_fonts/`,\n wasmUrl: config.wasmUrl ?? `${base}wasm/`,\n iccUrl: config.iccUrl ?? `${base}iccs/`,\n isEvalSupported: config.isEvalSupported ?? false,\n };\n}\n","/** A text item as returned by `getTextContent()` (marked-content entries have no `str`). */\nexport interface TextItemLike {\n str: string;\n hasEOL?: boolean;\n}\n\n/** Text of one page prepared for searching. Offsets stay aligned with the text layer's items. */\nexport interface PageText {\n /** All items joined; an end-of-line item is followed by a space. */\n text: string;\n /** Lower-cased `text` with identical offsets (falls back to `text` if lower-casing changes length). */\n folded: string;\n /** Start offset of each item within `text`. */\n offsets: number[];\n /** Text of each item, in text-layer order. */\n items: string[];\n}\n\n/** A match within a page's `text`. */\nexport interface TextRange {\n start: number;\n end: number;\n}\n\n/** The part of one text item covered by a match. */\nexport interface ItemSegment {\n item: number;\n start: number;\n end: number;\n}\n\n/** Keeps only real text items (the entries the text layer renders as spans). */\nexport function isTextItem<T>(item: T): item is T & TextItemLike {\n return (\n typeof item === 'object' && item !== null && typeof (item as { str?: unknown }).str === 'string'\n );\n}\n\nfunction fold(value: string): string {\n const lower = value.toLowerCase();\n return lower.length === value.length ? lower : value;\n}\n\nexport function buildPageText(items: readonly TextItemLike[]): PageText {\n const offsets: number[] = [];\n const strings: string[] = [];\n let text = '';\n for (const item of items) {\n offsets.push(text.length);\n strings.push(item.str);\n text += item.str;\n if (item.hasEOL) text += ' ';\n }\n return { text, folded: fold(text), offsets, items: strings };\n}\n\n/** Normalizes a query: trimmed, whitespace collapsed, lower-cased. */\nexport function normalizeQuery(query: string): string {\n return query.trim().replace(/\\s+/g, ' ').toLowerCase();\n}\n\n/** Non-overlapping, case-insensitive matches of `query` in a page. */\nexport function findMatches(page: PageText, query: string): TextRange[] {\n const needle = normalizeQuery(query);\n if (!needle) return [];\n const matches: TextRange[] = [];\n let from = 0;\n for (;;) {\n const index = page.folded.indexOf(needle, from);\n if (index === -1) break;\n matches.push({ start: index, end: index + needle.length });\n from = index + needle.length;\n }\n return matches;\n}\n\n/** Splits a page-level range into the per-item pieces the text layer can highlight. */\nexport function toItemSegments(page: PageText, range: TextRange): ItemSegment[] {\n const segments: ItemSegment[] = [];\n page.items.forEach((item, index) => {\n const itemStart = page.offsets[index] ?? 0;\n const start = Math.max(range.start, itemStart) - itemStart;\n const end = Math.min(range.end, itemStart + item.length) - itemStart;\n if (end > start) segments.push({ item: index, start, end });\n });\n return segments;\n}\n","import { useSyncExternalStore } from 'react';\n\nfunction subscribe(onChange: () => void): () => void {\n if (typeof window === 'undefined' || typeof window.matchMedia !== 'function') {\n return () => undefined;\n }\n let query: MediaQueryList | null = null;\n const listen = () => {\n query?.removeEventListener('change', handleChange);\n query = window.matchMedia(`(resolution: ${window.devicePixelRatio || 1}dppx)`);\n query.addEventListener('change', handleChange);\n };\n const handleChange = () => {\n // The query only matches the old ratio; re-arm for the new one.\n listen();\n onChange();\n };\n listen();\n return () => query?.removeEventListener('change', handleChange);\n}\n\nconst getSnapshot = () => window.devicePixelRatio || 1;\nconst getServerSnapshot = () => 1;\n\n/** Current `devicePixelRatio`, updated when the window moves between screens or zooms. */\nexport function useDevicePixelRatio(): number {\n return useSyncExternalStore(subscribe, getSnapshot, getServerSnapshot);\n}\n","import { useEffect, useLayoutEffect } from 'react';\n\n/** `useLayoutEffect` in the browser, `useEffect` on the server (avoids the SSR warning). */\nexport const useIsomorphicLayoutEffect =\n typeof window === 'undefined' ? useEffect : useLayoutEffect;\n","import { useCallback, useEffect, useRef, useState, type Ref } from 'react';\nimport type {\n PageViewport,\n PDFDocumentProxy,\n PDFPageProxy,\n RenderTask,\n TextLayer,\n} from 'pdfjs-dist';\nimport { isRenderCancelled, toPdfViewerError } from '../core/errors.js';\nimport {\n clampPage,\n DEFAULT_MAX_CANVAS_PIXELS,\n effectiveRotation,\n fitScale,\n getOutputScale,\n type FitOptions,\n} from '../core/geometry.js';\nimport { createLinkService } from '../core/linkService.js';\nimport { loadPdfJs, type PdfJsModule } from '../core/pdfjs.js';\nimport {\n buildPageText,\n findMatches,\n isTextItem,\n toItemSegments,\n type PageText,\n} from '../core/search.js';\nimport type { PdfViewerError, Rotation } from '../types.js';\nimport { useDevicePixelRatio } from './useDevicePixelRatio.js';\nimport { useIsomorphicLayoutEffect } from './useIsomorphicLayoutEffect.js';\n\n/** Details of a completed page render. */\nexport interface PageRenderInfo {\n /** 1-based page number that was rendered (after clamping). */\n page: number;\n /** Scale actually rendered (after fitting). */\n scale: number;\n /** Rendered CSS width in pixels. */\n width: number;\n /** Rendered CSS height in pixels. */\n height: number;\n /** Time from request to completion. */\n durationMs: number;\n}\n\n/** Search highlighting for one page's text layer. */\nexport interface PageHighlight {\n /** Text to highlight (case-insensitive). */\n query: string;\n /** Index of the page's match to mark as selected, if any. */\n selected: number | null;\n}\n\n/** Options for {@link usePageRenderer}. */\nexport interface UsePageRendererOptions {\n document: PDFDocumentProxy | null;\n /** 1-based page number; clamped to the document. */\n page: number;\n /** Requested scale (1 = 100%). */\n scale: number;\n /** User rotation, added to the page's intrinsic rotation. */\n rotation: Rotation;\n /** Optional box the page must fit into. */\n fit?: FitOptions | undefined;\n /** Canvas pixel budget. Default {@link DEFAULT_MAX_CANVAS_PIXELS}. */\n maxCanvasPixels?: number | undefined;\n /** Render a selectable text layer. */\n textLayer?: boolean | undefined;\n /** Render link annotations. */\n annotationLayer?: boolean | undefined;\n /** Highlight search matches in the text layer. */\n highlight?: PageHighlight | undefined;\n /** Called when an internal link targets a page. */\n onLinkNavigate?: ((page: number) => void) | undefined;\n /** Called with the selected highlight element, so it can be scrolled into view. */\n onHighlight?: ((element: HTMLElement) => void) | undefined;\n onRender?: ((info: PageRenderInfo) => void) | undefined;\n onError?: ((error: PdfViewerError) => void) | undefined;\n}\n\n/** Refs to attach and render state returned by {@link usePageRenderer}. */\nexport interface UsePageRendererResult {\n /** The page box; the renderer sets its CSS width and height. */\n pageRef: Ref<HTMLDivElement>;\n /** Element that receives the canvas. Must have no React children. */\n canvasHostRef: Ref<HTMLDivElement>;\n /** Element that receives the text and annotation layers. Must have no React children. */\n layersRef: Ref<HTMLDivElement>;\n /** The last render failure, cleared by the next successful render. */\n error: PdfViewerError | null;\n /** Renders again after a failure. */\n retry: () => void;\n}\n\ntype AnnotationLayerInstance = InstanceType<PdfJsModule['AnnotationLayer']>;\ntype AnnotationRenderParameters = Parameters<AnnotationLayerInstance['render']>[0];\n\ninterface TextLayerState {\n divs: HTMLElement[];\n pageText: PageText;\n highlighted: Set<number>;\n}\n\ninterface BuiltTextLayer {\n container: HTMLDivElement;\n state: TextLayerState;\n}\n\nfunction releaseCanvas(canvas: Element | null | undefined): void {\n if (canvas instanceof HTMLCanvasElement) {\n // Frees the backing store immediately (Safari otherwise holds on to it).\n canvas.width = 0;\n canvas.height = 0;\n }\n}\n\n/** Border + padding of the page box, which the fitted canvas must leave room for. */\nfunction measureChrome(element: HTMLElement): { x: number; y: number } {\n const style = element.ownerDocument.defaultView?.getComputedStyle(element);\n const px = (value: string | undefined) => Number.parseFloat(value ?? '') || 0;\n return {\n x: element.offsetWidth - element.clientWidth + px(style?.paddingLeft) + px(style?.paddingRight),\n y:\n element.offsetHeight -\n element.clientHeight +\n px(style?.paddingTop) +\n px(style?.paddingBottom),\n };\n}\n\nasync function buildTextLayer(\n lib: PdfJsModule,\n page: PDFPageProxy,\n viewport: PageViewport,\n ownerDocument: Document,\n track: (layer: TextLayer) => void,\n): Promise<BuiltTextLayer> {\n const content = await page.getTextContent();\n const container = ownerDocument.createElement('div');\n container.className = 'textLayer';\n const layer = new lib.TextLayer({ textContentSource: content, container, viewport });\n track(layer);\n await layer.render();\n // Lets a selection drag past the last line without jumping (as in PDF.js).\n const end = ownerDocument.createElement('div');\n end.className = 'endOfContent';\n container.append(end);\n container.addEventListener('mousedown', () => {\n container.classList.add('selecting');\n ownerDocument.addEventListener('mouseup', () => container.classList.remove('selecting'), {\n once: true,\n });\n });\n return {\n container,\n state: {\n divs: layer.textDivs,\n pageText: buildPageText(content.items.filter(isTextItem)),\n highlighted: new Set(),\n },\n };\n}\n\nasync function buildAnnotationLayer(\n lib: PdfJsModule,\n pdf: PDFDocumentProxy,\n page: PDFPageProxy,\n viewport: PageViewport,\n linkService: ReturnType<typeof createLinkService>,\n ownerDocument: Document,\n): Promise<HTMLDivElement> {\n const annotations = await page.getAnnotations({ intent: 'display' });\n const div = ownerDocument.createElement('div');\n div.className = 'annotationLayer';\n if (annotations.length === 0) return div;\n const annotationViewport = viewport.clone({ dontFlip: true });\n const service = linkService as unknown as AnnotationRenderParameters['linkService'];\n const layer = new lib.AnnotationLayer({\n div,\n accessibilityManager: null,\n annotationCanvasMap: null,\n annotationEditorUIManager: null,\n page,\n viewport: annotationViewport,\n structTreeLayer: null,\n commentManager: null,\n linkService: service,\n annotationStorage: pdf.annotationStorage,\n });\n await layer.render({\n viewport: annotationViewport,\n div,\n annotations,\n page,\n linkService: service,\n renderForms: false,\n annotationStorage: pdf.annotationStorage,\n });\n return div;\n}\n\n/** Rewrites the text layer's spans to wrap matches; returns the selected match's element. */\nfunction applyHighlights(\n state: TextLayerState,\n highlight: PageHighlight | undefined,\n): HTMLElement | null {\n const { divs, pageText, highlighted } = state;\n for (const index of highlighted) {\n const div = divs[index];\n if (div) div.textContent = pageText.items[index] ?? '';\n }\n highlighted.clear();\n if (!highlight?.query.trim()) return null;\n\n const segmentsByItem = new Map<number, { start: number; end: number; selected: boolean }[]>();\n findMatches(pageText, highlight.query).forEach((range, matchIndex) => {\n for (const segment of toItemSegments(pageText, range)) {\n const list = segmentsByItem.get(segment.item) ?? [];\n list.push({\n start: segment.start,\n end: segment.end,\n selected: matchIndex === highlight.selected,\n });\n segmentsByItem.set(segment.item, list);\n }\n });\n\n let selectedElement: HTMLElement | null = null;\n for (const [index, segments] of segmentsByItem) {\n const div = divs[index];\n const text = pageText.items[index];\n if (!div || text === undefined) continue;\n highlighted.add(index);\n div.textContent = '';\n let position = 0;\n for (const segment of segments.sort((a, b) => a.start - b.start)) {\n if (segment.start > position) div.append(text.slice(position, segment.start));\n const mark = div.ownerDocument.createElement('span');\n mark.className = segment.selected ? 'highlight selected appended' : 'highlight appended';\n mark.textContent = text.slice(segment.start, segment.end);\n div.append(mark);\n if (segment.selected) selectedElement ??= mark;\n position = segment.end;\n }\n if (position < text.length) div.append(text.slice(position));\n }\n return selectedElement;\n}\n\n/**\n * Renders one PDF page onto a canvas, optionally with text and annotation layers.\n *\n * - One render at a time: a newer request cancels the running `RenderTask` (cancellations are\n * silent), so bursts of changes complete exactly one render.\n * - Double-buffered: the canvas and its layers are built off-screen and swapped in together, so\n * there is no blank frame.\n * - HiDPI output, capped at `maxCanvasPixels`; re-renders when the device pixel ratio changes.\n * - The renderer is the single owner of the page's CSS size.\n */\nexport function usePageRenderer({\n document,\n page,\n scale,\n rotation,\n fit,\n maxCanvasPixels = DEFAULT_MAX_CANVAS_PIXELS,\n textLayer = false,\n annotationLayer = false,\n highlight,\n onLinkNavigate,\n onHighlight,\n onRender,\n onError,\n}: UsePageRendererOptions): UsePageRendererResult {\n const pageRef = useRef<HTMLDivElement>(null);\n const canvasHostRef = useRef<HTMLDivElement>(null);\n const layersRef = useRef<HTMLDivElement>(null);\n const displayedPageRef = useRef<PDFPageProxy | null>(null);\n const textStateRef = useRef<TextLayerState | null>(null);\n const [error, setError] = useState<PdfViewerError | null>(null);\n const [attempt, setAttempt] = useState(0);\n const [layerVersion, setLayerVersion] = useState(0);\n const devicePixelRatio = useDevicePixelRatio();\n\n const latest = useRef({ onRender, onError, onLinkNavigate, onHighlight, page });\n useIsomorphicLayoutEffect(() => {\n latest.current = { onRender, onError, onLinkNavigate, onHighlight, page };\n });\n\n const fitWidth = fit?.width;\n const fitHeight = fit?.height;\n const fitUpscale = fit?.upscale ?? false;\n\n useEffect(() => {\n const pageElement = pageRef.current;\n const host = canvasHostRef.current;\n const layersHost = layersRef.current;\n if (!document || !pageElement || !host || !layersHost) {\n return;\n }\n let cancelled = false;\n let task: RenderTask | null = null;\n let pendingTextLayer: TextLayer | null = null;\n const startedAt = performance.now();\n const ownerDocument = pageElement.ownerDocument;\n const linkService = createLinkService(document, {\n goToPage: (target) => latest.current.onLinkNavigate?.(target),\n getPage: () => latest.current.page,\n });\n\n const render = async () => {\n const pdfPage = await document.getPage(clampPage(page, document.numPages));\n if (cancelled) {\n return;\n }\n const pageRotation = effectiveRotation(pdfPage.rotate, rotation);\n const base = pdfPage.getViewport({ scale: 1, rotation: pageRotation });\n const chrome = measureChrome(pageElement);\n const renderScale = fitScale(scale, base.width, base.height, {\n width: fitWidth === undefined ? undefined : fitWidth - chrome.x,\n height: fitHeight === undefined ? undefined : fitHeight - chrome.y,\n upscale: fitUpscale,\n });\n const viewport = pdfPage.getViewport({ scale: renderScale, rotation: pageRotation });\n\n // Layers are optional extras: a failure there must not break the page.\n const layers =\n textLayer || annotationLayer\n ? loadPdfJs()\n .then((lib) =>\n Promise.all([\n textLayer\n ? buildTextLayer(lib, pdfPage, viewport, ownerDocument, (layer) => {\n pendingTextLayer = layer;\n })\n : null,\n annotationLayer\n ? buildAnnotationLayer(\n lib,\n document,\n pdfPage,\n viewport,\n linkService,\n ownerDocument,\n )\n : null,\n ]),\n )\n .catch(() => [null, null] as const)\n : Promise.resolve([null, null] as const);\n\n const outputScale = getOutputScale(\n viewport.width,\n viewport.height,\n devicePixelRatio,\n maxCanvasPixels,\n );\n const canvas = ownerDocument.createElement('canvas');\n canvas.className = 'rpv-page__canvas';\n canvas.width = Math.max(1, Math.floor(viewport.width * outputScale));\n canvas.height = Math.max(1, Math.floor(viewport.height * outputScale));\n Object.assign(canvas.style, { display: 'block', width: '100%', height: '100%' });\n\n task = pdfPage.render({\n canvas,\n viewport,\n ...(outputScale === 1 ? {} : { transform: [outputScale, 0, 0, outputScale, 0, 0] }),\n });\n try {\n await task.promise;\n } catch (renderError) {\n releaseCanvas(canvas);\n throw renderError;\n }\n const [builtText, annotationDiv] = await layers;\n if (cancelled) {\n releaseCanvas(canvas);\n return;\n }\n\n const previousCanvas = host.firstElementChild;\n host.replaceChildren(canvas);\n releaseCanvas(previousCanvas);\n layersHost.replaceChildren(\n ...[builtText?.container, annotationDiv].filter((node): node is HTMLDivElement =>\n Boolean(node),\n ),\n );\n pageElement.style.width = `${viewport.width}px`;\n pageElement.style.height = `${viewport.height}px`;\n pageElement.style.setProperty('--total-scale-factor', String(renderScale * pdfPage.userUnit));\n\n const previousPage = displayedPageRef.current;\n displayedPageRef.current = pdfPage;\n if (previousPage && previousPage !== pdfPage) {\n previousPage.cleanup();\n }\n\n textStateRef.current = builtText?.state ?? null;\n if (builtText) setLayerVersion((value) => value + 1);\n setError((current) => (current === null ? current : null));\n latest.current.onRender?.({\n page: pdfPage.pageNumber,\n scale: renderScale,\n width: viewport.width,\n height: viewport.height,\n durationMs: performance.now() - startedAt,\n });\n };\n\n render().catch((cause: unknown) => {\n if (cancelled || isRenderCancelled(cause)) {\n return;\n }\n const renderError = toPdfViewerError(cause, 'RENDER_FAILED');\n setError(renderError);\n latest.current.onError?.(renderError);\n });\n\n return () => {\n cancelled = true;\n task?.cancel();\n (pendingTextLayer as TextLayer | null)?.cancel();\n };\n }, [\n document,\n page,\n scale,\n rotation,\n fitWidth,\n fitHeight,\n fitUpscale,\n devicePixelRatio,\n maxCanvasPixels,\n textLayer,\n annotationLayer,\n attempt,\n ]);\n\n // Search highlights are applied to the current text layer, without re-rendering the page.\n const highlightQuery = highlight?.query ?? '';\n const highlightSelected = highlight?.selected ?? null;\n useEffect(() => {\n const state = textStateRef.current;\n if (!state) return;\n const selected = applyHighlights(\n state,\n highlightQuery ? { query: highlightQuery, selected: highlightSelected } : undefined,\n );\n if (selected) latest.current.onHighlight?.(selected);\n }, [highlightQuery, highlightSelected, layerVersion]);\n\n // Release the canvas, the layers and the page's cached resources when the document changes or\n // the component unmounts; otherwise every page scrolled past in a long document keeps its own.\n useEffect(() => {\n const host = canvasHostRef.current;\n const layersHost = layersRef.current;\n return () => {\n releaseCanvas(host?.firstElementChild);\n host?.replaceChildren();\n layersHost?.replaceChildren();\n displayedPageRef.current?.cleanup();\n displayedPageRef.current = null;\n textStateRef.current = null;\n };\n }, [document]);\n\n const retry = useCallback(() => {\n setError(null);\n setAttempt((value) => value + 1);\n }, []);\n\n return { pageRef, canvasHostRef, layersRef, error, retry };\n}\n","import { memo, type CSSProperties, type ReactNode } from 'react';\nimport type { PDFDocumentProxy } from 'pdfjs-dist';\nimport type { FitOptions } from '../core/geometry.js';\nimport {\n usePageRenderer,\n type PageHighlight,\n type PageRenderInfo,\n} from '../hooks/usePageRenderer.js';\nimport type { PdfViewerError, Rotation } from '../types.js';\n\n/** Props for {@link PdfPageCanvas}. */\nexport interface PdfPageCanvasProps {\n /** A loaded document, e.g. from `usePdfDocument`. */\n document: PDFDocumentProxy;\n /** 1-based page number; clamped to the document. */\n page: number;\n /** Scale, 1 = 100%. Default `1`. */\n scale?: number | undefined;\n /** User rotation, added to the page's intrinsic rotation. Default `0`. */\n rotation?: Rotation | undefined;\n /** Box the page must fit into (see {@link FitOptions}). */\n fit?: FitOptions | undefined;\n /** Canvas pixel budget. Default `16_777_216`. */\n maxCanvasPixels?: number | undefined;\n /** Render a selectable text layer (copy, find, assistive technology). Default `false`. */\n textLayer?: boolean | undefined;\n /** Render clickable links. Default `false`. */\n annotationLayer?: boolean | undefined;\n /** Highlight search matches (requires `textLayer`). */\n highlight?: PageHighlight | undefined;\n /** Called when an internal link targets another page. */\n onLinkNavigate?: ((page: number) => void) | undefined;\n /** Called with the selected search match's element (e.g. to scroll it into view). */\n onHighlight?: ((element: HTMLElement) => void) | undefined;\n /**\n * Accessible name, e.g. `Page 1 of 3`. With a name the page is exposed as an image (or, with\n * a text or annotation layer, as a group containing the text and links); without one it is\n * decorative.\n */\n 'aria-label'?: string | undefined;\n className?: string | undefined;\n style?: CSSProperties | undefined;\n /** Replaces the default in-place error view. */\n renderError?: ((error: PdfViewerError, actions: { retry: () => void }) => ReactNode) | undefined;\n /** Called after each completed render. */\n onRender?: ((info: PageRenderInfo) => void) | undefined;\n /** Called when rendering fails (cancellations are not failures). */\n onError?: ((error: PdfViewerError) => void) | undefined;\n}\n\nfunction PdfPageCanvasImpl({\n document,\n page,\n scale = 1,\n rotation = 0,\n fit,\n maxCanvasPixels,\n textLayer = false,\n annotationLayer = false,\n highlight,\n onLinkNavigate,\n onHighlight,\n 'aria-label': ariaLabel,\n className,\n style,\n renderError,\n onRender,\n onError,\n}: PdfPageCanvasProps) {\n const { pageRef, canvasHostRef, layersRef, error, retry } = usePageRenderer({\n document,\n page,\n scale,\n rotation,\n fit,\n maxCanvasPixels,\n textLayer,\n annotationLayer,\n highlight,\n onLinkNavigate,\n onHighlight,\n onRender,\n onError,\n });\n\n const labelled = ariaLabel !== undefined && !error;\n return (\n <div\n ref={pageRef}\n className={className ? `rpv-page ${className}` : 'rpv-page'}\n style={style}\n // An image must not contain interactive or readable content: pages with text or links are groups.\n role={labelled ? (textLayer || annotationLayer ? 'group' : 'img') : undefined}\n aria-label={labelled ? ariaLabel : undefined}\n data-state={error ? 'error' : undefined}\n >\n <div ref={canvasHostRef} className=\"rpv-page__canvas-host\" />\n <div ref={layersRef} className=\"rpv-page__layers\" />\n {error &&\n (renderError ? (\n renderError(error, { retry })\n ) : (\n <div className=\"rpv-page__error\" role=\"alert\">\n {error.message}\n </div>\n ))}\n </div>\n );\n}\n\n/**\n * Renders a single PDF page: cancellable, double-buffered, HiDPI and pixel-capped, with optional\n * text and annotation layers. The building block for custom viewers (see `usePdfDocument`).\n */\nexport const PdfPageCanvas = memo(PdfPageCanvasImpl);\n","import type { KeyboardEvent, Ref } from 'react';\nimport type { LabelContext, PdfViewerLabels } from '../labels.js';\nimport { ExpandLessIcon, ExpandMoreIcon, SearchIcon } from './icons.js';\n\ninterface SearchBarProps {\n inputRef: Ref<HTMLInputElement>;\n query: string;\n onQueryChange: (query: string) => void;\n total: number;\n /** 0-based index of the current match. */\n current: number;\n searching: boolean;\n onNext: () => void;\n onPrevious: () => void;\n labels: PdfViewerLabels;\n context: LabelContext;\n}\n\n/** Find-in-document field: `Enter` / `Shift+Enter` step through matches, `Esc` clears. */\nexport function SearchBar({\n inputRef,\n query,\n onQueryChange,\n total,\n current,\n searching,\n onNext,\n onPrevious,\n labels,\n context,\n}: SearchBarProps) {\n const handleKeyDown = (event: KeyboardEvent<HTMLInputElement>) => {\n if (event.key === 'Enter') {\n event.preventDefault();\n if (event.shiftKey) onPrevious();\n else onNext();\n } else if (event.key === 'Escape' && query) {\n event.preventDefault();\n event.stopPropagation();\n onQueryChange('');\n }\n };\n\n const status = !query.trim()\n ? ''\n : total > 0\n ? labels.searchResults(current + 1, total, context)\n : searching\n ? '…'\n : labels.searchNoResults;\n\n return (\n <div className=\"rpv-search\">\n <span className=\"rpv-search__icon\" aria-hidden=\"true\">\n <SearchIcon />\n </span>\n <input\n ref={inputRef}\n className=\"rpv-search__input\"\n type=\"search\"\n aria-label={labels.search}\n placeholder={labels.search}\n value={query}\n onChange={(event) => onQueryChange(event.target.value)}\n onKeyDown={handleKeyDown}\n />\n <output className=\"rpv-search__status\" aria-live=\"polite\">\n {status}\n </output>\n <button\n type=\"button\"\n className=\"rpv-button\"\n aria-label={labels.searchPrevious}\n disabled={total === 0}\n onClick={onPrevious}\n >\n <ExpandLessIcon />\n </button>\n <button\n type=\"button\"\n className=\"rpv-button\"\n aria-label={labels.searchNext}\n disabled={total === 0}\n onClick={onNext}\n >\n <ExpandMoreIcon />\n </button>\n </div>\n );\n}\n","import { memo, useCallback, useEffect, useRef, useState } from 'react';\nimport type { PDFDocumentProxy } from 'pdfjs-dist';\nimport type { PageRenderInfo } from '../hooks/usePageRenderer.js';\nimport type { LabelContext, PdfViewerLabels } from '../labels.js';\nimport type { Rotation } from '../types.js';\nimport { PdfPageCanvas } from './PdfPageCanvas.js';\n\nconst THUMBNAIL_WIDTH = 112;\nconst INITIALLY_MOUNTED = 8;\n/** How far beyond the visible part of the list thumbnails stay rendered. */\nconst MOUNT_MARGIN = '400px 0px';\n\ninterface Size {\n width: number;\n height: number;\n}\n\nconst NO_SIZES: ReadonlyMap<number, Size> = new Map();\n\ninterface ThumbnailsProps {\n document: PDFDocumentProxy;\n numPages: number;\n page: number;\n rotation: Rotation;\n onSelect: (page: number) => void;\n labels: PdfViewerLabels;\n context: LabelContext;\n}\n\nfunction ThumbnailsImpl({\n document,\n numPages,\n page,\n rotation,\n onSelect,\n labels,\n context,\n}: ThumbnailsProps) {\n const navRef = useRef<HTMLElement>(null);\n const items = useRef(new Map<number, HTMLLIElement>());\n const [mounted, setMounted] = useState<ReadonlySet<number>>(\n () => new Set(Array.from({ length: Math.min(numPages, INITIALLY_MOUNTED) }, (_, i) => i + 1)),\n );\n // Size of every rendered thumbnail, so a placeholder takes the space its thumbnail takes: its\n // own size once it has rendered, the latest rendered size before that. Sizes belong to one\n // document at one rotation.\n const [measured, setMeasured] = useState<{\n document: PDFDocumentProxy;\n rotation: Rotation;\n sizes: ReadonlyMap<number, Size>;\n latest: Size | undefined;\n }>(() => ({ document, rotation, sizes: new Map(), latest: undefined }));\n const current = measured.document === document && measured.rotation === rotation;\n const sizes = current ? measured.sizes : NO_SIZES;\n const latestSize = current ? measured.latest : undefined;\n\n const recordSize = useCallback(\n (info: PageRenderInfo) => {\n const rendered = items.current.get(info.page)?.querySelector<HTMLElement>('.rpv-page');\n if (!rendered || rendered.offsetWidth === 0 || rendered.offsetHeight === 0) return;\n const size = { width: rendered.offsetWidth, height: rendered.offsetHeight };\n setMeasured((state) => {\n const same = state.document === document && state.rotation === rotation;\n const known = same ? state.sizes.get(info.page) : undefined;\n if (known?.width === size.width && known.height === size.height) return state;\n return {\n document,\n rotation,\n sizes: new Map([...(same ? state.sizes : []), [info.page, size]]),\n latest: size,\n };\n });\n },\n [document, rotation],\n );\n\n // Only thumbnails near the visible part of the list are rendered: a long document holds a\n // handful of canvases, not one per page.\n useEffect(() => {\n const root = navRef.current;\n if (!root || typeof IntersectionObserver === 'undefined') return;\n const near = new Set<number>();\n const observer = new IntersectionObserver(\n (entries) => {\n for (const entry of entries) {\n const pageNumber = Number((entry.target as HTMLElement).dataset['page']);\n if (entry.isIntersecting) near.add(pageNumber);\n else near.delete(pageNumber);\n }\n setMounted((mountedNow) =>\n mountedNow.size === near.size && [...near].every((n) => mountedNow.has(n))\n ? mountedNow\n : new Set(near),\n );\n },\n { root, rootMargin: MOUNT_MARGIN },\n );\n for (const item of items.current.values()) observer.observe(item);\n return () => observer.disconnect();\n }, [numPages]);\n\n // Keep the current page's thumbnail visible.\n useEffect(() => {\n const root = navRef.current;\n const item = items.current.get(page);\n if (!root || !item) return;\n const top = item.offsetTop - root.offsetTop;\n if (top < root.scrollTop || top + item.offsetHeight > root.scrollTop + root.clientHeight) {\n root.scrollTop = top - (root.clientHeight - item.offsetHeight) / 2;\n }\n }, [page]);\n\n return (\n <nav ref={navRef} className=\"rpv-thumbnails\" aria-label={labels.thumbnails}>\n <ol className=\"rpv-thumbnails__list\">\n {Array.from({ length: numPages }, (_, index) => {\n const pageNumber = index + 1;\n return (\n <li\n key={pageNumber}\n ref={(node) => {\n if (node) items.current.set(pageNumber, node);\n else items.current.delete(pageNumber);\n }}\n data-page={pageNumber}\n >\n <button\n type=\"button\"\n className=\"rpv-thumbnail\"\n aria-label={labels.pageAriaLabel(pageNumber, numPages, context)}\n aria-current={pageNumber === page ? 'page' : undefined}\n onClick={() => onSelect(pageNumber)}\n >\n {mounted.has(pageNumber) ? (\n <PdfPageCanvas\n document={document}\n page={pageNumber}\n rotation={rotation}\n fit={{ width: THUMBNAIL_WIDTH + 2, upscale: true }}\n maxCanvasPixels={1_000_000}\n onRender={recordSize}\n />\n ) : (\n <span\n className=\"rpv-thumbnail__placeholder\"\n style={sizes.get(pageNumber) ?? latestSize}\n />\n )}\n <span className=\"rpv-thumbnail__number\" aria-hidden=\"true\">\n {context.formatNumber(pageNumber)}\n </span>\n </button>\n </li>\n );\n })}\n </ol>\n </nav>\n );\n}\n\n/** Page thumbnails sidebar; thumbnails render only while they are near the visible area. */\nexport const Thumbnails = memo(ThumbnailsImpl);\n","/** Default zoom floor (25%). */\nexport const DEFAULT_MIN_SCALE = 0.25;\n/** Default zoom ceiling (500%). */\nexport const DEFAULT_MAX_SCALE = 5;\n/** Default zoom increment (5%). */\nexport const DEFAULT_SCALE_STEP = 0.05;\n/** 100%: one PDF point per CSS pixel. */\nexport const DEFAULT_SCALE = 1;\n\nconst EPSILON = 1e-6;\n\n/** Removes floating-point noise (`1.5000000000000004` → `1.5`). */\nexport function roundScale(scale: number): number {\n return Math.round(scale * 10_000) / 10_000;\n}\n\n/** Tolerance-based scale comparison. */\nexport function scalesEqual(a: number, b: number): boolean {\n return Math.abs(a - b) < EPSILON;\n}\n\nfunction clampScale(scale: number, min: number, max: number): number {\n return Math.min(Math.max(scale, min), max);\n}\n\n/** Zoom constraints shared by the buttons, shortcuts and imperative API. */\nexport interface ZoomOptions {\n minScale: number;\n maxScale: number;\n scaleStep: number;\n /** Preset ladder; when non-empty the zoom buttons step between presets instead of by `scaleStep`. */\n zoomLevels?: readonly number[] | undefined;\n}\n\nfunction ladder({ zoomLevels, minScale, maxScale }: ZoomOptions): number[] {\n const levels = (zoomLevels ?? [])\n .filter((level) => Number.isFinite(level) && level > 0)\n .map((level) => roundScale(clampScale(level, minScale, maxScale)));\n return [...new Set(levels)].sort((a, b) => a - b);\n}\n\n/** The next zoom value in `direction`, or `null` when already at the bound. */\nexport function nextScale(current: number, direction: 1 | -1, options: ZoomOptions): number | null {\n const levels = ladder(options);\n let next: number | undefined;\n if (levels.length > 0) {\n next =\n direction > 0\n ? levels.find((level) => level > current + EPSILON)\n : levels.findLast((level) => level < current - EPSILON);\n } else {\n next = roundScale(\n clampScale(current + direction * options.scaleStep, options.minScale, options.maxScale),\n );\n }\n return next === undefined || scalesEqual(next, current) ? null : next;\n}\n\n/** Normalizes an arbitrary requested scale: clamps to the bounds and removes float noise. */\nexport function normalizeScale(scale: number, options: Pick<ZoomOptions, 'minScale' | 'maxScale'>) {\n return roundScale(clampScale(scale, options.minScale, options.maxScale));\n}\n\n/** Integer percentage shown in the zoom label (`Math.round(scale * 100)`). */\nexport function scaleToPercent(scale: number): number {\n return Math.round(scale * 100);\n}\n","import { useMemo } from 'react';\n\n/** Helpers passed to label functions. */\nexport interface LabelContext {\n /** Formats an integer for the viewer's `locale` (no grouping separators). */\n formatNumber: (value: number) => string;\n}\n\n/**\n * Every user-visible string and accessible name. Defaults are English; override any subset\n * through the `labels` prop.\n */\nexport interface PdfViewerLabels {\n /** Accessible name of the viewer region. */\n viewer: string;\n /** Accessible name of the toolbar. */\n toolbar: string;\n /** Accessible name of the scrollable document area. */\n document: string;\n zoomOut: string;\n zoomIn: string;\n /** Zoom label text, e.g. `100%`. */\n zoomLevel: (percent: number, context: LabelContext) => string;\n /** Accessible name of the reset-zoom action. */\n resetZoom: string;\n previousPage: string;\n nextPage: string;\n /** Page label text, e.g. `1 / 3`. */\n pageIndicator: (page: number, total: number, context: LabelContext) => string;\n /** Accessible name of the page image, e.g. `Page 1 of 3`. */\n pageAriaLabel: (page: number, total: number, context: LabelContext) => string;\n /** Accessible name of the page-number input. */\n pageInput: string;\n enterFullscreen: string;\n exitFullscreen: string;\n rotate: string;\n download: string;\n print: string;\n /** Accessible name of the overflow menu button (\"⋮\") shown when the toolbar is too narrow. */\n moreActions: string;\n loading: string;\n retry: string;\n /** Announced when there is no document. */\n empty: string;\n /** Print preparation status, e.g. `Preparing document for printing… 3 / 40`. */\n printProgress: (done: number, total: number, context: LabelContext) => string;\n cancel: string;\n passwordPrompt: string;\n passwordLabel: string;\n passwordSubmit: string;\n passwordIncorrect: string;\n /** Accessible name of the thumbnails sidebar. */\n thumbnails: string;\n /** Accessible name of the search field. */\n search: string;\n /** Search result status, e.g. `2 of 5`. */\n searchResults: (current: number, total: number, context: LabelContext) => string;\n searchPrevious: string;\n searchNext: string;\n searchNoResults: string;\n}\n\n/** The English defaults. */\nexport const defaultLabels: PdfViewerLabels = {\n viewer: 'PDF viewer',\n toolbar: 'PDF controls',\n document: 'Document',\n zoomOut: 'Zoom out',\n zoomIn: 'Zoom in',\n zoomLevel: (percent, { formatNumber }) => `${formatNumber(percent)}%`,\n resetZoom: 'Reset zoom',\n previousPage: 'Previous page',\n nextPage: 'Next page',\n pageIndicator: (page, total, { formatNumber }) =>\n `${formatNumber(page)} / ${formatNumber(total)}`,\n pageAriaLabel: (page, total, { formatNumber }) =>\n `Page ${formatNumber(page)} of ${formatNumber(total)}`,\n pageInput: 'Page number',\n enterFullscreen: 'Enter fullscreen',\n exitFullscreen: 'Exit fullscreen',\n rotate: 'Rotate PDF',\n download: 'Download PDF',\n print: 'Print PDF',\n moreActions: 'More actions',\n loading: 'Loading PDF...',\n retry: 'Retry',\n empty: 'No document',\n printProgress: (done, total, { formatNumber }) =>\n `Preparing document for printing… ${formatNumber(done)} / ${formatNumber(total)}`,\n cancel: 'Cancel',\n passwordPrompt: 'This document is password protected',\n passwordLabel: 'Password',\n passwordSubmit: 'Open',\n passwordIncorrect: 'Incorrect password. Please try again.',\n thumbnails: 'Pages',\n search: 'Search in document',\n searchResults: (current, total, { formatNumber }) =>\n `${formatNumber(current)} of ${formatNumber(total)}`,\n searchPrevious: 'Previous match',\n searchNext: 'Next match',\n searchNoResults: 'No matches',\n};\n\nfunction createNumberFormatter(locale: string | undefined): (value: number) => string {\n let format: Intl.NumberFormat;\n try {\n format = new Intl.NumberFormat(locale, { useGrouping: false, maximumFractionDigits: 0 });\n } catch {\n format = new Intl.NumberFormat(undefined, { useGrouping: false, maximumFractionDigits: 0 });\n }\n return (value) => format.format(value);\n}\n\n/** Label context for a locale (memoised). */\nexport function useLabelContext(locale: string | undefined): LabelContext {\n return useMemo(() => ({ formatNumber: createNumberFormatter(locale) }), [locale]);\n}\n\n/** Merges partial overrides onto the defaults (memoised on the overrides' identity). */\nexport function useLabels(overrides: Partial<PdfViewerLabels> | undefined): PdfViewerLabels {\n return useMemo(() => ({ ...defaultLabels, ...overrides }), [overrides]);\n}\n","import { memo, type ReactNode } from 'react';\nimport type { ToolbarAction } from '../types.js';\n\ninterface ToolbarButtonProps {\n action: ToolbarAction;\n label: string;\n icon: ReactNode;\n onClick: () => void;\n disabled?: boolean | undefined;\n tabIndex: number;\n onFocus: (action: ToolbarAction) => void;\n}\n\nfunction ToolbarButtonImpl({\n action,\n label,\n icon,\n onClick,\n disabled,\n tabIndex,\n onFocus,\n}: ToolbarButtonProps) {\n return (\n <button\n type=\"button\"\n className=\"rpv-button\"\n aria-label={label}\n data-action={action}\n disabled={disabled}\n tabIndex={tabIndex}\n onClick={onClick}\n onFocus={() => onFocus(action)}\n >\n {icon}\n </button>\n );\n}\n\n/** Round icon button used by the toolbar. */\nexport const ToolbarButton = memo(ToolbarButtonImpl);\n","import { useEffect, useId, useRef, useState, type KeyboardEvent, type ReactNode } from 'react';\nimport { MoreVertIcon } from './icons.js';\n\n/** An entry of the toolbar's overflow menu. */\nexport interface ToolbarMenuItem {\n key: string;\n label: string;\n icon: ReactNode;\n onSelect: () => void;\n disabled?: boolean | undefined;\n}\n\ninterface ToolbarMenuProps {\n /** Accessible name of the button and the menu. */\n label: string;\n items: readonly ToolbarMenuItem[];\n /** Opens above the toolbar (`'top'`, toolbar at the bottom) or below it. */\n placement: 'top' | 'bottom';\n tabIndex: number;\n onFocus: () => void;\n}\n\nconst ITEM_SELECTOR = '[role=\"menuitem\"]:not([aria-disabled=\"true\"])';\n\n/**\n * The \"More actions\" button and its menu (WAI-ARIA menu button pattern): arrow keys, Home and\n * End move between items, `Esc` closes and returns focus to the button, `Tab` or a click outside\n * closes it.\n */\nexport function ToolbarMenu({ label, items, placement, tabIndex, onFocus }: ToolbarMenuProps) {\n const menuId = useId();\n const buttonRef = useRef<HTMLButtonElement>(null);\n const menuRef = useRef<HTMLDivElement>(null);\n const [open, setOpen] = useState<false | 'first' | 'last'>(false);\n\n const enabledItems = () => [\n ...(menuRef.current?.querySelectorAll<HTMLElement>(ITEM_SELECTOR) ?? []),\n ];\n\n useEffect(() => {\n if (!open) return;\n const initial = enabledItems();\n (open === 'last' ? initial.at(-1) : initial[0])?.focus();\n const handlePointerDown = (event: PointerEvent) => {\n const target = event.target as Node;\n if (!menuRef.current?.contains(target) && !buttonRef.current?.contains(target)) {\n setOpen(false);\n }\n };\n document.addEventListener('pointerdown', handlePointerDown);\n return () => document.removeEventListener('pointerdown', handlePointerDown);\n }, [open]);\n\n const close = (restoreFocus: boolean) => {\n setOpen(false);\n if (restoreFocus) buttonRef.current?.focus();\n };\n\n const handleMenuKeyDown = (event: KeyboardEvent<HTMLDivElement>) => {\n const enabled = enabledItems();\n const index = enabled.indexOf(event.target as HTMLElement);\n const last = enabled.length - 1;\n let next: HTMLElement | undefined;\n switch (event.key) {\n case 'ArrowDown':\n next = enabled[index >= last ? 0 : index + 1];\n break;\n case 'ArrowUp':\n next = enabled[index <= 0 ? last : index - 1];\n break;\n case 'Home':\n next = enabled[0];\n break;\n case 'End':\n next = enabled[last];\n break;\n case 'Escape':\n event.preventDefault();\n event.stopPropagation();\n close(true);\n return;\n case 'Tab':\n close(false);\n return;\n default:\n return;\n }\n // Keep the toolbar's own arrow-key handling and the viewer shortcuts out of the menu.\n event.preventDefault();\n event.stopPropagation();\n next?.focus();\n };\n\n return (\n <div className=\"rpv-menu-anchor\">\n <button\n ref={buttonRef}\n type=\"button\"\n className=\"rpv-button\"\n aria-label={label}\n aria-haspopup=\"menu\"\n aria-expanded={Boolean(open)}\n aria-controls={open ? menuId : undefined}\n data-action=\"more\"\n tabIndex={tabIndex}\n onFocus={onFocus}\n onClick={() => setOpen((current) => (current ? false : 'first'))}\n onKeyDown={(event) => {\n if (event.key === 'ArrowDown' || event.key === 'ArrowUp') {\n event.preventDefault();\n setOpen(event.key === 'ArrowUp' ? 'last' : 'first');\n }\n }}\n >\n <MoreVertIcon />\n </button>\n {open && (\n <div\n ref={menuRef}\n id={menuId}\n role=\"menu\"\n aria-label={label}\n tabIndex={-1}\n className=\"rpv-menu\"\n data-placement={placement}\n onKeyDown={handleMenuKeyDown}\n >\n {items.map((item) => (\n <button\n key={item.key}\n type=\"button\"\n role=\"menuitem\"\n className=\"rpv-menu__item\"\n tabIndex={-1}\n aria-disabled={item.disabled || undefined}\n onClick={() => {\n if (item.disabled) return;\n close(true);\n item.onSelect();\n }}\n >\n <span className=\"rpv-menu__icon\" aria-hidden=\"true\">\n {item.icon}\n </span>\n <span className=\"rpv-menu__label\">{item.label}</span>\n </button>\n ))}\n </div>\n )}\n </div>\n );\n}\n","import { memo, useEffect, useRef, useState, type KeyboardEvent, type ReactNode } from 'react';\nimport { scaleToPercent } from '../core/scale.js';\nimport { useIsomorphicLayoutEffect } from '../hooks/useIsomorphicLayoutEffect.js';\nimport { useLabelContext, useLabels, type PdfViewerLabels } from '../labels.js';\nimport type { PdfViewerApi, ToolbarAction, ToolbarConfig } from '../types.js';\nimport {\n DownloadIcon,\n FullscreenExitIcon,\n FullscreenIcon,\n NavigateBeforeIcon,\n NavigateNextIcon,\n PrintIcon,\n RestartIcon,\n RotateRightIcon,\n ZoomInIcon,\n ZoomOutIcon,\n} from './icons.js';\nimport { ToolbarButton } from './ToolbarButton.js';\nimport { ToolbarMenu, type ToolbarMenuItem } from './ToolbarMenu.js';\n\n/** Every toolbar action, in display order. */\nconst DEFAULT_TOOLBAR_ACTIONS: readonly ToolbarAction[] = [\n 'zoomOut',\n 'zoomLevel',\n 'zoomIn',\n 'previousPage',\n 'pageIndicator',\n 'nextPage',\n 'fullscreen',\n 'rotate',\n 'download',\n 'print',\n];\n\n/** Actions hidden in compact, non-fullscreen mode by default. */\nconst DEFAULT_HIDDEN_WHEN_COMPACT: readonly ToolbarAction[] = ['rotate', 'print'];\n\nconst GROUPS: readonly (readonly ToolbarAction[])[] = [\n ['zoomOut', 'zoomLevel', 'zoomIn'],\n ['previousPage', 'pageIndicator', 'nextPage'],\n ['fullscreen', 'rotate', 'download', 'print'],\n];\nconst GROUP_NAMES = ['zoom', 'pages', 'actions'] as const;\n\n/**\n * Actions moved into the \"More actions\" menu at each collapse level. The toolbar always stays a\n * single row: when it does not fit, the secondary actions collapse first, then the zoom controls.\n * Page navigation always stays visible.\n */\nconst COLLAPSED: readonly (readonly ToolbarAction[])[] = [\n [],\n ['fullscreen', 'rotate', 'download', 'print'],\n ['zoomOut', 'zoomLevel', 'zoomIn', 'fullscreen', 'rotate', 'download', 'print'],\n];\nconst MAX_LEVEL = COLLAPSED.length - 1;\n\nconst px = (value: string) => Number.parseFloat(value) || 0;\n\n/** Width the toolbar needs on one row: its groups (which never shrink), gaps and padding. */\nfunction naturalWidth(toolbar: HTMLElement): number {\n const style = getComputedStyle(toolbar);\n const groups = [...toolbar.children] as HTMLElement[];\n const content = groups.reduce((sum, group) => sum + group.offsetWidth, 0);\n return (\n content +\n px(style.columnGap) * Math.max(0, groups.length - 1) +\n px(style.paddingLeft) +\n px(style.paddingRight)\n );\n}\n\n/** The element whose width bounds the toolbar: the viewer root, or (standalone) the parent. */\nfunction widthHost(toolbar: HTMLElement): HTMLElement | null {\n const wrapper = toolbar.parentElement;\n return wrapper?.classList.contains('rpv-toolbar-wrapper') ? wrapper.parentElement : wrapper;\n}\n\n/**\n * Width the toolbar may use. It may overhang its container by its own side\n * padding (it stays centered), but never the screen.\n */\nfunction availableWidth(toolbar: HTMLElement): number {\n const host = widthHost(toolbar);\n if (!host) return 0;\n const hostStyle = getComputedStyle(host);\n const hostWidth = host.clientWidth - px(hostStyle.paddingLeft) - px(hostStyle.paddingRight);\n if (hostWidth <= 0) return 0;\n const toolbarStyle = getComputedStyle(toolbar);\n const overhang = px(toolbarStyle.paddingLeft) + px(toolbarStyle.paddingRight);\n const screen = toolbar.ownerDocument.documentElement.clientWidth || Number.POSITIVE_INFINITY;\n return Math.min(hostWidth + overhang, screen);\n}\n\n/** Props for {@link PdfToolbar}. */\nexport interface PdfToolbarProps {\n /** The viewer API (from a `ref` or `renderToolbar`). */\n api: PdfViewerApi;\n /** Label overrides. */\n labels?: Partial<PdfViewerLabels> | undefined;\n /** Which actions to show and where. */\n config?: ToolbarConfig | undefined;\n /** Compact layout (narrow viewport): hides `hiddenWhenCompact` actions outside fullscreen. */\n compact?: boolean | undefined;\n /** Locale for number formatting. */\n locale?: string | undefined;\n /** The zoom label becomes a button that resets zoom. Default `false`. */\n zoomReset?: boolean | undefined;\n /** Replaces the page indicator text (e.g. with a page-number input). */\n pageIndicator?: ReactNode;\n /** Where the \"More actions\" menu opens: `'top'` (above; default) or `'bottom'`. */\n menuPlacement?: 'top' | 'bottom' | undefined;\n}\n\ninterface ButtonSpec {\n label: string;\n icon: ReactNode;\n onClick: () => void;\n disabled: boolean;\n}\n\ntype FocusKey = ToolbarAction | 'more';\n\nfunction PdfToolbarImpl({\n api,\n labels: labelOverrides,\n config,\n compact = false,\n locale,\n zoomReset = false,\n pageIndicator,\n menuPlacement = 'top',\n}: PdfToolbarProps) {\n const labels = useLabels(labelOverrides);\n const context = useLabelContext(locale);\n const toolbarRef = useRef<HTMLDivElement>(null);\n const [focusedAction, setFocusedAction] = useState<FocusKey | null>(null);\n\n const hiddenWhenCompact = config?.hiddenWhenCompact ?? DEFAULT_HIDDEN_WHEN_COMPACT;\n const visible = new Set(\n (config?.actions ?? DEFAULT_TOOLBAR_ACTIONS).filter(\n (action) => !(compact && !api.fullscreen && hiddenWhenCompact.includes(action)),\n ),\n );\n const ready = api.status === 'ready';\n const zoomText = labels.zoomLevel(scaleToPercent(api.scale), context);\n const extended = zoomReset || pageIndicator !== undefined;\n\n // ── Collapse level: the smallest level whose single row fits the available width ──────────\n const layoutKey = `${[...visible].join(',')}|${extended ? 'x' : ''}`;\n const [layout, setLayout] = useState({ key: layoutKey, level: 0 });\n if (layout.key !== layoutKey) {\n setLayout({ key: layoutKey, level: 0 });\n }\n const level = layout.key === layoutKey ? layout.level : 0;\n const widths = useRef(new Map<string, number[]>());\n const fit = useRef<() => void>(() => undefined);\n useIsomorphicLayoutEffect(() => {\n fit.current = () => {\n const toolbar = toolbarRef.current;\n if (!toolbar) return;\n const available = availableWidth(toolbar);\n if (available <= 0) return;\n let measured = widths.current.get(layoutKey);\n if (!measured) {\n measured = [];\n widths.current.set(layoutKey, measured);\n }\n measured[level] = naturalWidth(toolbar);\n let next = level;\n // Expand when a roomier level is known to fit (it is re-measured once shown).\n while (next > 0 && (measured[next - 1] ?? Infinity) <= available) next -= 1;\n if (next === level && (measured[level] ?? 0) > available + 0.5 && level < MAX_LEVEL) {\n next = level + 1;\n }\n if (next !== level) setLayout({ key: layoutKey, level: next });\n };\n fit.current();\n });\n useEffect(() => {\n const toolbar = toolbarRef.current;\n const host = toolbar ? widthHost(toolbar) : null;\n if (!host || typeof ResizeObserver === 'undefined') return;\n const observer = new ResizeObserver(() => fit.current());\n observer.observe(host);\n return () => observer.disconnect();\n }, []);\n\n const buttons: Partial<Record<ToolbarAction, ButtonSpec>> = {\n zoomOut: {\n label: labels.zoomOut,\n icon: <ZoomOutIcon />,\n onClick: api.zoomOut,\n disabled: !api.canZoomOut,\n },\n zoomIn: {\n label: labels.zoomIn,\n icon: <ZoomInIcon />,\n onClick: api.zoomIn,\n disabled: !api.canZoomIn,\n },\n previousPage: {\n label: labels.previousPage,\n icon: <NavigateBeforeIcon />,\n onClick: api.previousPage,\n disabled: !ready || api.page <= 1,\n },\n nextPage: {\n label: labels.nextPage,\n icon: <NavigateNextIcon />,\n onClick: api.nextPage,\n disabled: !ready || api.page >= api.numPages,\n },\n fullscreen: {\n label: api.fullscreen ? labels.exitFullscreen : labels.enterFullscreen,\n icon: api.fullscreen ? <FullscreenExitIcon /> : <FullscreenIcon />,\n onClick: api.toggleFullscreen,\n disabled: false,\n },\n rotate: {\n label: labels.rotate,\n icon: <RotateRightIcon />,\n onClick: () => api.rotate('cw'),\n disabled: false,\n },\n download: {\n label: labels.download,\n icon: <DownloadIcon />,\n onClick: () => void api.download(),\n disabled: !ready,\n },\n print: {\n label: labels.print,\n icon: <PrintIcon />,\n onClick: () => void api.print(),\n disabled: !ready,\n },\n };\n\n const collapsed = (COLLAPSED[level] ?? []).filter((action) => visible.has(action));\n const inline = (action: ToolbarAction) => visible.has(action) && !collapsed.includes(action);\n const menuItems: ToolbarMenuItem[] = collapsed.flatMap((action): ToolbarMenuItem[] => {\n if (action === 'zoomLevel') {\n return [\n {\n key: action,\n label: `${labels.resetZoom} (${zoomText})`,\n icon: <RestartIcon />,\n onSelect: api.resetZoom,\n },\n ];\n }\n const button = buttons[action];\n return button\n ? [\n {\n key: action,\n label: button.label,\n icon: button.icon,\n onSelect: button.onClick,\n disabled: button.disabled,\n },\n ]\n : [];\n });\n\n // Roving tab index: one tab stop for the whole toolbar; arrow keys move between controls.\n const focusable: FocusKey[] = DEFAULT_TOOLBAR_ACTIONS.filter((action) => {\n if (!inline(action) || action === 'pageIndicator') return false;\n if (action === 'zoomLevel') return zoomReset;\n const button = buttons[action];\n return button !== undefined && !button.disabled;\n });\n if (menuItems.length > 0) focusable.push('more');\n const tabStop =\n focusedAction !== null && focusable.includes(focusedAction) ? focusedAction : focusable[0];\n\n const handleKeyDown = (event: KeyboardEvent<HTMLDivElement>) => {\n const keys = ['ArrowLeft', 'ArrowRight', 'Home', 'End'];\n if (!keys.includes(event.key) || !toolbarRef.current) {\n return;\n }\n // Toolbar-level controls only (menu items and the page input handle their own keys).\n const controls = [\n ...toolbarRef.current.querySelectorAll<HTMLButtonElement>('[data-action]:not(:disabled)'),\n ];\n const index = controls.indexOf(event.target as HTMLButtonElement);\n if (index === -1) {\n return;\n }\n event.preventDefault();\n event.stopPropagation();\n const last = controls.length - 1;\n const next =\n event.key === 'Home'\n ? 0\n : event.key === 'End'\n ? last\n : event.key === 'ArrowRight'\n ? index === last\n ? 0\n : index + 1\n : index === 0\n ? last\n : index - 1;\n controls[next]?.focus();\n };\n\n const renderAction = (action: ToolbarAction) => {\n if (action === 'zoomLevel') {\n return zoomReset ? (\n <button\n key={action}\n type=\"button\"\n className=\"rpv-toolbar__label rpv-toolbar__zoom rpv-zoom-reset\"\n aria-label={`${labels.resetZoom} (${zoomText})`}\n title={labels.resetZoom}\n data-action={action}\n tabIndex={action === tabStop ? 0 : -1}\n onFocus={() => setFocusedAction(action)}\n onClick={api.resetZoom}\n >\n {zoomText}\n </button>\n ) : (\n <span key={action} className=\"rpv-toolbar__label rpv-toolbar__zoom\">\n {zoomText}\n </span>\n );\n }\n if (action === 'pageIndicator') {\n return pageIndicator ? (\n <span\n key={action}\n className=\"rpv-toolbar__label rpv-toolbar__pages rpv-toolbar__pages--input\"\n >\n {pageIndicator}\n </span>\n ) : (\n <span\n key={action}\n className=\"rpv-toolbar__label rpv-toolbar__pages\"\n aria-live=\"polite\"\n aria-atomic=\"true\"\n >\n {api.numPages > 0\n ? labels.pageIndicator(api.page, api.numPages, context)\n : labels.pageIndicator(0, 0, context)}\n </span>\n );\n }\n const button = buttons[action];\n if (!button) {\n return null;\n }\n return (\n <ToolbarButton\n key={action}\n action={action}\n label={button.label}\n icon={button.icon}\n onClick={button.onClick}\n disabled={button.disabled}\n tabIndex={action === tabStop ? 0 : -1}\n onFocus={setFocusedAction}\n />\n );\n };\n\n return (\n <div\n ref={toolbarRef}\n role=\"toolbar\"\n aria-label={labels.toolbar}\n aria-orientation=\"horizontal\"\n className=\"rpv-toolbar\"\n data-extended={extended ? '' : undefined}\n data-level={level}\n onKeyDown={handleKeyDown}\n >\n {GROUPS.map((group, index) => {\n const items = group.filter(inline);\n const withMenu = index === GROUPS.length - 1 && menuItems.length > 0;\n if (items.length === 0 && !withMenu) return null;\n return (\n <div\n key={GROUP_NAMES[index]}\n className=\"rpv-toolbar__group\"\n data-group={GROUP_NAMES[index]}\n >\n {items.map(renderAction)}\n {withMenu && (\n <ToolbarMenu\n label={labels.moreActions}\n items={menuItems}\n placement={menuPlacement}\n tabIndex={tabStop === 'more' ? 0 : -1}\n onFocus={() => setFocusedAction('more')}\n />\n )}\n </div>\n );\n })}\n </div>\n );\n}\n\n/**\n * The default toolbar: zoom, page navigation, fullscreen, rotate, download and print, on one\n * row. When the row does not fit, secondary actions collapse into a \"More actions\" menu. Usable\n * on its own, e.g. inside `renderToolbar`.\n */\nexport const PdfToolbar = memo(PdfToolbarImpl);\n","/** Wraps PDF bytes in a Blob (copying, so a shared or transferred buffer is never exposed). */\nexport function toPdfBlob(data: Uint8Array): Blob {\n return new Blob([new Uint8Array(data)], { type: 'application/pdf' });\n}\n\n/** Saves bytes as a file through a temporary object URL and a hidden `<a download>`. */\nexport function saveBytes(data: Uint8Array, fileName: string): void {\n const url = URL.createObjectURL(toPdfBlob(data));\n const link = document.createElement('a');\n link.href = url;\n link.download = fileName;\n link.rel = 'noopener';\n link.style.display = 'none';\n document.body.append(link);\n link.click();\n link.remove();\n // Revoking immediately can cancel the download in some browsers.\n setTimeout(() => URL.revokeObjectURL(url), 10_000);\n}\n","import type { PdfSource } from '../types.js';\n\n/** Name used when nothing better is known. */\nexport const DEFAULT_FILE_NAME = 'document.pdf';\n\n/** Last path segment of `url` when it ends in `.pdf`, otherwise `null`. */\nexport function fileNameFromUrl(url: string): string | null {\n let pathname: string;\n try {\n pathname = new URL(url, 'https://base.invalid/').pathname;\n } catch {\n return null;\n }\n const segment = pathname.split('/').pop() ?? '';\n let decoded = segment;\n try {\n decoded = decodeURIComponent(segment);\n } catch {\n // Malformed escape: use the raw segment.\n }\n return /\\.pdf$/i.test(decoded) ? decoded : null;\n}\n\n/**\n * Download file name: the explicit `fileName`, then a `File`'s name, then the URL's last\n * `.pdf` segment, then {@link DEFAULT_FILE_NAME}.\n */\nexport function resolveFileName(\n fileName: string | undefined,\n source: PdfSource | null | undefined,\n): string {\n if (fileName) {\n return fileName;\n }\n if (typeof Blob !== 'undefined' && source instanceof Blob && 'name' in source) {\n const name = (source as File).name;\n if (name) {\n return name;\n }\n }\n if (typeof source === 'string' || source instanceof URL) {\n const fromUrl = fileNameFromUrl(source.toString());\n if (fromUrl) {\n return fromUrl;\n }\n }\n return DEFAULT_FILE_NAME;\n}\n","import type { PDFDocumentProxy } from 'pdfjs-dist';\n\n/** 150 DPI: print resolution relative to PDF points (72 per inch). */\nconst PRINT_SCALE = 150 / 72;\n\n// Browsers without a blocking print() and without `afterprint` would otherwise keep the frame.\nconst PRINT_TIMEOUT_MS = 60_000;\n\n/** Options for {@link printDocument}. */\nexport interface PrintOptions {\n /** Aborts page preparation (the print dialog itself cannot be canceled). */\n signal?: AbortSignal | undefined;\n /** Called after each prepared page. */\n onProgress?: ((done: number, total: number) => void) | undefined;\n /** Render scale; default {@link PRINT_SCALE}. */\n scale?: number | undefined;\n}\n\nconst PRINT_STYLES = `\nhtml, body { margin: 0; padding: 0; height: 100%; }\n.page {\n display: flex; align-items: center; justify-content: center;\n width: 100%; height: 100%;\n break-after: page; page-break-after: always; break-inside: avoid; page-break-inside: avoid;\n}\n.page:last-child { break-after: auto; page-break-after: auto; }\nimg { display: block; max-width: 100%; max-height: 100%; }\n`;\n\nfunction canvasToBlob(canvas: HTMLCanvasElement): Promise<Blob> {\n return new Promise((resolve, reject) => {\n canvas.toBlob((blob) =>\n blob ? resolve(blob) : reject(new Error('Failed to encode a page for printing')),\n );\n });\n}\n\n/**\n * Prints a document without leaving the page: every page is rendered to an image at print\n * resolution inside a hidden iframe (one page per sheet, no margins), then the iframe's print\n * dialog opens. The iframe is removed after printing.\n */\nexport async function printDocument(\n pdf: PDFDocumentProxy,\n { signal, onProgress, scale = PRINT_SCALE }: PrintOptions = {},\n): Promise<void> {\n const hostDocument = window.document;\n const iframe = hostDocument.createElement('iframe');\n iframe.className = 'rpv-print-frame';\n iframe.title = 'Print';\n iframe.tabIndex = -1;\n iframe.setAttribute('aria-hidden', 'true');\n Object.assign(iframe.style, {\n position: 'fixed',\n right: '0',\n bottom: '0',\n width: '0',\n height: '0',\n border: '0',\n });\n hostDocument.body.append(iframe);\n\n const objectUrls: string[] = [];\n try {\n const frameWindow = iframe.contentWindow;\n const frameDocument = iframe.contentDocument;\n if (!frameWindow || !frameDocument) {\n throw new Error('The print frame is unavailable');\n }\n\n const total = pdf.numPages;\n const first = (await pdf.getPage(1)).getViewport({ scale: 1 });\n const style = frameDocument.createElement('style');\n style.textContent = `@page { size: ${first.width}pt ${first.height}pt; margin: 0; }${PRINT_STYLES}`;\n frameDocument.head.append(style);\n onProgress?.(0, total);\n\n // One named page per distinct page size, so a document of mixed sizes prints each page on a\n // sheet of its own size. Browsers without named-page support fall back to the `@page` size.\n const sheetNames = new Map<string, string>();\n const sheetNameFor = (width: number, height: number): string => {\n const key = `${Math.round(width)}x${Math.round(height)}`;\n let name = sheetNames.get(key);\n if (!name) {\n name = `rpv-sheet-${sheetNames.size}`;\n sheetNames.set(key, name);\n style.textContent += `@page ${name} { size: ${width}pt ${height}pt; margin: 0; }.${name} { page: ${name}; }`;\n }\n return name;\n };\n\n for (let pageNumber = 1; pageNumber <= total; pageNumber++) {\n signal?.throwIfAborted();\n const page = await pdf.getPage(pageNumber);\n const pageSize = page.getViewport({ scale: 1 });\n const sheetName = sheetNameFor(pageSize.width, pageSize.height);\n const viewport = page.getViewport({ scale });\n const canvas = hostDocument.createElement('canvas');\n canvas.width = Math.floor(viewport.width);\n canvas.height = Math.floor(viewport.height);\n await page.render({ canvas, viewport, intent: 'print' }).promise;\n const blob = await canvasToBlob(canvas);\n canvas.width = 0;\n canvas.height = 0;\n page.cleanup();\n\n const url = URL.createObjectURL(blob);\n objectUrls.push(url);\n const sheet = frameDocument.createElement('div');\n sheet.className = `page ${sheetName}`;\n const image = frameDocument.createElement('img');\n image.alt = '';\n image.src = url;\n sheet.append(image);\n frameDocument.body.append(sheet);\n onProgress?.(pageNumber, total);\n }\n\n await Promise.all(\n [...frameDocument.images].map((image) =>\n typeof image.decode === 'function' ? image.decode().catch(() => undefined) : undefined,\n ),\n );\n signal?.throwIfAborted();\n\n await new Promise<void>((resolve) => {\n const timer = setTimeout(resolve, PRINT_TIMEOUT_MS);\n frameWindow.addEventListener(\n 'afterprint',\n () => {\n clearTimeout(timer);\n resolve();\n },\n { once: true },\n );\n frameWindow.focus();\n frameWindow.print();\n });\n } finally {\n iframe.remove();\n objectUrls.forEach((url) => URL.revokeObjectURL(url));\n }\n}\n","import { useCallback, useEffect, useRef, useState } from 'react';\nimport { isDevelopment } from '../core/env.js';\nimport { useIsomorphicLayoutEffect } from './useIsomorphicLayoutEffect.js';\n\n/** Options for {@link useControllableState}. */\nexport interface UseControllableStateOptions<T> {\n /** The controlled value. `undefined` means uncontrolled. */\n value: T | undefined;\n /** Initial value while uncontrolled. */\n defaultValue: T | (() => T);\n /** Called with every change, in both controlled and uncontrolled mode. */\n onChange?: ((value: T) => void) | undefined;\n /** Prop name used in development warnings. */\n name?: string | undefined;\n}\n\n/** Setter returned by {@link useControllableState}; accepts a value or an updater function. */\nexport type SetControllableState<T> = (next: T | ((previous: T) => T)) => void;\n\n/**\n * The value / defaultValue / onValueChange pattern. Internal state is used while `value` is\n * `undefined`; `onChange` fires whenever the value changes. The setter is stable. Values must not\n * be functions (a function argument is treated as an updater).\n */\nexport function useControllableState<T>({\n value,\n defaultValue,\n onChange,\n name = 'value',\n}: UseControllableStateOptions<T>): readonly [T, SetControllableState<T>] {\n const [internal, setInternal] = useState<T>(defaultValue);\n const isControlled = value !== undefined;\n const current = isControlled ? value : internal;\n\n const latest = useRef({ current, isControlled, onChange });\n useIsomorphicLayoutEffect(() => {\n latest.current = { current, isControlled, onChange };\n });\n\n const wasControlled = useRef(isControlled);\n useEffect(() => {\n if (wasControlled.current !== isControlled && isDevelopment()) {\n const from = wasControlled.current ? 'controlled' : 'uncontrolled';\n const to = isControlled ? 'controlled' : 'uncontrolled';\n console.error(\n `[react-pdf-viewer] \\`${name}\\` changed from ${from} to ${to}. ` +\n 'Decide between a controlled and an uncontrolled value for the lifetime of the component.',\n );\n }\n wasControlled.current = isControlled;\n }, [isControlled, name]);\n\n const setValue = useCallback<SetControllableState<T>>((next) => {\n const state = latest.current;\n const resolved =\n typeof next === 'function' ? (next as (previous: T) => T)(state.current) : next;\n if (Object.is(resolved, state.current)) {\n return;\n }\n // Let several updates in one event compose before the next render.\n state.current = resolved;\n if (!state.isControlled) {\n setInternal(resolved);\n }\n state.onChange?.(resolved);\n }, []);\n\n return [current, setValue] as const;\n}\n","import { useEffect, useMemo, useState } from 'react';\nimport type { PDFDocumentProxy } from 'pdfjs-dist';\nimport {\n buildPageText,\n findMatches,\n isTextItem,\n normalizeQuery,\n type PageText,\n} from '../core/search.js';\n\n/** One search hit: its page and its index among that page's matches. */\nexport interface SearchMatch {\n page: number;\n index: number;\n}\n\ninterface SearchState {\n document: PDFDocumentProxy | null;\n query: string;\n matches: SearchMatch[];\n done: boolean;\n}\n\nconst DEBOUNCE_MS = 200;\n\n/** Loads (and caches) the searchable text of one page. */\nasync function loadPageText(\n pdf: PDFDocumentProxy,\n pageNumber: number,\n cache: Map<number, Promise<PageText>>,\n): Promise<PageText> {\n let text = cache.get(pageNumber);\n if (!text) {\n text = pdf\n .getPage(pageNumber)\n .then((page) => page.getTextContent())\n .then((content) => buildPageText(content.items.filter(isTextItem)));\n cache.set(pageNumber, text);\n }\n return text;\n}\n\n/**\n * Finds every match of `query` in the document, page by page (debounced; results stream in).\n */\nexport function useDocumentSearch(\n pdf: PDFDocumentProxy | null,\n query: string,\n): { matches: SearchMatch[]; searching: boolean } {\n const normalized = normalizeQuery(query);\n const cache = useMemo(() => {\n void pdf;\n return new Map<number, Promise<PageText>>();\n }, [pdf]);\n const [state, setState] = useState<SearchState>({\n document: null,\n query: '',\n matches: [],\n done: true,\n });\n\n useEffect(() => {\n if (!pdf || !normalized) return;\n let cancelled = false;\n const timer = setTimeout(() => {\n void (async () => {\n const matches: SearchMatch[] = [];\n for (let page = 1; page <= pdf.numPages; page++) {\n const text = await loadPageText(pdf, page, cache).catch(() => null);\n if (cancelled) return;\n if (text) {\n findMatches(text, normalized).forEach((_, index) => matches.push({ page, index }));\n }\n if (page % 8 === 0 || page === pdf.numPages) {\n setState({\n document: pdf,\n query: normalized,\n matches: [...matches],\n done: page === pdf.numPages,\n });\n }\n }\n })();\n }, DEBOUNCE_MS);\n return () => {\n cancelled = true;\n clearTimeout(timer);\n };\n }, [pdf, normalized, cache]);\n\n const current = state.document === pdf && state.query === normalized;\n return {\n matches: current && normalized ? state.matches : [],\n searching: Boolean(normalized) && (!current || !state.done),\n };\n}\n","import { useEffect, useState } from 'react';\n\n/** Content-box size of an element, in CSS pixels. */\nexport interface ElementSize {\n width: number;\n height: number;\n}\n\n/**\n * Tracks an element's content-box size with `ResizeObserver`. Returns a callback ref and the\n * size, which is `null` until the first measurement (and always on the server).\n */\nexport function useElementSize<T extends Element>(): [\n (node: T | null) => void,\n ElementSize | null,\n] {\n const [node, setNode] = useState<T | null>(null);\n const [size, setSize] = useState<ElementSize | null>(null);\n\n useEffect(() => {\n if (!node || typeof ResizeObserver === 'undefined') {\n return;\n }\n const observer = new ResizeObserver(([entry]) => {\n if (!entry) {\n return;\n }\n const box = entry.contentBoxSize[0];\n const width = box ? box.inlineSize : entry.contentRect.width;\n const height = box ? box.blockSize : entry.contentRect.height;\n setSize((previous) =>\n previous && previous.width === width && previous.height === height\n ? previous\n : { width, height },\n );\n });\n observer.observe(node);\n return () => observer.disconnect();\n }, [node]);\n\n return [setNode, size];\n}\n","import { useEffect, useRef, useState, useSyncExternalStore } from 'react';\nimport type { FullscreenMode } from '../types.js';\nimport { useIsomorphicLayoutEffect } from './useIsomorphicLayoutEffect.js';\n\n/** How fullscreen is currently presented. */\nexport type FullscreenPresentation = 'none' | 'layout' | 'native' | 'overlay';\n\nconst subscribeNever = () => () => undefined;\n\nfunction isNativeFullscreenSupported(): boolean {\n return (\n typeof document !== 'undefined' &&\n document.fullscreenEnabled === true &&\n typeof HTMLElement.prototype.requestFullscreen === 'function'\n );\n}\n\nconst FOCUSABLE =\n 'a[href], button:not(:disabled), input:not(:disabled), select:not(:disabled), textarea:not(:disabled), [tabindex]:not([tabindex=\"-1\"])';\n\nfunction trapFocus(event: KeyboardEvent, container: HTMLElement): void {\n // Only elements Tab can reach: roving-tabindex buttons (tabindex=-1) and hidden ones are skipped.\n const focusable = [...container.querySelectorAll<HTMLElement>(FOCUSABLE)].filter(\n (element) => element.tabIndex >= 0 && element.getClientRects().length > 0,\n );\n const first = focusable[0];\n const last = focusable.at(-1);\n const active = container.ownerDocument.activeElement;\n if (!first || !last) {\n event.preventDefault();\n return;\n }\n if (event.shiftKey && (active === first || !container.contains(active))) {\n event.preventDefault();\n last.focus();\n } else if (!event.shiftKey && (active === last || !container.contains(active))) {\n event.preventDefault();\n first.focus();\n }\n}\n\ninterface UseFullscreenOptions {\n mode: FullscreenMode;\n active: boolean;\n setActive: (active: boolean) => void;\n element: HTMLElement | null;\n}\n\n/**\n * Presents fullscreen:\n * - `controlled`: layout only, the parent decides.\n * - `native`: the Fullscreen API on `element`; leaving it (e.g. with `Esc`) reports `false`.\n * Falls back to `overlay` where element fullscreen is unavailable or refused.\n * - `overlay`: fixed full-viewport layer with a focus trap, scroll lock and `Esc` to close.\n */\nexport function useFullscreen({\n mode,\n active,\n setActive,\n element,\n}: UseFullscreenOptions): FullscreenPresentation {\n const nativeSupported = useSyncExternalStore(\n subscribeNever,\n isNativeFullscreenSupported,\n () => false,\n );\n const [nativeRefused, setNativeRefused] = useState(false);\n const setActiveRef = useRef(setActive);\n useIsomorphicLayoutEffect(() => {\n setActiveRef.current = setActive;\n });\n\n const presentation: FullscreenPresentation = !active\n ? 'none'\n : mode === 'controlled'\n ? 'layout'\n : mode === 'native' && nativeSupported && !nativeRefused\n ? 'native'\n : 'overlay';\n\n useEffect(() => {\n if (presentation !== 'native' || !element) {\n return;\n }\n const doc = element.ownerDocument;\n if (doc.fullscreenElement !== element) {\n // Refused without a user gesture, or blocked by permissions policy.\n element.requestFullscreen().catch(() => setNativeRefused(true));\n }\n const handleChange = () => {\n if (doc.fullscreenElement !== element) {\n setActiveRef.current(false);\n }\n };\n doc.addEventListener('fullscreenchange', handleChange);\n return () => {\n doc.removeEventListener('fullscreenchange', handleChange);\n if (doc.fullscreenElement === element) {\n doc.exitFullscreen().catch(() => undefined);\n }\n };\n }, [presentation, element]);\n\n // A refusal only applies to the current fullscreen session.\n if (!active && nativeRefused) {\n setNativeRefused(false);\n }\n\n useEffect(() => {\n if (presentation !== 'overlay' || !element) {\n return;\n }\n const doc = window.document;\n const previousFocus = doc.activeElement instanceof HTMLElement ? doc.activeElement : null;\n const previousOverflow = doc.body.style.overflow;\n doc.body.style.overflow = 'hidden';\n element.focus({ preventScroll: true });\n\n const handleKeyDown = (event: KeyboardEvent) => {\n if (event.key === 'Escape') {\n event.preventDefault();\n setActiveRef.current(false);\n } else if (event.key === 'Tab') {\n trapFocus(event, element);\n }\n };\n doc.addEventListener('keydown', handleKeyDown);\n return () => {\n doc.removeEventListener('keydown', handleKeyDown);\n doc.body.style.overflow = previousOverflow;\n previousFocus?.focus({ preventScroll: true });\n };\n }, [presentation, element]);\n\n return presentation;\n}\n","import { useEffect, useRef } from 'react';\nimport type { PdfViewerApi } from '../types.js';\nimport { useIsomorphicLayoutEffect } from './useIsomorphicLayoutEffect.js';\n\ntype Shortcut =\n | 'previousPage'\n | 'nextPage'\n | 'firstPage'\n | 'lastPage'\n | 'zoomIn'\n | 'zoomOut'\n | 'resetZoom'\n | 'rotateCw'\n | 'rotateCcw'\n | 'toggleFullscreen';\n\nfunction isEditable(target: EventTarget | null): boolean {\n return (\n target instanceof HTMLElement &&\n (target.isContentEditable || ['INPUT', 'TEXTAREA', 'SELECT'].includes(target.tagName))\n );\n}\n\n/** Whether `element` can still scroll horizontally in `direction`. */\nfunction canScrollX(element: HTMLElement | null, direction: -1 | 1): boolean {\n if (!element || element.scrollWidth <= element.clientWidth) {\n return false;\n }\n return direction < 0\n ? element.scrollLeft > 0\n : element.scrollLeft + element.clientWidth < element.scrollWidth - 1;\n}\n\n/** Maps a key press to a viewer shortcut, or `null`. Exported for tests. */\nexport function getShortcut(event: KeyboardEvent, viewport: HTMLElement | null): Shortcut | null {\n if (event.defaultPrevented || event.altKey || event.ctrlKey || event.metaKey) {\n return null;\n }\n if (isEditable(event.target)) {\n return null;\n }\n // Shift + navigation keys extend a text selection.\n if (event.shiftKey && /^(Arrow|Page|Home|End)/.test(event.key)) {\n return null;\n }\n // The toolbar uses arrows/Home/End for its roving focus. This native listener runs before\n // React's handler, so the toolbar cannot stop the event in time; skip those keys here.\n const inToolbar =\n event.target instanceof Element && event.target.closest('[role=\"toolbar\"]') !== null;\n if (inToolbar && ['ArrowLeft', 'ArrowRight', 'Home', 'End'].includes(event.key)) {\n return null;\n }\n switch (event.key) {\n case 'PageUp':\n return 'previousPage';\n case 'PageDown':\n return 'nextPage';\n // Arrows scroll a zoomed page first, then change pages.\n case 'ArrowLeft':\n return canScrollX(viewport, -1) ? null : 'previousPage';\n case 'ArrowRight':\n return canScrollX(viewport, 1) ? null : 'nextPage';\n case 'Home':\n return 'firstPage';\n case 'End':\n return 'lastPage';\n case '+':\n case '=':\n return 'zoomIn';\n case '-':\n case '_':\n return 'zoomOut';\n case '0':\n return 'resetZoom';\n case 'r':\n return 'rotateCw';\n case 'R':\n return 'rotateCcw';\n case 'f':\n case 'F':\n return 'toggleFullscreen';\n default:\n return null;\n }\n}\n\ninterface UseKeyboardShortcutsOptions {\n enabled: boolean;\n /** Shortcuts are active only while focus is inside this element. */\n element: HTMLElement | null;\n viewport: HTMLElement | null;\n api: PdfViewerApi;\n}\n\n/**\n * Viewer keyboard shortcuts (active while focus is inside the viewer): ←/→ and PageUp/PageDown\n * change pages, Home/End jump to the first/last page, `+`/`-` zoom, `0` resets zoom, `r`/`R`\n * rotate, `f` toggles fullscreen.\n */\nexport function useKeyboardShortcuts({\n enabled,\n element,\n viewport,\n api,\n}: UseKeyboardShortcutsOptions): void {\n const latest = useRef({ api, viewport });\n useIsomorphicLayoutEffect(() => {\n latest.current = { api, viewport };\n });\n\n useEffect(() => {\n if (!enabled || !element) {\n return;\n }\n const handleKeyDown = (event: KeyboardEvent) => {\n const { api: viewer, viewport: scroller } = latest.current;\n const shortcut = getShortcut(event, scroller);\n if (!shortcut) {\n return;\n }\n event.preventDefault();\n switch (shortcut) {\n case 'previousPage':\n viewer.previousPage();\n break;\n case 'nextPage':\n viewer.nextPage();\n break;\n case 'firstPage':\n viewer.goToPage(1);\n break;\n case 'lastPage':\n viewer.goToPage(viewer.numPages);\n break;\n case 'zoomIn':\n viewer.zoomIn();\n break;\n case 'zoomOut':\n viewer.zoomOut();\n break;\n case 'resetZoom':\n viewer.resetZoom();\n break;\n case 'rotateCw':\n viewer.rotate('cw');\n break;\n case 'rotateCcw':\n viewer.rotate('ccw');\n break;\n case 'toggleFullscreen':\n viewer.toggleFullscreen();\n break;\n }\n };\n element.addEventListener('keydown', handleKeyDown);\n return () => element.removeEventListener('keydown', handleKeyDown);\n }, [enabled, element]);\n}\n","import { useCallback, useSyncExternalStore } from 'react';\n\nconst hasMatchMedia = () =>\n typeof window !== 'undefined' && typeof window.matchMedia === 'function';\n\n/** Whether `query` matches. `false` on the server and where `matchMedia` is unavailable. */\nexport function useMediaQuery(query: string): boolean {\n const subscribe = useCallback(\n (onChange: () => void) => {\n if (!hasMatchMedia()) {\n return () => undefined;\n }\n const list = window.matchMedia(query);\n list.addEventListener('change', onChange);\n return () => list.removeEventListener('change', onChange);\n },\n [query],\n );\n const getSnapshot = () => hasMatchMedia() && window.matchMedia(query).matches;\n return useSyncExternalStore(subscribe, getSnapshot, () => false);\n}\n","import type { PdfRequestOptions, PdfSource } from '../types.js';\nimport { createPdfViewerError, isAbortError } from './errors.js';\n\n/** Result of reading a source: PDF bytes, or an HTTP error the host handled itself. */\nexport type LoadedSource =\n { readonly kind: 'bytes'; readonly data: Uint8Array } | { readonly kind: 'handled' };\n\n/** `null`, `undefined` and `''` mean \"no document\". */\nexport function isEmptySource(source: PdfSource | null | undefined): source is null | undefined {\n return source === null || source === undefined || source === '';\n}\n\nfunction isBlob(value: unknown): value is Blob {\n return (\n typeof value === 'object' &&\n value !== null &&\n typeof (value as Blob).arrayBuffer === 'function' &&\n typeof (value as Blob).size === 'number'\n );\n}\n\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n return typeof value === 'object' && value !== null;\n}\n\n/**\n * The default message logic: RFC 7807 `detail`, then `title`, then a JSON string body,\n * then `Failed to fetch PDF: {status} {statusText}`.\n */\nexport async function defaultHttpErrorMessage(response: Response): Promise<string> {\n let message = `Failed to fetch PDF: ${response.status} ${response.statusText}`;\n try {\n const body: unknown = await response.clone().json();\n if (isRecord(body) && body['detail']) {\n message = String(body['detail']);\n } else if (isRecord(body) && body['title']) {\n message = String(body['title']);\n } else if (typeof body === 'string') {\n message = body;\n }\n } catch {\n // Not JSON: keep the status message.\n }\n return message;\n}\n\nfunction combineSignals(own: AbortSignal, external: AbortSignal | null | undefined): AbortSignal {\n if (!external) {\n return own;\n }\n if (typeof AbortSignal.any === 'function') {\n return AbortSignal.any([own, external]);\n }\n // Older browsers (Safari before 17.4) have no AbortSignal.any: link the two by hand.\n const controller = new AbortController();\n const abort = (source: AbortSignal) => () => controller.abort(source.reason);\n for (const signal of [own, external]) {\n if (signal.aborted) {\n controller.abort(signal.reason);\n return controller.signal;\n }\n signal.addEventListener('abort', abort(signal), { once: true });\n }\n return controller.signal;\n}\n\nasync function fetchSource(\n url: string,\n signal: AbortSignal,\n options: PdfRequestOptions,\n): Promise<LoadedSource> {\n const init: RequestInit = {\n ...options.requestInit,\n signal: combineSignals(signal, options.requestInit?.signal),\n };\n\n let response: Response;\n try {\n response = options.fetcher ? await options.fetcher(url, init) : await fetch(url, init);\n } catch (error) {\n if (signal.aborted || isAbortError(error)) {\n throw error;\n }\n // `fetch` reports every network failure as a TypeError whose wording depends on the browser\n // (\"Failed to fetch\", \"Load failed\", …); those get the viewer's own message. Other errors come\n // from a custom fetcher and keep theirs.\n const message =\n error instanceof Error && !(error instanceof TypeError) && error.message\n ? error.message\n : undefined;\n throw createPdfViewerError('NETWORK_ERROR', message, { cause: error });\n }\n\n if (!response.ok) {\n const handled = options.onHttpError ? await options.onHttpError(response) : undefined;\n signal.throwIfAborted();\n if (handled === true) {\n return { kind: 'handled' };\n }\n const message =\n (await options.getHttpErrorMessage?.(response)) ?? (await defaultHttpErrorMessage(response));\n throw createPdfViewerError('HTTP_ERROR', message, { status: response.status });\n }\n\n const buffer = await response.arrayBuffer();\n signal.throwIfAborted();\n return { kind: 'bytes', data: new Uint8Array(buffer) };\n}\n\n/**\n * Turns any {@link PdfSource} into bytes for PDF.js.\n *\n * Binary sources are copied because PDF.js transfers (detaches) the buffer it receives; without\n * the copy a consumer's `ArrayBuffer` would become unusable after the first load.\n */\nexport async function loadSource(\n source: PdfSource,\n signal: AbortSignal,\n options: PdfRequestOptions = {},\n): Promise<LoadedSource> {\n signal.throwIfAborted();\n if (typeof source === 'string' || source instanceof URL) {\n return fetchSource(source.toString(), signal, options);\n }\n if (isBlob(source)) {\n const buffer = await source.arrayBuffer();\n signal.throwIfAborted();\n return { kind: 'bytes', data: new Uint8Array(buffer) };\n }\n if (ArrayBuffer.isView(source)) {\n const { buffer, byteOffset, byteLength } = source;\n return {\n kind: 'bytes',\n data: new Uint8Array(buffer.slice(byteOffset, byteOffset + byteLength)),\n };\n }\n return { kind: 'bytes', data: new Uint8Array(source.slice(0)) };\n}\n","import { useCallback, useEffect, useRef, useState } from 'react';\nimport type { PDFDocumentLoadingTask, PDFDocumentProxy } from 'pdfjs-dist';\nimport { isAbortError, toPdfViewerError } from '../core/errors.js';\nimport { isEmptySource, loadSource } from '../core/loadSource.js';\nimport { getDocumentDefaults, loadPdfJs } from '../core/pdfjs.js';\nimport type {\n PdfDocumentStatus,\n PdfJsDocumentOptions,\n PdfRequestOptions,\n PdfSource,\n PdfViewerError,\n} from '../types.js';\nimport { useIsomorphicLayoutEffect } from './useIsomorphicLayoutEffect.js';\n\n/** Options for {@link usePdfDocument}. Changes apply on the next load, except `password`. */\nexport interface UsePdfDocumentOptions extends PdfRequestOptions {\n /** Password for encrypted documents. Changing it reloads the document. */\n password?: string | undefined;\n /** Per-instance `getDocument` overrides. */\n pdfjsOptions?: PdfJsDocumentOptions | undefined;\n /** Called once the document is ready. */\n onLoad?: ((document: PDFDocumentProxy) => void) | undefined;\n /** Called for every load failure except aborts and handled HTTP errors. */\n onError?: ((error: PdfViewerError) => void) | undefined;\n}\n\n/** State returned by {@link usePdfDocument}. */\nexport interface UsePdfDocumentResult {\n /** `idle` (no source, or HTTP error handled by the host), `loading`, `ready` or `error`. */\n status: PdfDocumentStatus;\n /** The loaded document while `status === 'ready'`. Never a destroyed document. */\n document: PDFDocumentProxy | null;\n /** Page count, `0` without a document. */\n numPages: number;\n /** The failure while `status === 'error'`. */\n error: PdfViewerError | null;\n /** Loads the current source again (e.g. after an error). */\n reload: () => void;\n}\n\ninterface LoadState {\n source: PdfSource | null | undefined;\n password: string | undefined;\n attempt: number;\n status: PdfDocumentStatus;\n document: PDFDocumentProxy | null;\n error: PdfViewerError | null;\n}\n\n/**\n * Loads a PDF document. Every source change aborts the previous fetch, discards its result and\n * destroys the previous document; unmounting does the same.\n */\nexport function usePdfDocument(\n source: PdfSource | null | undefined,\n options: UsePdfDocumentOptions = {},\n): UsePdfDocumentResult {\n const { password } = options;\n const [attempt, setAttempt] = useState(0);\n const [state, setState] = useState<LoadState | null>(null);\n\n const optionsRef = useRef(options);\n useIsomorphicLayoutEffect(() => {\n optionsRef.current = options;\n });\n\n useEffect(() => {\n if (isEmptySource(source)) {\n return;\n }\n let disposed = false;\n let task: PDFDocumentLoadingTask | null = null;\n const controller = new AbortController();\n const commit = (next: Pick<LoadState, 'status' | 'document' | 'error'>) => {\n if (!disposed) {\n setState({ source, password, attempt, ...next });\n }\n };\n\n const load = async () => {\n const lib = await loadPdfJs();\n const loaded = await loadSource(source, controller.signal, optionsRef.current);\n if (disposed) {\n return;\n }\n if (loaded.kind === 'handled') {\n commit({ status: 'idle', document: null, error: null });\n return;\n }\n task = lib.getDocument({\n ...getDocumentDefaults(lib),\n ...optionsRef.current.pdfjsOptions,\n data: loaded.data,\n ...(password === undefined ? {} : { password }),\n });\n const document = await task.promise;\n if (disposed) {\n return;\n }\n commit({ status: 'ready', document, error: null });\n optionsRef.current.onLoad?.(document);\n };\n\n load().catch((cause: unknown) => {\n if (disposed || isAbortError(cause)) {\n return;\n }\n const error = toPdfViewerError(cause, 'UNKNOWN');\n commit({ status: 'error', document: null, error });\n optionsRef.current.onError?.(error);\n });\n\n return () => {\n disposed = true;\n controller.abort();\n // Destroying the loading task also destroys its document.\n void task?.destroy();\n };\n }, [source, password, attempt]);\n\n const reload = useCallback(() => setAttempt((value) => value + 1), []);\n\n // State belongs to the current request only; anything else is a request still in flight.\n const current =\n state !== null &&\n Object.is(state.source, source) &&\n state.password === password &&\n state.attempt === attempt\n ? state\n : null;\n const status: PdfDocumentStatus = current\n ? current.status\n : isEmptySource(source)\n ? 'idle'\n : 'loading';\n const document = current?.document ?? null;\n\n return {\n status,\n document,\n numPages: document?.numPages ?? 0,\n error: current?.error ?? null,\n reload,\n };\n}\n","import {\n forwardRef,\n useCallback,\n useEffect,\n useImperativeHandle,\n useMemo,\n useRef,\n useState,\n useSyncExternalStore,\n type ReactNode,\n} from 'react';\nimport { createPortal } from 'react-dom';\nimport type { PDFDocumentProxy } from 'pdfjs-dist';\nimport { ContinuousPages } from './components/ContinuousPages.js';\nimport { ErrorView } from './components/ErrorView.js';\nimport { LoadingView, Spinner } from './components/LoadingView.js';\nimport { PageInput } from './components/PageInput.js';\nimport { PasswordPrompt } from './components/PasswordPrompt.js';\nimport { PdfPageCanvas } from './components/PdfPageCanvas.js';\nimport { SearchBar } from './components/SearchBar.js';\nimport { Thumbnails } from './components/Thumbnails.js';\nimport { PdfToolbar } from './components/Toolbar.js';\nimport { saveBytes, toPdfBlob } from './core/download.js';\nimport { isAbortError, toPdfViewerError } from './core/errors.js';\nimport { resolveFileName } from './core/fileName.js';\nimport { clampPage, normalizeRotation, type FitOptions } from './core/geometry.js';\nimport { printDocument } from './core/print.js';\nimport {\n DEFAULT_MAX_SCALE,\n DEFAULT_MIN_SCALE,\n DEFAULT_SCALE,\n DEFAULT_SCALE_STEP,\n nextScale,\n normalizeScale,\n scalesEqual,\n type ZoomOptions,\n} from './core/scale.js';\nimport { useControllableState } from './hooks/useControllableState.js';\nimport { useDocumentSearch } from './hooks/useDocumentSearch.js';\nimport { useElementSize } from './hooks/useElementSize.js';\nimport { useFullscreen } from './hooks/useFullscreen.js';\nimport { useIsomorphicLayoutEffect } from './hooks/useIsomorphicLayoutEffect.js';\nimport { useKeyboardShortcuts } from './hooks/useKeyboardShortcuts.js';\nimport { useMediaQuery } from './hooks/useMediaQuery.js';\nimport type { PageHighlight, PageRenderInfo } from './hooks/usePageRenderer.js';\nimport { usePdfDocument } from './hooks/usePdfDocument.js';\nimport { useLabelContext, useLabels } from './labels.js';\nimport type { PdfSource, PdfViewerApi, PdfViewerError, PdfViewerProps, Rotation } from './types.js';\n\nconst subscribeNever = () => () => undefined;\n\n/** Where the pointer was over a page when wheel/pinch zoom started. */\ninterface ZoomAnchor {\n page: number;\n fx: number;\n fy: number;\n clientX: number;\n clientY: number;\n}\n\n/** The source as an absolute http(s) URL, or `null` for anything a new tab should not open. */\nfunction webUrl(source: PdfSource | null | undefined): string | null {\n if (typeof source !== 'string' && !(source instanceof URL)) return null;\n try {\n const url = new URL(source.toString(), window.location.href);\n return url.protocol === 'http:' || url.protocol === 'https:' ? url.href : null;\n } catch {\n return null;\n }\n}\n\n/**\n * Opens the document in a new tab. A plain web address opens as is; anything else, including a\n * URL loaded through a custom `fetcher` or with `requestInit` (a new tab would not send its\n * headers), opens the bytes already loaded.\n */\nasync function openInNewTab(\n pdf: PDFDocumentProxy,\n source: PdfSource | null | undefined,\n direct: boolean,\n) {\n const address = direct ? webUrl(source) : null;\n if (address) {\n window.open(address, '_blank', 'noopener,noreferrer');\n return;\n }\n const url = URL.createObjectURL(toPdfBlob(await pdf.getData()));\n window.open(url, '_blank', 'noopener,noreferrer');\n setTimeout(() => URL.revokeObjectURL(url), 60_000);\n}\n\n/** Scrolls `element` into the middle of `scroller` if it is not fully visible. */\nfunction revealWithin(scroller: HTMLElement, element: HTMLElement) {\n const box = element.getBoundingClientRect();\n const view = scroller.getBoundingClientRect();\n if (box.top < view.top || box.bottom > view.bottom) {\n scroller.scrollTop += box.top - view.top - (view.height - box.height) / 2;\n }\n if (box.left < view.left || box.right > view.right) {\n scroller.scrollLeft += box.left - view.left - (view.width - box.width) / 2;\n }\n}\n\n/**\n * A PDF viewer: one page at a time with a toolbar for zoom, navigation, fullscreen, rotation,\n * download and print. Default props give a classic single-page layout; every\n * additional feature (text layer, links, continuous layout, thumbnails, search, …) is opt-in.\n *\n * @example\n * ```tsx\n * import { PdfViewer } from '@kingtech/react-pdf-viewer';\n * import '@kingtech/react-pdf-viewer/styles.css';\n *\n * <PdfViewer source=\"/files/document.pdf\" fileName=\"document.pdf\" />\n * ```\n *\n * @cssClass rpv-root The root element. Add `rpv-theme-dark`, or `rpv-theme-auto` to follow the operating system, for the dark preset.\n * @cssAttribute data-status Document status: `idle`, `loading`, `ready` or `error`.\n * @cssAttribute data-layout The `layout` prop: `single` or `continuous`.\n * @cssAttribute data-compact Present while the viewport is narrower than `compactBreakpoint`.\n * @cssAttribute data-fullscreen Present in fullscreen, in any mode.\n * @cssAttribute data-presentation How fullscreen is presented: `layout` (controlled mode), `native` or `overlay`.\n * @cssAttribute data-zoomed Present while the scale is above `defaultScale`.\n */\nexport const PdfViewer = forwardRef<PdfViewerApi, PdfViewerProps>(function PdfViewer(props, ref) {\n const {\n source,\n fileName,\n page: pageProp,\n defaultPage = 1,\n onPageChange,\n scale: scaleProp,\n defaultScale = DEFAULT_SCALE,\n onScaleChange,\n rotation: rotationProp,\n defaultRotation = 0,\n onRotationChange,\n fullscreen: fullscreenProp,\n defaultFullscreen = false,\n onFullscreenChange,\n fullscreenMode: fullscreenModeProp,\n minScale = DEFAULT_MIN_SCALE,\n maxScale = DEFAULT_MAX_SCALE,\n scaleStep = DEFAULT_SCALE_STEP,\n zoomLevels,\n fitWidthAtDefaultScale = true,\n fitMode = 'none',\n requestInit,\n fetcher,\n onHttpError,\n getHttpErrorMessage,\n password: passwordProp,\n pdfjsOptions,\n layout = 'single',\n textLayer = false,\n annotationLayer = false,\n pageInput = false,\n zoomReset = false,\n wheelZoom = false,\n passwordPrompt = false,\n renderPasswordPrompt,\n thumbnails = false,\n search = false,\n toolbar = true,\n compactBreakpoint = 960,\n keyboardShortcuts = true,\n printMode = 'render',\n maxCanvasPixels,\n labels: labelOverrides,\n locale,\n renderLoading,\n renderError,\n renderToolbar,\n renderEmpty,\n onDocumentLoad,\n onPageRender,\n onError,\n onDownload,\n onPrint,\n className,\n style,\n id,\n 'aria-label': ariaLabel,\n } = props;\n\n const labels = useLabels(labelOverrides);\n const labelContext = useLabelContext(locale);\n const zoom = useMemo<ZoomOptions>(\n () => ({ minScale, maxScale, scaleStep, zoomLevels }),\n [minScale, maxScale, scaleStep, zoomLevels],\n );\n const continuous = layout === 'continuous';\n const showTextLayer = textLayer || search;\n\n // ── State ────────────────────────────────────────────────────────────────\n const [page, setPage] = useControllableState({\n value: pageProp,\n defaultValue: defaultPage,\n onChange: onPageChange,\n name: 'page',\n });\n const [scale, setScaleState] = useControllableState({\n value: scaleProp,\n defaultValue: defaultScale,\n onChange: onScaleChange,\n name: 'scale',\n });\n const [rotation, setRotation] = useControllableState<Rotation>({\n value: rotationProp,\n defaultValue: defaultRotation,\n onChange: onRotationChange,\n name: 'rotation',\n });\n const [fullscreen, setFullscreen] = useControllableState({\n value: fullscreenProp,\n defaultValue: defaultFullscreen,\n onChange: onFullscreenChange,\n name: 'fullscreen',\n });\n const fullscreenMode =\n fullscreenModeProp ?? (fullscreenProp === undefined ? 'native' : 'controlled');\n\n const callbacks = useRef({ onDownload, onPrint, onError, onDocumentLoad, onPageRender });\n useIsomorphicLayoutEffect(() => {\n callbacks.current = { onDownload, onPrint, onError, onDocumentLoad, onPageRender };\n });\n\n // ── Document ─────────────────────────────────────────────────────────────\n // A password typed into the prompt applies to the source it was typed for.\n const [entered, setEntered] = useState<{\n source: PdfSource | null | undefined;\n password: string;\n } | null>(null);\n const password =\n passwordProp ?? (entered && Object.is(entered.source, source) ? entered.password : undefined);\n\n const handleLoad = useCallback((pdf: PDFDocumentProxy) => {\n callbacks.current.onDocumentLoad?.({\n numPages: pdf.numPages,\n fingerprint: pdf.fingerprints[0] ?? '',\n });\n }, []);\n const handleError = useCallback((error: PdfViewerError) => {\n callbacks.current.onError?.(error);\n }, []);\n const {\n status,\n document: pdfDocument,\n numPages,\n error,\n reload,\n } = usePdfDocument(source, {\n requestInit,\n fetcher,\n onHttpError,\n getHttpErrorMessage,\n password,\n pdfjsOptions,\n onLoad: handleLoad,\n onError: handleError,\n });\n\n // A new source opens on `defaultPage`; an out-of-range page is clamped and reported.\n const isPageControlled = pageProp !== undefined;\n const handledDocument = useRef<{\n document: PDFDocumentProxy;\n source: PdfSource | null | undefined;\n } | null>(null);\n useIsomorphicLayoutEffect(() => {\n if (!pdfDocument) {\n return;\n }\n const previous = handledDocument.current;\n if (previous?.document !== pdfDocument) {\n handledDocument.current = { document: pdfDocument, source };\n if (previous && !Object.is(previous.source, source) && !isPageControlled) {\n setPage(clampPage(defaultPage, pdfDocument.numPages));\n return;\n }\n }\n const clamped = clampPage(page, pdfDocument.numPages);\n if (clamped !== page) {\n setPage(clamped);\n }\n }, [pdfDocument, source, page, defaultPage, isPageControlled, setPage]);\n\n const displayPage = pdfDocument ? clampPage(page, numPages) : page;\n const canZoomIn = nextScale(scale, 1, zoom) !== null;\n const canZoomOut = nextScale(scale, -1, zoom) !== null;\n\n // ── Layout ───────────────────────────────────────────────────────────────\n const compact = useMediaQuery(`(max-width: ${compactBreakpoint - 0.05}px)`);\n const [rootElement, setRootElement] = useState<HTMLElement | null>(null);\n const [measureViewport, viewportSize] = useElementSize<HTMLDivElement>();\n const [viewportElement, setViewportElement] = useState<HTMLDivElement | null>(null);\n const viewportRef = useCallback(\n (node: HTMLDivElement | null) => {\n measureViewport(node);\n setViewportElement(node);\n },\n [measureViewport],\n );\n const presentation = useFullscreen({\n mode: fullscreenMode,\n active: fullscreen,\n setActive: setFullscreen,\n element: rootElement,\n });\n const isClient = useSyncExternalStore(\n subscribeNever,\n () => true,\n () => false,\n );\n\n let fit: FitOptions | undefined;\n if (viewportSize && scalesEqual(scale, defaultScale)) {\n if (fitMode === 'width') {\n fit = { width: viewportSize.width, upscale: true };\n } else if (fitMode === 'page') {\n fit = { width: viewportSize.width, height: viewportSize.height, upscale: true };\n } else if (fitWidthAtDefaultScale) {\n fit = { width: viewportSize.width };\n }\n }\n\n // ── Actions ──────────────────────────────────────────────────────────────\n const goToPage = useCallback(\n (target: number) => {\n if (numPages > 0) {\n setPage(clampPage(target, numPages));\n }\n },\n [numPages, setPage],\n );\n const nextPage = useCallback(\n () => setPage((current) => (numPages > 0 ? clampPage(current + 1, numPages) : current)),\n [numPages, setPage],\n );\n const previousPage = useCallback(\n () => setPage((current) => (numPages > 0 ? clampPage(current - 1, numPages) : current)),\n [numPages, setPage],\n );\n const zoomIn = useCallback(\n () => setScaleState((current) => nextScale(current, 1, zoom) ?? current),\n [zoom, setScaleState],\n );\n const zoomOut = useCallback(\n () => setScaleState((current) => nextScale(current, -1, zoom) ?? current),\n [zoom, setScaleState],\n );\n const setScale = useCallback(\n (value: number) => {\n // NaN or Infinity would reach the renderer and fail the page.\n if (Number.isFinite(value)) setScaleState(normalizeScale(value, zoom));\n },\n [zoom, setScaleState],\n );\n const resetZoom = useCallback(() => setScaleState(defaultScale), [defaultScale, setScaleState]);\n const rotate = useCallback(\n (direction: 'cw' | 'ccw' = 'cw') =>\n setRotation((current) => normalizeRotation(current + (direction === 'ccw' ? -90 : 90))),\n [setRotation],\n );\n const toggleFullscreen = useCallback(() => setFullscreen((current) => !current), [setFullscreen]);\n\n const download = useCallback(async () => {\n if (!pdfDocument) {\n return;\n }\n try {\n const data = await pdfDocument.getData();\n const name = resolveFileName(fileName, source);\n if (callbacks.current.onDownload?.({ fileName: name, data }) === false) {\n return;\n }\n saveBytes(data, name);\n } catch (cause) {\n callbacks.current.onError?.(toPdfViewerError(cause, 'DOWNLOAD_FAILED'));\n }\n }, [pdfDocument, fileName, source]);\n\n const [printProgress, setPrintProgress] = useState<{ done: number; total: number } | null>(null);\n const printController = useRef<AbortController | null>(null);\n const print = useCallback(async () => {\n if (!pdfDocument || printController.current) {\n return;\n }\n if (callbacks.current.onPrint?.() === false) {\n return;\n }\n try {\n if (printMode === 'open-url') {\n await openInNewTab(pdfDocument, source, !fetcher && !requestInit);\n return;\n }\n const controller = new AbortController();\n printController.current = controller;\n setPrintProgress({ done: 0, total: pdfDocument.numPages });\n await printDocument(pdfDocument, {\n signal: controller.signal,\n onProgress: (done, total) => setPrintProgress({ done, total }),\n });\n } catch (cause) {\n if (!isAbortError(cause)) {\n callbacks.current.onError?.(toPdfViewerError(cause, 'PRINT_FAILED'));\n }\n } finally {\n printController.current = null;\n setPrintProgress(null);\n }\n }, [pdfDocument, printMode, source, fetcher, requestInit]);\n const cancelPrint = useCallback(() => printController.current?.abort(), []);\n useEffect(() => () => printController.current?.abort(), []);\n\n const api = useMemo<PdfViewerApi>(\n () => ({\n status,\n numPages,\n page: displayPage,\n scale,\n rotation,\n fullscreen,\n canZoomIn,\n canZoomOut,\n goToPage,\n nextPage,\n previousPage,\n zoomIn,\n zoomOut,\n setScale,\n resetZoom,\n rotate,\n toggleFullscreen,\n download,\n print,\n reload,\n getDocument: () => pdfDocument,\n }),\n [\n status,\n numPages,\n displayPage,\n scale,\n rotation,\n fullscreen,\n canZoomIn,\n canZoomOut,\n goToPage,\n nextPage,\n previousPage,\n zoomIn,\n zoomOut,\n setScale,\n resetZoom,\n rotate,\n toggleFullscreen,\n download,\n print,\n reload,\n pdfDocument,\n ],\n );\n useImperativeHandle(ref, () => api, [api]);\n useKeyboardShortcuts({\n enabled: keyboardShortcuts,\n element: rootElement,\n viewport: viewportElement,\n api,\n });\n\n // ── Search ───────────────────────────────────────────────────────────────\n const searchInputRef = useRef<HTMLInputElement>(null);\n const [searchQuery, setSearchQuery] = useState('');\n const [matchState, setMatchState] = useState<{\n query: string;\n index: number | null;\n fromPage: number;\n }>({ query: '', index: null, fromPage: 1 });\n if (matchState.query !== searchQuery) {\n // A new query starts at the first match on or after the current page.\n setMatchState({ query: searchQuery, index: null, fromPage: displayPage });\n }\n const { matches, searching } = useDocumentSearch(search ? pdfDocument : null, searchQuery);\n const autoIndex = Math.max(\n 0,\n matches.findIndex((match) => match.page >= matchState.fromPage),\n );\n const matchIndex =\n matches.length === 0 ? 0 : Math.min(matchState.index ?? autoIndex, matches.length - 1);\n const activeMatch = matches[matchIndex];\n const stepMatch = useCallback(\n (direction: 1 | -1) => {\n if (matches.length === 0) return;\n setMatchState((current) => ({\n ...current,\n index: (matchIndex + direction + matches.length) % matches.length,\n }));\n },\n [matches.length, matchIndex],\n );\n const activeMatchPage = activeMatch?.page;\n useEffect(() => {\n if (activeMatchPage !== undefined) goToPage(activeMatchPage);\n }, [activeMatchPage, matchIndex, searchQuery, goToPage]);\n\n const highlightFor = useCallback(\n (pageNumber: number): PageHighlight | undefined =>\n search && searchQuery.trim()\n ? {\n query: searchQuery,\n selected: activeMatch?.page === pageNumber ? activeMatch.index : null,\n }\n : undefined,\n [search, searchQuery, activeMatch],\n );\n const revealHighlight = useCallback(\n (element: HTMLElement) => {\n if (viewportElement) revealWithin(viewportElement, element);\n },\n [viewportElement],\n );\n\n // Ctrl/⌘ + F focuses the search field while focus is inside the viewer.\n useEffect(() => {\n if (!search || !rootElement) return;\n const handleKeyDown = (event: KeyboardEvent) => {\n if ((event.ctrlKey || event.metaKey) && event.key.toLowerCase() === 'f') {\n event.preventDefault();\n searchInputRef.current?.focus();\n searchInputRef.current?.select();\n }\n };\n rootElement.addEventListener('keydown', handleKeyDown);\n return () => rootElement.removeEventListener('keydown', handleKeyDown);\n }, [search, rootElement]);\n\n // ── Wheel / pinch zoom ───────────────────────────────────────────────────\n const zoomAnchor = useRef<ZoomAnchor | null>(null);\n const latestView = useRef({ scale, zoom, displayPage });\n useIsomorphicLayoutEffect(() => {\n latestView.current = { scale, zoom, displayPage };\n });\n useEffect(() => {\n if (!wheelZoom || !viewportElement) return;\n let clearTimer: ReturnType<typeof setTimeout> | undefined;\n let gestureStart = 1;\n\n const anchorAt = (target: EventTarget | null, clientX: number, clientY: number) => {\n const pageElement =\n (target instanceof Element ? target.closest<HTMLElement>('.rpv-page') : null) ??\n viewportElement.querySelector<HTMLElement>('.rpv-page');\n if (!pageElement) {\n zoomAnchor.current = null;\n return;\n }\n const box = pageElement.getBoundingClientRect();\n const slot = pageElement.closest<HTMLElement>('.rpv-page-slot');\n zoomAnchor.current = {\n page: slot ? Number(slot.dataset['page']) : latestView.current.displayPage,\n fx: box.width ? (clientX - box.left) / box.width : 0,\n fy: box.height ? (clientY - box.top) / box.height : 0,\n clientX,\n clientY,\n };\n clearTimeout(clearTimer);\n clearTimer = setTimeout(() => {\n zoomAnchor.current = null;\n }, 1500);\n };\n\n // Ctrl/⌘ + wheel, which is also what trackpad pinch produces in Chromium and Firefox.\n const handleWheel = (event: WheelEvent) => {\n if (!(event.ctrlKey || event.metaKey)) return;\n event.preventDefault();\n anchorAt(event.target, event.clientX, event.clientY);\n const factor = Math.exp(-event.deltaY * (event.deltaMode === 1 ? 0.05 : 0.002));\n setScaleState((current) => normalizeScale(current * factor, latestView.current.zoom));\n };\n // Safari reports trackpad pinch as gesture events.\n const handleGestureStart = (event: Event) => {\n event.preventDefault();\n gestureStart = latestView.current.scale;\n };\n const handleGestureChange = (event: Event) => {\n event.preventDefault();\n const gesture = event as Event & { scale?: number; clientX?: number; clientY?: number };\n anchorAt(event.target, gesture.clientX ?? 0, gesture.clientY ?? 0);\n setScaleState(normalizeScale(gestureStart * (gesture.scale ?? 1), latestView.current.zoom));\n };\n\n viewportElement.addEventListener('wheel', handleWheel, { passive: false });\n viewportElement.addEventListener('gesturestart', handleGestureStart);\n viewportElement.addEventListener('gesturechange', handleGestureChange);\n return () => {\n clearTimeout(clearTimer);\n viewportElement.removeEventListener('wheel', handleWheel);\n viewportElement.removeEventListener('gesturestart', handleGestureStart);\n viewportElement.removeEventListener('gesturechange', handleGestureChange);\n };\n }, [wheelZoom, viewportElement, setScaleState]);\n\n // After a zoomed render, keep the point that was under the pointer under the pointer.\n const handleRender = useCallback(\n (info: PageRenderInfo) => {\n callbacks.current.onPageRender?.(info);\n const anchor = zoomAnchor.current;\n if (!anchor || anchor.page !== info.page || !viewportElement) return;\n const pageElement = continuous\n ? viewportElement.querySelector(`.rpv-page-slot[data-page=\"${info.page}\"] > .rpv-page`)\n : viewportElement.querySelector('.rpv-page');\n if (!(pageElement instanceof HTMLElement)) return;\n const box = pageElement.getBoundingClientRect();\n viewportElement.scrollLeft += box.left + anchor.fx * box.width - anchor.clientX;\n viewportElement.scrollTop += box.top + anchor.fy * box.height - anchor.clientY;\n },\n [continuous, viewportElement],\n );\n\n // ── Render ───────────────────────────────────────────────────────────────\n const toolbarConfig = typeof toolbar === 'object' ? toolbar : undefined;\n const toolbarPosition = toolbarConfig?.position ?? 'bottom';\n const toolbarNode: ReactNode =\n toolbar === false ? null : (\n <div className=\"rpv-toolbar-wrapper\">\n {renderToolbar ? (\n renderToolbar(api)\n ) : (\n <PdfToolbar\n api={api}\n labels={labels}\n config={toolbarConfig}\n compact={compact}\n locale={locale}\n zoomReset={zoomReset}\n menuPlacement={toolbarPosition === 'top' ? 'bottom' : 'top'}\n pageIndicator={\n pageInput ? (\n <PageInput\n page={displayPage}\n numPages={numPages}\n label={labels.pageInput}\n context={labelContext}\n onCommit={goToPage}\n />\n ) : undefined\n }\n />\n )}\n </div>\n );\n\n const renderPageError = useCallback(\n (pageError: PdfViewerError, actions: { retry: () => void }) =>\n renderError ? (\n renderError(pageError, actions)\n ) : (\n <ErrorView\n variant=\"page\"\n message={pageError.message}\n retryLabel={labels.retry}\n onRetry={actions.retry}\n />\n ),\n [renderError, labels.retry],\n );\n\n const renderContinuousPage = useCallback(\n (pageNumber: number, pageScale: number) =>\n pdfDocument ? (\n <PdfPageCanvas\n document={pdfDocument}\n page={pageNumber}\n scale={pageScale}\n rotation={rotation}\n maxCanvasPixels={maxCanvasPixels}\n textLayer={showTextLayer}\n annotationLayer={annotationLayer}\n highlight={highlightFor(pageNumber)}\n aria-label={labels.pageAriaLabel(pageNumber, numPages, labelContext)}\n renderError={renderPageError}\n onRender={handleRender}\n onError={handleError}\n onLinkNavigate={goToPage}\n onHighlight={revealHighlight}\n />\n ) : null,\n [\n pdfDocument,\n rotation,\n maxCanvasPixels,\n showTextLayer,\n annotationLayer,\n highlightFor,\n labels,\n numPages,\n labelContext,\n renderPageError,\n handleRender,\n handleError,\n goToPage,\n revealHighlight,\n ],\n );\n\n const passwordNeeded =\n passwordPrompt && (error?.code === 'PASSWORD_REQUIRED' || error?.code === 'INCORRECT_PASSWORD');\n const submitPassword = useCallback(\n (value: string) => {\n if (entered && Object.is(entered.source, source) && entered.password === value) {\n reload();\n } else {\n setEntered({ source, password: value });\n }\n },\n [entered, source, reload],\n );\n\n let main: ReactNode;\n if (status === 'error' && error) {\n main = (\n <div className=\"rpv-error-area\">\n {passwordNeeded ? (\n renderPasswordPrompt ? (\n renderPasswordPrompt({\n incorrect: error.code === 'INCORRECT_PASSWORD',\n submit: submitPassword,\n })\n ) : (\n <div className=\"rpv-password-area\">\n <PasswordPrompt\n labels={labels}\n incorrect={error.code === 'INCORRECT_PASSWORD'}\n onSubmit={submitPassword}\n />\n </div>\n )\n ) : renderError ? (\n renderError(error, { retry: reload })\n ) : (\n <ErrorView message={error.message} retryLabel={labels.retry} onRetry={reload} />\n )}\n </div>\n );\n } else {\n main = (\n <div\n ref={viewportRef}\n className=\"rpv-viewport\"\n role=\"group\"\n aria-label={labels.document}\n // Scrollable regions must be keyboard-focusable (WCAG 2.1.1).\n // eslint-disable-next-line jsx-a11y-x/no-noninteractive-tabindex\n tabIndex={0}\n >\n {status === 'loading' &&\n (renderLoading ? renderLoading() : <LoadingView label={labels.loading} />)}\n {status === 'idle' &&\n (renderEmpty ? renderEmpty() : <p className=\"rpv-sr-only\">{labels.empty}</p>)}\n {pdfDocument &&\n (continuous ? (\n <ContinuousPages\n document={pdfDocument}\n numPages={numPages}\n page={displayPage}\n onVisiblePageChange={goToPage}\n scale={scale}\n rotation={rotation}\n fit={fit}\n scroller={viewportElement}\n renderPage={renderContinuousPage}\n />\n ) : (\n <PdfPageCanvas\n document={pdfDocument}\n page={displayPage}\n scale={scale}\n rotation={rotation}\n fit={fit}\n maxCanvasPixels={maxCanvasPixels}\n textLayer={showTextLayer}\n annotationLayer={annotationLayer}\n highlight={highlightFor(displayPage)}\n aria-label={labels.pageAriaLabel(displayPage, numPages, labelContext)}\n renderError={renderPageError}\n onRender={handleRender}\n onError={handleError}\n onLinkNavigate={goToPage}\n onHighlight={revealHighlight}\n />\n ))}\n </div>\n );\n }\n\n const showThumbnails =\n thumbnails && pdfDocument !== null && !(compact && presentation === 'none');\n const body: ReactNode = showThumbnails ? (\n <div className=\"rpv-body\">\n <Thumbnails\n document={pdfDocument}\n numPages={numPages}\n page={displayPage}\n rotation={rotation}\n onSelect={goToPage}\n labels={labels}\n context={labelContext}\n />\n {main}\n </div>\n ) : (\n main\n );\n\n const overlay = presentation === 'overlay';\n const content = (\n <section\n ref={setRootElement}\n id={id}\n className={className ? `rpv-root ${className}` : 'rpv-root'}\n style={style}\n aria-label={ariaLabel ?? labels.viewer}\n role={overlay ? 'dialog' : undefined}\n aria-modal={overlay ? true : undefined}\n tabIndex={-1}\n data-status={status}\n data-layout={layout}\n data-compact={compact ? '' : undefined}\n data-fullscreen={presentation === 'none' ? undefined : ''}\n data-presentation={presentation === 'none' ? undefined : presentation}\n data-zoomed={scale > defaultScale && !scalesEqual(scale, defaultScale) ? '' : undefined}\n data-toolbar-position={toolbarPosition}\n >\n {toolbarPosition === 'top' && toolbarNode}\n {search && (\n <SearchBar\n inputRef={searchInputRef}\n query={searchQuery}\n onQueryChange={setSearchQuery}\n total={matches.length}\n current={matchIndex}\n searching={searching}\n onNext={() => stepMatch(1)}\n onPrevious={() => stepMatch(-1)}\n labels={labels}\n context={labelContext}\n />\n )}\n {body}\n {toolbarPosition === 'bottom' && toolbarNode}\n {printProgress && (\n <div className=\"rpv-print-status\" role=\"status\">\n <Spinner />\n <p className=\"rpv-print-status__text\">\n {labels.printProgress(printProgress.done, printProgress.total, labelContext)}\n </p>\n <button type=\"button\" className=\"rpv-text-button\" onClick={cancelPrint}>\n {labels.cancel}\n </button>\n </div>\n )}\n </section>\n );\n\n return overlay && isClient ? createPortal(content, window.document.body) : content;\n});\n"],"mappings":"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"}
@@ -0,0 +1,64 @@
1
+ /** Helpers passed to label functions. */
2
+ export interface LabelContext {
3
+ /** Formats an integer for the viewer's `locale` (no grouping separators). */
4
+ formatNumber: (value: number) => string;
5
+ }
6
+ /**
7
+ * Every user-visible string and accessible name. Defaults are English; override any subset
8
+ * through the `labels` prop.
9
+ */
10
+ export interface PdfViewerLabels {
11
+ /** Accessible name of the viewer region. */
12
+ viewer: string;
13
+ /** Accessible name of the toolbar. */
14
+ toolbar: string;
15
+ /** Accessible name of the scrollable document area. */
16
+ document: string;
17
+ zoomOut: string;
18
+ zoomIn: string;
19
+ /** Zoom label text, e.g. `100%`. */
20
+ zoomLevel: (percent: number, context: LabelContext) => string;
21
+ /** Accessible name of the reset-zoom action. */
22
+ resetZoom: string;
23
+ previousPage: string;
24
+ nextPage: string;
25
+ /** Page label text, e.g. `1 / 3`. */
26
+ pageIndicator: (page: number, total: number, context: LabelContext) => string;
27
+ /** Accessible name of the page image, e.g. `Page 1 of 3`. */
28
+ pageAriaLabel: (page: number, total: number, context: LabelContext) => string;
29
+ /** Accessible name of the page-number input. */
30
+ pageInput: string;
31
+ enterFullscreen: string;
32
+ exitFullscreen: string;
33
+ rotate: string;
34
+ download: string;
35
+ print: string;
36
+ /** Accessible name of the overflow menu button ("⋮") shown when the toolbar is too narrow. */
37
+ moreActions: string;
38
+ loading: string;
39
+ retry: string;
40
+ /** Announced when there is no document. */
41
+ empty: string;
42
+ /** Print preparation status, e.g. `Preparing document for printing… 3 / 40`. */
43
+ printProgress: (done: number, total: number, context: LabelContext) => string;
44
+ cancel: string;
45
+ passwordPrompt: string;
46
+ passwordLabel: string;
47
+ passwordSubmit: string;
48
+ passwordIncorrect: string;
49
+ /** Accessible name of the thumbnails sidebar. */
50
+ thumbnails: string;
51
+ /** Accessible name of the search field. */
52
+ search: string;
53
+ /** Search result status, e.g. `2 of 5`. */
54
+ searchResults: (current: number, total: number, context: LabelContext) => string;
55
+ searchPrevious: string;
56
+ searchNext: string;
57
+ searchNoResults: string;
58
+ }
59
+ /** The English defaults. */
60
+ export declare const defaultLabels: PdfViewerLabels;
61
+ /** Label context for a locale (memoised). */
62
+ export declare function useLabelContext(locale: string | undefined): LabelContext;
63
+ /** Merges partial overrides onto the defaults (memoised on the overrides' identity). */
64
+ export declare function useLabels(overrides: Partial<PdfViewerLabels> | undefined): PdfViewerLabels;