@embedpdf/plugin-annotation 1.0.12 → 1.0.14

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