@embedpdf/plugin-annotation 1.1.1 → 1.2.1

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