@embedpdf/plugin-annotation 1.0.11 → 1.0.13

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 (109) hide show
  1. package/dist/index.cjs +2 -693
  2. package/dist/index.cjs.map +1 -1
  3. package/dist/index.d.ts +1 -266
  4. package/dist/index.js +509 -164
  5. package/dist/index.js.map +1 -1
  6. package/dist/lib/actions.d.ts +104 -0
  7. package/dist/lib/annotation-plugin.d.ts +34 -0
  8. package/dist/lib/helpers.d.ts +18 -0
  9. package/dist/lib/index.d.ts +12 -0
  10. package/dist/lib/manifest.d.ts +4 -0
  11. package/dist/lib/patching/derived-rect.d.ts +2 -0
  12. package/dist/lib/patching/index.d.ts +4 -0
  13. package/dist/lib/patching/line-ending-handlers.d.ts +20 -0
  14. package/dist/lib/patching/line-endings.d.ts +13 -0
  15. package/dist/lib/patching/patch-utils.d.ts +7 -0
  16. package/dist/lib/reducer.d.ts +5 -0
  17. package/dist/lib/selectors.d.ts +25 -0
  18. package/dist/lib/types.d.ts +168 -0
  19. package/dist/lib/utils.d.ts +11 -0
  20. package/dist/lib/variant-key.d.ts +8 -0
  21. package/dist/preact/adapter.d.ts +8 -0
  22. package/dist/preact/core.d.ts +1 -0
  23. package/dist/preact/index.cjs +2 -1038
  24. package/dist/preact/index.cjs.map +1 -1
  25. package/dist/preact/index.d.ts +1 -28
  26. package/dist/preact/index.js +2150 -539
  27. package/dist/preact/index.js.map +1 -1
  28. package/dist/preact/interaction-manager.d.ts +1 -0
  29. package/dist/preact/selection.d.ts +1 -0
  30. package/dist/react/adapter.d.ts +2 -0
  31. package/dist/react/core.d.ts +1 -0
  32. package/dist/react/index.cjs +2 -0
  33. package/dist/react/index.cjs.map +1 -0
  34. package/dist/react/index.d.ts +1 -0
  35. package/dist/react/index.js +2624 -0
  36. package/dist/react/index.js.map +1 -0
  37. package/dist/react/interaction-manager.d.ts +1 -0
  38. package/dist/react/selection.d.ts +1 -0
  39. package/dist/shared-preact/components/annotation-container.d.ts +24 -0
  40. package/dist/shared-preact/components/annotation-layer.d.ts +13 -0
  41. package/dist/shared-preact/components/annotations/circle-paint.d.ts +10 -0
  42. package/dist/shared-preact/components/annotations/circle.d.ts +29 -0
  43. package/dist/shared-preact/components/annotations/ink-highlight-paint.d.ts +0 -0
  44. package/dist/shared-preact/components/annotations/ink-paint.d.ts +18 -0
  45. package/dist/shared-preact/components/annotations/ink.d.ts +25 -0
  46. package/dist/shared-preact/components/annotations/line-paint.d.ts +10 -0
  47. package/dist/shared-preact/components/annotations/line.d.ts +33 -0
  48. package/dist/shared-preact/components/annotations/polygon-paint.d.ts +9 -0
  49. package/dist/shared-preact/components/annotations/polygon.d.ts +17 -0
  50. package/dist/shared-preact/components/annotations/polyline-paint.d.ts +10 -0
  51. package/dist/shared-preact/components/annotations/polyline.d.ts +17 -0
  52. package/dist/shared-preact/components/annotations/square-paint.d.ts +10 -0
  53. package/dist/shared-preact/components/annotations/square.d.ts +29 -0
  54. package/dist/shared-preact/components/annotations.d.ts +11 -0
  55. package/dist/shared-preact/components/counter-rotate-container.d.ts +32 -0
  56. package/dist/shared-preact/components/index.d.ts +1 -0
  57. package/dist/shared-preact/components/render-annotation.d.ts +11 -0
  58. package/dist/shared-preact/components/resize-handles.d.ts +9 -0
  59. package/dist/shared-preact/components/text-markup/highlight.d.ts +13 -0
  60. package/dist/shared-preact/components/text-markup/squiggly.d.ts +13 -0
  61. package/dist/shared-preact/components/text-markup/strikeout.d.ts +13 -0
  62. package/dist/shared-preact/components/text-markup/underline.d.ts +13 -0
  63. package/dist/shared-preact/components/text-markup.d.ts +6 -0
  64. package/dist/shared-preact/components/vertex-editor.d.ts +19 -0
  65. package/dist/shared-preact/hooks/index.d.ts +1 -0
  66. package/dist/shared-preact/hooks/use-annotation.d.ts +11 -0
  67. package/dist/shared-preact/hooks/use-drag-resize.d.ts +31 -0
  68. package/dist/shared-preact/index.d.ts +2 -0
  69. package/dist/shared-preact/patch-ink.d.ts +16 -0
  70. package/dist/shared-preact/patchers.d.ts +9 -0
  71. package/dist/shared-preact/types.d.ts +12 -0
  72. package/dist/shared-preact/vertex-patchers.d.ts +10 -0
  73. package/dist/shared-react/components/annotation-container.d.ts +24 -0
  74. package/dist/shared-react/components/annotation-layer.d.ts +13 -0
  75. package/dist/shared-react/components/annotations/circle-paint.d.ts +10 -0
  76. package/dist/shared-react/components/annotations/circle.d.ts +29 -0
  77. package/dist/shared-react/components/annotations/ink-highlight-paint.d.ts +0 -0
  78. package/dist/shared-react/components/annotations/ink-paint.d.ts +17 -0
  79. package/dist/shared-react/components/annotations/ink.d.ts +25 -0
  80. package/dist/shared-react/components/annotations/line-paint.d.ts +10 -0
  81. package/dist/shared-react/components/annotations/line.d.ts +33 -0
  82. package/dist/shared-react/components/annotations/polygon-paint.d.ts +9 -0
  83. package/dist/shared-react/components/annotations/polygon.d.ts +17 -0
  84. package/dist/shared-react/components/annotations/polyline-paint.d.ts +10 -0
  85. package/dist/shared-react/components/annotations/polyline.d.ts +17 -0
  86. package/dist/shared-react/components/annotations/square-paint.d.ts +10 -0
  87. package/dist/shared-react/components/annotations/square.d.ts +29 -0
  88. package/dist/shared-react/components/annotations.d.ts +11 -0
  89. package/dist/shared-react/components/counter-rotate-container.d.ts +32 -0
  90. package/dist/shared-react/components/index.d.ts +1 -0
  91. package/dist/shared-react/components/render-annotation.d.ts +11 -0
  92. package/dist/shared-react/components/resize-handles.d.ts +9 -0
  93. package/dist/shared-react/components/text-markup/highlight.d.ts +13 -0
  94. package/dist/shared-react/components/text-markup/squiggly.d.ts +13 -0
  95. package/dist/shared-react/components/text-markup/strikeout.d.ts +13 -0
  96. package/dist/shared-react/components/text-markup/underline.d.ts +13 -0
  97. package/dist/shared-react/components/text-markup.d.ts +6 -0
  98. package/dist/shared-react/components/vertex-editor.d.ts +19 -0
  99. package/dist/shared-react/hooks/index.d.ts +1 -0
  100. package/dist/shared-react/hooks/use-annotation.d.ts +11 -0
  101. package/dist/shared-react/hooks/use-drag-resize.d.ts +31 -0
  102. package/dist/shared-react/index.d.ts +2 -0
  103. package/dist/shared-react/patch-ink.d.ts +16 -0
  104. package/dist/shared-react/patchers.d.ts +9 -0
  105. package/dist/shared-react/types.d.ts +12 -0
  106. package/dist/shared-react/vertex-patchers.d.ts +10 -0
  107. package/package.json +17 -15
  108. package/dist/index.d.cts +0 -266
  109. package/dist/preact/index.d.cts +0 -28
@@ -1,26 +1,333 @@
1
- // src/preact/hooks/use-annotation.ts
2
- import { useCapability, usePlugin } from "@embedpdf/core/preact";
3
- import { AnnotationPlugin } from "@embedpdf/plugin-annotation";
4
- var useAnnotationPlugin = () => usePlugin(AnnotationPlugin.id);
5
- var useAnnotationCapability = () => useCapability(AnnotationPlugin.id);
6
-
7
- // src/preact/components/annotations.tsx
8
- import { PdfAnnotationSubtype as PdfAnnotationSubtype2 } from "@embedpdf/models";
1
+ import { usePlugin, useCapability } from "@embedpdf/core/preact";
2
+ import { AnnotationPlugin, patching, getAnnotationsByPageIndex, getSelectedAnnotationByPageIndex, isInk, isSquare, isCircle, isUnderline, isStrikeout, isSquiggly, isHighlight, isLine, isPolyline, isPolygon, makeVariantKey } from "@embedpdf/plugin-annotation";
3
+ import { jsx, jsxs, Fragment as Fragment$1 } from "preact/jsx-runtime";
4
+ import { restoreOffset, rectEquals, PdfAnnotationBorderStyle, PdfAnnotationSubtype, expandRect, rectFromPoints, blendModeToCss, PdfBlendMode } from "@embedpdf/models";
9
5
  import { usePointerHandlers } from "@embedpdf/plugin-interaction-manager/preact";
