import { Extension, Editor } from '@tiptap/core'; import { EditorState, PluginKey } from '@tiptap/pm/state'; import { Transform } from '@tiptap/pm/transform'; import { DecorationSet } from '@tiptap/pm/view'; import { SuggestionType } from '../../types'; import * as Y from 'yjs'; export interface CommentAnchor { id: string; anchorFrom: Y.RelativePosition; anchorTo: Y.RelativePosition; resolved: boolean; deleted: boolean; isSuggestion?: boolean; suggestionType?: SuggestionType; originalContent?: string; suggestedContent?: string; } interface CommentDecorationPluginState { decorations: DecorationSet; } type CommentAnchorRange = { from: number; to: number; }; type CommentAnchorRelativeRange = { anchorFrom: Y.RelativePosition; anchorTo: Y.RelativePosition; }; export type CommentAnchorTransactionChange = { id: string; type: 'unchanged'; } | { id: string; type: 'deleted'; } | ({ id: string; type: 'edited'; } & CommentAnchorRange & CommentAnchorRelativeRange); export declare const commentDecorationPluginKey: PluginKey; export declare function resolveCommentAnchorRangeInState(anchor: Pick, state: EditorState): CommentAnchorRange | null; /** * Resolve anchorFrom to a single absolute position. * Used for 'add' suggestion anchors where anchorFrom === anchorTo (cursor, * no initial selection) — resolveCommentAnchorRangeInState rejects from >= to, * so we need a separate path that allows a point position. */ export declare function resolveCommentAnchorPointInState(anchor: Pick, state: EditorState): number | null; export declare function hasResolvableCommentAnchorInState(anchor: Pick, state: EditorState): boolean; export declare function resolveCommentAnchorRangeForAnalysis(anchor: Pick, state: EditorState): CommentAnchorRange | null; export declare function resolveCommentAnchorPointForAnalysis(anchor: Pick, state: EditorState): number | null; /** * Analyze transaction changes to classify each active anchor's mutation status. * * This is the core transaction analysis function that determines * whether each anchor remains unchanged, gets edited, or is deleted. * * Classification rules (in order): * 1. If the transform preserves positions → 'unchanged' * 2. Skip deleted or resolved anchors → 'unchanged' * 3. If anchor has no old position → 'unchanged' * 4. If no changed ranges touch the anchor → 'unchanged' * 5. If any changed range fully covers the anchor → 'deleted' (full-span replacement) * 6. If combined changed ranges fully cover the anchor → 'deleted' (multi-step removal) * 7. If anchor maps through transform → check if position or content changed: * a. If both unchanged → 'unchanged' * b. Otherwise → 'edited' (return new position and relative anchor) * 8. If mapping fails → 'deleted' */ export declare function analyzeCommentAnchorTransactionChanges(anchors: CommentAnchor[], oldState: EditorState, newState: EditorState, transform: Transform): CommentAnchorTransactionChange[]; export interface CommentDecorationOptions { getAnchors: () => CommentAnchor[]; getActiveCommentId: () => string | null; } export declare const CommentDecorationExtension: Extension; /** * Public helper functions for comment anchor creation and inspection. * These are consumed by the draft-creation flow and transaction-analysis layer. */ export declare function createCommentAnchorFromEditor(editor: Editor, from: number, to: number): CommentAnchorRelativeRange | null; /** * Create a point anchor (anchorFrom === anchorTo) at a single doc position. * Used by the suggestion-mode draft flow when the viewer places a cursor * without selecting text — createCommentAnchorFromEditor rejects from >= to * since an empty range is invalid for regular comments. */ export declare function createCommentAnchorPointFromEditor(editor: Editor, pos: number): CommentAnchorRelativeRange | null; export declare function createCommentAnchorFromSelection(editor: Editor): CommentAnchorRelativeRange | null; export declare function triggerDecorationRebuild(editor: Editor): void; export declare function getCommentAtPosition(editor: Editor, pos: number, getAnchors: () => CommentAnchor[]): CommentAnchor | null; export declare function getCommentAnchorRange(editor: Editor, commentId: string, getAnchors: () => CommentAnchor[]): CommentAnchorRange | null; /** * Apply the accepted suggestion's change to the document. * Called by the store's acceptSuggestion action before resolving on-chain. * Returns false if the anchor can't be resolved or the suggestion type is unknown. */ export declare function applyAcceptedSuggestion(editor: Editor, anchor: CommentAnchor): boolean; export {};