@embedpdf/plugin-annotation 3.0.0-next.15 → 3.0.0-next.16

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,3 +1,3 @@
1
1
  import { $ as Color, A as AnnotationResources, At as annotationState, B as AnnotationTool, C as AnnotationPatch, Ct as StampPlacement, D as AnnotationRef, Dt as ThreadDeleteResult, E as AnnotationProperty, Et as TextItem, F as AnnotationSelectionChangedEvent, G as ArmedStampInfo, Gt as Face, H as AnnotationTransfer, I as AnnotationSettings, J as AttachmentFileSource, K as ArmedStampPreview, Kt as TextFormat, L as AnnotationStampsApi, M as AnnotationRotationAnchor, Mt as ARMED_STAMP_TOOL_ID, N as AnnotationSelectionAnchor, O as AnnotationReorderedEvent, Ot as ToolDefaults, P as AnnotationSelectionApi, Q as ClickCreate, R as AnnotationSubtype, S as AnnotationOption, St as StampInput, T as AnnotationProperties, Tt as TextAlign, U as AnnotationUpdatedEvent, V as AnnotationToolsApi, W as AnnotationWriteFailedEvent, X as BlendMode, Y as Behavior, Z as ChromeSettings, _ as AnnotationHoverChangedEvent, _t as MarkupSubtype, a as AnnotationBundle, at as EditableKind, b as AnnotationImportResult, bt as ReviewStatus, c as AnnotationCreatedEvent, ct as FilePickerProvider, d as AnnotationDraftApi, dt as HandleRole, et as CommentThread, f as AnnotationDraftChangedEvent, ft as ImageGhost, g as AnnotationFlags, gt as LinkNavItem, h as AnnotationFilter, ht as LineStyle, i as AnnotationAnchor, it as CreationDraft, j as AnnotationResyncedEvent, k as AnnotationResourceRole, kt as ToolDefaultsChangedEvent, l as AnnotationDeletedEvent, lt as FilePromptRequest, m as AnnotationExportSelection, mt as LineEndings, n as AfterCreateSettings, nt as CommentThreadReview, o as AnnotationCapability, ot as EditableKinds, p as AnnotationEditingChangedEvent, pt as LineEnding, q as AttachmentContent, qt as TextSelection, r as Annotation, rt as CommentsApi, s as AnnotationConfig, st as FieldValues, t as ANNOTATION_DEFAULTS, tt as CommentThreadChangedEvent, u as AnnotationDraft, ut as FlagKey, v as AnnotationImportDrop, vt as MeasurementIntent, w as AnnotationPosition, wt as StampPreviewProvider, x as AnnotationLinksApi, xt as SnapSettings, y as AnnotationImportOptions, yt as PdfLinkTarget, z as AnnotationTextApi } from "../contract-BK4LHe9v.cjs";
2
- import { a as CapturedAnnotationDraft, c as ANNOTATION_DRAW_PRIORITY, d as ANNOTATION_PLACE_PRIORITY, f as AnnotationState, i as AnnotationToken, l as ANNOTATION_EDIT_PRIORITY, n as AnnotationHostCapability, o as RecalibrationReport, r as AnnotationLender, s as previewBucket, t as AnnotationAppearancePicture, u as ANNOTATION_MARQUEE_PRIORITY } from "../host-contract-Nzxwh0XS.cjs";
2
+ import { a as CapturedAnnotationDraft, c as ANNOTATION_DRAW_PRIORITY, d as ANNOTATION_PLACE_PRIORITY, f as AnnotationState, i as AnnotationToken, l as ANNOTATION_EDIT_PRIORITY, n as AnnotationHostCapability, o as RecalibrationReport, r as AnnotationLender, s as previewBucket, t as AnnotationAppearancePicture, u as ANNOTATION_MARQUEE_PRIORITY } from "../host-contract-BU29qDEw.cjs";
3
3
  export { ANNOTATION_DEFAULTS, ANNOTATION_DRAW_PRIORITY, ANNOTATION_EDIT_PRIORITY, ANNOTATION_MARQUEE_PRIORITY, ANNOTATION_PLACE_PRIORITY, ARMED_STAMP_TOOL_ID, AfterCreateSettings, type Annotation, AnnotationAnchor, AnnotationAppearancePicture, type AnnotationBundle, AnnotationCapability, AnnotationConfig, AnnotationCreatedEvent, AnnotationDeletedEvent, type AnnotationDraft, AnnotationDraftApi, AnnotationDraftChangedEvent, AnnotationEditingChangedEvent, AnnotationExportSelection, AnnotationFilter, type AnnotationFlags, AnnotationHostCapability, AnnotationHoverChangedEvent, type AnnotationImportDrop, type AnnotationImportOptions, AnnotationImportResult, AnnotationLender, AnnotationLinksApi, type AnnotationOption, type AnnotationPatch, type AnnotationPosition, AnnotationProperties, type AnnotationProperty, type AnnotationRef, AnnotationReorderedEvent, type AnnotationResourceRole, type AnnotationResources, AnnotationResyncedEvent, AnnotationRotationAnchor, AnnotationSelectionAnchor, AnnotationSelectionApi, AnnotationSelectionChangedEvent, AnnotationSettings, AnnotationStampsApi, type AnnotationState, type AnnotationSubtype, AnnotationTextApi, AnnotationToken, AnnotationTool, AnnotationToolsApi, AnnotationTransfer, AnnotationUpdatedEvent, AnnotationWriteFailedEvent, ArmedStampInfo, ArmedStampPreview, type AttachmentContent, type AttachmentFileSource, Behavior, type BlendMode, CapturedAnnotationDraft, ChromeSettings, type ClickCreate, type Color, type CommentThread, CommentThreadChangedEvent, type CommentThreadReview, CommentsApi, CreationDraft, type EditableKind, type EditableKinds, type Face, type FieldValues, FilePickerProvider, FilePromptRequest, type FlagKey, type HandleRole, ImageGhost, type LineEnding, type LineEndings, LineStyle, LinkNavItem, MarkupSubtype, type MeasurementIntent, type PdfLinkTarget, RecalibrationReport, type ReviewStatus, type SnapSettings, StampInput, StampPlacement, StampPreviewProvider, type TextAlign, type TextFormat, TextItem, type TextSelection, ThreadDeleteResult, ToolDefaults, ToolDefaultsChangedEvent, annotationState, previewBucket };
@@ -1,3 +1,3 @@
1
1
  import { $ as Color, A as AnnotationResources, At as annotationState, B as AnnotationTool, C as AnnotationPatch, Ct as StampPlacement, D as AnnotationRef, Dt as ThreadDeleteResult, E as AnnotationProperty, Et as TextItem, F as AnnotationSelectionChangedEvent, G as ArmedStampInfo, Gt as Face, H as AnnotationTransfer, I as AnnotationSettings, J as AttachmentFileSource, K as ArmedStampPreview, Kt as TextFormat, L as AnnotationStampsApi, M as AnnotationRotationAnchor, Mt as ARMED_STAMP_TOOL_ID, N as AnnotationSelectionAnchor, O as AnnotationReorderedEvent, Ot as ToolDefaults, P as AnnotationSelectionApi, Q as ClickCreate, R as AnnotationSubtype, S as AnnotationOption, St as StampInput, T as AnnotationProperties, Tt as TextAlign, U as AnnotationUpdatedEvent, V as AnnotationToolsApi, W as AnnotationWriteFailedEvent, X as BlendMode, Y as Behavior, Z as ChromeSettings, _ as AnnotationHoverChangedEvent, _t as MarkupSubtype, a as AnnotationBundle, at as EditableKind, b as AnnotationImportResult, bt as ReviewStatus, c as AnnotationCreatedEvent, ct as FilePickerProvider, d as AnnotationDraftApi, dt as HandleRole, et as CommentThread, f as AnnotationDraftChangedEvent, ft as ImageGhost, g as AnnotationFlags, gt as LinkNavItem, h as AnnotationFilter, ht as LineStyle, i as AnnotationAnchor, it as CreationDraft, j as AnnotationResyncedEvent, k as AnnotationResourceRole, kt as ToolDefaultsChangedEvent, l as AnnotationDeletedEvent, lt as FilePromptRequest, m as AnnotationExportSelection, mt as LineEndings, n as AfterCreateSettings, nt as CommentThreadReview, o as AnnotationCapability, ot as EditableKinds, p as AnnotationEditingChangedEvent, pt as LineEnding, q as AttachmentContent, qt as TextSelection, r as Annotation, rt as CommentsApi, s as AnnotationConfig, st as FieldValues, t as ANNOTATION_DEFAULTS, tt as CommentThreadChangedEvent, u as AnnotationDraft, ut as FlagKey, v as AnnotationImportDrop, vt as MeasurementIntent, w as AnnotationPosition, wt as StampPreviewProvider, x as AnnotationLinksApi, xt as SnapSettings, y as AnnotationImportOptions, yt as PdfLinkTarget, z as AnnotationTextApi } from "../contract-BOo9iZKo.js";
2
- import { a as CapturedAnnotationDraft, c as ANNOTATION_DRAW_PRIORITY, d as ANNOTATION_PLACE_PRIORITY, f as AnnotationState, i as AnnotationToken, l as ANNOTATION_EDIT_PRIORITY, n as AnnotationHostCapability, o as RecalibrationReport, r as AnnotationLender, s as previewBucket, t as AnnotationAppearancePicture, u as ANNOTATION_MARQUEE_PRIORITY } from "../host-contract-BbjhS_Fo.js";
2
+ import { a as CapturedAnnotationDraft, c as ANNOTATION_DRAW_PRIORITY, d as ANNOTATION_PLACE_PRIORITY, f as AnnotationState, i as AnnotationToken, l as ANNOTATION_EDIT_PRIORITY, n as AnnotationHostCapability, o as RecalibrationReport, r as AnnotationLender, s as previewBucket, t as AnnotationAppearancePicture, u as ANNOTATION_MARQUEE_PRIORITY } from "../host-contract-DfSvbt8c.js";
3
3
  export { ANNOTATION_DEFAULTS, ANNOTATION_DRAW_PRIORITY, ANNOTATION_EDIT_PRIORITY, ANNOTATION_MARQUEE_PRIORITY, ANNOTATION_PLACE_PRIORITY, ARMED_STAMP_TOOL_ID, AfterCreateSettings, type Annotation, AnnotationAnchor, AnnotationAppearancePicture, type AnnotationBundle, AnnotationCapability, AnnotationConfig, AnnotationCreatedEvent, AnnotationDeletedEvent, type AnnotationDraft, AnnotationDraftApi, AnnotationDraftChangedEvent, AnnotationEditingChangedEvent, AnnotationExportSelection, AnnotationFilter, type AnnotationFlags, AnnotationHostCapability, AnnotationHoverChangedEvent, type AnnotationImportDrop, type AnnotationImportOptions, AnnotationImportResult, AnnotationLender, AnnotationLinksApi, type AnnotationOption, type AnnotationPatch, type AnnotationPosition, AnnotationProperties, type AnnotationProperty, type AnnotationRef, AnnotationReorderedEvent, type AnnotationResourceRole, type AnnotationResources, AnnotationResyncedEvent, AnnotationRotationAnchor, AnnotationSelectionAnchor, AnnotationSelectionApi, AnnotationSelectionChangedEvent, AnnotationSettings, AnnotationStampsApi, type AnnotationState, type AnnotationSubtype, AnnotationTextApi, AnnotationToken, AnnotationTool, AnnotationToolsApi, AnnotationTransfer, AnnotationUpdatedEvent, AnnotationWriteFailedEvent, ArmedStampInfo, ArmedStampPreview, type AttachmentContent, type AttachmentFileSource, Behavior, type BlendMode, CapturedAnnotationDraft, ChromeSettings, type ClickCreate, type Color, type CommentThread, CommentThreadChangedEvent, type CommentThreadReview, CommentsApi, CreationDraft, type EditableKind, type EditableKinds, type Face, type FieldValues, FilePickerProvider, FilePromptRequest, type FlagKey, type HandleRole, ImageGhost, type LineEnding, type LineEndings, LineStyle, LinkNavItem, MarkupSubtype, type MeasurementIntent, type PdfLinkTarget, RecalibrationReport, type ReviewStatus, type SnapSettings, StampInput, StampPlacement, StampPreviewProvider, type TextAlign, type TextFormat, TextItem, type TextSelection, ThreadDeleteResult, ToolDefaults, ToolDefaultsChangedEvent, annotationState, previewBucket };
