@anaralabs/lector 3.6.0 → 3.7.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.
package/dist/index.js CHANGED
@@ -1,15 +1,15 @@
1
1
  'use client';
2
2
 
3
- import React, { createContext, forwardRef, useRef, useState, useCallback, useContext, useEffect, cloneElement, createRef, useLayoutEffect } from 'react';
3
+ import React, { createContext, forwardRef, useRef, useState, useCallback, useContext, useEffect, cloneElement, createRef, useMemo, useLayoutEffect } 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
- import { useVirtualizer, elementScroll, debounce } from '@tanstack/react-virtual';
7
6
  import { create, useStore, createStore } from 'zustand';
8
7
  import { jsx, Fragment, jsxs } from 'react/jsx-runtime';
9
8
  import { AnnotationLayer, TextLayer, getDocument } from 'pdfjs-dist';
10
9
  import { useDebounce } from 'use-debounce';
11
10
  import { v4 } from 'uuid';
12
11
  import { Slot } from '@radix-ui/react-slot';
12
+ import { useVirtualizer, elementScroll, debounce } from '@tanstack/react-virtual';
13
13
 
14
14
  // src/components/annotation-tooltip.tsx
15
15
 
@@ -146,11 +146,7 @@ var useAnnotationTooltip = ({
146
146
  const viewportRef = usePdf((state) => state.viewportRef);
147
147
  const scale = usePdf((state) => state.zoom);
148
148
  const effectiveIsOpen = (isOpen && isPositionCalculated || controlledIsOpen) ?? false;
149
- const {
150
- refs,
151
- floatingStyles,
152
- context
153
- } = useFloating({
149
+ const { refs, floatingStyles, context } = useFloating({
154
150
  placement: position,
155
151
  open: effectiveIsOpen,
156
152
  onOpenChange: (open) => {
@@ -185,7 +181,9 @@ var useAnnotationTooltip = ({
185
181
  setIsPositionCalculated(false);
186
182
  return;
187
183
  }
188
- const pageElement = viewportElement.querySelector(`[data-page-number="${annotation.pageNumber}"]`);
184
+ const pageElement = viewportElement.querySelector(
185
+ `[data-page-number="${annotation.pageNumber}"]`
186
+ );
189
187
  if (!pageElement) {
190
188
  setIsPositionCalculated(false);
191
189
  return;
@@ -232,7 +230,14 @@ var useAnnotationTooltip = ({
232
230
  if (isNewAnnotation) {
233
231
  setIsOpen(true);
234
232
  }
235
- }, [annotation.highlights, annotation.pageNumber, refs, viewportRef, scale, isNewAnnotation]);
233
+ }, [
234
+ annotation.highlights,
235
+ annotation.pageNumber,
236
+ refs,
237
+ viewportRef,
238
+ scale,
239
+ isNewAnnotation
240
+ ]);
236
241
  useEffect(() => {
237
242
  const viewport = viewportRef.current;
238
243
  setIsPositionCalculated(false);
@@ -257,7 +262,7 @@ var useAnnotationTooltip = ({
257
262
  }
258
263
  window.removeEventListener("resize", handleResize);
259
264
  };
260
- }, [updateTooltipPosition, viewportRef, scale, controlledIsOpen]);
265
+ }, [updateTooltipPosition, viewportRef]);
261
266
  return {
262
267
  isOpen: effectiveIsOpen,
263
268
  setIsOpen,
@@ -326,7 +331,13 @@ var AnnotationTooltip = ({
326
331
  }
327
332
  setHoverIsOpen(true);
328
333
  }
329
- }, [hoverTooltipContent, setHoverIsOpen]);
334
+ }, [
335
+ hoverTooltipContent,
336
+ setHoverIsOpen,
337
+ annotation.id,
338
+ focusedHoverOpenId,
339
+ focusedOpenId
340
+ ]);
330
341
  const closeTooltip = useCallback(() => {
331
342
  if (!isMouseInTooltipRef.current) {
332
343
  setHoverIsOpen(false);
@@ -344,7 +355,7 @@ var AnnotationTooltip = ({
344
355
  clearTimeout(closeTimeoutRef.current);
345
356
  closeTimeoutRef.current = null;
346
357
  }
347
- }, []);
358
+ }, [annotation.id, focusedOpenId, focusedHoverOpenId]);
348
359
  const handleTooltipMouseLeave = useCallback(() => {
349
360
  isMouseInTooltipRef.current = false;
350
361
  setHoverIsOpen(false);
@@ -414,10 +425,7 @@ var AnnotationTooltip = ({
414
425
  var useAnnotations = create((set) => ({
415
426
  annotations: [],
416
427
  addAnnotation: (annotation) => set((state) => ({
417
- annotations: [
418
- ...state.annotations,
419
- annotation
420
- ]
428
+ annotations: [...state.annotations, annotation]
421
429
  })),
422
430
  updateAnnotation: (id, updates) => set((state) => ({
423
431
  annotations: state.annotations.map(
@@ -428,7 +436,9 @@ var useAnnotations = create((set) => ({
428
436
  )
429
437
  })),
430
438
  deleteAnnotation: (id) => set((state) => ({
431
- annotations: state.annotations.filter((annotation) => annotation.id !== id)
439
+ annotations: state.annotations.filter(
440
+ (annotation) => annotation.id !== id
441
+ )
432
442
  })),
433
443
  setAnnotations: (annotations) => set({ annotations })
434
444
  }));
@@ -545,7 +555,8 @@ var AnnotationHighlightLayer = ({
545
555
  },
546
556
  "data-highlight-id": annotation.id
547
557
  },
548
- `highlight-${index}`
558
+ `highlight-${// biome-ignore lint/suspicious/noArrayIndexKey: <index>
559
+ index}`
549
560
  )),
550
561
  annotation.comment && annotation.underlines?.map((rect, index) => /* @__PURE__ */ jsx(
551
562
  "div",
@@ -561,7 +572,8 @@ var AnnotationHighlightLayer = ({
561
572
  },
562
573
  "data-comment-id": annotation.id
563
574
  },
564
- `underline-${index}`
575
+ `underline-${// biome-ignore lint/suspicious/noArrayIndexKey: <index>
576
+ index}`
565
577
  )),
566
578
  annotation.comment && commmentIcon && /* @__PURE__ */ jsx(
567
579
  "div",
@@ -627,71 +639,86 @@ var cancellable = (promise) => {
627
639
  }
628
640
  };
629
641
  };
630
-
631
- // src/hooks/pages/usePdfJump.tsx
632
642
  var usePdfJump = () => {
633
643
  const virtualizer = usePdf((state) => state.virtualizer);
634
644
  const setHighlight = usePdf((state) => state.setHighlight);
635
- const jumpToPage = (pageIndex, options) => {
636
- if (!virtualizer) return;
637
- const defaultOptions = {
638
- align: "start",
639
- behavior: "smooth"
640
- };
641
- const finalOptions = { ...defaultOptions, ...options };
642
- virtualizer.scrollToIndex(pageIndex - 1, finalOptions);
643
- };
644
- const jumpToOffset = (offset3) => {
645
- if (!virtualizer) return;
646
- virtualizer.scrollToOffset(offset3, {
647
- align: "start",
648
- behavior: "smooth"
649
- });
650
- };
651
- const scrollToHighlightRects = (rects, type, align = "start", additionalOffset = 0) => {
652
- if (!virtualizer) return;
653
- const firstPage = Math.min(...rects.map((rect) => rect.pageNumber));
654
- const pageOffset = virtualizer.getOffsetForIndex(firstPage - 1, "start");
655
- if (pageOffset === null) return;
656
- const targetRect = rects.find((rect) => rect.pageNumber === firstPage);
657
- if (!targetRect) return;
658
- const isNumber = pageOffset?.[0] != null;
659
- if (!isNumber) return;
660
- const pageStart = pageOffset[0] ?? 0;
661
- let rectTop;
662
- let rectHeight;
663
- if (type === "percent") {
664
- const estimatePageHeight = virtualizer.options.estimateSize(
665
- firstPage - 1
666
- );
667
- rectTop = targetRect.top / 100 * estimatePageHeight;
668
- rectHeight = targetRect.height / 100 * estimatePageHeight;
669
- } else {
670
- rectTop = targetRect.top;
671
- rectHeight = targetRect.height;
672
- }
673
- let scrollOffset;
674
- if (align === "center") {
675
- const viewportHeight = virtualizer.scrollElement?.clientHeight || 0;
676
- const rectCenter = pageStart + rectTop + rectHeight / 2;
677
- scrollOffset = rectCenter - viewportHeight / 2;
678
- } else {
679
- scrollOffset = pageStart + rectTop;
680
- }
681
- scrollOffset += additionalOffset;
682
- const adjustedOffset = Math.max(0, scrollOffset);
683
- virtualizer.scrollToOffset(adjustedOffset, {
684
- align: "start",
685
- // Always use start when we've calculated our own centering
686
- behavior: "smooth"
687
- });
688
- };
689
- const jumpToHighlightRects = (rects, type, align = "start", additionalOffset = 0) => {
690
- if (!virtualizer) return;
691
- setHighlight(rects);
692
- scrollToHighlightRects(rects, type, align, additionalOffset);
645
+ const jumpToPage = useCallback(
646
+ (pageIndex, options) => {
647
+ if (!virtualizer) return;
648
+ const defaultOptions = {
649
+ align: "start",
650
+ behavior: "smooth"
651
+ };
652
+ const finalOptions = { ...defaultOptions, ...options };
653
+ virtualizer.scrollToIndex(pageIndex - 1, finalOptions);
654
+ },
655
+ [virtualizer]
656
+ );
657
+ const jumpToOffset = useCallback(
658
+ (offset3) => {
659
+ if (!virtualizer) return;
660
+ virtualizer.scrollToOffset(offset3, {
661
+ align: "start",
662
+ behavior: "smooth"
663
+ });
664
+ },
665
+ [virtualizer]
666
+ );
667
+ const scrollToHighlightRects = useCallback(
668
+ (rects, type, align = "start", additionalOffset = 0) => {
669
+ if (!virtualizer) return;
670
+ const firstPage = Math.min(...rects.map((rect) => rect.pageNumber));
671
+ const pageOffset = virtualizer.getOffsetForIndex(firstPage - 1, "start");
672
+ if (pageOffset === null) return;
673
+ const targetRect = rects.find((rect) => rect.pageNumber === firstPage);
674
+ if (!targetRect) return;
675
+ const isNumber = pageOffset?.[0] != null;
676
+ if (!isNumber) return;
677
+ const pageStart = pageOffset[0] ?? 0;
678
+ let rectTop;
679
+ let rectHeight;
680
+ if (type === "percent") {
681
+ const estimatePageHeight = virtualizer.options.estimateSize(
682
+ firstPage - 1
683
+ );
684
+ rectTop = targetRect.top / 100 * estimatePageHeight;
685
+ rectHeight = targetRect.height / 100 * estimatePageHeight;
686
+ } else {
687
+ rectTop = targetRect.top;
688
+ rectHeight = targetRect.height;
689
+ }
690
+ let scrollOffset;
691
+ if (align === "center") {
692
+ const viewportHeight = virtualizer.scrollElement?.clientHeight || 0;
693
+ const rectCenter = pageStart + rectTop + rectHeight / 2;
694
+ scrollOffset = rectCenter - viewportHeight / 2;
695
+ } else {
696
+ scrollOffset = pageStart + rectTop;
697
+ }
698
+ scrollOffset += additionalOffset;
699
+ const adjustedOffset = Math.max(0, scrollOffset);
700
+ virtualizer.scrollToOffset(adjustedOffset, {
701
+ align: "start",
702
+ // Always use start when we've calculated our own centering
703
+ behavior: "smooth"
704
+ });
705
+ },
706
+ [virtualizer]
707
+ );
708
+ const jumpToHighlightRects = useCallback(
709
+ (rects, type, align = "start", additionalOffset = 0) => {
710
+ if (!virtualizer) return;
711
+ setHighlight(rects);
712
+ scrollToHighlightRects(rects, type, align, additionalOffset);
713
+ },
714
+ [virtualizer, setHighlight, scrollToHighlightRects]
715
+ );
716
+ return {
717
+ jumpToPage,
718
+ jumpToOffset,
719
+ jumpToHighlightRects,
720
+ scrollToHighlightRects
693
721
  };
694
- return { jumpToPage, jumpToOffset, jumpToHighlightRects, scrollToHighlightRects };
695
722
  };
696
723
  var LinkService = class {
697
724
  _pdfDocumentProxy;
@@ -705,8 +732,6 @@ var LinkService = class {
705
732
  }
706
733
  return this._pdfDocumentProxy;
707
734
  }
708
- constructor() {
709
- }
710
735
  get pagesCount() {
711
736
  return this._pdfDocumentProxy?.numPages || 0;
712
737
  }
@@ -815,19 +840,14 @@ var LinkService = class {
815
840
  get rotation() {
816
841
  return 0;
817
842
  }
818
- set rotation(value) {
843
+ set rotation(_value) {
819
844
  }
820
- goToPage(pageNumber) {
821
- if (pageNumber >= 1 && pageNumber <= this.pagesCount) {
822
- if (this._pageNavigationCallback) {
823
- this._pageNavigationCallback(pageNumber);
824
- }
825
- }
845
+ goToPage(_page_valuer) {
826
846
  }
827
847
  setHash(hash) {
828
848
  if (hash.startsWith("#page=")) {
829
849
  const pageNumber = parseInt(hash.substring(6), 10);
830
- if (!isNaN(pageNumber)) {
850
+ if (!Number.isNaN(pageNumber)) {
831
851
  this.goToPage(pageNumber);
832
852
  }
833
853
  }
@@ -874,7 +894,9 @@ var defaultAnnotationLayerParams = {
874
894
  jumpOptions: { behavior: "smooth", align: "start" }
875
895
  };
876
896
  var useAnnotationLayer = (params) => {
877
- const mergedParams = { ...defaultAnnotationLayerParams, ...params };
897
+ const mergedParams = useMemo(() => {
898
+ return { ...defaultAnnotationLayerParams, ...params };
899
+ }, [params]);
878
900
  const annotationLayerRef = useRef(null);
879
901
  const annotationLayerObjectRef = useRef(null);
880
902
  const linkService = usePDFLinkService();
@@ -950,7 +972,7 @@ var useAnnotationLayer = (params) => {
950
972
  if (href.startsWith("#page=")) {
951
973
  e.preventDefault();
952
974
  const pageNumber2 = parseInt(href.substring(6), 10);
953
- if (!isNaN(pageNumber2)) {
975
+ if (!Number.isNaN(pageNumber2)) {
954
976
  linkService.goToPage(pageNumber2);
955
977
  }
956
978
  }
@@ -1060,11 +1082,13 @@ var useDpr = () => {
1060
1082
  return () => {
1061
1083
  windowMatch.removeEventListener("change", handleDPRChange);
1062
1084
  };
1063
- }, []);
1085
+ }, [dpr]);
1064
1086
  return dpr;
1065
1087
  };
1066
1088
 
1067
1089
  // src/hooks/layers/useCanvasLayer.tsx
1090
+ var MAX_CANVAS_PIXELS = 16777216;
1091
+ var MAX_CANVAS_DIMENSION = 32767;
1068
1092
  var useCanvasLayer = ({ background }) => {
1069
1093
  const canvasRef = useRef(null);
1070
1094
  const pageNumber = usePDFPageNumber();
@@ -1072,21 +1096,55 @@ var useCanvasLayer = ({ background }) => {
1072
1096
  const bouncyZoom = usePdf((state) => state.zoom);
1073
1097
  const pdfPageProxy = usePdf((state) => state.getPdfPageProxy(pageNumber));
1074
1098
  const [zoom] = useDebounce(bouncyZoom, 100);
1099
+ const clampScaleForPage = useCallback(
1100
+ (targetScale, pageWidth, pageHeight) => {
1101
+ if (!targetScale) {
1102
+ return 0;
1103
+ }
1104
+ const areaLimit = Math.sqrt(
1105
+ MAX_CANVAS_PIXELS / Math.max(pageWidth * pageHeight, 1)
1106
+ );
1107
+ const widthLimit = MAX_CANVAS_DIMENSION / Math.max(pageWidth, 1);
1108
+ const heightLimit = MAX_CANVAS_DIMENSION / Math.max(pageHeight, 1);
1109
+ const safeScale = Math.min(
1110
+ targetScale,
1111
+ Number.isFinite(areaLimit) ? areaLimit : targetScale,
1112
+ Number.isFinite(widthLimit) ? widthLimit : targetScale,
1113
+ Number.isFinite(heightLimit) ? heightLimit : targetScale
1114
+ );
1115
+ return Math.max(safeScale, 0);
1116
+ },
1117
+ []
1118
+ );
1075
1119
  useLayoutEffect(() => {
1076
1120
  if (!canvasRef.current) {
1077
1121
  return;
1078
1122
  }
1079
- const viewport = pdfPageProxy.getViewport({ scale: 1 });
1080
- const canvas = canvasRef.current;
1081
- const scale = dpr * zoom;
1082
- canvas.height = viewport.height * scale;
1083
- canvas.width = viewport.width * scale;
1084
- canvas.style.height = `${viewport.height}px`;
1085
- canvas.style.width = `${viewport.width}px`;
1086
- const canvasContext = canvas.getContext("2d");
1087
- canvasContext.scale(scale, scale);
1123
+ const baseCanvas = canvasRef.current;
1124
+ const baseViewport = pdfPageProxy.getViewport({ scale: 1 });
1125
+ const pageWidth = baseViewport.width;
1126
+ const pageHeight = baseViewport.height;
1127
+ const targetBaseScale = dpr * Math.min(zoom, 1);
1128
+ const baseScale = clampScaleForPage(targetBaseScale, pageWidth, pageHeight);
1129
+ baseCanvas.width = Math.floor(pageWidth * baseScale);
1130
+ baseCanvas.height = Math.floor(pageHeight * baseScale);
1131
+ baseCanvas.style.position = "absolute";
1132
+ baseCanvas.style.top = "0";
1133
+ baseCanvas.style.left = "0";
1134
+ baseCanvas.style.width = `${pageWidth}px`;
1135
+ baseCanvas.style.height = `${pageHeight}px`;
1136
+ baseCanvas.style.transform = "translate(0px, 0px)";
1137
+ baseCanvas.style.zIndex = "0";
1138
+ baseCanvas.style.pointerEvents = "none";
1139
+ const context = baseCanvas.getContext("2d");
1140
+ if (!context) {
1141
+ return;
1142
+ }
1143
+ context.setTransform(1, 0, 0, 1, 0, 0);
1144
+ context.clearRect(0, 0, baseCanvas.width, baseCanvas.height);
1145
+ const viewport = pdfPageProxy.getViewport({ scale: baseScale });
1088
1146
  const renderingTask = pdfPageProxy.render({
1089
- canvasContext,
1147
+ canvasContext: context,
1090
1148
  viewport,
1091
1149
  background
1092
1150
  });
@@ -1099,32 +1157,211 @@ var useCanvasLayer = ({ background }) => {
1099
1157
  return () => {
1100
1158
  void renderingTask.cancel();
1101
1159
  };
1102
- }, [pdfPageProxy, dpr, zoom]);
1160
+ }, [pdfPageProxy, background, dpr, zoom, clampScaleForPage]);
1103
1161
  return {
1104
1162
  canvasRef
1105
1163
  };
1106
1164
  };
1165
+ var MAX_CANVAS_PIXELS2 = 16777216;
1166
+ var MAX_CANVAS_DIMENSION2 = 32767;
1167
+ var useDetailCanvasLayer = ({
1168
+ background,
1169
+ baseCanvasRef
1170
+ }) => {
1171
+ const containerRef = useRef(null);
1172
+ const detailCanvasRef = useRef(null);
1173
+ const pageNumber = usePDFPageNumber();
1174
+ const dpr = useDpr();
1175
+ const bouncyZoom = usePdf((state) => state.zoom);
1176
+ const pdfPageProxy = usePdf((state) => state.getPdfPageProxy(pageNumber));
1177
+ const viewportRef = usePdf((state) => state.viewportRef);
1178
+ const [zoom] = useDebounce(bouncyZoom, 200);
1179
+ const [scrollTick, setScrollTick] = useState(0);
1180
+ const [debouncedScrollTick] = useDebounce(scrollTick, 20);
1181
+ const ensureDetailCanvas = useCallback(() => {
1182
+ let detailCanvas = detailCanvasRef.current;
1183
+ if (!detailCanvas) {
1184
+ const parent = baseCanvasRef.current?.parentElement;
1185
+ if (!parent) {
1186
+ return null;
1187
+ }
1188
+ detailCanvas = document.createElement("canvas");
1189
+ parent.appendChild(detailCanvas);
1190
+ detailCanvasRef.current = detailCanvas;
1191
+ }
1192
+ detailCanvas.style.position = "absolute";
1193
+ detailCanvas.style.top = "0";
1194
+ detailCanvas.style.left = "0";
1195
+ detailCanvas.style.pointerEvents = "none";
1196
+ detailCanvas.style.zIndex = "0";
1197
+ return detailCanvas;
1198
+ }, [baseCanvasRef]);
1199
+ const clampScaleForPage = useCallback(
1200
+ (targetScale, pageWidth, pageHeight) => {
1201
+ if (!targetScale) {
1202
+ return 0;
1203
+ }
1204
+ const areaLimit = Math.sqrt(
1205
+ MAX_CANVAS_PIXELS2 / Math.max(pageWidth * pageHeight, 1)
1206
+ );
1207
+ const widthLimit = MAX_CANVAS_DIMENSION2 / Math.max(pageWidth, 1);
1208
+ const heightLimit = MAX_CANVAS_DIMENSION2 / Math.max(pageHeight, 1);
1209
+ const safeScale = Math.min(
1210
+ targetScale,
1211
+ Number.isFinite(areaLimit) ? areaLimit : targetScale,
1212
+ Number.isFinite(widthLimit) ? widthLimit : targetScale,
1213
+ Number.isFinite(heightLimit) ? heightLimit : targetScale
1214
+ );
1215
+ return Math.max(safeScale, 0);
1216
+ },
1217
+ []
1218
+ );
1219
+ useLayoutEffect(() => {
1220
+ const scrollContainer = viewportRef?.current;
1221
+ if (!scrollContainer) return;
1222
+ const handleScroll = () => {
1223
+ setScrollTick((prev) => prev + 1);
1224
+ };
1225
+ scrollContainer.addEventListener("scroll", handleScroll, { passive: true });
1226
+ return () => {
1227
+ scrollContainer.removeEventListener("scroll", handleScroll);
1228
+ };
1229
+ }, [viewportRef?.current]);
1230
+ useLayoutEffect(() => {
1231
+ if (!viewportRef?.current) {
1232
+ return;
1233
+ }
1234
+ const detailCanvas = ensureDetailCanvas();
1235
+ const container = containerRef.current;
1236
+ if (!detailCanvas || !container) {
1237
+ return;
1238
+ }
1239
+ const scrollContainer = viewportRef.current;
1240
+ const pageContainer = baseCanvasRef.current?.parentElement ?? null;
1241
+ if (!pageContainer) {
1242
+ detailCanvas.style.display = "none";
1243
+ detailCanvas.width = 0;
1244
+ detailCanvas.height = 0;
1245
+ return;
1246
+ }
1247
+ const baseViewport = pdfPageProxy.getViewport({ scale: 1 });
1248
+ const pageWidth = baseViewport.width;
1249
+ const pageHeight = baseViewport.height;
1250
+ const scrollX = scrollContainer.scrollLeft / zoom;
1251
+ const scrollY = scrollContainer.scrollTop / zoom;
1252
+ const viewportWidth = scrollContainer.clientWidth / zoom;
1253
+ const viewportHeight = scrollContainer.clientHeight / zoom;
1254
+ const pageRect = pageContainer.getBoundingClientRect();
1255
+ const containerRect = scrollContainer.getBoundingClientRect();
1256
+ const pageLeft = (pageRect.left - containerRect.left) / zoom + scrollX;
1257
+ const pageTop = (pageRect.top - containerRect.top) / zoom + scrollY;
1258
+ const visibleLeft = Math.max(0, scrollX - pageLeft);
1259
+ const visibleTop = Math.max(0, scrollY - pageTop);
1260
+ const visibleRight = Math.min(
1261
+ pageWidth,
1262
+ scrollX + viewportWidth - pageLeft
1263
+ );
1264
+ const visibleBottom = Math.min(
1265
+ pageHeight,
1266
+ scrollY + viewportHeight - pageTop
1267
+ );
1268
+ const visibleWidth = Math.max(0, visibleRight - visibleLeft);
1269
+ const visibleHeight = Math.max(0, visibleBottom - visibleTop);
1270
+ const targetDetailScale = dpr * zoom / 2;
1271
+ const baseTargetScale = dpr * Math.min(zoom, 1);
1272
+ const baseScale = clampScaleForPage(baseTargetScale, pageWidth, pageHeight);
1273
+ const needsDetail = zoom > 1 && targetDetailScale - baseScale > 1e-3;
1274
+ if (!needsDetail || visibleWidth <= 0 || visibleHeight <= 0) {
1275
+ detailCanvas.style.display = "none";
1276
+ detailCanvas.width = 0;
1277
+ detailCanvas.height = 0;
1278
+ return;
1279
+ }
1280
+ detailCanvas.style.display = "block";
1281
+ const pdfOffsetX = visibleLeft;
1282
+ const pdfOffsetY = visibleTop;
1283
+ const pdfWidth = visibleWidth * targetDetailScale;
1284
+ const pdfHeight = visibleHeight * targetDetailScale;
1285
+ const effectiveScale = targetDetailScale;
1286
+ const actualWidth = pdfWidth;
1287
+ const actualHeight = pdfHeight;
1288
+ detailCanvas.width = actualWidth;
1289
+ detailCanvas.height = actualHeight;
1290
+ const scaledWidth = visibleWidth * zoom;
1291
+ const scaledHeight = visibleHeight * zoom;
1292
+ detailCanvas.style.width = `${scaledWidth}px`;
1293
+ detailCanvas.style.height = `${scaledHeight}px`;
1294
+ detailCanvas.style.transformOrigin = "center center";
1295
+ detailCanvas.style.transform = `translate(${visibleLeft * zoom}px, ${visibleTop * zoom}px) `;
1296
+ container.style.transform = `scale3d(${1 / zoom}, ${1 / zoom}, 1)`;
1297
+ container.style.transformOrigin = `0 0`;
1298
+ const context = detailCanvas.getContext("2d");
1299
+ if (!context) {
1300
+ return;
1301
+ }
1302
+ context.setTransform(1, 0, 0, 1, 0, 0);
1303
+ context.clearRect(0, 0, detailCanvas.width, detailCanvas.height);
1304
+ const transform = [
1305
+ 1,
1306
+ 0,
1307
+ 0,
1308
+ 1,
1309
+ -pdfOffsetX * effectiveScale,
1310
+ -pdfOffsetY * effectiveScale
1311
+ ];
1312
+ const detailViewport = pdfPageProxy.getViewport({ scale: effectiveScale });
1313
+ const renderingTask = pdfPageProxy.render({
1314
+ canvasContext: context,
1315
+ viewport: detailViewport,
1316
+ background,
1317
+ transform
1318
+ });
1319
+ renderingTask.promise.catch((error) => {
1320
+ if (error.name === "RenderingCancelledException") {
1321
+ return;
1322
+ }
1323
+ throw error;
1324
+ });
1325
+ return () => {
1326
+ void renderingTask.cancel();
1327
+ };
1328
+ }, [
1329
+ pdfPageProxy,
1330
+ zoom,
1331
+ background,
1332
+ dpr,
1333
+ viewportRef,
1334
+ ensureDetailCanvas,
1335
+ clampScaleForPage,
1336
+ baseCanvasRef,
1337
+ debouncedScrollTick
1338
+ ]);
1339
+ return {
1340
+ detailCanvasRef,
1341
+ containerRef
1342
+ };
1343
+ };
1107
1344
  var CanvasLayer = ({
1108
1345
  style,
1109
1346
  background,
1110
1347
  ...props
1111
1348
  }) => {
1112
1349
  const { canvasRef } = useCanvasLayer({ background });
1113
- return /* @__PURE__ */ jsx(
1114
- "canvas",
1115
- {
1116
- style: {
1117
- ...style,
1118
- position: "absolute",
1119
- top: 0,
1120
- left: 0,
1121
- width: "100%",
1122
- height: "100%"
1123
- },
1124
- ...props,
1125
- ref: canvasRef
1126
- }
1127
- );
1350
+ const { detailCanvasRef, containerRef } = useDetailCanvasLayer({
1351
+ background,
1352
+ baseCanvasRef: canvasRef
1353
+ });
1354
+ return /* @__PURE__ */ jsxs(Fragment, { children: [
1355
+ /* @__PURE__ */ jsx("canvas", { ...props, ref: canvasRef, style }),
1356
+ /* @__PURE__ */ jsx(
1357
+ "div",
1358
+ {
1359
+ ref: containerRef,
1360
+ className: "absolute top-0 left-0 w-full h-full flex items-center justify-center",
1361
+ children: /* @__PURE__ */ jsx("canvas", { ref: detailCanvasRef })
1362
+ }
1363
+ )
1364
+ ] });
1128
1365
  };
1129
1366
 
1130
1367
  // src/hooks/useSelectionDimensions.tsx
@@ -1155,9 +1392,15 @@ var consolidateHighlightRects = (rects) => {
1155
1392
  Math.abs(current.left + current.width - next.left) <= current.height * 0.2);
1156
1393
  if (horizontallyConnected) {
1157
1394
  const newLeft = Math.min(current.left, next.left);
1158
- const newRight = Math.max(current.left + current.width, next.left + next.width);
1395
+ const newRight = Math.max(
1396
+ current.left + current.width,
1397
+ next.left + next.width
1398
+ );
1159
1399
  const newTop = Math.min(current.top, next.top);
1160
- const newBottom = Math.max(current.top + current.height, next.top + next.height);
1400
+ const newBottom = Math.max(
1401
+ current.top + current.height,
1402
+ next.top + next.height
1403
+ );
1161
1404
  current = {
1162
1405
  left: newLeft,
1163
1406
  top: newTop,
@@ -1375,7 +1618,10 @@ var useSelectionDimensions = () => {
1375
1618
  const nextRect = group[endIndex + 1];
1376
1619
  if (!currentRect || !nextRect) break;
1377
1620
  const gap = nextRect.left - (currentRect.left + currentRect.width);
1378
- const maxGapAllowed = Math.max(MERGE_THRESHOLD, currentRect.height * 0.3);
1621
+ const maxGapAllowed = Math.max(
1622
+ MERGE_THRESHOLD,
1623
+ currentRect.height * 0.3
1624
+ );
1379
1625
  if (gap <= maxGapAllowed) {
1380
1626
  endIndex++;
1381
1627
  } else {
@@ -1416,7 +1662,9 @@ var useSelectionDimensions = () => {
1416
1662
  }
1417
1663
  return {
1418
1664
  highlights: highlightRects.sort((a, b) => a.pageNumber - b.pageNumber),
1419
- underlines: consolidateUnderlines(underlineRects).sort((a, b) => a.pageNumber - b.pageNumber),
1665
+ underlines: consolidateUnderlines(underlineRects).sort(
1666
+ (a, b) => a.pageNumber - b.pageNumber
1667
+ ),
1420
1668
  text: range.toString().trim(),
1421
1669
  isCollapsed: false
1422
1670
  };
@@ -1612,7 +1860,7 @@ var SelectionTooltip = ({ children }) => {
1612
1860
  viewportRef.current.removeEventListener("scroll", handleScroll);
1613
1861
  }
1614
1862
  };
1615
- }, [refs, isOpen, viewportRef, updateTooltipPosition]);
1863
+ }, [isOpen, viewportRef, updateTooltipPosition]);
1616
1864
  useEffect(() => {
1617
1865
  const handleFloatingClick = (e) => {
1618
1866
  if (refs.floating.current?.contains(e.target)) {
@@ -1824,23 +2072,26 @@ var ColoredHighlightLayer = ({
1824
2072
  (state) => state.coloredHighlights
1825
2073
  );
1826
2074
  const addColoredHighlight = usePdf((state) => state.addColoredHighlight);
1827
- const handleHighlighting = useCallback((color) => {
1828
- const dimension = getDimension();
1829
- if (!dimension) return;
1830
- const { highlights: highlights2, text } = dimension;
1831
- if (highlights2[0]) {
1832
- const highlight = {
1833
- uuid: v4(),
1834
- pageNumber: highlights2[0].pageNumber,
1835
- // usePDFPageNumber() doesn't return the correct page number, so i'm getting the number directly from the first highlight
1836
- color,
1837
- rectangles: highlights2,
1838
- text
1839
- };
1840
- addColoredHighlight(highlight);
1841
- if (onHighlight) onHighlight(highlight);
1842
- }
1843
- }, []);
2075
+ const handleHighlighting = useCallback(
2076
+ (color) => {
2077
+ const dimension = getDimension();
2078
+ if (!dimension) return;
2079
+ const { highlights: highlights2, text } = dimension;
2080
+ if (highlights2[0]) {
2081
+ const highlight = {
2082
+ uuid: v4(),
2083
+ pageNumber: highlights2[0].pageNumber,
2084
+ // usePDFPageNumber() doesn't return the correct page number, so i'm getting the number directly from the first highlight
2085
+ color,
2086
+ rectangles: highlights2,
2087
+ text
2088
+ };
2089
+ addColoredHighlight(highlight);
2090
+ if (onHighlight) onHighlight(highlight);
2091
+ }
2092
+ },
2093
+ [onHighlight, getDimension, addColoredHighlight]
2094
+ );
1844
2095
  return /* @__PURE__ */ jsxs("div", { className: "colored-highlights-layer", children: [
1845
2096
  highlights.filter((selection) => selection.pageNumber === pageNumber).map((selection) => /* @__PURE__ */ jsx(
1846
2097
  ColoredHighlightComponent,
@@ -1934,74 +2185,98 @@ var createTextSelectionManager = () => {
1934
2185
  endDiv.style.height = "";
1935
2186
  textLayer.classList.remove("selecting");
1936
2187
  };
1937
- document.addEventListener("pointerdown", () => {
1938
- isPointerDown = true;
1939
- }, { signal });
1940
- document.addEventListener("pointerup", () => {
1941
- isPointerDown = false;
1942
- textLayers.forEach(reset);
1943
- }, { signal });
1944
- window.addEventListener("blur", () => {
1945
- isPointerDown = false;
1946
- textLayers.forEach(reset);
1947
- }, { signal });
1948
- document.addEventListener("keyup", () => {
1949
- if (!isPointerDown) {
2188
+ document.addEventListener(
2189
+ "pointerdown",
2190
+ () => {
2191
+ isPointerDown = true;
2192
+ },
2193
+ { signal }
2194
+ );
2195
+ document.addEventListener(
2196
+ "pointerup",
2197
+ () => {
2198
+ isPointerDown = false;
1950
2199
  textLayers.forEach(reset);
1951
- }
1952
- }, { signal });
1953
- document.addEventListener("selectionchange", () => {
1954
- const selection = document.getSelection();
1955
- if (!selection || selection.rangeCount === 0) {
2200
+ },
2201
+ { signal }
2202
+ );
2203
+ window.addEventListener(
2204
+ "blur",
2205
+ () => {
2206
+ isPointerDown = false;
1956
2207
  textLayers.forEach(reset);
1957
- return;
1958
- }
1959
- const activeTextLayers = /* @__PURE__ */ new Set();
1960
- for (let i = 0; i < selection.rangeCount; i++) {
1961
- const range = selection.getRangeAt(i);
1962
- for (const textLayerDiv of textLayers.keys()) {
1963
- if (!activeTextLayers.has(textLayerDiv) && range.intersectsNode(textLayerDiv)) {
1964
- activeTextLayers.add(textLayerDiv);
2208
+ },
2209
+ { signal }
2210
+ );
2211
+ document.addEventListener(
2212
+ "keyup",
2213
+ () => {
2214
+ if (!isPointerDown) {
2215
+ textLayers.forEach(reset);
2216
+ }
2217
+ },
2218
+ { signal }
2219
+ );
2220
+ document.addEventListener(
2221
+ "selectionchange",
2222
+ () => {
2223
+ const selection = document.getSelection();
2224
+ if (!selection || selection.rangeCount === 0) {
2225
+ textLayers.forEach(reset);
2226
+ return;
2227
+ }
2228
+ const activeTextLayers = /* @__PURE__ */ new Set();
2229
+ for (let i = 0; i < selection.rangeCount; i++) {
2230
+ const range = selection.getRangeAt(i);
2231
+ for (const textLayerDiv of textLayers.keys()) {
2232
+ if (!activeTextLayers.has(textLayerDiv) && range.intersectsNode(textLayerDiv)) {
2233
+ activeTextLayers.add(textLayerDiv);
2234
+ }
1965
2235
  }
1966
2236
  }
1967
- }
1968
- for (const [textLayerDiv, endDiv] of textLayers) {
1969
- if (activeTextLayers.has(textLayerDiv)) {
1970
- textLayerDiv.classList.add("selecting");
1971
- } else {
1972
- reset(endDiv, textLayerDiv);
2237
+ for (const [textLayerDiv, endDiv] of textLayers) {
2238
+ if (activeTextLayers.has(textLayerDiv)) {
2239
+ textLayerDiv.classList.add("selecting");
2240
+ } else {
2241
+ reset(endDiv, textLayerDiv);
2242
+ }
1973
2243
  }
1974
- }
1975
- if (isFirefox === void 0) {
1976
- const firstTextLayer = textLayers.keys().next().value;
1977
- if (firstTextLayer) {
1978
- isFirefox = getComputedStyle(firstTextLayer).getPropertyValue("-moz-user-select") === "none";
2244
+ if (isFirefox === void 0) {
2245
+ const firstTextLayer = textLayers.keys().next().value;
2246
+ if (firstTextLayer) {
2247
+ isFirefox = getComputedStyle(firstTextLayer).getPropertyValue(
2248
+ "-moz-user-select"
2249
+ ) === "none";
2250
+ }
1979
2251
  }
1980
- }
1981
- if (isFirefox) {
1982
- return;
1983
- }
1984
- try {
1985
- const range = selection.getRangeAt(0);
1986
- const modifyStart = prevRange && (range.compareBoundaryPoints(Range.END_TO_END, prevRange) === 0 || range.compareBoundaryPoints(Range.START_TO_END, prevRange) === 0);
1987
- let anchor = modifyStart ? range.startContainer : range.endContainer;
1988
- if (anchor.nodeType === Node.TEXT_NODE) {
1989
- anchor = anchor.parentNode;
2252
+ if (isFirefox) {
2253
+ return;
1990
2254
  }
1991
- const parentTextLayer = anchor.parentElement?.closest(".textLayer");
1992
- const endDiv = textLayers.get(parentTextLayer);
1993
- if (endDiv && parentTextLayer) {
1994
- endDiv.style.width = parentTextLayer.style.width;
1995
- endDiv.style.height = parentTextLayer.style.height;
1996
- const insertTarget = modifyStart ? anchor : anchor.nextSibling;
1997
- if (anchor.parentElement && insertTarget) {
1998
- anchor.parentElement.insertBefore(endDiv, insertTarget);
2255
+ try {
2256
+ const range = selection.getRangeAt(0);
2257
+ const modifyStart = prevRange && (range.compareBoundaryPoints(Range.END_TO_END, prevRange) === 0 || range.compareBoundaryPoints(Range.START_TO_END, prevRange) === 0);
2258
+ let anchor = modifyStart ? range.startContainer : range.endContainer;
2259
+ if (anchor.nodeType === Node.TEXT_NODE) {
2260
+ anchor = anchor.parentNode;
2261
+ }
2262
+ const parentTextLayer = anchor.parentElement?.closest(
2263
+ ".textLayer"
2264
+ );
2265
+ const endDiv = textLayers.get(parentTextLayer);
2266
+ if (endDiv && parentTextLayer) {
2267
+ endDiv.style.width = parentTextLayer.style.width;
2268
+ endDiv.style.height = parentTextLayer.style.height;
2269
+ const insertTarget = modifyStart ? anchor : anchor.nextSibling;
2270
+ if (anchor.parentElement && insertTarget) {
2271
+ anchor.parentElement.insertBefore(endDiv, insertTarget);
2272
+ }
1999
2273
  }
2274
+ prevRange = range.cloneRange();
2275
+ } catch {
2000
2276
  }
2001
- prevRange = range.cloneRange();
2002
- } catch {
2003
- }
2004
- }, { signal });
2277
+ },
2278
+ { signal }
2279
+ );
2005
2280
  };
2006
2281
  const bindMouseEvents2 = (textLayerDiv, endOfContent) => {
2007
2282
  if (textLayerDiv._textSelectionBound) {
@@ -2071,7 +2346,7 @@ var useTextLayer = () => {
2071
2346
  delete textContainer._cleanupTextSelection;
2072
2347
  }
2073
2348
  };
2074
- }, [pdfPageProxy.pageNumber]);
2349
+ }, [pdfPageProxy.streamTextContent, pdfPageProxy.getViewport]);
2075
2350
  return {
2076
2351
  textContainerRef,
2077
2352
  pageNumber: pdfPageProxy.pageNumber
@@ -2095,7 +2370,7 @@ var TextLayer2 = ({
2095
2370
  },
2096
2371
  ...props,
2097
2372
  ...{
2098
- ["data-page-number"]: pageNumber
2373
+ "data-page-number": pageNumber
2099
2374
  },
2100
2375
  ref: textContainerRef
2101
2376
  }
@@ -2218,6 +2493,7 @@ var OutlineItem = ({
2218
2493
  level: level + 1,
2219
2494
  item: item2,
2220
2495
  outlineItem,
2496
+ // biome-ignore lint/suspicious/noArrayIndexKey: <stuff>
2221
2497
  key: index
2222
2498
  })
2223
2499
  )
@@ -2229,7 +2505,7 @@ var Outline = ({
2229
2505
  ...props
2230
2506
  }) => {
2231
2507
  const outline = usePDFOutline();
2232
- return /* @__PURE__ */ jsx(Primitive.ul, { ...props, children: outline && outline.map((item, idx) => {
2508
+ return /* @__PURE__ */ jsx(Primitive.ul, { ...props, children: outline?.map((item, idx) => {
2233
2509
  return cloneElement(children, {
2234
2510
  key: idx,
2235
2511
  item,
@@ -2301,7 +2577,9 @@ var CurrentPage = ({ ...props }) => {
2301
2577
  onChange: (e) => {
2302
2578
  setPageNumber(e.target.value);
2303
2579
  },
2304
- onClick: () => isSelected.current = true,
2580
+ onClick: () => {
2581
+ isSelected.current = true;
2582
+ },
2305
2583
  onBlur: (e) => {
2306
2584
  if (currentPage !== Number(e.target.value)) {
2307
2585
  jumpToPage(Number(e.target.value), {
@@ -2350,7 +2628,7 @@ var useFitWidth = ({ viewportRef }) => {
2350
2628
  }, [store, updateZoom, viewportRef, viewports, zoomOptions]);
2351
2629
  return null;
2352
2630
  };
2353
- var supportsScrollend = typeof window == "undefined" ? true : "onscrollend" in window;
2631
+ var supportsScrollend = typeof window === "undefined" ? true : "onscrollend" in window;
2354
2632
  var addEventListenerOptions = {
2355
2633
  passive: true
2356
2634
  };
@@ -2375,7 +2653,7 @@ var useObserveElement = () => {
2375
2653
  );
2376
2654
  const createHandler = (isScrolling) => () => {
2377
2655
  const { horizontal, isRtl } = instance.options;
2378
- offset3 = horizontal ? element["scrollLeft"] * (isRtl && -1 || 1) : element["scrollTop"];
2656
+ offset3 = horizontal ? element.scrollLeft * (isRtl && -1 || 1) : element.scrollTop;
2379
2657
  const zoom = store.getState().zoom;
2380
2658
  offset3 = offset3 / zoom;
2381
2659
  fallback();
@@ -4335,6 +4613,7 @@ var useViewportContainer = ({
4335
4613
  }
4336
4614
  const { zoom: zoom2, translateX, translateY } = transformations.current;
4337
4615
  elementRef.current.style.transform = `scale3d(${zoom2}, ${zoom2}, 1)`;
4616
+ elementRef.current.style.willChange = "scale3d";
4338
4617
  const elementBoundingBox = elementRef.current.getBoundingClientRect();
4339
4618
  const width = elementBoundingBox.width;
4340
4619
  elementWrapperRef.current.style.width = `${width}px`;
@@ -4356,10 +4635,7 @@ var useViewportContainer = ({
4356
4635
  zoom
4357
4636
  };
4358
4637
  updateTransform();
4359
- }, [containerRef, zoom]);
4360
- useLayoutEffect(() => {
4361
- updateTransform();
4362
- }, []);
4638
+ }, [containerRef, zoom, updateTransform]);
4363
4639
  useEffect(() => {
4364
4640
  const preventDefault = (e) => e.preventDefault();
4365
4641
  document.addEventListener("gesturestart", preventDefault);
@@ -4368,13 +4644,17 @@ var useViewportContainer = ({
4368
4644
  document.removeEventListener("gesturestart", preventDefault);
4369
4645
  document.removeEventListener("gesturechange", preventDefault);
4370
4646
  };
4371
- });
4647
+ }, []);
4372
4648
  useGesture(
4373
4649
  {
4374
4650
  onPinch: ({ origin: origin2, first, movement: [ms], memo }) => {
4651
+ const currentElement = elementRef.current;
4652
+ const currentContainer = containerRef.current;
4653
+ if (!currentElement || !currentContainer) return;
4654
+ if (!elementRef.current || !containerRef.current) return;
4375
4655
  const newMemo = firstMemo(first, memo, () => {
4376
- const elementRect = elementRef.current.getBoundingClientRect();
4377
- const containerRect = containerRef.current.getBoundingClientRect();
4656
+ const elementRect = currentElement.getBoundingClientRect();
4657
+ const containerRect = currentContainer.getBoundingClientRect();
4378
4658
  const contentPosition = [
4379
4659
  origin2[0] - elementRect.left,
4380
4660
  origin2[1] - elementRect.top
@@ -4422,7 +4702,7 @@ var EXTRA_HEIGHT = 0;
4422
4702
  var Pages = ({
4423
4703
  children,
4424
4704
  gap = 10,
4425
- virtualizerOptions = { overscan: 3 },
4705
+ virtualizerOptions = { overscan: 2 },
4426
4706
  initialOffset,
4427
4707
  onOffsetChange,
4428
4708
  ...props
@@ -4480,7 +4760,7 @@ var Pages = ({
4480
4760
  return () => {
4481
4761
  clearTimeout(timeout);
4482
4762
  };
4483
- }, [isPinching]);
4763
+ }, [isPinching, virtualizer?.measure, virtualizer?.getVirtualItems]);
4484
4764
  const virtualizerItems = virtualizer?.getVirtualItems() ?? [];
4485
4765
  const items = tempItems.length ? tempItems : virtualizerItems;
4486
4766
  useVisiblePage({
@@ -4490,7 +4770,6 @@ var Pages = ({
4490
4770
  const largestPageWidth = usePdf(
4491
4771
  (state) => Math.max(...state.viewports.map((v) => v.width))
4492
4772
  );
4493
- const zoom = usePdf((state) => state.zoom);
4494
4773
  useEffect(() => {
4495
4774
  virtualizer.getOffsetForAlignment = (toOffset, align, itemSize = 0) => {
4496
4775
  const size = virtualizer.getSize();
@@ -4510,7 +4789,7 @@ var Pages = ({
4510
4789
  ) : virtualizer.scrollElement[scrollSizeProp] : 0;
4511
4790
  return Math.max(toOffset, 0);
4512
4791
  };
4513
- }, [zoom, virtualizer]);
4792
+ }, [virtualizer]);
4514
4793
  return /* @__PURE__ */ jsx(
4515
4794
  Primitive.div,
4516
4795
  {
@@ -4547,7 +4826,7 @@ var Pages = ({
4547
4826
  margin: "0 auto"
4548
4827
  },
4549
4828
  children: items.map((virtualItem) => {
4550
- const innerBoxWidth = viewports && viewports[virtualItem.index] ? viewports[virtualItem.index]?.width : 0;
4829
+ const innerBoxWidth = viewports?.[virtualItem.index] ? viewports[virtualItem.index]?.width : 0;
4551
4830
  if (!innerBoxWidth) return null;
4552
4831
  return /* @__PURE__ */ jsx(
4553
4832
  "div",
@@ -4751,7 +5030,7 @@ var useThumbnail = (pageNumber, config = {}) => {
4751
5030
  return () => {
4752
5031
  renderTaskRef.current?.cancel();
4753
5032
  };
4754
- }, [pageNumber, pageProxy, isVisible, dpr, maxHeight, maxWidth]);
5033
+ }, [pageProxy, isVisible, dpr, maxHeight, maxWidth]);
4755
5034
  return {
4756
5035
  canvasRef,
4757
5036
  containerRef,
@@ -4808,7 +5087,7 @@ var ZoomIn = ({ ...props }) => {
4808
5087
  {
4809
5088
  ...props,
4810
5089
  onClick: (e) => {
4811
- props.onClick && props.onClick(e);
5090
+ props.onClick?.(e);
4812
5091
  setZoom((zoom) => Number((zoom + 0.1).toFixed(1)));
4813
5092
  }
4814
5093
  }
@@ -4821,7 +5100,7 @@ var ZoomOut = ({ ...props }) => {
4821
5100
  {
4822
5101
  ...props,
4823
5102
  onClick: (e) => {
4824
- props.onClick && props.onClick(e);
5103
+ props.onClick?.(e);
4825
5104
  setZoom((zoom) => Number((zoom - 0.1).toFixed(1)));
4826
5105
  }
4827
5106
  }
@@ -4843,7 +5122,9 @@ var CurrentZoom = ({ ...props }) => {
4843
5122
  {
4844
5123
  ...props,
4845
5124
  value: zoom,
4846
- onClick: () => isSelected.current = true,
5125
+ onClick: () => {
5126
+ isSelected.current = true;
5127
+ },
4847
5128
  onChange: (e) => {
4848
5129
  setRealZoom(Number(e.target.value) / 100);
4849
5130
  setZoom(e.target.value);
@@ -4886,59 +5167,65 @@ var useSearch = () => {
4886
5167
  fuzzyMatches: [],
4887
5168
  hasMoreResults: false
4888
5169
  });
4889
- const findExactMatches = (searchText, text, pageNumber, textSize) => {
4890
- const results = [];
4891
- const textLower = text.toLowerCase();
4892
- const searchLower = searchText.toLowerCase();
4893
- let index = 0;
4894
- while (true) {
4895
- const matchIndex = textLower.indexOf(searchLower, index);
4896
- if (matchIndex === -1) break;
4897
- results.push({
4898
- pageNumber,
4899
- text: text.substr(matchIndex, searchText.length + textSize),
4900
- score: 1,
4901
- matchIndex,
4902
- isExactMatch: true,
4903
- searchText
4904
- });
4905
- index = matchIndex + searchText.length;
4906
- }
4907
- return results;
4908
- };
4909
- const findFuzzyMatches = (searchText, text, pageNumber, threshold, excludeIndices, textSize) => {
4910
- const results = [];
4911
- const textLower = text.toLowerCase();
4912
- const searchLower = searchText.toLowerCase();
4913
- let index = 0;
4914
- while (index < textLower.length) {
4915
- if (excludeIndices.has(index)) {
4916
- index++;
4917
- continue;
4918
- }
4919
- const chunk = textLower.substr(index, searchLower.length + 10);
4920
- const distance = levenshteinDistance(
4921
- searchLower,
4922
- chunk.substr(0, searchLower.length)
4923
- );
4924
- const maxDistance = Math.floor(searchLower.length * (1 - threshold));
4925
- if (distance <= maxDistance && distance > 0) {
4926
- const score = 1 - distance / searchLower.length;
5170
+ const findExactMatches = useCallback(
5171
+ (searchText, text, pageNumber, textSize) => {
5172
+ const results = [];
5173
+ const textLower = text.toLowerCase();
5174
+ const searchLower = searchText.toLowerCase();
5175
+ let index = 0;
5176
+ while (true) {
5177
+ const matchIndex = textLower.indexOf(searchLower, index);
5178
+ if (matchIndex === -1) break;
4927
5179
  results.push({
4928
5180
  pageNumber,
4929
- text: text.substr(index, searchLower.length + textSize),
4930
- score,
4931
- matchIndex: index,
4932
- isExactMatch: false,
5181
+ text: text.substr(matchIndex, searchText.length + textSize),
5182
+ score: 1,
5183
+ matchIndex,
5184
+ isExactMatch: true,
4933
5185
  searchText
4934
5186
  });
4935
- index += searchLower.length;
4936
- } else {
4937
- index++;
5187
+ index = matchIndex + searchText.length;
4938
5188
  }
4939
- }
4940
- return results;
4941
- };
5189
+ return results;
5190
+ },
5191
+ []
5192
+ );
5193
+ const findFuzzyMatches = useCallback(
5194
+ (searchText, text, pageNumber, threshold, excludeIndices, textSize) => {
5195
+ const results = [];
5196
+ const textLower = text.toLowerCase();
5197
+ const searchLower = searchText.toLowerCase();
5198
+ let index = 0;
5199
+ while (index < textLower.length) {
5200
+ if (excludeIndices.has(index)) {
5201
+ index++;
5202
+ continue;
5203
+ }
5204
+ const chunk = textLower.substr(index, searchLower.length + 10);
5205
+ const distance = levenshteinDistance(
5206
+ searchLower,
5207
+ chunk.substr(0, searchLower.length)
5208
+ );
5209
+ const maxDistance = Math.floor(searchLower.length * (1 - threshold));
5210
+ if (distance <= maxDistance && distance > 0) {
5211
+ const score = 1 - distance / searchLower.length;
5212
+ results.push({
5213
+ pageNumber,
5214
+ text: text.substr(index, searchLower.length + textSize),
5215
+ score,
5216
+ matchIndex: index,
5217
+ isExactMatch: false,
5218
+ searchText
5219
+ });
5220
+ index += searchLower.length;
5221
+ } else {
5222
+ index++;
5223
+ }
5224
+ }
5225
+ return results;
5226
+ },
5227
+ []
5228
+ );
4942
5229
  const search = useCallback(
4943
5230
  (searchText, options = {}) => {
4944
5231
  const { threshold = 0.7, limit = 10, textSize = 100 } = options;
@@ -4991,7 +5278,7 @@ var useSearch = () => {
4991
5278
  setSearchResults(limitedResults);
4992
5279
  return limitedResults;
4993
5280
  },
4994
- [textContent]
5281
+ [textContent, findExactMatches, findFuzzyMatches]
4995
5282
  );
4996
5283
  return {
4997
5284
  textContent,