@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,17 +1,333 @@
1
1
  import { usePlugin, useCapability } from "@embedpdf/core/preact";
2
- import { AnnotationPlugin, getAnnotationsByPageIndex, getSelectedAnnotationByPageIndex, makeVariantKey } from "@embedpdf/plugin-annotation";
3
- import { jsxs, Fragment, jsx } from "preact/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 "preact/jsx-runtime";
4
+ import { restoreOffset, rectEquals, PdfAnnotationBorderStyle, PdfAnnotationSubtype, expandRect, rectFromPoints, blendModeToCss, PdfBlendMode } from "@embedpdf/models";
5
5
  import { usePointerHandlers } from "@embedpdf/plugin-interaction-manager/preact";
6
- import "preact";
7
- import { useRef, useState, useEffect, useMemo, useCallback } from "preact/hooks";
8
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
9
  const useAnnotationPlugin = () => usePlugin(AnnotationPlugin.id);
10
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
+ }
11
325
  function AnnotationContainer({
12
326
  scale,
13
327
  pageIndex,
14
328
  rotation,
329
+ pageWidth,
330
+ pageHeight,
15
331
  trackedAnnotation,
16
332
  children,
17
333
  style,
@@ -19,193 +335,119 @@ function AnnotationContainer({
19
335
  isSelected = false,
20
336
  isDraggable = true,
21
337
  isResizable = true,
22
- computeResizePatch,
338
+ computeVertices,
339
+ computePatch,
340
+ selectionMenu,
23
341
  ...props
24
342
  }) {
25
343
  const { provides: annotationProvides } = useAnnotationCapability();
26
- const ref = useRef(null);
27
- const [dragState, setDragState] = useState("idle");
28
- const [resizeDirection, setResizeDirection] = useState(null);
29
- const [startPos, setStartPos] = useState(null);
30
- const [startRect, setStartRect] = useState(null);
31
344
  const [currentRect, setCurrentRect] = useState(trackedAnnotation.object.rect);
345
+ const [currentVertices, setCurrentVertices] = useState(
346
+ (computeVertices == null ? void 0 : computeVertices(trackedAnnotation.object)) ?? []
347
+ );
32
348
  const [previewObject, setPreviewObject] = useState(null);
33
- useEffect(() => {
34
- setCurrentRect(trackedAnnotation.object.rect);
35
- setPreviewObject(null);
36
- }, [trackedAnnotation]);
37
- const handlePointerDown = (e) => {
38
- var _a;
39
- if (!isSelected) return;
40
- e.stopPropagation();
41
- e.preventDefault();
42
- const target = e.target;
43
- if (isResizable && target.classList.contains("resize-handle")) {
44
- setDragState("resizing");
45
- setResizeDirection(target.dataset.direction);
46
- } else if (isDraggable) {
47
- setDragState("dragging");
48
- } else {
49
- return;
50
- }
51
- setStartPos({ x: e.clientX, y: e.clientY });
52
- setStartRect(currentRect);
53
- (_a = ref.current) == null ? void 0 : _a.setPointerCapture(e.pointerId);
54
- };
55
- const handlePointerMove = (e) => {
56
- if (dragState === "idle" || !startPos || !startRect) return;
57
- const dispDelta = { x: e.clientX - startPos.x, y: e.clientY - startPos.y };
58
- const { x: dx, y: dy } = restoreOffset(dispDelta, rotation, scale);
59
- let newOriginX = startRect.origin.x;
60
- let newOriginY = startRect.origin.y;
61
- let newWidth = startRect.size.width;
62
- let newHeight = startRect.size.height;
63
- if (dragState === "dragging") {
64
- newOriginX += dx;
65
- newOriginY += dy;
66
- } else if (dragState === "resizing" && resizeDirection) {
67
- if (resizeDirection.includes("right")) {
68
- newWidth += dx;
69
- } else if (resizeDirection.includes("left")) {
70
- newOriginX += dx;
71
- newWidth -= dx;
72
- }
73
- if (resizeDirection.includes("bottom")) {
74
- newHeight += dy;
75
- } else if (resizeDirection.includes("top")) {
76
- newOriginY += dy;
77
- newHeight -= dy;
78
- }
79
- if (newWidth < 1 || newHeight < 1) return;
80
- }
81
- const tentativeRect = {
82
- origin: { x: newOriginX, y: newOriginY },
83
- size: { width: newWidth, height: newHeight }
84
- };
85
- let previewPatch = { rect: tentativeRect };
86
- if (computeResizePatch) {
87
- const dir = dragState === "resizing" ? resizeDirection : "bottom-right";
88
- if (dir) {
89
- previewPatch = computeResizePatch(trackedAnnotation.object, tentativeRect, dir);
90
- }
91
- }
92
- setCurrentRect(previewPatch.rect || tentativeRect);
93
- setPreviewObject(previewPatch);
94
- };
95
- const handlePointerUp = (e) => {
96
- var _a;
97
- if (dragState === "idle") return;
98
- const usedDirection = resizeDirection || "bottom-right";
99
- setDragState("idle");
100
- setResizeDirection(null);
101
- (_a = ref.current) == null ? void 0 : _a.releasePointerCapture(e.pointerId);
102
- if (annotationProvides && trackedAnnotation) {
103
- let patch = { rect: currentRect };
104
- if (computeResizePatch && usedDirection) {
105
- patch = computeResizePatch(trackedAnnotation.object, currentRect, usedDirection);
106
- }
107
- 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)) ?? []);
108
371
  }
109
- setStartPos(null);
110
- setStartRect(null);
111
- setPreviewObject(null);
112
- };
372
+ }, [trackedAnnotation]);
113
373
  const currentObject = previewObject ? { ...trackedAnnotation.object, ...previewObject } : trackedAnnotation.object;