@@ -199,7 +199,17 @@ interface AnnotationHostCapability extends AnnotationCapability {
199
199
  */
200
200
  getAnnotationAnchor(ref: AnnotationRef, view?: ViewEnv): AnnotationAnchor | null;
201
201
  listPageItems(page: PageRef, view?: ViewEnv): RenderItem[];
202
+ /**
203
+ * The text boxes the layer draws as elements: the ones typed in or redrawn
204
+ * live. A saved, idle one shows its engine picture instead.
205
+ */
202
206
  listTextItems(page: PageRef, view?: ViewEnv): TextItem[];
207
+ /**
208
+ * One free text's text box in every state, saved and idle included: for a
209
+ * renderer that draws the box itself (`useRichTextEditor`), which no
210
+ * engine picture is drawn under. `null` for one that isn't a free text here.
211
+ */
212
+ getTextItem(ref: AnnotationRef, view?: ViewEnv): TextItem | null;
203
213
  listChromeNodes(page: PageRef, scale?: number, rotation?: PageRotation, zoom?: number): ChromeNode[];
204
214
  listLinkItems(page: PageRef): LinkNavItem[];
205
215
  /**
@@ -307,4 +317,4 @@ interface AnnotationHostCapability extends AnnotationCapability {
307
317
  declare const AnnotationToken: import("@embedpdf/core").CapabilityToken<AnnotationHostCapability>;
308
318
  //#endregion
309
319
  export { CapturedAnnotationDraft as a, ANNOTATION_DRAW_PRIORITY as c, ANNOTATION_PLACE_PRIORITY as d, AnnotationState as f, AnnotationToken as i, ANNOTATION_EDIT_PRIORITY as l, AnnotationHostCapability as n, RecalibrationReport as o, AnnotationLender as r, previewBucket as s, AnnotationAppearancePicture as t, ANNOTATION_MARQUEE_PRIORITY as u };
310
- //# sourceMappingURL=host-contract-Nzxwh0XS.d.cts.map
320
+ //# sourceMappingURL=host-contract-BU29qDEw.d.cts.map
@@ -1 +1 @@
1
- {"version":3,"file":"host-contract-CxrQPcPj.js","names":["PublicAnnotationToken"],"sources":["../src/priorities.ts","../src/host-contract.ts"],"sourcesContent":["/**\n * The interaction-hub priorities of the annotation plugin's handlers — the\n * public contract a sibling plugin builds on when it needs to sit above or\n * below one of them for the same gesture. Priority only breaks ties between\n * simultaneously-eligible handlers (the tool's tags decide eligibility).\n *\n * 100 annotation-edit select/move/resize over an existing annotation\n * 95 annotation-place click-to-place an armed payload on empty page space\n * 55 annotation-draw drag-create under a draw tool (below text-select)\n * 50 annotation-marquee empty-space selection, the final fallback\n *\n * Hover runs in the same order, so a handler's hover sees the cursor claims\n * of every handler above it: a create handler shows its tool's ghost only\n * where nothing above it claims the pointer (an annotation, text).\n *\n * A handler that must win a click over an existing annotation while a\n * placing tool is active (a signature mark dropped onto a signature field)\n * registers above {@link ANNOTATION_EDIT_PRIORITY}, not merely above place:\n * the edit handler captures first over any annotation, a widget included.\n */\nexport const ANNOTATION_EDIT_PRIORITY = 100;\nexport const ANNOTATION_PLACE_PRIORITY = 95;\nexport const ANNOTATION_DRAW_PRIORITY = 55;\nexport const ANNOTATION_MARQUEE_PRIORITY = 50;\n","/**\n * @embedpdf/plugin-annotation/contract/host — the host lens: render\n * projections, sync, pointer routing, ghosts, the markup bridge and the\n * extension seams. Same runtime token as the public one, typed wider.\n */\nimport { createHostToken } from '@embedpdf/core';\nimport type { DocumentEvent, EventHook, PredictedOp, Unsubscribe } from '@embedpdf/core';\nimport type {\n ChromeNode,\n Effect,\n Id,\n Model,\n Rect,\n RenderItem,\n SceneNode,\n KindName,\n TextEndAnchor,\n Quad,\n Point,\n ViewEnv,\n} from '@embedpdf/core-annotation';\nimport type { PageRotation } from '@embedpdf/core-geometry';\nimport type {\n AnnotationAppearanceImage,\n AnnotationPosition,\n AnnotationRef,\n ChangeOp,\n ImageSource,\n PageMeasurementViewport,\n PageRef,\n PdfMeasure,\n RichTextParagraph,\n SerializedEngineError,\n} from '@embedpdf/engine-core/runtime';\nimport type { AnnotCommitEntry, AnnotCommitResult } from '@embedpdf/plugin-actions/contract/host';\nimport type { AppearancePicture } from '@embedpdf/plugin-render/contract/host';\n\nimport type {\n Annotation,\n AnnotationAnchor,\n AnnotationCapability,\n AnnotationSelectionAnchor,\n ArmedStampInfo,\n ArmedStampPreview,\n Behavior,\n LinkNavItem,\n TextItem,\n ImageGhost,\n} from './contract';\nimport { AnnotationToken as PublicAnnotationToken } from './token';\nimport type { ResolvedTool } from './tools/definitions';\n\nexport * from './contract';\nexport type { AnnotationState } from './model';\nexport {\n ANNOTATION_DRAW_PRIORITY,\n ANNOTATION_EDIT_PRIORITY,\n ANNOTATION_MARQUEE_PRIORITY,\n ANNOTATION_PLACE_PRIORITY,\n} from './priorities';\n\n/**\n * One annotation's look at rest in one of its states, as the render layer\n * paints it: the engine's picture, or, while the annotation's create is on\n * its way, the one this device made (a placed stamp's preview), which the\n * engine's replaces. `version` is the record's picture version it shows\n * (`RenderItem.pictureVersion`): one drawn at another version shows another look.\n */\nexport interface AnnotationAppearancePicture extends Pick<\n AnnotationAppearanceImage,\n 'ref' | 'mode' | 'state' | 'rect'\n> {\n readonly image: ImageSource;\n readonly version: number;\n}\n\n/**\n * A sibling plugin that lends this plugin records it owns (the form plugin's\n * widgets), so they are selected, moved, resized, restyled and deleted with\n * the annotation tools. This plugin never stores them: it shows them as the\n * lender says, and an edit of one becomes the lender's ops, in the same change\n * as the rest of the edit.\n */\nexport interface AnnotationLender {\n /** Who owns the records, for a refusal that sends you there (`'form'`). */\n readonly owner: string;\n /**\n * Its records as the engine confirmed them and as they show, each list the\n * same object until it changes; `null` while it lends none.\n */\n records(): {\n readonly confirmed: readonly Annotation[];\n readonly shown: readonly Annotation[];\n } | null;\n /**\n * The ops that write a message's effects on its records, all at once:\n * `model` is the model the message left, `before` the one it started from\n * (a record it deleted is there).\n */\n opsOf(effects: readonly Effect[], model: Model, before: Model): readonly ChangeOp[];\n /** What undoing these ops looks like. */\n undoOf(ops: readonly ChangeOp[]): readonly PredictedOp[];\n /** The ops that move these records of one page to `position` in its drawing order. */\n reorderOps(\n page: PageRef,\n refs: readonly AnnotationRef[],\n position: AnnotationPosition,\n ): readonly ChangeOp[];\n /** Whether this session may change and delete the record. */\n authority(record: Annotation): { readonly update: boolean; readonly delete: boolean };\n /** What its records' pictures on a page depend on: a new value means new pictures. */\n pictureEpoch(page: PageRef): string;\n /** A record's confirmed picture version; kept for one that went, so an undo brings it back with it. */\n pictureVersion(record: AnnotationRef): number;\n /**\n * The record's look as it shows isn't its confirmed look yet, whatever changed it (a restyle,\n * a resize, one just placed, a change the lender made itself): it draws live, by its\n * {@link painter}, until the engine's picture of it is there.\n */\n pending(record: AnnotationRef): boolean;\n /**\n * How the lender draws the record live: the record upright in `box` (its box, or where a\n * gesture has it), in page space; `null` for one it doesn't draw. A record with a painter\n * draws live while a gesture reshapes it, as a square does.\n */\n painter(record: Annotation): ((box: Rect) => readonly SceneNode[]) | null;\n /** Its records' pictures on a page, at rest, in every state, each with its record's picture version. */\n renderAppearances(\n page: PageRef,\n scale: number,\n signal?: AbortSignal,\n ): Promise<readonly AppearancePicture[]>;\n}\n\nexport interface RecalibrationReport {\n page: PageRef;\n scale: PdfMeasure;\n /** Page-wide read failure: no complete annotation set was available to recalculate. */\n error?: SerializedEngineError;\n updated: AnnotationRef[];\n skipped: {\n ref: AnnotationRef;\n reason: 'no-authority' | 'locked' | 'foreign-measure' | 'unavailable';\n }[];\n failed: { ref: AnnotationRef; error: SerializedEngineError }[];\n}\n\nexport interface CapturedAnnotationDraft {\n tool: string;\n page: PageRef;\n from: Point;\n to: Point;\n}\n\n/**\n * Ghost render buckets: powers of two from 128 px up to `cap`. The same policy\n * the page renderer uses — one bitmap per size class, never per zoom step.\n */\nexport function previewBucket(devicePixelWidth: number, maxWidth = 4096): number {\n const px = Math.max(128, Math.ceil(devicePixelWidth));\n return Math.min(maxWidth, 2 ** Math.ceil(Math.log2(px)));\n}\n\n/**\n * The host (framework) surface: everything the render layer, the interaction hub,\n * and sibling plugins need, on top of the public {@link AnnotationCapability}.\n * Host-only: sibling plugins and framework adapters import the token from\n * `@embedpdf/plugin-annotation/contract/host`. Never use it from application code.\n */\nexport interface AnnotationHostCapability extends AnnotationCapability {\n // ── measurement seam ──\n setPageViewports(\n page: PageRef,\n viewports: PageMeasurementViewport[] | undefined,\n fallback: PdfMeasure,\n ): void;\n remeasurePage(page: PageRef, scale: PdfMeasure): Promise<RecalibrationReport>;\n /** A distance draft was captured (the measurement plugin turns it into a calibration). */\n readonly onDraftCaptured: EventHook<CapturedAnnotationDraft>;\n distanceCreationPage(): PageRef | null;\n\n // ── render projections (page space; a view env projects for a rotated / zoomed view) ──\n /**\n * The selection's anchor as a page shows it: its rotation handle where the\n * page's view puts it (screen-sized, so it depends on the zoom), for a menu\n * that stays clear of it. `selection.getAnchor()` is the same without a view.\n */\n getSelectionAnchorIn(view: {\n scale?: number;\n rotation?: PageRotation;\n zoom?: number;\n }): AnnotationSelectionAnchor | null;\n /**\n * Where UI attaches to one annotation (its page and the box around what it\n * shows, a drag in progress included), or `null` for one that isn't here.\n * Without a view, an annotation that keeps its size on screen carries\n * `boundsIn` for the view it's shown in.\n */\n getAnnotationAnchor(ref: AnnotationRef, view?: ViewEnv): AnnotationAnchor | null;\n listPageItems(page: PageRef, view?: ViewEnv): RenderItem[];\n listTextItems(page: PageRef, view?: ViewEnv): TextItem[];\n listChromeNodes(\n page: PageRef,\n scale?: number,\n rotation?: PageRotation,\n zoom?: number,\n ): ChromeNode[];\n listLinkItems(page: PageRef): LinkNavItem[];\n /**\n * What a page's pictures depend on: its baked records at their picture\n * versions, the stamps this session placed, the pictures kept for an undone\n * delete and the lender's widgets. Load the pictures again when it changes,\n * or when the appearance scale (`render.getAppearanceScale`) does.\n */\n getAppearanceEpoch(page: PageRef): string;\n /**\n * Every picture a page's annotations show at rest, in every state, each\n * with its record's picture version: the engine's (through the render\n * plugin; none without it), the lender's, and this session's placed stamps.\n */\n renderAppearances(\n page: PageRef,\n scale: number,\n signal?: AbortSignal,\n ): Promise<AnnotationAppearancePicture[]>;\n\n // ── sync ──\n /**\n * Resolves once the annotations mirror has applied every confirmed change\n * it knows of, including page re-reads that events started.\n */\n whenSynced(): Promise<void>;\n\n // ── text editing (the editor's draft path: shown at once, written after a pause) ──\n getEditingId(): Id | null;\n beginTextEditAt(\n page: PageRef,\n point: Point,\n scale?: number,\n rotation?: PageRotation,\n zoom?: number,\n ): boolean;\n draftContents(ref: AnnotationRef, text: string): void;\n draftRichText(ref: AnnotationRef, doc: { paragraphs: RichTextParagraph[] }): void;\n setTextSelection(ref: AnnotationRef, range: { start: number; end: number } | null): void;\n getCssFontFamily(family: string): string;\n\n // ── pointer routing ──\n getHitKind(\n page: PageRef,\n point: Point,\n scale?: number,\n rotation?: PageRotation,\n zoom?: number,\n touch?: boolean,\n ): 'handle' | 'rotate' | 'group-handle' | 'annot' | 'empty';\n claimsTouchAt(\n page: PageRef,\n point: Point,\n scale?: number,\n rotation?: PageRotation,\n zoom?: number,\n ): boolean;\n getCursorAt(\n page: PageRef,\n point: Point,\n scale?: number,\n rotation?: PageRotation,\n zoom?: number,\n ): string | null;\n hoverAt(\n at: {\n page: PageRef;\n point: Point;\n scale?: number;\n rotation?: PageRotation;\n zoom?: number;\n } | null,\n ): void;\n editPointer(\n phase: 'down' | 'move' | 'up',\n page: PageRef,\n point: Point,\n shift: boolean,\n scale?: number,\n rotation?: PageRotation,\n zoom?: number,\n touch?: boolean,\n ): void;\n marqueePointer(\n phase: 'down' | 'move' | 'up',\n page: PageRef,\n point: Point,\n shift: boolean,\n scale?: number,\n rotation?: PageRotation,\n zoom?: number,\n ): void;\n createPointer(\n tool: string,\n phase: 'down' | 'move' | 'up',\n page: PageRef,\n point: Point,\n finish?: boolean,\n displayRotation?: PageRotation,\n ): void;\n finishInkDraft(): void;\n /** Place with the active tool at a click; `displayRotation` and `zoom` are the page's view there. */\n placeAt(page: PageRef, point: Point, displayRotation?: PageRotation, zoom?: number): boolean;\n placeArmedStamp(page: PageRef, point: Point, displayRotation?: PageRotation): boolean;\n requestStampAt(page: PageRef, point: Point, displayRotation?: PageRotation): boolean;\n\n // ── markup bridge (the selection plugin meets the text tools) ──\n /**\n * Turn the text selection into what the tool makes of it (markup, a caret,\n * a replace-text pair) and clear the selection; `false`, and nothing, for a\n * tool that makes nothing of a selection, without create authority, or\n * without a selection.\n */\n applyToolToSelection(toolId: string): boolean;\n createMarkup(subtype: KindName, page: PageRef, quads: Quad[], preset?: string): void;\n createCaret(page: PageRef, anchor: TextEndAnchor): void;\n createReplaceText(page: PageRef, quads: Quad[], anchor: TextEndAnchor, preset?: string): void;\n previewMarkup(subtype: KindName, quadsByPage: Record<number, Quad[]>, preset?: string): void;\n clearMarkupPreview(): void;\n\n // ── ghosts and previews (tools/ghost.ts) ──\n /**\n * Put the tool's ghost at a hover, what a click there would make;\n * `displayRotation` and `zoom` are the page's view there. The handler that\n * would take the click calls it, only where the click would reach it and\n * the user may create; a tool without a ghost clears it.\n */\n hoverGhostAt(\n toolId: string,\n page: PageRef,\n point: Point,\n displayRotation?: PageRotation,\n zoom?: number,\n ): void;\n clearGhost(): void;\n /**\n * A sibling plugin's placement gesture with one of this plugin's tools (the\n * form palette's drag-to-place): its press and the pointer now. Once it is a\n * drag, the page paints what releasing places; under that the tool's ghost\n * still shows the click.\n */\n previewPlacement(toolId: string, page: PageRef, from: Point, to: Point): void;\n clearPlacementPreview(): void;\n /** The armed stamp's ghost on a page, for the render layer's `<img>`. */\n getImageGhost(page: PageRef): ImageGhost | null;\n /** The armed stamp: a new object on every arm, null when nothing is armed. */\n getArmedStamp(): ArmedStampInfo | null;\n /** Render the armed stamp's ghost preview for a device pixel width (cached per size bucket). */\n renderArmedStampPreview(devicePixelWidth?: number): Promise<ArmedStampPreview | null>;\n\n // ── extension ──\n /**\n * Show a sibling's records with the annotations and edit them with the same\n * tools (see {@link AnnotationLender}). One lender at a time; returns the\n * release.\n */\n lend(lender: AnnotationLender): Unsubscribe;\n listResolvedTools(): ResolvedTool[];\n getResolvedTool(id: string): ResolvedTool | null;\n getToolSubtype(id: string): KindName;\n registerBehavior(behavior: Behavior): Unsubscribe;\n /** The engaged behavior that owns this annotation now, or `null`. */\n getBehaviorFor(annotation: Annotation): Behavior | null;\n pruneEngagedSelection(): void;\n commitScriptEffects(entries: AnnotCommitEntry[]): Promise<AnnotCommitResult>;\n}\n\n/**\n * The annotation capability token, typed to the full\n * {@link AnnotationHostCapability} (the package internals and `/contract/host`\n * use this view). The package root exports the same runtime token narrowed to\n * {@link AnnotationCapability}.\n */\nexport const AnnotationToken = createHostToken<AnnotationHostCapability>(PublicAnnotationToken);\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;AAoBA,MAAa,2BAA2B;AACxC,MAAa,4BAA4B;AACzC,MAAa,2BAA2B;AACxC,MAAa,8BAA8B;;;;;;;;;;;;ACuI3C,SAAgB,cAAc,kBAA0B,WAAW,MAAc;CAE/E,OAAO,KAAK,IAAI,UAAU,KAAK,KAAK,KAAK,KAAK,KADnC,KAAK,IAAI,KAAK,KAAK,KAAK,gBAAgB,CACC,CAAC,CAAC,CAAC;AACzD;;;;;;;AA0NA,MAAa,kBAAkB,gBAA0CA,iBAAqB"}
1
+ {"version":3,"file":"host-contract-CxrQPcPj.js","names":["PublicAnnotationToken"],"sources":["../src/priorities.ts","../src/host-contract.ts"],"sourcesContent":["/**\n * The interaction-hub priorities of the annotation plugin's handlers — the\n * public contract a sibling plugin builds on when it needs to sit above or\n * below one of them for the same gesture. Priority only breaks ties between\n * simultaneously-eligible handlers (the tool's tags decide eligibility).\n *\n * 100 annotation-edit select/move/resize over an existing annotation\n * 95 annotation-place click-to-place an armed payload on empty page space\n * 55 annotation-draw drag-create under a draw tool (below text-select)\n * 50 annotation-marquee empty-space selection, the final fallback\n *\n * Hover runs in the same order, so a handler's hover sees the cursor claims\n * of every handler above it: a create handler shows its tool's ghost only\n * where nothing above it claims the pointer (an annotation, text).\n *\n * A handler that must win a click over an existing annotation while a\n * placing tool is active (a signature mark dropped onto a signature field)\n * registers above {@link ANNOTATION_EDIT_PRIORITY}, not merely above place:\n * the edit handler captures first over any annotation, a widget included.\n */\nexport const ANNOTATION_EDIT_PRIORITY = 100;\nexport const ANNOTATION_PLACE_PRIORITY = 95;\nexport const ANNOTATION_DRAW_PRIORITY = 55;\nexport const ANNOTATION_MARQUEE_PRIORITY = 50;\n","/**\n * @embedpdf/plugin-annotation/contract/host — the host lens: render\n * projections, sync, pointer routing, ghosts, the markup bridge and the\n * extension seams. Same runtime token as the public one, typed wider.\n */\nimport { createHostToken } from '@embedpdf/core';\nimport type { DocumentEvent, EventHook, PredictedOp, Unsubscribe } from '@embedpdf/core';\nimport type {\n ChromeNode,\n Effect,\n Id,\n Model,\n Rect,\n RenderItem,\n SceneNode,\n KindName,\n TextEndAnchor,\n Quad,\n Point,\n ViewEnv,\n} from '@embedpdf/core-annotation';\nimport type { PageRotation } from '@embedpdf/core-geometry';\nimport type {\n AnnotationAppearanceImage,\n AnnotationPosition,\n AnnotationRef,\n ChangeOp,\n ImageSource,\n PageMeasurementViewport,\n PageRef,\n PdfMeasure,\n RichTextParagraph,\n SerializedEngineError,\n} from '@embedpdf/engine-core/runtime';\nimport type { AnnotCommitEntry, AnnotCommitResult } from '@embedpdf/plugin-actions/contract/host';\nimport type { AppearancePicture } from '@embedpdf/plugin-render/contract/host';\n\nimport type {\n Annotation,\n AnnotationAnchor,\n AnnotationCapability,\n AnnotationSelectionAnchor,\n ArmedStampInfo,\n ArmedStampPreview,\n Behavior,\n LinkNavItem,\n TextItem,\n ImageGhost,\n} from './contract';\nimport { AnnotationToken as PublicAnnotationToken } from './token';\nimport type { ResolvedTool } from './tools/definitions';\n\nexport * from './contract';\nexport type { AnnotationState } from './model';\nexport {\n ANNOTATION_DRAW_PRIORITY,\n ANNOTATION_EDIT_PRIORITY,\n ANNOTATION_MARQUEE_PRIORITY,\n ANNOTATION_PLACE_PRIORITY,\n} from './priorities';\n\n/**\n * One annotation's look at rest in one of its states, as the render layer\n * paints it: the engine's picture, or, while the annotation's create is on\n * its way, the one this device made (a placed stamp's preview), which the\n * engine's replaces. `version` is the record's picture version it shows\n * (`RenderItem.pictureVersion`): one drawn at another version shows another look.\n */\nexport interface AnnotationAppearancePicture extends Pick<\n AnnotationAppearanceImage,\n 'ref' | 'mode' | 'state' | 'rect'\n> {\n readonly image: ImageSource;\n readonly version: number;\n}\n\n/**\n * A sibling plugin that lends this plugin records it owns (the form plugin's\n * widgets), so they are selected, moved, resized, restyled and deleted with\n * the annotation tools. This plugin never stores them: it shows them as the\n * lender says, and an edit of one becomes the lender's ops, in the same change\n * as the rest of the edit.\n */\nexport interface AnnotationLender {\n /** Who owns the records, for a refusal that sends you there (`'form'`). */\n readonly owner: string;\n /**\n * Its records as the engine confirmed them and as they show, each list the\n * same object until it changes; `null` while it lends none.\n */\n records(): {\n readonly confirmed: readonly Annotation[];\n readonly shown: readonly Annotation[];\n } | null;\n /**\n * The ops that write a message's effects on its records, all at once:\n * `model` is the model the message left, `before` the one it started from\n * (a record it deleted is there).\n */\n opsOf(effects: readonly Effect[], model: Model, before: Model): readonly ChangeOp[];\n /** What undoing these ops looks like. */\n undoOf(ops: readonly ChangeOp[]): readonly PredictedOp[];\n /** The ops that move these records of one page to `position` in its drawing order. */\n reorderOps(\n page: PageRef,\n refs: readonly AnnotationRef[],\n position: AnnotationPosition,\n ): readonly ChangeOp[];\n /** Whether this session may change and delete the record. */\n authority(record: Annotation): { readonly update: boolean; readonly delete: boolean };\n /** What its records' pictures on a page depend on: a new value means new pictures. */\n pictureEpoch(page: PageRef): string;\n /** A record's confirmed picture version; kept for one that went, so an undo brings it back with it. */\n pictureVersion(record: AnnotationRef): number;\n /**\n * The record's look as it shows isn't its confirmed look yet, whatever changed it (a restyle,\n * a resize, one just placed, a change the lender made itself): it draws live, by its\n * {@link painter}, until the engine's picture of it is there.\n */\n pending(record: AnnotationRef): boolean;\n /**\n * How the lender draws the record live: the record upright in `box` (its box, or where a\n * gesture has it), in page space; `null` for one it doesn't draw. A record with a painter\n * draws live while a gesture reshapes it, as a square does.\n */\n painter(record: Annotation): ((box: Rect) => readonly SceneNode[]) | null;\n /** Its records' pictures on a page, at rest, in every state, each with its record's picture version. */\n renderAppearances(\n page: PageRef,\n scale: number,\n signal?: AbortSignal,\n ): Promise<readonly AppearancePicture[]>;\n}\n\nexport interface RecalibrationReport {\n page: PageRef;\n scale: PdfMeasure;\n /** Page-wide read failure: no complete annotation set was available to recalculate. */\n error?: SerializedEngineError;\n updated: AnnotationRef[];\n skipped: {\n ref: AnnotationRef;\n reason: 'no-authority' | 'locked' | 'foreign-measure' | 'unavailable';\n }[];\n failed: { ref: AnnotationRef; error: SerializedEngineError }[];\n}\n\nexport interface CapturedAnnotationDraft {\n tool: string;\n page: PageRef;\n from: Point;\n to: Point;\n}\n\n/**\n * Ghost render buckets: powers of two from 128 px up to `cap`. The same policy\n * the page renderer uses — one bitmap per size class, never per zoom step.\n */\nexport function previewBucket(devicePixelWidth: number, maxWidth = 4096): number {\n const px = Math.max(128, Math.ceil(devicePixelWidth));\n return Math.min(maxWidth, 2 ** Math.ceil(Math.log2(px)));\n}\n\n/**\n * The host (framework) surface: everything the render layer, the interaction hub,\n * and sibling plugins need, on top of the public {@link AnnotationCapability}.\n * Host-only: sibling plugins and framework adapters import the token from\n * `@embedpdf/plugin-annotation/contract/host`. Never use it from application code.\n */\nexport interface AnnotationHostCapability extends AnnotationCapability {\n // ── measurement seam ──\n setPageViewports(\n page: PageRef,\n viewports: PageMeasurementViewport[] | undefined,\n fallback: PdfMeasure,\n ): void;\n remeasurePage(page: PageRef, scale: PdfMeasure): Promise<RecalibrationReport>;\n /** A distance draft was captured (the measurement plugin turns it into a calibration). */\n readonly onDraftCaptured: EventHook<CapturedAnnotationDraft>;\n distanceCreationPage(): PageRef | null;\n\n // ── render projections (page space; a view env projects for a rotated / zoomed view) ──\n /**\n * The selection's anchor as a page shows it: its rotation handle where the\n * page's view puts it (screen-sized, so it depends on the zoom), for a menu\n * that stays clear of it. `selection.getAnchor()` is the same without a view.\n */\n getSelectionAnchorIn(view: {\n scale?: number;\n rotation?: PageRotation;\n zoom?: number;\n }): AnnotationSelectionAnchor | null;\n /**\n * Where UI attaches to one annotation (its page and the box around what it\n * shows, a drag in progress included), or `null` for one that isn't here.\n * Without a view, an annotation that keeps its size on screen carries\n * `boundsIn` for the view it's shown in.\n */\n getAnnotationAnchor(ref: AnnotationRef, view?: ViewEnv): AnnotationAnchor | null;\n listPageItems(page: PageRef, view?: ViewEnv): RenderItem[];\n /**\n * The text boxes the layer draws as elements: the ones typed in or redrawn\n * live. A saved, idle one shows its engine picture instead.\n */\n listTextItems(page: PageRef, view?: ViewEnv): TextItem[];\n /**\n * One free text's text box in every state, saved and idle included: for a\n * renderer that draws the box itself (`useRichTextEditor`), which no\n * engine picture is drawn under. `null` for one that isn't a free text here.\n */\n getTextItem(ref: AnnotationRef, view?: ViewEnv): TextItem | null;\n listChromeNodes(\n page: PageRef,\n scale?: number,\n rotation?: PageRotation,\n zoom?: number,\n ): ChromeNode[];\n listLinkItems(page: PageRef): LinkNavItem[];\n /**\n * What a page's pictures depend on: its baked records at their picture\n * versions, the stamps this session placed, the pictures kept for an undone\n * delete and the lender's widgets. Load the pictures again when it changes,\n * or when the appearance scale (`render.getAppearanceScale`) does.\n */\n getAppearanceEpoch(page: PageRef): string;\n /**\n * Every picture a page's annotations show at rest, in every state, each\n * with its record's picture version: the engine's (through the render\n * plugin; none without it), the lender's, and this session's placed stamps.\n */\n renderAppearances(\n page: PageRef,\n scale: number,\n signal?: AbortSignal,\n ): Promise<AnnotationAppearancePicture[]>;\n\n // ── sync ──\n /**\n * Resolves once the annotations mirror has applied every confirmed change\n * it knows of, including page re-reads that events started.\n */\n whenSynced(): Promise<void>;\n\n // ── text editing (the editor's draft path: shown at once, written after a pause) ──\n getEditingId(): Id | null;\n beginTextEditAt(\n page: PageRef,\n point: Point,\n scale?: number,\n rotation?: PageRotation,\n zoom?: number,\n ): boolean;\n draftContents(ref: AnnotationRef, text: string): void;\n draftRichText(ref: AnnotationRef, doc: { paragraphs: RichTextParagraph[] }): void;\n setTextSelection(ref: AnnotationRef, range: { start: number; end: number } | null): void;\n getCssFontFamily(family: string): string;\n\n // ── pointer routing ──\n getHitKind(\n page: PageRef,\n point: Point,\n scale?: number,\n rotation?: PageRotation,\n zoom?: number,\n touch?: boolean,\n ): 'handle' | 'rotate' | 'group-handle' | 'annot' | 'empty';\n claimsTouchAt(\n page: PageRef,\n point: Point,\n scale?: number,\n rotation?: PageRotation,\n zoom?: number,\n ): boolean;\n getCursorAt(\n page: PageRef,\n point: Point,\n scale?: number,\n rotation?: PageRotation,\n zoom?: number,\n ): string | null;\n hoverAt(\n at: {\n page: PageRef;\n point: Point;\n scale?: number;\n rotation?: PageRotation;\n zoom?: number;\n } | null,\n ): void;\n editPointer(\n phase: 'down' | 'move' | 'up',\n page: PageRef,\n point: Point,\n shift: boolean,\n scale?: number,\n rotation?: PageRotation,\n zoom?: number,\n touch?: boolean,\n ): void;\n marqueePointer(\n phase: 'down' | 'move' | 'up',\n page: PageRef,\n point: Point,\n shift: boolean,\n scale?: number,\n rotation?: PageRotation,\n zoom?: number,\n ): void;\n createPointer(\n tool: string,\n phase: 'down' | 'move' | 'up',\n page: PageRef,\n point: Point,\n finish?: boolean,\n displayRotation?: PageRotation,\n ): void;\n finishInkDraft(): void;\n /** Place with the active tool at a click; `displayRotation` and `zoom` are the page's view there. */\n placeAt(page: PageRef, point: Point, displayRotation?: PageRotation, zoom?: number): boolean;\n placeArmedStamp(page: PageRef, point: Point, displayRotation?: PageRotation): boolean;\n requestStampAt(page: PageRef, point: Point, displayRotation?: PageRotation): boolean;\n\n // ── markup bridge (the selection plugin meets the text tools) ──\n /**\n * Turn the text selection into what the tool makes of it (markup, a caret,\n * a replace-text pair) and clear the selection; `false`, and nothing, for a\n * tool that makes nothing of a selection, without create authority, or\n * without a selection.\n */\n applyToolToSelection(toolId: string): boolean;\n createMarkup(subtype: KindName, page: PageRef, quads: Quad[], preset?: string): void;\n createCaret(page: PageRef, anchor: TextEndAnchor): void;\n createReplaceText(page: PageRef, quads: Quad[], anchor: TextEndAnchor, preset?: string): void;\n previewMarkup(subtype: KindName, quadsByPage: Record<number, Quad[]>, preset?: string): void;\n clearMarkupPreview(): void;\n\n // ── ghosts and previews (tools/ghost.ts) ──\n /**\n * Put the tool's ghost at a hover, what a click there would make;\n * `displayRotation` and `zoom` are the page's view there. The handler that\n * would take the click calls it, only where the click would reach it and\n * the user may create; a tool without a ghost clears it.\n */\n hoverGhostAt(\n toolId: string,\n page: PageRef,\n point: Point,\n displayRotation?: PageRotation,\n zoom?: number,\n ): void;\n clearGhost(): void;\n /**\n * A sibling plugin's placement gesture with one of this plugin's tools (the\n * form palette's drag-to-place): its press and the pointer now. Once it is a\n * drag, the page paints what releasing places; under that the tool's ghost\n * still shows the click.\n */\n previewPlacement(toolId: string, page: PageRef, from: Point, to: Point): void;\n clearPlacementPreview(): void;\n /** The armed stamp's ghost on a page, for the render layer's `<img>`. */\n getImageGhost(page: PageRef): ImageGhost | null;\n /** The armed stamp: a new object on every arm, null when nothing is armed. */\n getArmedStamp(): ArmedStampInfo | null;\n /** Render the armed stamp's ghost preview for a device pixel width (cached per size bucket). */\n renderArmedStampPreview(devicePixelWidth?: number): Promise<ArmedStampPreview | null>;\n\n // ── extension ──\n /**\n * Show a sibling's records with the annotations and edit them with the same\n * tools (see {@link AnnotationLender}). One lender at a time; returns the\n * release.\n */\n lend(lender: AnnotationLender): Unsubscribe;\n listResolvedTools(): ResolvedTool[];\n getResolvedTool(id: string): ResolvedTool | null;\n getToolSubtype(id: string): KindName;\n registerBehavior(behavior: Behavior): Unsubscribe;\n /** The engaged behavior that owns this annotation now, or `null`. */\n getBehaviorFor(annotation: Annotation): Behavior | null;\n pruneEngagedSelection(): void;\n commitScriptEffects(entries: AnnotCommitEntry[]): Promise<AnnotCommitResult>;\n}\n\n/**\n * The annotation capability token, typed to the full\n * {@link AnnotationHostCapability} (the package internals and `/contract/host`\n * use this view). The package root exports the same runtime token narrowed to\n * {@link AnnotationCapability}.\n */\nexport const AnnotationToken = createHostToken<AnnotationHostCapability>(PublicAnnotationToken);\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;AAoBA,MAAa,2BAA2B;AACxC,MAAa,4BAA4B;AACzC,MAAa,2BAA2B;AACxC,MAAa,8BAA8B;;;;;;;;;;;;ACuI3C,SAAgB,cAAc,kBAA0B,WAAW,MAAc;CAE/E,OAAO,KAAK,IAAI,UAAU,KAAK,KAAK,KAAK,KAAK,KADnC,KAAK,IAAI,KAAK,KAAK,KAAK,gBAAgB,CACC,CAAC,CAAC,CAAC;AACzD;;;;;;;AAoOA,MAAa,kBAAkB,gBAA0CA,iBAAqB"}
@@ -1 +1 @@
1
- {"version":3,"file":"host-contract-DY9jFPPF.cjs","names":["PublicAnnotationToken"],"sources":["../src/priorities.ts","../src/host-contract.ts"],"sourcesContent":["/**\n * The interaction-hub priorities of the annotation plugin's handlers — the\n * public contract a sibling plugin builds on when it needs to sit above or\n * below one of them for the same gesture. Priority only breaks ties between\n * simultaneously-eligible handlers (the tool's tags decide eligibility).\n *\n * 100 annotation-edit select/move/resize over an existing annotation\n * 95 annotation-place click-to-place an armed payload on empty page space\n * 55 annotation-draw drag-create under a draw tool (below text-select)\n * 50 annotation-marquee empty-space selection, the final fallback\n *\n * Hover runs in the same order, so a handler's hover sees the cursor claims\n * of every handler above it: a create handler shows its tool's ghost only\n * where nothing above it claims the pointer (an annotation, text).\n *\n * A handler that must win a click over an existing annotation while a\n * placing tool is active (a signature mark dropped onto a signature field)\n * registers above {@link ANNOTATION_EDIT_PRIORITY}, not merely above place:\n * the edit handler captures first over any annotation, a widget included.\n */\nexport const ANNOTATION_EDIT_PRIORITY = 100;\nexport const ANNOTATION_PLACE_PRIORITY = 95;\nexport const ANNOTATION_DRAW_PRIORITY = 55;\nexport const ANNOTATION_MARQUEE_PRIORITY = 50;\n","/**\n * @embedpdf/plugin-annotation/contract/host — the host lens: render\n * projections, sync, pointer routing, ghosts, the markup bridge and the\n * extension seams. Same runtime token as the public one, typed wider.\n */\nimport { createHostToken } from '@embedpdf/core';\nimport type { DocumentEvent, EventHook, PredictedOp, Unsubscribe } from '@embedpdf/core';\nimport type {\n ChromeNode,\n Effect,\n Id,\n Model,\n Rect,\n RenderItem,\n SceneNode,\n KindName,\n TextEndAnchor,\n Quad,\n Point,\n ViewEnv,\n} from '@embedpdf/core-annotation';\nimport type { PageRotation } from '@embedpdf/core-geometry';\nimport type {\n AnnotationAppearanceImage,\n AnnotationPosition,\n AnnotationRef,\n ChangeOp,\n ImageSource,\n PageMeasurementViewport,\n PageRef,\n PdfMeasure,\n RichTextParagraph,\n SerializedEngineError,\n} from '@embedpdf/engine-core/runtime';\nimport type { AnnotCommitEntry, AnnotCommitResult } from '@embedpdf/plugin-actions/contract/host';\nimport type { AppearancePicture } from '@embedpdf/plugin-render/contract/host';\n\nimport type {\n Annotation,\n AnnotationAnchor,\n AnnotationCapability,\n AnnotationSelectionAnchor,\n ArmedStampInfo,\n ArmedStampPreview,\n Behavior,\n LinkNavItem,\n TextItem,\n ImageGhost,\n} from './contract';\nimport { AnnotationToken as PublicAnnotationToken } from './token';\nimport type { ResolvedTool } from './tools/definitions';\n\nexport * from './contract';\nexport type { AnnotationState } from './model';\nexport {\n ANNOTATION_DRAW_PRIORITY,\n ANNOTATION_EDIT_PRIORITY,\n ANNOTATION_MARQUEE_PRIORITY,\n ANNOTATION_PLACE_PRIORITY,\n} from './priorities';\n\n/**\n * One annotation's look at rest in one of its states, as the render layer\n * paints it: the engine's picture, or, while the annotation's create is on\n * its way, the one this device made (a placed stamp's preview), which the\n * engine's replaces. `version` is the record's picture version it shows\n * (`RenderItem.pictureVersion`): one drawn at another version shows another look.\n */\nexport interface AnnotationAppearancePicture extends Pick<\n AnnotationAppearanceImage,\n 'ref' | 'mode' | 'state' | 'rect'\n> {\n readonly image: ImageSource;\n readonly version: number;\n}\n\n/**\n * A sibling plugin that lends this plugin records it owns (the form plugin's\n * widgets), so they are selected, moved, resized, restyled and deleted with\n * the annotation tools. This plugin never stores them: it shows them as the\n * lender says, and an edit of one becomes the lender's ops, in the same change\n * as the rest of the edit.\n */\nexport interface AnnotationLender {\n /** Who owns the records, for a refusal that sends you there (`'form'`). */\n readonly owner: string;\n /**\n * Its records as the engine confirmed them and as they show, each list the\n * same object until it changes; `null` while it lends none.\n */\n records(): {\n readonly confirmed: readonly Annotation[];\n readonly shown: readonly Annotation[];\n } | null;\n /**\n * The ops that write a message's effects on its records, all at once:\n * `model` is the model the message left, `before` the one it started from\n * (a record it deleted is there).\n */\n opsOf(effects: readonly Effect[], model: Model, before: Model): readonly ChangeOp[];\n /** What undoing these ops looks like. */\n undoOf(ops: readonly ChangeOp[]): readonly PredictedOp[];\n /** The ops that move these records of one page to `position` in its drawing order. */\n reorderOps(\n page: PageRef,\n refs: readonly AnnotationRef[],\n position: AnnotationPosition,\n ): readonly ChangeOp[];\n /** Whether this session may change and delete the record. */\n authority(record: Annotation): { readonly update: boolean; readonly delete: boolean };\n /** What its records' pictures on a page depend on: a new value means new pictures. */\n pictureEpoch(page: PageRef): string;\n /** A record's confirmed picture version; kept for one that went, so an undo brings it back with it. */\n pictureVersion(record: AnnotationRef): number;\n /**\n * The record's look as it shows isn't its confirmed look yet, whatever changed it (a restyle,\n * a resize, one just placed, a change the lender made itself): it draws live, by its\n * {@link painter}, until the engine's picture of it is there.\n */\n pending(record: AnnotationRef): boolean;\n /**\n * How the lender draws the record live: the record upright in `box` (its box, or where a\n * gesture has it), in page space; `null` for one it doesn't draw. A record with a painter\n * draws live while a gesture reshapes it, as a square does.\n */\n painter(record: Annotation): ((box: Rect) => readonly SceneNode[]) | null;\n /** Its records' pictures on a page, at rest, in every state, each with its record's picture version. */\n renderAppearances(\n page: PageRef,\n scale: number,\n signal?: AbortSignal,\n ): Promise<readonly AppearancePicture[]>;\n}\n\nexport interface RecalibrationReport {\n page: PageRef;\n scale: PdfMeasure;\n /** Page-wide read failure: no complete annotation set was available to recalculate. */\n error?: SerializedEngineError;\n updated: AnnotationRef[];\n skipped: {\n ref: AnnotationRef;\n reason: 'no-authority' | 'locked' | 'foreign-measure' | 'unavailable';\n }[];\n failed: { ref: AnnotationRef; error: SerializedEngineError }[];\n}\n\nexport interface CapturedAnnotationDraft {\n tool: string;\n page: PageRef;\n from: Point;\n to: Point;\n}\n\n/**\n * Ghost render buckets: powers of two from 128 px up to `cap`. The same policy\n * the page renderer uses — one bitmap per size class, never per zoom step.\n */\nexport function previewBucket(devicePixelWidth: number, maxWidth = 4096): number {\n const px = Math.max(128, Math.ceil(devicePixelWidth));\n return Math.min(maxWidth, 2 ** Math.ceil(Math.log2(px)));\n}\n\n/**\n * The host (framework) surface: everything the render layer, the interaction hub,\n * and sibling plugins need, on top of the public {@link AnnotationCapability}.\n * Host-only: sibling plugins and framework adapters import the token from\n * `@embedpdf/plugin-annotation/contract/host`. Never use it from application code.\n */\nexport interface AnnotationHostCapability extends AnnotationCapability {\n // ── measurement seam ──\n setPageViewports(\n page: PageRef,\n viewports: PageMeasurementViewport[] | undefined,\n fallback: PdfMeasure,\n ): void;\n remeasurePage(page: PageRef, scale: PdfMeasure): Promise<RecalibrationReport>;\n /** A distance draft was captured (the measurement plugin turns it into a calibration). */\n readonly onDraftCaptured: EventHook<CapturedAnnotationDraft>;\n distanceCreationPage(): PageRef | null;\n\n // ── render projections (page space; a view env projects for a rotated / zoomed view) ──\n /**\n * The selection's anchor as a page shows it: its rotation handle where the\n * page's view puts it (screen-sized, so it depends on the zoom), for a menu\n * that stays clear of it. `selection.getAnchor()` is the same without a view.\n */\n getSelectionAnchorIn(view: {\n scale?: number;\n rotation?: PageRotation;\n zoom?: number;\n }): AnnotationSelectionAnchor | null;\n /**\n * Where UI attaches to one annotation (its page and the box around what it\n * shows, a drag in progress included), or `null` for one that isn't here.\n * Without a view, an annotation that keeps its size on screen carries\n * `boundsIn` for the view it's shown in.\n */\n getAnnotationAnchor(ref: AnnotationRef, view?: ViewEnv): AnnotationAnchor | null;\n listPageItems(page: PageRef, view?: ViewEnv): RenderItem[];\n listTextItems(page: PageRef, view?: ViewEnv): TextItem[];\n listChromeNodes(\n page: PageRef,\n scale?: number,\n rotation?: PageRotation,\n zoom?: number,\n ): ChromeNode[];\n listLinkItems(page: PageRef): LinkNavItem[];\n /**\n * What a page's pictures depend on: its baked records at their picture\n * versions, the stamps this session placed, the pictures kept for an undone\n * delete and the lender's widgets. Load the pictures again when it changes,\n * or when the appearance scale (`render.getAppearanceScale`) does.\n */\n getAppearanceEpoch(page: PageRef): string;\n /**\n * Every picture a page's annotations show at rest, in every state, each\n * with its record's picture version: the engine's (through the render\n * plugin; none without it), the lender's, and this session's placed stamps.\n */\n renderAppearances(\n page: PageRef,\n scale: number,\n signal?: AbortSignal,\n ): Promise<AnnotationAppearancePicture[]>;\n\n // ── sync ──\n /**\n * Resolves once the annotations mirror has applied every confirmed change\n * it knows of, including page re-reads that events started.\n */\n whenSynced(): Promise<void>;\n\n // ── text editing (the editor's draft path: shown at once, written after a pause) ──\n getEditingId(): Id | null;\n beginTextEditAt(\n page: PageRef,\n point: Point,\n scale?: number,\n rotation?: PageRotation,\n zoom?: number,\n ): boolean;\n draftContents(ref: AnnotationRef, text: string): void;\n draftRichText(ref: AnnotationRef, doc: { paragraphs: RichTextParagraph[] }): void;\n setTextSelection(ref: AnnotationRef, range: { start: number; end: number } | null): void;\n getCssFontFamily(family: string): string;\n\n // ── pointer routing ──\n getHitKind(\n page: PageRef,\n point: Point,\n scale?: number,\n rotation?: PageRotation,\n zoom?: number,\n touch?: boolean,\n ): 'handle' | 'rotate' | 'group-handle' | 'annot' | 'empty';\n claimsTouchAt(\n page: PageRef,\n point: Point,\n scale?: number,\n rotation?: PageRotation,\n zoom?: number,\n ): boolean;\n getCursorAt(\n page: PageRef,\n point: Point,\n scale?: number,\n rotation?: PageRotation,\n zoom?: number,\n ): string | null;\n hoverAt(\n at: {\n page: PageRef;\n point: Point;\n scale?: number;\n rotation?: PageRotation;\n zoom?: number;\n } | null,\n ): void;\n editPointer(\n phase: 'down' | 'move' | 'up',\n page: PageRef,\n point: Point,\n shift: boolean,\n scale?: number,\n rotation?: PageRotation,\n zoom?: number,\n touch?: boolean,\n ): void;\n marqueePointer(\n phase: 'down' | 'move' | 'up',\n page: PageRef,\n point: Point,\n shift: boolean,\n scale?: number,\n rotation?: PageRotation,\n zoom?: number,\n ): void;\n createPointer(\n tool: string,\n phase: 'down' | 'move' | 'up',\n page: PageRef,\n point: Point,\n finish?: boolean,\n displayRotation?: PageRotation,\n ): void;\n finishInkDraft(): void;\n /** Place with the active tool at a click; `displayRotation` and `zoom` are the page's view there. */\n placeAt(page: PageRef, point: Point, displayRotation?: PageRotation, zoom?: number): boolean;\n placeArmedStamp(page: PageRef, point: Point, displayRotation?: PageRotation): boolean;\n requestStampAt(page: PageRef, point: Point, displayRotation?: PageRotation): boolean;\n\n // ── markup bridge (the selection plugin meets the text tools) ──\n /**\n * Turn the text selection into what the tool makes of it (markup, a caret,\n * a replace-text pair) and clear the selection; `false`, and nothing, for a\n * tool that makes nothing of a selection, without create authority, or\n * without a selection.\n */\n applyToolToSelection(toolId: string): boolean;\n createMarkup(subtype: KindName, page: PageRef, quads: Quad[], preset?: string): void;\n createCaret(page: PageRef, anchor: TextEndAnchor): void;\n createReplaceText(page: PageRef, quads: Quad[], anchor: TextEndAnchor, preset?: string): void;\n previewMarkup(subtype: KindName, quadsByPage: Record<number, Quad[]>, preset?: string): void;\n clearMarkupPreview(): void;\n\n // ── ghosts and previews (tools/ghost.ts) ──\n /**\n * Put the tool's ghost at a hover, what a click there would make;\n * `displayRotation` and `zoom` are the page's view there. The handler that\n * would take the click calls it, only where the click would reach it and\n * the user may create; a tool without a ghost clears it.\n */\n hoverGhostAt(\n toolId: string,\n page: PageRef,\n point: Point,\n displayRotation?: PageRotation,\n zoom?: number,\n ): void;\n clearGhost(): void;\n /**\n * A sibling plugin's placement gesture with one of this plugin's tools (the\n * form palette's drag-to-place): its press and the pointer now. Once it is a\n * drag, the page paints what releasing places; under that the tool's ghost\n * still shows the click.\n */\n previewPlacement(toolId: string, page: PageRef, from: Point, to: Point): void;\n clearPlacementPreview(): void;\n /** The armed stamp's ghost on a page, for the render layer's `<img>`. */\n getImageGhost(page: PageRef): ImageGhost | null;\n /** The armed stamp: a new object on every arm, null when nothing is armed. */\n getArmedStamp(): ArmedStampInfo | null;\n /** Render the armed stamp's ghost preview for a device pixel width (cached per size bucket). */\n renderArmedStampPreview(devicePixelWidth?: number): Promise<ArmedStampPreview | null>;\n\n // ── extension ──\n /**\n * Show a sibling's records with the annotations and edit them with the same\n * tools (see {@link AnnotationLender}). One lender at a time; returns the\n * release.\n */\n lend(lender: AnnotationLender): Unsubscribe;\n listResolvedTools(): ResolvedTool[];\n getResolvedTool(id: string): ResolvedTool | null;\n getToolSubtype(id: string): KindName;\n registerBehavior(behavior: Behavior): Unsubscribe;\n /** The engaged behavior that owns this annotation now, or `null`. */\n getBehaviorFor(annotation: Annotation): Behavior | null;\n pruneEngagedSelection(): void;\n commitScriptEffects(entries: AnnotCommitEntry[]): Promise<AnnotCommitResult>;\n}\n\n/**\n * The annotation capability token, typed to the full\n * {@link AnnotationHostCapability} (the package internals and `/contract/host`\n * use this view). The package root exports the same runtime token narrowed to\n * {@link AnnotationCapability}.\n */\nexport const AnnotationToken = createHostToken<AnnotationHostCapability>(PublicAnnotationToken);\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;AAoBA,MAAa,2BAA2B;AACxC,MAAa,4BAA4B;AACzC,MAAa,2BAA2B;AACxC,MAAa,8BAA8B;;;;;;;;;;;;ACuI3C,SAAgB,cAAc,kBAA0B,WAAW,MAAc;CAE/E,OAAO,KAAK,IAAI,UAAU,KAAK,KAAK,KAAK,KAAK,KADnC,KAAK,IAAI,KAAK,KAAK,KAAK,gBAAgB,CACC,CAAC,CAAC,CAAC;AACzD;;;;;;;AA0NA,MAAa,mBAAA,GAAA,eAAA,gBAAA,CAA4DA,iBAAAA,eAAqB"}
1
+ {"version":3,"file":"host-contract-DY9jFPPF.cjs","names":["PublicAnnotationToken"],"sources":["../src/priorities.ts","../src/host-contract.ts"],"sourcesContent":["/**\n * The interaction-hub priorities of the annotation plugin's handlers — the\n * public contract a sibling plugin builds on when it needs to sit above or\n * below one of them for the same gesture. Priority only breaks ties between\n * simultaneously-eligible handlers (the tool's tags decide eligibility).\n *\n * 100 annotation-edit select/move/resize over an existing annotation\n * 95 annotation-place click-to-place an armed payload on empty page space\n * 55 annotation-draw drag-create under a draw tool (below text-select)\n * 50 annotation-marquee empty-space selection, the final fallback\n *\n * Hover runs in the same order, so a handler's hover sees the cursor claims\n * of every handler above it: a create handler shows its tool's ghost only\n * where nothing above it claims the pointer (an annotation, text).\n *\n * A handler that must win a click over an existing annotation while a\n * placing tool is active (a signature mark dropped onto a signature field)\n * registers above {@link ANNOTATION_EDIT_PRIORITY}, not merely above place:\n * the edit handler captures first over any annotation, a widget included.\n */\nexport const ANNOTATION_EDIT_PRIORITY = 100;\nexport const ANNOTATION_PLACE_PRIORITY = 95;\nexport const ANNOTATION_DRAW_PRIORITY = 55;\nexport const ANNOTATION_MARQUEE_PRIORITY = 50;\n","/**\n * @embedpdf/plugin-annotation/contract/host — the host lens: render\n * projections, sync, pointer routing, ghosts, the markup bridge and the\n * extension seams. Same runtime token as the public one, typed wider.\n */\nimport { createHostToken } from '@embedpdf/core';\nimport type { DocumentEvent, EventHook, PredictedOp, Unsubscribe } from '@embedpdf/core';\nimport type {\n ChromeNode,\n Effect,\n Id,\n Model,\n Rect,\n RenderItem,\n SceneNode,\n KindName,\n TextEndAnchor,\n Quad,\n Point,\n ViewEnv,\n} from '@embedpdf/core-annotation';\nimport type { PageRotation } from '@embedpdf/core-geometry';\nimport type {\n AnnotationAppearanceImage,\n AnnotationPosition,\n AnnotationRef,\n ChangeOp,\n ImageSource,\n PageMeasurementViewport,\n PageRef,\n PdfMeasure,\n RichTextParagraph,\n SerializedEngineError,\n} from '@embedpdf/engine-core/runtime';\nimport type { AnnotCommitEntry, AnnotCommitResult } from '@embedpdf/plugin-actions/contract/host';\nimport type { AppearancePicture } from '@embedpdf/plugin-render/contract/host';\n\nimport type {\n Annotation,\n AnnotationAnchor,\n AnnotationCapability,\n AnnotationSelectionAnchor,\n ArmedStampInfo,\n ArmedStampPreview,\n Behavior,\n LinkNavItem,\n TextItem,\n ImageGhost,\n} from './contract';\nimport { AnnotationToken as PublicAnnotationToken } from './token';\nimport type { ResolvedTool } from './tools/definitions';\n\nexport * from './contract';\nexport type { AnnotationState } from './model';\nexport {\n ANNOTATION_DRAW_PRIORITY,\n ANNOTATION_EDIT_PRIORITY,\n ANNOTATION_MARQUEE_PRIORITY,\n ANNOTATION_PLACE_PRIORITY,\n} from './priorities';\n\n/**\n * One annotation's look at rest in one of its states, as the render layer\n * paints it: the engine's picture, or, while the annotation's create is on\n * its way, the one this device made (a placed stamp's preview), which the\n * engine's replaces. `version` is the record's picture version it shows\n * (`RenderItem.pictureVersion`): one drawn at another version shows another look.\n */\nexport interface AnnotationAppearancePicture extends Pick<\n AnnotationAppearanceImage,\n 'ref' | 'mode' | 'state' | 'rect'\n> {\n readonly image: ImageSource;\n readonly version: number;\n}\n\n/**\n * A sibling plugin that lends this plugin records it owns (the form plugin's\n * widgets), so they are selected, moved, resized, restyled and deleted with\n * the annotation tools. This plugin never stores them: it shows them as the\n * lender says, and an edit of one becomes the lender's ops, in the same change\n * as the rest of the edit.\n */\nexport interface AnnotationLender {\n /** Who owns the records, for a refusal that sends you there (`'form'`). */\n readonly owner: string;\n /**\n * Its records as the engine confirmed them and as they show, each list the\n * same object until it changes; `null` while it lends none.\n */\n records(): {\n readonly confirmed: readonly Annotation[];\n readonly shown: readonly Annotation[];\n } | null;\n /**\n * The ops that write a message's effects on its records, all at once:\n * `model` is the model the message left, `before` the one it started from\n * (a record it deleted is there).\n */\n opsOf(effects: readonly Effect[], model: Model, before: Model): readonly ChangeOp[];\n /** What undoing these ops looks like. */\n undoOf(ops: readonly ChangeOp[]): readonly PredictedOp[];\n /** The ops that move these records of one page to `position` in its drawing order. */\n reorderOps(\n page: PageRef,\n refs: readonly AnnotationRef[],\n position: AnnotationPosition,\n ): readonly ChangeOp[];\n /** Whether this session may change and delete the record. */\n authority(record: Annotation): { readonly update: boolean; readonly delete: boolean };\n /** What its records' pictures on a page depend on: a new value means new pictures. */\n pictureEpoch(page: PageRef): string;\n /** A record's confirmed picture version; kept for one that went, so an undo brings it back with it. */\n pictureVersion(record: AnnotationRef): number;\n /**\n * The record's look as it shows isn't its confirmed look yet, whatever changed it (a restyle,\n * a resize, one just placed, a change the lender made itself): it draws live, by its\n * {@link painter}, until the engine's picture of it is there.\n */\n pending(record: AnnotationRef): boolean;\n /**\n * How the lender draws the record live: the record upright in `box` (its box, or where a\n * gesture has it), in page space; `null` for one it doesn't draw. A record with a painter\n * draws live while a gesture reshapes it, as a square does.\n */\n painter(record: Annotation): ((box: Rect) => readonly SceneNode[]) | null;\n /** Its records' pictures on a page, at rest, in every state, each with its record's picture version. */\n renderAppearances(\n page: PageRef,\n scale: number,\n signal?: AbortSignal,\n ): Promise<readonly AppearancePicture[]>;\n}\n\nexport interface RecalibrationReport {\n page: PageRef;\n scale: PdfMeasure;\n /** Page-wide read failure: no complete annotation set was available to recalculate. */\n error?: SerializedEngineError;\n updated: AnnotationRef[];\n skipped: {\n ref: AnnotationRef;\n reason: 'no-authority' | 'locked' | 'foreign-measure' | 'unavailable';\n }[];\n failed: { ref: AnnotationRef; error: SerializedEngineError }[];\n}\n\nexport interface CapturedAnnotationDraft {\n tool: string;\n page: PageRef;\n from: Point;\n to: Point;\n}\n\n/**\n * Ghost render buckets: powers of two from 128 px up to `cap`. The same policy\n * the page renderer uses — one bitmap per size class, never per zoom step.\n */\nexport function previewBucket(devicePixelWidth: number, maxWidth = 4096): number {\n const px = Math.max(128, Math.ceil(devicePixelWidth));\n return Math.min(maxWidth, 2 ** Math.ceil(Math.log2(px)));\n}\n\n/**\n * The host (framework) surface: everything the render layer, the interaction hub,\n * and sibling plugins need, on top of the public {@link AnnotationCapability}.\n * Host-only: sibling plugins and framework adapters import the token from\n * `@embedpdf/plugin-annotation/contract/host`. Never use it from application code.\n */\nexport interface AnnotationHostCapability extends AnnotationCapability {\n // ── measurement seam ──\n setPageViewports(\n page: PageRef,\n viewports: PageMeasurementViewport[] | undefined,\n fallback: PdfMeasure,\n ): void;\n remeasurePage(page: PageRef, scale: PdfMeasure): Promise<RecalibrationReport>;\n /** A distance draft was captured (the measurement plugin turns it into a calibration). */\n readonly onDraftCaptured: EventHook<CapturedAnnotationDraft>;\n distanceCreationPage(): PageRef | null;\n\n // ── render projections (page space; a view env projects for a rotated / zoomed view) ──\n /**\n * The selection's anchor as a page shows it: its rotation handle where the\n * page's view puts it (screen-sized, so it depends on the zoom), for a menu\n * that stays clear of it. `selection.getAnchor()` is the same without a view.\n */\n getSelectionAnchorIn(view: {\n scale?: number;\n rotation?: PageRotation;\n zoom?: number;\n }): AnnotationSelectionAnchor | null;\n /**\n * Where UI attaches to one annotation (its page and the box around what it\n * shows, a drag in progress included), or `null` for one that isn't here.\n * Without a view, an annotation that keeps its size on screen carries\n * `boundsIn` for the view it's shown in.\n */\n getAnnotationAnchor(ref: AnnotationRef, view?: ViewEnv): AnnotationAnchor | null;\n listPageItems(page: PageRef, view?: ViewEnv): RenderItem[];\n /**\n * The text boxes the layer draws as elements: the ones typed in or redrawn\n * live. A saved, idle one shows its engine picture instead.\n */\n listTextItems(page: PageRef, view?: ViewEnv): TextItem[];\n /**\n * One free text's text box in every state, saved and idle included: for a\n * renderer that draws the box itself (`useRichTextEditor`), which no\n * engine picture is drawn under. `null` for one that isn't a free text here.\n */\n getTextItem(ref: AnnotationRef, view?: ViewEnv): TextItem | null;\n listChromeNodes(\n page: PageRef,\n scale?: number,\n rotation?: PageRotation,\n zoom?: number,\n ): ChromeNode[];\n listLinkItems(page: PageRef): LinkNavItem[];\n /**\n * What a page's pictures depend on: its baked records at their picture\n * versions, the stamps this session placed, the pictures kept for an undone\n * delete and the lender's widgets. Load the pictures again when it changes,\n * or when the appearance scale (`render.getAppearanceScale`) does.\n */\n getAppearanceEpoch(page: PageRef): string;\n /**\n * Every picture a page's annotations show at rest, in every state, each\n * with its record's picture version: the engine's (through the render\n * plugin; none without it), the lender's, and this session's placed stamps.\n */\n renderAppearances(\n page: PageRef,\n scale: number,\n signal?: AbortSignal,\n ): Promise<AnnotationAppearancePicture[]>;\n\n // ── sync ──\n /**\n * Resolves once the annotations mirror has applied every confirmed change\n * it knows of, including page re-reads that events started.\n */\n whenSynced(): Promise<void>;\n\n // ── text editing (the editor's draft path: shown at once, written after a pause) ──\n getEditingId(): Id | null;\n beginTextEditAt(\n page: PageRef,\n point: Point,\n scale?: number,\n rotation?: PageRotation,\n zoom?: number,\n ): boolean;\n draftContents(ref: AnnotationRef, text: string): void;\n draftRichText(ref: AnnotationRef, doc: { paragraphs: RichTextParagraph[] }): void;\n setTextSelection(ref: AnnotationRef, range: { start: number; end: number } | null): void;\n getCssFontFamily(family: string): string;\n\n // ── pointer routing ──\n getHitKind(\n page: PageRef,\n point: Point,\n scale?: number,\n rotation?: PageRotation,\n zoom?: number,\n touch?: boolean,\n ): 'handle' | 'rotate' | 'group-handle' | 'annot' | 'empty';\n claimsTouchAt(\n page: PageRef,\n point: Point,\n scale?: number,\n rotation?: PageRotation,\n zoom?: number,\n ): boolean;\n getCursorAt(\n page: PageRef,\n point: Point,\n scale?: number,\n rotation?: PageRotation,\n zoom?: number,\n ): string | null;\n hoverAt(\n at: {\n page: PageRef;\n point: Point;\n scale?: number;\n rotation?: PageRotation;\n zoom?: number;\n } | null,\n ): void;\n editPointer(\n phase: 'down' | 'move' | 'up',\n page: PageRef,\n point: Point,\n shift: boolean,\n scale?: number,\n rotation?: PageRotation,\n zoom?: number,\n touch?: boolean,\n ): void;\n marqueePointer(\n phase: 'down' | 'move' | 'up',\n page: PageRef,\n point: Point,\n shift: boolean,\n scale?: number,\n rotation?: PageRotation,\n zoom?: number,\n ): void;\n createPointer(\n tool: string,\n phase: 'down' | 'move' | 'up',\n page: PageRef,\n point: Point,\n finish?: boolean,\n displayRotation?: PageRotation,\n ): void;\n finishInkDraft(): void;\n /** Place with the active tool at a click; `displayRotation` and `zoom` are the page's view there. */\n placeAt(page: PageRef, point: Point, displayRotation?: PageRotation, zoom?: number): boolean;\n placeArmedStamp(page: PageRef, point: Point, displayRotation?: PageRotation): boolean;\n requestStampAt(page: PageRef, point: Point, displayRotation?: PageRotation): boolean;\n\n // ── markup bridge (the selection plugin meets the text tools) ──\n /**\n * Turn the text selection into what the tool makes of it (markup, a caret,\n * a replace-text pair) and clear the selection; `false`, and nothing, for a\n * tool that makes nothing of a selection, without create authority, or\n * without a selection.\n */\n applyToolToSelection(toolId: string): boolean;\n createMarkup(subtype: KindName, page: PageRef, quads: Quad[], preset?: string): void;\n createCaret(page: PageRef, anchor: TextEndAnchor): void;\n createReplaceText(page: PageRef, quads: Quad[], anchor: TextEndAnchor, preset?: string): void;\n previewMarkup(subtype: KindName, quadsByPage: Record<number, Quad[]>, preset?: string): void;\n clearMarkupPreview(): void;\n\n // ── ghosts and previews (tools/ghost.ts) ──\n /**\n * Put the tool's ghost at a hover, what a click there would make;\n * `displayRotation` and `zoom` are the page's view there. The handler that\n * would take the click calls it, only where the click would reach it and\n * the user may create; a tool without a ghost clears it.\n */\n hoverGhostAt(\n toolId: string,\n page: PageRef,\n point: Point,\n displayRotation?: PageRotation,\n zoom?: number,\n ): void;\n clearGhost(): void;\n /**\n * A sibling plugin's placement gesture with one of this plugin's tools (the\n * form palette's drag-to-place): its press and the pointer now. Once it is a\n * drag, the page paints what releasing places; under that the tool's ghost\n * still shows the click.\n */\n previewPlacement(toolId: string, page: PageRef, from: Point, to: Point): void;\n clearPlacementPreview(): void;\n /** The armed stamp's ghost on a page, for the render layer's `<img>`. */\n getImageGhost(page: PageRef): ImageGhost | null;\n /** The armed stamp: a new object on every arm, null when nothing is armed. */\n getArmedStamp(): ArmedStampInfo | null;\n /** Render the armed stamp's ghost preview for a device pixel width (cached per size bucket). */\n renderArmedStampPreview(devicePixelWidth?: number): Promise<ArmedStampPreview | null>;\n\n // ── extension ──\n /**\n * Show a sibling's records with the annotations and edit them with the same\n * tools (see {@link AnnotationLender}). One lender at a time; returns the\n * release.\n */\n lend(lender: AnnotationLender): Unsubscribe;\n listResolvedTools(): ResolvedTool[];\n getResolvedTool(id: string): ResolvedTool | null;\n getToolSubtype(id: string): KindName;\n registerBehavior(behavior: Behavior): Unsubscribe;\n /** The engaged behavior that owns this annotation now, or `null`. */\n getBehaviorFor(annotation: Annotation): Behavior | null;\n pruneEngagedSelection(): void;\n commitScriptEffects(entries: AnnotCommitEntry[]): Promise<AnnotCommitResult>;\n}\n\n/**\n * The annotation capability token, typed to the full\n * {@link AnnotationHostCapability} (the package internals and `/contract/host`\n * use this view). The package root exports the same runtime token narrowed to\n * {@link AnnotationCapability}.\n */\nexport const AnnotationToken = createHostToken<AnnotationHostCapability>(PublicAnnotationToken);\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;AAoBA,MAAa,2BAA2B;AACxC,MAAa,4BAA4B;AACzC,MAAa,2BAA2B;AACxC,MAAa,8BAA8B;;;;;;;;;;;;ACuI3C,SAAgB,cAAc,kBAA0B,WAAW,MAAc;CAE/E,OAAO,KAAK,IAAI,UAAU,KAAK,KAAK,KAAK,KAAK,KADnC,KAAK,IAAI,KAAK,KAAK,KAAK,gBAAgB,CACC,CAAC,CAAC,CAAC;AACzD;;;;;;;AAoOA,MAAa,mBAAA,GAAA,eAAA,gBAAA,CAA4DA,iBAAAA,eAAqB"}
@@ -199,7 +199,17 @@ interface AnnotationHostCapability extends AnnotationCapability {
199
199
  */
200
200
  getAnnotationAnchor(ref: AnnotationRef, view?: ViewEnv): AnnotationAnchor | null;
201
201
  listPageItems(page: PageRef, view?: ViewEnv): RenderItem[];
202
+ /**
203
+ * The text boxes the layer draws as elements: the ones typed in or redrawn
204
+ * live. A saved, idle one shows its engine picture instead.
205
+ */
202
206
  listTextItems(page: PageRef, view?: ViewEnv): TextItem[];
207
+ /**
208
+ * One free text's text box in every state, saved and idle included: for a
209
+ * renderer that draws the box itself (`useRichTextEditor`), which no
210
+ * engine picture is drawn under. `null` for one that isn't a free text here.
211
+ */
212
+ getTextItem(ref: AnnotationRef, view?: ViewEnv): TextItem | null;
203
213
  listChromeNodes(page: PageRef, scale?: number, rotation?: PageRotation, zoom?: number): ChromeNode[];
204
214
  listLinkItems(page: PageRef): LinkNavItem[];
205
215
  /**
@@ -307,4 +317,4 @@ interface AnnotationHostCapability extends AnnotationCapability {
307
317
  declare const AnnotationToken: import("@embedpdf/core").CapabilityToken<AnnotationHostCapability>;
308
318
  //#endregion
309
319
  export { CapturedAnnotationDraft as a, ANNOTATION_DRAW_PRIORITY as c, ANNOTATION_PLACE_PRIORITY as d, AnnotationState as f, AnnotationToken as i, ANNOTATION_EDIT_PRIORITY as l, AnnotationHostCapability as n, RecalibrationReport as o, AnnotationLender as r, previewBucket as s, AnnotationAppearancePicture as t, ANNOTATION_MARQUEE_PRIORITY as u };
310
- //# sourceMappingURL=host-contract-BbjhS_Fo.d.ts.map
320
+ //# sourceMappingURL=host-contract-DfSvbt8c.d.ts.map
package/dist/index.cjs CHANGED
@@ -1453,31 +1453,39 @@ function createPropertyReads(ctx, { store, fonts }) {
1453
1453
  * core geometry (`textBoxes`) joined with the DTO-derived CSS. Pure; memoized by
1454
1454
  * model identity at the call site so selectors get a stable reference. */
1455
1455
  function buildTextItems(model, page, view) {
1456
- return (0, _embedpdf_core_annotation.textBoxes)(model, page, view).map((tb) => {
1457
- const record = model.byId[tb.id];
1458
- const style = (record && (0, _embedpdf_core_annotation.textOf)(record.annotation)) ?? _embedpdf_core_annotation.initialTextStyle;
1459
- const sw = record ? (0, _embedpdf_core_annotation.styleOf)(record.annotation).strokeWidth : 0;
1460
- const doc = record ? (0, _embedpdf_core_annotation.richDocOf)(record.annotation) : null;
1461
- return {
1462
- id: tb.id,
1463
- ref: (0, _embedpdf_core_annotation.refOf)(record),
1464
- box: tb.box,
1465
- contents: record?.annotation.contents ?? "",
1466
- richText: { paragraphs: doc ? stripBodyDefaults(doc.paragraphs, doc.body) : [{ runs: [{ text: "" }] }] },
1467
- editing: tb.editing,
1468
- ...tb.rot ? { rot: tb.rot } : {},
1469
- css: {
1470
- fontFamily: (0, _embedpdf_core_annotation.cssFontFamilyForFont)(style.fontFamily),
1471
- fontSize: style.fontSize,
1472
- color: style.fontColor,
1473
- fontWeight: style.bold ? 700 : 400,
1474
- fontStyle: style.italic ? "italic" : "normal",
1475
- textDecoration: style.underline ? "underline" : "none",
1476
- align: style.textAlign,
1477
- padding: (0, _embedpdf_core_annotation.textPlateInset)(sw)
1478
- }
1479
- };
1480
- });
1456
+ return (0, _embedpdf_core_annotation.textBoxes)(model, page, view).map((tb) => textItemOf(model, tb));
1457
+ }
1458
+ /** One free text's {@link TextItem}, live or baked (`textBoxOf`): what a renderer
1459
+ * that draws the text box itself edits. `null` for a record that isn't one. */
1460
+ function buildTextItem(model, id, view) {
1461
+ const tb = (0, _embedpdf_core_annotation.textBoxOf)(model, id, view);
1462
+ return tb && textItemOf(model, tb);
1463
+ }
1464
+ /** A text box joined with its record's text, style and plate inset. */
1465
+ function textItemOf(model, tb) {
1466
+ const record = model.byId[tb.id];
1467
+ const style = (record && (0, _embedpdf_core_annotation.textOf)(record.annotation)) ?? _embedpdf_core_annotation.initialTextStyle;
1468
+ const sw = record ? (0, _embedpdf_core_annotation.styleOf)(record.annotation).strokeWidth : 0;
1469
+ const doc = record ? (0, _embedpdf_core_annotation.richDocOf)(record.annotation) : null;
1470
+ return {
1471
+ id: tb.id,
1472
+ ref: (0, _embedpdf_core_annotation.refOf)(record),
1473
+ box: tb.box,
1474
+ contents: record?.annotation.contents ?? "",
1475
+ richText: { paragraphs: doc ? stripBodyDefaults(doc.paragraphs, doc.body) : [{ runs: [{ text: "" }] }] },
1476
+ editing: tb.editing,
1477
+ ...tb.rot ? { rot: tb.rot } : {},
1478
+ css: {
1479
+ fontFamily: (0, _embedpdf_core_annotation.cssFontFamilyForFont)(style.fontFamily),
1480
+ fontSize: style.fontSize,
1481
+ color: style.fontColor,
1482
+ fontWeight: style.bold ? 700 : 400,
1483
+ fontStyle: style.italic ? "italic" : "normal",
1484
+ textDecoration: style.underline ? "underline" : "none",
1485
+ align: style.textAlign,
1486
+ padding: (0, _embedpdf_core_annotation.textPlateInset)(sw)
1487
+ }
1488
+ };
1481
1489
  }
1482
1490
  //#endregion
1483
1491
  //#region src/read/render.ts
@@ -1526,6 +1534,21 @@ function createRenderReads(ctx, { view: { pageModel }, lending }, ghost, stamps)
1526
1534
  });
1527
1535
  return items;
1528
1536
  };
1537
+ const textCache = /* @__PURE__ */ new Map();
1538
+ const textItemOf = (ref, view) => {
1539
+ const key = (0, _embedpdf_engine_core_runtime.annotationKey)(ref);
1540
+ const model = pageModel(ref.page.objectNumber);
1541
+ const cached = textCache.get(key);
1542
+ if (cached && cached.model === model && cached.zoom === view?.zoom && cached.rotation === view?.rotation) return cached.v;
1543
+ const item = buildTextItem(model, key, view);
1544
+ textCache.set(key, {
1545
+ model,
1546
+ zoom: view?.zoom,
1547
+ rotation: view?.rotation,
1548
+ v: item
1549
+ });
1550
+ return item;
1551
+ };
1529
1552
  const linkItemsCache = /* @__PURE__ */ new Map();
1530
1553
  const linkItemsOf = (pageObjectNumber) => {
1531
1554
  const model = pageModel(pageObjectNumber);
@@ -1566,6 +1589,7 @@ function createRenderReads(ctx, { view: { pageModel }, lending }, ghost, stamps)
1566
1589
  const api = {
1567
1590
  listPageItems: (page, view) => pageItemsOf(page, view),
1568
1591
  listTextItems: (page, view) => textItemsOf(page, view),
1592
+ getTextItem: (ref, view) => textItemOf(ref, view),
1569
1593
  listLinkItems: (page) => linkItemsOf(page.objectNumber),
1570
1594
  getAppearanceEpoch: (page) => {
1571
1595
  const { engine, placed, lent } = epochOf(page);
@@ -2267,6 +2291,33 @@ const keysOnPages = (records, pages) => {
2267
2291
  return records.order.filter((key) => wanted.has(records.byKey[key].dto.page.objectNumber));
2268
2292
  };
2269
2293
  /**
2294
+ * The other pages whose annotations go to `pages`: a target or an action
2295
+ * that names one, or one that couldn't be read (the page it goes to wasn't
2296
+ * there). A link is read against the pages there are, so when pages go, come
2297
+ * or come back, these read differently.
2298
+ */
2299
+ function pagesGoingTo(records, pages) {
2300
+ const named = new Set(pages.map((page) => page.objectNumber));
2301
+ const found = /* @__PURE__ */ new Map();
2302
+ for (const key of records.order) {
2303
+ const { dto } = records.byKey[key];
2304
+ const { target, actions } = dto;
2305
+ if (named.has(dto.page.objectNumber) || found.has(dto.page.objectNumber)) continue;
2306
+ if (goesTo(target, named) || goesTo(actions, named)) found.set(dto.page.objectNumber, dto.page);
2307
+ }
2308
+ return [...found.values()];
2309
+ }
2310
+ /** Whether a target or an action tree names one of `pages`, or holds what couldn't be read. */
2311
+ function goesTo(value, pages) {
2312
+ if (!value || typeof value !== "object") return false;
2313
+ if (Array.isArray(value)) return value.some((entry) => goesTo(entry, pages));
2314
+ const node = value;
2315
+ if (node["kind"] === "unsupported") return true;
2316
+ const page = node["page"]?.objectNumber;
2317
+ if (typeof page === "number" && pages.has(page)) return true;
2318
+ return Object.values(node).some((entry) => goesTo(entry, pages));
2319
+ }
2320
+ /**
2270
2321
  * A fresh read of the whole document. Every record's appearance version moves
2271
2322
  * past the one it had, so a reload after a desync re-fetches every raster
2272
2323
  * (the appearances may have changed while the event stream was not trusted).
@@ -2307,8 +2358,12 @@ function foldRecords(records, event) {
2307
2358
  }
2308
2359
  case "annotations.deleted": return drop(records, event.deleted.map(_embedpdf_engine_core_runtime.annotationKey));
2309
2360
  case "annotations.restored": return (0, _embedpdf_core.reload)({ pages: [event.page] });
2310
- case "pages.deleted": return drop(records, keysOnPages(records, event.pages));
2311
- case "pages.inserted": return event.insertedPages.length ? (0, _embedpdf_core.reload)({ pages: event.insertedPages }) : records;
2361
+ case "pages.deleted": {
2362
+ const going = pagesGoingTo(records, event.pages);
2363
+ return going.length ? (0, _embedpdf_core.reload)({ pages: [...event.pages, ...going] }) : drop(records, keysOnPages(records, event.pages));
2364
+ }
2365
+ case "pages.inserted": return event.insertedPages.length ? (0, _embedpdf_core.reload)({ pages: [...event.insertedPages, ...pagesGoingTo(records, event.insertedPages)] }) : records;
2366
+ case "pages.restored": return (0, _embedpdf_core.reload)({ pages: [...event.pages, ...pagesGoingTo(records, event.pages)] });
2312
2367
  case "redaction.applied":
2313
2368
  case "pages.flattened": {
2314
2369
  const pages = event.results.filter((result) => result.status === "applied").map((result) => result.page);
@@ -2503,7 +2558,9 @@ function createRecordsMirror(ctx, events) {
2503
2558
  fold: foldRecords,
2504
2559
  predict: predictRecords,
2505
2560
  loadPages: async (doc, pages) => {
2506
- const { annotations } = await doc.annotations.list({ pages });
2561
+ const present = new Set(ctx.document()?.pages.map((page) => page.ref.objectNumber));
2562
+ const reading = pages.filter((page) => present.has(page.objectNumber));
2563
+ const { annotations } = reading.length ? await doc.annotations.list({ pages: reading }) : { annotations: [] };
2507
2564
  return (current) => withPages(current, pages, annotations);
2508
2565
  },
2509
2566
  changed: (change) => events.recordsChanged.emit(change)