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