@embedpdf/plugin-annotation 3.0.0-next.13 → 3.0.0-next.15
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +129 -0
- package/dist/authoring.cjs +12 -2
- package/dist/authoring.d.cts +2 -2
- package/dist/authoring.d.ts +2 -2
- package/dist/authoring.js +2 -3
- package/dist/contract/host.cjs +18 -2
- package/dist/contract/host.d.cts +3 -2
- package/dist/contract/host.d.ts +3 -2
- package/dist/contract/host.js +3 -2
- package/dist/contract-BK4LHe9v.d.cts +1127 -0
- package/dist/contract-BOo9iZKo.d.ts +1127 -0
- package/dist/contract-CPzpRG3h.cjs +692 -0
- package/dist/contract-CPzpRG3h.cjs.map +1 -0
- package/dist/contract-b2e_LZvu.js +651 -0
- package/dist/contract-b2e_LZvu.js.map +1 -0
- package/dist/contract.cjs +11 -10
- package/dist/contract.d.cts +2 -3
- package/dist/contract.d.ts +2 -3
- package/dist/contract.js +2 -4
- package/dist/host-contract-BbjhS_Fo.d.ts +310 -0
- package/dist/host-contract-CxrQPcPj.js +52 -0
- package/dist/host-contract-CxrQPcPj.js.map +1 -0
- package/dist/{contract-a4eaQWga.cjs → host-contract-DY9jFPPF.cjs} +36 -16
- package/dist/host-contract-DY9jFPPF.cjs.map +1 -0
- package/dist/host-contract-Nzxwh0XS.d.cts +310 -0
- package/dist/index.cjs +4995 -414
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +12 -17
- package/dist/index.d.ts +12 -17
- package/dist/index.js +4949 -388
- package/dist/index.js.map +1 -1
- package/package.json +11 -14
- package/dist/authoring-BhtyfsMx.d.cts +0 -37
- package/dist/authoring-R4ezdnXd.d.ts +0 -37
- package/dist/capability-B_dkoB1K.js +0 -3041
- package/dist/capability-B_dkoB1K.js.map +0 -1
- package/dist/capability-DVx1NmTe.cjs +0 -3064
- package/dist/capability-DVx1NmTe.cjs.map +0 -1
- package/dist/contract-CgAcfAE7.d.cts +0 -34
- package/dist/contract-CiG2_HBq.d.ts +0 -34
- package/dist/contract-DtXE1hjY.js +0 -32
- package/dist/contract-DtXE1hjY.js.map +0 -1
- package/dist/contract-a4eaQWga.cjs.map +0 -1
- package/dist/internal.cjs +0 -8
- package/dist/internal.d.cts +0 -14
- package/dist/internal.d.ts +0 -14
- package/dist/internal.js +0 -5
- package/dist/seam-6pJeKOOJ.cjs +0 -296
- package/dist/seam-6pJeKOOJ.cjs.map +0 -1
- package/dist/seam-C4L_7rDt.js +0 -225
- package/dist/seam-C4L_7rDt.js.map +0 -1
- package/dist/tools-0NI3b9z8.cjs +0 -536
- package/dist/tools-0NI3b9z8.cjs.map +0 -1
- package/dist/tools-DBEYx3-c.js +0 -513
- package/dist/tools-DBEYx3-c.js.map +0 -1
- package/dist/types-BvB1vUKb.js +0 -20
- package/dist/types-BvB1vUKb.js.map +0 -1
- package/dist/types-D5V0TIwk.d.ts +0 -1200
- package/dist/types-Dlhdw2k_.cjs +0 -31
- package/dist/types-Dlhdw2k_.cjs.map +0 -1
- package/dist/types-ObcPYc3-.d.cts +0 -1200
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"contract-CPzpRG3h.cjs","names":["ANNOTATION_FIELD_NAMES"],"sources":["../src/token.ts","../src/state.ts","../src/tools/definitions.ts","../src/contract.ts"],"sourcesContent":["/** The package token — created once here; `contract.ts` re-exports it and\n * `host-contract.ts` widens it to the host capability. */\nimport { createCapabilityToken } from '@embedpdf/core';\n\nimport type { AnnotationCapability } from './contract';\n\nexport const AnnotationToken = createCapabilityToken<AnnotationCapability>('annotation', {\n hint: `add annotationPlugin() from '@embedpdf/plugin-annotation' to your plugins list`,\n // Without a document, an adapter's stand-in rejects these with `not-ready`, as the\n // capability would; the type asks for every member that returns a promise.\n promises: {\n refresh: true,\n create: true,\n createFromSelection: true,\n update: true,\n delete: true,\n reorder: true,\n export: true,\n import: true,\n downloadResource: true,\n 'links.set': true,\n 'links.clear': true,\n 'selection.update': true,\n 'selection.updateLink': true,\n 'selection.delete': true,\n 'selection.rotateBy': true,\n 'selection.resetRotation': true,\n 'selection.group': true,\n 'selection.ungroup': true,\n 'draft.finish': true,\n 'text.end': true,\n 'text.toggleFormat': true,\n 'stamps.arm': true,\n 'stamps.place': true,\n 'comments.reply': true,\n 'comments.setText': true,\n 'comments.setStatus': true,\n 'comments.setMarked': true,\n 'comments.delete': true,\n 'comments.deleteThread': true,\n },\n});\n","/**\n * The selecting page's State table as code: what `useAnnotationState()`\n * returns, and the same fields in every other framework. The annotations\n * themselves are not here: `useAnnotationList()` reads them, so a component\n * that shows the selection doesn't re-render for every change on the page.\n */\nimport { defineState } from '@embedpdf/core';\n\nimport { AnnotationToken } from './token';\n\nexport const annotationState = defineState(AnnotationToken, {\n read: (annotation) => ({\n status: annotation.getStatus(),\n selected: annotation.selection.list(),\n hovered: annotation.getHovered(),\n editing: annotation.text.getEditing(),\n }),\n empty: { status: 'loading', selected: [], hovered: null, editing: null },\n});\n","/**\n * The annotation tool registry — the one place that says which tools exist and\n * what each one authors. A tool is a named authoring preset, not a new kind: it\n * binds an `id` to a PDF `subtype`, its `defaults` (the engine fields what it\n * draws takes: a draft without its shape), a cursor, and the interaction tags\n * it turns on. Two tools can share a subtype but differ in\n * defaults (an \"arrow\" is a `line` with an arrowhead default), which is exactly\n * why defaults are keyed by the tool id (the `preset`), never by the subtype.\n *\n * The built-in {@link DEFAULT_TOOLS} are the standard tool set; an embedder tweaks\n * or extends them with `annotationPlugin({ tools: [...] })`. Same-id entries merge\n * over the built-in (configure it); a new id adds a tool; `extends` inherits an\n * existing tool's subtype/cursor/tags so a preset is one line.\n */\nimport type {\n AnnotationFlags,\n ClickCreate,\n FieldValues,\n InkStraightenOptions,\n KindName,\n} from '@embedpdf/core-annotation';\nimport {\n ANNOTATION_FIELD_NAMES,\n type AnnotationDraft,\n type AnnotationSubtype,\n type BinarySource,\n type RichTextBody,\n type WidgetAppearance,\n} from '@embedpdf/engine-core/runtime';\nimport type { ToolTouch } from '@embedpdf/plugin-interaction/contract';\n\nimport type { AfterCreateSettings } from '../contract';\n\n/**\n * How a stamp-family tool resolves the image bytes it places — pure data, so a\n * tool table stays JSON-serializable (config can come from a file, a DB, or the\n * server). Evaluated at click time, so the user picks the spot first, then the\n * source:\n * - `{ kind: 'bytes' }` — fixed bytes: a company rubber-stamp.\n * - `{ kind: 'prompt' }` — ask the environment for bytes. The plugin does not\n * know how (a file dialog is DOM); the file-picker port (`FilePickerProvider`),\n * installed by the framework adapter, fulfils it. Resolve `null` there to cancel.\n */\nexport type StampSourceSpec = { kind: 'bytes'; source: BinarySource } | PromptSourceSpec;\n\n/**\n * The ask-the-environment resolution, shared by every click-then-pick tool\n * (a stamp's `'prompt'` source, the file-attachment tool). `accept` is the\n * file-dialog filter the picker request carries — a UX hint only, the engine\n * sniffs/validates the bytes for real. Unset = any file.\n */\nexport interface PromptSourceSpec {\n kind: 'prompt';\n accept?: string;\n}\n\n/**\n * The tool `stamps.arm` activates — and the only tool an armed payload survives\n * onto (plus the legacy `annotation-stamp` tag, honoured for embedder configs\n * written before the tags were unified). Placement consults the armed payload\n * before the active tool's own `source` spec, so a payload must not outlive\n * its tool onto a sibling stamp preset: an `image` preset's click has to open\n * its own picker, not silently place whatever the stamp panel last armed.\n */\nexport const ARMED_STAMP_TOOL_ID = 'stamp';\n\n/** Declarative result of committing a text selection while a tool is active. */\nexport type SelectionAuthoring =\n | { kind: 'markup' }\n | { kind: 'text-edit'; operation: 'insert' | 'replace' };\n\n/**\n * The tool's ghost: a see-through copy of what a click would place, following\n * the pointer, drawn with the tool's current defaults exactly where and as\n * the click will make it. `true` shows it half see-through, `{ opacity }`\n * as opaque as you say (0–1; `--epdf-ghost-opacity` wins over it from CSS),\n * `false` hides it. It shows only where a click creates: a tool whose click\n * makes nothing (ink, a polygon, `clickCreate: false`) has none, and it hides\n * over an annotation or text, where the click does something else.\n * The cursor says which tool is active; the ghost says where the click lands.\n */\nexport type GhostPolicy = boolean | { opacity: number };\n\n/** A resolved ghost: how opaque it paints, or `false` for none. */\nexport type ResolvedGhost = false | { opacity: number };\n\n/** How opaque a ghost paints unless its tool says. */\nexport const GHOST_OPACITY = 0.5;\n\n/** A tool's ghost setting, resolved: `true` is half see-through. */\nconst resolveGhost = (ghost: GhostPolicy): ResolvedGhost =>\n ghost === true ? { opacity: GHOST_OPACITY } : ghost;\n\n/** Time/geometry policy for freehand ink authoring. */\nexport interface InkAuthoringOptions {\n /** Group strokes made within this interval into one `/InkList`; 0 commits immediately. */\n groupStrokesMs?: number;\n /** Optional pure straight-line recognition applied to each completed stroke. */\n straighten?: InkStraightenOptions;\n}\n\n/**\n * The fields no tool's defaults may set: where the annotation goes (that comes\n * from the drawing), its identity and relationships, and what the engine\n * stamps or keeps by itself.\n */\nconst NOT_DEFAULTS = [\n 'ref',\n 'page',\n 'index',\n 'hasAppearance',\n 'appearanceState',\n 'nm',\n 'rect',\n 'box',\n 'linePoints',\n 'vertices',\n 'inkList',\n 'quadPoints',\n 'calloutLine',\n 'captionCenter',\n 'measure',\n 'reply',\n 'popup',\n 'parent',\n 'groupId',\n 'author',\n 'createdAt',\n 'modifiedAt',\n 'userId',\n 'createdBy',\n 'modifiedBy',\n 'importedBy',\n 'actions',\n] as const;\ntype NotDefault = (typeof NOT_DEFAULTS)[number];\n\nconst WIDGET_BOX_FIELDS = ['color', 'interiorColor', 'strokeWidth', 'borderStyle'] as const;\nconst WIDGET_TEXT_FIELDS = [\n ...WIDGET_BOX_FIELDS,\n 'fontFamily',\n 'fontSize',\n 'fontColor',\n 'textAlign',\n] as const;\n\n/** Every field of an engine kind a tool's defaults may set: any field but the ones above. */\nconst draftDefaults = (subtype: AnnotationSubtype): readonly string[] =>\n ANNOTATION_FIELD_NAMES[subtype].filter(\n (name) => !(NOT_DEFAULTS as readonly string[]).includes(name),\n );\n\n/**\n * The fields each known authoring kind's defaults may set: any field a create\n * from the tool takes besides where it goes, flags and `contents` included.\n * A key outside it stops the app at startup, naming the tool and the field.\n */\nexport const TOOL_DEFAULT_FIELDS = {\n square: draftDefaults('square'),\n circle: draftDefaults('circle'),\n line: draftDefaults('line'),\n polygon: draftDefaults('polygon'),\n polyline: draftDefaults('polyline'),\n ink: draftDefaults('ink'),\n 'free-text': draftDefaults('free-text'),\n 'free-text-callout': draftDefaults('free-text'),\n highlight: draftDefaults('highlight'),\n underline: draftDefaults('underline'),\n strikeout: draftDefaults('strikeout'),\n squiggly: draftDefaults('squiggly'),\n caret: draftDefaults('caret'),\n redact: draftDefaults('redact'),\n stamp: draftDefaults('stamp'),\n link: draftDefaults('link'),\n text: draftDefaults('text'),\n 'file-attachment': draftDefaults('file-attachment'),\n // Widget client kinds (the form plugin's palette tools): box styling for\n // every family, `/DA` text styling for the text-bearing ones. The engine\n // maps them onto /MK //BS //DA //Q.\n 'widget-text': WIDGET_TEXT_FIELDS,\n 'widget-choice': WIDGET_TEXT_FIELDS,\n 'widget-button': WIDGET_TEXT_FIELDS,\n 'widget-toggle': WIDGET_BOX_FIELDS,\n 'widget-radio': WIDGET_BOX_FIELDS,\n // The bare box every other widget family ingests as (a signature field's\n // widget among them): box styling only, no text to style.\n 'widget-box': WIDGET_BOX_FIELDS,\n} as const satisfies Record<string, readonly string[]>;\n\nexport type ToolAuthoringKind = keyof typeof TOOL_DEFAULT_FIELDS;\n/** The draft a kind's creates are: a callout is a free text; a form tool's kind is a widget's appearance. */\ntype ToolDraftOf<K extends ToolAuthoringKind> = K extends `widget-${string}`\n ? Partial<\n Pick<WidgetAppearance, (typeof TOOL_DEFAULT_FIELDS)[K][number] & keyof WidgetAppearance>\n >\n : Omit<\n Partial<\n Extract<AnnotationDraft, { subtype: K extends 'free-text-callout' ? 'free-text' : K }>\n >,\n NotDefault | 'subtype' | 'richText'\n >;\n/** A tool's rich text is its body: the formatting what it types starts with. */\ntype ToolRichText = {\n richText?: { body: Partial<RichTextBody> };\n};\n/**\n * The defaults a tool of kind `K` takes: any field of what it draws, flags\n * included, except where it goes (`box`, `rect`, points), which the drawing\n * gives.\n */\nexport type ToolDefaultsFor<K extends ToolAuthoringKind> = ToolDraftOf<K> &\n (K extends 'free-text' | 'free-text-callout' ? ToolRichText : unknown);\n\n/**\n * A tool definition — the public config vocabulary. Every field except `id` is\n * optional: the common cases are \"configure a built-in\" (`{ id, defaults }`) and\n * \"add a preset\" (`{ id, extends, defaults }`).\n */\nexport interface AnnotationToolDef<K extends ToolAuthoringKind = ToolAuthoringKind> {\n /** Stable tool id — the value passed to `activateTool` and the `defaults` key. */\n id: string;\n /** Inherit `subtype` / `fieldsKind` / `cursor` / `enables` / `source` /\n * `selection` / `intent` / `ink` / `meta`\n * from an existing tool id (a built-in or another entry). Own fields win. */\n extends?: string;\n /** The routing kind this tool authors — the core's client kind (the geometry\n * it draws + the props key). Usually the PDF subtype, but not always:\n * `free-text-callout` routes the callout gesture onto a free-text\n * annotation, and `widget-text`/`widget-choice`/`widget-toggle`/`widget-radio` are client\n * views of the one PDF `widget` subtype (a form tool's commit goes through\n * `doc.forms`, never this plugin — see the form plugin's tool table).\n * Defaults to the inherited kind, or the id when neither is given. */\n subtype?: KindName;\n /** The kind whose editable fields a style panel shows for this tool.\n * Defaults to `subtype`. */\n fieldsKind?: string;\n /** Advanced: the `defaults` key this tool reads/writes. Defaults to the id, and\n * that is almost always right — override it only to alias a shared defaults bag\n * (the built-in insert-caret tool points its preset at the `caret` key). */\n preset?: string;\n /** The engine fields what the tool draws takes, besides its shape: a draft\n * without its shape, merged over any inherited defaults (each value whole).\n * The engine's defaults fill in what they leave out. */\n defaults?: ToolDefaultsFor<K>;\n /**\n * `/F` annotation flags seeded on everything this tool creates, merged over\n * the drawn default (`print` set — Acrobat parity) and any inherited seed.\n * A note tool passes `{ noZoom: true, noRotate: true }` so its icons stay\n * screen-sized and upright (the spec's rule for Text annotations).\n */\n flags?: Partial<AnnotationFlags>;\n /** The pointer cursor while this tool is active. Defaults inherited / `crosshair`. */\n cursor?: string;\n /** Interaction capability tags this tool enables (which handlers wake up). */\n enables?: string[];\n /**\n * How the click-to-place payload resolves. Stamps take the full spec\n * ({@link StampSourceSpec}: fixed bytes or prompt); file attachments are\n * prompt-only ({@link PromptSourceSpec} — the file always comes from the\n * environment). Other kinds carry no payload.\n */\n source?: K extends 'stamp'\n ? StampSourceSpec\n : K extends 'file-attachment'\n ? PromptSourceSpec\n : never;\n /** What a committed text selection authors. Omit for pointer/click tools. */\n selection?: SelectionAuthoring;\n /** Ink-only stroke grouping and straightening policy. */\n ink?: K extends 'ink' ? InkAuthoringOptions : never;\n /**\n * Place annotations upright: counter-rotate what this tool creates against the\n * page's total display rotation (document /Rotate + any stage view rotation),\n * so it reads horizontally exactly as the author saw it — Adobe's behaviour\n * for stamps and text on rotated pages. WYSIWYG at authoring time: the\n * rotation is baked into the annotation, so a save keeps what the author saw\n * (other viewers apply only /Rotate — document that when view rotation is in\n * play). A drawing without a reading direction bakes no turn: a clicked\n * square or circle swaps its sides instead, so it shows its `clickCreate`\n * size as the author sees the page, and a clicked line points the way its\n * `clickCreate` says there; a drag, and a callout's leader, follow the\n * pointer. Default: on for the built-in `stamp`, `free-text`, `note`,\n * `attachment`, `square`, `circle` and `line` tools, off elsewhere.\n */\n upright?: boolean;\n /**\n * What a bare click creates ({@link ClickCreate}): a default-size shape\n * centred on the point, a default-length line centred on it, free text's\n * type-here box hanging from it — page-clamped, in PDF pt. `false` =\n * drag-only. Defaults: on for the built-in square/circle/line/free-text,\n * off elsewhere.\n */\n clickCreate?: ClickCreate | false;\n /**\n * The tool's ghost ({@link GhostPolicy}). Defaults: inherited, else off;\n * on for the built-in click-to-place tools (stamp, note, attachment).\n */\n ghost?: GhostPolicy;\n /**\n * What happens after this tool creates an annotation: select it, keep the\n * tool, start typing in a text box. Wins over the `afterCreate` setting for\n * every tool; what it leaves out comes from there.\n */\n afterCreate?: Partial<AfterCreateSettings>;\n /** Your own data, such as a label and an icon for a toolbar that builds itself\n * from the tool table. The plugin keeps it and never reads it. */\n meta?: Record<string, unknown>;\n}\n\nexport interface BuiltinToolKindMap {\n square: 'square';\n circle: 'circle';\n line: 'line';\n distance: 'line';\n perimeter: 'polyline';\n area: 'polygon';\n calibrate: 'line';\n polygon: 'polygon';\n polyline: 'polyline';\n ink: 'ink';\n 'ink-highlight': 'ink';\n 'free-text': 'free-text';\n 'free-text-callout': 'free-text-callout';\n highlight: 'highlight';\n underline: 'underline';\n strikeout: 'strikeout';\n squiggly: 'squiggly';\n 'insert-text': 'caret';\n 'replace-text': 'strikeout';\n redact: 'redact';\n stamp: 'stamp';\n note: 'text';\n attachment: 'file-attachment';\n link: 'link';\n}\n\ntype DirectToolDef = {\n [K in ToolAuthoringKind]: Omit<AnnotationToolDef<K>, 'subtype'> & { subtype: K };\n}[ToolAuthoringKind];\n// A key a shape doesn't take is `?: undefined`, not `?: never`: without `strictNullChecks` (plain\n// JavaScript, a non-strict app) a missing `never` key can't tell the shapes apart, so the union is\n// read as one, `id: 'highlight'` widens to `string` and no shape takes it.\ntype BuiltinToolOverride = {\n [I in keyof BuiltinToolKindMap]: Omit<\n AnnotationToolDef<BuiltinToolKindMap[I]>,\n 'id' | 'extends' | 'subtype'\n > & {\n id: I;\n extends?: undefined;\n subtype?: undefined;\n };\n}[keyof BuiltinToolKindMap];\ntype ExtendedBuiltinToolDef = {\n [I in keyof BuiltinToolKindMap]: Omit<\n AnnotationToolDef<BuiltinToolKindMap[I]>,\n 'extends' | 'subtype'\n > & {\n extends: I;\n subtype?: undefined;\n };\n}[keyof BuiltinToolKindMap];\n\n/** Public tool input: known overrides, known-base presets, or an explicit subtype. */\nexport type AnnotationToolInput = DirectToolDef | BuiltinToolOverride | ExtendedBuiltinToolDef;\n\n/** A fully-resolved tool — what the plugin, handlers, and registration loop read. */\nexport interface ResolvedTool {\n id: string;\n /** Routing token for the draw core + the created annotation's PDF subtype. */\n subtype: KindName;\n /** The `defaults` key (always the tool id) — keeps same-subtype tools apart. */\n preset: string;\n /** The kind whose properties the style panel shows (`propertiesOf(kindNamed(…))`). */\n fieldsKind: string;\n cursor: string;\n enables: ReadonlySet<string>;\n defaults?: FieldValues;\n /** `/F` seed for created annotations (see {@link AnnotationToolDef.flags}). */\n flags?: Partial<AnnotationFlags>;\n source?: StampSourceSpec;\n selection?: SelectionAuthoring;\n ink?: InkAuthoringOptions;\n /** Counter-rotate creations against the page's display rotation (see\n * {@link AnnotationToolDef.upright}). */\n upright: boolean;\n /** What a bare click creates, or `false` for drag-only. */\n clickCreate: ClickCreate | false;\n /** The tool's ghost ({@link GhostPolicy}): how opaque it paints, or `false` for none. */\n ghost: ResolvedGhost;\n /** Its own `afterCreate` (see {@link AnnotationToolDef.afterCreate}), over the setting. */\n afterCreate?: Partial<AfterCreateSettings>;\n /** A line gesture is captured, not created ({@link CAPTURE_TOOLS}). */\n capture: boolean;\n meta?: Record<string, unknown>;\n}\n\n/**\n * The tools whose line gesture is captured instead of created: the measurement\n * plugin turns the calibrate tool's two points into a scale. A tool that\n * extends one captures too.\n */\nconst CAPTURE_TOOLS: ReadonlySet<string> = new Set(['calibrate']);\n\n// ── field groups shared by the built-ins (keeps the table readable) ──────────\nconst DRAW_TAGS = ['annotation-draw', 'annotation-edit'];\n/** This viewer's drawing red: shapes, lines and text boxes start in it. */\nconst HOUSE_RED = '#e5484d';\nconst MARKUP_TAGS = ['text-select', 'annotation-edit'];\n\n/**\n * What one finger does while this annotation tool is active (`Tool.touch`):\n * drag-create tools (shape/ink draw and text-markup select) take it as `'draw'`\n * (a finger draws or marks, two fingers navigate: the drawing-app convention).\n * Click-to-place tools (stamp, note) are `'tap'`: a tap places, and drags keep\n * scrolling. Derived from the gesture tags, so custom registered tools inherit\n * the right behavior. Only annotation-owned tools run through this: the\n * built-in `pointer` tool also enables `text-select`, but the hub registers it.\n */\nexport const toolTouchOf = (enables: ReadonlySet<string>): ToolTouch =>\n enables.has('annotation-draw') || enables.has('text-select') ? 'draw' : 'tap';\n\n/**\n * The built-in tools, as data (shapes + lines + ink\n * + free text in the draw channel, text markup + caret behind text selection, and\n * the click-to-place stamp). Order is display-neutral; the toolbar owns layout.\n */\nexport const DEFAULT_TOOLS: AnnotationToolInput[] = [\n // shapes / lines / ink / free text — the `annotation-draw` gesture.\n // Draw tools carry click-create defaults (a bare click places a\n // default-size annotation). Their ghost is off: they are drag-first, so the\n // size usually comes from the drag, and `ghost: true` turns it on.\n {\n id: 'square',\n subtype: 'square',\n cursor: 'crosshair',\n enables: DRAW_TAGS,\n defaults: { color: HOUSE_RED, strokeWidth: 6 },\n // A click shows 80 wide and 60 tall as the page is seen, turned or not.\n clickCreate: { width: 80, height: 60 },\n upright: true,\n },\n {\n id: 'circle',\n subtype: 'circle',\n cursor: 'crosshair',\n enables: DRAW_TAGS,\n defaults: { color: HOUSE_RED, strokeWidth: 6 },\n // A click shows 80 wide and 60 tall as the page is seen, turned or not.\n clickCreate: { width: 80, height: 60 },\n upright: true,\n },\n {\n id: 'line',\n subtype: 'line',\n cursor: 'crosshair',\n enables: DRAW_TAGS,\n defaults: { color: HOUSE_RED, strokeWidth: 6 },\n // A click lays it centred on the point, pointing right as the page shows.\n clickCreate: { length: 80 },\n upright: true,\n },\n {\n id: 'distance',\n extends: 'line',\n clickCreate: false,\n defaults: {\n intent: 'line-dimension',\n strokeWidth: 1,\n lineEndings: { start: 'closed-arrow', end: 'closed-arrow' },\n captionEnabled: true,\n captionPosition: 'inline',\n leader: { length: 12, extension: 5, offset: 0 },\n },\n },\n {\n id: 'calibrate',\n extends: 'line',\n enables: ['annotation-draw'],\n defaults: { strokeWidth: 1 },\n clickCreate: false,\n },\n {\n id: 'polygon',\n subtype: 'polygon',\n cursor: 'crosshair',\n enables: DRAW_TAGS,\n defaults: { color: HOUSE_RED, strokeWidth: 6 },\n },\n {\n id: 'polyline',\n subtype: 'polyline',\n cursor: 'crosshair',\n enables: DRAW_TAGS,\n defaults: { color: HOUSE_RED, strokeWidth: 6 },\n },\n {\n id: 'perimeter',\n extends: 'polyline',\n defaults: {\n intent: 'polyline-dimension',\n strokeWidth: 1,\n lineEndings: { start: 'none', end: 'none' },\n captionEnabled: true,\n },\n },\n {\n id: 'area',\n extends: 'polygon',\n defaults: { intent: 'polygon-dimension', strokeWidth: 1, captionEnabled: true },\n },\n {\n id: 'ink',\n subtype: 'ink',\n cursor: 'crosshair',\n enables: DRAW_TAGS,\n defaults: { color: '#ef4444', strokeWidth: 6, blendMode: 'normal' },\n ink: { groupStrokesMs: 800 },\n },\n {\n id: 'ink-highlight',\n extends: 'ink',\n defaults: { intent: 'ink-highlight', color: '#ffcd45', strokeWidth: 14, blendMode: 'multiply' },\n ink: {\n straighten: { deviationThreshold: 0.15, axisSnapDegrees: 15 },\n },\n },\n {\n id: 'free-text',\n subtype: 'free-text',\n cursor: 'crosshair',\n enables: DRAW_TAGS,\n defaults: { color: HOUSE_RED, strokeWidth: 2, fontColor: '#ef4444' },\n upright: true,\n // Top-left anchored: the box hangs where you'll type (the kind's reading\n // feel); shapes default to `center`. Anchoring is explicit policy data.\n clickCreate: { width: 180, height: 40, anchor: 'top-left' },\n },\n {\n // Authors the `free-text-callout` kind: a `free-text` annotation with a\n // leader and a box. Its leader defaults to an open arrowhead.\n // `upright` applies to the text box only: on a rotated page it commits\n // counter-rotated (readable), while the leader tip/knee stay page-space\n // anchors — see the core's `calloutPointer`.\n id: 'free-text-callout',\n subtype: 'free-text-callout',\n cursor: 'crosshair',\n enables: DRAW_TAGS,\n defaults: { color: HOUSE_RED, strokeWidth: 6, lineEnding: 'open-arrow' },\n upright: true,\n },\n // text markup — the `text-select` gesture (inert without a selection plugin).\n // Base cursor is the plain arrow: the I-beam appears only where the action is\n // possible, via the selection handler's over-text claim (which an app can\n // replace with the tool's icon: the hub's `setToolCursor`).\n {\n id: 'highlight',\n subtype: 'highlight',\n cursor: 'default',\n enables: MARKUP_TAGS,\n defaults: { color: '#ffe16a', blendMode: 'multiply' },\n selection: { kind: 'markup' },\n },\n // Redaction marking — the composed tool: over text it rides the selection\n // gesture (per-line quad marks, like a highlight); anywhere else it drag-\n // draws an area mark. One tool, both modes; the destructive apply lives in\n // plugin-redaction.\n {\n id: 'redact',\n subtype: 'redact',\n cursor: 'crosshair',\n enables: ['text-select', 'annotation-draw', 'annotation-edit'],\n defaults: {\n color: '#e44234',\n interiorColor: '#000000',\n fontSize: 14,\n fontColor: '#ffffff',\n opacity: 1,\n },\n selection: { kind: 'markup' },\n },\n {\n id: 'underline',\n subtype: 'underline',\n cursor: 'default',\n enables: MARKUP_TAGS,\n defaults: { color: '#ef4444' },\n selection: { kind: 'markup' },\n },\n {\n id: 'strikeout',\n subtype: 'strikeout',\n cursor: 'default',\n enables: MARKUP_TAGS,\n defaults: { color: '#ef4444' },\n selection: { kind: 'markup' },\n },\n {\n id: 'squiggly',\n subtype: 'squiggly',\n cursor: 'default',\n enables: MARKUP_TAGS,\n defaults: { color: '#ef4444' },\n selection: { kind: 'markup' },\n },\n {\n // The insert-caret tool authors a `caret` from a text selection. Its defaults\n // live under the `caret` preset — the key `createCaret` resolves.\n id: 'insert-text',\n subtype: 'caret',\n fieldsKind: 'caret',\n preset: 'caret',\n cursor: 'default',\n enables: MARKUP_TAGS,\n defaults: { color: '#ef4444' },\n selection: { kind: 'text-edit', operation: 'insert' },\n },\n {\n id: 'replace-text',\n subtype: 'strikeout',\n fieldsKind: 'strikeout',\n cursor: 'default',\n enables: MARKUP_TAGS,\n defaults: { color: '#ef4444' },\n selection: { kind: 'text-edit', operation: 'replace' },\n },\n // stamp — click-to-place; 'prompt' asks the environment through the one\n // file-picker port (the React adapter wires a file dialog by default; an\n // embedder can pass fixed bytes instead). `accept` narrows the dialog to\n // what the engine's stamp sniffer takes anyway.\n {\n id: ARMED_STAMP_TOOL_ID,\n subtype: 'stamp',\n cursor: 'copy',\n enables: ['annotation-place', 'annotation-edit'],\n source: { kind: 'prompt', accept: 'image/png,image/jpeg,application/pdf' },\n upright: true,\n ghost: true,\n },\n // link — drag an invisible hit rectangle; the target is set afterwards\n // through the selection editor (create-then-edit), unless a preset carries\n // a fixed one (`{ id: 'docs-link', extends: 'link', defaults: { target: … } }`).\n // While this tool is active the navigation plane stands down (no `link-nav`),\n // so existing links become plain editable rects.\n {\n id: 'link',\n subtype: 'link',\n cursor: 'crosshair',\n enables: DRAW_TAGS,\n },\n // sticky note (\"comment\") — click-to-place, no payload: each click drops a\n // fixed 20×20 icon (engine-baked /AP from /C + /Name), screen-sized and\n // upright per the spec's Text-icon rule (the noZoom/noRotate seed). Its\n // ghost is the icon under the pointer, so the cursor is a plain plus.\n {\n id: 'note',\n subtype: 'text',\n cursor: 'crosshair',\n enables: ['annotation-place', 'annotation-edit'],\n defaults: { icon: 'comment', color: '#facc15' },\n flags: { noZoom: true, noRotate: true },\n upright: true,\n ghost: true,\n },\n // file attachment — click-to-place with the spot-first-file-second rule:\n // the click opens the installed file-picker port (a file dialog by\n // default; `accept` unset = any file — attaching any format is the point);\n // the picked file embeds at the clicked point. Like the note's, its ghost\n // is the icon under the pointer, so the cursor is a plain plus.\n {\n id: 'attachment',\n subtype: 'file-attachment',\n cursor: 'crosshair',\n enables: ['annotation-place', 'annotation-edit'],\n source: { kind: 'prompt' },\n defaults: { icon: 'paperclip', color: '#facc15' },\n flags: { noZoom: true, noRotate: true },\n upright: true,\n ghost: true,\n },\n];\n\n/** Merge two tools' defaults, `right` over `left`, each value whole. */\nfunction mergeDefaults(left?: FieldValues, right?: FieldValues): FieldValues | undefined {\n return left && right ? { ...left, ...right } : (right ?? left);\n}\n\n/** Overlay a same-id override onto a base definition (configure a built-in). */\nfunction mergeDef(base: AnnotationToolDef, over: AnnotationToolDef): AnnotationToolDef {\n return {\n ...base,\n ...over,\n enables: over.enables ?? base.enables,\n meta: base.meta || over.meta ? { ...base.meta, ...over.meta } : undefined,\n defaults: mergeDefaults(base.defaults, over.defaults) as AnnotationToolDef['defaults'],\n flags: base.flags || over.flags ? { ...base.flags, ...over.flags } : undefined,\n ink: base.ink || over.ink ? { ...base.ink, ...over.ink } : undefined,\n afterCreate:\n base.afterCreate || over.afterCreate\n ? { ...base.afterCreate, ...over.afterCreate }\n : undefined,\n };\n}\n\nfunction validateDefaults(tool: ResolvedTool): void {\n if (!tool.defaults) return;\n const allowed = TOOL_DEFAULT_FIELDS[tool.subtype as ToolAuthoringKind];\n // Unknown/custom routing kinds remain extensible; known built-ins are strict.\n if (!allowed) return;\n const keys = new Set<string>(allowed);\n for (const key of Object.keys(tool.defaults)) {\n if (!keys.has(key)) {\n throw new Error(\n `[annotation] tool '${tool.id}' does not support default '${key}' for '${tool.subtype}'`,\n );\n }\n }\n}\n\n/**\n * Resolve {@link DEFAULT_TOOLS} + embedder overrides into the ready-to-use table.\n * A same-id override merges over the built-in; a new id adds a tool; `extends`\n * inherits from an already-defined tool. Keyed by id, so lookups are O(1).\n */\nexport function buildToolRegistry(\n overrides: AnnotationToolInput[] = [],\n): Map<string, ResolvedTool> {\n const defs = new Map<string, AnnotationToolDef>();\n for (const definition of DEFAULT_TOOLS) defs.set(definition.id, definition);\n for (const override of overrides) {\n const previous = defs.get(override.id);\n defs.set(override.id, previous ? mergeDef(previous, override) : override);\n }\n\n const out = new Map<string, ResolvedTool>();\n const resolving = new Set<string>();\n const resolve = (id: string): ResolvedTool => {\n const cached = out.get(id);\n if (cached) return cached;\n const definition = defs.get(id);\n if (!definition) throw new Error(`[annotation] tool '${id}' extends an unknown tool`);\n // Inherit from the base first (guarding self / cyclic extends), then own fields win.\n let base: ResolvedTool | undefined;\n if (definition.extends && definition.extends !== id && !resolving.has(definition.extends)) {\n resolving.add(id);\n base = resolve(definition.extends);\n resolving.delete(id);\n }\n const subtype = (definition.subtype ?? base?.subtype ?? definition.id) as KindName;\n const resolved: ResolvedTool = {\n id: definition.id,\n subtype,\n preset: definition.preset ?? definition.id,\n fieldsKind: definition.fieldsKind ?? base?.fieldsKind ?? subtype,\n cursor: definition.cursor ?? base?.cursor ?? 'crosshair',\n enables: new Set(definition.enables ?? (base ? [...base.enables] : [])),\n defaults: mergeDefaults(base?.defaults, definition.defaults),\n flags: base?.flags || definition.flags ? { ...base?.flags, ...definition.flags } : undefined,\n source: definition.source ?? base?.source,\n selection: definition.selection ?? base?.selection,\n ink: base?.ink || definition.ink ? { ...base?.ink, ...definition.ink } : undefined,\n upright: definition.upright ?? base?.upright ?? false,\n clickCreate: definition.clickCreate ?? base?.clickCreate ?? false,\n ghost: resolveGhost(definition.ghost ?? base?.ghost ?? false),\n afterCreate:\n base?.afterCreate || definition.afterCreate\n ? { ...base?.afterCreate, ...definition.afterCreate }\n : undefined,\n capture: CAPTURE_TOOLS.has(definition.id) || (base?.capture ?? false),\n meta: base?.meta || definition.meta ? { ...base?.meta, ...definition.meta } : undefined,\n };\n validateDefaults(resolved);\n out.set(id, resolved);\n return resolved;\n };\n for (const id of defs.keys()) resolve(id);\n return out;\n}\n","/**\n * The public annotation protocol: the documented, stable surface for\n * application code (toolbars, sidebars, app logic). Resolve it with the token\n * exported here or from the package root. Framework-only plumbing (render\n * projection, pointer gestures, behavior registration) lives on the host lens\n * in `./host-contract`; both are the same runtime object, two typed lenses on\n * one token, so app code can't see the host methods.\n *\n * The capability has nouns for what it works on: `selection`, `draft` (a\n * polygon being drawn), `text` (typing in a text box), `tools`, `stamps`,\n * `links` and `comments`. Everything else is on the capability itself.\n */\nimport type {\n BatchResult,\n DeepPartial,\n EventHook,\n EventOrigin,\n OperationOptions,\n PluginErrorInfo,\n ResourceStatus,\n SettingsApi,\n Unsubscribe,\n} from '@embedpdf/core';\nimport type {\n AnnotationProperty,\n CreationDraftAnchor,\n EditableKinds,\n FieldValues,\n KindName,\n Rect,\n RotationAnchor,\n SnapSettings,\n ViewEnv,\n} from '@embedpdf/core-annotation';\nimport type { Point } from '@embedpdf/core-geometry';\nimport type {\n Annotation,\n AnnotationBundle,\n AnnotationDraft,\n AnnotationImportDrop,\n AnnotationImportOptions,\n AnnotationPatch,\n AnnotationPosition,\n AnnotationRef,\n AnnotationResourceRole,\n AnnotationResources,\n AnnotationSubtype,\n AttachmentFileSource,\n BinarySource,\n CommentThread,\n PageRef,\n PdfActionTree,\n PdfLinkTarget,\n RichTextParagraph,\n} from '@embedpdf/engine-core/runtime';\n\nimport type { TextFormat } from './rich-text';\nimport type { AnnotationToolInput, ResolvedGhost } from './tools/definitions';\n\nexport { AnnotationToken } from './token';\nexport { annotationState } from './state';\nexport { AnnotationTransfer } from '@embedpdf/engine-core/public';\nexport type { Face, TextFormat, TextSelection } from './rich-text';\nexport type {\n Annotation,\n AnnotationBundle,\n AnnotationDraft,\n AnnotationImportDrop,\n AnnotationImportOptions,\n AnnotationPatch,\n AnnotationPosition,\n AnnotationRef,\n AnnotationResourceRole,\n AnnotationResources,\n AnnotationSubtype,\n AttachmentContent,\n AttachmentFileSource,\n Color,\n CommentThread,\n CommentThreadReview,\n PdfLinkTarget,\n ReviewStatus,\n} from '@embedpdf/engine-core/runtime';\nexport type {\n AnnotationFlags,\n AnnotationOption,\n AnnotationProperty,\n BlendMode,\n ClickCreate,\n EditableKind,\n EditableKinds,\n FieldValues,\n FlagKey,\n HandleRole,\n LineEnding,\n LineEndings,\n MeasurementIntent,\n SnapSettings,\n TextAlign,\n} from '@embedpdf/core-annotation';\n/** The tool `stamps.arm` activates: a sibling that must win a click while a stamp is armed keys on it. */\nexport { ARMED_STAMP_TOOL_ID } from './tools/definitions';\n\n// ── settings ─────────────────────────────────────────────────────────────────\n\n/** `'solid'` or `'dashed'` (4 pixels on, 3 off). */\nexport type LineStyle = 'solid' | 'dashed';\n\n/**\n * How a selection looks: its outline, its handles and rotation handle, the\n * lines shown while snapping and turning, the box dragged to select, a text\n * box's outline while typing, and the angle while turning. Every size is in\n * screen pixels, so it looks the same at every zoom. A color left `null`\n * follows the part named in its doc, and in the end `accent`; every color,\n * width and dash can also come from a CSS variable (`--epdf-annotation-*`),\n * which wins over the setting.\n */\nexport interface ChromeSettings {\n /** The color of every part below that has none of its own; `null` follows the viewer's accent. */\n readonly accent: string | null;\n /** The box around the selection. */\n readonly outline: {\n /** `null` follows `accent`. */\n readonly color: string | null;\n readonly style: LineStyle;\n /** Line width, px. */\n readonly width: number;\n };\n /** The resize and point handles. */\n readonly handles: {\n readonly shape: 'square' | 'circle';\n /** What you see, px. */\n readonly size: number;\n /** What you can grab, px: keep it at 24 or more for touch. */\n readonly hitSize: number;\n readonly fill: string;\n /** `null` follows `accent`. */\n readonly stroke: string | null;\n };\n /** The round handle that turns the selection, on a short line (its stalk) above it. */\n readonly rotationHandle: {\n /** `false`: no rotation handle; the selection turns only from code. */\n readonly enabled: boolean;\n /** Its diameter, px. */\n readonly size: number;\n /** What you can grab, px. */\n readonly hitSize: number;\n /** How far it sits from the selection's edge, px. */\n readonly offset: number;\n /** `false` hides the line from the edge to it. */\n readonly stalk: boolean;\n /** `null` follows `handles.fill`. */\n readonly fill: string | null;\n /** `null` follows `handles.stroke`. */\n readonly stroke: string | null;\n };\n /** The lines shown while snapping (alignment) and while turning (rotation). */\n readonly guides: {\n /** `false`: no rotation guides while turning. */\n readonly enabled: boolean;\n /** What a move snaps to. */\n readonly color: string;\n /** The reference cross and the angle line while turning; `null` follows `accent`. */\n readonly rotationColor: string | null;\n readonly style: LineStyle;\n /** Line width of both kinds, px. */\n readonly width: number;\n };\n /** The box you drag to select several annotations. */\n readonly marquee: {\n /** `null`: `accent` at 8%. */\n readonly fill: string | null;\n /** `null` follows `accent`. */\n readonly stroke: string | null;\n };\n /** The outline of a text box while you type in it; `null` follows `accent`. */\n readonly textOutline: string | null;\n /** The angle shown next to the pointer while you turn a selection. */\n readonly readout: {\n readonly enabled: boolean;\n readonly background: string;\n readonly color: string;\n };\n}\n\n/**\n * A tool's defaults: the fields its next annotation starts with, its own over\n * the engine's. Which fields there are depends on the tool's kind; the style\n * fields most tools have are typed, the rest read as `unknown`.\n */\nexport interface ToolDefaults {\n readonly color?: string;\n readonly interiorColor?: string | null;\n readonly opacity?: number;\n readonly strokeWidth?: number;\n readonly fontFamily?: string;\n readonly fontSize?: number;\n readonly fontColor?: string;\n readonly textAlign?: 'left' | 'center' | 'right';\n readonly icon?: string;\n readonly contents?: string | null;\n readonly [field: string]: unknown;\n}\n\n/** What happens after a tool creates an annotation. A tool's own `afterCreate` wins over this. */\nexport interface AfterCreateSettings {\n /** Select the new annotation. */\n readonly select: boolean;\n /** `'stay'` keeps the tool active; `'default'` goes back to the default tool, usually `pointer`. */\n readonly tool: 'stay' | 'default';\n /** For text boxes: start typing in the new box right away. */\n readonly editText: boolean;\n}\n\n/**\n * The annotation settings: what `annotationPlugin(config)` registers over\n * {@link ANNOTATION_DEFAULTS}. `snap`, `chrome`, `afterCreate` and `editable`\n * change for every open document with `updateSettings()`; `tools` is read\n * when a document opens (add a tool to an open one with `tools.register()`).\n */\nexport interface AnnotationSettings {\n /**\n * Change the built-in tools or add your own. An entry with a built-in's id\n * changes it (`{ id: 'ink', defaults: { strokeWidth: 6 } }`), a new id adds\n * a tool, and `extends` starts from another tool.\n */\n readonly tools: readonly AnnotationToolInput[];\n readonly afterCreate: AfterCreateSettings;\n readonly chrome: ChromeSettings;\n /** Snapping to other annotations and the page while moving, and to angles while turning. */\n readonly snap: SnapSettings;\n /**\n * Which annotations people may change by hand: `true`, every one; `false`,\n * none; or a list of the kinds they may, by subtype (`'highlight'`), a\n * measurement by its intent (`'line-dimension'`). One left out can still be\n * selected, read and commented on, but not moved, resized, turned,\n * restyled, typed in or deleted. Only the interface: your code still\n * changes it, and `canUpdate()` and `canDelete()` don't change.\n */\n readonly editable: EditableKinds;\n}\n\n/** What the annotation settings are when the app registers none. */\nexport const ANNOTATION_DEFAULTS: AnnotationSettings = {\n tools: [],\n afterCreate: { select: true, tool: 'stay', editText: true },\n chrome: {\n accent: null,\n outline: { color: null, style: 'solid', width: 1 },\n handles: { shape: 'square', size: 8, hitSize: 24, fill: '#ffffff', stroke: null },\n rotationHandle: {\n enabled: true,\n size: 10,\n hitSize: 24,\n offset: 32,\n stalk: true,\n fill: null,\n stroke: null,\n },\n guides: { enabled: true, color: '#e91e63', rotationColor: null, style: 'solid', width: 1.5 },\n marquee: { fill: null, stroke: null },\n textOutline: null,\n readout: { enabled: true, background: 'rgb(0 0 0 / 0.8)', color: '#ffffff' },\n },\n snap: {\n alignment: true,\n alignmentThreshold: 6,\n rotation: true,\n rotationAngles: [0, 90, 180, 270],\n rotationThreshold: 4,\n },\n editable: true,\n};\n\n/** What `annotationPlugin(config)` takes: any of the settings, merged over the defaults. */\nexport type AnnotationConfig = DeepPartial<AnnotationSettings>;\n\n// ── what the capability hands out ────────────────────────────────────────────\n\n/**\n * The armed stamp's ghost: its image, see-through, in the box a click at the\n * pointer would place it in (page space). Every other tool's ghost paints\n * with the page's items (`source: 'ghost'`).\n */\nexport interface ImageGhost {\n page: PageRef;\n /** The box the stamp's placement would use, before its turn. */\n box: Rect;\n /** The tool's upright turn at this hover (degrees clockwise). */\n rot: number;\n /** How opaque it paints (0–1); `--epdf-ghost-opacity` wins over it. */\n opacity: number;\n}\n\n/**\n * One clickable link area on a page (page space): a standalone link\n * annotation, or one segment of a parent's attached link. See\n * {@link AnnotationHostCapability.listLinkItems}.\n */\nexport interface LinkNavItem {\n /** Stable per-page key: the annot id, `#n`-suffixed for attached segments. */\n id: string;\n /** The clickable area in page space. */\n bounds: Rect;\n target: PdfLinkTarget;\n /**\n * True for a link child riding an editable annotation (an `/RT /Group`\n * subordinate): a property of its parent while authoring, a nav behavior\n * only while reading. The nav layer stands its anchors down for attached\n * items whenever the active tool enables `annotation-edit`, so the parent\n * stays selectable/movable; standalone document links navigate regardless.\n */\n attached: boolean;\n /** The full payload-carrying `/A` tree, when one exists: the action\n * engine's dispatch input. `target` remains its root projection. */\n activate?: PdfActionTree;\n /** The annotation ref, carried for ActionSource context. */\n ref?: AnnotationRef;\n /** Which `/AA` hover trees this link carries: the nav layer's pump flags\n * (tree-less hover must cost zero dispatches). Links are behavior-inert\n * to the annotation plane's hover feed while navigable, so their\n * cursorEnter/cursorExit can only fire from the LinkLayer anchors. */\n hoverEvents?: { enter: boolean; exit: boolean };\n}\n\n/**\n * A plugin (forms, links) or an interactive renderer marks some annotations as\n * interactive: while engaged, they render their own DOM, take the pointer and\n * are not geometry-editable. Not engaged, they are edited like any other.\n */\nexport interface Behavior {\n id: string;\n /** Whether this behavior is about the annotation at all. */\n matches(annotation: Annotation): boolean;\n /** Whether it owns the annotation now (read live: the active tool, the app's mode). */\n engaged(annotation: Annotation): boolean;\n}\n\n/**\n * What a style panel shows: the {@link AnnotationProperty}s in display order,\n * their current `values` by key, and which differ across the selection\n * (`mixed`, shown as \"mixed\").\n *\n * For the selection, the properties are the ones every selected kind has (a\n * mixed selection shows the shared ones, in the first kind's order), and the\n * values the first member's; empty `properties` means nothing is selected. For\n * a tool, they are its kind's, with its defaults over the engine's. The\n * border's value is three keys (`borderStyle`, `dashArray`,\n * `cloudyIntensity`); a text's font, size, colour and alignment read as the\n * text shows (a free text's `fontColor` follows its `color` when it has none).\n */\nexport interface AnnotationProperties {\n readonly properties: readonly AnnotationProperty[];\n readonly values: FieldValues;\n readonly mixed: readonly string[];\n}\n\n/**\n * A free-text annotation projected for the framework: the box (page space,\n * live gesture applied) + the plain text + an `editing` flag + a ready-to-spread\n * CSS style. The framework renders one editable element from this and nothing\n * more: all the mapping (fonts, colours, alignment) is done here, once. The\n * element paints the text only: the box's fill and border are the vector\n * scene's (`listPageItems`), the same for a plain box and a callout, so the\n * live view matches the baked appearance.\n */\nexport interface TextItem {\n id: string;\n ref: AnnotationRef | null;\n box: Rect;\n contents: string;\n /** The rich paragraphs the editor renders and edits (run deltas over the\n * body, which `css` carries). `contents` is their plain projection. */\n richText: { paragraphs: RichTextParagraph[] };\n editing: boolean;\n /** Applied rotation (deg, CW). `box` is the unrotated text box; the framework\n * rotates the editable element about its centre by this. 0/undefined = none. */\n rot?: number;\n css: {\n fontFamily: string;\n /** Content units (the framework multiplies by the page scale). The line\n * height is not here: the editor binding states the engine's line model\n * per face on the element itself (`@embedpdf/web`, `lineModelFor`). */\n fontSize: number;\n color: string;\n /** The body's formatting (runs override it as inline spans). */\n fontWeight: number;\n fontStyle: 'normal' | 'italic';\n textDecoration: 'none' | 'underline';\n align: 'left' | 'center' | 'right';\n padding: number;\n };\n}\n\n/** What `comments.deleteThread()` did: everything went, or nothing did and `failed` says why. */\nexport interface ThreadDeleteResult {\n deleted: AnnotationRef[];\n failed: Array<{ ref: AnnotationRef; error: unknown }>;\n}\n\n/** The public shape of a tool: a named preset over a kind. */\nexport interface AnnotationTool {\n readonly id: string;\n readonly subtype: KindName;\n /** The defaults key this tool reads and writes. */\n readonly preset: string;\n readonly cursor: string;\n readonly enables: readonly string[];\n readonly defaults?: FieldValues;\n /** The tool's ghost, what a click would place following the pointer: how opaque it paints, or `false`. */\n readonly ghost: ResolvedGhost;\n /** Your own data from the tool's definition, such as a label and an icon. */\n readonly meta?: Readonly<Record<string, unknown>>;\n}\n\n/** A polygon or polyline being drawn: where it is, how many points it has, and whether it can end. */\nexport type CreationDraft = CreationDraftAnchor;\n\n/** A turn in progress: its page, the pointer there, and the angle so far (degrees clockwise). */\nexport type AnnotationRotationAnchor = RotationAnchor;\n\n/** Where a menu attaches to the selection: its page and the box around it (page space). */\nexport interface AnnotationSelectionAnchor {\n readonly page: PageRef;\n readonly bounds: Rect;\n /** The rotation handle's middle, so a menu can stay clear of it; absent without one. */\n readonly rotationHandle?: Point;\n}\n\n/** Where UI attaches to one annotation: its page and the box around what it shows (page space). */\nexport interface AnnotationAnchor {\n readonly page: PageRef;\n readonly bounds: Rect;\n /**\n * For an annotation that keeps its size or stays upright on screen (a note):\n * the box in a given view, where `bounds` is the box at 100%. `<Anchored>`\n * calls it, so the anchor doesn't change while people zoom. Absent for\n * every other annotation.\n */\n readonly boundsIn?: (view: ViewEnv) => Rect | null;\n}\n\n// ── events ───────────────────────────────────────────────────────────────────\n\n/** An annotation was added: the engine's record, whoever added it. */\nexport interface AnnotationCreatedEvent {\n readonly annotation: Annotation;\n readonly origin: EventOrigin;\n}\n\n/** An annotation was changed: the engine's record after the change. */\nexport interface AnnotationUpdatedEvent {\n readonly annotation: Annotation;\n readonly origin: EventOrigin;\n}\n\n/** Annotations were deleted: one, and what went with it (its popup, replies and review states). */\nexport interface AnnotationDeletedEvent {\n /** Everything that went, the annotation first. */\n readonly refs: readonly AnnotationRef[];\n readonly page: PageRef;\n readonly origin: EventOrigin;\n}\n\n/** The drawing order on a page changed: `order` is the page's annotations, bottom to top. */\nexport interface AnnotationReorderedEvent {\n readonly page: PageRef;\n readonly order: readonly AnnotationRef[];\n readonly origin: EventOrigin;\n}\n\n/** Annotations were read again (a document opening, a page re-read): not a list of creates. */\nexport interface AnnotationResyncedEvent {\n readonly pages: readonly PageRef[] | 'all';\n}\n\n/**\n * The engine refused a change the user made (a revoked grant, a lock set\n * elsewhere). The change is already gone from the view, which shows the\n * engine's record again; this says why, so a UI can tell the user.\n */\nexport interface AnnotationWriteFailedEvent {\n /** The existing annotations the refused write carried; empty for a refused create. */\n readonly refs: readonly AnnotationRef[];\n readonly error: PluginErrorInfo;\n}\n\n/** The selection changed. */\nexport interface AnnotationSelectionChangedEvent {\n readonly refs: readonly AnnotationRef[];\n readonly previousRefs: readonly AnnotationRef[];\n}\n\n/** A polygon or polyline started, got a point, or ended. */\nexport interface AnnotationDraftChangedEvent {\n readonly draft: CreationDraft | null;\n}\n\n/** Typing in a text box started (`ref`) or ended (`null`). */\nexport interface AnnotationEditingChangedEvent {\n readonly ref: AnnotationRef | null;\n}\n\n/** The pointer moved onto an annotation (`ref`), or off it (`null`). */\nexport interface AnnotationHoverChangedEvent {\n readonly ref: AnnotationRef | null;\n}\n\n/** A tool's defaults changed, from your UI or your code. */\nexport interface ToolDefaultsChangedEvent {\n readonly toolId: string;\n /** The tool's defaults now, as `tools.getDefaults(toolId)` returns them. */\n readonly defaults: ToolDefaults;\n}\n\n/** A thread changed through this viewer. */\nexport interface CommentThreadChangedEvent {\n readonly rootRef: AnnotationRef;\n readonly change: 'reply' | 'text' | 'status' | 'marked' | 'deleted';\n}\n\n/** Which annotations `list()` returns: every field narrows. */\nexport interface AnnotationFilter {\n /** Only these pages, as refs or indexes. */\n readonly pages?: readonly (PageRef | number)[];\n readonly subtype?: AnnotationSubtype;\n}\n\n/** What `import()` did: the new annotations, where each bundle ref went, and what was left out. */\nexport interface AnnotationImportResult {\n /** The new annotations, in bundle order. */\n readonly annotations: readonly Annotation[];\n /** Each imported annotation's ref in the bundle, and its new ref here. */\n readonly refMap: ReadonlyArray<{ readonly from: AnnotationRef; readonly to: AnnotationRef }>;\n /** What was left out, and why, in bundle order. */\n readonly dropped: readonly AnnotationImportDrop[];\n}\n\n/** Which annotations `export()` takes. */\nexport interface AnnotationExportSelection {\n /** These annotations, with what they point at and their replies. */\n readonly refs?: readonly AnnotationRef[];\n /** Every annotation on these pages, as refs or indexes. */\n readonly pages?: readonly (PageRef | number)[];\n}\n\n// ── the nouns ────────────────────────────────────────────────────────────────\n\n/** The selection: what is selected, and the verbs that change it as one. */\nexport interface AnnotationSelectionApi {\n /** Select these annotations; an annotation in a group brings its group. */\n set(refs: readonly AnnotationRef[]): void;\n /** Add these annotations to the selection, with their groups. */\n add(refs: readonly AnnotationRef[]): void;\n /** Select everything that can be selected, on one page or in the whole document. */\n selectAll(page?: PageRef | number): void;\n /**\n * Select everything a box on a page touches of what it paints (its lines,\n * or the inside of a filled shape), with the rest of each one's group, as\n * dragging on empty space does. Throws `not-found` for a page that isn't\n * in the document.\n */\n selectInRect(page: PageRef | number, rect: Rect): void;\n /** Clear the selection. */\n clear(): void;\n /** The selected annotations, as the user sees them. */\n list(): readonly Annotation[];\n /**\n * Change the selected annotations: each takes the fields its kind has, and\n * skips the rest. A function changes each relative to itself. While words\n * are selected in a text box being typed in, its font, size, colour and\n * formats change those words. Resolves once the engine wrote every change,\n * with what it refused in `failed`.\n */\n update(\n changes: AnnotationPatch | ((annotation: Annotation) => AnnotationPatch),\n options?: OperationOptions,\n ): Promise<BatchResult<AnnotationRef, AnnotationRef>>;\n /** Link the selected annotations to a page or a website, or remove their links with `null`. */\n updateLink(\n target: PdfLinkTarget | null,\n options?: OperationOptions,\n ): Promise<BatchResult<AnnotationRef, AnnotationRef>>;\n /** What a style panel shows for the selection. The same object while nothing changes. */\n getProperties(): AnnotationProperties;\n /** Delete every selected annotation. */\n delete(options?: OperationOptions): Promise<BatchResult<AnnotationRef, AnnotationRef>>;\n /** Turn the selection a quarter turn: `90` clockwise, `-90` the other way. */\n rotateBy(degrees: 90 | -90, options?: OperationOptions): Promise<void>;\n /** Turn the selection upright again. */\n resetRotation(options?: OperationOptions): Promise<void>;\n /** Make the selected annotations one group, saved the way Acrobat saves it. */\n group(options?: OperationOptions): Promise<void>;\n /** Split the selected groups up again. */\n ungroup(options?: OperationOptions): Promise<void>;\n /** Whether the selection can be grouped: two or more on one page, each changeable. */\n canGroup(): boolean;\n /** Whether the selection holds a group that can be split. */\n canUngroup(): boolean;\n /**\n * Where a menu attaches: the selection's page and the box around it, or\n * `null` with nothing selected, or while a gesture moves, resizes or turns it.\n */\n getAnchor(): AnnotationSelectionAnchor | null;\n /** While the selection is being turned: the pointer's point and the angle so far, or `null`. */\n getRotationAnchor(): AnnotationRotationAnchor | null;\n}\n\n/** A polygon or polyline being drawn, a click per point. */\nexport interface AnnotationDraftApi {\n /** The shape being drawn, or `null`. */\n get(): CreationDraft | null;\n /** End the shape and create it, as a double-click does. Resolves `null` when there was none to make. */\n finish(options?: OperationOptions): Promise<{ annotation: Annotation } | null>;\n /** Drop the shape being drawn. */\n cancel(): void;\n}\n\n/** Typing in a text box. */\nexport interface AnnotationTextApi {\n /** Start typing in a text box, as a double-click does. */\n begin(ref: AnnotationRef): void;\n /** Stop typing, and save what was typed. */\n end(options?: OperationOptions): Promise<void>;\n /** The text box being typed in, or `null`. */\n getEditing(): Annotation | null;\n /** Bold, italic or underline on or off: for the selected words, or the whole of each selected box. */\n toggleFormat(format: TextFormat, options?: OperationOptions): Promise<void>;\n}\n\n/** The tools: what a click or a drag creates, with which defaults. */\nexport interface AnnotationToolsApi {\n /** Every tool, the built-in ones and yours. */\n list(): readonly AnnotationTool[];\n /** One tool, or `null`. */\n get(id: string): AnnotationTool | null;\n /** Add a tool while the app runs, or replace the one with the same id. Returns a function that removes it. */\n register(tool: AnnotationToolInput): Unsubscribe;\n /** The fields a tool's next annotation starts with: its defaults over the engine's. The same object until they change. */\n getDefaults(id: string): ToolDefaults;\n /**\n * Change a tool's defaults for the drawings that follow: each value whole,\n * as in a patch. They stay in this viewer. Fires `onDefaultsChanged`.\n */\n updateDefaults(id: string, changes: FieldValues): void;\n /** What a style panel for the tool shows, the same shape as `selection.getProperties()`. */\n getProperties(id: string): AnnotationProperties;\n /** A tool's defaults changed. */\n readonly onDefaultsChanged: EventHook<ToolDefaultsChangedEvent>;\n}\n\n/** A stamp's bytes, to arm for a click or to place from code. */\nexport interface StampInput {\n /** PNG, JPEG, or one-page PDF bytes (`Blob | Uint8Array | BinaryPayload`). */\n source: BinarySource;\n /** Placed width in PDF points (height follows the picture). Default: the picture's own width. */\n targetWidth?: number;\n /** The placed annotation's `/Name`: the stamp identifier (standard or custom). */\n name?: string;\n /** The placed annotation's `/Subj`. */\n subject?: string;\n /**\n * The hover ghost's image. Either fixed bytes (PNG/JPEG) or, for vector\n * sources, which are only right at one size on screen, a\n * {@link StampPreviewProvider} the ghost asks for a render at the device\n * pixel width it shows at. Raster sources default to themselves; without\n * one a PDF source shows no ghost.\n */\n preview?: BinarySource | StampPreviewProvider;\n /**\n * The source's own size in PDF points. Raster sources are measured from\n * their header, but PDF bytes carry no size a sniff can read: a caller that\n * knows it (a stamp library does) passes it here so placement keeps the\n * picture's aspect.\n */\n intrinsicSize?: { width: number; height: number };\n}\n\n/** Where `stamps.place()` puts a stamp, without a click. */\nexport interface StampPlacement {\n /** The page, as a ref or an index. */\n page: PageRef | number;\n /** Where its middle goes, in page space. The size comes from the picture. */\n center: Point;\n /** Placed width in PDF points; default the picture's own (or the stamp's `targetWidth`). */\n targetWidth?: number;\n /** Its turn, degrees clockwise. Default 0. */\n rotation?: number;\n /** Select it, as placing it with a click would. Default false: code never changes the selection. */\n select?: boolean;\n}\n\n/** Stamps placed from bytes: armed for the next click, or placed from code. */\nexport interface AnnotationStampsApi {\n /**\n * Arm a stamp's bytes so the next click places them, as the `stamp` tool\n * does after picking a file. Rejects `invalid-input` for bytes that aren't\n * PNG, JPEG or a one-page PDF.\n */\n arm(stamp: StampInput, options?: OperationOptions): Promise<void>;\n /** Disarm the stamp. */\n disarm(): void;\n /** Whether a stamp is armed. */\n isArmed(): boolean;\n /**\n * Place a stamp's bytes with its middle on `center`, sized by its picture\n * and kept on the page, as a click would. Resolves `{ annotation }`.\n * Rejects `permission-denied` without `annotations:create`, `not-found` for\n * a page that isn't in the document, `invalid-input` for bytes that aren't\n * a picture.\n */\n place(\n stamp: StampInput,\n placement: StampPlacement,\n options?: OperationOptions,\n ): Promise<{ annotation: Annotation }>;\n}\n\n/** Links attached to annotations (a link child), or a link annotation's own target. */\nexport interface AnnotationLinksApi {\n /** Where an annotation links to, or `null`. */\n get(ref: AnnotationRef): PdfLinkTarget | null;\n /** Link an annotation to a page or a website. */\n set(ref: AnnotationRef, target: PdfLinkTarget, options?: OperationOptions): Promise<void>;\n /** Remove an annotation's link. */\n clear(ref: AnnotationRef, options?: OperationOptions): Promise<void>;\n}\n\n/**\n * Comments and replies: threads over the annotations. Every verb is a plain\n * annotation create, change or delete, so other people's changes, this\n * viewer's and reloads all show in `listThreads()`.\n */\nexport interface CommentsApi {\n /** Every thread, in reading order: by page, then from the top of the page. */\n listThreads(): readonly CommentThread[];\n /** The thread a comment is in (its first comment, a reply or a review state), or `null`. */\n getThread(ref: AnnotationRef): CommentThread | null;\n /**\n * Reply to the thread's first comment, whichever comment you pass.\n * Resolves `{ annotation }`. Rejects `permission-denied` without\n * `annotations:create`.\n */\n reply(\n ref: AnnotationRef,\n text: string,\n options?: OperationOptions,\n ): Promise<{ annotation: Annotation }>;\n /** Change a comment's text. Rejects `permission-denied` when `canSetText(ref)` is false. */\n setText(ref: AnnotationRef, text: string, options?: OperationOptions): Promise<void>;\n /** Set the user's review state on a thread, such as `'accepted'`. */\n setStatus(ref: AnnotationRef, state: string, options?: OperationOptions): Promise<void>;\n /** Check a thread off for the user, or clear the check mark. */\n setMarked(ref: AnnotationRef, marked: boolean, options?: OperationOptions): Promise<void>;\n /** Delete a comment with its replies; the first comment of a thread deletes the thread. */\n delete(ref: AnnotationRef, options?: OperationOptions): Promise<void>;\n /** Delete a whole thread, all of it or none. */\n deleteThread(ref: AnnotationRef, options?: OperationOptions): Promise<ThreadDeleteResult>;\n /** Whether the user may reply to this thread (`annotations:create`). */\n canReply(ref: AnnotationRef): boolean;\n /** Whether the user may change this comment's text (`annotations:update`, and not `lockedContents`). */\n canSetText(ref: AnnotationRef): boolean;\n /** Whether the user may set a review state on this thread (`annotations:create`). */\n canSetStatus(ref: AnnotationRef): boolean;\n /** Whether the user may check this thread off (`annotations:create`). */\n canSetMarked(ref: AnnotationRef): boolean;\n /** Whether the user may delete this comment (`annotations:delete`, and not `locked`). */\n canDelete(ref: AnnotationRef): boolean;\n /** Whether the user may delete every comment in this thread. */\n canDeleteThread(ref: AnnotationRef): boolean;\n /** A thread changed through this viewer: a reply, a text, a review state, a check mark or a delete. */\n readonly onThreadChanged: EventHook<CommentThreadChangedEvent>;\n}\n\n// ── the capability ───────────────────────────────────────────────────────────\n\n/**\n * The annotation API: the documented, stable surface for application code.\n * Resolve it with the token re-exported from the package root\n * (`@embedpdf/plugin-annotation`). Framework-only plumbing lives on\n * {@link AnnotationHostCapability} in `@embedpdf/plugin-annotation/contract/host`.\n */\nexport interface AnnotationCapability extends SettingsApi<AnnotationSettings> {\n // ── reading: the engine's records, with this session's pending changes on them ──\n /**\n * The annotation as the user sees it: the engine's record with any change\n * the user made applied, as the engine will apply it. A new annotation shows\n * before the engine confirms it, under the `nm` ref it was created with.\n */\n get(ref: AnnotationRef): Annotation | null;\n /** Every annotation in drawing order, or the ones on some pages or of one kind. */\n list(filter?: AnnotationFilter): readonly Annotation[];\n /**\n * The topmost annotation at a point on a page, or `null`. A selected\n * annotation's handles count as the annotation. A page that isn't in the\n * document has none.\n */\n getAt(page: PageRef | number, point: Point): Annotation | null;\n /** Whether a change the user made to it waits for the engine. */\n isPending(ref: AnnotationRef): boolean;\n /** `loading` until the document's annotations are in, then `ready`; `forbidden` or `error` when they can't load. */\n getStatus(): ResourceStatus;\n /** The annotation under the pointer, or `null`. */\n getHovered(): Annotation | null;\n /** Read every annotation from the engine again. */\n refresh(options?: OperationOptions): Promise<void>;\n\n // ── creating, changing and deleting, in the engine's own terms ──\n /**\n * Create an annotation from its kind and fields: what they leave out takes\n * the `tool`'s defaults when one is named, then the engine's. Bytes travel\n * beside them (a stamp's `appearance`, a file attachment's `file`). It\n * shows at once; resolves `{ annotation }` with the engine's record.\n * `select` selects it, as drawing it would; without it, code never changes\n * the selection. A read of another annotation makes the same one again (a\n * copy): its own fields are written, and where it is comes from `page`.\n * Rejects `permission-denied` without `annotations:create`, `not-found` for\n * a page that isn't in the document or an unknown `tool`, `invalid-input`\n * for a kind the engine doesn't know or a value a write can't make (another\n * app's beveled border).\n */\n create(\n page: PageRef | number,\n draft: AnnotationDraft | Annotation,\n resources?: AnnotationResources,\n options?: OperationOptions & { tool?: string; select?: boolean },\n ): Promise<{ annotation: Annotation }>;\n /**\n * What a text tool makes of the selected text, one annotation per page: a\n * highlight, underline, strikeout or squiggly line, an insertion caret, a\n * replacement or a redaction mark. Resolves `{ annotations }` (empty\n * without a text selection). The text selection is cleared afterwards\n * unless `clear` is `false`. Rejects `permission-denied` without\n * `annotations:create`, `not-found` for a tool that makes nothing of\n * selected text.\n */\n createFromSelection(\n tool: string,\n options?: OperationOptions & { clear?: boolean },\n ): Promise<{ annotations: readonly Annotation[] }>;\n /**\n * Change the fields the patch names, as given: the engine works out what\n * follows (a free text's body from its font, a measurement's label from its\n * points, a drawn kind's shape from a new `rect`). New bytes replace what\n * they are for. It shows at once; resolves `{ annotation }` with the\n * engine's record. Rejects `not-found` for an annotation that isn't here.\n */\n update(\n ref: AnnotationRef,\n patch: AnnotationPatch,\n resources?: AnnotationResources,\n options?: OperationOptions,\n ): Promise<{ annotation: Annotation }>;\n /** Delete an annotation, with its popup and its replies. Fires `onDeleted`. */\n delete(ref: AnnotationRef, options?: OperationOptions): Promise<void>;\n /**\n * Change the drawing order on one page: the annotations go together, in\n * the order given, right after or before a neighbour annotation of the page\n * (`{ after: ref }`, `{ before: ref }`), or to the bottom (`'start'`) or the\n * top (`'end'`). Shows at once; fires `onReordered`. Rejects `invalid-input`\n * for refs on different pages and `not-found` for a neighbour that isn't\n * there. Widgets paint above every annotation and are ordered by the form.\n */\n reorder(\n refs: readonly AnnotationRef[],\n position: AnnotationPosition,\n options?: OperationOptions,\n ): Promise<void>;\n /**\n * Take annotations out as a bundle, with the bytes they carry (a stamp's\n * drawing, an attached file): every annotation, a selection of them (with\n * what they point at and their replies), or some pages'. Waits for pending\n * changes first. Rejects `permission-denied` without `doc.download`.\n */\n export(\n selection?: AnnotationExportSelection,\n options?: OperationOptions,\n ): Promise<AnnotationBundle>;\n /**\n * Put a bundle's annotations into this document, as one change: they show\n * once it's done. Resolves `{ annotations, refMap, dropped }`. Rejects\n * `permission-denied` without `annotations:create` (and, for the default\n * `attribution: 'restore'`, `doc.annotate.import`).\n */\n import(\n bundle: AnnotationBundle,\n options?: AnnotationImportOptions & OperationOptions,\n ): Promise<AnnotationImportResult>;\n /**\n * Download a stamp's drawing (`'appearance'`) or an attachment's file\n * (`'file'`): the bytes `create()` takes to make it again. Rejects\n * `permission-denied` without `doc.download`, `not-found` for an annotation\n * that isn't here, `invalid-input` for a role its kind doesn't have.\n */\n downloadResource(\n ref: AnnotationRef,\n role: AnnotationResourceRole,\n options?: OperationOptions,\n ): Promise<Uint8Array>;\n\n // ── the nouns ──\n readonly links: AnnotationLinksApi;\n readonly selection: AnnotationSelectionApi;\n readonly draft: AnnotationDraftApi;\n readonly text: AnnotationTextApi;\n readonly tools: AnnotationToolsApi;\n readonly stamps: AnnotationStampsApi;\n readonly comments: CommentsApi;\n\n // ── ports and checks ──\n /**\n * Set the function that gives the `stamp` and `attachment` tools their\n * file, `null` to make them do nothing. Returns a function that removes it.\n */\n setFilePickerProvider(provider: FilePickerProvider | null): Unsubscribe;\n /** Whether the user may see annotations (`doc.annotate.read`). */\n canRead(): boolean;\n /** Whether the user may create annotations (`annotations:create`). */\n canCreate(): boolean;\n /** Whether the user may change this annotation: its permission and its own `locked` flag. */\n canUpdate(ref: AnnotationRef): boolean;\n /** Whether the user may delete this annotation: its permission and its own `locked` flag. */\n canDelete(ref: AnnotationRef): boolean;\n /**\n * Whether the `editable` setting lets people change this annotation by\n * hand; `false` for one the document doesn't have. Whether a change would\n * succeed is `canUpdate()` and `canDelete()`.\n */\n isEditable(ref: AnnotationRef): boolean;\n /** Stop a drag, or a polygon in progress. */\n cancel(): void;\n\n // ── events ──\n /** An annotation was added, once the engine saved it. */\n readonly onCreated: EventHook<AnnotationCreatedEvent>;\n /** An annotation was changed, once the engine saved it. */\n readonly onUpdated: EventHook<AnnotationUpdatedEvent>;\n /** Annotations were deleted: one, plus its popup and replies. */\n readonly onDeleted: EventHook<AnnotationDeletedEvent>;\n /** The drawing order on a page changed. */\n readonly onReordered: EventHook<AnnotationReorderedEvent>;\n /** Annotations were read again, as after loading a document. */\n readonly onResynced: EventHook<AnnotationResyncedEvent>;\n /** The engine refused a change the user made; the view already shows the engine's record again. */\n readonly onWriteFailed: EventHook<AnnotationWriteFailedEvent>;\n /** The selection changed. */\n readonly onSelectionChanged: EventHook<AnnotationSelectionChangedEvent>;\n /** A polygon or polyline is being drawn, or ended. */\n readonly onDraftChanged: EventHook<AnnotationDraftChangedEvent>;\n /** Typing in a text box started or ended. */\n readonly onEditingChanged: EventHook<AnnotationEditingChangedEvent>;\n /** The pointer moved onto an annotation, or off it. */\n readonly onHoverChanged: EventHook<AnnotationHoverChangedEvent>;\n}\n\nexport type MarkupSubtype = 'highlight' | 'underline' | 'strikeout' | 'squiggly';\n\n/** The armed stamp: its placement size and identity. */\nexport interface ArmedStampInfo {\n /** Placement size in PDF points. */\n readonly width: number;\n readonly height: number;\n readonly name?: string;\n readonly subject?: string;\n}\n\n/** The armed stamp's paintable preview, for the render layer's ghost `<img>`. */\nexport interface ArmedStampPreview {\n bytes: Uint8Array;\n mimeType?: string;\n}\n\n/**\n * Resolution-aware ghost preview: \"give me this stamp at `devicePixelWidth`\n * pixels wide\". The annotation plugin buckets the request (see\n * `previewBucket`) and caches per bucket for the arm's lifetime, so a zoom\n * gesture never renders per frame and one render serves a zoom range. A stamp\n * library renders its page lazily through its asset engine; a raster returns\n * itself (it cannot get sharper than its pixels).\n */\nexport type StampPreviewProvider = (devicePixelWidth: number) => Promise<ArmedStampPreview | null>;\n\n/**\n * What the {@link FilePickerProvider} is asked for: which tool clicked (id +\n * the kind it creates), the tool's `accept` filter, and the page-space point\n * the click landed on: enough to route per tool (asset library for stamps,\n * cloud drive for attachments) or position a picker near the click. Plain\n * data: the request crosses the plugin↔adapter boundary as a message.\n */\nexport interface FilePromptRequest {\n toolId: string;\n /** The kind the placement creates: the routing key for per-tool pickers. */\n subtype: KindName;\n /** The tool's file-dialog filter hint (from the tool def). UX only:\n * the engine sniffs and validates the bytes. */\n accept?: string;\n page: PageRef;\n /** The page-space point the placement is centred on. */\n point: Point;\n}\n\n/**\n * The one environment port behind every click-then-pick tool (the stamp\n * `'prompt'` source and the file-attachment tool, whose file is picked after\n * the spot): given a click, produce the file to place, `null` to cancel. The\n * plugin declares this contract but never implements it: a file dialog is a\n * DOM concern, so the framework adapter installs the implementation via\n * {@link AnnotationCapability.setFilePickerProvider}. The return shape is the\n * engine's file vocabulary: a stamp takes only `data`; an attachment embeds\n * the whole thing. A picked `File` carries its own name and type; a provider\n * returning raw bytes for an attachment must supply `name` itself.\n */\nexport type FilePickerProvider = (\n request: FilePromptRequest,\n) => Promise<AttachmentFileSource | null>;\n"],"mappings":";;;;;;AAMA,MAAa,mBAAA,GAAA,eAAA,sBAAA,CAA8D,cAAc;CACvF,MAAM;CAGN,UAAU;EACR,SAAS;EACT,QAAQ;EACR,qBAAqB;EACrB,QAAQ;EACR,QAAQ;EACR,SAAS;EACT,QAAQ;EACR,QAAQ;EACR,kBAAkB;EAClB,aAAa;EACb,eAAe;EACf,oBAAoB;EACpB,wBAAwB;EACxB,oBAAoB;EACpB,sBAAsB;EACtB,2BAA2B;EAC3B,mBAAmB;EACnB,qBAAqB;EACrB,gBAAgB;EAChB,YAAY;EACZ,qBAAqB;EACrB,cAAc;EACd,gBAAgB;EAChB,kBAAkB;EAClB,oBAAoB;EACpB,sBAAsB;EACtB,sBAAsB;EACtB,mBAAmB;EACnB,yBAAyB;CAC3B;AACF,CAAC;;;;;;;;;AC/BD,MAAa,mBAAA,GAAA,eAAA,YAAA,CAA8B,iBAAiB;CAC1D,OAAO,gBAAgB;EACrB,QAAQ,WAAW,UAAU;EAC7B,UAAU,WAAW,UAAU,KAAK;EACpC,SAAS,WAAW,WAAW;EAC/B,SAAS,WAAW,KAAK,WAAW;CACtC;CACA,OAAO;EAAE,QAAQ;EAAW,UAAU,CAAC;EAAG,SAAS;EAAM,SAAS;CAAK;AACzE,CAAC;;;;;;;;;;;AC8CD,MAAa,sBAAsB;;AAuBnC,MAAa,gBAAgB;;AAG7B,MAAM,gBAAgB,UACpB,UAAU,OAAO,EAAE,SAAS,cAAc,IAAI;;;;;;AAehD,MAAM,eAAe;CACnB;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;AACF;AAGA,MAAM,oBAAoB;CAAC;CAAS;CAAiB;CAAe;AAAa;AACjF,MAAM,qBAAqB;CACzB,GAAG;CACH;CACA;CACA;CACA;AACF;;AAGA,MAAM,iBAAiB,YACrBA,8BAAAA,uBAAuB,QAAQ,CAAC,QAC7B,SAAS,CAAE,aAAmC,SAAS,IAAI,CAC9D;;;;;;AAOF,MAAa,sBAAsB;CACjC,QAAQ,cAAc,QAAQ;CAC9B,QAAQ,cAAc,QAAQ;CAC9B,MAAM,cAAc,MAAM;CAC1B,SAAS,cAAc,SAAS;CAChC,UAAU,cAAc,UAAU;CAClC,KAAK,cAAc,KAAK;CACxB,aAAa,cAAc,WAAW;CACtC,qBAAqB,cAAc,WAAW;CAC9C,WAAW,cAAc,WAAW;CACpC,WAAW,cAAc,WAAW;CACpC,WAAW,cAAc,WAAW;CACpC,UAAU,cAAc,UAAU;CAClC,OAAO,cAAc,OAAO;CAC5B,QAAQ,cAAc,QAAQ;CAC9B,OAAO,cAAc,OAAO;CAC5B,MAAM,cAAc,MAAM;CAC1B,MAAM,cAAc,MAAM;CAC1B,mBAAmB,cAAc,iBAAiB;CAIlD,eAAe;CACf,iBAAiB;CACjB,iBAAiB;CACjB,iBAAiB;CACjB,gBAAgB;CAGhB,cAAc;AAChB;;;;;;AAsNA,MAAM,gCAAqC,IAAI,IAAI,CAAC,WAAW,CAAC;AAGhE,MAAM,YAAY,CAAC,mBAAmB,iBAAiB;;AAEvD,MAAM,YAAY;AAClB,MAAM,cAAc,CAAC,eAAe,iBAAiB;;;;;;;;;;AAWrD,MAAa,eAAe,YAC1B,QAAQ,IAAI,iBAAiB,KAAK,QAAQ,IAAI,aAAa,IAAI,SAAS;;;;;;AAO1E,MAAa,gBAAuC;CAKlD;EACE,IAAI;EACJ,SAAS;EACT,QAAQ;EACR,SAAS;EACT,UAAU;GAAE,OAAO;GAAW,aAAa;EAAE;EAE7C,aAAa;GAAE,OAAO;GAAI,QAAQ;EAAG;EACrC,SAAS;CACX;CACA;EACE,IAAI;EACJ,SAAS;EACT,QAAQ;EACR,SAAS;EACT,UAAU;GAAE,OAAO;GAAW,aAAa;EAAE;EAE7C,aAAa;GAAE,OAAO;GAAI,QAAQ;EAAG;EACrC,SAAS;CACX;CACA;EACE,IAAI;EACJ,SAAS;EACT,QAAQ;EACR,SAAS;EACT,UAAU;GAAE,OAAO;GAAW,aAAa;EAAE;EAE7C,aAAa,EAAE,QAAQ,GAAG;EAC1B,SAAS;CACX;CACA;EACE,IAAI;EACJ,SAAS;EACT,aAAa;EACb,UAAU;GACR,QAAQ;GACR,aAAa;GACb,aAAa;IAAE,OAAO;IAAgB,KAAK;GAAe;GAC1D,gBAAgB;GAChB,iBAAiB;GACjB,QAAQ;IAAE,QAAQ;IAAI,WAAW;IAAG,QAAQ;GAAE;EAChD;CACF;CACA;EACE,IAAI;EACJ,SAAS;EACT,SAAS,CAAC,iBAAiB;EAC3B,UAAU,EAAE,aAAa,EAAE;EAC3B,aAAa;CACf;CACA;EACE,IAAI;EACJ,SAAS;EACT,QAAQ;EACR,SAAS;EACT,UAAU;GAAE,OAAO;GAAW,aAAa;EAAE;CAC/C;CACA;EACE,IAAI;EACJ,SAAS;EACT,QAAQ;EACR,SAAS;EACT,UAAU;GAAE,OAAO;GAAW,aAAa;EAAE;CAC/C;CACA;EACE,IAAI;EACJ,SAAS;EACT,UAAU;GACR,QAAQ;GACR,aAAa;GACb,aAAa;IAAE,OAAO;IAAQ,KAAK;GAAO;GAC1C,gBAAgB;EAClB;CACF;CACA;EACE,IAAI;EACJ,SAAS;EACT,UAAU;GAAE,QAAQ;GAAqB,aAAa;GAAG,gBAAgB;EAAK;CAChF;CACA;EACE,IAAI;EACJ,SAAS;EACT,QAAQ;EACR,SAAS;EACT,UAAU;GAAE,OAAO;GAAW,aAAa;GAAG,WAAW;EAAS;EAClE,KAAK,EAAE,gBAAgB,IAAI;CAC7B;CACA;EACE,IAAI;EACJ,SAAS;EACT,UAAU;GAAE,QAAQ;GAAiB,OAAO;GAAW,aAAa;GAAI,WAAW;EAAW;EAC9F,KAAK,EACH,YAAY;GAAE,oBAAoB;GAAM,iBAAiB;EAAG,EAC9D;CACF;CACA;EACE,IAAI;EACJ,SAAS;EACT,QAAQ;EACR,SAAS;EACT,UAAU;GAAE,OAAO;GAAW,aAAa;GAAG,WAAW;EAAU;EACnE,SAAS;EAGT,aAAa;GAAE,OAAO;GAAK,QAAQ;GAAI,QAAQ;EAAW;CAC5D;CACA;EAME,IAAI;EACJ,SAAS;EACT,QAAQ;EACR,SAAS;EACT,UAAU;GAAE,OAAO;GAAW,aAAa;GAAG,YAAY;EAAa;EACvE,SAAS;CACX;CAKA;EACE,IAAI;EACJ,SAAS;EACT,QAAQ;EACR,SAAS;EACT,UAAU;GAAE,OAAO;GAAW,WAAW;EAAW;EACpD,WAAW,EAAE,MAAM,SAAS;CAC9B;CAKA;EACE,IAAI;EACJ,SAAS;EACT,QAAQ;EACR,SAAS;GAAC;GAAe;GAAmB;EAAiB;EAC7D,UAAU;GACR,OAAO;GACP,eAAe;GACf,UAAU;GACV,WAAW;GACX,SAAS;EACX;EACA,WAAW,EAAE,MAAM,SAAS;CAC9B;CACA;EACE,IAAI;EACJ,SAAS;EACT,QAAQ;EACR,SAAS;EACT,UAAU,EAAE,OAAO,UAAU;EAC7B,WAAW,EAAE,MAAM,SAAS;CAC9B;CACA;EACE,IAAI;EACJ,SAAS;EACT,QAAQ;EACR,SAAS;EACT,UAAU,EAAE,OAAO,UAAU;EAC7B,WAAW,EAAE,MAAM,SAAS;CAC9B;CACA;EACE,IAAI;EACJ,SAAS;EACT,QAAQ;EACR,SAAS;EACT,UAAU,EAAE,OAAO,UAAU;EAC7B,WAAW,EAAE,MAAM,SAAS;CAC9B;CACA;EAGE,IAAI;EACJ,SAAS;EACT,YAAY;EACZ,QAAQ;EACR,QAAQ;EACR,SAAS;EACT,UAAU,EAAE,OAAO,UAAU;EAC7B,WAAW;GAAE,MAAM;GAAa,WAAW;EAAS;CACtD;CACA;EACE,IAAI;EACJ,SAAS;EACT,YAAY;EACZ,QAAQ;EACR,SAAS;EACT,UAAU,EAAE,OAAO,UAAU;EAC7B,WAAW;GAAE,MAAM;GAAa,WAAW;EAAU;CACvD;CAKA;EACE,IAAI;EACJ,SAAS;EACT,QAAQ;EACR,SAAS,CAAC,oBAAoB,iBAAiB;EAC/C,QAAQ;GAAE,MAAM;GAAU,QAAQ;EAAuC;EACzE,SAAS;EACT,OAAO;CACT;CAMA;EACE,IAAI;EACJ,SAAS;EACT,QAAQ;EACR,SAAS;CACX;CAKA;EACE,IAAI;EACJ,SAAS;EACT,QAAQ;EACR,SAAS,CAAC,oBAAoB,iBAAiB;EAC/C,UAAU;GAAE,MAAM;GAAW,OAAO;EAAU;EAC9C,OAAO;GAAE,QAAQ;GAAM,UAAU;EAAK;EACtC,SAAS;EACT,OAAO;CACT;CAMA;EACE,IAAI;EACJ,SAAS;EACT,QAAQ;EACR,SAAS,CAAC,oBAAoB,iBAAiB;EAC/C,QAAQ,EAAE,MAAM,SAAS;EACzB,UAAU;GAAE,MAAM;GAAa,OAAO;EAAU;EAChD,OAAO;GAAE,QAAQ;GAAM,UAAU;EAAK;EACtC,SAAS;EACT,OAAO;CACT;AACF;;AAGA,SAAS,cAAc,MAAoB,OAA8C;CACvF,OAAO,QAAQ,QAAQ;EAAE,GAAG;EAAM,GAAG;CAAM,IAAK,SAAS;AAC3D;;AAGA,SAAS,SAAS,MAAyB,MAA4C;CACrF,OAAO;EACL,GAAG;EACH,GAAG;EACH,SAAS,KAAK,WAAW,KAAK;EAC9B,MAAM,KAAK,QAAQ,KAAK,OAAO;GAAE,GAAG,KAAK;GAAM,GAAG,KAAK;EAAK,IAAI,KAAA;EAChE,UAAU,cAAc,KAAK,UAAU,KAAK,QAAQ;EACpD,OAAO,KAAK,SAAS,KAAK,QAAQ;GAAE,GAAG,KAAK;GAAO,GAAG,KAAK;EAAM,IAAI,KAAA;EACrE,KAAK,KAAK,OAAO,KAAK,MAAM;GAAE,GAAG,KAAK;GAAK,GAAG,KAAK;EAAI,IAAI,KAAA;EAC3D,aACE,KAAK,eAAe,KAAK,cACrB;GAAE,GAAG,KAAK;GAAa,GAAG,KAAK;EAAY,IAC3C,KAAA;CACR;AACF;AAEA,SAAS,iBAAiB,MAA0B;CAClD,IAAI,CAAC,KAAK,UAAU;CACpB,MAAM,UAAU,oBAAoB,KAAK;CAEzC,IAAI,CAAC,SAAS;CACd,MAAM,OAAO,IAAI,IAAY,OAAO;CACpC,KAAK,MAAM,OAAO,OAAO,KAAK,KAAK,QAAQ,GACzC,IAAI,CAAC,KAAK,IAAI,GAAG,GACf,MAAM,IAAI,MACR,sBAAsB,KAAK,GAAG,8BAA8B,IAAI,SAAS,KAAK,QAAQ,EACxF;AAGN;;;;;;AAOA,SAAgB,kBACd,YAAmC,CAAC,GACT;CAC3B,MAAM,uBAAO,IAAI,IAA+B;CAChD,KAAK,MAAM,cAAc,eAAe,KAAK,IAAI,WAAW,IAAI,UAAU;CAC1E,KAAK,MAAM,YAAY,WAAW;EAChC,MAAM,WAAW,KAAK,IAAI,SAAS,EAAE;EACrC,KAAK,IAAI,SAAS,IAAI,WAAW,SAAS,UAAU,QAAQ,IAAI,QAAQ;CAC1E;CAEA,MAAM,sBAAM,IAAI,IAA0B;CAC1C,MAAM,4BAAY,IAAI,IAAY;CAClC,MAAM,WAAW,OAA6B;EAC5C,MAAM,SAAS,IAAI,IAAI,EAAE;EACzB,IAAI,QAAQ,OAAO;EACnB,MAAM,aAAa,KAAK,IAAI,EAAE;EAC9B,IAAI,CAAC,YAAY,MAAM,IAAI,MAAM,sBAAsB,GAAG,0BAA0B;EAEpF,IAAI;EACJ,IAAI,WAAW,WAAW,WAAW,YAAY,MAAM,CAAC,UAAU,IAAI,WAAW,OAAO,GAAG;GACzF,UAAU,IAAI,EAAE;GAChB,OAAO,QAAQ,WAAW,OAAO;GACjC,UAAU,OAAO,EAAE;EACrB;EACA,MAAM,UAAW,WAAW,WAAW,MAAM,WAAW,WAAW;EACnE,MAAM,WAAyB;GAC7B,IAAI,WAAW;GACf;GACA,QAAQ,WAAW,UAAU,WAAW;GACxC,YAAY,WAAW,cAAc,MAAM,cAAc;GACzD,QAAQ,WAAW,UAAU,MAAM,UAAU;GAC7C,SAAS,IAAI,IAAI,WAAW,YAAY,OAAO,CAAC,GAAG,KAAK,OAAO,IAAI,CAAC,EAAE;GACtE,UAAU,cAAc,MAAM,UAAU,WAAW,QAAQ;GAC3D,OAAO,MAAM,SAAS,WAAW,QAAQ;IAAE,GAAG,MAAM;IAAO,GAAG,WAAW;GAAM,IAAI,KAAA;GACnF,QAAQ,WAAW,UAAU,MAAM;GACnC,WAAW,WAAW,aAAa,MAAM;GACzC,KAAK,MAAM,OAAO,WAAW,MAAM;IAAE,GAAG,MAAM;IAAK,GAAG,WAAW;GAAI,IAAI,KAAA;GACzE,SAAS,WAAW,WAAW,MAAM,WAAW;GAChD,aAAa,WAAW,eAAe,MAAM,eAAe;GAC5D,OAAO,aAAa,WAAW,SAAS,MAAM,SAAS,KAAK;GAC5D,aACE,MAAM,eAAe,WAAW,cAC5B;IAAE,GAAG,MAAM;IAAa,GAAG,WAAW;GAAY,IAClD,KAAA;GACN,SAAS,cAAc,IAAI,WAAW,EAAE,MAAM,MAAM,WAAW;GAC/D,MAAM,MAAM,QAAQ,WAAW,OAAO;IAAE,GAAG,MAAM;IAAM,GAAG,WAAW;GAAK,IAAI,KAAA;EAChF;EACA,iBAAiB,QAAQ;EACzB,IAAI,IAAI,IAAI,QAAQ;EACpB,OAAO;CACT;CACA,KAAK,MAAM,MAAM,KAAK,KAAK,GAAG,QAAQ,EAAE;CACxC,OAAO;AACT;;;;ACrhBA,MAAa,sBAA0C;CACrD,OAAO,CAAC;CACR,aAAa;EAAE,QAAQ;EAAM,MAAM;EAAQ,UAAU;CAAK;CAC1D,QAAQ;EACN,QAAQ;EACR,SAAS;GAAE,OAAO;GAAM,OAAO;GAAS,OAAO;EAAE;EACjD,SAAS;GAAE,OAAO;GAAU,MAAM;GAAG,SAAS;GAAI,MAAM;GAAW,QAAQ;EAAK;EAChF,gBAAgB;GACd,SAAS;GACT,MAAM;GACN,SAAS;GACT,QAAQ;GACR,OAAO;GACP,MAAM;GACN,QAAQ;EACV;EACA,QAAQ;GAAE,SAAS;GAAM,OAAO;GAAW,eAAe;GAAM,OAAO;GAAS,OAAO;EAAI;EAC3F,SAAS;GAAE,MAAM;GAAM,QAAQ;EAAK;EACpC,aAAa;EACb,SAAS;GAAE,SAAS;GAAM,YAAY;GAAoB,OAAO;EAAU;CAC7E;CACA,MAAM;EACJ,WAAW;EACX,oBAAoB;EACpB,UAAU;EACV,gBAAgB;GAAC;GAAG;GAAI;GAAK;EAAG;EAChC,mBAAmB;CACrB;CACA,UAAU;AACZ"}
|