pdfjs-reader-core 0.5.11 → 0.5.12

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.
package/dist/index.js CHANGED
@@ -1902,8 +1902,10 @@ function getRenderConfig(quality = "auto", capabilities) {
1902
1902
  switch (quality) {
1903
1903
  case "low":
1904
1904
  return {
1905
- canvasScaleFactor: Math.min(1, caps.devicePixelRatio * 0.5),
1906
- maxCanvasDimension: 2048,
1905
+ canvasScaleFactor: caps.devicePixelRatio,
1906
+ // 3072² ≈ 9 MP — fits a full-DPR US Letter (DPR=3 → 1836×2376) at
1907
+ // default scale and caps at deep zoom on memory-constrained iPhones.
1908
+ maxCanvasDimension: 3072,
1907
1909
  overscanPages: 1,
1908
1910
  maxPagesInMemory: 3,
1909
1911
  scrollDebounceMs: 100,
@@ -1916,7 +1918,8 @@ function getRenderConfig(quality = "auto", capabilities) {
1916
1918
  };
1917
1919
  case "medium":
1918
1920
  return {
1919
- canvasScaleFactor: Math.min(1.5, caps.devicePixelRatio * 0.75),
1921
+ canvasScaleFactor: caps.devicePixelRatio,
1922
+ // 4096² ≈ 16 MP — within iOS Safari per-canvas budget across versions.
1920
1923
  maxCanvasDimension: 4096,
1921
1924
  overscanPages: 2,
1922
1925
  maxPagesInMemory: 5,
@@ -5190,9 +5193,37 @@ var init_ThumbnailPanel = __esm({
5190
5193
  onClick,
5191
5194
  scale
5192
5195
  }) {
5196
+ const buttonRef = useRef7(null);
5193
5197
  const canvasRef = useRef7(null);
5194
5198
  const [isRendered, setIsRendered] = useState6(false);
5199
+ const [shouldRender, setShouldRender] = useState6(false);
5200
+ useEffect9(() => {
5201
+ if (shouldRender) return;
5202
+ const el = buttonRef.current;
5203
+ if (!el) return;
5204
+ if (typeof IntersectionObserver === "undefined") {
5205
+ setShouldRender(true);
5206
+ return;
5207
+ }
5208
+ const observer = new IntersectionObserver(
5209
+ (entries) => {
5210
+ for (const entry of entries) {
5211
+ if (entry.isIntersecting) {
5212
+ setShouldRender(true);
5213
+ observer.disconnect();
5214
+ break;
5215
+ }
5216
+ }
5217
+ },
5218
+ // 200px root margin so the page is fetched just before it scrolls
5219
+ // into view, hiding the render latency.
5220
+ { rootMargin: "200px" }
5221
+ );
5222
+ observer.observe(el);
5223
+ return () => observer.disconnect();
5224
+ }, [shouldRender]);
5195
5225
  useEffect9(() => {
5226
+ if (!shouldRender) return;
5196
5227
  let cancelled = false;
5197
5228
  const renderThumbnail = async () => {
5198
5229
  const canvas = canvasRef.current;
@@ -5226,10 +5257,11 @@ var init_ThumbnailPanel = __esm({
5226
5257
  return () => {
5227
5258
  cancelled = true;
5228
5259
  };
5229
- }, [document2, pageNumber, scale]);
5260
+ }, [document2, pageNumber, scale, shouldRender]);
5230
5261
  return /* @__PURE__ */ jsxs3(
5231
5262
  "button",
5232
5263
  {
5264
+ ref: buttonRef,
5233
5265
  onClick,
5234
5266
  className: cn(
5235
5267
  "thumbnail-item",
@@ -9452,6 +9484,11 @@ var init_VirtualizedDocumentContainer = __esm({
9452
9484
  selectHighlight,
9453
9485
  activeColor
9454
9486
  } = useHighlights();
9487
+ const [defaultDims, setDefaultDims] = useState19({
9488
+ width: DEFAULT_PAGE_WIDTH2,
9489
+ height: DEFAULT_PAGE_HEIGHT2
9490
+ });
9491
+ const [dimsVersion, setDimsVersion] = useState19(0);
9455
9492
  useEffect20(() => {
9456
9493
  if (document2 !== documentRef.current) {
9457
9494
  documentRef.current = document2;
@@ -9460,39 +9497,47 @@ var init_VirtualizedDocumentContainer = __esm({
9460
9497
  setPageObjects(/* @__PURE__ */ new Map());
9461
9498
  }
9462
9499
  }, [document2]);
9500
+ useEffect20(() => {
9501
+ pageDimensionsCache.current.clear();
9502
+ setDimsVersion((v) => v + 1);
9503
+ }, [rotation]);
9463
9504
  useEffect20(() => {
9464
9505
  if (!document2 || numPages === 0) return;
9465
- const calculatePageInfos = async () => {
9466
- const infos = [];
9467
- let currentTop = 0;
9468
- for (let i = 1; i <= numPages; i++) {
9469
- let dimensions = pageDimensionsCache.current.get(i);
9470
- if (!dimensions) {
9471
- try {
9472
- const page = pageCache.current.get(i) || await document2.getPage(i);
9473
- if (!pageCache.current.has(i)) {
9474
- pageCache.current.set(i, page);
9475
- }
9476
- const viewport = page.getViewport({ scale: 1, rotation });
9477
- dimensions = { width: viewport.width, height: viewport.height };
9478
- pageDimensionsCache.current.set(i, dimensions);
9479
- } catch {
9480
- dimensions = { width: DEFAULT_PAGE_WIDTH2, height: DEFAULT_PAGE_HEIGHT2 };
9481
- }
9482
- }
9483
- const scaledHeight = Math.floor(dimensions.height * scale);
9484
- infos.push({
9485
- pageNumber: i,
9486
- top: currentTop,
9487
- height: scaledHeight
9488
- });
9489
- currentTop += scaledHeight + pageGap;
9506
+ let cancelled = false;
9507
+ (async () => {
9508
+ try {
9509
+ const page = pageCache.current.get(1) ?? await document2.getPage(1);
9510
+ if (cancelled) return;
9511
+ pageCache.current.set(1, page);
9512
+ const viewport = page.getViewport({ scale: 1, rotation });
9513
+ const dims = { width: viewport.width, height: viewport.height };
9514
+ pageDimensionsCache.current.set(1, dims);
9515
+ setDefaultDims(dims);
9516
+ setDimsVersion((v) => v + 1);
9517
+ } catch {
9490
9518
  }
9491
- setPageInfos(infos);
9492
- setTotalHeight(currentTop - pageGap);
9519
+ })();
9520
+ return () => {
9521
+ cancelled = true;
9493
9522
  };
9494
- calculatePageInfos();
9495
- }, [document2, numPages, scale, rotation, pageGap]);
9523
+ }, [document2, numPages, rotation]);
9524
+ useEffect20(() => {
9525
+ if (!document2 || numPages === 0) {
9526
+ setPageInfos([]);
9527
+ setTotalHeight(0);
9528
+ return;
9529
+ }
9530
+ const infos = [];
9531
+ let currentTop = 0;
9532
+ for (let i = 1; i <= numPages; i++) {
9533
+ const dimensions = pageDimensionsCache.current.get(i) ?? defaultDims;
9534
+ const scaledHeight = Math.floor(dimensions.height * scale);
9535
+ infos.push({ pageNumber: i, top: currentTop, height: scaledHeight });
9536
+ currentTop += scaledHeight + pageGap;
9537
+ }
9538
+ setPageInfos(infos);
9539
+ setTotalHeight(Math.max(0, currentTop - pageGap));
9540
+ }, [document2, numPages, scale, rotation, pageGap, defaultDims, dimsVersion]);
9496
9541
  const updateVisiblePages = useCallback30(() => {
9497
9542
  if (!scrollContainerRef.current || pageInfos.length === 0) return;
9498
9543
  const container = scrollContainerRef.current;
@@ -9540,6 +9585,7 @@ var init_VirtualizedDocumentContainer = __esm({
9540
9585
  const loadPages = async () => {
9541
9586
  const newPageObjects = new Map(pageObjects);
9542
9587
  let hasChanges = false;
9588
+ let dimsChanged = false;
9543
9589
  for (const pageNum of visiblePages) {
9544
9590
  if (!newPageObjects.has(pageNum)) {
9545
9591
  try {
@@ -9550,6 +9596,14 @@ var init_VirtualizedDocumentContainer = __esm({
9550
9596
  }
9551
9597
  newPageObjects.set(pageNum, page);
9552
9598
  hasChanges = true;
9599
+ if (!pageDimensionsCache.current.has(pageNum)) {
9600
+ const vp = page.getViewport({ scale: 1, rotation });
9601
+ pageDimensionsCache.current.set(pageNum, {
9602
+ width: vp.width,
9603
+ height: vp.height
9604
+ });
9605
+ dimsChanged = true;
9606
+ }
9553
9607
  } catch (error) {
9554
9608
  const errorMessage = error instanceof Error ? error.message : String(error);
9555
9609
  const isDocumentDestroyed = errorMessage.includes("destroyed") || errorMessage.includes("sendWithStream") || errorMessage.includes("sendWithPromise") || errorMessage.includes("Cannot read properties of null");
@@ -9569,9 +9623,12 @@ var init_VirtualizedDocumentContainer = __esm({
9569
9623
  if (hasChanges) {
9570
9624
  setPageObjects(newPageObjects);
9571
9625
  }
9626
+ if (dimsChanged) {
9627
+ setDimsVersion((v) => v + 1);
9628
+ }
9572
9629
  };
9573
9630
  loadPages();
9574
- }, [document2, visiblePages, pageObjects]);
9631
+ }, [document2, visiblePages, pageObjects, rotation]);
9575
9632
  useEffect20(() => {
9576
9633
  if (!scrollToPageRequest || !scrollContainerRef.current || pageInfos.length === 0) return;
9577
9634
  const { page, requestId, behavior } = scrollToPageRequest;
@@ -10136,10 +10193,10 @@ var init_DualPageContainer = __esm({
10136
10193
  });
10137
10194
 
10138
10195
  // src/components/PDFViewer/BookModeContainer.tsx
10139
- import React, { memo as memo26, useEffect as useEffect22, useState as useState21, useRef as useRef19, useCallback as useCallback32 } from "react";
10196
+ import React, { memo as memo26, useEffect as useEffect22, useMemo as useMemo14, useState as useState21, useRef as useRef19, useCallback as useCallback32 } from "react";
10140
10197
  import HTMLFlipBook from "react-pageflip";
10141
10198
  import { jsx as jsx27, jsxs as jsxs23 } from "react/jsx-runtime";
10142
- var BookPage, BookModeContainer;
10199
+ var BOOK_MODE_OVERSCAN, BookPage, BookModeContainer;
10143
10200
  var init_BookModeContainer = __esm({
10144
10201
  "src/components/PDFViewer/BookModeContainer.tsx"() {
10145
10202
  "use strict";
@@ -10147,6 +10204,7 @@ var init_BookModeContainer = __esm({
10147
10204
  init_PDFLoadingScreen2();
10148
10205
  init_hooks();
10149
10206
  init_utils();
10207
+ BOOK_MODE_OVERSCAN = 4;
10150
10208
  BookPage = React.forwardRef(function BookPage2({ pageNumber, page, scale, rotation, width, height }, ref) {
10151
10209
  return /* @__PURE__ */ jsx27("div", { ref, className: "book-page", "data-page-number": pageNumber, children: /* @__PURE__ */ jsx27("div", { style: { width, height, overflow: "hidden" }, children: /* @__PURE__ */ jsx27(
10152
10210
  PDFPage,
@@ -10179,9 +10237,10 @@ var init_BookModeContainer = __esm({
10179
10237
  } = usePDFViewer();
10180
10238
  const scrollToPageRequest = useViewerStore((s) => s.scrollToPageRequest);
10181
10239
  const { viewerStore } = usePDFViewerStores();
10182
- const [pages, setPages] = useState21([]);
10240
+ const [pages, setPages] = useState21(/* @__PURE__ */ new Map());
10183
10241
  const [rawPageDims, setRawPageDims] = useState21({ width: 612, height: 792 });
10184
- const [isLoadingPages, setIsLoadingPages] = useState21(false);
10242
+ const [hasFirstPage, setHasFirstPage] = useState21(false);
10243
+ const pageRequestsRef = useRef19(/* @__PURE__ */ new Set());
10185
10244
  const containerRef = useRef19(null);
10186
10245
  const [containerSize, setContainerSize] = useState21({ width: 0, height: 0 });
10187
10246
  const flipBookRef = useRef19(null);
@@ -10198,41 +10257,67 @@ var init_BookModeContainer = __esm({
10198
10257
  return () => ro.disconnect();
10199
10258
  }, []);
10200
10259
  useEffect22(() => {
10201
- if (!document2) {
10202
- setPages([]);
10203
- return;
10204
- }
10260
+ setPages(/* @__PURE__ */ new Map());
10261
+ pageRequestsRef.current.clear();
10262
+ setHasFirstPage(false);
10263
+ }, [document2]);
10264
+ useEffect22(() => {
10265
+ if (!document2 || numPages === 0) return;
10266
+ const start = Math.max(1, currentPage - BOOK_MODE_OVERSCAN);
10267
+ const end = Math.min(numPages, currentPage + BOOK_MODE_OVERSCAN);
10268
+ const isFirstLoad = !hasFirstPage;
10205
10269
  let cancelled = false;
10206
- const loadAllPages = async () => {
10207
- setIsLoadingPages(true);
10208
- try {
10209
- const pagePromises = [];
10210
- for (let i = 1; i <= numPages; i++) {
10211
- pagePromises.push(document2.getPage(i));
10270
+ const wanted = [];
10271
+ if (isFirstLoad && !pages.has(1) && !pageRequestsRef.current.has(1)) {
10272
+ wanted.push(1);
10273
+ pageRequestsRef.current.add(1);
10274
+ }
10275
+ for (let i = start; i <= end; i++) {
10276
+ if (pages.has(i) || pageRequestsRef.current.has(i)) continue;
10277
+ wanted.push(i);
10278
+ pageRequestsRef.current.add(i);
10279
+ }
10280
+ if (wanted.length === 0) return;
10281
+ (async () => {
10282
+ const results = await Promise.allSettled(
10283
+ wanted.map((i) => document2.getPage(i).then((p) => [i, p]))
10284
+ );
10285
+ if (cancelled) return;
10286
+ const next = new Map(pages);
10287
+ let firstPageJustLoaded = null;
10288
+ for (const r of results) {
10289
+ if (r.status === "fulfilled") {
10290
+ const [i, page] = r.value;
10291
+ next.set(i, page);
10292
+ if (i === 1) firstPageJustLoaded = page;
10212
10293
  }
10213
- const results = await Promise.allSettled(pagePromises);
10214
- if (!cancelled) {
10215
- const loaded2 = results.map((r) => r.status === "fulfilled" ? r.value : null);
10216
- setPages(loaded2);
10217
- const firstPage = loaded2[0];
10218
- if (firstPage) {
10219
- const vp = firstPage.getViewport({ scale: 1, rotation });
10220
- setRawPageDims({ width: vp.width, height: vp.height });
10221
- }
10294
+ }
10295
+ for (const i of next.keys()) {
10296
+ if (i !== 1 && (i < start || i > end)) {
10297
+ next.delete(i);
10222
10298
  }
10223
- } catch {
10224
- } finally {
10225
- if (!cancelled) setIsLoadingPages(false);
10226
10299
  }
10227
- };
10228
- loadAllPages();
10300
+ setPages(next);
10301
+ if (firstPageJustLoaded) {
10302
+ const vp = firstPageJustLoaded.getViewport({ scale: 1, rotation });
10303
+ setRawPageDims({ width: vp.width, height: vp.height });
10304
+ setHasFirstPage(true);
10305
+ }
10306
+ for (const i of wanted) {
10307
+ pageRequestsRef.current.delete(i);
10308
+ }
10309
+ })();
10229
10310
  return () => {
10230
10311
  cancelled = true;
10312
+ for (const i of wanted) {
10313
+ pageRequestsRef.current.delete(i);
10314
+ }
10231
10315
  };
10232
- }, [document2, numPages, rotation]);
10316
+ }, [document2, numPages, currentPage, rotation, pages, hasFirstPage]);
10233
10317
  useEffect22(() => {
10234
- if (pages[0]) {
10235
- const vp = pages[0].getViewport({ scale: 1, rotation });
10318
+ const firstPage = pages.get(1);
10319
+ if (firstPage) {
10320
+ const vp = firstPage.getViewport({ scale: 1, rotation });
10236
10321
  setRawPageDims({ width: vp.width, height: vp.height });
10237
10322
  }
10238
10323
  }, [pages, rotation]);
@@ -10283,8 +10368,28 @@ var init_BookModeContainer = __esm({
10283
10368
  sepia: "bg-amber-50"
10284
10369
  };
10285
10370
  const themeClass = theme === "dark" ? "dark" : theme === "sepia" ? "sepia" : "";
10286
- const ready = !!document2 && !isLoadingPages && pages.length > 0;
10371
+ const ready = !!document2 && hasFirstPage;
10287
10372
  const hasContainer = containerSize.width > 0 && containerSize.height > 0;
10373
+ const pageChildren = useMemo14(() => {
10374
+ if (numPages === 0) return null;
10375
+ const out = new Array(numPages);
10376
+ for (let i = 0; i < numPages; i++) {
10377
+ const pageNumber = i + 1;
10378
+ out[i] = /* @__PURE__ */ jsx27(
10379
+ BookPage,
10380
+ {
10381
+ pageNumber,
10382
+ page: pages.get(pageNumber) ?? null,
10383
+ scale: renderScale,
10384
+ rotation,
10385
+ width: displayWidth,
10386
+ height: displayHeight
10387
+ },
10388
+ pageNumber
10389
+ );
10390
+ }
10391
+ return out;
10392
+ }, [numPages, pages, renderScale, rotation, displayWidth, displayHeight]);
10288
10393
  return /* @__PURE__ */ jsxs23(
10289
10394
  "div",
10290
10395
  {
@@ -10334,18 +10439,7 @@ var init_BookModeContainer = __esm({
10334
10439
  autoSize: false,
10335
10440
  renderOnlyPageLengthChange: false,
10336
10441
  disableFlipByClick: false,
10337
- children: pages.map((page, index) => /* @__PURE__ */ jsx27(
10338
- BookPage,
10339
- {
10340
- pageNumber: index + 1,
10341
- page,
10342
- scale: renderScale,
10343
- rotation,
10344
- width: displayWidth,
10345
- height: displayHeight
10346
- },
10347
- index
10348
- ))
10442
+ children: pageChildren
10349
10443
  }
10350
10444
  )
10351
10445
  ]
@@ -12521,7 +12615,7 @@ var AskAboutTrigger = memo36(function AskAboutTrigger2({
12521
12615
  // src/components/Minimap/Minimap.tsx
12522
12616
  init_hooks();
12523
12617
  init_utils();
12524
- import { memo as memo37, useMemo as useMemo14, useCallback as useCallback41 } from "react";
12618
+ import { memo as memo37, useMemo as useMemo15, useCallback as useCallback41 } from "react";
12525
12619
  import { Fragment as Fragment3, jsx as jsx38, jsxs as jsxs32 } from "react/jsx-runtime";
12526
12620
  var PageIndicator = memo37(function PageIndicator2({
12527
12621
  pageNumber,
@@ -12572,7 +12666,7 @@ var Minimap = memo37(function Minimap2({
12572
12666
  const currentPage = useViewerStore((s) => s.currentPage);
12573
12667
  const numPages = useViewerStore((s) => s.numPages);
12574
12668
  const goToPage = useViewerStore((s) => s.goToPage);
12575
- const bookmarkedPages = useMemo14(() => {
12669
+ const bookmarkedPages = useMemo15(() => {
12576
12670
  return new Set(bookmarks.map((b) => b.pageNumber));
12577
12671
  }, [bookmarks]);
12578
12672
  const compact = numPages > 50;
@@ -12592,7 +12686,7 @@ var Minimap = memo37(function Minimap2({
12592
12686
  },
12593
12687
  [currentPage, visitedPages, bookmarkedPages]
12594
12688
  );
12595
- const pageIndicators = useMemo14(() => {
12689
+ const pageIndicators = useMemo15(() => {
12596
12690
  const pages = [];
12597
12691
  for (let i = 1; i <= numPages; i++) {
12598
12692
  pages.push(
@@ -13094,7 +13188,7 @@ init_PDFLoadingScreen2();
13094
13188
  // src/components/TutorMode/TutorModeContainer.tsx
13095
13189
  init_PDFPage2();
13096
13190
  init_hooks();
13097
- import { useEffect as useEffect28, useMemo as useMemo15, useRef as useRef27, useState as useState30 } from "react";
13191
+ import { useEffect as useEffect28, useMemo as useMemo16, useRef as useRef27, useState as useState30 } from "react";
13098
13192
  import { useStore as useStore2 } from "zustand";
13099
13193
 
13100
13194
  // src/components/TutorMode/CameraView.tsx
@@ -16086,7 +16180,7 @@ function TutorModeContainer({
16086
16180
  className
16087
16181
  }) {
16088
16182
  const containerRef = useRef27(null);
16089
- const index = useMemo15(() => buildBBoxIndex(bboxData), [bboxData]);
16183
+ const index = useMemo16(() => buildBBoxIndex(bboxData), [bboxData]);
16090
16184
  const {
16091
16185
  document: document2,
16092
16186
  currentPage: viewerCurrentPage,