@anaralabs/lector 3.5.14 → 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/_tsup-dts-rollup.d.ts +11 -12
- package/dist/index.js +562 -273
- 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 / 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
|
-
|
|
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,
|
|
@@ -1880,11 +2131,12 @@ var HighlightLayer = forwardRef(({ asChild, className, style, ...props }, ref) =
|
|
|
1880
2131
|
const rects = highlights.filter((area) => area.pageNumber === pageNumber);
|
|
1881
2132
|
if (!rects?.length) return null;
|
|
1882
2133
|
return /* @__PURE__ */ jsx(Fragment, { children: rects.map((rect, index) => {
|
|
1883
|
-
const { pageNumber: pageNumber2, type, ...coordinates } = rect;
|
|
2134
|
+
const { pageNumber: pageNumber2, type, style: customStyle, ...coordinates } = rect;
|
|
1884
2135
|
let dimensions = coordinates;
|
|
1885
2136
|
if (type === "percent") {
|
|
1886
2137
|
dimensions = convertToPercentString(rect);
|
|
1887
2138
|
}
|
|
2139
|
+
const customStyles = customStyle ? customStyle(rect) : {};
|
|
1888
2140
|
return /* @__PURE__ */ jsx(
|
|
1889
2141
|
Comp,
|
|
1890
2142
|
{
|
|
@@ -1895,7 +2147,8 @@ var HighlightLayer = forwardRef(({ asChild, className, style, ...props }, ref) =
|
|
|
1895
2147
|
...dimensions,
|
|
1896
2148
|
pointerEvents: "none",
|
|
1897
2149
|
zIndex: 30,
|
|
1898
|
-
...style
|
|
2150
|
+
...style,
|
|
2151
|
+
...customStyles
|
|
1899
2152
|
},
|
|
1900
2153
|
...props,
|
|
1901
2154
|
children: props.children
|
|
@@ -1932,74 +2185,98 @@ var createTextSelectionManager = () => {
|
|
|
1932
2185
|
endDiv.style.height = "";
|
|
1933
2186
|
textLayer.classList.remove("selecting");
|
|
1934
2187
|
};
|
|
1935
|
-
document.addEventListener(
|
|
1936
|
-
|
|
1937
|
-
|
|
1938
|
-
|
|
1939
|
-
|
|
1940
|
-
|
|
1941
|
-
|
|
1942
|
-
|
|
1943
|
-
|
|
1944
|
-
|
|
1945
|
-
|
|
1946
|
-
document.addEventListener("keyup", () => {
|
|
1947
|
-
if (!isPointerDown) {
|
|
2188
|
+
document.addEventListener(
|
|
2189
|
+
"pointerdown",
|
|
2190
|
+
() => {
|
|
2191
|
+
isPointerDown = true;
|
|
2192
|
+
},
|
|
2193
|
+
{ signal }
|
|
2194
|
+
);
|
|
2195
|
+
document.addEventListener(
|
|
2196
|
+
"pointerup",
|
|
2197
|
+
() => {
|
|
2198
|
+
isPointerDown = false;
|
|
1948
2199
|
textLayers.forEach(reset);
|
|
1949
|
-
}
|
|
1950
|
-
|
|
1951
|
-
|
|
1952
|
-
|
|
1953
|
-
|
|
2200
|
+
},
|
|
2201
|
+
{ signal }
|
|
2202
|
+
);
|
|
2203
|
+
window.addEventListener(
|
|
2204
|
+
"blur",
|
|
2205
|
+
() => {
|
|
2206
|
+
isPointerDown = false;
|
|
1954
2207
|
textLayers.forEach(reset);
|
|
1955
|
-
|
|
1956
|
-
}
|
|
1957
|
-
|
|
1958
|
-
|
|
1959
|
-
|
|
1960
|
-
|
|
1961
|
-
|
|
1962
|
-
|
|
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
|
+
}
|
|
1963
2235
|
}
|
|
1964
2236
|
}
|
|
1965
|
-
|
|
1966
|
-
|
|
1967
|
-
|
|
1968
|
-
|
|
1969
|
-
|
|
1970
|
-
|
|
2237
|
+
for (const [textLayerDiv, endDiv] of textLayers) {
|
|
2238
|
+
if (activeTextLayers.has(textLayerDiv)) {
|
|
2239
|
+
textLayerDiv.classList.add("selecting");
|
|
2240
|
+
} else {
|
|
2241
|
+
reset(endDiv, textLayerDiv);
|
|
2242
|
+
}
|
|
1971
2243
|
}
|
|
1972
|
-
|
|
1973
|
-
|
|
1974
|
-
|
|
1975
|
-
|
|
1976
|
-
|
|
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
|
+
}
|
|
1977
2251
|
}
|
|
1978
|
-
|
|
1979
|
-
|
|
1980
|
-
return;
|
|
1981
|
-
}
|
|
1982
|
-
try {
|
|
1983
|
-
const range = selection.getRangeAt(0);
|
|
1984
|
-
const modifyStart = prevRange && (range.compareBoundaryPoints(Range.END_TO_END, prevRange) === 0 || range.compareBoundaryPoints(Range.START_TO_END, prevRange) === 0);
|
|
1985
|
-
let anchor = modifyStart ? range.startContainer : range.endContainer;
|
|
1986
|
-
if (anchor.nodeType === Node.TEXT_NODE) {
|
|
1987
|
-
anchor = anchor.parentNode;
|
|
2252
|
+
if (isFirefox) {
|
|
2253
|
+
return;
|
|
1988
2254
|
}
|
|
1989
|
-
|
|
1990
|
-
|
|
1991
|
-
|
|
1992
|
-
|
|
1993
|
-
|
|
1994
|
-
|
|
1995
|
-
|
|
1996
|
-
|
|
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
|
+
}
|
|
1997
2273
|
}
|
|
2274
|
+
prevRange = range.cloneRange();
|
|
2275
|
+
} catch {
|
|
1998
2276
|
}
|
|
1999
|
-
|
|
2000
|
-
|
|
2001
|
-
|
|
2002
|
-
}, { signal });
|
|
2277
|
+
},
|
|
2278
|
+
{ signal }
|
|
2279
|
+
);
|
|
2003
2280
|
};
|
|
2004
2281
|
const bindMouseEvents2 = (textLayerDiv, endOfContent) => {
|
|
2005
2282
|
if (textLayerDiv._textSelectionBound) {
|
|
@@ -2069,7 +2346,7 @@ var useTextLayer = () => {
|
|
|
2069
2346
|
delete textContainer._cleanupTextSelection;
|
|
2070
2347
|
}
|
|
2071
2348
|
};
|
|
2072
|
-
}, [pdfPageProxy.
|
|
2349
|
+
}, [pdfPageProxy.streamTextContent, pdfPageProxy.getViewport]);
|
|
2073
2350
|
return {
|
|
2074
2351
|
textContainerRef,
|
|
2075
2352
|
pageNumber: pdfPageProxy.pageNumber
|
|
@@ -2093,7 +2370,7 @@ var TextLayer2 = ({
|
|
|
2093
2370
|
},
|
|
2094
2371
|
...props,
|
|
2095
2372
|
...{
|
|
2096
|
-
|
|
2373
|
+
"data-page-number": pageNumber
|
|
2097
2374
|
},
|
|
2098
2375
|
ref: textContainerRef
|
|
2099
2376
|
}
|
|
@@ -2216,6 +2493,7 @@ var OutlineItem = ({
|
|
|
2216
2493
|
level: level + 1,
|
|
2217
2494
|
item: item2,
|
|
2218
2495
|
outlineItem,
|
|
2496
|
+
// biome-ignore lint/suspicious/noArrayIndexKey: <stuff>
|
|
2219
2497
|
key: index
|
|
2220
2498
|
})
|
|
2221
2499
|
)
|
|
@@ -2227,7 +2505,7 @@ var Outline = ({
|
|
|
2227
2505
|
...props
|
|
2228
2506
|
}) => {
|
|
2229
2507
|
const outline = usePDFOutline();
|
|
2230
|
-
return /* @__PURE__ */ jsx(Primitive.ul, { ...props, children: outline
|
|
2508
|
+
return /* @__PURE__ */ jsx(Primitive.ul, { ...props, children: outline?.map((item, idx) => {
|
|
2231
2509
|
return cloneElement(children, {
|
|
2232
2510
|
key: idx,
|
|
2233
2511
|
item,
|
|
@@ -2299,7 +2577,9 @@ var CurrentPage = ({ ...props }) => {
|
|
|
2299
2577
|
onChange: (e) => {
|
|
2300
2578
|
setPageNumber(e.target.value);
|
|
2301
2579
|
},
|
|
2302
|
-
onClick: () =>
|
|
2580
|
+
onClick: () => {
|
|
2581
|
+
isSelected.current = true;
|
|
2582
|
+
},
|
|
2303
2583
|
onBlur: (e) => {
|
|
2304
2584
|
if (currentPage !== Number(e.target.value)) {
|
|
2305
2585
|
jumpToPage(Number(e.target.value), {
|
|
@@ -2348,7 +2628,7 @@ var useFitWidth = ({ viewportRef }) => {
|
|
|
2348
2628
|
}, [store, updateZoom, viewportRef, viewports, zoomOptions]);
|
|
2349
2629
|
return null;
|
|
2350
2630
|
};
|
|
2351
|
-
var supportsScrollend = typeof window
|
|
2631
|
+
var supportsScrollend = typeof window === "undefined" ? true : "onscrollend" in window;
|
|
2352
2632
|
var addEventListenerOptions = {
|
|
2353
2633
|
passive: true
|
|
2354
2634
|
};
|
|
@@ -2373,7 +2653,7 @@ var useObserveElement = () => {
|
|
|
2373
2653
|
);
|
|
2374
2654
|
const createHandler = (isScrolling) => () => {
|
|
2375
2655
|
const { horizontal, isRtl } = instance.options;
|
|
2376
|
-
offset3 = horizontal ? element
|
|
2656
|
+
offset3 = horizontal ? element.scrollLeft * (isRtl && -1 || 1) : element.scrollTop;
|
|
2377
2657
|
const zoom = store.getState().zoom;
|
|
2378
2658
|
offset3 = offset3 / zoom;
|
|
2379
2659
|
fallback();
|
|
@@ -4333,6 +4613,7 @@ var useViewportContainer = ({
|
|
|
4333
4613
|
}
|
|
4334
4614
|
const { zoom: zoom2, translateX, translateY } = transformations.current;
|
|
4335
4615
|
elementRef.current.style.transform = `scale3d(${zoom2}, ${zoom2}, 1)`;
|
|
4616
|
+
elementRef.current.style.willChange = "scale3d";
|
|
4336
4617
|
const elementBoundingBox = elementRef.current.getBoundingClientRect();
|
|
4337
4618
|
const width = elementBoundingBox.width;
|
|
4338
4619
|
elementWrapperRef.current.style.width = `${width}px`;
|
|
@@ -4354,10 +4635,7 @@ var useViewportContainer = ({
|
|
|
4354
4635
|
zoom
|
|
4355
4636
|
};
|
|
4356
4637
|
updateTransform();
|
|
4357
|
-
}, [containerRef, zoom]);
|
|
4358
|
-
useLayoutEffect(() => {
|
|
4359
|
-
updateTransform();
|
|
4360
|
-
}, []);
|
|
4638
|
+
}, [containerRef, zoom, updateTransform]);
|
|
4361
4639
|
useEffect(() => {
|
|
4362
4640
|
const preventDefault = (e) => e.preventDefault();
|
|
4363
4641
|
document.addEventListener("gesturestart", preventDefault);
|
|
@@ -4366,13 +4644,17 @@ var useViewportContainer = ({
|
|
|
4366
4644
|
document.removeEventListener("gesturestart", preventDefault);
|
|
4367
4645
|
document.removeEventListener("gesturechange", preventDefault);
|
|
4368
4646
|
};
|
|
4369
|
-
});
|
|
4647
|
+
}, []);
|
|
4370
4648
|
useGesture(
|
|
4371
4649
|
{
|
|
4372
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;
|
|
4373
4655
|
const newMemo = firstMemo(first, memo, () => {
|
|
4374
|
-
const elementRect =
|
|
4375
|
-
const containerRect =
|
|
4656
|
+
const elementRect = currentElement.getBoundingClientRect();
|
|
4657
|
+
const containerRect = currentContainer.getBoundingClientRect();
|
|
4376
4658
|
const contentPosition = [
|
|
4377
4659
|
origin2[0] - elementRect.left,
|
|
4378
4660
|
origin2[1] - elementRect.top
|
|
@@ -4420,7 +4702,7 @@ var EXTRA_HEIGHT = 0;
|
|
|
4420
4702
|
var Pages = ({
|
|
4421
4703
|
children,
|
|
4422
4704
|
gap = 10,
|
|
4423
|
-
virtualizerOptions = { overscan:
|
|
4705
|
+
virtualizerOptions = { overscan: 2 },
|
|
4424
4706
|
initialOffset,
|
|
4425
4707
|
onOffsetChange,
|
|
4426
4708
|
...props
|
|
@@ -4478,7 +4760,7 @@ var Pages = ({
|
|
|
4478
4760
|
return () => {
|
|
4479
4761
|
clearTimeout(timeout);
|
|
4480
4762
|
};
|
|
4481
|
-
}, [isPinching]);
|
|
4763
|
+
}, [isPinching, virtualizer?.measure, virtualizer?.getVirtualItems]);
|
|
4482
4764
|
const virtualizerItems = virtualizer?.getVirtualItems() ?? [];
|
|
4483
4765
|
const items = tempItems.length ? tempItems : virtualizerItems;
|
|
4484
4766
|
useVisiblePage({
|
|
@@ -4488,7 +4770,6 @@ var Pages = ({
|
|
|
4488
4770
|
const largestPageWidth = usePdf(
|
|
4489
4771
|
(state) => Math.max(...state.viewports.map((v) => v.width))
|
|
4490
4772
|
);
|
|
4491
|
-
const zoom = usePdf((state) => state.zoom);
|
|
4492
4773
|
useEffect(() => {
|
|
4493
4774
|
virtualizer.getOffsetForAlignment = (toOffset, align, itemSize = 0) => {
|
|
4494
4775
|
const size = virtualizer.getSize();
|
|
@@ -4508,7 +4789,7 @@ var Pages = ({
|
|
|
4508
4789
|
) : virtualizer.scrollElement[scrollSizeProp] : 0;
|
|
4509
4790
|
return Math.max(toOffset, 0);
|
|
4510
4791
|
};
|
|
4511
|
-
}, [
|
|
4792
|
+
}, [virtualizer]);
|
|
4512
4793
|
return /* @__PURE__ */ jsx(
|
|
4513
4794
|
Primitive.div,
|
|
4514
4795
|
{
|
|
@@ -4545,7 +4826,7 @@ var Pages = ({
|
|
|
4545
4826
|
margin: "0 auto"
|
|
4546
4827
|
},
|
|
4547
4828
|
children: items.map((virtualItem) => {
|
|
4548
|
-
const innerBoxWidth = viewports
|
|
4829
|
+
const innerBoxWidth = viewports?.[virtualItem.index] ? viewports[virtualItem.index]?.width : 0;
|
|
4549
4830
|
if (!innerBoxWidth) return null;
|
|
4550
4831
|
return /* @__PURE__ */ jsx(
|
|
4551
4832
|
"div",
|
|
@@ -4749,7 +5030,7 @@ var useThumbnail = (pageNumber, config = {}) => {
|
|
|
4749
5030
|
return () => {
|
|
4750
5031
|
renderTaskRef.current?.cancel();
|
|
4751
5032
|
};
|
|
4752
|
-
}, [
|
|
5033
|
+
}, [pageProxy, isVisible, dpr, maxHeight, maxWidth]);
|
|
4753
5034
|
return {
|
|
4754
5035
|
canvasRef,
|
|
4755
5036
|
containerRef,
|
|
@@ -4806,7 +5087,7 @@ var ZoomIn = ({ ...props }) => {
|
|
|
4806
5087
|
{
|
|
4807
5088
|
...props,
|
|
4808
5089
|
onClick: (e) => {
|
|
4809
|
-
props.onClick
|
|
5090
|
+
props.onClick?.(e);
|
|
4810
5091
|
setZoom((zoom) => Number((zoom + 0.1).toFixed(1)));
|
|
4811
5092
|
}
|
|
4812
5093
|
}
|
|
@@ -4819,7 +5100,7 @@ var ZoomOut = ({ ...props }) => {
|
|
|
4819
5100
|
{
|
|
4820
5101
|
...props,
|
|
4821
5102
|
onClick: (e) => {
|
|
4822
|
-
props.onClick
|
|
5103
|
+
props.onClick?.(e);
|
|
4823
5104
|
setZoom((zoom) => Number((zoom - 0.1).toFixed(1)));
|
|
4824
5105
|
}
|
|
4825
5106
|
}
|
|
@@ -4841,7 +5122,9 @@ var CurrentZoom = ({ ...props }) => {
|
|
|
4841
5122
|
{
|
|
4842
5123
|
...props,
|
|
4843
5124
|
value: zoom,
|
|
4844
|
-
onClick: () =>
|
|
5125
|
+
onClick: () => {
|
|
5126
|
+
isSelected.current = true;
|
|
5127
|
+
},
|
|
4845
5128
|
onChange: (e) => {
|
|
4846
5129
|
setRealZoom(Number(e.target.value) / 100);
|
|
4847
5130
|
setZoom(e.target.value);
|
|
@@ -4884,59 +5167,65 @@ var useSearch = () => {
|
|
|
4884
5167
|
fuzzyMatches: [],
|
|
4885
5168
|
hasMoreResults: false
|
|
4886
5169
|
});
|
|
4887
|
-
const findExactMatches = (
|
|
4888
|
-
|
|
4889
|
-
|
|
4890
|
-
|
|
4891
|
-
|
|
4892
|
-
|
|
4893
|
-
|
|
4894
|
-
|
|
4895
|
-
|
|
4896
|
-
pageNumber,
|
|
4897
|
-
text: text.substr(matchIndex, searchText.length + textSize),
|
|
4898
|
-
score: 1,
|
|
4899
|
-
matchIndex,
|
|
4900
|
-
isExactMatch: true,
|
|
4901
|
-
searchText
|
|
4902
|
-
});
|
|
4903
|
-
index = matchIndex + searchText.length;
|
|
4904
|
-
}
|
|
4905
|
-
return results;
|
|
4906
|
-
};
|
|
4907
|
-
const findFuzzyMatches = (searchText, text, pageNumber, threshold, excludeIndices, textSize) => {
|
|
4908
|
-
const results = [];
|
|
4909
|
-
const textLower = text.toLowerCase();
|
|
4910
|
-
const searchLower = searchText.toLowerCase();
|
|
4911
|
-
let index = 0;
|
|
4912
|
-
while (index < textLower.length) {
|
|
4913
|
-
if (excludeIndices.has(index)) {
|
|
4914
|
-
index++;
|
|
4915
|
-
continue;
|
|
4916
|
-
}
|
|
4917
|
-
const chunk = textLower.substr(index, searchLower.length + 10);
|
|
4918
|
-
const distance = levenshteinDistance(
|
|
4919
|
-
searchLower,
|
|
4920
|
-
chunk.substr(0, searchLower.length)
|
|
4921
|
-
);
|
|
4922
|
-
const maxDistance = Math.floor(searchLower.length * (1 - threshold));
|
|
4923
|
-
if (distance <= maxDistance && distance > 0) {
|
|
4924
|
-
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;
|
|
4925
5179
|
results.push({
|
|
4926
5180
|
pageNumber,
|
|
4927
|
-
text: text.substr(
|
|
4928
|
-
score,
|
|
4929
|
-
matchIndex
|
|
4930
|
-
isExactMatch:
|
|
5181
|
+
text: text.substr(matchIndex, searchText.length + textSize),
|
|
5182
|
+
score: 1,
|
|
5183
|
+
matchIndex,
|
|
5184
|
+
isExactMatch: true,
|
|
4931
5185
|
searchText
|
|
4932
5186
|
});
|
|
4933
|
-
index
|
|
4934
|
-
} else {
|
|
4935
|
-
index++;
|
|
5187
|
+
index = matchIndex + searchText.length;
|
|
4936
5188
|
}
|
|
4937
|
-
|
|
4938
|
-
|
|
4939
|
-
|
|
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
|
+
);
|
|
4940
5229
|
const search = useCallback(
|
|
4941
5230
|
(searchText, options = {}) => {
|
|
4942
5231
|
const { threshold = 0.7, limit = 10, textSize = 100 } = options;
|
|
@@ -4989,7 +5278,7 @@ var useSearch = () => {
|
|
|
4989
5278
|
setSearchResults(limitedResults);
|
|
4990
5279
|
return limitedResults;
|
|
4991
5280
|
},
|
|
4992
|
-
[textContent]
|
|
5281
|
+
[textContent, findExactMatches, findFuzzyMatches]
|
|
4993
5282
|
);
|
|
4994
5283
|
return {
|
|
4995
5284
|
textContent,
|