@anaralabs/lector 3.6.0 → 3.7.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.
- package/dist/_tsup-dts-rollup.d.ts +7 -8
- package/dist/index.js +558 -271
- package/package.json +101 -109
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(
|
|
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
|
-
}, [
|
|
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
|
|
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
|
-
}, [
|
|
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(
|
|
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 = (
|
|
636
|
-
|
|
637
|
-
|
|
638
|
-
|
|
639
|
-
|
|
640
|
-
|
|
641
|
-
|
|
642
|
-
|
|
643
|
-
|
|
644
|
-
|
|
645
|
-
|
|
646
|
-
|
|
647
|
-
|
|
648
|
-
|
|
649
|
-
|
|
650
|
-
|
|
651
|
-
|
|
652
|
-
|
|
653
|
-
|
|
654
|
-
|
|
655
|
-
|
|
656
|
-
|
|
657
|
-
|
|
658
|
-
|
|
659
|
-
|
|
660
|
-
|
|
661
|
-
|
|
662
|
-
|
|
663
|
-
|
|
664
|
-
|
|
665
|
-
|
|
666
|
-
);
|
|
667
|
-
|
|
668
|
-
|
|
669
|
-
|
|
670
|
-
|
|
671
|
-
|
|
672
|
-
|
|
673
|
-
|
|
674
|
-
|
|
675
|
-
|
|
676
|
-
|
|
677
|
-
|
|
678
|
-
|
|
679
|
-
|
|
680
|
-
|
|
681
|
-
|
|
682
|
-
|
|
683
|
-
|
|
684
|
-
|
|
685
|
-
|
|
686
|
-
|
|
687
|
-
|
|
688
|
-
|
|
689
|
-
|
|
690
|
-
|
|
691
|
-
|
|
692
|
-
|
|
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(
|
|
843
|
+
set rotation(_value) {
|
|
819
844
|
}
|
|
820
|
-
goToPage(
|
|
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 =
|
|
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
|
|
1080
|
-
const
|
|
1081
|
-
const
|
|
1082
|
-
|
|
1083
|
-
|
|
1084
|
-
|
|
1085
|
-
|
|
1086
|
-
|
|
1087
|
-
|
|
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 * 1.3;
|
|
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
|
-
|
|
1114
|
-
|
|
1115
|
-
|
|
1116
|
-
|
|
1117
|
-
|
|
1118
|
-
|
|
1119
|
-
|
|
1120
|
-
|
|
1121
|
-
|
|
1122
|
-
|
|
1123
|
-
|
|
1124
|
-
|
|
1125
|
-
|
|
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(
|
|
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(
|
|
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(
|
|
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(
|
|
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
|
-
}, [
|
|
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(
|
|
1828
|
-
|
|
1829
|
-
|
|
1830
|
-
|
|
1831
|
-
|
|
1832
|
-
|
|
1833
|
-
|
|
1834
|
-
|
|
1835
|
-
|
|
1836
|
-
|
|
1837
|
-
|
|
1838
|
-
|
|
1839
|
-
|
|
1840
|
-
|
|
1841
|
-
|
|
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(
|
|
1938
|
-
|
|
1939
|
-
|
|
1940
|
-
|
|
1941
|
-
|
|
1942
|
-
|
|
1943
|
-
|
|
1944
|
-
|
|
1945
|
-
|
|
1946
|
-
|
|
1947
|
-
|
|
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
|
-
|
|
1953
|
-
|
|
1954
|
-
|
|
1955
|
-
|
|
2200
|
+
},
|
|
2201
|
+
{ signal }
|
|
2202
|
+
);
|
|
2203
|
+
window.addEventListener(
|
|
2204
|
+
"blur",
|
|
2205
|
+
() => {
|
|
2206
|
+
isPointerDown = false;
|
|
1956
2207
|
textLayers.forEach(reset);
|
|
1957
|
-
|
|
1958
|
-
}
|
|
1959
|
-
|
|
1960
|
-
|
|
1961
|
-
|
|
1962
|
-
|
|
1963
|
-
|
|
1964
|
-
|
|
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
|
-
|
|
1969
|
-
|
|
1970
|
-
|
|
1971
|
-
|
|
1972
|
-
|
|
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
|
-
|
|
1976
|
-
|
|
1977
|
-
|
|
1978
|
-
|
|
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
|
-
|
|
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
|
-
|
|
1992
|
-
|
|
1993
|
-
|
|
1994
|
-
|
|
1995
|
-
|
|
1996
|
-
|
|
1997
|
-
|
|
1998
|
-
|
|
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
|
-
|
|
2002
|
-
|
|
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.
|
|
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
|
-
|
|
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
|
|
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: () =>
|
|
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
|
|
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
|
|
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 =
|
|
4377
|
-
const containerRect =
|
|
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:
|
|
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
|
-
}, [
|
|
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
|
|
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
|
-
}, [
|
|
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
|
|
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
|
|
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: () =>
|
|
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 = (
|
|
4890
|
-
|
|
4891
|
-
|
|
4892
|
-
|
|
4893
|
-
|
|
4894
|
-
|
|
4895
|
-
|
|
4896
|
-
|
|
4897
|
-
|
|
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(
|
|
4930
|
-
score,
|
|
4931
|
-
matchIndex
|
|
4932
|
-
isExactMatch:
|
|
5181
|
+
text: text.substr(matchIndex, searchText.length + textSize),
|
|
5182
|
+
score: 1,
|
|
5183
|
+
matchIndex,
|
|
5184
|
+
isExactMatch: true,
|
|
4933
5185
|
searchText
|
|
4934
5186
|
});
|
|
4935
|
-
index
|
|
4936
|
-
} else {
|
|
4937
|
-
index++;
|
|
5187
|
+
index = matchIndex + searchText.length;
|
|
4938
5188
|
}
|
|
4939
|
-
|
|
4940
|
-
|
|
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,
|