react-pdf-highlighter-plus 1.2.0 → 1.3.1

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