114
- return /* @__PURE__ */ jsxs(
115
- "div",
116
- {
117
- ref,
118
- onPointerDown: handlePointerDown,
119
- onPointerMove: handlePointerMove,
120
- onPointerUp: handlePointerUp,
121
- style: {
122
- position: "absolute",
123
- outline: isSelected ? "1px solid #007ACC" : "none",
124
- outlineOffset: isSelected ? `${outlineOffset}px` : "0px",
125
- left: `${currentRect.origin.x * scale}px`,
126
- top: `${currentRect.origin.y * scale}px`,
127
- width: `${currentRect.size.width * scale}px`,
128
- height: `${currentRect.size.height * scale}px`,
129
- pointerEvents: isSelected ? "auto" : "none",
130
- cursor: isSelected && isDraggable ? "move" : "default",
131
- ...style
132
- },
133
- ...props,
134
- children: [
135
- typeof children === "function" ? children(currentObject) : children,
136
- isSelected && isResizable && /* @__PURE__ */ jsxs(Fragment, { children: [
137
- /* @__PURE__ */ jsx(
138
- "div",
139
- {
140
- className: "resize-handle",
141
- "data-direction": "top-left",
142
- style: {
143
- position: "absolute",
144
- top: -7 - outlineOffset,
145
- left: -7 - outlineOffset,
146
- width: 13,
147
- height: 13,
148
- background: "blue",
149
- borderRadius: "50%",
150
- cursor: rotation % 2 ? "nesw-resize" : "nwse-resize"
151
- }
152
- }
153
- ),
154
- /* @__PURE__ */ jsx(
155
- "div",
156
- {
157
- className: "resize-handle",
158
- "data-direction": "top-right",
159
- style: {
160
- position: "absolute",
161
- top: -7 - outlineOffset,
162
- right: -7 - outlineOffset,
163
- width: 13,
164
- height: 13,
165
- background: "blue",
166
- borderRadius: "50%",
167
- cursor: rotation % 2 ? "nwse-resize" : "nesw-resize"
168
- }
169
- }
170
- ),
171
- /* @__PURE__ */ jsx(
172
- "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,
173
396
  {
174
- className: "resize-handle",
175
- "data-direction": "bottom-left",
176
- style: {
177
- position: "absolute",
178
- bottom: -7 - outlineOffset,
179
- left: -7 - outlineOffset,
180
- width: 13,
181
- height: 13,
182
- background: "blue",
183
- borderRadius: "50%",
184
- 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
+ }
185
420
  }
186
421
  }
187
422
  ),
188
- /* @__PURE__ */ jsx(
189
- "div",
423
+ isSelected && isResizable && /* @__PURE__ */ jsx(
424
+ ResizeHandles,
190
425
  {
191
- className: "resize-handle",
192
- "data-direction": "bottom-right",
193
- style: {
194
- position: "absolute",
195
- bottom: -7 - outlineOffset,
196
- right: -7 - outlineOffset,
197
- width: 13,
198
- height: 13,
199
- background: "blue",
200
- borderRadius: "50%",
201
- cursor: rotation % 2 ? "nesw-resize" : "nwse-resize"
202
- }
426
+ rotation,
427
+ outlineOffset,
428
+ startResize
203
429
  }
204
430
  )
205
- ] })
206
- ]
207
- }
208
- );
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
+ ] });
209
451
  }
