@embedpdf/plugin-annotation 1.1.0 → 1.2.0

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 (107) hide show
  1. package/dist/index.cjs +1 -1
  2. package/dist/index.cjs.map +1 -1
  3. package/dist/index.js +1916 -390
  4. package/dist/index.js.map +1 -1
  5. package/dist/lib/actions.d.ts +21 -15
  6. package/dist/lib/annotation-plugin.d.ts +30 -7
  7. package/dist/lib/handlers/circle.handler.d.ts +3 -0
  8. package/dist/lib/handlers/click-detector.d.ts +27 -0
  9. package/dist/lib/handlers/free-text.handler.d.ts +3 -0
  10. package/dist/lib/handlers/index.d.ts +8 -0
  11. package/dist/lib/handlers/ink.handler.d.ts +3 -0
  12. package/dist/lib/handlers/line.handler.d.ts +3 -0
  13. package/dist/lib/handlers/polygon.handler.d.ts +3 -0
  14. package/dist/lib/handlers/polyline.handler.d.ts +3 -0
  15. package/dist/lib/handlers/square.handler.d.ts +3 -0
  16. package/dist/lib/handlers/stamp.handler.d.ts +3 -0
  17. package/dist/lib/handlers/types.d.ts +139 -0
  18. package/dist/lib/helpers.d.ts +1 -6
  19. package/dist/lib/index.d.ts +3 -1
  20. package/dist/lib/patching/index.d.ts +1 -1
  21. package/dist/lib/patching/patch-registry.d.ts +27 -0
  22. package/dist/lib/patching/patches/index.d.ts +4 -0
  23. package/dist/lib/patching/patches/ink.patch.d.ts +3 -0
  24. package/dist/lib/patching/patches/line.patch.d.ts +3 -0
  25. package/dist/lib/patching/patches/polygon.patch.d.ts +3 -0
  26. package/dist/lib/patching/patches/polyline.patch.d.ts +3 -0
  27. package/dist/lib/selectors.d.ts +8 -12
  28. package/dist/lib/tools/default-tools.d.ts +450 -0
  29. package/dist/lib/tools/tools-utils.d.ts +25 -0
  30. package/dist/lib/tools/types.d.ts +96 -0
  31. package/dist/lib/types.d.ts +78 -161
  32. package/dist/lib/utils/index.d.ts +1 -0
  33. package/dist/lib/utils/use-state.d.ts +12 -0
  34. package/dist/preact/adapter.d.ts +1 -5
  35. package/dist/preact/index.cjs +1 -1
  36. package/dist/preact/index.cjs.map +1 -1
  37. package/dist/preact/index.js +390 -1795
  38. package/dist/preact/index.js.map +1 -1
  39. package/dist/react/adapter.d.ts +2 -4
  40. package/dist/react/index.cjs +1 -1
  41. package/dist/react/index.cjs.map +1 -1
  42. package/dist/react/index.js +391 -1794
  43. package/dist/react/index.js.map +1 -1
  44. package/dist/shared-preact/components/annotation-container.d.ts +18 -16
  45. package/dist/shared-preact/components/annotation-layer.d.ts +9 -2
  46. package/dist/shared-preact/components/annotation-paint-layer.d.ts +6 -0
  47. package/dist/shared-preact/components/annotations/free-text.d.ts +1 -0
  48. package/dist/shared-preact/components/annotations/polygon.d.ts +4 -1
  49. package/dist/shared-preact/components/annotations.d.ts +4 -1
  50. package/dist/shared-preact/components/preview-renderer.d.ts +7 -0
  51. package/dist/shared-preact/components/text-markup/highlight.d.ts +2 -2
  52. package/dist/shared-preact/components/text-markup/squiggly.d.ts +2 -2
  53. package/dist/shared-preact/components/text-markup/strikeout.d.ts +2 -2
  54. package/dist/shared-preact/components/text-markup/underline.d.ts +2 -2
  55. package/dist/shared-preact/types.d.ts +32 -2
  56. package/dist/shared-react/components/annotation-container.d.ts +18 -16
  57. package/dist/shared-react/components/annotation-layer.d.ts +9 -2
  58. package/dist/shared-react/components/annotation-paint-layer.d.ts +6 -0
  59. package/dist/shared-react/components/annotations/free-text.d.ts +1 -0
  60. package/dist/shared-react/components/annotations/polygon.d.ts +4 -1
  61. package/dist/shared-react/components/annotations.d.ts +4 -1
  62. package/dist/shared-react/components/preview-renderer.d.ts +7 -0
  63. package/dist/shared-react/components/text-markup/highlight.d.ts +2 -2
  64. package/dist/shared-react/components/text-markup/squiggly.d.ts +2 -2
  65. package/dist/shared-react/components/text-markup/strikeout.d.ts +2 -2
  66. package/dist/shared-react/components/text-markup/underline.d.ts +2 -2
  67. package/dist/shared-react/types.d.ts +32 -2
  68. package/dist/vue/hooks/index.d.ts +1 -0
  69. package/dist/vue/hooks/use-annotation.d.ts +3 -0
  70. package/dist/vue/index.cjs +2 -0
  71. package/dist/vue/index.cjs.map +1 -0
  72. package/dist/vue/index.d.ts +2 -0
  73. package/dist/vue/index.js +10 -0
  74. package/dist/vue/index.js.map +1 -0
  75. package/package.json +18 -11
  76. package/dist/lib/patching/derived-rect.d.ts +0 -2
  77. package/dist/lib/variant-key.d.ts +0 -8
  78. package/dist/shared-preact/components/annotations/circle-paint.d.ts +0 -10
  79. package/dist/shared-preact/components/annotations/free-text-paint.d.ts +0 -10
  80. package/dist/shared-preact/components/annotations/ink-highlight-paint.d.ts +0 -0
  81. package/dist/shared-preact/components/annotations/ink-paint.d.ts +0 -18
  82. package/dist/shared-preact/components/annotations/line-paint.d.ts +0 -10
  83. package/dist/shared-preact/components/annotations/polygon-paint.d.ts +0 -9
  84. package/dist/shared-preact/components/annotations/polyline-paint.d.ts +0 -10
  85. package/dist/shared-preact/components/annotations/square-paint.d.ts +0 -10
  86. package/dist/shared-preact/components/annotations/stamp-paint.d.ts +0 -8
  87. package/dist/shared-preact/components/resize-handles.d.ts +0 -9
  88. package/dist/shared-preact/components/vertex-editor.d.ts +0 -19
  89. package/dist/shared-preact/hooks/use-drag-resize.d.ts +0 -38
  90. package/dist/shared-preact/patch-ink.d.ts +0 -16
  91. package/dist/shared-preact/patchers.d.ts +0 -9
  92. package/dist/shared-preact/vertex-patchers.d.ts +0 -10
  93. package/dist/shared-react/components/annotations/circle-paint.d.ts +0 -10
  94. package/dist/shared-react/components/annotations/free-text-paint.d.ts +0 -10
  95. package/dist/shared-react/components/annotations/ink-highlight-paint.d.ts +0 -0
  96. package/dist/shared-react/components/annotations/ink-paint.d.ts +0 -17
  97. package/dist/shared-react/components/annotations/line-paint.d.ts +0 -10
  98. package/dist/shared-react/components/annotations/polygon-paint.d.ts +0 -9
  99. package/dist/shared-react/components/annotations/polyline-paint.d.ts +0 -10
  100. package/dist/shared-react/components/annotations/square-paint.d.ts +0 -10
  101. package/dist/shared-react/components/annotations/stamp-paint.d.ts +0 -8
  102. package/dist/shared-react/components/resize-handles.d.ts +0 -9
  103. package/dist/shared-react/components/vertex-editor.d.ts +0 -19
  104. package/dist/shared-react/hooks/use-drag-resize.d.ts +0 -38
  105. package/dist/shared-react/patch-ink.d.ts +0 -16
  106. package/dist/shared-react/patchers.d.ts +0 -9
  107. package/dist/shared-react/vertex-patchers.d.ts +0 -10
package/dist/index.js CHANGED
@@ -1,5 +1,5 @@
1
- import { BasePlugin, createBehaviorEmitter, SET_DOCUMENT } from "@embedpdf/core";
2
- import { PdfAnnotationSubtype, PdfAnnotationLineEnding, rectFromPoints, expandRect, rotateAndTranslatePoint, PdfBlendMode, uuidV4, ignore, PdfTaskHelper, PdfErrorCode, Task, PdfVerticalAlignment, PdfTextAlignment, PdfStandardFont, PdfAnnotationBorderStyle } from "@embedpdf/models";
1
+ import { clamp, BasePlugin, createBehaviorEmitter, SET_DOCUMENT } from "@embedpdf/core";
2
+ import { PdfAnnotationSubtype, expandRect, rectFromPoints, uuidV4, PdfVerticalAlignment, PdfTextAlignment, PdfStandardFont, PdfAnnotationLineEnding, rotateAndTranslatePoint, PdfAnnotationBorderStyle, PdfAnnotationIcon, ignore, PdfTaskHelper, PdfErrorCode, Task, PdfBlendMode } from "@embedpdf/models";
3
3
  const ANNOTATION_PLUGIN_ID = "annotation";
