@embedpdf/plugin-annotation 1.0.13 → 1.0.15

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.
Files changed (32) hide show
  1. package/dist/index.cjs +1 -1
  2. package/dist/index.cjs.map +1 -1
  3. package/dist/index.js +103 -49
  4. package/dist/index.js.map +1 -1
  5. package/dist/lib/annotation-plugin.d.ts +1 -0
  6. package/dist/lib/helpers.d.ts +9 -2
  7. package/dist/lib/types.d.ts +48 -7
  8. package/dist/preact/adapter.d.ts +6 -0
  9. package/dist/preact/index.cjs +1 -1
  10. package/dist/preact/index.cjs.map +1 -1
  11. package/dist/preact/index.js +500 -9
  12. package/dist/preact/index.js.map +1 -1
  13. package/dist/react/adapter.d.ts +6 -1
  14. package/dist/react/index.cjs +1 -1
  15. package/dist/react/index.cjs.map +1 -1
  16. package/dist/react/index.js +500 -9
  17. package/dist/react/index.js.map +1 -1
  18. package/dist/shared-preact/components/annotation-container.d.ts +4 -2
  19. package/dist/shared-preact/components/annotations/free-text-paint.d.ts +10 -0
  20. package/dist/shared-preact/components/annotations/free-text.d.ts +13 -0
  21. package/dist/shared-preact/components/annotations/stamp-paint.d.ts +8 -0
  22. package/dist/shared-preact/components/annotations/stamp.d.ts +12 -0
  23. package/dist/shared-preact/components/render-annotation.d.ts +1 -1
  24. package/dist/shared-preact/hooks/use-drag-resize.d.ts +5 -2
  25. package/dist/shared-react/components/annotation-container.d.ts +4 -2
  26. package/dist/shared-react/components/annotations/free-text-paint.d.ts +10 -0
  27. package/dist/shared-react/components/annotations/free-text.d.ts +13 -0
  28. package/dist/shared-react/components/annotations/stamp-paint.d.ts +8 -0
  29. package/dist/shared-react/components/annotations/stamp.d.ts +12 -0
  30. package/dist/shared-react/components/render-annotation.d.ts +1 -1
  31. package/dist/shared-react/hooks/use-drag-resize.d.ts +5 -2
  32. package/package.json +9 -9
@@ -1,12 +1,13 @@
1
1
  import { usePlugin, useCapability } from "@embedpdf/core/react";
2
- import { AnnotationPlugin, patching, getAnnotationsByPageIndex, getSelectedAnnotationByPageIndex, isInk, isSquare, isCircle, isUnderline, isStrikeout, isSquiggly, isHighlight, isLine, isPolyline, isPolygon, makeVariantKey } from "@embedpdf/plugin-annotation";
2
+ import { AnnotationPlugin, patching, getAnnotationsByPageIndex, getSelectedAnnotationByPageIndex, isInk, isSquare, isCircle, isUnderline, isStrikeout, isSquiggly, isHighlight, isLine, isPolyline, isPolygon, isFreeText, isStamp } from "@embedpdf/plugin-annotation";
3
3
  import { jsx, jsxs, Fragment as Fragment$1 } from "react/jsx-runtime";
4
- import { restoreOffset, rectEquals, PdfAnnotationBorderStyle, PdfAnnotationSubtype, expandRect, rectFromPoints, blendModeToCss, PdfBlendMode } from "@embedpdf/models";
4
+ import { restoreOffset, rectEquals, PdfAnnotationBorderStyle, PdfAnnotationSubtype, expandRect, rectFromPoints, textAlignmentToCss, standardFontCss, PdfVerticalAlignment, ignore, PdfErrorCode, blendModeToCss, PdfBlendMode } from "@embedpdf/models";
5
5
  import { usePointerHandlers } from "@embedpdf/plugin-interaction-manager/react";
6
6
  import { useSelectionCapability } from "@embedpdf/plugin-selection/react";
7
7
  import { Fragment, useState, useRef, useEffect, useLayoutEffect, useMemo, useCallback } from "react";
8
8
  const useAnnotationPlugin = () => usePlugin(AnnotationPlugin.id);
