react-pdf-highlighter-plus 1.2.0 → 1.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/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 +1530 -984
- 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 +30 -14
- 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
|
|
1540
|
+
const resizeObserverRef = useRef(null);
|
|
1541
|
+
const lastContainerSizeRef = useRef(null);
|
|
1542
|
+
const renderRetryTimeoutsRef = useRef(
|
|
1591
1543
|
[]
|
|
1592
1544
|
);
|
|
1593
|
-
const resumeScrollAwayTimeoutRef =
|
|
1545
|
+
const resumeScrollAwayTimeoutRef = useRef(
|
|
1594
1546
|
null
|
|
1595
1547
|
);
|
|
1596
|
-
const findControllerRef =
|
|
1597
|
-
const viewerRef =
|
|
1598
|
-
const
|
|
1599
|
-
const
|
|
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,29 @@ 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((entries) => {
|
|
1622
|
+
const rect = entries[entries.length - 1]?.contentRect;
|
|
1623
|
+
if (!rect) return;
|
|
1624
|
+
const last = lastContainerSizeRef.current;
|
|
1625
|
+
if (last && last.w === rect.width && last.h === rect.height) return;
|
|
1626
|
+
lastContainerSizeRef.current = { w: rect.width, h: rect.height };
|
|
1627
|
+
if (last) handleScaleValueRef.current();
|
|
1628
|
+
});
|
|
1669
1629
|
resizeObserverRef.current.observe(containerNodeRef.current);
|
|
1670
1630
|
const doc = containerNodeRef.current.ownerDocument;
|
|
1671
|
-
|
|
1672
|
-
eventBusRef.current.on("
|
|
1631
|
+
const handlePageRendered = () => renderHighlightLayers(true);
|
|
1632
|
+
eventBusRef.current.on("textlayerrendered", handlePageRendered);
|
|
1633
|
+
eventBusRef.current.on("pagerendered", handlePageRendered);
|
|
1673
1634
|
eventBusRef.current.on("pagesinit", handleScaleValue);
|
|
1674
1635
|
doc.addEventListener("keydown", handleKeyDown);
|
|
1675
1636
|
doc.addEventListener("copy", handleCopy, true);
|
|
1676
1637
|
scheduleRenderHighlightLayers();
|
|
1677
1638
|
return () => {
|
|
1678
1639
|
eventBusRef.current.off("pagesinit", handleScaleValue);
|
|
1679
|
-
eventBusRef.current.off("pagerendered",
|
|
1680
|
-
eventBusRef.current.off("textlayerrendered",
|
|
1640
|
+
eventBusRef.current.off("pagerendered", handlePageRendered);
|
|
1641
|
+
eventBusRef.current.off("textlayerrendered", handlePageRendered);
|
|
1681
1642
|
doc.removeEventListener("keydown", handleKeyDown);
|
|
1682
1643
|
doc.removeEventListener("copy", handleCopy, true);
|
|
1683
1644
|
resizeObserverRef.current?.disconnect();
|
|
@@ -1689,21 +1650,21 @@ var PdfHighlighter = ({
|
|
|
1689
1650
|
}
|
|
1690
1651
|
};
|
|
1691
1652
|
}, [selectionTip, highlights, onSelectionFinished]);
|
|
1692
|
-
|
|
1653
|
+
useEffect(() => {
|
|
1693
1654
|
return () => {
|
|
1694
1655
|
for (const binding of Object.values(highlightBindingsRef.current))
|
|
1695
|
-
unmountReactRoot(binding
|
|
1656
|
+
unmountReactRoot(binding);
|
|
1696
1657
|
for (const binding of Object.values(noteBindingsRef.current))
|
|
1697
|
-
unmountReactRoot(binding
|
|
1658
|
+
unmountReactRoot(binding);
|
|
1698
1659
|
};
|
|
1699
1660
|
}, []);
|
|
1700
|
-
const onPageChangeRef =
|
|
1661
|
+
const onPageChangeRef = useRef(onPageChange);
|
|
1701
1662
|
onPageChangeRef.current = onPageChange;
|
|
1702
|
-
const initialPageRef =
|
|
1663
|
+
const initialPageRef = useRef(initialPage);
|
|
1703
1664
|
initialPageRef.current = initialPage;
|
|
1704
|
-
const initialPageAppliedRef =
|
|
1705
|
-
const pendingInitialPageRef =
|
|
1706
|
-
|
|
1665
|
+
const initialPageAppliedRef = useRef(false);
|
|
1666
|
+
const pendingInitialPageRef = useRef(null);
|
|
1667
|
+
useEffect(() => {
|
|
1707
1668
|
const eventBus = eventBusRef.current;
|
|
1708
1669
|
const handlePageChanging = (evt) => {
|
|
1709
1670
|
if (pendingInitialPageRef.current != null) return;
|
|
@@ -1755,14 +1716,14 @@ var PdfHighlighter = ({
|
|
|
1755
1716
|
pendingInitialPageRef.current = null;
|
|
1756
1717
|
};
|
|
1757
1718
|
}, []);
|
|
1758
|
-
const onZoomChangeRef =
|
|
1719
|
+
const onZoomChangeRef = useRef(onZoomChange);
|
|
1759
1720
|
onZoomChangeRef.current = onZoomChange;
|
|
1760
|
-
|
|
1721
|
+
useEffect(() => {
|
|
1761
1722
|
const container = containerNodeRef.current;
|
|
1762
1723
|
if (!container || !isViewerReady) return;
|
|
1763
1724
|
const MIN_SCALE = 0.25;
|
|
1764
1725
|
const MAX_SCALE = 10;
|
|
1765
|
-
const COMMIT_DELAY =
|
|
1726
|
+
const COMMIT_DELAY = 280;
|
|
1766
1727
|
const g = {
|
|
1767
1728
|
active: false,
|
|
1768
1729
|
startScale: 1,
|
|
@@ -1826,10 +1787,11 @@ var PdfHighlighter = ({
|
|
|
1826
1787
|
Math.max(MIN_SCALE, g.startScale * g.k)
|
|
1827
1788
|
);
|
|
1828
1789
|
const ratio = finalScale / g.startScale;
|
|
1790
|
+
if (Math.abs(ratio - 1) < 1e-3) return;
|
|
1829
1791
|
viewer.currentScaleValue = String(finalScale);
|
|
1830
1792
|
container.scrollLeft = g.originX * ratio - g.anchorX;
|
|
1831
1793
|
container.scrollTop = g.originY * ratio - g.anchorY;
|
|
1832
|
-
onZoomChangeRef.current?.(finalScale);
|
|
1794
|
+
setTimeout(() => onZoomChangeRef.current?.(finalScale), 0);
|
|
1833
1795
|
console.log("[PdfHighlighter] pinch commit", {
|
|
1834
1796
|
from: g.startScale,
|
|
1835
1797
|
to: finalScale
|
|
@@ -1842,11 +1804,12 @@ var PdfHighlighter = ({
|
|
|
1842
1804
|
const handleWheel = (e) => {
|
|
1843
1805
|
if (!e.ctrlKey && !e.metaKey) return;
|
|
1844
1806
|
e.preventDefault();
|
|
1845
|
-
|
|
1846
|
-
|
|
1847
|
-
|
|
1848
|
-
|
|
1849
|
-
|
|
1807
|
+
if (!g.active) {
|
|
1808
|
+
const rect = container.getBoundingClientRect();
|
|
1809
|
+
if (!begin(e.clientX - rect.left, e.clientY - rect.top)) return;
|
|
1810
|
+
}
|
|
1811
|
+
const delta = e.deltaMode === 1 ? e.deltaY * 16 : e.deltaMode === 2 ? e.deltaY * 100 : e.deltaY;
|
|
1812
|
+
g.k = clampK(g.k * Math.exp(-delta * 0.01));
|
|
1850
1813
|
preview();
|
|
1851
1814
|
scheduleCommit();
|
|
1852
1815
|
};
|
|
@@ -2042,20 +2005,26 @@ var PdfHighlighter = ({
|
|
|
2042
2005
|
event.stopPropagation();
|
|
2043
2006
|
};
|
|
2044
2007
|
const handleScaleValue = () => {
|
|
2045
|
-
|
|
2046
|
-
|
|
2008
|
+
const viewer = viewerRef.current;
|
|
2009
|
+
if (!viewer) return;
|
|
2010
|
+
const target = parseFloat(String(pdfScaleValue));
|
|
2011
|
+
if (!Number.isNaN(target) && Math.abs(viewer.currentScale - target) / target < 5e-3) {
|
|
2012
|
+
return;
|
|
2047
2013
|
}
|
|
2014
|
+
viewer.currentScaleValue = pdfScaleValue.toString();
|
|
2048
2015
|
};
|
|
2049
|
-
const
|
|
2016
|
+
const handleScaleValueRef = useRef(handleScaleValue);
|
|
2017
|
+
handleScaleValueRef.current = handleScaleValue;
|
|
2018
|
+
useEffect(() => {
|
|
2019
|
+
handleScaleValueRef.current();
|
|
2020
|
+
}, [pdfScaleValue, isViewerReady]);
|
|
2021
|
+
const renderHighlightLayer = (highlightBindings, pageNumber, highlightsByPage, shouldRenderHighlight) => {
|
|
2050
2022
|
if (!viewerRef.current) return;
|
|
2051
2023
|
highlightBindings.reactRoot.render(
|
|
2052
|
-
/* @__PURE__ */
|
|
2024
|
+
/* @__PURE__ */ React11.createElement(PdfHighlighterContext.Provider, { value: pdfHighlighterUtils }, /* @__PURE__ */ React11.createElement(
|
|
2053
2025
|
HighlightLayer,
|
|
2054
2026
|
{
|
|
2055
|
-
highlightsByPage
|
|
2056
|
-
...highlightsRef.current,
|
|
2057
|
-
ghostHighlightRef.current
|
|
2058
|
-
]),
|
|
2027
|
+
highlightsByPage,
|
|
2059
2028
|
pageNumber,
|
|
2060
2029
|
scrolledToHighlightId: scrolledToHighlightIdRef.current,
|
|
2061
2030
|
viewer: viewerRef.current,
|
|
@@ -2066,40 +2035,61 @@ var PdfHighlighter = ({
|
|
|
2066
2035
|
))
|
|
2067
2036
|
);
|
|
2068
2037
|
};
|
|
2069
|
-
const
|
|
2038
|
+
const renderVersionRef = useRef(0);
|
|
2039
|
+
const pageRenderedVersionRef = useRef({});
|
|
2040
|
+
const renderHighlightLayers = (onlyStalePages = false) => {
|
|
2070
2041
|
if (!viewerRef.current) return;
|
|
2042
|
+
if (!onlyStalePages) renderVersionRef.current += 1;
|
|
2043
|
+
const version = renderVersionRef.current;
|
|
2044
|
+
const highlightsByPage = group_highlights_by_page_default([
|
|
2045
|
+
...highlightsRef.current,
|
|
2046
|
+
ghostHighlightRef.current
|
|
2047
|
+
]);
|
|
2071
2048
|
for (let pageNumber = 1; pageNumber <= pdfDocument.numPages; pageNumber++) {
|
|
2072
2049
|
const { textLayer } = viewerRef.current.getPageView(pageNumber - 1) || {};
|
|
2073
2050
|
if (!textLayer) continue;
|
|
2074
2051
|
const textLayerDiv = textLayer.div;
|
|
2052
|
+
const pageEl = textLayerDiv.closest(".page");
|
|
2053
|
+
if (!pageEl) continue;
|
|
2054
|
+
const existingBinding = highlightBindingsRef.current[pageNumber];
|
|
2055
|
+
const layerRebuilt = !existingBinding || existingBinding.container.parentNode !== pageEl;
|
|
2056
|
+
if (onlyStalePages && !layerRebuilt && pageRenderedVersionRef.current[pageNumber] === version) {
|
|
2057
|
+
continue;
|
|
2058
|
+
}
|
|
2075
2059
|
const highlightBindings = ensurePersistentLayer(
|
|
2076
2060
|
highlightBindingsRef.current,
|
|
2077
2061
|
pageNumber,
|
|
2078
|
-
|
|
2062
|
+
pageEl,
|
|
2079
2063
|
"PdfHighlighter__highlight-layer"
|
|
2080
2064
|
);
|
|
2081
2065
|
renderHighlightLayer(
|
|
2082
2066
|
highlightBindings,
|
|
2083
2067
|
pageNumber,
|
|
2084
|
-
|
|
2068
|
+
highlightsByPage,
|
|
2069
|
+
(highlight) => !needsOpaqueLayer(highlight)
|
|
2085
2070
|
);
|
|
2086
|
-
|
|
2087
|
-
if (pageEl) {
|
|
2071
|
+
{
|
|
2088
2072
|
const noteBindings = ensurePersistentLayer(
|
|
2089
2073
|
noteBindingsRef.current,
|
|
2090
2074
|
pageNumber,
|
|
2091
2075
|
pageEl,
|
|
2092
2076
|
"PdfHighlighter__note-layer"
|
|
2093
2077
|
);
|
|
2094
|
-
renderHighlightLayer(
|
|
2078
|
+
renderHighlightLayer(
|
|
2079
|
+
noteBindings,
|
|
2080
|
+
pageNumber,
|
|
2081
|
+
highlightsByPage,
|
|
2082
|
+
needsOpaqueLayer
|
|
2083
|
+
);
|
|
2095
2084
|
}
|
|
2085
|
+
pageRenderedVersionRef.current[pageNumber] = version;
|
|
2096
2086
|
}
|
|
2097
2087
|
};
|
|
2098
2088
|
const scheduleRenderHighlightLayers = () => {
|
|
2099
2089
|
renderHighlightLayers();
|
|
2100
2090
|
renderRetryTimeoutsRef.current.forEach(clearTimeout);
|
|
2101
|
-
renderRetryTimeoutsRef.current = [50,
|
|
2102
|
-
(delay) => setTimeout(renderHighlightLayers, delay)
|
|
2091
|
+
renderRetryTimeoutsRef.current = [50, 250, 1200].map(
|
|
2092
|
+
(delay) => setTimeout(() => renderHighlightLayers(true), delay)
|
|
2103
2093
|
);
|
|
2104
2094
|
};
|
|
2105
2095
|
const resumeScrollAwayListenerAfterNavigation = () => {
|
|
@@ -2185,7 +2175,7 @@ var PdfHighlighter = ({
|
|
|
2185
2175
|
matchDiacritics: options.matchDiacritics ?? false
|
|
2186
2176
|
});
|
|
2187
2177
|
};
|
|
2188
|
-
const currentSearchRef =
|
|
2178
|
+
const currentSearchRef = useRef({
|
|
2189
2179
|
query: "",
|
|
2190
2180
|
options: {}
|
|
2191
2181
|
});
|
|
@@ -2213,8 +2203,15 @@ var PdfHighlighter = ({
|
|
|
2213
2203
|
source: findControllerRef.current || viewerRef.current
|
|
2214
2204
|
});
|
|
2215
2205
|
};
|
|
2216
|
-
const
|
|
2206
|
+
const latestUtils = {
|
|
2217
2207
|
isEditingOrHighlighting,
|
|
2208
|
+
setHighlightSelected: (selected) => {
|
|
2209
|
+
selectedHighlightCountRef.current = Math.max(
|
|
2210
|
+
0,
|
|
2211
|
+
selectedHighlightCountRef.current + (selected ? 1 : -1)
|
|
2212
|
+
);
|
|
2213
|
+
},
|
|
2214
|
+
isHighlightSelected: () => selectedHighlightCountRef.current > 0,
|
|
2218
2215
|
getCurrentSelection: () => selectionRef.current,
|
|
2219
2216
|
getGhostHighlight: () => ghostHighlightRef.current,
|
|
2220
2217
|
removeGhostHighlight,
|
|
@@ -2292,8 +2289,19 @@ var PdfHighlighter = ({
|
|
|
2292
2289
|
}
|
|
2293
2290
|
}
|
|
2294
2291
|
};
|
|
2295
|
-
const
|
|
2296
|
-
|
|
2292
|
+
const latestUtilsRef = useRef(latestUtils);
|
|
2293
|
+
latestUtilsRef.current = latestUtils;
|
|
2294
|
+
const stableUtilsRef = useRef(null);
|
|
2295
|
+
if (!stableUtilsRef.current) {
|
|
2296
|
+
const facade = {};
|
|
2297
|
+
for (const key of Object.keys(latestUtils)) {
|
|
2298
|
+
facade[key] = (...args) => latestUtilsRef.current[key](...args);
|
|
2299
|
+
}
|
|
2300
|
+
stableUtilsRef.current = facade;
|
|
2301
|
+
}
|
|
2302
|
+
const pdfHighlighterUtils = stableUtilsRef.current;
|
|
2303
|
+
const utilsRefCalledRef = useRef(false);
|
|
2304
|
+
useEffect(() => {
|
|
2297
2305
|
if (viewerRef.current && !utilsRefCalledRef.current) {
|
|
2298
2306
|
utilsRefCalledRef.current = true;
|
|
2299
2307
|
utilsRef(pdfHighlighterUtils);
|
|
@@ -2312,7 +2320,7 @@ var PdfHighlighter = ({
|
|
|
2312
2320
|
...style,
|
|
2313
2321
|
backgroundColor: resolvedTheme.containerBackgroundColor
|
|
2314
2322
|
};
|
|
2315
|
-
return /* @__PURE__ */
|
|
2323
|
+
return /* @__PURE__ */ React11.createElement(PdfHighlighterContext.Provider, { value: pdfHighlighterUtils }, /* @__PURE__ */ React11.createElement(
|
|
2316
2324
|
"div",
|
|
2317
2325
|
{
|
|
2318
2326
|
ref: containerNodeRef,
|
|
@@ -2321,27 +2329,27 @@ var PdfHighlighter = ({
|
|
|
2321
2329
|
onPointerUp: handleMouseUp,
|
|
2322
2330
|
style: containerStyle
|
|
2323
2331
|
},
|
|
2324
|
-
/* @__PURE__ */
|
|
2325
|
-
/* @__PURE__ */
|
|
2332
|
+
/* @__PURE__ */ React11.createElement("div", { className: "pdfViewer" }),
|
|
2333
|
+
/* @__PURE__ */ React11.createElement("style", null, `
|
|
2326
2334
|
.textLayer ::selection {
|
|
2327
|
-
background: ${textSelectionColor};
|
|
2335
|
+
background: ${sanitizeCssColor(textSelectionColor, DEFAULT_TEXT_SELECTION_COLOR)};
|
|
2328
2336
|
}
|
|
2329
2337
|
.PdfHighlighter::-webkit-scrollbar-thumb {
|
|
2330
|
-
background-color: ${resolvedTheme.scrollbarThumbColor};
|
|
2338
|
+
background-color: ${sanitizeCssColor(resolvedTheme.scrollbarThumbColor, "#9f9f9f")};
|
|
2331
2339
|
}
|
|
2332
2340
|
.PdfHighlighter::-webkit-scrollbar-track,
|
|
2333
2341
|
.PdfHighlighter::-webkit-scrollbar-track-piece {
|
|
2334
|
-
background-color: ${resolvedTheme.scrollbarTrackColor};
|
|
2342
|
+
background-color: ${sanitizeCssColor(resolvedTheme.scrollbarTrackColor, "#d1d1d1")};
|
|
2335
2343
|
}
|
|
2336
2344
|
`),
|
|
2337
|
-
isViewerReady && /* @__PURE__ */
|
|
2345
|
+
isViewerReady && /* @__PURE__ */ React11.createElement(
|
|
2338
2346
|
TipContainer,
|
|
2339
2347
|
{
|
|
2340
2348
|
viewer: viewerRef.current,
|
|
2341
2349
|
updateTipPositionRef
|
|
2342
2350
|
}
|
|
2343
2351
|
),
|
|
2344
|
-
isViewerReady && enableAreaSelection && /* @__PURE__ */
|
|
2352
|
+
isViewerReady && enableAreaSelection && /* @__PURE__ */ React11.createElement(
|
|
2345
2353
|
MouseSelection,
|
|
2346
2354
|
{
|
|
2347
2355
|
viewer: viewerRef.current,
|
|
@@ -2375,7 +2383,7 @@ var PdfHighlighter = ({
|
|
|
2375
2383
|
}
|
|
2376
2384
|
}
|
|
2377
2385
|
),
|
|
2378
|
-
isViewerReady && enableDrawingMode && /* @__PURE__ */
|
|
2386
|
+
isViewerReady && enableDrawingMode && /* @__PURE__ */ React11.createElement(
|
|
2379
2387
|
DrawingCanvas,
|
|
2380
2388
|
{
|
|
2381
2389
|
isActive: enableDrawingMode,
|
|
@@ -2392,7 +2400,7 @@ var PdfHighlighter = ({
|
|
|
2392
2400
|
}
|
|
2393
2401
|
}
|
|
2394
2402
|
),
|
|
2395
|
-
isViewerReady && enableShapeMode && /* @__PURE__ */
|
|
2403
|
+
isViewerReady && enableShapeMode && /* @__PURE__ */ React11.createElement(
|
|
2396
2404
|
ShapeCanvas,
|
|
2397
2405
|
{
|
|
2398
2406
|
isActive: !!enableShapeMode,
|
|
@@ -2413,15 +2421,6 @@ var PdfHighlighter = ({
|
|
|
2413
2421
|
));
|
|
2414
2422
|
};
|
|
2415
2423
|
|
|
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
2424
|
// src/lib/copy-highlight-content.ts
|
|
2426
2425
|
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
2426
|
var copyTextToClipboard = async (text) => {
|
|
@@ -2485,13 +2484,15 @@ var findOrCreateHighlightConfigLayer = (anchor) => {
|
|
|
2485
2484
|
};
|
|
2486
2485
|
|
|
2487
2486
|
// 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
|
|
2487
|
+
var DefaultStyleIcon = () => /* @__PURE__ */ React11.createElement(Palette, { width: 14, height: 14 });
|
|
2488
|
+
var DefaultDeleteIcon = () => /* @__PURE__ */ React11.createElement(Trash2, { width: 14, height: 14 });
|
|
2489
|
+
var DefaultCopyIcon = () => /* @__PURE__ */ React11.createElement(Copy, { width: 14, height: 14 });
|
|
2490
|
+
var DefaultCopiedIcon = () => /* @__PURE__ */ React11.createElement(Check, { width: 14, height: 14, strokeWidth: 2.5 });
|
|
2491
|
+
var ChevronDownIcon = () => /* @__PURE__ */ React11.createElement(ChevronDown, { width: 12, height: 12, strokeWidth: 2.5 });
|
|
2492
|
+
var CheckIcon = () => /* @__PURE__ */ React11.createElement(Check, { width: 14, height: 14, strokeWidth: 2.5 });
|
|
2493
|
+
var HighlightIcon = () => /* @__PURE__ */ React11.createElement(Highlighter, { width: 16, height: 16 });
|
|
2494
|
+
var UnderlineIcon = () => /* @__PURE__ */ React11.createElement(Underline, { width: 16, height: 16 });
|
|
2495
|
+
var StrikethroughIcon = () => /* @__PURE__ */ React11.createElement(Strikethrough, { width: 16, height: 16 });
|
|
2495
2496
|
var DEFAULT_COLOR_PRESETS = [
|
|
2496
2497
|
"rgba(255, 226, 143, 1)",
|
|
2497
2498
|
// Yellow (default)
|
|
@@ -2504,7 +2505,14 @@ var DEFAULT_COLOR_PRESETS = [
|
|
|
2504
2505
|
"#e1bee7"
|
|
2505
2506
|
// Light purple
|
|
2506
2507
|
];
|
|
2507
|
-
var
|
|
2508
|
+
var COLOR_NAMES = {
|
|
2509
|
+
"rgba(255, 226, 143, 1)": "Yellow",
|
|
2510
|
+
"#ffcdd2": "Red",
|
|
2511
|
+
"#c8e6c9": "Green",
|
|
2512
|
+
"#bbdefb": "Blue",
|
|
2513
|
+
"#e1bee7": "Purple"
|
|
2514
|
+
};
|
|
2515
|
+
var TextHighlight = memo(({
|
|
2508
2516
|
highlight,
|
|
2509
2517
|
onClick,
|
|
2510
2518
|
onMouseOver,
|
|
@@ -2519,28 +2527,60 @@ var TextHighlight = ({
|
|
|
2519
2527
|
styleIcon,
|
|
2520
2528
|
deleteIcon,
|
|
2521
2529
|
copyText,
|
|
2522
|
-
colorPresets = DEFAULT_COLOR_PRESETS
|
|
2530
|
+
colorPresets = DEFAULT_COLOR_PRESETS,
|
|
2531
|
+
extraButtons,
|
|
2532
|
+
extraPanel
|
|
2523
2533
|
}) => {
|
|
2524
|
-
const [isStylePanelOpen, setIsStylePanelOpen] =
|
|
2525
|
-
const [
|
|
2526
|
-
const [
|
|
2527
|
-
const [
|
|
2528
|
-
const
|
|
2529
|
-
const
|
|
2530
|
-
const
|
|
2531
|
-
|
|
2534
|
+
const [isStylePanelOpen, setIsStylePanelOpen] = useState(false);
|
|
2535
|
+
const [isColorMenuOpen, setIsColorMenuOpen] = useState(false);
|
|
2536
|
+
const [isSelected, setIsSelected] = useState(false);
|
|
2537
|
+
const [isCopied, setIsCopied] = useState(false);
|
|
2538
|
+
const [configLayer, setConfigLayer] = useState(null);
|
|
2539
|
+
const stylePanelRef = useRef(null);
|
|
2540
|
+
const colorMenuRef = useRef(null);
|
|
2541
|
+
const containerRef = useRef(null);
|
|
2542
|
+
const toolbarWrapperRef = useRef(null);
|
|
2543
|
+
const copyResetTimeoutRef = useRef(null);
|
|
2544
|
+
useEffect(() => {
|
|
2545
|
+
if (!isSelected) return;
|
|
2546
|
+
const handlePointerDown = (e) => {
|
|
2547
|
+
const target = e.target;
|
|
2548
|
+
const insideRoot = containerRef.current?.contains(target);
|
|
2549
|
+
const insideToolbar = toolbarWrapperRef.current?.contains(target);
|
|
2550
|
+
if (!insideRoot && !insideToolbar) {
|
|
2551
|
+
setIsSelected(false);
|
|
2552
|
+
setIsStylePanelOpen(false);
|
|
2553
|
+
setIsColorMenuOpen(false);
|
|
2554
|
+
}
|
|
2555
|
+
};
|
|
2556
|
+
const handleKey = (e) => {
|
|
2557
|
+
if (e.key === "Escape") {
|
|
2558
|
+
setIsSelected(false);
|
|
2559
|
+
setIsStylePanelOpen(false);
|
|
2560
|
+
setIsColorMenuOpen(false);
|
|
2561
|
+
}
|
|
2562
|
+
};
|
|
2563
|
+
document.addEventListener("mousedown", handlePointerDown);
|
|
2564
|
+
document.addEventListener("keydown", handleKey);
|
|
2565
|
+
return () => {
|
|
2566
|
+
document.removeEventListener("mousedown", handlePointerDown);
|
|
2567
|
+
document.removeEventListener("keydown", handleKey);
|
|
2568
|
+
};
|
|
2569
|
+
}, [isSelected]);
|
|
2570
|
+
useLayoutEffect(() => {
|
|
2532
2571
|
if (containerRef.current) {
|
|
2533
|
-
|
|
2572
|
+
const layer = findOrCreateHighlightConfigLayer(containerRef.current);
|
|
2573
|
+
setConfigLayer((prev) => prev === layer ? prev : layer);
|
|
2534
2574
|
}
|
|
2535
|
-
}
|
|
2536
|
-
|
|
2575
|
+
});
|
|
2576
|
+
useEffect(() => {
|
|
2537
2577
|
return () => {
|
|
2538
2578
|
if (copyResetTimeoutRef.current) {
|
|
2539
2579
|
window.clearTimeout(copyResetTimeoutRef.current);
|
|
2540
2580
|
}
|
|
2541
2581
|
};
|
|
2542
2582
|
}, []);
|
|
2543
|
-
|
|
2583
|
+
useEffect(() => {
|
|
2544
2584
|
if (!isStylePanelOpen) return;
|
|
2545
2585
|
const handleClickOutside = (e) => {
|
|
2546
2586
|
if (stylePanelRef.current && !stylePanelRef.current.contains(e.target)) {
|
|
@@ -2555,9 +2595,26 @@ var TextHighlight = ({
|
|
|
2555
2595
|
document.removeEventListener("mousedown", handleClickOutside);
|
|
2556
2596
|
};
|
|
2557
2597
|
}, [isStylePanelOpen]);
|
|
2598
|
+
useEffect(() => {
|
|
2599
|
+
if (!isColorMenuOpen) return;
|
|
2600
|
+
const handleClickOutside = (e) => {
|
|
2601
|
+
if (colorMenuRef.current && !colorMenuRef.current.contains(e.target)) {
|
|
2602
|
+
setIsColorMenuOpen(false);
|
|
2603
|
+
}
|
|
2604
|
+
};
|
|
2605
|
+
const timeoutId = setTimeout(() => {
|
|
2606
|
+
document.addEventListener("mousedown", handleClickOutside);
|
|
2607
|
+
}, 0);
|
|
2608
|
+
return () => {
|
|
2609
|
+
clearTimeout(timeoutId);
|
|
2610
|
+
document.removeEventListener("mousedown", handleClickOutside);
|
|
2611
|
+
};
|
|
2612
|
+
}, [isColorMenuOpen]);
|
|
2558
2613
|
const highlightClass = isScrolledTo ? "TextHighlight--scrolledTo" : "";
|
|
2614
|
+
const selectedClass = isSelected ? "TextHighlight--selected" : "";
|
|
2559
2615
|
const { rects } = highlight.position;
|
|
2560
2616
|
const firstRect = rects[0];
|
|
2617
|
+
const flipToolbar = !!firstRect && firstRect.top < 40;
|
|
2561
2618
|
const getPartStyleClass = () => {
|
|
2562
2619
|
switch (highlightStyle) {
|
|
2563
2620
|
case "underline":
|
|
@@ -2591,46 +2648,68 @@ var TextHighlight = ({
|
|
|
2591
2648
|
copyResetTimeoutRef.current = null;
|
|
2592
2649
|
}, 1500);
|
|
2593
2650
|
};
|
|
2594
|
-
return /* @__PURE__ */
|
|
2651
|
+
return /* @__PURE__ */ React11.createElement(
|
|
2595
2652
|
"div",
|
|
2596
2653
|
{
|
|
2597
|
-
className: `TextHighlight ${highlightClass}`,
|
|
2654
|
+
className: `TextHighlight ${highlightClass} ${selectedClass}`,
|
|
2598
2655
|
onContextMenu,
|
|
2599
2656
|
ref: containerRef
|
|
2600
2657
|
},
|
|
2601
2658
|
configLayer && (onStyleChange || onDelete) && firstRect && createPortal(
|
|
2602
|
-
/* @__PURE__ */
|
|
2659
|
+
/* @__PURE__ */ React11.createElement(
|
|
2603
2660
|
"div",
|
|
2604
2661
|
{
|
|
2605
2662
|
className: "TextHighlight__toolbar-wrapper",
|
|
2663
|
+
ref: toolbarWrapperRef,
|
|
2606
2664
|
style: {
|
|
2607
2665
|
position: "absolute",
|
|
2608
2666
|
left: firstRect.left,
|
|
2609
|
-
top: firstRect.top
|
|
2610
|
-
|
|
2611
|
-
},
|
|
2612
|
-
onMouseEnter: () => setIsHovered(true),
|
|
2613
|
-
onMouseLeave: () => setIsHovered(false)
|
|
2667
|
+
top: firstRect.top
|
|
2668
|
+
}
|
|
2614
2669
|
},
|
|
2615
|
-
/* @__PURE__ */
|
|
2670
|
+
/* @__PURE__ */ React11.createElement(
|
|
2616
2671
|
"div",
|
|
2617
2672
|
{
|
|
2618
|
-
className: `TextHighlight__toolbar ${
|
|
2673
|
+
className: `TextHighlight__toolbar ${flipToolbar ? "TextHighlight__toolbar--below" : ""} ${isSelected || isScrolledTo || isStylePanelOpen || isColorMenuOpen ? "TextHighlight__toolbar--visible" : ""}`
|
|
2619
2674
|
},
|
|
2620
|
-
onStyleChange && /* @__PURE__ */
|
|
2675
|
+
onStyleChange && /* @__PURE__ */ React11.createElement(React11.Fragment, null, /* @__PURE__ */ React11.createElement(
|
|
2676
|
+
"button",
|
|
2677
|
+
{
|
|
2678
|
+
type: "button",
|
|
2679
|
+
className: "TextHighlight__color-trigger",
|
|
2680
|
+
"aria-label": "Highlight color",
|
|
2681
|
+
"aria-expanded": isColorMenuOpen,
|
|
2682
|
+
onClick: (e) => {
|
|
2683
|
+
e.stopPropagation();
|
|
2684
|
+
setIsStylePanelOpen(false);
|
|
2685
|
+
setIsColorMenuOpen((v) => !v);
|
|
2686
|
+
},
|
|
2687
|
+
title: "Highlight color"
|
|
2688
|
+
},
|
|
2689
|
+
/* @__PURE__ */ React11.createElement(
|
|
2690
|
+
"span",
|
|
2691
|
+
{
|
|
2692
|
+
className: "TextHighlight__color-trigger-dot",
|
|
2693
|
+
style: { backgroundColor: highlightColor }
|
|
2694
|
+
}
|
|
2695
|
+
),
|
|
2696
|
+
/* @__PURE__ */ React11.createElement(ChevronDownIcon, null)
|
|
2697
|
+
), /* @__PURE__ */ React11.createElement("div", { className: "TextHighlight__toolbar-divider" })),
|
|
2698
|
+
onStyleChange && /* @__PURE__ */ React11.createElement(
|
|
2621
2699
|
"button",
|
|
2622
2700
|
{
|
|
2623
2701
|
className: "TextHighlight__style-button",
|
|
2624
2702
|
onClick: (e) => {
|
|
2625
2703
|
e.stopPropagation();
|
|
2704
|
+
setIsColorMenuOpen(false);
|
|
2626
2705
|
setIsStylePanelOpen(!isStylePanelOpen);
|
|
2627
2706
|
},
|
|
2628
2707
|
title: "Change style",
|
|
2629
2708
|
type: "button"
|
|
2630
2709
|
},
|
|
2631
|
-
styleIcon || /* @__PURE__ */
|
|
2710
|
+
styleIcon || /* @__PURE__ */ React11.createElement(DefaultStyleIcon, null)
|
|
2632
2711
|
),
|
|
2633
|
-
/* @__PURE__ */
|
|
2712
|
+
/* @__PURE__ */ React11.createElement(
|
|
2634
2713
|
"button",
|
|
2635
2714
|
{
|
|
2636
2715
|
className: "TextHighlight__copy-button",
|
|
@@ -2638,9 +2717,10 @@ var TextHighlight = ({
|
|
|
2638
2717
|
title: isCopied ? "Copied" : "Copy text",
|
|
2639
2718
|
type: "button"
|
|
2640
2719
|
},
|
|
2641
|
-
isCopied ? /* @__PURE__ */
|
|
2720
|
+
isCopied ? /* @__PURE__ */ React11.createElement(DefaultCopiedIcon, null) : /* @__PURE__ */ React11.createElement(DefaultCopyIcon, null)
|
|
2642
2721
|
),
|
|
2643
|
-
|
|
2722
|
+
extraButtons,
|
|
2723
|
+
onDelete && /* @__PURE__ */ React11.createElement(
|
|
2644
2724
|
"button",
|
|
2645
2725
|
{
|
|
2646
2726
|
className: "TextHighlight__delete-button",
|
|
@@ -2651,17 +2731,17 @@ var TextHighlight = ({
|
|
|
2651
2731
|
title: "Delete",
|
|
2652
2732
|
type: "button"
|
|
2653
2733
|
},
|
|
2654
|
-
deleteIcon || /* @__PURE__ */
|
|
2734
|
+
deleteIcon || /* @__PURE__ */ React11.createElement(DefaultDeleteIcon, null)
|
|
2655
2735
|
)
|
|
2656
2736
|
),
|
|
2657
|
-
isStylePanelOpen && onStyleChange && /* @__PURE__ */
|
|
2737
|
+
isStylePanelOpen && onStyleChange && /* @__PURE__ */ React11.createElement(
|
|
2658
2738
|
"div",
|
|
2659
2739
|
{
|
|
2660
2740
|
className: "TextHighlight__style-panel",
|
|
2661
2741
|
ref: stylePanelRef,
|
|
2662
2742
|
onClick: (e) => e.stopPropagation()
|
|
2663
2743
|
},
|
|
2664
|
-
/* @__PURE__ */
|
|
2744
|
+
/* @__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
2745
|
"button",
|
|
2666
2746
|
{
|
|
2667
2747
|
type: "button",
|
|
@@ -2669,8 +2749,8 @@ var TextHighlight = ({
|
|
|
2669
2749
|
onClick: () => onStyleChange({ highlightStyle: "highlight" }),
|
|
2670
2750
|
title: "Highlight"
|
|
2671
2751
|
},
|
|
2672
|
-
/* @__PURE__ */
|
|
2673
|
-
), /* @__PURE__ */
|
|
2752
|
+
/* @__PURE__ */ React11.createElement(HighlightIcon, null)
|
|
2753
|
+
), /* @__PURE__ */ React11.createElement(
|
|
2674
2754
|
"button",
|
|
2675
2755
|
{
|
|
2676
2756
|
type: "button",
|
|
@@ -2678,8 +2758,8 @@ var TextHighlight = ({
|
|
|
2678
2758
|
onClick: () => onStyleChange({ highlightStyle: "underline" }),
|
|
2679
2759
|
title: "Underline"
|
|
2680
2760
|
},
|
|
2681
|
-
/* @__PURE__ */
|
|
2682
|
-
), /* @__PURE__ */
|
|
2761
|
+
/* @__PURE__ */ React11.createElement(UnderlineIcon, null)
|
|
2762
|
+
), /* @__PURE__ */ React11.createElement(
|
|
2683
2763
|
"button",
|
|
2684
2764
|
{
|
|
2685
2765
|
type: "button",
|
|
@@ -2687,45 +2767,56 @@ var TextHighlight = ({
|
|
|
2687
2767
|
onClick: () => onStyleChange({ highlightStyle: "strikethrough" }),
|
|
2688
2768
|
title: "Strikethrough"
|
|
2689
2769
|
},
|
|
2690
|
-
/* @__PURE__ */
|
|
2691
|
-
)))
|
|
2692
|
-
|
|
2770
|
+
/* @__PURE__ */ React11.createElement(StrikethroughIcon, null)
|
|
2771
|
+
)))
|
|
2772
|
+
),
|
|
2773
|
+
isColorMenuOpen && onStyleChange && /* @__PURE__ */ React11.createElement(
|
|
2774
|
+
"div",
|
|
2775
|
+
{
|
|
2776
|
+
className: "TextHighlight__color-menu",
|
|
2777
|
+
ref: colorMenuRef,
|
|
2778
|
+
onClick: (e) => e.stopPropagation()
|
|
2779
|
+
},
|
|
2780
|
+
colorPresets.map((c) => /* @__PURE__ */ React11.createElement(
|
|
2693
2781
|
"button",
|
|
2694
2782
|
{
|
|
2695
2783
|
key: c,
|
|
2696
2784
|
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 });
|
|
2785
|
+
className: "TextHighlight__color-menu-item",
|
|
2786
|
+
onClick: () => {
|
|
2787
|
+
onStyleChange({ highlightColor: c });
|
|
2788
|
+
setIsColorMenuOpen(false);
|
|
2709
2789
|
}
|
|
2710
|
-
}
|
|
2711
|
-
|
|
2712
|
-
|
|
2790
|
+
},
|
|
2791
|
+
/* @__PURE__ */ React11.createElement(
|
|
2792
|
+
"span",
|
|
2793
|
+
{
|
|
2794
|
+
className: "TextHighlight__color-menu-dot",
|
|
2795
|
+
style: { backgroundColor: c }
|
|
2796
|
+
}
|
|
2797
|
+
),
|
|
2798
|
+
/* @__PURE__ */ React11.createElement("span", { className: "TextHighlight__color-menu-label" }, COLOR_NAMES[c] || c),
|
|
2799
|
+
highlightColor === c && /* @__PURE__ */ React11.createElement("span", { className: "TextHighlight__color-menu-check" }, /* @__PURE__ */ React11.createElement(CheckIcon, null))
|
|
2800
|
+
))
|
|
2801
|
+
),
|
|
2802
|
+
extraPanel
|
|
2713
2803
|
),
|
|
2714
2804
|
configLayer
|
|
2715
2805
|
),
|
|
2716
|
-
/* @__PURE__ */
|
|
2806
|
+
/* @__PURE__ */ React11.createElement(
|
|
2717
2807
|
"div",
|
|
2718
2808
|
{
|
|
2719
|
-
className: "TextHighlight__parts"
|
|
2720
|
-
onMouseEnter: () => setIsHovered(true),
|
|
2721
|
-
onMouseLeave: () => setIsHovered(false)
|
|
2809
|
+
className: "TextHighlight__parts"
|
|
2722
2810
|
},
|
|
2723
|
-
rects.map((rect, index) => /* @__PURE__ */
|
|
2811
|
+
rects.map((rect, index) => /* @__PURE__ */ React11.createElement(
|
|
2724
2812
|
"div",
|
|
2725
2813
|
{
|
|
2726
2814
|
onMouseOver,
|
|
2727
2815
|
onMouseOut,
|
|
2728
|
-
onClick
|
|
2816
|
+
onClick: (event) => {
|
|
2817
|
+
setIsSelected(true);
|
|
2818
|
+
onClick?.(event);
|
|
2819
|
+
},
|
|
2729
2820
|
key: index,
|
|
2730
2821
|
style: getPartStyle(rect),
|
|
2731
2822
|
className: `TextHighlight__part ${getPartStyleClass()}`
|
|
@@ -2733,22 +2824,20 @@ var TextHighlight = ({
|
|
|
2733
2824
|
))
|
|
2734
2825
|
)
|
|
2735
2826
|
);
|
|
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";
|
|
2827
|
+
});
|
|
2828
|
+
TextHighlight.displayName = "TextHighlight";
|
|
2743
2829
|
var MouseMonitor = ({
|
|
2744
2830
|
onMoveAway,
|
|
2745
2831
|
paddingX,
|
|
2746
2832
|
paddingY,
|
|
2747
2833
|
children
|
|
2748
2834
|
}) => {
|
|
2749
|
-
const containerRef =
|
|
2835
|
+
const containerRef = useRef(null);
|
|
2750
2836
|
const onMouseMove = (event) => {
|
|
2751
2837
|
if (!containerRef.current) return;
|
|
2838
|
+
if (containerRef.current.contains(document.activeElement)) {
|
|
2839
|
+
return;
|
|
2840
|
+
}
|
|
2752
2841
|
const { clientX, clientY } = event;
|
|
2753
2842
|
const { left, top, width, height } = containerRef.current.getBoundingClientRect();
|
|
2754
2843
|
const inBoundsX = clientX > left - paddingX && clientX < left + width + paddingX;
|
|
@@ -2757,13 +2846,13 @@ var MouseMonitor = ({
|
|
|
2757
2846
|
onMoveAway();
|
|
2758
2847
|
}
|
|
2759
2848
|
};
|
|
2760
|
-
|
|
2849
|
+
useEffect(() => {
|
|
2761
2850
|
document.addEventListener("mousemove", onMouseMove);
|
|
2762
2851
|
return () => {
|
|
2763
2852
|
document.removeEventListener("mousemove", onMouseMove);
|
|
2764
2853
|
};
|
|
2765
2854
|
}, []);
|
|
2766
|
-
return /* @__PURE__ */
|
|
2855
|
+
return /* @__PURE__ */ React11.createElement("div", { ref: containerRef }, children);
|
|
2767
2856
|
};
|
|
2768
2857
|
|
|
2769
2858
|
// src/components/MonitoredHighlightContainer.tsx
|
|
@@ -2773,17 +2862,18 @@ var MonitoredHighlightContainer = ({
|
|
|
2773
2862
|
onMouseLeave,
|
|
2774
2863
|
children
|
|
2775
2864
|
}) => {
|
|
2776
|
-
const mouseInRef =
|
|
2777
|
-
const { setTip, isEditingOrHighlighting } = usePdfHighlighterContext();
|
|
2778
|
-
return /* @__PURE__ */
|
|
2865
|
+
const mouseInRef = useRef(false);
|
|
2866
|
+
const { setTip, isEditingOrHighlighting, isHighlightSelected } = usePdfHighlighterContext();
|
|
2867
|
+
return /* @__PURE__ */ React11.createElement(
|
|
2779
2868
|
"div",
|
|
2780
2869
|
{
|
|
2781
2870
|
onMouseEnter: () => {
|
|
2782
2871
|
mouseInRef.current = true;
|
|
2783
2872
|
onMouseEnter && onMouseEnter();
|
|
2784
2873
|
if (isEditingOrHighlighting()) return;
|
|
2874
|
+
if (isHighlightSelected()) return;
|
|
2785
2875
|
if (highlightTip) {
|
|
2786
|
-
const monitoredHighlightTip = /* @__PURE__ */
|
|
2876
|
+
const monitoredHighlightTip = /* @__PURE__ */ React11.createElement(
|
|
2787
2877
|
MouseMonitor,
|
|
2788
2878
|
{
|
|
2789
2879
|
onMoveAway: () => {
|
|
@@ -2812,20 +2902,11 @@ var MonitoredHighlightContainer = ({
|
|
|
2812
2902
|
children
|
|
2813
2903
|
);
|
|
2814
2904
|
};
|
|
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" }));
|
|
2905
|
+
var DefaultDeleteIcon2 = () => /* @__PURE__ */ React11.createElement(Trash2, { width: 14, height: 14 });
|
|
2906
|
+
var DefaultCopyIcon2 = () => /* @__PURE__ */ React11.createElement(Copy, { width: 14, height: 14 });
|
|
2907
|
+
var DefaultCopiedIcon2 = () => /* @__PURE__ */ React11.createElement(Check, { width: 14, height: 14, strokeWidth: 2.5 });
|
|
2908
|
+
var ChevronDownIcon2 = () => /* @__PURE__ */ React11.createElement(ChevronDown, { width: 12, height: 12, strokeWidth: 2.5 });
|
|
2909
|
+
var CheckIcon2 = () => /* @__PURE__ */ React11.createElement(Check, { width: 14, height: 14, strokeWidth: 2.5 });
|
|
2829
2910
|
var DEFAULT_COLOR_PRESETS2 = [
|
|
2830
2911
|
"rgba(255, 226, 143, 1)",
|
|
2831
2912
|
// Yellow (default)
|
|
@@ -2838,7 +2919,14 @@ var DEFAULT_COLOR_PRESETS2 = [
|
|
|
2838
2919
|
"#e1bee7"
|
|
2839
2920
|
// Light purple
|
|
2840
2921
|
];
|
|
2841
|
-
var
|
|
2922
|
+
var COLOR_NAMES2 = {
|
|
2923
|
+
"rgba(255, 226, 143, 1)": "Yellow",
|
|
2924
|
+
"#ffcdd2": "Red",
|
|
2925
|
+
"#c8e6c9": "Green",
|
|
2926
|
+
"#bbdefb": "Blue",
|
|
2927
|
+
"#e1bee7": "Purple"
|
|
2928
|
+
};
|
|
2929
|
+
var AreaHighlight = memo(({
|
|
2842
2930
|
highlight,
|
|
2843
2931
|
onChange,
|
|
2844
2932
|
isScrolledTo,
|
|
@@ -2849,35 +2937,62 @@ var AreaHighlight = ({
|
|
|
2849
2937
|
highlightColor = "rgba(255, 226, 143, 1)",
|
|
2850
2938
|
onStyleChange,
|
|
2851
2939
|
onDelete,
|
|
2852
|
-
styleIcon,
|
|
2853
2940
|
deleteIcon,
|
|
2854
2941
|
copyText,
|
|
2855
|
-
colorPresets = DEFAULT_COLOR_PRESETS2
|
|
2942
|
+
colorPresets = DEFAULT_COLOR_PRESETS2,
|
|
2943
|
+
extraButtons,
|
|
2944
|
+
extraPanel
|
|
2856
2945
|
}) => {
|
|
2857
|
-
const [
|
|
2858
|
-
const [
|
|
2859
|
-
const [isCopied, setIsCopied] =
|
|
2860
|
-
const [configLayer, setConfigLayer] =
|
|
2861
|
-
const
|
|
2862
|
-
const containerRef =
|
|
2863
|
-
const
|
|
2864
|
-
|
|
2946
|
+
const [isColorMenuOpen, setIsColorMenuOpen] = useState(false);
|
|
2947
|
+
const [isSelected, setIsSelected] = useState(false);
|
|
2948
|
+
const [isCopied, setIsCopied] = useState(false);
|
|
2949
|
+
const [configLayer, setConfigLayer] = useState(null);
|
|
2950
|
+
const colorMenuRef = useRef(null);
|
|
2951
|
+
const containerRef = useRef(null);
|
|
2952
|
+
const toolbarWrapperRef = useRef(null);
|
|
2953
|
+
const copyResetTimeoutRef = useRef(null);
|
|
2954
|
+
useEffect(() => {
|
|
2955
|
+
if (!isSelected) return;
|
|
2956
|
+
const handlePointerDown = (e) => {
|
|
2957
|
+
const target = e.target;
|
|
2958
|
+
const insideRoot = containerRef.current?.contains(target);
|
|
2959
|
+
const insideToolbar = toolbarWrapperRef.current?.contains(target);
|
|
2960
|
+
if (!insideRoot && !insideToolbar) {
|
|
2961
|
+
setIsSelected(false);
|
|
2962
|
+
setIsColorMenuOpen(false);
|
|
2963
|
+
}
|
|
2964
|
+
};
|
|
2965
|
+
const handleKey = (e) => {
|
|
2966
|
+
if (e.key === "Escape") {
|
|
2967
|
+
setIsSelected(false);
|
|
2968
|
+
setIsColorMenuOpen(false);
|
|
2969
|
+
}
|
|
2970
|
+
};
|
|
2971
|
+
document.addEventListener("mousedown", handlePointerDown);
|
|
2972
|
+
document.addEventListener("keydown", handleKey);
|
|
2973
|
+
return () => {
|
|
2974
|
+
document.removeEventListener("mousedown", handlePointerDown);
|
|
2975
|
+
document.removeEventListener("keydown", handleKey);
|
|
2976
|
+
};
|
|
2977
|
+
}, [isSelected]);
|
|
2978
|
+
useLayoutEffect(() => {
|
|
2865
2979
|
if (containerRef.current) {
|
|
2866
|
-
|
|
2980
|
+
const layer = findOrCreateHighlightConfigLayer(containerRef.current);
|
|
2981
|
+
setConfigLayer((prev) => prev === layer ? prev : layer);
|
|
2867
2982
|
}
|
|
2868
|
-
}
|
|
2869
|
-
|
|
2983
|
+
});
|
|
2984
|
+
useEffect(() => {
|
|
2870
2985
|
return () => {
|
|
2871
2986
|
if (copyResetTimeoutRef.current) {
|
|
2872
2987
|
window.clearTimeout(copyResetTimeoutRef.current);
|
|
2873
2988
|
}
|
|
2874
2989
|
};
|
|
2875
2990
|
}, []);
|
|
2876
|
-
|
|
2877
|
-
if (!
|
|
2991
|
+
useEffect(() => {
|
|
2992
|
+
if (!isColorMenuOpen) return;
|
|
2878
2993
|
const handleClickOutside = (e) => {
|
|
2879
|
-
if (
|
|
2880
|
-
|
|
2994
|
+
if (colorMenuRef.current && !colorMenuRef.current.contains(e.target)) {
|
|
2995
|
+
setIsColorMenuOpen(false);
|
|
2881
2996
|
}
|
|
2882
2997
|
};
|
|
2883
2998
|
const timeoutId = setTimeout(() => {
|
|
@@ -2887,8 +3002,10 @@ var AreaHighlight = ({
|
|
|
2887
3002
|
clearTimeout(timeoutId);
|
|
2888
3003
|
document.removeEventListener("mousedown", handleClickOutside);
|
|
2889
3004
|
};
|
|
2890
|
-
}, [
|
|
3005
|
+
}, [isColorMenuOpen]);
|
|
2891
3006
|
const highlightClass = isScrolledTo ? "AreaHighlight--scrolledTo" : "";
|
|
3007
|
+
const selectedClass = isSelected ? "AreaHighlight--selected" : "";
|
|
3008
|
+
const flipToolbar = highlight.position.boundingRect.top < 40;
|
|
2892
3009
|
const key = `${highlight.position.boundingRect.width}${highlight.position.boundingRect.height}${highlight.position.boundingRect.left}${highlight.position.boundingRect.top}`;
|
|
2893
3010
|
const mergedStyle = {
|
|
2894
3011
|
...style,
|
|
@@ -2910,46 +3027,53 @@ var AreaHighlight = ({
|
|
|
2910
3027
|
copyResetTimeoutRef.current = null;
|
|
2911
3028
|
}, 1500);
|
|
2912
3029
|
};
|
|
2913
|
-
return /* @__PURE__ */
|
|
3030
|
+
return /* @__PURE__ */ React11.createElement(
|
|
2914
3031
|
"div",
|
|
2915
3032
|
{
|
|
2916
|
-
className: `AreaHighlight ${highlightClass}`,
|
|
3033
|
+
className: `AreaHighlight ${highlightClass} ${selectedClass}`,
|
|
2917
3034
|
onContextMenu,
|
|
2918
3035
|
ref: containerRef
|
|
2919
3036
|
},
|
|
2920
|
-
configLayer && (onStyleChange || onDelete) &&
|
|
2921
|
-
/* @__PURE__ */
|
|
3037
|
+
configLayer && (onStyleChange || onDelete) && createPortal(
|
|
3038
|
+
/* @__PURE__ */ React11.createElement(
|
|
2922
3039
|
"div",
|
|
2923
3040
|
{
|
|
2924
3041
|
className: "AreaHighlight__toolbar-wrapper",
|
|
3042
|
+
ref: toolbarWrapperRef,
|
|
2925
3043
|
style: {
|
|
2926
3044
|
position: "absolute",
|
|
2927
3045
|
left: highlight.position.boundingRect.left,
|
|
2928
|
-
top: highlight.position.boundingRect.top
|
|
2929
|
-
|
|
2930
|
-
},
|
|
2931
|
-
onMouseEnter: () => setIsHovered(true),
|
|
2932
|
-
onMouseLeave: () => setIsHovered(false)
|
|
3046
|
+
top: highlight.position.boundingRect.top
|
|
3047
|
+
}
|
|
2933
3048
|
},
|
|
2934
|
-
/* @__PURE__ */
|
|
3049
|
+
/* @__PURE__ */ React11.createElement(
|
|
2935
3050
|
"div",
|
|
2936
3051
|
{
|
|
2937
|
-
className: `AreaHighlight__toolbar ${
|
|
3052
|
+
className: `AreaHighlight__toolbar ${flipToolbar ? "AreaHighlight__toolbar--below" : ""} ${isSelected || isScrolledTo || isColorMenuOpen ? "AreaHighlight__toolbar--visible" : ""}`
|
|
2938
3053
|
},
|
|
2939
|
-
onStyleChange && /* @__PURE__ */
|
|
3054
|
+
onStyleChange && /* @__PURE__ */ React11.createElement(React11.Fragment, null, /* @__PURE__ */ React11.createElement(
|
|
2940
3055
|
"button",
|
|
2941
3056
|
{
|
|
2942
|
-
|
|
3057
|
+
type: "button",
|
|
3058
|
+
className: "AreaHighlight__color-trigger",
|
|
3059
|
+
"aria-label": "Highlight color",
|
|
3060
|
+
"aria-expanded": isColorMenuOpen,
|
|
2943
3061
|
onClick: (e) => {
|
|
2944
3062
|
e.stopPropagation();
|
|
2945
|
-
|
|
3063
|
+
setIsColorMenuOpen((v) => !v);
|
|
2946
3064
|
},
|
|
2947
|
-
title: "
|
|
2948
|
-
type: "button"
|
|
3065
|
+
title: "Highlight color"
|
|
2949
3066
|
},
|
|
2950
|
-
|
|
2951
|
-
|
|
2952
|
-
|
|
3067
|
+
/* @__PURE__ */ React11.createElement(
|
|
3068
|
+
"span",
|
|
3069
|
+
{
|
|
3070
|
+
className: "AreaHighlight__color-trigger-dot",
|
|
3071
|
+
style: { backgroundColor: highlightColor }
|
|
3072
|
+
}
|
|
3073
|
+
),
|
|
3074
|
+
/* @__PURE__ */ React11.createElement(ChevronDownIcon2, null)
|
|
3075
|
+
), /* @__PURE__ */ React11.createElement("div", { className: "AreaHighlight__toolbar-divider" })),
|
|
3076
|
+
/* @__PURE__ */ React11.createElement(
|
|
2953
3077
|
"button",
|
|
2954
3078
|
{
|
|
2955
3079
|
className: "AreaHighlight__copy-button",
|
|
@@ -2957,9 +3081,10 @@ var AreaHighlight = ({
|
|
|
2957
3081
|
title: isCopied ? "Copied" : "Copy text",
|
|
2958
3082
|
type: "button"
|
|
2959
3083
|
},
|
|
2960
|
-
isCopied ? /* @__PURE__ */
|
|
3084
|
+
isCopied ? /* @__PURE__ */ React11.createElement(DefaultCopiedIcon2, null) : /* @__PURE__ */ React11.createElement(DefaultCopyIcon2, null)
|
|
2961
3085
|
),
|
|
2962
|
-
|
|
3086
|
+
extraButtons,
|
|
3087
|
+
onDelete && /* @__PURE__ */ React11.createElement(
|
|
2963
3088
|
"button",
|
|
2964
3089
|
{
|
|
2965
3090
|
className: "AreaHighlight__delete-button",
|
|
@@ -2970,45 +3095,45 @@ var AreaHighlight = ({
|
|
|
2970
3095
|
title: "Delete",
|
|
2971
3096
|
type: "button"
|
|
2972
3097
|
},
|
|
2973
|
-
deleteIcon || /* @__PURE__ */
|
|
3098
|
+
deleteIcon || /* @__PURE__ */ React11.createElement(DefaultDeleteIcon2, null)
|
|
2974
3099
|
)
|
|
2975
3100
|
),
|
|
2976
|
-
|
|
3101
|
+
isColorMenuOpen && onStyleChange && /* @__PURE__ */ React11.createElement(
|
|
2977
3102
|
"div",
|
|
2978
3103
|
{
|
|
2979
|
-
className: "
|
|
2980
|
-
ref:
|
|
3104
|
+
className: "AreaHighlight__color-menu",
|
|
3105
|
+
ref: colorMenuRef,
|
|
2981
3106
|
onClick: (e) => e.stopPropagation()
|
|
2982
3107
|
},
|
|
2983
|
-
|
|
3108
|
+
colorPresets.map((c) => /* @__PURE__ */ React11.createElement(
|
|
2984
3109
|
"button",
|
|
2985
3110
|
{
|
|
2986
3111
|
key: c,
|
|
2987
3112
|
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 });
|
|
3113
|
+
className: "AreaHighlight__color-menu-item",
|
|
3114
|
+
onClick: () => {
|
|
3115
|
+
onStyleChange({ highlightColor: c });
|
|
3116
|
+
setIsColorMenuOpen(false);
|
|
3000
3117
|
}
|
|
3001
|
-
}
|
|
3002
|
-
|
|
3003
|
-
|
|
3118
|
+
},
|
|
3119
|
+
/* @__PURE__ */ React11.createElement(
|
|
3120
|
+
"span",
|
|
3121
|
+
{
|
|
3122
|
+
className: "AreaHighlight__color-menu-dot",
|
|
3123
|
+
style: { backgroundColor: c }
|
|
3124
|
+
}
|
|
3125
|
+
),
|
|
3126
|
+
/* @__PURE__ */ React11.createElement("span", { className: "AreaHighlight__color-menu-label" }, COLOR_NAMES2[c] || c),
|
|
3127
|
+
highlightColor === c && /* @__PURE__ */ React11.createElement("span", { className: "AreaHighlight__color-menu-check" }, /* @__PURE__ */ React11.createElement(CheckIcon2, null))
|
|
3128
|
+
))
|
|
3129
|
+
),
|
|
3130
|
+
extraPanel
|
|
3004
3131
|
),
|
|
3005
3132
|
configLayer
|
|
3006
3133
|
),
|
|
3007
|
-
/* @__PURE__ */
|
|
3134
|
+
/* @__PURE__ */ React11.createElement(
|
|
3008
3135
|
Rnd,
|
|
3009
3136
|
{
|
|
3010
|
-
onMouseEnter: () => setIsHovered(true),
|
|
3011
|
-
onMouseLeave: () => setIsHovered(false),
|
|
3012
3137
|
className: "AreaHighlight__part",
|
|
3013
3138
|
onDragStop: (_, data) => {
|
|
3014
3139
|
const boundingRect = {
|
|
@@ -3028,7 +3153,10 @@ var AreaHighlight = ({
|
|
|
3028
3153
|
};
|
|
3029
3154
|
onChange && onChange(boundingRect);
|
|
3030
3155
|
},
|
|
3031
|
-
onDragStart:
|
|
3156
|
+
onDragStart: () => {
|
|
3157
|
+
setIsSelected(true);
|
|
3158
|
+
onEditStart?.();
|
|
3159
|
+
},
|
|
3032
3160
|
onResizeStart: onEditStart,
|
|
3033
3161
|
default: {
|
|
3034
3162
|
x: highlight.position.boundingRect.left,
|
|
@@ -3041,28 +3169,31 @@ var AreaHighlight = ({
|
|
|
3041
3169
|
onClick: (event) => {
|
|
3042
3170
|
event.stopPropagation();
|
|
3043
3171
|
event.preventDefault();
|
|
3172
|
+
setIsSelected(true);
|
|
3044
3173
|
},
|
|
3045
3174
|
style: mergedStyle
|
|
3046
3175
|
}
|
|
3047
3176
|
)
|
|
3048
3177
|
);
|
|
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" }));
|
|
3178
|
+
});
|
|
3179
|
+
AreaHighlight.displayName = "AreaHighlight";
|
|
3180
|
+
var DefaultEditIcon = () => /* @__PURE__ */ React11.createElement(Pencil, { width: 14, height: 14 });
|
|
3181
|
+
var DefaultStyleIcon2 = () => /* @__PURE__ */ React11.createElement(Palette, { width: 14, height: 14 });
|
|
3182
|
+
var DefaultDeleteIcon3 = () => /* @__PURE__ */ React11.createElement(Trash2, { width: 14, height: 14 });
|
|
3183
|
+
var DefaultCompactIcon = () => /* @__PURE__ */ React11.createElement(StickyNote, { width: 16, height: 16 });
|
|
3184
|
+
var DefaultCollapseIcon = () => /* @__PURE__ */ React11.createElement(Minimize2, { width: 14, height: 14 });
|
|
3185
|
+
var ChevronDownIcon3 = () => /* @__PURE__ */ React11.createElement(ChevronDown, { width: 12, height: 12, strokeWidth: 2.5 });
|
|
3186
|
+
var CheckIcon3 = () => /* @__PURE__ */ React11.createElement(Check, { width: 14, height: 14, strokeWidth: 2.5 });
|
|
3064
3187
|
var DEFAULT_BACKGROUND_PRESETS = ["transparent", "#ffffc8", "#ffcdd2", "#c8e6c9", "#bbdefb", "#e1bee7"];
|
|
3065
3188
|
var DEFAULT_TEXT_PRESETS = ["#333333", "#d32f2f", "#1976d2", "#388e3c", "#7b1fa2"];
|
|
3189
|
+
var BACKGROUND_COLOR_NAMES = {
|
|
3190
|
+
transparent: "None",
|
|
3191
|
+
"#ffffc8": "Yellow",
|
|
3192
|
+
"#ffcdd2": "Red",
|
|
3193
|
+
"#c8e6c9": "Green",
|
|
3194
|
+
"#bbdefb": "Blue",
|
|
3195
|
+
"#e1bee7": "Purple"
|
|
3196
|
+
};
|
|
3066
3197
|
var FreetextHighlight = ({
|
|
3067
3198
|
highlight,
|
|
3068
3199
|
onChange,
|
|
@@ -3089,29 +3220,58 @@ var FreetextHighlight = ({
|
|
|
3089
3220
|
compactSize = 32,
|
|
3090
3221
|
compactIcon
|
|
3091
3222
|
}) => {
|
|
3092
|
-
const [isEditing, setIsEditing] =
|
|
3093
|
-
const [
|
|
3094
|
-
|
|
3095
|
-
const [
|
|
3096
|
-
const
|
|
3097
|
-
const
|
|
3098
|
-
|
|
3223
|
+
const [isEditing, setIsEditing] = useState(false);
|
|
3224
|
+
const [isSelected, setIsSelected] = useState(false);
|
|
3225
|
+
useClearTipWhileSelected(isSelected);
|
|
3226
|
+
const [isExpanded, setIsExpanded] = useState(!compact);
|
|
3227
|
+
const [isStylePanelOpen, setIsStylePanelOpen] = useState(false);
|
|
3228
|
+
const [isColorMenuOpen, setIsColorMenuOpen] = useState(false);
|
|
3229
|
+
const [text, setText] = useState(highlight.content?.text || "");
|
|
3230
|
+
const textareaRef = useRef(null);
|
|
3231
|
+
const stylePanelRef = useRef(null);
|
|
3232
|
+
const colorMenuRef = useRef(null);
|
|
3233
|
+
const rootRef = useRef(null);
|
|
3234
|
+
useEffect(() => {
|
|
3235
|
+
if (!isSelected) return;
|
|
3236
|
+
const handlePointerDown = (e) => {
|
|
3237
|
+
if (rootRef.current && !rootRef.current.contains(e.target)) {
|
|
3238
|
+
setIsSelected(false);
|
|
3239
|
+
setIsStylePanelOpen(false);
|
|
3240
|
+
setIsColorMenuOpen(false);
|
|
3241
|
+
}
|
|
3242
|
+
};
|
|
3243
|
+
const handleKey = (e) => {
|
|
3244
|
+
if (e.key === "Escape" && !isEditing) {
|
|
3245
|
+
setIsSelected(false);
|
|
3246
|
+
setIsStylePanelOpen(false);
|
|
3247
|
+
setIsColorMenuOpen(false);
|
|
3248
|
+
}
|
|
3249
|
+
};
|
|
3250
|
+
document.addEventListener("mousedown", handlePointerDown);
|
|
3251
|
+
document.addEventListener("keydown", handleKey);
|
|
3252
|
+
return () => {
|
|
3253
|
+
document.removeEventListener("mousedown", handlePointerDown);
|
|
3254
|
+
document.removeEventListener("keydown", handleKey);
|
|
3255
|
+
};
|
|
3256
|
+
}, [isSelected, isEditing]);
|
|
3257
|
+
useEffect(() => {
|
|
3099
3258
|
setText(highlight.content?.text || "");
|
|
3100
3259
|
}, [highlight.content?.text]);
|
|
3101
|
-
|
|
3260
|
+
useEffect(() => {
|
|
3102
3261
|
setIsExpanded(!compact);
|
|
3103
3262
|
setIsStylePanelOpen(false);
|
|
3263
|
+
setIsColorMenuOpen(false);
|
|
3104
3264
|
if (!compact) {
|
|
3105
3265
|
setIsEditing(false);
|
|
3106
3266
|
}
|
|
3107
3267
|
}, [compact]);
|
|
3108
|
-
|
|
3268
|
+
useEffect(() => {
|
|
3109
3269
|
if (isEditing && textareaRef.current) {
|
|
3110
3270
|
textareaRef.current.focus();
|
|
3111
3271
|
textareaRef.current.select();
|
|
3112
3272
|
}
|
|
3113
3273
|
}, [isEditing]);
|
|
3114
|
-
|
|
3274
|
+
useEffect(() => {
|
|
3115
3275
|
if (!isStylePanelOpen) return;
|
|
3116
3276
|
const handleClickOutside = (e) => {
|
|
3117
3277
|
if (stylePanelRef.current && !stylePanelRef.current.contains(e.target)) {
|
|
@@ -3126,16 +3286,38 @@ var FreetextHighlight = ({
|
|
|
3126
3286
|
document.removeEventListener("mousedown", handleClickOutside);
|
|
3127
3287
|
};
|
|
3128
3288
|
}, [isStylePanelOpen]);
|
|
3289
|
+
useEffect(() => {
|
|
3290
|
+
if (!isColorMenuOpen) return;
|
|
3291
|
+
const handleClickOutside = (e) => {
|
|
3292
|
+
if (colorMenuRef.current && !colorMenuRef.current.contains(e.target)) {
|
|
3293
|
+
setIsColorMenuOpen(false);
|
|
3294
|
+
}
|
|
3295
|
+
};
|
|
3296
|
+
const timeoutId = setTimeout(() => {
|
|
3297
|
+
document.addEventListener("mousedown", handleClickOutside);
|
|
3298
|
+
}, 0);
|
|
3299
|
+
return () => {
|
|
3300
|
+
clearTimeout(timeoutId);
|
|
3301
|
+
document.removeEventListener("mousedown", handleClickOutside);
|
|
3302
|
+
};
|
|
3303
|
+
}, [isColorMenuOpen]);
|
|
3129
3304
|
const highlightClass = isScrolledTo ? "FreetextHighlight--scrolledTo" : "";
|
|
3130
3305
|
const editingClass = isEditing ? "FreetextHighlight--editing" : "";
|
|
3306
|
+
const selectedClass = isSelected ? "FreetextHighlight--selected" : "";
|
|
3131
3307
|
const compactClass = compact ? "FreetextHighlight--compact" : "";
|
|
3132
|
-
const isCompactCollapsed = compact && !isExpanded && !isEditing && !isStylePanelOpen;
|
|
3308
|
+
const isCompactCollapsed = compact && !isExpanded && !isEditing && !isStylePanelOpen && !isColorMenuOpen;
|
|
3133
3309
|
const collapsedClass = isCompactCollapsed ? "FreetextHighlight--collapsed" : "";
|
|
3310
|
+
const flipToolbar = highlight.position.boundingRect.top < 40;
|
|
3134
3311
|
const key = `${highlight.position.boundingRect.width}${highlight.position.boundingRect.height}${highlight.position.boundingRect.left}${highlight.position.boundingRect.top}${isCompactCollapsed ? "collapsed" : "expanded"}`;
|
|
3135
|
-
const
|
|
3312
|
+
const handleNoteClick = (e) => {
|
|
3136
3313
|
e.stopPropagation();
|
|
3314
|
+
if (!isEditing) setIsSelected(true);
|
|
3315
|
+
};
|
|
3316
|
+
const enterEditMode = (e) => {
|
|
3317
|
+
e?.stopPropagation();
|
|
3137
3318
|
if (!isEditing) {
|
|
3138
3319
|
setIsExpanded(true);
|
|
3320
|
+
setIsSelected(true);
|
|
3139
3321
|
setIsEditing(true);
|
|
3140
3322
|
onEditStart?.();
|
|
3141
3323
|
}
|
|
@@ -3170,11 +3352,12 @@ var FreetextHighlight = ({
|
|
|
3170
3352
|
return /* @__PURE__ */ React11.createElement(
|
|
3171
3353
|
"div",
|
|
3172
3354
|
{
|
|
3173
|
-
|
|
3355
|
+
ref: rootRef,
|
|
3356
|
+
className: `FreetextHighlight ${highlightClass} ${editingClass} ${selectedClass} ${compactClass} ${collapsedClass}`,
|
|
3174
3357
|
onContextMenu
|
|
3175
3358
|
},
|
|
3176
3359
|
/* @__PURE__ */ React11.createElement(
|
|
3177
|
-
|
|
3360
|
+
Rnd,
|
|
3178
3361
|
{
|
|
3179
3362
|
className: "FreetextHighlight__rnd",
|
|
3180
3363
|
onDragStop: (_, data) => {
|
|
@@ -3187,9 +3370,11 @@ var FreetextHighlight = ({
|
|
|
3187
3370
|
},
|
|
3188
3371
|
onDragStart: () => {
|
|
3189
3372
|
if (!isEditing) {
|
|
3373
|
+
setIsSelected(true);
|
|
3190
3374
|
onEditStart?.();
|
|
3191
3375
|
}
|
|
3192
3376
|
},
|
|
3377
|
+
disableDragging: isEditing,
|
|
3193
3378
|
default: {
|
|
3194
3379
|
x: highlight.position.boundingRect.left,
|
|
3195
3380
|
y: highlight.position.boundingRect.top,
|
|
@@ -3225,168 +3410,236 @@ var FreetextHighlight = ({
|
|
|
3225
3410
|
onEditStart?.();
|
|
3226
3411
|
}
|
|
3227
3412
|
},
|
|
3228
|
-
cancel: ".
|
|
3413
|
+
cancel: ".FreetextHighlight__input, .FreetextHighlight__toolbar, .FreetextHighlight__style-panel, .FreetextHighlight__color-menu, .FreetextHighlight__compact-button"
|
|
3229
3414
|
},
|
|
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(
|
|
3415
|
+
/* @__PURE__ */ React11.createElement(
|
|
3289
3416
|
"div",
|
|
3290
3417
|
{
|
|
3291
|
-
className: "
|
|
3292
|
-
|
|
3293
|
-
onClick:
|
|
3418
|
+
className: "FreetextHighlight__container",
|
|
3419
|
+
style: containerStyle,
|
|
3420
|
+
onClick: handleNoteClick,
|
|
3421
|
+
onDoubleClick: enterEditMode
|
|
3294
3422
|
},
|
|
3295
|
-
|
|
3423
|
+
isCompactCollapsed ? /* @__PURE__ */ React11.createElement(
|
|
3296
3424
|
"button",
|
|
3297
3425
|
{
|
|
3298
|
-
|
|
3426
|
+
className: "FreetextHighlight__compact-button",
|
|
3299
3427
|
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 });
|
|
3312
|
-
}
|
|
3313
|
-
}
|
|
3314
|
-
))),
|
|
3315
|
-
/* @__PURE__ */ React11.createElement("div", { className: "FreetextHighlight__style-row" }, /* @__PURE__ */ React11.createElement(
|
|
3316
|
-
"label",
|
|
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",
|
|
3331
|
-
{
|
|
3332
|
-
type: "color",
|
|
3333
|
-
value: color,
|
|
3334
|
-
onChange: (e) => {
|
|
3335
|
-
onStyleChange?.({ color: e.target.value });
|
|
3336
|
-
}
|
|
3337
|
-
}
|
|
3338
|
-
))),
|
|
3339
|
-
/* @__PURE__ */ React11.createElement("div", { className: "FreetextHighlight__style-row" }, /* @__PURE__ */ React11.createElement("label", null, "Font Size"), /* @__PURE__ */ React11.createElement(
|
|
3340
|
-
"select",
|
|
3341
|
-
{
|
|
3342
|
-
value: fontSize,
|
|
3343
|
-
onChange: (e) => {
|
|
3344
|
-
onStyleChange?.({ fontSize: e.target.value });
|
|
3428
|
+
title: text || "Open note",
|
|
3429
|
+
onClick: (event) => {
|
|
3430
|
+
event.stopPropagation();
|
|
3431
|
+
setIsExpanded(true);
|
|
3345
3432
|
}
|
|
3346
3433
|
},
|
|
3347
|
-
/* @__PURE__ */ React11.createElement(
|
|
3348
|
-
|
|
3349
|
-
|
|
3350
|
-
/* @__PURE__ */ React11.createElement("option", { value: "16px" }, "16px"),
|
|
3351
|
-
/* @__PURE__ */ React11.createElement("option", { value: "18px" }, "18px"),
|
|
3352
|
-
/* @__PURE__ */ React11.createElement("option", { value: "20px" }, "20px"),
|
|
3353
|
-
/* @__PURE__ */ React11.createElement("option", { value: "24px" }, "24px")
|
|
3354
|
-
)),
|
|
3355
|
-
/* @__PURE__ */ React11.createElement("div", { className: "FreetextHighlight__style-row" }, /* @__PURE__ */ React11.createElement("label", null, "Font"), /* @__PURE__ */ React11.createElement(
|
|
3356
|
-
"select",
|
|
3434
|
+
compactIcon || /* @__PURE__ */ React11.createElement(DefaultCompactIcon, null)
|
|
3435
|
+
) : /* @__PURE__ */ React11.createElement(React11.Fragment, null, /* @__PURE__ */ React11.createElement(
|
|
3436
|
+
"div",
|
|
3357
3437
|
{
|
|
3358
|
-
|
|
3359
|
-
onChange: (e) => {
|
|
3360
|
-
onStyleChange?.({ fontFamily: e.target.value });
|
|
3361
|
-
}
|
|
3438
|
+
className: `FreetextHighlight__toolbar ${flipToolbar ? "FreetextHighlight__toolbar--below" : ""}`
|
|
3362
3439
|
},
|
|
3363
|
-
/* @__PURE__ */ React11.createElement(
|
|
3364
|
-
|
|
3365
|
-
|
|
3366
|
-
|
|
3367
|
-
|
|
3368
|
-
|
|
3369
|
-
|
|
3370
|
-
|
|
3371
|
-
|
|
3372
|
-
|
|
3373
|
-
|
|
3374
|
-
|
|
3375
|
-
|
|
3376
|
-
|
|
3377
|
-
|
|
3378
|
-
|
|
3379
|
-
|
|
3380
|
-
|
|
3440
|
+
/* @__PURE__ */ React11.createElement(
|
|
3441
|
+
"button",
|
|
3442
|
+
{
|
|
3443
|
+
type: "button",
|
|
3444
|
+
className: "FreetextHighlight__color-trigger",
|
|
3445
|
+
"aria-label": "Background color",
|
|
3446
|
+
"aria-expanded": isColorMenuOpen,
|
|
3447
|
+
onClick: (e) => {
|
|
3448
|
+
e.stopPropagation();
|
|
3449
|
+
setIsStylePanelOpen(false);
|
|
3450
|
+
setIsColorMenuOpen((v) => !v);
|
|
3451
|
+
},
|
|
3452
|
+
title: "Background color"
|
|
3453
|
+
},
|
|
3454
|
+
/* @__PURE__ */ React11.createElement(
|
|
3455
|
+
"span",
|
|
3456
|
+
{
|
|
3457
|
+
className: "FreetextHighlight__color-trigger-dot",
|
|
3458
|
+
style: {
|
|
3459
|
+
backgroundColor: backgroundColor === "transparent" ? void 0 : backgroundColor
|
|
3460
|
+
}
|
|
3461
|
+
}
|
|
3462
|
+
),
|
|
3463
|
+
/* @__PURE__ */ React11.createElement(ChevronDownIcon3, null)
|
|
3464
|
+
),
|
|
3465
|
+
/* @__PURE__ */ React11.createElement("div", { className: "FreetextHighlight__toolbar-divider" }),
|
|
3466
|
+
/* @__PURE__ */ React11.createElement(
|
|
3467
|
+
"button",
|
|
3468
|
+
{
|
|
3469
|
+
className: "FreetextHighlight__edit-button",
|
|
3470
|
+
onClick: enterEditMode,
|
|
3471
|
+
title: "Edit text (or double-click the note)",
|
|
3472
|
+
type: "button"
|
|
3473
|
+
},
|
|
3474
|
+
editIcon || /* @__PURE__ */ React11.createElement(DefaultEditIcon, null)
|
|
3475
|
+
),
|
|
3476
|
+
/* @__PURE__ */ React11.createElement(
|
|
3477
|
+
"button",
|
|
3478
|
+
{
|
|
3479
|
+
className: "FreetextHighlight__style-button",
|
|
3480
|
+
onClick: (e) => {
|
|
3481
|
+
e.stopPropagation();
|
|
3482
|
+
setIsColorMenuOpen(false);
|
|
3483
|
+
setIsStylePanelOpen(!isStylePanelOpen);
|
|
3484
|
+
},
|
|
3485
|
+
title: "Change style",
|
|
3486
|
+
type: "button"
|
|
3487
|
+
},
|
|
3488
|
+
styleIcon || /* @__PURE__ */ React11.createElement(DefaultStyleIcon2, null)
|
|
3489
|
+
),
|
|
3490
|
+
compact && /* @__PURE__ */ React11.createElement(
|
|
3491
|
+
"button",
|
|
3492
|
+
{
|
|
3493
|
+
className: "FreetextHighlight__collapse-button",
|
|
3494
|
+
onClick: (e) => {
|
|
3495
|
+
e.stopPropagation();
|
|
3496
|
+
setIsExpanded(false);
|
|
3497
|
+
setIsStylePanelOpen(false);
|
|
3498
|
+
setIsColorMenuOpen(false);
|
|
3499
|
+
},
|
|
3500
|
+
title: "Collapse note",
|
|
3501
|
+
type: "button"
|
|
3502
|
+
},
|
|
3503
|
+
/* @__PURE__ */ React11.createElement(DefaultCollapseIcon, null)
|
|
3504
|
+
),
|
|
3505
|
+
onDelete && /* @__PURE__ */ React11.createElement(
|
|
3506
|
+
"button",
|
|
3507
|
+
{
|
|
3508
|
+
className: "FreetextHighlight__delete-button",
|
|
3509
|
+
onClick: (e) => {
|
|
3510
|
+
e.stopPropagation();
|
|
3511
|
+
onDelete();
|
|
3512
|
+
},
|
|
3513
|
+
title: "Delete",
|
|
3514
|
+
type: "button"
|
|
3515
|
+
},
|
|
3516
|
+
deleteIcon || /* @__PURE__ */ React11.createElement(DefaultDeleteIcon3, null)
|
|
3517
|
+
)
|
|
3518
|
+
), isColorMenuOpen && /* @__PURE__ */ React11.createElement(
|
|
3519
|
+
"div",
|
|
3520
|
+
{
|
|
3521
|
+
className: `FreetextHighlight__color-menu ${flipToolbar ? "FreetextHighlight__color-menu--below-toolbar" : ""}`,
|
|
3522
|
+
ref: colorMenuRef,
|
|
3523
|
+
onClick: (e) => e.stopPropagation()
|
|
3524
|
+
},
|
|
3525
|
+
backgroundColorPresets.map((c) => /* @__PURE__ */ React11.createElement(
|
|
3526
|
+
"button",
|
|
3527
|
+
{
|
|
3528
|
+
key: c,
|
|
3529
|
+
type: "button",
|
|
3530
|
+
className: "FreetextHighlight__color-menu-item",
|
|
3531
|
+
onClick: () => {
|
|
3532
|
+
onStyleChange?.({ backgroundColor: c });
|
|
3533
|
+
setIsColorMenuOpen(false);
|
|
3534
|
+
}
|
|
3535
|
+
},
|
|
3536
|
+
/* @__PURE__ */ React11.createElement(
|
|
3537
|
+
"span",
|
|
3538
|
+
{
|
|
3539
|
+
className: `FreetextHighlight__color-menu-dot ${c === "transparent" ? "FreetextHighlight__color-menu-dot--transparent" : ""}`,
|
|
3540
|
+
style: c !== "transparent" ? { backgroundColor: c } : void 0
|
|
3541
|
+
}
|
|
3542
|
+
),
|
|
3543
|
+
/* @__PURE__ */ React11.createElement("span", { className: "FreetextHighlight__color-menu-label" }, BACKGROUND_COLOR_NAMES[c] || c),
|
|
3544
|
+
backgroundColor === c && /* @__PURE__ */ React11.createElement("span", { className: "FreetextHighlight__color-menu-check" }, /* @__PURE__ */ React11.createElement(CheckIcon3, null))
|
|
3545
|
+
))
|
|
3546
|
+
), isStylePanelOpen && /* @__PURE__ */ React11.createElement(
|
|
3547
|
+
"div",
|
|
3548
|
+
{
|
|
3549
|
+
className: `FreetextHighlight__style-panel ${flipToolbar ? "FreetextHighlight__style-panel--below-toolbar" : ""}`,
|
|
3550
|
+
ref: stylePanelRef,
|
|
3551
|
+
onClick: (e) => e.stopPropagation()
|
|
3552
|
+
},
|
|
3553
|
+
/* @__PURE__ */ React11.createElement("div", { className: "FreetextHighlight__style-row" }, /* @__PURE__ */ React11.createElement(
|
|
3554
|
+
"label",
|
|
3555
|
+
null,
|
|
3556
|
+
"Text Color"
|
|
3557
|
+
), /* @__PURE__ */ React11.createElement("div", { className: "FreetextHighlight__color-options" }, /* @__PURE__ */ React11.createElement("div", { className: "FreetextHighlight__color-presets" }, textColorPresets.map((c) => /* @__PURE__ */ React11.createElement(
|
|
3558
|
+
"button",
|
|
3559
|
+
{
|
|
3560
|
+
key: c,
|
|
3561
|
+
type: "button",
|
|
3562
|
+
className: `FreetextHighlight__color-preset ${color === c ? "active" : ""}`,
|
|
3563
|
+
style: { backgroundColor: c },
|
|
3564
|
+
onClick: () => onStyleChange?.({ color: c }),
|
|
3565
|
+
title: c
|
|
3566
|
+
}
|
|
3567
|
+
))), /* @__PURE__ */ React11.createElement(
|
|
3568
|
+
"input",
|
|
3569
|
+
{
|
|
3570
|
+
type: "color",
|
|
3571
|
+
value: color,
|
|
3572
|
+
onChange: (e) => {
|
|
3573
|
+
onStyleChange?.({ color: e.target.value });
|
|
3574
|
+
}
|
|
3575
|
+
}
|
|
3576
|
+
))),
|
|
3577
|
+
/* @__PURE__ */ React11.createElement("div", { className: "FreetextHighlight__style-row" }, /* @__PURE__ */ React11.createElement("label", null, "Font Size"), /* @__PURE__ */ React11.createElement(
|
|
3578
|
+
"select",
|
|
3579
|
+
{
|
|
3580
|
+
value: fontSize,
|
|
3581
|
+
onChange: (e) => {
|
|
3582
|
+
onStyleChange?.({ fontSize: e.target.value });
|
|
3583
|
+
}
|
|
3584
|
+
},
|
|
3585
|
+
/* @__PURE__ */ React11.createElement("option", { value: "10px" }, "10px"),
|
|
3586
|
+
/* @__PURE__ */ React11.createElement("option", { value: "12px" }, "12px"),
|
|
3587
|
+
/* @__PURE__ */ React11.createElement("option", { value: "14px" }, "14px"),
|
|
3588
|
+
/* @__PURE__ */ React11.createElement("option", { value: "16px" }, "16px"),
|
|
3589
|
+
/* @__PURE__ */ React11.createElement("option", { value: "18px" }, "18px"),
|
|
3590
|
+
/* @__PURE__ */ React11.createElement("option", { value: "20px" }, "20px"),
|
|
3591
|
+
/* @__PURE__ */ React11.createElement("option", { value: "24px" }, "24px")
|
|
3592
|
+
)),
|
|
3593
|
+
/* @__PURE__ */ React11.createElement("div", { className: "FreetextHighlight__style-row" }, /* @__PURE__ */ React11.createElement("label", null, "Font"), /* @__PURE__ */ React11.createElement(
|
|
3594
|
+
"select",
|
|
3595
|
+
{
|
|
3596
|
+
value: fontFamily,
|
|
3597
|
+
onChange: (e) => {
|
|
3598
|
+
onStyleChange?.({ fontFamily: e.target.value });
|
|
3599
|
+
}
|
|
3600
|
+
},
|
|
3601
|
+
/* @__PURE__ */ React11.createElement("option", { value: "inherit" }, "Default"),
|
|
3602
|
+
/* @__PURE__ */ React11.createElement("option", { value: "Arial, sans-serif" }, "Arial"),
|
|
3603
|
+
/* @__PURE__ */ React11.createElement("option", { value: "Georgia, serif" }, "Georgia"),
|
|
3604
|
+
/* @__PURE__ */ React11.createElement("option", { value: "'Courier New', monospace" }, "Courier"),
|
|
3605
|
+
/* @__PURE__ */ React11.createElement("option", { value: "'Times New Roman', serif" }, "Times")
|
|
3606
|
+
))
|
|
3607
|
+
), /* @__PURE__ */ React11.createElement("div", { className: "FreetextHighlight__content" }, isEditing ? /* @__PURE__ */ React11.createElement(
|
|
3608
|
+
"textarea",
|
|
3609
|
+
{
|
|
3610
|
+
ref: textareaRef,
|
|
3611
|
+
className: "FreetextHighlight__input",
|
|
3612
|
+
value: text,
|
|
3613
|
+
onChange: (e) => setText(e.target.value),
|
|
3614
|
+
onBlur: handleTextBlur,
|
|
3615
|
+
onKeyDown: handleKeyDown,
|
|
3616
|
+
onClick: (e) => e.stopPropagation()
|
|
3617
|
+
}
|
|
3618
|
+
) : /* @__PURE__ */ React11.createElement("div", { className: "FreetextHighlight__text" }, text || "New note")))
|
|
3619
|
+
)
|
|
3381
3620
|
)
|
|
3382
3621
|
);
|
|
3383
3622
|
};
|
|
3384
|
-
|
|
3385
|
-
|
|
3386
|
-
|
|
3387
|
-
|
|
3388
|
-
|
|
3389
|
-
|
|
3623
|
+
var DefaultDeleteIcon4 = () => /* @__PURE__ */ React11.createElement(Trash2, { width: 14, height: 14 });
|
|
3624
|
+
var rotateImageDataUrl = (dataUrl, width, height, clockwise) => new Promise((resolve, reject) => {
|
|
3625
|
+
const img = new Image();
|
|
3626
|
+
img.onload = () => {
|
|
3627
|
+
const canvas = document.createElement("canvas");
|
|
3628
|
+
canvas.width = height;
|
|
3629
|
+
canvas.height = width;
|
|
3630
|
+
const ctx = canvas.getContext("2d");
|
|
3631
|
+
if (!ctx) {
|
|
3632
|
+
reject(new Error("Canvas 2D context unavailable"));
|
|
3633
|
+
return;
|
|
3634
|
+
}
|
|
3635
|
+
ctx.translate(height / 2, width / 2);
|
|
3636
|
+
ctx.rotate((clockwise ? 90 : -90) * Math.PI / 180);
|
|
3637
|
+
ctx.drawImage(img, -width / 2, -height / 2, width, height);
|
|
3638
|
+
resolve(canvas.toDataURL("image/png"));
|
|
3639
|
+
};
|
|
3640
|
+
img.onerror = () => reject(new Error("Failed to load image for rotation"));
|
|
3641
|
+
img.src = dataUrl;
|
|
3642
|
+
});
|
|
3390
3643
|
var ImageHighlight = ({
|
|
3391
3644
|
highlight,
|
|
3392
3645
|
onChange,
|
|
@@ -3398,19 +3651,60 @@ var ImageHighlight = ({
|
|
|
3398
3651
|
style,
|
|
3399
3652
|
dragIcon,
|
|
3400
3653
|
onDelete,
|
|
3401
|
-
deleteIcon
|
|
3654
|
+
deleteIcon,
|
|
3655
|
+
onImageChange
|
|
3402
3656
|
}) => {
|
|
3657
|
+
const [isSelected, setIsSelected] = useState(false);
|
|
3658
|
+
useClearTipWhileSelected(isSelected);
|
|
3659
|
+
const rootRef = useRef(null);
|
|
3403
3660
|
const highlightClass = isScrolledTo ? "ImageHighlight--scrolledTo" : "";
|
|
3661
|
+
const selectedClass = isSelected ? "ImageHighlight--selected" : "";
|
|
3662
|
+
useEffect(() => {
|
|
3663
|
+
if (!isSelected) return;
|
|
3664
|
+
const handlePointerDown = (e) => {
|
|
3665
|
+
if (rootRef.current && !rootRef.current.contains(e.target)) {
|
|
3666
|
+
setIsSelected(false);
|
|
3667
|
+
}
|
|
3668
|
+
};
|
|
3669
|
+
const handleKey = (e) => {
|
|
3670
|
+
if (e.key === "Escape") {
|
|
3671
|
+
setIsSelected(false);
|
|
3672
|
+
}
|
|
3673
|
+
};
|
|
3674
|
+
document.addEventListener("mousedown", handlePointerDown);
|
|
3675
|
+
document.addEventListener("keydown", handleKey);
|
|
3676
|
+
return () => {
|
|
3677
|
+
document.removeEventListener("mousedown", handlePointerDown);
|
|
3678
|
+
document.removeEventListener("keydown", handleKey);
|
|
3679
|
+
};
|
|
3680
|
+
}, [isSelected]);
|
|
3404
3681
|
const key = `${highlight.position.boundingRect.width}${highlight.position.boundingRect.height}${highlight.position.boundingRect.left}${highlight.position.boundingRect.top}`;
|
|
3405
3682
|
const imageUrl = highlight.content?.image;
|
|
3406
|
-
|
|
3683
|
+
const flipToolbar = highlight.position.boundingRect.top < 40;
|
|
3684
|
+
const handleRotate = async (clockwise) => {
|
|
3685
|
+
if (!imageUrl) return;
|
|
3686
|
+
const { width, height, left, top, pageNumber } = highlight.position.boundingRect;
|
|
3687
|
+
const newImage = await rotateImageDataUrl(imageUrl, width, height, clockwise);
|
|
3688
|
+
onImageChange?.(newImage);
|
|
3689
|
+
const centerX = left + width / 2;
|
|
3690
|
+
const centerY = top + height / 2;
|
|
3691
|
+
onChange?.({
|
|
3692
|
+
left: centerX - height / 2,
|
|
3693
|
+
top: centerY - width / 2,
|
|
3694
|
+
width: height,
|
|
3695
|
+
height: width,
|
|
3696
|
+
pageNumber
|
|
3697
|
+
});
|
|
3698
|
+
};
|
|
3699
|
+
return /* @__PURE__ */ React11.createElement(
|
|
3407
3700
|
"div",
|
|
3408
3701
|
{
|
|
3409
|
-
className: `ImageHighlight ${highlightClass}`,
|
|
3410
|
-
onContextMenu
|
|
3702
|
+
className: `ImageHighlight ${highlightClass} ${selectedClass}`,
|
|
3703
|
+
onContextMenu,
|
|
3704
|
+
ref: rootRef
|
|
3411
3705
|
},
|
|
3412
|
-
/* @__PURE__ */
|
|
3413
|
-
|
|
3706
|
+
/* @__PURE__ */ React11.createElement(
|
|
3707
|
+
Rnd,
|
|
3414
3708
|
{
|
|
3415
3709
|
className: "ImageHighlight__rnd",
|
|
3416
3710
|
onDragStop: (_, data) => {
|
|
@@ -3422,7 +3716,10 @@ var ImageHighlight = ({
|
|
|
3422
3716
|
onChange?.(boundingRect);
|
|
3423
3717
|
onEditEnd?.();
|
|
3424
3718
|
},
|
|
3425
|
-
onDragStart:
|
|
3719
|
+
onDragStart: () => {
|
|
3720
|
+
setIsSelected(true);
|
|
3721
|
+
onEditStart?.();
|
|
3722
|
+
},
|
|
3426
3723
|
onResizeStop: (_e, _direction, ref, _delta, position) => {
|
|
3427
3724
|
const boundingRect = {
|
|
3428
3725
|
top: position.y,
|
|
@@ -3446,26 +3743,58 @@ var ImageHighlight = ({
|
|
|
3446
3743
|
key,
|
|
3447
3744
|
bounds,
|
|
3448
3745
|
lockAspectRatio: true,
|
|
3449
|
-
|
|
3746
|
+
cancel: ".ImageHighlight__toolbar",
|
|
3450
3747
|
onClick: (event) => {
|
|
3451
3748
|
event.stopPropagation();
|
|
3452
3749
|
event.preventDefault();
|
|
3750
|
+
setIsSelected(true);
|
|
3453
3751
|
},
|
|
3454
3752
|
style
|
|
3455
3753
|
},
|
|
3456
|
-
/* @__PURE__ */
|
|
3457
|
-
"
|
|
3754
|
+
/* @__PURE__ */ React11.createElement("div", { className: "ImageHighlight__container" }, (onDelete || onImageChange) && /* @__PURE__ */ React11.createElement(
|
|
3755
|
+
"div",
|
|
3458
3756
|
{
|
|
3459
|
-
className: "
|
|
3460
|
-
onClick: (e) => {
|
|
3461
|
-
e.stopPropagation();
|
|
3462
|
-
onDelete();
|
|
3463
|
-
},
|
|
3464
|
-
title: "Delete",
|
|
3465
|
-
type: "button"
|
|
3757
|
+
className: `ImageHighlight__toolbar ${flipToolbar ? "ImageHighlight__toolbar--below" : ""}`
|
|
3466
3758
|
},
|
|
3467
|
-
|
|
3468
|
-
|
|
3759
|
+
onImageChange && imageUrl && /* @__PURE__ */ React11.createElement(React11.Fragment, null, /* @__PURE__ */ React11.createElement(
|
|
3760
|
+
"button",
|
|
3761
|
+
{
|
|
3762
|
+
className: "ImageHighlight__rotate-button",
|
|
3763
|
+
onClick: (e) => {
|
|
3764
|
+
e.stopPropagation();
|
|
3765
|
+
handleRotate(false);
|
|
3766
|
+
},
|
|
3767
|
+
title: "Rotate left",
|
|
3768
|
+
type: "button"
|
|
3769
|
+
},
|
|
3770
|
+
/* @__PURE__ */ React11.createElement(RotateCcw, { width: 14, height: 14 })
|
|
3771
|
+
), /* @__PURE__ */ React11.createElement(
|
|
3772
|
+
"button",
|
|
3773
|
+
{
|
|
3774
|
+
className: "ImageHighlight__rotate-button",
|
|
3775
|
+
onClick: (e) => {
|
|
3776
|
+
e.stopPropagation();
|
|
3777
|
+
handleRotate(true);
|
|
3778
|
+
},
|
|
3779
|
+
title: "Rotate right",
|
|
3780
|
+
type: "button"
|
|
3781
|
+
},
|
|
3782
|
+
/* @__PURE__ */ React11.createElement(RotateCw, { width: 14, height: 14 })
|
|
3783
|
+
), /* @__PURE__ */ React11.createElement("div", { className: "ImageHighlight__toolbar-divider" })),
|
|
3784
|
+
onDelete && /* @__PURE__ */ React11.createElement(
|
|
3785
|
+
"button",
|
|
3786
|
+
{
|
|
3787
|
+
className: "ImageHighlight__delete-button",
|
|
3788
|
+
onClick: (e) => {
|
|
3789
|
+
e.stopPropagation();
|
|
3790
|
+
onDelete();
|
|
3791
|
+
},
|
|
3792
|
+
title: "Delete",
|
|
3793
|
+
type: "button"
|
|
3794
|
+
},
|
|
3795
|
+
deleteIcon || /* @__PURE__ */ React11.createElement(DefaultDeleteIcon4, null)
|
|
3796
|
+
)
|
|
3797
|
+
), /* @__PURE__ */ React11.createElement("div", { className: "ImageHighlight__content" }, imageUrl ? /* @__PURE__ */ React11.createElement(
|
|
3469
3798
|
"img",
|
|
3470
3799
|
{
|
|
3471
3800
|
src: imageUrl,
|
|
@@ -3473,13 +3802,10 @@ var ImageHighlight = ({
|
|
|
3473
3802
|
className: "ImageHighlight__image",
|
|
3474
3803
|
draggable: false
|
|
3475
3804
|
}
|
|
3476
|
-
) : /* @__PURE__ */
|
|
3805
|
+
) : /* @__PURE__ */ React11.createElement("div", { className: "ImageHighlight__placeholder" }, "No image")))
|
|
3477
3806
|
)
|
|
3478
3807
|
);
|
|
3479
3808
|
};
|
|
3480
|
-
|
|
3481
|
-
// src/components/SignaturePad.tsx
|
|
3482
|
-
import React13, { useRef as useRef11, useEffect as useEffect9, useCallback as useCallback3 } from "react";
|
|
3483
3809
|
var SignaturePad = ({
|
|
3484
3810
|
isOpen,
|
|
3485
3811
|
onComplete,
|
|
@@ -3487,10 +3813,10 @@ var SignaturePad = ({
|
|
|
3487
3813
|
width = 400,
|
|
3488
3814
|
height = 200
|
|
3489
3815
|
}) => {
|
|
3490
|
-
const canvasRef =
|
|
3491
|
-
const isDrawingRef =
|
|
3492
|
-
const lastPosRef =
|
|
3493
|
-
|
|
3816
|
+
const canvasRef = useRef(null);
|
|
3817
|
+
const isDrawingRef = useRef(false);
|
|
3818
|
+
const lastPosRef = useRef({ x: 0, y: 0 });
|
|
3819
|
+
useEffect(() => {
|
|
3494
3820
|
if (!isOpen || !canvasRef.current) return;
|
|
3495
3821
|
const canvas = canvasRef.current;
|
|
3496
3822
|
const ctx = canvas.getContext("2d");
|
|
@@ -3501,7 +3827,7 @@ var SignaturePad = ({
|
|
|
3501
3827
|
ctx.lineJoin = "round";
|
|
3502
3828
|
ctx.clearRect(0, 0, width, height);
|
|
3503
3829
|
}, [isOpen, width, height]);
|
|
3504
|
-
const getPosition =
|
|
3830
|
+
const getPosition = useCallback(
|
|
3505
3831
|
(e) => {
|
|
3506
3832
|
const canvas = canvasRef.current;
|
|
3507
3833
|
if (!canvas) return { x: 0, y: 0 };
|
|
@@ -3522,7 +3848,7 @@ var SignaturePad = ({
|
|
|
3522
3848
|
},
|
|
3523
3849
|
[]
|
|
3524
3850
|
);
|
|
3525
|
-
const startDrawing =
|
|
3851
|
+
const startDrawing = useCallback(
|
|
3526
3852
|
(e) => {
|
|
3527
3853
|
e.preventDefault();
|
|
3528
3854
|
isDrawingRef.current = true;
|
|
@@ -3530,7 +3856,7 @@ var SignaturePad = ({
|
|
|
3530
3856
|
},
|
|
3531
3857
|
[getPosition]
|
|
3532
3858
|
);
|
|
3533
|
-
const draw =
|
|
3859
|
+
const draw = useCallback(
|
|
3534
3860
|
(e) => {
|
|
3535
3861
|
if (!isDrawingRef.current) return;
|
|
3536
3862
|
e.preventDefault();
|
|
@@ -3546,10 +3872,10 @@ var SignaturePad = ({
|
|
|
3546
3872
|
},
|
|
3547
3873
|
[getPosition]
|
|
3548
3874
|
);
|
|
3549
|
-
const stopDrawing =
|
|
3875
|
+
const stopDrawing = useCallback(() => {
|
|
3550
3876
|
isDrawingRef.current = false;
|
|
3551
3877
|
}, []);
|
|
3552
|
-
|
|
3878
|
+
useEffect(() => {
|
|
3553
3879
|
if (!isOpen) return;
|
|
3554
3880
|
const canvas = canvasRef.current;
|
|
3555
3881
|
if (!canvas) return;
|
|
@@ -3594,54 +3920,96 @@ var SignaturePad = ({
|
|
|
3594
3920
|
onClose();
|
|
3595
3921
|
}
|
|
3596
3922
|
};
|
|
3923
|
+
useEffect(() => {
|
|
3924
|
+
if (!isOpen) return;
|
|
3925
|
+
const onKey = (e) => {
|
|
3926
|
+
if (e.key === "Escape") onClose();
|
|
3927
|
+
};
|
|
3928
|
+
document.addEventListener("keydown", onKey);
|
|
3929
|
+
return () => document.removeEventListener("keydown", onKey);
|
|
3930
|
+
}, [isOpen, onClose]);
|
|
3597
3931
|
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",
|
|
3932
|
+
return /* @__PURE__ */ React11.createElement("div", { className: "SignaturePad__overlay", onClick: handleOverlayClick }, /* @__PURE__ */ React11.createElement(
|
|
3933
|
+
"div",
|
|
3624
3934
|
{
|
|
3625
|
-
|
|
3626
|
-
|
|
3627
|
-
|
|
3935
|
+
className: "SignaturePad__modal",
|
|
3936
|
+
role: "dialog",
|
|
3937
|
+
"aria-modal": "true",
|
|
3938
|
+
"aria-labelledby": "signaturepad-title"
|
|
3628
3939
|
},
|
|
3629
|
-
"
|
|
3630
|
-
|
|
3940
|
+
/* @__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(
|
|
3941
|
+
"button",
|
|
3942
|
+
{
|
|
3943
|
+
type: "button",
|
|
3944
|
+
className: "SignaturePad__close",
|
|
3945
|
+
onClick: onClose,
|
|
3946
|
+
"aria-label": "Close"
|
|
3947
|
+
},
|
|
3948
|
+
/* @__PURE__ */ React11.createElement(
|
|
3949
|
+
"svg",
|
|
3950
|
+
{
|
|
3951
|
+
width: "14",
|
|
3952
|
+
height: "14",
|
|
3953
|
+
viewBox: "0 0 24 24",
|
|
3954
|
+
fill: "none",
|
|
3955
|
+
stroke: "currentColor",
|
|
3956
|
+
strokeWidth: "2.5",
|
|
3957
|
+
strokeLinecap: "round",
|
|
3958
|
+
"aria-hidden": "true"
|
|
3959
|
+
},
|
|
3960
|
+
/* @__PURE__ */ React11.createElement("path", { d: "M18 6 6 18M6 6l12 12" })
|
|
3961
|
+
)
|
|
3962
|
+
)),
|
|
3963
|
+
/* @__PURE__ */ React11.createElement("div", { className: "SignaturePad__canvas-wrap" }, /* @__PURE__ */ React11.createElement(
|
|
3964
|
+
"canvas",
|
|
3965
|
+
{
|
|
3966
|
+
ref: canvasRef,
|
|
3967
|
+
className: "SignaturePad__canvas",
|
|
3968
|
+
width,
|
|
3969
|
+
height
|
|
3970
|
+
}
|
|
3971
|
+
), /* @__PURE__ */ React11.createElement("div", { className: "SignaturePad__baseline", "aria-hidden": "true" }, /* @__PURE__ */ React11.createElement("span", { className: "SignaturePad__baseline-x" }, "\u2715"))),
|
|
3972
|
+
/* @__PURE__ */ React11.createElement("div", { className: "SignaturePad__buttons" }, /* @__PURE__ */ React11.createElement(
|
|
3973
|
+
"button",
|
|
3974
|
+
{
|
|
3975
|
+
type: "button",
|
|
3976
|
+
className: "SignaturePad__button SignaturePad__button--clear",
|
|
3977
|
+
onClick: handleClear
|
|
3978
|
+
},
|
|
3979
|
+
"Clear"
|
|
3980
|
+
), /* @__PURE__ */ React11.createElement("div", { className: "SignaturePad__buttons-right" }, /* @__PURE__ */ React11.createElement(
|
|
3981
|
+
"button",
|
|
3982
|
+
{
|
|
3983
|
+
type: "button",
|
|
3984
|
+
className: "SignaturePad__button SignaturePad__button--cancel",
|
|
3985
|
+
onClick: onClose
|
|
3986
|
+
},
|
|
3987
|
+
"Cancel"
|
|
3988
|
+
), /* @__PURE__ */ React11.createElement(
|
|
3989
|
+
"button",
|
|
3990
|
+
{
|
|
3991
|
+
type: "button",
|
|
3992
|
+
className: "SignaturePad__button SignaturePad__button--done",
|
|
3993
|
+
onClick: handleDone
|
|
3994
|
+
},
|
|
3995
|
+
"Add signature"
|
|
3996
|
+
)))
|
|
3997
|
+
));
|
|
3631
3998
|
};
|
|
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
3999
|
var DRAWING_COLORS = ["#000000", "#FF0000", "#0000FF", "#00FF00", "#FFFF00"];
|
|
3638
4000
|
var STROKE_WIDTHS = [
|
|
3639
4001
|
{ label: "Thin", value: 1 },
|
|
3640
4002
|
{ label: "Medium", value: 3 },
|
|
3641
4003
|
{ label: "Thick", value: 5 }
|
|
3642
4004
|
];
|
|
3643
|
-
var
|
|
3644
|
-
|
|
4005
|
+
var COLOR_NAMES3 = {
|
|
4006
|
+
"#000000": "Black",
|
|
4007
|
+
"#FF0000": "Red",
|
|
4008
|
+
"#0000FF": "Blue",
|
|
4009
|
+
"#00FF00": "Green",
|
|
4010
|
+
"#FFFF00": "Yellow"
|
|
4011
|
+
};
|
|
4012
|
+
var DefaultDeleteIcon5 = () => /* @__PURE__ */ React11.createElement(Trash2, { width: 14, height: 14 });
|
|
3645
4013
|
var renderStrokesToImage = (strokes, width, height) => {
|
|
3646
4014
|
const canvas = document.createElement("canvas");
|
|
3647
4015
|
canvas.width = width;
|
|
@@ -3677,18 +4045,50 @@ var DrawingHighlight = ({
|
|
|
3677
4045
|
onDelete,
|
|
3678
4046
|
deleteIcon
|
|
3679
4047
|
}) => {
|
|
4048
|
+
const [showStyleControls, setShowStyleControls] = useState(false);
|
|
4049
|
+
const [isColorMenuOpen, setIsColorMenuOpen] = useState(false);
|
|
4050
|
+
const [isSelected, setIsSelected] = useState(false);
|
|
4051
|
+
useClearTipWhileSelected(isSelected);
|
|
4052
|
+
const [configLayer, setConfigLayer] = useState(null);
|
|
4053
|
+
const styleControlsRef = useRef(null);
|
|
4054
|
+
const colorMenuRef = useRef(null);
|
|
4055
|
+
const containerRef = useRef(null);
|
|
4056
|
+
const toolbarWrapperRef = useRef(null);
|
|
3680
4057
|
const highlightClass = isScrolledTo ? "DrawingHighlight--scrolledTo" : "";
|
|
3681
|
-
const
|
|
3682
|
-
|
|
3683
|
-
|
|
3684
|
-
|
|
3685
|
-
|
|
3686
|
-
|
|
4058
|
+
const selectedClass = isSelected ? "DrawingHighlight--selected" : "";
|
|
4059
|
+
useEffect(() => {
|
|
4060
|
+
if (!isSelected) return;
|
|
4061
|
+
const handlePointerDown = (e) => {
|
|
4062
|
+
const target = e.target;
|
|
4063
|
+
const insideRoot = containerRef.current?.contains(target);
|
|
4064
|
+
const insideToolbar = toolbarWrapperRef.current?.contains(target);
|
|
4065
|
+
if (!insideRoot && !insideToolbar) {
|
|
4066
|
+
setIsSelected(false);
|
|
4067
|
+
setShowStyleControls(false);
|
|
4068
|
+
setIsColorMenuOpen(false);
|
|
4069
|
+
}
|
|
4070
|
+
};
|
|
4071
|
+
const handleKey = (e) => {
|
|
4072
|
+
if (e.key === "Escape") {
|
|
4073
|
+
setIsSelected(false);
|
|
4074
|
+
setShowStyleControls(false);
|
|
4075
|
+
setIsColorMenuOpen(false);
|
|
4076
|
+
}
|
|
4077
|
+
};
|
|
4078
|
+
document.addEventListener("mousedown", handlePointerDown);
|
|
4079
|
+
document.addEventListener("keydown", handleKey);
|
|
4080
|
+
return () => {
|
|
4081
|
+
document.removeEventListener("mousedown", handlePointerDown);
|
|
4082
|
+
document.removeEventListener("keydown", handleKey);
|
|
4083
|
+
};
|
|
4084
|
+
}, [isSelected]);
|
|
4085
|
+
useLayoutEffect(() => {
|
|
3687
4086
|
if (containerRef.current) {
|
|
3688
|
-
|
|
4087
|
+
const layer = findOrCreateHighlightConfigLayer(containerRef.current);
|
|
4088
|
+
setConfigLayer((prev) => prev === layer ? prev : layer);
|
|
3689
4089
|
}
|
|
3690
|
-
}
|
|
3691
|
-
|
|
4090
|
+
});
|
|
4091
|
+
useEffect(() => {
|
|
3692
4092
|
if (!showStyleControls) return;
|
|
3693
4093
|
const handleClickOutside = (e) => {
|
|
3694
4094
|
if (styleControlsRef.current && !styleControlsRef.current.contains(e.target)) {
|
|
@@ -3703,10 +4103,25 @@ var DrawingHighlight = ({
|
|
|
3703
4103
|
document.removeEventListener("mousedown", handleClickOutside);
|
|
3704
4104
|
};
|
|
3705
4105
|
}, [showStyleControls]);
|
|
4106
|
+
useEffect(() => {
|
|
4107
|
+
if (!isColorMenuOpen) return;
|
|
4108
|
+
const handleClickOutside = (e) => {
|
|
4109
|
+
if (colorMenuRef.current && !colorMenuRef.current.contains(e.target)) {
|
|
4110
|
+
setIsColorMenuOpen(false);
|
|
4111
|
+
}
|
|
4112
|
+
};
|
|
4113
|
+
const timeoutId = setTimeout(() => {
|
|
4114
|
+
document.addEventListener("mousedown", handleClickOutside);
|
|
4115
|
+
}, 0);
|
|
4116
|
+
return () => {
|
|
4117
|
+
clearTimeout(timeoutId);
|
|
4118
|
+
document.removeEventListener("mousedown", handleClickOutside);
|
|
4119
|
+
};
|
|
4120
|
+
}, [isColorMenuOpen]);
|
|
3706
4121
|
const key = `${highlight.position.boundingRect.width}${highlight.position.boundingRect.height}${highlight.position.boundingRect.left}${highlight.position.boundingRect.top}`;
|
|
3707
4122
|
const imageUrl = highlight.content?.image;
|
|
3708
4123
|
const strokes = highlight.content?.strokes;
|
|
3709
|
-
const handleColorChange =
|
|
4124
|
+
const handleColorChange = useCallback((newColor) => {
|
|
3710
4125
|
if (!strokes || !onStyleChange) return;
|
|
3711
4126
|
console.log("DrawingHighlight: Changing color to", newColor);
|
|
3712
4127
|
const newStrokes = strokes.map((stroke) => ({
|
|
@@ -3720,7 +4135,7 @@ var DrawingHighlight = ({
|
|
|
3720
4135
|
);
|
|
3721
4136
|
onStyleChange(newImage, newStrokes);
|
|
3722
4137
|
}, [strokes, onStyleChange, highlight.position.boundingRect.width, highlight.position.boundingRect.height]);
|
|
3723
|
-
const handleWidthChange =
|
|
4138
|
+
const handleWidthChange = useCallback((newWidth) => {
|
|
3724
4139
|
if (!strokes || !onStyleChange) return;
|
|
3725
4140
|
console.log("DrawingHighlight: Changing width to", newWidth);
|
|
3726
4141
|
const newStrokes = strokes.map((stroke) => ({
|
|
@@ -3736,84 +4151,169 @@ var DrawingHighlight = ({
|
|
|
3736
4151
|
}, [strokes, onStyleChange, highlight.position.boundingRect.width, highlight.position.boundingRect.height]);
|
|
3737
4152
|
const currentColor = strokes?.[0]?.color || "#000000";
|
|
3738
4153
|
const currentWidth = strokes?.[0]?.width || 3;
|
|
3739
|
-
|
|
4154
|
+
const handleRotate = useCallback((clockwise) => {
|
|
4155
|
+
if (!strokes || !onStyleChange) return;
|
|
4156
|
+
const { width, height, left, top, pageNumber } = highlight.position.boundingRect;
|
|
4157
|
+
const newStrokes = strokes.map((stroke) => ({
|
|
4158
|
+
...stroke,
|
|
4159
|
+
points: stroke.points.map(
|
|
4160
|
+
(p) => clockwise ? { x: height - p.y, y: p.x } : { x: p.y, y: width - p.x }
|
|
4161
|
+
)
|
|
4162
|
+
}));
|
|
4163
|
+
const newImage = renderStrokesToImage(newStrokes, height, width);
|
|
4164
|
+
onStyleChange(newImage, newStrokes);
|
|
4165
|
+
const centerX = left + width / 2;
|
|
4166
|
+
const centerY = top + height / 2;
|
|
4167
|
+
onChange?.({
|
|
4168
|
+
left: centerX - height / 2,
|
|
4169
|
+
top: centerY - width / 2,
|
|
4170
|
+
width: height,
|
|
4171
|
+
height: width,
|
|
4172
|
+
pageNumber
|
|
4173
|
+
});
|
|
4174
|
+
}, [strokes, onStyleChange, onChange, highlight.position.boundingRect]);
|
|
4175
|
+
const flipToolbar = highlight.position.boundingRect.top < 40;
|
|
4176
|
+
return /* @__PURE__ */ React11.createElement(
|
|
3740
4177
|
"div",
|
|
3741
4178
|
{
|
|
3742
|
-
className: `DrawingHighlight ${highlightClass}`,
|
|
4179
|
+
className: `DrawingHighlight ${highlightClass} ${selectedClass}`,
|
|
3743
4180
|
onContextMenu,
|
|
3744
4181
|
ref: containerRef
|
|
3745
4182
|
},
|
|
3746
|
-
configLayer &&
|
|
3747
|
-
/* @__PURE__ */
|
|
4183
|
+
configLayer && createPortal(
|
|
4184
|
+
/* @__PURE__ */ React11.createElement(
|
|
3748
4185
|
"div",
|
|
3749
4186
|
{
|
|
3750
|
-
className:
|
|
4187
|
+
className: "DrawingHighlight__toolbar-wrapper",
|
|
4188
|
+
ref: toolbarWrapperRef,
|
|
3751
4189
|
style: {
|
|
3752
|
-
|
|
3753
|
-
|
|
3754
|
-
|
|
3755
|
-
|
|
3756
|
-
onMouseLeave: () => setIsHovered(false)
|
|
4190
|
+
position: "absolute",
|
|
4191
|
+
left: highlight.position.boundingRect.left,
|
|
4192
|
+
top: highlight.position.boundingRect.top
|
|
4193
|
+
}
|
|
3757
4194
|
},
|
|
3758
|
-
/* @__PURE__ */
|
|
3759
|
-
|
|
3760
|
-
"button",
|
|
4195
|
+
/* @__PURE__ */ React11.createElement(
|
|
4196
|
+
"div",
|
|
3761
4197
|
{
|
|
3762
|
-
|
|
3763
|
-
className: "DrawingHighlight__style-button",
|
|
3764
|
-
title: "Edit style",
|
|
3765
|
-
onClick: (e) => {
|
|
3766
|
-
e.stopPropagation();
|
|
3767
|
-
setShowStyleControls(!showStyleControls);
|
|
3768
|
-
}
|
|
4198
|
+
className: `DrawingHighlight__toolbar DrawingHighlight__toolbar--floating ${flipToolbar ? "DrawingHighlight__toolbar--below" : ""} ${isSelected || isScrolledTo || showStyleControls ? "DrawingHighlight__toolbar--visible" : ""}`
|
|
3769
4199
|
},
|
|
3770
|
-
|
|
3771
|
-
|
|
3772
|
-
|
|
3773
|
-
|
|
3774
|
-
|
|
3775
|
-
|
|
3776
|
-
|
|
3777
|
-
e
|
|
3778
|
-
|
|
4200
|
+
strokes && strokes.length > 0 && onStyleChange && /* @__PURE__ */ React11.createElement(React11.Fragment, null, /* @__PURE__ */ React11.createElement(
|
|
4201
|
+
"button",
|
|
4202
|
+
{
|
|
4203
|
+
type: "button",
|
|
4204
|
+
className: "DrawingHighlight__color-trigger",
|
|
4205
|
+
"aria-label": "Stroke color",
|
|
4206
|
+
"aria-expanded": isColorMenuOpen,
|
|
4207
|
+
onClick: (e) => {
|
|
4208
|
+
e.stopPropagation();
|
|
4209
|
+
setShowStyleControls(false);
|
|
4210
|
+
setIsColorMenuOpen((v) => !v);
|
|
4211
|
+
},
|
|
4212
|
+
title: "Stroke color"
|
|
3779
4213
|
},
|
|
3780
|
-
|
|
3781
|
-
|
|
3782
|
-
|
|
3783
|
-
|
|
3784
|
-
|
|
3785
|
-
|
|
3786
|
-
|
|
3787
|
-
|
|
3788
|
-
|
|
3789
|
-
|
|
3790
|
-
|
|
3791
|
-
|
|
3792
|
-
|
|
3793
|
-
|
|
3794
|
-
|
|
4214
|
+
/* @__PURE__ */ React11.createElement(
|
|
4215
|
+
"span",
|
|
4216
|
+
{
|
|
4217
|
+
className: "DrawingHighlight__color-trigger-dot",
|
|
4218
|
+
style: { backgroundColor: currentColor }
|
|
4219
|
+
}
|
|
4220
|
+
),
|
|
4221
|
+
/* @__PURE__ */ React11.createElement(ChevronDown, { width: 12, height: 12, strokeWidth: 2.5 })
|
|
4222
|
+
), /* @__PURE__ */ React11.createElement("div", { className: "DrawingHighlight__toolbar-divider" })),
|
|
4223
|
+
strokes && strokes.length > 0 && onStyleChange && /* @__PURE__ */ React11.createElement(
|
|
4224
|
+
"button",
|
|
4225
|
+
{
|
|
4226
|
+
type: "button",
|
|
4227
|
+
className: "DrawingHighlight__style-button",
|
|
4228
|
+
title: "Stroke width",
|
|
4229
|
+
onClick: (e) => {
|
|
4230
|
+
e.stopPropagation();
|
|
4231
|
+
setIsColorMenuOpen(false);
|
|
4232
|
+
setShowStyleControls(!showStyleControls);
|
|
4233
|
+
}
|
|
3795
4234
|
},
|
|
3796
|
-
|
|
3797
|
-
|
|
3798
|
-
|
|
3799
|
-
|
|
3800
|
-
|
|
3801
|
-
|
|
3802
|
-
|
|
3803
|
-
|
|
3804
|
-
|
|
3805
|
-
|
|
3806
|
-
|
|
4235
|
+
/* @__PURE__ */ React11.createElement(Pencil, { width: 14, height: 14 })
|
|
4236
|
+
),
|
|
4237
|
+
strokes && strokes.length > 0 && onStyleChange && /* @__PURE__ */ React11.createElement(React11.Fragment, null, /* @__PURE__ */ React11.createElement(
|
|
4238
|
+
"button",
|
|
4239
|
+
{
|
|
4240
|
+
type: "button",
|
|
4241
|
+
className: "DrawingHighlight__rotate-button",
|
|
4242
|
+
title: "Rotate left",
|
|
4243
|
+
onClick: (e) => {
|
|
4244
|
+
e.stopPropagation();
|
|
4245
|
+
handleRotate(false);
|
|
4246
|
+
}
|
|
3807
4247
|
},
|
|
3808
|
-
|
|
3809
|
-
|
|
3810
|
-
|
|
3811
|
-
|
|
4248
|
+
/* @__PURE__ */ React11.createElement(RotateCcw, { width: 14, height: 14 })
|
|
4249
|
+
), /* @__PURE__ */ React11.createElement(
|
|
4250
|
+
"button",
|
|
4251
|
+
{
|
|
4252
|
+
type: "button",
|
|
4253
|
+
className: "DrawingHighlight__rotate-button",
|
|
4254
|
+
title: "Rotate right",
|
|
4255
|
+
onClick: (e) => {
|
|
4256
|
+
e.stopPropagation();
|
|
4257
|
+
handleRotate(true);
|
|
4258
|
+
}
|
|
4259
|
+
},
|
|
4260
|
+
/* @__PURE__ */ React11.createElement(RotateCw, { width: 14, height: 14 })
|
|
4261
|
+
)),
|
|
4262
|
+
onDelete && /* @__PURE__ */ React11.createElement(
|
|
4263
|
+
"button",
|
|
4264
|
+
{
|
|
4265
|
+
className: "DrawingHighlight__delete-button",
|
|
4266
|
+
onClick: (e) => {
|
|
4267
|
+
e.stopPropagation();
|
|
4268
|
+
onDelete();
|
|
4269
|
+
},
|
|
4270
|
+
title: "Delete",
|
|
4271
|
+
type: "button"
|
|
4272
|
+
},
|
|
4273
|
+
deleteIcon || /* @__PURE__ */ React11.createElement(DefaultDeleteIcon5, null)
|
|
4274
|
+
),
|
|
4275
|
+
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(
|
|
4276
|
+
"button",
|
|
4277
|
+
{
|
|
4278
|
+
key: w.value,
|
|
4279
|
+
type: "button",
|
|
4280
|
+
className: `DrawingHighlight__width-button ${currentWidth === w.value ? "active" : ""}`,
|
|
4281
|
+
onClick: (e) => {
|
|
4282
|
+
e.stopPropagation();
|
|
4283
|
+
handleWidthChange(w.value);
|
|
4284
|
+
},
|
|
4285
|
+
title: w.label
|
|
4286
|
+
},
|
|
4287
|
+
w.label
|
|
4288
|
+
)))),
|
|
4289
|
+
isColorMenuOpen && strokes && strokes.length > 0 && onStyleChange && /* @__PURE__ */ React11.createElement("div", { className: "DrawingHighlight__color-menu", ref: colorMenuRef }, DRAWING_COLORS.map((color) => /* @__PURE__ */ React11.createElement(
|
|
4290
|
+
"button",
|
|
4291
|
+
{
|
|
4292
|
+
key: color,
|
|
4293
|
+
type: "button",
|
|
4294
|
+
className: "DrawingHighlight__color-menu-item",
|
|
4295
|
+
onClick: (e) => {
|
|
4296
|
+
e.stopPropagation();
|
|
4297
|
+
handleColorChange(color);
|
|
4298
|
+
setIsColorMenuOpen(false);
|
|
4299
|
+
}
|
|
4300
|
+
},
|
|
4301
|
+
/* @__PURE__ */ React11.createElement(
|
|
4302
|
+
"span",
|
|
4303
|
+
{
|
|
4304
|
+
className: "DrawingHighlight__color-menu-dot",
|
|
4305
|
+
style: { backgroundColor: color }
|
|
4306
|
+
}
|
|
4307
|
+
),
|
|
4308
|
+
/* @__PURE__ */ React11.createElement("span", { className: "DrawingHighlight__color-menu-label" }, COLOR_NAMES3[color] || color),
|
|
4309
|
+
currentColor === color && /* @__PURE__ */ React11.createElement("span", { className: "DrawingHighlight__color-menu-check" }, /* @__PURE__ */ React11.createElement(Check, { width: 14, height: 14, strokeWidth: 2.5 }))
|
|
4310
|
+
)))
|
|
4311
|
+
)
|
|
3812
4312
|
),
|
|
3813
4313
|
configLayer
|
|
3814
4314
|
),
|
|
3815
|
-
/* @__PURE__ */
|
|
3816
|
-
|
|
4315
|
+
/* @__PURE__ */ React11.createElement(
|
|
4316
|
+
Rnd,
|
|
3817
4317
|
{
|
|
3818
4318
|
className: "DrawingHighlight__rnd",
|
|
3819
4319
|
onDragStop: (_, data) => {
|
|
@@ -3825,7 +4325,10 @@ var DrawingHighlight = ({
|
|
|
3825
4325
|
onChange?.(boundingRect);
|
|
3826
4326
|
onEditEnd?.();
|
|
3827
4327
|
},
|
|
3828
|
-
onDragStart:
|
|
4328
|
+
onDragStart: () => {
|
|
4329
|
+
setIsSelected(true);
|
|
4330
|
+
onEditStart?.();
|
|
4331
|
+
},
|
|
3829
4332
|
onResizeStop: (_e, _direction, ref, _delta, position) => {
|
|
3830
4333
|
const boundingRect = {
|
|
3831
4334
|
top: position.y,
|
|
@@ -3852,17 +4355,16 @@ var DrawingHighlight = ({
|
|
|
3852
4355
|
onClick: (event) => {
|
|
3853
4356
|
event.stopPropagation();
|
|
3854
4357
|
event.preventDefault();
|
|
4358
|
+
setIsSelected(true);
|
|
3855
4359
|
},
|
|
3856
4360
|
style
|
|
3857
4361
|
},
|
|
3858
|
-
/* @__PURE__ */
|
|
4362
|
+
/* @__PURE__ */ React11.createElement(
|
|
3859
4363
|
"div",
|
|
3860
4364
|
{
|
|
3861
|
-
className: "DrawingHighlight__container"
|
|
3862
|
-
onMouseEnter: () => setIsHovered(true),
|
|
3863
|
-
onMouseLeave: () => setIsHovered(false)
|
|
4365
|
+
className: "DrawingHighlight__container"
|
|
3864
4366
|
},
|
|
3865
|
-
/* @__PURE__ */
|
|
4367
|
+
/* @__PURE__ */ React11.createElement("div", { className: "DrawingHighlight__content" }, imageUrl ? /* @__PURE__ */ React11.createElement(
|
|
3866
4368
|
"img",
|
|
3867
4369
|
{
|
|
3868
4370
|
src: imageUrl,
|
|
@@ -3870,23 +4372,13 @@ var DrawingHighlight = ({
|
|
|
3870
4372
|
className: "DrawingHighlight__image",
|
|
3871
4373
|
draggable: false
|
|
3872
4374
|
}
|
|
3873
|
-
) : /* @__PURE__ */
|
|
4375
|
+
) : /* @__PURE__ */ React11.createElement("div", { className: "DrawingHighlight__placeholder" }, "No drawing"))
|
|
3874
4376
|
)
|
|
3875
4377
|
)
|
|
3876
4378
|
);
|
|
3877
4379
|
};
|
|
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" }));
|
|
4380
|
+
var DefaultStyleIcon3 = () => /* @__PURE__ */ React11.createElement(Palette, { width: 14, height: 14 });
|
|
4381
|
+
var DefaultDeleteIcon6 = () => /* @__PURE__ */ React11.createElement(Trash2, { width: 14, height: 14 });
|
|
3890
4382
|
var DEFAULT_COLOR_PRESETS3 = [
|
|
3891
4383
|
"#000000",
|
|
3892
4384
|
// Black
|
|
@@ -3899,6 +4391,13 @@ var DEFAULT_COLOR_PRESETS3 = [
|
|
|
3899
4391
|
"#FF6600"
|
|
3900
4392
|
// Orange
|
|
3901
4393
|
];
|
|
4394
|
+
var COLOR_NAMES4 = {
|
|
4395
|
+
"#000000": "Black",
|
|
4396
|
+
"#FF0000": "Red",
|
|
4397
|
+
"#0000FF": "Blue",
|
|
4398
|
+
"#00AA00": "Green",
|
|
4399
|
+
"#FF6600": "Orange"
|
|
4400
|
+
};
|
|
3902
4401
|
var STROKE_WIDTHS2 = [
|
|
3903
4402
|
{ label: "Thin", value: 1 },
|
|
3904
4403
|
{ label: "Medium", value: 2 },
|
|
@@ -3924,17 +4423,48 @@ var ShapeHighlight = ({
|
|
|
3924
4423
|
startPoint,
|
|
3925
4424
|
endPoint
|
|
3926
4425
|
}) => {
|
|
3927
|
-
const [isStylePanelOpen, setIsStylePanelOpen] =
|
|
3928
|
-
const [
|
|
3929
|
-
const [
|
|
3930
|
-
|
|
3931
|
-
const
|
|
3932
|
-
|
|
4426
|
+
const [isStylePanelOpen, setIsStylePanelOpen] = useState(false);
|
|
4427
|
+
const [isColorMenuOpen, setIsColorMenuOpen] = useState(false);
|
|
4428
|
+
const [isSelected, setIsSelected] = useState(false);
|
|
4429
|
+
useClearTipWhileSelected(isSelected);
|
|
4430
|
+
const [configLayer, setConfigLayer] = useState(null);
|
|
4431
|
+
const stylePanelRef = useRef(null);
|
|
4432
|
+
const colorMenuRef = useRef(null);
|
|
4433
|
+
const containerRef = useRef(null);
|
|
4434
|
+
const toolbarWrapperRef = useRef(null);
|
|
4435
|
+
useEffect(() => {
|
|
4436
|
+
if (!isSelected) return;
|
|
4437
|
+
const handlePointerDown = (e) => {
|
|
4438
|
+
const target = e.target;
|
|
4439
|
+
const insideRoot = containerRef.current?.contains(target);
|
|
4440
|
+
const insideToolbar = toolbarWrapperRef.current?.contains(target);
|
|
4441
|
+
if (!insideRoot && !insideToolbar) {
|
|
4442
|
+
setIsSelected(false);
|
|
4443
|
+
setIsStylePanelOpen(false);
|
|
4444
|
+
setIsColorMenuOpen(false);
|
|
4445
|
+
}
|
|
4446
|
+
};
|
|
4447
|
+
const handleKey = (e) => {
|
|
4448
|
+
if (e.key === "Escape") {
|
|
4449
|
+
setIsSelected(false);
|
|
4450
|
+
setIsStylePanelOpen(false);
|
|
4451
|
+
setIsColorMenuOpen(false);
|
|
4452
|
+
}
|
|
4453
|
+
};
|
|
4454
|
+
document.addEventListener("mousedown", handlePointerDown);
|
|
4455
|
+
document.addEventListener("keydown", handleKey);
|
|
4456
|
+
return () => {
|
|
4457
|
+
document.removeEventListener("mousedown", handlePointerDown);
|
|
4458
|
+
document.removeEventListener("keydown", handleKey);
|
|
4459
|
+
};
|
|
4460
|
+
}, [isSelected]);
|
|
4461
|
+
useLayoutEffect(() => {
|
|
3933
4462
|
if (containerRef.current) {
|
|
3934
|
-
|
|
4463
|
+
const layer = findOrCreateHighlightConfigLayer(containerRef.current);
|
|
4464
|
+
setConfigLayer((prev) => prev === layer ? prev : layer);
|
|
3935
4465
|
}
|
|
3936
|
-
}
|
|
3937
|
-
|
|
4466
|
+
});
|
|
4467
|
+
useEffect(() => {
|
|
3938
4468
|
if (!isStylePanelOpen) return;
|
|
3939
4469
|
const handleClickOutside = (e) => {
|
|
3940
4470
|
if (stylePanelRef.current && !stylePanelRef.current.contains(e.target)) {
|
|
@@ -3949,13 +4479,29 @@ var ShapeHighlight = ({
|
|
|
3949
4479
|
document.removeEventListener("mousedown", handleClickOutside);
|
|
3950
4480
|
};
|
|
3951
4481
|
}, [isStylePanelOpen]);
|
|
4482
|
+
useEffect(() => {
|
|
4483
|
+
if (!isColorMenuOpen) return;
|
|
4484
|
+
const handleClickOutside = (e) => {
|
|
4485
|
+
if (colorMenuRef.current && !colorMenuRef.current.contains(e.target)) {
|
|
4486
|
+
setIsColorMenuOpen(false);
|
|
4487
|
+
}
|
|
4488
|
+
};
|
|
4489
|
+
const timeoutId = setTimeout(() => {
|
|
4490
|
+
document.addEventListener("mousedown", handleClickOutside);
|
|
4491
|
+
}, 0);
|
|
4492
|
+
return () => {
|
|
4493
|
+
clearTimeout(timeoutId);
|
|
4494
|
+
document.removeEventListener("mousedown", handleClickOutside);
|
|
4495
|
+
};
|
|
4496
|
+
}, [isColorMenuOpen]);
|
|
3952
4497
|
const highlightClass = isScrolledTo ? "ShapeHighlight--scrolledTo" : "";
|
|
4498
|
+
const selectedClass = isSelected ? "ShapeHighlight--selected" : "";
|
|
3953
4499
|
const key = `${highlight.position.boundingRect.width}${highlight.position.boundingRect.height}${highlight.position.boundingRect.left}${highlight.position.boundingRect.top}`;
|
|
3954
4500
|
const markerId = `arrowhead-${highlight.id}`;
|
|
3955
4501
|
const renderShape = (width, height) => {
|
|
3956
4502
|
switch (shapeType) {
|
|
3957
4503
|
case "rectangle":
|
|
3958
|
-
return /* @__PURE__ */
|
|
4504
|
+
return /* @__PURE__ */ React11.createElement(
|
|
3959
4505
|
"svg",
|
|
3960
4506
|
{
|
|
3961
4507
|
className: "ShapeHighlight__svg",
|
|
@@ -3963,7 +4509,7 @@ var ShapeHighlight = ({
|
|
|
3963
4509
|
height,
|
|
3964
4510
|
viewBox: `0 0 ${width} ${height}`
|
|
3965
4511
|
},
|
|
3966
|
-
/* @__PURE__ */
|
|
4512
|
+
/* @__PURE__ */ React11.createElement(
|
|
3967
4513
|
"rect",
|
|
3968
4514
|
{
|
|
3969
4515
|
x: strokeWidth / 2,
|
|
@@ -3977,7 +4523,7 @@ var ShapeHighlight = ({
|
|
|
3977
4523
|
)
|
|
3978
4524
|
);
|
|
3979
4525
|
case "circle":
|
|
3980
|
-
return /* @__PURE__ */
|
|
4526
|
+
return /* @__PURE__ */ React11.createElement(
|
|
3981
4527
|
"svg",
|
|
3982
4528
|
{
|
|
3983
4529
|
className: "ShapeHighlight__svg",
|
|
@@ -3985,7 +4531,7 @@ var ShapeHighlight = ({
|
|
|
3985
4531
|
height,
|
|
3986
4532
|
viewBox: `0 0 ${width} ${height}`
|
|
3987
4533
|
},
|
|
3988
|
-
/* @__PURE__ */
|
|
4534
|
+
/* @__PURE__ */ React11.createElement(
|
|
3989
4535
|
"ellipse",
|
|
3990
4536
|
{
|
|
3991
4537
|
cx: width / 2,
|
|
@@ -4003,7 +4549,7 @@ var ShapeHighlight = ({
|
|
|
4003
4549
|
const y1 = startPoint ? startPoint.y * height : height / 2;
|
|
4004
4550
|
const x2 = endPoint ? endPoint.x * width : width - strokeWidth - 10;
|
|
4005
4551
|
const y2 = endPoint ? endPoint.y * height : height / 2;
|
|
4006
|
-
return /* @__PURE__ */
|
|
4552
|
+
return /* @__PURE__ */ React11.createElement(
|
|
4007
4553
|
"svg",
|
|
4008
4554
|
{
|
|
4009
4555
|
className: "ShapeHighlight__svg",
|
|
@@ -4011,7 +4557,7 @@ var ShapeHighlight = ({
|
|
|
4011
4557
|
height,
|
|
4012
4558
|
viewBox: `0 0 ${width} ${height}`
|
|
4013
4559
|
},
|
|
4014
|
-
/* @__PURE__ */
|
|
4560
|
+
/* @__PURE__ */ React11.createElement("defs", null, /* @__PURE__ */ React11.createElement(
|
|
4015
4561
|
"marker",
|
|
4016
4562
|
{
|
|
4017
4563
|
id: markerId,
|
|
@@ -4021,9 +4567,9 @@ var ShapeHighlight = ({
|
|
|
4021
4567
|
refY: "3.5",
|
|
4022
4568
|
orient: "auto"
|
|
4023
4569
|
},
|
|
4024
|
-
/* @__PURE__ */
|
|
4570
|
+
/* @__PURE__ */ React11.createElement("polygon", { points: "0 0, 10 3.5, 0 7", fill: strokeColor })
|
|
4025
4571
|
)),
|
|
4026
|
-
/* @__PURE__ */
|
|
4572
|
+
/* @__PURE__ */ React11.createElement(
|
|
4027
4573
|
"line",
|
|
4028
4574
|
{
|
|
4029
4575
|
x1,
|
|
@@ -4041,46 +4587,68 @@ var ShapeHighlight = ({
|
|
|
4041
4587
|
return null;
|
|
4042
4588
|
}
|
|
4043
4589
|
};
|
|
4044
|
-
return /* @__PURE__ */
|
|
4590
|
+
return /* @__PURE__ */ React11.createElement(
|
|
4045
4591
|
"div",
|
|
4046
4592
|
{
|
|
4047
|
-
className: `ShapeHighlight ${highlightClass}`,
|
|
4593
|
+
className: `ShapeHighlight ${highlightClass} ${selectedClass}`,
|
|
4048
4594
|
onContextMenu,
|
|
4049
4595
|
ref: containerRef
|
|
4050
4596
|
},
|
|
4051
|
-
configLayer && (onStyleChange || onDelete) &&
|
|
4052
|
-
/* @__PURE__ */
|
|
4597
|
+
configLayer && (onStyleChange || onDelete) && createPortal(
|
|
4598
|
+
/* @__PURE__ */ React11.createElement(
|
|
4053
4599
|
"div",
|
|
4054
4600
|
{
|
|
4055
4601
|
className: "ShapeHighlight__toolbar-wrapper",
|
|
4602
|
+
ref: toolbarWrapperRef,
|
|
4056
4603
|
style: {
|
|
4057
4604
|
position: "absolute",
|
|
4058
4605
|
left: highlight.position.boundingRect.left,
|
|
4059
|
-
top: highlight.position.boundingRect.top
|
|
4060
|
-
|
|
4061
|
-
},
|
|
4062
|
-
onMouseEnter: () => setIsHovered(true),
|
|
4063
|
-
onMouseLeave: () => setIsHovered(false)
|
|
4606
|
+
top: highlight.position.boundingRect.top
|
|
4607
|
+
}
|
|
4064
4608
|
},
|
|
4065
|
-
/* @__PURE__ */
|
|
4609
|
+
/* @__PURE__ */ React11.createElement(
|
|
4066
4610
|
"div",
|
|
4067
4611
|
{
|
|
4068
|
-
className: `ShapeHighlight__toolbar ${
|
|
4612
|
+
className: `ShapeHighlight__toolbar ${isSelected || isScrolledTo || isStylePanelOpen || isColorMenuOpen ? "ShapeHighlight__toolbar--visible" : ""}`
|
|
4069
4613
|
},
|
|
4070
|
-
onStyleChange && /* @__PURE__ */
|
|
4614
|
+
onStyleChange && /* @__PURE__ */ React11.createElement(React11.Fragment, null, /* @__PURE__ */ React11.createElement(
|
|
4615
|
+
"button",
|
|
4616
|
+
{
|
|
4617
|
+
type: "button",
|
|
4618
|
+
className: "ShapeHighlight__color-trigger",
|
|
4619
|
+
"aria-label": "Stroke color",
|
|
4620
|
+
"aria-expanded": isColorMenuOpen,
|
|
4621
|
+
onClick: (e) => {
|
|
4622
|
+
e.stopPropagation();
|
|
4623
|
+
setIsStylePanelOpen(false);
|
|
4624
|
+
setIsColorMenuOpen((v) => !v);
|
|
4625
|
+
},
|
|
4626
|
+
title: "Stroke color"
|
|
4627
|
+
},
|
|
4628
|
+
/* @__PURE__ */ React11.createElement(
|
|
4629
|
+
"span",
|
|
4630
|
+
{
|
|
4631
|
+
className: "ShapeHighlight__color-trigger-dot",
|
|
4632
|
+
style: { backgroundColor: strokeColor }
|
|
4633
|
+
}
|
|
4634
|
+
),
|
|
4635
|
+
/* @__PURE__ */ React11.createElement(ChevronDown, { width: 12, height: 12, strokeWidth: 2.5 })
|
|
4636
|
+
), /* @__PURE__ */ React11.createElement("div", { className: "ShapeHighlight__toolbar-divider" })),
|
|
4637
|
+
onStyleChange && /* @__PURE__ */ React11.createElement(
|
|
4071
4638
|
"button",
|
|
4072
4639
|
{
|
|
4073
4640
|
className: "ShapeHighlight__style-button",
|
|
4074
4641
|
onClick: (e) => {
|
|
4075
4642
|
e.stopPropagation();
|
|
4643
|
+
setIsColorMenuOpen(false);
|
|
4076
4644
|
setIsStylePanelOpen(!isStylePanelOpen);
|
|
4077
4645
|
},
|
|
4078
|
-
title: "
|
|
4646
|
+
title: "Stroke width",
|
|
4079
4647
|
type: "button"
|
|
4080
4648
|
},
|
|
4081
|
-
styleIcon || /* @__PURE__ */
|
|
4649
|
+
styleIcon || /* @__PURE__ */ React11.createElement(DefaultStyleIcon3, null)
|
|
4082
4650
|
),
|
|
4083
|
-
onDelete && /* @__PURE__ */
|
|
4651
|
+
onDelete && /* @__PURE__ */ React11.createElement(
|
|
4084
4652
|
"button",
|
|
4085
4653
|
{
|
|
4086
4654
|
className: "ShapeHighlight__delete-button",
|
|
@@ -4091,37 +4659,46 @@ var ShapeHighlight = ({
|
|
|
4091
4659
|
title: "Delete",
|
|
4092
4660
|
type: "button"
|
|
4093
4661
|
},
|
|
4094
|
-
deleteIcon || /* @__PURE__ */
|
|
4662
|
+
deleteIcon || /* @__PURE__ */ React11.createElement(DefaultDeleteIcon6, null)
|
|
4095
4663
|
)
|
|
4096
4664
|
),
|
|
4097
|
-
|
|
4665
|
+
isColorMenuOpen && onStyleChange && /* @__PURE__ */ React11.createElement(
|
|
4098
4666
|
"div",
|
|
4099
4667
|
{
|
|
4100
|
-
className: "
|
|
4101
|
-
ref:
|
|
4668
|
+
className: "ShapeHighlight__color-menu",
|
|
4669
|
+
ref: colorMenuRef,
|
|
4102
4670
|
onClick: (e) => e.stopPropagation()
|
|
4103
4671
|
},
|
|
4104
|
-
|
|
4672
|
+
colorPresets.map((c) => /* @__PURE__ */ React11.createElement(
|
|
4105
4673
|
"button",
|
|
4106
4674
|
{
|
|
4107
4675
|
key: c,
|
|
4108
4676
|
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 });
|
|
4677
|
+
className: "ShapeHighlight__color-menu-item",
|
|
4678
|
+
onClick: () => {
|
|
4679
|
+
onStyleChange({ strokeColor: c });
|
|
4680
|
+
setIsColorMenuOpen(false);
|
|
4121
4681
|
}
|
|
4122
|
-
}
|
|
4123
|
-
|
|
4124
|
-
|
|
4682
|
+
},
|
|
4683
|
+
/* @__PURE__ */ React11.createElement(
|
|
4684
|
+
"span",
|
|
4685
|
+
{
|
|
4686
|
+
className: "ShapeHighlight__color-menu-dot",
|
|
4687
|
+
style: { backgroundColor: c }
|
|
4688
|
+
}
|
|
4689
|
+
),
|
|
4690
|
+
/* @__PURE__ */ React11.createElement("span", { className: "ShapeHighlight__color-menu-label" }, COLOR_NAMES4[c] || c),
|
|
4691
|
+
strokeColor === c && /* @__PURE__ */ React11.createElement("span", { className: "ShapeHighlight__color-menu-check" }, /* @__PURE__ */ React11.createElement(Check, { width: 14, height: 14, strokeWidth: 2.5 }))
|
|
4692
|
+
))
|
|
4693
|
+
),
|
|
4694
|
+
isStylePanelOpen && onStyleChange && /* @__PURE__ */ React11.createElement(
|
|
4695
|
+
"div",
|
|
4696
|
+
{
|
|
4697
|
+
className: "ShapeHighlight__style-panel",
|
|
4698
|
+
ref: stylePanelRef,
|
|
4699
|
+
onClick: (e) => e.stopPropagation()
|
|
4700
|
+
},
|
|
4701
|
+
/* @__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
4702
|
"button",
|
|
4126
4703
|
{
|
|
4127
4704
|
key: w.value,
|
|
@@ -4136,11 +4713,9 @@ var ShapeHighlight = ({
|
|
|
4136
4713
|
),
|
|
4137
4714
|
configLayer
|
|
4138
4715
|
),
|
|
4139
|
-
/* @__PURE__ */
|
|
4140
|
-
|
|
4716
|
+
/* @__PURE__ */ React11.createElement(
|
|
4717
|
+
Rnd,
|
|
4141
4718
|
{
|
|
4142
|
-
onMouseEnter: () => setIsHovered(true),
|
|
4143
|
-
onMouseLeave: () => setIsHovered(false),
|
|
4144
4719
|
className: "ShapeHighlight__rnd",
|
|
4145
4720
|
onDragStop: (_, data) => {
|
|
4146
4721
|
const boundingRect = {
|
|
@@ -4151,7 +4726,10 @@ var ShapeHighlight = ({
|
|
|
4151
4726
|
onChange?.(boundingRect);
|
|
4152
4727
|
onEditEnd?.();
|
|
4153
4728
|
},
|
|
4154
|
-
onDragStart:
|
|
4729
|
+
onDragStart: () => {
|
|
4730
|
+
setIsSelected(true);
|
|
4731
|
+
onEditStart?.();
|
|
4732
|
+
},
|
|
4155
4733
|
onResizeStop: (_e, _direction, ref, _delta, position) => {
|
|
4156
4734
|
const boundingRect = {
|
|
4157
4735
|
top: position.y,
|
|
@@ -4178,23 +4756,20 @@ var ShapeHighlight = ({
|
|
|
4178
4756
|
onClick: (event) => {
|
|
4179
4757
|
event.stopPropagation();
|
|
4180
4758
|
event.preventDefault();
|
|
4759
|
+
setIsSelected(true);
|
|
4181
4760
|
},
|
|
4182
4761
|
style
|
|
4183
4762
|
},
|
|
4184
|
-
/* @__PURE__ */
|
|
4763
|
+
/* @__PURE__ */ React11.createElement("div", { className: "ShapeHighlight__container" }, renderShape(
|
|
4185
4764
|
highlight.position.boundingRect.width || 100,
|
|
4186
4765
|
highlight.position.boundingRect.height || 100
|
|
4187
4766
|
))
|
|
4188
4767
|
)
|
|
4189
4768
|
);
|
|
4190
4769
|
};
|
|
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
4770
|
var DEFAULT_BEFORE_LOAD = (progress) => {
|
|
4196
4771
|
const pct = progress && progress.total ? Math.min(100, Math.floor(progress.loaded / progress.total * 100)) : null;
|
|
4197
|
-
return /* @__PURE__ */
|
|
4772
|
+
return /* @__PURE__ */ React11.createElement(
|
|
4198
4773
|
"div",
|
|
4199
4774
|
{
|
|
4200
4775
|
style: {
|
|
@@ -4209,7 +4784,7 @@ var DEFAULT_BEFORE_LOAD = (progress) => {
|
|
|
4209
4784
|
fontSize: 13
|
|
4210
4785
|
}
|
|
4211
4786
|
},
|
|
4212
|
-
/* @__PURE__ */
|
|
4787
|
+
/* @__PURE__ */ React11.createElement(
|
|
4213
4788
|
"div",
|
|
4214
4789
|
{
|
|
4215
4790
|
style: {
|
|
@@ -4222,11 +4797,11 @@ var DEFAULT_BEFORE_LOAD = (progress) => {
|
|
|
4222
4797
|
}
|
|
4223
4798
|
}
|
|
4224
4799
|
),
|
|
4225
|
-
/* @__PURE__ */
|
|
4226
|
-
/* @__PURE__ */
|
|
4800
|
+
/* @__PURE__ */ React11.createElement("div", null, pct !== null ? `Loading ${pct}%` : "Loading\u2026"),
|
|
4801
|
+
/* @__PURE__ */ React11.createElement("style", null, "@keyframes pdfloader-spin{to{transform:rotate(360deg)}}")
|
|
4227
4802
|
);
|
|
4228
4803
|
};
|
|
4229
|
-
var DEFAULT_ERROR_MESSAGE = (error) => /* @__PURE__ */
|
|
4804
|
+
var DEFAULT_ERROR_MESSAGE = (error) => /* @__PURE__ */ React11.createElement("div", { style: { color: "black" } }, error.message);
|
|
4230
4805
|
var DEFAULT_ON_ERROR = (error) => {
|
|
4231
4806
|
throw new Error(`Error loading PDF document: ${error.message}!`);
|
|
4232
4807
|
};
|
|
@@ -4267,13 +4842,17 @@ var stripUndefined = (obj) => {
|
|
|
4267
4842
|
if (v !== void 0) out[k] = v;
|
|
4268
4843
|
return out;
|
|
4269
4844
|
};
|
|
4845
|
+
var SECURE_DEFAULTS = {
|
|
4846
|
+
enableScripting: false,
|
|
4847
|
+
isEvalSupported: false
|
|
4848
|
+
};
|
|
4270
4849
|
var buildSource = (document2, perf) => {
|
|
4271
|
-
const cleaned = stripUndefined(perf);
|
|
4850
|
+
const cleaned = { ...SECURE_DEFAULTS, ...stripUndefined(perf) };
|
|
4272
4851
|
if (typeof document2 === "string" || document2 instanceof URL) {
|
|
4273
4852
|
return { url: document2, ...cleaned };
|
|
4274
4853
|
}
|
|
4275
4854
|
if (ArrayBuffer.isView(document2)) {
|
|
4276
|
-
return document2;
|
|
4855
|
+
return { ...SECURE_DEFAULTS, data: document2 };
|
|
4277
4856
|
}
|
|
4278
4857
|
return { ...cleaned, ...document2 };
|
|
4279
4858
|
};
|
|
@@ -4291,13 +4870,13 @@ var PdfLoader = ({
|
|
|
4291
4870
|
httpHeaders,
|
|
4292
4871
|
enableCache = true
|
|
4293
4872
|
}) => {
|
|
4294
|
-
const [pdfDocument, setPdfDocument] =
|
|
4295
|
-
const [error, setError] =
|
|
4296
|
-
const [loadingProgress, setLoadingProgress] =
|
|
4297
|
-
const onErrorRef =
|
|
4873
|
+
const [pdfDocument, setPdfDocument] = useState(null);
|
|
4874
|
+
const [error, setError] = useState(null);
|
|
4875
|
+
const [loadingProgress, setLoadingProgress] = useState(null);
|
|
4876
|
+
const onErrorRef = useRef(onError);
|
|
4298
4877
|
onErrorRef.current = onError;
|
|
4299
4878
|
const httpHeadersKey = httpHeaders ? JSON.stringify(httpHeaders) : "";
|
|
4300
|
-
|
|
4879
|
+
useEffect(() => {
|
|
4301
4880
|
GlobalWorkerOptions.workerSrc = workerSrc;
|
|
4302
4881
|
let cancelled = false;
|
|
4303
4882
|
setPdfDocument(null);
|
|
@@ -4315,7 +4894,7 @@ var PdfLoader = ({
|
|
|
4315
4894
|
console.log("[PdfLoader] loading", key ?? "(bytes)", {
|
|
4316
4895
|
disableAutoFetch
|
|
4317
4896
|
});
|
|
4318
|
-
const task =
|
|
4897
|
+
const task = getDocument$1(
|
|
4319
4898
|
buildSource(document2, {
|
|
4320
4899
|
disableAutoFetch,
|
|
4321
4900
|
disableStream,
|
|
@@ -4605,7 +5184,6 @@ var getTextItemsBoundingRect = (textItems) => {
|
|
|
4605
5184
|
return rects.length > 0 ? get_bounding_rect_default(rects) : void 0;
|
|
4606
5185
|
};
|
|
4607
5186
|
var getOrderedTextItems = (textItems, readingOrder) => {
|
|
4608
|
-
if (readingOrder === "document") return [...textItems];
|
|
4609
5187
|
const averageHeight = getAverageItemHeight(textItems);
|
|
4610
5188
|
return [...textItems].sort((a, b) => {
|
|
4611
5189
|
const topDelta = a.rect.top - b.rect.top;
|
|
@@ -4617,7 +5195,7 @@ var getOrderedTextItems = (textItems, readingOrder) => {
|
|
|
4617
5195
|
};
|
|
4618
5196
|
var groupTextItemsIntoLines = (textItems) => {
|
|
4619
5197
|
const averageHeight = getAverageItemHeight(textItems);
|
|
4620
|
-
const sortedItems = getOrderedTextItems(textItems
|
|
5198
|
+
const sortedItems = getOrderedTextItems(textItems);
|
|
4621
5199
|
const lines = [];
|
|
4622
5200
|
sortedItems.forEach((item) => {
|
|
4623
5201
|
const currentLine = lines[lines.length - 1];
|
|
@@ -4900,10 +5478,17 @@ var classifyTextUnit = (rawText, textItemIndexes, page) => {
|
|
|
4900
5478
|
if (isLikelyFootnoteOrReference(text) || isBottomOfPage && /^\d+\s/.test(text)) {
|
|
4901
5479
|
return text.includes("://") || /^\d+\s*https?:\/\//i.test(text) ? "footnote" : "reference";
|
|
4902
5480
|
}
|
|
5481
|
+
if (/^(figure|fig\.?|table|chart|diagram|listing|algorithm)\s*\d/i.test(text)) {
|
|
5482
|
+
return "caption";
|
|
5483
|
+
}
|
|
4903
5484
|
if (isLikelySectionHeading(text)) return "heading";
|
|
4904
5485
|
if (isTopOfFirstPage && isLargeText && isCentered) return "title";
|
|
4905
5486
|
if (isTopOfFirstPage && isLikelyAuthor(text)) return "author";
|
|
4906
5487
|
if (isTopOfFirstPage && isLikelyAffiliation(text)) return "affiliation";
|
|
5488
|
+
const wordCount = text.split(/\s+/).filter(Boolean).length;
|
|
5489
|
+
if (wordCount <= 6 && text.length <= 60 && !/[.!?…:]\s*$/.test(text)) {
|
|
5490
|
+
return "figureLabel";
|
|
5491
|
+
}
|
|
4907
5492
|
return "paragraph";
|
|
4908
5493
|
};
|
|
4909
5494
|
var extractTextUnitsFromPages = (pages, options = {}) => {
|
|
@@ -4981,7 +5566,30 @@ var extractTextUnits = async (pdfDocument, options = {}) => {
|
|
|
4981
5566
|
});
|
|
4982
5567
|
return extractTextUnitsFromPages(pages, resolvedOptions);
|
|
4983
5568
|
};
|
|
4984
|
-
var
|
|
5569
|
+
var pageTextItemsCache = /* @__PURE__ */ new WeakMap();
|
|
5570
|
+
var pageTextItemsCacheKey = (options) => {
|
|
5571
|
+
const pages = options.pages === void 0 || options.pages === "all" ? "all" : options.pages.join(",");
|
|
5572
|
+
return `${pages}|${options.columnDetection ?? DEFAULT_OPTIONS.columnDetection}`;
|
|
5573
|
+
};
|
|
5574
|
+
var extractPageTextItems = (pdfDocument, options = {}) => {
|
|
5575
|
+
let byOptions = pageTextItemsCache.get(pdfDocument);
|
|
5576
|
+
if (!byOptions) {
|
|
5577
|
+
byOptions = /* @__PURE__ */ new Map();
|
|
5578
|
+
pageTextItemsCache.set(pdfDocument, byOptions);
|
|
5579
|
+
}
|
|
5580
|
+
const key = pageTextItemsCacheKey(options);
|
|
5581
|
+
const cached = byOptions.get(key);
|
|
5582
|
+
if (cached) return cached;
|
|
5583
|
+
const promise = extractPageTextItemsUncached(pdfDocument, options).catch(
|
|
5584
|
+
(error) => {
|
|
5585
|
+
byOptions.delete(key);
|
|
5586
|
+
throw error;
|
|
5587
|
+
}
|
|
5588
|
+
);
|
|
5589
|
+
byOptions.set(key, promise);
|
|
5590
|
+
return promise;
|
|
5591
|
+
};
|
|
5592
|
+
var extractPageTextItemsUncached = async (pdfDocument, options = {}) => {
|
|
4985
5593
|
const pageNumbers = resolvePageNumbers(pdfDocument, options.pages);
|
|
4986
5594
|
const columnDetection = options.columnDetection ?? DEFAULT_OPTIONS.columnDetection;
|
|
4987
5595
|
const extractedPages = [];
|
|
@@ -5215,26 +5823,16 @@ var getTextPosition = async (pdfDocument, query, options = {}) => {
|
|
|
5215
5823
|
}
|
|
5216
5824
|
return null;
|
|
5217
5825
|
};
|
|
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(
|
|
5826
|
+
var LeftPanelContext = createContext(
|
|
5226
5827
|
void 0
|
|
5227
5828
|
);
|
|
5228
5829
|
var useLeftPanelContext = () => {
|
|
5229
|
-
const context =
|
|
5830
|
+
const context = useContext(LeftPanelContext);
|
|
5230
5831
|
if (context === void 0) {
|
|
5231
5832
|
throw new Error("useLeftPanelContext must be used within LeftPanel");
|
|
5232
5833
|
}
|
|
5233
5834
|
return context;
|
|
5234
5835
|
};
|
|
5235
|
-
|
|
5236
|
-
// src/hooks/useDocumentOutline.ts
|
|
5237
|
-
import { useState as useState12, useEffect as useEffect13, useCallback as useCallback5, useMemo as useMemo2 } from "react";
|
|
5238
5836
|
async function processOutlineItems(pdfDocument, items, level) {
|
|
5239
5837
|
const processed = [];
|
|
5240
5838
|
for (let i = 0; i < items.length; i++) {
|
|
@@ -5276,10 +5874,10 @@ function flattenOutline(items) {
|
|
|
5276
5874
|
}
|
|
5277
5875
|
function useDocumentOutline(options) {
|
|
5278
5876
|
const { pdfDocument, goToPage } = options;
|
|
5279
|
-
const [outline, setOutline] =
|
|
5280
|
-
const [isLoading, setIsLoading] =
|
|
5281
|
-
const [error, setError] =
|
|
5282
|
-
|
|
5877
|
+
const [outline, setOutline] = useState(null);
|
|
5878
|
+
const [isLoading, setIsLoading] = useState(true);
|
|
5879
|
+
const [error, setError] = useState(null);
|
|
5880
|
+
useEffect(() => {
|
|
5283
5881
|
let cancelled = false;
|
|
5284
5882
|
async function fetchOutline() {
|
|
5285
5883
|
try {
|
|
@@ -5312,7 +5910,7 @@ function useDocumentOutline(options) {
|
|
|
5312
5910
|
cancelled = true;
|
|
5313
5911
|
};
|
|
5314
5912
|
}, [pdfDocument]);
|
|
5315
|
-
const navigateToItem =
|
|
5913
|
+
const navigateToItem = useCallback(
|
|
5316
5914
|
(item) => {
|
|
5317
5915
|
if (goToPage && item.pageNumber) {
|
|
5318
5916
|
goToPage(item.pageNumber);
|
|
@@ -5320,18 +5918,15 @@ function useDocumentOutline(options) {
|
|
|
5320
5918
|
},
|
|
5321
5919
|
[goToPage]
|
|
5322
5920
|
);
|
|
5323
|
-
const flatOutline =
|
|
5921
|
+
const flatOutline = useMemo(() => {
|
|
5324
5922
|
if (!outline) return [];
|
|
5325
5923
|
return flattenOutline(outline);
|
|
5326
5924
|
}, [outline]);
|
|
5327
|
-
const hasOutline =
|
|
5925
|
+
const hasOutline = useMemo(() => {
|
|
5328
5926
|
return outline !== null && outline.length > 0;
|
|
5329
5927
|
}, [outline]);
|
|
5330
5928
|
return { outline, isLoading, error, navigateToItem, flatOutline, hasOutline };
|
|
5331
5929
|
}
|
|
5332
|
-
|
|
5333
|
-
// src/hooks/useThumbnails.ts
|
|
5334
|
-
import { useState as useState13, useCallback as useCallback6, useRef as useRef15, useEffect as useEffect14 } from "react";
|
|
5335
5930
|
var MAX_CONCURRENT_RENDERS = 3;
|
|
5336
5931
|
function useThumbnails(options) {
|
|
5337
5932
|
const {
|
|
@@ -5343,21 +5938,21 @@ function useThumbnails(options) {
|
|
|
5343
5938
|
// Changed to false - let virtualization control loading
|
|
5344
5939
|
imageQuality = 0.8
|
|
5345
5940
|
} = options;
|
|
5346
|
-
const [thumbnails, setThumbnails] =
|
|
5941
|
+
const [thumbnails, setThumbnails] = useState(
|
|
5347
5942
|
/* @__PURE__ */ new Map()
|
|
5348
5943
|
);
|
|
5349
|
-
const loadingRef =
|
|
5350
|
-
const loadedRef =
|
|
5351
|
-
const cacheOrderRef =
|
|
5352
|
-
const renderQueueRef =
|
|
5353
|
-
const activeRendersRef =
|
|
5354
|
-
const isProcessingRef =
|
|
5355
|
-
const thumbnailsRef =
|
|
5944
|
+
const loadingRef = useRef(/* @__PURE__ */ new Set());
|
|
5945
|
+
const loadedRef = useRef(/* @__PURE__ */ new Set());
|
|
5946
|
+
const cacheOrderRef = useRef([]);
|
|
5947
|
+
const renderQueueRef = useRef([]);
|
|
5948
|
+
const activeRendersRef = useRef(0);
|
|
5949
|
+
const isProcessingRef = useRef(false);
|
|
5950
|
+
const thumbnailsRef = useRef(thumbnails);
|
|
5356
5951
|
thumbnailsRef.current = thumbnails;
|
|
5357
|
-
const pendingUpdatesRef =
|
|
5358
|
-
const flushTimeoutRef =
|
|
5952
|
+
const pendingUpdatesRef = useRef(/* @__PURE__ */ new Map());
|
|
5953
|
+
const flushTimeoutRef = useRef(null);
|
|
5359
5954
|
const totalPages = pdfDocument.numPages;
|
|
5360
|
-
const flushUpdates =
|
|
5955
|
+
const flushUpdates = useCallback(() => {
|
|
5361
5956
|
if (pendingUpdatesRef.current.size === 0) return;
|
|
5362
5957
|
setThumbnails((prev) => {
|
|
5363
5958
|
const next = new Map(prev);
|
|
@@ -5377,7 +5972,7 @@ function useThumbnails(options) {
|
|
|
5377
5972
|
return next;
|
|
5378
5973
|
});
|
|
5379
5974
|
}, [cacheSize]);
|
|
5380
|
-
const queueUpdate =
|
|
5975
|
+
const queueUpdate = useCallback((pageNumber, data) => {
|
|
5381
5976
|
pendingUpdatesRef.current.set(pageNumber, data);
|
|
5382
5977
|
if (!flushTimeoutRef.current) {
|
|
5383
5978
|
flushTimeoutRef.current = setTimeout(() => {
|
|
@@ -5386,7 +5981,7 @@ function useThumbnails(options) {
|
|
|
5386
5981
|
}, 50);
|
|
5387
5982
|
}
|
|
5388
5983
|
}, [flushUpdates]);
|
|
5389
|
-
const renderThumbnail =
|
|
5984
|
+
const renderThumbnail = useCallback(
|
|
5390
5985
|
async (pageNumber) => {
|
|
5391
5986
|
try {
|
|
5392
5987
|
const page = await pdfDocument.getPage(pageNumber);
|
|
@@ -5424,7 +6019,7 @@ function useThumbnails(options) {
|
|
|
5424
6019
|
},
|
|
5425
6020
|
[pdfDocument, thumbnailWidth, imageQuality, queueUpdate]
|
|
5426
6021
|
);
|
|
5427
|
-
const processQueue =
|
|
6022
|
+
const processQueue = useCallback(async () => {
|
|
5428
6023
|
if (isProcessingRef.current) return;
|
|
5429
6024
|
isProcessingRef.current = true;
|
|
5430
6025
|
while (renderQueueRef.current.length > 0 && activeRendersRef.current < MAX_CONCURRENT_RENDERS) {
|
|
@@ -5440,7 +6035,7 @@ function useThumbnails(options) {
|
|
|
5440
6035
|
}
|
|
5441
6036
|
isProcessingRef.current = false;
|
|
5442
6037
|
}, [renderThumbnail]);
|
|
5443
|
-
const loadThumbnail =
|
|
6038
|
+
const loadThumbnail = useCallback(
|
|
5444
6039
|
async (pageNumber) => {
|
|
5445
6040
|
if (loadingRef.current.has(pageNumber) || loadedRef.current.has(pageNumber)) {
|
|
5446
6041
|
return;
|
|
@@ -5459,7 +6054,7 @@ function useThumbnails(options) {
|
|
|
5459
6054
|
},
|
|
5460
6055
|
[processQueue, queueUpdate]
|
|
5461
6056
|
);
|
|
5462
|
-
const getThumbnail =
|
|
6057
|
+
const getThumbnail = useCallback(
|
|
5463
6058
|
(pageNumber) => {
|
|
5464
6059
|
return thumbnailsRef.current.get(pageNumber) || {
|
|
5465
6060
|
pageNumber,
|
|
@@ -5470,7 +6065,7 @@ function useThumbnails(options) {
|
|
|
5470
6065
|
[]
|
|
5471
6066
|
// No dependencies - always stable
|
|
5472
6067
|
);
|
|
5473
|
-
const preloadThumbnails =
|
|
6068
|
+
const preloadThumbnails = useCallback(
|
|
5474
6069
|
(pageNumbers) => {
|
|
5475
6070
|
pageNumbers.forEach((pageNumber) => {
|
|
5476
6071
|
loadThumbnail(pageNumber);
|
|
@@ -5478,13 +6073,13 @@ function useThumbnails(options) {
|
|
|
5478
6073
|
},
|
|
5479
6074
|
[loadThumbnail]
|
|
5480
6075
|
);
|
|
5481
|
-
const clearCache =
|
|
6076
|
+
const clearCache = useCallback(() => {
|
|
5482
6077
|
setThumbnails(/* @__PURE__ */ new Map());
|
|
5483
6078
|
cacheOrderRef.current = [];
|
|
5484
6079
|
loadingRef.current.clear();
|
|
5485
6080
|
loadedRef.current.clear();
|
|
5486
6081
|
}, []);
|
|
5487
|
-
|
|
6082
|
+
useEffect(() => {
|
|
5488
6083
|
if (preloadAll && totalPages > 0) {
|
|
5489
6084
|
const pageNumbers = Array.from({ length: totalPages }, (_, i) => i + 1);
|
|
5490
6085
|
pageNumbers.forEach((pageNumber) => {
|
|
@@ -5492,7 +6087,7 @@ function useThumbnails(options) {
|
|
|
5492
6087
|
});
|
|
5493
6088
|
}
|
|
5494
6089
|
}, [preloadAll, totalPages, loadThumbnail]);
|
|
5495
|
-
|
|
6090
|
+
useEffect(() => {
|
|
5496
6091
|
return () => {
|
|
5497
6092
|
loadingRef.current.clear();
|
|
5498
6093
|
if (flushTimeoutRef.current) {
|
|
@@ -5510,9 +6105,6 @@ function useThumbnails(options) {
|
|
|
5510
6105
|
thumbnails
|
|
5511
6106
|
};
|
|
5512
6107
|
}
|
|
5513
|
-
|
|
5514
|
-
// src/hooks/usePageNavigation.ts
|
|
5515
|
-
import { useState as useState14, useEffect as useEffect15, useCallback as useCallback7, useRef as useRef16 } from "react";
|
|
5516
6108
|
var isEventBus = (obj) => {
|
|
5517
6109
|
return obj !== null && typeof obj === "object" && "on" in obj && "off" in obj;
|
|
5518
6110
|
};
|
|
@@ -5521,10 +6113,10 @@ var isViewer = (obj) => {
|
|
|
5521
6113
|
};
|
|
5522
6114
|
function usePageNavigation(options) {
|
|
5523
6115
|
const { viewer, eventBus } = options;
|
|
5524
|
-
const [currentPage, setCurrentPage] =
|
|
5525
|
-
const viewerRef =
|
|
6116
|
+
const [currentPage, setCurrentPage] = useState(1);
|
|
6117
|
+
const viewerRef = useRef(viewer);
|
|
5526
6118
|
viewerRef.current = viewer;
|
|
5527
|
-
|
|
6119
|
+
useEffect(() => {
|
|
5528
6120
|
if (!eventBus || !isEventBus(eventBus)) {
|
|
5529
6121
|
return;
|
|
5530
6122
|
}
|
|
@@ -5536,14 +6128,14 @@ function usePageNavigation(options) {
|
|
|
5536
6128
|
eventBus.off("pagechanging", handlePageChange);
|
|
5537
6129
|
};
|
|
5538
6130
|
}, [eventBus]);
|
|
5539
|
-
const prevViewerRef =
|
|
5540
|
-
|
|
6131
|
+
const prevViewerRef = useRef(viewer);
|
|
6132
|
+
useEffect(() => {
|
|
5541
6133
|
if (viewer !== prevViewerRef.current) {
|
|
5542
6134
|
setCurrentPage(1);
|
|
5543
6135
|
prevViewerRef.current = viewer;
|
|
5544
6136
|
}
|
|
5545
6137
|
}, [viewer]);
|
|
5546
|
-
const goToPage =
|
|
6138
|
+
const goToPage = useCallback(
|
|
5547
6139
|
(pageNumber) => {
|
|
5548
6140
|
const v = viewerRef.current;
|
|
5549
6141
|
if (v && isViewer(v)) {
|
|
@@ -5577,14 +6169,6 @@ function usePageNavigation(options) {
|
|
|
5577
6169
|
goToPage
|
|
5578
6170
|
};
|
|
5579
6171
|
}
|
|
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
6172
|
var OutlineItem = ({
|
|
5589
6173
|
item,
|
|
5590
6174
|
currentPage,
|
|
@@ -5596,8 +6180,8 @@ var OutlineItem = ({
|
|
|
5596
6180
|
classNames,
|
|
5597
6181
|
renderItem
|
|
5598
6182
|
}) => {
|
|
5599
|
-
const [isExpanded, setIsExpanded] =
|
|
5600
|
-
const [isHovered, setIsHovered] =
|
|
6183
|
+
const [isExpanded, setIsExpanded] = useState(defaultExpanded);
|
|
6184
|
+
const [isHovered, setIsHovered] = useState(false);
|
|
5601
6185
|
const hasChildren = item.children && item.children.length > 0;
|
|
5602
6186
|
const isActive = currentPage === item.pageNumber;
|
|
5603
6187
|
const canShowChildren = item.level < maxDepth;
|
|
@@ -5618,7 +6202,7 @@ var OutlineItem = ({
|
|
|
5618
6202
|
onNavigate: handleNavigate
|
|
5619
6203
|
};
|
|
5620
6204
|
if (renderItem) {
|
|
5621
|
-
return /* @__PURE__ */
|
|
6205
|
+
return /* @__PURE__ */ React11.createElement(React11.Fragment, null, renderItem(item, renderProps));
|
|
5622
6206
|
}
|
|
5623
6207
|
const indent = 12 + item.level * 16;
|
|
5624
6208
|
const defaultContainerStyle = {
|
|
@@ -5732,7 +6316,7 @@ var OutlineItem = ({
|
|
|
5732
6316
|
classNames?.pageNumber,
|
|
5733
6317
|
isActive ? classNames?.pageNumberActive : ""
|
|
5734
6318
|
].filter(Boolean).join(" ");
|
|
5735
|
-
return /* @__PURE__ */
|
|
6319
|
+
return /* @__PURE__ */ React11.createElement("div", { className: "outline-item" }, /* @__PURE__ */ React11.createElement(
|
|
5736
6320
|
"div",
|
|
5737
6321
|
{
|
|
5738
6322
|
className: containerClassName || void 0,
|
|
@@ -5749,7 +6333,7 @@ var OutlineItem = ({
|
|
|
5749
6333
|
}
|
|
5750
6334
|
}
|
|
5751
6335
|
},
|
|
5752
|
-
showExpandIcons && hasChildren && canShowChildren ? /* @__PURE__ */
|
|
6336
|
+
showExpandIcons && hasChildren && canShowChildren ? /* @__PURE__ */ React11.createElement(
|
|
5753
6337
|
"button",
|
|
5754
6338
|
{
|
|
5755
6339
|
className: classNames?.expandButton,
|
|
@@ -5766,12 +6350,12 @@ var OutlineItem = ({
|
|
|
5766
6350
|
},
|
|
5767
6351
|
"aria-label": isExpanded ? "Collapse" : "Expand"
|
|
5768
6352
|
},
|
|
5769
|
-
isExpanded ? /* @__PURE__ */
|
|
5770
|
-
) : /* @__PURE__ */
|
|
5771
|
-
isActive && /* @__PURE__ */
|
|
5772
|
-
/* @__PURE__ */
|
|
5773
|
-
/* @__PURE__ */
|
|
5774
|
-
), hasChildren && isExpanded && canShowChildren && /* @__PURE__ */
|
|
6353
|
+
isExpanded ? /* @__PURE__ */ React11.createElement(ChevronDown, { className: classNames?.expandIcon, style: expandIconStyle }) : /* @__PURE__ */ React11.createElement(ChevronRight, { className: classNames?.expandIcon, style: expandIconStyle })
|
|
6354
|
+
) : /* @__PURE__ */ React11.createElement("div", { style: { width: 16, flexShrink: 0 } }),
|
|
6355
|
+
isActive && /* @__PURE__ */ React11.createElement("div", { className: classNames?.activeIndicator, style: activeIndicatorStyle }),
|
|
6356
|
+
/* @__PURE__ */ React11.createElement("span", { className: titleClassName || void 0, style: titleStyle, title: item.title }, item.title),
|
|
6357
|
+
/* @__PURE__ */ React11.createElement("span", { className: pageNumberClassName || void 0, style: pageNumberStyle }, item.pageNumber)
|
|
6358
|
+
), hasChildren && isExpanded && canShowChildren && /* @__PURE__ */ React11.createElement("div", { className: classNames?.childrenContainer, style: childrenContainerStyle }, item.children.map((child) => /* @__PURE__ */ React11.createElement(
|
|
5775
6359
|
OutlineItem,
|
|
5776
6360
|
{
|
|
5777
6361
|
key: child.id,
|
|
@@ -5862,32 +6446,32 @@ var DocumentOutline = ({
|
|
|
5862
6446
|
paddingBottom: "8px"
|
|
5863
6447
|
};
|
|
5864
6448
|
if (isLoading) {
|
|
5865
|
-
return /* @__PURE__ */
|
|
6449
|
+
return /* @__PURE__ */ React11.createElement(
|
|
5866
6450
|
"div",
|
|
5867
6451
|
{
|
|
5868
6452
|
className: [className, classNames?.loadingContainer].filter(Boolean).join(" ") || void 0,
|
|
5869
6453
|
style: { ...defaultLoadingContainerStyle, ...styles?.loadingContainer }
|
|
5870
6454
|
},
|
|
5871
|
-
loadingContent || /* @__PURE__ */
|
|
6455
|
+
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
6456
|
);
|
|
5873
6457
|
}
|
|
5874
6458
|
if (!outline || outline.length === 0) {
|
|
5875
|
-
return /* @__PURE__ */
|
|
6459
|
+
return /* @__PURE__ */ React11.createElement(
|
|
5876
6460
|
"div",
|
|
5877
6461
|
{
|
|
5878
6462
|
className: [className, classNames?.emptyContainer].filter(Boolean).join(" ") || void 0,
|
|
5879
6463
|
style: { ...defaultEmptyContainerStyle, ...styles?.emptyContainer }
|
|
5880
6464
|
},
|
|
5881
|
-
emptyContent || /* @__PURE__ */
|
|
6465
|
+
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
6466
|
);
|
|
5883
6467
|
}
|
|
5884
|
-
return /* @__PURE__ */
|
|
6468
|
+
return /* @__PURE__ */ React11.createElement(
|
|
5885
6469
|
"div",
|
|
5886
6470
|
{
|
|
5887
6471
|
className: ["document-outline", className, classNames?.container].filter(Boolean).join(" "),
|
|
5888
6472
|
style: { ...defaultContainerStyle, ...styles?.container }
|
|
5889
6473
|
},
|
|
5890
|
-
outline.map((item) => /* @__PURE__ */
|
|
6474
|
+
outline.map((item) => /* @__PURE__ */ React11.createElement(
|
|
5891
6475
|
OutlineItem,
|
|
5892
6476
|
{
|
|
5893
6477
|
key: item.id,
|
|
@@ -5904,15 +6488,7 @@ var DocumentOutline = ({
|
|
|
5904
6488
|
))
|
|
5905
6489
|
);
|
|
5906
6490
|
};
|
|
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(({
|
|
6491
|
+
var ThumbnailItem = React11.memo(({
|
|
5916
6492
|
pageNumber,
|
|
5917
6493
|
thumbnail,
|
|
5918
6494
|
isActive,
|
|
@@ -5921,10 +6497,10 @@ var ThumbnailItem = React19.memo(({
|
|
|
5921
6497
|
showPageNumber = true,
|
|
5922
6498
|
className = ""
|
|
5923
6499
|
}) => {
|
|
5924
|
-
const containerRef =
|
|
5925
|
-
const hasLoadedRef =
|
|
5926
|
-
const [isHovered, setIsHovered] =
|
|
5927
|
-
|
|
6500
|
+
const containerRef = useRef(null);
|
|
6501
|
+
const hasLoadedRef = useRef(false);
|
|
6502
|
+
const [isHovered, setIsHovered] = useState(false);
|
|
6503
|
+
useEffect(() => {
|
|
5928
6504
|
const element = containerRef.current;
|
|
5929
6505
|
if (!element || hasLoadedRef.current) return;
|
|
5930
6506
|
const observer = new IntersectionObserver(
|
|
@@ -5979,7 +6555,7 @@ var ThumbnailItem = React19.memo(({
|
|
|
5979
6555
|
color: isActive ? "var(--lp-accent, #3b82f6)" : "var(--lp-muted, #6b7280)",
|
|
5980
6556
|
transition: "color 0.15s ease"
|
|
5981
6557
|
};
|
|
5982
|
-
return /* @__PURE__ */
|
|
6558
|
+
return /* @__PURE__ */ React11.createElement(
|
|
5983
6559
|
"div",
|
|
5984
6560
|
{
|
|
5985
6561
|
ref: containerRef,
|
|
@@ -5999,7 +6575,7 @@ var ThumbnailItem = React19.memo(({
|
|
|
5999
6575
|
"aria-label": `Page ${pageNumber}${isActive ? " (current)" : ""}`,
|
|
6000
6576
|
"aria-current": isActive ? "page" : void 0
|
|
6001
6577
|
},
|
|
6002
|
-
/* @__PURE__ */
|
|
6578
|
+
/* @__PURE__ */ React11.createElement("div", { style: imageContainerStyle }, thumbnail.isLoading && /* @__PURE__ */ React11.createElement(
|
|
6003
6579
|
"div",
|
|
6004
6580
|
{
|
|
6005
6581
|
style: {
|
|
@@ -6011,8 +6587,8 @@ var ThumbnailItem = React19.memo(({
|
|
|
6011
6587
|
backgroundColor: "var(--lp-hover, #f9fafb)"
|
|
6012
6588
|
}
|
|
6013
6589
|
},
|
|
6014
|
-
/* @__PURE__ */
|
|
6015
|
-
|
|
6590
|
+
/* @__PURE__ */ React11.createElement(
|
|
6591
|
+
Loader2,
|
|
6016
6592
|
{
|
|
6017
6593
|
style: {
|
|
6018
6594
|
width: 24,
|
|
@@ -6022,7 +6598,7 @@ var ThumbnailItem = React19.memo(({
|
|
|
6022
6598
|
}
|
|
6023
6599
|
}
|
|
6024
6600
|
)
|
|
6025
|
-
), thumbnail.error && !thumbnail.isLoading && /* @__PURE__ */
|
|
6601
|
+
), thumbnail.error && !thumbnail.isLoading && /* @__PURE__ */ React11.createElement(
|
|
6026
6602
|
"div",
|
|
6027
6603
|
{
|
|
6028
6604
|
style: {
|
|
@@ -6035,9 +6611,9 @@ var ThumbnailItem = React19.memo(({
|
|
|
6035
6611
|
backgroundColor: "#fef2f2"
|
|
6036
6612
|
}
|
|
6037
6613
|
},
|
|
6038
|
-
/* @__PURE__ */
|
|
6039
|
-
/* @__PURE__ */
|
|
6040
|
-
), thumbnail.dataUrl && !thumbnail.isLoading && /* @__PURE__ */
|
|
6614
|
+
/* @__PURE__ */ React11.createElement(AlertCircle, { style: { width: 20, height: 20, color: "#f87171", marginBottom: 4 } }),
|
|
6615
|
+
/* @__PURE__ */ React11.createElement("span", { style: { fontSize: 10, color: "#9ca3af" } }, "Failed")
|
|
6616
|
+
), thumbnail.dataUrl && !thumbnail.isLoading && /* @__PURE__ */ React11.createElement(
|
|
6041
6617
|
"img",
|
|
6042
6618
|
{
|
|
6043
6619
|
src: thumbnail.dataUrl,
|
|
@@ -6049,7 +6625,7 @@ var ThumbnailItem = React19.memo(({
|
|
|
6049
6625
|
},
|
|
6050
6626
|
draggable: false
|
|
6051
6627
|
}
|
|
6052
|
-
), !thumbnail.dataUrl && !thumbnail.isLoading && !thumbnail.error && /* @__PURE__ */
|
|
6628
|
+
), !thumbnail.dataUrl && !thumbnail.isLoading && !thumbnail.error && /* @__PURE__ */ React11.createElement(
|
|
6053
6629
|
"div",
|
|
6054
6630
|
{
|
|
6055
6631
|
style: {
|
|
@@ -6061,7 +6637,7 @@ var ThumbnailItem = React19.memo(({
|
|
|
6061
6637
|
backgroundColor: "var(--lp-hover, #f9fafb)"
|
|
6062
6638
|
}
|
|
6063
6639
|
},
|
|
6064
|
-
/* @__PURE__ */
|
|
6640
|
+
/* @__PURE__ */ React11.createElement(
|
|
6065
6641
|
"span",
|
|
6066
6642
|
{
|
|
6067
6643
|
style: {
|
|
@@ -6073,7 +6649,7 @@ var ThumbnailItem = React19.memo(({
|
|
|
6073
6649
|
pageNumber
|
|
6074
6650
|
)
|
|
6075
6651
|
)),
|
|
6076
|
-
showPageNumber && /* @__PURE__ */
|
|
6652
|
+
showPageNumber && /* @__PURE__ */ React11.createElement("div", { style: pageNumberStyle }, pageNumber)
|
|
6077
6653
|
);
|
|
6078
6654
|
});
|
|
6079
6655
|
|
|
@@ -6098,22 +6674,22 @@ var ThumbnailPanel = ({
|
|
|
6098
6674
|
isLoading: false
|
|
6099
6675
|
};
|
|
6100
6676
|
};
|
|
6101
|
-
const parentRef =
|
|
6677
|
+
const parentRef = useRef(null);
|
|
6102
6678
|
const virtualizer = useVirtualizer({
|
|
6103
6679
|
count: totalPages,
|
|
6104
6680
|
getScrollElement: () => parentRef.current,
|
|
6105
6681
|
estimateSize: () => estimatedItemHeight + gap,
|
|
6106
6682
|
overscan
|
|
6107
6683
|
});
|
|
6108
|
-
const scrollToIndexRef =
|
|
6684
|
+
const scrollToIndexRef = useRef(virtualizer.scrollToIndex);
|
|
6109
6685
|
scrollToIndexRef.current = virtualizer.scrollToIndex;
|
|
6110
|
-
|
|
6686
|
+
useEffect(() => {
|
|
6111
6687
|
if (currentPage > 0 && currentPage <= totalPages) {
|
|
6112
6688
|
scrollToIndexRef.current(currentPage - 1, { align: "center" });
|
|
6113
6689
|
}
|
|
6114
6690
|
}, [currentPage, totalPages]);
|
|
6115
6691
|
if (totalPages === 0) {
|
|
6116
|
-
return /* @__PURE__ */
|
|
6692
|
+
return /* @__PURE__ */ React11.createElement(
|
|
6117
6693
|
"div",
|
|
6118
6694
|
{
|
|
6119
6695
|
className,
|
|
@@ -6124,10 +6700,10 @@ var ThumbnailPanel = ({
|
|
|
6124
6700
|
padding: "48px 16px"
|
|
6125
6701
|
}
|
|
6126
6702
|
},
|
|
6127
|
-
/* @__PURE__ */
|
|
6703
|
+
/* @__PURE__ */ React11.createElement("p", { style: { fontSize: 13, color: "var(--lp-muted, #9ca3af)" } }, "No pages to display")
|
|
6128
6704
|
);
|
|
6129
6705
|
}
|
|
6130
|
-
return /* @__PURE__ */
|
|
6706
|
+
return /* @__PURE__ */ React11.createElement(
|
|
6131
6707
|
"div",
|
|
6132
6708
|
{
|
|
6133
6709
|
ref: parentRef,
|
|
@@ -6138,7 +6714,7 @@ var ThumbnailPanel = ({
|
|
|
6138
6714
|
padding: "12px"
|
|
6139
6715
|
}
|
|
6140
6716
|
},
|
|
6141
|
-
/* @__PURE__ */
|
|
6717
|
+
/* @__PURE__ */ React11.createElement(
|
|
6142
6718
|
"div",
|
|
6143
6719
|
{
|
|
6144
6720
|
style: {
|
|
@@ -6151,7 +6727,7 @@ var ThumbnailPanel = ({
|
|
|
6151
6727
|
const pageNumber = virtualItem.index + 1;
|
|
6152
6728
|
const thumbnail = getThumbnail(pageNumber);
|
|
6153
6729
|
const isActive = currentPage === pageNumber;
|
|
6154
|
-
return /* @__PURE__ */
|
|
6730
|
+
return /* @__PURE__ */ React11.createElement(
|
|
6155
6731
|
"div",
|
|
6156
6732
|
{
|
|
6157
6733
|
key: virtualItem.key,
|
|
@@ -6165,14 +6741,14 @@ var ThumbnailPanel = ({
|
|
|
6165
6741
|
paddingBottom: `${gap}px`
|
|
6166
6742
|
}
|
|
6167
6743
|
},
|
|
6168
|
-
renderThumbnail ? /* @__PURE__ */
|
|
6744
|
+
renderThumbnail ? /* @__PURE__ */ React11.createElement(
|
|
6169
6745
|
"div",
|
|
6170
6746
|
{
|
|
6171
6747
|
onClick: () => onPageSelect(pageNumber),
|
|
6172
6748
|
style: { cursor: "pointer", height: "100%" }
|
|
6173
6749
|
},
|
|
6174
6750
|
renderThumbnail(pageNumber, thumbnail, isActive)
|
|
6175
|
-
) : /* @__PURE__ */
|
|
6751
|
+
) : /* @__PURE__ */ React11.createElement(
|
|
6176
6752
|
ThumbnailItem,
|
|
6177
6753
|
{
|
|
6178
6754
|
pageNumber,
|
|
@@ -6192,18 +6768,18 @@ var ThumbnailPanel = ({
|
|
|
6192
6768
|
// src/components/leftpanel/LeftPanel.tsx
|
|
6193
6769
|
var defaultTheme = {
|
|
6194
6770
|
backgroundColor: "#ffffff",
|
|
6195
|
-
borderColor: "#
|
|
6196
|
-
accentColor: "#
|
|
6197
|
-
textColor: "#
|
|
6198
|
-
mutedTextColor: "#
|
|
6199
|
-
hoverBackgroundColor: "#
|
|
6771
|
+
borderColor: "#e6e2da",
|
|
6772
|
+
accentColor: "#5b50e6",
|
|
6773
|
+
textColor: "#1c1b18",
|
|
6774
|
+
mutedTextColor: "#8b8880",
|
|
6775
|
+
hoverBackgroundColor: "#f4f2ee"
|
|
6200
6776
|
};
|
|
6201
6777
|
var defaultDarkTheme2 = {
|
|
6202
|
-
backgroundColor: "#
|
|
6778
|
+
backgroundColor: "#211f1c",
|
|
6203
6779
|
borderColor: "#3a3733",
|
|
6204
|
-
accentColor: "#
|
|
6780
|
+
accentColor: "#7b71f0",
|
|
6205
6781
|
textColor: "#eae6e0",
|
|
6206
|
-
mutedTextColor: "#
|
|
6782
|
+
mutedTextColor: "#8b8880",
|
|
6207
6783
|
hoverBackgroundColor: "#2a2724"
|
|
6208
6784
|
};
|
|
6209
6785
|
var LeftPanel = ({
|
|
@@ -6239,17 +6815,17 @@ var LeftPanel = ({
|
|
|
6239
6815
|
outlineItemStyles,
|
|
6240
6816
|
outlineItemClassNames
|
|
6241
6817
|
}) => {
|
|
6242
|
-
const theme =
|
|
6818
|
+
const theme = useMemo(
|
|
6243
6819
|
() => ({
|
|
6244
6820
|
...mode === "dark" ? defaultDarkTheme2 : defaultTheme,
|
|
6245
6821
|
...userTheme
|
|
6246
6822
|
}),
|
|
6247
6823
|
[mode, userTheme]
|
|
6248
6824
|
);
|
|
6249
|
-
const [internalIsOpen, setInternalIsOpen] =
|
|
6250
|
-
const [activeTab, setActiveTab] =
|
|
6825
|
+
const [internalIsOpen, setInternalIsOpen] = useState(true);
|
|
6826
|
+
const [activeTab, setActiveTab] = useState(defaultTab);
|
|
6251
6827
|
const isOpen = controlledIsOpen !== void 0 ? controlledIsOpen : internalIsOpen;
|
|
6252
|
-
const setIsOpen =
|
|
6828
|
+
const setIsOpen = useCallback(
|
|
6253
6829
|
(open) => {
|
|
6254
6830
|
if (onOpenChange) {
|
|
6255
6831
|
onOpenChange(open);
|
|
@@ -6267,11 +6843,11 @@ var LeftPanel = ({
|
|
|
6267
6843
|
viewer,
|
|
6268
6844
|
eventBus
|
|
6269
6845
|
});
|
|
6270
|
-
const goToPagePropRef =
|
|
6271
|
-
|
|
6846
|
+
const goToPagePropRef = useRef(goToPageProp);
|
|
6847
|
+
useEffect(() => {
|
|
6272
6848
|
goToPagePropRef.current = goToPageProp;
|
|
6273
6849
|
}, [goToPageProp]);
|
|
6274
|
-
const handlePageSelect =
|
|
6850
|
+
const handlePageSelect = useCallback(
|
|
6275
6851
|
(pageNumber) => {
|
|
6276
6852
|
if (goToPagePropRef.current) {
|
|
6277
6853
|
goToPagePropRef.current(pageNumber);
|
|
@@ -6291,14 +6867,14 @@ var LeftPanel = ({
|
|
|
6291
6867
|
pdfDocument,
|
|
6292
6868
|
goToPage: handlePageSelect
|
|
6293
6869
|
});
|
|
6294
|
-
const handleOutlineNavigate =
|
|
6870
|
+
const handleOutlineNavigate = useCallback(
|
|
6295
6871
|
(item) => {
|
|
6296
6872
|
navigateToItem(item);
|
|
6297
6873
|
onPageSelect?.(item.pageNumber);
|
|
6298
6874
|
},
|
|
6299
6875
|
[navigateToItem, onPageSelect]
|
|
6300
6876
|
);
|
|
6301
|
-
const contextValue =
|
|
6877
|
+
const contextValue = useMemo(
|
|
6302
6878
|
() => ({
|
|
6303
6879
|
currentPage,
|
|
6304
6880
|
totalPages,
|
|
@@ -6340,7 +6916,7 @@ var LeftPanel = ({
|
|
|
6340
6916
|
"--lp-muted": theme.mutedTextColor,
|
|
6341
6917
|
"--lp-hover": theme.hoverBackgroundColor
|
|
6342
6918
|
};
|
|
6343
|
-
return /* @__PURE__ */
|
|
6919
|
+
return /* @__PURE__ */ React11.createElement(LeftPanelContext.Provider, { value: contextValue }, showToggleButton && /* @__PURE__ */ React11.createElement(
|
|
6344
6920
|
"button",
|
|
6345
6921
|
{
|
|
6346
6922
|
className: toggleButtonClassNames?.button,
|
|
@@ -6373,8 +6949,8 @@ var LeftPanel = ({
|
|
|
6373
6949
|
},
|
|
6374
6950
|
"aria-label": isOpen ? "Close panel" : "Open panel"
|
|
6375
6951
|
},
|
|
6376
|
-
isOpen ? /* @__PURE__ */
|
|
6377
|
-
), /* @__PURE__ */
|
|
6952
|
+
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 } })
|
|
6953
|
+
), /* @__PURE__ */ React11.createElement(
|
|
6378
6954
|
"div",
|
|
6379
6955
|
{
|
|
6380
6956
|
className: `left-panel ${className}`,
|
|
@@ -6393,7 +6969,7 @@ var LeftPanel = ({
|
|
|
6393
6969
|
...style
|
|
6394
6970
|
}
|
|
6395
6971
|
},
|
|
6396
|
-
/* @__PURE__ */
|
|
6972
|
+
/* @__PURE__ */ React11.createElement(
|
|
6397
6973
|
"div",
|
|
6398
6974
|
{
|
|
6399
6975
|
style: {
|
|
@@ -6405,7 +6981,7 @@ var LeftPanel = ({
|
|
|
6405
6981
|
minWidth: panelWidth
|
|
6406
6982
|
}
|
|
6407
6983
|
},
|
|
6408
|
-
tabs.length > 1 && /* @__PURE__ */
|
|
6984
|
+
tabs.length > 1 && /* @__PURE__ */ React11.createElement(
|
|
6409
6985
|
"div",
|
|
6410
6986
|
{
|
|
6411
6987
|
className: tabClassNames?.container,
|
|
@@ -6416,7 +6992,7 @@ var LeftPanel = ({
|
|
|
6416
6992
|
...tabStyles?.container
|
|
6417
6993
|
}
|
|
6418
6994
|
},
|
|
6419
|
-
tabs.includes("outline") && /* @__PURE__ */
|
|
6995
|
+
tabs.includes("outline") && /* @__PURE__ */ React11.createElement(
|
|
6420
6996
|
"button",
|
|
6421
6997
|
{
|
|
6422
6998
|
className: [tabClassNames?.tab, activeTab === "outline" ? tabClassNames?.tabActive : ""].filter(Boolean).join(" ") || void 0,
|
|
@@ -6440,10 +7016,10 @@ var LeftPanel = ({
|
|
|
6440
7016
|
...activeTab === "outline" ? tabStyles?.tabActive : {}
|
|
6441
7017
|
}
|
|
6442
7018
|
},
|
|
6443
|
-
/* @__PURE__ */
|
|
6444
|
-
/* @__PURE__ */
|
|
7019
|
+
/* @__PURE__ */ React11.createElement(FileText, { className: tabClassNames?.tabIcon, style: { width: 15, height: 15, ...tabStyles?.tabIcon } }),
|
|
7020
|
+
/* @__PURE__ */ React11.createElement("span", { className: tabClassNames?.tabText, style: tabStyles?.tabText }, "Outline")
|
|
6445
7021
|
),
|
|
6446
|
-
tabs.includes("thumbnails") && /* @__PURE__ */
|
|
7022
|
+
tabs.includes("thumbnails") && /* @__PURE__ */ React11.createElement(
|
|
6447
7023
|
"button",
|
|
6448
7024
|
{
|
|
6449
7025
|
className: [tabClassNames?.tab, activeTab === "thumbnails" ? tabClassNames?.tabActive : ""].filter(Boolean).join(" ") || void 0,
|
|
@@ -6467,11 +7043,11 @@ var LeftPanel = ({
|
|
|
6467
7043
|
...activeTab === "thumbnails" ? tabStyles?.tabActive : {}
|
|
6468
7044
|
}
|
|
6469
7045
|
},
|
|
6470
|
-
/* @__PURE__ */
|
|
6471
|
-
/* @__PURE__ */
|
|
7046
|
+
/* @__PURE__ */ React11.createElement(List, { className: tabClassNames?.tabIcon, style: { width: 15, height: 15, ...tabStyles?.tabIcon } }),
|
|
7047
|
+
/* @__PURE__ */ React11.createElement("span", { className: tabClassNames?.tabText, style: tabStyles?.tabText }, "Pages")
|
|
6472
7048
|
)
|
|
6473
7049
|
),
|
|
6474
|
-
tabs.length === 1 && /* @__PURE__ */
|
|
7050
|
+
tabs.length === 1 && /* @__PURE__ */ React11.createElement(
|
|
6475
7051
|
"div",
|
|
6476
7052
|
{
|
|
6477
7053
|
className: tabClassNames?.container,
|
|
@@ -6485,9 +7061,9 @@ var LeftPanel = ({
|
|
|
6485
7061
|
...tabStyles?.container
|
|
6486
7062
|
}
|
|
6487
7063
|
},
|
|
6488
|
-
tabs[0] === "outline" ? /* @__PURE__ */
|
|
7064
|
+
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
7065
|
),
|
|
6490
|
-
/* @__PURE__ */
|
|
7066
|
+
/* @__PURE__ */ React11.createElement(
|
|
6491
7067
|
"div",
|
|
6492
7068
|
{
|
|
6493
7069
|
style: {
|
|
@@ -6497,7 +7073,7 @@ var LeftPanel = ({
|
|
|
6497
7073
|
overflowX: "hidden"
|
|
6498
7074
|
}
|
|
6499
7075
|
},
|
|
6500
|
-
activeTab === "outline" && tabs.includes("outline") && /* @__PURE__ */
|
|
7076
|
+
activeTab === "outline" && tabs.includes("outline") && /* @__PURE__ */ React11.createElement(
|
|
6501
7077
|
DocumentOutline,
|
|
6502
7078
|
{
|
|
6503
7079
|
outline,
|
|
@@ -6511,7 +7087,7 @@ var LeftPanel = ({
|
|
|
6511
7087
|
itemClassNames: outlineItemClassNames
|
|
6512
7088
|
}
|
|
6513
7089
|
),
|
|
6514
|
-
activeTab === "thumbnails" && tabs.includes("thumbnails") && /* @__PURE__ */
|
|
7090
|
+
activeTab === "thumbnails" && tabs.includes("thumbnails") && /* @__PURE__ */ React11.createElement(
|
|
6515
7091
|
ThumbnailPanel,
|
|
6516
7092
|
{
|
|
6517
7093
|
totalPages,
|
|
@@ -6524,7 +7100,7 @@ var LeftPanel = ({
|
|
|
6524
7100
|
),
|
|
6525
7101
|
children
|
|
6526
7102
|
),
|
|
6527
|
-
showFooter && /* @__PURE__ */
|
|
7103
|
+
showFooter && /* @__PURE__ */ React11.createElement(
|
|
6528
7104
|
"div",
|
|
6529
7105
|
{
|
|
6530
7106
|
className: footerClassNames?.container,
|
|
@@ -6536,7 +7112,7 @@ var LeftPanel = ({
|
|
|
6536
7112
|
...footerStyles?.container
|
|
6537
7113
|
}
|
|
6538
7114
|
},
|
|
6539
|
-
/* @__PURE__ */
|
|
7115
|
+
/* @__PURE__ */ React11.createElement(
|
|
6540
7116
|
"div",
|
|
6541
7117
|
{
|
|
6542
7118
|
className: footerClassNames?.text,
|
|
@@ -6560,40 +7136,10 @@ var LeftPanel = ({
|
|
|
6560
7136
|
|
|
6561
7137
|
// src/index.ts
|
|
6562
7138
|
var exportPdf = async (...args) => {
|
|
6563
|
-
const { exportPdf: exportPdf2 } = await import(
|
|
7139
|
+
const { exportPdf: exportPdf2 } = await import('./export-pdf-DD7J5UHW.js');
|
|
6564
7140
|
return exportPdf2(...args);
|
|
6565
7141
|
};
|
|
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
|
-
};
|
|
7142
|
+
|
|
7143
|
+
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 };
|
|
7144
|
+
//# sourceMappingURL=index.js.map
|
|
6599
7145
|
//# sourceMappingURL=index.js.map
|