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