import type { DiagramAnchor } from '@plannotator/core/diagram-anchor'; import type { DiagramRenderKind } from '@plannotator/core/annotatable'; import type { QuestionAnswer } from '@plannotator/core/question-block'; export type { DiagramAnchor } from '@plannotator/core/diagram-anchor'; export type { QuestionAnswer } from '@plannotator/core/question-block'; export type { DiagramRenderKind } from '@plannotator/core/annotatable'; /** * How a document's body is rendered. `markdown` and `html` are the original * pair; the two diagram kinds are whole-file diagram sources (.mmd/.mermaid, * .dot/.gv) that render as ONE diagram through the same engine a ```mermaid * fence uses — see diagramDocumentBlocks in utils/parser. */ export type DocumentRenderAs = 'markdown' | 'html' | DiagramRenderKind; export enum AnnotationType { DELETION = 'DELETION', COMMENT = 'COMMENT', GLOBAL_COMMENT = 'GLOBAL_COMMENT', } export type EditorMode = 'selection' | 'comment' | 'redline' | 'quickLabel'; export type InputMethod = 'drag' | 'pinpoint'; /** * Compactness of the Viewer action button labels (Image / Comment / Copy). * Driven by measured plan-area width so the cluster collapses responsively * when the side panel squeezes the plan. * full → "Global comment" / "Copy plan" * short → "Comment" / "Copy" * icon → labels hidden entirely */ export type ActionsLabelMode = 'full' | 'short' | 'icon'; export type WideModeType = 'wide' | 'focus'; export interface ImageAttachment { path: string; name: string; } /** DOM-relative text position used to restore a document annotation selection. */ export interface AnnotationTextMeta { parentTagName: string; parentIndex: number; textOffset: number; } /** Durable, media-specific location for a note created in the PR artifact viewer. */ export type ArtifactAnnotationAnchor = | { kind: 'document'; originalText: string; blockId: string; startOffset: number; endOffset: number; startMeta?: AnnotationTextMeta; endMeta?: AnnotationTextMeta; } | { kind: 'image'; x: number; y: number } | { kind: 'video'; timestamp: number } | { kind: 'page' }; /** Context shared by description and comment annotations created on a PR artifact. */ export interface ArtifactAnnotationMeta { artifactId: string; artifactName: string; artifactUrl: string; artifactKind: 'image' | 'gif' | 'video' | 'html' | 'markdown'; sourceUrl: string; anchor: ArtifactAnnotationAnchor; } export interface Annotation { id: string; blockId: string; // Legacy - not used with web-highlighter startOffset: number; // Legacy endOffset: number; // Legacy type: AnnotationType; text?: string; // For comments originalText: string; // The text that was selected createdA: number; author?: string; // Tater identity for collaborative sharing source?: string; // External tool identifier (e.g., "eslint") — set when annotation comes from external API images?: ImageAttachment[]; // Attached images with human-readable names mentions?: readonly string[]; // opaque host ids named with `@` in the comment body, set ONLY when a host supplied a `mentionSource` to the composer and at least one token survived; the key is absent otherwise. Host data: the package never renders, exports, shares or archives it. isQuickLabel?: boolean; // true if created via quick label chip quickLabelTip?: string; // optional instruction tip from the label definition diffContext?: 'added' | 'removed' | 'modified'; // set when annotation created in plan diff view artifact?: ArtifactAnnotationMeta; // code-review artifact viewer anchor + source context mathTargets?: Array<{ blockId: string; tex: string; displayMode: boolean; }>; // math elements covered by a mixed text+formula selection prUrl?: string; // code-review PR mode: the PR this note belongs to, so it isn't shown/exported against another PR after an in-place switch pageUrl?: string; // set only by live app annotate sessions: the page (pathname + search) the annotation was made on; restore filters to the current page and export groups by page inReplyTo?: string; // id of the annotation this one replies to; a reply inherits its parent's anchor, renders indented under it in the panel, and exports grouped under it. Additive: annotations without it render and export exactly as before. htmlAnchor?: HtmlElementAnchor; // raw-HTML pinpoint: serialized element anchor for reliable restoration elementContext?: HtmlElementContext; // raw-HTML / live-app pinpoint: bounded agent-facing description of the primary element (never used by restore) htmlAdditionalTargets?: HtmlAnnotationTarget[]; // raw-HTML shift-click multi-select: extra elements this one comment covers (primary stays htmlAnchor/originalText) diagramAnchor?: DiagramAnchor; // a comment on a rendered diagram part (Mermaid / Graphviz fence): the part's own id, label and document source line; the highlighter skips it and the diagram overlay restores it (see @plannotator/core/diagram-anchor) questionAnswer?: QuestionAnswer; // the reviewer's answer to a `:::question` block (id `ann-question-`): the Viewer draws the answer from it, the highlighter skips it, and the export prints it in the "Answers to your questions" section instead of as a numbered comment (see @plannotator/core/question-block) // web-highlighter metadata for cross-element selections startMeta?: AnnotationTextMeta; endMeta?: AnnotationTextMeta; } /** * Serialized element anchor for annotations created on the raw-HTML surface * (pinpoint mode). Built inside the sandboxed viewer bridge: a verified-unique * CSS selector plus a fingerprint (tag + normalized text snapshot) used to * fail closed when a weak selector no longer matches the same content. * Additive — annotations without one restore via document-wide text search. */ export interface HtmlElementAnchor { selector: string; tagName: string; text?: string; /** * The user's selected point inside the target element's rect, normalized to * 0..1 on each axis. Placed comment markers reproject it against the * element's CURRENT rect, so the marker follows the element through * responsive movement instead of pinning stale pixels. Additive — anchors * without one (older records, keyboard-driven selections) fall back to the * target rect center. */ point?: { x: number; y: number }; } /** * One additional element covered by a multi-target raw-HTML pinpoint comment * (shift-click multi-select). Carries what the export and composer chips need * even when anchoring failed closed: the semantic label from the pinpoint * hover cascade and the element's text (or `[element: …]` description). * Additive — annotations without the array behave exactly as before. */ export interface HtmlAnnotationTarget { /** Semantic label from the hover-label cascade (e.g. "Button", "rowchip"). */ label?: string; /** The target element's capped text, or an element description when text-less. */ text: string; /** Element anchor for restoration; absent when the bridge failed closed. */ anchor?: HtmlElementAnchor; /** Agent-facing element description (smaller budget than the primary's). */ context?: HtmlElementContext; } /** * A bounded, agent-facing description of a pinpointed element, captured by the * bridge at annotation time (only it can see the DOM). Purely descriptive: * restore never reads it (that is `HtmlElementAnchor`'s job). It exists so the * exported feedback can tell an agent working in the app's SOURCE which * element the comment is about — identity (what it is), location (where it * sits), and hooks (what to grep for) — without dumping the page. Every field * is page-controlled and re-validated at the parent trust boundary * (`parseHtmlElementContext`). Additive: annotations without one export * exactly as before, and share links never carry it. */ export interface HtmlElementContext { tag: string; id?: string; /** Author classes, generated/hashed ones skipped; may end in "+N more". */ classes?: string[]; /** Ancestor path, e.g. `body > div#root > header.site-header > nav#site-nav`. */ path?: string; /** Explicit `role` or the tag's implicit ARIA role. */ role?: string; /** Accessible name: aria-label, aria-labelledby, alt, title,