react-pdf-highlighter-plus 1.2.0 → 1.3.0

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