/** * Framework-agnostic types for the Comments feature: text-anchored comment * threads with @mentions, persisted through a pluggable * `CommentsStorageAdapter`. Mirrors the shape of `history-types.ts` * (interface + plain data types, no DOM/React dependency) so the same * document can be wired to different backends (in-memory, localStorage, * IndexedDB, a real API) without changing this file. */ interface CommentMentionUser { id: string; name: string; avatar?: string; } interface CommentMessage { id: string; author: string; authorId?: string; body: string; /** `CommentMentionUser.id`s referenced in `body` via "@Name". */ mentions: string[]; /** ISO date string. */ createdAt: string; } interface CommentThread { /** Same id used as the anchoring `comment` mark's `id` attribute. */ id: string; /** Snapshot of the anchored text, so the thread stays meaningful even if the anchor is later deleted from the doc. */ quote: string; resolved: boolean; /** ISO date string. */ createdAt: string; /** First message is the original comment; later ones are replies. */ messages: CommentMessage[]; } interface CommentsStorageAdapter { list(): Promise; /** Upsert — creates the thread if it doesn't exist, otherwise replaces it. */ save(thread: CommentThread): Promise; remove(id: string): Promise; } /** * Snapshot `CommentsLayer` reports via `onHostOpen` whenever * `presentation: 'host'` and its panel-open state, thread list, expanded * thread, or pending-composer quote changes — everything a host-rendered * sheet (e.g. `packages/react-native`'s `CommentsSheet`) needs to render an * equivalent view without `CommentsPanel` ever mounting. */ interface CommentsHostViewState { open: boolean; threads: CommentThread[]; expandedId: string | null; /** Non-null while a new-comment composer would be showing (empty string means a quote-less thread, e.g. no selection text). */ pendingQuote: string | null; } /** * A single action a host-rendered sheet sends back into `CommentsLayer` via * its `hostCommand` prop — the same nonce-bumped-prop pattern * `commentRequest`/`AgentMentionView`'s `externalTrigger` already use, since * a plain prop change (not a ref/imperative call) is enough to cross the * WebView/native boundary as ordinary config data. */ interface CommentsHostCommand { /** Bump (e.g. `Date.now()`) on every command so an unchanged object is a no-op. */ nonce: number; action: 'reply' | 'resolveToggle' | 'delete' | 'create' | 'close' | 'expand'; threadId?: string; body?: string; mentions?: string[]; } type PageSizePreset = 'letter' | 'a4' | 'legal' | 'a3' | 'a5' | 'b5' | 'executive' | 'custom'; interface PageSetup { size: PageSizePreset; orientation: 'portrait' | 'landscape'; /** Only used when `size === 'custom'`. Millimeters. */ customWidthMm?: number; /** Only used when `size === 'custom'`. Millimeters. */ customHeightMm?: number; /** Horizontal margin (left + right), inches. */ marginX: number; /** Vertical margin (top + bottom), inches. */ marginY: number; } declare const PAGE_SIZE_PRESETS: Record, { label: string; width: string; height: string; }>; declare const DEFAULT_PAGE_SETUP: PageSetup; declare function mmToPx(mm: number): number; declare function pxToMm(px: number): number; /** Resolve a PageSetup into concrete pixel dimensions, honoring orientation swap. */ declare function resolvePageDimensions(setup: PageSetup): { widthPx: number; heightPx: number; }; /** OOXML page size/margin dimensions, in twips (DXA — 1/1440 inch). */ interface PageDimensionsTwips { widthTwips: number; heightTwips: number; marginXTwips: number; marginYTwips: number; } /** * Resolve a PageSetup into OOXML twips, for ``/`` — used by * both `.docx` export paths (`io/save.ts`'s `docx`-library rebuild and * `io/ooxml-serializer.ts`'s raw-XML rebuild) so an exported file's page * size/margins always match what's shown on screen, instead of each save * path hardcoding its own default (previously: both silently exported US * Letter with 1in margins regardless of the live page setup). */ declare function resolvePageDimensionsTwips(setup: PageSetup): PageDimensionsTwips; /** * Reverse of `resolvePageDimensionsTwips()`: given a page size/margin read * from a loaded .docx's ``, find the matching size preset + * orientation, or fall back to `'custom'` with the size expressed in mm — * so opening an existing A4/Legal/custom-size document restores the * editor's on-screen page setup to match, instead of resetting to whatever * the app's own default/last-used preference was. */ declare function pageSetupFromTwips(pd: PageDimensionsTwips): PageSetup; /** * Watermark — a repeating, tiled diagonal text overlay on the page. * * Implementation: we don't store the watermark in the document JSON (it's a * page-level property, not content). Instead, the DocxEditor class holds the * watermark state and renders it as a single absolutely-positioned overlay * (`inset: 0`) on the page element, whose `background-image` is a small SVG * tile containing one rotated instance of the watermark text, repeated via * `background-repeat: repeat`. * * Tiling (rather than one centered instance) is what makes this work for * BOTH view modes with the same code path: * - 'paged': the page element's height already spans every simulated * page, so the tile repeats down through all of them. * - 'pageless': the page is one continuous flowing surface with no fixed * height, so a single centered watermark would only ever be visible * once, near the top. Tiling keeps it visible throughout. * The browser handles the repetition natively, so nothing needs to be * recomputed as the page grows (new pages added, more content typed, etc). * * This module exports: * - WatermarkConfig type * - Default presets (CONFIDENTIAL, DRAFT, DO NOT COPY, etc.) * - createWatermarkElement — the (only) DOM builder */ interface WatermarkConfig { /** The text to show. */ text: string; /** Font size in px. Default: 56. */ fontSize?: number; /** Font family. Default: sans-serif. */ fontFamily?: string; /** Text color (CSS). Default: 'rgba(208, 7, 7, 0.18)'. */ color?: string; /** Rotation in degrees. Default: -30 (diagonal, bottom-left to top-right). */ rotation?: number; /** Opacity 0-1. Default: 0.18. */ opacity?: number; } declare const DEFAULT_WATERMARK_PRESETS: Array<{ label: string; config: WatermarkConfig; }>; declare const DEFAULT_WATERMARK: WatermarkConfig; /** * Build the watermark DOM element. Returns null if no watermark text. * * The element is a single overlay covering the whole page (`inset: 0`), * with a repeating SVG-tile background — one rotated instance of the text * per tile — so the watermark reads consistently down the entire document, * across every page, in both paged and pageless view modes. */ declare function createWatermarkElement(config: WatermarkConfig | null): HTMLElement | null; export { type CommentThread as C, DEFAULT_PAGE_SETUP as D, type PageSetup as P, type WatermarkConfig as W, type PageDimensionsTwips as a, type CommentMentionUser as b, type CommentMessage as c, type CommentsHostCommand as d, type CommentsHostViewState as e, type CommentsStorageAdapter as f, DEFAULT_WATERMARK as g, DEFAULT_WATERMARK_PRESETS as h, PAGE_SIZE_PRESETS as i, type PageSizePreset as j, createWatermarkElement as k, pxToMm as l, mmToPx as m, resolvePageDimensionsTwips as n, pageSetupFromTwips as p, resolvePageDimensions as r };