@anaralabs/lector 3.10.0 → 3.10.1

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.
@@ -38,7 +38,7 @@ declare interface Annotation {
38
38
  export { Annotation }
39
39
  export { Annotation as Annotation_alias_1 }
40
40
 
41
- export declare const AnnotationHighlightLayer: ({ className, style, renderTooltipContent, renderHoverTooltipContent, tooltipClassName, highlightClassName, underlineClassName, commentIconPosition, commmentIcon, commentIconClassName, focusedAnnotationId, focusedHoverAnnotationId, onAnnotationClick, onAnnotationTooltipClose, hoverTooltipClassName, }: AnnotationHighlightLayerProps) => JSX.Element;
41
+ export declare const AnnotationHighlightLayer: ({ className, style, renderTooltipContent, renderHoverTooltipContent, tooltipClassName, highlightClassName, underlineClassName, commentIconPosition, commmentIcon, commentIconClassName, focusedAnnotationId, focusedHoverAnnotationId, onAnnotationClick, onAnnotationTooltipClose, hoverTooltipClassName, }: AnnotationHighlightLayerProps) => JSX.Element | null;
42
42
 
43
43
  declare interface AnnotationHighlightLayerProps {
44
44
  className?: string;
@@ -124,6 +124,12 @@ declare interface AnnotationTooltipProps {
124
124
  }) => React.ReactNode;
125
125
  }
126
126
 
127
+ declare type CacheEntry = {
128
+ bitmap: ImageBitmap;
129
+ width: number;
130
+ height: number;
131
+ };
132
+
127
133
  /**
128
134
  * Calculates the highlight rectangles for a given text match.
129
135
  *
@@ -149,6 +155,8 @@ background?: string;
149
155
 
150
156
  export declare const clamp: (value: number, minimum: number, maximum: number) => number;
151
157
 
158
+ export declare function clampScaleForPage(targetScale: number, pageWidth: number, pageHeight: number): number;
159
+
152
160
  declare type CollapsibleSelection = {
153
161
  highlights: HighlightRect[];
154
162
  underlines?: HighlightRect[];
@@ -257,6 +265,10 @@ export declare class LinkService {
257
265
 
258
266
  export declare const loadPdfJs: () => Promise<pdfjsDist>;
259
267
 
268
+ export declare const MAX_CANVAS_DIMENSION = 32767;
269
+
270
+ export declare const MAX_CANVAS_PIXELS = 16777216;
271
+
260
272
  export declare const NextPage: () => void;
261
273
 
262
274
  export declare const Outline: ({ children, ...props }: HTMLProps<HTMLUListElement> & {
@@ -321,6 +333,9 @@ declare interface PDFState {
321
333
  coloredHighlights: ColoredHighlight[];
322
334
  addColoredHighlight: (value: ColoredHighlight) => void;
323
335
  deleteColoredHighlight: (uuid: string) => void;
336
+ renderedPages: Record<number, true>;
337
+ markPageRendered: (pageNumber: number) => void;
338
+ unmarkPageRendered: (pageNumber: number) => void;
324
339
  }
325
340
 
326
341
  export declare const PDFStore: {
@@ -336,6 +351,51 @@ export declare type PDFVirtualizer = Virtualizer<any, any>;
336
351
 
337
352
  export declare const PreviousPage: () => void;
338
353
 
354
+ /**
355
+ * LRU cache for rendered page bitmaps. When scrolling back to a previously
356
+ * rendered page at the same scale, we can draw from cache instantly instead
357
+ * of re-rendering through PDF.js.
358
+ *
359
+ * Cache keys include a document ID to prevent collisions when multiple
360
+ * <Root> instances render different PDFs on the same page.
361
+ */
362
+ declare class RenderCache {
363
+ private cache;
364
+ private maxEntries;
365
+ private invalidatedDocs;
366
+ constructor(maxEntries?: number);
367
+ private key;
368
+ get(documentId: string, pageNumber: number, scale: number, background?: string): CacheEntry | undefined;
369
+ set(documentId: string, pageNumber: number, scale: number, canvas: HTMLCanvasElement, background?: string): Promise<void>;
370
+ /** Remove all cached entries for a specific document (call on Root unmount). */
371
+ invalidateDocument(documentId: string): void;
372
+ clear(): void;
373
+ }
374
+
375
+ export declare const renderCache: RenderCache;
376
+
377
+ /**
378
+ * Serializes PDF page render operations so only one runs at a time.
379
+ * This prevents multiple heavy pages from competing for CPU and blocking the UI.
380
+ */
381
+ declare class RenderQueue {
382
+ private queue;
383
+ private running;
384
+ enqueue(execute: () => Promise<void>): {
385
+ promise: Promise<void>;
386
+ cancel: () => void;
387
+ };
388
+ private flush;
389
+ }
390
+
391
+ /**
392
+ * Global singleton — intentionally shared across all <Root> instances.
393
+ * Serializing renders across documents prevents overall GPU/CPU pressure
394
+ * on the main thread (CanvasGraphics is single-threaded). The trade-off
395
+ * is increased latency in multi-viewer setups.
396
+ */
397
+ export declare const renderQueue: RenderQueue;
398
+
339
399
  export declare const Root: ForwardRefExoticComponent<Omit<HTMLProps<HTMLDivElement> & usePDFDocumentParams & {
340
400
  loader?: ReactNode;
341
401
  }, "ref"> & RefAttributes<unknown>>;