4
4
  const manifest = {
5
5
  id: ANNOTATION_PLUGIN_ID,
@@ -11,20 +11,23 @@ const manifest = {
11
11
  defaultConfig: {
12
12
  enabled: true,
13
13
  autoCommit: true,
14
- annotationAuthor: "Guest"
14
+ annotationAuthor: "Guest",
15
+ deactivateToolAfterCreate: false,
16
+ selectAfterCreate: true
15
17
  }
16
18
  };
17
19
  const SET_ANNOTATIONS = "ANNOTATION/SET_ANNOTATIONS";
18
20
  const SELECT_ANNOTATION = "ANNOTATION/SELECT_ANNOTATION";
19
21
  const DESELECT_ANNOTATION = "ANNOTATION/DESELECT_ANNOTATION";
20
- const UPDATE_TOOL_DEFAULTS = "ANNOTATION/UPDATE_TOOL_DEFAULTS";
21
22
  const ADD_COLOR_PRESET = "ANNOTATION/ADD_COLOR_PRESET";
22
23
  const CREATE_ANNOTATION = "ANNOTATION/CREATE_ANNOTATION";
23
24
  const PATCH_ANNOTATION = "ANNOTATION/PATCH_ANNOTATION";
24
25
  const DELETE_ANNOTATION = "ANNOTATION/DELETE_ANNOTATION";
25
26
  const COMMIT_PENDING_CHANGES = "ANNOTATION/COMMIT";
26
27
  const PURGE_ANNOTATION = "ANNOTATION/PURGE_ANNOTATION";
27
- const SET_ACTIVE_VARIANT = "ANNOTATION/SET_ACTIVE_VARIANT";
28
+ const SET_ACTIVE_TOOL_ID = "ANNOTATION/SET_ACTIVE_TOOL_ID";
29
+ const SET_TOOL_DEFAULTS = "ANNOTATION/SET_TOOL_DEFAULTS";
30
+ const ADD_TOOL = "ANNOTATION/ADD_TOOL";
28
31
  const setAnnotations = (p) => ({
29
32
  type: SET_ANNOTATIONS,
30
33
  payload: p
@@ -34,19 +37,12 @@ const selectAnnotation = (pageIndex, id) => ({
34
37
  payload: { pageIndex, id }
35
38
  });
36
39
  const deselectAnnotation = () => ({ type: DESELECT_ANNOTATION });
37
- const updateToolDefaults = (variantKey, patch) => ({ type: UPDATE_TOOL_DEFAULTS, payload: { variantKey, patch } });
38
40
  const addColorPreset = (c) => ({
39
41
  type: ADD_COLOR_PRESET,
40
42
  payload: c
41
43
  });
42
- const createAnnotation = (pageIndex, annotation) => ({
43
- type: CREATE_ANNOTATION,
44
- payload: { pageIndex, annotation }
45
- });
46
- const patchAnnotation = (pageIndex, id, patch) => ({
47
- type: PATCH_ANNOTATION,
48
- payload: { pageIndex, id, patch }
49
- });
44
+ const createAnnotation = (pageIndex, annotation) => ({ type: CREATE_ANNOTATION, payload: { pageIndex, annotation } });
45
+ const patchAnnotation = (pageIndex, id, patch) => ({ type: PATCH_ANNOTATION, payload: { pageIndex, id, patch } });
50
46
  const deleteAnnotation = (pageIndex, id) => ({
51
47
  type: DELETE_ANNOTATION,
52
48
  payload: { pageIndex, id }
@@ -56,16 +52,15 @@ const purgeAnnotation = (uid) => ({
56
52
  type: PURGE_ANNOTATION,
57
53
  payload: { uid }
58
54
  });
59
- const setActiveVariant = (k) => ({
60
- type: SET_ACTIVE_VARIANT,
61
- payload: k
55
+ const setActiveToolId = (id) => ({
56
+ type: SET_ACTIVE_TOOL_ID,
57
+ payload: id
62
58
  });
63
- const makeVariantKey = (subtype, intent) => intent ? `${subtype}#${intent}` : `${subtype}`;
64
- const parseVariantKey = (key) => {
65
- const [subStr, intent] = key.split("#");
66
- return { subtype: Number(subStr), intent };
67
- };
68
- const variantKeyFromAnnotation = (a) => makeVariantKey(a.type, a.intent);
59
+ const setToolDefaults = (toolId, patch) => ({
60
+ type: SET_TOOL_DEFAULTS,
61
+ payload: { toolId, patch }
62
+ });
63
+ const addTool = (tool) => ({ type: ADD_TOOL, payload: tool });
69
64
  function isInk(a) {
70
65
  return a.object.type === PdfAnnotationSubtype.INK;
71
66
  }
@@ -111,21 +106,6 @@ function isText(a) {
111
106
  function isSidebarAnnotation(a) {
112
107
  return isTextMarkup(a) || isInk(a) || isSquare(a) || isCircle(a) || isPolygon(a) || isLine(a) || isPolyline(a) || isFreeText(a) || isStamp(a);
113
108
  }
114
- function isHighlightDefaults(defaults) {
115
- return defaults.subtype === PdfAnnotationSubtype.HIGHLIGHT;
116
- }
117
- function isUnderlineDefaults(defaults) {
118
- return defaults.subtype === PdfAnnotationSubtype.UNDERLINE;
119
- }
120
- function isStrikeoutDefaults(defaults) {
121
- return defaults.subtype === PdfAnnotationSubtype.STRIKEOUT;
122
- }
123
- function isSquigglyDefaults(defaults) {
124
- return defaults.subtype === PdfAnnotationSubtype.SQUIGGLY;
125
- }
126
- function isTextMarkupDefaults(defaults) {
127
- return isHighlightDefaults(defaults) || isUnderlineDefaults(defaults) || isStrikeoutDefaults(defaults) || isSquigglyDefaults(defaults);
128
- }
129
109
  const getAnnotationsByPageIndex = (s, page) => (s.pages[page] ?? []).map((uid) => s.byUid[uid]);
130
110
  const getAnnotations = (s) => {
131
111
  const out = {};
@@ -141,26 +121,17 @@ const getSelectedAnnotationByPageIndex = (s, pageIndex) => {
141
121
  }
142
122
  return null;
143
123
  };
144
- const isInAnnotationVariant = (s) => s.activeVariant !== null;
145
- const getSelectedAnnotationVariant = (s) => s.activeVariant;
146
124
  const isAnnotationSelected = (s, id) => s.selectedUid === id;
147
- function getToolDefaultsBySubtypeAndIntent(state, subtype, intent) {
148
- const variantKey = makeVariantKey(subtype, intent ?? void 0);
149
- const fallbackKey = makeVariantKey(subtype);
150
- const defaults = state.toolDefaults[variantKey] ?? state.toolDefaults[fallbackKey];
151
- if (!defaults) {
152
- throw new Error(
153
- `No tool defaults found for subtype ${subtype}${intent ? ` and intent ${intent}` : ""}`
154
- );
155
- }
156
- return defaults;
125
+ function getToolDefaultsById(state, toolId) {
126
+ const tool = state.tools.find((t) => t.id === toolId);
127
+ return tool == null ? void 0 : tool.defaults;
157
128
  }
158
129
  const getSidebarAnnotationsWithRepliesGroupedByPage = (s) => {
159
130
  const repliesByParent = {};
160
131
  for (const uidList of Object.values(s.pages)) {
161
132
  for (const uid of uidList) {
162
133
  const ta = s.byUid[uid];
163
- if (isText(ta)) {
134
+ if (ta && isText(ta)) {
164
135
  const parentId = ta.object.inReplyToId;
165
136
  if (parentId) (repliesByParent[parentId] || (repliesByParent[parentId] = [])).push(ta);
166
137
  }
@@ -172,7 +143,7 @@ const getSidebarAnnotationsWithRepliesGroupedByPage = (s) => {
172
143
  const pageAnnotations = [];
173
144
  for (const uid of uidList) {
174
145
  const ta = s.byUid[uid];
175
- if (isSidebarAnnotation(ta)) {
146
+ if (ta && isSidebarAnnotation(ta)) {
176
147
  pageAnnotations.push({
177
148
  page,
178
149
  annotation: ta,
@@ -195,6 +166,293 @@ const getSidebarAnnotationsWithReplies = (s) => {
195
166
  }
196
167
  return out;
197
168
  };
169
+ function useState(initialValue) {
170
+ let value = initialValue;
171
+ const getValue = () => value;
172
+ const setValue = (newValue) => {
173
+ value = newValue;
174
+ };
175
+ return [getValue, setValue];
176
+ }
177
+ const inkHandlerFactory = {
178
+ annotationType: PdfAnnotationSubtype.INK,
179
+ create(context) {
180
+ const { onCommit, onPreview, getTool, pageSize } = context;
181
+ const [getStrokes, setStrokes] = useState([]);
182
+ const [getIsDrawing, setIsDrawing] = useState(false);
183
+ const timerRef = { current: null };
184
+ const clampToPage = (pos) => ({
185
+ x: clamp(pos.x, 0, pageSize.width),
186
+ y: clamp(pos.y, 0, pageSize.height)
187
+ });
188
+ const getDefaults = () => {
189
+ const tool = getTool();
190
+ if (!tool) return null;
191
+ return {
192
+ ...tool.defaults,
193
+ strokeWidth: tool.defaults.strokeWidth ?? 1,
194
+ color: tool.defaults.color ?? "#000000",
195
+ opacity: tool.defaults.opacity ?? 1
196
+ };
197
+ };
198
+ const getPreview = () => {
199
+ const strokes = getStrokes();
200
+ if (strokes.length === 0 || strokes[0].points.length === 0) return null;
201
+ const defaults = getDefaults();
202
+ if (!defaults) return null;
203
+ const allPoints = strokes.flatMap((s) => s.points);
204
+ const bounds = expandRect(rectFromPoints(allPoints), defaults.strokeWidth / 2);
205
+ return {
206
+ type: PdfAnnotationSubtype.INK,
207
+ bounds,
208
+ data: {
209
+ ...defaults,
210
+ rect: bounds,
211
+ inkList: strokes
212
+ }
213
+ };
214
+ };
215
+ return {
216
+ onPointerDown: (pos, evt) => {
217
+ var _a;
218
+ const clampedPos = clampToPage(pos);
219
+ setIsDrawing(true);
220
+ if (timerRef.current) clearTimeout(timerRef.current);
221
+ const newStrokes = [...getStrokes(), { points: [clampedPos] }];
222
+ setStrokes(newStrokes);
223
+ onPreview(getPreview());
224
+ (_a = evt.setPointerCapture) == null ? void 0 : _a.call(evt);
225
+ },
226
+ onPointerMove: (pos) => {
227
+ if (!getIsDrawing()) return;
228
+ const strokes = getStrokes();
229
+ if (strokes.length === 0) return;
230
+ const clampedPos = clampToPage(pos);
231
+ strokes[strokes.length - 1].points.push(clampedPos);
232
+ setStrokes(strokes);
233
+ onPreview(getPreview());
234
+ },
235
+ onPointerUp: (_, evt) => {
236
+ var _a;
237
+ setIsDrawing(false);
238
+ (_a = evt.releasePointerCapture) == null ? void 0 : _a.call(evt);
239
+ if (timerRef.current) clearTimeout(timerRef.current);
240
+ timerRef.current = setTimeout(() => {
241
+ const strokes = getStrokes();
242
+ if (strokes.length > 0 && strokes[0].points.length > 1) {
243
+ const defaults = getDefaults();
244
+ if (!defaults) return;
245
+ const allPoints = strokes.flatMap((s) => s.points);
246
+ const rect = expandRect(rectFromPoints(allPoints), defaults.strokeWidth / 2);
247
+ onCommit({
248
+ ...defaults,
249
+ inkList: strokes,
250
+ rect,
251
+ type: PdfAnnotationSubtype.INK,
252
+ flags: ["print"],
253
+ pageIndex: context.pageIndex,
254
+ id: uuidV4(),
255
+ created: /* @__PURE__ */ new Date()
256
+ });
257
+ }
258
+ setStrokes([]);
259
+ onPreview(null);
260
+ }, 800);
261
+ },
262
+ onPointerCancel: (_, evt) => {
263
+ var _a;
264
+ setStrokes([]);
265
+ setIsDrawing(false);
266
+ onPreview(null);
267
+ if (timerRef.current) clearTimeout(timerRef.current);
268
+ (_a = evt.releasePointerCapture) == null ? void 0 : _a.call(evt);
269
+ }
270
+ };
271
+ }
272
+ };
273
+ function useClickDetector({
274
+ threshold = 5,
275
+ getTool,
276
+ onClickDetected
277
+ }) {
278
+ const [getStartPos, setStartPos] = useState(null);
279
+ const [getHasMoved, setHasMoved] = useState(false);
280
+ return {
281
+ onStart: (pos) => {
282
+ setStartPos(pos);
283
+ setHasMoved(false);
284
+ },
285
+ onMove: (pos) => {
286
+ const start = getStartPos();
287
+ if (!start || getHasMoved()) return;
288
+ const distance = Math.sqrt(Math.pow(pos.x - start.x, 2) + Math.pow(pos.y - start.y, 2));
289
+ if (distance > threshold) {
290
+ setHasMoved(true);
291
+ }
292
+ },
293
+ onEnd: (pos) => {
294
+ var _a;
295
+ const start = getStartPos();
296
+ if (start && !getHasMoved()) {
297
+ const tool = getTool();
298
+ if (tool && "clickBehavior" in tool && ((_a = tool.clickBehavior) == null ? void 0 : _a.enabled)) {
299
+ onClickDetected(pos, tool);
300
+ }
301
+ }
302
+ setStartPos(null);
303
+ setHasMoved(false);
304
+ },
305
+ hasMoved: getHasMoved,
306
+ reset: () => {
307
+ setStartPos(null);
308
+ setHasMoved(false);
309
+ }
310
+ };
311
+ }
312
+ const freeTextHandlerFactory = {
313
+ annotationType: PdfAnnotationSubtype.FREETEXT,
314
+ create(context) {
315
+ const { onCommit, onPreview, getTool, pageSize, pageIndex } = context;
316
+ const [getStart, setStart] = useState(null);
317
+ const clampToPage = (pos) => ({
318
+ x: clamp(pos.x, 0, pageSize.width),
319
+ y: clamp(pos.y, 0, pageSize.height)
320
+ });
321
+ const getDefaults = () => {
322
+ const tool = getTool();
323
+ if (!tool) return null;
324
+ return {
325
+ ...tool.defaults,
326
+ fontColor: tool.defaults.fontColor ?? "#000000",
327
+ opacity: tool.defaults.opacity ?? 1,
328
+ fontSize: tool.defaults.fontSize ?? 12,
329
+ fontFamily: tool.defaults.fontFamily ?? PdfStandardFont.Helvetica,
330
+ backgroundColor: tool.defaults.backgroundColor ?? "transparent",
331
+ textAlign: tool.defaults.textAlign ?? PdfTextAlignment.Left,
332
+ verticalAlign: tool.defaults.verticalAlign ?? PdfVerticalAlignment.Top,
333
+ contents: tool.defaults.contents ?? "Insert text here"
334
+ };
335
+ };
336
+ const clickDetector = useClickDetector({
337
+ threshold: 5,
338
+ getTool,
339
+ onClickDetected: (pos, tool) => {
340
+ const defaults = getDefaults();
341
+ if (!defaults) return;
342
+ const clickConfig = tool.clickBehavior;
343
+ if (!(clickConfig == null ? void 0 : clickConfig.enabled)) return;
344
+ const { width, height } = clickConfig.defaultSize;
345
+ const halfWidth = width / 2;
346
+ const halfHeight = height / 2;
347
+ const x = clamp(pos.x - halfWidth, 0, pageSize.width - width);
348
+ const y = clamp(pos.y - halfHeight, 0, pageSize.height - height);
349
+ const rect = {
350
+ origin: { x, y },
351
+ size: { width, height }
352
+ };
353
+ const contents = clickConfig.defaultContent ?? defaults.contents;
354
+ const anno = {
355
+ ...defaults,
356
+ contents,
357
+ type: PdfAnnotationSubtype.FREETEXT,
358
+ rect,
359
+ flags: ["print"],
360
+ pageIndex,
361
+ id: uuidV4(),
362
+ created: /* @__PURE__ */ new Date()
363
+ };
364
+ onCommit(anno);
365
+ }
366
+ });
367
+ const getPreview = (current) => {
368
+ const start = getStart();
369
+ if (!start) return null;
370
+ const defaults = getDefaults();
371
+ if (!defaults) return null;
372
+ const minX = Math.min(start.x, current.x);
373
+ const minY = Math.min(start.y, current.y);
374
+ const width = Math.abs(start.x - current.x);
375
+ const height = Math.abs(start.y - current.y);
376
+ const rect = {
377
+ origin: { x: minX, y: minY },
378
+ size: { width, height }
379
+ };
380
+ return {
381
+ type: PdfAnnotationSubtype.FREETEXT,
382
+ bounds: rect,
383
+ data: {
384
+ ...defaults,
385
+ rect
386
+ }
387
+ };
388
+ };
389
+ return {
390
+ onPointerDown: (pos, evt) => {
391
+ var _a;
392
+ const clampedPos = clampToPage(pos);
393
+ setStart(clampedPos);
394
+ clickDetector.onStart(clampedPos);
395
+ onPreview(getPreview(clampedPos));
396
+ (_a = evt.setPointerCapture) == null ? void 0 : _a.call(evt);
397
+ },
398
+ onPointerMove: (pos) => {
399
+ const clampedPos = clampToPage(pos);
400
+ clickDetector.onMove(clampedPos);
401
+ if (getStart() && clickDetector.hasMoved()) {
402
+ onPreview(getPreview(clampedPos));
403
+ }
404
+ },
405
+ onPointerUp: (pos, evt) => {
406
+ var _a;
407
+ const start = getStart();
408
+ if (!start) return;
409
+ const defaults = getDefaults();
410
+ if (!defaults) return;
411
+ const clampedPos = clampToPage(pos);
412
+ if (!clickDetector.hasMoved()) {
413
+ clickDetector.onEnd(clampedPos);
414
+ } else {
415
+ const minX = Math.min(start.x, clampedPos.x);
416
+ const minY = Math.min(start.y, clampedPos.y);
417
+ const width = Math.abs(start.x - clampedPos.x);
418
+ const height = Math.abs(start.y - clampedPos.y);
419
+ const rect = {
420
+ origin: { x: minX, y: minY },
421
+ size: { width, height }
422
+ };
423
+ const anno = {
424
+ ...defaults,
425
+ type: PdfAnnotationSubtype.FREETEXT,
426
+ rect,
427
+ flags: ["print"],
428
+ pageIndex: context.pageIndex,
429
+ id: uuidV4(),
430
+ created: /* @__PURE__ */ new Date()
431
+ };
432
+ onCommit(anno);
433
+ }
434
+ setStart(null);
435
+ onPreview(null);
436
+ clickDetector.reset();
437
+ (_a = evt.releasePointerCapture) == null ? void 0 : _a.call(evt);
438
+ },
439
+ onPointerLeave: (_, evt) => {
440
+ var _a;
441
+ setStart(null);
442
+ onPreview(null);
443
+ clickDetector.reset();
444
+ (_a = evt.releasePointerCapture) == null ? void 0 : _a.call(evt);
445
+ },
446
+ onPointerCancel: (_, evt) => {
447
+ var _a;
448
+ setStart(null);
449
+ onPreview(null);
450
+ clickDetector.reset();
451
+ (_a = evt.releasePointerCapture) == null ? void 0 : _a.call(evt);
452
+ }
453
+ };
454
+ }
455
+ };
198
456
  function createArrowHandler(isClosed) {
199
457
  const calculateGeometry = (sw) => {
200
458
  const len = sw * 9;
@@ -344,38 +602,6 @@ function lineRectWithEndings(vertices, strokeWidth, endings) {
344
602
  const pad = strokeWidth / 2 + EXTRA_PADDING * strokeWidth;
345
603
  return expandRect(baseRect, pad);
346
604
  }
347
- const vertsRect = (verts, sw) => expandRect(rectFromPoints(verts), sw / 2);
348
- function deriveRect(a) {
349
- switch (a.type) {
350
- /* mark‑ups already carry their real rect */
351
- case PdfAnnotationSubtype.HIGHLIGHT:
352
- case PdfAnnotationSubtype.UNDERLINE:
353
- case PdfAnnotationSubtype.STRIKEOUT:
354
- case PdfAnnotationSubtype.SQUIGGLY:
355
- case PdfAnnotationSubtype.SQUARE:
356
- case PdfAnnotationSubtype.CIRCLE:
357
- return a.rect;
358
- /* ink */
359
- case PdfAnnotationSubtype.INK: {
360
- const pts = a.inkList.flatMap((s) => s.points);
361
- return vertsRect(pts, a.strokeWidth);
362
- }
363
- /* one‑segment */
364
- case PdfAnnotationSubtype.LINE:
365
- return lineRectWithEndings(
366
- [a.linePoints.start, a.linePoints.end],
367
- a.strokeWidth,
368
- a.lineEndings
369
- );
370
- /* multi‑segment */
371
- case PdfAnnotationSubtype.POLYLINE:
372
- return lineRectWithEndings(a.vertices, a.strokeWidth, a.lineEndings);
373
- case PdfAnnotationSubtype.POLYGON:
374
- return vertsRect(a.vertices, a.strokeWidth);
375
- default:
376
- return a.rect;
377
- }
378
- }
379
605
  function createEnding(ending, strokeWidth, rad, px, py) {
380
606
  if (!ending) return null;
381
607
  const handler = LINE_ENDING_HANDLERS[ending];
@@ -388,187 +614,1249 @@ function createEnding(ending, strokeWidth, rad, px, py) {
388
614
  filled: handler.filled
389
615
  };
390
616
  }
617
+ class PatchRegistry {
618
+ constructor() {
619
+ this.patches = /* @__PURE__ */ new Map();
620
+ }
621
+ register(type, patchFn) {
622
+ this.patches.set(type, patchFn);
623
+ }
624
+ /**
625
+ * Transform an annotation based on the context.
626
+ * Returns the transformed properties or just the changes if no patch function exists.
627
+ */
628
+ transform(annotation, context) {
629
+ const patchFn = this.patches.get(annotation.type);
630
+ if (patchFn) {
631
+ return patchFn(annotation, context);
632
+ }
633
+ return context.changes;
634
+ }
635
+ }
636
+ const patchRegistry = new PatchRegistry();
391
637
  const index = /* @__PURE__ */ Object.freeze(/* @__PURE__ */ Object.defineProperty({
392
638
  __proto__: null,
393
639
  LINE_ENDING_HANDLERS,
640
+ PatchRegistry,
394
641
  createEnding,
395
- deriveRect,
396
- lineRectWithEndings
642
+ lineRectWithEndings,
643
+ patchRegistry
397
644
  }, Symbol.toStringTag, { value: "Module" }));
645
+ const lineHandlerFactory = {
646
+ annotationType: PdfAnnotationSubtype.LINE,
647
+ create(context) {
648
+ const { pageIndex, onCommit, onPreview, getTool, pageSize } = context;
649
+ const [getStart, setStart] = useState(null);
650
+ const clampToPage = (pos) => ({
651
+ x: clamp(pos.x, 0, pageSize.width),
652
+ y: clamp(pos.y, 0, pageSize.height)
653
+ });
654
+ const getDefaults = () => {
655
+ const tool = getTool();
656
+ if (!tool) return null;
657
+ return {
658
+ ...tool.defaults,
659
+ strokeWidth: tool.defaults.strokeWidth ?? 1,
660
+ lineEndings: tool.defaults.lineEndings ?? {
661
+ start: PdfAnnotationLineEnding.None,
662
+ end: PdfAnnotationLineEnding.None
663
+ },
664
+ color: tool.defaults.color ?? "#000000",
665
+ opacity: tool.defaults.opacity ?? 1,
666
+ strokeStyle: tool.defaults.strokeStyle ?? PdfAnnotationBorderStyle.SOLID,
667
+ strokeDashArray: tool.defaults.strokeDashArray ?? [],
668
+ strokeColor: tool.defaults.strokeColor ?? "#000000"
669
+ };
670
+ };
671
+ const clickDetector = useClickDetector({
672
+ threshold: 5,
673
+ getTool,
674
+ onClickDetected: (pos, tool) => {
675
+ const defaults = getDefaults();
676
+ if (!defaults) return;
677
+ const clickConfig = tool.clickBehavior;
678
+ if (!(clickConfig == null ? void 0 : clickConfig.enabled)) return;
679
+ const angle = clickConfig.defaultAngle ?? 0;
680
+ const length = clickConfig.defaultLength;
681
+ const halfLength = length / 2;
682
+ const startX = pos.x - halfLength * Math.cos(angle);
683
+ const startY = pos.y - halfLength * Math.sin(angle);
684
+ const endX = pos.x + halfLength * Math.cos(angle);
685
+ const endY = pos.y + halfLength * Math.sin(angle);
686
+ const start = clampToPage({ x: startX, y: startY });
687
+ const end = clampToPage({ x: endX, y: endY });
688
+ const rect = lineRectWithEndings(
689
+ [start, end],
690
+ defaults.strokeWidth,
691
+ defaults.lineEndings
692
+ );
693
+ onCommit({
694
+ ...defaults,
695
+ rect,
696
+ linePoints: { start, end },
697
+ pageIndex,
698
+ id: uuidV4(),
699
+ flags: ["print"],
700
+ created: /* @__PURE__ */ new Date(),
701
+ type: PdfAnnotationSubtype.LINE
702
+ });
703
+ }
704
+ });
705
+ const getPreview = (current) => {
706
+ const start = getStart();
707
+ if (!start) return null;
708
+ const defaults = getDefaults();
709
+ if (!defaults) return null;
710
+ const bounds = lineRectWithEndings(
711
+ [start, current],
712
+ defaults.strokeWidth,
713
+ defaults.lineEndings
714
+ );
715
+ return {
716
+ type: PdfAnnotationSubtype.LINE,
717
+ bounds,
718
+ data: {
719
+ ...defaults,
720
+ rect: bounds,
721
+ linePoints: { start, end: current }
722
+ }
723
+ };
724
+ };
725
+ return {
726
+ onPointerDown: (pos, evt) => {
727
+ var _a;
728
+ const clampedPos = clampToPage(pos);
729
+ setStart(clampedPos);
730
+ clickDetector.onStart(clampedPos);
731
+ onPreview(getPreview(clampedPos));
732
+ (_a = evt.setPointerCapture) == null ? void 0 : _a.call(evt);
733
+ },
734
+ onPointerMove: (pos) => {
735
+ const clampedPos = clampToPage(pos);
736
+ clickDetector.onMove(clampedPos);
737
+ if (getStart() && clickDetector.hasMoved()) {
738
+ onPreview(getPreview(clampedPos));
739
+ }
740
+ },
741
+ onPointerUp: (pos, evt) => {
742
+ var _a;
743
+ const start = getStart();
744
+ if (!start) return;
745
+ const clampedPos = clampToPage(pos);
746
+ if (!clickDetector.hasMoved()) {
747
+ clickDetector.onEnd(clampedPos);
748
+ } else {
749
+ const defaults = getDefaults();
750
+ if (!defaults) return;
751
+ if (Math.abs(clampedPos.x - start.x) > 2 || Math.abs(clampedPos.y - start.y) > 2) {
752
+ const rect = lineRectWithEndings(
753
+ [start, clampedPos],
754
+ defaults.strokeWidth,
755
+ defaults.lineEndings
756
+ );
757
+ onCommit({
758
+ ...defaults,
759
+ rect,
760
+ linePoints: { start, end: clampedPos },
761
+ pageIndex,
762
+ id: uuidV4(),
763
+ flags: ["print"],
764
+ created: /* @__PURE__ */ new Date(),
765
+ type: PdfAnnotationSubtype.LINE
766
+ });
767
+ }
768
+ }
769
+ setStart(null);
770
+ onPreview(null);
771
+ clickDetector.reset();
772
+ (_a = evt.releasePointerCapture) == null ? void 0 : _a.call(evt);
773
+ },
774
+ onPointerLeave: (_, evt) => {
775
+ var _a;
776
+ setStart(null);
777
+ onPreview(null);
778
+ clickDetector.reset();
779
+ (_a = evt.releasePointerCapture) == null ? void 0 : _a.call(evt);
780
+ },
781
+ onPointerCancel: (_, evt) => {
782
+ var _a;
783
+ setStart(null);
784
+ onPreview(null);
785
+ clickDetector.reset();
786
+ (_a = evt.releasePointerCapture) == null ? void 0 : _a.call(evt);
787
+ }
788
+ };
789
+ }
790
+ };
791
+ const polylineHandlerFactory = {
792
+ annotationType: PdfAnnotationSubtype.POLYLINE,
793
+ create(context) {
794
+ const { onCommit, onPreview, getTool, pageSize } = context;
795
+ const [getVertices, setVertices] = useState([]);
796
+ const [getCurrent, setCurrent] = useState(null);
797
+ const clampToPage = (pos) => ({
798
+ x: clamp(pos.x, 0, pageSize.width),
799
+ y: clamp(pos.y, 0, pageSize.height)
800
+ });
801
+ const getDefaults = () => {
802
+ const tool = getTool();
803
+ if (!tool) return null;
804
+ return {
805
+ ...tool.defaults,
806
+ strokeWidth: tool.defaults.strokeWidth ?? 1,
807
+ lineEndings: tool.defaults.lineEndings ?? {
808
+ start: PdfAnnotationLineEnding.None,
809
+ end: PdfAnnotationLineEnding.None
810
+ },
811
+ color: tool.defaults.color ?? "#000000",
812
+ opacity: tool.defaults.opacity ?? 1,
813
+ strokeColor: tool.defaults.strokeColor ?? "#000000",
814
+ strokeStyle: tool.defaults.strokeStyle ?? PdfAnnotationBorderStyle.SOLID,
815
+ strokeDashArray: tool.defaults.strokeDashArray ?? []
816
+ };
817
+ };
818
+ const commitPolyline = () => {
819
+ const vertices = getVertices();
820
+ if (vertices.length < 2) return;
821
+ const defaults = getDefaults();
822
+ if (!defaults) return;
823
+ const rect = lineRectWithEndings(
824
+ vertices,
825
+ defaults.strokeWidth,
826
+ defaults.lineEndings
827
+ );
828
+ const anno = {
829
+ ...defaults,
830
+ vertices,
831
+ rect,
832
+ type: PdfAnnotationSubtype.POLYLINE,
833
+ flags: ["print"],
834
+ pageIndex: context.pageIndex,
835
+ id: uuidV4(),
836
+ created: /* @__PURE__ */ new Date()
837
+ };
838
+ onCommit(anno);
839
+ setVertices([]);
840
+ setCurrent(null);
841
+ onPreview(null);
842
+ };
843
+ const getPreview = () => {
844
+ const vertices = getVertices();
845
+ const currentPos = getCurrent();
846
+ if (vertices.length === 0 || !currentPos) return null;
847
+ const defaults = getDefaults();
848
+ if (!defaults) return null;
849
+ const allPoints = [...vertices, currentPos];
850
+ const bounds = lineRectWithEndings(
851
+ allPoints,
852
+ defaults.strokeWidth,
853
+ defaults.lineEndings
854
+ );
855
+ return {
856
+ type: PdfAnnotationSubtype.POLYLINE,
857
+ bounds,
858
+ data: {
859
+ ...defaults,
860
+ rect: bounds,
861
+ vertices: allPoints,
862
+ currentVertex: currentPos
863
+ }
864
+ };
865
+ };
866
+ return {
867
+ onClick: (pos) => {
868
+ const clampedPos = clampToPage(pos);
869
+ const vertices = getVertices();
870
+ const lastVertex = vertices[vertices.length - 1];
871
+ if (lastVertex && Math.abs(lastVertex.x - clampedPos.x) < 1 && Math.abs(lastVertex.y - clampedPos.y) < 1) {
872
+ return;
873
+ }
874
+ setVertices([...vertices, clampedPos]);
875
+ setCurrent(clampedPos);
876
+ onPreview(getPreview());
877
+ },
878
+ onDoubleClick: () => {
879
+ commitPolyline();
880
+ },
881
+ onPointerMove: (pos) => {
882
+ if (getVertices().length > 0) {
883
+ const clampedPos = clampToPage(pos);
884
+ setCurrent(clampedPos);
885
+ onPreview(getPreview());
886
+ }
887
+ },
888
+ onPointerCancel: () => {
889
+ setVertices([]);
890
+ setCurrent(null);
891
+ onPreview(null);
892
+ }
893
+ };
894
+ }
895
+ };
896
+ const HANDLE_SIZE_PX = 14;
897
+ const polygonHandlerFactory = {
898
+ annotationType: PdfAnnotationSubtype.POLYGON,
899
+ create(context) {
900
+ const { onCommit, onPreview, getTool, scale, pageSize } = context;
901
+ const [getVertices, setVertices] = useState([]);
902
+ const [getCurrent, setCurrent] = useState(null);
903
+ const clampToPage = (pos) => ({
904
+ x: clamp(pos.x, 0, pageSize.width),
905
+ y: clamp(pos.y, 0, pageSize.height)
906
+ });
907
+ const isInsideStartHandle = (pos) => {
908
+ const vertices = getVertices();
909
+ if (vertices.length < 2) return false;
910
+ const sizePDF = HANDLE_SIZE_PX / scale;
911
+ const half = sizePDF / 2;
912
+ const v0 = vertices[0];
913
+ return pos.x >= v0.x - half && pos.x <= v0.x + half && pos.y >= v0.y - half && pos.y <= v0.y + half;
914
+ };
915
+ const getDefaults = () => {
916
+ const tool = getTool();
917
+ if (!tool) return null;
918
+ return {
919
+ ...tool.defaults,
920
+ color: tool.defaults.color ?? "#000000",
921
+ opacity: tool.defaults.opacity ?? 1,
922
+ strokeWidth: tool.defaults.strokeWidth ?? 1,
923
+ strokeColor: tool.defaults.strokeColor ?? "#000000",
924
+ strokeStyle: tool.defaults.strokeStyle ?? PdfAnnotationBorderStyle.SOLID,
925
+ strokeDashArray: tool.defaults.strokeDashArray ?? []
926
+ };
927
+ };
928
+ const commitPolygon = () => {
929
+ const vertices = getVertices();
930
+ if (vertices.length < 3) return;
931
+ const defaults = getDefaults();
932
+ if (!defaults) return;
933
+ const rect = expandRect(rectFromPoints(vertices), defaults.strokeWidth / 2);
934
+ const anno = {
935
+ ...defaults,
936
+ vertices,
937
+ rect,
938
+ type: PdfAnnotationSubtype.POLYGON,
939
+ flags: ["print"],
940
+ pageIndex: context.pageIndex,
941
+ id: uuidV4(),
942
+ created: /* @__PURE__ */ new Date()
943
+ };
944
+ onCommit(anno);
945
+ setVertices([]);
946
+ setCurrent(null);
947
+ onPreview(null);
948
+ };
949
+ const getPreview = () => {
950
+ const vertices = getVertices();
951
+ const currentPos = getCurrent();
952
+ if (vertices.length === 0 || !currentPos) return null;
953
+ const defaults = getDefaults();
954
+ if (!defaults) return null;
955
+ const allPoints = [...vertices, currentPos];
956
+ const bounds = expandRect(rectFromPoints(allPoints), defaults.strokeWidth / 2);
957
+ return {
958
+ type: PdfAnnotationSubtype.POLYGON,
959
+ bounds,
960
+ data: {
961
+ ...defaults,
962
+ rect: bounds,
963
+ vertices,
964
+ currentVertex: currentPos
965
+ }
966
+ };
967
+ };
968
+ return {
969
+ onClick: (pos) => {
970
+ const clampedPos = clampToPage(pos);
971
+ if (isInsideStartHandle(clampedPos) && getVertices().length >= 3) {
972
+ commitPolygon();
973
+ return;
974
+ }
975
+ const vertices = getVertices();
976
+ const lastVertex = vertices[vertices.length - 1];
977
+ if (lastVertex && Math.abs(lastVertex.x - clampedPos.x) < 1 && Math.abs(lastVertex.y - clampedPos.y) < 1) {
978
+ return;
979
+ }
980
+ setVertices([...vertices, clampedPos]);
981
+ setCurrent(clampedPos);
982
+ onPreview(getPreview());
983
+ },
984
+ onDoubleClick: (_) => {
985
+ commitPolygon();
986
+ },
987
+ onPointerMove: (pos) => {
988
+ if (getVertices().length > 0) {
989
+ const clampedPos = clampToPage(pos);
990
+ setCurrent(clampedPos);
991
+ onPreview(getPreview());
992
+ }
993
+ },
994
+ onPointerCancel: (_) => {
995
+ setVertices([]);
996
+ setCurrent(null);
997
+ onPreview(null);
998
+ }
999
+ };
1000
+ }
1001
+ };
1002
+ const squareHandlerFactory = {
1003
+ annotationType: PdfAnnotationSubtype.SQUARE,
1004
+ create(context) {
1005
+ const { pageIndex, onCommit, onPreview, getTool, pageSize } = context;
1006
+ const [getStart, setStart] = useState(null);
1007
+ const clampToPage = (pos) => ({
1008
+ x: clamp(pos.x, 0, pageSize.width),
1009
+ y: clamp(pos.y, 0, pageSize.height)
1010
+ });
1011
+ const getDefaults = () => {
1012
+ const tool = getTool();
1013
+ if (!tool) return null;
1014
+ return {
1015
+ ...tool.defaults,
1016
+ strokeWidth: tool.defaults.strokeWidth ?? 2,
1017
+ strokeColor: tool.defaults.strokeColor ?? "#000000",
1018
+ strokeStyle: tool.defaults.strokeStyle ?? PdfAnnotationBorderStyle.SOLID,
1019
+ strokeDashArray: tool.defaults.strokeDashArray ?? [],
1020
+ color: tool.defaults.color ?? "#000000",
1021
+ opacity: tool.defaults.opacity ?? 1
1022
+ };
1023
+ };
1024
+ const clickDetector = useClickDetector({
1025
+ threshold: 5,
1026
+ getTool,
1027
+ onClickDetected: (pos, tool) => {
1028
+ const defaults = getDefaults();
1029
+ if (!defaults) return;
1030
+ const clickConfig = tool.clickBehavior;
1031
+ if (!(clickConfig == null ? void 0 : clickConfig.enabled)) return;
1032
+ const { width, height } = clickConfig.defaultSize;
1033
+ const halfWidth = width / 2;
1034
+ const halfHeight = height / 2;
1035
+ const x = clamp(pos.x - halfWidth, 0, pageSize.width - width);
1036
+ const y = clamp(pos.y - halfHeight, 0, pageSize.height - height);
1037
+ const strokeWidth = defaults.strokeWidth;
1038
+ const halfStroke = strokeWidth / 2;
1039
+ const rect = {
1040
+ origin: { x: x - halfStroke, y: y - halfStroke },
1041
+ size: { width: width + strokeWidth, height: height + strokeWidth }
1042
+ };
1043
+ const anno = {
1044
+ ...defaults,
1045
+ type: PdfAnnotationSubtype.SQUARE,
1046
+ flags: ["print"],
1047
+ created: /* @__PURE__ */ new Date(),
1048
+ id: uuidV4(),
1049
+ pageIndex,
1050
+ rect
1051
+ };
1052
+ onCommit(anno);
1053
+ }
1054
+ });
1055
+ const getPreview = (current) => {
1056
+ const p1 = getStart();
1057
+ if (!p1) return null;
1058
+ const minX = Math.min(p1.x, current.x);
1059
+ const minY = Math.min(p1.y, current.y);
1060
+ const width = Math.abs(p1.x - current.x);
1061
+ const height = Math.abs(p1.y - current.y);
1062
+ const defaults = getDefaults();
1063
+ if (!defaults) return null;
1064
+ const strokeWidth = defaults.strokeWidth;
1065
+ const halfStroke = strokeWidth / 2;
1066
+ const rect = {
1067
+ origin: { x: minX - halfStroke, y: minY - halfStroke },
1068
+ size: { width: width + strokeWidth, height: height + strokeWidth }
1069
+ };
1070
+ return {
1071
+ type: PdfAnnotationSubtype.SQUARE,
1072
+ bounds: rect,
1073
+ data: {
1074
+ rect,
1075
+ ...defaults
1076
+ }
1077
+ };
1078
+ };
1079
+ return {
1080
+ onPointerDown: (pos, evt) => {
1081
+ var _a;
1082
+ const clampedPos = clampToPage(pos);
1083
+ setStart(clampedPos);
1084
+ clickDetector.onStart(clampedPos);
1085
+ onPreview(getPreview(clampedPos));
1086
+ (_a = evt.setPointerCapture) == null ? void 0 : _a.call(evt);
1087
+ },
1088
+ onPointerMove: (pos) => {
1089
+ const clampedPos = clampToPage(pos);
1090
+ clickDetector.onMove(clampedPos);
1091
+ if (getStart() && clickDetector.hasMoved()) {
1092
+ onPreview(getPreview(clampedPos));
1093
+ }
1094
+ },
1095
+ onPointerUp: (pos, evt) => {
1096
+ var _a;
1097
+ const p1 = getStart();
1098
+ if (!p1) return;
1099
+ const defaults = getDefaults();
1100
+ if (!defaults) return;
1101
+ const clampedPos = clampToPage(pos);
1102
+ if (!clickDetector.hasMoved()) {
1103
+ clickDetector.onEnd(clampedPos);
1104
+ } else {
1105
+ const defaults2 = getDefaults();
1106
+ if (!defaults2) return;
1107
+ const preview = getPreview(clampedPos);
1108
+ if (preview) {
1109
+ const anno = {
1110
+ ...defaults2,
1111
+ type: PdfAnnotationSubtype.SQUARE,
1112
+ flags: ["print"],
1113
+ created: /* @__PURE__ */ new Date(),
1114
+ id: uuidV4(),
1115
+ pageIndex,
1116
+ rect: preview.data.rect
1117
+ };
1118
+ onCommit(anno);
1119
+ }
1120
+ }
1121
+ setStart(null);
1122
+ onPreview(null);
1123
+ clickDetector.reset();
1124
+ (_a = evt.releasePointerCapture) == null ? void 0 : _a.call(evt);
1125
+ },
1126
+ onPointerLeave: (_, evt) => {
1127
+ var _a;
1128
+ setStart(null);
1129
+ onPreview(null);
1130
+ clickDetector.reset();
1131
+ (_a = evt.releasePointerCapture) == null ? void 0 : _a.call(evt);
1132
+ },
1133
+ onPointerCancel: (_, evt) => {
1134
+ var _a;
1135
+ setStart(null);
1136
+ onPreview(null);
1137
+ clickDetector.reset();
1138
+ (_a = evt.releasePointerCapture) == null ? void 0 : _a.call(evt);
1139
+ }
1140
+ };
1141
+ }
1142
+ };
1143
+ const stampHandlerFactory = {
1144
+ annotationType: PdfAnnotationSubtype.STAMP,
1145
+ create(context) {
1146
+ const { services, onCommit, getTool, pageSize } = context;
1147
+ return {
1148
+ onPointerDown: (pos) => {
1149
+ const tool = getTool();
1150
+ if (!tool) return;
1151
+ const { imageSrc, imageSize } = tool.defaults;
1152
+ const placeStamp = (imageData, width, height) => {
1153
+ const originX = pos.x - width / 2;
1154
+ const originY = pos.y - height / 2;
1155
+ const finalX = clamp(originX, 0, pageSize.width - width);
1156
+ const finalY = clamp(originY, 0, pageSize.height - height);
1157
+ const rect = {
1158
+ origin: { x: finalX, y: finalY },
1159
+ size: { width, height }
1160
+ };
1161
+ const anno = {
1162
+ rect,
1163
+ type: PdfAnnotationSubtype.STAMP,
1164
+ icon: PdfAnnotationIcon.Draft,
1165
+ subject: "Stamp",
1166
+ pageIndex: context.pageIndex,
1167
+ id: uuidV4(),
1168
+ created: /* @__PURE__ */ new Date(),
1169
+ flags: ["print"]
1170
+ };
1171
+ onCommit(anno, { imageData });
1172
+ };
1173
+ if (imageSrc) {
1174
+ services.processImage({
1175
+ source: imageSrc,
1176
+ maxWidth: pageSize.width,
1177
+ maxHeight: pageSize.height,
1178
+ onComplete: (result) => placeStamp(
1179
+ result.imageData,
1180
+ (imageSize == null ? void 0 : imageSize.width) ?? result.width,
1181
+ (imageSize == null ? void 0 : imageSize.height) ?? result.height
1182
+ )
1183
+ });
1184
+ } else {
1185
+ services.requestFile({
1186
+ accept: "image/png,image/jpeg",
1187
+ onFile: (file) => {
1188
+ services.processImage({
1189
+ source: file,
1190
+ maxWidth: pageSize.width,
1191
+ maxHeight: pageSize.height,
1192
+ onComplete: (result) => placeStamp(result.imageData, result.width, result.height)
1193
+ });
1194
+ }
1195
+ });
1196
+ }
1197
+ }
1198
+ };
1199
+ }
1200
+ };
1201
+ const circleHandlerFactory = {
1202
+ annotationType: PdfAnnotationSubtype.CIRCLE,
1203
+ create(context) {
1204
+ const { pageIndex, onCommit, onPreview, getTool, pageSize } = context;
1205
+ const [getStart, setStart] = useState(null);
1206
+ const clampToPage = (pos) => ({
1207
+ x: clamp(pos.x, 0, pageSize.width),
1208
+ y: clamp(pos.y, 0, pageSize.height)
1209
+ });
1210
+ const getDefaults = () => {
1211
+ const tool = getTool();
1212
+ if (!tool) return null;
1213
+ return {
1214
+ ...tool.defaults,
1215
+ strokeWidth: tool.defaults.strokeWidth ?? 2,
1216
+ strokeColor: tool.defaults.strokeColor ?? "#000000",
1217
+ strokeStyle: tool.defaults.strokeStyle ?? PdfAnnotationBorderStyle.SOLID,
1218
+ strokeDashArray: tool.defaults.strokeDashArray ?? [],
1219
+ color: tool.defaults.color ?? "#000000",
1220
+ opacity: tool.defaults.opacity ?? 1
1221
+ };
1222
+ };
1223
+ const clickDetector = useClickDetector({
1224
+ threshold: 5,
1225
+ getTool,
1226
+ onClickDetected: (pos, tool) => {
1227
+ const defaults = getDefaults();
1228
+ if (!defaults) return;
1229
+ const clickConfig = tool.clickBehavior;
1230
+ if (!(clickConfig == null ? void 0 : clickConfig.enabled)) return;
1231
+ const { width, height } = clickConfig.defaultSize;
1232
+ const halfWidth = width / 2;
1233
+ const halfHeight = height / 2;
1234
+ const x = clamp(pos.x - halfWidth, 0, pageSize.width - width);
1235
+ const y = clamp(pos.y - halfHeight, 0, pageSize.height - height);
1236
+ const strokeWidth = defaults.strokeWidth;
1237
+ const halfStroke = strokeWidth / 2;
1238
+ const rect = {
1239
+ origin: { x: x - halfStroke, y: y - halfStroke },
1240
+ size: { width: width + strokeWidth, height: height + strokeWidth }
1241
+ };
1242
+ const anno = {
1243
+ ...defaults,
1244
+ type: PdfAnnotationSubtype.CIRCLE,
1245
+ flags: ["print"],
1246
+ created: /* @__PURE__ */ new Date(),
1247
+ id: uuidV4(),
1248
+ pageIndex,
1249
+ rect
1250
+ };
1251
+ onCommit(anno);
1252
+ }
1253
+ });
1254
+ const getPreview = (current) => {
1255
+ const p1 = getStart();
1256
+ if (!p1) return null;
1257
+ const minX = Math.min(p1.x, current.x);
1258
+ const minY = Math.min(p1.y, current.y);
1259
+ const width = Math.abs(p1.x - current.x);
1260
+ const height = Math.abs(p1.y - current.y);
1261
+ const defaults = getDefaults();
1262
+ if (!defaults) return null;
1263
+ const strokeWidth = defaults.strokeWidth;
1264
+ const halfStroke = strokeWidth / 2;
1265
+ const rect = {
1266
+ origin: { x: minX - halfStroke, y: minY - halfStroke },
1267
+ size: { width: width + strokeWidth, height: height + strokeWidth }
1268
+ };
1269
+ return {
1270
+ type: PdfAnnotationSubtype.CIRCLE,
1271
+ bounds: rect,
1272
+ data: {
1273
+ rect,
1274
+ ...defaults
1275
+ }
1276
+ };
1277
+ };
1278
+ return {
1279
+ onPointerDown: (pos, evt) => {
1280
+ var _a;
1281
+ const clampedPos = clampToPage(pos);
1282
+ setStart(clampedPos);
1283
+ clickDetector.onStart(clampedPos);
1284
+ onPreview(getPreview(clampedPos));
1285
+ (_a = evt.setPointerCapture) == null ? void 0 : _a.call(evt);
1286
+ },
1287
+ onPointerMove: (pos) => {
1288
+ const clampedPos = clampToPage(pos);
1289
+ clickDetector.onMove(clampedPos);
1290
+ if (getStart() && clickDetector.hasMoved()) {
1291
+ onPreview(getPreview(clampedPos));
1292
+ }
1293
+ },
1294
+ onPointerUp: (pos, evt) => {
1295
+ var _a;
1296
+ const p1 = getStart();
1297
+ if (!p1) return;
1298
+ const defaults = getDefaults();
1299
+ if (!defaults) return;
1300
+ const clampedPos = clampToPage(pos);
1301
+ if (!clickDetector.hasMoved()) {
1302
+ clickDetector.onEnd(clampedPos);
1303
+ } else {
1304
+ const defaults2 = getDefaults();
1305
+ if (!defaults2) return;
1306
+ const preview = getPreview(clampedPos);
1307
+ if (preview) {
1308
+ const anno = {
1309
+ ...defaults2,
1310
+ type: PdfAnnotationSubtype.CIRCLE,
1311
+ flags: ["print"],
1312
+ created: /* @__PURE__ */ new Date(),
1313
+ id: uuidV4(),
1314
+ pageIndex,
1315
+ rect: preview.data.rect
1316
+ };
1317
+ onCommit(anno);
1318
+ }
1319
+ }
1320
+ setStart(null);
1321
+ onPreview(null);
1322
+ clickDetector.reset();
1323
+ (_a = evt.releasePointerCapture) == null ? void 0 : _a.call(evt);
1324
+ },
1325
+ onPointerLeave: (_, evt) => {
1326
+ var _a;
1327
+ setStart(null);
1328
+ onPreview(null);
1329
+ clickDetector.reset();
1330
+ (_a = evt.releasePointerCapture) == null ? void 0 : _a.call(evt);
1331
+ },
1332
+ onPointerCancel: (_, evt) => {
1333
+ var _a;
1334
+ setStart(null);
1335
+ onPreview(null);
1336
+ clickDetector.reset();
1337
+ (_a = evt.releasePointerCapture) == null ? void 0 : _a.call(evt);
1338
+ }
1339
+ };
1340
+ }
1341
+ };
1342
+ const patchInk = (original, ctx) => {
1343
+ var _a;
1344
+ switch (ctx.type) {
1345
+ case "vertex-edit":
1346
+ return ctx.changes;
1347
+ case "move":
1348
+ if (ctx.changes.rect) {
1349
+ const dx = ctx.changes.rect.origin.x - original.rect.origin.x;
1350
+ const dy = ctx.changes.rect.origin.y - original.rect.origin.y;
1351
+ const movedInkList = original.inkList.map((stroke) => ({
1352
+ points: stroke.points.map((p) => ({
1353
+ x: p.x + dx,
1354
+ y: p.y + dy
1355
+ }))
1356
+ }));
1357
+ return {
1358
+ rect: ctx.changes.rect,
1359
+ inkList: movedInkList
1360
+ };
1361
+ }
1362
+ return ctx.changes;
1363
+ case "resize":
1364
+ if (ctx.changes.rect) {
1365
+ const oldRect = original.rect;
1366
+ const newRect = ctx.changes.rect;
1367
+ let scaleX = newRect.size.width / oldRect.size.width;
1368
+ let scaleY = newRect.size.height / oldRect.size.height;
1369
+ const minSize = 10;
1370
+ if (newRect.size.width < minSize || newRect.size.height < minSize) {
1371
+ scaleX = Math.max(scaleX, minSize / oldRect.size.width);
1372
+ scaleY = Math.max(scaleY, minSize / oldRect.size.height);
1373
+ ctx.changes.rect = {
1374
+ origin: newRect.origin,
1375
+ size: {
1376
+ width: oldRect.size.width * scaleX,
1377
+ height: oldRect.size.height * scaleY
1378
+ }
1379
+ };
1380
+ }
1381
+ if ((_a = ctx.metadata) == null ? void 0 : _a.maintainAspectRatio) {
1382
+ const minScale = Math.min(scaleX, scaleY);
1383
+ scaleX = minScale;
1384
+ scaleY = minScale;
1385
+ ctx.changes.rect.size = {
1386
+ width: oldRect.size.width * minScale,
1387
+ height: oldRect.size.height * minScale
1388
+ };
1389
+ }
1390
+ const inset = (r, pad) => ({
1391
+ origin: { x: r.origin.x + pad, y: r.origin.y + pad },
1392
+ size: {
1393
+ width: Math.max(1, r.size.width - pad * 2),
1394
+ height: Math.max(1, r.size.height - pad * 2)
1395
+ }
1396
+ });
1397
+ const strokeScale = Math.min(
1398
+ ctx.changes.rect.size.width / oldRect.size.width,
1399
+ ctx.changes.rect.size.height / oldRect.size.height
1400
+ );
1401
+ const newStrokeWidth = Math.max(1, Math.round(original.strokeWidth * strokeScale));
1402
+ const innerOld = inset(oldRect, original.strokeWidth / 2);
1403
+ const innerNew = inset(ctx.changes.rect, newStrokeWidth / 2);
1404
+ const sx = innerNew.size.width / Math.max(innerOld.size.width, 1e-6);
1405
+ const sy = innerNew.size.height / Math.max(innerOld.size.height, 1e-6);
1406
+ const newInkList = original.inkList.map((stroke) => ({
1407
+ points: stroke.points.map((p) => ({
1408
+ x: innerNew.origin.x + (p.x - innerOld.origin.x) * sx,
1409
+ y: innerNew.origin.y + (p.y - innerOld.origin.y) * sy
1410
+ }))
1411
+ }));
1412
+ return {
1413
+ rect: ctx.changes.rect,
1414
+ inkList: newInkList,
1415
+ strokeWidth: newStrokeWidth
1416
+ };
1417
+ }
1418
+ return ctx.changes;
1419
+ case "property-update":
1420
+ if (ctx.changes.strokeWidth !== void 0) {
1421
+ const merged = { ...original, ...ctx.changes };
1422
+ const pts = merged.inkList.flatMap((s) => s.points);
1423
+ const rect = expandRect(rectFromPoints(pts), merged.strokeWidth / 2);
1424
+ return { ...ctx.changes, rect };
1425
+ }
1426
+ return ctx.changes;
1427
+ default:
1428
+ return ctx.changes;
1429
+ }
1430
+ };
1431
+ const patchLine = (orig, ctx) => {
1432
+ var _a;
1433
+ switch (ctx.type) {
1434
+ case "vertex-edit":
1435
+ if (ctx.changes.linePoints) {
1436
+ const { start, end } = ctx.changes.linePoints;
1437
+ const rect = lineRectWithEndings([start, end], orig.strokeWidth, orig.lineEndings);
1438
+ return {
1439
+ rect,
1440
+ linePoints: { start, end }
1441
+ };
1442
+ }
1443
+ return ctx.changes;
1444
+ case "move":
1445
+ if (ctx.changes.rect) {
1446
+ const dx = ctx.changes.rect.origin.x - orig.rect.origin.x;
1447
+ const dy = ctx.changes.rect.origin.y - orig.rect.origin.y;
1448
+ return {
1449
+ rect: ctx.changes.rect,
1450
+ linePoints: {
1451
+ start: { x: orig.linePoints.start.x + dx, y: orig.linePoints.start.y + dy },
1452
+ end: { x: orig.linePoints.end.x + dx, y: orig.linePoints.end.y + dy }
1453
+ }
1454
+ };
1455
+ }
1456
+ return ctx.changes;
1457
+ case "resize":
1458
+ if (ctx.changes.rect) {
1459
+ const oldRect = orig.rect;
1460
+ const newRect = ctx.changes.rect;
1461
+ let scaleX = newRect.size.width / oldRect.size.width;
1462
+ let scaleY = newRect.size.height / oldRect.size.height;
1463
+ const minSize = 10;
1464
+ if (newRect.size.width < minSize || newRect.size.height < minSize) {
1465
+ scaleX = Math.max(scaleX, minSize / oldRect.size.width);
1466
+ scaleY = Math.max(scaleY, minSize / oldRect.size.height);
1467
+ ctx.changes.rect = {
1468
+ origin: newRect.origin,
1469
+ size: {
1470
+ width: oldRect.size.width * scaleX,
1471
+ height: oldRect.size.height * scaleY
1472
+ }
1473
+ };
1474
+ }
1475
+ if ((_a = ctx.metadata) == null ? void 0 : _a.maintainAspectRatio) {
1476
+ const minScale = Math.min(scaleX, scaleY);
1477
+ scaleX = minScale;
1478
+ scaleY = minScale;
1479
+ ctx.changes.rect.size = {
1480
+ width: oldRect.size.width * minScale,
1481
+ height: oldRect.size.height * minScale
1482
+ };
1483
+ }
1484
+ const newLinePoints = {
1485
+ start: {
1486
+ x: ctx.changes.rect.origin.x + (orig.linePoints.start.x - oldRect.origin.x) * scaleX,
1487
+ y: ctx.changes.rect.origin.y + (orig.linePoints.start.y - oldRect.origin.y) * scaleY
1488
+ },
1489
+ end: {
1490
+ x: ctx.changes.rect.origin.x + (orig.linePoints.end.x - oldRect.origin.x) * scaleX,
1491
+ y: ctx.changes.rect.origin.y + (orig.linePoints.end.y - oldRect.origin.y) * scaleY
1492
+ }
1493
+ };
1494
+ return {
1495
+ rect: ctx.changes.rect,
1496
+ linePoints: newLinePoints
1497
+ };
1498
+ }
1499
+ return ctx.changes;
1500
+ case "property-update":
1501
+ if (ctx.changes.strokeWidth || ctx.changes.lineEndings) {
1502
+ const merged = { ...orig, ...ctx.changes };
1503
+ const rect = lineRectWithEndings(
1504
+ [merged.linePoints.start, merged.linePoints.end],
1505
+ merged.strokeWidth,
1506
+ merged.lineEndings
1507
+ );
1508
+ return { ...ctx.changes, rect };
1509
+ }
1510
+ return ctx.changes;
1511
+ default:
1512
+ return ctx.changes;
1513
+ }
1514
+ };
1515
+ const patchPolyline = (orig, ctx) => {
1516
+ var _a;
1517
+ switch (ctx.type) {
1518
+ case "vertex-edit":
1519
+ if (ctx.changes.vertices && ctx.changes.vertices.length) {
1520
+ return {
1521
+ rect: lineRectWithEndings(ctx.changes.vertices, orig.strokeWidth, orig.lineEndings),
1522
+ vertices: ctx.changes.vertices
1523
+ };
1524
+ }
1525
+ return ctx.changes;
1526
+ case "move":
1527
+ if (ctx.changes.rect) {
1528
+ const dx = ctx.changes.rect.origin.x - orig.rect.origin.x;
1529
+ const dy = ctx.changes.rect.origin.y - orig.rect.origin.y;
1530
+ const moved = orig.vertices.map((p) => ({ x: p.x + dx, y: p.y + dy }));
1531
+ return {
1532
+ rect: ctx.changes.rect,
1533
+ vertices: moved
1534
+ };
1535
+ }
1536
+ return ctx.changes;
1537
+ case "resize":
1538
+ if (ctx.changes.rect) {
1539
+ const oldRect = orig.rect;
1540
+ const newRect = ctx.changes.rect;
1541
+ let scaleX = newRect.size.width / oldRect.size.width;
1542
+ let scaleY = newRect.size.height / oldRect.size.height;
1543
+ const minSize = 10;
1544
+ if (newRect.size.width < minSize || newRect.size.height < minSize) {
1545
+ scaleX = Math.max(scaleX, minSize / oldRect.size.width);
1546
+ scaleY = Math.max(scaleY, minSize / oldRect.size.height);
1547
+ ctx.changes.rect = {
1548
+ origin: newRect.origin,
1549
+ size: {
1550
+ width: oldRect.size.width * scaleX,
1551
+ height: oldRect.size.height * scaleY
1552
+ }
1553
+ };
1554
+ }
1555
+ if ((_a = ctx.metadata) == null ? void 0 : _a.maintainAspectRatio) {
1556
+ const minScale = Math.min(scaleX, scaleY);
1557
+ scaleX = minScale;
1558
+ scaleY = minScale;
1559
+ ctx.changes.rect.size = {
1560
+ width: oldRect.size.width * minScale,
1561
+ height: oldRect.size.height * minScale
1562
+ };
1563
+ }
1564
+ const scaledVertices = orig.vertices.map((vertex) => ({
1565
+ x: ctx.changes.rect.origin.x + (vertex.x - oldRect.origin.x) * scaleX,
1566
+ y: ctx.changes.rect.origin.y + (vertex.y - oldRect.origin.y) * scaleY
1567
+ }));
1568
+ return {
1569
+ rect: ctx.changes.rect,
1570
+ vertices: scaledVertices
1571
+ };
1572
+ }
1573
+ return ctx.changes;
1574
+ case "property-update":
1575
+ if (ctx.changes.strokeWidth !== void 0 || ctx.changes.lineEndings !== void 0) {
1576
+ const merged = { ...orig, ...ctx.changes };
1577
+ const rect = lineRectWithEndings(merged.vertices, merged.strokeWidth, merged.lineEndings);
1578
+ return { ...ctx.changes, rect };
1579
+ }
1580
+ return ctx.changes;
1581
+ default:
1582
+ return ctx.changes;
1583
+ }
1584
+ };
1585
+ const patchPolygon = (orig, ctx) => {
1586
+ var _a;
1587
+ switch (ctx.type) {
1588
+ case "vertex-edit":
1589
+ if (ctx.changes.vertices && ctx.changes.vertices.length) {
1590
+ const pad = orig.strokeWidth / 2;
1591
+ return {
1592
+ rect: expandRect(rectFromPoints(ctx.changes.vertices), pad),
1593
+ vertices: ctx.changes.vertices
1594
+ };
1595
+ }
1596
+ return ctx.changes;
1597
+ case "move":
1598
+ if (ctx.changes.rect) {
1599
+ const dx = ctx.changes.rect.origin.x - orig.rect.origin.x;
1600
+ const dy = ctx.changes.rect.origin.y - orig.rect.origin.y;
1601
+ const moved = orig.vertices.map((p) => ({ x: p.x + dx, y: p.y + dy }));
1602
+ return {
1603
+ rect: ctx.changes.rect,
1604
+ vertices: moved
1605
+ };
1606
+ }
1607
+ return ctx.changes;
1608
+ case "resize":
1609
+ if (ctx.changes.rect) {
1610
+ const oldRect = orig.rect;
1611
+ const newRect = ctx.changes.rect;
1612
+ let scaleX = newRect.size.width / oldRect.size.width;
1613
+ let scaleY = newRect.size.height / oldRect.size.height;
1614
+ const minSize = 10;
1615
+ if (newRect.size.width < minSize || newRect.size.height < minSize) {
1616
+ scaleX = Math.max(scaleX, minSize / oldRect.size.width);
1617
+ scaleY = Math.max(scaleY, minSize / oldRect.size.height);
1618
+ ctx.changes.rect = {
1619
+ origin: newRect.origin,
1620
+ size: {
1621
+ width: oldRect.size.width * scaleX,
1622
+ height: oldRect.size.height * scaleY
1623
+ }
1624
+ };
1625
+ }
1626
+ if ((_a = ctx.metadata) == null ? void 0 : _a.maintainAspectRatio) {
1627
+ const minScale = Math.min(scaleX, scaleY);
1628
+ scaleX = minScale;
1629
+ scaleY = minScale;
1630
+ ctx.changes.rect.size = {
1631
+ width: oldRect.size.width * minScale,
1632
+ height: oldRect.size.height * minScale
1633
+ };
1634
+ }
1635
+ const scaledVertices = orig.vertices.map((vertex) => ({
1636
+ x: ctx.changes.rect.origin.x + (vertex.x - oldRect.origin.x) * scaleX,
1637
+ y: ctx.changes.rect.origin.y + (vertex.y - oldRect.origin.y) * scaleY
1638
+ }));
1639
+ return {
1640
+ rect: ctx.changes.rect,
1641
+ vertices: scaledVertices
1642
+ };
1643
+ }
1644
+ return ctx.changes;
1645
+ case "property-update":
1646
+ if (ctx.changes.strokeWidth !== void 0) {
1647
+ const merged = { ...orig, ...ctx.changes };
1648
+ const pad = merged.strokeWidth / 2;
1649
+ const rect = expandRect(rectFromPoints(merged.vertices), pad);
1650
+ return { ...ctx.changes, rect };
1651
+ }
1652
+ return ctx.changes;
1653
+ default:
1654
+ return ctx.changes;
1655
+ }
1656
+ };
398
1657
  const _AnnotationPlugin = class _AnnotationPlugin extends BasePlugin {
399
1658
  constructor(id, registry, config) {
1659
+ var _a, _b, _c;
400
1660
  super(id, registry);
401
1661
  this.ANNOTATION_HISTORY_TOPIC = "annotations";
402
1662
  this.state$ = createBehaviorEmitter();
403
- this.modeByVariant = /* @__PURE__ */ new Map();
404
- this.variantByMode = /* @__PURE__ */ new Map();
405
1663
  this.pendingContexts = /* @__PURE__ */ new Map();
406
- this.activeVariantChange$ = createBehaviorEmitter();
407
- this.activeTool$ = createBehaviorEmitter({
408
- variantKey: null,
409
- defaults: null
410
- });
1664
+ this.handlerFactories = /* @__PURE__ */ new Map();
1665
+ this.activeTool$ = createBehaviorEmitter(null);
1666
+ this.events$ = createBehaviorEmitter();
1667
+ this.patchRegistry = new PatchRegistry();
1668
+ this.isInitialLoadComplete = false;
1669
+ this.importQueue = [];
411
1670
  this.config = config;
412
- const selection = registry.getPlugin("selection");
413
- this.selection = (selection == null ? void 0 : selection.provides()) ?? null;
414
- const history = registry.getPlugin("history");
415
- this.history = (history == null ? void 0 : history.provides()) ?? null;
416
- const interactionManager = registry.getPlugin("interaction-manager");
417
- this.interactionManager = (interactionManager == null ? void 0 : interactionManager.provides()) ?? null;
418
- this.coreStore.onAction(SET_DOCUMENT, (_action, state) => {
1671
+ this.selection = ((_a = registry.getPlugin("selection")) == null ? void 0 : _a.provides()) ?? null;
1672
+ this.history = ((_b = registry.getPlugin("history")) == null ? void 0 : _b.provides()) ?? null;
1673
+ this.interactionManager = ((_c = registry.getPlugin("interaction-manager")) == null ? void 0 : _c.provides()) ?? null;
1674
+ this.coreStore.onAction(SET_DOCUMENT, (_, state) => {
419
1675
  const doc = state.core.document;
420
- if (doc) {
421
- this.getAllAnnotations(doc);
422
- }
1676
+ this.isInitialLoadComplete = false;
1677
+ if (doc) this.getAllAnnotations(doc);
423
1678
  });
1679
+ this.registerHandlerFactories();
1680
+ this.registerBuiltInPatches();
1681
+ }
1682
+ registerHandlerFactories() {
1683
+ this.handlerFactories.set(PdfAnnotationSubtype.CIRCLE, circleHandlerFactory);
1684
+ this.handlerFactories.set(PdfAnnotationSubtype.SQUARE, squareHandlerFactory);
1685
+ this.handlerFactories.set(PdfAnnotationSubtype.STAMP, stampHandlerFactory);
1686
+ this.handlerFactories.set(PdfAnnotationSubtype.POLYGON, polygonHandlerFactory);
1687
+ this.handlerFactories.set(PdfAnnotationSubtype.POLYLINE, polylineHandlerFactory);
1688
+ this.handlerFactories.set(PdfAnnotationSubtype.LINE, lineHandlerFactory);
1689
+ this.handlerFactories.set(PdfAnnotationSubtype.INK, inkHandlerFactory);
1690
+ this.handlerFactories.set(PdfAnnotationSubtype.FREETEXT, freeTextHandlerFactory);
1691
+ }
1692
+ registerBuiltInPatches() {
1693
+ this.patchRegistry.register(PdfAnnotationSubtype.INK, patchInk);
1694
+ this.patchRegistry.register(PdfAnnotationSubtype.LINE, patchLine);
1695
+ this.patchRegistry.register(PdfAnnotationSubtype.POLYLINE, patchPolyline);
1696
+ this.patchRegistry.register(PdfAnnotationSubtype.POLYGON, patchPolygon);
424
1697
  }
425
1698
  async initialize() {
426
1699
  var _a, _b, _c;
427
- for (const [variantKey, defaults] of Object.entries(this.state.toolDefaults)) {
428
- this.registerTool(variantKey, defaults);
429
- }
1700
+ this.state.tools.forEach((tool) => this.registerInteractionForTool(tool));
430
1701
  (_a = this.history) == null ? void 0 : _a.onHistoryChange((topic) => {
431
1702
  if (topic === this.ANNOTATION_HISTORY_TOPIC && this.config.autoCommit !== false) {
432
1703
  this.commit();
433
1704
  }
434
1705
  });
435
1706
  (_b = this.interactionManager) == null ? void 0 : _b.onModeChange((s) => {
436
- const newVariant = this.variantByMode.get(s.activeMode) ?? null;
437
- if (newVariant !== this.state.activeVariant) {
438
- this.dispatch(setActiveVariant(newVariant));
439
- this.activeVariantChange$.emit(newVariant);
1707
+ var _a2;
1708
+ const newToolId = ((_a2 = this.state.tools.find((t) => t.interaction.mode === s.activeMode)) == null ? void 0 : _a2.id) ?? null;
1709
+ if (newToolId !== this.state.activeToolId) {
1710
+ this.dispatch(setActiveToolId(newToolId));
440
1711
  }
441
1712
  });
442
1713
  (_c = this.selection) == null ? void 0 : _c.onEndSelection(() => {
443
1714
  var _a2, _b2, _c2;
444
- if (!this.state.activeVariant) return;
445
- const defaults = this.state.toolDefaults[this.state.activeVariant];
446
- if (!defaults || !isTextMarkupDefaults(defaults)) return;
1715
+ const activeTool = this.getActiveTool();
1716
+ if (!activeTool || !activeTool.interaction.textSelection) return;
447
1717
  const formattedSelection = (_a2 = this.selection) == null ? void 0 : _a2.getFormattedSelection();
448
1718
  const selectionText = (_b2 = this.selection) == null ? void 0 : _b2.getSelectedText();
449
1719
  if (!formattedSelection || !selectionText) return;
450
1720
  for (const selection of formattedSelection) {
451
- const rect = selection.rect;
452
- const segmentRects = selection.segmentRects;
453
- const subtype = defaults.subtype;
454
- const color = defaults.color;
455
- const opacity = defaults.opacity;
456
- const blendMode = defaults.blendMode ?? PdfBlendMode.Normal;
457
1721
  selectionText.wait((text) => {
1722
+ const annotationId = uuidV4();
458
1723
  this.createAnnotation(selection.pageIndex, {
459
- type: subtype,
460
- rect,
461
- segmentRects,
462
- color,
463
- opacity,
464
- flags: ["print"],
465
- blendMode,
1724
+ ...activeTool.defaults,
1725
+ rect: selection.rect,
1726
+ segmentRects: selection.segmentRects,
466
1727
  pageIndex: selection.pageIndex,
467
- id: uuidV4(),
468
- author: this.config.annotationAuthor,
1728
+ created: /* @__PURE__ */ new Date(),
1729
+ id: annotationId,
469
1730
  custom: {
470
1731
  text: text.join("\n")
471
1732
  }
472
1733
  });
1734
+ if (this.getToolBehavior(activeTool, "deactivateToolAfterCreate")) {
1735
+ this.setActiveTool(null);
1736
+ }
1737
+ if (this.getToolBehavior(activeTool, "selectAfterCreate")) {
1738
+ this.selectAnnotation(selection.pageIndex, annotationId);
1739
+ }
473
1740
  }, ignore);
474
1741
  }
475
1742
  (_c2 = this.selection) == null ? void 0 : _c2.clear();
476
1743
  });
477
1744
  }
478
- registerTool(variantKey, defaults) {
1745
+ registerInteractionForTool(tool) {
479
1746
  var _a, _b;
480
- const modeId = defaults.interaction.mode;
481
- const interactionMode = {
482
- id: modeId,
1747
+ (_a = this.interactionManager) == null ? void 0 : _a.registerMode({
1748
+ id: tool.interaction.mode,
483
1749
  scope: "page",
484
- exclusive: defaults.interaction.exclusive,
485
- cursor: defaults.interaction.cursor
486
- };
487
- (_a = this.interactionManager) == null ? void 0 : _a.registerMode(interactionMode);
488
- if (defaults.textSelection) {
489
- (_b = this.selection) == null ? void 0 : _b.enableForMode(modeId);
1750
+ exclusive: tool.interaction.exclusive,
1751
+ cursor: tool.interaction.cursor
1752
+ });
1753
+ if (tool.interaction.textSelection) {
1754
+ (_b = this.selection) == null ? void 0 : _b.enableForMode(tool.interaction.mode);
490
1755
  }
491
- this.modeByVariant.set(variantKey, modeId);
492
- this.variantByMode.set(modeId, variantKey);
493
1756
  }
494
1757
  buildCapability() {
495
1758
  return {
496
- getPageAnnotations: (options) => {
497
- return this.getPageAnnotations(options);
498
- },
499
- getSelectedAnnotation: () => {
500
- return getSelectedAnnotation(this.state);
501
- },
502
- selectAnnotation: (pageIndex, annotationId) => {
503
- this.selectAnnotation(pageIndex, annotationId);
504
- },
505
- deselectAnnotation: () => {
506
- this.dispatch(deselectAnnotation());
507
- },
508
- getActiveVariant: () => {
509
- return this.state.activeVariant;
510
- },
511
- setActiveVariant: (variantKey) => {
512
- var _a, _b;
513
- if (variantKey === this.state.activeVariant) return;
514
- if (variantKey) {
515
- const mode = this.modeByVariant.get(variantKey);
516
- if (!mode) throw new Error(`Mode missing for variant ${variantKey}`);
517
- (_a = this.interactionManager) == null ? void 0 : _a.activate(mode);
518
- } else {
519
- (_b = this.interactionManager) == null ? void 0 : _b.activateDefaultMode();
520
- }
521
- },
522
- getSubtypeAndIntentByVariant: (variantKey) => {
523
- return parseVariantKey(variantKey);
524
- },
525
- getToolDefaults: (variantKey) => {
526
- const defaults = this.state.toolDefaults[variantKey];
527
- if (!defaults) {
528
- throw new Error(`No defaults found for variant: ${variantKey}`);
529
- }
530
- return defaults;
531
- },
532
- getToolDefaultsBySubtypeAndIntent: (subtype, intent) => {
533
- return getToolDefaultsBySubtypeAndIntent(this.state, subtype, intent);
534
- },
535
- getToolDefaultsBySubtype: (subtype) => {
536
- return getToolDefaultsBySubtypeAndIntent(this.state, subtype);
537
- },
538
- setToolDefaults: (variantKey, patch) => {
539
- this.dispatch(updateToolDefaults(variantKey, patch));
1759
+ getPageAnnotations: (options) => this.getPageAnnotations(options),
1760
+ getSelectedAnnotation: () => getSelectedAnnotation(this.state),
1761
+ selectAnnotation: (pageIndex, id) => this.selectAnnotation(pageIndex, id),
1762
+ deselectAnnotation: () => this.dispatch(deselectAnnotation()),
1763
+ getActiveTool: () => this.getActiveTool(),
1764
+ setActiveTool: (toolId) => this.setActiveTool(toolId),
1765
+ getTools: () => this.state.tools,
1766
+ getTool: (toolId) => this.getTool(toolId),
1767
+ addTool: (tool) => {
1768
+ this.dispatch(addTool(tool));
1769
+ this.registerInteractionForTool(tool);
540
1770
  },
1771
+ transformAnnotation: (annotation, options) => this.transformAnnotation(annotation, options),
1772
+ registerPatchFunction: (type, patchFn) => this.registerPatchFunction(type, patchFn),
1773
+ findToolForAnnotation: (anno) => this.findToolForAnnotation(anno),
1774
+ setToolDefaults: (toolId, patch) => this.dispatch(setToolDefaults(toolId, patch)),
541
1775
  getColorPresets: () => [...this.state.colorPresets],
542
1776
  addColorPreset: (color) => this.dispatch(addColorPreset(color)),
543
- createAnnotation: (pageIndex, annotation, ctx) => this.createAnnotation(pageIndex, annotation, ctx),
1777
+ importAnnotations: (items) => this.importAnnotations(items),
1778
+ createAnnotation: (pageIndex, anno, ctx) => this.createAnnotation(pageIndex, anno, ctx),
544
1779
  updateAnnotation: (pageIndex, id, patch) => this.updateAnnotation(pageIndex, id, patch),
545
1780
  deleteAnnotation: (pageIndex, id) => this.deleteAnnotation(pageIndex, id),
546
1781
  renderAnnotation: (options) => this.renderAnnotation(options),
547
1782
  onStateChange: this.state$.on,
548
- onActiveVariantChange: this.activeVariantChange$.on,
549
1783
  onActiveToolChange: this.activeTool$.on,
1784
+ onAnnotationEvent: this.events$.on,
550
1785
  commit: () => this.commit()
551
1786
  };
552
1787
  }
553
- createActiveTool(mode, toolDefaults) {
554
- if (mode === null) {
555
- return { variantKey: null, defaults: null };
1788
+ onStoreUpdated(prev, next) {
1789
+ this.state$.emit(next);
1790
+ if (prev.activeToolId !== next.activeToolId || prev.tools !== next.tools) {
1791
+ this.activeTool$.emit(this.getActiveTool());
556
1792
  }
557
- return { variantKey: mode, defaults: toolDefaults[mode] };
558
1793
  }
559
- emitActiveTool(state) {
560
- const activeTool = this.createActiveTool(state.activeVariant, state.toolDefaults);
561
- this.activeTool$.emit(activeTool);
1794
+ registerPatchFunction(type, patchFn) {
1795
+ this.patchRegistry.register(type, patchFn);
562
1796
  }
563
- onStoreUpdated(prev, next) {
564
- this.state$.emit(next);
565
- if (prev.activeVariant !== next.activeVariant || prev.toolDefaults[prev.activeVariant ?? PdfAnnotationSubtype.HIGHLIGHT] !== next.toolDefaults[next.activeVariant ?? PdfAnnotationSubtype.HIGHLIGHT]) {
566
- this.emitActiveTool(next);
1797
+ transformAnnotation(annotation, options) {
1798
+ const context = {
1799
+ type: options.type,
1800
+ changes: options.changes,
1801
+ metadata: options.metadata
1802
+ };
1803
+ return this.patchRegistry.transform(annotation, context);
1804
+ }
1805
+ registerPageHandlers(pageIndex, scale, callbacks) {
1806
+ var _a;
1807
+ const page = (_a = this.coreState.core.document) == null ? void 0 : _a.pages[pageIndex];
1808
+ if (!page) return () => {
1809
+ };
1810
+ if (!this.interactionManager) return () => {
1811
+ };
1812
+ const unregisterFns = [];
1813
+ for (const tool of this.state.tools) {
1814
+ if (!tool.defaults.type) continue;
1815
+ const factory = this.handlerFactories.get(tool.defaults.type);
1816
+ if (!factory) continue;
1817
+ const context = {
1818
+ pageIndex,
1819
+ pageSize: page.size,
1820
+ scale,
1821
+ services: callbacks.services,
1822
+ // Pass through services
1823
+ onPreview: (state) => callbacks.onPreview(tool.id, state),
1824
+ onCommit: (annotation, ctx) => {
1825
+ this.createAnnotation(pageIndex, annotation, ctx);
1826
+ if (this.getToolBehavior(tool, "deactivateToolAfterCreate")) {
1827
+ this.setActiveTool(null);
1828
+ }
1829
+ if (this.getToolBehavior(tool, "selectAfterCreate")) {
1830
+ this.selectAnnotation(pageIndex, annotation.id);
1831
+ }
1832
+ },
1833
+ getTool: () => this.state.tools.find((t) => t.id === tool.id)
1834
+ };
1835
+ const unregister = this.interactionManager.registerHandlers({
1836
+ modeId: tool.interaction.mode,
1837
+ handlers: factory.create(context),
1838
+ pageIndex
1839
+ });
1840
+ unregisterFns.push(unregister);
567
1841
  }
1842
+ return () => unregisterFns.forEach((fn) => fn());
568
1843
  }
569
1844
  getAllAnnotations(doc) {
570
1845
  const task = this.engine.getAllAnnotations(doc);
571
- task.wait((annotations) => this.dispatch(setAnnotations(annotations)), ignore);
1846
+ task.wait((annotations) => {
1847
+ this.dispatch(setAnnotations(annotations));
1848
+ this.isInitialLoadComplete = true;
1849
+ if (this.importQueue.length > 0) {
1850
+ this.processImportQueue();
1851
+ }
1852
+ this.events$.emit({
1853
+ type: "loaded",
1854
+ total: Object.values(annotations).reduce(
1855
+ (sum, pageAnnotations) => sum + pageAnnotations.length,
1856
+ 0
1857
+ )
1858
+ });
1859
+ }, ignore);
572
1860
  }
573
1861
  getPageAnnotations(options) {
574
1862
  const { pageIndex } = options;
@@ -585,16 +1873,36 @@ const _AnnotationPlugin = class _AnnotationPlugin extends BasePlugin {
585
1873
  renderAnnotation({ pageIndex, annotation, options }) {
586
1874
  const coreState = this.coreState.core;
587
1875
  if (!coreState.document) {
588
- throw new Error("document does not open");
1876
+ return PdfTaskHelper.reject({ code: PdfErrorCode.NotFound, message: "Document not found" });
589
1877
  }
590
1878
  const page = coreState.document.pages.find((page2) => page2.index === pageIndex);
591
1879
  if (!page) {
592
- throw new Error("page does not exist");
1880
+ return PdfTaskHelper.reject({ code: PdfErrorCode.NotFound, message: "Page not found" });
593
1881
  }
594
1882
  return this.engine.renderPageAnnotation(coreState.document, page, annotation, options);
595
1883
  }
596
- selectAnnotation(pageIndex, annotationId) {
597
- this.dispatch(selectAnnotation(pageIndex, annotationId));
1884
+ importAnnotations(items) {
1885
+ if (!this.isInitialLoadComplete) {
1886
+ this.importQueue.push(...items);
1887
+ return;
1888
+ }
1889
+ this.processImportItems(items);
1890
+ }
1891
+ processImportQueue() {
1892
+ if (this.importQueue.length === 0) return;
1893
+ const items = [...this.importQueue];
1894
+ this.importQueue = [];
1895
+ this.processImportItems(items);
1896
+ }
1897
+ processImportItems(items) {
1898
+ for (const item of items) {
1899
+ const { annotation, ctx } = item;
1900
+ const pageIndex = annotation.pageIndex;
1901
+ const id = annotation.id;
1902
+ this.dispatch(createAnnotation(pageIndex, annotation));
1903
+ if (ctx) this.pendingContexts.set(id, ctx);
1904
+ }
1905
+ if (this.config.autoCommit !== false) this.commit();
598
1906
  }
599
1907
  createAnnotation(pageIndex, annotation, ctx) {
600
1908
  const id = annotation.id;
@@ -607,6 +1915,7 @@ const _AnnotationPlugin = class _AnnotationPlugin extends BasePlugin {
607
1915
  })
608
1916
  );
609
1917
  if (ctx) this.pendingContexts.set(id, ctx);
1918
+ this.events$.emit({ type: "create", annotation, pageIndex, ctx, committed: false });
610
1919
  };
611
1920
  if (!this.history) {
612
1921
  execute();
@@ -619,14 +1928,17 @@ const _AnnotationPlugin = class _AnnotationPlugin extends BasePlugin {
619
1928
  this.pendingContexts.delete(id);
620
1929
  this.dispatch(deselectAnnotation());
621
1930
  this.dispatch(deleteAnnotation(pageIndex, id));
1931
+ this.events$.emit({ type: "delete", annotation, pageIndex, committed: false });
622
1932
  }
623
1933
  };
624
1934
  this.history.register(command, this.ANNOTATION_HISTORY_TOPIC);
625
1935
  }
626
1936
  buildPatch(original, patch) {
627
1937
  if ("rect" in patch) return patch;
628
- const merged = { ...original, ...patch };
629
- return { ...patch, rect: deriveRect(merged) };
1938
+ return this.transformAnnotation(original, {
1939
+ type: "property-update",
1940
+ changes: patch
1941
+ });
630
1942
  }
631
1943
  updateAnnotation(pageIndex, id, patch) {
632
1944
  const originalObject = this.state.byUid[id].object;
@@ -634,8 +1946,18 @@ const _AnnotationPlugin = class _AnnotationPlugin extends BasePlugin {
634
1946
  ...patch,
635
1947
  author: patch.author ?? this.config.annotationAuthor
636
1948
  });
637
- if (!this.history) {
1949
+ const execute = () => {
638
1950
  this.dispatch(patchAnnotation(pageIndex, id, finalPatch));
1951
+ this.events$.emit({
1952
+ type: "update",
1953
+ annotation: originalObject,
1954
+ pageIndex,
1955
+ patch: finalPatch,
1956
+ committed: false
1957
+ });
1958
+ };
1959
+ if (!this.history) {
1960
+ execute();
639
1961
  if (this.config.autoCommit !== false) {
640
1962
  this.commit();
641
1963
  }
@@ -645,30 +1967,85 @@ const _AnnotationPlugin = class _AnnotationPlugin extends BasePlugin {
645
1967
  Object.keys(patch).map((key) => [key, originalObject[key]])
646
1968
  );
647
1969
  const command = {
648
- execute: () => this.dispatch(patchAnnotation(pageIndex, id, finalPatch)),
649
- undo: () => this.dispatch(patchAnnotation(pageIndex, id, originalPatch))
1970
+ execute,
1971
+ undo: () => {
1972
+ this.dispatch(patchAnnotation(pageIndex, id, originalPatch));
1973
+ this.events$.emit({
1974
+ type: "update",
1975
+ annotation: originalObject,
1976
+ pageIndex,
1977
+ patch: originalPatch,
1978
+ committed: false
1979
+ });
1980
+ }
650
1981
  };
651
1982
  this.history.register(command, this.ANNOTATION_HISTORY_TOPIC);
652
1983
  }
653
1984
  deleteAnnotation(pageIndex, id) {
654
- if (!this.history) {
1985
+ var _a;
1986
+ const originalAnnotation = (_a = this.state.byUid[id]) == null ? void 0 : _a.object;
1987
+ if (!originalAnnotation) return;
1988
+ const execute = () => {
655
1989
  this.dispatch(deselectAnnotation());
656
1990
  this.dispatch(deleteAnnotation(pageIndex, id));
657
- if (this.config.autoCommit !== false) {
658
- this.commit();
659
- }
1991
+ this.events$.emit({
1992
+ type: "delete",
1993
+ annotation: originalAnnotation,
1994
+ pageIndex,
1995
+ committed: false
1996
+ });
1997
+ };
1998
+ if (!this.history) {
1999
+ execute();
2000
+ if (this.config.autoCommit !== false) this.commit();
660
2001
  return;
661
2002
  }
662
- const originalAnnotation = this.state.byUid[id].object;
663
2003
  const command = {
664
- execute: () => {
665
- this.dispatch(deselectAnnotation());
666
- this.dispatch(deleteAnnotation(pageIndex, id));
667
- },
668
- undo: () => this.dispatch(createAnnotation(pageIndex, originalAnnotation))
2004
+ execute,
2005
+ undo: () => {
2006
+ this.dispatch(createAnnotation(pageIndex, originalAnnotation));
2007
+ this.events$.emit({
2008
+ type: "create",
2009
+ annotation: originalAnnotation,
2010
+ pageIndex,
2011
+ committed: false
2012
+ });
2013
+ }
669
2014
  };
670
2015
  this.history.register(command, this.ANNOTATION_HISTORY_TOPIC);
671
2016
  }
2017
+ selectAnnotation(pageIndex, id) {
2018
+ this.dispatch(selectAnnotation(pageIndex, id));
2019
+ }
2020
+ getActiveTool() {
2021
+ if (!this.state.activeToolId) return null;
2022
+ return this.state.tools.find((t) => t.id === this.state.activeToolId) ?? null;
2023
+ }
2024
+ setActiveTool(toolId) {
2025
+ var _a, _b;
2026
+ if (toolId === this.state.activeToolId) return;
2027
+ const tool = this.state.tools.find((t) => t.id === toolId);
2028
+ if (tool) {
2029
+ (_a = this.interactionManager) == null ? void 0 : _a.activate(tool.interaction.mode);
2030
+ } else {
2031
+ (_b = this.interactionManager) == null ? void 0 : _b.activateDefaultMode();
2032
+ }
2033
+ }
2034
+ getTool(toolId) {
2035
+ return this.state.tools.find((t) => t.id === toolId);
2036
+ }
2037
+ findToolForAnnotation(annotation) {
2038
+ let bestTool = null;
2039
+ let bestScore = 0;
2040
+ for (const tool of this.state.tools) {
2041
+ const score = tool.matchScore(annotation);
2042
+ if (score > bestScore) {
2043
+ bestScore = score;
2044
+ bestTool = tool;
2045
+ }
2046
+ }
2047
+ return bestTool;
2048
+ }
672
2049
  commit() {
673
2050
  const task = new Task();
674
2051
  if (!this.state.hasPendingChanges) return PdfTaskHelper.resolve(true);
@@ -687,12 +2064,29 @@ const _AnnotationPlugin = class _AnnotationPlugin extends BasePlugin {
687
2064
  const ctx = this.pendingContexts.get(ta.object.id);
688
2065
  const task2 = this.engine.createPageAnnotation(doc, page, ta.object, ctx);
689
2066
  task2.wait(() => {
2067
+ this.events$.emit({
2068
+ type: "create",
2069
+ annotation: ta.object,
2070
+ pageIndex: ta.object.pageIndex,
2071
+ ctx,
2072
+ committed: true
2073
+ });
690
2074
  this.pendingContexts.delete(ta.object.id);
691
2075
  }, ignore);
692
2076
  creations.push(task2);
693
2077
  break;
694
2078
  case "dirty":
695
- updates.push(this.engine.updatePageAnnotation(doc, page, ta.object));
2079
+ const updateTask = this.engine.updatePageAnnotation(doc, page, ta.object);
2080
+ updateTask.wait(() => {
2081
+ this.events$.emit({
2082
+ type: "update",
2083
+ annotation: ta.object,
2084
+ pageIndex: ta.object.pageIndex,
2085
+ patch: ta.object,
2086
+ committed: true
2087
+ });
2088
+ }, ignore);
2089
+ updates.push(updateTask);
696
2090
  break;
697
2091
  case "deleted":
698
2092
  deletions.push({ ta, uid });
@@ -707,6 +2101,12 @@ const _AnnotationPlugin = class _AnnotationPlugin extends BasePlugin {
707
2101
  const removeTask = this.engine.removePageAnnotation(doc, page, ta.object);
708
2102
  removeTask.wait(() => {
709
2103
  this.dispatch(purgeAnnotation(uid));
2104
+ this.events$.emit({
2105
+ type: "delete",
2106
+ annotation: ta.object,
2107
+ pageIndex: ta.object.pageIndex,
2108
+ committed: true
2109
+ });
710
2110
  task2.resolve(true);
711
2111
  }, task2.fail);
712
2112
  deletionTasks.push(task2);
@@ -721,189 +2121,301 @@ const _AnnotationPlugin = class _AnnotationPlugin extends BasePlugin {
721
2121
  }, task.fail);
722
2122
  return task;
723
2123
  }
2124
+ /**
2125
+ * Gets the effective behavior setting for a tool, checking tool-specific config first,
2126
+ * then falling back to plugin config.
2127
+ */
2128
+ getToolBehavior(tool, setting) {
2129
+ var _a;
2130
+ if (((_a = tool.behavior) == null ? void 0 : _a[setting]) !== void 0) {
2131
+ return tool.behavior[setting];
2132
+ }
2133
+ return this.config[setting] !== false;
2134
+ }
724
2135
  };
725
2136
  _AnnotationPlugin.id = "annotation";
726
2137
  let AnnotationPlugin = _AnnotationPlugin;
727
- const DEFAULT_COLORS = [
728
- "#E44234",
729
- "#FF8D00",
730
- "#FFCD45",
731
- "#5CC96E",
732
- "#25D2D1",
733
- "#597CE2",
734
- "#C544CE",
735
- "#7D2E25",
736
- "#000000",
737
- "#FFFFFF"
738
- ];
739
- const patchAnno = (state, uid, patch) => {
740
- const prev = state.byUid[uid];
741
- if (!prev) return state;
742
- return {
743
- ...state,
744
- byUid: {
745
- ...state.byUid,
746
- [uid]: {
747
- ...prev,
748
- commitState: prev.commitState === "synced" ? "dirty" : prev.commitState,
749
- object: { ...prev.object, ...patch }
750
- }
2138
+ const defaultTools = [
2139
+ // Text Markup Tools
2140
+ {
2141
+ id: "highlight",
2142
+ name: "Highlight",
2143
+ matchScore: (a) => a.type === PdfAnnotationSubtype.HIGHLIGHT ? 1 : 0,
2144
+ interaction: {
2145
+ mode: "highlight",
2146
+ exclusive: false,
2147
+ textSelection: true
751
2148
  },
752
- hasPendingChanges: true
753
- };
754
- };
755
- const initialState = (cfg) => ({
756
- pages: {},
757
- byUid: {},
758
- selectedUid: null,
759
- activeVariant: null,
760
- toolDefaults: {
761
- [makeVariantKey(PdfAnnotationSubtype.HIGHLIGHT)]: {
762
- name: "Highlight",
763
- subtype: PdfAnnotationSubtype.HIGHLIGHT,
764
- interaction: { mode: "highlight", exclusive: false },
765
- textSelection: true,
2149
+ defaults: {
2150
+ type: PdfAnnotationSubtype.HIGHLIGHT,
766
2151
  color: "#FFCD45",
767
2152
  opacity: 1,
768
2153
  blendMode: PdfBlendMode.Multiply
2154
+ }
2155
+ },
2156
+ {
2157
+ id: "underline",
2158
+ name: "Underline",
2159
+ matchScore: (a) => a.type === PdfAnnotationSubtype.UNDERLINE ? 1 : 0,
2160
+ interaction: {
2161
+ mode: "underline",
2162
+ exclusive: false,
2163
+ textSelection: true
769
2164
  },
770
- [makeVariantKey(PdfAnnotationSubtype.UNDERLINE)]: {
771
- name: "Underline",
772
- subtype: PdfAnnotationSubtype.UNDERLINE,
773
- interaction: { mode: "underline", exclusive: false },
774
- textSelection: true,
2165
+ defaults: {
2166
+ type: PdfAnnotationSubtype.UNDERLINE,
775
2167
  color: "#E44234",
776
- opacity: 1,
777
- blendMode: PdfBlendMode.Normal
2168
+ opacity: 1
2169
+ }
2170
+ },
2171
+ {
2172
+ id: "strikeout",
2173
+ name: "Strikeout",
2174
+ matchScore: (a) => a.type === PdfAnnotationSubtype.STRIKEOUT ? 1 : 0,
2175
+ interaction: {
2176
+ mode: "strikeout",
2177
+ exclusive: false,
2178
+ textSelection: true
778
2179
  },
779
- [makeVariantKey(PdfAnnotationSubtype.STRIKEOUT)]: {
780
- name: "Strikeout",
781
- subtype: PdfAnnotationSubtype.STRIKEOUT,
782
- interaction: { mode: "strikeout", exclusive: false },
783
- textSelection: true,
2180
+ defaults: {
2181
+ type: PdfAnnotationSubtype.STRIKEOUT,
784
2182
  color: "#E44234",
785
- opacity: 1,
786
- blendMode: PdfBlendMode.Normal
2183
+ opacity: 1
2184
+ }
2185
+ },
2186
+ {
2187
+ id: "squiggly",
2188
+ name: "Squiggly",
2189
+ matchScore: (a) => a.type === PdfAnnotationSubtype.SQUIGGLY ? 1 : 0,
2190
+ interaction: {
2191
+ mode: "squiggly",
2192
+ exclusive: false,
2193
+ textSelection: true
787
2194
  },
788
- [makeVariantKey(PdfAnnotationSubtype.SQUIGGLY)]: {
789
- name: "Squiggly",
790
- subtype: PdfAnnotationSubtype.SQUIGGLY,
791
- interaction: { mode: "squiggly", exclusive: false },
792
- textSelection: true,
793
- color: "#E44234",
794
- opacity: 1,
795
- blendMode: PdfBlendMode.Normal
2195
+ defaults: {
2196
+ type: PdfAnnotationSubtype.SQUIGGLY,
2197
+ color: "#5CC96E",
2198
+ opacity: 1
2199
+ }
2200
+ },
2201
+ // Drawing Tools
2202
+ {
2203
+ id: "ink",
2204
+ name: "Pen",
2205
+ matchScore: (a) => a.type === PdfAnnotationSubtype.INK && a.intent !== "InkHighlight" ? 5 : 0,
2206
+ interaction: {
2207
+ mode: "ink",
2208
+ exclusive: false,
2209
+ cursor: "crosshair"
796
2210
  },
797
- [makeVariantKey(PdfAnnotationSubtype.INK)]: {
798
- name: "Ink",
799
- subtype: PdfAnnotationSubtype.INK,
800
- interaction: { mode: "ink", exclusive: true, cursor: "crosshair" },
2211
+ defaults: {
2212
+ type: PdfAnnotationSubtype.INK,
801
2213
  color: "#E44234",
802
2214
  opacity: 1,
803
- strokeWidth: 11,
804
- blendMode: PdfBlendMode.Normal
2215
+ strokeWidth: 6
2216
+ }
2217
+ },
2218
+ {
2219
+ id: "inkHighlighter",
2220
+ name: "Ink Highlighter",
2221
+ matchScore: (a) => a.type === PdfAnnotationSubtype.INK && a.intent === "InkHighlight" ? 10 : 0,
2222
+ interaction: {
2223
+ mode: "inkHighlighter",
2224
+ exclusive: false,
2225
+ cursor: "crosshair"
805
2226
  },
806
- [makeVariantKey(PdfAnnotationSubtype.INK, "InkHighlight")]: {
807
- name: "Ink Highlight",
808
- subtype: PdfAnnotationSubtype.INK,
2227
+ defaults: {
2228
+ type: PdfAnnotationSubtype.INK,
809
2229
  intent: "InkHighlight",
810
- interaction: { mode: "inkHighlight", exclusive: true, cursor: "crosshair" },
811
- color: "#E44234",
2230
+ color: "#FFCD45",
812
2231
  opacity: 1,
813
- strokeWidth: 11,
2232
+ strokeWidth: 14,
814
2233
  blendMode: PdfBlendMode.Multiply
815
- },
816
- [makeVariantKey(PdfAnnotationSubtype.CIRCLE)]: {
817
- name: "Circle",
818
- subtype: PdfAnnotationSubtype.CIRCLE,
819
- interaction: { mode: "circle", exclusive: true, cursor: "crosshair" },
2234
+ }
2235
+ },
2236
+ // Shape Tools
2237
+ {
2238
+ id: "circle",
2239
+ name: "Circle",
2240
+ matchScore: (a) => a.type === PdfAnnotationSubtype.CIRCLE ? 1 : 0,
2241
+ interaction: { mode: "circle", exclusive: false, cursor: "crosshair" },
2242
+ defaults: {
2243
+ type: PdfAnnotationSubtype.CIRCLE,
820
2244
  color: "transparent",
821
2245
  opacity: 1,
822
- strokeWidth: 4,
2246
+ strokeWidth: 6,
823
2247
  strokeColor: "#E44234",
824
2248
  strokeStyle: PdfAnnotationBorderStyle.SOLID
825
2249
  },
826
- [makeVariantKey(PdfAnnotationSubtype.SQUARE)]: {
827
- name: "Square",
828
- subtype: PdfAnnotationSubtype.SQUARE,
829
- interaction: { mode: "square", exclusive: true, cursor: "crosshair" },
2250
+ clickBehavior: {
2251
+ enabled: true,
2252
+ defaultSize: { width: 100, height: 100 }
2253
+ }
2254
+ },
2255
+ {
2256
+ id: "square",
2257
+ name: "Square",
2258
+ matchScore: (a) => a.type === PdfAnnotationSubtype.SQUARE ? 1 : 0,
2259
+ interaction: { mode: "square", exclusive: false, cursor: "crosshair" },
2260
+ defaults: {
2261
+ type: PdfAnnotationSubtype.SQUARE,
830
2262
  color: "transparent",
831
2263
  opacity: 1,
832
- strokeWidth: 4,
2264
+ strokeWidth: 6,
833
2265
  strokeColor: "#E44234",
834
2266
  strokeStyle: PdfAnnotationBorderStyle.SOLID
835
2267
  },
836
- [makeVariantKey(PdfAnnotationSubtype.LINE)]: {
837
- name: "Line",
838
- subtype: PdfAnnotationSubtype.LINE,
839
- interaction: { mode: "line", exclusive: true, cursor: "crosshair" },
2268
+ clickBehavior: {
2269
+ enabled: true,
2270
+ defaultSize: { width: 100, height: 100 }
2271
+ }
2272
+ },
2273
+ {
2274
+ id: "line",
2275
+ name: "Line",
2276
+ matchScore: (a) => a.type === PdfAnnotationSubtype.LINE && a.intent !== "LineArrow" ? 5 : 0,
2277
+ interaction: { mode: "line", exclusive: false, cursor: "crosshair" },
2278
+ defaults: {
2279
+ type: PdfAnnotationSubtype.LINE,
840
2280
  color: "transparent",
841
2281
  opacity: 1,
842
- strokeWidth: 4,
843
- strokeColor: "#E44234",
844
- strokeStyle: PdfAnnotationBorderStyle.SOLID
2282
+ strokeWidth: 6,
2283
+ strokeColor: "#E44234"
845
2284
  },
846
- [makeVariantKey(PdfAnnotationSubtype.LINE, "LineArrow")]: {
847
- name: "Line Arrow",
848
- subtype: PdfAnnotationSubtype.LINE,
849
- interaction: { mode: "lineArrow", exclusive: true, cursor: "crosshair" },
850
- color: "transparent",
2285
+ clickBehavior: {
2286
+ enabled: true,
2287
+ defaultLength: 100,
2288
+ defaultAngle: 0
2289
+ }
2290
+ },
2291
+ {
2292
+ id: "lineArrow",
2293
+ name: "Arrow",
2294
+ matchScore: (a) => a.type === PdfAnnotationSubtype.LINE && a.intent === "LineArrow" ? 10 : 0,
2295
+ interaction: { mode: "lineArrow", exclusive: false, cursor: "crosshair" },
2296
+ defaults: {
2297
+ type: PdfAnnotationSubtype.LINE,
851
2298
  intent: "LineArrow",
2299
+ color: "transparent",
852
2300
  opacity: 1,
853
- strokeWidth: 4,
2301
+ strokeWidth: 6,
854
2302
  strokeColor: "#E44234",
855
- strokeStyle: PdfAnnotationBorderStyle.SOLID,
856
2303
  lineEndings: {
857
2304
  start: PdfAnnotationLineEnding.None,
858
2305
  end: PdfAnnotationLineEnding.OpenArrow
859
2306
  }
860
2307
  },
861
- [makeVariantKey(PdfAnnotationSubtype.POLYLINE)]: {
862
- name: "Polyline",
863
- subtype: PdfAnnotationSubtype.POLYLINE,
864
- interaction: { mode: "polyline", exclusive: true, cursor: "crosshair" },
2308
+ clickBehavior: {
2309
+ enabled: true,
2310
+ defaultLength: 100,
2311
+ defaultAngle: 0
2312
+ }
2313
+ },
2314
+ {
2315
+ id: "polyline",
2316
+ name: "Polyline",
2317
+ matchScore: (a) => a.type === PdfAnnotationSubtype.POLYLINE ? 1 : 0,
2318
+ interaction: { mode: "polyline", exclusive: false, cursor: "crosshair" },
2319
+ defaults: {
2320
+ type: PdfAnnotationSubtype.POLYLINE,
865
2321
  color: "transparent",
866
2322
  opacity: 1,
867
- strokeWidth: 4,
868
- strokeColor: "#E44234",
869
- strokeStyle: PdfAnnotationBorderStyle.SOLID
870
- },
871
- [makeVariantKey(PdfAnnotationSubtype.POLYGON)]: {
872
- name: "Polygon",
873
- subtype: PdfAnnotationSubtype.POLYGON,
874
- interaction: { mode: "polygon", exclusive: true, cursor: "crosshair" },
2323
+ strokeWidth: 6,
2324
+ strokeColor: "#E44234"
2325
+ }
2326
+ },
2327
+ {
2328
+ id: "polygon",
2329
+ name: "Polygon",
2330
+ matchScore: (a) => a.type === PdfAnnotationSubtype.POLYGON ? 1 : 0,
2331
+ interaction: { mode: "polygon", exclusive: false, cursor: "crosshair" },
2332
+ defaults: {
2333
+ type: PdfAnnotationSubtype.POLYGON,
875
2334
  color: "transparent",
876
2335
  opacity: 1,
877
- strokeWidth: 4,
878
- strokeColor: "#E44234",
879
- strokeStyle: PdfAnnotationBorderStyle.SOLID
880
- },
881
- [makeVariantKey(PdfAnnotationSubtype.FREETEXT)]: {
882
- name: "Free Text",
883
- subtype: PdfAnnotationSubtype.FREETEXT,
884
- interaction: { mode: "freeText", exclusive: true, cursor: "crosshair" },
885
- backgroundColor: "transparent",
886
- opacity: 1,
2336
+ strokeWidth: 6,
2337
+ strokeColor: "#E44234"
2338
+ }
2339
+ },
2340
+ // Text & Stamp
2341
+ {
2342
+ id: "freeText",
2343
+ name: "Free Text",
2344
+ matchScore: (a) => a.type === PdfAnnotationSubtype.FREETEXT ? 1 : 0,
2345
+ interaction: { mode: "freeText", exclusive: false, cursor: "crosshair" },
2346
+ defaults: {
2347
+ type: PdfAnnotationSubtype.FREETEXT,
2348
+ contents: "Insert text",
887
2349
  fontSize: 14,
888
2350
  fontColor: "#E44234",
889
- content: "Insert text here",
890
2351
  fontFamily: PdfStandardFont.Helvetica,
891
2352
  textAlign: PdfTextAlignment.Left,
892
- verticalAlign: PdfVerticalAlignment.Top
893
- },
894
- [makeVariantKey(PdfAnnotationSubtype.STAMP)]: {
895
- name: "Photo",
896
- subtype: PdfAnnotationSubtype.STAMP,
897
- interaction: { mode: "stamp", exclusive: true, cursor: "crosshair" }
2353
+ verticalAlign: PdfVerticalAlignment.Top,
2354
+ backgroundColor: "transparent",
2355
+ opacity: 1
898
2356
  },
899
- ...cfg.toolDefaults
2357
+ clickBehavior: {
2358
+ enabled: true,
2359
+ defaultSize: { width: 100, height: 20 },
2360
+ defaultContent: "Insert text"
2361
+ }
900
2362
  },
901
- colorPresets: cfg.colorPresets ?? DEFAULT_COLORS,
902
- hasPendingChanges: false
903
- });
2363
+ {
2364
+ id: "stamp",
2365
+ name: "Image",
2366
+ matchScore: (a) => a.type === PdfAnnotationSubtype.STAMP ? 1 : 0,
2367
+ interaction: { mode: "stamp", exclusive: false, cursor: "copy" },
2368
+ defaults: {
2369
+ type: PdfAnnotationSubtype.STAMP
2370
+ // No imageSrc by default, which tells the UI to open a file picker
2371
+ }
2372
+ }
2373
+ ];
2374
+ const DEFAULT_COLORS = [
2375
+ "#E44234",
2376
+ "#FF8D00",
2377
+ "#FFCD45",
2378
+ "#5CC96E",
2379
+ "#25D2D1",
2380
+ "#597CE2",
2381
+ "#C544CE",
2382
+ "#7D2E25",
2383
+ "#000000",
2384
+ "#FFFFFF"
2385
+ ];
2386
+ const patchAnno = (state, uid, patch) => {
2387
+ const prev = state.byUid[uid];
2388
+ if (!prev) return state;
2389
+ return {
2390
+ ...state,
2391
+ byUid: {
2392
+ ...state.byUid,
2393
+ [uid]: {
2394
+ ...prev,
2395
+ commitState: prev.commitState === "synced" ? "dirty" : prev.commitState,
2396
+ object: { ...prev.object, ...patch }
2397
+ }
2398
+ },
2399
+ hasPendingChanges: true
2400
+ };
2401
+ };
2402
+ const initialState = (cfg) => {
2403
+ const toolMap = /* @__PURE__ */ new Map();
2404
+ defaultTools.forEach((t) => toolMap.set(t.id, t));
2405
+ (cfg.tools || []).forEach((t) => toolMap.set(t.id, t));
2406
+ return {
2407
+ pages: {},
2408
+ byUid: {},
2409
+ selectedUid: null,
2410
+ activeToolId: null,
2411
+ // `Array.from(toolMap.values())` now correctly returns `AnnotationTool[]`, which matches the state's type.
2412
+ tools: Array.from(toolMap.values()),
2413
+ colorPresets: cfg.colorPresets ?? DEFAULT_COLORS,
2414
+ hasPendingChanges: false
2415
+ };
2416
+ };
904
2417
  const reducer = (state, action) => {
905
2418
  switch (action.type) {
906
- /* ───── bulk load from engine ───── */
907
2419
  case SET_ANNOTATIONS: {
908
2420
  const newPages = { ...state.pages };
909
2421
  const newByUid = { ...state.byUid };
@@ -922,45 +2434,41 @@ const reducer = (state, action) => {
922
2434
  }
923
2435
  return { ...state, pages: newPages, byUid: newByUid };
924
2436
  }
925
- /* ───── GUI bits ───── */
926
- case SET_ACTIVE_VARIANT:
927
- return { ...state, activeVariant: action.payload };
928
- case SELECT_ANNOTATION:
2437
+ case SET_ACTIVE_TOOL_ID:
2438
+ return { ...state, activeToolId: action.payload };
2439
+ case ADD_TOOL: {
2440
+ const toolMap = new Map(state.tools.map((t) => [t.id, t]));
2441
+ toolMap.set(action.payload.id, action.payload);
2442
+ return { ...state, tools: Array.from(toolMap.values()) };
2443
+ }
2444
+ case SET_TOOL_DEFAULTS: {
2445
+ const { toolId, patch } = action.payload;
929
2446
  return {
930
2447
  ...state,
931
- selectedUid: action.payload.id
2448
+ tools: state.tools.map((tool) => {
2449
+ if (tool.id === toolId) {
2450
+ return { ...tool, defaults: { ...tool.defaults, ...patch } };
2451
+ }
2452
+ return tool;
2453
+ })
932
2454
  };
2455
+ }
2456
+ case SELECT_ANNOTATION:
2457
+ return { ...state, selectedUid: action.payload.id };
933
2458
  case DESELECT_ANNOTATION:
934
2459
  return { ...state, selectedUid: null };
935
2460
  case ADD_COLOR_PRESET:
936
2461
  return state.colorPresets.includes(action.payload) ? state : { ...state, colorPresets: [...state.colorPresets, action.payload] };
937
- case UPDATE_TOOL_DEFAULTS: {
938
- const { variantKey, patch } = action.payload;
939
- const prev = state.toolDefaults[variantKey];
940
- if (!prev) return state;
941
- return {
942
- ...state,
943
- toolDefaults: {
944
- ...state.toolDefaults,
945
- [variantKey]: { ...prev, ...patch }
946
- }
947
- };
948
- }
949
- /* ───── create ───── */
950
2462
  case CREATE_ANNOTATION: {
951
2463
  const { pageIndex, annotation } = action.payload;
952
2464
  const uid = annotation.id;
953
2465
  return {
954
2466
  ...state,
955
2467
  pages: { ...state.pages, [pageIndex]: [...state.pages[pageIndex] ?? [], uid] },
956
- byUid: {
957
- ...state.byUid,
958
- [uid]: { commitState: "new", object: annotation }
959
- },
2468
+ byUid: { ...state.byUid, [uid]: { commitState: "new", object: annotation } },
960
2469
  hasPendingChanges: true
961
2470
  };
962
2471
  }
963
- /* ───── delete ───── */
964
2472
  case DELETE_ANNOTATION: {
965
2473
  const { pageIndex, id: uid } = action.payload;
966
2474
  if (!state.byUid[uid]) return state;
@@ -977,12 +2485,8 @@ const reducer = (state, action) => {
977
2485
  hasPendingChanges: true
978
2486
  };
979
2487
  }
980
- /* ───── field edits ───── */
981
- case PATCH_ANNOTATION: {
982
- const uid = action.payload.id;
983
- return patchAnno(state, uid, action.payload.patch);
984
- }
985
- /* ───── commit bookkeeping ───── */
2488
+ case PATCH_ANNOTATION:
2489
+ return patchAnno(state, action.payload.id, action.payload.patch);
986
2490
  case COMMIT_PENDING_CHANGES: {
987
2491
  const cleaned = {};
988
2492
  for (const [uid, ta] of Object.entries(state.byUid)) {
@@ -1002,6 +2506,24 @@ const reducer = (state, action) => {
1002
2506
  return state;
1003
2507
  }
1004
2508
  };
2509
+ function createToolPredicate(id) {
2510
+ return (tool) => {
2511
+ return (tool == null ? void 0 : tool.id) === id;
2512
+ };
2513
+ }
2514
+ const isHighlightTool = createToolPredicate("highlight");
2515
+ const isSquigglyTool = createToolPredicate("squiggly");
2516
+ const isUnderlineTool = createToolPredicate("underline");
2517
+ const isStrikeoutTool = createToolPredicate("strikeout");
2518
+ const isInkTool = createToolPredicate("ink");
2519
+ const isInkHighlighterTool = createToolPredicate("inkHighlighter");
2520
+ const isSquareTool = createToolPredicate("square");
2521
+ const isCircleTool = createToolPredicate("circle");
2522
+ const isLineTool = createToolPredicate("line");
2523
+ const isPolylineTool = createToolPredicate("polyline");
2524
+ const isPolygonTool = createToolPredicate("polygon");
2525
+ const isFreeTextTool = createToolPredicate("freeText");
2526
+ const isStampTool = createToolPredicate("stamp");
1005
2527
  const AnnotationPluginPackage = {
1006
2528
  manifest,
1007
2529
  create: (registry, config) => new AnnotationPlugin(ANNOTATION_PLUGIN_ID, registry, config),
@@ -1012,40 +2534,44 @@ export {
1012
2534
  ANNOTATION_PLUGIN_ID,
1013
2535
  AnnotationPlugin,
1014
2536
  AnnotationPluginPackage,
2537
+ createToolPredicate,
1015
2538
  getAnnotations,
1016
2539
  getAnnotationsByPageIndex,
1017
2540
  getSelectedAnnotation,
1018
2541
  getSelectedAnnotationByPageIndex,
1019
- getSelectedAnnotationVariant,
1020
2542
  getSidebarAnnotationsWithReplies,
1021
2543
  getSidebarAnnotationsWithRepliesGroupedByPage,
1022
- getToolDefaultsBySubtypeAndIntent,
2544
+ getToolDefaultsById,
1023
2545
  isAnnotationSelected,
1024
2546
  isCircle,
2547
+ isCircleTool,
1025
2548
  isFreeText,
2549
+ isFreeTextTool,
1026
2550
  isHighlight,
1027
- isHighlightDefaults,
1028
- isInAnnotationVariant,
2551
+ isHighlightTool,
1029
2552
  isInk,
2553
+ isInkHighlighterTool,
2554
+ isInkTool,
1030
2555
  isLine,
2556
+ isLineTool,
1031
2557
  isPolygon,
2558
+ isPolygonTool,
1032
2559
  isPolyline,
2560
+ isPolylineTool,
1033
2561
  isSidebarAnnotation,
1034
2562
  isSquare,
2563
+ isSquareTool,
1035
2564
  isSquiggly,
1036
- isSquigglyDefaults,
2565
+ isSquigglyTool,
1037
2566
  isStamp,
2567
+ isStampTool,
1038
2568
  isStrikeout,
1039
- isStrikeoutDefaults,
2569
+ isStrikeoutTool,
1040
2570
  isText,
1041
2571
  isTextMarkup,
1042
- isTextMarkupDefaults,
1043
2572
  isUnderline,
1044
- isUnderlineDefaults,
1045
- makeVariantKey,
2573
+ isUnderlineTool,
1046
2574
  manifest,
1047
- parseVariantKey,
1048
- index as patching,
1049
- variantKeyFromAnnotation
2575
+ index as patching
1050
2576
  };
1051
2577
  //# sourceMappingURL=index.js.map