import React, {
useCallback,
useEffect,
useMemo,
useRef,
useState,
} from "react";
import { Document, pdfjs } from "react-pdf";
import { FilePdf } from "@phosphor-icons/react";
import { api } from "./api.js";
import { Spinner } from "./ui.jsx";
import { useContinuousPdf } from "./pdf/useContinuousPdf.js";
import { PdfSheet } from "./pdf/PdfSheet.jsx";
import { PdfToolbar } from "./pdf/PdfToolbar.jsx";
import { BookSearchDialog } from "./pdf/BookSearchDialog.jsx";
import { readPdfOutline } from "./pdf/outline.js";
import "react-pdf/dist/Page/TextLayer.css";
import "react-pdf/dist/Page/AnnotationLayer.css";
pdfjs.GlobalWorkerOptions.workerSrc = new URL(
"pdfjs-dist/build/pdf.worker.min.mjs",
import.meta.url,
).toString();
const pdfOptions = {
cMapUrl: "/pdf-assets/cmaps/",
cMapPacked: true,
standardFontDataUrl: "/pdf-assets/standard_fonts/",
// Bundled fallback fonts keep base-14 PDFs consistent across local platforms.
useSystemFonts: false,
wasmUrl: "/pdf-assets/wasm/",
disableAutoFetch: true,
disableStream: true,
rangeChunkSize: 128 * 1024,
};
const EMPTY_HIGHLIGHTS = [];
export function PdfReader({
material,
highlights,
page,
navigationToken,
onPage,
onVisiblePage,
onSelection,
onContext,
onOutline,
notify,
screenshotRef,
}) {
const viewer = useContinuousPdf({
material,
page,
navigationToken,
onVisiblePage,
notify,
screenshotRef,
});
const [search, setSearch] = useState(false);
const alive = useRef(true);
useEffect(() => {
alive.current = true;
return () => {
alive.current = false;
};
}, []);
const pageHighlights = useMemo(() => {
const byPage = new Map();
for (const highlight of highlights) {
if (!byPage.has(highlight.page)) byPage.set(highlight.page, []);
byPage.get(highlight.page).push(highlight);
}
return byPage;
}, [highlights]);
const loaded = useCallback(
async (pdf) => {
try {
await viewer.loadDocument(pdf);
const outline = await readPdfOutline(pdf);
if (alive.current) onOutline(outline);
} catch (error) {
if (alive.current) notify(error.message, "error");
}
},
[viewer.loadDocument, onOutline, notify],
);
const pages = [];
for (
let number = viewer.windowRange.start;
number <= viewer.windowRange.end;
number++
) {
pages.push(