@embedpdf/plugin-annotation 3.0.0-next.1 → 3.0.0-next.10

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.
@@ -1,7 +1,7 @@
1
- import { PageObjectNumber } from "@embedpdf/core";
1
+ import { DocumentEvent, PageObjectNumber } from "@embedpdf/core";
2
+ import { AnnotationAppearanceImage, AnnotationDTO, AnnotationDraft, AnnotationPatch, AnnotationRef, AttachmentContent, AttachmentFileSource, BinarySource, CommentThread, InkIntent, PdfLinkTarget, PdfRect } from "@embedpdf/engine-core/runtime";
3
+ import { AnnotationFlags, AnnotationProps, AnnotationPropsPatch, ChromeNode, ClickCreate, CreationDraftAnchor, Geom, Id, InkStraightenOptions, Model, PropKey, PropSpec, Rect, RenderItem, SnapSettings, Subtype, TextEndAnchor, TextQuad, Vec, ViewEnv } from "@embedpdf/core-annotation";
2
4
  import { PageRotation } from "@embedpdf/core-geometry";
3
- import { AnnotationAppearanceImage, AnnotationDTO, AnnotationDraft, AnnotationPatch, AnnotationRef, AttachmentContent, AttachmentFileSource, BinarySource, InkIntent, PdfLinkTarget, PdfRect } from "@embedpdf/engine-core/runtime";
4
- import { AnnotationFlags, AnnotationProps, AnnotationPropsPatch, ChromeNode, ClickCreate, CreationDraftAnchor, Geom, Id, InkStraightenOptions, Model, PropKey, PropSpec, Rect, RenderItem, SnapSettings, Subtype, Vec, ViewEnv } from "@embedpdf/core-annotation";
5
5
  //#region src/tools.d.ts
6
6
  /**
7
7
  * How a stamp-family tool resolves the image bytes it places — pure DATA, so a
@@ -315,8 +315,28 @@ interface ChromeSettingsPatch {
315
315
  knob?: Partial<ChromeSettings['knob']>;
316
316
  guides?: Partial<ChromeSettings['guides']>;
317
317
  }
318
+ /**
319
+ * Whole-document annotation hydration. The plugin always hydrates ALL
320
+ * pages through `doc.annotations.listRawAll()` (one bulk request on
321
+ * cloud, one worker job locally) — a comments sidebar needs every page,
322
+ * and per-page lazy loading could never truthfully claim completeness.
323
+ * `loading` covers the initial ingest AND a desync re-ingest; `error`
324
+ * means live events still apply but the whole-document view is
325
+ * incomplete until a rehydrate succeeds.
326
+ */
327
+ type AnnotationHydration = {
328
+ status: 'loading';
329
+ } | {
330
+ status: 'complete';
331
+ } | {
332
+ status: 'error';
333
+ error: unknown;
334
+ } | {
335
+ status: 'forbidden';
336
+ };
318
337
  interface AnnotationState {
319
338
  model: Model;
339
+ hydration: AnnotationHydration;
320
340
  chrome: ChromeSettings;
321
341
  /**
322
342
  * The armed tool's FOOTPRINT ghost: where (and what) the NEXT click would
@@ -377,6 +397,9 @@ interface AnnotationConfig {
377
397
  type AnnotationAction = {
378
398
  type: 'SET_MODEL';
379
399
  model: Model;
400
+ } | {
401
+ type: 'SET_HYDRATION';
402
+ hydration: AnnotationHydration;
380
403
  } | {
381
404
  type: 'SET_CHROME';
382
405
  patch: ChromeSettingsPatch;
@@ -398,6 +421,14 @@ interface LinkNavItem {
398
421
  id: string;
399
422
  rect: Rect;
400
423
  target: PdfLinkTarget;
424
+ /**
425
+ * True for a link CHILD riding an editable annotation (an `/RT /Group`
426
+ * subordinate) — a PROPERTY of its parent while authoring, a nav behavior
427
+ * only while reading. The nav layer stands its anchors down for attached
428
+ * items whenever the active tool enables `annotation-edit`, so the parent
429
+ * stays selectable/movable; standalone document links navigate regardless.
430
+ */
431
+ attached: boolean;
401
432
  }