10
- import {
11
- getAnnotationsByPageIndex,
12
- getSelectedAnnotationByPageIndex
13
- } from "@embedpdf/plugin-annotation";
14
- import { useMemo as useMemo2, useState as useState2, useEffect as useEffect2, useCallback } from "preact/hooks";
15
-
16
- // src/preact/components/annotation-container.tsx
17
- import { useEffect, useRef, useState } from "preact/hooks";
18
- import { restoreOffset } from "@embedpdf/models";
19
- import { Fragment, jsx, jsxs } from "preact/jsx-runtime";
6
+ import { useSelectionCapability } from "@embedpdf/plugin-selection/preact";
7
+ import { Fragment } from "preact";
8
+ import { useState, useRef, useEffect, useLayoutEffect, useMemo, useCallback } from "preact/hooks";
9
+ const useAnnotationPlugin = () => usePlugin(AnnotationPlugin.id);
10
+ const useAnnotationCapability = () => useCapability(AnnotationPlugin.id);
11
+ function getCounterRotation(rect, rotation) {
12
+ const { width: w, height: h } = rect.size;
13
+ switch (rotation % 4) {
14
+ case 1:
15
+ return {
16
+ matrix: `matrix(0, -1, 1, 0, 0, ${h})`,
17
+ width: h,
18
+ height: w
19
+ };
20
+ case 2:
21
+ return {
22
+ matrix: `matrix(-1, 0, 0, -1, ${w}, ${h})`,
23
+ width: w,
24
+ height: h
25
+ };
26
+ case 3:
27
+ return {
28
+ matrix: `matrix(0, 1, -1, 0, ${w}, 0)`,
29
+ width: h,
30
+ height: w
31
+ };
32
+ default:
33
+ return {
34
+ matrix: `matrix(1, 0, 0, 1, 0, 0)`,
35
+ width: w,
36
+ height: h
37
+ };
38
+ }
39
+ }
40
+ function CounterRotate({ children, ...props }) {
41
+ const { rect, rotation } = props;
42
+ const { matrix, width, height } = getCounterRotation(rect, rotation);
43
+ const menuWrapperStyle = {
44
+ position: "absolute",
45
+ left: rect.origin.x,
46
+ top: rect.origin.y,
47
+ transform: matrix,
48
+ transformOrigin: "0 0",
49
+ width,
50
+ height,
51
+ pointerEvents: "none",
52
+ zIndex: 3
53
+ };
54
+ const menuWrapperProps = {
55
+ style: menuWrapperStyle,
56
+ onPointerDown: (e) => e.stopPropagation()
57
+ };
58
+ return /* @__PURE__ */ jsx(Fragment, { children: children({
59
+ menuWrapperProps,
60
+ matrix,
61
+ rect: {
62
+ origin: { x: rect.origin.x, y: rect.origin.y },
63
+ size: { width, height }
64
+ }
65
+ }) });
66
+ }
67
+ function VertexEditor({
68
+ rect,
69
+ rotation,
70
+ scale,
71
+ vertices,
72
+ onEdit,
73
+ onCommit,
74
+ handleSize = 12
75
+ }) {
76
+ const [dragIdx, setDragIdx] = useState(null);
77
+ const startScreen = useRef(null);
78
+ const startVerts = useRef([]);
79
+ const applyDelta = (deltaScreen) => {
80
+ const deltaPdf = restoreOffset(deltaScreen, rotation, scale);
81
+ const next = [...startVerts.current];
82
+ if (dragIdx !== null) {
83
+ next[dragIdx] = {
84
+ x: next[dragIdx].x + deltaPdf.x,
85
+ y: next[dragIdx].y + deltaPdf.y
86
+ };
87
+ }
88
+ return next;
89
+ };
90
+ const handleDown = (idx) => (e) => {
91
+ e.stopPropagation();
92
+ e.preventDefault();
93
+ setDragIdx(idx);
94
+ startScreen.current = { x: e.clientX, y: e.clientY };
95
+ startVerts.current = vertices;
96
+ e.target.setPointerCapture(e.pointerId);
97
+ };
98
+ const handleMove = (e) => {
99
+ if (dragIdx === null || !startScreen.current) return;
100
+ const deltaRaw = {
101
+ x: e.clientX - startScreen.current.x,
102
+ y: e.clientY - startScreen.current.y
103
+ };
104
+ onEdit(applyDelta(deltaRaw));
105
+ };
106
+ const handleUp = (e) => {
107
+ if (dragIdx === null || !startScreen.current) return;
108
+ e.target.releasePointerCapture(e.pointerId);
109
+ const deltaRaw = {
110
+ x: e.clientX - startScreen.current.x,
111
+ y: e.clientY - startScreen.current.y
112
+ };
113
+ onCommit(applyDelta(deltaRaw));
114
+ setDragIdx(null);
115
+ };
116
+ return /* @__PURE__ */ jsx(Fragment, { children: vertices.map((v, i) => {
117
+ const left = (v.x - rect.origin.x) * scale - handleSize / 2;
118
+ const top = (v.y - rect.origin.y) * scale - handleSize / 2;
119
+ return /* @__PURE__ */ jsx(
120
+ "div",
121
+ {
122
+ style: {
123
+ position: "absolute",
124
+ left,
125
+ top,
126
+ width: handleSize,
127
+ height: handleSize,
128
+ borderRadius: "50%",
129
+ background: "#2196f3",
130
+ cursor: "pointer",
131
+ pointerEvents: "auto",
132
+ zIndex: 4
133
+ },
134
+ onPointerDown: handleDown(i),
135
+ onPointerMove: handleMove,
136
+ onPointerUp: handleUp
137
+ },
138
+ i
139
+ );
140
+ }) });
141
+ }
142
+ function useDragResize({
143
+ scale,
144
+ pageWidth,
145
+ pageHeight,
146
+ rotation,
147
+ tracked,
148
+ isSelected,
149
+ isDraggable,
150
+ isResizable,
151
+ computePatch,
152
+ computeVertices,
153
+ currentRect,
154
+ setCurrentRect,
155
+ setCurrentVertices,
156
+ setPreviewObject,
157
+ commit
158
+ }) {
159
+ const drag = useRef("idle");
160
+ const dir = useRef("none");
161
+ const startPos = useRef(null);
162
+ const startRect = useRef(null);
163
+ const clamp = (v, min, max) => Math.max(min, Math.min(max, v));
164
+ const pageW = pageWidth / scale;
165
+ const pageH = pageHeight / scale;
166
+ const applyDelta = (dx, dy) => {
167
+ if (!startRect.current) return currentRect;
168
+ let { origin, size } = startRect.current;
169
+ let ox = origin.x;
170
+ let oy = origin.y;
171
+ let w = size.width;
172
+ let h = size.height;
173
+ if (drag.current === "dragging") {
174
+ ox += dx;
175
+ oy += dy;
176
+ } else if (drag.current === "resizing") {
177
+ if (dir.current.includes("right")) w += dx;
178
+ else if (dir.current.includes("left")) {
179
+ ox += dx;
180
+ w -= dx;
181
+ }
182
+ if (dir.current.includes("bottom")) h += dy;
183
+ else if (dir.current.includes("top")) {
184
+ oy += dy;
185
+ h -= dy;
186
+ }
187
+ }
188
+ if (w < 1 || h < 1) return currentRect;
189
+ w = clamp(w, 1, pageW);
190
+ h = clamp(h, 1, pageH);
191
+ ox = clamp(ox, 0, pageW - w);
192
+ oy = clamp(oy, 0, pageH - h);
193
+ return { origin: { x: ox, y: oy }, size: { width: w, height: h } };
194
+ };
195
+ const onPointerDown = (e) => {
196
+ if (!isSelected || !isDraggable) return;
197
+ e.stopPropagation();
198
+ e.preventDefault();
199
+ drag.current = "dragging";
200
+ startPos.current = { x: e.clientX, y: e.clientY };
201
+ startRect.current = currentRect;
202
+ e.currentTarget.setPointerCapture(e.pointerId);
203
+ };
204
+ const onPointerMove = (e) => {
205
+ if (drag.current === "idle" || !startPos.current) return;
206
+ const disp = {
207
+ x: e.clientX - startPos.current.x,
208
+ y: e.clientY - startPos.current.y
209
+ };
210
+ const { x, y } = restoreOffset(disp, rotation, scale);
211
+ const nextRect = applyDelta(x, y);
212
+ let patch = { rect: nextRect };
213
+ if (computePatch) {
214
+ patch = computePatch(tracked.object, {
215
+ rect: nextRect,
216
+ direction: drag.current === "resizing" ? dir.current : "bottom-right"
217
+ });
218
+ if (computeVertices) setCurrentVertices(computeVertices({ ...tracked.object, ...patch }));
219
+ }
220
+ setCurrentRect(patch.rect ?? nextRect);
221
+ setPreviewObject(patch);
222
+ };
223
+ const onPointerUp = () => {
224
+ if (drag.current === "idle") return;
225
+ const usedDir = dir.current || "bottom-right";
226
+ drag.current = "idle";
227
+ let patch = { rect: currentRect };
228
+ if (computePatch) {
229
+ patch = computePatch(tracked.object, {
230
+ rect: currentRect,
231
+ direction: usedDir
232
+ });
233
+ }
234
+ commit(patch);
235
+ startPos.current = null;
236
+ startRect.current = null;
237
+ dir.current = "none";
238
+ setPreviewObject(null);
239
+ };
240
+ const startResize = (direction) => (e) => {
241
+ if (!isSelected || !isResizable) return;
242
+ e.stopPropagation();
243
+ e.preventDefault();
244
+ drag.current = "resizing";
245
+ dir.current = direction;
246
+ startPos.current = { x: e.clientX, y: e.clientY };
247
+ startRect.current = currentRect;
248
+ e.currentTarget.setPointerCapture(e.pointerId);
249
+ };
250
+ useEffect(() => {
251
+ drag.current = "idle";
252
+ dir.current = "none";
253
+ startPos.current = null;
254
+ startRect.current = null;
255
+ }, [tracked]);
256
+ return {
257
+ rootHandlers: {
258
+ onPointerDown,
259
+ onPointerMove,
260
+ onPointerUp
261
+ },
262
+ startResize
263
+ };
264
+ }
265
+ const commonStyle = (o) => ({
266
+ position: "absolute",
267
+ width: 13,
268
+ height: 13,
269
+ background: "blue",
270
+ borderRadius: "50%"
271
+ });
272
+ function ResizeHandles({ rotation, outlineOffset = 1, startResize }) {
273
+ const o = outlineOffset;
274
+ return /* @__PURE__ */ jsxs(Fragment$1, { children: [
275
+ /* @__PURE__ */ jsx(
276
+ "div",
277
+ {
278
+ style: {
279
+ ...commonStyle(),
280
+ top: -7 - o,
281
+ left: -7 - o,
282
+ cursor: rotation % 2 ? "nesw-resize" : "nwse-resize"
283
+ },
284
+ onPointerDown: startResize("top-left")
285
+ }
286
+ ),
287
+ /* @__PURE__ */ jsx(
288
+ "div",
289
+ {
290
+ style: {
291
+ ...commonStyle(),
292
+ top: -7 - o,
293
+ right: -7 - o,
294
+ cursor: rotation % 2 ? "nwse-resize" : "nesw-resize"
295
+ },
296
+ onPointerDown: startResize("top-right")
297
+ }
298
+ ),
299
+ /* @__PURE__ */ jsx(
300
+ "div",
301
+ {
302
+ style: {
303
+ ...commonStyle(),
304
+ bottom: -7 - o,
305
+ left: -7 - o,
306
+ cursor: rotation % 2 ? "nwse-resize" : "nesw-resize"
307
+ },
308
+ onPointerDown: startResize("bottom-left")
309
+ }
310
+ ),
311
+ /* @__PURE__ */ jsx(
312
+ "div",
313
+ {
314
+ style: {
315
+ ...commonStyle(),
316
+ bottom: -7 - o,
317
+ right: -7 - o,
318
+ cursor: rotation % 2 ? "nesw-resize" : "nwse-resize"
319
+ },
320
+ onPointerDown: startResize("bottom-right")
321
+ }
322
+ )
323
+ ] });
324
+ }
20
325
  function AnnotationContainer({
21
326
  scale,
22
327
  pageIndex,
23
328
  rotation,
329
+ pageWidth,
330
+ pageHeight,
24
331
  trackedAnnotation,
25
332
  children,
26
333
  style,
@@ -28,195 +335,120 @@ function AnnotationContainer({
28
335
  isSelected = false,
29
336
  isDraggable = true,
30
337
  isResizable = true,
31
- computeResizePatch,
338
+ computeVertices,
339
+ computePatch,
340
+ selectionMenu,
32
341
  ...props
33
342
  }) {
34
343
  const { provides: annotationProvides } = useAnnotationCapability();
35
- const ref = useRef(null);
36
- const [dragState, setDragState] = useState("idle");
37
- const [resizeDirection, setResizeDirection] = useState(null);
38
- const [startPos, setStartPos] = useState(null);
39
- const [startRect, setStartRect] = useState(null);
40
344
  const [currentRect, setCurrentRect] = useState(trackedAnnotation.object.rect);
345
+ const [currentVertices, setCurrentVertices] = useState(
346
+ (computeVertices == null ? void 0 : computeVertices(trackedAnnotation.object)) ?? []
347
+ );
41
348
  const [previewObject, setPreviewObject] = useState(null);
42
- useEffect(() => {
43
- setCurrentRect(trackedAnnotation.object.rect);
44
- setPreviewObject(null);
45
- }, [trackedAnnotation]);
46
- const handlePointerDown = (e) => {
47
- if (!isSelected) return;
48
- e.stopPropagation();
49
- e.preventDefault();
50
- const target = e.target;
51
- if (isResizable && target.classList.contains("resize-handle")) {
52
- setDragState("resizing");
53
- setResizeDirection(target.dataset.direction);
54
- } else if (isDraggable) {
55
- setDragState("dragging");
56
- } else {
57
- return;
58
- }
59
- setStartPos({ x: e.clientX, y: e.clientY });
60
- setStartRect(currentRect);
61
- ref.current?.setPointerCapture(e.pointerId);
62
- };
63
- const handlePointerMove = (e) => {
64
- if (dragState === "idle" || !startPos || !startRect) return;
65
- const dispDelta = { x: e.clientX - startPos.x, y: e.clientY - startPos.y };
66
- const { x: dx, y: dy } = restoreOffset(dispDelta, rotation, scale);
67
- let newOriginX = startRect.origin.x;
68
- let newOriginY = startRect.origin.y;
69
- let newWidth = startRect.size.width;
70
- let newHeight = startRect.size.height;
71
- if (dragState === "dragging") {
72
- newOriginX += dx;
73
- newOriginY += dy;
74
- } else if (dragState === "resizing" && resizeDirection) {
75
- if (resizeDirection.includes("right")) {
76
- newWidth += dx;
77
- } else if (resizeDirection.includes("left")) {
78
- newOriginX += dx;
79
- newWidth -= dx;
80
- }
81
- if (resizeDirection.includes("bottom")) {
82
- newHeight += dy;
83
- } else if (resizeDirection.includes("top")) {
84
- newOriginY += dy;
85
- newHeight -= dy;
86
- }
87
- if (newWidth < 1 || newHeight < 1) return;
88
- }
89
- const tentativeRect = {
90
- origin: { x: newOriginX, y: newOriginY },
91
- size: { width: newWidth, height: newHeight }
92
- };
93
- let previewPatch = { rect: tentativeRect };
94
- if (computeResizePatch) {
95
- const dir = dragState === "resizing" ? resizeDirection : "bottom-right";
96
- if (dir) {
97
- previewPatch = computeResizePatch(trackedAnnotation.object, tentativeRect, dir);
98
- }
99
- }
100
- setCurrentRect(previewPatch.rect || tentativeRect);
101
- setPreviewObject(previewPatch);
102
- };
103
- const handlePointerUp = (e) => {
104
- if (dragState === "idle") return;
105
- const usedDirection = resizeDirection || "bottom-right";
106
- setDragState("idle");
107
- setResizeDirection(null);
108
- ref.current?.releasePointerCapture(e.pointerId);
109
- if (annotationProvides && trackedAnnotation) {
110
- let patch = { rect: currentRect };
111
- if (computeResizePatch && usedDirection) {
112
- patch = computeResizePatch(trackedAnnotation.object, currentRect, usedDirection);
113
- }
114
- annotationProvides.updateAnnotation(pageIndex, trackedAnnotation.localId, patch);
349
+ const { rootHandlers, startResize } = useDragResize({
350
+ scale,
351
+ pageWidth,
352
+ pageHeight,
353
+ rotation,
354
+ tracked: trackedAnnotation,
355
+ isSelected,
356
+ isDraggable,
357
+ isResizable,
358
+ computePatch,
359
+ computeVertices,
360
+ currentRect,
361
+ setCurrentRect,
362
+ setCurrentVertices,
363
+ setPreviewObject,
364
+ commit: (patch) => annotationProvides == null ? void 0 : annotationProvides.updateAnnotation(pageIndex, trackedAnnotation.localId, patch)
365
+ });
366
+ useLayoutEffect(() => {
367
+ if (!rectEquals(trackedAnnotation.object.rect, currentRect)) {
368
+ setCurrentRect(trackedAnnotation.object.rect);
369
+ setPreviewObject((prev) => prev ? { ...prev, rect: trackedAnnotation.object.rect } : null);
370
+ setCurrentVertices((computeVertices == null ? void 0 : computeVertices(trackedAnnotation.object)) ?? []);
115
371
  }
116
- setStartPos(null);
117
- setStartRect(null);
118
- setPreviewObject(null);
119
- };
372
+ }, [trackedAnnotation]);
120
373
  const currentObject = previewObject ? { ...trackedAnnotation.object, ...previewObject } : trackedAnnotation.object;
121
- return /* @__PURE__ */ jsxs(
122
- "div",
123
- {
124
- ref,
125
- onPointerDown: handlePointerDown,
126
- onPointerMove: handlePointerMove,
127
- onPointerUp: handlePointerUp,
128
- style: {
129
- position: "absolute",
130
- outline: isSelected ? "1px solid #007ACC" : "none",
131
- outlineOffset: isSelected ? `${outlineOffset}px` : "0px",
132
- left: `${currentRect.origin.x * scale}px`,
133
- top: `${currentRect.origin.y * scale}px`,
134
- width: `${currentRect.size.width * scale}px`,
135
- height: `${currentRect.size.height * scale}px`,
136
- pointerEvents: isSelected ? "auto" : "none",
137
- cursor: isSelected && isDraggable ? "move" : "default",
138
- ...style
139
- },
140
- ...props,
141
- children: [
142
- typeof children === "function" ? children(currentObject) : children,
143
- isSelected && isResizable && /* @__PURE__ */ jsxs(Fragment, { children: [
144
- /* @__PURE__ */ jsx(
145
- "div",
146
- {
147
- className: "resize-handle",
148
- "data-direction": "top-left",
149
- style: {
150
- position: "absolute",
151
- top: -7 - outlineOffset,
152
- left: -7 - outlineOffset,
153
- width: 13,
154
- height: 13,
155
- background: "blue",
156
- borderRadius: "50%",
157
- cursor: rotation % 2 ? "nesw-resize" : "nwse-resize"
158
- }
159
- }
160
- ),
161
- /* @__PURE__ */ jsx(
162
- "div",
163
- {
164
- className: "resize-handle",
165
- "data-direction": "top-right",
166
- style: {
167
- position: "absolute",
168
- top: -7 - outlineOffset,
169
- right: -7 - outlineOffset,
170
- width: 13,
171
- height: 13,
172
- background: "blue",
173
- borderRadius: "50%",
174
- cursor: rotation % 2 ? "nwse-resize" : "nesw-resize"
175
- }
176
- }
177
- ),
178
- /* @__PURE__ */ jsx(
179
- "div",
374
+ return /* @__PURE__ */ jsxs(Fragment, { children: [
375
+ /* @__PURE__ */ jsxs(
376
+ "div",
377
+ {
378
+ ...rootHandlers,
379
+ style: {
380
+ position: "absolute",
381
+ outline: isSelected ? "1px solid #007ACC" : "none",
382
+ outlineOffset: isSelected ? `${outlineOffset}px` : "0px",
383
+ left: `${currentRect.origin.x * scale}px`,
384
+ top: `${currentRect.origin.y * scale}px`,
385
+ width: `${currentRect.size.width * scale}px`,
386
+ height: `${currentRect.size.height * scale}px`,
387
+ pointerEvents: isSelected ? "auto" : "none",
388
+ cursor: isSelected && isDraggable ? "move" : "default",
389
+ ...style
390
+ },
391
+ ...props,
392
+ children: [
393
+ typeof children === "function" ? children(currentObject) : children,
394
+ isSelected && currentVertices.length > 0 && /* @__PURE__ */ jsx(
395
+ VertexEditor,
180
396
  {
181
- className: "resize-handle",
182
- "data-direction": "bottom-left",
183
- style: {
184
- position: "absolute",
185
- bottom: -7 - outlineOffset,
186
- left: -7 - outlineOffset,
187
- width: 13,
188
- height: 13,
189
- background: "blue",
190
- borderRadius: "50%",
191
- cursor: rotation % 2 ? "nwse-resize" : "nesw-resize"
397
+ rect: currentRect,
398
+ rotation,
399
+ scale,
400
+ vertices: currentVertices,
401
+ onEdit: (v) => {
402
+ setCurrentVertices(v);
403
+ if (computePatch) {
404
+ const patch = computePatch(trackedAnnotation.object, {
405
+ rect: currentRect,
406
+ vertices: v
407
+ });
408
+ setPreviewObject(patch);
409
+ setCurrentRect(patch.rect || currentRect);
410
+ }
411
+ },
412
+ onCommit: (v) => {
413
+ if (annotationProvides && computePatch) {
414
+ const patch = computePatch(trackedAnnotation.object, {
415
+ rect: currentRect,
416
+ vertices: v
417
+ });
418
+ annotationProvides.updateAnnotation(pageIndex, trackedAnnotation.localId, patch);
419
+ }
192
420
  }
193
421
  }
194
422
  ),
195
- /* @__PURE__ */ jsx(
196
- "div",
423
+ isSelected && isResizable && /* @__PURE__ */ jsx(
424
+ ResizeHandles,
197
425
  {
198
- className: "resize-handle",
199
- "data-direction": "bottom-right",
200
- style: {
201
- position: "absolute",
202
- bottom: -7 - outlineOffset,
203
- right: -7 - outlineOffset,
204
- width: 13,
205
- height: 13,
206
- background: "blue",
207
- borderRadius: "50%",
208
- cursor: rotation % 2 ? "nesw-resize" : "nwse-resize"
209
- }
426
+ rotation,
427
+ outlineOffset,
428
+ startResize
210
429
  }
211
430
  )
212
- ] })
213
- ]
214
- }
215
- );
431
+ ]
432
+ }
433
+ ),
434
+ /* @__PURE__ */ jsx(
435
+ CounterRotate,
436
+ {
437
+ rect: {
438
+ origin: { x: currentRect.origin.x * scale, y: currentRect.origin.y * scale },
439
+ size: { width: currentRect.size.width * scale, height: currentRect.size.height * scale }
440
+ },
441
+ rotation,
442
+ children: ({ rect, menuWrapperProps }) => selectionMenu && selectionMenu({
443
+ annotation: trackedAnnotation,
444
+ selected: isSelected,
445
+ rect,
446
+ menuWrapperProps
447
+ })
448
+ }
449
+ )
450
+ ] });
216
451
  }
217
-
218
- // src/preact/components/text-markup/highlight.tsx
219
- import { Fragment as Fragment2, jsx as jsx2 } from "preact/jsx-runtime";
220
452
  function Highlight({
221
453
  color = "#FFFF00",
222
454
  opacity = 0.5,
@@ -227,7 +459,7 @@ function Highlight({
227
459
  style,
228
460
  ...props
229
461
  }) {
230
- return /* @__PURE__ */ jsx2(Fragment2, { children: rects.map((b, i) => /* @__PURE__ */ jsx2(
462
+ return /* @__PURE__ */ jsx(Fragment$1, { children: rects.map((b, i) => /* @__PURE__ */ jsx(
231
463
  "div",
232
464
  {
233
465
  onMouseDown: onClick,
@@ -241,7 +473,7 @@ function Highlight({
241
473
  opacity,
242
474
  pointerEvents: onClick ? "auto" : "none",
243
475
  cursor: onClick ? "pointer" : "default",
244
- zIndex: onClick ? 1 : null,
476
+ zIndex: onClick ? 1 : void 0,
245
477
  ...style
246
478
  },
247
479
  ...props
@@ -249,9 +481,6 @@ function Highlight({
249
481
  i
250
482
  )) });
251
483
  }
252
-
253
- // src/preact/components/text-markup/underline.tsx
254
- import { Fragment as Fragment3, jsx as jsx3 } from "preact/jsx-runtime";
255
484
  function Underline({
256
485
  color = "#FFFF00",
257
486
  opacity = 0.5,
@@ -263,7 +492,7 @@ function Underline({
263
492
  ...props
264
493
  }) {
265
494
  const thickness = 2 * scale;
266
- return /* @__PURE__ */ jsx3(Fragment3, { children: rects.map((r, i) => /* @__PURE__ */ jsx3(
495
+ return /* @__PURE__ */ jsx(Fragment$1, { children: rects.map((r, i) => /* @__PURE__ */ jsx(
267
496
  "div",
268
497
  {
269
498
  onMouseDown: onClick,
@@ -280,7 +509,7 @@ function Underline({
280
509
  ...style
281
510
  },
282
511
  ...props,
283
- children: /* @__PURE__ */ jsx3(
512
+ children: /* @__PURE__ */ jsx(
284
513
  "div",
285
514
  {
286
515
  style: {
@@ -299,9 +528,6 @@ function Underline({
299
528
  i
300
529
  )) });
301
530
  }
302
-
303
- // src/preact/components/text-markup/strikeout.tsx
304
- import { Fragment as Fragment4, jsx as jsx4 } from "preact/jsx-runtime";
305
531
  function Strikeout({
306
532
  color = "#FFFF00",
307
533
  opacity = 0.5,
@@ -313,7 +539,7 @@ function Strikeout({
313
539
  ...props
314
540
  }) {
315
541
  const thickness = 2 * scale;
316
- return /* @__PURE__ */ jsx4(Fragment4, { children: rects.map((r, i) => /* @__PURE__ */ jsx4(
542
+ return /* @__PURE__ */ jsx(Fragment$1, { children: rects.map((r, i) => /* @__PURE__ */ jsx(
317
543
  "div",
318
544
  {
319
545
  onMouseDown: onClick,
@@ -330,7 +556,7 @@ function Strikeout({
330
556
  ...style
331
557
  },
332
558
  ...props,
333
- children: /* @__PURE__ */ jsx4(
559
+ children: /* @__PURE__ */ jsx(
334
560
  "div",
335
561
  {
336
562
  style: {
@@ -350,9 +576,6 @@ function Strikeout({
350
576
  i
351
577
  )) });
352
578
  }
353
-
354
- // src/preact/components/text-markup/squiggly.tsx
355
- import { Fragment as Fragment5, jsx as jsx5 } from "preact/jsx-runtime";
356
579
  function Squiggly({
357
580
  color = "#FFFF00",
358
581
  opacity = 0.5,
@@ -370,7 +593,7 @@ function Squiggly({
370
593
  fill="none" stroke="${color}" stroke-width="${amplitude}" stroke-linecap="round"/>
371
594
  </svg>`;
372
595
  const svgDataUri = `url("data:image/svg+xml;utf8,${encodeURIComponent(svg)}")`;
373
- return /* @__PURE__ */ jsx5(Fragment5, { children: rects.map((r, i) => /* @__PURE__ */ jsx5(
596
+ return /* @__PURE__ */ jsx(Fragment$1, { children: rects.map((r, i) => /* @__PURE__ */ jsx(
374
597
  "div",
375
598
  {
376
599
  onMouseDown: onClick,
@@ -387,7 +610,7 @@ function Squiggly({
387
610
  ...style
388
611
  },
389
612
  ...props,
390
- children: /* @__PURE__ */ jsx5(
613
+ children: /* @__PURE__ */ jsx(
391
614
  "div",
392
615
  {
393
616
  style: {
@@ -408,10 +631,6 @@ function Squiggly({
408
631
  i
409
632
  )) });
410
633
  }
411
-
412
- // src/preact/components/annotations/ink.tsx
413
- import { useMemo } from "preact/hooks";
414
- import { jsx as jsx6 } from "preact/jsx-runtime";
415
634
  function Ink({
416
635
  color = "#000000",
417
636
  opacity = 1,
@@ -419,7 +638,8 @@ function Ink({
419
638
  inkList,
420
639
  rect,
421
640
  scale,
422
- onClick
641
+ onClick,
642
+ cursor
423
643
  }) {
424
644
  const paths = useMemo(() => {
425
645
  return inkList.map(({ points }) => {
@@ -434,7 +654,7 @@ function Ink({
434
654
  }, [inkList, rect]);
435
655
  const width = rect.size.width * scale;
436
656
  const height = rect.size.height * scale;
437
- return /* @__PURE__ */ jsx6(
657
+ return /* @__PURE__ */ jsx(
438
658
  "svg",
439
659
  {
440
660
  style: {
@@ -442,25 +662,26 @@ function Ink({
442
662
  width,
443
663
  height,
444
664
  pointerEvents: "none",
445
- zIndex: 2
665
+ zIndex: 2,
666
+ overflow: "visible"
446
667
  },
447
668
  width,
448
669
  height,
449
670
  viewBox: `0 0 ${rect.size.width} ${rect.size.height}`,
450
- children: paths.map((d, i) => /* @__PURE__ */ jsx6(
671
+ children: paths.map((d, i) => /* @__PURE__ */ jsx(
451
672
  "path",
452
673
  {
453
674
  d,
454
675
  fill: "none",
455
- stroke: color,
456
- strokeWidth,
457
- strokeLinecap: "round",
458
- strokeLinejoin: "round",
459
676
  opacity,
460
- pointerEvents: "visibleStroke",
461
677
  onMouseDown: onClick,
462
678
  style: {
463
- cursor: "pointer"
679
+ cursor,
680
+ pointerEvents: "visibleStroke",
681
+ stroke: color,
682
+ strokeWidth,
683
+ strokeLinecap: "round",
684
+ strokeLinejoin: "round"
464
685
  }
465
686
  },
466
687
  i
@@ -468,330 +689,967 @@ function Ink({
468
689
  }
469
690
  );
470
691
  }
471
-
472
- // src/preact/components/annotations.tsx
473
- import { useSelectionCapability } from "@embedpdf/plugin-selection/preact";
474
-
475
- // src/shared/resize-ink.ts
476
- import {
477
- PdfAnnotationSubtype
478
- } from "@embedpdf/models";
479
- function resizeInkAnnotation(original, newRect, direction, uniform = false) {
692
+ function Square({
693
+ color = "#000000",
694
+ strokeColor,
695
+ opacity = 1,
696
+ strokeWidth,
697
+ strokeStyle = PdfAnnotationBorderStyle.SOLID,
698
+ strokeDashArray,
699
+ rect,
700
+ scale,
701
+ onClick,
702
+ cursor
703
+ }) {
704
+ const { width, height, x, y } = useMemo(() => {
705
+ const outerW = rect.size.width;
706
+ const outerH = rect.size.height;
707
+ const innerW = Math.max(outerW - strokeWidth, 0);
708
+ const innerH = Math.max(outerH - strokeWidth, 0);
709
+ return {
710
+ width: innerW,
711
+ height: innerH,
712
+ x: strokeWidth / 2,
713
+ y: strokeWidth / 2
714
+ };
715
+ }, [rect, strokeWidth]);
716
+ const svgWidth = (width + strokeWidth) * scale;
717
+ const svgHeight = (height + strokeWidth) * scale;
718
+ return /* @__PURE__ */ jsx(
719
+ "svg",
720
+ {
721
+ style: {
722
+ position: "absolute",
723
+ width: svgWidth,
724
+ height: svgHeight,
725
+ pointerEvents: "none",
726
+ zIndex: 2
727
+ },
728
+ width: svgWidth,
729
+ height: svgHeight,
730
+ viewBox: `0 0 ${width + strokeWidth} ${height + strokeWidth}`,
731
+ children: /* @__PURE__ */ jsx(
732
+ "rect",
733
+ {
734
+ x,
735
+ y,
736
+ width,
737
+ height,
738
+ fill: color,
739
+ opacity,
740
+ onMouseDown: onClick,
741
+ style: {
742
+ cursor,
743
+ pointerEvents: color === "transparent" ? "visibleStroke" : "visible",
744
+ stroke: strokeColor ?? color,
745
+ strokeWidth,
746
+ ...strokeStyle === PdfAnnotationBorderStyle.DASHED && {
747
+ strokeDasharray: strokeDashArray == null ? void 0 : strokeDashArray.join(",")
748
+ }
749
+ }
750
+ }
751
+ )
752
+ }
753
+ );
754
+ }
755
+ function Circle({
756
+ color = "#000000",
757
+ strokeColor,
758
+ opacity = 1,
759
+ strokeWidth,
760
+ strokeStyle = PdfAnnotationBorderStyle.SOLID,
761
+ strokeDashArray,
762
+ rect,
763
+ scale,
764
+ onClick,
765
+ cursor
766
+ }) {
767
+ const { width, height, cx, cy, rx, ry } = useMemo(() => {
768
+ const outerW = rect.size.width;
769
+ const outerH = rect.size.height;
770
+ const innerW = Math.max(outerW - strokeWidth, 0);
771
+ const innerH = Math.max(outerH - strokeWidth, 0);
772
+ return {
773
+ width: outerW,
774
+ height: outerH,
775
+ // Centre of the fill sits strokeWidth/2 in from the edges
776
+ cx: strokeWidth / 2 + innerW / 2,
777
+ cy: strokeWidth / 2 + innerH / 2,
778
+ rx: innerW / 2,
779
+ ry: innerH / 2
780
+ };
781
+ }, [rect, strokeWidth]);
782
+ const svgWidth = width * scale;
783
+ const svgHeight = height * scale;
784
+ return /* @__PURE__ */ jsx(
785
+ "svg",
786
+ {
787
+ style: {
788
+ position: "absolute",
789
+ width: svgWidth,
790
+ height: svgHeight,
791
+ pointerEvents: "none",
792
+ zIndex: 2
793
+ },
794
+ width: svgWidth,
795
+ height: svgHeight,
796
+ viewBox: `0 0 ${width} ${height}`,
797
+ children: /* @__PURE__ */ jsx(
798
+ "ellipse",
799
+ {
800
+ cx,
801
+ cy,
802
+ rx,
803
+ ry,
804
+ fill: color,
805
+ opacity,
806
+ onMouseDown: onClick,
807
+ style: {
808
+ cursor,
809
+ pointerEvents: color === "transparent" ? "visibleStroke" : "visible",
810
+ stroke: strokeColor ?? color,
811
+ strokeWidth,
812
+ ...strokeStyle === PdfAnnotationBorderStyle.DASHED && {
813
+ strokeDasharray: strokeDashArray == null ? void 0 : strokeDashArray.join(",")
814
+ }
815
+ }
816
+ }
817
+ )
818
+ }
819
+ );
820
+ }
821
+ const patchInk = (original, ctx) => {
480
822
  if (original.type !== PdfAnnotationSubtype.INK) {
481
823
  throw new Error("resizeInkAnnotation: original is not an ink annotation");
482
824
  }
483
825
  const oldRect = original.rect;
484
- let scaleX = newRect.size.width / oldRect.size.width;
485
- let scaleY = newRect.size.height / oldRect.size.height;
826
+ let scaleX = ctx.rect.size.width / oldRect.size.width;
827
+ let scaleY = ctx.rect.size.height / oldRect.size.height;
486
828
  const minSize = 10;
487
- if (newRect.size.width < minSize || newRect.size.height < minSize) {
829
+ if (ctx.rect.size.width < minSize || ctx.rect.size.height < minSize) {
488
830
  scaleX = Math.max(scaleX, minSize / oldRect.size.width);
489
831
  scaleY = Math.max(scaleY, minSize / oldRect.size.height);
490
- newRect = {
491
- origin: newRect.origin,
832
+ ctx.rect = {
833
+ origin: ctx.rect.origin,
492
834
  size: {
493
835
  width: oldRect.size.width * scaleX,
494
836
  height: oldRect.size.height * scaleY
495
837
  }
496
838
  };
497
839
  }
498
- if (uniform) {
840
+ if (ctx.uniform) {
499
841
  const minScale = Math.min(scaleX, scaleY);
500
842
  scaleX = minScale;
501
843
  scaleY = minScale;
502
- newRect.size = {
844
+ ctx.rect.size = {
503
845
  width: oldRect.size.width * minScale,
504
846
  height: oldRect.size.height * minScale
505
847
  };
506
848
  }
507
849
  const newInkList = original.inkList.map((stroke) => ({
508
850
  points: stroke.points.map((p) => ({
509
- x: newRect.origin.x + (p.x - oldRect.origin.x) * scaleX,
510
- y: newRect.origin.y + (p.y - oldRect.origin.y) * scaleY
851
+ x: ctx.rect.origin.x + (p.x - oldRect.origin.x) * scaleX,
852
+ y: ctx.rect.origin.y + (p.y - oldRect.origin.y) * scaleY
511
853
  }))
512
854
  }));
513
855
  const avgScale = (scaleX + scaleY) / 2;
514
- const newStrokeWidth = original.strokeWidth * avgScale;
856
+ const newStrokeWidth = Math.round(original.strokeWidth * avgScale);
515
857
  return {
516
- rect: newRect,
858
+ rect: ctx.rect,
517
859
  inkList: newInkList,
518
860
  strokeWidth: newStrokeWidth
519
861
  };
520
- }
521
-
522
- // src/preact/components/annotations.tsx
523
- import { Fragment as Fragment6, jsx as jsx7 } from "preact/jsx-runtime";
524
- function Annotations(annotationsProps) {
525
- const { pageIndex, scale } = annotationsProps;
526
- const { provides: annotationProvides } = useAnnotationCapability();
527
- const { provides: selectionProvides } = useSelectionCapability();
528
- const [annotations, setAnnotations] = useState2([]);
529
- const { register } = usePointerHandlers({ pageIndex });
530
- const [selectionState, setSelectionState] = useState2(null);
531
- useEffect2(() => {
532
- if (annotationProvides) {
533
- annotationProvides.onStateChange((state) => {
534
- setAnnotations(getAnnotationsByPageIndex(state, pageIndex));
535
- setSelectionState(getSelectedAnnotationByPageIndex(state, pageIndex));
536
- });
537
- }
538
- }, [annotationProvides]);
539
- const handlers = useMemo2(
540
- () => ({
541
- onPointerDown: (_, pe) => {
542
- if (pe.target === pe.currentTarget && annotationProvides) {
543
- annotationProvides.deselectAnnotation();
544
- }
545
- }
546
- }),
547
- [annotationProvides]
548
- );
549
- const handleClick = useCallback(
550
- (e, annotation) => {
551
- e.stopPropagation();
552
- if (annotationProvides && selectionProvides) {
553
- annotationProvides.selectAnnotation(pageIndex, annotation.localId);
554
- selectionProvides.clear();
555
- }
556
- },
557
- [annotationProvides, selectionProvides, pageIndex]
558
- );
559
- useEffect2(() => {
560
- return register(handlers);
561
- }, [register, handlers]);
562
- return /* @__PURE__ */ jsx7(Fragment6, { children: annotations.map((annotation) => {
563
- const isSelected = selectionState?.localId === annotation.localId;
564
- switch (annotation.object.type) {
565
- case PdfAnnotationSubtype2.UNDERLINE:
566
- return /* @__PURE__ */ jsx7(
567
- AnnotationContainer,
568
- {
569
- trackedAnnotation: annotation,
570
- isSelected,
571
- isDraggable: false,
572
- isResizable: false,
573
- style: { mixBlendMode: "multiply" },
574
- ...annotationsProps,
575
- children: /* @__PURE__ */ jsx7(
576
- Underline,
577
- {
578
- rect: annotation.object.rect,
579
- color: annotation.object.color,
580
- opacity: annotation.object.opacity,
581
- rects: annotation.object.segmentRects,
582
- scale,
583
- onClick: (e) => handleClick(e, annotation)
584
- }
585
- )
586
- },
587
- annotation.localId
588
- );
589
- case PdfAnnotationSubtype2.STRIKEOUT:
590
- return /* @__PURE__ */ jsx7(
591
- AnnotationContainer,
592
- {
593
- trackedAnnotation: annotation,
594
- isSelected,
595
- isDraggable: false,
596
- isResizable: false,
597
- style: { mixBlendMode: "multiply" },
598
- ...annotationsProps,
599
- children: /* @__PURE__ */ jsx7(
600
- Strikeout,
601
- {
602
- rect: annotation.object.rect,
603
- color: annotation.object.color,
604
- opacity: annotation.object.opacity,
605
- rects: annotation.object.segmentRects,
606
- scale,
607
- onClick: (e) => handleClick(e, annotation)
608
- }
609
- )
610
- },
611
- annotation.localId
612
- );
613
- case PdfAnnotationSubtype2.SQUIGGLY:
614
- return /* @__PURE__ */ jsx7(
615
- AnnotationContainer,
862
+ };
863
+ function Line({
864
+ color = "transparent",
865
+ opacity = 1,
866
+ strokeWidth,
867
+ strokeColor = "#000000",
868
+ strokeStyle = PdfAnnotationBorderStyle.SOLID,
869
+ strokeDashArray,
870
+ rect,
871
+ linePoints,
872
+ lineEndings,
873
+ scale,
874
+ onClick,
875
+ isSelected
876
+ }) {
877
+ const { x1, y1, x2, y2 } = useMemo(() => {
878
+ return {
879
+ x1: linePoints.start.x - rect.origin.x,
880
+ y1: linePoints.start.y - rect.origin.y,
881
+ x2: linePoints.end.x - rect.origin.x,
882
+ y2: linePoints.end.y - rect.origin.y
883
+ };
884
+ }, [linePoints, rect]);
885
+ const endings = useMemo(() => {
886
+ const angle = Math.atan2(y2 - y1, x2 - x1);
887
+ return {
888
+ start: patching.createEnding(lineEndings == null ? void 0 : lineEndings.start, strokeWidth, angle + Math.PI, x1, y1),
889
+ end: patching.createEnding(lineEndings == null ? void 0 : lineEndings.end, strokeWidth, angle, x2, y2)
890
+ };
891
+ }, [lineEndings, strokeWidth, x1, y1, x2, y2]);
892
+ const width = rect.size.width * scale;
893
+ const height = rect.size.height * scale;
894
+ return /* @__PURE__ */ jsxs(
895
+ "svg",
896
+ {
897
+ style: {
898
+ position: "absolute",
899
+ width,
900
+ height,
901
+ pointerEvents: "none",
902
+ zIndex: 2,
903
+ overflow: "visible"
904
+ },
905
+ width,
906
+ height,
907
+ viewBox: `0 0 ${rect.size.width} ${rect.size.height}`,
908
+ children: [
909
+ /* @__PURE__ */ jsx(
910
+ "line",
616
911
  {
617
- trackedAnnotation: annotation,
618
- isSelected,
619
- isDraggable: false,
620
- isResizable: false,
621
- style: { mixBlendMode: "multiply" },
622
- ...annotationsProps,
623
- children: /* @__PURE__ */ jsx7(
624
- Squiggly,
625
- {
626
- color: annotation.object.color,
627
- opacity: annotation.object.opacity,
628
- rects: annotation.object.segmentRects,
629
- rect: annotation.object.rect,
630
- scale,
631
- onClick: (e) => handleClick(e, annotation)
912
+ x1,
913
+ y1,
914
+ x2,
915
+ y2,
916
+ opacity,
917
+ onMouseDown: onClick,
918
+ style: {
919
+ cursor: isSelected ? "move" : "pointer",
920
+ pointerEvents: "visibleStroke",
921
+ stroke: strokeColor,
922
+ strokeWidth,
923
+ strokeLinecap: "butt",
924
+ ...strokeStyle === PdfAnnotationBorderStyle.DASHED && {
925
+ strokeDasharray: strokeDashArray == null ? void 0 : strokeDashArray.join(",")
632
926
  }
633
- )
634
- },
635
- annotation.localId
636
- );
637
- case PdfAnnotationSubtype2.HIGHLIGHT:
638
- return /* @__PURE__ */ jsx7(
639
- AnnotationContainer,
927
+ }
928
+ }
929
+ ),
930
+ endings.start && /* @__PURE__ */ jsx(
931
+ "path",
640
932
  {
641
- trackedAnnotation: annotation,
642
- isSelected,
643
- isDraggable: false,
644
- isResizable: false,
645
- style: { mixBlendMode: "multiply" },
646
- ...annotationsProps,
647
- children: /* @__PURE__ */ jsx7(
648
- Highlight,
649
- {
650
- color: annotation.object.color,
651
- opacity: annotation.object.opacity,
652
- rects: annotation.object.segmentRects,
653
- scale,
654
- rect: annotation.object.rect,
655
- onClick: (e) => handleClick(e, annotation)
933
+ d: endings.start.d,
934
+ transform: endings.start.transform,
935
+ onMouseDown: onClick,
936
+ stroke: strokeColor,
937
+ style: {
938
+ cursor: isSelected ? "move" : "pointer",
939
+ strokeWidth,
940
+ strokeLinecap: "butt",
941
+ pointerEvents: endings.start.filled ? "visible" : "visibleStroke",
942
+ ...strokeStyle === PdfAnnotationBorderStyle.DASHED && {
943
+ strokeDasharray: strokeDashArray == null ? void 0 : strokeDashArray.join(",")
656
944
  }
657
- )
658
- },
659
- annotation.localId
660
- );
661
- case PdfAnnotationSubtype2.INK:
662
- return /* @__PURE__ */ jsx7(
663
- AnnotationContainer,
945
+ },
946
+ fill: endings.start.filled ? color : "none"
947
+ }
948
+ ),
949
+ endings.end && /* @__PURE__ */ jsx(
950
+ "path",
664
951
  {
665
- isSelected,
666
- trackedAnnotation: annotation,
667
- outlineOffset: 6,
668
- computeResizePatch: resizeInkAnnotation,
669
- ...annotationsProps,
670
- children: (obj) => /* @__PURE__ */ jsx7(
671
- Ink,
672
- {
673
- color: obj.color,
674
- opacity: obj.opacity,
675
- strokeWidth: obj.strokeWidth,
676
- inkList: obj.inkList,
677
- rect: obj.rect,
678
- scale,
679
- onClick: (e) => handleClick(e, annotation)
952
+ d: endings.end.d,
953
+ transform: endings.end.transform,
954
+ stroke: strokeColor,
955
+ onMouseDown: onClick,
956
+ style: {
957
+ cursor: isSelected ? "move" : "pointer",
958
+ strokeWidth,
959
+ strokeLinecap: "butt",
960
+ pointerEvents: endings.end.filled ? "visible" : "visibleStroke",
961
+ ...strokeStyle === PdfAnnotationBorderStyle.DASHED && {
962
+ strokeDasharray: strokeDashArray == null ? void 0 : strokeDashArray.join(",")
680
963
  }
681
- )
682
- },
683
- annotation.localId
684
- );
685
- default:
686
- return null;
964
+ },
965
+ fill: endings.end.filled ? color : "none"
966
+ }
967
+ )
968
+ ]
687
969
  }
688
- }) });
970
+ );
689
971
  }
690
-
691
- // src/preact/components/text-markup.tsx
692
- import { PdfAnnotationSubtype as PdfAnnotationSubtype3 } from "@embedpdf/models";
693
- import { useSelectionCapability as useSelectionCapability2 } from "@embedpdf/plugin-selection/preact";
694
- import { useEffect as useEffect3, useState as useState3 } from "preact/hooks";
695
- import { jsx as jsx8 } from "preact/jsx-runtime";
696
- function TextMarkup({ pageIndex, scale }) {
697
- const { provides: selectionProvides } = useSelectionCapability2();
698
- const { provides: annotationProvides } = useAnnotationCapability();
699
- const [rects, setRects] = useState3([]);
700
- const [boundingRect, setBoundingRect] = useState3(null);
701
- const [activeTool, setActiveTool] = useState3({ mode: null, defaults: null });
702
- useEffect3(() => {
703
- if (!selectionProvides) return;
704
- const off = selectionProvides.onSelectionChange(() => {
705
- setRects(selectionProvides.getHighlightRectsForPage(pageIndex));
706
- setBoundingRect(selectionProvides.getBoundingRectForPage(pageIndex));
707
- });
708
- return off;
709
- }, [selectionProvides, pageIndex]);
710
- useEffect3(() => {
711
- if (!annotationProvides) return;
712
- const off = annotationProvides.onActiveToolChange(setActiveTool);
713
- return off;
714
- }, [annotationProvides]);
715
- if (!boundingRect) return null;
716
- switch (activeTool.mode) {
717
- case PdfAnnotationSubtype3.UNDERLINE:
718
- return /* @__PURE__ */ jsx8(
719
- "div",
972
+ function Polyline({
973
+ rect,
974
+ vertices,
975
+ color = "transparent",
976
+ strokeColor = "#000000",
977
+ opacity = 1,
978
+ strokeWidth,
979
+ scale,
980
+ isSelected,
981
+ onClick,
982
+ lineEndings
983
+ }) {
984
+ const localPts = useMemo(
985
+ () => vertices.map(({ x, y }) => ({ x: x - rect.origin.x, y: y - rect.origin.y })),
986
+ [vertices, rect]
987
+ );
988
+ const pathData = useMemo(() => {
989
+ if (!localPts.length) return "";
990
+ const [first, ...rest] = localPts;
991
+ return `M ${first.x} ${first.y} ` + rest.map((p) => `L ${p.x} ${p.y} `).join("").trim();
992
+ }, [localPts]);
993
+ const endings = useMemo(() => {
994
+ if (localPts.length < 2) return { start: null, end: null };
995
+ const toAngle = (a, b) => Math.atan2(b.y - a.y, b.x - a.x);
996
+ const startRad = toAngle(localPts[1], localPts[0]);
997
+ const endRad = toAngle(localPts[localPts.length - 2], localPts[localPts.length - 1]);
998
+ const start = patching.createEnding(
999
+ lineEndings == null ? void 0 : lineEndings.start,
1000
+ strokeWidth,
1001
+ startRad + Math.PI,
1002
+ // tip points outward from first segment start
1003
+ localPts[0].x,
1004
+ localPts[0].y
1005
+ );
1006
+ const end = patching.createEnding(
1007
+ lineEndings == null ? void 0 : lineEndings.end,
1008
+ strokeWidth,
1009
+ endRad,
1010
+ localPts[localPts.length - 1].x,
1011
+ localPts[localPts.length - 1].y
1012
+ );
1013
+ return { start, end };
1014
+ }, [localPts, lineEndings, strokeWidth]);
1015
+ const width = rect.size.width * scale;
1016
+ const height = rect.size.height * scale;
1017
+ return /* @__PURE__ */ jsxs(
1018
+ "svg",
1019
+ {
1020
+ style: {
1021
+ position: "absolute",
1022
+ width,
1023
+ height,
1024
+ pointerEvents: "none",
1025
+ zIndex: 2,
1026
+ overflow: "visible"
1027
+ },
1028
+ width,
1029
+ height,
1030
+ viewBox: `0 0 ${rect.size.width} ${rect.size.height}`,
1031
+ children: [
1032
+ /* @__PURE__ */ jsx(
1033
+ "path",
1034
+ {
1035
+ d: pathData,
1036
+ onMouseDown: onClick,
1037
+ opacity,
1038
+ style: {
1039
+ fill: "none",
1040
+ stroke: strokeColor ?? color,
1041
+ strokeWidth,
1042
+ cursor: isSelected ? "move" : "pointer",
1043
+ pointerEvents: "visibleStroke",
1044
+ strokeLinecap: "butt",
1045
+ strokeLinejoin: "miter"
1046
+ }
1047
+ }
1048
+ ),
1049
+ endings.start && /* @__PURE__ */ jsx(
1050
+ "path",
1051
+ {
1052
+ d: endings.start.d,
1053
+ transform: endings.start.transform,
1054
+ stroke: strokeColor,
1055
+ fill: endings.start.filled ? color : "none",
1056
+ onMouseDown: onClick,
1057
+ style: {
1058
+ cursor: isSelected ? "move" : "pointer",
1059
+ strokeWidth,
1060
+ pointerEvents: endings.start.filled ? "visible" : "visibleStroke",
1061
+ strokeLinecap: "butt"
1062
+ }
1063
+ }
1064
+ ),
1065
+ endings.end && /* @__PURE__ */ jsx(
1066
+ "path",
1067
+ {
1068
+ d: endings.end.d,
1069
+ transform: endings.end.transform,
1070
+ stroke: strokeColor,
1071
+ fill: endings.end.filled ? color : "none",
1072
+ onMouseDown: onClick,
1073
+ style: {
1074
+ cursor: isSelected ? "move" : "pointer",
1075
+ strokeWidth,
1076
+ pointerEvents: endings.end.filled ? "visible" : "visibleStroke",
1077
+ strokeLinecap: "butt"
1078
+ }
1079
+ }
1080
+ )
1081
+ ]
1082
+ }
1083
+ );
1084
+ }
1085
+ function Polygon({
1086
+ rect,
1087
+ vertices,
1088
+ color = "transparent",
1089
+ strokeColor = "#000000",
1090
+ opacity = 1,
1091
+ strokeWidth,
1092
+ strokeStyle = PdfAnnotationBorderStyle.SOLID,
1093
+ strokeDashArray,
1094
+ scale,
1095
+ isSelected,
1096
+ onClick
1097
+ }) {
1098
+ const localPts = useMemo(
1099
+ () => vertices.map(({ x, y }) => ({ x: x - rect.origin.x, y: y - rect.origin.y })),
1100
+ [vertices, rect]
1101
+ );
1102
+ const pathData = useMemo(() => {
1103
+ if (!localPts.length) return "";
1104
+ const [first, ...rest] = localPts;
1105
+ return (`M ${first.x} ${first.y} ` + rest.map((p) => `L ${p.x} ${p.y} `).join("") + "Z").trim();
1106
+ }, [localPts]);
1107
+ const width = rect.size.width * scale;
1108
+ const height = rect.size.height * scale;
1109
+ return /* @__PURE__ */ jsx(
1110
+ "svg",
1111
+ {
1112
+ style: {
1113
+ position: "absolute",
1114
+ width,
1115
+ height,
1116
+ pointerEvents: "none",
1117
+ zIndex: 2,
1118
+ overflow: "visible"
1119
+ },
1120
+ width,
1121
+ height,
1122
+ viewBox: `0 0 ${rect.size.width} ${rect.size.height}`,
1123
+ children: /* @__PURE__ */ jsx(
1124
+ "path",
1125
+ {
1126
+ d: pathData,
1127
+ onMouseDown: onClick,
1128
+ opacity,
1129
+ style: {
1130
+ fill: color,
1131
+ stroke: strokeColor ?? color,
1132
+ strokeWidth,
1133
+ cursor: isSelected ? "move" : "pointer",
1134
+ pointerEvents: color === "transparent" ? "visibleStroke" : "visible",
1135
+ strokeLinecap: "butt",
1136
+ strokeLinejoin: "miter",
1137
+ ...strokeStyle === PdfAnnotationBorderStyle.DASHED && {
1138
+ strokeDasharray: strokeDashArray == null ? void 0 : strokeDashArray.join(",")
1139
+ }
1140
+ }
1141
+ }
1142
+ )
1143
+ }
1144
+ );
1145
+ }
1146
+ const patchLine = (orig, ctx) => {
1147
+ if (ctx.vertices && ctx.vertices.length >= 2) {
1148
+ const rect = patching.lineRectWithEndings(ctx.vertices, orig.strokeWidth, orig.lineEndings);
1149
+ return {
1150
+ rect,
1151
+ linePoints: { start: ctx.vertices[0], end: ctx.vertices[1] }
1152
+ };
1153
+ }
1154
+ const dx = ctx.rect.origin.x - orig.rect.origin.x;
1155
+ const dy = ctx.rect.origin.y - orig.rect.origin.y;
1156
+ return {
1157
+ rect: ctx.rect,
1158
+ linePoints: {
1159
+ start: { x: orig.linePoints.start.x + dx, y: orig.linePoints.start.y + dy },
1160
+ end: { x: orig.linePoints.end.x + dx, y: orig.linePoints.end.y + dy }
1161
+ }
1162
+ };
1163
+ };
1164
+ const patchPolyline = (orig, ctx) => {
1165
+ if (ctx.vertices && ctx.vertices.length) {
1166
+ return {
1167
+ rect: patching.lineRectWithEndings(ctx.vertices, orig.strokeWidth, orig.lineEndings),
1168
+ vertices: ctx.vertices
1169
+ };
1170
+ }
1171
+ const dx = ctx.rect.origin.x - orig.rect.origin.x;
1172
+ const dy = ctx.rect.origin.y - orig.rect.origin.y;
1173
+ const moved = orig.vertices.map((p) => ({ x: p.x + dx, y: p.y + dy }));
1174
+ return {
1175
+ rect: ctx.rect,
1176
+ vertices: moved
1177
+ };
1178
+ };
1179
+ const patchPolygon = (orig, ctx) => {
1180
+ if (ctx.vertices && ctx.vertices.length) {
1181
+ const pad = orig.strokeWidth / 2;
1182
+ return {
1183
+ rect: expandRect(rectFromPoints(ctx.vertices), pad),
1184
+ vertices: ctx.vertices
1185
+ };
1186
+ }
1187
+ const dx = ctx.rect.origin.x - orig.rect.origin.x;
1188
+ const dy = ctx.rect.origin.y - orig.rect.origin.y;
1189
+ const moved = orig.vertices.map((p) => ({ x: p.x + dx, y: p.y + dy }));
1190
+ return {
1191
+ rect: ctx.rect,
1192
+ vertices: moved
1193
+ };
1194
+ };
1195
+ function Annotations(annotationsProps) {
1196
+ const { pageIndex, scale, selectionMenu } = annotationsProps;
1197
+ const { provides: annotationProvides } = useAnnotationCapability();
1198
+ const { provides: selectionProvides } = useSelectionCapability();
1199
+ const [annotations, setAnnotations] = useState([]);
1200
+ const { register } = usePointerHandlers({ pageIndex });
1201
+ const [selectionState, setSelectionState] = useState(null);
1202
+ useEffect(() => {
1203
+ if (annotationProvides) {
1204
+ annotationProvides.onStateChange((state) => {
1205
+ setAnnotations(getAnnotationsByPageIndex(state, pageIndex));
1206
+ setSelectionState(getSelectedAnnotationByPageIndex(state, pageIndex));
1207
+ });
1208
+ }
1209
+ }, [annotationProvides]);
1210
+ const handlers = useMemo(
1211
+ () => ({
1212
+ onPointerDown: (_, pe) => {
1213
+ if (pe.target === pe.currentTarget && annotationProvides) {
1214
+ annotationProvides.deselectAnnotation();
1215
+ }
1216
+ }
1217
+ }),
1218
+ [annotationProvides]
1219
+ );
1220
+ const handleClick = useCallback(
1221
+ (e, annotation) => {
1222
+ e.stopPropagation();
1223
+ if (annotationProvides && selectionProvides) {
1224
+ annotationProvides.selectAnnotation(pageIndex, annotation.localId);
1225
+ selectionProvides.clear();
1226
+ }
1227
+ },
1228
+ [annotationProvides, selectionProvides, pageIndex]
1229
+ );
1230
+ useEffect(() => {
1231
+ return register(handlers);
1232
+ }, [register, handlers]);
1233
+ return /* @__PURE__ */ jsx(Fragment$1, { children: annotations.map((annotation) => {
1234
+ const isSelected = (selectionState == null ? void 0 : selectionState.localId) === annotation.localId;
1235
+ if (isInk(annotation)) {
1236
+ return /* @__PURE__ */ jsx(
1237
+ AnnotationContainer,
1238
+ {
1239
+ trackedAnnotation: annotation,
1240
+ isSelected,
1241
+ isDraggable: true,
1242
+ isResizable: true,
1243
+ selectionMenu,
1244
+ computePatch: patchInk,
1245
+ style: {
1246
+ mixBlendMode: blendModeToCss(annotation.object.blendMode ?? PdfBlendMode.Normal)
1247
+ },
1248
+ ...annotationsProps,
1249
+ children: (obj) => /* @__PURE__ */ jsx(
1250
+ Ink,
1251
+ {
1252
+ cursor: isSelected ? "move" : "pointer",
1253
+ color: obj.color,
1254
+ opacity: obj.opacity,
1255
+ strokeWidth: obj.strokeWidth,
1256
+ inkList: obj.inkList,
1257
+ rect: obj.rect,
1258
+ scale,
1259
+ onClick: (e) => handleClick(e, annotation)
1260
+ }
1261
+ )
1262
+ },
1263
+ annotation.localId
1264
+ );
1265
+ }
1266
+ if (isSquare(annotation)) {
1267
+ return /* @__PURE__ */ jsx(
1268
+ AnnotationContainer,
1269
+ {
1270
+ trackedAnnotation: annotation,
1271
+ isSelected,
1272
+ isDraggable: true,
1273
+ isResizable: true,
1274
+ selectionMenu,
1275
+ style: {
1276
+ mixBlendMode: blendModeToCss(annotation.object.blendMode ?? PdfBlendMode.Normal)
1277
+ },
1278
+ ...annotationsProps,
1279
+ children: (obj) => /* @__PURE__ */ jsx(
1280
+ Square,
1281
+ {
1282
+ cursor: isSelected ? "move" : "pointer",
1283
+ rect: obj.rect,
1284
+ color: obj.color,
1285
+ opacity: obj.opacity,
1286
+ strokeWidth: obj.strokeWidth,
1287
+ strokeColor: obj.strokeColor,
1288
+ strokeStyle: obj.strokeStyle,
1289
+ strokeDashArray: obj.strokeDashArray,
1290
+ scale,
1291
+ onClick: (e) => handleClick(e, annotation)
1292
+ }
1293
+ )
1294
+ },
1295
+ annotation.localId
1296
+ );
1297
+ }
1298
+ if (isCircle(annotation)) {
1299
+ return /* @__PURE__ */ jsx(
1300
+ AnnotationContainer,
1301
+ {
1302
+ trackedAnnotation: annotation,
1303
+ isSelected,
1304
+ isDraggable: true,
1305
+ isResizable: true,
1306
+ selectionMenu,
1307
+ style: {
1308
+ mixBlendMode: blendModeToCss(annotation.object.blendMode ?? PdfBlendMode.Normal)
1309
+ },
1310
+ ...annotationsProps,
1311
+ children: (obj) => /* @__PURE__ */ jsx(
1312
+ Circle,
1313
+ {
1314
+ cursor: isSelected ? "move" : "pointer",
1315
+ rect: obj.rect,
1316
+ color: obj.color,
1317
+ opacity: obj.opacity,
1318
+ strokeWidth: obj.strokeWidth,
1319
+ strokeColor: obj.strokeColor,
1320
+ strokeStyle: obj.strokeStyle,
1321
+ strokeDashArray: obj.strokeDashArray,
1322
+ scale,
1323
+ onClick: (e) => handleClick(e, annotation)
1324
+ }
1325
+ )
1326
+ },
1327
+ annotation.localId
1328
+ );
1329
+ }
1330
+ if (isUnderline(annotation)) {
1331
+ return /* @__PURE__ */ jsx(
1332
+ AnnotationContainer,
1333
+ {
1334
+ trackedAnnotation: annotation,
1335
+ isSelected,
1336
+ isDraggable: false,
1337
+ isResizable: false,
1338
+ selectionMenu,
1339
+ style: {
1340
+ mixBlendMode: blendModeToCss(annotation.object.blendMode ?? PdfBlendMode.Normal)
1341
+ },
1342
+ ...annotationsProps,
1343
+ children: (obj) => /* @__PURE__ */ jsx(
1344
+ Underline,
1345
+ {
1346
+ rect: obj.rect,
1347
+ color: obj.color,
1348
+ opacity: obj.opacity,
1349
+ rects: obj.segmentRects,
1350
+ scale,
1351
+ onClick: (e) => handleClick(e, annotation)
1352
+ }
1353
+ )
1354
+ },
1355
+ annotation.localId
1356
+ );
1357
+ }
1358
+ if (isStrikeout(annotation)) {
1359
+ return /* @__PURE__ */ jsx(
1360
+ AnnotationContainer,
1361
+ {
1362
+ trackedAnnotation: annotation,
1363
+ isSelected,
1364
+ isDraggable: false,
1365
+ isResizable: false,
1366
+ selectionMenu,
1367
+ style: {
1368
+ mixBlendMode: blendModeToCss(annotation.object.blendMode ?? PdfBlendMode.Normal)
1369
+ },
1370
+ ...annotationsProps,
1371
+ children: (obj) => /* @__PURE__ */ jsx(
1372
+ Strikeout,
1373
+ {
1374
+ rect: obj.rect,
1375
+ color: obj.color,
1376
+ opacity: obj.opacity,
1377
+ rects: obj.segmentRects,
1378
+ scale,
1379
+ onClick: (e) => handleClick(e, annotation)
1380
+ }
1381
+ )
1382
+ },
1383
+ annotation.localId
1384
+ );
1385
+ }
1386
+ if (isSquiggly(annotation)) {
1387
+ return /* @__PURE__ */ jsx(
1388
+ AnnotationContainer,
1389
+ {
1390
+ trackedAnnotation: annotation,
1391
+ isSelected,
1392
+ isDraggable: false,
1393
+ isResizable: false,
1394
+ selectionMenu,
1395
+ style: {
1396
+ mixBlendMode: blendModeToCss(annotation.object.blendMode ?? PdfBlendMode.Normal)
1397
+ },
1398
+ ...annotationsProps,
1399
+ children: (obj) => /* @__PURE__ */ jsx(
1400
+ Squiggly,
1401
+ {
1402
+ color: obj.color,
1403
+ opacity: obj.opacity,
1404
+ rects: obj.segmentRects,
1405
+ rect: obj.rect,
1406
+ scale,
1407
+ onClick: (e) => handleClick(e, annotation)
1408
+ }
1409
+ )
1410
+ },
1411
+ annotation.localId
1412
+ );
1413
+ }
1414
+ if (isHighlight(annotation)) {
1415
+ return /* @__PURE__ */ jsx(
1416
+ AnnotationContainer,
1417
+ {
1418
+ trackedAnnotation: annotation,
1419
+ isSelected,
1420
+ isDraggable: false,
1421
+ isResizable: false,
1422
+ selectionMenu,
1423
+ style: {
1424
+ mixBlendMode: blendModeToCss(annotation.object.blendMode ?? PdfBlendMode.Multiply)
1425
+ },
1426
+ ...annotationsProps,
1427
+ children: (obj) => /* @__PURE__ */ jsx(
1428
+ Highlight,
1429
+ {
1430
+ color: obj.color,
1431
+ opacity: obj.opacity,
1432
+ rects: obj.segmentRects,
1433
+ scale,
1434
+ rect: obj.rect,
1435
+ onClick: (e) => handleClick(e, annotation)
1436
+ }
1437
+ )
1438
+ },
1439
+ annotation.localId
1440
+ );
1441
+ }
1442
+ if (isLine(annotation)) {
1443
+ return /* @__PURE__ */ jsx(
1444
+ AnnotationContainer,
1445
+ {
1446
+ trackedAnnotation: annotation,
1447
+ isSelected,
1448
+ isDraggable: true,
1449
+ isResizable: false,
1450
+ selectionMenu,
1451
+ computePatch: patchLine,
1452
+ computeVertices: (annotation2) => [
1453
+ annotation2.linePoints.start,
1454
+ annotation2.linePoints.end
1455
+ ],
1456
+ style: {
1457
+ mixBlendMode: blendModeToCss(annotation.object.blendMode ?? PdfBlendMode.Normal)
1458
+ },
1459
+ ...annotationsProps,
1460
+ children: (obj) => /* @__PURE__ */ jsx(Fragment, { children: /* @__PURE__ */ jsx(
1461
+ Line,
1462
+ {
1463
+ isSelected,
1464
+ rect: obj.rect,
1465
+ color: obj.color,
1466
+ opacity: obj.opacity,
1467
+ linePoints: obj.linePoints,
1468
+ lineEndings: obj.lineEndings,
1469
+ strokeWidth: obj.strokeWidth,
1470
+ strokeColor: obj.strokeColor,
1471
+ strokeStyle: obj.strokeStyle,
1472
+ strokeDashArray: obj.strokeDashArray,
1473
+ scale,
1474
+ onClick: (e) => handleClick(e, annotation)
1475
+ }
1476
+ ) })
1477
+ },
1478
+ annotation.localId
1479
+ );
1480
+ }
1481
+ if (isPolyline(annotation)) {
1482
+ return /* @__PURE__ */ jsx(
1483
+ AnnotationContainer,
1484
+ {
1485
+ trackedAnnotation: annotation,
1486
+ isSelected,
1487
+ isDraggable: true,
1488
+ isResizable: false,
1489
+ selectionMenu,
1490
+ computePatch: patchPolyline,
1491
+ computeVertices: (annotation2) => annotation2.vertices,
1492
+ style: {
1493
+ mixBlendMode: blendModeToCss(annotation.object.blendMode ?? PdfBlendMode.Normal)
1494
+ },
1495
+ ...annotationsProps,
1496
+ children: (obj) => /* @__PURE__ */ jsx(Fragment, { children: /* @__PURE__ */ jsx(
1497
+ Polyline,
1498
+ {
1499
+ isSelected,
1500
+ rect: obj.rect,
1501
+ color: obj.color,
1502
+ opacity: obj.opacity,
1503
+ vertices: obj.vertices,
1504
+ lineEndings: obj.lineEndings,
1505
+ strokeWidth: obj.strokeWidth,
1506
+ strokeColor: obj.strokeColor,
1507
+ scale,
1508
+ onClick: (e) => handleClick(e, annotation)
1509
+ }
1510
+ ) })
1511
+ },
1512
+ annotation.localId
1513
+ );
1514
+ }
1515
+ if (isPolygon(annotation)) {
1516
+ return /* @__PURE__ */ jsx(
1517
+ AnnotationContainer,
1518
+ {
1519
+ trackedAnnotation: annotation,
1520
+ isSelected,
1521
+ isDraggable: true,
1522
+ isResizable: false,
1523
+ selectionMenu,
1524
+ computeVertices: (annotation2) => annotation2.vertices,
1525
+ computePatch: patchPolygon,
1526
+ style: {
1527
+ mixBlendMode: blendModeToCss(annotation.object.blendMode ?? PdfBlendMode.Normal)
1528
+ },
1529
+ ...annotationsProps,
1530
+ children: (obj) => /* @__PURE__ */ jsx(Fragment, { children: /* @__PURE__ */ jsx(
1531
+ Polygon,
1532
+ {
1533
+ isSelected,
1534
+ rect: obj.rect,
1535
+ color: obj.color,
1536
+ opacity: obj.opacity,
1537
+ vertices: obj.vertices,
1538
+ strokeWidth: obj.strokeWidth,
1539
+ strokeColor: obj.strokeColor,
1540
+ strokeStyle: obj.strokeStyle,
1541
+ strokeDashArray: obj.strokeDashArray,
1542
+ scale,
1543
+ onClick: (e) => handleClick(e, annotation)
1544
+ }
1545
+ ) })
1546
+ },
1547
+ annotation.localId
1548
+ );
1549
+ }
1550
+ return null;
1551
+ }) });
1552
+ }
1553
+ function TextMarkup({ pageIndex, scale }) {
1554
+ var _a, _b, _c, _d, _e, _f, _g, _h, _i, _j, _k, _l;
1555
+ const { provides: selectionProvides } = useSelectionCapability();
1556
+ const { provides: annotationProvides } = useAnnotationCapability();
1557
+ const [rects, setRects] = useState([]);
1558
+ const [boundingRect, setBoundingRect] = useState(null);
1559
+ const [activeTool, setActiveTool] = useState({ variantKey: null, defaults: null });
1560
+ useEffect(() => {
1561
+ if (!selectionProvides) return;
1562
+ const off = selectionProvides.onSelectionChange(() => {
1563
+ setRects(selectionProvides.getHighlightRectsForPage(pageIndex));
1564
+ setBoundingRect(selectionProvides.getBoundingRectForPage(pageIndex));
1565
+ });
1566
+ return off;
1567
+ }, [selectionProvides, pageIndex]);
1568
+ useEffect(() => {
1569
+ if (!annotationProvides) return;
1570
+ const off = annotationProvides.onActiveToolChange(setActiveTool);
1571
+ return off;
1572
+ }, [annotationProvides]);
1573
+ if (!boundingRect) return null;
1574
+ switch (activeTool.variantKey) {
1575
+ case makeVariantKey(PdfAnnotationSubtype.UNDERLINE):
1576
+ return /* @__PURE__ */ jsx(
1577
+ "div",
720
1578
  {
721
1579
  style: {
722
- mixBlendMode: "multiply",
1580
+ mixBlendMode: blendModeToCss(((_a = activeTool.defaults) == null ? void 0 : _a.blendMode) ?? PdfBlendMode.Normal),
723
1581
  pointerEvents: "none",
724
1582
  position: "absolute",
725
1583
  inset: 0
726
1584
  },
727
- children: /* @__PURE__ */ jsx8(
1585
+ children: /* @__PURE__ */ jsx(
728
1586
  Underline,
729
1587
  {
730
- color: activeTool.defaults?.color,
731
- opacity: activeTool.defaults?.opacity,
1588
+ color: (_b = activeTool.defaults) == null ? void 0 : _b.color,
1589
+ opacity: (_c = activeTool.defaults) == null ? void 0 : _c.opacity,
732
1590
  rects,
733
1591
  scale
734
1592
  }
735
1593
  )
736
1594
  }
737
1595
  );
738
- case PdfAnnotationSubtype3.HIGHLIGHT:
739
- return /* @__PURE__ */ jsx8(
1596
+ case makeVariantKey(PdfAnnotationSubtype.HIGHLIGHT):
1597
+ return /* @__PURE__ */ jsx(
740
1598
  "div",
741
1599
  {
742
1600
  style: {
743
- mixBlendMode: "multiply",
1601
+ mixBlendMode: blendModeToCss(((_d = activeTool.defaults) == null ? void 0 : _d.blendMode) ?? PdfBlendMode.Multiply),
744
1602
  pointerEvents: "none",
745
1603
  position: "absolute",
746
1604
  inset: 0
747
1605
  },
748
- children: /* @__PURE__ */ jsx8(
1606
+ children: /* @__PURE__ */ jsx(
749
1607
  Highlight,
750
1608
  {
751
- color: activeTool.defaults?.color,
752
- opacity: activeTool.defaults?.opacity,
1609
+ color: (_e = activeTool.defaults) == null ? void 0 : _e.color,
1610
+ opacity: (_f = activeTool.defaults) == null ? void 0 : _f.opacity,
753
1611
  rects,
754
1612
  scale
755
1613
  }
756
1614
  )
757
1615
  }
758
1616
  );
759
- case PdfAnnotationSubtype3.STRIKEOUT:
760
- return /* @__PURE__ */ jsx8(
1617
+ case makeVariantKey(PdfAnnotationSubtype.STRIKEOUT):
1618
+ return /* @__PURE__ */ jsx(
761
1619
  "div",
762
1620
  {
763
1621
  style: {
764
- mixBlendMode: "multiply",
1622
+ mixBlendMode: blendModeToCss(((_g = activeTool.defaults) == null ? void 0 : _g.blendMode) ?? PdfBlendMode.Normal),
765
1623
  pointerEvents: "none",
766
1624
  position: "absolute",
767
1625
  inset: 0
768
1626
  },
769
- children: /* @__PURE__ */ jsx8(
1627
+ children: /* @__PURE__ */ jsx(
770
1628
  Strikeout,
771
1629
  {
772
- color: activeTool.defaults?.color,
773
- opacity: activeTool.defaults?.opacity,
1630
+ color: (_h = activeTool.defaults) == null ? void 0 : _h.color,
1631
+ opacity: (_i = activeTool.defaults) == null ? void 0 : _i.opacity,
774
1632
  rects,
775
1633
  scale
776
1634
  }
777
1635
  )
778
1636
  }
779
1637
  );
780
- case PdfAnnotationSubtype3.SQUIGGLY:
781
- return /* @__PURE__ */ jsx8(
1638
+ case makeVariantKey(PdfAnnotationSubtype.SQUIGGLY):
1639
+ return /* @__PURE__ */ jsx(
782
1640
  "div",
783
1641
  {
784
1642
  style: {
785
- mixBlendMode: "multiply",
1643
+ mixBlendMode: blendModeToCss(((_j = activeTool.defaults) == null ? void 0 : _j.blendMode) ?? PdfBlendMode.Normal),
786
1644
  pointerEvents: "none",
787
1645
  position: "absolute",
788
1646
  inset: 0
789
1647
  },
790
- children: /* @__PURE__ */ jsx8(
1648
+ children: /* @__PURE__ */ jsx(
791
1649
  Squiggly,
792
1650
  {
793
- color: activeTool.defaults?.color,
794
- opacity: activeTool.defaults?.opacity,
1651
+ color: (_k = activeTool.defaults) == null ? void 0 : _k.color,
1652
+ opacity: (_l = activeTool.defaults) == null ? void 0 : _l.opacity,
795
1653
  rects,
796
1654
  scale
797
1655
  }
@@ -802,35 +1660,33 @@ function TextMarkup({ pageIndex, scale }) {
802
1660
  return null;
803
1661
  }
804
1662
  }
805
-
806
- // src/preact/components/annotations/ink-paint.tsx
807
- import { useEffect as useEffect4, useMemo as useMemo3, useRef as useRef2, useState as useState4 } from "preact/hooks";
808
- import { usePointerHandlers as usePointerHandlers2 } from "@embedpdf/plugin-interaction-manager/preact";
809
- import { PdfAnnotationSubtype as PdfAnnotationSubtype4 } from "@embedpdf/models";
810
- import { jsx as jsx9 } from "preact/jsx-runtime";
811
- var MAX_STROKE_WIDTH = 30;
812
- var InkPaint = ({ pageIndex, scale, pageWidth, pageHeight }) => {
1663
+ const InkPaint = ({ pageIndex, scale, pageWidth, pageHeight }) => {
1664
+ var _a, _b, _c, _d, _e;
813
1665
  const { provides: annotationProvides } = useAnnotationCapability();
814
- const [activeTool, setActiveTool] = useState4({ mode: null, defaults: null });
815
- useEffect4(() => {
1666
+ const [activeTool, setActiveTool] = useState({ variantKey: null, defaults: null });
1667
+ useEffect(() => {
816
1668
  if (!annotationProvides) return;
817
1669
  const off = annotationProvides.onActiveToolChange(setActiveTool);
818
1670
  return off;
819
1671
  }, [annotationProvides]);
820
- if (activeTool.mode !== PdfAnnotationSubtype4.INK) return null;
821
- const toolColor = activeTool.defaults?.color ?? "#000000";
822
- const toolOpacity = activeTool.defaults?.opacity ?? 1;
823
- const toolStrokeWidth = activeTool.defaults?.strokeWidth ?? 2;
824
- const { register } = usePointerHandlers2({ modeId: "ink", pageIndex });
1672
+ if (!activeTool.defaults) return null;
1673
+ if (activeTool.defaults.subtype !== PdfAnnotationSubtype.INK) return null;
1674
+ const toolColor = ((_a = activeTool.defaults) == null ? void 0 : _a.color) ?? "#000000";
1675
+ const toolOpacity = ((_b = activeTool.defaults) == null ? void 0 : _b.opacity) ?? 1;
1676
+ const toolStrokeWidth = ((_c = activeTool.defaults) == null ? void 0 : _c.strokeWidth) ?? 2;
1677
+ const toolBlendMode = ((_d = activeTool.defaults) == null ? void 0 : _d.blendMode) ?? PdfBlendMode.Normal;
1678
+ const intent = (_e = activeTool.defaults) == null ? void 0 : _e.intent;
1679
+ const { register } = usePointerHandlers({ modeId: "ink", pageIndex });
825
1680
  const clamp = (v, min, max) => Math.max(min, Math.min(max, v));
826
- const [currentStrokes, setCurrentStrokes] = useState4([]);
827
- const [isDrawing, setIsDrawing] = useState4(false);
828
- const timerRef = useRef2(null);
1681
+ const [currentStrokes, setCurrentStrokes] = useState([]);
1682
+ const [isDrawing, setIsDrawing] = useState(false);
1683
+ const timerRef = useRef(null);
829
1684
  const pageWidthPDF = pageWidth / scale;
830
1685
  const pageHeightPDF = pageHeight / scale;
831
- const handlers = useMemo3(
1686
+ const handlers = useMemo(
832
1687
  () => ({
833
1688
  onPointerDown: (pos, evt) => {
1689
+ var _a2, _b2;
834
1690
  const curX = clamp(pos.x, 0, pageWidthPDF);
835
1691
  const curY = clamp(pos.y, 0, pageHeightPDF);
836
1692
  setIsDrawing(true);
@@ -841,7 +1697,7 @@ var InkPaint = ({ pageIndex, scale, pageWidth, pageHeight }) => {
841
1697
  } else {
842
1698
  setCurrentStrokes([{ points: [{ x: curX, y: curY }] }]);
843
1699
  }
844
- evt.target?.setPointerCapture?.(evt.pointerId);
1700
+ (_b2 = (_a2 = evt.target) == null ? void 0 : _a2.setPointerCapture) == null ? void 0 : _b2.call(_a2, evt.pointerId);
845
1701
  },
846
1702
  onPointerMove: (pos) => {
847
1703
  if (!isDrawing) return;
@@ -855,30 +1711,21 @@ var InkPaint = ({ pageIndex, scale, pageWidth, pageHeight }) => {
855
1711
  });
856
1712
  },
857
1713
  onPointerUp: (_, evt) => {
1714
+ var _a2, _b2;
858
1715
  setIsDrawing(false);
859
- evt.target?.releasePointerCapture?.(evt.pointerId);
1716
+ (_b2 = (_a2 = evt.target) == null ? void 0 : _a2.releasePointerCapture) == null ? void 0 : _b2.call(_a2, evt.pointerId);
860
1717
  if (timerRef.current) clearTimeout(timerRef.current);
861
1718
  timerRef.current = setTimeout(() => {
862
1719
  if (currentStrokes.length && annotationProvides) {
863
1720
  const allPoints2 = currentStrokes.flatMap((s) => s.points);
864
1721
  if (!allPoints2.length) return;
865
- const minX2 = Math.min(...allPoints2.map((p) => p.x));
866
- const minY2 = Math.min(...allPoints2.map((p) => p.y));
867
- const maxX2 = Math.max(...allPoints2.map((p) => p.x));
868
- const maxY2 = Math.max(...allPoints2.map((p) => p.y));
869
- const halfStroke2 = MAX_STROKE_WIDTH / 2;
870
- const rectMinX = minX2 - halfStroke2;
871
- const rectMinY = minY2 - halfStroke2;
872
- const rectMaxX = maxX2 + halfStroke2;
873
- const rectMaxY = maxY2 + halfStroke2;
874
- if (rectMaxX - rectMinX < 1 || rectMaxY - rectMinY < 1) return;
875
- const rect = {
876
- origin: { x: rectMinX, y: rectMinY },
877
- size: { width: rectMaxX - rectMinX, height: rectMaxY - rectMinY }
878
- };
1722
+ const rect2 = expandRect(rectFromPoints(allPoints2), toolStrokeWidth / 2);
1723
+ if (rect2.size.width < 1 || rect2.size.height < 1) return;
879
1724
  const anno = {
880
- type: PdfAnnotationSubtype4.INK,
881
- rect,
1725
+ type: PdfAnnotationSubtype.INK,
1726
+ intent,
1727
+ blendMode: toolBlendMode,
1728
+ rect: rect2,
882
1729
  inkList: currentStrokes,
883
1730
  color: toolColor,
884
1731
  opacity: toolOpacity,
@@ -887,7 +1734,7 @@ var InkPaint = ({ pageIndex, scale, pageWidth, pageHeight }) => {
887
1734
  id: Date.now() + Math.random()
888
1735
  };
889
1736
  annotationProvides.createAnnotation(pageIndex, anno);
890
- annotationProvides.setAnnotationMode(null);
1737
+ annotationProvides.setActiveVariant(null);
891
1738
  annotationProvides.selectAnnotation(pageIndex, anno.id);
892
1739
  }
893
1740
  setCurrentStrokes([]);
@@ -895,8 +1742,9 @@ var InkPaint = ({ pageIndex, scale, pageWidth, pageHeight }) => {
895
1742
  }, 3e3);
896
1743
  },
897
1744
  onPointerCancel: (_, evt) => {
1745
+ var _a2, _b2;
898
1746
  setIsDrawing(false);
899
- evt.target?.releasePointerCapture?.(evt.pointerId);
1747
+ (_b2 = (_a2 = evt.target) == null ? void 0 : _a2.releasePointerCapture) == null ? void 0 : _b2.call(_a2, evt.pointerId);
900
1748
  setCurrentStrokes([]);
901
1749
  if (timerRef.current) {
902
1750
  clearTimeout(timerRef.current);
@@ -916,11 +1764,11 @@ var InkPaint = ({ pageIndex, scale, pageWidth, pageHeight }) => {
916
1764
  isDrawing
917
1765
  ]
918
1766
  );
919
- useEffect4(() => {
1767
+ useEffect(() => {
920
1768
  if (!register) return;
921
1769
  return register(handlers);
922
1770
  }, [register, handlers]);
923
- useEffect4(() => {
1771
+ useEffect(() => {
924
1772
  return () => {
925
1773
  if (timerRef.current) clearTimeout(timerRef.current);
926
1774
  };
@@ -928,80 +1776,843 @@ var InkPaint = ({ pageIndex, scale, pageWidth, pageHeight }) => {
928
1776
  if (!currentStrokes.length) return null;
929
1777
  const allPoints = currentStrokes.flatMap((s) => s.points);
930
1778
  if (!allPoints.length) return null;
931
- const minX = Math.min(...allPoints.map((p) => p.x));
932
- const minY = Math.min(...allPoints.map((p) => p.y));
933
- const maxX = Math.max(...allPoints.map((p) => p.x));
934
- const maxY = Math.max(...allPoints.map((p) => p.y));
935
- const halfStroke = MAX_STROKE_WIDTH / 2;
936
- const svgMinX = minX - halfStroke;
937
- const svgMinY = minY - halfStroke;
938
- const svgMaxX = maxX + halfStroke;
939
- const svgMaxY = maxY + halfStroke;
940
- const dw = svgMaxX - svgMinX;
941
- const dh = svgMaxY - svgMinY;
1779
+ const rect = expandRect(rectFromPoints(allPoints), toolStrokeWidth / 2);
942
1780
  const paths = currentStrokes.map(({ points }) => {
943
1781
  let d = "";
944
1782
  points.forEach(({ x, y }, i) => {
945
- const lx = x - svgMinX;
946
- const ly = y - svgMinY;
1783
+ const lx = x - rect.origin.x;
1784
+ const ly = y - rect.origin.y;
947
1785
  d += (i === 0 ? "M" : "L") + lx + " " + ly + " ";
948
1786
  });
949
1787
  return d.trim();
950
1788
  });
951
- return /* @__PURE__ */ jsx9(
1789
+ return /* @__PURE__ */ jsx(
952
1790
  "svg",
953
1791
  {
954
1792
  style: {
955
1793
  position: "absolute",
956
- left: svgMinX * scale,
957
- top: svgMinY * scale,
958
- width: dw * scale,
959
- height: dh * scale,
1794
+ left: rect.origin.x * scale,
1795
+ top: rect.origin.y * scale,
1796
+ width: rect.size.width * scale,
1797
+ height: rect.size.height * scale,
960
1798
  pointerEvents: "none",
961
1799
  zIndex: 2
962
1800
  },
963
- width: dw * scale,
964
- height: dh * scale,
965
- viewBox: `0 0 ${dw} ${dh}`,
966
- children: paths.map((d, i) => /* @__PURE__ */ jsx9(
1801
+ width: rect.size.width * scale,
1802
+ height: rect.size.height * scale,
1803
+ viewBox: `0 0 ${rect.size.width} ${rect.size.height}`,
1804
+ children: paths.map((d, i) => /* @__PURE__ */ jsx(
967
1805
  "path",
968
1806
  {
969
1807
  d,
970
1808
  fill: "none",
971
- stroke: toolColor,
972
- strokeWidth: toolStrokeWidth,
973
- strokeLinecap: "round",
974
- strokeLinejoin: "round",
975
- opacity: toolOpacity
1809
+ opacity: toolOpacity,
1810
+ style: {
1811
+ stroke: toolColor,
1812
+ strokeWidth: toolStrokeWidth,
1813
+ strokeLinecap: "round",
1814
+ strokeLinejoin: "round"
1815
+ }
976
1816
  },
977
1817
  i
978
1818
  ))
979
1819
  }
980
1820
  );
981
1821
  };
982
-
983
- // src/preact/components/annotation-layer.tsx
984
- import { jsx as jsx10, jsxs as jsxs2 } from "preact/jsx-runtime";
985
- function AnnotationLayer({
1822
+ const CirclePaint = ({
986
1823
  pageIndex,
987
1824
  scale,
988
1825
  pageWidth,
989
1826
  pageHeight,
990
- rotation,
991
- style,
992
- ...props
993
- }) {
994
- return /* @__PURE__ */ jsxs2(
995
- "div",
1827
+ cursor
1828
+ }) => {
1829
+ const { provides: annotationProvides } = useAnnotationCapability();
1830
+ const [activeTool, setActiveTool] = useState({ variantKey: null, defaults: null });
1831
+ useEffect(() => {
1832
+ if (!annotationProvides) return;
1833
+ return annotationProvides.onActiveToolChange(setActiveTool);
1834
+ }, [annotationProvides]);
1835
+ if (!activeTool.defaults) return null;
1836
+ if (activeTool.defaults.subtype !== PdfAnnotationSubtype.CIRCLE) return null;
1837
+ const toolColor = activeTool.defaults.color ?? "#000000";
1838
+ const toolOpacity = activeTool.defaults.opacity ?? 1;
1839
+ const toolStrokeWidth = activeTool.defaults.strokeWidth ?? 2;
1840
+ const toolStrokeColor = activeTool.defaults.strokeColor ?? "#000000";
1841
+ const toolStrokeStyle = activeTool.defaults.strokeStyle ?? PdfAnnotationBorderStyle.SOLID;
1842
+ const toolStrokeDashArray = activeTool.defaults.strokeDashArray ?? [];
1843
+ const { register } = usePointerHandlers({ modeId: "circle", pageIndex });
1844
+ const clamp = (v, min, max) => Math.max(min, Math.min(max, v));
1845
+ const pageWidthPDF = pageWidth / scale;
1846
+ const pageHeightPDF = pageHeight / scale;
1847
+ const [start, setStart] = useState(null);
1848
+ const [current, setCurrent] = useState(null);
1849
+ const handlers = useMemo(
1850
+ () => ({
1851
+ onPointerDown: (pos, evt) => {
1852
+ var _a, _b;
1853
+ const x = clamp(pos.x, 0, pageWidthPDF);
1854
+ const y = clamp(pos.y, 0, pageHeightPDF);
1855
+ setStart({ x, y });
1856
+ setCurrent({ x, y });
1857
+ (_b = (_a = evt.target) == null ? void 0 : _a.setPointerCapture) == null ? void 0 : _b.call(_a, evt.pointerId);
1858
+ },
1859
+ onPointerMove: (pos) => {
1860
+ if (!start) return;
1861
+ const x = clamp(pos.x, 0, pageWidthPDF);
1862
+ const y = clamp(pos.y, 0, pageHeightPDF);
1863
+ setCurrent({ x, y });
1864
+ },
1865
+ onPointerUp: (_, evt) => {
1866
+ var _a, _b;
1867
+ if (start && current && annotationProvides) {
1868
+ const minX2 = Math.min(start.x, current.x);
1869
+ const minY2 = Math.min(start.y, current.y);
1870
+ const maxX2 = Math.max(start.x, current.x);
1871
+ const maxY2 = Math.max(start.y, current.y);
1872
+ if (maxX2 - minX2 >= 1 && maxY2 - minY2 >= 1) {
1873
+ const halfStroke2 = toolStrokeWidth / 2;
1874
+ const rect = {
1875
+ origin: { x: minX2 - halfStroke2, y: minY2 - halfStroke2 },
1876
+ size: {
1877
+ width: maxX2 - minX2 + toolStrokeWidth,
1878
+ height: maxY2 - minY2 + toolStrokeWidth
1879
+ }
1880
+ };
1881
+ const anno = {
1882
+ type: PdfAnnotationSubtype.CIRCLE,
1883
+ rect,
1884
+ flags: ["print"],
1885
+ color: toolColor,
1886
+ opacity: toolOpacity,
1887
+ strokeWidth: toolStrokeWidth,
1888
+ strokeColor: toolStrokeColor,
1889
+ strokeStyle: toolStrokeStyle,
1890
+ strokeDashArray: toolStrokeDashArray,
1891
+ pageIndex,
1892
+ id: Date.now() + Math.random()
1893
+ };
1894
+ annotationProvides.createAnnotation(pageIndex, anno);
1895
+ annotationProvides.setActiveVariant(null);
1896
+ annotationProvides.selectAnnotation(pageIndex, anno.id);
1897
+ }
1898
+ }
1899
+ (_b = (_a = evt.target) == null ? void 0 : _a.releasePointerCapture) == null ? void 0 : _b.call(_a, evt.pointerId);
1900
+ setStart(null);
1901
+ setCurrent(null);
1902
+ },
1903
+ onPointerCancel: (_, evt) => {
1904
+ var _a, _b;
1905
+ (_b = (_a = evt.target) == null ? void 0 : _a.releasePointerCapture) == null ? void 0 : _b.call(_a, evt.pointerId);
1906
+ setStart(null);
1907
+ setCurrent(null);
1908
+ }
1909
+ }),
1910
+ [
1911
+ start,
1912
+ current,
1913
+ annotationProvides,
1914
+ pageIndex,
1915
+ pageWidthPDF,
1916
+ pageHeightPDF,
1917
+ toolColor,
1918
+ toolOpacity,
1919
+ toolStrokeWidth
1920
+ ]
1921
+ );
1922
+ useEffect(() => register ? register(handlers) : void 0, [register, handlers]);
1923
+ if (!start || !current) return null;
1924
+ const minX = Math.min(start.x, current.x);
1925
+ const minY = Math.min(start.y, current.y);
1926
+ const maxX = Math.max(start.x, current.x);
1927
+ const maxY = Math.max(start.y, current.y);
1928
+ const halfStroke = toolStrokeWidth / 2;
1929
+ const svgMinX = minX - halfStroke;
1930
+ const svgMinY = minY - halfStroke;
1931
+ const width = maxX - minX;
1932
+ const height = maxY - minY;
1933
+ const dw = width + toolStrokeWidth;
1934
+ const dh = height + toolStrokeWidth;
1935
+ const cx = halfStroke + width / 2;
1936
+ const cy = halfStroke + height / 2;
1937
+ const rx = width / 2;
1938
+ const ry = height / 2;
1939
+ return /* @__PURE__ */ jsx(
1940
+ "svg",
1941
+ {
1942
+ style: {
1943
+ position: "absolute",
1944
+ left: svgMinX * scale,
1945
+ top: svgMinY * scale,
1946
+ width: dw * scale,
1947
+ height: dh * scale,
1948
+ pointerEvents: "none",
1949
+ zIndex: 2
1950
+ },
1951
+ width: dw * scale,
1952
+ height: dh * scale,
1953
+ viewBox: `0 0 ${dw} ${dh}`,
1954
+ children: /* @__PURE__ */ jsx(
1955
+ "ellipse",
1956
+ {
1957
+ cx,
1958
+ cy,
1959
+ rx,
1960
+ ry,
1961
+ fill: toolColor,
1962
+ opacity: toolOpacity,
1963
+ style: {
1964
+ cursor,
1965
+ stroke: toolStrokeColor,
1966
+ strokeWidth: toolStrokeWidth,
1967
+ ...toolStrokeStyle === PdfAnnotationBorderStyle.DASHED && {
1968
+ strokeDasharray: toolStrokeDashArray.join(",")
1969
+ }
1970
+ }
1971
+ }
1972
+ )
1973
+ }
1974
+ );
1975
+ };
1976
+ const SquarePaint = ({
1977
+ pageIndex,
1978
+ scale,
1979
+ pageWidth,
1980
+ pageHeight,
1981
+ cursor
1982
+ }) => {
1983
+ const { provides: annotationProvides } = useAnnotationCapability();
1984
+ const [activeTool, setActiveTool] = useState({ variantKey: null, defaults: null });
1985
+ useEffect(() => {
1986
+ if (!annotationProvides) return;
1987
+ return annotationProvides.onActiveToolChange(setActiveTool);
1988
+ }, [annotationProvides]);
1989
+ if (!activeTool.defaults) return null;
1990
+ if (activeTool.defaults.subtype !== PdfAnnotationSubtype.SQUARE) return null;
1991
+ const toolColor = activeTool.defaults.color ?? "#000000";
1992
+ const toolOpacity = activeTool.defaults.opacity ?? 1;
1993
+ const toolStrokeWidth = activeTool.defaults.strokeWidth ?? 2;
1994
+ const toolStrokeColor = activeTool.defaults.strokeColor ?? "#000000";
1995
+ const toolStrokeStyle = activeTool.defaults.strokeStyle ?? PdfAnnotationBorderStyle.SOLID;
1996
+ const toolStrokeDashArray = activeTool.defaults.strokeDashArray ?? [];
1997
+ const { register } = usePointerHandlers({ modeId: "square", pageIndex });
1998
+ const clamp = (v, min, max) => Math.max(min, Math.min(max, v));
1999
+ const pageWidthPDF = pageWidth / scale;
2000
+ const pageHeightPDF = pageHeight / scale;
2001
+ const [start, setStart] = useState(null);
2002
+ const [current, setCurrent] = useState(null);
2003
+ const handlers = useMemo(
2004
+ () => ({
2005
+ onPointerDown: (pos, evt) => {
2006
+ var _a, _b;
2007
+ const x = clamp(pos.x, 0, pageWidthPDF);
2008
+ const y = clamp(pos.y, 0, pageHeightPDF);
2009
+ setStart({ x, y });
2010
+ setCurrent({ x, y });
2011
+ (_b = (_a = evt.target) == null ? void 0 : _a.setPointerCapture) == null ? void 0 : _b.call(_a, evt.pointerId);
2012
+ },
2013
+ onPointerMove: (pos) => {
2014
+ if (!start) return;
2015
+ const x = clamp(pos.x, 0, pageWidthPDF);
2016
+ const y = clamp(pos.y, 0, pageHeightPDF);
2017
+ setCurrent({ x, y });
2018
+ },
2019
+ onPointerUp: (_, evt) => {
2020
+ var _a, _b;
2021
+ if (start && current && annotationProvides) {
2022
+ const minX2 = Math.min(start.x, current.x);
2023
+ const minY2 = Math.min(start.y, current.y);
2024
+ const maxX2 = Math.max(start.x, current.x);
2025
+ const maxY2 = Math.max(start.y, current.y);
2026
+ if (maxX2 - minX2 >= 1 && maxY2 - minY2 >= 1) {
2027
+ const halfStroke2 = toolStrokeWidth / 2;
2028
+ const rect = {
2029
+ origin: { x: minX2 - halfStroke2, y: minY2 - halfStroke2 },
2030
+ size: {
2031
+ width: maxX2 - minX2 + toolStrokeWidth,
2032
+ height: maxY2 - minY2 + toolStrokeWidth
2033
+ }
2034
+ };
2035
+ const anno = {
2036
+ type: PdfAnnotationSubtype.SQUARE,
2037
+ rect,
2038
+ flags: ["print"],
2039
+ color: toolColor,
2040
+ opacity: toolOpacity,
2041
+ strokeWidth: toolStrokeWidth,
2042
+ strokeColor: toolStrokeColor,
2043
+ strokeStyle: toolStrokeStyle,
2044
+ strokeDashArray: toolStrokeDashArray,
2045
+ pageIndex,
2046
+ id: Date.now() + Math.random()
2047
+ };
2048
+ annotationProvides.createAnnotation(pageIndex, anno);
2049
+ annotationProvides.setActiveVariant(null);
2050
+ annotationProvides.selectAnnotation(pageIndex, anno.id);
2051
+ }
2052
+ }
2053
+ (_b = (_a = evt.target) == null ? void 0 : _a.releasePointerCapture) == null ? void 0 : _b.call(_a, evt.pointerId);
2054
+ setStart(null);
2055
+ setCurrent(null);
2056
+ },
2057
+ onPointerCancel: (_, evt) => {
2058
+ var _a, _b;
2059
+ (_b = (_a = evt.target) == null ? void 0 : _a.releasePointerCapture) == null ? void 0 : _b.call(_a, evt.pointerId);
2060
+ setStart(null);
2061
+ setCurrent(null);
2062
+ }
2063
+ }),
2064
+ [
2065
+ start,
2066
+ current,
2067
+ annotationProvides,
2068
+ pageIndex,
2069
+ pageWidthPDF,
2070
+ pageHeightPDF,
2071
+ toolColor,
2072
+ toolOpacity,
2073
+ toolStrokeWidth
2074
+ ]
2075
+ );
2076
+ useEffect(() => register ? register(handlers) : void 0, [register, handlers]);
2077
+ if (!start || !current) return null;
2078
+ const minX = Math.min(start.x, current.x);
2079
+ const minY = Math.min(start.y, current.y);
2080
+ const maxX = Math.max(start.x, current.x);
2081
+ const maxY = Math.max(start.y, current.y);
2082
+ const halfStroke = toolStrokeWidth / 2;
2083
+ const svgMinX = minX - halfStroke;
2084
+ const svgMinY = minY - halfStroke;
2085
+ const width = maxX - minX;
2086
+ const height = maxY - minY;
2087
+ const dw = width + toolStrokeWidth;
2088
+ const dh = height + toolStrokeWidth;
2089
+ return /* @__PURE__ */ jsx(
2090
+ "svg",
2091
+ {
2092
+ style: {
2093
+ position: "absolute",
2094
+ left: svgMinX * scale,
2095
+ top: svgMinY * scale,
2096
+ width: dw * scale,
2097
+ height: dh * scale,
2098
+ pointerEvents: "none",
2099
+ zIndex: 2
2100
+ },
2101
+ width: dw * scale,
2102
+ height: dh * scale,
2103
+ viewBox: `0 0 ${dw} ${dh}`,
2104
+ children: /* @__PURE__ */ jsx(
2105
+ "rect",
2106
+ {
2107
+ x: halfStroke,
2108
+ y: halfStroke,
2109
+ width,
2110
+ height,
2111
+ fill: toolColor,
2112
+ opacity: toolOpacity,
2113
+ style: {
2114
+ cursor,
2115
+ stroke: toolStrokeColor,
2116
+ strokeWidth: toolStrokeWidth,
2117
+ ...toolStrokeStyle === PdfAnnotationBorderStyle.DASHED && {
2118
+ strokeDasharray: toolStrokeDashArray.join(",")
2119
+ }
2120
+ }
2121
+ }
2122
+ )
2123
+ }
2124
+ );
2125
+ };
2126
+ const PolylinePaint = ({
2127
+ pageIndex,
2128
+ scale,
2129
+ pageWidth,
2130
+ pageHeight,
2131
+ cursor
2132
+ }) => {
2133
+ const { provides: annotationProvides } = useAnnotationCapability();
2134
+ const [activeTool, setActiveTool] = useState({ variantKey: null, defaults: null });
2135
+ useEffect(() => {
2136
+ if (!annotationProvides) return;
2137
+ return annotationProvides.onActiveToolChange(setActiveTool);
2138
+ }, [annotationProvides]);
2139
+ if (!activeTool.defaults) return null;
2140
+ if (activeTool.defaults.subtype !== PdfAnnotationSubtype.POLYLINE) return null;
2141
+ const toolColor = activeTool.defaults.color ?? "#000000";
2142
+ const toolOpacity = activeTool.defaults.opacity ?? 1;
2143
+ const toolStrokeWidth = activeTool.defaults.strokeWidth ?? 2;
2144
+ const toolStrokeColor = activeTool.defaults.strokeColor ?? "#000000";
2145
+ const toolLineEndings = activeTool.defaults.lineEndings;
2146
+ const toolStrokeStyle = activeTool.defaults.strokeStyle ?? PdfAnnotationBorderStyle.SOLID;
2147
+ const toolStrokeDashArray = activeTool.defaults.strokeDashArray;
2148
+ const { register } = usePointerHandlers({ modeId: "polyline", pageIndex });
2149
+ const clamp = (v, min, max) => Math.max(min, Math.min(max, v));
2150
+ const pageWidthPDF = pageWidth / scale;
2151
+ const pageHeightPDF = pageHeight / scale;
2152
+ const [vertices, setVertices] = useState([]);
2153
+ const [current, setCurrent] = useState(null);
2154
+ const commitPolyline = (pts) => {
2155
+ if (pts.length < 2) return;
2156
+ const rect2 = patching.lineRectWithEndings(pts, toolStrokeWidth, toolLineEndings);
2157
+ const anno = {
2158
+ type: PdfAnnotationSubtype.POLYLINE,
2159
+ rect: rect2,
2160
+ vertices: pts,
2161
+ color: toolColor,
2162
+ opacity: toolOpacity,
2163
+ strokeWidth: toolStrokeWidth,
2164
+ strokeColor: toolStrokeColor,
2165
+ strokeStyle: toolStrokeStyle,
2166
+ strokeDashArray: toolStrokeDashArray,
2167
+ lineEndings: toolLineEndings,
2168
+ pageIndex,
2169
+ id: Date.now() + Math.random()
2170
+ };
2171
+ annotationProvides.createAnnotation(pageIndex, anno);
2172
+ annotationProvides.setActiveVariant(null);
2173
+ annotationProvides.selectAnnotation(pageIndex, anno.id);
2174
+ };
2175
+ const handlers = useMemo(
2176
+ () => ({
2177
+ onClick: (pos) => {
2178
+ const x = clamp(pos.x, 0, pageWidthPDF);
2179
+ const y = clamp(pos.y, 0, pageHeightPDF);
2180
+ setVertices((prev) => [...prev, { x, y }]);
2181
+ setCurrent({ x, y });
2182
+ },
2183
+ onDoubleClick: () => {
2184
+ if (vertices.length >= 1 && annotationProvides) {
2185
+ commitPolyline(vertices);
2186
+ }
2187
+ setVertices([]);
2188
+ setCurrent(null);
2189
+ },
2190
+ onPointerMove: (pos) => {
2191
+ if (!vertices.length) return;
2192
+ const x = clamp(pos.x, 0, pageWidthPDF);
2193
+ const y = clamp(pos.y, 0, pageHeightPDF);
2194
+ setCurrent({ x, y });
2195
+ },
2196
+ onPointerCancel: () => {
2197
+ setVertices([]);
2198
+ setCurrent(null);
2199
+ }
2200
+ }),
2201
+ [vertices, annotationProvides, pageWidthPDF, pageHeightPDF]
2202
+ );
2203
+ useEffect(() => register ? register(handlers) : void 0, [register, handlers]);
2204
+ if (!vertices.length || !current) return null;
2205
+ const allPts = [...vertices, current];
2206
+ const rect = patching.lineRectWithEndings(allPts, toolStrokeWidth, toolLineEndings);
2207
+ return /* @__PURE__ */ jsx(
2208
+ "div",
2209
+ {
2210
+ style: {
2211
+ position: "absolute",
2212
+ left: rect.origin.x * scale,
2213
+ top: rect.origin.y * scale,
2214
+ width: rect.size.width * scale,
2215
+ height: rect.size.height * scale,
2216
+ pointerEvents: "none",
2217
+ zIndex: 2,
2218
+ overflow: "visible",
2219
+ cursor
2220
+ },
2221
+ children: /* @__PURE__ */ jsx(
2222
+ Polyline,
2223
+ {
2224
+ rect,
2225
+ vertices: allPts,
2226
+ strokeWidth: toolStrokeWidth,
2227
+ scale,
2228
+ isSelected: false,
2229
+ color: toolColor,
2230
+ strokeColor: toolStrokeColor,
2231
+ opacity: toolOpacity,
2232
+ lineEndings: toolLineEndings
2233
+ }
2234
+ )
2235
+ }
2236
+ );
2237
+ };
2238
+ const LinePaint = ({ pageIndex, scale, pageWidth, pageHeight, cursor }) => {
2239
+ const { provides: annotationProvides } = useAnnotationCapability();
2240
+ const [activeTool, setActiveTool] = useState({ variantKey: null, defaults: null });
2241
+ useEffect(() => {
2242
+ if (!annotationProvides) return;
2243
+ return annotationProvides.onActiveToolChange(setActiveTool);
2244
+ }, [annotationProvides]);
2245
+ if (!activeTool.defaults) return null;
2246
+ if (activeTool.defaults.subtype !== PdfAnnotationSubtype.LINE) return null;
2247
+ const toolColor = activeTool.defaults.color ?? "#000000";
2248
+ const toolOpacity = activeTool.defaults.opacity ?? 1;
2249
+ const toolStrokeWidth = activeTool.defaults.strokeWidth ?? 2;
2250
+ const toolStrokeColor = activeTool.defaults.strokeColor ?? "#000000";
2251
+ const toolStrokeStyle = activeTool.defaults.strokeStyle ?? PdfAnnotationBorderStyle.SOLID;
2252
+ const toolStrokeDashArray = activeTool.defaults.strokeDashArray;
2253
+ const toolLineEndings = activeTool.defaults.lineEndings;
2254
+ const intent = activeTool.defaults.intent;
2255
+ const { register } = usePointerHandlers({ modeId: ["line", "lineArrow"], pageIndex });
2256
+ const clamp = (v, min, max) => Math.max(min, Math.min(max, v));
2257
+ const pageWidthPDF = pageWidth / scale;
2258
+ const pageHeightPDF = pageHeight / scale;
2259
+ const [start, setStart] = useState(null);
2260
+ const [current, setCurrent] = useState(null);
2261
+ const commitLine = (p1, p2) => {
2262
+ if (Math.abs(p2.x - p1.x) < 1 && Math.abs(p2.y - p1.y) < 1) return;
2263
+ const rect2 = patching.lineRectWithEndings([p1, p2], toolStrokeWidth, toolLineEndings);
2264
+ const anno = {
2265
+ type: PdfAnnotationSubtype.LINE,
2266
+ rect: rect2,
2267
+ linePoints: { start: p1, end: p2 },
2268
+ color: toolColor,
2269
+ opacity: toolOpacity,
2270
+ strokeWidth: toolStrokeWidth,
2271
+ strokeColor: toolStrokeColor,
2272
+ strokeStyle: toolStrokeStyle,
2273
+ strokeDashArray: toolStrokeDashArray,
2274
+ lineEndings: toolLineEndings,
2275
+ intent,
2276
+ pageIndex,
2277
+ id: Date.now() + Math.random()
2278
+ };
2279
+ annotationProvides.createAnnotation(pageIndex, anno);
2280
+ annotationProvides.setActiveVariant(null);
2281
+ annotationProvides.selectAnnotation(pageIndex, anno.id);
2282
+ };
2283
+ const handlers = useMemo(
2284
+ () => ({
2285
+ onPointerDown: (pos, evt) => {
2286
+ var _a, _b;
2287
+ const x = clamp(pos.x, 0, pageWidthPDF);
2288
+ const y = clamp(pos.y, 0, pageHeightPDF);
2289
+ setStart({ x, y });
2290
+ setCurrent({ x, y });
2291
+ (_b = (_a = evt.target) == null ? void 0 : _a.setPointerCapture) == null ? void 0 : _b.call(_a, evt.pointerId);
2292
+ },
2293
+ onPointerMove: (pos) => {
2294
+ if (!start) return;
2295
+ const x = clamp(pos.x, 0, pageWidthPDF);
2296
+ const y = clamp(pos.y, 0, pageHeightPDF);
2297
+ setCurrent({ x, y });
2298
+ },
2299
+ onPointerUp: (_, evt) => {
2300
+ var _a, _b;
2301
+ if (start && current && annotationProvides) {
2302
+ commitLine(start, current);
2303
+ }
2304
+ (_b = (_a = evt.target) == null ? void 0 : _a.releasePointerCapture) == null ? void 0 : _b.call(_a, evt.pointerId);
2305
+ setStart(null);
2306
+ setCurrent(null);
2307
+ },
2308
+ onPointerCancel: (_, evt) => {
2309
+ var _a, _b;
2310
+ (_b = (_a = evt.target) == null ? void 0 : _a.releasePointerCapture) == null ? void 0 : _b.call(_a, evt.pointerId);
2311
+ setStart(null);
2312
+ setCurrent(null);
2313
+ }
2314
+ }),
2315
+ [start, current, annotationProvides, pageWidthPDF, pageHeightPDF]
2316
+ );
2317
+ useEffect(() => register ? register(handlers) : void 0, [register, handlers]);
2318
+ if (!start || !current) return null;
2319
+ const rect = patching.lineRectWithEndings([start, current], toolStrokeWidth, toolLineEndings);
2320
+ return /* @__PURE__ */ jsx(
2321
+ "div",
2322
+ {
2323
+ style: {
2324
+ position: "absolute",
2325
+ left: rect.origin.x * scale,
2326
+ top: rect.origin.y * scale,
2327
+ width: rect.size.width * scale,
2328
+ height: rect.size.height * scale,
2329
+ pointerEvents: "none",
2330
+ zIndex: 2,
2331
+ overflow: "visible",
2332
+ cursor
2333
+ },
2334
+ children: /* @__PURE__ */ jsx(
2335
+ Line,
2336
+ {
2337
+ rect,
2338
+ linePoints: { start, end: current },
2339
+ strokeWidth: toolStrokeWidth,
2340
+ scale,
2341
+ isSelected: false,
2342
+ color: toolColor,
2343
+ strokeColor: toolStrokeColor,
2344
+ opacity: toolOpacity,
2345
+ lineEndings: toolLineEndings,
2346
+ strokeStyle: toolStrokeStyle,
2347
+ strokeDashArray: toolStrokeDashArray
2348
+ }
2349
+ )
2350
+ }
2351
+ );
2352
+ };
2353
+ const HANDLE_SIZE_PX = 14;
2354
+ const PolygonPaint = ({
2355
+ pageIndex,
2356
+ scale,
2357
+ pageWidth,
2358
+ pageHeight,
2359
+ cursor
2360
+ }) => {
2361
+ const { provides: annotationProvides } = useAnnotationCapability();
2362
+ const [activeTool, setActiveTool] = useState({ variantKey: null, defaults: null });
2363
+ useEffect(() => annotationProvides == null ? void 0 : annotationProvides.onActiveToolChange(setActiveTool), [annotationProvides]);
2364
+ if (!activeTool.defaults || activeTool.defaults.subtype !== PdfAnnotationSubtype.POLYGON)
2365
+ return null;
2366
+ const toolColor = activeTool.defaults.color ?? "#000000";
2367
+ const toolOpacity = activeTool.defaults.opacity ?? 1;
2368
+ const toolStrokeWidth = activeTool.defaults.strokeWidth ?? 2;
2369
+ const toolStrokeColor = activeTool.defaults.strokeColor ?? "#000000";
2370
+ const toolStrokeStyle = activeTool.defaults.strokeStyle ?? PdfAnnotationBorderStyle.SOLID;
2371
+ const toolStrokeDashArray = activeTool.defaults.strokeDashArray;
2372
+ const { register } = usePointerHandlers({ modeId: "polygon", pageIndex });
2373
+ const clamp = (v, min, max) => Math.max(min, Math.min(max, v));
2374
+ const pageWidthPDF = pageWidth / scale;
2375
+ const pageHeightPDF = pageHeight / scale;
2376
+ const [vertices, setVertices] = useState([]);
2377
+ const [current, setCurrent] = useState(null);
2378
+ const commitPolygon = (pts) => {
2379
+ const xs2 = pts.map((p) => p.x), ys2 = pts.map((p) => p.y);
2380
+ const minX2 = Math.min(...xs2), minY2 = Math.min(...ys2);
2381
+ const maxX2 = Math.max(...xs2), maxY2 = Math.max(...ys2);
2382
+ if (maxX2 - minX2 < 1 || maxY2 - minY2 < 1) return;
2383
+ const half2 = toolStrokeWidth / 2;
2384
+ const rect = {
2385
+ origin: { x: minX2 - half2, y: minY2 - half2 },
2386
+ size: { width: maxX2 - minX2 + toolStrokeWidth, height: maxY2 - minY2 + toolStrokeWidth }
2387
+ };
2388
+ const anno = {
2389
+ type: PdfAnnotationSubtype.POLYGON,
2390
+ rect,
2391
+ vertices: pts,
2392
+ color: toolColor,
2393
+ opacity: toolOpacity,
2394
+ strokeWidth: toolStrokeWidth,
2395
+ strokeColor: toolStrokeColor,
2396
+ strokeStyle: toolStrokeStyle,
2397
+ strokeDashArray: toolStrokeDashArray,
2398
+ pageIndex,
2399
+ id: Date.now() + Math.random()
2400
+ };
2401
+ annotationProvides.createAnnotation(pageIndex, anno);
2402
+ annotationProvides.setActiveVariant(null);
2403
+ annotationProvides.selectAnnotation(pageIndex, anno.id);
2404
+ };
2405
+ const isInsideStartHandle = (x, y) => {
2406
+ if (vertices.length < 2) return false;
2407
+ const sizePDF = HANDLE_SIZE_PX / scale;
2408
+ const half2 = sizePDF / 2;
2409
+ const v0 = vertices[0];
2410
+ return x >= v0.x - half2 && x <= v0.x + half2 && y >= v0.y - half2 && y <= v0.y + half2;
2411
+ };
2412
+ const handlers = useMemo(
2413
+ () => ({
2414
+ onClick: (pos) => {
2415
+ const x = clamp(pos.x, 0, pageWidthPDF);
2416
+ const y = clamp(pos.y, 0, pageHeightPDF);
2417
+ if (isInsideStartHandle(x, y) && vertices.length >= 3 && annotationProvides) {
2418
+ commitPolygon(vertices);
2419
+ setVertices([]);
2420
+ setCurrent(null);
2421
+ return;
2422
+ }
2423
+ setVertices((prev) => [...prev, { x, y }]);
2424
+ setCurrent({ x, y });
2425
+ },
2426
+ onDoubleClick: () => {
2427
+ if (vertices.length >= 3 && annotationProvides) {
2428
+ commitPolygon(vertices);
2429
+ setVertices([]);
2430
+ setCurrent(null);
2431
+ } else {
2432
+ setVertices([]);
2433
+ setCurrent(null);
2434
+ }
2435
+ },
2436
+ onPointerMove: (pos) => {
2437
+ if (!vertices.length) return;
2438
+ const x = clamp(pos.x, 0, pageWidthPDF);
2439
+ const y = clamp(pos.y, 0, pageHeightPDF);
2440
+ setCurrent({ x, y });
2441
+ },
2442
+ onPointerCancel: () => {
2443
+ setVertices([]);
2444
+ setCurrent(null);
2445
+ }
2446
+ }),
2447
+ [vertices, current, annotationProvides, pageWidthPDF, pageHeightPDF]
2448
+ );
2449
+ useEffect(() => register ? register(handlers) : void 0, [register, handlers]);
2450
+ if (!vertices.length || !current) return null;
2451
+ const allPts = [...vertices, current];
2452
+ const xs = allPts.map((p) => p.x), ys = allPts.map((p) => p.y);
2453
+ const minX = Math.min(...xs), minY = Math.min(...ys);
2454
+ const maxX = Math.max(...xs), maxY = Math.max(...ys);
2455
+ const half = toolStrokeWidth / 2;
2456
+ const svgMinX = minX - half;
2457
+ const svgMinY = minY - half;
2458
+ const svgMaxX = maxX + half;
2459
+ const svgMaxY = maxY + half;
2460
+ const dw = svgMaxX - svgMinX;
2461
+ const dh = svgMaxY - svgMinY;
2462
+ const mainPath = useMemo(() => {
2463
+ let d = "";
2464
+ allPts.forEach(({ x, y }, i) => {
2465
+ d += (i === 0 ? "M" : "L") + (x - svgMinX) + " " + (y - svgMinY) + " ";
2466
+ });
2467
+ return d.trim();
2468
+ }, [allPts, svgMinX, svgMinY]);
2469
+ const dottedPath = vertices.length >= 2 ? (() => {
2470
+ const curLx = current.x - svgMinX;
2471
+ const curLy = current.y - svgMinY;
2472
+ const firstLx = vertices[0].x - svgMinX;
2473
+ const firstLy = vertices[0].y - svgMinY;
2474
+ return `M ${curLx} ${curLy} L ${firstLx} ${firstLy}`;
2475
+ })() : null;
2476
+ const handleSizePDF = HANDLE_SIZE_PX / scale;
2477
+ const hHalf = handleSizePDF / 2;
2478
+ const hx = vertices[0].x - hHalf - svgMinX;
2479
+ const hy = vertices[0].y - hHalf - svgMinY;
2480
+ return /* @__PURE__ */ jsxs(
2481
+ "svg",
2482
+ {
2483
+ style: {
2484
+ position: "absolute",
2485
+ left: svgMinX * scale,
2486
+ top: svgMinY * scale,
2487
+ width: dw * scale,
2488
+ height: dh * scale,
2489
+ pointerEvents: "none",
2490
+ // we handle clicks at the page layer
2491
+ zIndex: 2,
2492
+ overflow: "visible"
2493
+ },
2494
+ width: dw * scale,
2495
+ height: dh * scale,
2496
+ viewBox: `0 0 ${dw} ${dh}`,
2497
+ children: [
2498
+ /* @__PURE__ */ jsx(
2499
+ "path",
2500
+ {
2501
+ d: mainPath,
2502
+ fill: toolColor,
2503
+ opacity: toolOpacity,
2504
+ style: {
2505
+ cursor,
2506
+ stroke: toolStrokeColor,
2507
+ strokeWidth: toolStrokeWidth,
2508
+ ...toolStrokeStyle === PdfAnnotationBorderStyle.DASHED && {
2509
+ strokeDasharray: toolStrokeDashArray == null ? void 0 : toolStrokeDashArray.join(",")
2510
+ }
2511
+ }
2512
+ }
2513
+ ),
2514
+ dottedPath && /* @__PURE__ */ jsx(
2515
+ "path",
2516
+ {
2517
+ d: dottedPath,
2518
+ fill: "none",
2519
+ style: { stroke: toolStrokeColor, strokeWidth: toolStrokeWidth, strokeDasharray: "4,4" }
2520
+ }
2521
+ ),
2522
+ vertices.length >= 3 && /* @__PURE__ */ jsx(
2523
+ "rect",
2524
+ {
2525
+ x: hx,
2526
+ y: hy,
2527
+ width: handleSizePDF,
2528
+ height: handleSizePDF,
2529
+ fill: toolStrokeColor,
2530
+ opacity: 0.4,
2531
+ stroke: toolStrokeColor,
2532
+ strokeWidth: toolStrokeWidth / 2,
2533
+ style: { pointerEvents: "none" }
2534
+ }
2535
+ )
2536
+ ]
2537
+ }
2538
+ );
2539
+ };
2540
+ function AnnotationLayer({
2541
+ pageIndex,
2542
+ scale,
2543
+ pageWidth,
2544
+ pageHeight,
2545
+ rotation,
2546
+ selectionMenu,
2547
+ style,
2548
+ ...props
2549
+ }) {
2550
+ return /* @__PURE__ */ jsxs(
2551
+ "div",
996
2552
  {
997
2553
  style: {
998
2554
  ...style
999
2555
  },
1000
2556
  ...props,
1001
2557
  children: [
1002
- /* @__PURE__ */ jsx10(Annotations, { pageIndex, scale, rotation }),
1003
- /* @__PURE__ */ jsx10(TextMarkup, { pageIndex, scale }),
1004
- /* @__PURE__ */ jsx10(InkPaint, { pageIndex, scale, pageWidth, pageHeight })
2558
+ /* @__PURE__ */ jsx(
2559
+ Annotations,
2560
+ {
2561
+ selectionMenu,
2562
+ pageIndex,
2563
+ scale,
2564
+ rotation,
2565
+ pageWidth,
2566
+ pageHeight
2567
+ }
2568
+ ),
2569
+ /* @__PURE__ */ jsx(TextMarkup, { pageIndex, scale }),
2570
+ /* @__PURE__ */ jsx(InkPaint, { pageIndex, scale, pageWidth, pageHeight }),
2571
+ /* @__PURE__ */ jsx(
2572
+ CirclePaint,
2573
+ {
2574
+ pageIndex,
2575
+ scale,
2576
+ pageWidth,
2577
+ pageHeight
2578
+ }
2579
+ ),
2580
+ /* @__PURE__ */ jsx(
2581
+ SquarePaint,
2582
+ {
2583
+ pageIndex,
2584
+ scale,
2585
+ pageWidth,
2586
+ pageHeight
2587
+ }
2588
+ ),
2589
+ /* @__PURE__ */ jsx(
2590
+ PolygonPaint,
2591
+ {
2592
+ pageIndex,
2593
+ scale,
2594
+ pageWidth,
2595
+ pageHeight
2596
+ }
2597
+ ),
2598
+ /* @__PURE__ */ jsx(
2599
+ PolylinePaint,
2600
+ {
2601
+ pageIndex,
2602
+ scale,
2603
+ pageWidth,
2604
+ pageHeight
2605
+ }
2606
+ ),
2607
+ /* @__PURE__ */ jsx(
2608
+ LinePaint,
2609
+ {
2610
+ pageIndex,
2611
+ scale,
2612
+ pageWidth,
2613
+ pageHeight
2614
+ }
2615
+ )
1005
2616
  ]
1006
2617
  }
1007
2618
  );
@@ -1011,4 +2622,4 @@ export {
1011
2622
  useAnnotationCapability,
1012
2623
  useAnnotationPlugin
1013
2624
  };
1014
- //# sourceMappingURL=index.js.map
2625
+ //# sourceMappingURL=index.js.map