@@ -426,11 +486,15 @@ declare interface UseAnnotationTooltipReturn {
426
486
 
427
487
  export declare const useCreatePDFLinkService: (pdfDocumentProxy: PDFDocumentProxy | null) => LinkService;
428
488
 
489
+ declare const usePageRendered: (pageNumber: number) => boolean;
490
+ export { usePageRendered }
491
+ export { usePageRendered as usePageRendered_alias_1 }
492
+
429
493
  declare const usePdf: <T>(selector: (state: PDFState) => T) => T;
430
494
  export { usePdf }
431
495
  export { usePdf as usePdf_alias_1 }
432
496
 
433
- export declare const usePDFDocumentContext: ({ onDocumentLoad, source, initialRotation, isZoomFitWidth, zoom, zoomOptions, }: usePDFDocumentParams) => {
497
+ export declare const usePDFDocumentContext: ({ onDocumentLoad, source, initialRotation, isZoomFitWidth, zoom, zoomOptions, documentOptions, }: usePDFDocumentParams) => {
434
498
  initialState: InitialPDFState | null | undefined;
435
499
  };
436
500
 
@@ -447,6 +511,12 @@ export declare interface usePDFDocumentParams {
447
511
  isZoomFitWidth?: boolean;
448
512
  zoom?: number;
449
513
  zoomOptions?: ZoomOptions;
514
+ /**
515
+ * Override or extend the PDF.js DocumentInitParameters passed to getDocument().
516
+ * These take highest precedence over both the source object and lector's defaults.
517
+ * Must be a stable reference (module-level constant or useMemo) to avoid reloading the document.
518
+ */
519
+ documentOptions?: Partial<DocumentInitParameters>;
450
520
  }
451
521
 
452
522
  export declare const usePdfJump: () => {
package/dist/index.d.ts CHANGED
@@ -31,6 +31,7 @@ export { useSearch } from './_tsup-dts-rollup.js';
31
31
  export { calculateHighlightRects } from './_tsup-dts-rollup.js';
32
32
  export { Annotation } from './_tsup-dts-rollup.js';
33
33
  export { useAnnotations } from './_tsup-dts-rollup.js';
34
+ export { usePageRendered } from './_tsup-dts-rollup.js';
34
35
  export { LinkService } from './_tsup-dts-rollup.js';
35
36
  export { PDFLinkServiceContext } from './_tsup-dts-rollup.js';
36
37
  export { useCreatePDFLinkService } from './_tsup-dts-rollup.js';
package/dist/index.js CHANGED
@@ -1,6 +1,6 @@
1
1
  'use client';
2
2
 
3
- import React, { createContext, memo, forwardRef, cloneElement, useRef, useState, useCallback, useContext, useEffect, useMemo, useLayoutEffect, createRef } from 'react';
3
+ import React, { createContext, memo, forwardRef, useMemo, cloneElement, useEffect, useRef, useState, useCallback, useContext, useLayoutEffect, createRef } from 'react';
4
4
  import { createPortal } from 'react-dom';
5
5
  import { useFloating, autoUpdate, offset, shift, useDismiss, useInteractions, inline, flip } from '@floating-ui/react';
6
6
  import { create, useStore, createStore } from 'zustand';
@@ -124,7 +124,19 @@ var PDFStore = createZustandContext(
124
124
  coloredHighlights: prevState.coloredHighlights.filter(
125
125
  (rect) => rect.uuid !== uuid
126
126
  )
127
- }))
127
+ })),
128
+ renderedPages: {},
129
+ markPageRendered: (pageNumber) => {
130
+ const current = get().renderedPages;
131
+ if (current[pageNumber]) return;
132
+ set({ renderedPages: { ...current, [pageNumber]: true } });
133
+ },
134
+ unmarkPageRendered: (pageNumber) => {
135
+ const current = get().renderedPages;
136
+ if (!current[pageNumber]) return;
137
+ const { [pageNumber]: _, ...rest } = current;
138
+ set({ renderedPages: rest });
139
+ }
128
140
  }));
129
141
  }
130
142
  );