402
433
  interface Behavior {
403
434
  id: string;
@@ -464,6 +495,85 @@ interface TextItem {
464
495
  * object — two typed lenses on one token — so app code simply can't see the host
465
496
  * methods.
466
497
  */
498
+ /**
499
+ * Per-thread action gates, composed from two axes: authority (the
500
+ * engine's collab-resolver mirrors — `allowsAnnotationCreate` for
501
+ * reply/status, `allowsAnnotationMutation` against each target's
502
+ * stamped owner for edit/delete) and PDF state (the two lock flags
503
+ * gate DIFFERENT aspects, ISO 32000 Table 167: `lockedContents` blocks
504
+ * text edits, `locked` blocks deletion). A courtesy, not the guard — the
505
+ * engine independently enforces every write.
506
+ */
507
+ interface CommentPermissions {
508
+ /** A reply is an annotation CREATE. */
509
+ canReply: boolean;
510
+ /** Editing this comment's text (`contents`) — gated by `lockedContents`. */
511
+ canEditText: boolean;
512
+ /** Deleting this one annotation — gated by `locked`. */
513
+ canDelete: boolean;
514
+ /** A status change is a NEW hidden annotation — create authority only,
515
+ * never edit rights on someone else's comment. */
516
+ canSetStatus: boolean;
517
+ /** `canDelete` over EVERY thread member (root, replies, grouped parts,
518
+ * state annotations) — the whole-thread preflight. */
519
+ canDeleteThread: boolean;
520
+ }
521
+ interface ThreadDeleteResult {
522
+ deleted: AnnotationRef[];
523
+ failed: Array<{
524
+ ref: AnnotationRef;
525
+ error: unknown;
526
+ }>;
527
+ }
528
+ /**
529
+ * The conversation plane's surface: a derived, memoized threads index over
530
+ * the annotation substrate, plus the ISO-native verbs. Every verb compiles
531
+ * down to plain annotation creates/patches/deletes — one optimistic
532
+ * pipeline, no second write path — so remote SSE events, own edits, and
533
+ * hydration all update `threads()` for free.
534
+ *
535
+ * Threads carry `pageObjectNumber` (identity is PON, like everything
536
+ * else); DISPLAY order is a behavior of `threads()` (sorted against the
537
+ * live layout at computation time), and display labels (`pageIndex`) are a
538
+ * framework-hook enrichment — the layer that watches both stores.
539
+ */
540
+ interface CommentsApi {
541
+ /** Every comment thread in the document, display-ordered, memoized. */
542
+ threads(): CommentThread[];
543
+ /** The thread containing ANY member ref (root, reply, grouped part, or
544
+ * state annotation), or null. */
545
+ thread(ref: AnnotationRef): CommentThread | null;
546
+ /** Whole-document hydration status (the sidebar's honest loading state). */
547
+ hydration(): AnnotationHydration;
548
+ /** Re-run whole-document hydration (desync recovery / manual refresh). */
549
+ rehydrate(): Promise<void>;
550
+ /** Reply to a thread. Writes FLAT (`/IRT` → the thread root, ISO reply
551
+ * type), whatever member was passed — presentation stays one level. */
552
+ reply(ref: AnnotationRef, text: string): Promise<AnnotationRef>;
553
+ /** Edit a comment's text. Appearance-inert for every kind except
554
+ * free-text and redaction (whose `/AP` paints `/Contents`). */
555
+ edit(ref: AnnotationRef, text: string): Promise<void>;
556
+ /**
557
+ * Set this session's review status on the thread (ISO 32000 §12.5.6.3):
558
+ * creates a hidden state annotation chained to the caller's previous
559
+ * status when one exists, else to the root. The target annotation is
560
+ * never modified. Known states: accepted / rejected / cancelled /
561
+ * completed / none (custom vocabularies ride the raw create API).
562
+ */
563
+ setStatus(ref: AnnotationRef, state: string): Promise<void>;
564
+ /** Toggle this session's Marked-model checkmark on the thread. */
565
+ setMarked(ref: AnnotationRef, marked: boolean): Promise<void>;
566
+ /** Delete exactly ONE annotation (a reply, a status, or a bare root). */
567
+ remove(ref: AnnotationRef): Promise<void>;
568
+ /**
569
+ * Delete a WHOLE thread, children first. Preflighted: when any member
570
+ * fails the delete gate the call returns every blocked ref as `failed`
571
+ * and deletes nothing; mid-flight races surface the same way.
572
+ */
573
+ removeThread(ref: AnnotationRef): Promise<ThreadDeleteResult>;
574
+ /** Truthful per-thread action gates for the ref's thread. */
575
+ permissionsFor(ref: AnnotationRef): CommentPermissions;
576
+ }
467
577
  interface AnnotationCapability {
468
578
  /**
469
579
  * Create an annotation on a page. `draft` is the engine-core draft for its
@@ -515,9 +625,27 @@ interface AnnotationCapability {
515
625
  * free-text kind). Drives the same sidebar when nothing is selected, paired
516
626
  * with {@link currentDefaults}/{@link setDefaults}. */
517
627
  propsForTool(toolId: string): PropSpec[];
628
+ canRead(): boolean;
518
629
  canCreate(): boolean;
519
630
  canEdit(ref: AnnotationRef): boolean;
520
631
  canDelete(ref: AnnotationRef): boolean;
632
+ /** The conversation plane's read/write surface — see {@link CommentsApi}. */
633
+ comments: CommentsApi;
634
+ /**
635
+ * The attached-link lens: an annotation's link is a `/Link` CHILD grouped
636
+ * under it in the document (ISO-native, Acrobat-interoperable) — a
637
+ * PROPERTY while authoring, a nav BEHAVIOR while reading. `of` derives
638
+ * from the committed children (the one source of truth); `set`/`clear`
639
+ * resolve when the children are committed, after which `of` reflects the
640
+ * change. `updateSelection({ link })` remains the props-pipeline alias.
641
+ * On the link KIND itself, `of` reads the annotation's own `/A` target
642
+ * (retarget standalone links via `updateSelection`).
643
+ */
644
+ links: {
645
+ of(ref: AnnotationRef): PdfLinkTarget | null;
646
+ set(ref: AnnotationRef, target: PdfLinkTarget): Promise<void>;
647
+ clear(ref: AnnotationRef): Promise<void>;
648
+ };
521
649
  /** The annotation for a ref, or null if unknown / not yet committed. */
522
650
  get(ref: AnnotationRef): AnnotationDTO | null;
523
651
  /** Every committed annotation on a page, in z-order. */
@@ -604,6 +732,21 @@ interface AnnotationCapability {
604
732
  * (`extends`, per-tool `defaults`, …). Returns an unregister fn.
605
733
  */
606
734
  registerTool(def: AnnotationToolInput): () => void;
735
+ /**
736
+ * Turn the CURRENT text selection into markup annotations — one per
737
+ * selected page, from the selection's oriented per-line quads — then clear
738
+ * the selection. The one-call form of what the markup tools do on
739
+ * commit, made for selection-menu buttons ("Highlight") and automation.
740
+ * `preset` is a tool id whose defaults style the markup (e.g.
741
+ * `'highlight'`); defaults to the subtype's own. Returns false (and does
742
+ * nothing) when no selection plugin is installed or nothing is selected.
743
+ */
744
+ markupFromSelection(subtype: Subtype, preset?: string): boolean;
745
+ /** Commit the in-progress multi-click creation draft (no-op when there is
746
+ * none, or it can't finish yet — see `creationDraftAnchor().canFinish`). */
747
+ finishCreationDraft(): void;
748
+ /** Discard the in-progress multi-click creation draft. */
749
+ cancelCreationDraft(): void;
607
750
  deleteSelection(): void;
608
751
  deselect(): void;
609
752
  cancel(): void;
@@ -723,6 +866,9 @@ interface AnnotationHostCapability extends AnnotationCapability {
723
866
  * the renderer places the baked bitmap by its OWN `/Rect` without touching the
724
867
  * PDF↔content seam. Null if the page's crop box is unknown. */
725
868
  toContentBox(pon: PageObjectNumber, rect: PdfRect): Rect | null;
869
+ /** No-op since whole-document hydration: the model is seeded by
870
+ * `listRawAll()` at document open. Kept as API for layers that call it
871
+ * on page mount. */
726
872
  ensurePage(pon: PageObjectNumber): void;
727
873
  /**
728
874
  * Drop and RE-READ one page's annotations from the engine — the hook for
@@ -732,6 +878,21 @@ interface AnnotationHostCapability extends AnnotationCapability {
732
878
  * created.
733
879
  */
734
880
  reloadPage(pon: PageObjectNumber): Promise<void>;
881
+ /** Live hydration status — `loading` covers initial ingest AND a desync
882
+ * re-ingest. */
883
+ hydration(): AnnotationHydration;
884
+ /** Kick hydration exactly once per document; the effects layer calls
885
+ * this at registration. Subsequent calls no-op. */
886
+ ensureHydrated(): void;
887
+ /** Re-run whole-document hydration (desync recovery). Safe to call while
888
+ * one is in flight — the fresh run is chained after it. */
889
+ rehydrate(): Promise<void>;
890
+ /**
891
+ * The effects layer hands every REMOTE `annotation.*` event here: during
892
+ * a hydration window it queues (replayed by audit cursor after ingest —
893
+ * the delete-resurrection guard); otherwise it applies immediately.
894
+ */
895
+ deliverRemoteAnnotationEvent(event: DocumentEvent): void;
735
896
  /** The free-text boxes on a page, ready to render as editable elements.
736
897
  * `view` as in {@link pageItems}. */
737
898
  textItems(pon: PageObjectNumber, view?: ViewEnv): TextItem[];
@@ -741,8 +902,11 @@ interface AnnotationHostCapability extends AnnotationCapability {
741
902
  /** Enter text-edit on a free-text annotation (focus its editable element). */
742
903
  beginTextEdit(ref: AnnotationRef): void;
743
904
  /** Enter text-edit on whatever free-text box is under a content point — wired
744
- * to a double-click by the interaction edit handler. */
745
- beginTextEditAt(pon: PageObjectNumber, point: Vec, scale?: number, rotation?: PageRotation, zoom?: number): void;
905
+ * to a double-click / long-press by the interaction edit handler. Returns
906
+ * whether an editable free-text was actually found and opened; false lets
907
+ * the caller fall through to a normal press (so a long-press on a highlight
908
+ * selects it instead of being swallowed by a no-op edit attempt). */
909
+ beginTextEditAt(pon: PageObjectNumber, point: Vec, scale?: number, rotation?: PageRotation, zoom?: number): boolean;
746
910
  /** Apply the editor's plain text — optimistic locally, debounced to the engine. */
747
911
  setContents(ref: AnnotationRef, text: string): void;
748
912
  /** Leave text-edit (flush any pending write). */
@@ -752,7 +916,19 @@ interface AnnotationHostCapability extends AnnotationCapability {
752
916
  * screen-constant; `rotation` + `zoom` (relative, `transform.zoom`)
753
917
  * complete the view env for screen-anchored bodies. Pass all three from
754
918
  * the pointer sample. */
755
- hitKind(pon: PageObjectNumber, point: Vec, scale?: number, rotation?: PageRotation, zoom?: number): 'handle' | 'rotate' | 'group-handle' | 'annot' | 'empty';
919
+ hitKind(pon: PageObjectNumber, point: Vec, scale?: number, rotation?: PageRotation, zoom?: number,
920
+ /** Widen grab zones to finger-sized targets (pass `pointerType === 'touch'`). */
921
+ touch?: boolean): 'handle' | 'rotate' | 'group-handle' | 'annot' | 'empty';
922
+ /**
923
+ * TOUCH CONSENT (the interaction hub's `claimsTouch` predicate): should a
924
+ * finger landing here own a TOOL gesture instead of navigating? True over
925
+ * the selection's chrome (resize handles, rotate knob, group box) and over
926
+ * the body of an already-SELECTED, transformable annotation — never over an
927
+ * unselected one, so annotation-dense pages still scroll; tap-select first
928
+ * is the platform convention (Apple Markup). Uses finger-sized grab zones.
929
+ * Pure read.
930
+ */
931
+ claimsTouchAt(pon: PageObjectNumber, point: Vec, scale?: number, rotation?: PageRotation, zoom?: number): boolean;
756
932
  /** The cursor to show at a content point (resize over a handle, move/pointer over a body, else null). */
757
933
  cursorAt(pon: PageObjectNumber, point: Vec, scale?: number, rotation?: PageRotation, zoom?: number): string | null;
758
934
  /**
@@ -786,27 +962,30 @@ interface AnnotationHostCapability extends AnnotationCapability {
786
962
  * things cannot stay selected. Call after anything that flips engagement
787
963
  * (the plugin wires it to tool changes). */
788
964
  pruneEngagedSelection(): void;
789
- editPointer(phase: 'down' | 'move' | 'up', pon: PageObjectNumber, point: Vec, shift: boolean, scale?: number, rotation?: PageRotation, zoom?: number): void;
965
+ editPointer(phase: 'down' | 'move' | 'up', pon: PageObjectNumber, point: Vec, shift: boolean, scale?: number, rotation?: PageRotation, zoom?: number,
966
+ /** Finger-sized grab zones for the gesture's own hit resolution — pass the
967
+ * sample's `pointerType === 'touch'` so the gesture grabs exactly what
968
+ * {@link claimsTouchAt} claimed. */
969
+ touch?: boolean): void;
790
970
  marqueePointer(phase: 'down' | 'move' | 'up', pon: PageObjectNumber, point: Vec, shift: boolean, scale?: number, rotation?: PageRotation, zoom?: number): void;
791
971
  /** Run the draw gesture for an authoring TOOL (by id). The plugin resolves it
792
972
  * to a routing subtype + defaults preset; a bare subtype also works (headless).
793
973
  * `displayRotation` (the DOWN sample's page rotation: /Rotate + view rotation)
794
974
  * feeds the tool's `upright` policy — omit it and upright is a no-op. */
795
975
  createPointer(tool: string, phase: 'down' | 'move' | 'up', pon: PageObjectNumber, point: Vec, finish?: boolean, displayRotation?: PageRotation): void;
796
- finishCreationDraft(): void;
797
976
  /** Commit the strokes currently buffered by an ink tool's grouping window. */
798
977
  finishInkDraft(): void;
799
- cancelCreationDraft(): void;
800
- /** Create one text-markup annotation on a page from the selected text's per-line
801
- * rects (content space) — the `text-selection` create gesture. */
802
- createMarkup(subtype: Subtype, pon: PageObjectNumber, rects: Rect[], preset?: string): void;
803
- /** Create a caret annotation from the final line rect of a text selection. */
804
- createCaret(pon: PageObjectNumber, textEndRect: Rect): void;
978
+ /** Create one text-markup annotation on a page from the selected text's
979
+ * per-line oriented quads (content space) — the `text-selection` create
980
+ * gesture. Axis-aligned callers build quads with `textQuadFromRect`. */
981
+ createMarkup(subtype: Subtype, pon: PageObjectNumber, quads: TextQuad[], preset?: string): void;
982
+ /** Create a caret annotation at a text-selection end anchor. */
983
+ createCaret(pon: PageObjectNumber, anchor: TextEndAnchor): void;
805
984
  /** Create one Adobe-compatible Caret + StrikeOut replace-text group. */
806
- createReplaceText(pon: PageObjectNumber, rects: Rect[], textEndRect: Rect, preset?: string): void;
807
- /** Set the live markup preview from the selection's per-page rects (renders a
985
+ createReplaceText(pon: PageObjectNumber, quads: TextQuad[], anchor: TextEndAnchor, preset?: string): void;
986
+ /** Set the live markup preview from the selection's per-page quads (renders a
808
987
  * ghost that looks like the markup it will become). */
809
- previewMarkup(subtype: Subtype, rectsByPage: Record<number, Rect[]>, preset?: string): void;
988
+ previewMarkup(subtype: Subtype, quadsByPage: Record<number, TextQuad[]>, preset?: string): void;
810
989
  clearMarkupPreview(): void;
811
990
  /** Place the armed stamp centred on a content point. Returns false (no
812
991
  * capture) when nothing is armed. `displayRotation` (the click sample's page
@@ -875,5 +1054,5 @@ interface AnnotationHostCapability extends AnnotationCapability {
875
1054
  */
876
1055
  declare const AnnotationToken: import("@embedpdf/core").CapabilityToken<AnnotationHostCapability>;
877
1056
  //#endregion
878
- export { PromptSourceSpec as C, ToolAuthoringKind as D, StampSourceSpec as E, ToolDefaultsFor as O, InkAuthoringOptions as S, SelectionAuthoring as T, ToolGhost as _, AnnotationState as a, DEFAULT_TOOLS as b, ChromeSettings as c, FilePromptRequest as d, LinkNavItem as f, TextItem as g, StampToolInput as h, AnnotationHostCapability as i, buildToolRegistry as k, ChromeSettingsPatch as l, SelectionProps as m, AnnotationCapability as n, AnnotationToken as o, SelectionFlags as p, AnnotationConfig as r, Behavior as s, AnnotationAction as t, FilePickerProvider as u, AnnotationToolDef as v, ResolvedTool as w, GhostPolicy as x, AnnotationToolInput as y };
879
- //# sourceMappingURL=types-BhWgqgbX.d.cts.map
1057
+ export { StampSourceSpec as A, AnnotationToolInput as C, PromptSourceSpec as D, InkAuthoringOptions as E, ToolDefaultsFor as M, buildToolRegistry as N, ResolvedTool as O, AnnotationToolDef as S, GhostPolicy as T, SelectionProps as _, AnnotationHydration as a, ThreadDeleteResult as b, Behavior as c, CommentPermissions as d, CommentsApi as f, SelectionFlags as g, LinkNavItem as h, AnnotationHostCapability as i, ToolAuthoringKind as j, SelectionAuthoring as k, ChromeSettings as l, FilePromptRequest as m, AnnotationCapability as n, AnnotationState as o, FilePickerProvider as p, AnnotationConfig as r, AnnotationToken as s, AnnotationAction as t, ChromeSettingsPatch as u, StampToolInput as v, DEFAULT_TOOLS as w, ToolGhost as x, TextItem as y };
1058
+ //# sourceMappingURL=types-DITX_3CG.d.ts.map
@@ -1,7 +1,7 @@
1
- import { PageObjectNumber } from "@embedpdf/core";
2
- import { AnnotationAppearanceImage, AnnotationDTO, AnnotationDraft, AnnotationPatch, AnnotationRef, AttachmentContent, AttachmentFileSource, BinarySource, InkIntent, PdfLinkTarget, PdfRect } from "@embedpdf/engine-core/runtime";
3
- import { AnnotationFlags, AnnotationProps, AnnotationPropsPatch, ChromeNode, ClickCreate, CreationDraftAnchor, Geom, Id, InkStraightenOptions, Model, PropKey, PropSpec, Rect, RenderItem, SnapSettings, Subtype, Vec, ViewEnv } from "@embedpdf/core-annotation";
1
+ import { DocumentEvent, PageObjectNumber } from "@embedpdf/core";
4
2
  import { PageRotation } from "@embedpdf/core-geometry";
3
+ import { AnnotationAppearanceImage, AnnotationDTO, AnnotationDraft, AnnotationPatch, AnnotationRef, AttachmentContent, AttachmentFileSource, BinarySource, CommentThread, InkIntent, PdfLinkTarget, PdfRect } from "@embedpdf/engine-core/runtime";
4
+ import { AnnotationFlags, AnnotationProps, AnnotationPropsPatch, ChromeNode, ClickCreate, CreationDraftAnchor, Geom, Id, InkStraightenOptions, Model, PropKey, PropSpec, Rect, RenderItem, SnapSettings, Subtype, TextEndAnchor, TextQuad, Vec, ViewEnv } from "@embedpdf/core-annotation";
5
5
  //#region src/tools.d.ts
6
6
  /**
7
7
  * How a stamp-family tool resolves the image bytes it places — pure DATA, so a
@@ -315,8 +315,28 @@ interface ChromeSettingsPatch {
315
315
  knob?: Partial<ChromeSettings['knob']>;
316
316
  guides?: Partial<ChromeSettings['guides']>;
317
317
  }
318
+ /**
319
+ * Whole-document annotation hydration. The plugin always hydrates ALL
320
+ * pages through `doc.annotations.listRawAll()` (one bulk request on
321
+ * cloud, one worker job locally) — a comments sidebar needs every page,
322
+ * and per-page lazy loading could never truthfully claim completeness.
323
+ * `loading` covers the initial ingest AND a desync re-ingest; `error`
324
+ * means live events still apply but the whole-document view is
325
+ * incomplete until a rehydrate succeeds.
326
+ */
327
+ type AnnotationHydration = {
328
+ status: 'loading';
329
+ } | {
330
+ status: 'complete';
331
+ } | {
332
+ status: 'error';
333
+ error: unknown;
334
+ } | {
335
+ status: 'forbidden';
336
+ };
318
337
  interface AnnotationState {
319
338
  model: Model;
339
+ hydration: AnnotationHydration;
320
340
  chrome: ChromeSettings;
321
341
  /**
322
342
  * The armed tool's FOOTPRINT ghost: where (and what) the NEXT click would
@@ -377,6 +397,9 @@ interface AnnotationConfig {
377
397
  type AnnotationAction = {
378
398
  type: 'SET_MODEL';
379
399
  model: Model;
400
+ } | {
401
+ type: 'SET_HYDRATION';
402
+ hydration: AnnotationHydration;
380
403
  } | {
381
404
  type: 'SET_CHROME';
382
405
  patch: ChromeSettingsPatch;
@@ -398,6 +421,14 @@ interface LinkNavItem {
398
421
  id: string;
399
422
  rect: Rect;
400
423
  target: PdfLinkTarget;
424
+ /**
425
+ * True for a link CHILD riding an editable annotation (an `/RT /Group`
426
+ * subordinate) — a PROPERTY of its parent while authoring, a nav behavior
427
+ * only while reading. The nav layer stands its anchors down for attached
428
+ * items whenever the active tool enables `annotation-edit`, so the parent
429
+ * stays selectable/movable; standalone document links navigate regardless.
430
+ */
431
+ attached: boolean;
401
432
  }
402
433
  interface Behavior {
403
434
  id: string;
@@ -464,6 +495,85 @@ interface TextItem {
464
495
  * object — two typed lenses on one token — so app code simply can't see the host
465
496
  * methods.
466
497
  */
498
+ /**
499
+ * Per-thread action gates, composed from two axes: authority (the
500
+ * engine's collab-resolver mirrors — `allowsAnnotationCreate` for
501
+ * reply/status, `allowsAnnotationMutation` against each target's
502
+ * stamped owner for edit/delete) and PDF state (the two lock flags
503
+ * gate DIFFERENT aspects, ISO 32000 Table 167: `lockedContents` blocks
504
+ * text edits, `locked` blocks deletion). A courtesy, not the guard — the
505
+ * engine independently enforces every write.
506
+ */
507
+ interface CommentPermissions {
508
+ /** A reply is an annotation CREATE. */
509
+ canReply: boolean;
510
+ /** Editing this comment's text (`contents`) — gated by `lockedContents`. */
511
+ canEditText: boolean;
512
+ /** Deleting this one annotation — gated by `locked`. */
513
+ canDelete: boolean;
514
+ /** A status change is a NEW hidden annotation — create authority only,
515
+ * never edit rights on someone else's comment. */
516
+ canSetStatus: boolean;
517
+ /** `canDelete` over EVERY thread member (root, replies, grouped parts,
518
+ * state annotations) — the whole-thread preflight. */
519
+ canDeleteThread: boolean;
520
+ }
521
+ interface ThreadDeleteResult {
522
+ deleted: AnnotationRef[];
523
+ failed: Array<{
524
+ ref: AnnotationRef;
525
+ error: unknown;
526
+ }>;
527
+ }
528
+ /**
529
+ * The conversation plane's surface: a derived, memoized threads index over
530
+ * the annotation substrate, plus the ISO-native verbs. Every verb compiles
531
+ * down to plain annotation creates/patches/deletes — one optimistic
532
+ * pipeline, no second write path — so remote SSE events, own edits, and
533
+ * hydration all update `threads()` for free.
534
+ *
535
+ * Threads carry `pageObjectNumber` (identity is PON, like everything
536
+ * else); DISPLAY order is a behavior of `threads()` (sorted against the
537
+ * live layout at computation time), and display labels (`pageIndex`) are a
538
+ * framework-hook enrichment — the layer that watches both stores.
539
+ */
540
+ interface CommentsApi {
541
+ /** Every comment thread in the document, display-ordered, memoized. */
542
+ threads(): CommentThread[];
543
+ /** The thread containing ANY member ref (root, reply, grouped part, or
544
+ * state annotation), or null. */
545
+ thread(ref: AnnotationRef): CommentThread | null;
546
+ /** Whole-document hydration status (the sidebar's honest loading state). */
547
+ hydration(): AnnotationHydration;
548
+ /** Re-run whole-document hydration (desync recovery / manual refresh). */
549
+ rehydrate(): Promise<void>;
550
+ /** Reply to a thread. Writes FLAT (`/IRT` → the thread root, ISO reply
551
+ * type), whatever member was passed — presentation stays one level. */
552
+ reply(ref: AnnotationRef, text: string): Promise<AnnotationRef>;
553
+ /** Edit a comment's text. Appearance-inert for every kind except
554
+ * free-text and redaction (whose `/AP` paints `/Contents`). */
555
+ edit(ref: AnnotationRef, text: string): Promise<void>;
556
+ /**
557
+ * Set this session's review status on the thread (ISO 32000 §12.5.6.3):
558
+ * creates a hidden state annotation chained to the caller's previous
559
+ * status when one exists, else to the root. The target annotation is
560
+ * never modified. Known states: accepted / rejected / cancelled /
561
+ * completed / none (custom vocabularies ride the raw create API).
562
+ */
563
+ setStatus(ref: AnnotationRef, state: string): Promise<void>;
564
+ /** Toggle this session's Marked-model checkmark on the thread. */
565
+ setMarked(ref: AnnotationRef, marked: boolean): Promise<void>;
566
+ /** Delete exactly ONE annotation (a reply, a status, or a bare root). */
567
+ remove(ref: AnnotationRef): Promise<void>;
568
+ /**
569
+ * Delete a WHOLE thread, children first. Preflighted: when any member
570
+ * fails the delete gate the call returns every blocked ref as `failed`
571
+ * and deletes nothing; mid-flight races surface the same way.
572
+ */
573
+ removeThread(ref: AnnotationRef): Promise<ThreadDeleteResult>;
574
+ /** Truthful per-thread action gates for the ref's thread. */
575
+ permissionsFor(ref: AnnotationRef): CommentPermissions;
576
+ }
467
577
  interface AnnotationCapability {
468
578
  /**
469
579
  * Create an annotation on a page. `draft` is the engine-core draft for its
@@ -515,9 +625,27 @@ interface AnnotationCapability {
515
625
  * free-text kind). Drives the same sidebar when nothing is selected, paired
516
626
  * with {@link currentDefaults}/{@link setDefaults}. */
517
627
  propsForTool(toolId: string): PropSpec[];
628
+ canRead(): boolean;
518
629
  canCreate(): boolean;
519
630
  canEdit(ref: AnnotationRef): boolean;
520
631
  canDelete(ref: AnnotationRef): boolean;
632
+ /** The conversation plane's read/write surface — see {@link CommentsApi}. */
633
+ comments: CommentsApi;
634
+ /**
635
+ * The attached-link lens: an annotation's link is a `/Link` CHILD grouped
636
+ * under it in the document (ISO-native, Acrobat-interoperable) — a
637
+ * PROPERTY while authoring, a nav BEHAVIOR while reading. `of` derives
638
+ * from the committed children (the one source of truth); `set`/`clear`
639
+ * resolve when the children are committed, after which `of` reflects the
640
+ * change. `updateSelection({ link })` remains the props-pipeline alias.
641
+ * On the link KIND itself, `of` reads the annotation's own `/A` target
642
+ * (retarget standalone links via `updateSelection`).
643
+ */
644
+ links: {
645
+ of(ref: AnnotationRef): PdfLinkTarget | null;
646
+ set(ref: AnnotationRef, target: PdfLinkTarget): Promise<void>;
647
+ clear(ref: AnnotationRef): Promise<void>;
648
+ };
521
649
  /** The annotation for a ref, or null if unknown / not yet committed. */
522
650
  get(ref: AnnotationRef): AnnotationDTO | null;
523
651
  /** Every committed annotation on a page, in z-order. */
@@ -604,6 +732,21 @@ interface AnnotationCapability {
604
732
  * (`extends`, per-tool `defaults`, …). Returns an unregister fn.
605
733
  */
606
734
  registerTool(def: AnnotationToolInput): () => void;
735
+ /**
736
+ * Turn the CURRENT text selection into markup annotations — one per
737
+ * selected page, from the selection's oriented per-line quads — then clear
738
+ * the selection. The one-call form of what the markup tools do on
739
+ * commit, made for selection-menu buttons ("Highlight") and automation.
740
+ * `preset` is a tool id whose defaults style the markup (e.g.
741
+ * `'highlight'`); defaults to the subtype's own. Returns false (and does
742
+ * nothing) when no selection plugin is installed or nothing is selected.
743
+ */
744
+ markupFromSelection(subtype: Subtype, preset?: string): boolean;
745
+ /** Commit the in-progress multi-click creation draft (no-op when there is
746
+ * none, or it can't finish yet — see `creationDraftAnchor().canFinish`). */
747
+ finishCreationDraft(): void;
748
+ /** Discard the in-progress multi-click creation draft. */
749
+ cancelCreationDraft(): void;
607
750
  deleteSelection(): void;
608
751
  deselect(): void;
609
752
  cancel(): void;
@@ -723,6 +866,9 @@ interface AnnotationHostCapability extends AnnotationCapability {
723
866
  * the renderer places the baked bitmap by its OWN `/Rect` without touching the
724
867
  * PDF↔content seam. Null if the page's crop box is unknown. */
725
868
  toContentBox(pon: PageObjectNumber, rect: PdfRect): Rect | null;
869
+ /** No-op since whole-document hydration: the model is seeded by
870
+ * `listRawAll()` at document open. Kept as API for layers that call it
871
+ * on page mount. */
726
872
  ensurePage(pon: PageObjectNumber): void;
727
873
  /**
728
874
  * Drop and RE-READ one page's annotations from the engine — the hook for
@@ -732,6 +878,21 @@ interface AnnotationHostCapability extends AnnotationCapability {
732
878
  * created.
733
879
  */
734
880
  reloadPage(pon: PageObjectNumber): Promise<void>;
881
+ /** Live hydration status — `loading` covers initial ingest AND a desync
882
+ * re-ingest. */
883
+ hydration(): AnnotationHydration;
884
+ /** Kick hydration exactly once per document; the effects layer calls
885
+ * this at registration. Subsequent calls no-op. */
886
+ ensureHydrated(): void;
887
+ /** Re-run whole-document hydration (desync recovery). Safe to call while
888
+ * one is in flight — the fresh run is chained after it. */
889
+ rehydrate(): Promise<void>;
890
+ /**
891
+ * The effects layer hands every REMOTE `annotation.*` event here: during
892
+ * a hydration window it queues (replayed by audit cursor after ingest —
893
+ * the delete-resurrection guard); otherwise it applies immediately.
894
+ */
895
+ deliverRemoteAnnotationEvent(event: DocumentEvent): void;
735
896
  /** The free-text boxes on a page, ready to render as editable elements.
736
897
  * `view` as in {@link pageItems}. */
737
898
  textItems(pon: PageObjectNumber, view?: ViewEnv): TextItem[];
@@ -741,8 +902,11 @@ interface AnnotationHostCapability extends AnnotationCapability {
741
902
  /** Enter text-edit on a free-text annotation (focus its editable element). */
742
903
  beginTextEdit(ref: AnnotationRef): void;
743
904
  /** Enter text-edit on whatever free-text box is under a content point — wired
744
- * to a double-click by the interaction edit handler. */
745
- beginTextEditAt(pon: PageObjectNumber, point: Vec, scale?: number, rotation?: PageRotation, zoom?: number): void;
905
+ * to a double-click / long-press by the interaction edit handler. Returns
906
+ * whether an editable free-text was actually found and opened; false lets
907
+ * the caller fall through to a normal press (so a long-press on a highlight
908
+ * selects it instead of being swallowed by a no-op edit attempt). */
909
+ beginTextEditAt(pon: PageObjectNumber, point: Vec, scale?: number, rotation?: PageRotation, zoom?: number): boolean;
746
910
  /** Apply the editor's plain text — optimistic locally, debounced to the engine. */
747
911
  setContents(ref: AnnotationRef, text: string): void;
748
912
  /** Leave text-edit (flush any pending write). */
@@ -752,7 +916,19 @@ interface AnnotationHostCapability extends AnnotationCapability {
752
916
  * screen-constant; `rotation` + `zoom` (relative, `transform.zoom`)
753
917
  * complete the view env for screen-anchored bodies. Pass all three from
754
918
  * the pointer sample. */
755
- hitKind(pon: PageObjectNumber, point: Vec, scale?: number, rotation?: PageRotation, zoom?: number): 'handle' | 'rotate' | 'group-handle' | 'annot' | 'empty';
919
+ hitKind(pon: PageObjectNumber, point: Vec, scale?: number, rotation?: PageRotation, zoom?: number,
920
+ /** Widen grab zones to finger-sized targets (pass `pointerType === 'touch'`). */
921
+ touch?: boolean): 'handle' | 'rotate' | 'group-handle' | 'annot' | 'empty';
922
+ /**
923
+ * TOUCH CONSENT (the interaction hub's `claimsTouch` predicate): should a
924
+ * finger landing here own a TOOL gesture instead of navigating? True over
925
+ * the selection's chrome (resize handles, rotate knob, group box) and over
926
+ * the body of an already-SELECTED, transformable annotation — never over an
927
+ * unselected one, so annotation-dense pages still scroll; tap-select first
928
+ * is the platform convention (Apple Markup). Uses finger-sized grab zones.
929
+ * Pure read.
930
+ */
931
+ claimsTouchAt(pon: PageObjectNumber, point: Vec, scale?: number, rotation?: PageRotation, zoom?: number): boolean;
756
932
  /** The cursor to show at a content point (resize over a handle, move/pointer over a body, else null). */
757
933
  cursorAt(pon: PageObjectNumber, point: Vec, scale?: number, rotation?: PageRotation, zoom?: number): string | null;
758
934
  /**
@@ -786,27 +962,30 @@ interface AnnotationHostCapability extends AnnotationCapability {
786
962
  * things cannot stay selected. Call after anything that flips engagement
787
963
  * (the plugin wires it to tool changes). */
788
964
  pruneEngagedSelection(): void;
789
- editPointer(phase: 'down' | 'move' | 'up', pon: PageObjectNumber, point: Vec, shift: boolean, scale?: number, rotation?: PageRotation, zoom?: number): void;
965
+ editPointer(phase: 'down' | 'move' | 'up', pon: PageObjectNumber, point: Vec, shift: boolean, scale?: number, rotation?: PageRotation, zoom?: number,
966
+ /** Finger-sized grab zones for the gesture's own hit resolution — pass the
967
+ * sample's `pointerType === 'touch'` so the gesture grabs exactly what
968
+ * {@link claimsTouchAt} claimed. */
969
+ touch?: boolean): void;
790
970
  marqueePointer(phase: 'down' | 'move' | 'up', pon: PageObjectNumber, point: Vec, shift: boolean, scale?: number, rotation?: PageRotation, zoom?: number): void;
791
971
  /** Run the draw gesture for an authoring TOOL (by id). The plugin resolves it
792
972
  * to a routing subtype + defaults preset; a bare subtype also works (headless).
793
973
  * `displayRotation` (the DOWN sample's page rotation: /Rotate + view rotation)
794
974
  * feeds the tool's `upright` policy — omit it and upright is a no-op. */
795
975
  createPointer(tool: string, phase: 'down' | 'move' | 'up', pon: PageObjectNumber, point: Vec, finish?: boolean, displayRotation?: PageRotation): void;
796
- finishCreationDraft(): void;
797
976
  /** Commit the strokes currently buffered by an ink tool's grouping window. */
798
977
  finishInkDraft(): void;
799
- cancelCreationDraft(): void;
800
- /** Create one text-markup annotation on a page from the selected text's per-line
801
- * rects (content space) — the `text-selection` create gesture. */
802
- createMarkup(subtype: Subtype, pon: PageObjectNumber, rects: Rect[], preset?: string): void;
803
- /** Create a caret annotation from the final line rect of a text selection. */
804
- createCaret(pon: PageObjectNumber, textEndRect: Rect): void;
978
+ /** Create one text-markup annotation on a page from the selected text's
979
+ * per-line oriented quads (content space) — the `text-selection` create
980
+ * gesture. Axis-aligned callers build quads with `textQuadFromRect`. */
981
+ createMarkup(subtype: Subtype, pon: PageObjectNumber, quads: TextQuad[], preset?: string): void;
982
+ /** Create a caret annotation at a text-selection end anchor. */
983
+ createCaret(pon: PageObjectNumber, anchor: TextEndAnchor): void;
805
984
  /** Create one Adobe-compatible Caret + StrikeOut replace-text group. */
806
- createReplaceText(pon: PageObjectNumber, rects: Rect[], textEndRect: Rect, preset?: string): void;
807
- /** Set the live markup preview from the selection's per-page rects (renders a
985
+ createReplaceText(pon: PageObjectNumber, quads: TextQuad[], anchor: TextEndAnchor, preset?: string): void;
986
+ /** Set the live markup preview from the selection's per-page quads (renders a
808
987
  * ghost that looks like the markup it will become). */
809
- previewMarkup(subtype: Subtype, rectsByPage: Record<number, Rect[]>, preset?: string): void;
988
+ previewMarkup(subtype: Subtype, quadsByPage: Record<number, TextQuad[]>, preset?: string): void;
810
989
  clearMarkupPreview(): void;
811
990
  /** Place the armed stamp centred on a content point. Returns false (no
812
991
  * capture) when nothing is armed. `displayRotation` (the click sample's page
@@ -875,5 +1054,5 @@ interface AnnotationHostCapability extends AnnotationCapability {
875
1054
  */
876
1055
  declare const AnnotationToken: import("@embedpdf/core").CapabilityToken<AnnotationHostCapability>;
877
1056
  //#endregion
878
- export { PromptSourceSpec as C, ToolAuthoringKind as D, StampSourceSpec as E, ToolDefaultsFor as O, InkAuthoringOptions as S, SelectionAuthoring as T, ToolGhost as _, AnnotationState as a, DEFAULT_TOOLS as b, ChromeSettings as c, FilePromptRequest as d, LinkNavItem as f, TextItem as g, StampToolInput as h, AnnotationHostCapability as i, buildToolRegistry as k, ChromeSettingsPatch as l, SelectionProps as m, AnnotationCapability as n, AnnotationToken as o, SelectionFlags as p, AnnotationConfig as r, Behavior as s, AnnotationAction as t, FilePickerProvider as u, AnnotationToolDef as v, ResolvedTool as w, GhostPolicy as x, AnnotationToolInput as y };
879
- //# sourceMappingURL=types-Da6JRmhw.d.ts.map
1057
+ export { StampSourceSpec as A, AnnotationToolInput as C, PromptSourceSpec as D, InkAuthoringOptions as E, ToolDefaultsFor as M, buildToolRegistry as N, ResolvedTool as O, AnnotationToolDef as S, GhostPolicy as T, SelectionProps as _, AnnotationHydration as a, ThreadDeleteResult as b, Behavior as c, CommentPermissions as d, CommentsApi as f, SelectionFlags as g, LinkNavItem as h, AnnotationHostCapability as i, ToolAuthoringKind as j, SelectionAuthoring as k, ChromeSettings as l, FilePromptRequest as m, AnnotationCapability as n, AnnotationState as o, FilePickerProvider as p, AnnotationConfig as r, AnnotationToken as s, AnnotationAction as t, ChromeSettingsPatch as u, StampToolInput as v, DEFAULT_TOOLS as w, ToolGhost as x, TextItem as y };
1058
+ //# sourceMappingURL=types-Due7UgzE.d.cts.map