@embedpdf/plugin-annotation 2.6.2 → 2.8.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (176) hide show
  1. package/dist/index.cjs +1 -1
  2. package/dist/index.cjs.map +1 -1
  3. package/dist/index.js +538 -90
  4. package/dist/index.js.map +1 -1
  5. package/dist/lib/actions.d.ts +12 -1
  6. package/dist/lib/annotation-plugin.d.ts +19 -0
  7. package/dist/lib/handlers/index.d.ts +4 -0
  8. package/dist/lib/handlers/insert-text.handler.d.ts +8 -0
  9. package/dist/lib/handlers/replace-text.handler.d.ts +9 -0
  10. package/dist/lib/handlers/selection-utils.d.ts +7 -0
  11. package/dist/lib/handlers/text-markup.handler.d.ts +7 -0
  12. package/dist/lib/handlers/text.handler.d.ts +3 -0
  13. package/dist/lib/handlers/types.d.ts +12 -0
  14. package/dist/lib/helpers.d.ts +2 -1
  15. package/dist/lib/selectors.d.ts +6 -1
  16. package/dist/lib/tools/default-tools.d.ts +153 -6
  17. package/dist/lib/tools/tools-utils.d.ts +2 -0
  18. package/dist/lib/tools/types.d.ts +4 -0
  19. package/dist/lib/types.d.ts +19 -2
  20. package/dist/preact/index.cjs +1 -1
  21. package/dist/preact/index.cjs.map +1 -1
  22. package/dist/preact/index.js +1258 -1074
  23. package/dist/preact/index.js.map +1 -1
  24. package/dist/react/index.cjs +1 -1
  25. package/dist/react/index.cjs.map +1 -1
  26. package/dist/react/index.js +1258 -1074
  27. package/dist/react/index.js.map +1 -1
  28. package/dist/shared/annotation-bounds.d.ts +14 -0
  29. package/dist/shared/components/annotation-container.d.ts +11 -5
  30. package/dist/shared/components/annotations/caret.d.ts +24 -0
  31. package/dist/shared/components/annotations/circle.d.ts +6 -4
  32. package/dist/shared/components/annotations/free-text.d.ts +6 -3
  33. package/dist/shared/components/annotations/ink.d.ts +5 -3
  34. package/dist/shared/components/annotations/line.d.ts +5 -3
  35. package/dist/shared/components/annotations/link.d.ts +2 -2
  36. package/dist/shared/components/annotations/polygon.d.ts +5 -4
  37. package/dist/shared/components/annotations/polyline.d.ts +10 -4
  38. package/dist/shared/components/annotations/square.d.ts +6 -4
  39. package/dist/shared/components/annotations/stamp.d.ts +2 -2
  40. package/dist/shared/components/annotations/text.d.ts +14 -0
  41. package/dist/shared/components/annotations.d.ts +0 -1
  42. package/dist/shared/components/appearance-image.d.ts +12 -0
  43. package/dist/shared/components/built-in-renderers.d.ts +2 -0
  44. package/dist/shared/components/text-markup/highlight.d.ts +5 -3
  45. package/dist/shared/components/text-markup/squiggly.d.ts +5 -3
  46. package/dist/shared/components/text-markup/strikeout.d.ts +5 -3
  47. package/dist/shared/components/text-markup/underline.d.ts +5 -3
  48. package/dist/shared/components/types.d.ts +67 -11
  49. package/dist/shared-preact/annotation-bounds.d.ts +14 -0
  50. package/dist/shared-preact/components/annotation-container.d.ts +11 -5
  51. package/dist/shared-preact/components/annotations/caret.d.ts +24 -0
  52. package/dist/shared-preact/components/annotations/circle.d.ts +6 -4
  53. package/dist/shared-preact/components/annotations/free-text.d.ts +6 -3
  54. package/dist/shared-preact/components/annotations/ink.d.ts +5 -3
  55. package/dist/shared-preact/components/annotations/line.d.ts +5 -3
  56. package/dist/shared-preact/components/annotations/link.d.ts +2 -2
  57. package/dist/shared-preact/components/annotations/polygon.d.ts +5 -4
  58. package/dist/shared-preact/components/annotations/polyline.d.ts +10 -4
  59. package/dist/shared-preact/components/annotations/square.d.ts +6 -4
  60. package/dist/shared-preact/components/annotations/stamp.d.ts +2 -2
  61. package/dist/shared-preact/components/annotations/text.d.ts +14 -0
  62. package/dist/shared-preact/components/annotations.d.ts +0 -1
  63. package/dist/shared-preact/components/appearance-image.d.ts +12 -0
  64. package/dist/shared-preact/components/built-in-renderers.d.ts +2 -0
  65. package/dist/shared-preact/components/text-markup/highlight.d.ts +5 -3
  66. package/dist/shared-preact/components/text-markup/squiggly.d.ts +5 -3
  67. package/dist/shared-preact/components/text-markup/strikeout.d.ts +5 -3
  68. package/dist/shared-preact/components/text-markup/underline.d.ts +5 -3
  69. package/dist/shared-preact/components/types.d.ts +67 -11
  70. package/dist/shared-react/annotation-bounds.d.ts +14 -0
  71. package/dist/shared-react/components/annotation-container.d.ts +11 -5
  72. package/dist/shared-react/components/annotations/caret.d.ts +24 -0
  73. package/dist/shared-react/components/annotations/circle.d.ts +6 -4
  74. package/dist/shared-react/components/annotations/free-text.d.ts +6 -3
  75. package/dist/shared-react/components/annotations/ink.d.ts +5 -3
  76. package/dist/shared-react/components/annotations/line.d.ts +5 -3
  77. package/dist/shared-react/components/annotations/link.d.ts +2 -2
  78. package/dist/shared-react/components/annotations/polygon.d.ts +5 -4
  79. package/dist/shared-react/components/annotations/polyline.d.ts +10 -4
  80. package/dist/shared-react/components/annotations/square.d.ts +6 -4
  81. package/dist/shared-react/components/annotations/stamp.d.ts +2 -2
  82. package/dist/shared-react/components/annotations/text.d.ts +14 -0
  83. package/dist/shared-react/components/annotations.d.ts +0 -1
  84. package/dist/shared-react/components/appearance-image.d.ts +12 -0
  85. package/dist/shared-react/components/built-in-renderers.d.ts +2 -0
  86. package/dist/shared-react/components/text-markup/highlight.d.ts +5 -3
  87. package/dist/shared-react/components/text-markup/squiggly.d.ts +5 -3
  88. package/dist/shared-react/components/text-markup/strikeout.d.ts +5 -3
  89. package/dist/shared-react/components/text-markup/underline.d.ts +5 -3
  90. package/dist/shared-react/components/types.d.ts +67 -11
  91. package/dist/shared-vue/annotation-bounds.d.ts +14 -0
  92. package/dist/svelte/components/Annotations.svelte.d.ts +0 -7
  93. package/dist/svelte/components/AppearanceImage.svelte.d.ts +8 -0
  94. package/dist/svelte/components/annotations/Caret.svelte.d.ts +13 -0
  95. package/dist/svelte/components/annotations/Circle.svelte.d.ts +2 -11
  96. package/dist/svelte/components/annotations/FreeText.svelte.d.ts +2 -1
  97. package/dist/svelte/components/annotations/Ink.svelte.d.ts +2 -2
  98. package/dist/svelte/components/annotations/Line.svelte.d.ts +2 -1
  99. package/dist/svelte/components/annotations/Link.svelte.d.ts +1 -1
  100. package/dist/svelte/components/annotations/Polygon.svelte.d.ts +2 -1
  101. package/dist/svelte/components/annotations/Polyline.svelte.d.ts +5 -3
  102. package/dist/svelte/components/annotations/Square.svelte.d.ts +2 -1
  103. package/dist/svelte/components/annotations/Stamp.svelte.d.ts +1 -1
  104. package/dist/svelte/components/annotations/Text.svelte.d.ts +10 -0
  105. package/dist/svelte/components/annotations/index.d.ts +1 -0
  106. package/dist/svelte/components/built-in-renderers.d.ts +2 -0
  107. package/dist/svelte/components/renderers/CaretRenderer.svelte.d.ts +5 -0
  108. package/dist/svelte/components/renderers/CircleRenderer.svelte.d.ts +5 -0
  109. package/dist/svelte/components/renderers/FreeTextRenderer.svelte.d.ts +5 -0
  110. package/dist/svelte/components/renderers/HighlightRenderer.svelte.d.ts +5 -0
  111. package/dist/svelte/components/renderers/InkRenderer.svelte.d.ts +5 -0
  112. package/dist/svelte/components/renderers/LineRenderer.svelte.d.ts +5 -0
  113. package/dist/svelte/components/renderers/LinkRenderer.svelte.d.ts +5 -0
  114. package/dist/svelte/components/renderers/PolygonRenderer.svelte.d.ts +5 -0
  115. package/dist/svelte/components/renderers/PolylineRenderer.svelte.d.ts +5 -0
  116. package/dist/svelte/components/renderers/SquareRenderer.svelte.d.ts +5 -0
  117. package/dist/svelte/components/renderers/SquigglyRenderer.svelte.d.ts +5 -0
  118. package/dist/svelte/components/renderers/StampRenderer.svelte.d.ts +5 -0
  119. package/dist/svelte/components/renderers/StrikeoutRenderer.svelte.d.ts +5 -0
  120. package/dist/svelte/components/renderers/TextRenderer.svelte.d.ts +5 -0
  121. package/dist/svelte/components/renderers/UnderlineRenderer.svelte.d.ts +5 -0
  122. package/dist/svelte/components/text-markup/Highlight.svelte.d.ts +3 -1
  123. package/dist/svelte/components/text-markup/Squiggly.svelte.d.ts +3 -1
  124. package/dist/svelte/components/text-markup/Strikeout.svelte.d.ts +3 -1
  125. package/dist/svelte/components/text-markup/Underline.svelte.d.ts +3 -1
  126. package/dist/svelte/components/types.d.ts +8 -2
  127. package/dist/svelte/context/renderer-registry.svelte.d.ts +2 -2
  128. package/dist/svelte/context/types.d.ts +63 -2
  129. package/dist/svelte/index.cjs +1 -1
  130. package/dist/svelte/index.cjs.map +1 -1
  131. package/dist/svelte/index.js +2738 -2890
  132. package/dist/svelte/index.js.map +1 -1
  133. package/dist/vue/components/annotation-container.vue.d.ts +7 -2
  134. package/dist/vue/components/annotation-layer.vue.d.ts +2 -21
  135. package/dist/vue/components/annotations/caret.vue.d.ts +24 -0
  136. package/dist/vue/components/annotations/circle.vue.d.ts +19 -6
  137. package/dist/vue/components/annotations/free-text.vue.d.ts +18 -6
  138. package/dist/vue/components/annotations/index.d.ts +1 -0
  139. package/dist/vue/components/annotations/ink.vue.d.ts +17 -7
  140. package/dist/vue/components/annotations/line.vue.d.ts +21 -6
  141. package/dist/vue/components/annotations/link.vue.d.ts +24 -6
  142. package/dist/vue/components/annotations/polygon.vue.d.ts +22 -6
  143. package/dist/vue/components/annotations/polyline.vue.d.ts +25 -7
  144. package/dist/vue/components/annotations/square.vue.d.ts +19 -6
  145. package/dist/vue/components/annotations/stamp.vue.d.ts +12 -6
  146. package/dist/vue/components/annotations/text.vue.d.ts +14 -0
  147. package/dist/vue/components/annotations.vue.d.ts +9 -576
  148. package/dist/vue/components/appearance-image.vue.d.ts +9 -0
  149. package/dist/vue/components/built-in-renderers.d.ts +2 -0
  150. package/dist/vue/components/group-selection-box.vue.d.ts +2 -2
  151. package/dist/vue/components/renderers/caret-renderer.vue.d.ts +6 -0
  152. package/dist/vue/components/renderers/circle-renderer.vue.d.ts +6 -0
  153. package/dist/vue/components/renderers/free-text-renderer.vue.d.ts +6 -0
  154. package/dist/vue/components/renderers/highlight-renderer.vue.d.ts +6 -0
  155. package/dist/vue/components/renderers/ink-renderer.vue.d.ts +6 -0
  156. package/dist/vue/components/renderers/line-renderer.vue.d.ts +6 -0
  157. package/dist/vue/components/renderers/link-renderer.vue.d.ts +6 -0
  158. package/dist/vue/components/renderers/polygon-renderer.vue.d.ts +6 -0
  159. package/dist/vue/components/renderers/polyline-renderer.vue.d.ts +6 -0
  160. package/dist/vue/components/renderers/square-renderer.vue.d.ts +6 -0
  161. package/dist/vue/components/renderers/squiggly-renderer.vue.d.ts +6 -0
  162. package/dist/vue/components/renderers/stamp-renderer.vue.d.ts +6 -0
  163. package/dist/vue/components/renderers/strikeout-renderer.vue.d.ts +6 -0
  164. package/dist/vue/components/renderers/text-renderer.vue.d.ts +6 -0
  165. package/dist/vue/components/renderers/underline-renderer.vue.d.ts +6 -0
  166. package/dist/vue/components/text-markup/highlight.vue.d.ts +18 -6
  167. package/dist/vue/components/text-markup/squiggly.vue.d.ts +18 -6
  168. package/dist/vue/components/text-markup/strikeout.vue.d.ts +18 -6
  169. package/dist/vue/components/text-markup/underline.vue.d.ts +18 -6
  170. package/dist/vue/context/renderer-registry.d.ts +2 -2
  171. package/dist/vue/context/types.d.ts +63 -2
  172. package/dist/vue/index.cjs +1 -1
  173. package/dist/vue/index.cjs.map +1 -1
  174. package/dist/vue/index.js +1995 -1336
  175. package/dist/vue/index.js.map +1 -1
  176. package/package.json +10 -10
