@anaralabs/lector 3.5.7 → 3.5.9
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 +9 -6
- package/dist/index.d.ts +1 -0
- package/dist/index.js +223 -43
- package/package.json +1 -1
|
@@ -46,10 +46,7 @@ export declare const AnnotationHighlightLayer: ({ className, style, renderToolti
|
|
|
46
46
|
declare interface AnnotationHighlightLayerProps {
|
|
47
47
|
className?: string;
|
|
48
48
|
style?: React.CSSProperties;
|
|
49
|
-
renderTooltipContent: (props:
|
|
50
|
-
annotation: Annotation;
|
|
51
|
-
onClose: () => void;
|
|
52
|
-
}) => React.ReactNode;
|
|
49
|
+
renderTooltipContent: (props: AnnotationTooltipContentProps) => React.ReactNode;
|
|
53
50
|
renderHoverTooltipContent: (props: {
|
|
54
51
|
annotation: Annotation;
|
|
55
52
|
onClose: () => void;
|
|
@@ -100,12 +97,18 @@ declare interface AnnotationState {
|
|
|
100
97
|
setAnnotations: (annotations: Annotation[]) => void;
|
|
101
98
|
}
|
|
102
99
|
|
|
103
|
-
export declare const AnnotationTooltip: ({ annotation, children,
|
|
100
|
+
export declare const AnnotationTooltip: ({ annotation, children, renderTooltipContent, hoverTooltipContent, onOpenChange, className, hoverClassName, isOpen: controlledIsOpen, tooltipBubbleSize, hoverIsOpen: controlledHoverIsOpen, }: AnnotationTooltipProps) => JSX.Element;
|
|
101
|
+
|
|
102
|
+
export declare type AnnotationTooltipContentProps = {
|
|
103
|
+
annotation: Annotation;
|
|
104
|
+
onClose: () => void;
|
|
105
|
+
setPosition?: (position: 'top' | 'bottom' | undefined) => void;
|
|
106
|
+
};
|
|
104
107
|
|
|
105
108
|
declare interface AnnotationTooltipProps {
|
|
106
109
|
annotation: Annotation;
|
|
107
110
|
children: React.ReactNode;
|
|
108
|
-
|
|
111
|
+
renderTooltipContent: (props: AnnotationTooltipContentProps) => React.ReactNode;
|
|
109
112
|
hoverTooltipContent?: React.ReactNode;
|
|
110
113
|
onOpenChange?: (open: boolean) => void;
|
|
111
114
|
isOpen?: boolean;
|
package/dist/index.d.ts
CHANGED
package/dist/index.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
'use client';
|
|
2
2
|
|
|
3
|
-
import React, { createContext, forwardRef, useRef, useCallback, useContext,
|
|
3
|
+
import React, { createContext, forwardRef, useRef, useState, useCallback, useContext, useEffect, cloneElement, createRef, 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
6
|
import { useVirtualizer, elementScroll, debounce } from '@tanstack/react-virtual';
|
|
@@ -270,7 +270,7 @@ var useAnnotationTooltip = ({
|
|
|
270
270
|
var AnnotationTooltip = ({
|
|
271
271
|
annotation,
|
|
272
272
|
children,
|
|
273
|
-
|
|
273
|
+
renderTooltipContent,
|
|
274
274
|
hoverTooltipContent,
|
|
275
275
|
onOpenChange,
|
|
276
276
|
className,
|
|
@@ -282,6 +282,7 @@ var AnnotationTooltip = ({
|
|
|
282
282
|
const viewportRef = usePdf((state) => state.viewportRef);
|
|
283
283
|
const closeTimeoutRef = useRef(null);
|
|
284
284
|
const isMouseInTooltipRef = useRef(false);
|
|
285
|
+
const [triggeredPosition, setTriggeredPosition] = useState();
|
|
285
286
|
const {
|
|
286
287
|
isOpen: uncontrolledIsOpen,
|
|
287
288
|
setIsOpen,
|
|
@@ -292,6 +293,7 @@ var AnnotationTooltip = ({
|
|
|
292
293
|
} = useAnnotationTooltip({
|
|
293
294
|
annotation,
|
|
294
295
|
onOpenChange,
|
|
296
|
+
position: triggeredPosition,
|
|
295
297
|
isOpen: controlledIsOpen
|
|
296
298
|
});
|
|
297
299
|
const {
|
|
@@ -383,7 +385,11 @@ var AnnotationTooltip = ({
|
|
|
383
385
|
zIndex: 50
|
|
384
386
|
},
|
|
385
387
|
...getFloatingProps(),
|
|
386
|
-
children:
|
|
388
|
+
children: renderTooltipContent({
|
|
389
|
+
annotation,
|
|
390
|
+
onClose: () => setIsOpen(false),
|
|
391
|
+
setPosition: (position) => setTriggeredPosition(position)
|
|
392
|
+
})
|
|
387
393
|
}
|
|
388
394
|
),
|
|
389
395
|
viewportRef.current
|
|
@@ -468,11 +474,7 @@ var AnnotationHighlightLayer = ({
|
|
|
468
474
|
onAnnotationClick(annotation);
|
|
469
475
|
}
|
|
470
476
|
},
|
|
471
|
-
|
|
472
|
-
annotation,
|
|
473
|
-
onClose: () => {
|
|
474
|
-
}
|
|
475
|
-
}),
|
|
477
|
+
renderTooltipContent,
|
|
476
478
|
hoverTooltipContent: renderHoverTooltipContent({
|
|
477
479
|
annotation,
|
|
478
480
|
onClose: () => {
|
|
@@ -1053,39 +1055,69 @@ var shouldMergeRects = (rect1, rect2) => {
|
|
|
1053
1055
|
const horizontallyClose = Math.abs(rect1.left + rect1.width - rect2.left) < MERGE_THRESHOLD || Math.abs(rect2.left + rect2.width - rect1.left) < MERGE_THRESHOLD || rect1.left < rect2.left + rect2.width && rect2.left < rect1.left + rect1.width;
|
|
1054
1056
|
return verticalOverlap && horizontallyClose;
|
|
1055
1057
|
};
|
|
1056
|
-
var mergeRects = (rect1, rect2) => {
|
|
1057
|
-
return {
|
|
1058
|
-
left: Math.min(rect1.left, rect2.left),
|
|
1059
|
-
top: Math.min(rect1.top, rect2.top),
|
|
1060
|
-
width: Math.max(rect1.left + rect1.width, rect2.left + rect2.width) - Math.min(rect1.left, rect2.left),
|
|
1061
|
-
height: Math.max(rect1.top + rect1.height, rect2.top + rect2.height) - Math.min(rect1.top, rect2.top),
|
|
1062
|
-
pageNumber: rect1.pageNumber
|
|
1063
|
-
};
|
|
1064
|
-
};
|
|
1065
1058
|
var consolidateRects = (rects) => {
|
|
1066
1059
|
if (rects.length <= 1) return rects;
|
|
1067
|
-
const
|
|
1068
|
-
|
|
1069
|
-
|
|
1070
|
-
|
|
1071
|
-
|
|
1072
|
-
|
|
1073
|
-
|
|
1074
|
-
|
|
1075
|
-
|
|
1076
|
-
|
|
1077
|
-
|
|
1078
|
-
|
|
1079
|
-
|
|
1080
|
-
|
|
1081
|
-
|
|
1060
|
+
const result = [];
|
|
1061
|
+
const visited = /* @__PURE__ */ new Set();
|
|
1062
|
+
for (let i = 0; i < rects.length; i++) {
|
|
1063
|
+
if (visited.has(i)) continue;
|
|
1064
|
+
const currentRect = rects[i];
|
|
1065
|
+
if (!currentRect) continue;
|
|
1066
|
+
const currentGroup = [currentRect];
|
|
1067
|
+
visited.add(i);
|
|
1068
|
+
let foundNew = true;
|
|
1069
|
+
while (foundNew) {
|
|
1070
|
+
foundNew = false;
|
|
1071
|
+
for (let j = 0; j < rects.length; j++) {
|
|
1072
|
+
if (visited.has(j)) continue;
|
|
1073
|
+
const candidateRect = rects[j];
|
|
1074
|
+
if (!candidateRect) continue;
|
|
1075
|
+
const shouldMergeWithGroup = currentGroup.some(
|
|
1076
|
+
(groupRect) => doRectsOverlap(groupRect, candidateRect)
|
|
1077
|
+
);
|
|
1078
|
+
if (shouldMergeWithGroup) {
|
|
1079
|
+
currentGroup.push(candidateRect);
|
|
1080
|
+
visited.add(j);
|
|
1081
|
+
foundNew = true;
|
|
1082
|
+
}
|
|
1082
1083
|
}
|
|
1083
1084
|
}
|
|
1084
|
-
|
|
1085
|
-
|
|
1086
|
-
|
|
1087
|
-
|
|
1088
|
-
|
|
1085
|
+
result.push(mergeRectGroup(currentGroup));
|
|
1086
|
+
}
|
|
1087
|
+
return result;
|
|
1088
|
+
};
|
|
1089
|
+
var doRectsOverlap = (rect1, rect2) => {
|
|
1090
|
+
const horizontalOverlap = rect1.left < rect2.left + rect2.width && rect2.left < rect1.left + rect1.width;
|
|
1091
|
+
const verticalOverlap = rect1.top < rect2.top + rect2.height && rect2.top < rect1.top + rect1.height;
|
|
1092
|
+
const closeEnough = shouldMergeRects(rect1, rect2);
|
|
1093
|
+
return horizontalOverlap && verticalOverlap || closeEnough;
|
|
1094
|
+
};
|
|
1095
|
+
var mergeRectGroup = (rects) => {
|
|
1096
|
+
if (rects.length === 1) {
|
|
1097
|
+
const rect = rects[0];
|
|
1098
|
+
if (!rect) throw new Error("Invalid rect in group");
|
|
1099
|
+
return rect;
|
|
1100
|
+
}
|
|
1101
|
+
const firstRect = rects[0];
|
|
1102
|
+
if (!firstRect) throw new Error("Invalid first rect in group");
|
|
1103
|
+
let minLeft = firstRect.left;
|
|
1104
|
+
let minTop = firstRect.top;
|
|
1105
|
+
let maxRight = firstRect.left + firstRect.width;
|
|
1106
|
+
let maxBottom = firstRect.top + firstRect.height;
|
|
1107
|
+
rects.forEach((rect) => {
|
|
1108
|
+
if (!rect) return;
|
|
1109
|
+
minLeft = Math.min(minLeft, rect.left);
|
|
1110
|
+
minTop = Math.min(minTop, rect.top);
|
|
1111
|
+
maxRight = Math.max(maxRight, rect.left + rect.width);
|
|
1112
|
+
maxBottom = Math.max(maxBottom, rect.top + rect.height);
|
|
1113
|
+
});
|
|
1114
|
+
return {
|
|
1115
|
+
left: minLeft,
|
|
1116
|
+
top: minTop,
|
|
1117
|
+
width: maxRight - minLeft,
|
|
1118
|
+
height: maxBottom - minTop,
|
|
1119
|
+
pageNumber: firstRect.pageNumber
|
|
1120
|
+
};
|
|
1089
1121
|
};
|
|
1090
1122
|
var useSelectionDimensions = () => {
|
|
1091
1123
|
const store = PDFStore.useContext();
|
|
@@ -1125,7 +1157,8 @@ var useSelectionDimensions = () => {
|
|
|
1125
1157
|
});
|
|
1126
1158
|
textLayerMap.forEach((rects) => {
|
|
1127
1159
|
if (rects.length > 0) {
|
|
1128
|
-
|
|
1160
|
+
const consolidated = consolidateRects(rects);
|
|
1161
|
+
highlights.push(...consolidated);
|
|
1129
1162
|
}
|
|
1130
1163
|
});
|
|
1131
1164
|
return {
|
|
@@ -1520,24 +1553,171 @@ var HighlightLayer = forwardRef(({ asChild, className, style, ...props }, ref) =
|
|
|
1520
1553
|
}) });
|
|
1521
1554
|
});
|
|
1522
1555
|
HighlightLayer.displayName = "HighlightLayer";
|
|
1556
|
+
var createTextSelectionManager = () => {
|
|
1557
|
+
const textLayers = /* @__PURE__ */ new Map();
|
|
1558
|
+
let selectionChangeAbortController = null;
|
|
1559
|
+
let isPointerDown = false;
|
|
1560
|
+
let prevRange = null;
|
|
1561
|
+
let isFirefox;
|
|
1562
|
+
const removeGlobalSelectionListener = (textLayerDiv) => {
|
|
1563
|
+
textLayers.delete(textLayerDiv);
|
|
1564
|
+
if (textLayers.size === 0) {
|
|
1565
|
+
selectionChangeAbortController?.abort();
|
|
1566
|
+
selectionChangeAbortController = null;
|
|
1567
|
+
}
|
|
1568
|
+
};
|
|
1569
|
+
const enableGlobalSelectionListener = () => {
|
|
1570
|
+
if (selectionChangeAbortController) {
|
|
1571
|
+
return;
|
|
1572
|
+
}
|
|
1573
|
+
selectionChangeAbortController = new AbortController();
|
|
1574
|
+
const { signal } = selectionChangeAbortController;
|
|
1575
|
+
const reset = (endDiv, textLayer) => {
|
|
1576
|
+
if (endDiv.parentNode !== textLayer) {
|
|
1577
|
+
textLayer.appendChild(endDiv);
|
|
1578
|
+
}
|
|
1579
|
+
endDiv.style.width = "";
|
|
1580
|
+
endDiv.style.height = "";
|
|
1581
|
+
textLayer.classList.remove("selecting");
|
|
1582
|
+
};
|
|
1583
|
+
document.addEventListener("pointerdown", () => {
|
|
1584
|
+
isPointerDown = true;
|
|
1585
|
+
}, { signal });
|
|
1586
|
+
document.addEventListener("pointerup", () => {
|
|
1587
|
+
isPointerDown = false;
|
|
1588
|
+
textLayers.forEach(reset);
|
|
1589
|
+
}, { signal });
|
|
1590
|
+
window.addEventListener("blur", () => {
|
|
1591
|
+
isPointerDown = false;
|
|
1592
|
+
textLayers.forEach(reset);
|
|
1593
|
+
}, { signal });
|
|
1594
|
+
document.addEventListener("keyup", () => {
|
|
1595
|
+
if (!isPointerDown) {
|
|
1596
|
+
textLayers.forEach(reset);
|
|
1597
|
+
}
|
|
1598
|
+
}, { signal });
|
|
1599
|
+
document.addEventListener("selectionchange", () => {
|
|
1600
|
+
const selection = document.getSelection();
|
|
1601
|
+
if (!selection || selection.rangeCount === 0) {
|
|
1602
|
+
textLayers.forEach(reset);
|
|
1603
|
+
return;
|
|
1604
|
+
}
|
|
1605
|
+
const activeTextLayers = /* @__PURE__ */ new Set();
|
|
1606
|
+
for (let i = 0; i < selection.rangeCount; i++) {
|
|
1607
|
+
const range = selection.getRangeAt(i);
|
|
1608
|
+
for (const textLayerDiv of textLayers.keys()) {
|
|
1609
|
+
if (!activeTextLayers.has(textLayerDiv) && range.intersectsNode(textLayerDiv)) {
|
|
1610
|
+
activeTextLayers.add(textLayerDiv);
|
|
1611
|
+
}
|
|
1612
|
+
}
|
|
1613
|
+
}
|
|
1614
|
+
for (const [textLayerDiv, endDiv] of textLayers) {
|
|
1615
|
+
if (activeTextLayers.has(textLayerDiv)) {
|
|
1616
|
+
textLayerDiv.classList.add("selecting");
|
|
1617
|
+
} else {
|
|
1618
|
+
reset(endDiv, textLayerDiv);
|
|
1619
|
+
}
|
|
1620
|
+
}
|
|
1621
|
+
if (isFirefox === void 0) {
|
|
1622
|
+
const firstTextLayer = textLayers.keys().next().value;
|
|
1623
|
+
if (firstTextLayer) {
|
|
1624
|
+
isFirefox = getComputedStyle(firstTextLayer).getPropertyValue("-moz-user-select") === "none";
|
|
1625
|
+
}
|
|
1626
|
+
}
|
|
1627
|
+
if (isFirefox) {
|
|
1628
|
+
return;
|
|
1629
|
+
}
|
|
1630
|
+
try {
|
|
1631
|
+
const range = selection.getRangeAt(0);
|
|
1632
|
+
const modifyStart = prevRange && (range.compareBoundaryPoints(Range.END_TO_END, prevRange) === 0 || range.compareBoundaryPoints(Range.START_TO_END, prevRange) === 0);
|
|
1633
|
+
let anchor = modifyStart ? range.startContainer : range.endContainer;
|
|
1634
|
+
if (anchor.nodeType === Node.TEXT_NODE) {
|
|
1635
|
+
anchor = anchor.parentNode;
|
|
1636
|
+
}
|
|
1637
|
+
const parentTextLayer = anchor.parentElement?.closest(".textLayer");
|
|
1638
|
+
const endDiv = textLayers.get(parentTextLayer);
|
|
1639
|
+
if (endDiv && parentTextLayer) {
|
|
1640
|
+
endDiv.style.width = parentTextLayer.style.width;
|
|
1641
|
+
endDiv.style.height = parentTextLayer.style.height;
|
|
1642
|
+
const insertTarget = modifyStart ? anchor : anchor.nextSibling;
|
|
1643
|
+
if (anchor.parentElement && insertTarget) {
|
|
1644
|
+
anchor.parentElement.insertBefore(endDiv, insertTarget);
|
|
1645
|
+
}
|
|
1646
|
+
}
|
|
1647
|
+
prevRange = range.cloneRange();
|
|
1648
|
+
} catch {
|
|
1649
|
+
}
|
|
1650
|
+
}, { signal });
|
|
1651
|
+
};
|
|
1652
|
+
const bindMouseEvents2 = (textLayerDiv, endOfContent) => {
|
|
1653
|
+
if (textLayerDiv._textSelectionBound) {
|
|
1654
|
+
return;
|
|
1655
|
+
}
|
|
1656
|
+
textLayerDiv._textSelectionBound = true;
|
|
1657
|
+
textLayers.set(textLayerDiv, endOfContent);
|
|
1658
|
+
enableGlobalSelectionListener();
|
|
1659
|
+
const handleMouseDown = () => {
|
|
1660
|
+
textLayerDiv.classList.add("selecting");
|
|
1661
|
+
};
|
|
1662
|
+
textLayerDiv.addEventListener("mousedown", handleMouseDown);
|
|
1663
|
+
textLayerDiv._cleanupTextSelection = () => {
|
|
1664
|
+
textLayerDiv.removeEventListener("mousedown", handleMouseDown);
|
|
1665
|
+
removeGlobalSelectionListener(textLayerDiv);
|
|
1666
|
+
delete textLayerDiv._textSelectionBound;
|
|
1667
|
+
};
|
|
1668
|
+
};
|
|
1669
|
+
return bindMouseEvents2;
|
|
1670
|
+
};
|
|
1671
|
+
var bindMouseEvents = createTextSelectionManager();
|
|
1523
1672
|
var useTextLayer = () => {
|
|
1524
1673
|
const textContainerRef = useRef(null);
|
|
1674
|
+
const textLayerRef = useRef(null);
|
|
1675
|
+
const isRenderingRef = useRef(false);
|
|
1525
1676
|
const pageNumber = usePDFPageNumber();
|
|
1526
1677
|
const pdfPageProxy = usePdf((state) => state.getPdfPageProxy(pageNumber));
|
|
1527
1678
|
useEffect(() => {
|
|
1528
|
-
|
|
1679
|
+
const textContainer = textContainerRef.current;
|
|
1680
|
+
if (!textContainer || isRenderingRef.current) {
|
|
1529
1681
|
return;
|
|
1530
1682
|
}
|
|
1683
|
+
isRenderingRef.current = true;
|
|
1684
|
+
textContainer.innerHTML = "";
|
|
1685
|
+
if (textLayerRef.current) {
|
|
1686
|
+
textLayerRef.current.cancel();
|
|
1687
|
+
textLayerRef.current = null;
|
|
1688
|
+
}
|
|
1531
1689
|
const textLayer = new TextLayer({
|
|
1532
1690
|
textContentSource: pdfPageProxy.streamTextContent(),
|
|
1533
|
-
container:
|
|
1691
|
+
container: textContainer,
|
|
1534
1692
|
viewport: pdfPageProxy.getViewport({ scale: 1 })
|
|
1535
1693
|
});
|
|
1536
|
-
|
|
1694
|
+
textLayerRef.current = textLayer;
|
|
1695
|
+
textLayer.render().then(() => {
|
|
1696
|
+
if (textLayerRef.current === textLayer && textContainer) {
|
|
1697
|
+
const endOfContent = document.createElement("div");
|
|
1698
|
+
endOfContent.className = "endOfContent";
|
|
1699
|
+
textContainer.appendChild(endOfContent);
|
|
1700
|
+
bindMouseEvents(textContainer, endOfContent);
|
|
1701
|
+
}
|
|
1702
|
+
}).catch((error) => {
|
|
1703
|
+
if (error.name !== "AbortException") {
|
|
1704
|
+
console.error("TextLayer rendering error:", error);
|
|
1705
|
+
}
|
|
1706
|
+
}).finally(() => {
|
|
1707
|
+
isRenderingRef.current = false;
|
|
1708
|
+
});
|
|
1537
1709
|
return () => {
|
|
1538
|
-
|
|
1710
|
+
isRenderingRef.current = false;
|
|
1711
|
+
if (textLayerRef.current) {
|
|
1712
|
+
textLayerRef.current.cancel();
|
|
1713
|
+
textLayerRef.current = null;
|
|
1714
|
+
}
|
|
1715
|
+
if (textContainer?._cleanupTextSelection) {
|
|
1716
|
+
textContainer._cleanupTextSelection();
|
|
1717
|
+
delete textContainer._cleanupTextSelection;
|
|
1718
|
+
}
|
|
1539
1719
|
};
|
|
1540
|
-
}, [pdfPageProxy]);
|
|
1720
|
+
}, [pdfPageProxy.pageNumber]);
|
|
1541
1721
|
return {
|
|
1542
1722
|
textContainerRef,
|
|
1543
1723
|
pageNumber: pdfPageProxy.pageNumber
|