react-pdf-highlighter-plus 1.2.0 → 1.3.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/esm/{export-pdf-W2QGWADM.js → export-pdf-DD7J5UHW.js} +113 -15
- package/dist/esm/export-pdf-DD7J5UHW.js.map +1 -0
- package/dist/esm/index.d.ts +45 -8
- package/dist/esm/index.js +1553 -988
- package/dist/esm/index.js.map +1 -1
- package/dist/esm/pdf.worker.min.mjs +2 -2
- package/dist/esm/style/AreaHighlight.css +178 -73
- package/dist/esm/style/DrawingCanvas.css +24 -16
- package/dist/esm/style/DrawingHighlight.css +193 -61
- package/dist/esm/style/FreetextHighlight.css +217 -76
- package/dist/esm/style/ImageHighlight.css +98 -26
- package/dist/esm/style/MouseSelection.css +2 -2
- package/dist/esm/style/PdfHighlighter.css +29 -15
- package/dist/esm/style/ShapeCanvas.css +18 -12
- package/dist/esm/style/ShapeHighlight.css +142 -72
- package/dist/esm/style/SignaturePad.css +154 -38
- package/dist/esm/style/TextHighlight.css +205 -75
- package/dist/esm/style/style.css +1 -0
- package/dist/esm/style/tokens.css +88 -0
- package/package.json +32 -16
- package/dist/esm/export-pdf-W2QGWADM.js.map +0 -1
package/dist/esm/index.js
CHANGED
|
@@ -1,15 +1,12 @@
|
|
|
1
|
-
|
|
2
|
-
import
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
} from "react";
|
|
9
|
-
import { createRoot } from "react-dom/client";
|
|
1
|
+
import React11, { createContext, memo, useState, useRef, useEffect, useLayoutEffect, useContext, useCallback, useMemo } from 'react';
|
|
2
|
+
import { createRoot } from 'react-dom/client';
|
|
3
|
+
import { createPortal } from 'react-dom';
|
|
4
|
+
import { Loader2, AlertCircle, ChevronDown, Palette, Check, Copy, Trash2, Highlighter, Underline, Strikethrough, RotateCcw, RotateCw, Pencil, ChevronRight, FileQuestion, ChevronLeft, FileText, List, StickyNote, Minimize2 } from 'lucide-react';
|
|
5
|
+
import { Rnd } from 'react-rnd';
|
|
6
|
+
import { GlobalWorkerOptions, getDocument as getDocument$1 } from 'pdfjs-dist';
|
|
7
|
+
import { useVirtualizer } from '@tanstack/react-virtual';
|
|
10
8
|
|
|
11
|
-
// src/
|
|
12
|
-
import { createContext, useContext } from "react";
|
|
9
|
+
// src/components/PdfHighlighter.tsx
|
|
13
10
|
var PdfHighlighterContext = createContext(void 0);
|
|
14
11
|
var usePdfHighlighterContext = () => {
|
|
15
12
|
const pdfHighlighterUtils = useContext(PdfHighlighterContext);
|
|
@@ -20,6 +17,15 @@ var usePdfHighlighterContext = () => {
|
|
|
20
17
|
}
|
|
21
18
|
return pdfHighlighterUtils;
|
|
22
19
|
};
|
|
20
|
+
var useClearTipWhileSelected = (isSelected) => {
|
|
21
|
+
const pdfHighlighterUtils = useContext(PdfHighlighterContext);
|
|
22
|
+
useEffect(() => {
|
|
23
|
+
if (!isSelected || !pdfHighlighterUtils) return;
|
|
24
|
+
pdfHighlighterUtils.setTip(null);
|
|
25
|
+
pdfHighlighterUtils.setHighlightSelected(true);
|
|
26
|
+
return () => pdfHighlighterUtils.setHighlightSelected(false);
|
|
27
|
+
}, [isSelected, pdfHighlighterUtils]);
|
|
28
|
+
};
|
|
23
29
|
|
|
24
30
|
// src/lib/coordinates.ts
|
|
25
31
|
var viewportToScaled = (rect, { width, height }) => {
|
|
@@ -542,8 +548,10 @@ var groupHighlightsByPage = (highlights) => highlights.reduce((acc, highlight) =
|
|
|
542
548
|
return acc;
|
|
543
549
|
}
|
|
544
550
|
const pageNumbers = [
|
|
545
|
-
|
|
546
|
-
|
|
551
|
+
.../* @__PURE__ */ new Set([
|
|
552
|
+
highlight.position.boundingRect.pageNumber,
|
|
553
|
+
...highlight.position.rects.map((rect) => rect.pageNumber || 0)
|
|
554
|
+
])
|
|
547
555
|
];
|
|
548
556
|
pageNumbers.forEach((pageNumber) => {
|
|
549
557
|
acc[pageNumber] ||= [];
|
|
@@ -609,14 +617,6 @@ var getPagesFromRange = (range) => {
|
|
|
609
617
|
}
|
|
610
618
|
return pages;
|
|
611
619
|
};
|
|
612
|
-
|
|
613
|
-
// src/components/DrawingCanvas.tsx
|
|
614
|
-
import React, {
|
|
615
|
-
useRef,
|
|
616
|
-
useEffect,
|
|
617
|
-
useCallback,
|
|
618
|
-
useState
|
|
619
|
-
} from "react";
|
|
620
620
|
var DrawingCanvas = ({
|
|
621
621
|
isActive,
|
|
622
622
|
strokeColor = "#000000",
|
|
@@ -631,6 +631,9 @@ var DrawingCanvas = ({
|
|
|
631
631
|
const isDrawingRef = useRef(false);
|
|
632
632
|
const [pageNumber, setPageNumber] = useState(null);
|
|
633
633
|
const [pageElement, setPageElement] = useState(null);
|
|
634
|
+
const cancelledRef = useRef(false);
|
|
635
|
+
const commitRef = useRef(() => {
|
|
636
|
+
});
|
|
634
637
|
const findPageFromPoint = useCallback(
|
|
635
638
|
(clientX, clientY) => {
|
|
636
639
|
if (!viewer) return null;
|
|
@@ -777,23 +780,16 @@ var DrawingCanvas = ({
|
|
|
777
780
|
const handleKeyDown = (e) => {
|
|
778
781
|
if (e.code === "Escape") {
|
|
779
782
|
console.log("DrawingCanvas: Cancelled via Escape");
|
|
783
|
+
cancelledRef.current = true;
|
|
780
784
|
onCancel();
|
|
781
785
|
}
|
|
782
786
|
};
|
|
783
787
|
document.addEventListener("keydown", handleKeyDown);
|
|
784
788
|
return () => document.removeEventListener("keydown", handleKeyDown);
|
|
785
789
|
}, [isActive, onCancel]);
|
|
786
|
-
const
|
|
787
|
-
console.log("DrawingCanvas: Cleared strokes");
|
|
788
|
-
setStrokes([]);
|
|
789
|
-
setCurrentStroke(null);
|
|
790
|
-
setPageNumber(null);
|
|
791
|
-
setPageElement(null);
|
|
792
|
-
};
|
|
793
|
-
const handleDone = () => {
|
|
790
|
+
const commitDrawing = () => {
|
|
794
791
|
if (strokes.length === 0 || pageNumber === null || !pageElement || !viewer) {
|
|
795
792
|
console.log("DrawingCanvas: No strokes to save");
|
|
796
|
-
onCancel();
|
|
797
793
|
return;
|
|
798
794
|
}
|
|
799
795
|
console.log("DrawingCanvas: Completing drawing with", strokes.length, "strokes");
|
|
@@ -820,7 +816,6 @@ var DrawingCanvas = ({
|
|
|
820
816
|
const outputCtx = outputCanvas.getContext("2d");
|
|
821
817
|
if (!outputCtx) {
|
|
822
818
|
console.error("DrawingCanvas: Could not get output canvas context");
|
|
823
|
-
onCancel();
|
|
824
819
|
return;
|
|
825
820
|
}
|
|
826
821
|
strokes.forEach((stroke) => {
|
|
@@ -857,13 +852,15 @@ var DrawingCanvas = ({
|
|
|
857
852
|
}));
|
|
858
853
|
console.log("DrawingCanvas: Created drawing at position", scaledPosition);
|
|
859
854
|
onComplete(dataUrl, scaledPosition, normalizedStrokes);
|
|
860
|
-
setStrokes([]);
|
|
861
|
-
setCurrentStroke(null);
|
|
862
|
-
setPageNumber(null);
|
|
863
|
-
setPageElement(null);
|
|
864
855
|
};
|
|
856
|
+
commitRef.current = commitDrawing;
|
|
857
|
+
useEffect(() => {
|
|
858
|
+
return () => {
|
|
859
|
+
if (!cancelledRef.current) commitRef.current();
|
|
860
|
+
};
|
|
861
|
+
}, []);
|
|
865
862
|
if (!isActive) return null;
|
|
866
|
-
return /* @__PURE__ */
|
|
863
|
+
return /* @__PURE__ */ React11.createElement(
|
|
867
864
|
"canvas",
|
|
868
865
|
{
|
|
869
866
|
ref: canvasRef,
|
|
@@ -881,41 +878,11 @@ var DrawingCanvas = ({
|
|
|
881
878
|
onTouchMove: handleTouchMove,
|
|
882
879
|
onTouchEnd: handleTouchEnd
|
|
883
880
|
}
|
|
884
|
-
)
|
|
885
|
-
"button",
|
|
886
|
-
{
|
|
887
|
-
type: "button",
|
|
888
|
-
className: "DrawingCanvas__clearButton",
|
|
889
|
-
onClick: handleClear
|
|
890
|
-
},
|
|
891
|
-
"Clear"
|
|
892
|
-
), /* @__PURE__ */ React.createElement(
|
|
893
|
-
"button",
|
|
894
|
-
{
|
|
895
|
-
type: "button",
|
|
896
|
-
className: "DrawingCanvas__cancelButton",
|
|
897
|
-
onClick: onCancel
|
|
898
|
-
},
|
|
899
|
-
"Cancel"
|
|
900
|
-
), /* @__PURE__ */ React.createElement(
|
|
901
|
-
"button",
|
|
902
|
-
{
|
|
903
|
-
type: "button",
|
|
904
|
-
className: "DrawingCanvas__doneButton",
|
|
905
|
-
onClick: handleDone
|
|
906
|
-
},
|
|
907
|
-
"Done"
|
|
908
|
-
)));
|
|
881
|
+
);
|
|
909
882
|
};
|
|
910
|
-
|
|
911
|
-
// src/components/HighlightLayer.tsx
|
|
912
|
-
import React2 from "react";
|
|
913
|
-
|
|
914
|
-
// src/contexts/HighlightContext.ts
|
|
915
|
-
import { createContext as createContext2, useContext as useContext2 } from "react";
|
|
916
|
-
var HighlightContext = createContext2(void 0);
|
|
883
|
+
var HighlightContext = createContext(void 0);
|
|
917
884
|
var useHighlightContainerContext = () => {
|
|
918
|
-
const highlightContainerUtils =
|
|
885
|
+
const highlightContainerUtils = useContext(HighlightContext);
|
|
919
886
|
if (highlightContainerUtils === void 0) {
|
|
920
887
|
throw new Error(
|
|
921
888
|
"useHighlightContainerContext must be used within a child of PdfHighlighter!"
|
|
@@ -971,7 +938,7 @@ var HighlightLayer = ({
|
|
|
971
938
|
const currentHighlights = (highlightsByPage[pageNumber] || []).filter(
|
|
972
939
|
(highlight) => shouldRenderHighlight?.(highlight) ?? true
|
|
973
940
|
);
|
|
974
|
-
return /* @__PURE__ */
|
|
941
|
+
return /* @__PURE__ */ React11.createElement("div", null, currentHighlights.map((highlight, index) => {
|
|
975
942
|
const viewportHighlight = {
|
|
976
943
|
...highlight,
|
|
977
944
|
id: "id" in highlight ? highlight.id : EMPTY_ID,
|
|
@@ -994,12 +961,9 @@ var HighlightLayer = ({
|
|
|
994
961
|
isScrolledTo,
|
|
995
962
|
highlightBindings
|
|
996
963
|
};
|
|
997
|
-
return /* @__PURE__ */
|
|
964
|
+
return /* @__PURE__ */ React11.createElement(HighlightContext.Provider, { value: highlightUtils, key: index }, children);
|
|
998
965
|
}));
|
|
999
966
|
};
|
|
1000
|
-
|
|
1001
|
-
// src/components/MouseSelection.tsx
|
|
1002
|
-
import React3, { useEffect as useEffect2, useRef as useRef2, useState as useState2 } from "react";
|
|
1003
967
|
var getBoundingRect2 = (start, end) => {
|
|
1004
968
|
return {
|
|
1005
969
|
left: Math.min(end.x, start.x),
|
|
@@ -1024,18 +988,18 @@ var MouseSelection = ({
|
|
|
1024
988
|
onChange,
|
|
1025
989
|
style
|
|
1026
990
|
}) => {
|
|
1027
|
-
const [start, setStart] =
|
|
1028
|
-
const [end, setEnd] =
|
|
1029
|
-
const [locked, setLocked] =
|
|
1030
|
-
const rootRef =
|
|
1031
|
-
const startTargetRef =
|
|
991
|
+
const [start, setStart] = useState(null);
|
|
992
|
+
const [end, setEnd] = useState(null);
|
|
993
|
+
const [locked, setLocked] = useState(false);
|
|
994
|
+
const rootRef = useRef(null);
|
|
995
|
+
const startTargetRef = useRef(null);
|
|
1032
996
|
const reset = () => {
|
|
1033
997
|
onReset && onReset();
|
|
1034
998
|
setStart(null);
|
|
1035
999
|
setEnd(null);
|
|
1036
1000
|
setLocked(false);
|
|
1037
1001
|
};
|
|
1038
|
-
|
|
1002
|
+
useEffect(() => {
|
|
1039
1003
|
onChange && onChange(Boolean(start && end));
|
|
1040
1004
|
if (!rootRef.current) return;
|
|
1041
1005
|
const container = asElement(rootRef.current.parentElement);
|
|
@@ -1094,7 +1058,7 @@ var MouseSelection = ({
|
|
|
1094
1058
|
document.removeEventListener("mouseup", handleMouseUp);
|
|
1095
1059
|
};
|
|
1096
1060
|
}, [start, end, enableAreaSelection]);
|
|
1097
|
-
return /* @__PURE__ */
|
|
1061
|
+
return /* @__PURE__ */ React11.createElement("div", { className: "MouseSelection-container", ref: rootRef }, start && end && /* @__PURE__ */ React11.createElement(
|
|
1098
1062
|
"div",
|
|
1099
1063
|
{
|
|
1100
1064
|
className: "MouseSelection",
|
|
@@ -1102,14 +1066,6 @@ var MouseSelection = ({
|
|
|
1102
1066
|
}
|
|
1103
1067
|
));
|
|
1104
1068
|
};
|
|
1105
|
-
|
|
1106
|
-
// src/components/ShapeCanvas.tsx
|
|
1107
|
-
import React4, {
|
|
1108
|
-
useRef as useRef3,
|
|
1109
|
-
useEffect as useEffect3,
|
|
1110
|
-
useCallback as useCallback2,
|
|
1111
|
-
useState as useState3
|
|
1112
|
-
} from "react";
|
|
1113
1069
|
var ShapeCanvas = ({
|
|
1114
1070
|
isActive,
|
|
1115
1071
|
shapeType,
|
|
@@ -1119,13 +1075,13 @@ var ShapeCanvas = ({
|
|
|
1119
1075
|
onComplete,
|
|
1120
1076
|
onCancel
|
|
1121
1077
|
}) => {
|
|
1122
|
-
const containerRef =
|
|
1123
|
-
const [startPoint, setStartPoint] =
|
|
1124
|
-
const [currentPoint, setCurrentPoint] =
|
|
1125
|
-
const [pageNumber, setPageNumber] =
|
|
1126
|
-
const [pageRect, setPageRect] =
|
|
1127
|
-
const isDrawingRef =
|
|
1128
|
-
const findPageFromPoint =
|
|
1078
|
+
const containerRef = useRef(null);
|
|
1079
|
+
const [startPoint, setStartPoint] = useState(null);
|
|
1080
|
+
const [currentPoint, setCurrentPoint] = useState(null);
|
|
1081
|
+
const [pageNumber, setPageNumber] = useState(null);
|
|
1082
|
+
const [pageRect, setPageRect] = useState(null);
|
|
1083
|
+
const isDrawingRef = useRef(false);
|
|
1084
|
+
const findPageFromPoint = useCallback(
|
|
1129
1085
|
(clientX, clientY) => {
|
|
1130
1086
|
if (!viewer) return null;
|
|
1131
1087
|
for (let i = 0; i < viewer.pagesCount; i++) {
|
|
@@ -1144,7 +1100,7 @@ var ShapeCanvas = ({
|
|
|
1144
1100
|
},
|
|
1145
1101
|
[viewer]
|
|
1146
1102
|
);
|
|
1147
|
-
const handleStart =
|
|
1103
|
+
const handleStart = useCallback(
|
|
1148
1104
|
(clientX, clientY) => {
|
|
1149
1105
|
const pageInfo = findPageFromPoint(clientX, clientY);
|
|
1150
1106
|
if (!pageInfo) return;
|
|
@@ -1161,7 +1117,7 @@ var ShapeCanvas = ({
|
|
|
1161
1117
|
},
|
|
1162
1118
|
[findPageFromPoint]
|
|
1163
1119
|
);
|
|
1164
|
-
const handleMove =
|
|
1120
|
+
const handleMove = useCallback(
|
|
1165
1121
|
(clientX, clientY) => {
|
|
1166
1122
|
if (!isDrawingRef.current || !pageRect) return;
|
|
1167
1123
|
const pos = {
|
|
@@ -1172,7 +1128,7 @@ var ShapeCanvas = ({
|
|
|
1172
1128
|
},
|
|
1173
1129
|
[pageRect]
|
|
1174
1130
|
);
|
|
1175
|
-
const handleEnd =
|
|
1131
|
+
const handleEnd = useCallback(() => {
|
|
1176
1132
|
if (!isDrawingRef.current || !startPoint || !currentPoint || pageNumber === null || !viewer) {
|
|
1177
1133
|
isDrawingRef.current = false;
|
|
1178
1134
|
setStartPoint(null);
|
|
@@ -1227,23 +1183,23 @@ var ShapeCanvas = ({
|
|
|
1227
1183
|
setPageNumber(null);
|
|
1228
1184
|
setPageRect(null);
|
|
1229
1185
|
}, [startPoint, currentPoint, pageNumber, viewer, shapeType, strokeColor, strokeWidth, onComplete]);
|
|
1230
|
-
const handleMouseDown =
|
|
1186
|
+
const handleMouseDown = useCallback(
|
|
1231
1187
|
(e) => {
|
|
1232
1188
|
e.preventDefault();
|
|
1233
1189
|
handleStart(e.clientX, e.clientY);
|
|
1234
1190
|
},
|
|
1235
1191
|
[handleStart]
|
|
1236
1192
|
);
|
|
1237
|
-
const handleMouseMove =
|
|
1193
|
+
const handleMouseMove = useCallback(
|
|
1238
1194
|
(e) => {
|
|
1239
1195
|
handleMove(e.clientX, e.clientY);
|
|
1240
1196
|
},
|
|
1241
1197
|
[handleMove]
|
|
1242
1198
|
);
|
|
1243
|
-
const handleMouseUp =
|
|
1199
|
+
const handleMouseUp = useCallback(() => {
|
|
1244
1200
|
handleEnd();
|
|
1245
1201
|
}, [handleEnd]);
|
|
1246
|
-
const handleTouchStart =
|
|
1202
|
+
const handleTouchStart = useCallback(
|
|
1247
1203
|
(e) => {
|
|
1248
1204
|
e.preventDefault();
|
|
1249
1205
|
if (e.touches.length > 0) {
|
|
@@ -1252,7 +1208,7 @@ var ShapeCanvas = ({
|
|
|
1252
1208
|
},
|
|
1253
1209
|
[handleStart]
|
|
1254
1210
|
);
|
|
1255
|
-
const handleTouchMove =
|
|
1211
|
+
const handleTouchMove = useCallback(
|
|
1256
1212
|
(e) => {
|
|
1257
1213
|
e.preventDefault();
|
|
1258
1214
|
if (e.touches.length > 0) {
|
|
@@ -1261,10 +1217,10 @@ var ShapeCanvas = ({
|
|
|
1261
1217
|
},
|
|
1262
1218
|
[handleMove]
|
|
1263
1219
|
);
|
|
1264
|
-
const handleTouchEnd =
|
|
1220
|
+
const handleTouchEnd = useCallback(() => {
|
|
1265
1221
|
handleEnd();
|
|
1266
1222
|
}, [handleEnd]);
|
|
1267
|
-
|
|
1223
|
+
useEffect(() => {
|
|
1268
1224
|
if (!isActive) return;
|
|
1269
1225
|
const handleKeyDown = (e) => {
|
|
1270
1226
|
if (e.code === "Escape") {
|
|
@@ -1290,7 +1246,7 @@ var ShapeCanvas = ({
|
|
|
1290
1246
|
pointerEvents: "none",
|
|
1291
1247
|
zIndex: 1001
|
|
1292
1248
|
};
|
|
1293
|
-
return /* @__PURE__ */
|
|
1249
|
+
return /* @__PURE__ */ React11.createElement("svg", { style: svgStyle }, shapeType === "rectangle" && /* @__PURE__ */ React11.createElement(
|
|
1294
1250
|
"rect",
|
|
1295
1251
|
{
|
|
1296
1252
|
x: minX,
|
|
@@ -1301,7 +1257,7 @@ var ShapeCanvas = ({
|
|
|
1301
1257
|
strokeWidth,
|
|
1302
1258
|
fill: "none"
|
|
1303
1259
|
}
|
|
1304
|
-
), shapeType === "circle" && /* @__PURE__ */
|
|
1260
|
+
), shapeType === "circle" && /* @__PURE__ */ React11.createElement(
|
|
1305
1261
|
"ellipse",
|
|
1306
1262
|
{
|
|
1307
1263
|
cx: minX + width / 2,
|
|
@@ -1312,7 +1268,7 @@ var ShapeCanvas = ({
|
|
|
1312
1268
|
strokeWidth,
|
|
1313
1269
|
fill: "none"
|
|
1314
1270
|
}
|
|
1315
|
-
), shapeType === "arrow" && /* @__PURE__ */
|
|
1271
|
+
), shapeType === "arrow" && /* @__PURE__ */ React11.createElement(React11.Fragment, null, /* @__PURE__ */ React11.createElement("defs", null, /* @__PURE__ */ React11.createElement(
|
|
1316
1272
|
"marker",
|
|
1317
1273
|
{
|
|
1318
1274
|
id: "shape-canvas-arrowhead",
|
|
@@ -1322,8 +1278,8 @@ var ShapeCanvas = ({
|
|
|
1322
1278
|
refY: "3.5",
|
|
1323
1279
|
orient: "auto"
|
|
1324
1280
|
},
|
|
1325
|
-
/* @__PURE__ */
|
|
1326
|
-
)), /* @__PURE__ */
|
|
1281
|
+
/* @__PURE__ */ React11.createElement("polygon", { points: "0 0, 10 3.5, 0 7", fill: strokeColor })
|
|
1282
|
+
)), /* @__PURE__ */ React11.createElement(
|
|
1327
1283
|
"line",
|
|
1328
1284
|
{
|
|
1329
1285
|
x1: startPoint.x,
|
|
@@ -1337,7 +1293,7 @@ var ShapeCanvas = ({
|
|
|
1337
1293
|
)));
|
|
1338
1294
|
};
|
|
1339
1295
|
if (!isActive) return null;
|
|
1340
|
-
return /* @__PURE__ */
|
|
1296
|
+
return /* @__PURE__ */ React11.createElement(React11.Fragment, null, /* @__PURE__ */ React11.createElement(
|
|
1341
1297
|
"div",
|
|
1342
1298
|
{
|
|
1343
1299
|
ref: containerRef,
|
|
@@ -1350,32 +1306,17 @@ var ShapeCanvas = ({
|
|
|
1350
1306
|
onTouchMove: handleTouchMove,
|
|
1351
1307
|
onTouchEnd: handleTouchEnd
|
|
1352
1308
|
}
|
|
1353
|
-
), renderShapePreview()
|
|
1354
|
-
"button",
|
|
1355
|
-
{
|
|
1356
|
-
type: "button",
|
|
1357
|
-
className: "ShapeCanvas__cancelButton",
|
|
1358
|
-
onClick: onCancel
|
|
1359
|
-
},
|
|
1360
|
-
"Cancel"
|
|
1361
|
-
)));
|
|
1309
|
+
), renderShapePreview());
|
|
1362
1310
|
};
|
|
1363
|
-
|
|
1364
|
-
// src/components/TipContainer.tsx
|
|
1365
|
-
import React5, {
|
|
1366
|
-
useLayoutEffect,
|
|
1367
|
-
useRef as useRef4,
|
|
1368
|
-
useState as useState4
|
|
1369
|
-
} from "react";
|
|
1370
1311
|
var clamp = (value, left, right) => Math.min(Math.max(value, left), right);
|
|
1371
1312
|
var VERTICAL_PADDING = 5;
|
|
1372
1313
|
var TipContainer = ({
|
|
1373
1314
|
viewer,
|
|
1374
1315
|
updateTipPositionRef
|
|
1375
1316
|
}) => {
|
|
1376
|
-
const [height, setHeight] =
|
|
1377
|
-
const [width, setWidth] =
|
|
1378
|
-
const containerRef =
|
|
1317
|
+
const [height, setHeight] = useState(0);
|
|
1318
|
+
const [width, setWidth] = useState(0);
|
|
1319
|
+
const containerRef = useRef(null);
|
|
1379
1320
|
const updatePosition = () => {
|
|
1380
1321
|
if (!containerRef.current) return;
|
|
1381
1322
|
const { offsetHeight, offsetWidth } = containerRef.current;
|
|
@@ -1402,7 +1343,7 @@ var TipContainer = ({
|
|
|
1402
1343
|
const shouldMove = highlightTop - height - VERTICAL_PADDING < scrollTop;
|
|
1403
1344
|
const top = shouldMove ? highlightBottom + VERTICAL_PADDING : highlightTop - height - VERTICAL_PADDING;
|
|
1404
1345
|
const clampedLeft = clamp(left - width / 2, 0, pageLeft + pageWidth - width);
|
|
1405
|
-
return /* @__PURE__ */
|
|
1346
|
+
return /* @__PURE__ */ React11.createElement(
|
|
1406
1347
|
"div",
|
|
1407
1348
|
{
|
|
1408
1349
|
className: "PdfHighlighter__tip-container",
|
|
@@ -1424,7 +1365,7 @@ var PDFFindController;
|
|
|
1424
1365
|
var PDFLinkService;
|
|
1425
1366
|
var PDFViewer;
|
|
1426
1367
|
(async () => {
|
|
1427
|
-
const pdfjs = await import(
|
|
1368
|
+
const pdfjs = await import('pdfjs-dist/web/pdf_viewer.mjs');
|
|
1428
1369
|
EventBus = pdfjs.EventBus;
|
|
1429
1370
|
PDFFindController = pdfjs.PDFFindController;
|
|
1430
1371
|
PDFLinkService = pdfjs.PDFLinkService;
|
|
@@ -1432,18 +1373,20 @@ var PDFViewer;
|
|
|
1432
1373
|
})();
|
|
1433
1374
|
var SCROLL_MARGIN = 10;
|
|
1434
1375
|
var DEFAULT_SCALE_VALUE = "auto";
|
|
1435
|
-
var DEFAULT_TEXT_SELECTION_COLOR = "rgba(
|
|
1376
|
+
var DEFAULT_TEXT_SELECTION_COLOR = "rgba(216, 212, 250, 1)";
|
|
1436
1377
|
var DEFAULT_DARK_MODE_COLORS2 = {
|
|
1437
1378
|
background: "#141210",
|
|
1438
1379
|
foreground: "#eae6e0"
|
|
1439
1380
|
};
|
|
1440
|
-
var unmountReactRoot = (
|
|
1441
|
-
if (!
|
|
1381
|
+
var unmountReactRoot = (binding) => {
|
|
1382
|
+
if (!binding) return;
|
|
1383
|
+
const { reactRoot, container } = binding;
|
|
1442
1384
|
queueMicrotask(() => {
|
|
1443
1385
|
try {
|
|
1444
|
-
|
|
1386
|
+
reactRoot.unmount();
|
|
1445
1387
|
} catch {
|
|
1446
1388
|
}
|
|
1389
|
+
container.remove();
|
|
1447
1390
|
});
|
|
1448
1391
|
};
|
|
1449
1392
|
var RECOLOR_PATCHED = /* @__PURE__ */ Symbol("pdfRecolorPatched");
|
|
@@ -1473,24 +1416,25 @@ var patchPageRenderRecolor = (pdfDocument, getMap) => {
|
|
|
1473
1416
|
};
|
|
1474
1417
|
var defaultLightTheme = {
|
|
1475
1418
|
mode: "light",
|
|
1476
|
-
containerBackgroundColor: "#
|
|
1477
|
-
scrollbarThumbColor: "#
|
|
1478
|
-
scrollbarTrackColor: "
|
|
1419
|
+
containerBackgroundColor: "#efece5",
|
|
1420
|
+
scrollbarThumbColor: "#b7b3ab",
|
|
1421
|
+
scrollbarTrackColor: "transparent",
|
|
1479
1422
|
darkModeInvertIntensity: 0.9,
|
|
1480
1423
|
darkModeColors: DEFAULT_DARK_MODE_COLORS2
|
|
1481
1424
|
};
|
|
1482
1425
|
var defaultDarkTheme = {
|
|
1483
1426
|
mode: "dark",
|
|
1484
|
-
containerBackgroundColor: "#
|
|
1427
|
+
containerBackgroundColor: "#2a2724",
|
|
1485
1428
|
// Lighter than PDF page for contrast
|
|
1486
|
-
scrollbarThumbColor: "#
|
|
1487
|
-
scrollbarTrackColor: "
|
|
1429
|
+
scrollbarThumbColor: "#57544d",
|
|
1430
|
+
scrollbarTrackColor: "transparent",
|
|
1488
1431
|
darkModeInvertIntensity: 0.9,
|
|
1489
1432
|
darkModeColors: DEFAULT_DARK_MODE_COLORS2
|
|
1490
1433
|
};
|
|
1491
1434
|
var ensurePersistentLayer = (bindings, pageNumber, parent, className) => {
|
|
1492
1435
|
let binding = bindings[pageNumber];
|
|
1493
1436
|
if (!binding) {
|
|
1437
|
+
parent.querySelectorAll(`:scope > .${className}`).forEach((stray) => stray.remove());
|
|
1494
1438
|
const doc = getDocument(parent);
|
|
1495
1439
|
const layer = doc.createElement("div");
|
|
1496
1440
|
layer.className = className;
|
|
@@ -1507,7 +1451,14 @@ var ensurePersistentLayer = (bindings, pageNumber, parent, className) => {
|
|
|
1507
1451
|
}
|
|
1508
1452
|
return binding;
|
|
1509
1453
|
};
|
|
1510
|
-
var
|
|
1454
|
+
var sanitizeCssColor = (value, fallback) => {
|
|
1455
|
+
if (!value) return fallback;
|
|
1456
|
+
if (typeof CSS !== "undefined" && typeof CSS.supports === "function") {
|
|
1457
|
+
return CSS.supports("color", value) ? value : fallback;
|
|
1458
|
+
}
|
|
1459
|
+
return /^(#[0-9a-f]{3,8}|(rgb|hsl)a?\([\d.,%\s/]+\)|[a-z]{1,25})$/i.test(value) ? value : fallback;
|
|
1460
|
+
};
|
|
1461
|
+
var needsOpaqueLayer = (highlight) => "type" in highlight && (highlight.type === "freetext" || highlight.type === "image" || highlight.type === "drawing" || highlight.type === "shape");
|
|
1511
1462
|
var disableTextSelection = (viewer, flag) => {
|
|
1512
1463
|
viewer.viewer?.classList.toggle("PdfHighlighter--disable-selection", flag);
|
|
1513
1464
|
};
|
|
@@ -1558,48 +1509,50 @@ var PdfHighlighter = ({
|
|
|
1558
1509
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
1559
1510
|
[recolorKey]
|
|
1560
1511
|
);
|
|
1561
|
-
const recolorMapRef =
|
|
1512
|
+
const recolorMapRef = useRef(recolorMap);
|
|
1562
1513
|
recolorMapRef.current = recolorMap;
|
|
1563
1514
|
const defaultStrokeColor = resolvedTheme.mode === "dark" ? "#ffffff" : "#000000";
|
|
1564
1515
|
const drawingStrokeColor = drawingStrokeColorProp ?? defaultStrokeColor;
|
|
1565
1516
|
const shapeStrokeColor = shapeStrokeColorProp ?? defaultStrokeColor;
|
|
1566
|
-
const [tip, setTip] =
|
|
1567
|
-
const [isViewerReady, setIsViewerReady] =
|
|
1568
|
-
const containerNodeRef =
|
|
1569
|
-
const highlightBindingsRef =
|
|
1517
|
+
const [tip, setTip] = useState(null);
|
|
1518
|
+
const [isViewerReady, setIsViewerReady] = useState(false);
|
|
1519
|
+
const containerNodeRef = useRef(null);
|
|
1520
|
+
const highlightBindingsRef = useRef(
|
|
1570
1521
|
{}
|
|
1571
1522
|
);
|
|
1572
|
-
const noteBindingsRef =
|
|
1573
|
-
const highlightsRef =
|
|
1574
|
-
const childrenRef =
|
|
1575
|
-
const ghostHighlightRef =
|
|
1576
|
-
const selectionRef =
|
|
1577
|
-
const scrolledToHighlightIdRef =
|
|
1578
|
-
const isAreaSelectionInProgressRef =
|
|
1579
|
-
const isEditInProgressRef =
|
|
1580
|
-
const updateTipPositionRef =
|
|
1523
|
+
const noteBindingsRef = useRef({});
|
|
1524
|
+
const highlightsRef = useRef(highlights);
|
|
1525
|
+
const childrenRef = useRef(children);
|
|
1526
|
+
const ghostHighlightRef = useRef(null);
|
|
1527
|
+
const selectionRef = useRef(null);
|
|
1528
|
+
const scrolledToHighlightIdRef = useRef(null);
|
|
1529
|
+
const isAreaSelectionInProgressRef = useRef(false);
|
|
1530
|
+
const isEditInProgressRef = useRef(false);
|
|
1531
|
+
const updateTipPositionRef = useRef(() => {
|
|
1581
1532
|
});
|
|
1582
|
-
const eventBusRef =
|
|
1583
|
-
const linkServiceRef =
|
|
1533
|
+
const eventBusRef = useRef(new EventBus());
|
|
1534
|
+
const linkServiceRef = useRef(
|
|
1584
1535
|
new PDFLinkService({
|
|
1585
1536
|
eventBus: eventBusRef.current,
|
|
1586
1537
|
externalLinkTarget: 2
|
|
1587
1538
|
})
|
|
1588
1539
|
);
|
|
1589
|
-
const resizeObserverRef =
|
|
1590
|
-
const renderRetryTimeoutsRef =
|
|
1540
|
+
const resizeObserverRef = useRef(null);
|
|
1541
|
+
const renderRetryTimeoutsRef = useRef(
|
|
1591
1542
|
[]
|
|
1592
1543
|
);
|
|
1593
|
-
const resumeScrollAwayTimeoutRef =
|
|
1544
|
+
const resumeScrollAwayTimeoutRef = useRef(
|
|
1594
1545
|
null
|
|
1595
1546
|
);
|
|
1596
|
-
const
|
|
1597
|
-
const
|
|
1598
|
-
const
|
|
1599
|
-
const
|
|
1547
|
+
const settleScrollListenerRef = useRef(null);
|
|
1548
|
+
const findControllerRef = useRef(null);
|
|
1549
|
+
const viewerRef = useRef(null);
|
|
1550
|
+
const selectedHighlightCountRef = useRef(0);
|
|
1551
|
+
const prevDocRef = useRef(null);
|
|
1552
|
+
const lastRenderKeyRef = useRef(null);
|
|
1600
1553
|
highlightsRef.current = highlights;
|
|
1601
1554
|
childrenRef.current = children;
|
|
1602
|
-
|
|
1555
|
+
useLayoutEffect(() => {
|
|
1603
1556
|
if (!containerNodeRef.current) return;
|
|
1604
1557
|
const renderKey = `${pdfDocument.fingerprints ?? pdfDocument.numPages}::${recolorKey}`;
|
|
1605
1558
|
if (lastRenderKeyRef.current === renderKey) {
|
|
@@ -1663,21 +1616,27 @@ var PdfHighlighter = ({
|
|
|
1663
1616
|
linkServiceRef.current.setViewer(viewerRef.current);
|
|
1664
1617
|
setIsViewerReady(true);
|
|
1665
1618
|
}, [pdfDocument, recolorKey]);
|
|
1666
|
-
|
|
1619
|
+
useLayoutEffect(() => {
|
|
1667
1620
|
if (!containerNodeRef.current) return;
|
|
1668
|
-
resizeObserverRef.current = new ResizeObserver(
|
|
1621
|
+
resizeObserverRef.current = new ResizeObserver(() => {
|
|
1622
|
+
handleScaleValueRef.current();
|
|
1623
|
+
});
|
|
1669
1624
|
resizeObserverRef.current.observe(containerNodeRef.current);
|
|
1670
1625
|
const doc = containerNodeRef.current.ownerDocument;
|
|
1671
|
-
|
|
1672
|
-
eventBusRef.current.on("
|
|
1626
|
+
const handlePageRendered = () => renderHighlightLayers(true);
|
|
1627
|
+
eventBusRef.current.on("textlayerrendered", handlePageRendered);
|
|
1628
|
+
eventBusRef.current.on("pagerendered", handlePageRendered);
|
|
1673
1629
|
eventBusRef.current.on("pagesinit", handleScaleValue);
|
|
1630
|
+
if (scrolledToHighlightIdRef.current) {
|
|
1631
|
+
resumeScrollAwayListenerAfterNavigation();
|
|
1632
|
+
}
|
|
1674
1633
|
doc.addEventListener("keydown", handleKeyDown);
|
|
1675
1634
|
doc.addEventListener("copy", handleCopy, true);
|
|
1676
1635
|
scheduleRenderHighlightLayers();
|
|
1677
1636
|
return () => {
|
|
1678
1637
|
eventBusRef.current.off("pagesinit", handleScaleValue);
|
|
1679
|
-
eventBusRef.current.off("pagerendered",
|
|
1680
|
-
eventBusRef.current.off("textlayerrendered",
|
|
1638
|
+
eventBusRef.current.off("pagerendered", handlePageRendered);
|
|
1639
|
+
eventBusRef.current.off("textlayerrendered", handlePageRendered);
|
|
1681
1640
|
doc.removeEventListener("keydown", handleKeyDown);
|
|
1682
1641
|
doc.removeEventListener("copy", handleCopy, true);
|
|
1683
1642
|
resizeObserverRef.current?.disconnect();
|
|
@@ -1687,23 +1646,30 @@ var PdfHighlighter = ({
|
|
|
1687
1646
|
clearTimeout(resumeScrollAwayTimeoutRef.current);
|
|
1688
1647
|
resumeScrollAwayTimeoutRef.current = null;
|
|
1689
1648
|
}
|
|
1649
|
+
if (settleScrollListenerRef.current) {
|
|
1650
|
+
viewerRef.current?.container.removeEventListener(
|
|
1651
|
+
"scroll",
|
|
1652
|
+
settleScrollListenerRef.current
|
|
1653
|
+
);
|
|
1654
|
+
settleScrollListenerRef.current = null;
|
|
1655
|
+
}
|
|
1690
1656
|
};
|
|
1691
1657
|
}, [selectionTip, highlights, onSelectionFinished]);
|
|
1692
|
-
|
|
1658
|
+
useEffect(() => {
|
|
1693
1659
|
return () => {
|
|
1694
1660
|
for (const binding of Object.values(highlightBindingsRef.current))
|
|
1695
|
-
unmountReactRoot(binding
|
|
1661
|
+
unmountReactRoot(binding);
|
|
1696
1662
|
for (const binding of Object.values(noteBindingsRef.current))
|
|
1697
|
-
unmountReactRoot(binding
|
|
1663
|
+
unmountReactRoot(binding);
|
|
1698
1664
|
};
|
|
1699
1665
|
}, []);
|
|
1700
|
-
const onPageChangeRef =
|
|
1666
|
+
const onPageChangeRef = useRef(onPageChange);
|
|
1701
1667
|
onPageChangeRef.current = onPageChange;
|
|
1702
|
-
const initialPageRef =
|
|
1668
|
+
const initialPageRef = useRef(initialPage);
|
|
1703
1669
|
initialPageRef.current = initialPage;
|
|
1704
|
-
const initialPageAppliedRef =
|
|
1705
|
-
const pendingInitialPageRef =
|
|
1706
|
-
|
|
1670
|
+
const initialPageAppliedRef = useRef(false);
|
|
1671
|
+
const pendingInitialPageRef = useRef(null);
|
|
1672
|
+
useEffect(() => {
|
|
1707
1673
|
const eventBus = eventBusRef.current;
|
|
1708
1674
|
const handlePageChanging = (evt) => {
|
|
1709
1675
|
if (pendingInitialPageRef.current != null) return;
|
|
@@ -1755,14 +1721,14 @@ var PdfHighlighter = ({
|
|
|
1755
1721
|
pendingInitialPageRef.current = null;
|
|
1756
1722
|
};
|
|
1757
1723
|
}, []);
|
|
1758
|
-
const onZoomChangeRef =
|
|
1724
|
+
const onZoomChangeRef = useRef(onZoomChange);
|
|
1759
1725
|
onZoomChangeRef.current = onZoomChange;
|
|
1760
|
-
|
|
1726
|
+
useEffect(() => {
|
|
1761
1727
|
const container = containerNodeRef.current;
|
|
1762
1728
|
if (!container || !isViewerReady) return;
|
|
1763
1729
|
const MIN_SCALE = 0.25;
|
|
1764
1730
|
const MAX_SCALE = 10;
|
|
1765
|
-
const COMMIT_DELAY =
|
|
1731
|
+
const COMMIT_DELAY = 280;
|
|
1766
1732
|
const g = {
|
|
1767
1733
|
active: false,
|
|
1768
1734
|
startScale: 1,
|
|
@@ -1826,10 +1792,11 @@ var PdfHighlighter = ({
|
|
|
1826
1792
|
Math.max(MIN_SCALE, g.startScale * g.k)
|
|
1827
1793
|
);
|
|
1828
1794
|
const ratio = finalScale / g.startScale;
|
|
1795
|
+
if (Math.abs(ratio - 1) < 1e-3) return;
|
|
1829
1796
|
viewer.currentScaleValue = String(finalScale);
|
|
1830
1797
|
container.scrollLeft = g.originX * ratio - g.anchorX;
|
|
1831
1798
|
container.scrollTop = g.originY * ratio - g.anchorY;
|
|
1832
|
-
onZoomChangeRef.current?.(finalScale);
|
|
1799
|
+
setTimeout(() => onZoomChangeRef.current?.(finalScale), 0);
|
|
1833
1800
|
console.log("[PdfHighlighter] pinch commit", {
|
|
1834
1801
|
from: g.startScale,
|
|
1835
1802
|
to: finalScale
|
|
@@ -1842,11 +1809,12 @@ var PdfHighlighter = ({
|
|
|
1842
1809
|
const handleWheel = (e) => {
|
|
1843
1810
|
if (!e.ctrlKey && !e.metaKey) return;
|
|
1844
1811
|
e.preventDefault();
|
|
1845
|
-
|
|
1846
|
-
|
|
1847
|
-
|
|
1848
|
-
|
|
1849
|
-
|
|
1812
|
+
if (!g.active) {
|
|
1813
|
+
const rect = container.getBoundingClientRect();
|
|
1814
|
+
if (!begin(e.clientX - rect.left, e.clientY - rect.top)) return;
|
|
1815
|
+
}
|
|
1816
|
+
const delta = e.deltaMode === 1 ? e.deltaY * 16 : e.deltaMode === 2 ? e.deltaY * 100 : e.deltaY;
|
|
1817
|
+
g.k = clampK(g.k * Math.exp(-delta * 0.01));
|
|
1850
1818
|
preview();
|
|
1851
1819
|
scheduleCommit();
|
|
1852
1820
|
};
|
|
@@ -2042,20 +2010,26 @@ var PdfHighlighter = ({
|
|
|
2042
2010
|
event.stopPropagation();
|
|
2043
2011
|
};
|
|
2044
2012
|
const handleScaleValue = () => {
|
|
2045
|
-
|
|
2046
|
-
|
|
2013
|
+
const viewer = viewerRef.current;
|
|
2014
|
+
if (!viewer) return;
|
|
2015
|
+
const target = parseFloat(String(pdfScaleValue));
|
|
2016
|
+
if (!Number.isNaN(target) && Math.abs(viewer.currentScale - target) / target < 5e-3) {
|
|
2017
|
+
return;
|
|
2047
2018
|
}
|
|
2019
|
+
viewer.currentScaleValue = pdfScaleValue.toString();
|
|
2048
2020
|
};
|
|
2049
|
-
const
|
|
2021
|
+
const handleScaleValueRef = useRef(handleScaleValue);
|
|
2022
|
+
handleScaleValueRef.current = handleScaleValue;
|
|
2023
|
+
useEffect(() => {
|
|
2024
|
+
handleScaleValueRef.current();
|
|
2025
|
+
}, [pdfScaleValue, isViewerReady]);
|
|
2026
|
+
const renderHighlightLayer = (highlightBindings, pageNumber, highlightsByPage, shouldRenderHighlight) => {
|
|
2050
2027
|
if (!viewerRef.current) return;
|
|
2051
2028
|
highlightBindings.reactRoot.render(
|
|
2052
|
-
/* @__PURE__ */
|
|
2029
|
+
/* @__PURE__ */ React11.createElement(PdfHighlighterContext.Provider, { value: pdfHighlighterUtils }, /* @__PURE__ */ React11.createElement(
|
|
2053
2030
|
HighlightLayer,
|
|
2054
2031
|
{
|
|
2055
|
-
highlightsByPage
|
|
2056
|
-
...highlightsRef.current,
|
|
2057
|
-
ghostHighlightRef.current
|
|
2058
|
-
]),
|
|
2032
|
+
highlightsByPage,
|
|
2059
2033
|
pageNumber,
|
|
2060
2034
|
scrolledToHighlightId: scrolledToHighlightIdRef.current,
|
|
2061
2035
|
viewer: viewerRef.current,
|
|
@@ -2066,40 +2040,61 @@ var PdfHighlighter = ({
|
|
|
2066
2040
|
))
|
|
2067
2041
|
);
|
|
2068
2042
|
};
|
|
2069
|
-
const
|
|
2043
|
+
const renderVersionRef = useRef(0);
|
|
2044
|
+
const pageRenderedVersionRef = useRef({});
|
|
2045
|
+
const renderHighlightLayers = (onlyStalePages = false) => {
|
|
2070
2046
|
if (!viewerRef.current) return;
|
|
2047
|
+
if (!onlyStalePages) renderVersionRef.current += 1;
|
|
2048
|
+
const version = renderVersionRef.current;
|
|
2049
|
+
const highlightsByPage = group_highlights_by_page_default([
|
|
2050
|
+
...highlightsRef.current,
|
|
2051
|
+
ghostHighlightRef.current
|
|
2052
|
+
]);
|
|
2071
2053
|
for (let pageNumber = 1; pageNumber <= pdfDocument.numPages; pageNumber++) {
|
|
2072
2054
|
const { textLayer } = viewerRef.current.getPageView(pageNumber - 1) || {};
|
|
2073
2055
|
if (!textLayer) continue;
|
|
2074
2056
|
const textLayerDiv = textLayer.div;
|
|
2057
|
+
const pageEl = textLayerDiv.closest(".page");
|
|
2058
|
+
if (!pageEl) continue;
|
|
2059
|
+
const existingBinding = highlightBindingsRef.current[pageNumber];
|
|
2060
|
+
const layerRebuilt = !existingBinding || existingBinding.container.parentNode !== pageEl;
|
|
2061
|
+
if (onlyStalePages && !layerRebuilt && pageRenderedVersionRef.current[pageNumber] === version) {
|
|
2062
|
+
continue;
|
|
2063
|
+
}
|
|
2075
2064
|
const highlightBindings = ensurePersistentLayer(
|
|
2076
2065
|
highlightBindingsRef.current,
|
|
2077
2066
|
pageNumber,
|
|
2078
|
-
|
|
2067
|
+
pageEl,
|
|
2079
2068
|
"PdfHighlighter__highlight-layer"
|
|
2080
2069
|
);
|
|
2081
2070
|
renderHighlightLayer(
|
|
2082
2071
|
highlightBindings,
|
|
2083
2072
|
pageNumber,
|
|
2084
|
-
|
|
2073
|
+
highlightsByPage,
|
|
2074
|
+
(highlight) => !needsOpaqueLayer(highlight)
|
|
2085
2075
|
);
|
|
2086
|
-
|
|
2087
|
-
if (pageEl) {
|
|
2076
|
+
{
|
|
2088
2077
|
const noteBindings = ensurePersistentLayer(
|
|
2089
2078
|
noteBindingsRef.current,
|
|
2090
2079
|
pageNumber,
|
|
2091
2080
|
pageEl,
|
|
2092
2081
|
"PdfHighlighter__note-layer"
|
|
2093
2082
|
);
|
|
2094
|
-
renderHighlightLayer(
|
|
2083
|
+
renderHighlightLayer(
|
|
2084
|
+
noteBindings,
|
|
2085
|
+
pageNumber,
|
|
2086
|
+
highlightsByPage,
|
|
2087
|
+
needsOpaqueLayer
|
|
2088
|
+
);
|
|
2095
2089
|
}
|
|
2090
|
+
pageRenderedVersionRef.current[pageNumber] = version;
|
|
2096
2091
|
}
|
|
2097
2092
|
};
|
|
2098
2093
|
const scheduleRenderHighlightLayers = () => {
|
|
2099
2094
|
renderHighlightLayers();
|
|
2100
2095
|
renderRetryTimeoutsRef.current.forEach(clearTimeout);
|
|
2101
|
-
renderRetryTimeoutsRef.current = [50,
|
|
2102
|
-
(delay) => setTimeout(renderHighlightLayers, delay)
|
|
2096
|
+
renderRetryTimeoutsRef.current = [50, 250, 1200].map(
|
|
2097
|
+
(delay) => setTimeout(() => renderHighlightLayers(true), delay)
|
|
2103
2098
|
);
|
|
2104
2099
|
};
|
|
2105
2100
|
const resumeScrollAwayListenerAfterNavigation = () => {
|
|
@@ -2107,13 +2102,27 @@ var PdfHighlighter = ({
|
|
|
2107
2102
|
if (!container) return;
|
|
2108
2103
|
if (resumeScrollAwayTimeoutRef.current) {
|
|
2109
2104
|
clearTimeout(resumeScrollAwayTimeoutRef.current);
|
|
2110
|
-
}
|
|
2111
|
-
resumeScrollAwayTimeoutRef.current = setTimeout(() => {
|
|
2112
|
-
container.addEventListener("scroll", handleScroll, {
|
|
2113
|
-
once: true
|
|
2114
|
-
});
|
|
2115
2105
|
resumeScrollAwayTimeoutRef.current = null;
|
|
2116
|
-
}
|
|
2106
|
+
}
|
|
2107
|
+
if (settleScrollListenerRef.current) {
|
|
2108
|
+
container.removeEventListener("scroll", settleScrollListenerRef.current);
|
|
2109
|
+
settleScrollListenerRef.current = null;
|
|
2110
|
+
}
|
|
2111
|
+
const QUIET_MS = 150;
|
|
2112
|
+
const onSettleTick = () => {
|
|
2113
|
+
if (resumeScrollAwayTimeoutRef.current) {
|
|
2114
|
+
clearTimeout(resumeScrollAwayTimeoutRef.current);
|
|
2115
|
+
}
|
|
2116
|
+
resumeScrollAwayTimeoutRef.current = setTimeout(() => {
|
|
2117
|
+
container.removeEventListener("scroll", onSettleTick);
|
|
2118
|
+
settleScrollListenerRef.current = null;
|
|
2119
|
+
container.addEventListener("scroll", handleScroll, { once: true });
|
|
2120
|
+
resumeScrollAwayTimeoutRef.current = null;
|
|
2121
|
+
}, QUIET_MS);
|
|
2122
|
+
};
|
|
2123
|
+
settleScrollListenerRef.current = onSettleTick;
|
|
2124
|
+
container.addEventListener("scroll", onSettleTick);
|
|
2125
|
+
onSettleTick();
|
|
2117
2126
|
};
|
|
2118
2127
|
const isEditingOrHighlighting = () => {
|
|
2119
2128
|
return Boolean(selectionRef.current) || Boolean(ghostHighlightRef.current) || isAreaSelectionInProgressRef.current || isEditInProgressRef.current;
|
|
@@ -2185,7 +2194,7 @@ var PdfHighlighter = ({
|
|
|
2185
2194
|
matchDiacritics: options.matchDiacritics ?? false
|
|
2186
2195
|
});
|
|
2187
2196
|
};
|
|
2188
|
-
const currentSearchRef =
|
|
2197
|
+
const currentSearchRef = useRef({
|
|
2189
2198
|
query: "",
|
|
2190
2199
|
options: {}
|
|
2191
2200
|
});
|
|
@@ -2213,8 +2222,15 @@ var PdfHighlighter = ({
|
|
|
2213
2222
|
source: findControllerRef.current || viewerRef.current
|
|
2214
2223
|
});
|
|
2215
2224
|
};
|
|
2216
|
-
const
|
|
2225
|
+
const latestUtils = {
|
|
2217
2226
|
isEditingOrHighlighting,
|
|
2227
|
+
setHighlightSelected: (selected) => {
|
|
2228
|
+
selectedHighlightCountRef.current = Math.max(
|
|
2229
|
+
0,
|
|
2230
|
+
selectedHighlightCountRef.current + (selected ? 1 : -1)
|
|
2231
|
+
);
|
|
2232
|
+
},
|
|
2233
|
+
isHighlightSelected: () => selectedHighlightCountRef.current > 0,
|
|
2218
2234
|
getCurrentSelection: () => selectionRef.current,
|
|
2219
2235
|
getGhostHighlight: () => ghostHighlightRef.current,
|
|
2220
2236
|
removeGhostHighlight,
|
|
@@ -2292,8 +2308,19 @@ var PdfHighlighter = ({
|
|
|
2292
2308
|
}
|
|
2293
2309
|
}
|
|
2294
2310
|
};
|
|
2295
|
-
const
|
|
2296
|
-
|
|
2311
|
+
const latestUtilsRef = useRef(latestUtils);
|
|
2312
|
+
latestUtilsRef.current = latestUtils;
|
|
2313
|
+
const stableUtilsRef = useRef(null);
|
|
2314
|
+
if (!stableUtilsRef.current) {
|
|
2315
|
+
const facade = {};
|
|
2316
|
+
for (const key of Object.keys(latestUtils)) {
|
|
2317
|
+
facade[key] = (...args) => latestUtilsRef.current[key](...args);
|
|
2318
|
+
}
|
|
2319
|
+
stableUtilsRef.current = facade;
|
|
2320
|
+
}
|
|
2321
|
+
const pdfHighlighterUtils = stableUtilsRef.current;
|
|
2322
|
+
const utilsRefCalledRef = useRef(false);
|
|
2323
|
+
useEffect(() => {
|
|
2297
2324
|
if (viewerRef.current && !utilsRefCalledRef.current) {
|
|
2298
2325
|
utilsRefCalledRef.current = true;
|
|
2299
2326
|
utilsRef(pdfHighlighterUtils);
|
|
@@ -2312,7 +2339,7 @@ var PdfHighlighter = ({
|
|
|
2312
2339
|
...style,
|
|
2313
2340
|
backgroundColor: resolvedTheme.containerBackgroundColor
|
|
2314
2341
|
};
|
|
2315
|
-
return /* @__PURE__ */
|
|
2342
|
+
return /* @__PURE__ */ React11.createElement(PdfHighlighterContext.Provider, { value: pdfHighlighterUtils }, /* @__PURE__ */ React11.createElement(
|
|
2316
2343
|
"div",
|
|
2317
2344
|
{
|
|
2318
2345
|
ref: containerNodeRef,
|
|
@@ -2321,27 +2348,27 @@ var PdfHighlighter = ({
|
|
|
2321
2348
|
onPointerUp: handleMouseUp,
|
|
2322
2349
|
style: containerStyle
|
|
2323
2350
|
},
|
|
2324
|
-
/* @__PURE__ */
|
|
2325
|
-
/* @__PURE__ */
|
|
2351
|
+
/* @__PURE__ */ React11.createElement("div", { className: "pdfViewer" }),
|
|
2352
|
+
/* @__PURE__ */ React11.createElement("style", null, `
|
|
2326
2353
|
.textLayer ::selection {
|
|
2327
|
-
background: ${textSelectionColor};
|
|
2354
|
+
background: ${sanitizeCssColor(textSelectionColor, DEFAULT_TEXT_SELECTION_COLOR)};
|
|
2328
2355
|
}
|
|
2329
2356
|
.PdfHighlighter::-webkit-scrollbar-thumb {
|
|
2330
|
-
background-color: ${resolvedTheme.scrollbarThumbColor};
|
|
2357
|
+
background-color: ${sanitizeCssColor(resolvedTheme.scrollbarThumbColor, "#9f9f9f")};
|
|
2331
2358
|
}
|
|
2332
2359
|
.PdfHighlighter::-webkit-scrollbar-track,
|
|
2333
2360
|
.PdfHighlighter::-webkit-scrollbar-track-piece {
|
|
2334
|
-
background-color: ${resolvedTheme.scrollbarTrackColor};
|
|
2361
|
+
background-color: ${sanitizeCssColor(resolvedTheme.scrollbarTrackColor, "#d1d1d1")};
|
|
2335
2362
|
}
|
|
2336
2363
|
`),
|
|
2337
|
-
isViewerReady && /* @__PURE__ */
|
|
2364
|
+
isViewerReady && /* @__PURE__ */ React11.createElement(
|
|
2338
2365
|
TipContainer,
|
|
2339
2366
|
{
|
|
2340
2367
|
viewer: viewerRef.current,
|
|
2341
2368
|
updateTipPositionRef
|
|
2342
2369
|
}
|
|
2343
2370
|
),
|
|
2344
|
-
isViewerReady && enableAreaSelection && /* @__PURE__ */
|
|
2371
|
+
isViewerReady && enableAreaSelection && /* @__PURE__ */ React11.createElement(
|
|
2345
2372
|
MouseSelection,
|
|
2346
2373
|
{
|
|
2347
2374
|
viewer: viewerRef.current,
|
|
@@ -2375,7 +2402,7 @@ var PdfHighlighter = ({
|
|
|
2375
2402
|
}
|
|
2376
2403
|
}
|
|
2377
2404
|
),
|
|
2378
|
-
isViewerReady && enableDrawingMode && /* @__PURE__ */
|
|
2405
|
+
isViewerReady && enableDrawingMode && /* @__PURE__ */ React11.createElement(
|
|
2379
2406
|
DrawingCanvas,
|
|
2380
2407
|
{
|
|
2381
2408
|
isActive: enableDrawingMode,
|
|
@@ -2392,7 +2419,7 @@ var PdfHighlighter = ({
|
|
|
2392
2419
|
}
|
|
2393
2420
|
}
|
|
2394
2421
|
),
|
|
2395
|
-
isViewerReady && enableShapeMode && /* @__PURE__ */
|
|
2422
|
+
isViewerReady && enableShapeMode && /* @__PURE__ */ React11.createElement(
|
|
2396
2423
|
ShapeCanvas,
|
|
2397
2424
|
{
|
|
2398
2425
|
isActive: !!enableShapeMode,
|
|
@@ -2413,15 +2440,6 @@ var PdfHighlighter = ({
|
|
|
2413
2440
|
));
|
|
2414
2441
|
};
|
|
2415
2442
|
|
|
2416
|
-
// src/components/TextHighlight.tsx
|
|
2417
|
-
import React7, {
|
|
2418
|
-
useState as useState6,
|
|
2419
|
-
useRef as useRef6,
|
|
2420
|
-
useEffect as useEffect5,
|
|
2421
|
-
useLayoutEffect as useLayoutEffect3
|
|
2422
|
-
} from "react";
|
|
2423
|
-
import { createPortal } from "react-dom";
|
|
2424
|
-
|
|
2425
2443
|
// src/lib/copy-highlight-content.ts
|
|
2426
2444
|
var intersects = (a, b) => a.left < b.left + b.width && a.left + a.width > b.left && a.top < b.top + b.height && a.top + a.height > b.top;
|
|
2427
2445
|
var copyTextToClipboard = async (text) => {
|
|
@@ -2485,13 +2503,15 @@ var findOrCreateHighlightConfigLayer = (anchor) => {
|
|
|
2485
2503
|
};
|
|
2486
2504
|
|
|
2487
2505
|
// src/components/TextHighlight.tsx
|
|
2488
|
-
var DefaultStyleIcon = () => /* @__PURE__ */
|
|
2489
|
-
var DefaultDeleteIcon = () => /* @__PURE__ */
|
|
2490
|
-
var DefaultCopyIcon = () => /* @__PURE__ */
|
|
2491
|
-
var DefaultCopiedIcon = () => /* @__PURE__ */
|
|
2492
|
-
var
|
|
2493
|
-
var
|
|
2494
|
-
var
|
|
2506
|
+
var DefaultStyleIcon = () => /* @__PURE__ */ React11.createElement(Palette, { width: 14, height: 14 });
|
|
2507
|
+
var DefaultDeleteIcon = () => /* @__PURE__ */ React11.createElement(Trash2, { width: 14, height: 14 });
|
|
2508
|
+
var DefaultCopyIcon = () => /* @__PURE__ */ React11.createElement(Copy, { width: 14, height: 14 });
|
|
2509
|
+
var DefaultCopiedIcon = () => /* @__PURE__ */ React11.createElement(Check, { width: 14, height: 14, strokeWidth: 2.5 });
|
|
2510
|
+
var ChevronDownIcon = () => /* @__PURE__ */ React11.createElement(ChevronDown, { width: 12, height: 12, strokeWidth: 2.5 });
|
|
2511
|
+
var CheckIcon = () => /* @__PURE__ */ React11.createElement(Check, { width: 14, height: 14, strokeWidth: 2.5 });
|
|
2512
|
+
var HighlightIcon = () => /* @__PURE__ */ React11.createElement(Highlighter, { width: 16, height: 16 });
|
|
2513
|
+
var UnderlineIcon = () => /* @__PURE__ */ React11.createElement(Underline, { width: 16, height: 16 });
|
|
2514
|
+
var StrikethroughIcon = () => /* @__PURE__ */ React11.createElement(Strikethrough, { width: 16, height: 16 });
|
|
2495
2515
|
var DEFAULT_COLOR_PRESETS = [
|
|
2496
2516
|
"rgba(255, 226, 143, 1)",
|
|
2497
2517
|
// Yellow (default)
|
|
@@ -2504,7 +2524,14 @@ var DEFAULT_COLOR_PRESETS = [
|
|
|
2504
2524
|
"#e1bee7"
|
|
2505
2525
|
// Light purple
|
|
2506
2526
|
];
|
|
2507
|
-
var
|
|
2527
|
+
var COLOR_NAMES = {
|
|
2528
|
+
"rgba(255, 226, 143, 1)": "Yellow",
|
|
2529
|
+
"#ffcdd2": "Red",
|
|
2530
|
+
"#c8e6c9": "Green",
|
|
2531
|
+
"#bbdefb": "Blue",
|
|
2532
|
+
"#e1bee7": "Purple"
|
|
2533
|
+
};
|
|
2534
|
+
var TextHighlight = memo(({
|
|
2508
2535
|
highlight,
|
|
2509
2536
|
onClick,
|
|
2510
2537
|
onMouseOver,
|
|
@@ -2519,28 +2546,60 @@ var TextHighlight = ({
|
|
|
2519
2546
|
styleIcon,
|
|
2520
2547
|
deleteIcon,
|
|
2521
2548
|
copyText,
|
|
2522
|
-
colorPresets = DEFAULT_COLOR_PRESETS
|
|
2549
|
+
colorPresets = DEFAULT_COLOR_PRESETS,
|
|
2550
|
+
extraButtons,
|
|
2551
|
+
extraPanel
|
|
2523
2552
|
}) => {
|
|
2524
|
-
const [isStylePanelOpen, setIsStylePanelOpen] =
|
|
2525
|
-
const [
|
|
2526
|
-
const [
|
|
2527
|
-
const [
|
|
2528
|
-
const
|
|
2529
|
-
const
|
|
2530
|
-
const
|
|
2531
|
-
|
|
2553
|
+
const [isStylePanelOpen, setIsStylePanelOpen] = useState(false);
|
|
2554
|
+
const [isColorMenuOpen, setIsColorMenuOpen] = useState(false);
|
|
2555
|
+
const [isSelected, setIsSelected] = useState(false);
|
|
2556
|
+
const [isCopied, setIsCopied] = useState(false);
|
|
2557
|
+
const [configLayer, setConfigLayer] = useState(null);
|
|
2558
|
+
const stylePanelRef = useRef(null);
|
|
2559
|
+
const colorMenuRef = useRef(null);
|
|
2560
|
+
const containerRef = useRef(null);
|
|
2561
|
+
const toolbarWrapperRef = useRef(null);
|
|
2562
|
+
const copyResetTimeoutRef = useRef(null);
|
|
2563
|
+
useEffect(() => {
|
|
2564
|
+
if (!isSelected) return;
|
|
2565
|
+
const handlePointerDown = (e) => {
|
|
2566
|
+
const target = e.target;
|
|
2567
|
+
const insideRoot = containerRef.current?.contains(target);
|
|
2568
|
+
const insideToolbar = toolbarWrapperRef.current?.contains(target);
|
|
2569
|
+
if (!insideRoot && !insideToolbar) {
|
|
2570
|
+
setIsSelected(false);
|
|
2571
|
+
setIsStylePanelOpen(false);
|
|
2572
|
+
setIsColorMenuOpen(false);
|
|
2573
|
+
}
|
|
2574
|
+
};
|
|
2575
|
+
const handleKey = (e) => {
|
|
2576
|
+
if (e.key === "Escape") {
|
|
2577
|
+
setIsSelected(false);
|
|
2578
|
+
setIsStylePanelOpen(false);
|
|
2579
|
+
setIsColorMenuOpen(false);
|
|
2580
|
+
}
|
|
2581
|
+
};
|
|
2582
|
+
document.addEventListener("mousedown", handlePointerDown);
|
|
2583
|
+
document.addEventListener("keydown", handleKey);
|
|
2584
|
+
return () => {
|
|
2585
|
+
document.removeEventListener("mousedown", handlePointerDown);
|
|
2586
|
+
document.removeEventListener("keydown", handleKey);
|
|
2587
|
+
};
|
|
2588
|
+
}, [isSelected]);
|
|
2589
|
+
useLayoutEffect(() => {
|
|
2532
2590
|
if (containerRef.current) {
|
|
2533
|
-
|
|
2591
|
+
const layer = findOrCreateHighlightConfigLayer(containerRef.current);
|
|
2592
|
+
setConfigLayer((prev) => prev === layer ? prev : layer);
|
|
2534
2593
|
}
|
|
2535
|
-
}
|
|
2536
|
-
|
|
2594
|
+
});
|
|
2595
|
+
useEffect(() => {
|
|
2537
2596
|
return () => {
|
|
2538
2597
|
if (copyResetTimeoutRef.current) {
|
|
2539
2598
|
window.clearTimeout(copyResetTimeoutRef.current);
|
|
2540
2599
|
}
|
|
2541
2600
|
};
|
|
2542
2601
|
}, []);
|
|
2543
|
-
|
|
2602
|
+
useEffect(() => {
|
|
2544
2603
|
if (!isStylePanelOpen) return;
|
|
2545
2604
|
const handleClickOutside = (e) => {
|
|
2546
2605
|
if (stylePanelRef.current && !stylePanelRef.current.contains(e.target)) {
|
|
@@ -2555,9 +2614,26 @@ var TextHighlight = ({
|
|
|
2555
2614
|
document.removeEventListener("mousedown", handleClickOutside);
|
|
2556
2615
|
};
|
|
2557
2616
|
}, [isStylePanelOpen]);
|
|
2617
|
+
useEffect(() => {
|
|
2618
|
+
if (!isColorMenuOpen) return;
|
|
2619
|
+
const handleClickOutside = (e) => {
|
|
2620
|
+
if (colorMenuRef.current && !colorMenuRef.current.contains(e.target)) {
|
|
2621
|
+
setIsColorMenuOpen(false);
|
|
2622
|
+
}
|
|
2623
|
+
};
|
|
2624
|
+
const timeoutId = setTimeout(() => {
|
|
2625
|
+
document.addEventListener("mousedown", handleClickOutside);
|
|
2626
|
+
}, 0);
|
|
2627
|
+
return () => {
|
|
2628
|
+
clearTimeout(timeoutId);
|
|
2629
|
+
document.removeEventListener("mousedown", handleClickOutside);
|
|
2630
|
+
};
|
|
2631
|
+
}, [isColorMenuOpen]);
|
|
2558
2632
|
const highlightClass = isScrolledTo ? "TextHighlight--scrolledTo" : "";
|
|
2633
|
+
const selectedClass = isSelected ? "TextHighlight--selected" : "";
|
|
2559
2634
|
const { rects } = highlight.position;
|
|
2560
2635
|
const firstRect = rects[0];
|
|
2636
|
+
const flipToolbar = !!firstRect && firstRect.top < 40;
|
|
2561
2637
|
const getPartStyleClass = () => {
|
|
2562
2638
|
switch (highlightStyle) {
|
|
2563
2639
|
case "underline":
|
|
@@ -2591,46 +2667,68 @@ var TextHighlight = ({
|
|
|
2591
2667
|
copyResetTimeoutRef.current = null;
|
|
2592
2668
|
}, 1500);
|
|
2593
2669
|
};
|
|
2594
|
-
return /* @__PURE__ */
|
|
2670
|
+
return /* @__PURE__ */ React11.createElement(
|
|
2595
2671
|
"div",
|
|
2596
2672
|
{
|
|
2597
|
-
className: `TextHighlight ${highlightClass}`,
|
|
2673
|
+
className: `TextHighlight ${highlightClass} ${selectedClass}`,
|
|
2598
2674
|
onContextMenu,
|
|
2599
2675
|
ref: containerRef
|
|
2600
2676
|
},
|
|
2601
2677
|
configLayer && (onStyleChange || onDelete) && firstRect && createPortal(
|
|
2602
|
-
/* @__PURE__ */
|
|
2678
|
+
/* @__PURE__ */ React11.createElement(
|
|
2603
2679
|
"div",
|
|
2604
2680
|
{
|
|
2605
2681
|
className: "TextHighlight__toolbar-wrapper",
|
|
2682
|
+
ref: toolbarWrapperRef,
|
|
2606
2683
|
style: {
|
|
2607
2684
|
position: "absolute",
|
|
2608
2685
|
left: firstRect.left,
|
|
2609
|
-
top: firstRect.top
|
|
2610
|
-
|
|
2611
|
-
},
|
|
2612
|
-
onMouseEnter: () => setIsHovered(true),
|
|
2613
|
-
onMouseLeave: () => setIsHovered(false)
|
|
2686
|
+
top: firstRect.top
|
|
2687
|
+
}
|
|
2614
2688
|
},
|
|
2615
|
-
/* @__PURE__ */
|
|
2689
|
+
/* @__PURE__ */ React11.createElement(
|
|
2616
2690
|
"div",
|
|
2617
2691
|
{
|
|
2618
|
-
className: `TextHighlight__toolbar ${
|
|
2692
|
+
className: `TextHighlight__toolbar ${flipToolbar ? "TextHighlight__toolbar--below" : ""} ${isSelected || isScrolledTo || isStylePanelOpen || isColorMenuOpen ? "TextHighlight__toolbar--visible" : ""}`
|
|
2619
2693
|
},
|
|
2620
|
-
onStyleChange && /* @__PURE__ */
|
|
2694
|
+
onStyleChange && /* @__PURE__ */ React11.createElement(React11.Fragment, null, /* @__PURE__ */ React11.createElement(
|
|
2695
|
+
"button",
|
|
2696
|
+
{
|
|
2697
|
+
type: "button",
|
|
2698
|
+
className: "TextHighlight__color-trigger",
|
|
2699
|
+
"aria-label": "Highlight color",
|
|
2700
|
+
"aria-expanded": isColorMenuOpen,
|
|
2701
|
+
onClick: (e) => {
|
|
2702
|
+
e.stopPropagation();
|
|
2703
|
+
setIsStylePanelOpen(false);
|
|
2704
|
+
setIsColorMenuOpen((v) => !v);
|
|
2705
|
+
},
|
|
2706
|
+
title: "Highlight color"
|
|
2707
|
+
},
|
|
2708
|
+
/* @__PURE__ */ React11.createElement(
|
|
2709
|
+
"span",
|
|
2710
|
+
{
|
|
2711
|
+
className: "TextHighlight__color-trigger-dot",
|
|
2712
|
+
style: { backgroundColor: highlightColor }
|
|
2713
|
+
}
|
|
2714
|
+
),
|
|
2715
|
+
/* @__PURE__ */ React11.createElement(ChevronDownIcon, null)
|
|
2716
|
+
), /* @__PURE__ */ React11.createElement("div", { className: "TextHighlight__toolbar-divider" })),
|
|
2717
|
+
onStyleChange && /* @__PURE__ */ React11.createElement(
|
|
2621
2718
|
"button",
|
|
2622
2719
|
{
|
|
2623
2720
|
className: "TextHighlight__style-button",
|
|
2624
2721
|
onClick: (e) => {
|
|
2625
2722
|
e.stopPropagation();
|
|
2723
|
+
setIsColorMenuOpen(false);
|
|
2626
2724
|
setIsStylePanelOpen(!isStylePanelOpen);
|
|
2627
2725
|
},
|
|
2628
2726
|
title: "Change style",
|
|
2629
2727
|
type: "button"
|
|
2630
2728
|
},
|
|
2631
|
-
styleIcon || /* @__PURE__ */
|
|
2729
|
+
styleIcon || /* @__PURE__ */ React11.createElement(DefaultStyleIcon, null)
|
|
2632
2730
|
),
|
|
2633
|
-
/* @__PURE__ */
|
|
2731
|
+
/* @__PURE__ */ React11.createElement(
|
|
2634
2732
|
"button",
|
|
2635
2733
|
{
|
|
2636
2734
|
className: "TextHighlight__copy-button",
|
|
@@ -2638,9 +2736,10 @@ var TextHighlight = ({
|
|
|
2638
2736
|
title: isCopied ? "Copied" : "Copy text",
|
|
2639
2737
|
type: "button"
|
|
2640
2738
|
},
|
|
2641
|
-
isCopied ? /* @__PURE__ */
|
|
2739
|
+
isCopied ? /* @__PURE__ */ React11.createElement(DefaultCopiedIcon, null) : /* @__PURE__ */ React11.createElement(DefaultCopyIcon, null)
|
|
2642
2740
|
),
|
|
2643
|
-
|
|
2741
|
+
extraButtons,
|
|
2742
|
+
onDelete && /* @__PURE__ */ React11.createElement(
|
|
2644
2743
|
"button",
|
|
2645
2744
|
{
|
|
2646
2745
|
className: "TextHighlight__delete-button",
|
|
@@ -2651,17 +2750,17 @@ var TextHighlight = ({
|
|
|
2651
2750
|
title: "Delete",
|
|
2652
2751
|
type: "button"
|
|
2653
2752
|
},
|
|
2654
|
-
deleteIcon || /* @__PURE__ */
|
|
2753
|
+
deleteIcon || /* @__PURE__ */ React11.createElement(DefaultDeleteIcon, null)
|
|
2655
2754
|
)
|
|
2656
2755
|
),
|
|
2657
|
-
isStylePanelOpen && onStyleChange && /* @__PURE__ */
|
|
2756
|
+
isStylePanelOpen && onStyleChange && /* @__PURE__ */ React11.createElement(
|
|
2658
2757
|
"div",
|
|
2659
2758
|
{
|
|
2660
2759
|
className: "TextHighlight__style-panel",
|
|
2661
2760
|
ref: stylePanelRef,
|
|
2662
2761
|
onClick: (e) => e.stopPropagation()
|
|
2663
2762
|
},
|
|
2664
|
-
/* @__PURE__ */
|
|
2763
|
+
/* @__PURE__ */ React11.createElement("div", { className: "TextHighlight__style-row" }, /* @__PURE__ */ React11.createElement("label", null, "Style"), /* @__PURE__ */ React11.createElement("div", { className: "TextHighlight__style-buttons" }, /* @__PURE__ */ React11.createElement(
|
|
2665
2764
|
"button",
|
|
2666
2765
|
{
|
|
2667
2766
|
type: "button",
|
|
@@ -2669,8 +2768,8 @@ var TextHighlight = ({
|
|
|
2669
2768
|
onClick: () => onStyleChange({ highlightStyle: "highlight" }),
|
|
2670
2769
|
title: "Highlight"
|
|
2671
2770
|
},
|
|
2672
|
-
/* @__PURE__ */
|
|
2673
|
-
), /* @__PURE__ */
|
|
2771
|
+
/* @__PURE__ */ React11.createElement(HighlightIcon, null)
|
|
2772
|
+
), /* @__PURE__ */ React11.createElement(
|
|
2674
2773
|
"button",
|
|
2675
2774
|
{
|
|
2676
2775
|
type: "button",
|
|
@@ -2678,8 +2777,8 @@ var TextHighlight = ({
|
|
|
2678
2777
|
onClick: () => onStyleChange({ highlightStyle: "underline" }),
|
|
2679
2778
|
title: "Underline"
|
|
2680
2779
|
},
|
|
2681
|
-
/* @__PURE__ */
|
|
2682
|
-
), /* @__PURE__ */
|
|
2780
|
+
/* @__PURE__ */ React11.createElement(UnderlineIcon, null)
|
|
2781
|
+
), /* @__PURE__ */ React11.createElement(
|
|
2683
2782
|
"button",
|
|
2684
2783
|
{
|
|
2685
2784
|
type: "button",
|
|
@@ -2687,45 +2786,56 @@ var TextHighlight = ({
|
|
|
2687
2786
|
onClick: () => onStyleChange({ highlightStyle: "strikethrough" }),
|
|
2688
2787
|
title: "Strikethrough"
|
|
2689
2788
|
},
|
|
2690
|
-
/* @__PURE__ */
|
|
2691
|
-
)))
|
|
2692
|
-
|
|
2789
|
+
/* @__PURE__ */ React11.createElement(StrikethroughIcon, null)
|
|
2790
|
+
)))
|
|
2791
|
+
),
|
|
2792
|
+
isColorMenuOpen && onStyleChange && /* @__PURE__ */ React11.createElement(
|
|
2793
|
+
"div",
|
|
2794
|
+
{
|
|
2795
|
+
className: "TextHighlight__color-menu",
|
|
2796
|
+
ref: colorMenuRef,
|
|
2797
|
+
onClick: (e) => e.stopPropagation()
|
|
2798
|
+
},
|
|
2799
|
+
colorPresets.map((c) => /* @__PURE__ */ React11.createElement(
|
|
2693
2800
|
"button",
|
|
2694
2801
|
{
|
|
2695
2802
|
key: c,
|
|
2696
2803
|
type: "button",
|
|
2697
|
-
className:
|
|
2698
|
-
|
|
2699
|
-
|
|
2700
|
-
|
|
2701
|
-
}
|
|
2702
|
-
))), /* @__PURE__ */ React7.createElement(
|
|
2703
|
-
"input",
|
|
2704
|
-
{
|
|
2705
|
-
type: "color",
|
|
2706
|
-
value: highlightColor,
|
|
2707
|
-
onChange: (e) => {
|
|
2708
|
-
onStyleChange({ highlightColor: e.target.value });
|
|
2804
|
+
className: "TextHighlight__color-menu-item",
|
|
2805
|
+
onClick: () => {
|
|
2806
|
+
onStyleChange({ highlightColor: c });
|
|
2807
|
+
setIsColorMenuOpen(false);
|
|
2709
2808
|
}
|
|
2710
|
-
}
|
|
2711
|
-
|
|
2712
|
-
|
|
2809
|
+
},
|
|
2810
|
+
/* @__PURE__ */ React11.createElement(
|
|
2811
|
+
"span",
|
|
2812
|
+
{
|
|
2813
|
+
className: "TextHighlight__color-menu-dot",
|
|
2814
|
+
style: { backgroundColor: c }
|
|
2815
|
+
}
|
|
2816
|
+
),
|
|
2817
|
+
/* @__PURE__ */ React11.createElement("span", { className: "TextHighlight__color-menu-label" }, COLOR_NAMES[c] || c),
|
|
2818
|
+
highlightColor === c && /* @__PURE__ */ React11.createElement("span", { className: "TextHighlight__color-menu-check" }, /* @__PURE__ */ React11.createElement(CheckIcon, null))
|
|
2819
|
+
))
|
|
2820
|
+
),
|
|
2821
|
+
extraPanel
|
|
2713
2822
|
),
|
|
2714
2823
|
configLayer
|
|
2715
2824
|
),
|
|
2716
|
-
/* @__PURE__ */
|
|
2825
|
+
/* @__PURE__ */ React11.createElement(
|
|
2717
2826
|
"div",
|
|
2718
2827
|
{
|
|
2719
|
-
className: "TextHighlight__parts"
|
|
2720
|
-
onMouseEnter: () => setIsHovered(true),
|
|
2721
|
-
onMouseLeave: () => setIsHovered(false)
|
|
2828
|
+
className: "TextHighlight__parts"
|
|
2722
2829
|
},
|
|
2723
|
-
rects.map((rect, index) => /* @__PURE__ */
|
|
2830
|
+
rects.map((rect, index) => /* @__PURE__ */ React11.createElement(
|
|
2724
2831
|
"div",
|
|
2725
2832
|
{
|
|
2726
2833
|
onMouseOver,
|
|
2727
2834
|
onMouseOut,
|
|
2728
|
-
onClick
|
|
2835
|
+
onClick: (event) => {
|
|
2836
|
+
setIsSelected(true);
|
|
2837
|
+
onClick?.(event);
|
|
2838
|
+
},
|
|
2729
2839
|
key: index,
|
|
2730
2840
|
style: getPartStyle(rect),
|
|
2731
2841
|
className: `TextHighlight__part ${getPartStyleClass()}`
|
|
@@ -2733,22 +2843,20 @@ var TextHighlight = ({
|
|
|
2733
2843
|
))
|
|
2734
2844
|
)
|
|
2735
2845
|
);
|
|
2736
|
-
};
|
|
2737
|
-
|
|
2738
|
-
// src/components/MonitoredHighlightContainer.tsx
|
|
2739
|
-
import React9, { useRef as useRef8 } from "react";
|
|
2740
|
-
|
|
2741
|
-
// src/components/MouseMonitor.tsx
|
|
2742
|
-
import React8, { useEffect as useEffect6, useRef as useRef7 } from "react";
|
|
2846
|
+
});
|
|
2847
|
+
TextHighlight.displayName = "TextHighlight";
|
|
2743
2848
|
var MouseMonitor = ({
|
|
2744
2849
|
onMoveAway,
|
|
2745
2850
|
paddingX,
|
|
2746
2851
|
paddingY,
|
|
2747
2852
|
children
|
|
2748
2853
|
}) => {
|
|
2749
|
-
const containerRef =
|
|
2854
|
+
const containerRef = useRef(null);
|
|
2750
2855
|
const onMouseMove = (event) => {
|
|
2751
2856
|
if (!containerRef.current) return;
|
|
2857
|
+
if (containerRef.current.contains(document.activeElement)) {
|
|
2858
|
+
return;
|
|
2859
|
+
}
|
|
2752
2860
|
const { clientX, clientY } = event;
|
|
2753
2861
|
const { left, top, width, height } = containerRef.current.getBoundingClientRect();
|
|
2754
2862
|
const inBoundsX = clientX > left - paddingX && clientX < left + width + paddingX;
|
|
@@ -2757,13 +2865,13 @@ var MouseMonitor = ({
|
|
|
2757
2865
|
onMoveAway();
|
|
2758
2866
|
}
|
|
2759
2867
|
};
|
|
2760
|
-
|
|
2868
|
+
useEffect(() => {
|
|
2761
2869
|
document.addEventListener("mousemove", onMouseMove);
|
|
2762
2870
|
return () => {
|
|
2763
2871
|
document.removeEventListener("mousemove", onMouseMove);
|
|
2764
2872
|
};
|
|
2765
2873
|
}, []);
|
|
2766
|
-
return /* @__PURE__ */
|
|
2874
|
+
return /* @__PURE__ */ React11.createElement("div", { ref: containerRef }, children);
|
|
2767
2875
|
};
|
|
2768
2876
|
|
|
2769
2877
|
// src/components/MonitoredHighlightContainer.tsx
|
|
@@ -2773,17 +2881,18 @@ var MonitoredHighlightContainer = ({
|
|
|
2773
2881
|
onMouseLeave,
|
|
2774
2882
|
children
|
|
2775
2883
|
}) => {
|
|
2776
|
-
const mouseInRef =
|
|
2777
|
-
const { setTip, isEditingOrHighlighting } = usePdfHighlighterContext();
|
|
2778
|
-
return /* @__PURE__ */
|
|
2884
|
+
const mouseInRef = useRef(false);
|
|
2885
|
+
const { setTip, isEditingOrHighlighting, isHighlightSelected } = usePdfHighlighterContext();
|
|
2886
|
+
return /* @__PURE__ */ React11.createElement(
|
|
2779
2887
|
"div",
|
|
2780
2888
|
{
|
|
2781
2889
|
onMouseEnter: () => {
|
|
2782
2890
|
mouseInRef.current = true;
|
|
2783
2891
|
onMouseEnter && onMouseEnter();
|
|
2784
2892
|
if (isEditingOrHighlighting()) return;
|
|
2893
|
+
if (isHighlightSelected()) return;
|
|
2785
2894
|
if (highlightTip) {
|
|
2786
|
-
const monitoredHighlightTip = /* @__PURE__ */
|
|
2895
|
+
const monitoredHighlightTip = /* @__PURE__ */ React11.createElement(
|
|
2787
2896
|
MouseMonitor,
|
|
2788
2897
|
{
|
|
2789
2898
|
onMoveAway: () => {
|
|
@@ -2812,20 +2921,11 @@ var MonitoredHighlightContainer = ({
|
|
|
2812
2921
|
children
|
|
2813
2922
|
);
|
|
2814
2923
|
};
|
|
2815
|
-
|
|
2816
|
-
|
|
2817
|
-
|
|
2818
|
-
|
|
2819
|
-
|
|
2820
|
-
useEffect as useEffect7,
|
|
2821
|
-
useLayoutEffect as useLayoutEffect4
|
|
2822
|
-
} from "react";
|
|
2823
|
-
import { createPortal as createPortal2 } from "react-dom";
|
|
2824
|
-
import { Rnd } from "react-rnd";
|
|
2825
|
-
var DefaultStyleIcon2 = () => /* @__PURE__ */ React10.createElement("svg", { width: "14", height: "14", viewBox: "0 0 24 24", fill: "currentColor" }, /* @__PURE__ */ React10.createElement("path", { d: "M12 3c-4.97 0-9 4.03-9 9s4.03 9 9 9c.83 0 1.5-.67 1.5-1.5 0-.39-.15-.74-.39-1.01-.23-.26-.38-.61-.38-.99 0-.83.67-1.5 1.5-1.5H16c2.76 0 5-2.24 5-5 0-4.42-4.03-8-9-8zm-5.5 9c-.83 0-1.5-.67-1.5-1.5S5.67 9 6.5 9 8 9.67 8 10.5 7.33 12 6.5 12zm3-4C8.67 8 8 7.33 8 6.5S8.67 5 9.5 5s1.5.67 1.5 1.5S10.33 8 9.5 8zm5 0c-.83 0-1.5-.67-1.5-1.5S13.67 5 14.5 5s1.5.67 1.5 1.5S15.33 8 14.5 8zm3 4c-.83 0-1.5-.67-1.5-1.5S16.67 9 17.5 9s1.5.67 1.5 1.5-.67 1.5-1.5 1.5z" }));
|
|
2826
|
-
var DefaultDeleteIcon2 = () => /* @__PURE__ */ React10.createElement("svg", { width: "14", height: "14", viewBox: "0 0 24 24", fill: "currentColor" }, /* @__PURE__ */ React10.createElement("path", { d: "M6 19c0 1.1.9 2 2 2h8c1.1 0 2-.9 2-2V7H6v12zM19 4h-3.5l-1-1h-5l-1 1H5v2h14V4z" }));
|
|
2827
|
-
var DefaultCopyIcon2 = () => /* @__PURE__ */ React10.createElement("svg", { width: "14", height: "14", viewBox: "0 0 24 24", fill: "currentColor" }, /* @__PURE__ */ React10.createElement("path", { d: "M16 1H4c-1.1 0-2 .9-2 2v12h2V3h12V1zm3 4H8c-1.1 0-2 .9-2 2v14c0 1.1.9 2 2 2h11c1.1 0 2-.9 2-2V7c0-1.1-.9-2-2-2zm0 16H8V7h11v14z" }));
|
|
2828
|
-
var DefaultCopiedIcon2 = () => /* @__PURE__ */ React10.createElement("svg", { width: "14", height: "14", viewBox: "0 0 24 24", fill: "currentColor" }, /* @__PURE__ */ React10.createElement("path", { d: "M9 16.17 4.83 12l-1.42 1.41L9 19 21 7l-1.41-1.41L9 16.17z" }));
|
|
2924
|
+
var DefaultDeleteIcon2 = () => /* @__PURE__ */ React11.createElement(Trash2, { width: 14, height: 14 });
|
|
2925
|
+
var DefaultCopyIcon2 = () => /* @__PURE__ */ React11.createElement(Copy, { width: 14, height: 14 });
|
|
2926
|
+
var DefaultCopiedIcon2 = () => /* @__PURE__ */ React11.createElement(Check, { width: 14, height: 14, strokeWidth: 2.5 });
|
|
2927
|
+
var ChevronDownIcon2 = () => /* @__PURE__ */ React11.createElement(ChevronDown, { width: 12, height: 12, strokeWidth: 2.5 });
|
|
2928
|
+
var CheckIcon2 = () => /* @__PURE__ */ React11.createElement(Check, { width: 14, height: 14, strokeWidth: 2.5 });
|
|
2829
2929
|
var DEFAULT_COLOR_PRESETS2 = [
|
|
2830
2930
|
"rgba(255, 226, 143, 1)",
|
|
2831
2931
|
// Yellow (default)
|
|
@@ -2838,7 +2938,14 @@ var DEFAULT_COLOR_PRESETS2 = [
|
|
|
2838
2938
|
"#e1bee7"
|
|
2839
2939
|
// Light purple
|
|
2840
2940
|
];
|
|
2841
|
-
var
|
|
2941
|
+
var COLOR_NAMES2 = {
|
|
2942
|
+
"rgba(255, 226, 143, 1)": "Yellow",
|
|
2943
|
+
"#ffcdd2": "Red",
|
|
2944
|
+
"#c8e6c9": "Green",
|
|
2945
|
+
"#bbdefb": "Blue",
|
|
2946
|
+
"#e1bee7": "Purple"
|
|
2947
|
+
};
|
|
2948
|
+
var AreaHighlight = memo(({
|
|
2842
2949
|
highlight,
|
|
2843
2950
|
onChange,
|
|
2844
2951
|
isScrolledTo,
|
|
@@ -2849,35 +2956,62 @@ var AreaHighlight = ({
|
|
|
2849
2956
|
highlightColor = "rgba(255, 226, 143, 1)",
|
|
2850
2957
|
onStyleChange,
|
|
2851
2958
|
onDelete,
|
|
2852
|
-
styleIcon,
|
|
2853
2959
|
deleteIcon,
|
|
2854
2960
|
copyText,
|
|
2855
|
-
colorPresets = DEFAULT_COLOR_PRESETS2
|
|
2961
|
+
colorPresets = DEFAULT_COLOR_PRESETS2,
|
|
2962
|
+
extraButtons,
|
|
2963
|
+
extraPanel
|
|
2856
2964
|
}) => {
|
|
2857
|
-
const [
|
|
2858
|
-
const [
|
|
2859
|
-
const [isCopied, setIsCopied] =
|
|
2860
|
-
const [configLayer, setConfigLayer] =
|
|
2861
|
-
const
|
|
2862
|
-
const containerRef =
|
|
2863
|
-
const
|
|
2864
|
-
|
|
2965
|
+
const [isColorMenuOpen, setIsColorMenuOpen] = useState(false);
|
|
2966
|
+
const [isSelected, setIsSelected] = useState(false);
|
|
2967
|
+
const [isCopied, setIsCopied] = useState(false);
|
|
2968
|
+
const [configLayer, setConfigLayer] = useState(null);
|
|
2969
|
+
const colorMenuRef = useRef(null);
|
|
2970
|
+
const containerRef = useRef(null);
|
|
2971
|
+
const toolbarWrapperRef = useRef(null);
|
|
2972
|
+
const copyResetTimeoutRef = useRef(null);
|
|
2973
|
+
useEffect(() => {
|
|
2974
|
+
if (!isSelected) return;
|
|
2975
|
+
const handlePointerDown = (e) => {
|
|
2976
|
+
const target = e.target;
|
|
2977
|
+
const insideRoot = containerRef.current?.contains(target);
|
|
2978
|
+
const insideToolbar = toolbarWrapperRef.current?.contains(target);
|
|
2979
|
+
if (!insideRoot && !insideToolbar) {
|
|
2980
|
+
setIsSelected(false);
|
|
2981
|
+
setIsColorMenuOpen(false);
|
|
2982
|
+
}
|
|
2983
|
+
};
|
|
2984
|
+
const handleKey = (e) => {
|
|
2985
|
+
if (e.key === "Escape") {
|
|
2986
|
+
setIsSelected(false);
|
|
2987
|
+
setIsColorMenuOpen(false);
|
|
2988
|
+
}
|
|
2989
|
+
};
|
|
2990
|
+
document.addEventListener("mousedown", handlePointerDown);
|
|
2991
|
+
document.addEventListener("keydown", handleKey);
|
|
2992
|
+
return () => {
|
|
2993
|
+
document.removeEventListener("mousedown", handlePointerDown);
|
|
2994
|
+
document.removeEventListener("keydown", handleKey);
|
|
2995
|
+
};
|
|
2996
|
+
}, [isSelected]);
|
|
2997
|
+
useLayoutEffect(() => {
|
|
2865
2998
|
if (containerRef.current) {
|
|
2866
|
-
|
|
2999
|
+
const layer = findOrCreateHighlightConfigLayer(containerRef.current);
|
|
3000
|
+
setConfigLayer((prev) => prev === layer ? prev : layer);
|
|
2867
3001
|
}
|
|
2868
|
-
}
|
|
2869
|
-
|
|
3002
|
+
});
|
|
3003
|
+
useEffect(() => {
|
|
2870
3004
|
return () => {
|
|
2871
3005
|
if (copyResetTimeoutRef.current) {
|
|
2872
3006
|
window.clearTimeout(copyResetTimeoutRef.current);
|
|
2873
3007
|
}
|
|
2874
3008
|
};
|
|
2875
3009
|
}, []);
|
|
2876
|
-
|
|
2877
|
-
if (!
|
|
3010
|
+
useEffect(() => {
|
|
3011
|
+
if (!isColorMenuOpen) return;
|
|
2878
3012
|
const handleClickOutside = (e) => {
|
|
2879
|
-
if (
|
|
2880
|
-
|
|
3013
|
+
if (colorMenuRef.current && !colorMenuRef.current.contains(e.target)) {
|
|
3014
|
+
setIsColorMenuOpen(false);
|
|
2881
3015
|
}
|
|
2882
3016
|
};
|
|
2883
3017
|
const timeoutId = setTimeout(() => {
|
|
@@ -2887,8 +3021,10 @@ var AreaHighlight = ({
|
|
|
2887
3021
|
clearTimeout(timeoutId);
|
|
2888
3022
|
document.removeEventListener("mousedown", handleClickOutside);
|
|
2889
3023
|
};
|
|
2890
|
-
}, [
|
|
3024
|
+
}, [isColorMenuOpen]);
|
|
2891
3025
|
const highlightClass = isScrolledTo ? "AreaHighlight--scrolledTo" : "";
|
|
3026
|
+
const selectedClass = isSelected ? "AreaHighlight--selected" : "";
|
|
3027
|
+
const flipToolbar = highlight.position.boundingRect.top < 40;
|
|
2892
3028
|
const key = `${highlight.position.boundingRect.width}${highlight.position.boundingRect.height}${highlight.position.boundingRect.left}${highlight.position.boundingRect.top}`;
|
|
2893
3029
|
const mergedStyle = {
|
|
2894
3030
|
...style,
|
|
@@ -2910,46 +3046,53 @@ var AreaHighlight = ({
|
|
|
2910
3046
|
copyResetTimeoutRef.current = null;
|
|
2911
3047
|
}, 1500);
|
|
2912
3048
|
};
|
|
2913
|
-
return /* @__PURE__ */
|
|
3049
|
+
return /* @__PURE__ */ React11.createElement(
|
|
2914
3050
|
"div",
|
|
2915
3051
|
{
|
|
2916
|
-
className: `AreaHighlight ${highlightClass}`,
|
|
3052
|
+
className: `AreaHighlight ${highlightClass} ${selectedClass}`,
|
|
2917
3053
|
onContextMenu,
|
|
2918
3054
|
ref: containerRef
|
|
2919
3055
|
},
|
|
2920
|
-
configLayer && (onStyleChange || onDelete) &&
|
|
2921
|
-
/* @__PURE__ */
|
|
3056
|
+
configLayer && (onStyleChange || onDelete) && createPortal(
|
|
3057
|
+
/* @__PURE__ */ React11.createElement(
|
|
2922
3058
|
"div",
|
|
2923
3059
|
{
|
|
2924
3060
|
className: "AreaHighlight__toolbar-wrapper",
|
|
3061
|
+
ref: toolbarWrapperRef,
|
|
2925
3062
|
style: {
|
|
2926
3063
|
position: "absolute",
|
|
2927
3064
|
left: highlight.position.boundingRect.left,
|
|
2928
|
-
top: highlight.position.boundingRect.top
|
|
2929
|
-
|
|
2930
|
-
},
|
|
2931
|
-
onMouseEnter: () => setIsHovered(true),
|
|
2932
|
-
onMouseLeave: () => setIsHovered(false)
|
|
3065
|
+
top: highlight.position.boundingRect.top
|
|
3066
|
+
}
|
|
2933
3067
|
},
|
|
2934
|
-
/* @__PURE__ */
|
|
3068
|
+
/* @__PURE__ */ React11.createElement(
|
|
2935
3069
|
"div",
|
|
2936
3070
|
{
|
|
2937
|
-
className: `AreaHighlight__toolbar ${
|
|
3071
|
+
className: `AreaHighlight__toolbar ${flipToolbar ? "AreaHighlight__toolbar--below" : ""} ${isSelected || isScrolledTo || isColorMenuOpen ? "AreaHighlight__toolbar--visible" : ""}`
|
|
2938
3072
|
},
|
|
2939
|
-
onStyleChange && /* @__PURE__ */
|
|
3073
|
+
onStyleChange && /* @__PURE__ */ React11.createElement(React11.Fragment, null, /* @__PURE__ */ React11.createElement(
|
|
2940
3074
|
"button",
|
|
2941
3075
|
{
|
|
2942
|
-
|
|
3076
|
+
type: "button",
|
|
3077
|
+
className: "AreaHighlight__color-trigger",
|
|
3078
|
+
"aria-label": "Highlight color",
|
|
3079
|
+
"aria-expanded": isColorMenuOpen,
|
|
2943
3080
|
onClick: (e) => {
|
|
2944
3081
|
e.stopPropagation();
|
|
2945
|
-
|
|
3082
|
+
setIsColorMenuOpen((v) => !v);
|
|
2946
3083
|
},
|
|
2947
|
-
title: "
|
|
2948
|
-
type: "button"
|
|
3084
|
+
title: "Highlight color"
|
|
2949
3085
|
},
|
|
2950
|
-
|
|
2951
|
-
|
|
2952
|
-
|
|
3086
|
+
/* @__PURE__ */ React11.createElement(
|
|
3087
|
+
"span",
|
|
3088
|
+
{
|
|
3089
|
+
className: "AreaHighlight__color-trigger-dot",
|
|
3090
|
+
style: { backgroundColor: highlightColor }
|
|
3091
|
+
}
|
|
3092
|
+
),
|
|
3093
|
+
/* @__PURE__ */ React11.createElement(ChevronDownIcon2, null)
|
|
3094
|
+
), /* @__PURE__ */ React11.createElement("div", { className: "AreaHighlight__toolbar-divider" })),
|
|
3095
|
+
/* @__PURE__ */ React11.createElement(
|
|
2953
3096
|
"button",
|
|
2954
3097
|
{
|
|
2955
3098
|
className: "AreaHighlight__copy-button",
|
|
@@ -2957,9 +3100,10 @@ var AreaHighlight = ({
|
|
|
2957
3100
|
title: isCopied ? "Copied" : "Copy text",
|
|
2958
3101
|
type: "button"
|
|
2959
3102
|
},
|
|
2960
|
-
isCopied ? /* @__PURE__ */
|
|
3103
|
+
isCopied ? /* @__PURE__ */ React11.createElement(DefaultCopiedIcon2, null) : /* @__PURE__ */ React11.createElement(DefaultCopyIcon2, null)
|
|
2961
3104
|
),
|
|
2962
|
-
|
|
3105
|
+
extraButtons,
|
|
3106
|
+
onDelete && /* @__PURE__ */ React11.createElement(
|
|
2963
3107
|
"button",
|
|
2964
3108
|
{
|
|
2965
3109
|
className: "AreaHighlight__delete-button",
|
|
@@ -2970,45 +3114,45 @@ var AreaHighlight = ({
|
|
|
2970
3114
|
title: "Delete",
|
|
2971
3115
|
type: "button"
|
|
2972
3116
|
},
|
|
2973
|
-
deleteIcon || /* @__PURE__ */
|
|
3117
|
+
deleteIcon || /* @__PURE__ */ React11.createElement(DefaultDeleteIcon2, null)
|
|
2974
3118
|
)
|
|
2975
3119
|
),
|
|
2976
|
-
|
|
3120
|
+
isColorMenuOpen && onStyleChange && /* @__PURE__ */ React11.createElement(
|
|
2977
3121
|
"div",
|
|
2978
3122
|
{
|
|
2979
|
-
className: "
|
|
2980
|
-
ref:
|
|
3123
|
+
className: "AreaHighlight__color-menu",
|
|
3124
|
+
ref: colorMenuRef,
|
|
2981
3125
|
onClick: (e) => e.stopPropagation()
|
|
2982
3126
|
},
|
|
2983
|
-
|
|
3127
|
+
colorPresets.map((c) => /* @__PURE__ */ React11.createElement(
|
|
2984
3128
|
"button",
|
|
2985
3129
|
{
|
|
2986
3130
|
key: c,
|
|
2987
3131
|
type: "button",
|
|
2988
|
-
className:
|
|
2989
|
-
|
|
2990
|
-
|
|
2991
|
-
|
|
2992
|
-
}
|
|
2993
|
-
))), /* @__PURE__ */ React10.createElement(
|
|
2994
|
-
"input",
|
|
2995
|
-
{
|
|
2996
|
-
type: "color",
|
|
2997
|
-
value: highlightColor,
|
|
2998
|
-
onChange: (e) => {
|
|
2999
|
-
onStyleChange({ highlightColor: e.target.value });
|
|
3132
|
+
className: "AreaHighlight__color-menu-item",
|
|
3133
|
+
onClick: () => {
|
|
3134
|
+
onStyleChange({ highlightColor: c });
|
|
3135
|
+
setIsColorMenuOpen(false);
|
|
3000
3136
|
}
|
|
3001
|
-
}
|
|
3002
|
-
|
|
3003
|
-
|
|
3137
|
+
},
|
|
3138
|
+
/* @__PURE__ */ React11.createElement(
|
|
3139
|
+
"span",
|
|
3140
|
+
{
|
|
3141
|
+
className: "AreaHighlight__color-menu-dot",
|
|
3142
|
+
style: { backgroundColor: c }
|
|
3143
|
+
}
|
|
3144
|
+
),
|
|
3145
|
+
/* @__PURE__ */ React11.createElement("span", { className: "AreaHighlight__color-menu-label" }, COLOR_NAMES2[c] || c),
|
|
3146
|
+
highlightColor === c && /* @__PURE__ */ React11.createElement("span", { className: "AreaHighlight__color-menu-check" }, /* @__PURE__ */ React11.createElement(CheckIcon2, null))
|
|
3147
|
+
))
|
|
3148
|
+
),
|
|
3149
|
+
extraPanel
|
|
3004
3150
|
),
|
|
3005
3151
|
configLayer
|
|
3006
3152
|
),
|
|
3007
|
-
/* @__PURE__ */
|
|
3153
|
+
/* @__PURE__ */ React11.createElement(
|
|
3008
3154
|
Rnd,
|
|
3009
3155
|
{
|
|
3010
|
-
onMouseEnter: () => setIsHovered(true),
|
|
3011
|
-
onMouseLeave: () => setIsHovered(false),
|
|
3012
3156
|
className: "AreaHighlight__part",
|
|
3013
3157
|
onDragStop: (_, data) => {
|
|
3014
3158
|
const boundingRect = {
|
|
@@ -3028,7 +3172,10 @@ var AreaHighlight = ({
|
|
|
3028
3172
|
};
|
|
3029
3173
|
onChange && onChange(boundingRect);
|
|
3030
3174
|
},
|
|
3031
|
-
onDragStart:
|
|
3175
|
+
onDragStart: () => {
|
|
3176
|
+
setIsSelected(true);
|
|
3177
|
+
onEditStart?.();
|
|
3178
|
+
},
|
|
3032
3179
|
onResizeStart: onEditStart,
|
|
3033
3180
|
default: {
|
|
3034
3181
|
x: highlight.position.boundingRect.left,
|
|
@@ -3041,28 +3188,31 @@ var AreaHighlight = ({
|
|
|
3041
3188
|
onClick: (event) => {
|
|
3042
3189
|
event.stopPropagation();
|
|
3043
3190
|
event.preventDefault();
|
|
3191
|
+
setIsSelected(true);
|
|
3044
3192
|
},
|
|
3045
3193
|
style: mergedStyle
|
|
3046
3194
|
}
|
|
3047
3195
|
)
|
|
3048
3196
|
);
|
|
3049
|
-
};
|
|
3050
|
-
|
|
3051
|
-
|
|
3052
|
-
|
|
3053
|
-
|
|
3054
|
-
|
|
3055
|
-
|
|
3056
|
-
|
|
3057
|
-
|
|
3058
|
-
var DefaultDragIcon = () => /* @__PURE__ */ React11.createElement("svg", { width: "14", height: "14", viewBox: "0 0 24 24", fill: "currentColor" }, /* @__PURE__ */ React11.createElement("circle", { cx: "8", cy: "6", r: "2" }), /* @__PURE__ */ React11.createElement("circle", { cx: "16", cy: "6", r: "2" }), /* @__PURE__ */ React11.createElement("circle", { cx: "8", cy: "12", r: "2" }), /* @__PURE__ */ React11.createElement("circle", { cx: "16", cy: "12", r: "2" }), /* @__PURE__ */ React11.createElement("circle", { cx: "8", cy: "18", r: "2" }), /* @__PURE__ */ React11.createElement("circle", { cx: "16", cy: "18", r: "2" }));
|
|
3059
|
-
var DefaultEditIcon = () => /* @__PURE__ */ React11.createElement("svg", { width: "14", height: "14", viewBox: "0 0 24 24", fill: "currentColor" }, /* @__PURE__ */ React11.createElement("path", { d: "M3 17.25V21h3.75L17.81 9.94l-3.75-3.75L3 17.25zM20.71 7.04c.39-.39.39-1.02 0-1.41l-2.34-2.34c-.39-.39-1.02-.39-1.41 0l-1.83 1.83 3.75 3.75 1.83-1.83z" }));
|
|
3060
|
-
var DefaultStyleIcon3 = () => /* @__PURE__ */ React11.createElement("svg", { width: "14", height: "14", viewBox: "0 0 24 24", fill: "currentColor" }, /* @__PURE__ */ React11.createElement("path", { d: "M12 3c-4.97 0-9 4.03-9 9s4.03 9 9 9c.83 0 1.5-.67 1.5-1.5 0-.39-.15-.74-.39-1.01-.23-.26-.38-.61-.38-.99 0-.83.67-1.5 1.5-1.5H16c2.76 0 5-2.24 5-5 0-4.42-4.03-8-9-8zm-5.5 9c-.83 0-1.5-.67-1.5-1.5S5.67 9 6.5 9 8 9.67 8 10.5 7.33 12 6.5 12zm3-4C8.67 8 8 7.33 8 6.5S8.67 5 9.5 5s1.5.67 1.5 1.5S10.33 8 9.5 8zm5 0c-.83 0-1.5-.67-1.5-1.5S13.67 5 14.5 5s1.5.67 1.5 1.5S15.33 8 14.5 8zm3 4c-.83 0-1.5-.67-1.5-1.5S16.67 9 17.5 9s1.5.67 1.5 1.5-.67 1.5-1.5 1.5z" }));
|
|
3061
|
-
var DefaultDeleteIcon3 = () => /* @__PURE__ */ React11.createElement("svg", { width: "14", height: "14", viewBox: "0 0 24 24", fill: "currentColor" }, /* @__PURE__ */ React11.createElement("path", { d: "M6 19c0 1.1.9 2 2 2h8c1.1 0 2-.9 2-2V7H6v12zM19 4h-3.5l-1-1h-5l-1 1H5v2h14V4z" }));
|
|
3062
|
-
var DefaultCompactIcon = () => /* @__PURE__ */ React11.createElement("svg", { width: "16", height: "16", viewBox: "0 0 24 24", fill: "currentColor" }, /* @__PURE__ */ React11.createElement("path", { d: "M6 3h9l5 5v13H6V3zm8 1.5V9h4.5L14 4.5zM8 12h8v1.5H8V12zm0 3h8v1.5H8V15zm0 3h5v1.5H8V18z" }));
|
|
3063
|
-
var DefaultCollapseIcon = () => /* @__PURE__ */ React11.createElement("svg", { width: "14", height: "14", viewBox: "0 0 24 24", fill: "currentColor" }, /* @__PURE__ */ React11.createElement("path", { d: "M7 10v2h10v-2H7zm-2-7h14c1.1 0 2 .9 2 2v14c0 1.1-.9 2-2 2H5c-1.1 0-2-.9-2-2V5c0-1.1.9-2 2-2zm0 2v14h14V5H5z" }));
|
|
3197
|
+
});
|
|
3198
|
+
AreaHighlight.displayName = "AreaHighlight";
|
|
3199
|
+
var DefaultEditIcon = () => /* @__PURE__ */ React11.createElement(Pencil, { width: 14, height: 14 });
|
|
3200
|
+
var DefaultStyleIcon2 = () => /* @__PURE__ */ React11.createElement(Palette, { width: 14, height: 14 });
|
|
3201
|
+
var DefaultDeleteIcon3 = () => /* @__PURE__ */ React11.createElement(Trash2, { width: 14, height: 14 });
|
|
3202
|
+
var DefaultCompactIcon = () => /* @__PURE__ */ React11.createElement(StickyNote, { width: 16, height: 16 });
|
|
3203
|
+
var DefaultCollapseIcon = () => /* @__PURE__ */ React11.createElement(Minimize2, { width: 14, height: 14 });
|
|
3204
|
+
var ChevronDownIcon3 = () => /* @__PURE__ */ React11.createElement(ChevronDown, { width: 12, height: 12, strokeWidth: 2.5 });
|
|
3205
|
+
var CheckIcon3 = () => /* @__PURE__ */ React11.createElement(Check, { width: 14, height: 14, strokeWidth: 2.5 });
|
|
3064
3206
|
var DEFAULT_BACKGROUND_PRESETS = ["transparent", "#ffffc8", "#ffcdd2", "#c8e6c9", "#bbdefb", "#e1bee7"];
|
|
3065
3207
|
var DEFAULT_TEXT_PRESETS = ["#333333", "#d32f2f", "#1976d2", "#388e3c", "#7b1fa2"];
|
|
3208
|
+
var BACKGROUND_COLOR_NAMES = {
|
|
3209
|
+
transparent: "None",
|
|
3210
|
+
"#ffffc8": "Yellow",
|
|
3211
|
+
"#ffcdd2": "Red",
|
|
3212
|
+
"#c8e6c9": "Green",
|
|
3213
|
+
"#bbdefb": "Blue",
|
|
3214
|
+
"#e1bee7": "Purple"
|
|
3215
|
+
};
|
|
3066
3216
|
var FreetextHighlight = ({
|
|
3067
3217
|
highlight,
|
|
3068
3218
|
onChange,
|
|
@@ -3089,29 +3239,58 @@ var FreetextHighlight = ({
|
|
|
3089
3239
|
compactSize = 32,
|
|
3090
3240
|
compactIcon
|
|
3091
3241
|
}) => {
|
|
3092
|
-
const [isEditing, setIsEditing] =
|
|
3093
|
-
const [
|
|
3094
|
-
|
|
3095
|
-
const [
|
|
3096
|
-
const
|
|
3097
|
-
const
|
|
3098
|
-
|
|
3242
|
+
const [isEditing, setIsEditing] = useState(false);
|
|
3243
|
+
const [isSelected, setIsSelected] = useState(false);
|
|
3244
|
+
useClearTipWhileSelected(isSelected);
|
|
3245
|
+
const [isExpanded, setIsExpanded] = useState(!compact);
|
|
3246
|
+
const [isStylePanelOpen, setIsStylePanelOpen] = useState(false);
|
|
3247
|
+
const [isColorMenuOpen, setIsColorMenuOpen] = useState(false);
|
|
3248
|
+
const [text, setText] = useState(highlight.content?.text || "");
|
|
3249
|
+
const textareaRef = useRef(null);
|
|
3250
|
+
const stylePanelRef = useRef(null);
|
|
3251
|
+
const colorMenuRef = useRef(null);
|
|
3252
|
+
const rootRef = useRef(null);
|
|
3253
|
+
useEffect(() => {
|
|
3254
|
+
if (!isSelected) return;
|
|
3255
|
+
const handlePointerDown = (e) => {
|
|
3256
|
+
if (rootRef.current && !rootRef.current.contains(e.target)) {
|
|
3257
|
+
setIsSelected(false);
|
|
3258
|
+
setIsStylePanelOpen(false);
|
|
3259
|
+
setIsColorMenuOpen(false);
|
|
3260
|
+
}
|
|
3261
|
+
};
|
|
3262
|
+
const handleKey = (e) => {
|
|
3263
|
+
if (e.key === "Escape" && !isEditing) {
|
|
3264
|
+
setIsSelected(false);
|
|
3265
|
+
setIsStylePanelOpen(false);
|
|
3266
|
+
setIsColorMenuOpen(false);
|
|
3267
|
+
}
|
|
3268
|
+
};
|
|
3269
|
+
document.addEventListener("mousedown", handlePointerDown);
|
|
3270
|
+
document.addEventListener("keydown", handleKey);
|
|
3271
|
+
return () => {
|
|
3272
|
+
document.removeEventListener("mousedown", handlePointerDown);
|
|
3273
|
+
document.removeEventListener("keydown", handleKey);
|
|
3274
|
+
};
|
|
3275
|
+
}, [isSelected, isEditing]);
|
|
3276
|
+
useEffect(() => {
|
|
3099
3277
|
setText(highlight.content?.text || "");
|
|
3100
3278
|
}, [highlight.content?.text]);
|
|
3101
|
-
|
|
3279
|
+
useEffect(() => {
|
|
3102
3280
|
setIsExpanded(!compact);
|
|
3103
3281
|
setIsStylePanelOpen(false);
|
|
3282
|
+
setIsColorMenuOpen(false);
|
|
3104
3283
|
if (!compact) {
|
|
3105
3284
|
setIsEditing(false);
|
|
3106
3285
|
}
|
|
3107
3286
|
}, [compact]);
|
|
3108
|
-
|
|
3287
|
+
useEffect(() => {
|
|
3109
3288
|
if (isEditing && textareaRef.current) {
|
|
3110
3289
|
textareaRef.current.focus();
|
|
3111
3290
|
textareaRef.current.select();
|
|
3112
3291
|
}
|
|
3113
3292
|
}, [isEditing]);
|
|
3114
|
-
|
|
3293
|
+
useEffect(() => {
|
|
3115
3294
|
if (!isStylePanelOpen) return;
|
|
3116
3295
|
const handleClickOutside = (e) => {
|
|
3117
3296
|
if (stylePanelRef.current && !stylePanelRef.current.contains(e.target)) {
|
|
@@ -3126,16 +3305,38 @@ var FreetextHighlight = ({
|
|
|
3126
3305
|
document.removeEventListener("mousedown", handleClickOutside);
|
|
3127
3306
|
};
|
|
3128
3307
|
}, [isStylePanelOpen]);
|
|
3308
|
+
useEffect(() => {
|
|
3309
|
+
if (!isColorMenuOpen) return;
|
|
3310
|
+
const handleClickOutside = (e) => {
|
|
3311
|
+
if (colorMenuRef.current && !colorMenuRef.current.contains(e.target)) {
|
|
3312
|
+
setIsColorMenuOpen(false);
|
|
3313
|
+
}
|
|
3314
|
+
};
|
|
3315
|
+
const timeoutId = setTimeout(() => {
|
|
3316
|
+
document.addEventListener("mousedown", handleClickOutside);
|
|
3317
|
+
}, 0);
|
|
3318
|
+
return () => {
|
|
3319
|
+
clearTimeout(timeoutId);
|
|
3320
|
+
document.removeEventListener("mousedown", handleClickOutside);
|
|
3321
|
+
};
|
|
3322
|
+
}, [isColorMenuOpen]);
|
|
3129
3323
|
const highlightClass = isScrolledTo ? "FreetextHighlight--scrolledTo" : "";
|
|
3130
3324
|
const editingClass = isEditing ? "FreetextHighlight--editing" : "";
|
|
3325
|
+
const selectedClass = isSelected ? "FreetextHighlight--selected" : "";
|
|
3131
3326
|
const compactClass = compact ? "FreetextHighlight--compact" : "";
|
|
3132
|
-
const isCompactCollapsed = compact && !isExpanded && !isEditing && !isStylePanelOpen;
|
|
3327
|
+
const isCompactCollapsed = compact && !isExpanded && !isEditing && !isStylePanelOpen && !isColorMenuOpen;
|
|
3133
3328
|
const collapsedClass = isCompactCollapsed ? "FreetextHighlight--collapsed" : "";
|
|
3329
|
+
const flipToolbar = highlight.position.boundingRect.top < 40;
|
|
3134
3330
|
const key = `${highlight.position.boundingRect.width}${highlight.position.boundingRect.height}${highlight.position.boundingRect.left}${highlight.position.boundingRect.top}${isCompactCollapsed ? "collapsed" : "expanded"}`;
|
|
3135
|
-
const
|
|
3331
|
+
const handleNoteClick = (e) => {
|
|
3136
3332
|
e.stopPropagation();
|
|
3333
|
+
if (!isEditing) setIsSelected(true);
|
|
3334
|
+
};
|
|
3335
|
+
const enterEditMode = (e) => {
|
|
3336
|
+
e?.stopPropagation();
|
|
3137
3337
|
if (!isEditing) {
|
|
3138
3338
|
setIsExpanded(true);
|
|
3339
|
+
setIsSelected(true);
|
|
3139
3340
|
setIsEditing(true);
|
|
3140
3341
|
onEditStart?.();
|
|
3141
3342
|
}
|
|
@@ -3170,11 +3371,12 @@ var FreetextHighlight = ({
|
|
|
3170
3371
|
return /* @__PURE__ */ React11.createElement(
|
|
3171
3372
|
"div",
|
|
3172
3373
|
{
|
|
3173
|
-
|
|
3374
|
+
ref: rootRef,
|
|
3375
|
+
className: `FreetextHighlight ${highlightClass} ${editingClass} ${selectedClass} ${compactClass} ${collapsedClass}`,
|
|
3174
3376
|
onContextMenu
|
|
3175
3377
|
},
|
|
3176
3378
|
/* @__PURE__ */ React11.createElement(
|
|
3177
|
-
|
|
3379
|
+
Rnd,
|
|
3178
3380
|
{
|
|
3179
3381
|
className: "FreetextHighlight__rnd",
|
|
3180
3382
|
onDragStop: (_, data) => {
|
|
@@ -3187,9 +3389,11 @@ var FreetextHighlight = ({
|
|
|
3187
3389
|
},
|
|
3188
3390
|
onDragStart: () => {
|
|
3189
3391
|
if (!isEditing) {
|
|
3392
|
+
setIsSelected(true);
|
|
3190
3393
|
onEditStart?.();
|
|
3191
3394
|
}
|
|
3192
3395
|
},
|
|
3396
|
+
disableDragging: isEditing,
|
|
3193
3397
|
default: {
|
|
3194
3398
|
x: highlight.position.boundingRect.left,
|
|
3195
3399
|
y: highlight.position.boundingRect.top,
|
|
@@ -3225,168 +3429,236 @@ var FreetextHighlight = ({
|
|
|
3225
3429
|
onEditStart?.();
|
|
3226
3430
|
}
|
|
3227
3431
|
},
|
|
3228
|
-
cancel: ".
|
|
3432
|
+
cancel: ".FreetextHighlight__input, .FreetextHighlight__toolbar, .FreetextHighlight__style-panel, .FreetextHighlight__color-menu, .FreetextHighlight__compact-button"
|
|
3229
3433
|
},
|
|
3230
|
-
/* @__PURE__ */ React11.createElement(
|
|
3231
|
-
"button",
|
|
3232
|
-
{
|
|
3233
|
-
className: "FreetextHighlight__compact-button",
|
|
3234
|
-
type: "button",
|
|
3235
|
-
title: text || "Open note",
|
|
3236
|
-
onClick: (event) => {
|
|
3237
|
-
event.stopPropagation();
|
|
3238
|
-
setIsExpanded(true);
|
|
3239
|
-
}
|
|
3240
|
-
},
|
|
3241
|
-
compactIcon || /* @__PURE__ */ React11.createElement(DefaultCompactIcon, null)
|
|
3242
|
-
) : /* @__PURE__ */ React11.createElement(React11.Fragment, null, /* @__PURE__ */ React11.createElement("div", { className: "FreetextHighlight__toolbar" }, /* @__PURE__ */ React11.createElement("div", { className: "FreetextHighlight__drag-handle", title: "Drag to move" }, dragIcon || /* @__PURE__ */ React11.createElement(DefaultDragIcon, null)), /* @__PURE__ */ React11.createElement(
|
|
3243
|
-
"button",
|
|
3244
|
-
{
|
|
3245
|
-
className: "FreetextHighlight__edit-button",
|
|
3246
|
-
onClick: handleTextClick,
|
|
3247
|
-
title: "Edit text",
|
|
3248
|
-
type: "button"
|
|
3249
|
-
},
|
|
3250
|
-
editIcon || /* @__PURE__ */ React11.createElement(DefaultEditIcon, null)
|
|
3251
|
-
), /* @__PURE__ */ React11.createElement(
|
|
3252
|
-
"button",
|
|
3253
|
-
{
|
|
3254
|
-
className: "FreetextHighlight__style-button",
|
|
3255
|
-
onClick: (e) => {
|
|
3256
|
-
e.stopPropagation();
|
|
3257
|
-
setIsStylePanelOpen(!isStylePanelOpen);
|
|
3258
|
-
},
|
|
3259
|
-
title: "Change style",
|
|
3260
|
-
type: "button"
|
|
3261
|
-
},
|
|
3262
|
-
styleIcon || /* @__PURE__ */ React11.createElement(DefaultStyleIcon3, null)
|
|
3263
|
-
), compact && /* @__PURE__ */ React11.createElement(
|
|
3264
|
-
"button",
|
|
3265
|
-
{
|
|
3266
|
-
className: "FreetextHighlight__collapse-button",
|
|
3267
|
-
onClick: (e) => {
|
|
3268
|
-
e.stopPropagation();
|
|
3269
|
-
setIsExpanded(false);
|
|
3270
|
-
setIsStylePanelOpen(false);
|
|
3271
|
-
},
|
|
3272
|
-
title: "Collapse note",
|
|
3273
|
-
type: "button"
|
|
3274
|
-
},
|
|
3275
|
-
/* @__PURE__ */ React11.createElement(DefaultCollapseIcon, null)
|
|
3276
|
-
), onDelete && /* @__PURE__ */ React11.createElement(
|
|
3277
|
-
"button",
|
|
3278
|
-
{
|
|
3279
|
-
className: "FreetextHighlight__delete-button",
|
|
3280
|
-
onClick: (e) => {
|
|
3281
|
-
e.stopPropagation();
|
|
3282
|
-
onDelete();
|
|
3283
|
-
},
|
|
3284
|
-
title: "Delete",
|
|
3285
|
-
type: "button"
|
|
3286
|
-
},
|
|
3287
|
-
deleteIcon || /* @__PURE__ */ React11.createElement(DefaultDeleteIcon3, null)
|
|
3288
|
-
)), isStylePanelOpen && /* @__PURE__ */ React11.createElement(
|
|
3434
|
+
/* @__PURE__ */ React11.createElement(
|
|
3289
3435
|
"div",
|
|
3290
3436
|
{
|
|
3291
|
-
className: "
|
|
3292
|
-
|
|
3293
|
-
onClick:
|
|
3437
|
+
className: "FreetextHighlight__container",
|
|
3438
|
+
style: containerStyle,
|
|
3439
|
+
onClick: handleNoteClick,
|
|
3440
|
+
onDoubleClick: enterEditMode
|
|
3294
3441
|
},
|
|
3295
|
-
|
|
3442
|
+
isCompactCollapsed ? /* @__PURE__ */ React11.createElement(
|
|
3296
3443
|
"button",
|
|
3297
3444
|
{
|
|
3298
|
-
|
|
3445
|
+
className: "FreetextHighlight__compact-button",
|
|
3299
3446
|
type: "button",
|
|
3300
|
-
|
|
3301
|
-
|
|
3302
|
-
|
|
3303
|
-
|
|
3304
|
-
}
|
|
3305
|
-
))), /* @__PURE__ */ React11.createElement(
|
|
3306
|
-
"input",
|
|
3307
|
-
{
|
|
3308
|
-
type: "color",
|
|
3309
|
-
value: backgroundColor === "transparent" ? "#ffffff" : backgroundColor,
|
|
3310
|
-
onChange: (e) => {
|
|
3311
|
-
onStyleChange?.({ backgroundColor: e.target.value });
|
|
3447
|
+
title: text || "Open note",
|
|
3448
|
+
onClick: (event) => {
|
|
3449
|
+
event.stopPropagation();
|
|
3450
|
+
setIsExpanded(true);
|
|
3312
3451
|
}
|
|
3313
|
-
}
|
|
3314
|
-
|
|
3315
|
-
/* @__PURE__ */ React11.createElement(
|
|
3316
|
-
"
|
|
3317
|
-
null,
|
|
3318
|
-
"Text Color"
|
|
3319
|
-
), /* @__PURE__ */ React11.createElement("div", { className: "FreetextHighlight__color-options" }, /* @__PURE__ */ React11.createElement("div", { className: "FreetextHighlight__color-presets" }, textColorPresets.map((c) => /* @__PURE__ */ React11.createElement(
|
|
3320
|
-
"button",
|
|
3321
|
-
{
|
|
3322
|
-
key: c,
|
|
3323
|
-
type: "button",
|
|
3324
|
-
className: `FreetextHighlight__color-preset ${color === c ? "active" : ""}`,
|
|
3325
|
-
style: { backgroundColor: c },
|
|
3326
|
-
onClick: () => onStyleChange?.({ color: c }),
|
|
3327
|
-
title: c
|
|
3328
|
-
}
|
|
3329
|
-
))), /* @__PURE__ */ React11.createElement(
|
|
3330
|
-
"input",
|
|
3452
|
+
},
|
|
3453
|
+
compactIcon || /* @__PURE__ */ React11.createElement(DefaultCompactIcon, null)
|
|
3454
|
+
) : /* @__PURE__ */ React11.createElement(React11.Fragment, null, /* @__PURE__ */ React11.createElement(
|
|
3455
|
+
"div",
|
|
3331
3456
|
{
|
|
3332
|
-
|
|
3333
|
-
|
|
3334
|
-
|
|
3335
|
-
|
|
3336
|
-
|
|
3337
|
-
|
|
3338
|
-
|
|
3339
|
-
|
|
3340
|
-
|
|
3457
|
+
className: `FreetextHighlight__toolbar ${flipToolbar ? "FreetextHighlight__toolbar--below" : ""}`
|
|
3458
|
+
},
|
|
3459
|
+
/* @__PURE__ */ React11.createElement(
|
|
3460
|
+
"button",
|
|
3461
|
+
{
|
|
3462
|
+
type: "button",
|
|
3463
|
+
className: "FreetextHighlight__color-trigger",
|
|
3464
|
+
"aria-label": "Background color",
|
|
3465
|
+
"aria-expanded": isColorMenuOpen,
|
|
3466
|
+
onClick: (e) => {
|
|
3467
|
+
e.stopPropagation();
|
|
3468
|
+
setIsStylePanelOpen(false);
|
|
3469
|
+
setIsColorMenuOpen((v) => !v);
|
|
3470
|
+
},
|
|
3471
|
+
title: "Background color"
|
|
3472
|
+
},
|
|
3473
|
+
/* @__PURE__ */ React11.createElement(
|
|
3474
|
+
"span",
|
|
3475
|
+
{
|
|
3476
|
+
className: "FreetextHighlight__color-trigger-dot",
|
|
3477
|
+
style: {
|
|
3478
|
+
backgroundColor: backgroundColor === "transparent" ? void 0 : backgroundColor
|
|
3479
|
+
}
|
|
3480
|
+
}
|
|
3481
|
+
),
|
|
3482
|
+
/* @__PURE__ */ React11.createElement(ChevronDownIcon3, null)
|
|
3483
|
+
),
|
|
3484
|
+
/* @__PURE__ */ React11.createElement("div", { className: "FreetextHighlight__toolbar-divider" }),
|
|
3485
|
+
/* @__PURE__ */ React11.createElement(
|
|
3486
|
+
"button",
|
|
3487
|
+
{
|
|
3488
|
+
className: "FreetextHighlight__edit-button",
|
|
3489
|
+
onClick: enterEditMode,
|
|
3490
|
+
title: "Edit text (or double-click the note)",
|
|
3491
|
+
type: "button"
|
|
3492
|
+
},
|
|
3493
|
+
editIcon || /* @__PURE__ */ React11.createElement(DefaultEditIcon, null)
|
|
3494
|
+
),
|
|
3495
|
+
/* @__PURE__ */ React11.createElement(
|
|
3496
|
+
"button",
|
|
3497
|
+
{
|
|
3498
|
+
className: "FreetextHighlight__style-button",
|
|
3499
|
+
onClick: (e) => {
|
|
3500
|
+
e.stopPropagation();
|
|
3501
|
+
setIsColorMenuOpen(false);
|
|
3502
|
+
setIsStylePanelOpen(!isStylePanelOpen);
|
|
3503
|
+
},
|
|
3504
|
+
title: "Change style",
|
|
3505
|
+
type: "button"
|
|
3506
|
+
},
|
|
3507
|
+
styleIcon || /* @__PURE__ */ React11.createElement(DefaultStyleIcon2, null)
|
|
3508
|
+
),
|
|
3509
|
+
compact && /* @__PURE__ */ React11.createElement(
|
|
3510
|
+
"button",
|
|
3511
|
+
{
|
|
3512
|
+
className: "FreetextHighlight__collapse-button",
|
|
3513
|
+
onClick: (e) => {
|
|
3514
|
+
e.stopPropagation();
|
|
3515
|
+
setIsExpanded(false);
|
|
3516
|
+
setIsStylePanelOpen(false);
|
|
3517
|
+
setIsColorMenuOpen(false);
|
|
3518
|
+
},
|
|
3519
|
+
title: "Collapse note",
|
|
3520
|
+
type: "button"
|
|
3521
|
+
},
|
|
3522
|
+
/* @__PURE__ */ React11.createElement(DefaultCollapseIcon, null)
|
|
3523
|
+
),
|
|
3524
|
+
onDelete && /* @__PURE__ */ React11.createElement(
|
|
3525
|
+
"button",
|
|
3526
|
+
{
|
|
3527
|
+
className: "FreetextHighlight__delete-button",
|
|
3528
|
+
onClick: (e) => {
|
|
3529
|
+
e.stopPropagation();
|
|
3530
|
+
onDelete();
|
|
3531
|
+
},
|
|
3532
|
+
title: "Delete",
|
|
3533
|
+
type: "button"
|
|
3534
|
+
},
|
|
3535
|
+
deleteIcon || /* @__PURE__ */ React11.createElement(DefaultDeleteIcon3, null)
|
|
3536
|
+
)
|
|
3537
|
+
), isColorMenuOpen && /* @__PURE__ */ React11.createElement(
|
|
3538
|
+
"div",
|
|
3341
3539
|
{
|
|
3342
|
-
|
|
3343
|
-
|
|
3344
|
-
|
|
3345
|
-
}
|
|
3540
|
+
className: `FreetextHighlight__color-menu ${flipToolbar ? "FreetextHighlight__color-menu--below-toolbar" : ""}`,
|
|
3541
|
+
ref: colorMenuRef,
|
|
3542
|
+
onClick: (e) => e.stopPropagation()
|
|
3346
3543
|
},
|
|
3347
|
-
/* @__PURE__ */ React11.createElement(
|
|
3348
|
-
|
|
3349
|
-
|
|
3350
|
-
|
|
3351
|
-
|
|
3352
|
-
|
|
3353
|
-
|
|
3354
|
-
|
|
3355
|
-
|
|
3356
|
-
|
|
3544
|
+
backgroundColorPresets.map((c) => /* @__PURE__ */ React11.createElement(
|
|
3545
|
+
"button",
|
|
3546
|
+
{
|
|
3547
|
+
key: c,
|
|
3548
|
+
type: "button",
|
|
3549
|
+
className: "FreetextHighlight__color-menu-item",
|
|
3550
|
+
onClick: () => {
|
|
3551
|
+
onStyleChange?.({ backgroundColor: c });
|
|
3552
|
+
setIsColorMenuOpen(false);
|
|
3553
|
+
}
|
|
3554
|
+
},
|
|
3555
|
+
/* @__PURE__ */ React11.createElement(
|
|
3556
|
+
"span",
|
|
3557
|
+
{
|
|
3558
|
+
className: `FreetextHighlight__color-menu-dot ${c === "transparent" ? "FreetextHighlight__color-menu-dot--transparent" : ""}`,
|
|
3559
|
+
style: c !== "transparent" ? { backgroundColor: c } : void 0
|
|
3560
|
+
}
|
|
3561
|
+
),
|
|
3562
|
+
/* @__PURE__ */ React11.createElement("span", { className: "FreetextHighlight__color-menu-label" }, BACKGROUND_COLOR_NAMES[c] || c),
|
|
3563
|
+
backgroundColor === c && /* @__PURE__ */ React11.createElement("span", { className: "FreetextHighlight__color-menu-check" }, /* @__PURE__ */ React11.createElement(CheckIcon3, null))
|
|
3564
|
+
))
|
|
3565
|
+
), isStylePanelOpen && /* @__PURE__ */ React11.createElement(
|
|
3566
|
+
"div",
|
|
3357
3567
|
{
|
|
3358
|
-
|
|
3359
|
-
|
|
3360
|
-
|
|
3361
|
-
}
|
|
3568
|
+
className: `FreetextHighlight__style-panel ${flipToolbar ? "FreetextHighlight__style-panel--below-toolbar" : ""}`,
|
|
3569
|
+
ref: stylePanelRef,
|
|
3570
|
+
onClick: (e) => e.stopPropagation()
|
|
3362
3571
|
},
|
|
3363
|
-
/* @__PURE__ */ React11.createElement("
|
|
3364
|
-
|
|
3365
|
-
|
|
3366
|
-
|
|
3367
|
-
/* @__PURE__ */ React11.createElement("
|
|
3368
|
-
|
|
3369
|
-
|
|
3370
|
-
|
|
3371
|
-
|
|
3372
|
-
|
|
3373
|
-
|
|
3374
|
-
|
|
3375
|
-
|
|
3376
|
-
|
|
3377
|
-
|
|
3378
|
-
|
|
3379
|
-
|
|
3380
|
-
|
|
3572
|
+
/* @__PURE__ */ React11.createElement("div", { className: "FreetextHighlight__style-row" }, /* @__PURE__ */ React11.createElement(
|
|
3573
|
+
"label",
|
|
3574
|
+
null,
|
|
3575
|
+
"Text Color"
|
|
3576
|
+
), /* @__PURE__ */ React11.createElement("div", { className: "FreetextHighlight__color-options" }, /* @__PURE__ */ React11.createElement("div", { className: "FreetextHighlight__color-presets" }, textColorPresets.map((c) => /* @__PURE__ */ React11.createElement(
|
|
3577
|
+
"button",
|
|
3578
|
+
{
|
|
3579
|
+
key: c,
|
|
3580
|
+
type: "button",
|
|
3581
|
+
className: `FreetextHighlight__color-preset ${color === c ? "active" : ""}`,
|
|
3582
|
+
style: { backgroundColor: c },
|
|
3583
|
+
onClick: () => onStyleChange?.({ color: c }),
|
|
3584
|
+
title: c
|
|
3585
|
+
}
|
|
3586
|
+
))), /* @__PURE__ */ React11.createElement(
|
|
3587
|
+
"input",
|
|
3588
|
+
{
|
|
3589
|
+
type: "color",
|
|
3590
|
+
value: color,
|
|
3591
|
+
onChange: (e) => {
|
|
3592
|
+
onStyleChange?.({ color: e.target.value });
|
|
3593
|
+
}
|
|
3594
|
+
}
|
|
3595
|
+
))),
|
|
3596
|
+
/* @__PURE__ */ React11.createElement("div", { className: "FreetextHighlight__style-row" }, /* @__PURE__ */ React11.createElement("label", null, "Font Size"), /* @__PURE__ */ React11.createElement(
|
|
3597
|
+
"select",
|
|
3598
|
+
{
|
|
3599
|
+
value: fontSize,
|
|
3600
|
+
onChange: (e) => {
|
|
3601
|
+
onStyleChange?.({ fontSize: e.target.value });
|
|
3602
|
+
}
|
|
3603
|
+
},
|
|
3604
|
+
/* @__PURE__ */ React11.createElement("option", { value: "10px" }, "10px"),
|
|
3605
|
+
/* @__PURE__ */ React11.createElement("option", { value: "12px" }, "12px"),
|
|
3606
|
+
/* @__PURE__ */ React11.createElement("option", { value: "14px" }, "14px"),
|
|
3607
|
+
/* @__PURE__ */ React11.createElement("option", { value: "16px" }, "16px"),
|
|
3608
|
+
/* @__PURE__ */ React11.createElement("option", { value: "18px" }, "18px"),
|
|
3609
|
+
/* @__PURE__ */ React11.createElement("option", { value: "20px" }, "20px"),
|
|
3610
|
+
/* @__PURE__ */ React11.createElement("option", { value: "24px" }, "24px")
|
|
3611
|
+
)),
|
|
3612
|
+
/* @__PURE__ */ React11.createElement("div", { className: "FreetextHighlight__style-row" }, /* @__PURE__ */ React11.createElement("label", null, "Font"), /* @__PURE__ */ React11.createElement(
|
|
3613
|
+
"select",
|
|
3614
|
+
{
|
|
3615
|
+
value: fontFamily,
|
|
3616
|
+
onChange: (e) => {
|
|
3617
|
+
onStyleChange?.({ fontFamily: e.target.value });
|
|
3618
|
+
}
|
|
3619
|
+
},
|
|
3620
|
+
/* @__PURE__ */ React11.createElement("option", { value: "inherit" }, "Default"),
|
|
3621
|
+
/* @__PURE__ */ React11.createElement("option", { value: "Arial, sans-serif" }, "Arial"),
|
|
3622
|
+
/* @__PURE__ */ React11.createElement("option", { value: "Georgia, serif" }, "Georgia"),
|
|
3623
|
+
/* @__PURE__ */ React11.createElement("option", { value: "'Courier New', monospace" }, "Courier"),
|
|
3624
|
+
/* @__PURE__ */ React11.createElement("option", { value: "'Times New Roman', serif" }, "Times")
|
|
3625
|
+
))
|
|
3626
|
+
), /* @__PURE__ */ React11.createElement("div", { className: "FreetextHighlight__content" }, isEditing ? /* @__PURE__ */ React11.createElement(
|
|
3627
|
+
"textarea",
|
|
3628
|
+
{
|
|
3629
|
+
ref: textareaRef,
|
|
3630
|
+
className: "FreetextHighlight__input",
|
|
3631
|
+
value: text,
|
|
3632
|
+
onChange: (e) => setText(e.target.value),
|
|
3633
|
+
onBlur: handleTextBlur,
|
|
3634
|
+
onKeyDown: handleKeyDown,
|
|
3635
|
+
onClick: (e) => e.stopPropagation()
|
|
3636
|
+
}
|
|
3637
|
+
) : /* @__PURE__ */ React11.createElement("div", { className: "FreetextHighlight__text" }, text || "New note")))
|
|
3638
|
+
)
|
|
3381
3639
|
)
|
|
3382
3640
|
);
|
|
3383
3641
|
};
|
|
3384
|
-
|
|
3385
|
-
|
|
3386
|
-
|
|
3387
|
-
|
|
3388
|
-
|
|
3389
|
-
|
|
3642
|
+
var DefaultDeleteIcon4 = () => /* @__PURE__ */ React11.createElement(Trash2, { width: 14, height: 14 });
|
|
3643
|
+
var rotateImageDataUrl = (dataUrl, width, height, clockwise) => new Promise((resolve, reject) => {
|
|
3644
|
+
const img = new Image();
|
|
3645
|
+
img.onload = () => {
|
|
3646
|
+
const canvas = document.createElement("canvas");
|
|
3647
|
+
canvas.width = height;
|
|
3648
|
+
canvas.height = width;
|
|
3649
|
+
const ctx = canvas.getContext("2d");
|
|
3650
|
+
if (!ctx) {
|
|
3651
|
+
reject(new Error("Canvas 2D context unavailable"));
|
|
3652
|
+
return;
|
|
3653
|
+
}
|
|
3654
|
+
ctx.translate(height / 2, width / 2);
|
|
3655
|
+
ctx.rotate((clockwise ? 90 : -90) * Math.PI / 180);
|
|
3656
|
+
ctx.drawImage(img, -width / 2, -height / 2, width, height);
|
|
3657
|
+
resolve(canvas.toDataURL("image/png"));
|
|
3658
|
+
};
|
|
3659
|
+
img.onerror = () => reject(new Error("Failed to load image for rotation"));
|
|
3660
|
+
img.src = dataUrl;
|
|
3661
|
+
});
|
|
3390
3662
|
var ImageHighlight = ({
|
|
3391
3663
|
highlight,
|
|
3392
3664
|
onChange,
|
|
@@ -3398,19 +3670,60 @@ var ImageHighlight = ({
|
|
|
3398
3670
|
style,
|
|
3399
3671
|
dragIcon,
|
|
3400
3672
|
onDelete,
|
|
3401
|
-
deleteIcon
|
|
3673
|
+
deleteIcon,
|
|
3674
|
+
onImageChange
|
|
3402
3675
|
}) => {
|
|
3676
|
+
const [isSelected, setIsSelected] = useState(false);
|
|
3677
|
+
useClearTipWhileSelected(isSelected);
|
|
3678
|
+
const rootRef = useRef(null);
|
|
3403
3679
|
const highlightClass = isScrolledTo ? "ImageHighlight--scrolledTo" : "";
|
|
3680
|
+
const selectedClass = isSelected ? "ImageHighlight--selected" : "";
|
|
3681
|
+
useEffect(() => {
|
|
3682
|
+
if (!isSelected) return;
|
|
3683
|
+
const handlePointerDown = (e) => {
|
|
3684
|
+
if (rootRef.current && !rootRef.current.contains(e.target)) {
|
|
3685
|
+
setIsSelected(false);
|
|
3686
|
+
}
|
|
3687
|
+
};
|
|
3688
|
+
const handleKey = (e) => {
|
|
3689
|
+
if (e.key === "Escape") {
|
|
3690
|
+
setIsSelected(false);
|
|
3691
|
+
}
|
|
3692
|
+
};
|
|
3693
|
+
document.addEventListener("mousedown", handlePointerDown);
|
|
3694
|
+
document.addEventListener("keydown", handleKey);
|
|
3695
|
+
return () => {
|
|
3696
|
+
document.removeEventListener("mousedown", handlePointerDown);
|
|
3697
|
+
document.removeEventListener("keydown", handleKey);
|
|
3698
|
+
};
|
|
3699
|
+
}, [isSelected]);
|
|
3404
3700
|
const key = `${highlight.position.boundingRect.width}${highlight.position.boundingRect.height}${highlight.position.boundingRect.left}${highlight.position.boundingRect.top}`;
|
|
3405
3701
|
const imageUrl = highlight.content?.image;
|
|
3406
|
-
|
|
3702
|
+
const flipToolbar = highlight.position.boundingRect.top < 40;
|
|
3703
|
+
const handleRotate = async (clockwise) => {
|
|
3704
|
+
if (!imageUrl) return;
|
|
3705
|
+
const { width, height, left, top, pageNumber } = highlight.position.boundingRect;
|
|
3706
|
+
const newImage = await rotateImageDataUrl(imageUrl, width, height, clockwise);
|
|
3707
|
+
onImageChange?.(newImage);
|
|
3708
|
+
const centerX = left + width / 2;
|
|
3709
|
+
const centerY = top + height / 2;
|
|
3710
|
+
onChange?.({
|
|
3711
|
+
left: centerX - height / 2,
|
|
3712
|
+
top: centerY - width / 2,
|
|
3713
|
+
width: height,
|
|
3714
|
+
height: width,
|
|
3715
|
+
pageNumber
|
|
3716
|
+
});
|
|
3717
|
+
};
|
|
3718
|
+
return /* @__PURE__ */ React11.createElement(
|
|
3407
3719
|
"div",
|
|
3408
3720
|
{
|
|
3409
|
-
className: `ImageHighlight ${highlightClass}`,
|
|
3410
|
-
onContextMenu
|
|
3721
|
+
className: `ImageHighlight ${highlightClass} ${selectedClass}`,
|
|
3722
|
+
onContextMenu,
|
|
3723
|
+
ref: rootRef
|
|
3411
3724
|
},
|
|
3412
|
-
/* @__PURE__ */
|
|
3413
|
-
|
|
3725
|
+
/* @__PURE__ */ React11.createElement(
|
|
3726
|
+
Rnd,
|
|
3414
3727
|
{
|
|
3415
3728
|
className: "ImageHighlight__rnd",
|
|
3416
3729
|
onDragStop: (_, data) => {
|
|
@@ -3422,7 +3735,10 @@ var ImageHighlight = ({
|
|
|
3422
3735
|
onChange?.(boundingRect);
|
|
3423
3736
|
onEditEnd?.();
|
|
3424
3737
|
},
|
|
3425
|
-
onDragStart:
|
|
3738
|
+
onDragStart: () => {
|
|
3739
|
+
setIsSelected(true);
|
|
3740
|
+
onEditStart?.();
|
|
3741
|
+
},
|
|
3426
3742
|
onResizeStop: (_e, _direction, ref, _delta, position) => {
|
|
3427
3743
|
const boundingRect = {
|
|
3428
3744
|
top: position.y,
|
|
@@ -3446,26 +3762,58 @@ var ImageHighlight = ({
|
|
|
3446
3762
|
key,
|
|
3447
3763
|
bounds,
|
|
3448
3764
|
lockAspectRatio: true,
|
|
3449
|
-
|
|
3765
|
+
cancel: ".ImageHighlight__toolbar",
|
|
3450
3766
|
onClick: (event) => {
|
|
3451
3767
|
event.stopPropagation();
|
|
3452
3768
|
event.preventDefault();
|
|
3769
|
+
setIsSelected(true);
|
|
3453
3770
|
},
|
|
3454
3771
|
style
|
|
3455
3772
|
},
|
|
3456
|
-
/* @__PURE__ */
|
|
3457
|
-
"
|
|
3773
|
+
/* @__PURE__ */ React11.createElement("div", { className: "ImageHighlight__container" }, (onDelete || onImageChange) && /* @__PURE__ */ React11.createElement(
|
|
3774
|
+
"div",
|
|
3458
3775
|
{
|
|
3459
|
-
className: "
|
|
3460
|
-
onClick: (e) => {
|
|
3461
|
-
e.stopPropagation();
|
|
3462
|
-
onDelete();
|
|
3463
|
-
},
|
|
3464
|
-
title: "Delete",
|
|
3465
|
-
type: "button"
|
|
3776
|
+
className: `ImageHighlight__toolbar ${flipToolbar ? "ImageHighlight__toolbar--below" : ""}`
|
|
3466
3777
|
},
|
|
3467
|
-
|
|
3468
|
-
|
|
3778
|
+
onImageChange && imageUrl && /* @__PURE__ */ React11.createElement(React11.Fragment, null, /* @__PURE__ */ React11.createElement(
|
|
3779
|
+
"button",
|
|
3780
|
+
{
|
|
3781
|
+
className: "ImageHighlight__rotate-button",
|
|
3782
|
+
onClick: (e) => {
|
|
3783
|
+
e.stopPropagation();
|
|
3784
|
+
handleRotate(false);
|
|
3785
|
+
},
|
|
3786
|
+
title: "Rotate left",
|
|
3787
|
+
type: "button"
|
|
3788
|
+
},
|
|
3789
|
+
/* @__PURE__ */ React11.createElement(RotateCcw, { width: 14, height: 14 })
|
|
3790
|
+
), /* @__PURE__ */ React11.createElement(
|
|
3791
|
+
"button",
|
|
3792
|
+
{
|
|
3793
|
+
className: "ImageHighlight__rotate-button",
|
|
3794
|
+
onClick: (e) => {
|
|
3795
|
+
e.stopPropagation();
|
|
3796
|
+
handleRotate(true);
|
|
3797
|
+
},
|
|
3798
|
+
title: "Rotate right",
|
|
3799
|
+
type: "button"
|
|
3800
|
+
},
|
|
3801
|
+
/* @__PURE__ */ React11.createElement(RotateCw, { width: 14, height: 14 })
|
|
3802
|
+
), /* @__PURE__ */ React11.createElement("div", { className: "ImageHighlight__toolbar-divider" })),
|
|
3803
|
+
onDelete && /* @__PURE__ */ React11.createElement(
|
|
3804
|
+
"button",
|
|
3805
|
+
{
|
|
3806
|
+
className: "ImageHighlight__delete-button",
|
|
3807
|
+
onClick: (e) => {
|
|
3808
|
+
e.stopPropagation();
|
|
3809
|
+
onDelete();
|
|
3810
|
+
},
|
|
3811
|
+
title: "Delete",
|
|
3812
|
+
type: "button"
|
|
3813
|
+
},
|
|
3814
|
+
deleteIcon || /* @__PURE__ */ React11.createElement(DefaultDeleteIcon4, null)
|
|
3815
|
+
)
|
|
3816
|
+
), /* @__PURE__ */ React11.createElement("div", { className: "ImageHighlight__content" }, imageUrl ? /* @__PURE__ */ React11.createElement(
|
|
3469
3817
|
"img",
|
|
3470
3818
|
{
|
|
3471
3819
|
src: imageUrl,
|
|
@@ -3473,13 +3821,10 @@ var ImageHighlight = ({
|
|
|
3473
3821
|
className: "ImageHighlight__image",
|
|
3474
3822
|
draggable: false
|
|
3475
3823
|
}
|
|
3476
|
-
) : /* @__PURE__ */
|
|
3824
|
+
) : /* @__PURE__ */ React11.createElement("div", { className: "ImageHighlight__placeholder" }, "No image")))
|
|
3477
3825
|
)
|
|
3478
3826
|
);
|
|
3479
3827
|
};
|
|
3480
|
-
|
|
3481
|
-
// src/components/SignaturePad.tsx
|
|
3482
|
-
import React13, { useRef as useRef11, useEffect as useEffect9, useCallback as useCallback3 } from "react";
|
|
3483
3828
|
var SignaturePad = ({
|
|
3484
3829
|
isOpen,
|
|
3485
3830
|
onComplete,
|
|
@@ -3487,10 +3832,10 @@ var SignaturePad = ({
|
|
|
3487
3832
|
width = 400,
|
|
3488
3833
|
height = 200
|
|
3489
3834
|
}) => {
|
|
3490
|
-
const canvasRef =
|
|
3491
|
-
const isDrawingRef =
|
|
3492
|
-
const lastPosRef =
|
|
3493
|
-
|
|
3835
|
+
const canvasRef = useRef(null);
|
|
3836
|
+
const isDrawingRef = useRef(false);
|
|
3837
|
+
const lastPosRef = useRef({ x: 0, y: 0 });
|
|
3838
|
+
useEffect(() => {
|
|
3494
3839
|
if (!isOpen || !canvasRef.current) return;
|
|
3495
3840
|
const canvas = canvasRef.current;
|
|
3496
3841
|
const ctx = canvas.getContext("2d");
|
|
@@ -3501,7 +3846,7 @@ var SignaturePad = ({
|
|
|
3501
3846
|
ctx.lineJoin = "round";
|
|
3502
3847
|
ctx.clearRect(0, 0, width, height);
|
|
3503
3848
|
}, [isOpen, width, height]);
|
|
3504
|
-
const getPosition =
|
|
3849
|
+
const getPosition = useCallback(
|
|
3505
3850
|
(e) => {
|
|
3506
3851
|
const canvas = canvasRef.current;
|
|
3507
3852
|
if (!canvas) return { x: 0, y: 0 };
|
|
@@ -3522,7 +3867,7 @@ var SignaturePad = ({
|
|
|
3522
3867
|
},
|
|
3523
3868
|
[]
|
|
3524
3869
|
);
|
|
3525
|
-
const startDrawing =
|
|
3870
|
+
const startDrawing = useCallback(
|
|
3526
3871
|
(e) => {
|
|
3527
3872
|
e.preventDefault();
|
|
3528
3873
|
isDrawingRef.current = true;
|
|
@@ -3530,7 +3875,7 @@ var SignaturePad = ({
|
|
|
3530
3875
|
},
|
|
3531
3876
|
[getPosition]
|
|
3532
3877
|
);
|
|
3533
|
-
const draw =
|
|
3878
|
+
const draw = useCallback(
|
|
3534
3879
|
(e) => {
|
|
3535
3880
|
if (!isDrawingRef.current) return;
|
|
3536
3881
|
e.preventDefault();
|
|
@@ -3546,10 +3891,10 @@ var SignaturePad = ({
|
|
|
3546
3891
|
},
|
|
3547
3892
|
[getPosition]
|
|
3548
3893
|
);
|
|
3549
|
-
const stopDrawing =
|
|
3894
|
+
const stopDrawing = useCallback(() => {
|
|
3550
3895
|
isDrawingRef.current = false;
|
|
3551
3896
|
}, []);
|
|
3552
|
-
|
|
3897
|
+
useEffect(() => {
|
|
3553
3898
|
if (!isOpen) return;
|
|
3554
3899
|
const canvas = canvasRef.current;
|
|
3555
3900
|
if (!canvas) return;
|
|
@@ -3594,54 +3939,96 @@ var SignaturePad = ({
|
|
|
3594
3939
|
onClose();
|
|
3595
3940
|
}
|
|
3596
3941
|
};
|
|
3942
|
+
useEffect(() => {
|
|
3943
|
+
if (!isOpen) return;
|
|
3944
|
+
const onKey = (e) => {
|
|
3945
|
+
if (e.key === "Escape") onClose();
|
|
3946
|
+
};
|
|
3947
|
+
document.addEventListener("keydown", onKey);
|
|
3948
|
+
return () => document.removeEventListener("keydown", onKey);
|
|
3949
|
+
}, [isOpen, onClose]);
|
|
3597
3950
|
if (!isOpen) return null;
|
|
3598
|
-
return /* @__PURE__ */
|
|
3599
|
-
"
|
|
3600
|
-
{
|
|
3601
|
-
ref: canvasRef,
|
|
3602
|
-
className: "SignaturePad__canvas",
|
|
3603
|
-
width,
|
|
3604
|
-
height
|
|
3605
|
-
}
|
|
3606
|
-
), /* @__PURE__ */ React13.createElement("div", { className: "SignaturePad__buttons" }, /* @__PURE__ */ React13.createElement(
|
|
3607
|
-
"button",
|
|
3608
|
-
{
|
|
3609
|
-
type: "button",
|
|
3610
|
-
className: "SignaturePad__button SignaturePad__button--clear",
|
|
3611
|
-
onClick: handleClear
|
|
3612
|
-
},
|
|
3613
|
-
"Clear"
|
|
3614
|
-
), /* @__PURE__ */ React13.createElement(
|
|
3615
|
-
"button",
|
|
3616
|
-
{
|
|
3617
|
-
type: "button",
|
|
3618
|
-
className: "SignaturePad__button SignaturePad__button--cancel",
|
|
3619
|
-
onClick: onClose
|
|
3620
|
-
},
|
|
3621
|
-
"Cancel"
|
|
3622
|
-
), /* @__PURE__ */ React13.createElement(
|
|
3623
|
-
"button",
|
|
3951
|
+
return /* @__PURE__ */ React11.createElement("div", { className: "SignaturePad__overlay", onClick: handleOverlayClick }, /* @__PURE__ */ React11.createElement(
|
|
3952
|
+
"div",
|
|
3624
3953
|
{
|
|
3625
|
-
|
|
3626
|
-
|
|
3627
|
-
|
|
3954
|
+
className: "SignaturePad__modal",
|
|
3955
|
+
role: "dialog",
|
|
3956
|
+
"aria-modal": "true",
|
|
3957
|
+
"aria-labelledby": "signaturepad-title"
|
|
3628
3958
|
},
|
|
3629
|
-
"
|
|
3630
|
-
|
|
3959
|
+
/* @__PURE__ */ React11.createElement("div", { className: "SignaturePad__header" }, /* @__PURE__ */ React11.createElement("div", null, /* @__PURE__ */ React11.createElement("h3", { id: "signaturepad-title", className: "SignaturePad__title" }, "Add your signature"), /* @__PURE__ */ React11.createElement("p", { className: "SignaturePad__subtitle" }, "Draw with your mouse or finger")), /* @__PURE__ */ React11.createElement(
|
|
3960
|
+
"button",
|
|
3961
|
+
{
|
|
3962
|
+
type: "button",
|
|
3963
|
+
className: "SignaturePad__close",
|
|
3964
|
+
onClick: onClose,
|
|
3965
|
+
"aria-label": "Close"
|
|
3966
|
+
},
|
|
3967
|
+
/* @__PURE__ */ React11.createElement(
|
|
3968
|
+
"svg",
|
|
3969
|
+
{
|
|
3970
|
+
width: "14",
|
|
3971
|
+
height: "14",
|
|
3972
|
+
viewBox: "0 0 24 24",
|
|
3973
|
+
fill: "none",
|
|
3974
|
+
stroke: "currentColor",
|
|
3975
|
+
strokeWidth: "2.5",
|
|
3976
|
+
strokeLinecap: "round",
|
|
3977
|
+
"aria-hidden": "true"
|
|
3978
|
+
},
|
|
3979
|
+
/* @__PURE__ */ React11.createElement("path", { d: "M18 6 6 18M6 6l12 12" })
|
|
3980
|
+
)
|
|
3981
|
+
)),
|
|
3982
|
+
/* @__PURE__ */ React11.createElement("div", { className: "SignaturePad__canvas-wrap" }, /* @__PURE__ */ React11.createElement(
|
|
3983
|
+
"canvas",
|
|
3984
|
+
{
|
|
3985
|
+
ref: canvasRef,
|
|
3986
|
+
className: "SignaturePad__canvas",
|
|
3987
|
+
width,
|
|
3988
|
+
height
|
|
3989
|
+
}
|
|
3990
|
+
), /* @__PURE__ */ React11.createElement("div", { className: "SignaturePad__baseline", "aria-hidden": "true" }, /* @__PURE__ */ React11.createElement("span", { className: "SignaturePad__baseline-x" }, "\u2715"))),
|
|
3991
|
+
/* @__PURE__ */ React11.createElement("div", { className: "SignaturePad__buttons" }, /* @__PURE__ */ React11.createElement(
|
|
3992
|
+
"button",
|
|
3993
|
+
{
|
|
3994
|
+
type: "button",
|
|
3995
|
+
className: "SignaturePad__button SignaturePad__button--clear",
|
|
3996
|
+
onClick: handleClear
|
|
3997
|
+
},
|
|
3998
|
+
"Clear"
|
|
3999
|
+
), /* @__PURE__ */ React11.createElement("div", { className: "SignaturePad__buttons-right" }, /* @__PURE__ */ React11.createElement(
|
|
4000
|
+
"button",
|
|
4001
|
+
{
|
|
4002
|
+
type: "button",
|
|
4003
|
+
className: "SignaturePad__button SignaturePad__button--cancel",
|
|
4004
|
+
onClick: onClose
|
|
4005
|
+
},
|
|
4006
|
+
"Cancel"
|
|
4007
|
+
), /* @__PURE__ */ React11.createElement(
|
|
4008
|
+
"button",
|
|
4009
|
+
{
|
|
4010
|
+
type: "button",
|
|
4011
|
+
className: "SignaturePad__button SignaturePad__button--done",
|
|
4012
|
+
onClick: handleDone
|
|
4013
|
+
},
|
|
4014
|
+
"Add signature"
|
|
4015
|
+
)))
|
|
4016
|
+
));
|
|
3631
4017
|
};
|
|
3632
|
-
|
|
3633
|
-
// src/components/DrawingHighlight.tsx
|
|
3634
|
-
import React14, { useState as useState9, useCallback as useCallback4, useEffect as useEffect10, useLayoutEffect as useLayoutEffect5, useRef as useRef12 } from "react";
|
|
3635
|
-
import { createPortal as createPortal3 } from "react-dom";
|
|
3636
|
-
import { Rnd as Rnd4 } from "react-rnd";
|
|
3637
4018
|
var DRAWING_COLORS = ["#000000", "#FF0000", "#0000FF", "#00FF00", "#FFFF00"];
|
|
3638
4019
|
var STROKE_WIDTHS = [
|
|
3639
4020
|
{ label: "Thin", value: 1 },
|
|
3640
4021
|
{ label: "Medium", value: 3 },
|
|
3641
4022
|
{ label: "Thick", value: 5 }
|
|
3642
4023
|
];
|
|
3643
|
-
var
|
|
3644
|
-
|
|
4024
|
+
var COLOR_NAMES3 = {
|
|
4025
|
+
"#000000": "Black",
|
|
4026
|
+
"#FF0000": "Red",
|
|
4027
|
+
"#0000FF": "Blue",
|
|
4028
|
+
"#00FF00": "Green",
|
|
4029
|
+
"#FFFF00": "Yellow"
|
|
4030
|
+
};
|
|
4031
|
+
var DefaultDeleteIcon5 = () => /* @__PURE__ */ React11.createElement(Trash2, { width: 14, height: 14 });
|
|
3645
4032
|
var renderStrokesToImage = (strokes, width, height) => {
|
|
3646
4033
|
const canvas = document.createElement("canvas");
|
|
3647
4034
|
canvas.width = width;
|
|
@@ -3677,18 +4064,50 @@ var DrawingHighlight = ({
|
|
|
3677
4064
|
onDelete,
|
|
3678
4065
|
deleteIcon
|
|
3679
4066
|
}) => {
|
|
4067
|
+
const [showStyleControls, setShowStyleControls] = useState(false);
|
|
4068
|
+
const [isColorMenuOpen, setIsColorMenuOpen] = useState(false);
|
|
4069
|
+
const [isSelected, setIsSelected] = useState(false);
|
|
4070
|
+
useClearTipWhileSelected(isSelected);
|
|
4071
|
+
const [configLayer, setConfigLayer] = useState(null);
|
|
4072
|
+
const styleControlsRef = useRef(null);
|
|
4073
|
+
const colorMenuRef = useRef(null);
|
|
4074
|
+
const containerRef = useRef(null);
|
|
4075
|
+
const toolbarWrapperRef = useRef(null);
|
|
3680
4076
|
const highlightClass = isScrolledTo ? "DrawingHighlight--scrolledTo" : "";
|
|
3681
|
-
const
|
|
3682
|
-
|
|
3683
|
-
|
|
3684
|
-
|
|
3685
|
-
|
|
3686
|
-
|
|
4077
|
+
const selectedClass = isSelected ? "DrawingHighlight--selected" : "";
|
|
4078
|
+
useEffect(() => {
|
|
4079
|
+
if (!isSelected) return;
|
|
4080
|
+
const handlePointerDown = (e) => {
|
|
4081
|
+
const target = e.target;
|
|
4082
|
+
const insideRoot = containerRef.current?.contains(target);
|
|
4083
|
+
const insideToolbar = toolbarWrapperRef.current?.contains(target);
|
|
4084
|
+
if (!insideRoot && !insideToolbar) {
|
|
4085
|
+
setIsSelected(false);
|
|
4086
|
+
setShowStyleControls(false);
|
|
4087
|
+
setIsColorMenuOpen(false);
|
|
4088
|
+
}
|
|
4089
|
+
};
|
|
4090
|
+
const handleKey = (e) => {
|
|
4091
|
+
if (e.key === "Escape") {
|
|
4092
|
+
setIsSelected(false);
|
|
4093
|
+
setShowStyleControls(false);
|
|
4094
|
+
setIsColorMenuOpen(false);
|
|
4095
|
+
}
|
|
4096
|
+
};
|
|
4097
|
+
document.addEventListener("mousedown", handlePointerDown);
|
|
4098
|
+
document.addEventListener("keydown", handleKey);
|
|
4099
|
+
return () => {
|
|
4100
|
+
document.removeEventListener("mousedown", handlePointerDown);
|
|
4101
|
+
document.removeEventListener("keydown", handleKey);
|
|
4102
|
+
};
|
|
4103
|
+
}, [isSelected]);
|
|
4104
|
+
useLayoutEffect(() => {
|
|
3687
4105
|
if (containerRef.current) {
|
|
3688
|
-
|
|
4106
|
+
const layer = findOrCreateHighlightConfigLayer(containerRef.current);
|
|
4107
|
+
setConfigLayer((prev) => prev === layer ? prev : layer);
|
|
3689
4108
|
}
|
|
3690
|
-
}
|
|
3691
|
-
|
|
4109
|
+
});
|
|
4110
|
+
useEffect(() => {
|
|
3692
4111
|
if (!showStyleControls) return;
|
|
3693
4112
|
const handleClickOutside = (e) => {
|
|
3694
4113
|
if (styleControlsRef.current && !styleControlsRef.current.contains(e.target)) {
|
|
@@ -3703,10 +4122,25 @@ var DrawingHighlight = ({
|
|
|
3703
4122
|
document.removeEventListener("mousedown", handleClickOutside);
|
|
3704
4123
|
};
|
|
3705
4124
|
}, [showStyleControls]);
|
|
4125
|
+
useEffect(() => {
|
|
4126
|
+
if (!isColorMenuOpen) return;
|
|
4127
|
+
const handleClickOutside = (e) => {
|
|
4128
|
+
if (colorMenuRef.current && !colorMenuRef.current.contains(e.target)) {
|
|
4129
|
+
setIsColorMenuOpen(false);
|
|
4130
|
+
}
|
|
4131
|
+
};
|
|
4132
|
+
const timeoutId = setTimeout(() => {
|
|
4133
|
+
document.addEventListener("mousedown", handleClickOutside);
|
|
4134
|
+
}, 0);
|
|
4135
|
+
return () => {
|
|
4136
|
+
clearTimeout(timeoutId);
|
|
4137
|
+
document.removeEventListener("mousedown", handleClickOutside);
|
|
4138
|
+
};
|
|
4139
|
+
}, [isColorMenuOpen]);
|
|
3706
4140
|
const key = `${highlight.position.boundingRect.width}${highlight.position.boundingRect.height}${highlight.position.boundingRect.left}${highlight.position.boundingRect.top}`;
|
|
3707
4141
|
const imageUrl = highlight.content?.image;
|
|
3708
4142
|
const strokes = highlight.content?.strokes;
|
|
3709
|
-
const handleColorChange =
|
|
4143
|
+
const handleColorChange = useCallback((newColor) => {
|
|
3710
4144
|
if (!strokes || !onStyleChange) return;
|
|
3711
4145
|
console.log("DrawingHighlight: Changing color to", newColor);
|
|
3712
4146
|
const newStrokes = strokes.map((stroke) => ({
|
|
@@ -3720,7 +4154,7 @@ var DrawingHighlight = ({
|
|
|
3720
4154
|
);
|
|
3721
4155
|
onStyleChange(newImage, newStrokes);
|
|
3722
4156
|
}, [strokes, onStyleChange, highlight.position.boundingRect.width, highlight.position.boundingRect.height]);
|
|
3723
|
-
const handleWidthChange =
|
|
4157
|
+
const handleWidthChange = useCallback((newWidth) => {
|
|
3724
4158
|
if (!strokes || !onStyleChange) return;
|
|
3725
4159
|
console.log("DrawingHighlight: Changing width to", newWidth);
|
|
3726
4160
|
const newStrokes = strokes.map((stroke) => ({
|
|
@@ -3736,84 +4170,169 @@ var DrawingHighlight = ({
|
|
|
3736
4170
|
}, [strokes, onStyleChange, highlight.position.boundingRect.width, highlight.position.boundingRect.height]);
|
|
3737
4171
|
const currentColor = strokes?.[0]?.color || "#000000";
|
|
3738
4172
|
const currentWidth = strokes?.[0]?.width || 3;
|
|
3739
|
-
|
|
4173
|
+
const handleRotate = useCallback((clockwise) => {
|
|
4174
|
+
if (!strokes || !onStyleChange) return;
|
|
4175
|
+
const { width, height, left, top, pageNumber } = highlight.position.boundingRect;
|
|
4176
|
+
const newStrokes = strokes.map((stroke) => ({
|
|
4177
|
+
...stroke,
|
|
4178
|
+
points: stroke.points.map(
|
|
4179
|
+
(p) => clockwise ? { x: height - p.y, y: p.x } : { x: p.y, y: width - p.x }
|
|
4180
|
+
)
|
|
4181
|
+
}));
|
|
4182
|
+
const newImage = renderStrokesToImage(newStrokes, height, width);
|
|
4183
|
+
onStyleChange(newImage, newStrokes);
|
|
4184
|
+
const centerX = left + width / 2;
|
|
4185
|
+
const centerY = top + height / 2;
|
|
4186
|
+
onChange?.({
|
|
4187
|
+
left: centerX - height / 2,
|
|
4188
|
+
top: centerY - width / 2,
|
|
4189
|
+
width: height,
|
|
4190
|
+
height: width,
|
|
4191
|
+
pageNumber
|
|
4192
|
+
});
|
|
4193
|
+
}, [strokes, onStyleChange, onChange, highlight.position.boundingRect]);
|
|
4194
|
+
const flipToolbar = highlight.position.boundingRect.top < 40;
|
|
4195
|
+
return /* @__PURE__ */ React11.createElement(
|
|
3740
4196
|
"div",
|
|
3741
4197
|
{
|
|
3742
|
-
className: `DrawingHighlight ${highlightClass}`,
|
|
4198
|
+
className: `DrawingHighlight ${highlightClass} ${selectedClass}`,
|
|
3743
4199
|
onContextMenu,
|
|
3744
4200
|
ref: containerRef
|
|
3745
4201
|
},
|
|
3746
|
-
configLayer &&
|
|
3747
|
-
/* @__PURE__ */
|
|
4202
|
+
configLayer && createPortal(
|
|
4203
|
+
/* @__PURE__ */ React11.createElement(
|
|
3748
4204
|
"div",
|
|
3749
4205
|
{
|
|
3750
|
-
className:
|
|
4206
|
+
className: "DrawingHighlight__toolbar-wrapper",
|
|
4207
|
+
ref: toolbarWrapperRef,
|
|
3751
4208
|
style: {
|
|
3752
|
-
|
|
3753
|
-
|
|
3754
|
-
|
|
3755
|
-
|
|
3756
|
-
onMouseLeave: () => setIsHovered(false)
|
|
4209
|
+
position: "absolute",
|
|
4210
|
+
left: highlight.position.boundingRect.left,
|
|
4211
|
+
top: highlight.position.boundingRect.top
|
|
4212
|
+
}
|
|
3757
4213
|
},
|
|
3758
|
-
/* @__PURE__ */
|
|
3759
|
-
|
|
3760
|
-
"button",
|
|
4214
|
+
/* @__PURE__ */ React11.createElement(
|
|
4215
|
+
"div",
|
|
3761
4216
|
{
|
|
3762
|
-
|
|
3763
|
-
className: "DrawingHighlight__style-button",
|
|
3764
|
-
title: "Edit style",
|
|
3765
|
-
onClick: (e) => {
|
|
3766
|
-
e.stopPropagation();
|
|
3767
|
-
setShowStyleControls(!showStyleControls);
|
|
3768
|
-
}
|
|
4217
|
+
className: `DrawingHighlight__toolbar DrawingHighlight__toolbar--floating ${flipToolbar ? "DrawingHighlight__toolbar--below" : ""} ${isSelected || isScrolledTo || showStyleControls ? "DrawingHighlight__toolbar--visible" : ""}`
|
|
3769
4218
|
},
|
|
3770
|
-
|
|
3771
|
-
|
|
3772
|
-
|
|
3773
|
-
|
|
3774
|
-
|
|
3775
|
-
|
|
3776
|
-
|
|
3777
|
-
e
|
|
3778
|
-
|
|
4219
|
+
strokes && strokes.length > 0 && onStyleChange && /* @__PURE__ */ React11.createElement(React11.Fragment, null, /* @__PURE__ */ React11.createElement(
|
|
4220
|
+
"button",
|
|
4221
|
+
{
|
|
4222
|
+
type: "button",
|
|
4223
|
+
className: "DrawingHighlight__color-trigger",
|
|
4224
|
+
"aria-label": "Stroke color",
|
|
4225
|
+
"aria-expanded": isColorMenuOpen,
|
|
4226
|
+
onClick: (e) => {
|
|
4227
|
+
e.stopPropagation();
|
|
4228
|
+
setShowStyleControls(false);
|
|
4229
|
+
setIsColorMenuOpen((v) => !v);
|
|
4230
|
+
},
|
|
4231
|
+
title: "Stroke color"
|
|
3779
4232
|
},
|
|
3780
|
-
|
|
3781
|
-
|
|
3782
|
-
|
|
3783
|
-
|
|
3784
|
-
|
|
3785
|
-
|
|
3786
|
-
|
|
3787
|
-
|
|
3788
|
-
|
|
3789
|
-
|
|
3790
|
-
|
|
3791
|
-
|
|
3792
|
-
|
|
3793
|
-
|
|
3794
|
-
|
|
4233
|
+
/* @__PURE__ */ React11.createElement(
|
|
4234
|
+
"span",
|
|
4235
|
+
{
|
|
4236
|
+
className: "DrawingHighlight__color-trigger-dot",
|
|
4237
|
+
style: { backgroundColor: currentColor }
|
|
4238
|
+
}
|
|
4239
|
+
),
|
|
4240
|
+
/* @__PURE__ */ React11.createElement(ChevronDown, { width: 12, height: 12, strokeWidth: 2.5 })
|
|
4241
|
+
), /* @__PURE__ */ React11.createElement("div", { className: "DrawingHighlight__toolbar-divider" })),
|
|
4242
|
+
strokes && strokes.length > 0 && onStyleChange && /* @__PURE__ */ React11.createElement(
|
|
4243
|
+
"button",
|
|
4244
|
+
{
|
|
4245
|
+
type: "button",
|
|
4246
|
+
className: "DrawingHighlight__style-button",
|
|
4247
|
+
title: "Stroke width",
|
|
4248
|
+
onClick: (e) => {
|
|
4249
|
+
e.stopPropagation();
|
|
4250
|
+
setIsColorMenuOpen(false);
|
|
4251
|
+
setShowStyleControls(!showStyleControls);
|
|
4252
|
+
}
|
|
3795
4253
|
},
|
|
3796
|
-
|
|
3797
|
-
|
|
3798
|
-
|
|
3799
|
-
|
|
3800
|
-
|
|
3801
|
-
|
|
3802
|
-
|
|
3803
|
-
|
|
3804
|
-
|
|
3805
|
-
|
|
3806
|
-
|
|
4254
|
+
/* @__PURE__ */ React11.createElement(Pencil, { width: 14, height: 14 })
|
|
4255
|
+
),
|
|
4256
|
+
strokes && strokes.length > 0 && onStyleChange && /* @__PURE__ */ React11.createElement(React11.Fragment, null, /* @__PURE__ */ React11.createElement(
|
|
4257
|
+
"button",
|
|
4258
|
+
{
|
|
4259
|
+
type: "button",
|
|
4260
|
+
className: "DrawingHighlight__rotate-button",
|
|
4261
|
+
title: "Rotate left",
|
|
4262
|
+
onClick: (e) => {
|
|
4263
|
+
e.stopPropagation();
|
|
4264
|
+
handleRotate(false);
|
|
4265
|
+
}
|
|
3807
4266
|
},
|
|
3808
|
-
|
|
3809
|
-
|
|
3810
|
-
|
|
3811
|
-
|
|
4267
|
+
/* @__PURE__ */ React11.createElement(RotateCcw, { width: 14, height: 14 })
|
|
4268
|
+
), /* @__PURE__ */ React11.createElement(
|
|
4269
|
+
"button",
|
|
4270
|
+
{
|
|
4271
|
+
type: "button",
|
|
4272
|
+
className: "DrawingHighlight__rotate-button",
|
|
4273
|
+
title: "Rotate right",
|
|
4274
|
+
onClick: (e) => {
|
|
4275
|
+
e.stopPropagation();
|
|
4276
|
+
handleRotate(true);
|
|
4277
|
+
}
|
|
4278
|
+
},
|
|
4279
|
+
/* @__PURE__ */ React11.createElement(RotateCw, { width: 14, height: 14 })
|
|
4280
|
+
)),
|
|
4281
|
+
onDelete && /* @__PURE__ */ React11.createElement(
|
|
4282
|
+
"button",
|
|
4283
|
+
{
|
|
4284
|
+
className: "DrawingHighlight__delete-button",
|
|
4285
|
+
onClick: (e) => {
|
|
4286
|
+
e.stopPropagation();
|
|
4287
|
+
onDelete();
|
|
4288
|
+
},
|
|
4289
|
+
title: "Delete",
|
|
4290
|
+
type: "button"
|
|
4291
|
+
},
|
|
4292
|
+
deleteIcon || /* @__PURE__ */ React11.createElement(DefaultDeleteIcon5, null)
|
|
4293
|
+
),
|
|
4294
|
+
showStyleControls && strokes && strokes.length > 0 && onStyleChange && /* @__PURE__ */ React11.createElement("div", { className: "DrawingHighlight__style-controls", ref: styleControlsRef }, /* @__PURE__ */ React11.createElement("div", { className: "DrawingHighlight__width-picker" }, STROKE_WIDTHS.map((w) => /* @__PURE__ */ React11.createElement(
|
|
4295
|
+
"button",
|
|
4296
|
+
{
|
|
4297
|
+
key: w.value,
|
|
4298
|
+
type: "button",
|
|
4299
|
+
className: `DrawingHighlight__width-button ${currentWidth === w.value ? "active" : ""}`,
|
|
4300
|
+
onClick: (e) => {
|
|
4301
|
+
e.stopPropagation();
|
|
4302
|
+
handleWidthChange(w.value);
|
|
4303
|
+
},
|
|
4304
|
+
title: w.label
|
|
4305
|
+
},
|
|
4306
|
+
w.label
|
|
4307
|
+
)))),
|
|
4308
|
+
isColorMenuOpen && strokes && strokes.length > 0 && onStyleChange && /* @__PURE__ */ React11.createElement("div", { className: "DrawingHighlight__color-menu", ref: colorMenuRef }, DRAWING_COLORS.map((color) => /* @__PURE__ */ React11.createElement(
|
|
4309
|
+
"button",
|
|
4310
|
+
{
|
|
4311
|
+
key: color,
|
|
4312
|
+
type: "button",
|
|
4313
|
+
className: "DrawingHighlight__color-menu-item",
|
|
4314
|
+
onClick: (e) => {
|
|
4315
|
+
e.stopPropagation();
|
|
4316
|
+
handleColorChange(color);
|
|
4317
|
+
setIsColorMenuOpen(false);
|
|
4318
|
+
}
|
|
4319
|
+
},
|
|
4320
|
+
/* @__PURE__ */ React11.createElement(
|
|
4321
|
+
"span",
|
|
4322
|
+
{
|
|
4323
|
+
className: "DrawingHighlight__color-menu-dot",
|
|
4324
|
+
style: { backgroundColor: color }
|
|
4325
|
+
}
|
|
4326
|
+
),
|
|
4327
|
+
/* @__PURE__ */ React11.createElement("span", { className: "DrawingHighlight__color-menu-label" }, COLOR_NAMES3[color] || color),
|
|
4328
|
+
currentColor === color && /* @__PURE__ */ React11.createElement("span", { className: "DrawingHighlight__color-menu-check" }, /* @__PURE__ */ React11.createElement(Check, { width: 14, height: 14, strokeWidth: 2.5 }))
|
|
4329
|
+
)))
|
|
4330
|
+
)
|
|
3812
4331
|
),
|
|
3813
4332
|
configLayer
|
|
3814
4333
|
),
|
|
3815
|
-
/* @__PURE__ */
|
|
3816
|
-
|
|
4334
|
+
/* @__PURE__ */ React11.createElement(
|
|
4335
|
+
Rnd,
|
|
3817
4336
|
{
|
|
3818
4337
|
className: "DrawingHighlight__rnd",
|
|
3819
4338
|
onDragStop: (_, data) => {
|
|
@@ -3825,7 +4344,10 @@ var DrawingHighlight = ({
|
|
|
3825
4344
|
onChange?.(boundingRect);
|
|
3826
4345
|
onEditEnd?.();
|
|
3827
4346
|
},
|
|
3828
|
-
onDragStart:
|
|
4347
|
+
onDragStart: () => {
|
|
4348
|
+
setIsSelected(true);
|
|
4349
|
+
onEditStart?.();
|
|
4350
|
+
},
|
|
3829
4351
|
onResizeStop: (_e, _direction, ref, _delta, position) => {
|
|
3830
4352
|
const boundingRect = {
|
|
3831
4353
|
top: position.y,
|
|
@@ -3852,17 +4374,16 @@ var DrawingHighlight = ({
|
|
|
3852
4374
|
onClick: (event) => {
|
|
3853
4375
|
event.stopPropagation();
|
|
3854
4376
|
event.preventDefault();
|
|
4377
|
+
setIsSelected(true);
|
|
3855
4378
|
},
|
|
3856
4379
|
style
|
|
3857
4380
|
},
|
|
3858
|
-
/* @__PURE__ */
|
|
4381
|
+
/* @__PURE__ */ React11.createElement(
|
|
3859
4382
|
"div",
|
|
3860
4383
|
{
|
|
3861
|
-
className: "DrawingHighlight__container"
|
|
3862
|
-
onMouseEnter: () => setIsHovered(true),
|
|
3863
|
-
onMouseLeave: () => setIsHovered(false)
|
|
4384
|
+
className: "DrawingHighlight__container"
|
|
3864
4385
|
},
|
|
3865
|
-
/* @__PURE__ */
|
|
4386
|
+
/* @__PURE__ */ React11.createElement("div", { className: "DrawingHighlight__content" }, imageUrl ? /* @__PURE__ */ React11.createElement(
|
|
3866
4387
|
"img",
|
|
3867
4388
|
{
|
|
3868
4389
|
src: imageUrl,
|
|
@@ -3870,23 +4391,13 @@ var DrawingHighlight = ({
|
|
|
3870
4391
|
className: "DrawingHighlight__image",
|
|
3871
4392
|
draggable: false
|
|
3872
4393
|
}
|
|
3873
|
-
) : /* @__PURE__ */
|
|
4394
|
+
) : /* @__PURE__ */ React11.createElement("div", { className: "DrawingHighlight__placeholder" }, "No drawing"))
|
|
3874
4395
|
)
|
|
3875
4396
|
)
|
|
3876
4397
|
);
|
|
3877
4398
|
};
|
|
3878
|
-
|
|
3879
|
-
|
|
3880
|
-
import React15, {
|
|
3881
|
-
useState as useState10,
|
|
3882
|
-
useRef as useRef13,
|
|
3883
|
-
useEffect as useEffect11,
|
|
3884
|
-
useLayoutEffect as useLayoutEffect6
|
|
3885
|
-
} from "react";
|
|
3886
|
-
import { createPortal as createPortal4 } from "react-dom";
|
|
3887
|
-
import { Rnd as Rnd5 } from "react-rnd";
|
|
3888
|
-
var DefaultStyleIcon4 = () => /* @__PURE__ */ React15.createElement("svg", { width: "14", height: "14", viewBox: "0 0 24 24", fill: "currentColor" }, /* @__PURE__ */ React15.createElement("path", { d: "M12 3c-4.97 0-9 4.03-9 9s4.03 9 9 9c.83 0 1.5-.67 1.5-1.5 0-.39-.15-.74-.39-1.01-.23-.26-.38-.61-.38-.99 0-.83.67-1.5 1.5-1.5H16c2.76 0 5-2.24 5-5 0-4.42-4.03-8-9-8zm-5.5 9c-.83 0-1.5-.67-1.5-1.5S5.67 9 6.5 9 8 9.67 8 10.5 7.33 12 6.5 12zm3-4C8.67 8 8 7.33 8 6.5S8.67 5 9.5 5s1.5.67 1.5 1.5S10.33 8 9.5 8zm5 0c-.83 0-1.5-.67-1.5-1.5S13.67 5 14.5 5s1.5.67 1.5 1.5S15.33 8 14.5 8zm3 4c-.83 0-1.5-.67-1.5-1.5S16.67 9 17.5 9s1.5.67 1.5 1.5-.67 1.5-1.5 1.5z" }));
|
|
3889
|
-
var DefaultDeleteIcon6 = () => /* @__PURE__ */ React15.createElement("svg", { width: "14", height: "14", viewBox: "0 0 24 24", fill: "currentColor" }, /* @__PURE__ */ React15.createElement("path", { d: "M6 19c0 1.1.9 2 2 2h8c1.1 0 2-.9 2-2V7H6v12zM19 4h-3.5l-1-1h-5l-1 1H5v2h14V4z" }));
|
|
4399
|
+
var DefaultStyleIcon3 = () => /* @__PURE__ */ React11.createElement(Palette, { width: 14, height: 14 });
|
|
4400
|
+
var DefaultDeleteIcon6 = () => /* @__PURE__ */ React11.createElement(Trash2, { width: 14, height: 14 });
|
|
3890
4401
|
var DEFAULT_COLOR_PRESETS3 = [
|
|
3891
4402
|
"#000000",
|
|
3892
4403
|
// Black
|
|
@@ -3899,6 +4410,13 @@ var DEFAULT_COLOR_PRESETS3 = [
|
|
|
3899
4410
|
"#FF6600"
|
|
3900
4411
|
// Orange
|
|
3901
4412
|
];
|
|
4413
|
+
var COLOR_NAMES4 = {
|
|
4414
|
+
"#000000": "Black",
|
|
4415
|
+
"#FF0000": "Red",
|
|
4416
|
+
"#0000FF": "Blue",
|
|
4417
|
+
"#00AA00": "Green",
|
|
4418
|
+
"#FF6600": "Orange"
|
|
4419
|
+
};
|
|
3902
4420
|
var STROKE_WIDTHS2 = [
|
|
3903
4421
|
{ label: "Thin", value: 1 },
|
|
3904
4422
|
{ label: "Medium", value: 2 },
|
|
@@ -3924,17 +4442,48 @@ var ShapeHighlight = ({
|
|
|
3924
4442
|
startPoint,
|
|
3925
4443
|
endPoint
|
|
3926
4444
|
}) => {
|
|
3927
|
-
const [isStylePanelOpen, setIsStylePanelOpen] =
|
|
3928
|
-
const [
|
|
3929
|
-
const [
|
|
3930
|
-
|
|
3931
|
-
const
|
|
3932
|
-
|
|
4445
|
+
const [isStylePanelOpen, setIsStylePanelOpen] = useState(false);
|
|
4446
|
+
const [isColorMenuOpen, setIsColorMenuOpen] = useState(false);
|
|
4447
|
+
const [isSelected, setIsSelected] = useState(false);
|
|
4448
|
+
useClearTipWhileSelected(isSelected);
|
|
4449
|
+
const [configLayer, setConfigLayer] = useState(null);
|
|
4450
|
+
const stylePanelRef = useRef(null);
|
|
4451
|
+
const colorMenuRef = useRef(null);
|
|
4452
|
+
const containerRef = useRef(null);
|
|
4453
|
+
const toolbarWrapperRef = useRef(null);
|
|
4454
|
+
useEffect(() => {
|
|
4455
|
+
if (!isSelected) return;
|
|
4456
|
+
const handlePointerDown = (e) => {
|
|
4457
|
+
const target = e.target;
|
|
4458
|
+
const insideRoot = containerRef.current?.contains(target);
|
|
4459
|
+
const insideToolbar = toolbarWrapperRef.current?.contains(target);
|
|
4460
|
+
if (!insideRoot && !insideToolbar) {
|
|
4461
|
+
setIsSelected(false);
|
|
4462
|
+
setIsStylePanelOpen(false);
|
|
4463
|
+
setIsColorMenuOpen(false);
|
|
4464
|
+
}
|
|
4465
|
+
};
|
|
4466
|
+
const handleKey = (e) => {
|
|
4467
|
+
if (e.key === "Escape") {
|
|
4468
|
+
setIsSelected(false);
|
|
4469
|
+
setIsStylePanelOpen(false);
|
|
4470
|
+
setIsColorMenuOpen(false);
|
|
4471
|
+
}
|
|
4472
|
+
};
|
|
4473
|
+
document.addEventListener("mousedown", handlePointerDown);
|
|
4474
|
+
document.addEventListener("keydown", handleKey);
|
|
4475
|
+
return () => {
|
|
4476
|
+
document.removeEventListener("mousedown", handlePointerDown);
|
|
4477
|
+
document.removeEventListener("keydown", handleKey);
|
|
4478
|
+
};
|
|
4479
|
+
}, [isSelected]);
|
|
4480
|
+
useLayoutEffect(() => {
|
|
3933
4481
|
if (containerRef.current) {
|
|
3934
|
-
|
|
4482
|
+
const layer = findOrCreateHighlightConfigLayer(containerRef.current);
|
|
4483
|
+
setConfigLayer((prev) => prev === layer ? prev : layer);
|
|
3935
4484
|
}
|
|
3936
|
-
}
|
|
3937
|
-
|
|
4485
|
+
});
|
|
4486
|
+
useEffect(() => {
|
|
3938
4487
|
if (!isStylePanelOpen) return;
|
|
3939
4488
|
const handleClickOutside = (e) => {
|
|
3940
4489
|
if (stylePanelRef.current && !stylePanelRef.current.contains(e.target)) {
|
|
@@ -3949,13 +4498,29 @@ var ShapeHighlight = ({
|
|
|
3949
4498
|
document.removeEventListener("mousedown", handleClickOutside);
|
|
3950
4499
|
};
|
|
3951
4500
|
}, [isStylePanelOpen]);
|
|
4501
|
+
useEffect(() => {
|
|
4502
|
+
if (!isColorMenuOpen) return;
|
|
4503
|
+
const handleClickOutside = (e) => {
|
|
4504
|
+
if (colorMenuRef.current && !colorMenuRef.current.contains(e.target)) {
|
|
4505
|
+
setIsColorMenuOpen(false);
|
|
4506
|
+
}
|
|
4507
|
+
};
|
|
4508
|
+
const timeoutId = setTimeout(() => {
|
|
4509
|
+
document.addEventListener("mousedown", handleClickOutside);
|
|
4510
|
+
}, 0);
|
|
4511
|
+
return () => {
|
|
4512
|
+
clearTimeout(timeoutId);
|
|
4513
|
+
document.removeEventListener("mousedown", handleClickOutside);
|
|
4514
|
+
};
|
|
4515
|
+
}, [isColorMenuOpen]);
|
|
3952
4516
|
const highlightClass = isScrolledTo ? "ShapeHighlight--scrolledTo" : "";
|
|
4517
|
+
const selectedClass = isSelected ? "ShapeHighlight--selected" : "";
|
|
3953
4518
|
const key = `${highlight.position.boundingRect.width}${highlight.position.boundingRect.height}${highlight.position.boundingRect.left}${highlight.position.boundingRect.top}`;
|
|
3954
4519
|
const markerId = `arrowhead-${highlight.id}`;
|
|
3955
4520
|
const renderShape = (width, height) => {
|
|
3956
4521
|
switch (shapeType) {
|
|
3957
4522
|
case "rectangle":
|
|
3958
|
-
return /* @__PURE__ */
|
|
4523
|
+
return /* @__PURE__ */ React11.createElement(
|
|
3959
4524
|
"svg",
|
|
3960
4525
|
{
|
|
3961
4526
|
className: "ShapeHighlight__svg",
|
|
@@ -3963,7 +4528,7 @@ var ShapeHighlight = ({
|
|
|
3963
4528
|
height,
|
|
3964
4529
|
viewBox: `0 0 ${width} ${height}`
|
|
3965
4530
|
},
|
|
3966
|
-
/* @__PURE__ */
|
|
4531
|
+
/* @__PURE__ */ React11.createElement(
|
|
3967
4532
|
"rect",
|
|
3968
4533
|
{
|
|
3969
4534
|
x: strokeWidth / 2,
|
|
@@ -3977,7 +4542,7 @@ var ShapeHighlight = ({
|
|
|
3977
4542
|
)
|
|
3978
4543
|
);
|
|
3979
4544
|
case "circle":
|
|
3980
|
-
return /* @__PURE__ */
|
|
4545
|
+
return /* @__PURE__ */ React11.createElement(
|
|
3981
4546
|
"svg",
|
|
3982
4547
|
{
|
|
3983
4548
|
className: "ShapeHighlight__svg",
|
|
@@ -3985,7 +4550,7 @@ var ShapeHighlight = ({
|
|
|
3985
4550
|
height,
|
|
3986
4551
|
viewBox: `0 0 ${width} ${height}`
|
|
3987
4552
|
},
|
|
3988
|
-
/* @__PURE__ */
|
|
4553
|
+
/* @__PURE__ */ React11.createElement(
|
|
3989
4554
|
"ellipse",
|
|
3990
4555
|
{
|
|
3991
4556
|
cx: width / 2,
|
|
@@ -4003,7 +4568,7 @@ var ShapeHighlight = ({
|
|
|
4003
4568
|
const y1 = startPoint ? startPoint.y * height : height / 2;
|
|
4004
4569
|
const x2 = endPoint ? endPoint.x * width : width - strokeWidth - 10;
|
|
4005
4570
|
const y2 = endPoint ? endPoint.y * height : height / 2;
|
|
4006
|
-
return /* @__PURE__ */
|
|
4571
|
+
return /* @__PURE__ */ React11.createElement(
|
|
4007
4572
|
"svg",
|
|
4008
4573
|
{
|
|
4009
4574
|
className: "ShapeHighlight__svg",
|
|
@@ -4011,7 +4576,7 @@ var ShapeHighlight = ({
|
|
|
4011
4576
|
height,
|
|
4012
4577
|
viewBox: `0 0 ${width} ${height}`
|
|
4013
4578
|
},
|
|
4014
|
-
/* @__PURE__ */
|
|
4579
|
+
/* @__PURE__ */ React11.createElement("defs", null, /* @__PURE__ */ React11.createElement(
|
|
4015
4580
|
"marker",
|
|
4016
4581
|
{
|
|
4017
4582
|
id: markerId,
|
|
@@ -4021,9 +4586,9 @@ var ShapeHighlight = ({
|
|
|
4021
4586
|
refY: "3.5",
|
|
4022
4587
|
orient: "auto"
|
|
4023
4588
|
},
|
|
4024
|
-
/* @__PURE__ */
|
|
4589
|
+
/* @__PURE__ */ React11.createElement("polygon", { points: "0 0, 10 3.5, 0 7", fill: strokeColor })
|
|
4025
4590
|
)),
|
|
4026
|
-
/* @__PURE__ */
|
|
4591
|
+
/* @__PURE__ */ React11.createElement(
|
|
4027
4592
|
"line",
|
|
4028
4593
|
{
|
|
4029
4594
|
x1,
|
|
@@ -4041,46 +4606,68 @@ var ShapeHighlight = ({
|
|
|
4041
4606
|
return null;
|
|
4042
4607
|
}
|
|
4043
4608
|
};
|
|
4044
|
-
return /* @__PURE__ */
|
|
4609
|
+
return /* @__PURE__ */ React11.createElement(
|
|
4045
4610
|
"div",
|
|
4046
4611
|
{
|
|
4047
|
-
className: `ShapeHighlight ${highlightClass}`,
|
|
4612
|
+
className: `ShapeHighlight ${highlightClass} ${selectedClass}`,
|
|
4048
4613
|
onContextMenu,
|
|
4049
4614
|
ref: containerRef
|
|
4050
4615
|
},
|
|
4051
|
-
configLayer && (onStyleChange || onDelete) &&
|
|
4052
|
-
/* @__PURE__ */
|
|
4616
|
+
configLayer && (onStyleChange || onDelete) && createPortal(
|
|
4617
|
+
/* @__PURE__ */ React11.createElement(
|
|
4053
4618
|
"div",
|
|
4054
4619
|
{
|
|
4055
4620
|
className: "ShapeHighlight__toolbar-wrapper",
|
|
4621
|
+
ref: toolbarWrapperRef,
|
|
4056
4622
|
style: {
|
|
4057
4623
|
position: "absolute",
|
|
4058
4624
|
left: highlight.position.boundingRect.left,
|
|
4059
|
-
top: highlight.position.boundingRect.top
|
|
4060
|
-
|
|
4061
|
-
},
|
|
4062
|
-
onMouseEnter: () => setIsHovered(true),
|
|
4063
|
-
onMouseLeave: () => setIsHovered(false)
|
|
4625
|
+
top: highlight.position.boundingRect.top
|
|
4626
|
+
}
|
|
4064
4627
|
},
|
|
4065
|
-
/* @__PURE__ */
|
|
4628
|
+
/* @__PURE__ */ React11.createElement(
|
|
4066
4629
|
"div",
|
|
4067
4630
|
{
|
|
4068
|
-
className: `ShapeHighlight__toolbar ${
|
|
4631
|
+
className: `ShapeHighlight__toolbar ${isSelected || isScrolledTo || isStylePanelOpen || isColorMenuOpen ? "ShapeHighlight__toolbar--visible" : ""}`
|
|
4069
4632
|
},
|
|
4070
|
-
onStyleChange && /* @__PURE__ */
|
|
4633
|
+
onStyleChange && /* @__PURE__ */ React11.createElement(React11.Fragment, null, /* @__PURE__ */ React11.createElement(
|
|
4634
|
+
"button",
|
|
4635
|
+
{
|
|
4636
|
+
type: "button",
|
|
4637
|
+
className: "ShapeHighlight__color-trigger",
|
|
4638
|
+
"aria-label": "Stroke color",
|
|
4639
|
+
"aria-expanded": isColorMenuOpen,
|
|
4640
|
+
onClick: (e) => {
|
|
4641
|
+
e.stopPropagation();
|
|
4642
|
+
setIsStylePanelOpen(false);
|
|
4643
|
+
setIsColorMenuOpen((v) => !v);
|
|
4644
|
+
},
|
|
4645
|
+
title: "Stroke color"
|
|
4646
|
+
},
|
|
4647
|
+
/* @__PURE__ */ React11.createElement(
|
|
4648
|
+
"span",
|
|
4649
|
+
{
|
|
4650
|
+
className: "ShapeHighlight__color-trigger-dot",
|
|
4651
|
+
style: { backgroundColor: strokeColor }
|
|
4652
|
+
}
|
|
4653
|
+
),
|
|
4654
|
+
/* @__PURE__ */ React11.createElement(ChevronDown, { width: 12, height: 12, strokeWidth: 2.5 })
|
|
4655
|
+
), /* @__PURE__ */ React11.createElement("div", { className: "ShapeHighlight__toolbar-divider" })),
|
|
4656
|
+
onStyleChange && /* @__PURE__ */ React11.createElement(
|
|
4071
4657
|
"button",
|
|
4072
4658
|
{
|
|
4073
4659
|
className: "ShapeHighlight__style-button",
|
|
4074
4660
|
onClick: (e) => {
|
|
4075
4661
|
e.stopPropagation();
|
|
4662
|
+
setIsColorMenuOpen(false);
|
|
4076
4663
|
setIsStylePanelOpen(!isStylePanelOpen);
|
|
4077
4664
|
},
|
|
4078
|
-
title: "
|
|
4665
|
+
title: "Stroke width",
|
|
4079
4666
|
type: "button"
|
|
4080
4667
|
},
|
|
4081
|
-
styleIcon || /* @__PURE__ */
|
|
4668
|
+
styleIcon || /* @__PURE__ */ React11.createElement(DefaultStyleIcon3, null)
|
|
4082
4669
|
),
|
|
4083
|
-
onDelete && /* @__PURE__ */
|
|
4670
|
+
onDelete && /* @__PURE__ */ React11.createElement(
|
|
4084
4671
|
"button",
|
|
4085
4672
|
{
|
|
4086
4673
|
className: "ShapeHighlight__delete-button",
|
|
@@ -4091,37 +4678,46 @@ var ShapeHighlight = ({
|
|
|
4091
4678
|
title: "Delete",
|
|
4092
4679
|
type: "button"
|
|
4093
4680
|
},
|
|
4094
|
-
deleteIcon || /* @__PURE__ */
|
|
4681
|
+
deleteIcon || /* @__PURE__ */ React11.createElement(DefaultDeleteIcon6, null)
|
|
4095
4682
|
)
|
|
4096
4683
|
),
|
|
4097
|
-
|
|
4684
|
+
isColorMenuOpen && onStyleChange && /* @__PURE__ */ React11.createElement(
|
|
4098
4685
|
"div",
|
|
4099
4686
|
{
|
|
4100
|
-
className: "
|
|
4101
|
-
ref:
|
|
4687
|
+
className: "ShapeHighlight__color-menu",
|
|
4688
|
+
ref: colorMenuRef,
|
|
4102
4689
|
onClick: (e) => e.stopPropagation()
|
|
4103
4690
|
},
|
|
4104
|
-
|
|
4691
|
+
colorPresets.map((c) => /* @__PURE__ */ React11.createElement(
|
|
4105
4692
|
"button",
|
|
4106
4693
|
{
|
|
4107
4694
|
key: c,
|
|
4108
4695
|
type: "button",
|
|
4109
|
-
className:
|
|
4110
|
-
|
|
4111
|
-
|
|
4112
|
-
|
|
4113
|
-
}
|
|
4114
|
-
))), /* @__PURE__ */ React15.createElement(
|
|
4115
|
-
"input",
|
|
4116
|
-
{
|
|
4117
|
-
type: "color",
|
|
4118
|
-
value: strokeColor,
|
|
4119
|
-
onChange: (e) => {
|
|
4120
|
-
onStyleChange({ strokeColor: e.target.value });
|
|
4696
|
+
className: "ShapeHighlight__color-menu-item",
|
|
4697
|
+
onClick: () => {
|
|
4698
|
+
onStyleChange({ strokeColor: c });
|
|
4699
|
+
setIsColorMenuOpen(false);
|
|
4121
4700
|
}
|
|
4122
|
-
}
|
|
4123
|
-
|
|
4124
|
-
|
|
4701
|
+
},
|
|
4702
|
+
/* @__PURE__ */ React11.createElement(
|
|
4703
|
+
"span",
|
|
4704
|
+
{
|
|
4705
|
+
className: "ShapeHighlight__color-menu-dot",
|
|
4706
|
+
style: { backgroundColor: c }
|
|
4707
|
+
}
|
|
4708
|
+
),
|
|
4709
|
+
/* @__PURE__ */ React11.createElement("span", { className: "ShapeHighlight__color-menu-label" }, COLOR_NAMES4[c] || c),
|
|
4710
|
+
strokeColor === c && /* @__PURE__ */ React11.createElement("span", { className: "ShapeHighlight__color-menu-check" }, /* @__PURE__ */ React11.createElement(Check, { width: 14, height: 14, strokeWidth: 2.5 }))
|
|
4711
|
+
))
|
|
4712
|
+
),
|
|
4713
|
+
isStylePanelOpen && onStyleChange && /* @__PURE__ */ React11.createElement(
|
|
4714
|
+
"div",
|
|
4715
|
+
{
|
|
4716
|
+
className: "ShapeHighlight__style-panel",
|
|
4717
|
+
ref: stylePanelRef,
|
|
4718
|
+
onClick: (e) => e.stopPropagation()
|
|
4719
|
+
},
|
|
4720
|
+
/* @__PURE__ */ React11.createElement("div", { className: "ShapeHighlight__style-row" }, /* @__PURE__ */ React11.createElement("label", null, "Width"), /* @__PURE__ */ React11.createElement("div", { className: "ShapeHighlight__width-options" }, STROKE_WIDTHS2.map((w) => /* @__PURE__ */ React11.createElement(
|
|
4125
4721
|
"button",
|
|
4126
4722
|
{
|
|
4127
4723
|
key: w.value,
|
|
@@ -4136,11 +4732,9 @@ var ShapeHighlight = ({
|
|
|
4136
4732
|
),
|
|
4137
4733
|
configLayer
|
|
4138
4734
|
),
|
|
4139
|
-
/* @__PURE__ */
|
|
4140
|
-
|
|
4735
|
+
/* @__PURE__ */ React11.createElement(
|
|
4736
|
+
Rnd,
|
|
4141
4737
|
{
|
|
4142
|
-
onMouseEnter: () => setIsHovered(true),
|
|
4143
|
-
onMouseLeave: () => setIsHovered(false),
|
|
4144
4738
|
className: "ShapeHighlight__rnd",
|
|
4145
4739
|
onDragStop: (_, data) => {
|
|
4146
4740
|
const boundingRect = {
|
|
@@ -4151,7 +4745,10 @@ var ShapeHighlight = ({
|
|
|
4151
4745
|
onChange?.(boundingRect);
|
|
4152
4746
|
onEditEnd?.();
|
|
4153
4747
|
},
|
|
4154
|
-
onDragStart:
|
|
4748
|
+
onDragStart: () => {
|
|
4749
|
+
setIsSelected(true);
|
|
4750
|
+
onEditStart?.();
|
|
4751
|
+
},
|
|
4155
4752
|
onResizeStop: (_e, _direction, ref, _delta, position) => {
|
|
4156
4753
|
const boundingRect = {
|
|
4157
4754
|
top: position.y,
|
|
@@ -4178,23 +4775,20 @@ var ShapeHighlight = ({
|
|
|
4178
4775
|
onClick: (event) => {
|
|
4179
4776
|
event.stopPropagation();
|
|
4180
4777
|
event.preventDefault();
|
|
4778
|
+
setIsSelected(true);
|
|
4181
4779
|
},
|
|
4182
4780
|
style
|
|
4183
4781
|
},
|
|
4184
|
-
/* @__PURE__ */
|
|
4782
|
+
/* @__PURE__ */ React11.createElement("div", { className: "ShapeHighlight__container" }, renderShape(
|
|
4185
4783
|
highlight.position.boundingRect.width || 100,
|
|
4186
4784
|
highlight.position.boundingRect.height || 100
|
|
4187
4785
|
))
|
|
4188
4786
|
)
|
|
4189
4787
|
);
|
|
4190
4788
|
};
|
|
4191
|
-
|
|
4192
|
-
// src/components/PdfLoader.tsx
|
|
4193
|
-
import React16, { useEffect as useEffect12, useRef as useRef14, useState as useState11 } from "react";
|
|
4194
|
-
import { GlobalWorkerOptions, getDocument as getDocument2 } from "pdfjs-dist";
|
|
4195
4789
|
var DEFAULT_BEFORE_LOAD = (progress) => {
|
|
4196
4790
|
const pct = progress && progress.total ? Math.min(100, Math.floor(progress.loaded / progress.total * 100)) : null;
|
|
4197
|
-
return /* @__PURE__ */
|
|
4791
|
+
return /* @__PURE__ */ React11.createElement(
|
|
4198
4792
|
"div",
|
|
4199
4793
|
{
|
|
4200
4794
|
style: {
|
|
@@ -4209,7 +4803,7 @@ var DEFAULT_BEFORE_LOAD = (progress) => {
|
|
|
4209
4803
|
fontSize: 13
|
|
4210
4804
|
}
|
|
4211
4805
|
},
|
|
4212
|
-
/* @__PURE__ */
|
|
4806
|
+
/* @__PURE__ */ React11.createElement(
|
|
4213
4807
|
"div",
|
|
4214
4808
|
{
|
|
4215
4809
|
style: {
|
|
@@ -4222,11 +4816,11 @@ var DEFAULT_BEFORE_LOAD = (progress) => {
|
|
|
4222
4816
|
}
|
|
4223
4817
|
}
|
|
4224
4818
|
),
|
|
4225
|
-
/* @__PURE__ */
|
|
4226
|
-
/* @__PURE__ */
|
|
4819
|
+
/* @__PURE__ */ React11.createElement("div", null, pct !== null ? `Loading ${pct}%` : "Loading\u2026"),
|
|
4820
|
+
/* @__PURE__ */ React11.createElement("style", null, "@keyframes pdfloader-spin{to{transform:rotate(360deg)}}")
|
|
4227
4821
|
);
|
|
4228
4822
|
};
|
|
4229
|
-
var DEFAULT_ERROR_MESSAGE = (error) => /* @__PURE__ */
|
|
4823
|
+
var DEFAULT_ERROR_MESSAGE = (error) => /* @__PURE__ */ React11.createElement("div", { style: { color: "black" } }, error.message);
|
|
4230
4824
|
var DEFAULT_ON_ERROR = (error) => {
|
|
4231
4825
|
throw new Error(`Error loading PDF document: ${error.message}!`);
|
|
4232
4826
|
};
|
|
@@ -4267,13 +4861,17 @@ var stripUndefined = (obj) => {
|
|
|
4267
4861
|
if (v !== void 0) out[k] = v;
|
|
4268
4862
|
return out;
|
|
4269
4863
|
};
|
|
4864
|
+
var SECURE_DEFAULTS = {
|
|
4865
|
+
enableScripting: false,
|
|
4866
|
+
isEvalSupported: false
|
|
4867
|
+
};
|
|
4270
4868
|
var buildSource = (document2, perf) => {
|
|
4271
|
-
const cleaned = stripUndefined(perf);
|
|
4869
|
+
const cleaned = { ...SECURE_DEFAULTS, ...stripUndefined(perf) };
|
|
4272
4870
|
if (typeof document2 === "string" || document2 instanceof URL) {
|
|
4273
4871
|
return { url: document2, ...cleaned };
|
|
4274
4872
|
}
|
|
4275
4873
|
if (ArrayBuffer.isView(document2)) {
|
|
4276
|
-
return document2;
|
|
4874
|
+
return { ...SECURE_DEFAULTS, data: document2 };
|
|
4277
4875
|
}
|
|
4278
4876
|
return { ...cleaned, ...document2 };
|
|
4279
4877
|
};
|
|
@@ -4291,13 +4889,13 @@ var PdfLoader = ({
|
|
|
4291
4889
|
httpHeaders,
|
|
4292
4890
|
enableCache = true
|
|
4293
4891
|
}) => {
|
|
4294
|
-
const [pdfDocument, setPdfDocument] =
|
|
4295
|
-
const [error, setError] =
|
|
4296
|
-
const [loadingProgress, setLoadingProgress] =
|
|
4297
|
-
const onErrorRef =
|
|
4892
|
+
const [pdfDocument, setPdfDocument] = useState(null);
|
|
4893
|
+
const [error, setError] = useState(null);
|
|
4894
|
+
const [loadingProgress, setLoadingProgress] = useState(null);
|
|
4895
|
+
const onErrorRef = useRef(onError);
|
|
4298
4896
|
onErrorRef.current = onError;
|
|
4299
4897
|
const httpHeadersKey = httpHeaders ? JSON.stringify(httpHeaders) : "";
|
|
4300
|
-
|
|
4898
|
+
useEffect(() => {
|
|
4301
4899
|
GlobalWorkerOptions.workerSrc = workerSrc;
|
|
4302
4900
|
let cancelled = false;
|
|
4303
4901
|
setPdfDocument(null);
|
|
@@ -4315,7 +4913,7 @@ var PdfLoader = ({
|
|
|
4315
4913
|
console.log("[PdfLoader] loading", key ?? "(bytes)", {
|
|
4316
4914
|
disableAutoFetch
|
|
4317
4915
|
});
|
|
4318
|
-
const task =
|
|
4916
|
+
const task = getDocument$1(
|
|
4319
4917
|
buildSource(document2, {
|
|
4320
4918
|
disableAutoFetch,
|
|
4321
4919
|
disableStream,
|
|
@@ -4605,7 +5203,6 @@ var getTextItemsBoundingRect = (textItems) => {
|
|
|
4605
5203
|
return rects.length > 0 ? get_bounding_rect_default(rects) : void 0;
|
|
4606
5204
|
};
|
|
4607
5205
|
var getOrderedTextItems = (textItems, readingOrder) => {
|
|
4608
|
-
if (readingOrder === "document") return [...textItems];
|
|
4609
5206
|
const averageHeight = getAverageItemHeight(textItems);
|
|
4610
5207
|
return [...textItems].sort((a, b) => {
|
|
4611
5208
|
const topDelta = a.rect.top - b.rect.top;
|
|
@@ -4617,7 +5214,7 @@ var getOrderedTextItems = (textItems, readingOrder) => {
|
|
|
4617
5214
|
};
|
|
4618
5215
|
var groupTextItemsIntoLines = (textItems) => {
|
|
4619
5216
|
const averageHeight = getAverageItemHeight(textItems);
|
|
4620
|
-
const sortedItems = getOrderedTextItems(textItems
|
|
5217
|
+
const sortedItems = getOrderedTextItems(textItems);
|
|
4621
5218
|
const lines = [];
|
|
4622
5219
|
sortedItems.forEach((item) => {
|
|
4623
5220
|
const currentLine = lines[lines.length - 1];
|
|
@@ -4900,10 +5497,17 @@ var classifyTextUnit = (rawText, textItemIndexes, page) => {
|
|
|
4900
5497
|
if (isLikelyFootnoteOrReference(text) || isBottomOfPage && /^\d+\s/.test(text)) {
|
|
4901
5498
|
return text.includes("://") || /^\d+\s*https?:\/\//i.test(text) ? "footnote" : "reference";
|
|
4902
5499
|
}
|
|
5500
|
+
if (/^(figure|fig\.?|table|chart|diagram|listing|algorithm)\s*\d/i.test(text)) {
|
|
5501
|
+
return "caption";
|
|
5502
|
+
}
|
|
4903
5503
|
if (isLikelySectionHeading(text)) return "heading";
|
|
4904
5504
|
if (isTopOfFirstPage && isLargeText && isCentered) return "title";
|
|
4905
5505
|
if (isTopOfFirstPage && isLikelyAuthor(text)) return "author";
|
|
4906
5506
|
if (isTopOfFirstPage && isLikelyAffiliation(text)) return "affiliation";
|
|
5507
|
+
const wordCount = text.split(/\s+/).filter(Boolean).length;
|
|
5508
|
+
if (wordCount <= 6 && text.length <= 60 && !/[.!?…:]\s*$/.test(text)) {
|
|
5509
|
+
return "figureLabel";
|
|
5510
|
+
}
|
|
4907
5511
|
return "paragraph";
|
|
4908
5512
|
};
|
|
4909
5513
|
var extractTextUnitsFromPages = (pages, options = {}) => {
|
|
@@ -4981,7 +5585,30 @@ var extractTextUnits = async (pdfDocument, options = {}) => {
|
|
|
4981
5585
|
});
|
|
4982
5586
|
return extractTextUnitsFromPages(pages, resolvedOptions);
|
|
4983
5587
|
};
|
|
4984
|
-
var
|
|
5588
|
+
var pageTextItemsCache = /* @__PURE__ */ new WeakMap();
|
|
5589
|
+
var pageTextItemsCacheKey = (options) => {
|
|
5590
|
+
const pages = options.pages === void 0 || options.pages === "all" ? "all" : options.pages.join(",");
|
|
5591
|
+
return `${pages}|${options.columnDetection ?? DEFAULT_OPTIONS.columnDetection}`;
|
|
5592
|
+
};
|
|
5593
|
+
var extractPageTextItems = (pdfDocument, options = {}) => {
|
|
5594
|
+
let byOptions = pageTextItemsCache.get(pdfDocument);
|
|
5595
|
+
if (!byOptions) {
|
|
5596
|
+
byOptions = /* @__PURE__ */ new Map();
|
|
5597
|
+
pageTextItemsCache.set(pdfDocument, byOptions);
|
|
5598
|
+
}
|
|
5599
|
+
const key = pageTextItemsCacheKey(options);
|
|
5600
|
+
const cached = byOptions.get(key);
|
|
5601
|
+
if (cached) return cached;
|
|
5602
|
+
const promise = extractPageTextItemsUncached(pdfDocument, options).catch(
|
|
5603
|
+
(error) => {
|
|
5604
|
+
byOptions.delete(key);
|
|
5605
|
+
throw error;
|
|
5606
|
+
}
|
|
5607
|
+
);
|
|
5608
|
+
byOptions.set(key, promise);
|
|
5609
|
+
return promise;
|
|
5610
|
+
};
|
|
5611
|
+
var extractPageTextItemsUncached = async (pdfDocument, options = {}) => {
|
|
4985
5612
|
const pageNumbers = resolvePageNumbers(pdfDocument, options.pages);
|
|
4986
5613
|
const columnDetection = options.columnDetection ?? DEFAULT_OPTIONS.columnDetection;
|
|
4987
5614
|
const extractedPages = [];
|
|
@@ -5215,26 +5842,16 @@ var getTextPosition = async (pdfDocument, query, options = {}) => {
|
|
|
5215
5842
|
}
|
|
5216
5843
|
return null;
|
|
5217
5844
|
};
|
|
5218
|
-
|
|
5219
|
-
// src/components/leftpanel/LeftPanel.tsx
|
|
5220
|
-
import React21, { useState as useState17, useMemo as useMemo3, useCallback as useCallback8, useRef as useRef19, useEffect as useEffect18 } from "react";
|
|
5221
|
-
import { List, FileText, ChevronLeft, ChevronRight as ChevronRight2 } from "lucide-react";
|
|
5222
|
-
|
|
5223
|
-
// src/contexts/LeftPanelContext.ts
|
|
5224
|
-
import { createContext as createContext3, useContext as useContext3 } from "react";
|
|
5225
|
-
var LeftPanelContext = createContext3(
|
|
5845
|
+
var LeftPanelContext = createContext(
|
|
5226
5846
|
void 0
|
|
5227
5847
|
);
|
|
5228
5848
|
var useLeftPanelContext = () => {
|
|
5229
|
-
const context =
|
|
5849
|
+
const context = useContext(LeftPanelContext);
|
|
5230
5850
|
if (context === void 0) {
|
|
5231
5851
|
throw new Error("useLeftPanelContext must be used within LeftPanel");
|
|
5232
5852
|
}
|
|
5233
5853
|
return context;
|
|
5234
5854
|
};
|
|
5235
|
-
|
|
5236
|
-
// src/hooks/useDocumentOutline.ts
|
|
5237
|
-
import { useState as useState12, useEffect as useEffect13, useCallback as useCallback5, useMemo as useMemo2 } from "react";
|
|
5238
5855
|
async function processOutlineItems(pdfDocument, items, level) {
|
|
5239
5856
|
const processed = [];
|
|
5240
5857
|
for (let i = 0; i < items.length; i++) {
|
|
@@ -5276,10 +5893,10 @@ function flattenOutline(items) {
|
|
|
5276
5893
|
}
|
|
5277
5894
|
function useDocumentOutline(options) {
|
|
5278
5895
|
const { pdfDocument, goToPage } = options;
|
|
5279
|
-
const [outline, setOutline] =
|
|
5280
|
-
const [isLoading, setIsLoading] =
|
|
5281
|
-
const [error, setError] =
|
|
5282
|
-
|
|
5896
|
+
const [outline, setOutline] = useState(null);
|
|
5897
|
+
const [isLoading, setIsLoading] = useState(true);
|
|
5898
|
+
const [error, setError] = useState(null);
|
|
5899
|
+
useEffect(() => {
|
|
5283
5900
|
let cancelled = false;
|
|
5284
5901
|
async function fetchOutline() {
|
|
5285
5902
|
try {
|
|
@@ -5312,7 +5929,7 @@ function useDocumentOutline(options) {
|
|
|
5312
5929
|
cancelled = true;
|
|
5313
5930
|
};
|
|
5314
5931
|
}, [pdfDocument]);
|
|
5315
|
-
const navigateToItem =
|
|
5932
|
+
const navigateToItem = useCallback(
|
|
5316
5933
|
(item) => {
|
|
5317
5934
|
if (goToPage && item.pageNumber) {
|
|
5318
5935
|
goToPage(item.pageNumber);
|
|
@@ -5320,18 +5937,15 @@ function useDocumentOutline(options) {
|
|
|
5320
5937
|
},
|
|
5321
5938
|
[goToPage]
|
|
5322
5939
|
);
|
|
5323
|
-
const flatOutline =
|
|
5940
|
+
const flatOutline = useMemo(() => {
|
|
5324
5941
|
if (!outline) return [];
|
|
5325
5942
|
return flattenOutline(outline);
|
|
5326
5943
|
}, [outline]);
|
|
5327
|
-
const hasOutline =
|
|
5944
|
+
const hasOutline = useMemo(() => {
|
|
5328
5945
|
return outline !== null && outline.length > 0;
|
|
5329
5946
|
}, [outline]);
|
|
5330
5947
|
return { outline, isLoading, error, navigateToItem, flatOutline, hasOutline };
|
|
5331
5948
|
}
|
|
5332
|
-
|
|
5333
|
-
// src/hooks/useThumbnails.ts
|
|
5334
|
-
import { useState as useState13, useCallback as useCallback6, useRef as useRef15, useEffect as useEffect14 } from "react";
|
|
5335
5949
|
var MAX_CONCURRENT_RENDERS = 3;
|
|
5336
5950
|
function useThumbnails(options) {
|
|
5337
5951
|
const {
|
|
@@ -5343,21 +5957,21 @@ function useThumbnails(options) {
|
|
|
5343
5957
|
// Changed to false - let virtualization control loading
|
|
5344
5958
|
imageQuality = 0.8
|
|
5345
5959
|
} = options;
|
|
5346
|
-
const [thumbnails, setThumbnails] =
|
|
5960
|
+
const [thumbnails, setThumbnails] = useState(
|
|
5347
5961
|
/* @__PURE__ */ new Map()
|
|
5348
5962
|
);
|
|
5349
|
-
const loadingRef =
|
|
5350
|
-
const loadedRef =
|
|
5351
|
-
const cacheOrderRef =
|
|
5352
|
-
const renderQueueRef =
|
|
5353
|
-
const activeRendersRef =
|
|
5354
|
-
const isProcessingRef =
|
|
5355
|
-
const thumbnailsRef =
|
|
5963
|
+
const loadingRef = useRef(/* @__PURE__ */ new Set());
|
|
5964
|
+
const loadedRef = useRef(/* @__PURE__ */ new Set());
|
|
5965
|
+
const cacheOrderRef = useRef([]);
|
|
5966
|
+
const renderQueueRef = useRef([]);
|
|
5967
|
+
const activeRendersRef = useRef(0);
|
|
5968
|
+
const isProcessingRef = useRef(false);
|
|
5969
|
+
const thumbnailsRef = useRef(thumbnails);
|
|
5356
5970
|
thumbnailsRef.current = thumbnails;
|
|
5357
|
-
const pendingUpdatesRef =
|
|
5358
|
-
const flushTimeoutRef =
|
|
5971
|
+
const pendingUpdatesRef = useRef(/* @__PURE__ */ new Map());
|
|
5972
|
+
const flushTimeoutRef = useRef(null);
|
|
5359
5973
|
const totalPages = pdfDocument.numPages;
|
|
5360
|
-
const flushUpdates =
|
|
5974
|
+
const flushUpdates = useCallback(() => {
|
|
5361
5975
|
if (pendingUpdatesRef.current.size === 0) return;
|
|
5362
5976
|
setThumbnails((prev) => {
|
|
5363
5977
|
const next = new Map(prev);
|
|
@@ -5377,7 +5991,7 @@ function useThumbnails(options) {
|
|
|
5377
5991
|
return next;
|
|
5378
5992
|
});
|
|
5379
5993
|
}, [cacheSize]);
|
|
5380
|
-
const queueUpdate =
|
|
5994
|
+
const queueUpdate = useCallback((pageNumber, data) => {
|
|
5381
5995
|
pendingUpdatesRef.current.set(pageNumber, data);
|
|
5382
5996
|
if (!flushTimeoutRef.current) {
|
|
5383
5997
|
flushTimeoutRef.current = setTimeout(() => {
|
|
@@ -5386,7 +6000,7 @@ function useThumbnails(options) {
|
|
|
5386
6000
|
}, 50);
|
|
5387
6001
|
}
|
|
5388
6002
|
}, [flushUpdates]);
|
|
5389
|
-
const renderThumbnail =
|
|
6003
|
+
const renderThumbnail = useCallback(
|
|
5390
6004
|
async (pageNumber) => {
|
|
5391
6005
|
try {
|
|
5392
6006
|
const page = await pdfDocument.getPage(pageNumber);
|
|
@@ -5424,7 +6038,7 @@ function useThumbnails(options) {
|
|
|
5424
6038
|
},
|
|
5425
6039
|
[pdfDocument, thumbnailWidth, imageQuality, queueUpdate]
|
|
5426
6040
|
);
|
|
5427
|
-
const processQueue =
|
|
6041
|
+
const processQueue = useCallback(async () => {
|
|
5428
6042
|
if (isProcessingRef.current) return;
|
|
5429
6043
|
isProcessingRef.current = true;
|
|
5430
6044
|
while (renderQueueRef.current.length > 0 && activeRendersRef.current < MAX_CONCURRENT_RENDERS) {
|
|
@@ -5440,7 +6054,7 @@ function useThumbnails(options) {
|
|
|
5440
6054
|
}
|
|
5441
6055
|
isProcessingRef.current = false;
|
|
5442
6056
|
}, [renderThumbnail]);
|
|
5443
|
-
const loadThumbnail =
|
|
6057
|
+
const loadThumbnail = useCallback(
|
|
5444
6058
|
async (pageNumber) => {
|
|
5445
6059
|
if (loadingRef.current.has(pageNumber) || loadedRef.current.has(pageNumber)) {
|
|
5446
6060
|
return;
|
|
@@ -5459,7 +6073,7 @@ function useThumbnails(options) {
|
|
|
5459
6073
|
},
|
|
5460
6074
|
[processQueue, queueUpdate]
|
|
5461
6075
|
);
|
|
5462
|
-
const getThumbnail =
|
|
6076
|
+
const getThumbnail = useCallback(
|
|
5463
6077
|
(pageNumber) => {
|
|
5464
6078
|
return thumbnailsRef.current.get(pageNumber) || {
|
|
5465
6079
|
pageNumber,
|
|
@@ -5470,7 +6084,7 @@ function useThumbnails(options) {
|
|
|
5470
6084
|
[]
|
|
5471
6085
|
// No dependencies - always stable
|
|
5472
6086
|
);
|
|
5473
|
-
const preloadThumbnails =
|
|
6087
|
+
const preloadThumbnails = useCallback(
|
|
5474
6088
|
(pageNumbers) => {
|
|
5475
6089
|
pageNumbers.forEach((pageNumber) => {
|
|
5476
6090
|
loadThumbnail(pageNumber);
|
|
@@ -5478,13 +6092,13 @@ function useThumbnails(options) {
|
|
|
5478
6092
|
},
|
|
5479
6093
|
[loadThumbnail]
|
|
5480
6094
|
);
|
|
5481
|
-
const clearCache =
|
|
6095
|
+
const clearCache = useCallback(() => {
|
|
5482
6096
|
setThumbnails(/* @__PURE__ */ new Map());
|
|
5483
6097
|
cacheOrderRef.current = [];
|
|
5484
6098
|
loadingRef.current.clear();
|
|
5485
6099
|
loadedRef.current.clear();
|
|
5486
6100
|
}, []);
|
|
5487
|
-
|
|
6101
|
+
useEffect(() => {
|
|
5488
6102
|
if (preloadAll && totalPages > 0) {
|
|
5489
6103
|
const pageNumbers = Array.from({ length: totalPages }, (_, i) => i + 1);
|
|
5490
6104
|
pageNumbers.forEach((pageNumber) => {
|
|
@@ -5492,7 +6106,7 @@ function useThumbnails(options) {
|
|
|
5492
6106
|
});
|
|
5493
6107
|
}
|
|
5494
6108
|
}, [preloadAll, totalPages, loadThumbnail]);
|
|
5495
|
-
|
|
6109
|
+
useEffect(() => {
|
|
5496
6110
|
return () => {
|
|
5497
6111
|
loadingRef.current.clear();
|
|
5498
6112
|
if (flushTimeoutRef.current) {
|
|
@@ -5510,9 +6124,6 @@ function useThumbnails(options) {
|
|
|
5510
6124
|
thumbnails
|
|
5511
6125
|
};
|
|
5512
6126
|
}
|
|
5513
|
-
|
|
5514
|
-
// src/hooks/usePageNavigation.ts
|
|
5515
|
-
import { useState as useState14, useEffect as useEffect15, useCallback as useCallback7, useRef as useRef16 } from "react";
|
|
5516
6127
|
var isEventBus = (obj) => {
|
|
5517
6128
|
return obj !== null && typeof obj === "object" && "on" in obj && "off" in obj;
|
|
5518
6129
|
};
|
|
@@ -5521,10 +6132,10 @@ var isViewer = (obj) => {
|
|
|
5521
6132
|
};
|
|
5522
6133
|
function usePageNavigation(options) {
|
|
5523
6134
|
const { viewer, eventBus } = options;
|
|
5524
|
-
const [currentPage, setCurrentPage] =
|
|
5525
|
-
const viewerRef =
|
|
6135
|
+
const [currentPage, setCurrentPage] = useState(1);
|
|
6136
|
+
const viewerRef = useRef(viewer);
|
|
5526
6137
|
viewerRef.current = viewer;
|
|
5527
|
-
|
|
6138
|
+
useEffect(() => {
|
|
5528
6139
|
if (!eventBus || !isEventBus(eventBus)) {
|
|
5529
6140
|
return;
|
|
5530
6141
|
}
|
|
@@ -5536,14 +6147,14 @@ function usePageNavigation(options) {
|
|
|
5536
6147
|
eventBus.off("pagechanging", handlePageChange);
|
|
5537
6148
|
};
|
|
5538
6149
|
}, [eventBus]);
|
|
5539
|
-
const prevViewerRef =
|
|
5540
|
-
|
|
6150
|
+
const prevViewerRef = useRef(viewer);
|
|
6151
|
+
useEffect(() => {
|
|
5541
6152
|
if (viewer !== prevViewerRef.current) {
|
|
5542
6153
|
setCurrentPage(1);
|
|
5543
6154
|
prevViewerRef.current = viewer;
|
|
5544
6155
|
}
|
|
5545
6156
|
}, [viewer]);
|
|
5546
|
-
const goToPage =
|
|
6157
|
+
const goToPage = useCallback(
|
|
5547
6158
|
(pageNumber) => {
|
|
5548
6159
|
const v = viewerRef.current;
|
|
5549
6160
|
if (v && isViewer(v)) {
|
|
@@ -5577,14 +6188,6 @@ function usePageNavigation(options) {
|
|
|
5577
6188
|
goToPage
|
|
5578
6189
|
};
|
|
5579
6190
|
}
|
|
5580
|
-
|
|
5581
|
-
// src/components/leftpanel/DocumentOutline.tsx
|
|
5582
|
-
import React18 from "react";
|
|
5583
|
-
import { Loader2, FileQuestion } from "lucide-react";
|
|
5584
|
-
|
|
5585
|
-
// src/components/leftpanel/OutlineItem.tsx
|
|
5586
|
-
import React17, { useState as useState15 } from "react";
|
|
5587
|
-
import { ChevronRight, ChevronDown } from "lucide-react";
|
|
5588
6191
|
var OutlineItem = ({
|
|
5589
6192
|
item,
|
|
5590
6193
|
currentPage,
|
|
@@ -5596,8 +6199,8 @@ var OutlineItem = ({
|
|
|
5596
6199
|
classNames,
|
|
5597
6200
|
renderItem
|
|
5598
6201
|
}) => {
|
|
5599
|
-
const [isExpanded, setIsExpanded] =
|
|
5600
|
-
const [isHovered, setIsHovered] =
|
|
6202
|
+
const [isExpanded, setIsExpanded] = useState(defaultExpanded);
|
|
6203
|
+
const [isHovered, setIsHovered] = useState(false);
|
|
5601
6204
|
const hasChildren = item.children && item.children.length > 0;
|
|
5602
6205
|
const isActive = currentPage === item.pageNumber;
|
|
5603
6206
|
const canShowChildren = item.level < maxDepth;
|
|
@@ -5618,7 +6221,7 @@ var OutlineItem = ({
|
|
|
5618
6221
|
onNavigate: handleNavigate
|
|
5619
6222
|
};
|
|
5620
6223
|
if (renderItem) {
|
|
5621
|
-
return /* @__PURE__ */
|
|
6224
|
+
return /* @__PURE__ */ React11.createElement(React11.Fragment, null, renderItem(item, renderProps));
|
|
5622
6225
|
}
|
|
5623
6226
|
const indent = 12 + item.level * 16;
|
|
5624
6227
|
const defaultContainerStyle = {
|
|
@@ -5732,7 +6335,7 @@ var OutlineItem = ({
|
|
|
5732
6335
|
classNames?.pageNumber,
|
|
5733
6336
|
isActive ? classNames?.pageNumberActive : ""
|
|
5734
6337
|
].filter(Boolean).join(" ");
|
|
5735
|
-
return /* @__PURE__ */
|
|
6338
|
+
return /* @__PURE__ */ React11.createElement("div", { className: "outline-item" }, /* @__PURE__ */ React11.createElement(
|
|
5736
6339
|
"div",
|
|
5737
6340
|
{
|
|
5738
6341
|
className: containerClassName || void 0,
|
|
@@ -5749,7 +6352,7 @@ var OutlineItem = ({
|
|
|
5749
6352
|
}
|
|
5750
6353
|
}
|
|
5751
6354
|
},
|
|
5752
|
-
showExpandIcons && hasChildren && canShowChildren ? /* @__PURE__ */
|
|
6355
|
+
showExpandIcons && hasChildren && canShowChildren ? /* @__PURE__ */ React11.createElement(
|
|
5753
6356
|
"button",
|
|
5754
6357
|
{
|
|
5755
6358
|
className: classNames?.expandButton,
|
|
@@ -5766,12 +6369,12 @@ var OutlineItem = ({
|
|
|
5766
6369
|
},
|
|
5767
6370
|
"aria-label": isExpanded ? "Collapse" : "Expand"
|
|
5768
6371
|
},
|
|
5769
|
-
isExpanded ? /* @__PURE__ */
|
|
5770
|
-
) : /* @__PURE__ */
|
|
5771
|
-
isActive && /* @__PURE__ */
|
|
5772
|
-
/* @__PURE__ */
|
|
5773
|
-
/* @__PURE__ */
|
|
5774
|
-
), hasChildren && isExpanded && canShowChildren && /* @__PURE__ */
|
|
6372
|
+
isExpanded ? /* @__PURE__ */ React11.createElement(ChevronDown, { className: classNames?.expandIcon, style: expandIconStyle }) : /* @__PURE__ */ React11.createElement(ChevronRight, { className: classNames?.expandIcon, style: expandIconStyle })
|
|
6373
|
+
) : /* @__PURE__ */ React11.createElement("div", { style: { width: 16, flexShrink: 0 } }),
|
|
6374
|
+
isActive && /* @__PURE__ */ React11.createElement("div", { className: classNames?.activeIndicator, style: activeIndicatorStyle }),
|
|
6375
|
+
/* @__PURE__ */ React11.createElement("span", { className: titleClassName || void 0, style: titleStyle, title: item.title }, item.title),
|
|
6376
|
+
/* @__PURE__ */ React11.createElement("span", { className: pageNumberClassName || void 0, style: pageNumberStyle }, item.pageNumber)
|
|
6377
|
+
), hasChildren && isExpanded && canShowChildren && /* @__PURE__ */ React11.createElement("div", { className: classNames?.childrenContainer, style: childrenContainerStyle }, item.children.map((child) => /* @__PURE__ */ React11.createElement(
|
|
5775
6378
|
OutlineItem,
|
|
5776
6379
|
{
|
|
5777
6380
|
key: child.id,
|
|
@@ -5862,32 +6465,32 @@ var DocumentOutline = ({
|
|
|
5862
6465
|
paddingBottom: "8px"
|
|
5863
6466
|
};
|
|
5864
6467
|
if (isLoading) {
|
|
5865
|
-
return /* @__PURE__ */
|
|
6468
|
+
return /* @__PURE__ */ React11.createElement(
|
|
5866
6469
|
"div",
|
|
5867
6470
|
{
|
|
5868
6471
|
className: [className, classNames?.loadingContainer].filter(Boolean).join(" ") || void 0,
|
|
5869
6472
|
style: { ...defaultLoadingContainerStyle, ...styles?.loadingContainer }
|
|
5870
6473
|
},
|
|
5871
|
-
loadingContent || /* @__PURE__ */
|
|
6474
|
+
loadingContent || /* @__PURE__ */ React11.createElement(React11.Fragment, null, /* @__PURE__ */ React11.createElement(Loader2, { className: classNames?.loadingSpinner, style: { ...defaultLoadingSpinnerStyle, ...styles?.loadingSpinner } }), /* @__PURE__ */ React11.createElement("p", { className: classNames?.loadingText, style: { ...defaultLoadingTextStyle, ...styles?.loadingText } }, "Loading outline..."))
|
|
5872
6475
|
);
|
|
5873
6476
|
}
|
|
5874
6477
|
if (!outline || outline.length === 0) {
|
|
5875
|
-
return /* @__PURE__ */
|
|
6478
|
+
return /* @__PURE__ */ React11.createElement(
|
|
5876
6479
|
"div",
|
|
5877
6480
|
{
|
|
5878
6481
|
className: [className, classNames?.emptyContainer].filter(Boolean).join(" ") || void 0,
|
|
5879
6482
|
style: { ...defaultEmptyContainerStyle, ...styles?.emptyContainer }
|
|
5880
6483
|
},
|
|
5881
|
-
emptyContent || /* @__PURE__ */
|
|
6484
|
+
emptyContent || /* @__PURE__ */ React11.createElement(React11.Fragment, null, /* @__PURE__ */ React11.createElement("div", { className: classNames?.emptyIconContainer, style: { ...defaultEmptyIconContainerStyle, ...styles?.emptyIconContainer } }, /* @__PURE__ */ React11.createElement(FileQuestion, { className: classNames?.emptyIcon, style: { ...defaultEmptyIconStyle, ...styles?.emptyIcon } })), /* @__PURE__ */ React11.createElement("p", { className: classNames?.emptyTitle, style: { ...defaultEmptyTitleStyle, ...styles?.emptyTitle } }, "No outline available"), /* @__PURE__ */ React11.createElement("p", { className: classNames?.emptyDescription, style: { ...defaultEmptyDescriptionStyle, ...styles?.emptyDescription } }, "This document doesn't have a table of contents"))
|
|
5882
6485
|
);
|
|
5883
6486
|
}
|
|
5884
|
-
return /* @__PURE__ */
|
|
6487
|
+
return /* @__PURE__ */ React11.createElement(
|
|
5885
6488
|
"div",
|
|
5886
6489
|
{
|
|
5887
6490
|
className: ["document-outline", className, classNames?.container].filter(Boolean).join(" "),
|
|
5888
6491
|
style: { ...defaultContainerStyle, ...styles?.container }
|
|
5889
6492
|
},
|
|
5890
|
-
outline.map((item) => /* @__PURE__ */
|
|
6493
|
+
outline.map((item) => /* @__PURE__ */ React11.createElement(
|
|
5891
6494
|
OutlineItem,
|
|
5892
6495
|
{
|
|
5893
6496
|
key: item.id,
|
|
@@ -5904,15 +6507,7 @@ var DocumentOutline = ({
|
|
|
5904
6507
|
))
|
|
5905
6508
|
);
|
|
5906
6509
|
};
|
|
5907
|
-
|
|
5908
|
-
// src/components/leftpanel/ThumbnailPanel.tsx
|
|
5909
|
-
import React20, { useRef as useRef18, useEffect as useEffect17 } from "react";
|
|
5910
|
-
import { useVirtualizer } from "@tanstack/react-virtual";
|
|
5911
|
-
|
|
5912
|
-
// src/components/leftpanel/ThumbnailItem.tsx
|
|
5913
|
-
import React19, { useEffect as useEffect16, useRef as useRef17, useState as useState16 } from "react";
|
|
5914
|
-
import { Loader2 as Loader22, AlertCircle } from "lucide-react";
|
|
5915
|
-
var ThumbnailItem = React19.memo(({
|
|
6510
|
+
var ThumbnailItem = React11.memo(({
|
|
5916
6511
|
pageNumber,
|
|
5917
6512
|
thumbnail,
|
|
5918
6513
|
isActive,
|
|
@@ -5921,10 +6516,10 @@ var ThumbnailItem = React19.memo(({
|
|
|
5921
6516
|
showPageNumber = true,
|
|
5922
6517
|
className = ""
|
|
5923
6518
|
}) => {
|
|
5924
|
-
const containerRef =
|
|
5925
|
-
const hasLoadedRef =
|
|
5926
|
-
const [isHovered, setIsHovered] =
|
|
5927
|
-
|
|
6519
|
+
const containerRef = useRef(null);
|
|
6520
|
+
const hasLoadedRef = useRef(false);
|
|
6521
|
+
const [isHovered, setIsHovered] = useState(false);
|
|
6522
|
+
useEffect(() => {
|
|
5928
6523
|
const element = containerRef.current;
|
|
5929
6524
|
if (!element || hasLoadedRef.current) return;
|
|
5930
6525
|
const observer = new IntersectionObserver(
|
|
@@ -5979,7 +6574,7 @@ var ThumbnailItem = React19.memo(({
|
|
|
5979
6574
|
color: isActive ? "var(--lp-accent, #3b82f6)" : "var(--lp-muted, #6b7280)",
|
|
5980
6575
|
transition: "color 0.15s ease"
|
|
5981
6576
|
};
|
|
5982
|
-
return /* @__PURE__ */
|
|
6577
|
+
return /* @__PURE__ */ React11.createElement(
|
|
5983
6578
|
"div",
|
|
5984
6579
|
{
|
|
5985
6580
|
ref: containerRef,
|
|
@@ -5999,7 +6594,7 @@ var ThumbnailItem = React19.memo(({
|
|
|
5999
6594
|
"aria-label": `Page ${pageNumber}${isActive ? " (current)" : ""}`,
|
|
6000
6595
|
"aria-current": isActive ? "page" : void 0
|
|
6001
6596
|
},
|
|
6002
|
-
/* @__PURE__ */
|
|
6597
|
+
/* @__PURE__ */ React11.createElement("div", { style: imageContainerStyle }, thumbnail.isLoading && /* @__PURE__ */ React11.createElement(
|
|
6003
6598
|
"div",
|
|
6004
6599
|
{
|
|
6005
6600
|
style: {
|
|
@@ -6011,8 +6606,8 @@ var ThumbnailItem = React19.memo(({
|
|
|
6011
6606
|
backgroundColor: "var(--lp-hover, #f9fafb)"
|
|
6012
6607
|
}
|
|
6013
6608
|
},
|
|
6014
|
-
/* @__PURE__ */
|
|
6015
|
-
|
|
6609
|
+
/* @__PURE__ */ React11.createElement(
|
|
6610
|
+
Loader2,
|
|
6016
6611
|
{
|
|
6017
6612
|
style: {
|
|
6018
6613
|
width: 24,
|
|
@@ -6022,7 +6617,7 @@ var ThumbnailItem = React19.memo(({
|
|
|
6022
6617
|
}
|
|
6023
6618
|
}
|
|
6024
6619
|
)
|
|
6025
|
-
), thumbnail.error && !thumbnail.isLoading && /* @__PURE__ */
|
|
6620
|
+
), thumbnail.error && !thumbnail.isLoading && /* @__PURE__ */ React11.createElement(
|
|
6026
6621
|
"div",
|
|
6027
6622
|
{
|
|
6028
6623
|
style: {
|
|
@@ -6035,9 +6630,9 @@ var ThumbnailItem = React19.memo(({
|
|
|
6035
6630
|
backgroundColor: "#fef2f2"
|
|
6036
6631
|
}
|
|
6037
6632
|
},
|
|
6038
|
-
/* @__PURE__ */
|
|
6039
|
-
/* @__PURE__ */
|
|
6040
|
-
), thumbnail.dataUrl && !thumbnail.isLoading && /* @__PURE__ */
|
|
6633
|
+
/* @__PURE__ */ React11.createElement(AlertCircle, { style: { width: 20, height: 20, color: "#f87171", marginBottom: 4 } }),
|
|
6634
|
+
/* @__PURE__ */ React11.createElement("span", { style: { fontSize: 10, color: "#9ca3af" } }, "Failed")
|
|
6635
|
+
), thumbnail.dataUrl && !thumbnail.isLoading && /* @__PURE__ */ React11.createElement(
|
|
6041
6636
|
"img",
|
|
6042
6637
|
{
|
|
6043
6638
|
src: thumbnail.dataUrl,
|
|
@@ -6049,7 +6644,7 @@ var ThumbnailItem = React19.memo(({
|
|
|
6049
6644
|
},
|
|
6050
6645
|
draggable: false
|
|
6051
6646
|
}
|
|
6052
|
-
), !thumbnail.dataUrl && !thumbnail.isLoading && !thumbnail.error && /* @__PURE__ */
|
|
6647
|
+
), !thumbnail.dataUrl && !thumbnail.isLoading && !thumbnail.error && /* @__PURE__ */ React11.createElement(
|
|
6053
6648
|
"div",
|
|
6054
6649
|
{
|
|
6055
6650
|
style: {
|
|
@@ -6061,7 +6656,7 @@ var ThumbnailItem = React19.memo(({
|
|
|
6061
6656
|
backgroundColor: "var(--lp-hover, #f9fafb)"
|
|
6062
6657
|
}
|
|
6063
6658
|
},
|
|
6064
|
-
/* @__PURE__ */
|
|
6659
|
+
/* @__PURE__ */ React11.createElement(
|
|
6065
6660
|
"span",
|
|
6066
6661
|
{
|
|
6067
6662
|
style: {
|
|
@@ -6073,7 +6668,7 @@ var ThumbnailItem = React19.memo(({
|
|
|
6073
6668
|
pageNumber
|
|
6074
6669
|
)
|
|
6075
6670
|
)),
|
|
6076
|
-
showPageNumber && /* @__PURE__ */
|
|
6671
|
+
showPageNumber && /* @__PURE__ */ React11.createElement("div", { style: pageNumberStyle }, pageNumber)
|
|
6077
6672
|
);
|
|
6078
6673
|
});
|
|
6079
6674
|
|
|
@@ -6098,22 +6693,22 @@ var ThumbnailPanel = ({
|
|
|
6098
6693
|
isLoading: false
|
|
6099
6694
|
};
|
|
6100
6695
|
};
|
|
6101
|
-
const parentRef =
|
|
6696
|
+
const parentRef = useRef(null);
|
|
6102
6697
|
const virtualizer = useVirtualizer({
|
|
6103
6698
|
count: totalPages,
|
|
6104
6699
|
getScrollElement: () => parentRef.current,
|
|
6105
6700
|
estimateSize: () => estimatedItemHeight + gap,
|
|
6106
6701
|
overscan
|
|
6107
6702
|
});
|
|
6108
|
-
const scrollToIndexRef =
|
|
6703
|
+
const scrollToIndexRef = useRef(virtualizer.scrollToIndex);
|
|
6109
6704
|
scrollToIndexRef.current = virtualizer.scrollToIndex;
|
|
6110
|
-
|
|
6705
|
+
useEffect(() => {
|
|
6111
6706
|
if (currentPage > 0 && currentPage <= totalPages) {
|
|
6112
6707
|
scrollToIndexRef.current(currentPage - 1, { align: "center" });
|
|
6113
6708
|
}
|
|
6114
6709
|
}, [currentPage, totalPages]);
|
|
6115
6710
|
if (totalPages === 0) {
|
|
6116
|
-
return /* @__PURE__ */
|
|
6711
|
+
return /* @__PURE__ */ React11.createElement(
|
|
6117
6712
|
"div",
|
|
6118
6713
|
{
|
|
6119
6714
|
className,
|
|
@@ -6124,10 +6719,10 @@ var ThumbnailPanel = ({
|
|
|
6124
6719
|
padding: "48px 16px"
|
|
6125
6720
|
}
|
|
6126
6721
|
},
|
|
6127
|
-
/* @__PURE__ */
|
|
6722
|
+
/* @__PURE__ */ React11.createElement("p", { style: { fontSize: 13, color: "var(--lp-muted, #9ca3af)" } }, "No pages to display")
|
|
6128
6723
|
);
|
|
6129
6724
|
}
|
|
6130
|
-
return /* @__PURE__ */
|
|
6725
|
+
return /* @__PURE__ */ React11.createElement(
|
|
6131
6726
|
"div",
|
|
6132
6727
|
{
|
|
6133
6728
|
ref: parentRef,
|
|
@@ -6138,7 +6733,7 @@ var ThumbnailPanel = ({
|
|
|
6138
6733
|
padding: "12px"
|
|
6139
6734
|
}
|
|
6140
6735
|
},
|
|
6141
|
-
/* @__PURE__ */
|
|
6736
|
+
/* @__PURE__ */ React11.createElement(
|
|
6142
6737
|
"div",
|
|
6143
6738
|
{
|
|
6144
6739
|
style: {
|
|
@@ -6151,7 +6746,7 @@ var ThumbnailPanel = ({
|
|
|
6151
6746
|
const pageNumber = virtualItem.index + 1;
|
|
6152
6747
|
const thumbnail = getThumbnail(pageNumber);
|
|
6153
6748
|
const isActive = currentPage === pageNumber;
|
|
6154
|
-
return /* @__PURE__ */
|
|
6749
|
+
return /* @__PURE__ */ React11.createElement(
|
|
6155
6750
|
"div",
|
|
6156
6751
|
{
|
|
6157
6752
|
key: virtualItem.key,
|
|
@@ -6165,14 +6760,14 @@ var ThumbnailPanel = ({
|
|
|
6165
6760
|
paddingBottom: `${gap}px`
|
|
6166
6761
|
}
|
|
6167
6762
|
},
|
|
6168
|
-
renderThumbnail ? /* @__PURE__ */
|
|
6763
|
+
renderThumbnail ? /* @__PURE__ */ React11.createElement(
|
|
6169
6764
|
"div",
|
|
6170
6765
|
{
|
|
6171
6766
|
onClick: () => onPageSelect(pageNumber),
|
|
6172
6767
|
style: { cursor: "pointer", height: "100%" }
|
|
6173
6768
|
},
|
|
6174
6769
|
renderThumbnail(pageNumber, thumbnail, isActive)
|
|
6175
|
-
) : /* @__PURE__ */
|
|
6770
|
+
) : /* @__PURE__ */ React11.createElement(
|
|
6176
6771
|
ThumbnailItem,
|
|
6177
6772
|
{
|
|
6178
6773
|
pageNumber,
|
|
@@ -6192,18 +6787,18 @@ var ThumbnailPanel = ({
|
|
|
6192
6787
|
// src/components/leftpanel/LeftPanel.tsx
|
|
6193
6788
|
var defaultTheme = {
|
|
6194
6789
|
backgroundColor: "#ffffff",
|
|
6195
|
-
borderColor: "#
|
|
6196
|
-
accentColor: "#
|
|
6197
|
-
textColor: "#
|
|
6198
|
-
mutedTextColor: "#
|
|
6199
|
-
hoverBackgroundColor: "#
|
|
6790
|
+
borderColor: "#e6e2da",
|
|
6791
|
+
accentColor: "#5b50e6",
|
|
6792
|
+
textColor: "#1c1b18",
|
|
6793
|
+
mutedTextColor: "#8b8880",
|
|
6794
|
+
hoverBackgroundColor: "#f4f2ee"
|
|
6200
6795
|
};
|
|
6201
6796
|
var defaultDarkTheme2 = {
|
|
6202
|
-
backgroundColor: "#
|
|
6797
|
+
backgroundColor: "#211f1c",
|
|
6203
6798
|
borderColor: "#3a3733",
|
|
6204
|
-
accentColor: "#
|
|
6799
|
+
accentColor: "#7b71f0",
|
|
6205
6800
|
textColor: "#eae6e0",
|
|
6206
|
-
mutedTextColor: "#
|
|
6801
|
+
mutedTextColor: "#8b8880",
|
|
6207
6802
|
hoverBackgroundColor: "#2a2724"
|
|
6208
6803
|
};
|
|
6209
6804
|
var LeftPanel = ({
|
|
@@ -6239,17 +6834,17 @@ var LeftPanel = ({
|
|
|
6239
6834
|
outlineItemStyles,
|
|
6240
6835
|
outlineItemClassNames
|
|
6241
6836
|
}) => {
|
|
6242
|
-
const theme =
|
|
6837
|
+
const theme = useMemo(
|
|
6243
6838
|
() => ({
|
|
6244
6839
|
...mode === "dark" ? defaultDarkTheme2 : defaultTheme,
|
|
6245
6840
|
...userTheme
|
|
6246
6841
|
}),
|
|
6247
6842
|
[mode, userTheme]
|
|
6248
6843
|
);
|
|
6249
|
-
const [internalIsOpen, setInternalIsOpen] =
|
|
6250
|
-
const [activeTab, setActiveTab] =
|
|
6844
|
+
const [internalIsOpen, setInternalIsOpen] = useState(true);
|
|
6845
|
+
const [activeTab, setActiveTab] = useState(defaultTab);
|
|
6251
6846
|
const isOpen = controlledIsOpen !== void 0 ? controlledIsOpen : internalIsOpen;
|
|
6252
|
-
const setIsOpen =
|
|
6847
|
+
const setIsOpen = useCallback(
|
|
6253
6848
|
(open) => {
|
|
6254
6849
|
if (onOpenChange) {
|
|
6255
6850
|
onOpenChange(open);
|
|
@@ -6267,11 +6862,11 @@ var LeftPanel = ({
|
|
|
6267
6862
|
viewer,
|
|
6268
6863
|
eventBus
|
|
6269
6864
|
});
|
|
6270
|
-
const goToPagePropRef =
|
|
6271
|
-
|
|
6865
|
+
const goToPagePropRef = useRef(goToPageProp);
|
|
6866
|
+
useEffect(() => {
|
|
6272
6867
|
goToPagePropRef.current = goToPageProp;
|
|
6273
6868
|
}, [goToPageProp]);
|
|
6274
|
-
const handlePageSelect =
|
|
6869
|
+
const handlePageSelect = useCallback(
|
|
6275
6870
|
(pageNumber) => {
|
|
6276
6871
|
if (goToPagePropRef.current) {
|
|
6277
6872
|
goToPagePropRef.current(pageNumber);
|
|
@@ -6291,14 +6886,14 @@ var LeftPanel = ({
|
|
|
6291
6886
|
pdfDocument,
|
|
6292
6887
|
goToPage: handlePageSelect
|
|
6293
6888
|
});
|
|
6294
|
-
const handleOutlineNavigate =
|
|
6889
|
+
const handleOutlineNavigate = useCallback(
|
|
6295
6890
|
(item) => {
|
|
6296
6891
|
navigateToItem(item);
|
|
6297
6892
|
onPageSelect?.(item.pageNumber);
|
|
6298
6893
|
},
|
|
6299
6894
|
[navigateToItem, onPageSelect]
|
|
6300
6895
|
);
|
|
6301
|
-
const contextValue =
|
|
6896
|
+
const contextValue = useMemo(
|
|
6302
6897
|
() => ({
|
|
6303
6898
|
currentPage,
|
|
6304
6899
|
totalPages,
|
|
@@ -6340,7 +6935,7 @@ var LeftPanel = ({
|
|
|
6340
6935
|
"--lp-muted": theme.mutedTextColor,
|
|
6341
6936
|
"--lp-hover": theme.hoverBackgroundColor
|
|
6342
6937
|
};
|
|
6343
|
-
return /* @__PURE__ */
|
|
6938
|
+
return /* @__PURE__ */ React11.createElement(LeftPanelContext.Provider, { value: contextValue }, showToggleButton && /* @__PURE__ */ React11.createElement(
|
|
6344
6939
|
"button",
|
|
6345
6940
|
{
|
|
6346
6941
|
className: toggleButtonClassNames?.button,
|
|
@@ -6373,8 +6968,8 @@ var LeftPanel = ({
|
|
|
6373
6968
|
},
|
|
6374
6969
|
"aria-label": isOpen ? "Close panel" : "Open panel"
|
|
6375
6970
|
},
|
|
6376
|
-
isOpen ? /* @__PURE__ */
|
|
6377
|
-
), /* @__PURE__ */
|
|
6971
|
+
isOpen ? /* @__PURE__ */ React11.createElement(ChevronLeft, { className: toggleButtonClassNames?.icon, style: { width: 14, height: 14, color: theme.mutedTextColor, ...toggleButtonStyles?.icon } }) : /* @__PURE__ */ React11.createElement(ChevronRight, { className: toggleButtonClassNames?.icon, style: { width: 14, height: 14, color: theme.mutedTextColor, ...toggleButtonStyles?.icon } })
|
|
6972
|
+
), /* @__PURE__ */ React11.createElement(
|
|
6378
6973
|
"div",
|
|
6379
6974
|
{
|
|
6380
6975
|
className: `left-panel ${className}`,
|
|
@@ -6393,7 +6988,7 @@ var LeftPanel = ({
|
|
|
6393
6988
|
...style
|
|
6394
6989
|
}
|
|
6395
6990
|
},
|
|
6396
|
-
/* @__PURE__ */
|
|
6991
|
+
/* @__PURE__ */ React11.createElement(
|
|
6397
6992
|
"div",
|
|
6398
6993
|
{
|
|
6399
6994
|
style: {
|
|
@@ -6405,7 +7000,7 @@ var LeftPanel = ({
|
|
|
6405
7000
|
minWidth: panelWidth
|
|
6406
7001
|
}
|
|
6407
7002
|
},
|
|
6408
|
-
tabs.length > 1 && /* @__PURE__ */
|
|
7003
|
+
tabs.length > 1 && /* @__PURE__ */ React11.createElement(
|
|
6409
7004
|
"div",
|
|
6410
7005
|
{
|
|
6411
7006
|
className: tabClassNames?.container,
|
|
@@ -6416,7 +7011,7 @@ var LeftPanel = ({
|
|
|
6416
7011
|
...tabStyles?.container
|
|
6417
7012
|
}
|
|
6418
7013
|
},
|
|
6419
|
-
tabs.includes("outline") && /* @__PURE__ */
|
|
7014
|
+
tabs.includes("outline") && /* @__PURE__ */ React11.createElement(
|
|
6420
7015
|
"button",
|
|
6421
7016
|
{
|
|
6422
7017
|
className: [tabClassNames?.tab, activeTab === "outline" ? tabClassNames?.tabActive : ""].filter(Boolean).join(" ") || void 0,
|
|
@@ -6440,10 +7035,10 @@ var LeftPanel = ({
|
|
|
6440
7035
|
...activeTab === "outline" ? tabStyles?.tabActive : {}
|
|
6441
7036
|
}
|
|
6442
7037
|
},
|
|
6443
|
-
/* @__PURE__ */
|
|
6444
|
-
/* @__PURE__ */
|
|
7038
|
+
/* @__PURE__ */ React11.createElement(FileText, { className: tabClassNames?.tabIcon, style: { width: 15, height: 15, ...tabStyles?.tabIcon } }),
|
|
7039
|
+
/* @__PURE__ */ React11.createElement("span", { className: tabClassNames?.tabText, style: tabStyles?.tabText }, "Outline")
|
|
6445
7040
|
),
|
|
6446
|
-
tabs.includes("thumbnails") && /* @__PURE__ */
|
|
7041
|
+
tabs.includes("thumbnails") && /* @__PURE__ */ React11.createElement(
|
|
6447
7042
|
"button",
|
|
6448
7043
|
{
|
|
6449
7044
|
className: [tabClassNames?.tab, activeTab === "thumbnails" ? tabClassNames?.tabActive : ""].filter(Boolean).join(" ") || void 0,
|
|
@@ -6467,11 +7062,11 @@ var LeftPanel = ({
|
|
|
6467
7062
|
...activeTab === "thumbnails" ? tabStyles?.tabActive : {}
|
|
6468
7063
|
}
|
|
6469
7064
|
},
|
|
6470
|
-
/* @__PURE__ */
|
|
6471
|
-
/* @__PURE__ */
|
|
7065
|
+
/* @__PURE__ */ React11.createElement(List, { className: tabClassNames?.tabIcon, style: { width: 15, height: 15, ...tabStyles?.tabIcon } }),
|
|
7066
|
+
/* @__PURE__ */ React11.createElement("span", { className: tabClassNames?.tabText, style: tabStyles?.tabText }, "Pages")
|
|
6472
7067
|
)
|
|
6473
7068
|
),
|
|
6474
|
-
tabs.length === 1 && /* @__PURE__ */
|
|
7069
|
+
tabs.length === 1 && /* @__PURE__ */ React11.createElement(
|
|
6475
7070
|
"div",
|
|
6476
7071
|
{
|
|
6477
7072
|
className: tabClassNames?.container,
|
|
@@ -6485,9 +7080,9 @@ var LeftPanel = ({
|
|
|
6485
7080
|
...tabStyles?.container
|
|
6486
7081
|
}
|
|
6487
7082
|
},
|
|
6488
|
-
tabs[0] === "outline" ? /* @__PURE__ */
|
|
7083
|
+
tabs[0] === "outline" ? /* @__PURE__ */ React11.createElement(React11.Fragment, null, /* @__PURE__ */ React11.createElement(FileText, { className: tabClassNames?.tabIcon, style: { width: 15, height: 15, color: theme.mutedTextColor, ...tabStyles?.tabIcon } }), /* @__PURE__ */ React11.createElement("span", { className: tabClassNames?.tabText, style: { fontSize: "13px", fontWeight: 500, color: theme.textColor, ...tabStyles?.tabText } }, "Outline")) : /* @__PURE__ */ React11.createElement(React11.Fragment, null, /* @__PURE__ */ React11.createElement(List, { className: tabClassNames?.tabIcon, style: { width: 15, height: 15, color: theme.mutedTextColor, ...tabStyles?.tabIcon } }), /* @__PURE__ */ React11.createElement("span", { className: tabClassNames?.tabText, style: { fontSize: "13px", fontWeight: 500, color: theme.textColor, ...tabStyles?.tabText } }, "Pages"))
|
|
6489
7084
|
),
|
|
6490
|
-
/* @__PURE__ */
|
|
7085
|
+
/* @__PURE__ */ React11.createElement(
|
|
6491
7086
|
"div",
|
|
6492
7087
|
{
|
|
6493
7088
|
style: {
|
|
@@ -6497,7 +7092,7 @@ var LeftPanel = ({
|
|
|
6497
7092
|
overflowX: "hidden"
|
|
6498
7093
|
}
|
|
6499
7094
|
},
|
|
6500
|
-
activeTab === "outline" && tabs.includes("outline") && /* @__PURE__ */
|
|
7095
|
+
activeTab === "outline" && tabs.includes("outline") && /* @__PURE__ */ React11.createElement(
|
|
6501
7096
|
DocumentOutline,
|
|
6502
7097
|
{
|
|
6503
7098
|
outline,
|
|
@@ -6511,7 +7106,7 @@ var LeftPanel = ({
|
|
|
6511
7106
|
itemClassNames: outlineItemClassNames
|
|
6512
7107
|
}
|
|
6513
7108
|
),
|
|
6514
|
-
activeTab === "thumbnails" && tabs.includes("thumbnails") && /* @__PURE__ */
|
|
7109
|
+
activeTab === "thumbnails" && tabs.includes("thumbnails") && /* @__PURE__ */ React11.createElement(
|
|
6515
7110
|
ThumbnailPanel,
|
|
6516
7111
|
{
|
|
6517
7112
|
totalPages,
|
|
@@ -6524,7 +7119,7 @@ var LeftPanel = ({
|
|
|
6524
7119
|
),
|
|
6525
7120
|
children
|
|
6526
7121
|
),
|
|
6527
|
-
showFooter && /* @__PURE__ */
|
|
7122
|
+
showFooter && /* @__PURE__ */ React11.createElement(
|
|
6528
7123
|
"div",
|
|
6529
7124
|
{
|
|
6530
7125
|
className: footerClassNames?.container,
|
|
@@ -6536,7 +7131,7 @@ var LeftPanel = ({
|
|
|
6536
7131
|
...footerStyles?.container
|
|
6537
7132
|
}
|
|
6538
7133
|
},
|
|
6539
|
-
/* @__PURE__ */
|
|
7134
|
+
/* @__PURE__ */ React11.createElement(
|
|
6540
7135
|
"div",
|
|
6541
7136
|
{
|
|
6542
7137
|
className: footerClassNames?.text,
|
|
@@ -6560,40 +7155,10 @@ var LeftPanel = ({
|
|
|
6560
7155
|
|
|
6561
7156
|
// src/index.ts
|
|
6562
7157
|
var exportPdf = async (...args) => {
|
|
6563
|
-
const { exportPdf: exportPdf2 } = await import(
|
|
7158
|
+
const { exportPdf: exportPdf2 } = await import('./export-pdf-DD7J5UHW.js');
|
|
6564
7159
|
return exportPdf2(...args);
|
|
6565
7160
|
};
|
|
6566
|
-
|
|
6567
|
-
|
|
6568
|
-
|
|
6569
|
-
DrawingCanvas,
|
|
6570
|
-
DrawingHighlight,
|
|
6571
|
-
FreetextHighlight,
|
|
6572
|
-
ImageHighlight,
|
|
6573
|
-
LeftPanel,
|
|
6574
|
-
MonitoredHighlightContainer,
|
|
6575
|
-
OutlineItem,
|
|
6576
|
-
PdfHighlighter,
|
|
6577
|
-
PdfLoader,
|
|
6578
|
-
ShapeCanvas,
|
|
6579
|
-
ShapeHighlight,
|
|
6580
|
-
SignaturePad,
|
|
6581
|
-
TextHighlight,
|
|
6582
|
-
ThumbnailItem,
|
|
6583
|
-
ThumbnailPanel,
|
|
6584
|
-
exportPdf,
|
|
6585
|
-
extractPageTextItems,
|
|
6586
|
-
extractSentences,
|
|
6587
|
-
extractTextUnits,
|
|
6588
|
-
getTextPosition,
|
|
6589
|
-
scaledPositionToViewport,
|
|
6590
|
-
sentenceToHighlight,
|
|
6591
|
-
useDocumentOutline,
|
|
6592
|
-
useHighlightContainerContext,
|
|
6593
|
-
useLeftPanelContext,
|
|
6594
|
-
usePageNavigation,
|
|
6595
|
-
usePdfHighlighterContext,
|
|
6596
|
-
useThumbnails,
|
|
6597
|
-
viewportPositionToScaled
|
|
6598
|
-
};
|
|
7161
|
+
|
|
7162
|
+
export { AreaHighlight, DocumentOutline, DrawingCanvas, DrawingHighlight, FreetextHighlight, ImageHighlight, LeftPanel, MonitoredHighlightContainer, OutlineItem, PdfHighlighter, PdfLoader, ShapeCanvas, ShapeHighlight, SignaturePad, TextHighlight, ThumbnailItem, ThumbnailPanel, exportPdf, extractPageTextItems, extractSentences, extractTextUnits, getTextPosition, scaledPositionToViewport, sentenceToHighlight, useDocumentOutline, useHighlightContainerContext, useLeftPanelContext, usePageNavigation, usePdfHighlighterContext, useThumbnails, viewportPositionToScaled };
|
|
7163
|
+
//# sourceMappingURL=index.js.map
|
|
6599
7164
|
//# sourceMappingURL=index.js.map
|