210
452
  function Highlight({
211
453
  color = "#FFFF00",
@@ -217,7 +459,7 @@ function Highlight({
217
459
  style,
218
460
  ...props
219
461
  }) {
220
- return /* @__PURE__ */ jsx(Fragment, { children: rects.map((b, i) => /* @__PURE__ */ jsx(
462
+ return /* @__PURE__ */ jsx(Fragment$1, { children: rects.map((b, i) => /* @__PURE__ */ jsx(
221
463
  "div",
222
464
  {
223
465
  onMouseDown: onClick,
@@ -250,7 +492,7 @@ function Underline({
250
492
  ...props
251
493
  }) {
252
494
  const thickness = 2 * scale;
253
- return /* @__PURE__ */ jsx(Fragment, { children: rects.map((r, i) => /* @__PURE__ */ jsx(
495
+ return /* @__PURE__ */ jsx(Fragment$1, { children: rects.map((r, i) => /* @__PURE__ */ jsx(
254
496
  "div",
255
497
  {
256
498
  onMouseDown: onClick,
@@ -297,7 +539,7 @@ function Strikeout({
297
539
  ...props
298
540
  }) {
299
541
  const thickness = 2 * scale;
300
- return /* @__PURE__ */ jsx(Fragment, { children: rects.map((r, i) => /* @__PURE__ */ jsx(
542
+ return /* @__PURE__ */ jsx(Fragment$1, { children: rects.map((r, i) => /* @__PURE__ */ jsx(
301
543
  "div",
302
544
  {
303
545
  onMouseDown: onClick,
@@ -351,7 +593,7 @@ function Squiggly({
351
593
  fill="none" stroke="${color}" stroke-width="${amplitude}" stroke-linecap="round"/>
352
594
  </svg>`;
353
595
  const svgDataUri = `url("data:image/svg+xml;utf8,${encodeURIComponent(svg)}")`;
354
- return /* @__PURE__ */ jsx(Fragment, { children: rects.map((r, i) => /* @__PURE__ */ jsx(
596
+ return /* @__PURE__ */ jsx(Fragment$1, { children: rects.map((r, i) => /* @__PURE__ */ jsx(
355
597
  "div",
356
598
  {
357
599
  onMouseDown: onClick,
@@ -396,7 +638,8 @@ function Ink({
396
638
  inkList,
397
639
  rect,
398
640
  scale,
399
- onClick
641
+ onClick,
642
+ cursor
400
643
  }) {
401
644
  const paths = useMemo(() => {
402
645
  return inkList.map(({ points }) => {
@@ -419,7 +662,8 @@ function Ink({
419
662
  width,
420
663
  height,
421
664
  pointerEvents: "none",
422
- zIndex: 2
665
+ zIndex: 2,
666
+ overflow: "visible"
423
667
  },
424
668
  width,
425
669
  height,
@@ -429,15 +673,15 @@ function Ink({
429
673
  {
430
674
  d,
431
675
  fill: "none",
432
- stroke: color,
433
- strokeWidth,
434
- strokeLinecap: "round",
435
- strokeLinejoin: "round",
436
676
  opacity,
437
- pointerEvents: "visibleStroke",
438
677
  onMouseDown: onClick,
439
678
  style: {
440
- cursor: "pointer"
679
+ cursor,
680
+ pointerEvents: "visibleStroke",
681
+ stroke: color,
682
+ strokeWidth,
683
+ strokeLinecap: "round",
684
+ strokeLinejoin: "round"
441
685
  }
442
686
  },
443
687
  i
@@ -445,229 +689,869 @@ function Ink({
445
689
  }
446
690
  );
447
691
  }
448
- 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) => {
449
822
  if (original.type !== PdfAnnotationSubtype.INK) {
450
823
  throw new Error("resizeInkAnnotation: original is not an ink annotation");
451
824
  }
452
825
  const oldRect = original.rect;
453
- let scaleX = newRect.size.width / oldRect.size.width;
454
- 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;
455
828
  const minSize = 10;
456
- if (newRect.size.width < minSize || newRect.size.height < minSize) {
829
+ if (ctx.rect.size.width < minSize || ctx.rect.size.height < minSize) {
457
830
  scaleX = Math.max(scaleX, minSize / oldRect.size.width);
458
831
  scaleY = Math.max(scaleY, minSize / oldRect.size.height);
459
- newRect = {
460
- origin: newRect.origin,
832
+ ctx.rect = {
833
+ origin: ctx.rect.origin,
461
834
  size: {
462
835
  width: oldRect.size.width * scaleX,
463
836
  height: oldRect.size.height * scaleY
464
837
  }
465
838
  };
466
839
  }
467
- if (uniform) {
840
+ if (ctx.uniform) {
468
841
  const minScale = Math.min(scaleX, scaleY);
469
842
  scaleX = minScale;
470
843
  scaleY = minScale;
471
- newRect.size = {
844
+ ctx.rect.size = {
472
845
  width: oldRect.size.width * minScale,
473
846
  height: oldRect.size.height * minScale
474
847
  };
475
848
  }
476
849
  const newInkList = original.inkList.map((stroke) => ({
477
850
  points: stroke.points.map((p) => ({
478
- x: newRect.origin.x + (p.x - oldRect.origin.x) * scaleX,
479
- 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
480
853
  }))
481
854
  }));
482
855
  const avgScale = (scaleX + scaleY) / 2;
483
- const newStrokeWidth = original.strokeWidth * avgScale;
856
+ const newStrokeWidth = Math.round(original.strokeWidth * avgScale);
484
857
  return {
485
- rect: newRect,
858
+ rect: ctx.rect,
486
859
  inkList: newInkList,
487
860
  strokeWidth: newStrokeWidth
488
861
  };
489
- }
490
- function Annotations(annotationsProps) {
491
- const { pageIndex, scale } = annotationsProps;
492
- const { provides: annotationProvides } = useAnnotationCapability();
493
- const { provides: selectionProvides } = useSelectionCapability();
494
- const [annotations, setAnnotations] = useState([]);
495
- const { register } = usePointerHandlers({ pageIndex });
496
- const [selectionState, setSelectionState] = useState(null);
497
- useEffect(() => {
498
- if (annotationProvides) {
499
- annotationProvides.onStateChange((state) => {
500
- setAnnotations(getAnnotationsByPageIndex(state, pageIndex));
501
- setSelectionState(getSelectedAnnotationByPageIndex(state, pageIndex));
502
- });
503
- }
504
- }, [annotationProvides]);
505
- const handlers = useMemo(
506
- () => ({
507
- onPointerDown: (_, pe) => {
508
- if (pe.target === pe.currentTarget && annotationProvides) {
509
- annotationProvides.deselectAnnotation();
510
- }
511
- }
512
- }),
513
- [annotationProvides]
514
- );
515
- const handleClick = useCallback(
516
- (e, annotation) => {
517
- e.stopPropagation();
518
- if (annotationProvides && selectionProvides) {
519
- annotationProvides.selectAnnotation(pageIndex, annotation.localId);
520
- selectionProvides.clear();
521
- }
522
- },
523
- [annotationProvides, selectionProvides, pageIndex]
524
- );
525
- useEffect(() => {
526
- return register(handlers);
527
- }, [register, handlers]);
528
- return /* @__PURE__ */ jsx(Fragment, { children: annotations.map((annotation) => {
529
- const isSelected = (selectionState == null ? void 0 : selectionState.localId) === annotation.localId;
530
- switch (annotation.object.type) {
531
- case PdfAnnotationSubtype.UNDERLINE:
532
- return /* @__PURE__ */ jsx(
533
- 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",
534
911
  {
535
- trackedAnnotation: annotation,
536
- isSelected,
537
- isDraggable: false,
538
- isResizable: false,
912
+ x1,
913
+ y1,
914
+ x2,
915
+ y2,
916
+ opacity,
917
+ onMouseDown: onClick,
539
918
  style: {
540
- mixBlendMode: blendModeToCss(annotation.object.blendMode ?? PdfBlendMode.Normal)
541
- },
542
- ...annotationsProps,
543
- children: /* @__PURE__ */ jsx(
544
- Underline,
545
- {
546
- rect: annotation.object.rect,
547
- color: annotation.object.color,
548
- opacity: annotation.object.opacity,
549
- rects: annotation.object.segmentRects,
550
- scale,
551
- onClick: (e) => handleClick(e, annotation)
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(",")
552
926
  }
553
- )
554
- },
555
- annotation.localId
556
- );
557
- case PdfAnnotationSubtype.STRIKEOUT:
558
- return /* @__PURE__ */ jsx(
559
- AnnotationContainer,
927
+ }
928
+ }
929
+ ),
930
+ endings.start && /* @__PURE__ */ jsx(
931
+ "path",
560
932
  {
561
- trackedAnnotation: annotation,
562
- isSelected,
563
- isDraggable: false,
564
- isResizable: false,
933
+ d: endings.start.d,
934
+ transform: endings.start.transform,
935
+ onMouseDown: onClick,
936
+ stroke: strokeColor,
565
937
  style: {
566
- mixBlendMode: blendModeToCss(annotation.object.blendMode ?? PdfBlendMode.Normal)
567
- },
568
- ...annotationsProps,
569
- children: /* @__PURE__ */ jsx(
570
- Strikeout,
571
- {
572
- rect: annotation.object.rect,
573
- color: annotation.object.color,
574
- opacity: annotation.object.opacity,
575
- rects: annotation.object.segmentRects,
576
- scale,
577
- onClick: (e) => handleClick(e, annotation)
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(",")
578
944
  }
579
- )
580
- },
581
- annotation.localId
582
- );
583
- case PdfAnnotationSubtype.SQUIGGLY:
584
- return /* @__PURE__ */ jsx(
585
- AnnotationContainer,
586
- {
587
- trackedAnnotation: annotation,
588
- isSelected,
589
- isDraggable: false,
590
- isResizable: false,
591
- style: {
592
- mixBlendMode: blendModeToCss(annotation.object.blendMode ?? PdfBlendMode.Normal)
593
945
  },
594
- ...annotationsProps,
595
- children: /* @__PURE__ */ jsx(
596
- Squiggly,
597
- {
598
- color: annotation.object.color,
599
- opacity: annotation.object.opacity,
600
- rects: annotation.object.segmentRects,
601
- rect: annotation.object.rect,
602
- scale,
603
- onClick: (e) => handleClick(e, annotation)
604
- }
605
- )
606
- },
607
- annotation.localId
608
- );
609
- case PdfAnnotationSubtype.HIGHLIGHT:
610
- return /* @__PURE__ */ jsx(
611
- AnnotationContainer,
946
+ fill: endings.start.filled ? color : "none"
947
+ }
948
+ ),
949
+ endings.end && /* @__PURE__ */ jsx(
950
+ "path",
612
951
  {
613
- trackedAnnotation: annotation,
614
- isSelected,
615
- isDraggable: false,
616
- isResizable: false,
952
+ d: endings.end.d,
953
+ transform: endings.end.transform,
954
+ stroke: strokeColor,
955
+ onMouseDown: onClick,
617
956
  style: {
618
- mixBlendMode: blendModeToCss(
619
- annotation.object.blendMode ?? PdfBlendMode.Multiply
620
- )
621
- },
622
- ...annotationsProps,
623
- children: /* @__PURE__ */ jsx(
624
- Highlight,
625
- {
626
- color: annotation.object.color,
627
- opacity: annotation.object.opacity,
628
- rects: annotation.object.segmentRects,
629
- scale,
630
- rect: annotation.object.rect,
631
- onClick: (e) => handleClick(e, annotation)
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(",")
632
963
  }
633
- )
634
- },
635
- annotation.localId
636
- );
637
- case PdfAnnotationSubtype.INK:
638
- return /* @__PURE__ */ jsx(
639
- AnnotationContainer,
640
- {
641
- isSelected,
642
- trackedAnnotation: annotation,
643
- outlineOffset: 6,
644
- computeResizePatch: resizeInkAnnotation,
645
- style: {
646
- mixBlendMode: blendModeToCss(annotation.object.blendMode ?? PdfBlendMode.Normal)
647
964
  },
648
- ...annotationsProps,
649
- children: (obj) => /* @__PURE__ */ jsx(
650
- Ink,
651
- {
652
- color: obj.color,
653
- opacity: obj.opacity,
654
- strokeWidth: obj.strokeWidth,
655
- inkList: obj.inkList,
656
- rect: obj.rect,
657
- scale,
658
- onClick: (e) => handleClick(e, annotation)
659
- }
660
- )
661
- },
662
- annotation.localId
663
- );
664
- default:
665
- return null;
965
+ fill: endings.end.filled ? color : "none"
966
+ }
967
+ )
968
+ ]
666
969
  }
667
- }) });
970
+ );
668
971
  }
669
- function TextMarkup({ pageIndex, scale }) {
670
- var _a, _b, _c, _d, _e, _f, _g, _h, _i, _j, _k, _l;
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;
671
1555
  const { provides: selectionProvides } = useSelectionCapability();
672
1556
  const { provides: annotationProvides } = useAnnotationCapability();
673
1557
  const [rects, setRects] = useState([]);
@@ -776,9 +1660,8 @@ function TextMarkup({ pageIndex, scale }) {
776
1660
  return null;
777
1661
  }
778
1662
  }
779
- const MAX_STROKE_WIDTH = 30;
780
1663
  const InkPaint = ({ pageIndex, scale, pageWidth, pageHeight }) => {
781
- var _a, _b, _c;
1664
+ var _a, _b, _c, _d, _e;
782
1665
  const { provides: annotationProvides } = useAnnotationCapability();
783
1666
  const [activeTool, setActiveTool] = useState({ variantKey: null, defaults: null });
784
1667
  useEffect(() => {
@@ -791,6 +1674,8 @@ const InkPaint = ({ pageIndex, scale, pageWidth, pageHeight }) => {
791
1674
  const toolColor = ((_a = activeTool.defaults) == null ? void 0 : _a.color) ?? "#000000";
792
1675
  const toolOpacity = ((_b = activeTool.defaults) == null ? void 0 : _b.opacity) ?? 1;
793
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;
794
1679
  const { register } = usePointerHandlers({ modeId: "ink", pageIndex });
795
1680
  const clamp = (v, min, max) => Math.max(min, Math.min(max, v));
796
1681
  const [currentStrokes, setCurrentStrokes] = useState([]);
@@ -834,23 +1719,13 @@ const InkPaint = ({ pageIndex, scale, pageWidth, pageHeight }) => {
834
1719
  if (currentStrokes.length && annotationProvides) {
835
1720
  const allPoints2 = currentStrokes.flatMap((s) => s.points);
836
1721
  if (!allPoints2.length) return;
837
- const minX2 = Math.min(...allPoints2.map((p) => p.x));
838
- const minY2 = Math.min(...allPoints2.map((p) => p.y));
839
- const maxX2 = Math.max(...allPoints2.map((p) => p.x));
840
- const maxY2 = Math.max(...allPoints2.map((p) => p.y));
841
- const halfStroke2 = MAX_STROKE_WIDTH / 2;
842
- const rectMinX = minX2 - halfStroke2;
843
- const rectMinY = minY2 - halfStroke2;
844
- const rectMaxX = maxX2 + halfStroke2;
845
- const rectMaxY = maxY2 + halfStroke2;
846
- if (rectMaxX - rectMinX < 1 || rectMaxY - rectMinY < 1) return;
847
- const rect = {
848
- origin: { x: rectMinX, y: rectMinY },
849
- size: { width: rectMaxX - rectMinX, height: rectMaxY - rectMinY }
850
- };
1722
+ const rect2 = expandRect(rectFromPoints(allPoints2), toolStrokeWidth / 2);
1723
+ if (rect2.size.width < 1 || rect2.size.height < 1) return;
851
1724
  const anno = {
852
1725
  type: PdfAnnotationSubtype.INK,
853
- rect,
1726
+ intent,
1727
+ blendMode: toolBlendMode,
1728
+ rect: rect2,
854
1729
  inkList: currentStrokes,
855
1730
  color: toolColor,
856
1731
  opacity: toolOpacity,
@@ -901,22 +1776,12 @@ const InkPaint = ({ pageIndex, scale, pageWidth, pageHeight }) => {
901
1776
  if (!currentStrokes.length) return null;
902
1777
  const allPoints = currentStrokes.flatMap((s) => s.points);
903
1778
  if (!allPoints.length) return null;
904
- const minX = Math.min(...allPoints.map((p) => p.x));
905
- const minY = Math.min(...allPoints.map((p) => p.y));
906
- const maxX = Math.max(...allPoints.map((p) => p.x));
907
- const maxY = Math.max(...allPoints.map((p) => p.y));
908
- const halfStroke = MAX_STROKE_WIDTH / 2;
909
- const svgMinX = minX - halfStroke;
910
- const svgMinY = minY - halfStroke;
911
- const svgMaxX = maxX + halfStroke;
912
- const svgMaxY = maxY + halfStroke;
913
- const dw = svgMaxX - svgMinX;
914
- const dh = svgMaxY - svgMinY;
1779
+ const rect = expandRect(rectFromPoints(allPoints), toolStrokeWidth / 2);
915
1780
  const paths = currentStrokes.map(({ points }) => {
916
1781
  let d = "";
917
1782
  points.forEach(({ x, y }, i) => {
918
- const lx = x - svgMinX;
919
- const ly = y - svgMinY;
1783
+ const lx = x - rect.origin.x;
1784
+ const ly = y - rect.origin.y;
920
1785
  d += (i === 0 ? "M" : "L") + lx + " " + ly + " ";
921
1786
  });
922
1787
  return d.trim();
@@ -926,42 +1791,763 @@ const InkPaint = ({ pageIndex, scale, pageWidth, pageHeight }) => {
926
1791
  {
927
1792
  style: {
928
1793
  position: "absolute",
929
- left: svgMinX * scale,
930
- top: svgMinY * scale,
931
- width: dw * scale,
932
- 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,
933
1798
  pointerEvents: "none",
934
1799
  zIndex: 2
935
1800
  },
936
- width: dw * scale,
937
- height: dh * scale,
938
- viewBox: `0 0 ${dw} ${dh}`,
1801
+ width: rect.size.width * scale,
1802
+ height: rect.size.height * scale,
1803
+ viewBox: `0 0 ${rect.size.width} ${rect.size.height}`,
939
1804
  children: paths.map((d, i) => /* @__PURE__ */ jsx(
940
1805
  "path",
941
1806
  {
942
1807
  d,
943
1808
  fill: "none",
944
- stroke: toolColor,
945
- strokeWidth: toolStrokeWidth,
946
- strokeLinecap: "round",
947
- strokeLinejoin: "round",
948
- opacity: toolOpacity
1809
+ opacity: toolOpacity,
1810
+ style: {
1811
+ stroke: toolColor,
1812
+ strokeWidth: toolStrokeWidth,
1813
+ strokeLinecap: "round",
1814
+ strokeLinejoin: "round"
1815
+ }
949
1816
  },
950
1817
  i
951
1818
  ))
952
1819
  }
953
1820
  );
954
1821
  };
955
- function AnnotationLayer({
1822
+ const CirclePaint = ({
956
1823
  pageIndex,
957
1824
  scale,
958
1825
  pageWidth,
959
1826
  pageHeight,
960
- rotation,
961
- style,
962
- ...props
963
- }) {
964
- return /* @__PURE__ */ jsxs(
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(
965
2551
  "div",
966
2552
  {
967
2553
  style: {
@@ -969,9 +2555,64 @@ function AnnotationLayer({
969
2555
  },
970
2556
  ...props,
971
2557
  children: [
972
- /* @__PURE__ */ jsx(Annotations, { pageIndex, scale, rotation }),
2558
+ /* @__PURE__ */ jsx(
2559
+ Annotations,
2560
+ {
2561
+ selectionMenu,
2562
+ pageIndex,
2563
+ scale,
2564
+ rotation,
2565
+ pageWidth,
2566
+ pageHeight
2567
+ }
2568
+ ),
973
2569
  /* @__PURE__ */ jsx(TextMarkup, { pageIndex, scale }),
974
- /* @__PURE__ */ jsx(InkPaint, { pageIndex, scale, pageWidth, pageHeight })
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
+ )
975
2616
  ]
976
2617
  }
977
2618
  );