9
9
  const useAnnotationCapability = () => useCapability(AnnotationPlugin.id);
10
+ const mapDoubleClick = (handler) => handler ? { onDoubleClick: handler } : {};
10
11
  function getCounterRotation(rect, rotation) {
11
12
  const { width: w, height: h } = rect.size;
12
13
  switch (rotation % 4) {
@@ -149,6 +150,7 @@ function useDragResize({
149
150
  isResizable,
150
151
  computePatch,
151
152
  computeVertices,
153
+ lockAspectRatio = false,
152
154
  currentRect,
153
155
  setCurrentRect,
154
156
  setCurrentVertices,
@@ -183,6 +185,23 @@ function useDragResize({
183
185
  oy += dy;
184
186
  h -= dy;
185
187
  }
188
+ if (lockAspectRatio && startRect.current) {
189
+ const ratio = startRect.current.size.width / startRect.current.size.height;
190
+ const anchorRight = ox + w;
191
+ const anchorBottom = oy + h;
192
+ const horizontalPrimary = dir.current.includes("left") || dir.current.includes("right");
193
+ if (horizontalPrimary) {
194
+ h = w / ratio;
195
+ } else {
196
+ w = h * ratio;
197
+ }
198
+ if (dir.current.includes("left")) {
199
+ ox = anchorRight - w;
200
+ }
201
+ if (dir.current.includes("top")) {
202
+ oy = anchorBottom - h;
203
+ }
204
+ }
186
205
  }
187
206
  if (w < 1 || h < 1) return currentRect;
188
207
  w = clamp(w, 1, pageW);
@@ -219,8 +238,14 @@ function useDragResize({
219
238
  setCurrentRect(patch.rect ?? nextRect);
220
239
  setPreviewObject(patch);
221
240
  };
222
- const onPointerUp = () => {
241
+ const onPointerUp = (e) => {
223
242
  if (drag.current === "idle") return;
243
+ if ((e == null ? void 0 : e.currentTarget) && e.pointerId !== void 0) {
244
+ try {
245
+ e.currentTarget.releasePointerCapture(e.pointerId);
246
+ } catch {
247
+ }
248
+ }
224
249
  const usedDir = dir.current || "bottom-right";
225
250
  drag.current = "idle";
226
251
  let patch = { rect: currentRect };
@@ -256,7 +281,9 @@ function useDragResize({
256
281
  rootHandlers: {
257
282
  onPointerDown,
258
283
  onPointerMove,
259
- onPointerUp
284
+ onPointerUp,
285
+ onPointerCancel: () => onPointerUp(),
286
+ onLostPointerCapture: () => onPointerUp()
260
287
  },
261
288
  startResize
262
289
  };
@@ -334,9 +361,11 @@ function AnnotationContainer({
334
361
  isSelected = false,
335
362
  isDraggable = true,
336
363
  isResizable = true,
364
+ lockAspectRatio = false,
337
365
  computeVertices,
338
366
  computePatch,
339
367
  selectionMenu,
368
+ onDoubleClick,
340
369
  ...props
341
370
  }) {
342
371
  const { provides: annotationProvides } = useAnnotationCapability();
@@ -354,6 +383,7 @@ function AnnotationContainer({
354
383
  isSelected,
355
384
  isDraggable,
356
385
  isResizable,
386
+ lockAspectRatio,
357
387
  computePatch,
358
388
  computeVertices,
359
389
  currentRect,
@@ -375,6 +405,7 @@ function AnnotationContainer({
375
405
  "div",
376
406
  {
377
407
  ...rootHandlers,
408
+ ...mapDoubleClick(onDoubleClick),
378
409
  style: {
379
410
  position: "absolute",
380
411
  outline: isSelected ? "1px solid #007ACC" : "none",
@@ -385,6 +416,9 @@ function AnnotationContainer({
385
416
  height: `${currentRect.size.height * scale}px`,
386
417
  pointerEvents: isSelected ? "auto" : "none",
387
418
  cursor: isSelected && isDraggable ? "move" : "default",
419
+ ...isSelected && {
420
+ zIndex: 3
421
+ },
388
422
  ...style
389
423
  },
390
424
  ...props,
@@ -1191,6 +1225,158 @@ const patchPolygon = (orig, ctx) => {
1191
1225
  vertices: moved
1192
1226
  };
1193
1227
  };
1228
+ function FreeText({
1229
+ isSelected,
1230
+ isEditing,
1231
+ annotation,
1232
+ pageIndex,
1233
+ scale,
1234
+ onClick
1235
+ }) {
1236
+ const editorRef = useRef(null);
1237
+ const { provides: annotationProvides } = useAnnotationCapability();
1238
+ useEffect(() => {
1239
+ if (isEditing && editorRef.current) {
1240
+ const editor = editorRef.current;
1241
+ editor.focus();
1242
+ const selection = window.getSelection();
1243
+ if (selection) {
1244
+ const range = document.createRange();
1245
+ range.selectNodeContents(editor);
1246
+ range.collapse(false);
1247
+ selection.removeAllRanges();
1248
+ selection.addRange(range);
1249
+ }
1250
+ }
1251
+ }, [isEditing]);
1252
+ const handleBlur = () => {
1253
+ if (!annotationProvides) return;
1254
+ if (!editorRef.current) return;
1255
+ annotationProvides.updateAnnotation(pageIndex, annotation.localId, {
1256
+ contents: editorRef.current.innerText
1257
+ });
1258
+ };
1259
+ return /* @__PURE__ */ jsx(
1260
+ "div",
1261
+ {
1262
+ style: {
1263
+ position: "absolute",
1264
+ width: annotation.object.rect.size.width * scale,
1265
+ height: annotation.object.rect.size.height * scale,
1266
+ cursor: isSelected && !isEditing ? "move" : "default",
1267
+ pointerEvents: isSelected && !isEditing ? "none" : "auto",
1268
+ zIndex: 2
1269
+ },
1270
+ onPointerDown: onClick,
1271
+ children: /* @__PURE__ */ jsx(
1272
+ "span",
1273
+ {
1274
+ ref: editorRef,
1275
+ onBlur: handleBlur,
1276
+ style: {
1277
+ color: annotation.object.fontColor,
1278
+ fontSize: annotation.object.fontSize * scale,
1279
+ fontFamily: standardFontCss(annotation.object.fontFamily),
1280
+ textAlign: textAlignmentToCss(annotation.object.textAlign),
1281
+ flexDirection: "column",
1282
+ justifyContent: annotation.object.verticalAlign === PdfVerticalAlignment.Top ? "flex-start" : annotation.object.verticalAlign === PdfVerticalAlignment.Middle ? "center" : "flex-end",
1283
+ display: "flex",
1284
+ backgroundColor: annotation.object.backgroundColor,
1285
+ opacity: annotation.object.opacity,
1286
+ width: "100%",
1287
+ height: "100%",
1288
+ lineHeight: "1.18",
1289
+ overflow: "hidden",
1290
+ cursor: isEditing ? "text" : "pointer"
1291
+ },
1292
+ contentEditable: isEditing,
1293
+ suppressContentEditableWarning: true,
1294
+ children: annotation.object.contents
1295
+ }
1296
+ )
1297
+ }
1298
+ );
1299
+ }
1300
+ function RenderAnnotation({
1301
+ pageIndex,
1302
+ annotation,
1303
+ scaleFactor = 1,
1304
+ style,
1305
+ ...props
1306
+ }) {
1307
+ const { provides: annotationProvides } = useAnnotationCapability();
1308
+ const [imageUrl, setImageUrl] = useState(null);
1309
+ const urlRef = useRef(null);
1310
+ const { width, height } = annotation.rect.size;
1311
+ useEffect(() => {
1312
+ if (annotationProvides) {
1313
+ const task = annotationProvides.renderAnnotation({
1314
+ pageIndex,
1315
+ annotation,
1316
+ scaleFactor,
1317
+ dpr: window.devicePixelRatio
1318
+ });
1319
+ task.wait((blob) => {
1320
+ const url = URL.createObjectURL(blob);
1321
+ setImageUrl(url);
1322
+ urlRef.current = url;
1323
+ }, ignore);
1324
+ return () => {
1325
+ if (urlRef.current) {
1326
+ URL.revokeObjectURL(urlRef.current);
1327
+ urlRef.current = null;
1328
+ } else {
1329
+ task.abort({
1330
+ code: PdfErrorCode.Cancelled,
1331
+ message: "canceled render task"
1332
+ });
1333
+ }
1334
+ };
1335
+ }
1336
+ }, [pageIndex, scaleFactor, annotationProvides, annotation.id, width, height]);
1337
+ const handleImageLoad = () => {
1338
+ if (urlRef.current) {
1339
+ URL.revokeObjectURL(urlRef.current);
1340
+ urlRef.current = null;
1341
+ }
1342
+ };
1343
+ return /* @__PURE__ */ jsx(Fragment, { children: imageUrl && /* @__PURE__ */ jsx(
1344
+ "img",
1345
+ {
1346
+ src: imageUrl,
1347
+ onLoad: handleImageLoad,
1348
+ ...props,
1349
+ style: {
1350
+ width: "100%",
1351
+ height: "100%",
1352
+ ...style || {}
1353
+ }
1354
+ }
1355
+ ) });
1356
+ }
1357
+ function Stamp({ isSelected, annotation, pageIndex, scale, onClick }) {
1358
+ return /* @__PURE__ */ jsx(
1359
+ "div",
1360
+ {
1361
+ style: {
1362
+ position: "absolute",
1363
+ width: "100%",
1364
+ height: "100%",
1365
+ zIndex: 2,
1366
+ pointerEvents: isSelected ? "none" : "auto"
1367
+ },
1368
+ onPointerDown: onClick,
1369
+ children: annotation.pdfId !== void 0 && /* @__PURE__ */ jsx(
1370
+ RenderAnnotation,
1371
+ {
1372
+ pageIndex,
1373
+ annotation: { ...annotation.object, id: annotation.pdfId },
1374
+ scaleFactor: scale
1375
+ }
1376
+ )
1377
+ }
1378
+ );
1379
+ }
1194
1380
  function Annotations(annotationsProps) {
1195
1381
  const { pageIndex, scale, selectionMenu } = annotationsProps;
1196
1382
  const { provides: annotationProvides } = useAnnotationCapability();
@@ -1198,6 +1384,7 @@ function Annotations(annotationsProps) {
1198
1384
  const [annotations, setAnnotations] = useState([]);
1199
1385
  const { register } = usePointerHandlers({ pageIndex });
1200
1386
  const [selectionState, setSelectionState] = useState(null);
1387
+ const [editingId, setEditingId] = useState(null);
1201
1388
  useEffect(() => {
1202
1389
  if (annotationProvides) {
1203
1390
  annotationProvides.onStateChange((state) => {
@@ -1211,6 +1398,7 @@ function Annotations(annotationsProps) {
1211
1398
  onPointerDown: (_, pe) => {
1212
1399
  if (pe.target === pe.currentTarget && annotationProvides) {
1213
1400
  annotationProvides.deselectAnnotation();
1401
+ setEditingId(null);
1214
1402
  }
1215
1403
  }
1216
1404
  }),
@@ -1222,6 +1410,7 @@ function Annotations(annotationsProps) {
1222
1410
  if (annotationProvides && selectionProvides) {
1223
1411
  annotationProvides.selectAnnotation(pageIndex, annotation.localId);
1224
1412
  selectionProvides.clear();
1413
+ setEditingId(null);
1225
1414
  }
1226
1415
  },
1227
1416
  [annotationProvides, selectionProvides, pageIndex]
@@ -1231,6 +1420,7 @@ function Annotations(annotationsProps) {
1231
1420
  }, [register, handlers]);
1232
1421
  return /* @__PURE__ */ jsx(Fragment$1, { children: annotations.map((annotation) => {
1233
1422
  const isSelected = (selectionState == null ? void 0 : selectionState.localId) === annotation.localId;
1423
+ const isEditing = editingId === annotation.localId;
1234
1424
  if (isInk(annotation)) {
1235
1425
  return /* @__PURE__ */ jsx(
1236
1426
  AnnotationContainer,
@@ -1546,6 +1736,70 @@ function Annotations(annotationsProps) {
1546
1736
  annotation.localId
1547
1737
  );
1548
1738
  }
1739
+ if (isFreeText(annotation)) {
1740
+ return /* @__PURE__ */ jsx(
1741
+ AnnotationContainer,
1742
+ {
1743
+ trackedAnnotation: annotation,
1744
+ isSelected,
1745
+ isDraggable: true,
1746
+ isResizable: true,
1747
+ selectionMenu,
1748
+ outlineOffset: 6,
1749
+ onDoubleClick: (e) => {
1750
+ e.stopPropagation();
1751
+ setEditingId(annotation.localId);
1752
+ },
1753
+ style: {
1754
+ mixBlendMode: blendModeToCss(annotation.object.blendMode ?? PdfBlendMode.Normal)
1755
+ },
1756
+ ...annotationsProps,
1757
+ children: (object) => /* @__PURE__ */ jsx(
1758
+ FreeText,
1759
+ {
1760
+ isSelected,
1761
+ isEditing,
1762
+ annotation: {
1763
+ ...annotation,
1764
+ object
1765
+ },
1766
+ pageIndex,
1767
+ scale,
1768
+ onClick: (e) => handleClick(e, annotation)
1769
+ }
1770
+ )
1771
+ },
1772
+ annotation.localId
1773
+ );
1774
+ }
1775
+ if (isStamp(annotation)) {
1776
+ return /* @__PURE__ */ jsx(
1777
+ AnnotationContainer,
1778
+ {
1779
+ trackedAnnotation: annotation,
1780
+ isSelected,
1781
+ isDraggable: true,
1782
+ isResizable: true,
1783
+ selectionMenu,
1784
+ lockAspectRatio: true,
1785
+ style: {
1786
+ mixBlendMode: blendModeToCss(annotation.object.blendMode ?? PdfBlendMode.Normal)
1787
+ },
1788
+ ...annotationsProps,
1789
+ children: (_object) => /* @__PURE__ */ jsx(
1790
+ Stamp,
1791
+ {
1792
+ isSelected,
1793
+ annotation,
1794
+ pageIndex,
1795
+ scale,
1796
+ onClick: (e) => handleClick(e, annotation)
1797
+ }
1798
+ )
1799
+ },
1800
+ annotation.localId
1801
+ );
1802
+ }
1549
1803
  return null;
1550
1804
  }) });
1551
1805
  }
@@ -1570,8 +1824,9 @@ function TextMarkup({ pageIndex, scale }) {
1570
1824
  return off;
1571
1825
  }, [annotationProvides]);
1572
1826
  if (!boundingRect) return null;
1573
- switch (activeTool.variantKey) {
1574
- case makeVariantKey(PdfAnnotationSubtype.UNDERLINE):
1827
+ if (!activeTool.defaults) return null;
1828
+ switch (activeTool.defaults.subtype) {
1829
+ case PdfAnnotationSubtype.UNDERLINE:
1575
1830
  return /* @__PURE__ */ jsx(
1576
1831
  "div",
1577
1832
  {
@@ -1592,7 +1847,7 @@ function TextMarkup({ pageIndex, scale }) {
1592
1847
  )
1593
1848
  }
1594
1849
  );
1595
- case makeVariantKey(PdfAnnotationSubtype.HIGHLIGHT):
1850
+ case PdfAnnotationSubtype.HIGHLIGHT:
1596
1851
  return /* @__PURE__ */ jsx(
1597
1852
  "div",
1598
1853
  {
@@ -1613,7 +1868,7 @@ function TextMarkup({ pageIndex, scale }) {
1613
1868
  )
1614
1869
  }
1615
1870
  );
1616
- case makeVariantKey(PdfAnnotationSubtype.STRIKEOUT):
1871
+ case PdfAnnotationSubtype.STRIKEOUT:
1617
1872
  return /* @__PURE__ */ jsx(
1618
1873
  "div",
1619
1874
  {
@@ -1634,7 +1889,7 @@ function TextMarkup({ pageIndex, scale }) {
1634
1889
  )
1635
1890
  }
1636
1891
  );
1637
- case makeVariantKey(PdfAnnotationSubtype.SQUIGGLY):
1892
+ case PdfAnnotationSubtype.SQUIGGLY:
1638
1893
  return /* @__PURE__ */ jsx(
1639
1894
  "div",
1640
1895
  {
@@ -2536,6 +2791,224 @@ const PolygonPaint = ({
2536
2791
  }
2537
2792
  );
2538
2793
  };
2794
+ const FreeTextPaint = ({
2795
+ pageIndex,
2796
+ scale,
2797
+ pageWidth,
2798
+ pageHeight,
2799
+ cursor = "text"
2800
+ }) => {
2801
+ const { provides: annotationProvides } = useAnnotationCapability();
2802
+ const [activeTool, setActiveTool] = useState({ variantKey: null, defaults: null });
2803
+ useEffect(() => annotationProvides == null ? void 0 : annotationProvides.onActiveToolChange(setActiveTool), [annotationProvides]);
2804
+ if (!activeTool.defaults || activeTool.defaults.subtype !== PdfAnnotationSubtype.FREETEXT)
2805
+ return null;
2806
+ const toolFontColor = activeTool.defaults.fontColor ?? "#000000";
2807
+ const toolOpacity = activeTool.defaults.opacity ?? 1;
2808
+ const toolFontSize = activeTool.defaults.fontSize ?? 12;
2809
+ const toolFontFamily = activeTool.defaults.fontFamily;
2810
+ const toolBackgroundColor = activeTool.defaults.backgroundColor ?? "transparent";
2811
+ const toolTextAlign = activeTool.defaults.textAlign;
2812
+ const toolVerticalAlign = activeTool.defaults.verticalAlign;
2813
+ const toolContent = activeTool.defaults.content ?? "Insert text here";
2814
+ const { register } = usePointerHandlers({ modeId: "freeText", pageIndex });
2815
+ const clamp = (v, min, max) => Math.max(min, Math.min(max, v));
2816
+ const pageWidthPDF = pageWidth / scale;
2817
+ const pageHeightPDF = pageHeight / scale;
2818
+ const [start, setStart] = useState(null);
2819
+ const [current, setCurrent] = useState(null);
2820
+ const commitFreeText = (p1, p2) => {
2821
+ const minX2 = Math.min(p1.x, p2.x);
2822
+ const minY2 = Math.min(p1.y, p2.y);
2823
+ const maxX2 = Math.max(p1.x, p2.x);
2824
+ const maxY2 = Math.max(p1.y, p2.y);
2825
+ const w = maxX2 - minX2;
2826
+ const h = maxY2 - minY2;
2827
+ if (w < 1 || h < 1) return;
2828
+ const rect = {
2829
+ origin: { x: minX2, y: minY2 },
2830
+ size: { width: w, height: h }
2831
+ };
2832
+ const anno = {
2833
+ type: PdfAnnotationSubtype.FREETEXT,
2834
+ rect,
2835
+ contents: toolContent,
2836
+ fontColor: toolFontColor,
2837
+ fontSize: toolFontSize,
2838
+ fontFamily: toolFontFamily,
2839
+ opacity: toolOpacity,
2840
+ backgroundColor: toolBackgroundColor,
2841
+ textAlign: toolTextAlign,
2842
+ verticalAlign: toolVerticalAlign,
2843
+ pageIndex,
2844
+ id: Date.now() + Math.random()
2845
+ };
2846
+ annotationProvides.createAnnotation(pageIndex, anno);
2847
+ annotationProvides.setActiveVariant(null);
2848
+ annotationProvides.selectAnnotation(pageIndex, anno.id);
2849
+ };
2850
+ const handlers = useMemo(
2851
+ () => ({
2852
+ onPointerDown: (pos, evt) => {
2853
+ var _a, _b;
2854
+ const x = clamp(pos.x, 0, pageWidthPDF);
2855
+ const y = clamp(pos.y, 0, pageHeightPDF);
2856
+ setStart({ x, y });
2857
+ setCurrent({ x, y });
2858
+ (_b = (_a = evt.target) == null ? void 0 : _a.setPointerCapture) == null ? void 0 : _b.call(_a, evt.pointerId);
2859
+ },
2860
+ onPointerMove: (pos) => {
2861
+ if (!start) return;
2862
+ const x = clamp(pos.x, 0, pageWidthPDF);
2863
+ const y = clamp(pos.y, 0, pageHeightPDF);
2864
+ setCurrent({ x, y });
2865
+ },
2866
+ onPointerUp: (_, evt) => {
2867
+ var _a, _b;
2868
+ if (start && current && annotationProvides) {
2869
+ commitFreeText(start, current);
2870
+ }
2871
+ (_b = (_a = evt.target) == null ? void 0 : _a.releasePointerCapture) == null ? void 0 : _b.call(_a, evt.pointerId);
2872
+ setStart(null);
2873
+ setCurrent(null);
2874
+ },
2875
+ onPointerCancel: (_, evt) => {
2876
+ var _a, _b;
2877
+ (_b = (_a = evt.target) == null ? void 0 : _a.releasePointerCapture) == null ? void 0 : _b.call(_a, evt.pointerId);
2878
+ setStart(null);
2879
+ setCurrent(null);
2880
+ }
2881
+ }),
2882
+ [start, current, annotationProvides, pageWidthPDF, pageHeightPDF]
2883
+ );
2884
+ useEffect(() => register ? register(handlers) : void 0, [register, handlers]);
2885
+ if (!start || !current) return null;
2886
+ const minX = Math.min(start.x, current.x);
2887
+ const minY = Math.min(start.y, current.y);
2888
+ const maxX = Math.max(start.x, current.x);
2889
+ const maxY = Math.max(start.y, current.y);
2890
+ const dw = maxX - minX;
2891
+ const dh = maxY - minY;
2892
+ return /* @__PURE__ */ jsx(
2893
+ "svg",
2894
+ {
2895
+ style: {
2896
+ position: "absolute",
2897
+ left: minX * scale,
2898
+ top: minY * scale,
2899
+ width: dw * scale,
2900
+ height: dh * scale,
2901
+ pointerEvents: "none",
2902
+ zIndex: 2
2903
+ },
2904
+ width: dw * scale,
2905
+ height: dh * scale,
2906
+ viewBox: `0 0 ${dw} ${dh}`,
2907
+ children: /* @__PURE__ */ jsx(
2908
+ "rect",
2909
+ {
2910
+ x: 0,
2911
+ y: 0,
2912
+ width: dw,
2913
+ height: dh,
2914
+ fill: "transparent",
2915
+ style: {
2916
+ stroke: toolFontColor,
2917
+ strokeWidth: 1,
2918
+ strokeDasharray: "4,4",
2919
+ cursor
2920
+ }
2921
+ }
2922
+ )
2923
+ }
2924
+ );
2925
+ };
2926
+ const StampPaint = ({ pageIndex, scale, pageWidth, pageHeight }) => {
2927
+ const { provides: annotationProvides } = useAnnotationCapability();
2928
+ const inputRef = useRef(null);
2929
+ const canvasRef = useRef(null);
2930
+ const [activeTool, setActiveTool] = useState({ variantKey: null, defaults: null });
2931
+ useEffect(() => {
2932
+ if (!annotationProvides) return;
2933
+ return annotationProvides.onActiveToolChange(setActiveTool);
2934
+ }, [annotationProvides]);
2935
+ if (!activeTool.defaults) return null;
2936
+ if (activeTool.defaults.subtype !== PdfAnnotationSubtype.STAMP) return null;
2937
+ const { register } = usePointerHandlers({ modeId: "stamp", pageIndex });
2938
+ const pageWidthPDF = pageWidth / scale;
2939
+ const pageHeightPDF = pageHeight / scale;
2940
+ const clamp = (v, min, max) => Math.max(min, Math.min(max, v));
2941
+ const [start, setStart] = useState(null);
2942
+ const handlers = useMemo(
2943
+ () => ({
2944
+ onPointerDown: (pos, evt) => {
2945
+ var _a;
2946
+ const x = clamp(pos.x, 0, pageWidthPDF);
2947
+ const y = clamp(pos.y, 0, pageHeightPDF);
2948
+ setStart({ x, y });
2949
+ (_a = inputRef.current) == null ? void 0 : _a.click();
2950
+ }
2951
+ }),
2952
+ [pageWidthPDF, pageHeightPDF]
2953
+ );
2954
+ useEffect(() => register ? register(handlers) : void 0, [register, handlers]);
2955
+ const onChange = async (e) => {
2956
+ var _a;
2957
+ if (!annotationProvides || !start) return;
2958
+ const file = (_a = e.currentTarget.files) == null ? void 0 : _a[0];
2959
+ if (!file) return;
2960
+ const img = await new Promise((res, rej) => {
2961
+ const i = new Image();
2962
+ i.onload = () => res(i);
2963
+ i.onerror = rej;
2964
+ i.src = URL.createObjectURL(file);
2965
+ });
2966
+ const imgW = img.naturalWidth;
2967
+ const imgH = img.naturalHeight;
2968
+ const maxW = pageWidthPDF;
2969
+ const maxH = pageHeightPDF;
2970
+ const scaleFactor = Math.min(1, maxW / imgW, maxH / imgH);
2971
+ const pdfW = imgW * scaleFactor;
2972
+ const pdfH = imgH * scaleFactor;
2973
+ const posX = clamp(start.x, 0, maxW - pdfW);
2974
+ const posY = clamp(start.y, 0, maxH - pdfH);
2975
+ const rect = {
2976
+ origin: { x: posX, y: posY },
2977
+ size: { width: pdfW, height: pdfH }
2978
+ };
2979
+ const canvas = canvasRef.current;
2980
+ if (!canvas) return;
2981
+ canvas.width = pdfW;
2982
+ canvas.height = pdfH;
2983
+ const ctx = canvas.getContext("2d");
2984
+ ctx.drawImage(img, 0, 0, pdfW, pdfH);
2985
+ const imageData = ctx.getImageData(0, 0, pdfW, pdfH);
2986
+ const anno = {
2987
+ type: PdfAnnotationSubtype.STAMP,
2988
+ flags: ["print"],
2989
+ pageIndex,
2990
+ id: Date.now() + Math.random(),
2991
+ rect
2992
+ };
2993
+ annotationProvides.createAnnotation(pageIndex, anno, { imageData });
2994
+ annotationProvides.setActiveVariant(null);
2995
+ annotationProvides.selectAnnotation(pageIndex, anno.id);
2996
+ setStart(null);
2997
+ };
2998
+ return /* @__PURE__ */ jsxs(Fragment, { children: [
2999
+ /* @__PURE__ */ jsx("canvas", { style: { display: "none" }, ref: canvasRef }),
3000
+ /* @__PURE__ */ jsx(
3001
+ "input",
3002
+ {
3003
+ ref: inputRef,
3004
+ type: "file",
3005
+ accept: "image/png,image/jpeg",
3006
+ style: { display: "none" },
3007
+ onChange
3008
+ }
3009
+ )
3010
+ ] });
3011
+ };
2539
3012
  function AnnotationLayer({
2540
3013
  pageIndex,
2541
3014
  scale,
@@ -2611,6 +3084,24 @@ function AnnotationLayer({
2611
3084
  pageWidth,
2612
3085
  pageHeight
2613
3086
  }
3087
+ ),
3088
+ /* @__PURE__ */ jsx(
3089
+ FreeTextPaint,
3090
+ {
3091
+ pageIndex,
3092
+ scale,
3093
+ pageWidth,
3094
+ pageHeight
3095
+ }
3096
+ ),
3097
+ /* @__PURE__ */ jsx(
3098
+ StampPaint,
3099
+ {
3100
+ pageIndex,
3101
+ scale,
3102
+ pageWidth,
3103
+ pageHeight
3104
+ }
2614
3105
  )
2615
3106
  ]
2616
3107
  }