@@ -462,12 +474,15 @@ var AnnotationHighlightLayer = ({
462
474
  }) => {
463
475
  const { annotations } = useAnnotations();
464
476
  const pageNumber = usePDFPageNumber();
465
- const pageAnnotations = annotations.filter(
466
- (annotation) => annotation.pageNumber === pageNumber
477
+ const isPageRendered = usePdf((state) => !!state.renderedPages[pageNumber]);
478
+ const pageAnnotations = useMemo(
479
+ () => annotations.filter((a) => a.pageNumber === pageNumber),
480
+ [annotations, pageNumber]
467
481
  );
482
+ if (!isPageRendered) return null;
468
483
  const getCommentIconPosition = (highlights) => {
469
484
  if (!highlights.length) return { top: 0, right: 10 };
470
- const sortedHighlights = [...highlights].sort((a, b) => {
485
+ const sortedHighlights = highlights.toSorted((a, b) => {
471
486
  const topDiff = a.top - b.top;
472
487
  return Math.abs(topDiff) < 3 ? a.left - b.left : topDiff;
473
488
  });
@@ -691,7 +706,7 @@ var cancellable = (promise) => {
691
706
  var pdfJsPromise = null;
692
707
  var loadPdfJs = () => {
693
708
  if (!pdfJsPromise) {
694
- pdfJsPromise = import('pdfjs-dist');
709
+ pdfJsPromise = import('pdfjs-dist/legacy/build/pdf.mjs');
695
710
  }
696
711
  return pdfJsPromise;
697
712
  };
@@ -1099,6 +1114,146 @@ var AnnotationLayer = memo(
1099
1114
  }
1100
1115
  );
1101
1116
  AnnotationLayer.displayName = "AnnotationLayer";
1117
+
1118
+ // src/lib/canvas-utils.ts
1119
+ var MAX_CANVAS_PIXELS = 16777216;
1120
+ var MAX_CANVAS_DIMENSION = 32767;
1121
+ function clampScaleForPage(targetScale, pageWidth, pageHeight) {
1122
+ if (!targetScale) {
1123
+ return 0;
1124
+ }
1125
+ const areaLimit = Math.sqrt(
1126
+ MAX_CANVAS_PIXELS / Math.max(pageWidth * pageHeight, 1)
1127
+ );
1128
+ const widthLimit = MAX_CANVAS_DIMENSION / Math.max(pageWidth, 1);
1129
+ const heightLimit = MAX_CANVAS_DIMENSION / Math.max(pageHeight, 1);
1130
+ const safeScale = Math.min(
1131
+ targetScale,
1132
+ Number.isFinite(areaLimit) ? areaLimit : targetScale,
1133
+ Number.isFinite(widthLimit) ? widthLimit : targetScale,
1134
+ Number.isFinite(heightLimit) ? heightLimit : targetScale
1135
+ );
1136
+ return Math.max(safeScale, 0);
1137
+ }
1138
+
1139
+ // src/lib/render-cache.ts
1140
+ var RenderCache = class {
1141
+ cache = /* @__PURE__ */ new Map();
1142
+ maxEntries;
1143
+ // Tracks invalidated documents so in-flight createImageBitmap calls
1144
+ // don't insert orphaned entries after invalidateDocument() runs.
1145
+ invalidatedDocs = /* @__PURE__ */ new Set();
1146
+ constructor(maxEntries = 30) {
1147
+ this.maxEntries = maxEntries;
1148
+ }
1149
+ key(documentId, pageNumber, scale, background) {
1150
+ return `${documentId}-${pageNumber}-${scale}-${background ?? "white"}`;
1151
+ }
1152
+ get(documentId, pageNumber, scale, background) {
1153
+ const k = this.key(documentId, pageNumber, scale, background);
1154
+ const entry = this.cache.get(k);
1155
+ if (!entry) return void 0;
1156
+ this.cache.delete(k);
1157
+ this.cache.set(k, entry);
1158
+ return entry;
1159
+ }
1160
+ async set(documentId, pageNumber, scale, canvas, background) {
1161
+ const k = this.key(documentId, pageNumber, scale, background);
1162
+ const w = canvas.width;
1163
+ const h = canvas.height;
1164
+ if (w === 0 || h === 0) return;
1165
+ while (this.cache.size >= this.maxEntries) {
1166
+ const oldest = this.cache.keys().next().value;
1167
+ if (oldest !== void 0) {
1168
+ const entry = this.cache.get(oldest);
1169
+ entry?.bitmap.close();
1170
+ this.cache.delete(oldest);
1171
+ }
1172
+ }
1173
+ try {
1174
+ const bitmap = await createImageBitmap(canvas);
1175
+ if (this.invalidatedDocs.has(documentId)) {
1176
+ bitmap.close();
1177
+ return;
1178
+ }
1179
+ this.cache.set(k, {
1180
+ bitmap,
1181
+ width: w,
1182
+ height: h
1183
+ });
1184
+ } catch {
1185
+ }
1186
+ }
1187
+ /** Remove all cached entries for a specific document (call on Root unmount). */
1188
+ invalidateDocument(documentId) {
1189
+ this.invalidatedDocs.add(documentId);
1190
+ for (const [k, entry] of this.cache) {
1191
+ if (k.startsWith(`${documentId}-`)) {
1192
+ entry.bitmap.close();
1193
+ this.cache.delete(k);
1194
+ }
1195
+ }
1196
+ setTimeout(() => {
1197
+ this.invalidatedDocs.delete(documentId);
1198
+ }, 1e3);
1199
+ }
1200
+ clear() {
1201
+ for (const entry of this.cache.values()) {
1202
+ entry.bitmap.close();
1203
+ }
1204
+ this.cache.clear();
1205
+ this.invalidatedDocs.clear();
1206
+ }
1207
+ };
1208
+ var renderCache = new RenderCache();
1209
+
1210
+ // src/lib/render-queue.ts
1211
+ var RenderQueue = class {
1212
+ queue = [];
1213
+ running = false;
1214
+ enqueue(execute) {
1215
+ let resolve;
1216
+ let reject;
1217
+ const promise = new Promise((res, rej) => {
1218
+ resolve = res;
1219
+ reject = rej;
1220
+ });
1221
+ const job = {
1222
+ execute,
1223
+ resolve,
1224
+ reject,
1225
+ cancelled: false
1226
+ };
1227
+ this.queue.push(job);
1228
+ this.flush();
1229
+ return {
1230
+ promise,
1231
+ cancel: () => {
1232
+ job.cancelled = true;
1233
+ job.resolve();
1234
+ }
1235
+ };
1236
+ }
1237
+ async flush() {
1238
+ if (this.running) return;
1239
+ this.running = true;
1240
+ while (this.queue.length > 0) {
1241
+ const job = this.queue.shift();
1242
+ if (job.cancelled) {
1243
+ job.resolve();
1244
+ continue;
1245
+ }
1246
+ try {
1247
+ await job.execute();
1248
+ job.resolve();
1249
+ } catch (error) {
1250
+ job.reject(error);
1251
+ }
1252
+ }
1253
+ this.running = false;
1254
+ }
1255
+ };
1256
+ var renderQueue = new RenderQueue();
1102
1257
  var useDpr = () => {
1103
1258
  const [dpr, setDPR] = useState(
1104
1259
  typeof window === "undefined" ? 1 : Math.min(window.devicePixelRatio, 2)
@@ -1122,79 +1277,136 @@ var useDpr = () => {
1122
1277
  };
1123
1278
 
1124
1279
  // src/hooks/layers/useCanvasLayer.tsx
1125
- var MAX_CANVAS_PIXELS = 16777216;
1126
- var MAX_CANVAS_DIMENSION = 32767;
1127
1280
  var useCanvasLayer = ({ background }) => {
1128
1281
  const canvasRef = useRef(null);
1129
1282
  const pageNumber = usePDFPageNumber();
1130
1283
  const dpr = useDpr();
1131
1284
  const bouncyZoom = usePdf((state) => state.zoom);
1132
1285
  const pdfPageProxy = usePdf((state) => state.getPdfPageProxy(pageNumber));
1133
- const [zoom] = useDebounce(bouncyZoom, 100);
1134
- const clampScaleForPage = useCallback(
1135
- (targetScale, pageWidth, pageHeight) => {
1136
- if (!targetScale) {
1137
- return 0;
1138
- }
1139
- const areaLimit = Math.sqrt(
1140
- MAX_CANVAS_PIXELS / Math.max(pageWidth * pageHeight, 1)
1141
- );
1142
- const widthLimit = MAX_CANVAS_DIMENSION / Math.max(pageWidth, 1);
1143
- const heightLimit = MAX_CANVAS_DIMENSION / Math.max(pageHeight, 1);
1144
- const safeScale = Math.min(
1145
- targetScale,
1146
- Number.isFinite(areaLimit) ? areaLimit : targetScale,
1147
- Number.isFinite(widthLimit) ? widthLimit : targetScale,
1148
- Number.isFinite(heightLimit) ? heightLimit : targetScale
1149
- );
1150
- return Math.max(safeScale, 0);
1151
- },
1152
- []
1286
+ const markPageRendered = usePdf((state) => state.markPageRendered);
1287
+ const unmarkPageRendered = usePdf((state) => state.unmarkPageRendered);
1288
+ const documentId = usePdf(
1289
+ (state) => state.pdfDocumentProxy.fingerprints[0] ?? "default"
1153
1290
  );
1291
+ const [zoom] = useDebounce(bouncyZoom, 100);
1292
+ const lastRenderedScaleRef = useRef(0);
1293
+ const lastBackgroundRef = useRef(background);
1294
+ const lastPageProxyRef = useRef(pdfPageProxy);
1154
1295
  useLayoutEffect(() => {
1155
1296
  if (!canvasRef.current) {
1156
1297
  return;
1157
1298
  }
1158
- const baseCanvas = canvasRef.current;
1299
+ if (lastPageProxyRef.current !== pdfPageProxy || lastBackgroundRef.current !== background) {
1300
+ lastPageProxyRef.current = pdfPageProxy;
1301
+ lastBackgroundRef.current = background;
1302
+ lastRenderedScaleRef.current = 0;
1303
+ }
1159
1304
  const baseViewport = pdfPageProxy.getViewport({ scale: 1 });
1160
1305
  const pageWidth = baseViewport.width;
1161
1306
  const pageHeight = baseViewport.height;
1307
+ const bgColor = background ?? "white";
1162
1308
  const targetBaseScale = dpr * Math.min(zoom, 1);
1163
1309
  const baseScale = clampScaleForPage(targetBaseScale, pageWidth, pageHeight);
1164
- baseCanvas.width = Math.floor(pageWidth * baseScale);
1165
- baseCanvas.height = Math.floor(pageHeight * baseScale);
1166
- baseCanvas.style.position = "absolute";
1167
- baseCanvas.style.top = "0";
1168
- baseCanvas.style.left = "0";
1169
- baseCanvas.style.width = `${pageWidth}px`;
1170
- baseCanvas.style.height = `${pageHeight}px`;
1171
- baseCanvas.style.transform = "translate(0px, 0px)";
1172
- baseCanvas.style.zIndex = "0";
1173
- baseCanvas.style.pointerEvents = "none";
1174
- baseCanvas.style.backgroundColor = background ?? "white";
1175
- const context = baseCanvas.getContext("2d");
1176
- if (!context) {
1310
+ if (baseScale === lastRenderedScaleRef.current) {
1177
1311
  return;
1178
1312
  }
1179
- context.setTransform(1, 0, 0, 1, 0, 0);
1180
- context.clearRect(0, 0, baseCanvas.width, baseCanvas.height);
1181
- const viewport = pdfPageProxy.getViewport({ scale: baseScale });
1182
- const renderingTask = pdfPageProxy.render({
1183
- canvas: baseCanvas,
1184
- canvasContext: context,
1185
- viewport,
1186
- background
1187
- });
1188
- renderingTask.promise.catch((error) => {
1189
- if (error.name === "RenderingCancelledException") {
1190
- return;
1313
+ const w = Math.floor(pageWidth * baseScale);
1314
+ const h = Math.floor(pageHeight * baseScale);
1315
+ const cssText = `position:absolute;top:0;left:0;width:${pageWidth}px;height:${pageHeight}px;transform:translate(0px,0px);z-index:0;pointer-events:none;background-color:${bgColor}`;
1316
+ const swapToCanvas = (source, sw, sh) => {
1317
+ const canvas = canvasRef.current;
1318
+ if (!canvas) return;
1319
+ canvas.width = sw;
1320
+ canvas.height = sh;
1321
+ canvas.style.cssText = cssText;
1322
+ const ctx = canvas.getContext("2d");
1323
+ if (ctx) {
1324
+ ctx.drawImage(source, 0, 0);
1191
1325
  }
1192
- throw error;
1326
+ lastRenderedScaleRef.current = baseScale;
1327
+ };
1328
+ const cached = renderCache.get(
1329
+ documentId,
1330
+ pageNumber,
1331
+ baseScale,
1332
+ background
1333
+ );
1334
+ if (cached) {
1335
+ swapToCanvas(cached.bitmap, cached.width, cached.height);
1336
+ markPageRendered(pageNumber);
1337
+ return;
1338
+ }
1339
+ let cancelled = false;
1340
+ let activeRenderingTask = null;
1341
+ const job = renderQueue.enqueue(() => {
1342
+ return new Promise((resolve, reject) => {
1343
+ if (cancelled || !canvasRef.current) {
1344
+ resolve();
1345
+ return;
1346
+ }
1347
+ const buffer = document.createElement("canvas");
1348
+ buffer.width = w;
1349
+ buffer.height = h;
1350
+ const bufferCtx = buffer.getContext("2d");
1351
+ if (!bufferCtx) {
1352
+ resolve();
1353
+ return;
1354
+ }
1355
+ const viewport = pdfPageProxy.getViewport({ scale: baseScale });
1356
+ const renderingTask = pdfPageProxy.render({
1357
+ canvas: buffer,
1358
+ canvasContext: bufferCtx,
1359
+ viewport,
1360
+ background
1361
+ });
1362
+ activeRenderingTask = renderingTask;
1363
+ renderingTask.promise.then(() => {
1364
+ activeRenderingTask = null;
1365
+ if (cancelled || !canvasRef.current) {
1366
+ resolve();
1367
+ return;
1368
+ }
1369
+ swapToCanvas(buffer, w, h);
1370
+ markPageRendered(pageNumber);
1371
+ renderCache.set(documentId, pageNumber, baseScale, buffer, background).finally(() => {
1372
+ buffer.width = 0;
1373
+ buffer.height = 0;
1374
+ });
1375
+ resolve();
1376
+ }).catch((error) => {
1377
+ activeRenderingTask = null;
1378
+ if (error.name === "RenderingCancelledException") {
1379
+ resolve();
1380
+ return;
1381
+ }
1382
+ reject(error);
1383
+ });
1384
+ });
1193
1385
  });
1194
1386
  return () => {
1195
- void renderingTask.cancel();
1387
+ cancelled = true;
1388
+ job.cancel();
1389
+ void activeRenderingTask?.cancel();
1196
1390
  };
1197
- }, [pdfPageProxy, background, dpr, zoom, clampScaleForPage]);
1391
+ }, [
1392
+ pdfPageProxy,
1393
+ background,
1394
+ dpr,
1395
+ zoom,
1396
+ pageNumber,
1397
+ documentId,
1398
+ markPageRendered
1399
+ ]);
1400
+ useEffect(() => {
1401
+ const canvas = canvasRef.current;
1402
+ return () => {
1403
+ unmarkPageRendered(pageNumber);
1404
+ if (canvas) {
1405
+ canvas.width = 1;
1406
+ canvas.height = 1;
1407
+ }
1408
+ };
1409
+ }, [pageNumber, unmarkPageRendered]);
1198
1410
  return {
1199
1411
  canvasRef
1200
1412
  };
@@ -1264,8 +1476,6 @@ var subscribeToViewportInvalidation = (viewport, callback) => {
1264
1476
  };
1265
1477
 
1266
1478
  // src/hooks/layers/useDetailCanvasLayer.tsx
1267
- var MAX_CANVAS_PIXELS2 = 16777216;
1268
- var MAX_CANVAS_DIMENSION2 = 32767;
1269
1479
  var DETAIL_RENDER_IDLE_MS = 80;
1270
1480
  var useDetailCanvasLayer = ({
1271
1481
  background,
@@ -1280,57 +1490,24 @@ var useDetailCanvasLayer = ({
1280
1490
  const pdfPageProxy = usePdf((state) => state.getPdfPageProxy(pageNumber));
1281
1491
  const viewportRef = usePdf((state) => state.viewportRef);
1282
1492
  const [zoom] = useDebounce(bouncyZoom, 200);
1283
- const getDetailCanvas = useCallback(() => {
1284
- const detailCanvas = detailCanvasRef.current;
1285
- if (!detailCanvas) {
1286
- return null;
1287
- }
1288
- detailCanvas.style.position = "absolute";
1289
- detailCanvas.style.top = "0";
1290
- detailCanvas.style.left = "0";
1291
- detailCanvas.style.pointerEvents = "none";
1292
- detailCanvas.style.zIndex = "1";
1293
- detailCanvas.style.backgroundColor = background ?? "white";
1294
- return detailCanvas;
1295
- }, [background]);
1296
- const clampScaleForPage = useCallback(
1297
- (targetScale, pageWidth, pageHeight) => {
1298
- if (!targetScale) {
1299
- return 0;
1300
- }
1301
- const areaLimit = Math.sqrt(
1302
- MAX_CANVAS_PIXELS2 / Math.max(pageWidth * pageHeight, 1)
1303
- );
1304
- const widthLimit = MAX_CANVAS_DIMENSION2 / Math.max(pageWidth, 1);
1305
- const heightLimit = MAX_CANVAS_DIMENSION2 / Math.max(pageHeight, 1);
1306
- const safeScale = Math.min(
1307
- targetScale,
1308
- Number.isFinite(areaLimit) ? areaLimit : targetScale,
1309
- Number.isFinite(widthLimit) ? widthLimit : targetScale,
1310
- Number.isFinite(heightLimit) ? heightLimit : targetScale
1311
- );
1312
- return Math.max(safeScale, 0);
1313
- },
1314
- []
1315
- );
1316
1493
  useLayoutEffect(() => {
1317
1494
  const scrollContainer = viewportRef?.current;
1318
1495
  if (!scrollContainer) {
1319
1496
  return;
1320
1497
  }
1321
- const detailCanvas = getDetailCanvas();
1498
+ const detailCanvas = detailCanvasRef.current;
1322
1499
  const container = containerRef.current;
1323
1500
  if (!detailCanvas || !container) {
1324
1501
  return;
1325
1502
  }
1326
1503
  let renderingTask = null;
1327
1504
  let renderTimeoutId = null;
1505
+ const bgColor = background ?? "white";
1506
+ const detailBaseStyle = `position:absolute;top:0;left:0;pointer-events:none;z-index:1;background-color:${bgColor}`;
1328
1507
  const hideDetailCanvas = () => {
1329
1508
  renderingTask?.cancel();
1330
- detailCanvas.style.display = "block";
1331
- detailCanvas.style.opacity = "0";
1332
- container.style.transform = "";
1333
- container.style.transformOrigin = "";
1509
+ detailCanvas.style.cssText = `${detailBaseStyle};display:block;opacity:0`;
1510
+ container.style.cssText = "";
1334
1511
  };
1335
1512
  const renderDetailCanvas = () => {
1336
1513
  const pageContainer = baseCanvasRef.current?.parentElement ?? null;
@@ -1374,27 +1551,19 @@ var useDetailCanvasLayer = ({
1374
1551
  return;
1375
1552
  }
1376
1553
  renderingTask?.cancel();
1377
- detailCanvas.style.display = "block";
1378
- detailCanvas.style.opacity = "0";
1379
1554
  const pdfOffsetX = visibleLeft;
1380
1555
  const pdfOffsetY = visibleTop;
1381
1556
  const effectiveScale = targetDetailScale;
1382
1557
  const actualWidth = visibleWidth * effectiveScale;
1383
1558
  const actualHeight = visibleHeight * effectiveScale;
1384
- detailCanvas.width = actualWidth;
1385
- detailCanvas.height = actualHeight;
1386
- detailCanvas.style.width = `${visibleWidth * zoom}px`;
1387
- detailCanvas.style.height = `${visibleHeight * zoom}px`;
1388
- detailCanvas.style.transformOrigin = "center center";
1389
- detailCanvas.style.transform = `translate(${visibleLeft * zoom}px, ${visibleTop * zoom}px)`;
1390
- container.style.transform = `scale3d(${1 / zoom}, ${1 / zoom}, 1)`;
1391
- container.style.transformOrigin = "0 0";
1392
- const context = detailCanvas.getContext("2d");
1393
- if (!context) {
1559
+ const buffer = document.createElement("canvas");
1560
+ buffer.width = actualWidth;
1561
+ buffer.height = actualHeight;
1562
+ const bufferCtx = buffer.getContext("2d");
1563
+ if (!bufferCtx) {
1394
1564
  return;
1395
1565
  }
1396
- context.setTransform(1, 0, 0, 1, 0, 0);
1397
- context.clearRect(0, 0, detailCanvas.width, detailCanvas.height);
1566
+ bufferCtx.setTransform(1, 0, 0, 1, 0, 0);
1398
1567
  const transform = [
1399
1568
  1,
1400
1569
  0,
@@ -1407,16 +1576,22 @@ var useDetailCanvasLayer = ({
1407
1576
  scale: effectiveScale
1408
1577
  });
1409
1578
  const currentRenderingTask = pdfPageProxy.render({
1410
- canvas: detailCanvas,
1411
- canvasContext: context,
1579
+ canvas: buffer,
1580
+ canvasContext: bufferCtx,
1412
1581
  viewport: detailViewport,
1413
1582
  background,
1414
1583
  transform
1415
1584
  });
1416
1585
  renderingTask = currentRenderingTask;
1417
1586
  currentRenderingTask.promise.then(() => {
1418
- if (renderingTask === currentRenderingTask) {
1419
- detailCanvas.style.opacity = "1";
1587
+ if (renderingTask !== currentRenderingTask) return;
1588
+ detailCanvas.width = actualWidth;
1589
+ detailCanvas.height = actualHeight;
1590
+ detailCanvas.style.cssText = `${detailBaseStyle};display:block;opacity:1;width:${visibleWidth * zoom}px;height:${visibleHeight * zoom}px;transform-origin:center center;transform:translate(${visibleLeft * zoom}px,${visibleTop * zoom}px)`;
1591
+ container.style.cssText = `transform:scale3d(${1 / zoom},${1 / zoom},1);transform-origin:0 0`;
1592
+ const ctx = detailCanvas.getContext("2d");
1593
+ if (ctx) {
1594
+ ctx.drawImage(buffer, 0, 0);
1420
1595
  }
1421
1596
  }).catch((error) => {
1422
1597
  if (error.name === "RenderingCancelledException") {
@@ -1427,13 +1602,15 @@ var useDetailCanvasLayer = ({
1427
1602
  if (renderingTask === currentRenderingTask) {
1428
1603
  renderingTask = null;
1429
1604
  }
1605
+ buffer.width = 0;
1606
+ buffer.height = 0;
1430
1607
  });
1431
1608
  };
1432
1609
  const scheduleRender = (delay = DETAIL_RENDER_IDLE_MS) => {
1433
1610
  if (renderTimeoutId !== null) {
1434
1611
  clearTimeout(renderTimeoutId);
1435
1612
  }
1436
- hideDetailCanvas();
1613
+ renderingTask?.cancel();
1437
1614
  renderTimeoutId = setTimeout(() => {
1438
1615
  renderTimeoutId = null;
1439
1616
  renderDetailCanvas();
@@ -1443,7 +1620,11 @@ var useDetailCanvasLayer = ({
1443
1620
  scrollContainer,
1444
1621
  scheduleRender
1445
1622
  );
1446
- scheduleRender(isPinching ? DETAIL_RENDER_IDLE_MS * 2 : 0);
1623
+ if (zoom <= 1 || isPinching) {
1624
+ hideDetailCanvas();
1625
+ } else {
1626
+ scheduleRender(0);
1627
+ }
1447
1628
  return () => {
1448
1629
  unsubscribe();
1449
1630
  if (renderTimeoutId !== null) {
@@ -1458,10 +1639,17 @@ var useDetailCanvasLayer = ({
1458
1639
  background,
1459
1640
  dpr,
1460
1641
  viewportRef,
1461
- getDetailCanvas,
1462
- clampScaleForPage,
1463
1642
  baseCanvasRef
1464
1643
  ]);
1644
+ useEffect(() => {
1645
+ const canvas = detailCanvasRef.current;
1646
+ return () => {
1647
+ if (canvas) {
1648
+ canvas.width = 1;
1649
+ canvas.height = 1;
1650
+ }
1651
+ };
1652
+ }, []);
1465
1653
  return {
1466
1654
  detailCanvasRef,
1467
1655
  containerRef
@@ -2201,6 +2389,10 @@ var ColoredHighlightLayer = ({
2201
2389
  (state) => state.coloredHighlights
2202
2390
  );
2203
2391
  const addColoredHighlight = usePdf((state) => state.addColoredHighlight);
2392
+ const pageHighlights = useMemo(
2393
+ () => highlights.filter((s) => s.pageNumber === pageNumber),
2394
+ [highlights, pageNumber]
2395
+ );
2204
2396
  const handleHighlighting = useCallback(
2205
2397
  (color) => {
2206
2398
  const dimension = getDimension();
@@ -2222,13 +2414,7 @@ var ColoredHighlightLayer = ({
2222
2414
  [onHighlight, getDimension, addColoredHighlight]
2223
2415
  );
2224
2416
  return /* @__PURE__ */ jsxs("div", { className: "colored-highlights-layer", children: [
2225
- highlights.filter((selection) => selection.pageNumber === pageNumber).map((selection) => /* @__PURE__ */ jsx(
2226
- ColoredHighlightComponent,
2227
- {
2228
- selection
2229
- },
2230
- selection.uuid
2231
- )),
2417
+ pageHighlights.map((selection) => /* @__PURE__ */ jsx(ColoredHighlightComponent, { selection }, selection.uuid)),
2232
2418
  /* @__PURE__ */ jsx(
2233
2419
  ColorSelectionTool,
2234
2420
  {
@@ -2256,7 +2442,10 @@ var HighlightLayer = forwardRef(({ asChild, className, style, ...props }, ref) =
2256
2442
  const pageNumber = usePDFPageNumber();
2257
2443
  const highlights = usePdf((state) => state.highlights);
2258
2444
  const Comp = asChild ? Slot : "div";
2259
- const rects = highlights.filter((area) => area.pageNumber === pageNumber);
2445
+ const rects = useMemo(
2446
+ () => highlights.filter((area) => area.pageNumber === pageNumber),
2447
+ [highlights, pageNumber]
2448
+ );
2260
2449
  if (!rects?.length) return null;
2261
2450
  return /* @__PURE__ */ jsx(Fragment, { children: rects.map((rect, index) => {
2262
2451
  const { pageNumber: pageNumber2, type, style: customStyle, ...coordinates } = rect;
@@ -2831,6 +3020,7 @@ var useVisiblePage = ({ items }) => {
2831
3020
  const isPinching = usePdf((state) => state.isPinching);
2832
3021
  const setCurrentPage = usePdf((state) => state.setCurrentPage);
2833
3022
  const scrollElement = usePdf((state) => state.viewportRef?.current);
3023
+ const lastPageRef = useRef(0);
2834
3024
  const calculateVisiblePageIndex = useCallback(
2835
3025
  (virtualItems) => {
2836
3026
  if (!scrollElement || virtualItems.length === 0) return 0;
@@ -2854,7 +3044,11 @@ var useVisiblePage = ({ items }) => {
2854
3044
  useEffect(() => {
2855
3045
  if (!isPinching && items.length > 0) {
2856
3046
  const mostVisibleIndex = calculateVisiblePageIndex(items);
2857
- setCurrentPage?.(mostVisibleIndex + 1);
3047
+ const page = mostVisibleIndex + 1;
3048
+ if (page !== lastPageRef.current) {
3049
+ lastPageRef.current = page;
3050
+ setCurrentPage?.(page);
3051
+ }
2858
3052
  }
2859
3053
  }, [items, isPinching, calculateVisiblePageIndex, setCurrentPage]);
2860
3054
  return null;
@@ -4929,8 +5123,10 @@ var useViewportContainer = ({
4929
5123
  origin
4930
5124
  };
4931
5125
  };
5126
+ var selectLargestPageWidth = (state) => state.viewports.reduce((max, vp) => Math.max(max, vp.width), 0);
4932
5127
  var DEFAULT_HEIGHT = 600;
4933
5128
  var EXTRA_HEIGHT = 0;
5129
+ var DEFAULT_VIRTUALIZER_OPTIONS = { overscan: 1 };
4934
5130
  var VirtualizedPageItem = memo(
4935
5131
  ({ child, virtualItem, innerBoxWidth }) => {
4936
5132
  return /* @__PURE__ */ jsx(
@@ -4963,7 +5159,7 @@ VirtualizedPageItem.displayName = "VirtualizedPageItem";
4963
5159
  var Pages = ({
4964
5160
  children,
4965
5161
  gap = 10,
4966
- virtualizerOptions = { overscan: 1 },
5162
+ virtualizerOptions = DEFAULT_VIRTUALIZER_OPTIONS,
4967
5163
  initialOffset,
4968
5164
  onOffsetChange,
4969
5165
  ...props
@@ -4983,12 +5179,16 @@ var Pages = ({
4983
5179
  const setVirtualizer = usePdf((state) => state.setVirtualizer);
4984
5180
  const { scrollToFn } = useScrollFn();
4985
5181
  const { observeElementOffset } = useObserveElement();
5182
+ const viewportsRef = useRef(viewports);
5183
+ viewportsRef.current = viewports;
4986
5184
  const estimateSize = useCallback(
4987
5185
  (index) => {
4988
- if (!viewports || !viewports[index]) return DEFAULT_HEIGHT;
4989
- return viewports[index].height + EXTRA_HEIGHT;
5186
+ const vp = viewportsRef.current;
5187
+ if (!vp || !vp[index]) return DEFAULT_HEIGHT;
5188
+ return vp[index].height + EXTRA_HEIGHT;
4990
5189
  },
4991
- [viewports]
5190
+ []
5191
+ // Stable — reads from ref
4992
5192
  );
4993
5193
  const virtualizer = useVirtualizer({
4994
5194
  count: numPages || 0,
@@ -5028,11 +5228,7 @@ var Pages = ({
5028
5228
  items
5029
5229
  });
5030
5230
  useFitWidth({ viewportRef: containerRef });
5031
- const largestPageWidth = usePdf(
5032
- (state) => state.viewports.reduce((largestWidth, viewport) => {
5033
- return Math.max(largestWidth, viewport.width);
5034
- }, 0)
5035
- );
5231
+ const largestPageWidth = usePdf(selectLargestPageWidth);
5036
5232
  useEffect(() => {
5037
5233
  virtualizer.getOffsetForAlignment = (toOffset, align, itemSize = 0) => {
5038
5234
  const size = virtualizer.getSize();
@@ -5108,17 +5304,44 @@ var Pages = ({
5108
5304
  }
5109
5305
  );
5110
5306
  };
5307
+ function buildDocumentInitParams(source, overrides) {
5308
+ let params;
5309
+ if (typeof source === "string" || source instanceof URL) {
5310
+ params = { url: source };
5311
+ } else if (source instanceof ArrayBuffer || ArrayBuffer.isView(source)) {
5312
+ params = { data: source };
5313
+ } else {
5314
+ params = { ...source };
5315
+ }
5316
+ const defaults = {
5317
+ // Skip the slow _guessMax binary-search auto-detection of max canvas area.
5318
+ // 1 GiB = 256 megapixels at 4 bytes/pixel. If the device can't allocate
5319
+ // this, pdfjs falls back gracefully via try/catch.
5320
+ canvasMaxAreaInBytes: 1024 * 1024 * 1024,
5321
+ // Enable GPU-backed canvases (willReadFrequently: false). PDF viewers are
5322
+ // render-dominated — they don't call getImageData() — so GPU compositing
5323
+ // is the correct path. This is the browser's default when no hint is given.
5324
+ enableHWA: true,
5325
+ // Explicitly opt-in to OffscreenCanvas in the worker for image processing.
5326
+ // Already the browser default, but being explicit avoids edge cases.
5327
+ isOffscreenCanvasSupported: true
5328
+ };
5329
+ return { ...defaults, ...params, ...overrides };
5330
+ }
5111
5331
  var usePDFDocumentContext = ({
5112
5332
  onDocumentLoad,
5113
5333
  source,
5114
5334
  initialRotation = 0,
5115
5335
  isZoomFitWidth,
5116
5336
  zoom = 1,
5117
- zoomOptions
5337
+ zoomOptions,
5338
+ documentOptions
5118
5339
  }) => {
5119
5340
  const [_, setProgress] = useState(0);
5120
5341
  const [initialState, setInitialState] = useState();
5121
5342
  const [rotation] = useState(initialRotation);
5343
+ const documentOptionsRef = useRef(documentOptions);
5344
+ documentOptionsRef.current = documentOptions;
5122
5345
  useEffect(() => {
5123
5346
  const generateViewports = async (pdf) => {
5124
5347
  const pageProxies = [];
@@ -5136,9 +5359,9 @@ var usePDFDocumentContext = ({
5136
5359
  return viewport;
5137
5360
  })
5138
5361
  );
5139
- const sortedPageProxies = pageProxies.sort((a, b) => {
5140
- return a.pageNumber - b.pageNumber;
5141
- });
5362
+ const sortedPageProxies = pageProxies.toSorted(
5363
+ (a, b) => a.pageNumber - b.pageNumber
5364
+ );
5142
5365
  setInitialState((prev) => ({
5143
5366
  ...prev,
5144
5367
  isZoomFitWidth,
@@ -5158,7 +5381,9 @@ var usePDFDocumentContext = ({
5158
5381
  if (isDisposed) {
5159
5382
  return;
5160
5383
  }
5161
- loadingTask = getDocument(source);
5384
+ loadingTask = getDocument(
5385
+ buildDocumentInitParams(source, documentOptionsRef.current)
5386
+ );
5162
5387
  loadingTask.onProgress = (progressEvent) => {
5163
5388
  if (progressEvent.loaded === progressEvent.total) {
5164
5389
  return;
@@ -5204,6 +5429,7 @@ var Root = forwardRef(
5204
5429
  isZoomFitWidth,
5205
5430
  zoom,
5206
5431
  zoomOptions,
5432
+ documentOptions,
5207
5433
  ...props
5208
5434
  }, ref) => {
5209
5435
  const { initialState } = usePDFDocumentContext({
@@ -5211,12 +5437,20 @@ var Root = forwardRef(
5211
5437
  onDocumentLoad,
5212
5438
  isZoomFitWidth,
5213
5439
  zoom,
5214
- zoomOptions
5440
+ zoomOptions,
5441
+ documentOptions
5215
5442
  });
5216
5443
  const linkService = useCreatePDFLinkService(
5217
5444
  initialState?.pdfDocumentProxy ?? null
5218
5445
  );
5219
- return /* @__PURE__ */ jsx(Primitive.div, { ref, ...props, children: initialState ? /* @__PURE__ */ jsx(PDFStore.Provider, { initialValue: initialState, children: /* @__PURE__ */ jsx(PDFLinkServiceContext.Provider, { value: linkService, children }) }) : loader || "Loading..." });
5446
+ const documentId = initialState?.pdfDocumentProxy.fingerprints[0];
5447
+ useEffect(() => {
5448
+ if (!documentId) return;
5449
+ return () => {
5450
+ renderCache.invalidateDocument(documentId);
5451
+ };
5452
+ }, [documentId]);
5453
+ return /* @__PURE__ */ jsx(Primitive.div, { ref, ...props, children: initialState ? /* @__PURE__ */ jsx(PDFStore.Provider, { initialValue: initialState, children: /* @__PURE__ */ jsx(PDFLinkServiceContext.Provider, { value: linkService, children }) }) : loader ?? "Loading..." });
5220
5454
  }
5221
5455
  );
5222
5456
  Root.displayName = "Root";
@@ -5266,8 +5500,8 @@ var useThumbnail = (pageNumber, config = {}) => {
5266
5500
  const isVisible = isFirstPage || debouncedVisible;
5267
5501
  useEffect(() => {
5268
5502
  const renderThumbnail = async () => {
5269
- const canvas = canvasRef.current;
5270
- if (!canvas || !pageProxy) return;
5503
+ const canvas2 = canvasRef.current;
5504
+ if (!canvas2 || !pageProxy) return;
5271
5505
  try {
5272
5506
  if (renderTaskRef.current) {
5273
5507
  renderTaskRef.current.cancel();
@@ -5275,12 +5509,12 @@ var useThumbnail = (pageNumber, config = {}) => {
5275
5509
  const viewport = pageProxy.getViewport({ scale: 1 });
5276
5510
  const scale = Math.min(maxWidth / viewport.width, maxHeight / viewport.height) * (isVisible ? dpr : 0.5);
5277
5511
  const scaledViewport = pageProxy.getViewport({ scale });
5278
- canvas.width = scaledViewport.width;
5279
- canvas.height = scaledViewport.height;
5280
- const context = canvas.getContext("2d");
5512
+ canvas2.width = scaledViewport.width;
5513
+ canvas2.height = scaledViewport.height;
5514
+ const context = canvas2.getContext("2d");
5281
5515
  if (!context) return;
5282
5516
  const renderTask = pageProxy.render({
5283
- canvas,
5517
+ canvas: canvas2,
5284
5518
  canvasContext: context,
5285
5519
  viewport: scaledViewport
5286
5520
  });
@@ -5295,8 +5529,13 @@ var useThumbnail = (pageNumber, config = {}) => {
5295
5529
  }
5296
5530
  };
5297
5531
  renderThumbnail();
5532
+ const canvas = canvasRef.current;
5298
5533
  return () => {
5299
5534
  renderTaskRef.current?.cancel();
5535
+ if (canvas) {
5536
+ canvas.width = 1;
5537
+ canvas.height = 1;
5538
+ }
5300
5539
  };
5301
5540
  }, [pageProxy, isVisible, dpr, maxHeight, maxWidth]);
5302
5541
  return {
@@ -5375,12 +5614,12 @@ var ZoomOut = ({ ...props }) => {
5375
5614
  );
5376
5615
  };
5377
5616
  var CurrentZoom = ({ ...props }) => {
5378
- const setRealZoom = usePdf((state) => state.updateZoom);
5617
+ const updateZoom = usePdf((state) => state.updateZoom);
5379
5618
  const realZoom = usePdf((state) => state.zoom);
5380
5619
  const [zoom, setZoom] = useState((realZoom * 100).toFixed(0));
5381
- const isSelected = useRef(false);
5620
+ const isInputFocused = useRef(false);
5382
5621
  useEffect(() => {
5383
- if (isSelected.current) {
5622
+ if (isInputFocused.current) {
5384
5623
  return;
5385
5624
  }
5386
5625
  setZoom((realZoom * 100).toFixed(0));
@@ -5391,14 +5630,14 @@ var CurrentZoom = ({ ...props }) => {
5391
5630
  ...props,
5392
5631
  value: zoom,
5393
5632
  onClick: () => {
5394
- isSelected.current = true;
5633
+ isInputFocused.current = true;
5395
5634
  },
5396
5635
  onChange: (e) => {
5397
- setRealZoom(Number(e.target.value) / 100);
5636
+ updateZoom(Number(e.target.value) / 100);
5398
5637
  setZoom(e.target.value);
5399
5638
  },
5400
5639
  onBlur: () => {
5401
- isSelected.current = false;
5640
+ isInputFocused.current = false;
5402
5641
  setZoom((realZoom * 100).toFixed(0));
5403
5642
  }
5404
5643
  }
@@ -5631,4 +5870,7 @@ function mergeAdjacentRects(rects) {
5631
5870
  return merged;
5632
5871
  }
5633
5872
 
5634
- export { AnnotationHighlightLayer, AnnotationLayer, AnnotationTooltip, CanvasLayer, ColoredHighlightLayer, CurrentPage, CurrentZoom, CustomLayer, HighlightLayer, LinkService, NextPage, Outline, OutlineChildItems, OutlineItem, PDFLinkServiceContext, Page, Pages, PreviousPage, Root, Search, SelectionTooltip, TextLayer, Thumbnail, Thumbnails, TotalPages, ZoomIn, ZoomOut, calculateHighlightRects, useAnnotations, useCreatePDFLinkService, usePDFLinkService, usePDFPageNumber, usePdf, usePdfJump, useSearch, useSelectionDimensions };
5873
+ // src/hooks/usePageRendered.ts
5874
+ var usePageRendered = (pageNumber) => usePdf((state) => !!state.renderedPages[pageNumber]);
5875
+
5876
+ export { AnnotationHighlightLayer, AnnotationLayer, AnnotationTooltip, CanvasLayer, ColoredHighlightLayer, CurrentPage, CurrentZoom, CustomLayer, HighlightLayer, LinkService, NextPage, Outline, OutlineChildItems, OutlineItem, PDFLinkServiceContext, Page, Pages, PreviousPage, Root, Search, SelectionTooltip, TextLayer, Thumbnail, Thumbnails, TotalPages, ZoomIn, ZoomOut, calculateHighlightRects, useAnnotations, useCreatePDFLinkService, usePDFLinkService, usePDFPageNumber, usePageRendered, usePdf, usePdfJump, useSearch, useSelectionDimensions };
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@anaralabs/lector",
3
- "version": "3.10.0",
4
- "description": "Headless PDF viewer for React",
3
+ "version": "3.10.1",
4
+ "description": "A headless PDF viewer for React",
5
5
  "author": "andrewdr (https://github.com/andrewdoro)",
6
6
  "license": "MIT",
7
7
  "type": "module",