import { DecorationSet } from '@milkdown/kit/prose/view'; import { ReviewSuggestion, ReviewSuggestionOpType } from '../../types'; /** * Resolved PM position for a suggestion. Flat-text offsets from the input are * resolved into live PM positions exactly once and then maintained by mapping * them through every subsequent transaction. */ export type ResolvedReviewSuggestionRange = { id: string; from: number; to: number; opType: ReviewSuggestionOpType; /** Markdown (or plain) source for the proposed insertion/replacement. */ replacementText: string; }; export type ReviewSuggestionsPluginState = { decorations: DecorationSet; ranges: ResolvedReviewSuggestionRange[]; /** * Source suggestions that successfully entered the editor-owned lifecycle. * Unresolved suggestions remain in resolution summaries but are excluded from * card navigation because they have no live range. */ suggestions: ReviewSuggestion[]; selectedId: string | null | undefined; needsInitialResolve: boolean; /** * Number of docChanged transactions spent re-probing while `needsInitialResolve` * is set. Bounds the collab re-resolve retry so anchors that never match the * synced doc don't turn every keystroke into full-document resolution. */ initialResolveAttempts?: number; }; /** * Two-shape meta contract so callers must declare intent: * - `suggestions`: replace full suggestion set (re-resolve offsets). * - `selection`: update only selected id (preserve mapped ranges). */ export type ReviewSuggestionsMeta = { type: 'suggestions'; suggestions: ReviewSuggestion[] | undefined; selectedId: string | null | undefined; } | { type: 'selection'; selectedId: string | null | undefined; } | { type: 'applySuggestion'; suggestionId: string; } | { type: 'dismissSuggestion'; suggestionId: string; };