@embedpdf/plugin-annotation 1.0.16 → 1.0.17

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.
package/dist/index.js CHANGED
@@ -1,5 +1,5 @@
1
1
  import { BasePlugin, createBehaviorEmitter, SET_DOCUMENT } from "@embedpdf/core";
2
- import { PdfAnnotationLineEnding, rectFromPoints, expandRect, rotateAndTranslatePoint, PdfAnnotationSubtype, PdfBlendMode, ignore, PdfTaskHelper, PdfErrorCode, Rotation, AppearanceMode, Task, PdfVerticalAlignment, PdfTextAlignment, PdfStandardFont, PdfAnnotationBorderStyle } from "@embedpdf/models";
2
+ import { PdfAnnotationSubtype, PdfAnnotationLineEnding, rectFromPoints, expandRect, rotateAndTranslatePoint, PdfBlendMode, uuidV4, ignore, PdfTaskHelper, PdfErrorCode, Rotation, AppearanceMode, Task, PdfVerticalAlignment, PdfTextAlignment, PdfStandardFont, PdfAnnotationBorderStyle } from "@embedpdf/models";
3
3
  const ANNOTATION_PLUGIN_ID = "annotation";
4
4
  const manifest = {
5
5
  id: ANNOTATION_PLUGIN_ID,
@@ -10,11 +10,11 @@ const manifest = {
10
10
  optional: ["history"],
11
11
  defaultConfig: {
12
12
  enabled: true,
13
- autoCommit: true
13
+ autoCommit: true,
14
+ annotationAuthor: "Guest"
14
15
  }
15
16
  };
16
17
  const SET_ANNOTATIONS = "ANNOTATION/SET_ANNOTATIONS";
17
- const REINDEX_PAGE_ANNOTATIONS = "ANNOTATION/REINDEX_PAGE";
18
18
  const SELECT_ANNOTATION = "ANNOTATION/SELECT_ANNOTATION";
19
19
  const DESELECT_ANNOTATION = "ANNOTATION/DESELECT_ANNOTATION";
20
20
  const UPDATE_TOOL_DEFAULTS = "ANNOTATION/UPDATE_TOOL_DEFAULTS";
@@ -23,20 +23,15 @@ const CREATE_ANNOTATION = "ANNOTATION/CREATE_ANNOTATION";
23
23
  const PATCH_ANNOTATION = "ANNOTATION/PATCH_ANNOTATION";
24
24
  const DELETE_ANNOTATION = "ANNOTATION/DELETE_ANNOTATION";
25
25
  const COMMIT_PENDING_CHANGES = "ANNOTATION/COMMIT";
26
- const STORE_PDF_ID = "ANNOTATION/STORE_PDF_ID";
27
26
  const PURGE_ANNOTATION = "ANNOTATION/PURGE_ANNOTATION";
28
27
  const SET_ACTIVE_VARIANT = "ANNOTATION/SET_ACTIVE_VARIANT";
29
28
  const setAnnotations = (p) => ({
30
29
  type: SET_ANNOTATIONS,
31
30
  payload: p
32
31
  });
33
- const reindexPageAnnotations = (pageIndex) => ({
34
- type: REINDEX_PAGE_ANNOTATIONS,
35
- payload: { pageIndex }
36
- });
37
- const selectAnnotation = (pageIndex, localId) => ({
32
+ const selectAnnotation = (pageIndex, id) => ({
38
33
  type: SELECT_ANNOTATION,
39
- payload: { pageIndex, localId }
34
+ payload: { pageIndex, id }
40
35
  });
41
36
  const deselectAnnotation = () => ({ type: DESELECT_ANNOTATION });
42
37
  const updateToolDefaults = (variantKey, patch) => ({ type: UPDATE_TOOL_DEFAULTS, payload: { variantKey, patch } });
@@ -44,23 +39,19 @@ const addColorPreset = (c) => ({
44
39
  type: ADD_COLOR_PRESET,
45
40
  payload: c
46
41
  });
47
- const createAnnotation = (pageIndex, localId, annotation) => ({
42
+ const createAnnotation = (pageIndex, annotation) => ({
48
43
  type: CREATE_ANNOTATION,
49
- payload: { pageIndex, localId, annotation }
44
+ payload: { pageIndex, annotation }
50
45
  });
51
- const patchAnnotation = (pageIndex, localId, patch) => ({
46
+ const patchAnnotation = (pageIndex, id, patch) => ({
52
47
  type: PATCH_ANNOTATION,
53
- payload: { pageIndex, localId, patch }
48
+ payload: { pageIndex, id, patch }
54
49
  });
55
- const deleteAnnotation = (pageIndex, localId) => ({
50
+ const deleteAnnotation = (pageIndex, id) => ({
56
51
  type: DELETE_ANNOTATION,
57
- payload: { pageIndex, localId }
52
+ payload: { pageIndex, id }
58
53
  });
59
54
  const commitPendingChanges = () => ({ type: COMMIT_PENDING_CHANGES });
60
- const storePdfId = (uid, pdfId) => ({
61
- type: STORE_PDF_ID,
62
- payload: { uid, pdfId }
63
- });
64
55
  const purgeAnnotation = (uid) => ({
65
56
  type: PURGE_ANNOTATION,
66
57
  payload: { uid }
@@ -69,18 +60,72 @@ const setActiveVariant = (k) => ({
69
60
  type: SET_ACTIVE_VARIANT,
70
61
  payload: k
71
62
  });
72
- const makeUid$1 = (pageIndex, localId) => `p${pageIndex}#${localId}`;
73
- const parseUid = (uid) => {
74
- const [pg, rest] = uid.slice(1).split("#");
75
- return { pageIndex: Number(pg), localId: Number(rest) };
76
- };
77
63
  const makeVariantKey = (subtype, intent) => intent ? `${subtype}#${intent}` : `${subtype}`;
78
64
  const parseVariantKey = (key) => {
79
65
  const [subStr, intent] = key.split("#");
80
66
  return { subtype: Number(subStr), intent };
81
67
  };
82
68
  const variantKeyFromAnnotation = (a) => makeVariantKey(a.type, a.intent);
83
- const makeUid = (page, id) => `p${page}#${id}`;
69
+ function isInk(a) {
70
+ return a.object.type === PdfAnnotationSubtype.INK;
71
+ }
72
+ function isCircle(a) {
73
+ return a.object.type === PdfAnnotationSubtype.CIRCLE;
74
+ }
75
+ function isPolygon(a) {
76
+ return a.object.type === PdfAnnotationSubtype.POLYGON;
77
+ }
78
+ function isSquare(a) {
79
+ return a.object.type === PdfAnnotationSubtype.SQUARE;
80
+ }
81
+ function isLine(a) {
82
+ return a.object.type === PdfAnnotationSubtype.LINE;
83
+ }
84
+ function isPolyline(a) {
85
+ return a.object.type === PdfAnnotationSubtype.POLYLINE;
86
+ }
87
+ function isHighlight(a) {
88
+ return a.object.type === PdfAnnotationSubtype.HIGHLIGHT;
89
+ }
90
+ function isUnderline(a) {
91
+ return a.object.type === PdfAnnotationSubtype.UNDERLINE;
92
+ }
93
+ function isStrikeout(a) {
94
+ return a.object.type === PdfAnnotationSubtype.STRIKEOUT;
95
+ }
96
+ function isSquiggly(a) {
97
+ return a.object.type === PdfAnnotationSubtype.SQUIGGLY;
98
+ }
99
+ function isTextMarkup(a) {
100
+ return isHighlight(a) || isUnderline(a) || isStrikeout(a) || isSquiggly(a);
101
+ }
102
+ function isFreeText(a) {
103
+ return a.object.type === PdfAnnotationSubtype.FREETEXT;
104
+ }
105
+ function isStamp(a) {
106
+ return a.object.type === PdfAnnotationSubtype.STAMP;
107
+ }
108
+ function isText(a) {
109
+ return a.object.type === PdfAnnotationSubtype.TEXT;
110
+ }
111
+ function isSidebarAnnotation(a) {
112
+ return isTextMarkup(a) || isInk(a) || isSquare(a) || isCircle(a) || isPolygon(a) || isLine(a) || isPolyline(a) || isFreeText(a) || isStamp(a);
113
+ }
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
+ }
84
129
  const getAnnotationsByPageIndex = (s, page) => (s.pages[page] ?? []).map((uid) => s.byUid[uid]);
85
130
  const getAnnotations = (s) => {
86
131
  const out = {};
@@ -88,11 +133,6 @@ const getAnnotations = (s) => {
88
133
  return out;
89
134
  };
90
135
  const getSelectedAnnotation = (s) => s.selectedUid ? s.byUid[s.selectedUid] : null;
91
- const getSelectedAnnotationWithPageIndex = (s) => {
92
- if (!s.selectedUid) return null;
93
- const { pageIndex, localId } = parseUid(s.selectedUid);
94
- return { pageIndex, localId, annotation: s.byUid[s.selectedUid].object };
95
- };
96
136
  const getSelectedAnnotationByPageIndex = (s, pageIndex) => {
97
137
  if (!s.selectedUid) return null;
98
138
  const pageUids = s.pages[pageIndex] ?? [];
@@ -103,7 +143,7 @@ const getSelectedAnnotationByPageIndex = (s, pageIndex) => {
103
143
  };
104
144
  const isInAnnotationVariant = (s) => s.activeVariant !== null;
105
145
  const getSelectedAnnotationVariant = (s) => s.activeVariant;
106
- const isAnnotationSelected = (s, page, id) => s.selectedUid === makeUid(page, id);
146
+ const isAnnotationSelected = (s, id) => s.selectedUid === id;
107
147
  function getToolDefaultsBySubtypeAndIntent(state, subtype, intent) {
108
148
  const variantKey = makeVariantKey(subtype, intent ?? void 0);
109
149
  const fallbackKey = makeVariantKey(subtype);
@@ -115,6 +155,46 @@ function getToolDefaultsBySubtypeAndIntent(state, subtype, intent) {
115
155
  }
116
156
  return defaults;
117
157
  }
158
+ const getSidebarAnnotationsWithRepliesGroupedByPage = (s) => {
159
+ const repliesByParent = {};
160
+ for (const uidList of Object.values(s.pages)) {
161
+ for (const uid of uidList) {
162
+ const ta = s.byUid[uid];
163
+ if (isText(ta)) {
164
+ const parentId = ta.object.inReplyToId;
165
+ if (parentId) (repliesByParent[parentId] || (repliesByParent[parentId] = [])).push(ta);
166
+ }
167
+ }
168
+ }
169
+ const out = {};
170
+ for (const [pageStr, uidList] of Object.entries(s.pages)) {
171
+ const page = Number(pageStr);
172
+ const pageAnnotations = [];
173
+ for (const uid of uidList) {
174
+ const ta = s.byUid[uid];
175
+ if (isSidebarAnnotation(ta)) {
176
+ pageAnnotations.push({
177
+ page,
178
+ annotation: ta,
179
+ replies: repliesByParent[ta.object.id] ?? []
180
+ });
181
+ }
182
+ }
183
+ if (pageAnnotations.length > 0) {
184
+ out[page] = pageAnnotations;
185
+ }
186
+ }
187
+ return out;
188
+ };
189
+ const getSidebarAnnotationsWithReplies = (s) => {
190
+ const grouped = getSidebarAnnotationsWithRepliesGroupedByPage(s);
191
+ const out = [];
192
+ const sortedPages = Object.keys(grouped).map(Number).sort((a, b) => a - b);
193
+ for (const page of sortedPages) {
194
+ out.push(...grouped[page]);
195
+ }
196
+ return out;
197
+ };
118
198
  function createArrowHandler(isClosed) {
119
199
  const calculateGeometry = (sw) => {
120
200
  const len = sw * 9;
@@ -315,60 +395,6 @@ const index = /* @__PURE__ */ Object.freeze(/* @__PURE__ */ Object.definePropert
315
395
  deriveRect,
316
396
  lineRectWithEndings
317
397
  }, Symbol.toStringTag, { value: "Module" }));
318
- function isInk(a) {
319
- return a.object.type === PdfAnnotationSubtype.INK;
320
- }
321
- function isCircle(a) {
322
- return a.object.type === PdfAnnotationSubtype.CIRCLE;
323
- }
324
- function isPolygon(a) {
325
- return a.object.type === PdfAnnotationSubtype.POLYGON;
326
- }
327
- function isSquare(a) {
328
- return a.object.type === PdfAnnotationSubtype.SQUARE;
329
- }
330
- function isLine(a) {
331
- return a.object.type === PdfAnnotationSubtype.LINE;
332
- }
333
- function isPolyline(a) {
334
- return a.object.type === PdfAnnotationSubtype.POLYLINE;
335
- }
336
- function isHighlight(a) {
337
- return a.object.type === PdfAnnotationSubtype.HIGHLIGHT;
338
- }
339
- function isUnderline(a) {
340
- return a.object.type === PdfAnnotationSubtype.UNDERLINE;
341
- }
342
- function isStrikeout(a) {
343
- return a.object.type === PdfAnnotationSubtype.STRIKEOUT;
344
- }
345
- function isSquiggly(a) {
346
- return a.object.type === PdfAnnotationSubtype.SQUIGGLY;
347
- }
348
- function isTextMarkup(a) {
349
- return isHighlight(a) || isUnderline(a) || isStrikeout(a) || isSquiggly(a);
350
- }
351
- function isFreeText(a) {
352
- return a.object.type === PdfAnnotationSubtype.FREETEXT;
353
- }
354
- function isStamp(a) {
355
- return a.object.type === PdfAnnotationSubtype.STAMP;
356
- }
357
- function isHighlightDefaults(defaults) {
358
- return defaults.subtype === PdfAnnotationSubtype.HIGHLIGHT;
359
- }
360
- function isUnderlineDefaults(defaults) {
361
- return defaults.subtype === PdfAnnotationSubtype.UNDERLINE;
362
- }
363
- function isStrikeoutDefaults(defaults) {
364
- return defaults.subtype === PdfAnnotationSubtype.STRIKEOUT;
365
- }
366
- function isSquigglyDefaults(defaults) {
367
- return defaults.subtype === PdfAnnotationSubtype.SQUIGGLY;
368
- }
369
- function isTextMarkupDefaults(defaults) {
370
- return isHighlightDefaults(defaults) || isUnderlineDefaults(defaults) || isStrikeoutDefaults(defaults) || isSquigglyDefaults(defaults);
371
- }
372
398
  const _AnnotationPlugin = class _AnnotationPlugin extends BasePlugin {
373
399
  constructor(id, registry, engine, config) {
374
400
  super(id, registry);
@@ -415,12 +441,13 @@ const _AnnotationPlugin = class _AnnotationPlugin extends BasePlugin {
415
441
  }
416
442
  });
417
443
  (_c = this.selection) == null ? void 0 : _c.onEndSelection(() => {
418
- var _a2, _b2;
444
+ var _a2, _b2, _c2;
419
445
  if (!this.state.activeVariant) return;
420
446
  const defaults = this.state.toolDefaults[this.state.activeVariant];
421
447
  if (!defaults || !isTextMarkupDefaults(defaults)) return;
422
448
  const formattedSelection = (_a2 = this.selection) == null ? void 0 : _a2.getFormattedSelection();
423
- if (!formattedSelection) return;
449
+ const selectionText = (_b2 = this.selection) == null ? void 0 : _b2.getSelectedText();
450
+ if (!formattedSelection || !selectionText) return;
424
451
  for (const selection of formattedSelection) {
425
452
  const rect = selection.rect;
426
453
  const segmentRects = selection.segmentRects;
@@ -428,18 +455,24 @@ const _AnnotationPlugin = class _AnnotationPlugin extends BasePlugin {
428
455
  const color = defaults.color;
429
456
  const opacity = defaults.opacity;
430
457
  const blendMode = defaults.blendMode ?? PdfBlendMode.Normal;
431
- this.createAnnotation(selection.pageIndex, {
432
- type: subtype,
433
- rect,
434
- segmentRects,
435
- color,
436
- opacity,
437
- blendMode,
438
- pageIndex: selection.pageIndex,
439
- id: Date.now() + Math.random()
440
- });
458
+ selectionText.wait((text) => {
459
+ this.createAnnotation(selection.pageIndex, {
460
+ type: subtype,
461
+ rect,
462
+ segmentRects,
463
+ color,
464
+ opacity,
465
+ blendMode,
466
+ pageIndex: selection.pageIndex,
467
+ id: uuidV4(),
468
+ author: this.config.annotationAuthor,
469
+ custom: {
470
+ text: text.join("\n")
471
+ }
472
+ });
473
+ }, ignore);
441
474
  }
442
- (_b2 = this.selection) == null ? void 0 : _b2.clear();
475
+ (_c2 = this.selection) == null ? void 0 : _c2.clear();
443
476
  });
444
477
  }
445
478
  registerTool(variantKey, defaults) {
@@ -508,8 +541,8 @@ const _AnnotationPlugin = class _AnnotationPlugin extends BasePlugin {
508
541
  getColorPresets: () => [...this.state.colorPresets],
509
542
  addColorPreset: (color) => this.dispatch(addColorPreset(color)),
510
543
  createAnnotation: (pageIndex, annotation, ctx) => this.createAnnotation(pageIndex, annotation, ctx),
511
- updateAnnotation: (pageIndex, localId, patch) => this.updateAnnotation(pageIndex, localId, patch),
512
- deleteAnnotation: (pageIndex, localId) => this.deleteAnnotation(pageIndex, localId),
544
+ updateAnnotation: (pageIndex, id, patch) => this.updateAnnotation(pageIndex, id, patch),
545
+ deleteAnnotation: (pageIndex, id) => this.deleteAnnotation(pageIndex, id),
513
546
  renderAnnotation: (options) => this.renderAnnotation(options),
514
547
  onStateChange: this.state$.on,
515
548
  onActiveVariantChange: this.activeVariantChange$.on,
@@ -581,10 +614,15 @@ const _AnnotationPlugin = class _AnnotationPlugin extends BasePlugin {
581
614
  this.dispatch(selectAnnotation(pageIndex, annotationId));
582
615
  }
583
616
  createAnnotation(pageIndex, annotation, ctx) {
584
- const localId = annotation.id;
617
+ const id = annotation.id;
585
618
  const execute = () => {
586
- this.dispatch(createAnnotation(pageIndex, localId, annotation));
587
- if (ctx) this.pendingContexts.set(localId, ctx);
619
+ this.dispatch(
620
+ createAnnotation(pageIndex, {
621
+ ...annotation,
622
+ author: annotation.author ?? this.config.annotationAuthor
623
+ })
624
+ );
625
+ if (ctx) this.pendingContexts.set(id, ctx);
588
626
  };
589
627
  if (!this.history) {
590
628
  execute();
@@ -594,9 +632,9 @@ const _AnnotationPlugin = class _AnnotationPlugin extends BasePlugin {
594
632
  const command = {
595
633
  execute,
596
634
  undo: () => {
597
- this.pendingContexts.delete(localId);
635
+ this.pendingContexts.delete(id);
598
636
  this.dispatch(deselectAnnotation());
599
- this.dispatch(deleteAnnotation(pageIndex, localId));
637
+ this.dispatch(deleteAnnotation(pageIndex, id));
600
638
  }
601
639
  };
602
640
  this.history.register(command, this.ANNOTATION_HISTORY_TOPIC);
@@ -606,11 +644,14 @@ const _AnnotationPlugin = class _AnnotationPlugin extends BasePlugin {
606
644
  const merged = { ...original, ...patch };
607
645
  return { ...patch, rect: deriveRect(merged) };
608
646
  }
609
- updateAnnotation(pageIndex, localId, patch) {
610
- const originalObject = this.state.byUid[makeUid$1(pageIndex, localId)].object;
611
- const finalPatch = this.buildPatch(originalObject, patch);
647
+ updateAnnotation(pageIndex, id, patch) {
648
+ const originalObject = this.state.byUid[id].object;
649
+ const finalPatch = this.buildPatch(originalObject, {
650
+ ...patch,
651
+ author: patch.author ?? this.config.annotationAuthor
652
+ });
612
653
  if (!this.history) {
613
- this.dispatch(patchAnnotation(pageIndex, localId, finalPatch));
654
+ this.dispatch(patchAnnotation(pageIndex, id, finalPatch));
614
655
  if (this.config.autoCommit !== false) {
615
656
  this.commit();
616
657
  }
@@ -620,27 +661,27 @@ const _AnnotationPlugin = class _AnnotationPlugin extends BasePlugin {
620
661
  Object.keys(patch).map((key) => [key, originalObject[key]])
621
662
  );
622
663
  const command = {
623
- execute: () => this.dispatch(patchAnnotation(pageIndex, localId, finalPatch)),
624
- undo: () => this.dispatch(patchAnnotation(pageIndex, localId, originalPatch))
664
+ execute: () => this.dispatch(patchAnnotation(pageIndex, id, finalPatch)),
665
+ undo: () => this.dispatch(patchAnnotation(pageIndex, id, originalPatch))
625
666
  };
626
667
  this.history.register(command, this.ANNOTATION_HISTORY_TOPIC);
627
668
  }
628
- deleteAnnotation(pageIndex, localId) {
669
+ deleteAnnotation(pageIndex, id) {
629
670
  if (!this.history) {
630
671
  this.dispatch(deselectAnnotation());
631
- this.dispatch(deleteAnnotation(pageIndex, localId));
672
+ this.dispatch(deleteAnnotation(pageIndex, id));
632
673
  if (this.config.autoCommit !== false) {
633
674
  this.commit();
634
675
  }
635
676
  return;
636
677
  }
637
- const originalAnnotation = this.state.byUid[makeUid$1(pageIndex, localId)].object;
678
+ const originalAnnotation = this.state.byUid[id].object;
638
679
  const command = {
639
680
  execute: () => {
640
681
  this.dispatch(deselectAnnotation());
641
- this.dispatch(deleteAnnotation(pageIndex, localId));
682
+ this.dispatch(deleteAnnotation(pageIndex, id));
642
683
  },
643
- undo: () => this.dispatch(createAnnotation(pageIndex, localId, originalAnnotation))
684
+ undo: () => this.dispatch(createAnnotation(pageIndex, originalAnnotation))
644
685
  };
645
686
  this.history.register(command, this.ANNOTATION_HISTORY_TOPIC);
646
687
  }
@@ -652,63 +693,45 @@ const _AnnotationPlugin = class _AnnotationPlugin extends BasePlugin {
652
693
  return PdfTaskHelper.reject({ code: PdfErrorCode.NotFound, message: "Document not found" });
653
694
  const creations = [];
654
695
  const updates = [];
655
- const deletionsByPage = /* @__PURE__ */ new Map();
656
- const affectedPages = /* @__PURE__ */ new Set();
696
+ const deletions = [];
657
697
  for (const [uid, ta] of Object.entries(this.state.byUid)) {
658
698
  if (ta.commitState === "synced") continue;
659
- const { pageIndex } = parseUid(uid);
660
- const page = doc.pages.find((p) => p.index === pageIndex);
699
+ const page = doc.pages.find((p) => p.index === ta.object.pageIndex);
661
700
  if (!page) continue;
662
- affectedPages.add(pageIndex);
663
701
  switch (ta.commitState) {
664
702
  case "new":
665
- const ctx = this.pendingContexts.get(ta.localId);
703
+ const ctx = this.pendingContexts.get(ta.object.id);
666
704
  const task2 = this.engine.createPageAnnotation(doc, page, ta.object, ctx);
667
- task2.wait((annoId) => {
668
- this.dispatch(storePdfId(uid, annoId));
669
- this.pendingContexts.delete(ta.localId);
705
+ task2.wait(() => {
706
+ this.pendingContexts.delete(ta.object.id);
670
707
  }, ignore);
671
708
  creations.push(task2);
672
709
  break;
673
710
  case "dirty":
674
- updates.push(
675
- this.engine.updatePageAnnotation(doc, page, { ...ta.object, id: ta.pdfId })
676
- );
711
+ updates.push(this.engine.updatePageAnnotation(doc, page, ta.object));
677
712
  break;
678
713
  case "deleted":
679
- if (!deletionsByPage.has(pageIndex)) {
680
- deletionsByPage.set(pageIndex, []);
681
- }
682
- deletionsByPage.get(pageIndex).push({ ta, uid });
714
+ deletions.push({ ta, uid });
683
715
  break;
684
716
  }
685
717
  }
686
718
  const deletionTasks = [];
687
- for (const [pageIndex, deletions] of deletionsByPage.entries()) {
688
- const page = doc.pages.find((p) => p.index === pageIndex);
689
- deletions.sort((a, b) => (b.ta.pdfId ?? -1) - (a.ta.pdfId ?? -1));
690
- for (const { ta, uid } of deletions) {
691
- if (ta.pdfId !== void 0) {
692
- const task2 = new Task();
693
- const removeTask = this.engine.removePageAnnotation(doc, page, {
694
- ...ta.object,
695
- id: ta.pdfId
696
- });
697
- removeTask.wait(() => {
698
- this.dispatch(purgeAnnotation(uid));
699
- task2.resolve(true);
700
- }, task2.fail);
701
- deletionTasks.push(task2);
702
- } else {
719
+ for (const { ta, uid } of deletions) {
720
+ const page = doc.pages.find((p) => p.index === ta.object.pageIndex);
721
+ if (ta.commitState === "deleted" && ta.object.id) {
722
+ const task2 = new Task();
723
+ const removeTask = this.engine.removePageAnnotation(doc, page, ta.object);
724
+ removeTask.wait(() => {
703
725
  this.dispatch(purgeAnnotation(uid));
704
- }
726
+ task2.resolve(true);
727
+ }, task2.fail);
728
+ deletionTasks.push(task2);
729
+ } else {
730
+ this.dispatch(purgeAnnotation(uid));
705
731
  }
706
732
  }
707
733
  const allWriteTasks = [...creations, ...updates, ...deletionTasks];
708
734
  Task.allSettled(allWriteTasks).wait(() => {
709
- for (const pageIndex of affectedPages) {
710
- this.dispatch(reindexPageAnnotations(pageIndex));
711
- }
712
735
  this.dispatch(commitPendingChanges());
713
736
  task.resolve(true);
714
737
  }, task.fail);
@@ -906,10 +929,9 @@ const reducer = (state, action) => {
906
929
  for (const uid of oldUidsOnPage) {
907
930
  delete newByUid[uid];
908
931
  }
909
- const newUidsOnPage = list.map((a, index2) => {
910
- const localId = Date.now() + Math.random() + index2;
911
- const uid = makeUid$1(pageIndex, localId);
912
- newByUid[uid] = { localId, pdfId: a.id, commitState: "synced", object: a };
932
+ const newUidsOnPage = list.map((a) => {
933
+ const uid = a.id;
934
+ newByUid[uid] = { commitState: "synced", object: a };
913
935
  return uid;
914
936
  });
915
937
  newPages[pageIndex] = newUidsOnPage;
@@ -922,7 +944,7 @@ const reducer = (state, action) => {
922
944
  case SELECT_ANNOTATION:
923
945
  return {
924
946
  ...state,
925
- selectedUid: makeUid$1(action.payload.pageIndex, action.payload.localId)
947
+ selectedUid: action.payload.id
926
948
  };
927
949
  case DESELECT_ANNOTATION:
928
950
  return { ...state, selectedUid: null };
@@ -942,22 +964,21 @@ const reducer = (state, action) => {
942
964
  }
943
965
  /* ───── create ───── */
944
966
  case CREATE_ANNOTATION: {
945
- const { pageIndex, localId, annotation } = action.payload;
946
- const uid = makeUid$1(pageIndex, localId);
967
+ const { pageIndex, annotation } = action.payload;
968
+ const uid = annotation.id;
947
969
  return {
948
970
  ...state,
949
971
  pages: { ...state.pages, [pageIndex]: [...state.pages[pageIndex] ?? [], uid] },
950
972
  byUid: {
951
973
  ...state.byUid,
952
- [uid]: { localId, pdfId: void 0, commitState: "new", object: annotation }
974
+ [uid]: { commitState: "new", object: annotation }
953
975
  },
954
976
  hasPendingChanges: true
955
977
  };
956
978
  }
957
979
  /* ───── delete ───── */
958
980
  case DELETE_ANNOTATION: {
959
- const { pageIndex, localId } = action.payload;
960
- const uid = makeUid$1(pageIndex, localId);
981
+ const { pageIndex, id: uid } = action.payload;
961
982
  if (!state.byUid[uid]) return state;
962
983
  return {
963
984
  ...state,
@@ -974,7 +995,7 @@ const reducer = (state, action) => {
974
995
  }
975
996
  /* ───── field edits ───── */
976
997
  case PATCH_ANNOTATION: {
977
- const uid = makeUid$1(action.payload.pageIndex, action.payload.localId);
998
+ const uid = action.payload.id;
978
999
  return patchAnno(state, uid, action.payload.patch);
979
1000
  }
980
1001
  /* ───── commit bookkeeping ───── */
@@ -988,30 +1009,6 @@ const reducer = (state, action) => {
988
1009
  }
989
1010
  return { ...state, byUid: cleaned, hasPendingChanges: false };
990
1011
  }
991
- case REINDEX_PAGE_ANNOTATIONS: {
992
- const { pageIndex } = action.payload;
993
- const newByUid = { ...state.byUid };
994
- const uidsOnPage = state.pages[pageIndex] || [];
995
- const annosOnPage = uidsOnPage.map((uid) => state.byUid[uid]).filter((ta) => ta && ta.commitState !== "deleted");
996
- annosOnPage.sort((a, b) => (a.pdfId ?? Infinity) - (b.pdfId ?? Infinity));
997
- annosOnPage.forEach((ta, newPdfId) => {
998
- const uid = makeUid$1(pageIndex, ta.localId);
999
- newByUid[uid] = { ...newByUid[uid], pdfId: newPdfId };
1000
- });
1001
- return { ...state, byUid: newByUid };
1002
- }
1003
- case STORE_PDF_ID: {
1004
- const { uid, pdfId } = action.payload;
1005
- const ta = state.byUid[uid];
1006
- if (!ta) return state;
1007
- return {
1008
- ...state,
1009
- byUid: {
1010
- ...state.byUid,
1011
- [uid]: { ...ta, pdfId, commitState: "synced" }
1012
- }
1013
- };
1014
- }
1015
1012
  case PURGE_ANNOTATION: {
1016
1013
  const { uid } = action.payload;
1017
1014
  const { [uid]: _gone, ...rest } = state.byUid;
@@ -1036,7 +1033,8 @@ export {
1036
1033
  getSelectedAnnotation,
1037
1034
  getSelectedAnnotationByPageIndex,
1038
1035
  getSelectedAnnotationVariant,
1039
- getSelectedAnnotationWithPageIndex,
1036
+ getSidebarAnnotationsWithReplies,
1037
+ getSidebarAnnotationsWithRepliesGroupedByPage,
1040
1038
  getToolDefaultsBySubtypeAndIntent,
1041
1039
  isAnnotationSelected,
1042
1040
  isCircle,
@@ -1048,12 +1046,14 @@ export {
1048
1046
  isLine,
1049
1047
  isPolygon,
1050
1048
  isPolyline,
1049
+ isSidebarAnnotation,
1051
1050
  isSquare,
1052
1051
  isSquiggly,
1053
1052
  isSquigglyDefaults,
1054
1053
  isStamp,
1055
1054
  isStrikeout,
1056
1055
  isStrikeoutDefaults,
1056
+ isText,
1057
1057
  isTextMarkup,
1058
1058
  isTextMarkupDefaults,
1059
1059
  isUnderline,