package/dist/index.js CHANGED
@@ -28,6 +28,7 @@ const SET_SELECTION = "ANNOTATION/SET_SELECTION";
28
28
  const SET_ACTIVE_TOOL_ID = "ANNOTATION/SET_ACTIVE_TOOL_ID";
29
29
  const CREATE_ANNOTATION = "ANNOTATION/CREATE_ANNOTATION";
30
30
  const PATCH_ANNOTATION = "ANNOTATION/PATCH_ANNOTATION";
31
+ const MOVE_ANNOTATION = "ANNOTATION/MOVE_ANNOTATION";
31
32
  const DELETE_ANNOTATION = "ANNOTATION/DELETE_ANNOTATION";
32
33
  const COMMIT_PENDING_CHANGES = "ANNOTATION/COMMIT";
33
34
  const PURGE_ANNOTATION = "ANNOTATION/PURGE_ANNOTATION";
@@ -76,6 +77,10 @@ const patchAnnotation = (documentId, pageIndex, id, patch) => ({
76
77
  type: PATCH_ANNOTATION,
77
78
  payload: { documentId, pageIndex, id, patch }
78
79
  });
80
+ const moveAnnotation = (documentId, pageIndex, id, patch) => ({
81
+ type: MOVE_ANNOTATION,
82
+ payload: { documentId, pageIndex, id, patch }
83
+ });
79
84
  const deleteAnnotation = (documentId, pageIndex, id) => ({
80
85
  type: DELETE_ANNOTATION,
81
86
  payload: { documentId, pageIndex, id }
@@ -151,8 +156,11 @@ function isLink(a) {
151
156
  function isRedact(a) {
152
157
  return a.object.type === PdfAnnotationSubtype.REDACT;
153
158
  }
159
+ function isCaret(a) {
160
+ return a.object.type === PdfAnnotationSubtype.CARET;
161
+ }
154
162
  function isSidebarAnnotation(a) {
155
- return isTextMarkup(a) || isInk(a) || isSquare(a) || isCircle(a) || isPolygon(a) || isLine(a) || isPolyline(a) || isFreeText(a) || isStamp(a) || isRedact(a);
163
+ return isText(a) && !a.object.inReplyToId || isTextMarkup(a) || isInk(a) || isSquare(a) || isCircle(a) || isPolygon(a) || isLine(a) || isPolyline(a) || isFreeText(a) || isStamp(a) || isRedact(a) || isCaret(a);
156
164
  }
157
165
  const getAnnotationsByPageIndex = (s, page) => (s.pages[page] ?? []).map((uid) => s.byUid[uid]);
158
166
  const getAnnotations = (s) => {
@@ -194,19 +202,33 @@ const getSidebarAnnotationsWithRepliesGroupedByPage = (s) => {
194
202
  }
195
203
  }
196
204
  }
205
+ const membersByLeader = {};
206
+ const consumedAsGroupMember = /* @__PURE__ */ new Set();
207
+ for (const uidList of Object.values(s.pages)) {
208
+ for (const uid of uidList) {
209
+ const ta = s.byUid[uid];
210
+ if (ta && ta.object.inReplyToId && ta.object.replyType === PdfAnnotationReplyType.Group && ta.object.type !== PdfAnnotationSubtype.LINK && isSidebarAnnotation(ta)) {
211
+ const leaderId = ta.object.inReplyToId;
212
+ (membersByLeader[leaderId] || (membersByLeader[leaderId] = [])).push(ta);
213
+ consumedAsGroupMember.add(ta.object.id);
214
+ }
215
+ }
216
+ }
197
217
  const out = {};
198
218
  for (const [pageStr, uidList] of Object.entries(s.pages)) {
199
219
  const page = Number(pageStr);
200
220
  const pageAnnotations = [];
201
221
  for (const uid of uidList) {
202
222
  const ta = s.byUid[uid];
203
- if (ta && isSidebarAnnotation(ta)) {
204
- pageAnnotations.push({
205
- page,
206
- annotation: ta,
207
- replies: repliesByParent[ta.object.id] ?? []
208
- });
209
- }
223
+ if (!ta || !isSidebarAnnotation(ta)) continue;
224
+ if (consumedAsGroupMember.has(ta.object.id)) continue;
225
+ const members = membersByLeader[ta.object.id];
226
+ pageAnnotations.push({
227
+ page,
228
+ annotation: ta,
229
+ replies: repliesByParent[ta.object.id] ?? [],
230
+ ...members && members.length > 0 ? { groupMembers: members } : {}
231
+ });
210
232
  }
211
233
  if (pageAnnotations.length > 0) {
212
234
  out[page] = pageAnnotations;
@@ -329,6 +351,7 @@ const defaultTools = [
329
351
  textSelection: true,
330
352
  isDraggable: false,
331
353
  isResizable: false,
354
+ isRotatable: false,
332
355
  // Text markup annotations are anchored to text and should not move/resize in groups
333
356
  isGroupDraggable: false,
334
357
  isGroupResizable: false
@@ -351,6 +374,7 @@ const defaultTools = [
351
374
  textSelection: true,
352
375
  isDraggable: false,
353
376
  isResizable: false,
377
+ isRotatable: false,
354
378
  isGroupDraggable: false,
355
379
  isGroupResizable: false
356
380
  },
@@ -371,6 +395,7 @@ const defaultTools = [
371
395
  textSelection: true,
372
396
  isDraggable: false,
373
397
  isResizable: false,
398
+ isRotatable: false,
374
399
  isGroupDraggable: false,
375
400
  isGroupResizable: false
376
401
  },
@@ -391,6 +416,7 @@ const defaultTools = [
391
416
  textSelection: true,
392
417
  isDraggable: false,
393
418
  isResizable: false,
419
+ isRotatable: false,
394
420
  isGroupDraggable: false,
395
421
  isGroupResizable: false
396
422
  },
@@ -402,6 +428,59 @@ const defaultTools = [
402
428
  opacity: 1
403
429
  }
404
430
  },
431
+ // Insert Text (Caret with intent Insert)
432
+ {
433
+ id: "insertText",
434
+ name: "Insert Text",
435
+ matchScore: (a) => {
436
+ var _a;
437
+ if (a.type !== PdfAnnotationSubtype.CARET) return 0;
438
+ return ((_a = a.intent) == null ? void 0 : _a.includes("Insert")) ? 2 : 1;
439
+ },
440
+ interaction: {
441
+ exclusive: false,
442
+ textSelection: true,
443
+ showSelectionRects: true,
444
+ isDraggable: false,
445
+ isResizable: false,
446
+ isRotatable: false,
447
+ isGroupDraggable: false,
448
+ isGroupResizable: false
449
+ },
450
+ defaults: {
451
+ type: PdfAnnotationSubtype.CARET,
452
+ strokeColor: "#E44234",
453
+ opacity: 1,
454
+ intent: "Insert"
455
+ }
456
+ },
457
+ // Replace Text (StrikeOut + Caret group)
458
+ {
459
+ id: "replaceText",
460
+ name: "Replace Text",
461
+ matchScore: (a) => {
462
+ var _a, _b;
463
+ if (a.type === PdfAnnotationSubtype.STRIKEOUT && ((_a = a.intent) == null ? void 0 : _a.includes("StrikeOutTextEdit")))
464
+ return 2;
465
+ if (a.type === PdfAnnotationSubtype.CARET && ((_b = a.intent) == null ? void 0 : _b.includes("Replace"))) return 2;
466
+ return 0;
467
+ },
468
+ interaction: {
469
+ exclusive: false,
470
+ textSelection: true,
471
+ isDraggable: false,
472
+ isResizable: false,
473
+ isRotatable: false,
474
+ isGroupDraggable: false,
475
+ isGroupResizable: false
476
+ },
477
+ defaults: {
478
+ type: PdfAnnotationSubtype.STRIKEOUT,
479
+ strokeColor: "#E44234",
480
+ opacity: 1,
481
+ intent: "StrikeOutTextEdit"
482
+ }
483
+ },
405
484
  // Drawing Tools
406
485
  {
407
486
  id: "ink",
@@ -626,6 +705,26 @@ const defaultTools = [
626
705
  }
627
706
  },
628
707
  // Text & Stamp
708
+ {
709
+ id: "textComment",
710
+ name: "Comment",
711
+ matchScore: (a) => a.type === PdfAnnotationSubtype.TEXT && !a.inReplyToId ? 1 : 0,
712
+ interaction: {
713
+ exclusive: false,
714
+ cursor: "crosshair",
715
+ isDraggable: true,
716
+ isResizable: false,
717
+ isRotatable: false
718
+ },
719
+ defaults: {
720
+ type: PdfAnnotationSubtype.TEXT,
721
+ strokeColor: "#FFCD45",
722
+ opacity: 1
723
+ },
724
+ behavior: {
725
+ selectAfterCreate: true
726
+ }
727
+ },
629
728
  {
630
729
  id: "freeText",
631
730
  name: "Free Text",
@@ -681,7 +780,8 @@ const defaultTools = [
681
780
  // No imageSrc by default, which tells the UI to open a file picker
682
781
  },
683
782
  behavior: {
684
- insertUpright: true
783
+ insertUpright: true,
784
+ useAppearanceStream: false
685
785
  }
686
786
  }
687
787
  ];
@@ -715,7 +815,25 @@ const patchAnno = (docState, uid, patch) => {
715
815
  ...docState.byUid,
716
816
  [uid]: {
717
817
  ...prev,
718
- commitState: prev.commitState === "synced" ? "dirty" : prev.commitState,
818
+ commitState: prev.commitState === "synced" || prev.commitState === "moved" ? "dirty" : prev.commitState,
819
+ object: { ...prev.object, ...patch },
820
+ dictMode: true
821
+ }
822
+ },
823
+ hasPendingChanges: true
824
+ };
825
+ };
826
+ const moveAnno = (docState, uid, patch) => {
827
+ const prev = docState.byUid[uid];
828
+ if (!prev) return docState;
829
+ return {
830
+ ...docState,
831
+ byUid: {
832
+ ...docState.byUid,
833
+ [uid]: {
834
+ ...prev,
835
+ // synced -> moved, moved -> moved, dirty stays dirty, new stays new
836
+ commitState: prev.commitState === "synced" ? "moved" : prev.commitState,
719
837
  object: { ...prev.object, ...patch }
720
838
  }
721
839
  },
@@ -928,7 +1046,7 @@ const reducer = (state, action) => {
928
1046
  },
929
1047
  byUid: {
930
1048
  ...docState.byUid,
931
- [uid]: { commitState: "new", object: annotation }
1049
+ [uid]: { commitState: "new", object: annotation, dictMode: true }
932
1050
  },
933
1051
  hasPendingChanges: true
934
1052
  }
@@ -970,6 +1088,18 @@ const reducer = (state, action) => {
970
1088
  }
971
1089
  };
972
1090
  }
1091
+ case MOVE_ANNOTATION: {
1092
+ const { documentId, id, patch } = action.payload;
1093
+ const docState = state.documents[documentId];
1094
+ if (!docState) return state;
1095
+ return {
1096
+ ...state,
1097
+ documents: {
1098
+ ...state.documents,
1099
+ [documentId]: moveAnno(docState, id, patch)
1100
+ }
1101
+ };
1102
+ }
973
1103
  case COMMIT_PENDING_CHANGES: {
974
1104
  const { documentId, committedUids } = action.payload;
975
1105
  const docState = state.documents[documentId];
@@ -981,11 +1111,11 @@ const reducer = (state, action) => {
981
1111
  if (committedSet.has(uid)) {
982
1112
  cleaned[uid] = {
983
1113
  ...ta,
984
- commitState: ta.commitState === "dirty" || ta.commitState === "new" ? "synced" : ta.commitState
1114
+ commitState: ta.commitState === "dirty" || ta.commitState === "new" || ta.commitState === "moved" ? "synced" : ta.commitState
985
1115
  };
986
1116
  } else {
987
1117
  cleaned[uid] = ta;
988
- if (ta.commitState === "new" || ta.commitState === "dirty" || ta.commitState === "deleted") {
1118
+ if (ta.commitState === "new" || ta.commitState === "dirty" || ta.commitState === "moved" || ta.commitState === "deleted") {
989
1119
  stillHasPending = true;
990
1120
  }
991
1121
  }
@@ -1146,45 +1276,6 @@ const inkHandlerFactory = {
1146
1276
  };
1147
1277
  }
1148
1278
  };
1149
- function useClickDetector({
1150
- threshold = 5,
1151
- getTool,
1152
- onClickDetected
1153
- }) {
1154
- const [getStartPos, setStartPos] = useState(null);
1155
- const [getHasMoved, setHasMoved] = useState(false);
1156
- return {
1157
- onStart: (pos) => {
1158
- setStartPos(pos);
1159
- setHasMoved(false);
1160
- },
1161
- onMove: (pos) => {
1162
- const start = getStartPos();
1163
- if (!start || getHasMoved()) return;
1164
- const distance = Math.sqrt(Math.pow(pos.x - start.x, 2) + Math.pow(pos.y - start.y, 2));
1165
- if (distance > threshold) {
1166
- setHasMoved(true);
1167
- }
1168
- },
1169
- onEnd: (pos) => {
1170
- var _a;
1171
- const start = getStartPos();
1172
- if (start && !getHasMoved()) {
1173
- const tool = getTool();
1174
- if (tool && "clickBehavior" in tool && ((_a = tool.clickBehavior) == null ? void 0 : _a.enabled)) {
1175
- onClickDetected(pos, tool);
1176
- }
1177
- }
1178
- setStartPos(null);
1179
- setHasMoved(false);
1180
- },
1181
- hasMoved: getHasMoved,
1182
- reset: () => {
1183
- setStartPos(null);
1184
- setHasMoved(false);
1185
- }
1186
- };
1187
- }
1188
1279
  function createArrowHandler(isClosed) {
1189
1280
  const calculateGeometry = (sw) => {
1190
1281
  const len = sw * 9;
@@ -1565,6 +1656,75 @@ const index = /* @__PURE__ */ Object.freeze(/* @__PURE__ */ Object.definePropert
1565
1656
  rotatePointAroundCenter: rotatePointAround,
1566
1657
  rotateVertices
1567
1658
  }, Symbol.toStringTag, { value: "Module" }));
1659
+ const COMMENT_SIZE = 24;
1660
+ const textHandlerFactory = {
1661
+ annotationType: PdfAnnotationSubtype.TEXT,
1662
+ create(context) {
1663
+ const { onCommit, getTool, pageSize } = context;
1664
+ return {
1665
+ onPointerDown: (pos) => {
1666
+ const tool = getTool();
1667
+ if (!tool) return;
1668
+ const rect = {
1669
+ origin: { x: pos.x - COMMENT_SIZE / 2, y: pos.y - COMMENT_SIZE / 2 },
1670
+ size: { width: COMMENT_SIZE, height: COMMENT_SIZE }
1671
+ };
1672
+ let anno = {
1673
+ ...tool.defaults,
1674
+ rect,
1675
+ type: PdfAnnotationSubtype.TEXT,
1676
+ icon: tool.defaults.icon ?? PdfAnnotationIcon.Comment,
1677
+ contents: tool.defaults.contents ?? "",
1678
+ flags: tool.defaults.flags ?? ["print", "noRotate", "noZoom"],
1679
+ pageIndex: context.pageIndex,
1680
+ id: uuidV4(),
1681
+ created: /* @__PURE__ */ new Date()
1682
+ };
1683
+ anno = clampAnnotationToPage(anno, pageSize);
1684
+ onCommit(anno);
1685
+ }
1686
+ };
1687
+ }
1688
+ };
1689
+ function useClickDetector({
1690
+ threshold = 5,
1691
+ getTool,
1692
+ onClickDetected
1693
+ }) {
1694
+ const [getStartPos, setStartPos] = useState(null);
1695
+ const [getHasMoved, setHasMoved] = useState(false);
1696
+ return {
1697
+ onStart: (pos) => {
1698
+ setStartPos(pos);
1699
+ setHasMoved(false);
1700
+ },
1701
+ onMove: (pos) => {
1702
+ const start = getStartPos();
1703
+ if (!start || getHasMoved()) return;
1704
+ const distance = Math.sqrt(Math.pow(pos.x - start.x, 2) + Math.pow(pos.y - start.y, 2));
1705
+ if (distance > threshold) {
1706
+ setHasMoved(true);
1707
+ }
1708
+ },
1709
+ onEnd: (pos) => {
1710
+ var _a;
1711
+ const start = getStartPos();
1712
+ if (start && !getHasMoved()) {
1713
+ const tool = getTool();
1714
+ if (tool && "clickBehavior" in tool && ((_a = tool.clickBehavior) == null ? void 0 : _a.enabled)) {
1715
+ onClickDetected(pos, tool);
1716
+ }
1717
+ }
1718
+ setStartPos(null);
1719
+ setHasMoved(false);
1720
+ },
1721
+ hasMoved: getHasMoved,
1722
+ reset: () => {
1723
+ setStartPos(null);
1724
+ setHasMoved(false);
1725
+ }
1726
+ };
1727
+ }
1568
1728
  const freeTextHandlerFactory = {
1569
1729
  annotationType: PdfAnnotationSubtype.FREETEXT,
1570
1730
  create(context) {
@@ -2417,6 +2577,135 @@ const circleHandlerFactory = {
2417
2577
  };
2418
2578
  }
2419
2579
  };
2580
+ const textMarkupSelectionHandler = {
2581
+ toolId: "__textMarkup__",
2582
+ handle(context, selections, getText) {
2583
+ const tool = context.getTool();
2584
+ if (!tool) return;
2585
+ for (const selection of selections) {
2586
+ const id = uuidV4();
2587
+ getText().then((text) => {
2588
+ var _a;
2589
+ context.createAnnotation(selection.pageIndex, {
2590
+ ...tool.defaults,
2591
+ rect: selection.rect,
2592
+ segmentRects: selection.segmentRects,
2593
+ pageIndex: selection.pageIndex,
2594
+ created: /* @__PURE__ */ new Date(),
2595
+ id,
2596
+ ...text != null && { custom: { text } }
2597
+ });
2598
+ if ((_a = tool.behavior) == null ? void 0 : _a.selectAfterCreate) {
2599
+ context.selectAnnotation(selection.pageIndex, id);
2600
+ }
2601
+ });
2602
+ }
2603
+ }
2604
+ };
2605
+ function computeCaretRect(lastSegRect) {
2606
+ const lineHeight = lastSegRect.size.height;
2607
+ const height = lineHeight / 2;
2608
+ const width = height;
2609
+ const lineEndX = lastSegRect.origin.x + lastSegRect.size.width;
2610
+ return {
2611
+ origin: {
2612
+ x: lineEndX - width / 2,
2613
+ y: lastSegRect.origin.y + lineHeight / 2
2614
+ },
2615
+ size: { width, height }
2616
+ };
2617
+ }
2618
+ const insertTextSelectionHandler = {
2619
+ toolId: "insertText",
2620
+ handle(context, selections, getText) {
2621
+ const tool = context.getTool();
2622
+ if (!tool) return;
2623
+ const getDefaults = () => ({
2624
+ strokeColor: tool.defaults.strokeColor ?? "#E44234",
2625
+ opacity: tool.defaults.opacity ?? 1,
2626
+ flags: tool.defaults.flags ?? ["print"]
2627
+ });
2628
+ for (const selection of selections) {
2629
+ const lastSegRect = selection.segmentRects[selection.segmentRects.length - 1];
2630
+ if (!lastSegRect) continue;
2631
+ const caretRect = computeCaretRect(lastSegRect);
2632
+ const caretId = uuidV4();
2633
+ const defaults = getDefaults();
2634
+ getText().then((text) => {
2635
+ var _a;
2636
+ context.createAnnotation(selection.pageIndex, {
2637
+ type: PdfAnnotationSubtype.CARET,
2638
+ id: caretId,
2639
+ pageIndex: selection.pageIndex,
2640
+ rect: caretRect,
2641
+ strokeColor: defaults.strokeColor,
2642
+ opacity: defaults.opacity,
2643
+ intent: "Insert",
2644
+ rectangleDifferences: { left: 0.5, top: 0.5, right: 0.5, bottom: 0.5 },
2645
+ created: /* @__PURE__ */ new Date(),
2646
+ flags: defaults.flags,
2647
+ ...text != null && { custom: { text } }
2648
+ });
2649
+ if ((_a = tool.behavior) == null ? void 0 : _a.selectAfterCreate) {
2650
+ context.selectAnnotation(selection.pageIndex, caretId);
2651
+ }
2652
+ });
2653
+ }
2654
+ }
2655
+ };
2656
+ const replaceTextSelectionHandler = {
2657
+ toolId: "replaceText",
2658
+ handle(context, selections, getText) {
2659
+ const tool = context.getTool();
2660
+ if (!tool) return;
2661
+ const getDefaults = () => ({
2662
+ strokeColor: tool.defaults.strokeColor ?? "#E44234",
2663
+ opacity: tool.defaults.opacity ?? 1,
2664
+ flags: tool.defaults.flags ?? ["print"]
2665
+ });
2666
+ for (const selection of selections) {
2667
+ const lastSegRect = selection.segmentRects[selection.segmentRects.length - 1];
2668
+ if (!lastSegRect) continue;
2669
+ const caretRect = computeCaretRect(lastSegRect);
2670
+ const caretId = uuidV4();
2671
+ const strikeoutId = uuidV4();
2672
+ const defaults = getDefaults();
2673
+ getText().then((text) => {
2674
+ var _a;
2675
+ context.createAnnotation(selection.pageIndex, {
2676
+ type: PdfAnnotationSubtype.CARET,
2677
+ id: caretId,
2678
+ pageIndex: selection.pageIndex,
2679
+ rect: caretRect,
2680
+ strokeColor: defaults.strokeColor,
2681
+ opacity: defaults.opacity,
2682
+ intent: "Replace",
2683
+ rectangleDifferences: { left: 0.5, top: 0.5, right: 0.5, bottom: 0.5 },
2684
+ created: /* @__PURE__ */ new Date(),
2685
+ flags: defaults.flags
2686
+ });
2687
+ context.createAnnotation(selection.pageIndex, {
2688
+ type: PdfAnnotationSubtype.STRIKEOUT,
2689
+ id: strikeoutId,
2690
+ pageIndex: selection.pageIndex,
2691
+ rect: selection.rect,
2692
+ segmentRects: selection.segmentRects,
2693
+ strokeColor: defaults.strokeColor,
2694
+ opacity: defaults.opacity,
2695
+ intent: "StrikeOutTextEdit",
2696
+ inReplyToId: caretId,
2697
+ replyType: PdfAnnotationReplyType.Group,
2698
+ created: /* @__PURE__ */ new Date(),
2699
+ flags: defaults.flags,
2700
+ ...text != null && { custom: { text } }
2701
+ });
2702
+ if ((_a = tool.behavior) == null ? void 0 : _a.selectAfterCreate) {
2703
+ context.selectAnnotation(selection.pageIndex, caretId);
2704
+ }
2705
+ });
2706
+ }
2707
+ }
2708
+ };
2420
2709
  const patchInk = (original, ctx) => {
2421
2710
  switch (ctx.type) {
2422
2711
  case "vertex-edit":
@@ -2845,10 +3134,12 @@ const _AnnotationPlugin = class _AnnotationPlugin extends BasePlugin {
2845
3134
  this.importQueue = /* @__PURE__ */ new Map();
2846
3135
  this.commitInProgress = /* @__PURE__ */ new Map();
2847
3136
  this.handlerFactories = /* @__PURE__ */ new Map();
3137
+ this.selectionHandlerFactories = /* @__PURE__ */ new Map();
2848
3138
  this.activeTool$ = createBehaviorEmitter();
2849
3139
  this.events$ = createBehaviorEmitter();
2850
3140
  this.toolsChange$ = createBehaviorEmitter();
2851
3141
  this.patchRegistry = new PatchRegistry();
3142
+ this.appearanceCache = /* @__PURE__ */ new Map();
2852
3143
  this.unifiedDragStates = /* @__PURE__ */ new Map();
2853
3144
  this.unifiedDrag$ = createBehaviorEmitter();
2854
3145
  this.unifiedResizeStates = /* @__PURE__ */ new Map();
@@ -2860,6 +3151,7 @@ const _AnnotationPlugin = class _AnnotationPlugin extends BasePlugin {
2860
3151
  this.history = ((_b = registry.getPlugin("history")) == null ? void 0 : _b.provides()) ?? null;
2861
3152
  this.interactionManager = ((_c = registry.getPlugin("interaction-manager")) == null ? void 0 : _c.provides()) ?? null;
2862
3153
  this.registerHandlerFactories();
3154
+ this.registerSelectionHandlerFactories();
2863
3155
  this.registerBuiltInPatches();
2864
3156
  }
2865
3157
  // ─────────────────────────────────────────────────────────
@@ -2885,7 +3177,7 @@ const _AnnotationPlugin = class _AnnotationPlugin extends BasePlugin {
2885
3177
  for (const tool of this.state.tools) {
2886
3178
  if (tool.interaction.textSelection) {
2887
3179
  this.selection.enableForMode(tool.interaction.mode ?? tool.id, {
2888
- showSelectionRects: false,
3180
+ showSelectionRects: tool.interaction.showSelectionRects ?? false,
2889
3181
  enableSelection: true,
2890
3182
  enableMarquee: false
2891
3183
  });
@@ -2898,6 +3190,7 @@ const _AnnotationPlugin = class _AnnotationPlugin extends BasePlugin {
2898
3190
  this.pendingContexts.delete(documentId);
2899
3191
  this.isInitialLoadComplete.delete(documentId);
2900
3192
  this.importQueue.delete(documentId);
3193
+ this.appearanceCache.delete(documentId);
2901
3194
  this.logger.debug(
2902
3195
  "AnnotationPlugin",
2903
3196
  "DocumentClosed",
@@ -2913,6 +3206,11 @@ const _AnnotationPlugin = class _AnnotationPlugin extends BasePlugin {
2913
3206
  this.handlerFactories.set(PdfAnnotationSubtype.LINE, lineHandlerFactory);
2914
3207
  this.handlerFactories.set(PdfAnnotationSubtype.INK, inkHandlerFactory);
2915
3208
  this.handlerFactories.set(PdfAnnotationSubtype.FREETEXT, freeTextHandlerFactory);
3209
+ this.handlerFactories.set(PdfAnnotationSubtype.TEXT, textHandlerFactory);
3210
+ }
3211
+ registerSelectionHandlerFactories() {
3212
+ this.selectionHandlerFactories.set("insertText", insertTextSelectionHandler);
3213
+ this.selectionHandlerFactories.set("replaceText", replaceTextSelectionHandler);
2916
3214
  }
2917
3215
  registerBuiltInPatches() {
2918
3216
  this.patchRegistry.register(PdfAnnotationSubtype.INK, patchInk);
@@ -2946,7 +3244,7 @@ const _AnnotationPlugin = class _AnnotationPlugin extends BasePlugin {
2946
3244
  if (modeId !== "pointerMode") return;
2947
3245
  const docState = this.state.documents[documentId];
2948
3246
  if (!docState) return;
2949
- const pageAnnotations = (docState.pages[pageIndex] ?? []).map((uid) => docState.byUid[uid]).filter((ta) => ta !== void 0).filter((ta) => !isLink(ta));
3247
+ const pageAnnotations = (docState.pages[pageIndex] ?? []).map((uid) => docState.byUid[uid]).filter((ta) => ta !== void 0).filter((ta) => isSidebarAnnotation(ta));
2950
3248
  const selectedIds = pageAnnotations.filter((ta) => rectsIntersect(rect, ta.object.rect)).map((ta) => ta.object.id);
2951
3249
  if (selectedIds.length > 0) {
2952
3250
  const expandedIds = /* @__PURE__ */ new Set();
@@ -2964,44 +3262,32 @@ const _AnnotationPlugin = class _AnnotationPlugin extends BasePlugin {
2964
3262
  }
2965
3263
  });
2966
3264
  (_c = this.selection) == null ? void 0 : _c.onEndSelection(({ documentId }) => {
2967
- var _a2, _b2, _c2;
2968
- if (!this.checkPermission(documentId, PdfPermissionFlag.ModifyAnnotations)) {
2969
- return;
2970
- }
3265
+ var _a2, _b2, _c2, _d;
3266
+ if (!this.checkPermission(documentId, PdfPermissionFlag.ModifyAnnotations)) return;
2971
3267
  const activeTool = this.getActiveTool(documentId);
2972
3268
  if (!activeTool || !activeTool.interaction.textSelection) return;
2973
3269
  const formattedSelection = (_a2 = this.selection) == null ? void 0 : _a2.getFormattedSelection();
2974
3270
  const selectionText = (_b2 = this.selection) == null ? void 0 : _b2.getSelectedText();
2975
3271
  if (!formattedSelection || !selectionText) return;
2976
- for (const selection of formattedSelection) {
2977
- selectionText.wait((text) => {
2978
- var _a3, _b3;
2979
- const annotationId = uuidV4();
2980
- this.createAnnotation(
2981
- selection.pageIndex,
2982
- {
2983
- ...activeTool.defaults,
2984
- rect: selection.rect,
2985
- segmentRects: selection.segmentRects,
2986
- pageIndex: selection.pageIndex,
2987
- created: /* @__PURE__ */ new Date(),
2988
- id: annotationId,
2989
- custom: {
2990
- text: text.join("\n")
2991
- }
2992
- },
2993
- void 0,
2994
- documentId
2995
- );
2996
- if ((_a3 = activeTool.behavior) == null ? void 0 : _a3.deactivateToolAfterCreate) {
2997
- this.setActiveTool(null, documentId);
2998
- }
2999
- if ((_b3 = activeTool.behavior) == null ? void 0 : _b3.selectAfterCreate) {
3000
- this.selectAnnotation(selection.pageIndex, annotationId, documentId);
3001
- }
3002
- }, ignore);
3272
+ const getText = () => new Promise((resolve) => {
3273
+ selectionText.wait(
3274
+ (text) => resolve(text.join("\n")),
3275
+ () => resolve(void 0)
3276
+ );
3277
+ });
3278
+ const context = {
3279
+ toolId: activeTool.id,
3280
+ documentId,
3281
+ getTool: () => this.getActiveTool(documentId) ?? null,
3282
+ createAnnotation: (pageIndex, annotation) => this.createAnnotation(pageIndex, annotation, void 0, documentId),
3283
+ selectAnnotation: (pageIndex, id) => this.selectAnnotation(pageIndex, id, documentId)
3284
+ };
3285
+ const handler = this.selectionHandlerFactories.get(activeTool.id) ?? textMarkupSelectionHandler;
3286
+ handler.handle(context, formattedSelection, getText);
3287
+ if ((_c2 = activeTool.behavior) == null ? void 0 : _c2.deactivateToolAfterCreate) {
3288
+ this.setActiveTool(null, documentId);
3003
3289
  }
3004
- (_c2 = this.selection) == null ? void 0 : _c2.clear();
3290
+ (_d = this.selection) == null ? void 0 : _d.clear();
3005
3291
  });
3006
3292
  }
3007
3293
  registerInteractionForTool(tool) {
@@ -3034,10 +3320,13 @@ const _AnnotationPlugin = class _AnnotationPlugin extends BasePlugin {
3034
3320
  createAnnotation: (pageIndex, anno, ctx) => this.createAnnotation(pageIndex, anno, ctx),
3035
3321
  updateAnnotation: (pageIndex, id, patch) => this.updateAnnotation(pageIndex, id, patch),
3036
3322
  updateAnnotations: (patches) => this.updateAnnotationsMethod(patches),
3323
+ moveAnnotation: (pageIndex, id, position, mode, documentId) => this.moveAnnotationMethod(pageIndex, id, position, mode, documentId),
3037
3324
  deleteAnnotation: (pageIndex, id) => this.deleteAnnotation(pageIndex, id),
3038
3325
  deleteAnnotations: (annotations, documentId) => this.deleteAnnotationsMethod(annotations, documentId),
3039
3326
  purgeAnnotation: (pageIndex, id, documentId) => this.purgeAnnotationMethod(pageIndex, id, documentId),
3040
3327
  renderAnnotation: (options) => this.renderAnnotation(options),
3328
+ getPageAppearances: (pageIndex, options, documentId) => this.getPageAppearances(pageIndex, options, documentId),
3329
+ invalidatePageAppearances: (pageIndex, documentId) => this.invalidatePageAppearances(pageIndex, documentId),
3041
3330
  commit: () => this.commit(),
3042
3331
  // Attached links (IRT link children)
3043
3332
  getAttachedLinks: (id, documentId) => this.getAttachedLinksMethod(id, documentId),
@@ -3094,10 +3383,13 @@ const _AnnotationPlugin = class _AnnotationPlugin extends BasePlugin {
3094
3383
  createAnnotation: (pageIndex, anno, ctx) => this.createAnnotation(pageIndex, anno, ctx, documentId),
3095
3384
  updateAnnotation: (pageIndex, id, patch) => this.updateAnnotation(pageIndex, id, patch, documentId),
3096
3385
  updateAnnotations: (patches) => this.updateAnnotationsMethod(patches, documentId),
3386
+ moveAnnotation: (pageIndex, id, position, mode) => this.moveAnnotationMethod(pageIndex, id, position, mode, documentId),
3097
3387
  deleteAnnotation: (pageIndex, id) => this.deleteAnnotation(pageIndex, id, documentId),
3098
3388
  deleteAnnotations: (annotations) => this.deleteAnnotationsMethod(annotations, documentId),
3099
3389
  purgeAnnotation: (pageIndex, id) => this.purgeAnnotationMethod(pageIndex, id, documentId),
3100
3390
  renderAnnotation: (options) => this.renderAnnotation(options, documentId),
3391
+ getPageAppearances: (pageIndex, options) => this.getPageAppearances(pageIndex, options, documentId),
3392
+ invalidatePageAppearances: (pageIndex) => this.invalidatePageAppearances(pageIndex, documentId),
3101
3393
  commit: () => this.commit(documentId),
3102
3394
  getAttachedLinks: (id) => this.getAttachedLinksMethod(id, documentId),
3103
3395
  hasAttachedLinks: (id) => this.hasAttachedLinksMethod(id, documentId),
@@ -3269,6 +3561,67 @@ const _AnnotationPlugin = class _AnnotationPlugin extends BasePlugin {
3269
3561
  }
3270
3562
  return this.engine.renderPageAnnotation(doc, page, annotation, options);
3271
3563
  }
3564
+ /**
3565
+ * Batch-fetch rendered appearance stream images for all annotations on a page.
3566
+ * Results are cached per document + page. Call invalidatePageAppearances to clear.
3567
+ */
3568
+ getPageAppearances(pageIndex, options, documentId) {
3569
+ const id = documentId ?? this.getActiveDocumentId();
3570
+ const docState = this.getCoreDocument(id);
3571
+ const doc = docState == null ? void 0 : docState.document;
3572
+ if (!doc) {
3573
+ return PdfTaskHelper.reject({ code: PdfErrorCode.NotFound, message: "Document not found" });
3574
+ }
3575
+ const page = doc.pages.find((p) => p.index === pageIndex);
3576
+ if (!page) {
3577
+ return PdfTaskHelper.reject({ code: PdfErrorCode.NotFound, message: "Page not found" });
3578
+ }
3579
+ let docCache = this.appearanceCache.get(id);
3580
+ if (!docCache) {
3581
+ docCache = /* @__PURE__ */ new Map();
3582
+ this.appearanceCache.set(id, docCache);
3583
+ }
3584
+ const cached = docCache.get(pageIndex);
3585
+ if (cached && !options) {
3586
+ const task = new Task();
3587
+ task.resolve(cached);
3588
+ return task;
3589
+ }
3590
+ const engineTask = this.engine.renderPageAnnotations(doc, page, options);
3591
+ const resultTask = new Task();
3592
+ engineTask.wait(
3593
+ (result) => {
3594
+ docCache.set(pageIndex, result);
3595
+ resultTask.resolve(result);
3596
+ },
3597
+ (error) => {
3598
+ resultTask.fail(error);
3599
+ }
3600
+ );
3601
+ return resultTask;
3602
+ }
3603
+ /**
3604
+ * Clear cached appearances for a specific page (e.g. on zoom change).
3605
+ */
3606
+ invalidatePageAppearances(pageIndex, documentId) {
3607
+ const id = documentId ?? this.getActiveDocumentId();
3608
+ const docCache = this.appearanceCache.get(id);
3609
+ if (docCache) {
3610
+ docCache.delete(pageIndex);
3611
+ }
3612
+ }
3613
+ /**
3614
+ * Remove a single annotation's entry from the page appearance cache.
3615
+ * Used after committing changes that regenerate the annotation's appearance.
3616
+ */
3617
+ invalidateAnnotationAppearance(annotId, pageIndex, documentId) {
3618
+ const id = documentId ?? this.getActiveDocumentId();
3619
+ const docCache = this.appearanceCache.get(id);
3620
+ if (!docCache) return;
3621
+ const pageMap = docCache.get(pageIndex);
3622
+ if (!pageMap) return;
3623
+ delete pageMap[annotId];
3624
+ }
3272
3625
  importAnnotations(items, documentId) {
3273
3626
  const id = documentId ?? this.getActiveDocumentId();
3274
3627
  if (!this.isInitialLoadComplete.get(id)) {
@@ -3840,7 +4193,7 @@ const _AnnotationPlugin = class _AnnotationPlugin extends BasePlugin {
3840
4193
  patches.push({ pageIndex: ta.object.pageIndex, id, patch });
3841
4194
  }
3842
4195
  if (patches.length > 0) {
3843
- this.updateAnnotationsMethod(patches, documentId);
4196
+ this.moveAnnotationsMethod(patches, documentId);
3844
4197
  }
3845
4198
  }
3846
4199
  const endPatches = this.computeDragPreviewPatches(state, documentId);
@@ -4424,6 +4777,87 @@ const _AnnotationPlugin = class _AnnotationPlugin extends BasePlugin {
4424
4777
  const historyScope = this.history.forDocument(docId);
4425
4778
  historyScope.register(command, this.ANNOTATION_HISTORY_TOPIC);
4426
4779
  }
4780
+ moveAnnotationsMethod(patches, documentId) {
4781
+ const docId = documentId ?? this.getActiveDocumentId();
4782
+ if (!this.checkPermission(docId, PdfPermissionFlag.ModifyAnnotations)) {
4783
+ this.logger.debug(
4784
+ "AnnotationPlugin",
4785
+ "MoveAnnotations",
4786
+ `Cannot move annotations: document ${docId} lacks ModifyAnnotations permission`
4787
+ );
4788
+ return;
4789
+ }
4790
+ const docState = this.getDocumentState(docId);
4791
+ const moveData = patches.map(({ pageIndex, id, patch }) => {
4792
+ var _a;
4793
+ const originalObject = (_a = docState.byUid[id]) == null ? void 0 : _a.object;
4794
+ if (!originalObject) return null;
4795
+ return { pageIndex, id, patch, originalObject };
4796
+ }).filter((p) => p !== null);
4797
+ if (moveData.length === 0) return;
4798
+ const execute = () => {
4799
+ for (const { pageIndex, id, patch, originalObject } of moveData) {
4800
+ this.dispatch(moveAnnotation(docId, pageIndex, id, patch));
4801
+ this.events$.emit({
4802
+ type: "update",
4803
+ documentId: docId,
4804
+ annotation: originalObject,
4805
+ pageIndex,
4806
+ patch,
4807
+ committed: false
4808
+ });
4809
+ }
4810
+ };
4811
+ if (!this.history) {
4812
+ execute();
4813
+ if (this.config.autoCommit !== false) {
4814
+ this.commit(docId);
4815
+ }
4816
+ return;
4817
+ }
4818
+ const undoData = moveData.map(({ pageIndex, id, patch, originalObject }) => ({
4819
+ pageIndex,
4820
+ id,
4821
+ originalPatch: Object.fromEntries(
4822
+ Object.keys(patch).map((key) => [key, originalObject[key]])
4823
+ ),
4824
+ originalObject
4825
+ }));
4826
+ const command = {
4827
+ execute,
4828
+ undo: () => {
4829
+ for (const { pageIndex, id, originalPatch, originalObject } of undoData) {
4830
+ this.dispatch(moveAnnotation(docId, pageIndex, id, originalPatch));
4831
+ this.events$.emit({
4832
+ type: "update",
4833
+ documentId: docId,
4834
+ annotation: originalObject,
4835
+ pageIndex,
4836
+ patch: originalPatch,
4837
+ committed: false
4838
+ });
4839
+ }
4840
+ },
4841
+ metadata: { annotationIds: moveData.map((p) => p.id) }
4842
+ };
4843
+ const historyScope = this.history.forDocument(docId);
4844
+ historyScope.register(command, this.ANNOTATION_HISTORY_TOPIC);
4845
+ }
4846
+ moveAnnotationMethod(pageIndex, annotationId, position, mode = "delta", documentId) {
4847
+ const docId = documentId ?? this.getActiveDocumentId();
4848
+ const ta = this.getAnnotationById(annotationId, docId);
4849
+ if (!ta) return;
4850
+ const currentRect = ta.object.rect;
4851
+ const newRect = {
4852
+ ...currentRect,
4853
+ origin: mode === "absolute" ? { x: position.x, y: position.y } : { x: currentRect.origin.x + position.x, y: currentRect.origin.y + position.y }
4854
+ };
4855
+ const patch = this.transformAnnotation(ta.object, {
4856
+ type: "move",
4857
+ changes: { rect: newRect }
4858
+ });
4859
+ this.moveAnnotationsMethod([{ pageIndex, id: annotationId, patch }], docId);
4860
+ }
4427
4861
  getActiveTool(documentId) {
4428
4862
  const docState = this.getDocumentState(documentId);
4429
4863
  if (!docState.activeToolId) return null;
@@ -4493,6 +4927,9 @@ const _AnnotationPlugin = class _AnnotationPlugin extends BasePlugin {
4493
4927
  ctx: contexts == null ? void 0 : contexts.get(ta.object.id)
4494
4928
  });
4495
4929
  break;
4930
+ case "moved":
4931
+ batch.updates.push({ uid, ta, moved: true });
4932
+ break;
4496
4933
  case "dirty":
4497
4934
  batch.updates.push({ uid, ta });
4498
4935
  break;
@@ -4517,11 +4954,11 @@ const _AnnotationPlugin = class _AnnotationPlugin extends BasePlugin {
4517
4954
  const createTask = this.engine.createPageAnnotation(doc, page, ta.object, ctx);
4518
4955
  pendingOps.push({ type: "create", task: createTask, ta, uid, ctx });
4519
4956
  }
4520
- for (const { uid, ta } of batch.updates) {
4957
+ for (const { uid, ta, moved } of batch.updates) {
4521
4958
  const page = doc.pages.find((p) => p.index === ta.object.pageIndex);
4522
4959
  if (!page) continue;
4523
- const updateTask = this.engine.updatePageAnnotation(doc, page, ta.object);
4524
- pendingOps.push({ type: "update", task: updateTask, ta, uid });
4960
+ const updateTask = moved ? this.engine.updatePageAnnotation(doc, page, ta.object, { regenerateAppearance: false }) : this.engine.updatePageAnnotation(doc, page, ta.object);
4961
+ pendingOps.push({ type: "update", task: updateTask, ta, uid, moved });
4525
4962
  }
4526
4963
  for (const { uid, ta } of batch.deletions) {
4527
4964
  const page = doc.pages.find((p) => p.index === ta.object.pageIndex);
@@ -4539,6 +4976,12 @@ const _AnnotationPlugin = class _AnnotationPlugin extends BasePlugin {
4539
4976
  Task.allSettled(allTasks).wait(
4540
4977
  () => {
4541
4978
  this.emitCommitEvents(docId, pendingOps, contexts);
4979
+ for (const op of pendingOps) {
4980
+ if (op.type === "update" && op.moved) continue;
4981
+ if (op.type === "create" || op.type === "update" || op.type === "delete") {
4982
+ this.invalidateAnnotationAppearance(op.ta.object.id, op.ta.object.pageIndex, docId);
4983
+ }
4984
+ }
4542
4985
  this.dispatch(commitPendingChanges(docId, batch.committedUids));
4543
4986
  task.resolve(true);
4544
4987
  },
@@ -4672,6 +5115,8 @@ const isPolylineTool = createToolPredicate("polyline");
4672
5115
  const isPolygonTool = createToolPredicate("polygon");
4673
5116
  const isFreeTextTool = createToolPredicate("freeText");
4674
5117
  const isStampTool = createToolPredicate("stamp");
5118
+ const isInsertTextTool = createToolPredicate("insertText");
5119
+ const isReplaceTextTool = createToolPredicate("replaceText");
4675
5120
  const AnnotationPluginPackage = {
4676
5121
  manifest,
4677
5122
  create: (registry, config) => new AnnotationPlugin(ANNOTATION_PLUGIN_ID, registry, config),
@@ -4711,6 +5156,7 @@ export {
4711
5156
  initialDocumentState,
4712
5157
  initialState,
4713
5158
  isAnnotationSelected,
5159
+ isCaret,
4714
5160
  isCircle,
4715
5161
  isCircleTool,
4716
5162
  isFreeText,
@@ -4721,6 +5167,7 @@ export {
4721
5167
  isInk,
4722
5168
  isInkHighlighterTool,
4723
5169
  isInkTool,
5170
+ isInsertTextTool,
4724
5171
  isLine,
4725
5172
  isLineTool,
4726
5173
  isLink,
@@ -4729,6 +5176,7 @@ export {
4729
5176
  isPolyline,
4730
5177
  isPolylineTool,
4731
5178
  isRedact,
5179
+ isReplaceTextTool,
4732
5180
  isSidebarAnnotation,
4733
5181
  isSquare,
4734
5182
  isSquareTool,