@sofereditor/core 0.3.2 → 0.5.0
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/dist/index.cjs +132 -0
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +161 -2
- package/dist/index.d.ts +161 -2
- package/dist/index.js +119 -0
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/index.ts","../src/types.ts","../src/schema.ts","../src/page-settings.ts","../src/document.ts","../src/collab-cursor.ts","../src/selection.ts","../src/marks.ts","../src/commands.ts","../src/clipboard.ts","../src/history.ts"],"sourcesContent":["export * from \"./types\";\nexport * from \"./schema\";\nexport * from \"./page-settings\";\nexport * from \"./document\";\nexport * from \"./collab-cursor\";\nexport * from \"./selection\";\nexport * from \"./marks\";\nexport * from \"./commands\";\nexport * from \"./clipboard\";\nexport * from \"./history\";\n","/**\n * Public type definitions for the document model.\n * The runtime representation lives in Y.js (see document.ts);\n * these types describe its shape for consumers.\n */\n\nexport type BlockType =\n | \"paragraph\"\n | \"heading\"\n | \"blockquote\"\n | \"codeBlock\"\n | \"listItem\"\n | \"table\";\n\nexport type AlignValue = \"left\" | \"center\" | \"right\" | \"justify\";\nexport type DirValue = \"ltr\" | \"rtl\";\nexport type ListKind = \"bullet\" | \"ordered\";\n\nexport type ListStyleType =\n | \"decimal\"\n | \"lower-alpha\"\n | \"upper-alpha\"\n | \"lower-roman\"\n | \"upper-roman\";\n\n/** Maximum supported list nesting (0 = top level). */\nexport const MAX_LIST_LEVEL = 5;\n\nexport interface BlockAttrs {\n align?: AlignValue;\n dir?: DirValue;\n /** Only meaningful when `type === \"heading\"`. 1..6. */\n level?: 1 | 2 | 3 | 4 | 5 | 6;\n /** Only meaningful when `type === \"codeBlock\"`. Free-form (CSS-style language hint). */\n language?: string;\n /** Only meaningful when `type === \"listItem\"`. */\n listKind?: ListKind;\n /** Only meaningful when `type === \"listItem\"`. 0..MAX_LIST_LEVEL. */\n listLevel?: number;\n /**\n * Only meaningful when `type === \"listItem\"` and `listKind === \"ordered\"`.\n * When set on a listItem, that item starts a NEW list group whose first\n * `<ol>` carries `start={listStart}`. Used to renumerate questions or pick\n * up an interrupted sequence.\n */\n listStart?: number;\n /**\n * Only meaningful when `type === \"listItem\"`. Overrides the default per-level\n * CSS cycle (decimal → lower-alpha → lower-roman) with an explicit style.\n * Like `listStart`, setting this on a listItem breaks the group so the new\n * `<ol>` carries the requested `list-style-type`.\n */\n listStyle?: ListStyleType;\n /** Only meaningful when `type === \"table\"`. */\n rows?: number;\n /** Only meaningful when `type === \"table\"`. */\n cols?: number;\n /**\n * Only meaningful when `type === \"table\"`. Per-column widths in CSS px.\n * Length should equal `cols` when set; missing or short arrays fall back to\n * an auto distribution at render time.\n */\n colWidths?: number[];\n}\n\nexport interface CellAttrs {\n /**\n * Number of rows this cell spans, starting at its row. Default 1.\n * Only meaningful on REAL cells (not covered).\n */\n rowspan?: number;\n /** Default 1. Only meaningful on REAL cells. */\n colspan?: number;\n /**\n * `true` iff this cell is occluded by an owning cell with a `rowspan`/`colspan`\n * spanning into this position. Covered cells do not render their own `<td>`,\n * never accept input, and are skipped by Tab navigation.\n *\n * The cells array keeps `rows * cols` entries to preserve the row-major index\n * scheme — covered cells are placeholders, not gaps.\n */\n covered?: true;\n /** Alinhamento horizontal do texto da célula. Mesmos valores de bloco. */\n align?: AlignValue;\n /** Cor de fundo da célula (CSS color, ex. `#ffe58f`). Ausente = sem fundo. */\n bgColor?: string;\n}\n\nexport interface Position {\n blockIndex: number;\n /**\n * When the caret is inside a table cell, identifies which cell within the\n * table at `blockIndex`. Flat row-major index: `row * cols + col`.\n * `undefined` means the position addresses the block's own text (or the block\n * itself, for atomic blocks). Tables have no own text — every caret position\n * inside a table block carries a defined `cellIndex`.\n */\n cellIndex?: number;\n offset: number;\n}\n\nexport interface Selection {\n anchor: Position;\n focus: Position;\n}\n\nexport type MarkName =\n | \"bold\"\n | \"italic\"\n | \"underline\"\n | \"strike\"\n | \"color\"\n | \"fontFamily\"\n | \"fontSize\"\n | \"link\"\n | \"comment\";\n\nexport interface LinkAttr {\n href: string;\n title?: string;\n}\n\nexport interface CommentAttr {\n /** Identificador estável compartilhado com o backend (ProvaDocumentoComentario.markId). */\n markId: string;\n}\n\nexport interface MarkAttrs {\n bold?: true;\n italic?: true;\n underline?: true;\n strike?: true;\n color?: string;\n fontFamily?: string;\n fontSize?: string;\n link?: LinkAttr;\n comment?: CommentAttr;\n}\n\nexport type MarkValue<K extends MarkName = MarkName> = NonNullable<MarkAttrs[K]>;\n\n/**\n * Visual layout mode for an image embed.\n *\n * - `inline` (default): part of the text run, flows like a character.\n * - `wrap-left` / `wrap-right`: image floats to the named side of the anchor\n * paragraph (Word-style \"wrap square\"). Text in the paragraph wraps around it.\n * - `behind`: image is absolutely positioned beneath the text (z-index < text).\n * - `front`: image is absolutely positioned above the text (z-index > text).\n *\n * In every non-inline mode the embed remains in the Y.Text run at its offset —\n * the offset is its **anchor** (it follows the paragraph during pagination\n * and re-flows). Visual position is offset from the anchor block's content box.\n */\nexport type ImageLayout = \"inline\" | \"wrap-left\" | \"wrap-right\" | \"behind\" | \"front\";\n\nexport interface ImageEmbed {\n type: \"image\";\n /** Data URL (base64) — self-contained so the embed travels with the Y.Doc. */\n src: string;\n /** Rendered CSS px (display size — may differ from intrinsic dimensions). */\n width: number;\n height: number;\n /** When set (inline mode only), the image renders `display: block` with the matching margin auto. */\n align?: \"left\" | \"center\" | \"right\";\n /** Visual layout. Defaults to \"inline\" when omitted. */\n layout?: ImageLayout;\n /**\n * Horizontal offset in CSS px from the anchor block's content box.\n * - wrap-left: extra left margin from the paragraph's start edge.\n * - wrap-right: extra right margin from the paragraph's end edge.\n * - behind / front: `left` relative to the anchor block's padding-box.\n * Ignored for `inline`.\n */\n offsetX?: number;\n /**\n * Vertical offset in CSS px from the anchor block's content box.\n * - wrap-left / wrap-right: extra top margin pushing the float down inside\n * the paragraph.\n * - behind / front: `top` relative to the anchor block's padding-box.\n * Ignored for `inline`.\n */\n offsetY?: number;\n /**\n * Optional plain-text caption. Renders inside a `<figcaption>` beneath the\n * image in any layout — the figure wraps the image so the caption travels\n * with floats/anchors. Plain text only; rich marks are out of scope (we\n * never want a sub-editor inside an inline embed).\n */\n caption?: string;\n /**\n * Text alignment for the caption. Defaults to \"center\" (Word/Google Docs\n * default for figure captions). Only meaningful when `caption` is set.\n * Note: DOCX export emits captions inside the host paragraph, so this\n * setting only affects the editor and HTML/PDF exports — Word displays the\n * caption using the paragraph's own alignment.\n */\n captionAlign?: \"left\" | \"center\" | \"right\";\n}\n\nexport type InsertContent = string | ImageEmbed;\n\nexport function isImageEmbed(v: unknown): v is ImageEmbed {\n return (\n typeof v === \"object\" &&\n v !== null &&\n (v as { type?: unknown }).type === \"image\" &&\n typeof (v as { src?: unknown }).src === \"string\"\n );\n}\n\nexport interface DeltaOp {\n insert: InsertContent;\n attributes?: MarkAttrs;\n}\n\nexport interface SerializedCell {\n /** Plain concatenated text. */\n text: string;\n /** Delta with marks. */\n delta: DeltaOp[];\n attrs: CellAttrs;\n}\n\nexport interface SerializedBlock {\n /** Id estável do bloco (cursores colaborativos / keying). Ausente em docs antigos. */\n id?: string;\n type: BlockType;\n /** Plain concatenated text (no marks). Kept for ergonomic equality checks. */\n text: string;\n /** Yjs delta — used by the renderer to draw mark-aware spans. */\n delta: DeltaOp[];\n /** Block-level attributes (align, dir, heading level, code language…). */\n attrs: BlockAttrs;\n /** Only present when `type === \"table\"`. Flat row-major list, length = rows * cols. */\n cells?: SerializedCell[];\n}\n\nimport type { PageSettings } from \"./page-settings\";\n\n/**\n * Document JSON shape used by `EditorDocument.toJSON` / `fromJSON`, the\n * exporters and the importer. Until Fase 9.5 this was a bare `SerializedBlock[]`;\n * Fase 9.6 promoted it to an object so per-document settings (page size,\n * margins) can travel with the content.\n *\n * `fromJSON` still accepts a legacy array for backwards compatibility — see\n * `isLegacySerializedDocument`.\n */\nexport interface SerializedDocument {\n blocks: SerializedBlock[];\n /** Page settings. Optional; omitted means default A4 + 1\" margins. */\n pageSettings?: PageSettings;\n}\n\n/** A `SerializedDocument` produced before Fase 9.6 — just an array of blocks. */\nexport type LegacySerializedDocument = SerializedBlock[];\n\nexport function isLegacySerializedDocument(\n v: SerializedDocument | LegacySerializedDocument,\n): v is LegacySerializedDocument {\n return Array.isArray(v);\n}\n","import type { BlockAttrs, BlockType } from \"./types\";\n\ninterface BlockSpec {\n type: BlockType;\n defaultAttrs: BlockAttrs;\n}\n\nexport const BLOCK_SPECS: Record<BlockType, BlockSpec> = {\n paragraph: {\n type: \"paragraph\",\n defaultAttrs: {},\n },\n heading: {\n type: \"heading\",\n defaultAttrs: { level: 1 },\n },\n blockquote: {\n type: \"blockquote\",\n defaultAttrs: {},\n },\n codeBlock: {\n type: \"codeBlock\",\n defaultAttrs: {},\n },\n listItem: {\n type: \"listItem\",\n defaultAttrs: { listKind: \"bullet\", listLevel: 0 },\n },\n table: {\n type: \"table\",\n defaultAttrs: { rows: 1, cols: 1 },\n },\n};\n\nexport function isKnownBlockType(t: string): t is BlockType {\n return t in BLOCK_SPECS;\n}\n\nexport function defaultAttrsFor(type: BlockType): BlockAttrs {\n return { ...BLOCK_SPECS[type].defaultAttrs };\n}\n","/**\n * Document-level page configuration: physical size and margins.\n *\n * Everything is stored in **CSS pixels @ 96dpi** for consistency with the\n * pagination engine (`packages/react/src/usePagination.ts` reads these\n * directly). Conversion helpers (`mmToPx`, `pxToMm`) round-trip with millimeter\n * inputs from the UI and the OOXML twip values used by docx import/export.\n */\n\nexport type PagePreset = \"a4\" | \"letter\" | \"oficio\" | \"custom\";\n\nexport interface PageSettings {\n /** Page width in CSS px. */\n width: number;\n /** Page height in CSS px. */\n height: number;\n marginTop: number;\n marginBottom: number;\n marginLeft: number;\n marginRight: number;\n /**\n * The preset whose size the geometry matches, with the ±0.5mm tolerance used\n * by `detectPreset`. \"custom\" when the dimensions don't match any preset.\n * This is purely a UI hint — it's recomputed from width/height when needed.\n */\n preset?: PagePreset;\n /**\n * Free-form title persisted on the document for a consumer-rendered\n * \"system header\" (e.g. a non-editable letterhead/identification block\n * drawn on page 1 via `renderPageHeader`). Stored in `docSettings` so it\n * survives serialization and is visible to every client/consumer of the\n * `SerializedDocument`, including headless exports.\n *\n * The renderer is application-defined — this field just transports the\n * title string. Use it when the header content is part of the document\n * (and therefore must round-trip through exports), not a UI chrome\n * decoration.\n */\n systemHeaderTitle?: string;\n /**\n * Owner/author display name for the same consumer-rendered system\n * header (see [[systemHeaderTitle]]). Useful when the header should\n * show the document's CREATOR, not the current viewer (e.g. an author\n * name on a doc viewed by a third party). Persisted in `docSettings`\n * for consistent rendering across clients and headless renderers.\n */\n systemHeaderAuthor?: string;\n}\n\n/** Page sizes in CSS px @ 96dpi. */\nexport const PAGE_PRESETS = {\n a4: { width: 794, height: 1123 }, // 210×297 mm\n letter: { width: 816, height: 1056 }, // 8.5×11 in\n oficio: { width: 816, height: 1248 }, // 216×330 mm (BR Ofício)\n} as const;\n\n/** Margin presets in CSS px. Match common Word defaults. */\nexport const MARGIN_PRESETS = {\n normal: 96, // 25.4 mm = 1 in\n narrow: 48, // 12.7 mm = 0.5 in\n wide: 192, // 50.8 mm = 2 in\n} as const;\n\nexport const DEFAULT_PAGE_SETTINGS: PageSettings = {\n ...PAGE_PRESETS.a4,\n marginTop: MARGIN_PRESETS.normal,\n marginBottom: MARGIN_PRESETS.normal,\n marginLeft: MARGIN_PRESETS.normal,\n marginRight: MARGIN_PRESETS.normal,\n preset: \"a4\",\n};\n\nconst PX_PER_MM = 96 / 25.4;\n\nexport function mmToPx(mm: number): number {\n return mm * PX_PER_MM;\n}\n\nexport function pxToMm(px: number): number {\n return px / PX_PER_MM;\n}\n\n/**\n * Detect which preset a (width, height) pair matches. Tolerance is ±0.5mm to\n * absorb rounding from the twips↔px conversion used by docx round-trip.\n */\nexport function detectPreset(width: number, height: number): PagePreset {\n const TOL = mmToPx(0.5);\n for (const [name, size] of Object.entries(PAGE_PRESETS) as Array<[PagePreset, { width: number; height: number }]>) {\n if (Math.abs(width - size.width) <= TOL && Math.abs(height - size.height) <= TOL) {\n return name;\n }\n }\n return \"custom\";\n}\n\n/** Fill missing fields with the default. Useful when reading from a Y.Map that may be partially populated. */\nexport function withDefaults(partial: Partial<PageSettings> | undefined): PageSettings {\n const merged = { ...DEFAULT_PAGE_SETTINGS, ...(partial ?? {}) };\n return { ...merged, preset: detectPreset(merged.width, merged.height) };\n}\n","import * as Y from \"yjs\";\nimport { defaultAttrsFor } from \"./schema\";\nimport {\n DEFAULT_PAGE_SETTINGS,\n detectPreset,\n type PageSettings,\n} from \"./page-settings\";\nimport {\n isLegacySerializedDocument,\n type BlockAttrs,\n type BlockType,\n type CellAttrs,\n type DeltaOp,\n type LegacySerializedDocument,\n type SerializedBlock,\n type SerializedCell,\n type SerializedDocument,\n} from \"./types\";\n\n/**\n * Gera um id estável de bloco. Usado para ancorar cursores colaborativos\n * remotos (fallback) e para keying estável no overlay. Persistido no Y.Map do\n * bloco, então sobrevive a reload (binário Yjs). Docs antigos não têm — os\n * helpers de cursor lidam com a ausência (caem na RelativePosition).\n */\nexport function newBlockId(): string {\n try {\n if (typeof crypto !== \"undefined\" && typeof crypto.randomUUID === \"function\") {\n return crypto.randomUUID();\n }\n } catch {\n /* ambiente sem crypto.randomUUID — fallback abaixo */\n }\n return `b-${Math.random().toString(36).slice(2, 10)}${Date.now().toString(36)}`;\n}\n\n/** Lê o id de um bloco Y.Map (undefined em docs antigos sem id). */\nexport function getBlockId(block: Y.Map<unknown>): string | undefined {\n const id = block.get(\"id\");\n return typeof id === \"string\" ? id : undefined;\n}\n\n/**\n * Y.js-backed document.\n *\n * Storage layout:\n * ydoc.getArray(\"blocks\") : Y.Array<Y.Map>\n * each Y.Map (\"block\"):\n * - type: string (\"paragraph\" | \"heading\" | \"blockquote\" | \"codeBlock\" | \"listItem\" | \"table\")\n * - text: Y.Text (NOT present on tables)\n * - attrs: Y.Map<unknown> (align, dir, level, language… plus rows/cols for tables)\n * - cells: Y.Array<Y.Map> (only on tables, length = rows * cols, row-major)\n * each cell map: { text: Y.Text, attrs: Y.Map<unknown> }\n *\n * Block-level attrs live inside a nested Y.Map so concurrent edits (e.g. two users\n * changing alignment at once) reconcile through Yjs' last-write-wins per key.\n */\nexport class EditorDocument {\n readonly ydoc: Y.Doc;\n readonly blocks: Y.Array<Y.Map<unknown>>;\n /** Document-level settings (page size, margins). See `getPageSettings`. */\n readonly docSettings: Y.Map<unknown>;\n\n constructor(ydoc?: Y.Doc) {\n this.ydoc = ydoc ?? new Y.Doc();\n this.blocks = this.ydoc.getArray<Y.Map<unknown>>(\"blocks\");\n this.docSettings = this.ydoc.getMap<unknown>(\"docSettings\");\n\n if (this.blocks.length === 0) {\n this.ydoc.transact(() => {\n this.blocks.push([createBlock(\"paragraph\")]);\n }, \"init\");\n }\n }\n\n /**\n * Returns the current page settings. Missing fields fall back to\n * `DEFAULT_PAGE_SETTINGS`. The returned object is a fresh snapshot — mutating\n * it does not write back to the Y.Doc. Use `setPageSettings` for that.\n */\n getPageSettings(): PageSettings {\n const m = this.docSettings;\n const pick = <K extends keyof PageSettings>(key: K): PageSettings[K] | undefined => {\n const v = m.get(key as string);\n return typeof v === \"number\" || typeof v === \"string\" ? (v as PageSettings[K]) : undefined;\n };\n const merged: PageSettings = {\n width: pick(\"width\") ?? DEFAULT_PAGE_SETTINGS.width,\n height: pick(\"height\") ?? DEFAULT_PAGE_SETTINGS.height,\n marginTop: pick(\"marginTop\") ?? DEFAULT_PAGE_SETTINGS.marginTop,\n marginBottom: pick(\"marginBottom\") ?? DEFAULT_PAGE_SETTINGS.marginBottom,\n marginLeft: pick(\"marginLeft\") ?? DEFAULT_PAGE_SETTINGS.marginLeft,\n marginRight: pick(\"marginRight\") ?? DEFAULT_PAGE_SETTINGS.marginRight,\n systemHeaderTitle: pick(\"systemHeaderTitle\"),\n systemHeaderAuthor: pick(\"systemHeaderAuthor\"),\n };\n merged.preset = detectPreset(merged.width, merged.height);\n return merged;\n }\n\n /**\n * Merge `partial` into the docSettings Y.Map. Runs in a `ydoc.transact` with\n * origin `\"pageSettings\"` (NOT tracked by the UndoManager, mirroring the\n * `\"import\"` convention from Fase 9.5).\n */\n setPageSettings(partial: Partial<PageSettings>): void {\n this.ydoc.transact(() => {\n for (const [k, v] of Object.entries(partial)) {\n if (k === \"preset\") continue; // derived, never stored\n if (v === undefined) continue;\n this.docSettings.set(k, v);\n }\n }, \"pageSettings\");\n }\n\n /** Listen for page-settings changes. Returns an unsubscribe function. */\n observePageSettings(cb: () => void): () => void {\n const handler = () => cb();\n this.docSettings.observe(handler);\n return () => this.docSettings.unobserve(handler);\n }\n\n getBlock(index: number): Y.Map<unknown> | undefined {\n if (index < 0 || index >= this.blocks.length) return undefined;\n return this.blocks.get(index);\n }\n\n getBlockText(index: number): Y.Text | undefined {\n const b = this.getBlock(index);\n return b?.get(\"text\") as Y.Text | undefined;\n }\n\n getBlockType(index: number): BlockType | undefined {\n const b = this.getBlock(index);\n return b?.get(\"type\") as BlockType | undefined;\n }\n\n getBlockAttrsMap(index: number): Y.Map<unknown> | undefined {\n const b = this.getBlock(index);\n return b?.get(\"attrs\") as Y.Map<unknown> | undefined;\n }\n\n getBlockAttrs(index: number): BlockAttrs {\n const m = this.getBlockAttrsMap(index);\n if (!m) return {};\n return Object.fromEntries(m.entries()) as BlockAttrs;\n }\n\n blockCount(): number {\n return this.blocks.length;\n }\n\n // ---------- Table helpers ----------\n\n isTable(index: number): boolean {\n return this.getBlockType(index) === \"table\";\n }\n\n /** Returns rows/cols read from the block's attrs map. `{0,0}` for non-table blocks. */\n getTableSize(index: number): { rows: number; cols: number } {\n const attrs = this.getBlockAttrs(index);\n const rows = typeof attrs.rows === \"number\" ? attrs.rows : 0;\n const cols = typeof attrs.cols === \"number\" ? attrs.cols : 0;\n return { rows, cols };\n }\n\n getCells(index: number): Y.Array<Y.Map<unknown>> | undefined {\n const b = this.getBlock(index);\n return b?.get(\"cells\") as Y.Array<Y.Map<unknown>> | undefined;\n }\n\n getCell(blockIndex: number, cellIndex: number): Y.Map<unknown> | undefined {\n const cells = this.getCells(blockIndex);\n if (!cells) return undefined;\n if (cellIndex < 0 || cellIndex >= cells.length) return undefined;\n return cells.get(cellIndex);\n }\n\n getCellText(blockIndex: number, cellIndex: number): Y.Text | undefined {\n const cell = this.getCell(blockIndex, cellIndex);\n return cell?.get(\"text\") as Y.Text | undefined;\n }\n\n getCellAttrsMap(blockIndex: number, cellIndex: number): Y.Map<unknown> | undefined {\n const cell = this.getCell(blockIndex, cellIndex);\n return cell?.get(\"attrs\") as Y.Map<unknown> | undefined;\n }\n\n getCellAttrs(blockIndex: number, cellIndex: number): CellAttrs {\n const m = this.getCellAttrsMap(blockIndex, cellIndex);\n if (!m) return {};\n return Object.fromEntries(m.entries()) as CellAttrs;\n }\n\n /**\n * Returns the editable Y.Text targeted by a position:\n * - When `cellIndex` is set: the cell's text (or the owner's text if the\n * target cell is covered by a span — we treat the covered position as\n * addressing the owner).\n * - Otherwise: the block's own text.\n */\n textAt(blockIndex: number, cellIndex: number | undefined): Y.Text | undefined {\n if (cellIndex == null) return this.getBlockText(blockIndex);\n const real = this.realCellIndex(blockIndex, cellIndex);\n if (real == null) return undefined;\n return this.getCellText(blockIndex, real);\n }\n\n /**\n * Returns the \"real\" (non-covered) cell index for a target cell. When the\n * target is already a real cell, returns it unchanged. When covered, walks\n * up-and-left to find the owner.\n *\n * The walk is robust to oversized or non-rectangular spans by skipping\n * candidates whose declared span doesn't actually cover the target.\n */\n realCellIndex(blockIndex: number, cellIndex: number): number | undefined {\n if (!this.isTable(blockIndex)) return undefined;\n const { rows, cols } = this.getTableSize(blockIndex);\n if (rows <= 0 || cols <= 0) return undefined;\n if (cellIndex < 0 || cellIndex >= rows * cols) return undefined;\n const targetAttrs = this.getCellAttrs(blockIndex, cellIndex);\n if (targetAttrs.covered !== true) return cellIndex;\n\n const tRow = Math.floor(cellIndex / cols);\n const tCol = cellIndex - tRow * cols;\n // Scan candidate owners — any real cell (or, oc) with or <= tRow, oc <= tCol,\n // spanning into (tRow, tCol). Walk from (tRow, tCol) up-and-left.\n for (let or = tRow; or >= 0; or--) {\n for (let oc = tCol; oc >= 0; oc--) {\n const idx = or * cols + oc;\n if (idx === cellIndex) continue;\n const a = this.getCellAttrs(blockIndex, idx);\n if (a.covered === true) continue;\n const rs = spanOf(a.rowspan);\n const cs = spanOf(a.colspan);\n if (or + rs - 1 >= tRow && oc + cs - 1 >= tCol) return idx;\n }\n }\n return undefined;\n }\n\n /**\n * Replace the document contents with a `SerializedDocument`. Runs in a single\n * `ydoc.transact` with origin `\"import\"` so the UndoManager can group or skip\n * the operation as one step.\n *\n * Reuses `createBlock` / `createTableBlock` so every block ends up with the\n * exact same Y.js shape produced by the rest of the editor.\n */\n loadFromJSON(serialized: SerializedDocument | LegacySerializedDocument): void {\n const { blocks: sourceBlocks, pageSettings } = normalizeSerialized(serialized);\n // Lock anti-concorrência: `loadFromJSON` é destrutivo (clear+push) e\n // dois imports concorrentes (especialmente entre clientes via CRDT)\n // historicamente produziram blocks duplicados em massa (caso 172k).\n // Marker em `docSettings.__importLock` com TTL 5s — se outro import\n // foi iniciado < 5s atrás, este aborta com warning ao invés de\n // sobrescrever. A janela de 5s cobre a latência de rede do Hocuspocus\n // entre clients durante imports humanos típicos.\n const LOCK_KEY = \"__importLock\";\n const LOCK_TTL_MS = 5_000;\n const existing = this.docSettings.get(LOCK_KEY);\n if (typeof existing === \"number\" && Date.now() - existing < LOCK_TTL_MS) {\n const ageMs = Date.now() - existing;\n console.warn(\n `[EditorDocument.loadFromJSON] import já em andamento (${ageMs}ms atrás, TTL ${LOCK_TTL_MS}ms) — ignorando esta chamada para evitar duplicação de blocks.`,\n );\n return;\n }\n this.docSettings.set(LOCK_KEY, Date.now());\n this.ydoc.transact(() => {\n if (this.blocks.length > 0) {\n this.blocks.delete(0, this.blocks.length);\n }\n // Build the Y structure in two passes: first create empty blocks (with\n // correct type/attrs/cells shape) and push them so their inner Y.Texts\n // get integrated into the document; only then apply each delta. Y.Text\n // requires an active transaction context that exists for integrated\n // instances — `applyDelta` on a detached Y.Text throws.\n const sources = sourceBlocks.length > 0 ? sourceBlocks : [makeEmptyParagraphSource()];\n const fresh: Y.Map<unknown>[] = sources.map((b) => buildEmptyBlockFromSerialized(b));\n this.blocks.push(fresh);\n\n for (let i = 0; i < sources.length; i++) {\n const src = sources[i];\n const yBlock = this.blocks.get(i);\n applyDeltaIntoBlock(yBlock, src);\n }\n\n if (pageSettings) {\n for (const [k, v] of Object.entries(pageSettings)) {\n if (k === \"preset\") continue;\n if (v === undefined) continue;\n this.docSettings.set(k, v);\n }\n }\n // Limpa o lock no fim do import (mesma transaction \"import\"). Se\n // crashar antes daqui, o TTL de 5s expira a entrada e o doc volta a\n // aceitar imports.\n this.docSettings.delete(LOCK_KEY);\n }, \"import\");\n }\n\n /** Build a fresh `EditorDocument` from a `SerializedDocument`. */\n static fromJSON(serialized: SerializedDocument | LegacySerializedDocument): EditorDocument {\n const ydoc = new Y.Doc();\n // Touch the shared array before loadFromJSON so the constructor doesn't\n // insert its default paragraph — we replace the contents anyway.\n ydoc.getArray<Y.Map<unknown>>(\"blocks\");\n const doc = new EditorDocument(ydoc);\n doc.loadFromJSON(serialized);\n return doc;\n }\n\n toJSON(): SerializedDocument {\n const blocks = this.blocks.toArray().map<SerializedBlock>((b) => {\n const type = (b.get(\"type\") as BlockType) ?? \"paragraph\";\n const attrsMap = b.get(\"attrs\") as Y.Map<unknown> | undefined;\n const attrs = attrsMap ? (Object.fromEntries(attrsMap.entries()) as BlockAttrs) : {};\n\n // NOTA: o `id` do bloco NÃO entra no serialized_json (mantém a forma do\n // JSON estável p/ bloat-check/API e os testes de round-trip). O id vive no\n // Y.Map e persiste no binário Yjs — é onde os cursores precisam dele.\n if (type === \"table\") {\n const cellsArray = b.get(\"cells\") as Y.Array<Y.Map<unknown>> | undefined;\n const cells: SerializedCell[] = cellsArray\n ? cellsArray.toArray().map((c) => serializeCell(c))\n : [];\n return {\n type,\n text: \"\",\n delta: [],\n attrs,\n cells,\n };\n }\n\n const yText = b.get(\"text\") as Y.Text | undefined;\n return {\n type,\n text: yText?.toString() ?? \"\",\n delta: (yText?.toDelta() as DeltaOp[] | undefined) ?? [],\n attrs,\n };\n });\n return { blocks, pageSettings: this.getPageSettings() };\n }\n}\n\nfunction normalizeSerialized(\n v: SerializedDocument | LegacySerializedDocument,\n): { blocks: SerializedBlock[]; pageSettings?: PageSettings } {\n if (isLegacySerializedDocument(v)) {\n return { blocks: v };\n }\n return { blocks: v.blocks, pageSettings: v.pageSettings };\n}\n\nfunction serializeCell(c: Y.Map<unknown>): SerializedCell {\n const yText = c.get(\"text\") as Y.Text | undefined;\n const attrsMap = c.get(\"attrs\") as Y.Map<unknown> | undefined;\n return {\n text: yText?.toString() ?? \"\",\n delta: (yText?.toDelta() as DeltaOp[] | undefined) ?? [],\n attrs: attrsMap ? (Object.fromEntries(attrsMap.entries()) as Record<string, unknown>) : {},\n };\n}\n\nexport function createBlock(\n type: BlockType,\n initialText = \"\",\n attrs?: BlockAttrs,\n): Y.Map<unknown> {\n if (type === \"table\") {\n // Callers that need a table should use createTableBlock(rows, cols).\n // We honor any rows/cols passed via attrs but default to 1x1 to keep the\n // invariant `cells.length === rows * cols` non-zero.\n const merged = { ...defaultAttrsFor(\"table\"), ...(attrs ?? {}) };\n const rows = typeof merged.rows === \"number\" && merged.rows > 0 ? Math.trunc(merged.rows) : 1;\n const cols = typeof merged.cols === \"number\" && merged.cols > 0 ? Math.trunc(merged.cols) : 1;\n return createTableBlock(rows, cols);\n }\n\n const block = new Y.Map<unknown>();\n block.set(\"id\", newBlockId());\n block.set(\"type\", type);\n const yText = new Y.Text();\n if (initialText.length > 0) yText.insert(0, initialText);\n block.set(\"text\", yText);\n const attrsMap = new Y.Map<unknown>();\n const merged = { ...defaultAttrsFor(type), ...(attrs ?? {}) };\n for (const [k, v] of Object.entries(merged)) {\n if (v !== undefined) attrsMap.set(k, v);\n }\n block.set(\"attrs\", attrsMap);\n return block;\n}\n\n/**\n * Build a table block with `rows × cols` empty cells.\n * Cells are stored in row-major order: `cell[row * cols + col]`.\n */\nexport function createTableBlock(rows: number, cols: number): Y.Map<unknown> {\n const r = Math.max(1, Math.trunc(rows));\n const c = Math.max(1, Math.trunc(cols));\n const block = new Y.Map<unknown>();\n block.set(\"id\", newBlockId());\n block.set(\"type\", \"table\");\n const attrsMap = new Y.Map<unknown>();\n attrsMap.set(\"rows\", r);\n attrsMap.set(\"cols\", c);\n block.set(\"attrs\", attrsMap);\n const cells = new Y.Array<Y.Map<unknown>>();\n const total = r * c;\n const fresh: Y.Map<unknown>[] = [];\n for (let i = 0; i < total; i++) fresh.push(createCell());\n cells.push(fresh);\n block.set(\"cells\", cells);\n return block;\n}\n\nexport function createCell(attrs?: CellAttrs): Y.Map<unknown> {\n const m = new Y.Map<unknown>();\n m.set(\"text\", new Y.Text());\n const attrsMap = new Y.Map<unknown>();\n if (attrs) {\n for (const [k, v] of Object.entries(attrs)) {\n if (v === undefined) continue;\n attrsMap.set(k, v);\n }\n }\n m.set(\"attrs\", attrsMap);\n return m;\n}\n\nfunction makeEmptyParagraphSource(): SerializedBlock {\n return { type: \"paragraph\", text: \"\", delta: [], attrs: {} };\n}\n\nfunction buildEmptyBlockFromSerialized(block: SerializedBlock): Y.Map<unknown> {\n if (block.type === \"table\") {\n const rows =\n typeof block.attrs.rows === \"number\" ? Math.max(1, Math.trunc(block.attrs.rows)) : 1;\n const cols =\n typeof block.attrs.cols === \"number\" ? Math.max(1, Math.trunc(block.attrs.cols)) : 1;\n const yBlock = new Y.Map<unknown>();\n yBlock.set(\"id\", typeof block.id === \"string\" ? block.id : newBlockId());\n yBlock.set(\"type\", \"table\");\n const attrsMap = new Y.Map<unknown>();\n attrsMap.set(\"rows\", rows);\n attrsMap.set(\"cols\", cols);\n for (const [k, v] of Object.entries(block.attrs)) {\n if (k === \"rows\" || k === \"cols\") continue;\n if (v === undefined) continue;\n attrsMap.set(k, v);\n }\n yBlock.set(\"attrs\", attrsMap);\n const cellsArr = new Y.Array<Y.Map<unknown>>();\n const total = rows * cols;\n const fresh: Y.Map<unknown>[] = [];\n const cells = block.cells ?? [];\n for (let i = 0; i < total; i++) {\n const src = cells[i];\n fresh.push(createCell((src?.attrs ?? undefined) as CellAttrs | undefined));\n }\n cellsArr.push(fresh);\n yBlock.set(\"cells\", cellsArr);\n return yBlock;\n }\n const yb = createBlock(block.type, \"\", block.attrs);\n // Preserva o id serializado (round-trip JSON), senão usa o gerado em createBlock.\n if (typeof block.id === \"string\") yb.set(\"id\", block.id);\n return yb;\n}\n\nfunction applyDeltaIntoBlock(yBlock: Y.Map<unknown> | undefined, src: SerializedBlock): void {\n if (!yBlock) return;\n if (src.type === \"table\") {\n const cellsArr = yBlock.get(\"cells\") as Y.Array<Y.Map<unknown>> | undefined;\n if (!cellsArr) return;\n const cells = src.cells ?? [];\n for (let i = 0; i < cellsArr.length; i++) {\n const cellSrc = cells[i];\n if (!cellSrc || !cellSrc.delta || cellSrc.delta.length === 0) continue;\n const cell = cellsArr.get(i);\n const yText = cell.get(\"text\") as Y.Text | undefined;\n if (!yText) continue;\n yText.applyDelta(cellSrc.delta as unknown as Array<{ insert: unknown; attributes?: unknown }>);\n }\n return;\n }\n if (!src.delta || src.delta.length === 0) return;\n const yText = yBlock.get(\"text\") as Y.Text | undefined;\n if (!yText) return;\n yText.applyDelta(src.delta as unknown as Array<{ insert: unknown; attributes?: unknown }>);\n}\n\n/** Coerce a `rowspan`/`colspan` attribute value into a positive integer. */\nexport function spanOf(value: unknown): number {\n if (typeof value !== \"number\" || !Number.isFinite(value)) return 1;\n return Math.max(1, Math.trunc(value));\n}\n","import * as Y from \"yjs\";\nimport type { EditorDocument } from \"./document\";\nimport { getBlockId } from \"./document\";\nimport type { Position, Selection } from \"./types\";\n\n/**\n * Codificação de cursor colaborativo resiliente a edição concorrente.\n *\n * Posições do editor são ABSOLUTAS ({blockIndex, offset}) — quebram quando\n * blocos/texto são inseridos/removidos acima por outro usuário. Aqui usamos\n * `Y.RelativePosition`, que ancora no caractere exato dentro do `Y.Text` e\n * sobrevive a moves/edições (é o que o Google Docs faz). O `blockId` é um\n * fallback: se o caractere ancorado foi apagado, posicionamos no início do\n * bloco original.\n */\n\n// ---------- base64 de Uint8Array (browser + node) ----------\nfunction toBase64(bytes: Uint8Array): string {\n if (typeof Buffer !== \"undefined\") return Buffer.from(bytes).toString(\"base64\");\n let s = \"\";\n for (let i = 0; i < bytes.length; i++) s += String.fromCharCode(bytes[i]);\n return btoa(s);\n}\nfunction fromBase64(b64: string): Uint8Array {\n if (typeof Buffer !== \"undefined\") return new Uint8Array(Buffer.from(b64, \"base64\"));\n const s = atob(b64);\n const out = new Uint8Array(s.length);\n for (let i = 0; i < s.length; i++) out[i] = s.charCodeAt(i);\n return out;\n}\n\n/** Y.Text que contém a posição (texto do bloco, ou de uma célula de tabela). */\nfunction yTextAt(doc: EditorDocument, pos: Position): Y.Text | null {\n const block = doc.blocks.get(pos.blockIndex);\n if (!block) return null;\n if (typeof pos.cellIndex === \"number\") {\n const cells = block.get(\"cells\") as Y.Array<Y.Map<unknown>> | undefined;\n const cell = cells?.get(pos.cellIndex);\n const t = cell?.get(\"text\");\n return t instanceof Y.Text ? t : null;\n }\n const t = block.get(\"text\");\n return t instanceof Y.Text ? t : null;\n}\n\n/** Localiza {blockIndex, cellIndex?} de um Y.Text já resolvido. O(n) nos blocos. */\nfunction locateYText(\n doc: EditorDocument,\n target: Y.Text,\n): { blockIndex: number; cellIndex?: number } | null {\n const blocks = doc.blocks;\n for (let i = 0; i < blocks.length; i++) {\n const block = blocks.get(i);\n if (block.get(\"text\") === target) return { blockIndex: i };\n const cells = block.get(\"cells\") as Y.Array<Y.Map<unknown>> | undefined;\n if (cells) {\n for (let c = 0; c < cells.length; c++) {\n if (cells.get(c)?.get(\"text\") === target) {\n return { blockIndex: i, cellIndex: c };\n }\n }\n }\n }\n return null;\n}\n\nexport interface EncodedCursorPoint {\n /** base64 de Y.encodeRelativePosition — rastreia o caractere exato. */\n rel: string;\n /** Fallback: id do bloco original (ancora no início se o char sumiu). */\n blockId?: string;\n /** Fallback: célula da tabela, se aplicável. */\n cellIndex?: number;\n}\n\nexport interface EncodedCursor {\n anchor: EncodedCursorPoint;\n focus: EncodedCursorPoint;\n}\n\nfunction encodePoint(doc: EditorDocument, pos: Position): EncodedCursorPoint | null {\n const yText = yTextAt(doc, pos);\n if (!yText) return null;\n const offset = Math.max(0, Math.min(pos.offset, yText.length));\n const rel = Y.createRelativePositionFromTypeIndex(yText, offset);\n const block = doc.blocks.get(pos.blockIndex);\n const point: EncodedCursorPoint = { rel: toBase64(Y.encodeRelativePosition(rel)) };\n const blockId = block ? getBlockId(block) : undefined;\n if (blockId) point.blockId = blockId;\n if (typeof pos.cellIndex === \"number\") point.cellIndex = pos.cellIndex;\n return point;\n}\n\nfunction decodePoint(doc: EditorDocument, enc: EncodedCursorPoint): Position | null {\n // 1) Primário: RelativePosition (rastreia o char mesmo após edições/moves).\n try {\n const rel = Y.decodeRelativePosition(fromBase64(enc.rel));\n const abs = Y.createAbsolutePositionFromRelativePosition(rel, doc.ydoc);\n if (abs && abs.type instanceof Y.Text) {\n const loc = locateYText(doc, abs.type);\n if (loc) return { ...loc, offset: abs.index };\n }\n } catch {\n /* cai no fallback */\n }\n // 2) Fallback: acha o bloco pelo id e ancora no início.\n if (enc.blockId) {\n for (let i = 0; i < doc.blocks.length; i++) {\n if (getBlockId(doc.blocks.get(i)) === enc.blockId) {\n const p: Position = { blockIndex: i, offset: 0 };\n if (typeof enc.cellIndex === \"number\") p.cellIndex = enc.cellIndex;\n return p;\n }\n }\n }\n return null;\n}\n\n/** Codifica a seleção local em um descritor portável (para o awareness). */\nexport function encodeSelection(\n doc: EditorDocument,\n sel: Selection,\n): EncodedCursor | null {\n const anchor = encodePoint(doc, sel.anchor);\n const focus = encodePoint(doc, sel.focus);\n if (!anchor || !focus) return null;\n return { anchor, focus };\n}\n\n/** Decodifica um descritor remoto para uma seleção absoluta no doc atual. */\nexport function decodeSelection(\n doc: EditorDocument,\n enc: EncodedCursor,\n): Selection | null {\n const anchor = decodePoint(doc, enc.anchor);\n const focus = decodePoint(doc, enc.focus);\n if (!anchor || !focus) return null;\n return { anchor, focus };\n}\n","import type { Position, Selection } from \"./types\";\n\nexport function isCollapsed(sel: Selection): boolean {\n return positionsEqual(sel.anchor, sel.focus);\n}\n\nexport function positionsEqual(a: Position, b: Position): boolean {\n return (\n a.blockIndex === b.blockIndex &&\n (a.cellIndex ?? -1) === (b.cellIndex ?? -1) &&\n a.offset === b.offset\n );\n}\n\nexport function comparePositions(a: Position, b: Position): number {\n if (a.blockIndex !== b.blockIndex) return a.blockIndex - b.blockIndex;\n const ac = a.cellIndex ?? -1;\n const bc = b.cellIndex ?? -1;\n if (ac !== bc) return ac - bc;\n return a.offset - b.offset;\n}\n\nexport function orderedRange(sel: Selection): { start: Position; end: Position } {\n if (comparePositions(sel.anchor, sel.focus) <= 0) {\n return { start: sel.anchor, end: sel.focus };\n }\n return { start: sel.focus, end: sel.anchor };\n}\n\nexport function collapsedSelection(pos: Position): Selection {\n return { anchor: pos, focus: pos };\n}\n\n/**\n * Two positions are in the same \"editable run\" (same Y.Text) when they share\n * the block index AND the cellIndex (treating absent and present-with-undefined\n * the same way: a non-table position has cellIndex === undefined for both).\n */\nexport function sameTextRun(a: Position, b: Position): boolean {\n return a.blockIndex === b.blockIndex && (a.cellIndex ?? -1) === (b.cellIndex ?? -1);\n}\n","import type * as Y from \"yjs\";\nimport type { DeltaOp, MarkAttrs, MarkName } from \"./types\";\n\n/**\n * Helpers for reading mark attributes off a Y.Text by inspecting its delta.\n * Writing is done with `yText.format(...)` directly in commands.ts.\n */\n\n/**\n * Every mark name as a runtime record. Typed as `Record<MarkName, true>` so the\n * object is compiler-enforced to stay complete: adding a new `MarkName` fails to\n * compile until it's listed here.\n */\nconst ALL_MARKS: Record<MarkName, true> = {\n bold: true,\n italic: true,\n underline: true,\n strike: true,\n color: true,\n fontFamily: true,\n fontSize: true,\n link: true,\n comment: true,\n};\n\n/**\n * Attributes object that explicitly clears every mark (sets each to `null`).\n * Spread your desired marks on top to insert text carrying EXACTLY those marks,\n * overriding any formatting Y.Text would otherwise inherit from an adjacent run.\n */\nexport const CLEAR_ALL_MARKS: Record<string, null> = Object.fromEntries(\n Object.keys(ALL_MARKS).map((k) => [k, null]),\n);\n\nfunction iterateRunsInRange(\n yText: Y.Text,\n start: number,\n end: number,\n visit: (run: DeltaOp, runStart: number, runEnd: number) => void,\n): void {\n if (start >= end) return;\n const delta = yText.toDelta() as DeltaOp[];\n let cursor = 0;\n for (const op of delta) {\n if (typeof op.insert !== \"string\") {\n // Embed: advance cursor (counts as 1 char) but don't visit — mark queries\n // are about text runs, not embed attributes.\n if (op.insert == null) continue;\n cursor += 1;\n if (cursor > end) break;\n continue;\n }\n const opStart = cursor;\n const opEnd = cursor + op.insert.length;\n cursor = opEnd;\n if (opEnd <= start) continue;\n if (opStart >= end) break;\n const runStart = Math.max(opStart, start);\n const runEnd = Math.min(opEnd, end);\n visit(op, runStart, runEnd);\n }\n}\n\n/**\n * Returns the marks observed across `[start, end)`. For each mark name encountered:\n * - if every covered character has the same value, returns that value\n * - if values differ OR some characters lack the mark, returns \"mixed\"\n */\nexport function getMarksInRange(\n yText: Y.Text,\n start: number,\n end: number,\n): Partial<Record<MarkName, MarkAttrs[MarkName] | \"mixed\">> {\n const result: Partial<Record<MarkName, MarkAttrs[MarkName] | \"mixed\">> = {};\n if (start >= end) return result;\n\n // Track total covered length and per-mark covered length to detect \"some chars lacked it\".\n const total = end - start;\n const coveredByName: Partial<Record<MarkName, number>> = {};\n\n iterateRunsInRange(yText, start, end, (run, runStart, runEnd) => {\n const len = runEnd - runStart;\n const attrs = (run.attributes ?? {}) as MarkAttrs;\n (Object.keys(attrs) as MarkName[]).forEach((name) => {\n const value = attrs[name];\n if (value === undefined || value === null) return;\n const prev = result[name];\n if (prev === undefined) {\n result[name] = value;\n } else if (prev !== \"mixed\" && !sameMarkValue(prev, value)) {\n result[name] = \"mixed\";\n }\n coveredByName[name] = (coveredByName[name] ?? 0) + len;\n });\n });\n\n (Object.keys(result) as MarkName[]).forEach((name) => {\n if ((coveredByName[name] ?? 0) < total) {\n result[name] = \"mixed\";\n }\n });\n\n return result;\n}\n\nexport function isMarkUniformInRange(\n yText: Y.Text,\n start: number,\n end: number,\n name: MarkName,\n value?: MarkAttrs[MarkName],\n): boolean {\n if (start >= end) return false;\n const total = end - start;\n let covered = 0;\n let observed: MarkAttrs[MarkName] | undefined;\n let ok = true;\n iterateRunsInRange(yText, start, end, (run, runStart, runEnd) => {\n if (!ok) return;\n const len = runEnd - runStart;\n const attr = (run.attributes ?? {})[name];\n if (attr === undefined || attr === null) {\n ok = false;\n return;\n }\n if (value !== undefined && !sameMarkValue(value, attr)) {\n ok = false;\n return;\n }\n if (observed === undefined) {\n observed = attr;\n } else if (!sameMarkValue(observed, attr)) {\n ok = false;\n return;\n }\n covered += len;\n });\n return ok && covered === total;\n}\n\n/** Total number of inserted characters. Embeds (non-string inserts) count as 1. */\nexport function deltaLength(delta: DeltaOp[]): number {\n let sum = 0;\n for (const op of delta) {\n if (typeof op.insert === \"string\") sum += op.insert.length;\n else if (op.insert != null) sum += 1;\n }\n return sum;\n}\n\n/**\n * Return the subset of `delta` covering `[start, end)` characters.\n * Embeds are atomic length-1 ops: included whole if their slot intersects the range.\n */\nexport function sliceDelta(delta: DeltaOp[], start: number, end: number): DeltaOp[] {\n if (end <= start) return [];\n const out: DeltaOp[] = [];\n let cursor = 0;\n for (const op of delta) {\n if (typeof op.insert === \"string\") {\n const opStart = cursor;\n const opEnd = cursor + op.insert.length;\n cursor = opEnd;\n if (opEnd <= start) continue;\n if (opStart >= end) break;\n const sliceFrom = Math.max(opStart, start) - opStart;\n const sliceTo = Math.min(opEnd, end) - opStart;\n out.push({\n insert: op.insert.slice(sliceFrom, sliceTo),\n attributes: op.attributes,\n });\n } else if (op.insert != null) {\n const opStart = cursor;\n const opEnd = cursor + 1;\n cursor = opEnd;\n if (opEnd <= start) continue;\n if (opStart >= end) break;\n out.push({ insert: op.insert, attributes: op.attributes });\n }\n }\n return out;\n}\n\nfunction sameMarkValue(a: unknown, b: unknown): boolean {\n if (a === b) return true;\n if (typeof a === \"object\" && typeof b === \"object\" && a && b) {\n const aKeys = Object.keys(a);\n const bKeys = Object.keys(b);\n if (aKeys.length !== bKeys.length) return false;\n return aKeys.every((k) => (a as Record<string, unknown>)[k] === (b as Record<string, unknown>)[k]);\n }\n return false;\n}\n","import * as Y from \"yjs\";\nimport { EditorDocument, createBlock, createCell, createTableBlock, spanOf } from \"./document\";\nimport { CLEAR_ALL_MARKS, deltaLength, isMarkUniformInRange, sliceDelta } from \"./marks\";\nimport { sliceToInlineDelta, type ClipboardSlice } from \"./clipboard\";\nimport { defaultAttrsFor } from \"./schema\";\nimport { collapsedSelection, isCollapsed, orderedRange, sameTextRun } from \"./selection\";\nimport type {\n BlockAttrs,\n BlockType,\n CellAttrs,\n DeltaOp,\n ImageEmbed,\n ListKind,\n MarkAttrs,\n MarkName,\n Position,\n Selection,\n} from \"./types\";\nimport { isImageEmbed, MAX_LIST_LEVEL } from \"./types\";\n\nexport const COMMAND_ORIGIN: unique symbol = Symbol(\"editor-command\");\n\nexport interface CommandContext {\n doc: EditorDocument;\n getSelection: () => Selection;\n setSelection: (sel: Selection) => void;\n}\n\nfunction transact(doc: EditorDocument, fn: () => void): void {\n doc.ydoc.transact(fn, COMMAND_ORIGIN);\n}\n\n/**\n * Insert text at the current selection.\n *\n * `marks` is an explicit override map applied to the freshly inserted range.\n * - Entry value: apply that mark value.\n * - Entry value `null`: clear that mark (used when the UI just toggled it off\n * with a collapsed caret and the next typed char must NOT inherit the\n * surrounding run's attribute).\n * - When `marks` is undefined, Y.Text's default inheritance applies (good for\n * normal typing inside a marked run).\n */\nexport function insertText(\n ctx: CommandContext,\n text: string,\n marks?: Partial<Record<MarkName, MarkAttrs[MarkName] | null>>,\n): void {\n if (text.length === 0) return;\n // Rectangular cell selection: clear all selected cells, collapse to top-left,\n // then insert into the owner like a normal call.\n const collapsedFromRect = clearRectCells(ctx);\n transact(ctx.doc, () => {\n const sel = collapsedFromRect ?? ctx.getSelection();\n let cursor = sel;\n if (!isCollapsed(sel)) {\n cursor = deleteRange(ctx.doc, sel);\n }\n const pos = cursor.focus;\n const yText = ctx.doc.textAt(pos.blockIndex, pos.cellIndex);\n if (!yText) return;\n yText.insert(pos.offset, text);\n if (marks && Object.keys(marks).length > 0) {\n yText.format(pos.offset, text.length, marks as Record<string, unknown>);\n }\n const newPos: Position = {\n blockIndex: pos.blockIndex,\n cellIndex: pos.cellIndex,\n offset: pos.offset + text.length,\n };\n ctx.setSelection(collapsedSelection(newPos));\n });\n}\n\nexport function insertParagraph(ctx: CommandContext): void {\n // Rectangular selection: collapse + clear first.\n clearRectCells(ctx);\n transact(ctx.doc, () => {\n const sel = ctx.getSelection();\n let cursor = sel;\n if (!isCollapsed(sel)) {\n cursor = deleteRange(ctx.doc, sel);\n }\n const pos = cursor.focus;\n // Inside a table cell, Enter inserts a literal newline rather than splitting\n // the cell into two paragraphs. Cells in 4.1 are single-text containers; we\n // rely on `white-space: pre-wrap` in CSS to render the line break visibly.\n if (pos.cellIndex != null) {\n const yText = ctx.doc.getCellText(pos.blockIndex, pos.cellIndex);\n if (!yText) return;\n yText.insert(pos.offset, \"\\n\");\n ctx.setSelection(\n collapsedSelection({\n blockIndex: pos.blockIndex,\n cellIndex: pos.cellIndex,\n offset: pos.offset + 1,\n }),\n );\n return;\n }\n const yText = ctx.doc.getBlockText(pos.blockIndex);\n if (!yText) return;\n\n const totalLen = yText.length;\n // Read the tail's delta (preserves marks) before mutating yText.\n const tailDelta = totalLen > pos.offset\n ? sliceDelta(yText.toDelta() as DeltaOp[], pos.offset, totalLen)\n : [];\n\n if (totalLen > pos.offset) {\n yText.delete(pos.offset, totalLen - pos.offset);\n }\n\n const newBlock = createBlock(\"paragraph\");\n ctx.doc.blocks.insert(pos.blockIndex + 1, [newBlock]);\n if (tailDelta.length > 0) {\n const newYText = newBlock.get(\"text\") as Y.Text;\n writeDeltaInto(newYText, 0, tailDelta);\n }\n\n const newPos: Position = { blockIndex: pos.blockIndex + 1, offset: 0 };\n ctx.setSelection(collapsedSelection(newPos));\n });\n}\n\nexport function deleteBackward(ctx: CommandContext): void {\n // Rectangular selection: clear text of every selected cell and collapse to\n // the rect's top-left, then return — no further character delete needed.\n if (clearRectCells(ctx)) return;\n transact(ctx.doc, () => {\n const sel = ctx.getSelection();\n if (!isCollapsed(sel)) {\n const cursor = deleteRange(ctx.doc, sel);\n ctx.setSelection(cursor);\n return;\n }\n const pos = sel.focus;\n if (pos.offset > 0) {\n const yText = ctx.doc.textAt(pos.blockIndex, pos.cellIndex);\n if (!yText) return;\n yText.delete(pos.offset - 1, 1);\n ctx.setSelection(\n collapsedSelection({\n blockIndex: pos.blockIndex,\n cellIndex: pos.cellIndex,\n offset: pos.offset - 1,\n }),\n );\n return;\n }\n // offset === 0\n // Inside a table cell, backspace at the cell start is a no-op — the user\n // cannot escape the table by pressing backspace.\n if (pos.cellIndex != null) return;\n // At offset 0: if it's a listItem, dedent (or convert to paragraph at level 0)\n // before falling back to merging with the previous block.\n const blockType = ctx.doc.getBlockType(pos.blockIndex);\n if (blockType === \"listItem\") {\n const block = ctx.doc.getBlock(pos.blockIndex);\n const attrsMap = block?.get(\"attrs\") as Y.Map<unknown> | undefined;\n const rawLevel = attrsMap?.get(\"listLevel\") as number | undefined;\n const level = typeof rawLevel === \"number\" && Number.isFinite(rawLevel)\n ? Math.max(0, Math.min(MAX_LIST_LEVEL, Math.trunc(rawLevel)))\n : 0;\n if (level > 0) {\n attrsMap!.set(\"listLevel\", level - 1);\n ctx.setSelection(collapsedSelection(pos));\n return;\n }\n // Level 0 listItem → convert to paragraph (escape the list).\n setBlockTypeAtIndex(ctx.doc, pos.blockIndex, \"paragraph\", {});\n ctx.setSelection(collapsedSelection(pos));\n return;\n }\n if (pos.blockIndex > 0) {\n const prevType = ctx.doc.getBlockType(pos.blockIndex - 1);\n if (prevType === \"table\") {\n // Can't merge with a table; move caret to the table's last cell instead.\n const tableIdx = pos.blockIndex - 1;\n const { rows, cols } = ctx.doc.getTableSize(tableIdx);\n const lastCell = rows * cols - 1;\n const cellText = ctx.doc.getCellText(tableIdx, lastCell);\n const off = cellText?.length ?? 0;\n ctx.setSelection(\n collapsedSelection({ blockIndex: tableIdx, cellIndex: lastCell, offset: off }),\n );\n return;\n }\n mergeWithPrevious(ctx, pos.blockIndex);\n }\n });\n}\n\nexport function deleteForward(ctx: CommandContext): void {\n if (clearRectCells(ctx)) return;\n transact(ctx.doc, () => {\n const sel = ctx.getSelection();\n if (!isCollapsed(sel)) {\n const cursor = deleteRange(ctx.doc, sel);\n ctx.setSelection(cursor);\n return;\n }\n const pos = sel.focus;\n const yText = ctx.doc.textAt(pos.blockIndex, pos.cellIndex);\n if (!yText) return;\n if (pos.offset < yText.length) {\n yText.delete(pos.offset, 1);\n ctx.setSelection(collapsedSelection(pos));\n return;\n }\n // at end of editable run\n // Inside a table cell, forward-delete at the cell end is a no-op.\n if (pos.cellIndex != null) return;\n // at end of block: merge next into current (but tables are atomic)\n if (pos.blockIndex + 1 < ctx.doc.blockCount()) {\n const nextType = ctx.doc.getBlockType(pos.blockIndex + 1);\n if (nextType === \"table\") {\n // Jump caret into the table's first cell.\n const tableIdx = pos.blockIndex + 1;\n ctx.setSelection(collapsedSelection({ blockIndex: tableIdx, cellIndex: 0, offset: 0 }));\n return;\n }\n const nextText = ctx.doc.getBlockText(pos.blockIndex + 1);\n if (!nextText) return;\n const tail = nextText.toString();\n if (tail.length > 0) yText.insert(yText.length, tail);\n ctx.doc.blocks.delete(pos.blockIndex + 1, 1);\n ctx.setSelection(collapsedSelection(pos));\n }\n });\n}\n\n// ---------- Marks ----------\n\nconst booleanMarks: Set<MarkName> = new Set([\"bold\", \"italic\", \"underline\", \"strike\"]);\n\n/**\n * Toggle a mark across the current selection.\n * - If the selection is collapsed: no-op (the UI layer handles pendingMarks).\n * - Boolean marks (bold/italic/underline/strike): if every character already has\n * the mark, remove it; otherwise apply.\n * - Parametric marks (color, fontFamily, fontSize, link): require `value` to apply;\n * when uniform with that value across the range, remove instead (acts like toggle).\n */\nexport function toggleMark(\n ctx: CommandContext,\n name: MarkName,\n value?: MarkAttrs[MarkName],\n): void {\n const sel = ctx.getSelection();\n if (isCollapsed(sel)) return;\n transact(ctx.doc, () => {\n const { start, end } = orderedRange(sel);\n forEachBlockTextInRange(ctx.doc, start, end, (yText, localStart, localEnd) => {\n const uniform = isMarkUniformInRange(yText, localStart, localEnd, name, value);\n const attrs: Record<string, unknown> = {};\n if (uniform) {\n attrs[name] = null;\n } else {\n attrs[name] = value ?? (booleanMarks.has(name) ? true : null);\n }\n if (attrs[name] === null && !uniform) return;\n yText.format(localStart, localEnd - localStart, attrs);\n });\n ctx.setSelection(sel);\n });\n}\n\nexport function setMark(\n ctx: CommandContext,\n name: MarkName,\n value: MarkAttrs[MarkName],\n): void {\n const sel = ctx.getSelection();\n if (isCollapsed(sel)) return;\n transact(ctx.doc, () => {\n const { start, end } = orderedRange(sel);\n forEachBlockTextInRange(ctx.doc, start, end, (yText, localStart, localEnd) => {\n yText.format(localStart, localEnd - localStart, { [name]: value });\n });\n ctx.setSelection(sel);\n });\n}\n\nexport function removeMark(ctx: CommandContext, name: MarkName): void {\n const sel = ctx.getSelection();\n if (isCollapsed(sel)) return;\n transact(ctx.doc, () => {\n const { start, end } = orderedRange(sel);\n forEachBlockTextInRange(ctx.doc, start, end, (yText, localStart, localEnd) => {\n yText.format(localStart, localEnd - localStart, { [name]: null });\n });\n ctx.setSelection(sel);\n });\n}\n\n// ---------- Block-level commands (Sub-phase 2.2) ----------\n\n/**\n * Change the type of every block covered by the current selection.\n * When `attrs` is provided, merges those on top of the new type's defaults.\n * Preserves `Y.Text` content (and therefore all inline marks) and the selection.\n */\nexport function setBlockType(\n ctx: CommandContext,\n type: BlockType,\n attrs?: BlockAttrs,\n): void {\n transact(ctx.doc, () => {\n const sel = ctx.getSelection();\n // Inert when the caret is inside a cell — block-level operations only\n // apply to top-level blocks (the table itself), and changing a table's\n // block type is not exposed in 4.1.\n if (sel.anchor.cellIndex != null || sel.focus.cellIndex != null) return;\n const indices = selectedBlockIndices(sel, ctx.doc.blockCount());\n for (const i of indices) {\n const block = ctx.doc.getBlock(i);\n if (!block) continue;\n block.set(\"type\", type);\n const attrsMap = (block.get(\"attrs\") as Y.Map<unknown> | undefined) ?? new Y.Map<unknown>();\n if (!block.get(\"attrs\")) block.set(\"attrs\", attrsMap);\n // Reset attrs to the new type's defaults, then layer caller overrides.\n // Strategy: clear keys that aren't in either map, then write new ones.\n const next = { ...defaultAttrsFor(type), ...(attrs ?? {}) };\n const keep = new Set(Object.keys(next));\n for (const k of Array.from(attrsMap.keys())) {\n if (!keep.has(k)) attrsMap.delete(k);\n }\n for (const [k, v] of Object.entries(next)) {\n if (v === undefined) continue;\n if (attrsMap.get(k) !== v) attrsMap.set(k, v);\n }\n }\n ctx.setSelection(sel);\n });\n}\n\n/**\n * Set a single attribute on every block covered by the selection.\n * Passing `value === null` deletes the key.\n */\nexport function setBlockAttr<K extends keyof BlockAttrs>(\n ctx: CommandContext,\n key: K,\n value: BlockAttrs[K] | null,\n): void {\n transact(ctx.doc, () => {\n const sel = ctx.getSelection();\n if (sel.anchor.cellIndex != null || sel.focus.cellIndex != null) return;\n const indices = selectedBlockIndices(sel, ctx.doc.blockCount());\n for (const i of indices) {\n const block = ctx.doc.getBlock(i);\n if (!block) continue;\n const attrsMap = (block.get(\"attrs\") as Y.Map<unknown> | undefined) ?? new Y.Map<unknown>();\n if (!block.get(\"attrs\")) block.set(\"attrs\", attrsMap);\n if (value === null || value === undefined) {\n attrsMap.delete(key as string);\n } else {\n attrsMap.set(key as string, value);\n }\n }\n ctx.setSelection(sel);\n });\n}\n\n/**\n * Set a single attribute on the table cell(s) under the selection.\n * - Caret numa única célula → essa célula (tableRectSelection retorna null\n * para seleção colapsada (ou âncora/foco no mesmo owner), então usamos\n * a célula focada (redirecionada ao owner real).\n * - Seleção retangular de várias células → todas as células reais do rect.\n * Células `covered` são puladas. `value === null` apaga a key.\n * No-op se a seleção não estiver dentro de uma tabela.\n */\nexport function setCellAttr<K extends keyof CellAttrs>(\n ctx: CommandContext,\n key: K,\n value: CellAttrs[K] | null,\n): void {\n transact(ctx.doc, () => {\n const sel = ctx.getSelection();\n const { blockIndex, cellIndex } = sel.focus;\n if (cellIndex == null || !ctx.doc.isTable(blockIndex)) return;\n const { cols } = ctx.doc.getTableSize(blockIndex);\n if (cols <= 0) return;\n const rect = tableRectSelection(ctx.doc, sel);\n const targets: number[] = [];\n if (rect) {\n for (let r = rect.top; r <= rect.bottom; r++)\n for (let c = rect.left; c <= rect.right; c++) targets.push(r * cols + c);\n } else {\n const real = ctx.doc.realCellIndex(blockIndex, cellIndex);\n if (real != null) targets.push(real);\n }\n for (const flat of targets) {\n if (ctx.doc.getCellAttrs(blockIndex, flat).covered) continue;\n const m = ctx.doc.getCellAttrsMap(blockIndex, flat);\n if (!m) continue;\n if (value === null || value === undefined) m.delete(key as string);\n else m.set(key as string, value);\n }\n ctx.setSelection(sel);\n });\n}\n\n/** Delete the current selection range and collapse the caret. Used by cut. */\nexport function deleteSelection(ctx: CommandContext): void {\n transact(ctx.doc, () => {\n const s = deleteRange(ctx.doc, ctx.getSelection());\n ctx.setSelection(s);\n });\n}\n\n/**\n * Replace the current selection with a clipboard slice (A1).\n * - Single-block slice → inline splice (Dhead + S0 + Dtail), target keeps its type.\n * - Multi-block slice → openStart merges S0 inline; middle/last blocks inserted\n * discretely; openEnd appends the post-caret tail onto the last pasted block.\n * - Target inside a table cell → slice flattened to inline (no block structure).\n */\nexport function insertSlice(ctx: CommandContext, slice: ClipboardSlice): void {\n if (!slice.blocks || slice.blocks.length === 0) return;\n transact(ctx.doc, () => {\n let sel = ctx.getSelection();\n if (!isCollapsed(sel)) sel = deleteRange(ctx.doc, sel);\n const { blockIndex, cellIndex, offset } = sel.focus;\n\n if (cellIndex != null) {\n const cellText = ctx.doc.textAt(blockIndex, cellIndex);\n if (!cellText) return;\n const after = writeDeltaInto(cellText, offset, sliceToInlineDelta(slice));\n ctx.setSelection(collapsedSelection({ blockIndex, cellIndex, offset: after }));\n return;\n }\n\n const targetText = ctx.doc.getBlockText(blockIndex);\n if (!targetText) return;\n\n const full = targetText.toDelta() as DeltaOp[];\n const tailDelta = sliceDelta(full, offset, deltaLength(full));\n targetText.delete(offset, targetText.length - offset);\n\n const blocks = slice.blocks;\n\n if (blocks.length === 1) {\n const afterS0 = writeDeltaInto(targetText, offset, blocks[0].delta);\n writeDeltaInto(targetText, afterS0, tailDelta);\n ctx.setSelection(collapsedSelection({ blockIndex, offset: afterS0 }));\n return;\n }\n\n // Multi-block. Capture the target's original type/attrs BEFORE any mutation,\n // for the !openEnd tail block.\n const originalType = ctx.doc.getBlockType(blockIndex);\n const originalAttrs = ctx.doc.getBlockAttrs(blockIndex);\n let insertAt = blockIndex;\n\n // First block.\n if (slice.openStart) {\n // Partial fragment → merge S0 inline into the target (Dhead already present);\n // target keeps its own type.\n writeDeltaInto(targetText, offset, blocks[0].delta);\n } else if (offset === 0) {\n // Whole-block fragment pasted into an empty Dhead → reuse the empty target\n // AS S0 in place (adopt S0's type/attrs), avoiding a stray leading block.\n const blk = ctx.doc.blocks.get(blockIndex) as Y.Map<unknown>;\n blk.set(\"type\", blocks[0].type);\n const am = blk.get(\"attrs\") as Y.Map<unknown>;\n am.clear();\n for (const [k, v] of Object.entries(blocks[0].attrs)) {\n if (v !== undefined) am.set(k, v);\n }\n writeDeltaInto(targetText, 0, blocks[0].delta);\n } else {\n // Whole-block fragment after a non-empty Dhead → S0 as its own block.\n const b = createBlock(blocks[0].type, \"\", blocks[0].attrs);\n ctx.doc.blocks.insert(++insertAt, [b]);\n writeDeltaInto(b.get(\"text\") as Y.Text, 0, blocks[0].delta);\n }\n\n // Middle blocks (whole).\n for (let i = 1; i < blocks.length - 1; i++) {\n const b = createBlock(blocks[i].type, \"\", blocks[i].attrs);\n ctx.doc.blocks.insert(++insertAt, [b]);\n writeDeltaInto(b.get(\"text\") as Y.Text, 0, blocks[i].delta);\n }\n\n // Last block.\n const last = blocks[blocks.length - 1];\n if (slice.openEnd) {\n const b = createBlock(last.type, \"\", last.attrs);\n ctx.doc.blocks.insert(++insertAt, [b]);\n const t = b.get(\"text\") as Y.Text;\n const caretPos = writeDeltaInto(t, 0, last.delta);\n writeDeltaInto(t, caretPos, tailDelta);\n ctx.setSelection(collapsedSelection({ blockIndex: insertAt, offset: caretPos }));\n } else {\n const b = createBlock(last.type, \"\", last.attrs);\n ctx.doc.blocks.insert(++insertAt, [b]);\n const lastLen = writeDeltaInto(b.get(\"text\") as Y.Text, 0, last.delta);\n const lastIdx = insertAt;\n // Only materialize the tail block when there's actually a tail (avoids a\n // stray empty block when pasting at end-of-line).\n if (tailDelta.length > 0) {\n const tb = createBlock(originalType ?? \"paragraph\", \"\", originalAttrs);\n ctx.doc.blocks.insert(++insertAt, [tb]);\n writeDeltaInto(tb.get(\"text\") as Y.Text, 0, tailDelta);\n }\n ctx.setSelection(collapsedSelection({ blockIndex: lastIdx, offset: lastLen }));\n }\n });\n}\n\nfunction selectedBlockIndices(sel: Selection, blockCount: number): number[] {\n const { start, end } = orderedRange(sel);\n const out: number[] = [];\n const last = Math.min(end.blockIndex, blockCount - 1);\n for (let i = Math.max(start.blockIndex, 0); i <= last; i++) out.push(i);\n return out;\n}\n\nfunction forEachBlockTextInRange(\n doc: EditorDocument,\n start: Position,\n end: Position,\n visit: (yText: Y.Text, localStart: number, localEnd: number) => void,\n): void {\n // Same text-run (block or cell): straightforward.\n if (sameTextRun(start, end)) {\n const yText = doc.textAt(start.blockIndex, start.cellIndex);\n if (!yText) return;\n if (start.offset < end.offset) visit(yText, start.offset, end.offset);\n return;\n }\n // Cross-run selections involving a cell are currently treated as inert for\n // mark application; the UI surfaces them as \"no-op\" rather than partially\n // applying marks across mismatched runs.\n if (start.cellIndex != null || end.cellIndex != null) return;\n\n for (let i = start.blockIndex; i <= end.blockIndex; i++) {\n const yText = doc.getBlockText(i);\n if (!yText) continue;\n const localStart = i === start.blockIndex ? start.offset : 0;\n const localEnd = i === end.blockIndex ? end.offset : yText.length;\n if (localStart < localEnd) visit(yText, localStart, localEnd);\n }\n}\n\n/**\n * Deletes the content of a non-collapsed selection.\n * Returns the new collapsed selection at the deletion point.\n * Must be called inside a Y.Doc transaction.\n *\n * Selections that span DIFFERENT text-runs (different blocks, or two cells of\n * the same table) are bridged conservatively:\n * - Same text-run (block+cell): delete the range normally.\n * - Different runs but both outside tables (i.e. cellIndex undefined on both):\n * delete and merge blocks as before.\n * - Otherwise (one endpoint is in a table cell): no destructive cross-cell\n * delete in 4.1; collapse to `start` instead.\n */\nfunction deleteRange(doc: EditorDocument, sel: Selection): Selection {\n const { start, end } = orderedRange(sel);\n\n if (sameTextRun(start, end)) {\n const yText = doc.textAt(start.blockIndex, start.cellIndex);\n if (yText) yText.delete(start.offset, end.offset - start.offset);\n return collapsedSelection(start);\n }\n\n // Reject cross-cell / cross-table-to-paragraph multi-run deletions for now.\n if (start.cellIndex != null || end.cellIndex != null) {\n return collapsedSelection(start);\n }\n\n const startText = doc.getBlockText(start.blockIndex);\n const endText = doc.getBlockText(end.blockIndex);\n if (!startText || !endText) return collapsedSelection(start);\n\n // Trim tail of start block\n startText.delete(start.offset, startText.length - start.offset);\n // Read remaining tail from end block, after the deleted prefix\n const remainingTail = endText.toString().slice(end.offset);\n if (remainingTail.length > 0) {\n startText.insert(startText.length, remainingTail);\n }\n // Remove all blocks between start (exclusive) and end (inclusive)\n doc.blocks.delete(start.blockIndex + 1, end.blockIndex - start.blockIndex);\n return collapsedSelection(start);\n}\n\nfunction mergeWithPrevious(ctx: CommandContext, blockIndex: number): void {\n const prevText = ctx.doc.getBlockText(blockIndex - 1);\n const currText = ctx.doc.getBlockText(blockIndex);\n if (!prevText || !currText) return;\n const prevLen = prevText.length;\n const tail = currText.toString();\n if (tail.length > 0) prevText.insert(prevLen, tail);\n ctx.doc.blocks.delete(blockIndex, 1);\n ctx.setSelection(collapsedSelection({ blockIndex: blockIndex - 1, offset: prevLen }));\n}\n\n// ---------- List commands (Sub-phase 2.3) ----------\n\n/**\n * Convert every block in the selection to/from a `listItem` of `kind`.\n * If every covered block is already a `listItem` of `kind` → convert them all to paragraphs.\n * Otherwise → convert them all to `listItem` (keeping existing `listLevel` when already\n * a listItem, defaulting to 0 otherwise).\n */\nexport function toggleList(ctx: CommandContext, kind: ListKind): void {\n transact(ctx.doc, () => {\n const sel = ctx.getSelection();\n if (sel.anchor.cellIndex != null || sel.focus.cellIndex != null) return;\n const indices = selectedBlockIndices(sel, ctx.doc.blockCount());\n const allMatching = indices.every((i) => {\n const block = ctx.doc.getBlock(i);\n if (!block) return false;\n if (block.get(\"type\") !== \"listItem\") return false;\n const attrs = ctx.doc.getBlockAttrs(i);\n return attrs.listKind === kind;\n });\n for (const i of indices) {\n if (allMatching) {\n // Strip list → paragraph (defaults reset).\n setBlockTypeAtIndex(ctx.doc, i, \"paragraph\", {});\n } else {\n const prev = ctx.doc.getBlockAttrs(i);\n const level = clampLevel(prev.listLevel);\n setBlockTypeAtIndex(ctx.doc, i, \"listItem\", { listKind: kind, listLevel: level });\n }\n }\n ctx.setSelection(sel);\n });\n}\n\n/** Increase nesting of every listItem in the selection (clamped to MAX_LIST_LEVEL). */\nexport function indentList(ctx: CommandContext): void {\n transact(ctx.doc, () => {\n const sel = ctx.getSelection();\n if (sel.anchor.cellIndex != null || sel.focus.cellIndex != null) return;\n const indices = selectedBlockIndices(sel, ctx.doc.blockCount());\n for (const i of indices) {\n const block = ctx.doc.getBlock(i);\n if (!block || block.get(\"type\") !== \"listItem\") continue;\n const attrsMap = block.get(\"attrs\") as Y.Map<unknown>;\n const current = clampLevel((attrsMap.get(\"listLevel\") as number | undefined) ?? 0);\n const next = Math.min(current + 1, MAX_LIST_LEVEL);\n if (next !== current) attrsMap.set(\"listLevel\", next);\n }\n ctx.setSelection(sel);\n });\n}\n\n/**\n * Decrease nesting of every listItem in the selection.\n * When level was 0, demote to paragraph (escape from the list).\n */\nexport function dedentList(ctx: CommandContext): void {\n transact(ctx.doc, () => {\n const sel = ctx.getSelection();\n if (sel.anchor.cellIndex != null || sel.focus.cellIndex != null) return;\n const indices = selectedBlockIndices(sel, ctx.doc.blockCount());\n for (const i of indices) {\n const block = ctx.doc.getBlock(i);\n if (!block || block.get(\"type\") !== \"listItem\") continue;\n const attrsMap = block.get(\"attrs\") as Y.Map<unknown>;\n const current = clampLevel((attrsMap.get(\"listLevel\") as number | undefined) ?? 0);\n if (current > 0) {\n attrsMap.set(\"listLevel\", current - 1);\n } else {\n // Escape from the list at level 0.\n setBlockTypeAtIndex(ctx.doc, i, \"paragraph\", {});\n }\n }\n ctx.setSelection(sel);\n });\n}\n\n/**\n * Enter behavior inside a listItem.\n * - Empty listItem at level > 0 → dedent (stays a listItem, one level out).\n * - Empty listItem at level 0 → convert to paragraph (exit the list).\n * - Non-empty → split: tail moves to a new listItem with same kind/level.\n *\n * Returns `true` when it handled the event; `false` to let the default `insertParagraph` run.\n */\nexport function splitListItem(ctx: CommandContext): boolean {\n const sel = ctx.getSelection();\n if (!isCollapsed(sel)) return false;\n const pos = sel.focus;\n // Inside a table cell, Enter is handled by insertParagraph (newline within cell).\n if (pos.cellIndex != null) return false;\n const block = ctx.doc.getBlock(pos.blockIndex);\n if (!block || block.get(\"type\") !== \"listItem\") return false;\n const yText = ctx.doc.getBlockText(pos.blockIndex);\n if (!yText) return false;\n\n const attrs = ctx.doc.getBlockAttrs(pos.blockIndex);\n const kind = (attrs.listKind ?? \"bullet\") as ListKind;\n const level = clampLevel(attrs.listLevel ?? 0);\n\n transact(ctx.doc, () => {\n if (yText.length === 0) {\n if (level > 0) {\n const m = block.get(\"attrs\") as Y.Map<unknown>;\n m.set(\"listLevel\", level - 1);\n } else {\n setBlockTypeAtIndex(ctx.doc, pos.blockIndex, \"paragraph\", {});\n }\n ctx.setSelection(collapsedSelection({ blockIndex: pos.blockIndex, offset: 0 }));\n return;\n }\n const tail = yText.toString().slice(pos.offset);\n if (tail.length > 0) yText.delete(pos.offset, tail.length);\n ctx.doc.blocks.insert(pos.blockIndex + 1, [\n createBlock(\"listItem\", tail, { listKind: kind, listLevel: level }),\n ]);\n ctx.setSelection(collapsedSelection({ blockIndex: pos.blockIndex + 1, offset: 0 }));\n });\n return true;\n}\n\n/**\n * Internal: reset a single block's type + attrs (used by list commands).\n * Same merge rules as the public `setBlockType` but scoped to one block and\n * intended to run already inside a transaction.\n */\nfunction setBlockTypeAtIndex(\n doc: EditorDocument,\n index: number,\n type: BlockType,\n attrs: BlockAttrs,\n): void {\n const block = doc.getBlock(index);\n if (!block) return;\n block.set(\"type\", type);\n const attrsMap = (block.get(\"attrs\") as Y.Map<unknown> | undefined) ?? new Y.Map<unknown>();\n if (!block.get(\"attrs\")) block.set(\"attrs\", attrsMap);\n const next = { ...defaultAttrsFor(type), ...attrs };\n const keep = new Set(Object.keys(next));\n for (const k of Array.from(attrsMap.keys())) {\n if (!keep.has(k)) attrsMap.delete(k);\n }\n for (const [k, v] of Object.entries(next)) {\n if (v === undefined) continue;\n if (attrsMap.get(k) !== v) attrsMap.set(k, v);\n }\n}\n\nfunction clampLevel(l: number | undefined): number {\n if (typeof l !== \"number\" || !Number.isFinite(l)) return 0;\n return Math.max(0, Math.min(MAX_LIST_LEVEL, Math.trunc(l)));\n}\n\n// ---------- Table commands (Sub-phase 4.1 / 4.2) ----------\n\n/**\n * Insert a fresh `rows × cols` table after the block currently holding the\n * caret (or at the end of the document if the selection is somehow invalid),\n * and place the caret in the table's first cell.\n *\n * Sub-phase 4.1 doesn't try to be clever: it does NOT replace an empty\n * preceding paragraph. Callers can clean that up themselves; an extra empty\n * paragraph above a table is a small price for predictable behavior.\n */\nexport function insertTable(ctx: CommandContext, rows: number, cols: number): void {\n const r = Math.max(1, Math.trunc(rows));\n const c = Math.max(1, Math.trunc(cols));\n transact(ctx.doc, () => {\n const sel = ctx.getSelection();\n // Anchor point: the block holding the focus. If focus is inside a cell of\n // an existing table, insert AFTER that table.\n const focusBlock = Math.max(0, Math.min(sel.focus.blockIndex, ctx.doc.blockCount() - 1));\n const insertAt = focusBlock + 1;\n ctx.doc.blocks.insert(insertAt, [createTableBlock(r, c)]);\n // Invariante: documento nunca termina em tabela — o caret precisa de um\n // destino editável abaixo dela. Só acrescenta quando a tabela virou o último bloco.\n if (insertAt === ctx.doc.blockCount() - 1) {\n ctx.doc.blocks.insert(insertAt + 1, [createBlock(\"paragraph\")]);\n }\n ctx.setSelection(\n collapsedSelection({ blockIndex: insertAt, cellIndex: 0, offset: 0 }),\n );\n });\n}\n\n/** Remove the entire table at `blockIndex` and place the caret at the start of the next block (or the previous one if removal would leave the doc empty). */\nexport function deleteTable(ctx: CommandContext, blockIndex: number): void {\n if (!ctx.doc.isTable(blockIndex)) return;\n transact(ctx.doc, () => {\n ctx.doc.blocks.delete(blockIndex, 1);\n if (ctx.doc.blocks.length === 0) {\n ctx.doc.blocks.push([createBlock(\"paragraph\")]);\n ctx.setSelection(collapsedSelection({ blockIndex: 0, offset: 0 }));\n return;\n }\n const targetIdx = Math.max(0, Math.min(blockIndex, ctx.doc.blockCount() - 1));\n const targetType = ctx.doc.getBlockType(targetIdx);\n if (targetType === \"table\") {\n ctx.setSelection(collapsedSelection({ blockIndex: targetIdx, cellIndex: 0, offset: 0 }));\n } else {\n ctx.setSelection(collapsedSelection({ blockIndex: targetIdx, offset: 0 }));\n }\n });\n}\n\n/**\n * Sub-phase 4.1 has no rowspan/colspan, so row/col operations are pure splice\n * on the flat `cells` array. The flat index of `(r, c)` is `r * cols + c`.\n */\n\nexport interface TableLocation {\n blockIndex: number;\n row: number;\n col: number;\n}\n\n/**\n * Derive `{row, col}` from a position inside a table — always pointing at the\n * owner of the targeted cell (covered cells redirect to their owner). Returns\n * null when the position isn't inside a table cell.\n */\nexport function tableLocationOf(\n doc: EditorDocument,\n pos: Position,\n): TableLocation | null {\n if (pos.cellIndex == null) return null;\n if (!doc.isTable(pos.blockIndex)) return null;\n const { cols } = doc.getTableSize(pos.blockIndex);\n if (cols <= 0) return null;\n const real = doc.realCellIndex(pos.blockIndex, pos.cellIndex);\n if (real == null) return null;\n const row = Math.floor(real / cols);\n const col = real - row * cols;\n return { blockIndex: pos.blockIndex, row, col };\n}\n\n/**\n * Insert a fresh row above (`where === \"before\"`) or below (`\"after\"`) the\n * given row. Spans that previously crossed the insertion boundary are extended\n * by 1; the corresponding columns of the new row become `covered: true`.\n */\nexport function insertTableRow(\n ctx: CommandContext,\n blockIndex: number,\n row: number,\n where: \"before\" | \"after\",\n): void {\n if (!ctx.doc.isTable(blockIndex)) return;\n const { rows, cols } = ctx.doc.getTableSize(blockIndex);\n if (rows <= 0 || cols <= 0) return;\n const targetRow = Math.max(0, Math.min(row, rows - 1));\n const P = where === \"before\" ? targetRow : targetRow + 1;\n transact(ctx.doc, () => {\n const cells = ctx.doc.getCells(blockIndex);\n const attrs = ctx.doc.getBlockAttrsMap(blockIndex);\n if (!cells || !attrs) return;\n\n // Snapshot: for each column, does a span crossing the [P-1, P] boundary\n // cover this column at row P? Compute BEFORE mutating spans.\n const newRowCovered: boolean[] = new Array(cols).fill(false);\n if (P > 0 && P < rows) {\n // Walk row P-1 to find spans crossing into row P (i.e., or < P and or+rs > P).\n for (let r = 0; r < P; r++) {\n for (let c = 0; c < cols; c++) {\n const a = ctx.doc.getCellAttrs(blockIndex, r * cols + c);\n if (a.covered === true) continue;\n const rs = spanOf(a.rowspan);\n const cs = spanOf(a.colspan);\n if (r < P && r + rs > P) {\n for (let cc = c; cc < c + cs && cc < cols; cc++) newRowCovered[cc] = true;\n }\n }\n }\n // Now extend those spans' rowspan by 1.\n for (let r = 0; r < P; r++) {\n for (let c = 0; c < cols; c++) {\n const idx = r * cols + c;\n const a = ctx.doc.getCellAttrs(blockIndex, idx);\n if (a.covered === true) continue;\n const rs = spanOf(a.rowspan);\n if (r < P && r + rs > P) {\n const m = ctx.doc.getCellAttrsMap(blockIndex, idx);\n m?.set(\"rowspan\", rs + 1);\n }\n }\n }\n }\n\n const fresh: Y.Map<unknown>[] = [];\n for (let c = 0; c < cols; c++) {\n fresh.push(createCell(newRowCovered[c] ? { covered: true } : undefined));\n }\n cells.insert(P * cols, fresh);\n attrs.set(\"rows\", rows + 1);\n // Caret on the first non-covered cell of the new row (falls back to flat-0\n // if every column is covered — pathologically possible only with bad data).\n const firstReal = newRowCovered.findIndex((v) => !v);\n const targetCellIdx = P * cols + (firstReal < 0 ? 0 : firstReal);\n ctx.setSelection(\n collapsedSelection({ blockIndex, cellIndex: targetCellIdx, offset: 0 }),\n );\n });\n}\n\n/**\n * Remove `row` from the table. Spans that pass through the row are shortened\n * by one; spans that START at the row are removed AND the cell at row R+1 (in\n * each affected column) is promoted to be the new owner with `rowspan - 1`.\n * When it was the last row, deletes the whole table.\n */\nexport function deleteTableRow(ctx: CommandContext, blockIndex: number, row: number): void {\n if (!ctx.doc.isTable(blockIndex)) return;\n const { rows, cols } = ctx.doc.getTableSize(blockIndex);\n if (rows <= 0 || cols <= 0) return;\n if (rows === 1) {\n deleteTable(ctx, blockIndex);\n return;\n }\n const R = Math.max(0, Math.min(row, rows - 1));\n transact(ctx.doc, () => {\n const cells = ctx.doc.getCells(blockIndex);\n const attrs = ctx.doc.getBlockAttrsMap(blockIndex);\n if (!cells || !attrs) return;\n\n // Phase 1: spans crossing R (started above, end at or after R): shorten by 1.\n for (let r = 0; r < R; r++) {\n for (let c = 0; c < cols; c++) {\n const idx = r * cols + c;\n const a = ctx.doc.getCellAttrs(blockIndex, idx);\n if (a.covered === true) continue;\n const rs = spanOf(a.rowspan);\n if (r < R && r + rs > R) {\n const m = ctx.doc.getCellAttrsMap(blockIndex, idx);\n m?.set(\"rowspan\", rs - 1);\n if (rs - 1 === 1) m?.delete(\"rowspan\");\n }\n }\n }\n\n // Phase 2: spans starting AT row R with rowspan > 1: promote the cell at\n // (R+1, c) to be the new owner. Capture the promotion list FIRST so we\n // can apply changes after the row delete (since indices shift).\n interface Promotion {\n // Flat index AFTER the row delete.\n flatNew: number;\n rowspan: number;\n colspan: number;\n }\n const promotions: Promotion[] = [];\n for (let c = 0; c < cols; c++) {\n const a = ctx.doc.getCellAttrs(blockIndex, R * cols + c);\n if (a.covered === true) continue;\n const rs = spanOf(a.rowspan);\n const cs = spanOf(a.colspan);\n if (rs > 1 && R + 1 < rows) {\n // After delete, what was (R+1, c) becomes (R, c).\n promotions.push({ flatNew: R * cols + c, rowspan: rs - 1, colspan: cs });\n }\n }\n\n cells.delete(R * cols, cols);\n attrs.set(\"rows\", rows - 1);\n\n for (const p of promotions) {\n const m = ctx.doc.getCellAttrsMap(blockIndex, p.flatNew);\n if (!m) continue;\n m.delete(\"covered\");\n if (p.rowspan > 1) m.set(\"rowspan\", p.rowspan); else m.delete(\"rowspan\");\n if (p.colspan > 1) m.set(\"colspan\", p.colspan); else m.delete(\"colspan\");\n }\n\n const newRow = Math.min(R, rows - 2);\n const target = findNextRealCell(ctx.doc, blockIndex, newRow * cols, (rows - 1) * cols) ?? 0;\n ctx.setSelection(\n collapsedSelection({ blockIndex, cellIndex: target, offset: 0 }),\n );\n });\n}\n\n/**\n * Insert a fresh column to the left (`\"before\"`) or right (`\"after\"`) of `col`.\n * Spans crossing the insertion column have `colspan += 1`; the new column's\n * cells in covered rows are themselves `covered: true`.\n *\n * Also resizes `colWidths` (if defined) by inserting a default width.\n */\nexport function insertTableColumn(\n ctx: CommandContext,\n blockIndex: number,\n col: number,\n where: \"before\" | \"after\",\n): void {\n if (!ctx.doc.isTable(blockIndex)) return;\n const { rows, cols } = ctx.doc.getTableSize(blockIndex);\n if (rows <= 0 || cols <= 0) return;\n const targetCol = Math.max(0, Math.min(col, cols - 1));\n const C = where === \"before\" ? targetCol : targetCol + 1;\n transact(ctx.doc, () => {\n const cells = ctx.doc.getCells(blockIndex);\n const attrs = ctx.doc.getBlockAttrsMap(blockIndex);\n if (!cells || !attrs) return;\n\n // Snapshot covered rows BEFORE mutating spans.\n const newColCovered: boolean[] = new Array(rows).fill(false);\n if (C > 0 && C < cols) {\n for (let r = 0; r < rows; r++) {\n for (let c = 0; c < C; c++) {\n const a = ctx.doc.getCellAttrs(blockIndex, r * cols + c);\n if (a.covered === true) continue;\n const rs = spanOf(a.rowspan);\n const cs = spanOf(a.colspan);\n if (c < C && c + cs > C) {\n for (let rr = r; rr < r + rs && rr < rows; rr++) newColCovered[rr] = true;\n }\n }\n }\n // Extend colspans.\n for (let r = 0; r < rows; r++) {\n for (let c = 0; c < C; c++) {\n const idx = r * cols + c;\n const a = ctx.doc.getCellAttrs(blockIndex, idx);\n if (a.covered === true) continue;\n const cs = spanOf(a.colspan);\n if (c < C && c + cs > C) {\n const m = ctx.doc.getCellAttrsMap(blockIndex, idx);\n m?.set(\"colspan\", cs + 1);\n }\n }\n }\n }\n\n // Walk rows LAST→FIRST so insert indices stay correct.\n for (let r = rows - 1; r >= 0; r--) {\n const at = r * cols + C;\n cells.insert(at, [createCell(newColCovered[r] ? { covered: true } : undefined)]);\n }\n attrs.set(\"cols\", cols + 1);\n\n // Resize colWidths if present — insert a 100px placeholder for the new col.\n const widths = attrs.get(\"colWidths\") as number[] | undefined;\n if (Array.isArray(widths) && widths.length === cols) {\n const next = widths.slice();\n next.splice(C, 0, 100);\n attrs.set(\"colWidths\", next);\n }\n\n const newCols = cols + 1;\n const focusRow = 0;\n const firstReal = newColCovered.findIndex((_, r) => r === focusRow && !newColCovered[r]);\n ctx.setSelection(\n collapsedSelection({\n blockIndex,\n cellIndex: focusRow * newCols + C + (firstReal < 0 ? 0 : 0),\n offset: 0,\n }),\n );\n });\n}\n\n/**\n * Remove `col` from the table. Spans that pass through the column are\n * shortened by one; spans that START at the column with `colspan > 1` get\n * their owner promoted from (r, C+1) to take over with `colspan - 1`.\n *\n * Also shrinks `colWidths` (if defined). When it was the last column, deletes\n * the whole table.\n */\nexport function deleteTableColumn(ctx: CommandContext, blockIndex: number, col: number): void {\n if (!ctx.doc.isTable(blockIndex)) return;\n const { rows, cols } = ctx.doc.getTableSize(blockIndex);\n if (rows <= 0 || cols <= 0) return;\n if (cols === 1) {\n deleteTable(ctx, blockIndex);\n return;\n }\n const C = Math.max(0, Math.min(col, cols - 1));\n transact(ctx.doc, () => {\n const cells = ctx.doc.getCells(blockIndex);\n const attrs = ctx.doc.getBlockAttrsMap(blockIndex);\n if (!cells || !attrs) return;\n\n // Phase 1: spans crossing C — colspan -= 1.\n for (let r = 0; r < rows; r++) {\n for (let c = 0; c < C; c++) {\n const idx = r * cols + c;\n const a = ctx.doc.getCellAttrs(blockIndex, idx);\n if (a.covered === true) continue;\n const cs = spanOf(a.colspan);\n if (c < C && c + cs > C) {\n const m = ctx.doc.getCellAttrsMap(blockIndex, idx);\n m?.set(\"colspan\", cs - 1);\n if (cs - 1 === 1) m?.delete(\"colspan\");\n }\n }\n }\n\n // Phase 2: capture promotions for spans starting at column C with colspan > 1.\n // After deletion, what was (r, C+1) becomes (r, C). Capture both the\n // FUTURE flat index in the post-delete (rows x (cols-1)) grid and the\n // attrs to apply.\n interface Promotion {\n flatNew: number;\n rowspan: number;\n colspan: number;\n }\n const promotions: Promotion[] = [];\n const newCols = cols - 1;\n for (let r = 0; r < rows; r++) {\n const a = ctx.doc.getCellAttrs(blockIndex, r * cols + C);\n if (a.covered === true) continue;\n const rs = spanOf(a.rowspan);\n const cs = spanOf(a.colspan);\n if (cs > 1 && C + 1 < cols) {\n promotions.push({\n flatNew: r * newCols + C,\n rowspan: rs,\n colspan: cs - 1,\n });\n }\n }\n\n // Walk rows LAST→FIRST so deletions don't perturb indices we still need.\n for (let r = rows - 1; r >= 0; r--) {\n const at = r * cols + C;\n cells.delete(at, 1);\n }\n attrs.set(\"cols\", newCols);\n\n for (const p of promotions) {\n const m = ctx.doc.getCellAttrsMap(blockIndex, p.flatNew);\n if (!m) continue;\n m.delete(\"covered\");\n if (p.rowspan > 1) m.set(\"rowspan\", p.rowspan); else m.delete(\"rowspan\");\n if (p.colspan > 1) m.set(\"colspan\", p.colspan); else m.delete(\"colspan\");\n }\n\n // Trim colWidths.\n const widths = attrs.get(\"colWidths\") as number[] | undefined;\n if (Array.isArray(widths) && widths.length === cols) {\n const next = widths.slice();\n next.splice(C, 1);\n attrs.set(\"colWidths\", next);\n }\n\n const newCol = Math.min(C, newCols - 1);\n const target = findNextRealCell(ctx.doc, blockIndex, newCol, rows * newCols) ?? 0;\n ctx.setSelection(\n collapsedSelection({ blockIndex, cellIndex: target, offset: 0 }),\n );\n });\n}\n\n// ---------- Rectangular cell selection (Sub-phase 4.5) ----------\n\nexport interface TableRect {\n blockIndex: number;\n /** Inclusive bounds in OWNER coordinates. */\n top: number;\n left: number;\n bottom: number;\n right: number;\n}\n\n/**\n * Interpret a `Selection` as a rectangular cell range when:\n * - Both endpoints carry `cellIndex`.\n * - They live in the same table block.\n * - They point to DIFFERENT owner cells.\n *\n * The naive bounds are then EXPANDED until every span fully fits inside —\n * essential so that operations like `mergeSelection` can never produce a\n * non-rectangular shape, and so visual highlights always cover whole spans.\n */\nexport function tableRectSelection(\n doc: EditorDocument,\n sel: Selection,\n): TableRect | null {\n if (sel.anchor.blockIndex !== sel.focus.blockIndex) return null;\n if (sel.anchor.cellIndex == null || sel.focus.cellIndex == null) return null;\n const blockIndex = sel.anchor.blockIndex;\n if (!doc.isTable(blockIndex)) return null;\n const aLoc = tableLocationOf(doc, sel.anchor);\n const fLoc = tableLocationOf(doc, sel.focus);\n if (!aLoc || !fLoc) return null;\n // After redirection to owners, anchor and focus may collapse to the same\n // owner cell (e.g. anchor in an owner, focus in one of its covered cells).\n if (aLoc.row === fLoc.row && aLoc.col === fLoc.col) return null;\n return expandTableRect(\n doc,\n blockIndex,\n Math.min(aLoc.row, fLoc.row),\n Math.min(aLoc.col, fLoc.col),\n Math.max(aLoc.row, fLoc.row),\n Math.max(aLoc.col, fLoc.col),\n );\n}\n\n/**\n * Grow a candidate rect until every owner whose span starts within the rect\n * fits entirely, and every covered cell inside it has its owner inside too.\n * Converges in O(rows × cols) iterations in the worst case (each pass either\n * grows a bound or terminates).\n */\nexport function expandTableRect(\n doc: EditorDocument,\n blockIndex: number,\n initTop: number,\n initLeft: number,\n initBottom: number,\n initRight: number,\n): TableRect {\n const { rows, cols } = doc.getTableSize(blockIndex);\n let top = Math.max(0, initTop);\n let left = Math.max(0, initLeft);\n let bottom = Math.min(rows - 1, initBottom);\n let right = Math.min(cols - 1, initRight);\n\n let changed = true;\n let guard = rows * cols + 1;\n while (changed && guard-- > 0) {\n changed = false;\n for (let r = top; r <= bottom; r++) {\n for (let c = left; c <= right; c++) {\n const idx = r * cols + c;\n const a = doc.getCellAttrs(blockIndex, idx);\n if (a.covered === true) {\n const owner = doc.realCellIndex(blockIndex, idx);\n if (owner == null) continue;\n const oRow = Math.floor(owner / cols);\n const oCol = owner - oRow * cols;\n if (oRow < top) { top = oRow; changed = true; }\n if (oCol < left) { left = oCol; changed = true; }\n // Owner's far edge:\n const oAttrs = doc.getCellAttrs(blockIndex, owner);\n const oRs = spanOf(oAttrs.rowspan);\n const oCs = spanOf(oAttrs.colspan);\n if (oRow + oRs - 1 > bottom) { bottom = oRow + oRs - 1; changed = true; }\n if (oCol + oCs - 1 > right) { right = oCol + oCs - 1; changed = true; }\n } else {\n const rs = spanOf(a.rowspan);\n const cs = spanOf(a.colspan);\n if (r + rs - 1 > bottom) { bottom = r + rs - 1; changed = true; }\n if (c + cs - 1 > right) { right = c + cs - 1; changed = true; }\n }\n }\n }\n }\n return { blockIndex, top, left, bottom, right };\n}\n\n/** Enumerate every cell-index (real or covered) contained in `rect`. */\nexport function cellsInRect(doc: EditorDocument, rect: TableRect): number[] {\n const { cols } = doc.getTableSize(rect.blockIndex);\n const out: number[] = [];\n for (let r = rect.top; r <= rect.bottom; r++) {\n for (let c = rect.left; c <= rect.right; c++) out.push(r * cols + c);\n }\n return out;\n}\n\n/**\n * Merge every cell in the current rectangular selection into one owner at the\n * rect's top-left. The owner's text is the concatenation of all non-empty\n * inner texts (space-separated, mark-preserving). Returns true on success, false\n * when there is no rect selection.\n */\nexport function mergeSelection(ctx: CommandContext): boolean {\n const sel = ctx.getSelection();\n const rect = tableRectSelection(ctx.doc, sel);\n if (!rect) return false;\n const { blockIndex, top, left, bottom, right } = rect;\n const { cols } = ctx.doc.getTableSize(blockIndex);\n const ownerIdx = top * cols + left;\n\n transact(ctx.doc, () => {\n const ownerText = ctx.doc.getCellText(blockIndex, ownerIdx);\n if (!ownerText) return;\n\n // Walk every cell in the rect (skip the owner itself). For real cells with\n // non-empty text, append to owner.\n for (let r = top; r <= bottom; r++) {\n for (let c = left; c <= right; c++) {\n const idx = r * cols + c;\n if (idx === ownerIdx) continue;\n const a = ctx.doc.getCellAttrs(blockIndex, idx);\n if (a.covered !== true) {\n const t = ctx.doc.getCellText(blockIndex, idx);\n if (t && t.length > 0) {\n const sep = ownerText.length > 0 ? \" \" : \"\";\n const delta = t.toDelta() as DeltaOp[];\n let pos = ownerText.length;\n if (sep) {\n ownerText.insert(pos, sep);\n pos += 1;\n }\n writeDeltaInto(ownerText, pos, delta);\n t.delete(0, t.length);\n }\n }\n // Reset attrs to \"covered\" — drops any prior rowspan/colspan.\n const m = ctx.doc.getCellAttrsMap(blockIndex, idx);\n if (m) {\n m.delete(\"rowspan\");\n m.delete(\"colspan\");\n m.set(\"covered\", true);\n }\n }\n }\n // Update owner spans.\n const oMap = ctx.doc.getCellAttrsMap(blockIndex, ownerIdx);\n if (oMap) {\n const newRs = bottom - top + 1;\n const newCs = right - left + 1;\n if (newRs > 1) oMap.set(\"rowspan\", newRs); else oMap.delete(\"rowspan\");\n if (newCs > 1) oMap.set(\"colspan\", newCs); else oMap.delete(\"colspan\");\n oMap.delete(\"covered\");\n }\n ctx.setSelection(\n collapsedSelection({ blockIndex, cellIndex: ownerIdx, offset: 0 }),\n );\n });\n return true;\n}\n\n/**\n * Clears the text of every cell in the current rectangular selection (no\n * structural mutation — spans stay intact). Returns the collapsed selection\n * at the rect's top-left when something was cleared, otherwise null.\n */\nexport function clearRectCells(ctx: CommandContext): Selection | null {\n const sel = ctx.getSelection();\n const rect = tableRectSelection(ctx.doc, sel);\n if (!rect) return null;\n const { blockIndex, top, left, bottom, right } = rect;\n const { cols } = ctx.doc.getTableSize(blockIndex);\n const ownerIdx = top * cols + left;\n let result: Selection | null = null;\n transact(ctx.doc, () => {\n for (let r = top; r <= bottom; r++) {\n for (let c = left; c <= right; c++) {\n const idx = r * cols + c;\n const a = ctx.doc.getCellAttrs(blockIndex, idx);\n if (a.covered === true) continue;\n const t = ctx.doc.getCellText(blockIndex, idx);\n if (t && t.length > 0) t.delete(0, t.length);\n }\n }\n result = collapsedSelection({ blockIndex, cellIndex: ownerIdx, offset: 0 });\n ctx.setSelection(result);\n });\n return result;\n}\n\n// ---------- Merge / split ----------\n\n/**\n * Merge the cell at `(row, col)` with its immediate right neighbor. The right\n * neighbor must be a real cell with matching `rowspan` (otherwise the merge\n * would form a non-rectangle). Returns true on success, false on shape\n * mismatch or when there is no neighbor.\n *\n * After: the owner's `colspan` grows by the neighbor's `colspan`; the\n * neighbor and all its formerly-covered cells in the merged rectangle are\n * marked `covered: true`. The neighbor's text is appended to the owner with a\n * single space delimiter (when both sides had content).\n */\nexport function mergeRight(ctx: CommandContext, blockIndex: number, row: number, col: number): boolean {\n if (!ctx.doc.isTable(blockIndex)) return false;\n const { rows, cols } = ctx.doc.getTableSize(blockIndex);\n if (row < 0 || row >= rows || col < 0 || col >= cols) return false;\n const ownerIdx = row * cols + col;\n const ownerAttrs = ctx.doc.getCellAttrs(blockIndex, ownerIdx);\n if (ownerAttrs.covered === true) return false;\n const ownerRs = spanOf(ownerAttrs.rowspan);\n const ownerCs = spanOf(ownerAttrs.colspan);\n const nbCol = col + ownerCs;\n if (nbCol >= cols) return false;\n const nbIdx = row * cols + nbCol;\n const nbAttrs = ctx.doc.getCellAttrs(blockIndex, nbIdx);\n if (nbAttrs.covered === true) return false;\n const nbRs = spanOf(nbAttrs.rowspan);\n const nbCs = spanOf(nbAttrs.colspan);\n if (nbRs !== ownerRs) return false;\n\n transact(ctx.doc, () => {\n // Append neighbor's text into the owner.\n const ownerText = ctx.doc.getCellText(blockIndex, ownerIdx);\n const nbText = ctx.doc.getCellText(blockIndex, nbIdx);\n if (ownerText && nbText && nbText.length > 0) {\n const sep = ownerText.length > 0 ? \" \" : \"\";\n // Re-apply delta with marks and embeds preserved.\n const delta = nbText.toDelta() as DeltaOp[];\n let pos = ownerText.length;\n if (sep) {\n ownerText.insert(pos, sep);\n pos += 1;\n }\n writeDeltaInto(ownerText, pos, delta);\n }\n // Clear neighbor text.\n if (nbText && nbText.length > 0) nbText.delete(0, nbText.length);\n\n // Owner gets the widened colspan.\n const ownerMap = ctx.doc.getCellAttrsMap(blockIndex, ownerIdx);\n if (ownerMap) ownerMap.set(\"colspan\", ownerCs + nbCs);\n\n // Mark all cells in the neighbor's old rectangle as covered (in case nbCs > 1,\n // they were already covered — flag still applies).\n for (let r = row; r < row + ownerRs; r++) {\n for (let c = nbCol; c < nbCol + nbCs; c++) {\n const m = ctx.doc.getCellAttrsMap(blockIndex, r * cols + c);\n if (!m) continue;\n m.delete(\"rowspan\");\n m.delete(\"colspan\");\n m.set(\"covered\", true);\n }\n }\n ctx.setSelection(collapsedSelection({ blockIndex, cellIndex: ownerIdx, offset: 0 }));\n });\n return true;\n}\n\n/** Merge with the immediate bottom neighbor. Mirror of `mergeRight`. */\nexport function mergeDown(ctx: CommandContext, blockIndex: number, row: number, col: number): boolean {\n if (!ctx.doc.isTable(blockIndex)) return false;\n const { rows, cols } = ctx.doc.getTableSize(blockIndex);\n if (row < 0 || row >= rows || col < 0 || col >= cols) return false;\n const ownerIdx = row * cols + col;\n const ownerAttrs = ctx.doc.getCellAttrs(blockIndex, ownerIdx);\n if (ownerAttrs.covered === true) return false;\n const ownerRs = spanOf(ownerAttrs.rowspan);\n const ownerCs = spanOf(ownerAttrs.colspan);\n const nbRow = row + ownerRs;\n if (nbRow >= rows) return false;\n const nbIdx = nbRow * cols + col;\n const nbAttrs = ctx.doc.getCellAttrs(blockIndex, nbIdx);\n if (nbAttrs.covered === true) return false;\n const nbRs = spanOf(nbAttrs.rowspan);\n const nbCs = spanOf(nbAttrs.colspan);\n if (nbCs !== ownerCs) return false;\n\n transact(ctx.doc, () => {\n const ownerText = ctx.doc.getCellText(blockIndex, ownerIdx);\n const nbText = ctx.doc.getCellText(blockIndex, nbIdx);\n if (ownerText && nbText && nbText.length > 0) {\n const sep = ownerText.length > 0 ? \" \" : \"\";\n const delta = nbText.toDelta() as DeltaOp[];\n let pos = ownerText.length;\n if (sep) {\n ownerText.insert(pos, sep);\n pos += 1;\n }\n writeDeltaInto(ownerText, pos, delta);\n }\n if (nbText && nbText.length > 0) nbText.delete(0, nbText.length);\n\n const ownerMap = ctx.doc.getCellAttrsMap(blockIndex, ownerIdx);\n if (ownerMap) ownerMap.set(\"rowspan\", ownerRs + nbRs);\n\n for (let r = nbRow; r < nbRow + nbRs; r++) {\n for (let c = col; c < col + ownerCs; c++) {\n const m = ctx.doc.getCellAttrsMap(blockIndex, r * cols + c);\n if (!m) continue;\n m.delete(\"rowspan\");\n m.delete(\"colspan\");\n m.set(\"covered\", true);\n }\n }\n ctx.setSelection(collapsedSelection({ blockIndex, cellIndex: ownerIdx, offset: 0 }));\n });\n return true;\n}\n\n/**\n * Split a merged cell back into a `rowspan × colspan` grid of independent real\n * cells. Each formerly-covered cell becomes empty and real. Returns true when\n * something was split. No-op (returns false) on a cell with no spans.\n */\nexport function splitCell(ctx: CommandContext, blockIndex: number, row: number, col: number): boolean {\n if (!ctx.doc.isTable(blockIndex)) return false;\n const { rows, cols } = ctx.doc.getTableSize(blockIndex);\n if (row < 0 || row >= rows || col < 0 || col >= cols) return false;\n const idx = row * cols + col;\n const attrs = ctx.doc.getCellAttrs(blockIndex, idx);\n if (attrs.covered === true) return false;\n const rs = spanOf(attrs.rowspan);\n const cs = spanOf(attrs.colspan);\n if (rs === 1 && cs === 1) return false;\n\n transact(ctx.doc, () => {\n const ownerMap = ctx.doc.getCellAttrsMap(blockIndex, idx);\n if (ownerMap) {\n ownerMap.delete(\"rowspan\");\n ownerMap.delete(\"colspan\");\n }\n for (let r = row; r < row + rs; r++) {\n for (let c = col; c < col + cs; c++) {\n if (r === row && c === col) continue;\n const m = ctx.doc.getCellAttrsMap(blockIndex, r * cols + c);\n if (!m) continue;\n m.delete(\"covered\");\n m.delete(\"rowspan\");\n m.delete(\"colspan\");\n }\n }\n ctx.setSelection(collapsedSelection({ blockIndex, cellIndex: idx, offset: 0 }));\n });\n return true;\n}\n\n// ---------- Column widths (Sub-phase 4.4) ----------\n\n/** Set the width (in CSS px) of a specific column. Auto-initializes `colWidths`. */\nexport function setColumnWidth(\n ctx: CommandContext,\n blockIndex: number,\n col: number,\n widthPx: number,\n): void {\n if (!ctx.doc.isTable(blockIndex)) return;\n const { cols } = ctx.doc.getTableSize(blockIndex);\n if (col < 0 || col >= cols) return;\n const w = Math.max(20, Math.round(widthPx));\n transact(ctx.doc, () => {\n const attrsMap = ctx.doc.getBlockAttrsMap(blockIndex);\n if (!attrsMap) return;\n const current = attrsMap.get(\"colWidths\") as number[] | undefined;\n const next = Array.isArray(current) && current.length === cols\n ? current.slice()\n : new Array<number>(cols).fill(120);\n next[col] = w;\n attrsMap.set(\"colWidths\", next);\n });\n}\n\n/**\n * Move the caret to the next cell of the same table (Tab). At the last cell of\n * the last row, creates a new row and lands in its first cell. Returns true\n * when handled. Caret must be inside a table for this to act.\n */\nexport function moveToNextCell(ctx: CommandContext): boolean {\n const sel = ctx.getSelection();\n const loc = tableLocationOf(ctx.doc, sel.focus);\n if (!loc) return false;\n const { rows, cols } = ctx.doc.getTableSize(loc.blockIndex);\n if (rows <= 0 || cols <= 0) return false;\n\n // Walk forward starting at the cell immediately following the owner's bottom-right.\n // For a non-spanning cell that's `flat + 1`; for a span, it's `(loc.row, loc.col + colspan)`\n // — but conceptually the owner's \"next\" sibling is simply the next real cell in row-major\n // order after the owner's flat index, since covered cells get skipped by the loop below.\n const startFlat = loc.row * cols + loc.col + 1;\n const next = findNextRealCell(ctx.doc, loc.blockIndex, startFlat, rows * cols);\n if (next == null) {\n // No more cells in the table — append a new row and land in its first cell.\n insertTableRow(ctx, loc.blockIndex, rows - 1, \"after\");\n return true;\n }\n ctx.setSelection(\n collapsedSelection({ blockIndex: loc.blockIndex, cellIndex: next, offset: 0 }),\n );\n return true;\n}\n\n/** Move the caret to the previous cell (Shift+Tab). At the first cell, no-op (returns true). */\nexport function moveToPrevCell(ctx: CommandContext): boolean {\n const sel = ctx.getSelection();\n const loc = tableLocationOf(ctx.doc, sel.focus);\n if (!loc) return false;\n const { rows, cols } = ctx.doc.getTableSize(loc.blockIndex);\n if (rows <= 0 || cols <= 0) return false;\n const startFlat = loc.row * cols + loc.col - 1;\n if (startFlat < 0) return true; // at (0,0) — handled but no-op\n const prev = findPrevRealCell(ctx.doc, loc.blockIndex, startFlat);\n if (prev == null) return true;\n const cellText = ctx.doc.getCellText(loc.blockIndex, prev);\n const off = cellText?.length ?? 0;\n ctx.setSelection(\n collapsedSelection({ blockIndex: loc.blockIndex, cellIndex: prev, offset: off }),\n );\n return true;\n}\n\nfunction findNextRealCell(\n doc: EditorDocument,\n blockIndex: number,\n startFlat: number,\n total: number,\n): number | null {\n for (let i = startFlat; i < total; i++) {\n if (doc.getCellAttrs(blockIndex, i).covered !== true) return i;\n }\n return null;\n}\n\nfunction findPrevRealCell(\n doc: EditorDocument,\n blockIndex: number,\n startFlat: number,\n): number | null {\n for (let i = startFlat; i >= 0; i--) {\n if (doc.getCellAttrs(blockIndex, i).covered !== true) return i;\n }\n return null;\n}\n\n/**\n * Append/write a delta's ops into `yText` starting at `pos`, preserving marks\n * AND image embeds. Returns the position right after the last write.\n */\nfunction writeDeltaInto(yText: Y.Text, pos: number, delta: DeltaOp[]): number {\n let cursor = pos;\n for (const op of delta) {\n if (typeof op.insert === \"string\") {\n if (op.insert.length === 0) continue;\n // Always pass an explicit attributes object that clears every mark, then\n // layers the op's own marks on top. Without this, `Y.Text.insert` lets the\n // new text inherit the formatting of the adjacent run (e.g. a plain run\n // pasted right after a bold run would turn bold). See CLEAR_ALL_MARKS.\n yText.insert(cursor, op.insert, {\n ...CLEAR_ALL_MARKS,\n ...((op.attributes as Record<string, unknown> | undefined) ?? {}),\n });\n cursor += op.insert.length;\n } else if (op.insert != null) {\n // Embed (e.g. ImageEmbed). Y.Text accepts arbitrary JSON-serializable\n // objects as length-1 inserts.\n if (op.attributes && Object.keys(op.attributes).length > 0) {\n yText.insert(\n cursor,\n op.insert as unknown as string,\n op.attributes as Record<string, unknown>,\n );\n } else {\n yText.insert(cursor, op.insert as unknown as string);\n }\n cursor += 1;\n }\n }\n return cursor;\n}\n\n// ---------- Inline embeds (Fase 5: imagens) ----------\n\n/**\n * Insert an inline image embed at the current selection. Embeds occupy 1 char\n * in offset arithmetic (Y.Text treats them as length-1 inserts).\n */\nexport function insertImage(ctx: CommandContext, embed: ImageEmbed): void {\n clearRectCells(ctx);\n transact(ctx.doc, () => {\n const sel0 = ctx.getSelection();\n let cursor = sel0;\n if (!isCollapsed(sel0)) cursor = deleteRange(ctx.doc, sel0);\n const pos = cursor.focus;\n const yText = ctx.doc.textAt(pos.blockIndex, pos.cellIndex);\n if (!yText) return;\n // Y.Text accepts non-string inserts natively.\n yText.insert(pos.offset, embed as unknown as string);\n const newPos: Position = {\n blockIndex: pos.blockIndex,\n cellIndex: pos.cellIndex,\n offset: pos.offset + 1,\n };\n ctx.setSelection(collapsedSelection(newPos));\n });\n}\n\n/**\n * Update attributes of an existing image embed at `(blockIndex, embedOffset)`.\n * Implementation: delete the 1-char slot and re-insert the merged embed in the\n * SAME transaction — Y.UndoManager coalesces delete+insert in one transact, so\n * undo treats it as a single step.\n *\n * If `newOffset` is provided and differs from `embedOffset`, the embed is moved\n * to that offset within the same block/cell. Used by wrap-left/wrap-right\n * layouts which must anchor the image at the block start so floated text wraps\n * around it (CSS float only flows text that comes AFTER the float in DOM order).\n */\nexport function setImageAttrs(\n ctx: CommandContext,\n blockIndex: number,\n embedOffset: number,\n partial: Partial<ImageEmbed>,\n cellIndex?: number,\n newOffset?: number,\n): void {\n transact(ctx.doc, () => {\n const yText = ctx.doc.textAt(blockIndex, cellIndex);\n if (!yText) return;\n const delta = yText.toDelta() as DeltaOp[];\n let cursor = 0;\n let prev: ImageEmbed | null = null;\n for (const op of delta) {\n if (typeof op.insert === \"string\") {\n cursor += op.insert.length;\n continue;\n }\n if (cursor === embedOffset && isImageEmbed(op.insert)) {\n prev = op.insert;\n break;\n }\n cursor += 1;\n }\n if (!prev) return;\n const merged: ImageEmbed = { ...prev, ...partial };\n yText.delete(embedOffset, 1);\n const insertAt =\n newOffset != null && newOffset !== embedOffset\n ? Math.max(0, Math.min(newOffset, yText.length))\n : embedOffset;\n yText.insert(insertAt, merged as unknown as string);\n });\n}\n\n/** Location of an embed in the model (block or table cell). */\nexport interface EmbedLoc {\n blockIndex: number;\n offset: number;\n cellIndex?: number;\n}\n\n/**\n * Layouts whose embed is re-anchorable between Y.Texts. Only `front`/`behind`\n * use absolute `left`/`top`, so only they can be re-anchored. Inline embeds are\n * not positioned absolutely, and `wrap-left`/`wrap-right` are governed by float\n * margins (not absolute coordinates) — both are EXCLUDED and stay on the\n * same-page `setImageAttrs` path (see RESOLVED DECISION at plan header).\n */\nconst REANCHORABLE_LAYOUTS: ReadonlySet<string> = new Set([\"front\", \"behind\"]);\n\n/**\n * Move a floating image embed from `from` to `to` in a SINGLE Y.Doc\n * transaction, applying new positional offsets. Atomic delete+insert keeps the\n * CRDT consistent for collab peers and coalesces into one undo step.\n *\n * Guard: only non-inline (re-anchorable) image embeds are moved; everything\n * else is a no-op. When `from` and `to` resolve to the SAME Y.Text, the insert\n * index is adjusted for the prior delete (mirrors `setImageAttrs`'s clamp at\n * lines 1709-1714). Sets the selection to the embed's new 1-char home so the\n * resize overlay stays attached.\n */\nexport function moveEmbedAnchor(\n ctx: CommandContext,\n from: EmbedLoc,\n to: EmbedLoc,\n newOffsetX: number,\n newOffsetY: number,\n): void {\n transact(ctx.doc, () => {\n const srcText = ctx.doc.textAt(from.blockIndex, from.cellIndex);\n if (!srcText) return;\n\n // Locate the embed at from.offset via the same delta scan as setImageAttrs.\n const delta = srcText.toDelta() as DeltaOp[];\n let cursor = 0;\n let prev: ImageEmbed | null = null;\n for (const op of delta) {\n if (typeof op.insert === \"string\") {\n cursor += op.insert.length;\n continue;\n }\n if (cursor === from.offset && isImageEmbed(op.insert)) {\n prev = op.insert;\n break;\n }\n cursor += 1;\n }\n if (!prev) return;\n\n // Guard: only re-anchor non-inline layouts.\n const layout = prev.layout ?? \"inline\";\n if (!REANCHORABLE_LAYOUTS.has(layout)) return;\n\n const dstText = ctx.doc.textAt(to.blockIndex, to.cellIndex);\n if (!dstText) return;\n\n const merged: ImageEmbed = { ...prev, offsetX: newOffsetX, offsetY: newOffsetY };\n\n const sameRun = srcText === dstText;\n\n // Delete the source slot first.\n srcText.delete(from.offset, 1);\n\n // Compute the landing offset. When same run, the delete shifts indices that\n // were AFTER from.offset down by one. Clamp to the (post-delete) length.\n let landed = to.offset;\n if (sameRun && to.offset > from.offset) {\n landed = to.offset - 1;\n }\n landed = Math.max(0, Math.min(landed, dstText.length));\n\n dstText.insert(landed, merged as unknown as string);\n\n ctx.setSelection({\n anchor: { blockIndex: to.blockIndex, cellIndex: to.cellIndex, offset: landed },\n focus: { blockIndex: to.blockIndex, cellIndex: to.cellIndex, offset: landed + 1 },\n });\n });\n}\n\n// Expose the Y origin so consumers (e.g. UndoManager) can filter on it.\nexport function isCommandOrigin(origin: unknown): boolean {\n return origin === COMMAND_ORIGIN;\n}\n\n// Allow Y.UndoManager.trackedOrigins to include the symbol.\nexport const TRACKED_ORIGINS: Set<unknown> = new Set([COMMAND_ORIGIN]);\n\n// Re-export Y for downstream type checks if needed.\nexport { Y };\n","import type { EditorDocument } from \"./document\";\nimport type { DeltaOp, Selection, SerializedBlock } from \"./types\";\nimport { sliceDelta } from \"./marks\";\nimport { isCollapsed, orderedRange } from \"./selection\";\n\n/** MIME custom que carrega o slice serializado no clipboard. */\nexport const SOFER_MIME = \"application/x-sofer-slice\";\n\nexport interface ClipboardSlice {\n /** 1..n blocos; cada delta carrega marks + embeds de imagem. */\n blocks: SerializedBlock[];\n /** 1º bloco é fragmento parcial → mescla inline no alvo da colagem. */\n openStart: boolean;\n /** último bloco é fragmento parcial → conteúdo após o caret continua nele. */\n openEnd: boolean;\n}\n\n/** Texto puro de um delta (embeds não contribuem caractere visível). */\nfunction deltaToText(delta: DeltaOp[]): string {\n let s = \"\";\n for (const op of delta) if (typeof op.insert === \"string\") s += op.insert;\n return s;\n}\n\n/** Monta um SerializedBlock inline a partir de um delta já fatiado.\n * Para conteúdo vindo de célula (cellIndex != null) o bloco vira \"paragraph\". */\nfunction blockFromDelta(\n doc: EditorDocument,\n blockIndex: number,\n cellIndex: number | undefined,\n delta: DeltaOp[],\n): SerializedBlock {\n if (cellIndex != null) {\n return { type: \"paragraph\", text: deltaToText(delta), delta, attrs: {} };\n }\n return {\n type: doc.getBlockType(blockIndex) ?? \"paragraph\",\n text: deltaToText(delta),\n delta,\n attrs: doc.getBlockAttrs(blockIndex),\n };\n}\n\n/**\n * Lê a seleção e produz um ClipboardSlice, ou null se:\n * - colapsada; - âncora/foco em células diferentes; - multi-bloco com tabela.\n */\nexport function serializeSelection(\n doc: EditorDocument,\n sel: Selection,\n): ClipboardSlice | null {\n if (isCollapsed(sel)) return null;\n const { start, end } = orderedRange(sel);\n if ((start.cellIndex ?? -1) !== (end.cellIndex ?? -1)) return null;\n\n if (start.blockIndex === end.blockIndex) {\n const yText = doc.textAt(start.blockIndex, start.cellIndex);\n if (!yText) return null;\n const delta = sliceDelta(yText.toDelta() as DeltaOp[], start.offset, end.offset);\n return {\n blocks: [blockFromDelta(doc, start.blockIndex, start.cellIndex, delta)],\n openStart: start.offset > 0,\n openEnd: end.offset < yText.length,\n };\n }\n\n if (start.cellIndex != null || end.cellIndex != null) return null;\n for (let i = start.blockIndex; i <= end.blockIndex; i++) {\n if (doc.getBlockType(i) === \"table\") return null;\n }\n const startText = doc.getBlockText(start.blockIndex);\n const endText = doc.getBlockText(end.blockIndex);\n if (!startText || !endText) return null;\n\n const blocks: SerializedBlock[] = [];\n blocks.push(\n blockFromDelta(doc, start.blockIndex, undefined,\n sliceDelta(startText.toDelta() as DeltaOp[], start.offset, startText.length)),\n );\n for (let i = start.blockIndex + 1; i < end.blockIndex; i++) {\n const t = doc.getBlockText(i);\n blocks.push(blockFromDelta(doc, i, undefined, (t?.toDelta() as DeltaOp[]) ?? []));\n }\n blocks.push(\n blockFromDelta(doc, end.blockIndex, undefined,\n sliceDelta(endText.toDelta() as DeltaOp[], 0, end.offset)),\n );\n return {\n blocks,\n openStart: start.offset > 0,\n openEnd: end.offset < endText.length,\n };\n}\n\n/** Fallback texto puro: textos dos blocos unidos por \"\\n\". */\nexport function sliceToText(slice: ClipboardSlice): string {\n return slice.blocks.map((b) => deltaToText(b.delta)).join(\"\\n\");\n}\n\n/** Achata o slice num único delta inline (para colar dentro de uma célula).\n * Fronteiras de bloco viram quebra de linha \"\\n\" (células renderizam pre-wrap),\n * para não grudar palavras de parágrafos distintos. */\nexport function sliceToInlineDelta(slice: ClipboardSlice): DeltaOp[] {\n const out: DeltaOp[] = [];\n slice.blocks.forEach((b, i) => {\n if (i > 0) out.push({ insert: \"\\n\" });\n out.push(...b.delta);\n });\n return out;\n}\n","import * as Y from \"yjs\";\nimport type { EditorDocument } from \"./document\";\nimport { TRACKED_ORIGINS } from \"./commands\";\n\nexport class EditorHistory {\n readonly undoManager: Y.UndoManager;\n\n constructor(doc: EditorDocument) {\n this.undoManager = new Y.UndoManager(doc.blocks, {\n trackedOrigins: TRACKED_ORIGINS,\n captureTimeout: 400,\n });\n }\n\n undo(): boolean {\n return this.undoManager.undo() != null;\n }\n\n redo(): boolean {\n return this.undoManager.redo() != null;\n }\n\n destroy(): void {\n this.undoManager.destroy();\n }\n}\n"],"mappings":"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","names":["Y","merged","yText","Y","t","Y","yText","Y"]}
|
|
1
|
+
{"version":3,"sources":["../src/index.ts","../src/types.ts","../src/schema.ts","../src/page-settings.ts","../src/document.ts","../src/collab-cursor.ts","../src/selection.ts","../src/marks.ts","../src/decorations.ts","../src/table-borders.ts","../src/commands.ts","../src/clipboard.ts","../src/history.ts"],"sourcesContent":["export * from \"./types\";\nexport * from \"./schema\";\nexport * from \"./page-settings\";\nexport * from \"./document\";\nexport * from \"./collab-cursor\";\nexport * from \"./selection\";\nexport * from \"./marks\";\nexport * from \"./decorations\";\nexport * from \"./table-borders\";\nexport * from \"./commands\";\nexport * from \"./clipboard\";\nexport * from \"./history\";\n","/**\n * Public type definitions for the document model.\n * The runtime representation lives in Y.js (see document.ts);\n * these types describe its shape for consumers.\n */\n\nexport type BlockType =\n | \"paragraph\"\n | \"heading\"\n | \"blockquote\"\n | \"codeBlock\"\n | \"listItem\"\n | \"table\";\n\nexport type AlignValue = \"left\" | \"center\" | \"right\" | \"justify\";\nexport type DirValue = \"ltr\" | \"rtl\";\nexport type ListKind = \"bullet\" | \"ordered\";\n\nexport type ListStyleType =\n | \"decimal\"\n | \"lower-alpha\"\n | \"upper-alpha\"\n | \"lower-roman\"\n | \"upper-roman\";\n\n/** Maximum supported list nesting (0 = top level). */\nexport const MAX_LIST_LEVEL = 5;\n\n/** Entrelinha de uma linha de resposta: simples, 1,5 ou dupla. */\nexport type AnswerLineSpacing = 1 | 1.5 | 2;\n\n/**\n * Onde as linhas da grade de uma tabela aparecem.\n * Vocabulário nativo de `w:tblBorders` (top/left/bottom/right/insideH/insideV).\n */\nexport type TableBorderPreset = \"all\" | \"outer\" | \"horizontal\" | \"vertical\" | \"none\";\n\nexport interface BlockAttrs {\n align?: AlignValue;\n dir?: DirValue;\n /** Only meaningful when `type === \"heading\"`. 1..6. */\n level?: 1 | 2 | 3 | 4 | 5 | 6;\n /** Only meaningful when `type === \"codeBlock\"`. Free-form (CSS-style language hint). */\n language?: string;\n /** Only meaningful when `type === \"listItem\"`. */\n listKind?: ListKind;\n /** Only meaningful when `type === \"listItem\"`. 0..MAX_LIST_LEVEL. */\n listLevel?: number;\n /**\n * Only meaningful when `type === \"listItem\"` and `listKind === \"ordered\"`.\n * When set on a listItem, that item starts a NEW list group whose first\n * `<ol>` carries `start={listStart}`. Used to renumerate questions or pick\n * up an interrupted sequence.\n */\n listStart?: number;\n /**\n * Only meaningful when `type === \"listItem\"`. Overrides the default per-level\n * CSS cycle (decimal → lower-alpha → lower-roman) with an explicit style.\n * Like `listStart`, setting this on a listItem breaks the group so the new\n * `<ol>` carries the requested `list-style-type`.\n */\n listStyle?: ListStyleType;\n /** Only meaningful when `type === \"table\"`. */\n rows?: number;\n /** Only meaningful when `type === \"table\"`. */\n cols?: number;\n /**\n * Only meaningful when `type === \"table\"`. Per-column widths in CSS px.\n * Length should equal `cols` when set; missing or short arrays fall back to\n * an auto distribution at render time.\n */\n colWidths?: number[];\n /**\n * Só relevante quando `type === \"table\"`. Onde as linhas da grade aparecem.\n * Ausente = \"all\" — documentos existentes não mudam de aparência.\n */\n borderPreset?: TableBorderPreset;\n /**\n * Só relevante quando `type === \"table\"`. Cor das linhas da grade.\n * Ausente = `TABLE_BORDER_COLOR` — documentos existentes não mudam.\n */\n borderColor?: string;\n /**\n * Só relevante quando `type === \"paragraph\"`. Parágrafo pautado para o aluno\n * escrever a resposta: renderiza com régua inferior de largura total.\n */\n answerLine?: true;\n /**\n * Só relevante quando `answerLine`. Entrelinha. Ausente = 1.\n *\n * Deliberadamente escopado a linhas de resposta em vez de um `lineSpacing`\n * genérico de parágrafo: entrelinha geral mudaria a medição de paginação de\n * TODO parágrafo do documento, o que é outra feature com outro raio de impacto.\n */\n answerLineSpacing?: AnswerLineSpacing;\n}\n\nexport interface CellAttrs {\n /**\n * Number of rows this cell spans, starting at its row. Default 1.\n * Only meaningful on REAL cells (not covered).\n */\n rowspan?: number;\n /** Default 1. Only meaningful on REAL cells. */\n colspan?: number;\n /**\n * `true` iff this cell is occluded by an owning cell with a `rowspan`/`colspan`\n * spanning into this position. Covered cells do not render their own `<td>`,\n * never accept input, and are skipped by Tab navigation.\n *\n * The cells array keeps `rows * cols` entries to preserve the row-major index\n * scheme — covered cells are placeholders, not gaps.\n */\n covered?: true;\n /** Alinhamento horizontal do texto da célula. Mesmos valores de bloco. */\n align?: AlignValue;\n /** Cor de fundo da célula (CSS color, ex. `#ffe58f`). Ausente = sem fundo. */\n bgColor?: string;\n}\n\nexport interface Position {\n blockIndex: number;\n /**\n * When the caret is inside a table cell, identifies which cell within the\n * table at `blockIndex`. Flat row-major index: `row * cols + col`.\n * `undefined` means the position addresses the block's own text (or the block\n * itself, for atomic blocks). Tables have no own text — every caret position\n * inside a table block carries a defined `cellIndex`.\n */\n cellIndex?: number;\n offset: number;\n}\n\nexport interface Selection {\n anchor: Position;\n focus: Position;\n}\n\nexport type MarkName =\n | \"bold\"\n | \"italic\"\n | \"underline\"\n | \"strike\"\n | \"color\"\n | \"highlight\"\n | \"fontFamily\"\n | \"fontSize\"\n | \"link\"\n | \"comment\";\n\nexport interface LinkAttr {\n href: string;\n title?: string;\n}\n\nexport interface CommentAttr {\n /** Identificador estável compartilhado com o backend (ProvaDocumentoComentario.markId). */\n markId: string;\n}\n\nexport interface MarkAttrs {\n bold?: true;\n italic?: true;\n underline?: true;\n strike?: true;\n color?: string;\n /** Cor de fundo do texto (marca-texto). CSS color, ex. `#fff176`. */\n highlight?: string;\n fontFamily?: string;\n fontSize?: string;\n link?: LinkAttr;\n comment?: CommentAttr;\n}\n\nexport type MarkValue<K extends MarkName = MarkName> = NonNullable<MarkAttrs[K]>;\n\n/**\n * Visual layout mode for an image embed.\n *\n * - `inline` (default): part of the text run, flows like a character.\n * - `wrap-left` / `wrap-right`: image floats to the named side of the anchor\n * paragraph (Word-style \"wrap square\"). Text in the paragraph wraps around it.\n * - `behind`: image is absolutely positioned beneath the text (z-index < text).\n * - `front`: image is absolutely positioned above the text (z-index > text).\n *\n * In every non-inline mode the embed remains in the Y.Text run at its offset —\n * the offset is its **anchor** (it follows the paragraph during pagination\n * and re-flows). Visual position is offset from the anchor block's content box.\n */\nexport type ImageLayout = \"inline\" | \"wrap-left\" | \"wrap-right\" | \"behind\" | \"front\";\n\nexport interface ImageEmbed {\n type: \"image\";\n /** Data URL (base64) — self-contained so the embed travels with the Y.Doc. */\n src: string;\n /** Rendered CSS px (display size — may differ from intrinsic dimensions). */\n width: number;\n height: number;\n /** When set (inline mode only), the image renders `display: block` with the matching margin auto. */\n align?: \"left\" | \"center\" | \"right\";\n /** Visual layout. Defaults to \"inline\" when omitted. */\n layout?: ImageLayout;\n /**\n * Horizontal offset in CSS px from the anchor block's content box.\n * - wrap-left: extra left margin from the paragraph's start edge.\n * - wrap-right: extra right margin from the paragraph's end edge.\n * - behind / front: `left` relative to the anchor block's padding-box.\n * Ignored for `inline`.\n */\n offsetX?: number;\n /**\n * Vertical offset in CSS px from the anchor block's content box.\n * - wrap-left / wrap-right: extra top margin pushing the float down inside\n * the paragraph.\n * - behind / front: `top` relative to the anchor block's padding-box.\n * Ignored for `inline`.\n */\n offsetY?: number;\n /**\n * Optional plain-text caption. Renders inside a `<figcaption>` beneath the\n * image in any layout — the figure wraps the image so the caption travels\n * with floats/anchors. Plain text only; rich marks are out of scope (we\n * never want a sub-editor inside an inline embed).\n */\n caption?: string;\n /**\n * Text alignment for the caption. Defaults to \"center\" (Word/Google Docs\n * default for figure captions). Only meaningful when `caption` is set.\n * Note: DOCX export emits captions inside the host paragraph, so this\n * setting only affects the editor and HTML/PDF exports — Word displays the\n * caption using the paragraph's own alignment.\n */\n captionAlign?: \"left\" | \"center\" | \"right\";\n}\n\nexport type InsertContent = string | ImageEmbed;\n\nexport function isImageEmbed(v: unknown): v is ImageEmbed {\n return (\n typeof v === \"object\" &&\n v !== null &&\n (v as { type?: unknown }).type === \"image\" &&\n typeof (v as { src?: unknown }).src === \"string\"\n );\n}\n\nexport interface DeltaOp {\n insert: InsertContent;\n attributes?: MarkAttrs;\n}\n\nexport interface SerializedCell {\n /** Plain concatenated text. */\n text: string;\n /** Delta with marks. */\n delta: DeltaOp[];\n attrs: CellAttrs;\n}\n\nexport interface SerializedBlock {\n /** Id estável do bloco (cursores colaborativos / keying). Ausente em docs antigos. */\n id?: string;\n type: BlockType;\n /** Plain concatenated text (no marks). Kept for ergonomic equality checks. */\n text: string;\n /** Yjs delta — used by the renderer to draw mark-aware spans. */\n delta: DeltaOp[];\n /** Block-level attributes (align, dir, heading level, code language…). */\n attrs: BlockAttrs;\n /** Only present when `type === \"table\"`. Flat row-major list, length = rows * cols. */\n cells?: SerializedCell[];\n}\n\nimport type { PageSettings } from \"./page-settings\";\n\n/**\n * Document JSON shape used by `EditorDocument.toJSON` / `fromJSON`, the\n * exporters and the importer. Until Fase 9.5 this was a bare `SerializedBlock[]`;\n * Fase 9.6 promoted it to an object so per-document settings (page size,\n * margins) can travel with the content.\n *\n * `fromJSON` still accepts a legacy array for backwards compatibility — see\n * `isLegacySerializedDocument`.\n */\nexport interface SerializedDocument {\n blocks: SerializedBlock[];\n /** Page settings. Optional; omitted means default A4 + 1\" margins. */\n pageSettings?: PageSettings;\n}\n\n/** A `SerializedDocument` produced before Fase 9.6 — just an array of blocks. */\nexport type LegacySerializedDocument = SerializedBlock[];\n\nexport function isLegacySerializedDocument(\n v: SerializedDocument | LegacySerializedDocument,\n): v is LegacySerializedDocument {\n return Array.isArray(v);\n}\n","import type { BlockAttrs, BlockType } from \"./types\";\n\ninterface BlockSpec {\n type: BlockType;\n defaultAttrs: BlockAttrs;\n}\n\nexport const BLOCK_SPECS: Record<BlockType, BlockSpec> = {\n paragraph: {\n type: \"paragraph\",\n defaultAttrs: {},\n },\n heading: {\n type: \"heading\",\n defaultAttrs: { level: 1 },\n },\n blockquote: {\n type: \"blockquote\",\n defaultAttrs: {},\n },\n codeBlock: {\n type: \"codeBlock\",\n defaultAttrs: {},\n },\n listItem: {\n type: \"listItem\",\n defaultAttrs: { listKind: \"bullet\", listLevel: 0 },\n },\n table: {\n type: \"table\",\n defaultAttrs: { rows: 1, cols: 1 },\n },\n};\n\nexport function isKnownBlockType(t: string): t is BlockType {\n return t in BLOCK_SPECS;\n}\n\nexport function defaultAttrsFor(type: BlockType): BlockAttrs {\n return { ...BLOCK_SPECS[type].defaultAttrs };\n}\n","/**\n * Document-level page configuration: physical size and margins.\n *\n * Everything is stored in **CSS pixels @ 96dpi** for consistency with the\n * pagination engine (`packages/react/src/usePagination.ts` reads these\n * directly). Conversion helpers (`mmToPx`, `pxToMm`) round-trip with millimeter\n * inputs from the UI and the OOXML twip values used by docx import/export.\n */\n\nexport type PagePreset = \"a4\" | \"letter\" | \"oficio\" | \"custom\";\n\nexport interface PageSettings {\n /** Page width in CSS px. */\n width: number;\n /** Page height in CSS px. */\n height: number;\n marginTop: number;\n marginBottom: number;\n marginLeft: number;\n marginRight: number;\n /**\n * The preset whose size the geometry matches, with the ±0.5mm tolerance used\n * by `detectPreset`. \"custom\" when the dimensions don't match any preset.\n * This is purely a UI hint — it's recomputed from width/height when needed.\n */\n preset?: PagePreset;\n /**\n * Free-form title persisted on the document for a consumer-rendered\n * \"system header\" (e.g. a non-editable letterhead/identification block\n * drawn on page 1 via `renderPageHeader`). Stored in `docSettings` so it\n * survives serialization and is visible to every client/consumer of the\n * `SerializedDocument`, including headless exports.\n *\n * The renderer is application-defined — this field just transports the\n * title string. Use it when the header content is part of the document\n * (and therefore must round-trip through exports), not a UI chrome\n * decoration.\n */\n systemHeaderTitle?: string;\n /**\n * Owner/author display name for the same consumer-rendered system\n * header (see [[systemHeaderTitle]]). Useful when the header should\n * show the document's CREATOR, not the current viewer (e.g. an author\n * name on a doc viewed by a third party). Persisted in `docSettings`\n * for consistent rendering across clients and headless renderers.\n */\n systemHeaderAuthor?: string;\n}\n\n/** Page sizes in CSS px @ 96dpi. */\nexport const PAGE_PRESETS = {\n a4: { width: 794, height: 1123 }, // 210×297 mm\n letter: { width: 816, height: 1056 }, // 8.5×11 in\n oficio: { width: 816, height: 1248 }, // 216×330 mm (BR Ofício)\n} as const;\n\n/** Margin presets in CSS px. Match common Word defaults. */\nexport const MARGIN_PRESETS = {\n normal: 96, // 25.4 mm = 1 in\n narrow: 48, // 12.7 mm = 0.5 in\n wide: 192, // 50.8 mm = 2 in\n} as const;\n\nexport const DEFAULT_PAGE_SETTINGS: PageSettings = {\n ...PAGE_PRESETS.a4,\n marginTop: MARGIN_PRESETS.normal,\n marginBottom: MARGIN_PRESETS.normal,\n marginLeft: MARGIN_PRESETS.normal,\n marginRight: MARGIN_PRESETS.normal,\n preset: \"a4\",\n};\n\nconst PX_PER_MM = 96 / 25.4;\n\nexport function mmToPx(mm: number): number {\n return mm * PX_PER_MM;\n}\n\nexport function pxToMm(px: number): number {\n return px / PX_PER_MM;\n}\n\n/**\n * Detect which preset a (width, height) pair matches. Tolerance is ±0.5mm to\n * absorb rounding from the twips↔px conversion used by docx round-trip.\n */\nexport function detectPreset(width: number, height: number): PagePreset {\n const TOL = mmToPx(0.5);\n for (const [name, size] of Object.entries(PAGE_PRESETS) as Array<[PagePreset, { width: number; height: number }]>) {\n if (Math.abs(width - size.width) <= TOL && Math.abs(height - size.height) <= TOL) {\n return name;\n }\n }\n return \"custom\";\n}\n\n/** Fill missing fields with the default. Useful when reading from a Y.Map that may be partially populated. */\nexport function withDefaults(partial: Partial<PageSettings> | undefined): PageSettings {\n const merged = { ...DEFAULT_PAGE_SETTINGS, ...(partial ?? {}) };\n return { ...merged, preset: detectPreset(merged.width, merged.height) };\n}\n","import * as Y from \"yjs\";\nimport { defaultAttrsFor } from \"./schema\";\nimport {\n DEFAULT_PAGE_SETTINGS,\n detectPreset,\n type PageSettings,\n} from \"./page-settings\";\nimport {\n isLegacySerializedDocument,\n type BlockAttrs,\n type BlockType,\n type CellAttrs,\n type DeltaOp,\n type LegacySerializedDocument,\n type SerializedBlock,\n type SerializedCell,\n type SerializedDocument,\n} from \"./types\";\n\n/**\n * Gera um id estável de bloco. Usado para ancorar cursores colaborativos\n * remotos (fallback) e para keying estável no overlay. Persistido no Y.Map do\n * bloco, então sobrevive a reload (binário Yjs). Docs antigos não têm — os\n * helpers de cursor lidam com a ausência (caem na RelativePosition).\n */\nexport function newBlockId(): string {\n try {\n if (typeof crypto !== \"undefined\" && typeof crypto.randomUUID === \"function\") {\n return crypto.randomUUID();\n }\n } catch {\n /* ambiente sem crypto.randomUUID — fallback abaixo */\n }\n return `b-${Math.random().toString(36).slice(2, 10)}${Date.now().toString(36)}`;\n}\n\n/** Lê o id de um bloco Y.Map (undefined em docs antigos sem id). */\nexport function getBlockId(block: Y.Map<unknown>): string | undefined {\n const id = block.get(\"id\");\n return typeof id === \"string\" ? id : undefined;\n}\n\n/**\n * Y.js-backed document.\n *\n * Storage layout:\n * ydoc.getArray(\"blocks\") : Y.Array<Y.Map>\n * each Y.Map (\"block\"):\n * - type: string (\"paragraph\" | \"heading\" | \"blockquote\" | \"codeBlock\" | \"listItem\" | \"table\")\n * - text: Y.Text (NOT present on tables)\n * - attrs: Y.Map<unknown> (align, dir, level, language… plus rows/cols for tables)\n * - cells: Y.Array<Y.Map> (only on tables, length = rows * cols, row-major)\n * each cell map: { text: Y.Text, attrs: Y.Map<unknown> }\n *\n * Block-level attrs live inside a nested Y.Map so concurrent edits (e.g. two users\n * changing alignment at once) reconcile through Yjs' last-write-wins per key.\n */\nexport class EditorDocument {\n readonly ydoc: Y.Doc;\n readonly blocks: Y.Array<Y.Map<unknown>>;\n /** Document-level settings (page size, margins). See `getPageSettings`. */\n readonly docSettings: Y.Map<unknown>;\n\n constructor(ydoc?: Y.Doc) {\n this.ydoc = ydoc ?? new Y.Doc();\n this.blocks = this.ydoc.getArray<Y.Map<unknown>>(\"blocks\");\n this.docSettings = this.ydoc.getMap<unknown>(\"docSettings\");\n\n if (this.blocks.length === 0) {\n this.ydoc.transact(() => {\n this.blocks.push([createBlock(\"paragraph\")]);\n }, \"init\");\n }\n }\n\n /**\n * Returns the current page settings. Missing fields fall back to\n * `DEFAULT_PAGE_SETTINGS`. The returned object is a fresh snapshot — mutating\n * it does not write back to the Y.Doc. Use `setPageSettings` for that.\n */\n getPageSettings(): PageSettings {\n const m = this.docSettings;\n const pick = <K extends keyof PageSettings>(key: K): PageSettings[K] | undefined => {\n const v = m.get(key as string);\n return typeof v === \"number\" || typeof v === \"string\" ? (v as PageSettings[K]) : undefined;\n };\n const merged: PageSettings = {\n width: pick(\"width\") ?? DEFAULT_PAGE_SETTINGS.width,\n height: pick(\"height\") ?? DEFAULT_PAGE_SETTINGS.height,\n marginTop: pick(\"marginTop\") ?? DEFAULT_PAGE_SETTINGS.marginTop,\n marginBottom: pick(\"marginBottom\") ?? DEFAULT_PAGE_SETTINGS.marginBottom,\n marginLeft: pick(\"marginLeft\") ?? DEFAULT_PAGE_SETTINGS.marginLeft,\n marginRight: pick(\"marginRight\") ?? DEFAULT_PAGE_SETTINGS.marginRight,\n systemHeaderTitle: pick(\"systemHeaderTitle\"),\n systemHeaderAuthor: pick(\"systemHeaderAuthor\"),\n };\n merged.preset = detectPreset(merged.width, merged.height);\n return merged;\n }\n\n /**\n * Merge `partial` into the docSettings Y.Map. Runs in a `ydoc.transact` with\n * origin `\"pageSettings\"` (NOT tracked by the UndoManager, mirroring the\n * `\"import\"` convention from Fase 9.5).\n */\n setPageSettings(partial: Partial<PageSettings>): void {\n this.ydoc.transact(() => {\n for (const [k, v] of Object.entries(partial)) {\n if (k === \"preset\") continue; // derived, never stored\n if (v === undefined) continue;\n this.docSettings.set(k, v);\n }\n }, \"pageSettings\");\n }\n\n /** Listen for page-settings changes. Returns an unsubscribe function. */\n observePageSettings(cb: () => void): () => void {\n const handler = () => cb();\n this.docSettings.observe(handler);\n return () => this.docSettings.unobserve(handler);\n }\n\n getBlock(index: number): Y.Map<unknown> | undefined {\n if (index < 0 || index >= this.blocks.length) return undefined;\n return this.blocks.get(index);\n }\n\n getBlockText(index: number): Y.Text | undefined {\n const b = this.getBlock(index);\n return b?.get(\"text\") as Y.Text | undefined;\n }\n\n getBlockType(index: number): BlockType | undefined {\n const b = this.getBlock(index);\n return b?.get(\"type\") as BlockType | undefined;\n }\n\n getBlockAttrsMap(index: number): Y.Map<unknown> | undefined {\n const b = this.getBlock(index);\n return b?.get(\"attrs\") as Y.Map<unknown> | undefined;\n }\n\n getBlockAttrs(index: number): BlockAttrs {\n const m = this.getBlockAttrsMap(index);\n if (!m) return {};\n return Object.fromEntries(m.entries()) as BlockAttrs;\n }\n\n blockCount(): number {\n return this.blocks.length;\n }\n\n // ---------- Table helpers ----------\n\n isTable(index: number): boolean {\n return this.getBlockType(index) === \"table\";\n }\n\n /** Returns rows/cols read from the block's attrs map. `{0,0}` for non-table blocks. */\n getTableSize(index: number): { rows: number; cols: number } {\n const attrs = this.getBlockAttrs(index);\n const rows = typeof attrs.rows === \"number\" ? attrs.rows : 0;\n const cols = typeof attrs.cols === \"number\" ? attrs.cols : 0;\n return { rows, cols };\n }\n\n getCells(index: number): Y.Array<Y.Map<unknown>> | undefined {\n const b = this.getBlock(index);\n return b?.get(\"cells\") as Y.Array<Y.Map<unknown>> | undefined;\n }\n\n getCell(blockIndex: number, cellIndex: number): Y.Map<unknown> | undefined {\n const cells = this.getCells(blockIndex);\n if (!cells) return undefined;\n if (cellIndex < 0 || cellIndex >= cells.length) return undefined;\n return cells.get(cellIndex);\n }\n\n getCellText(blockIndex: number, cellIndex: number): Y.Text | undefined {\n const cell = this.getCell(blockIndex, cellIndex);\n return cell?.get(\"text\") as Y.Text | undefined;\n }\n\n getCellAttrsMap(blockIndex: number, cellIndex: number): Y.Map<unknown> | undefined {\n const cell = this.getCell(blockIndex, cellIndex);\n return cell?.get(\"attrs\") as Y.Map<unknown> | undefined;\n }\n\n getCellAttrs(blockIndex: number, cellIndex: number): CellAttrs {\n const m = this.getCellAttrsMap(blockIndex, cellIndex);\n if (!m) return {};\n return Object.fromEntries(m.entries()) as CellAttrs;\n }\n\n /**\n * Returns the editable Y.Text targeted by a position:\n * - When `cellIndex` is set: the cell's text (or the owner's text if the\n * target cell is covered by a span — we treat the covered position as\n * addressing the owner).\n * - Otherwise: the block's own text.\n */\n textAt(blockIndex: number, cellIndex: number | undefined): Y.Text | undefined {\n if (cellIndex == null) return this.getBlockText(blockIndex);\n const real = this.realCellIndex(blockIndex, cellIndex);\n if (real == null) return undefined;\n return this.getCellText(blockIndex, real);\n }\n\n /**\n * Returns the \"real\" (non-covered) cell index for a target cell. When the\n * target is already a real cell, returns it unchanged. When covered, walks\n * up-and-left to find the owner.\n *\n * The walk is robust to oversized or non-rectangular spans by skipping\n * candidates whose declared span doesn't actually cover the target.\n */\n realCellIndex(blockIndex: number, cellIndex: number): number | undefined {\n if (!this.isTable(blockIndex)) return undefined;\n const { rows, cols } = this.getTableSize(blockIndex);\n if (rows <= 0 || cols <= 0) return undefined;\n if (cellIndex < 0 || cellIndex >= rows * cols) return undefined;\n const targetAttrs = this.getCellAttrs(blockIndex, cellIndex);\n if (targetAttrs.covered !== true) return cellIndex;\n\n const tRow = Math.floor(cellIndex / cols);\n const tCol = cellIndex - tRow * cols;\n // Scan candidate owners — any real cell (or, oc) with or <= tRow, oc <= tCol,\n // spanning into (tRow, tCol). Walk from (tRow, tCol) up-and-left.\n for (let or = tRow; or >= 0; or--) {\n for (let oc = tCol; oc >= 0; oc--) {\n const idx = or * cols + oc;\n if (idx === cellIndex) continue;\n const a = this.getCellAttrs(blockIndex, idx);\n if (a.covered === true) continue;\n const rs = spanOf(a.rowspan);\n const cs = spanOf(a.colspan);\n if (or + rs - 1 >= tRow && oc + cs - 1 >= tCol) return idx;\n }\n }\n return undefined;\n }\n\n /**\n * Replace the document contents with a `SerializedDocument`. Runs in a single\n * `ydoc.transact` with origin `\"import\"` so the UndoManager can group or skip\n * the operation as one step.\n *\n * Reuses `createBlock` / `createTableBlock` so every block ends up with the\n * exact same Y.js shape produced by the rest of the editor.\n */\n loadFromJSON(serialized: SerializedDocument | LegacySerializedDocument): void {\n const { blocks: sourceBlocks, pageSettings } = normalizeSerialized(serialized);\n // Lock anti-concorrência: `loadFromJSON` é destrutivo (clear+push) e\n // dois imports concorrentes (especialmente entre clientes via CRDT)\n // historicamente produziram blocks duplicados em massa (caso 172k).\n // Marker em `docSettings.__importLock` com TTL 5s — se outro import\n // foi iniciado < 5s atrás, este aborta com warning ao invés de\n // sobrescrever. A janela de 5s cobre a latência de rede do Hocuspocus\n // entre clients durante imports humanos típicos.\n const LOCK_KEY = \"__importLock\";\n const LOCK_TTL_MS = 5_000;\n const existing = this.docSettings.get(LOCK_KEY);\n if (typeof existing === \"number\" && Date.now() - existing < LOCK_TTL_MS) {\n const ageMs = Date.now() - existing;\n console.warn(\n `[EditorDocument.loadFromJSON] import já em andamento (${ageMs}ms atrás, TTL ${LOCK_TTL_MS}ms) — ignorando esta chamada para evitar duplicação de blocks.`,\n );\n return;\n }\n this.docSettings.set(LOCK_KEY, Date.now());\n this.ydoc.transact(() => {\n if (this.blocks.length > 0) {\n this.blocks.delete(0, this.blocks.length);\n }\n // Build the Y structure in two passes: first create empty blocks (with\n // correct type/attrs/cells shape) and push them so their inner Y.Texts\n // get integrated into the document; only then apply each delta. Y.Text\n // requires an active transaction context that exists for integrated\n // instances — `applyDelta` on a detached Y.Text throws.\n const sources = sourceBlocks.length > 0 ? sourceBlocks : [makeEmptyParagraphSource()];\n const fresh: Y.Map<unknown>[] = sources.map((b) => buildEmptyBlockFromSerialized(b));\n this.blocks.push(fresh);\n\n for (let i = 0; i < sources.length; i++) {\n const src = sources[i];\n const yBlock = this.blocks.get(i);\n applyDeltaIntoBlock(yBlock, src);\n }\n\n if (pageSettings) {\n for (const [k, v] of Object.entries(pageSettings)) {\n if (k === \"preset\") continue;\n if (v === undefined) continue;\n this.docSettings.set(k, v);\n }\n }\n // Limpa o lock no fim do import (mesma transaction \"import\"). Se\n // crashar antes daqui, o TTL de 5s expira a entrada e o doc volta a\n // aceitar imports.\n this.docSettings.delete(LOCK_KEY);\n }, \"import\");\n }\n\n /** Build a fresh `EditorDocument` from a `SerializedDocument`. */\n static fromJSON(serialized: SerializedDocument | LegacySerializedDocument): EditorDocument {\n const ydoc = new Y.Doc();\n // Touch the shared array before loadFromJSON so the constructor doesn't\n // insert its default paragraph — we replace the contents anyway.\n ydoc.getArray<Y.Map<unknown>>(\"blocks\");\n const doc = new EditorDocument(ydoc);\n doc.loadFromJSON(serialized);\n return doc;\n }\n\n toJSON(): SerializedDocument {\n const blocks = this.blocks.toArray().map<SerializedBlock>((b) => {\n const type = (b.get(\"type\") as BlockType) ?? \"paragraph\";\n const attrsMap = b.get(\"attrs\") as Y.Map<unknown> | undefined;\n const attrs = attrsMap ? (Object.fromEntries(attrsMap.entries()) as BlockAttrs) : {};\n\n // NOTA: o `id` do bloco NÃO entra no serialized_json (mantém a forma do\n // JSON estável p/ bloat-check/API e os testes de round-trip). O id vive no\n // Y.Map e persiste no binário Yjs — é onde os cursores precisam dele.\n if (type === \"table\") {\n const cellsArray = b.get(\"cells\") as Y.Array<Y.Map<unknown>> | undefined;\n const cells: SerializedCell[] = cellsArray\n ? cellsArray.toArray().map((c) => serializeCell(c))\n : [];\n return {\n type,\n text: \"\",\n delta: [],\n attrs,\n cells,\n };\n }\n\n const yText = b.get(\"text\") as Y.Text | undefined;\n return {\n type,\n text: yText?.toString() ?? \"\",\n delta: (yText?.toDelta() as DeltaOp[] | undefined) ?? [],\n attrs,\n };\n });\n return { blocks, pageSettings: this.getPageSettings() };\n }\n}\n\nfunction normalizeSerialized(\n v: SerializedDocument | LegacySerializedDocument,\n): { blocks: SerializedBlock[]; pageSettings?: PageSettings } {\n if (isLegacySerializedDocument(v)) {\n return { blocks: v };\n }\n return { blocks: v.blocks, pageSettings: v.pageSettings };\n}\n\nfunction serializeCell(c: Y.Map<unknown>): SerializedCell {\n const yText = c.get(\"text\") as Y.Text | undefined;\n const attrsMap = c.get(\"attrs\") as Y.Map<unknown> | undefined;\n return {\n text: yText?.toString() ?? \"\",\n delta: (yText?.toDelta() as DeltaOp[] | undefined) ?? [],\n attrs: attrsMap ? (Object.fromEntries(attrsMap.entries()) as Record<string, unknown>) : {},\n };\n}\n\nexport function createBlock(\n type: BlockType,\n initialText = \"\",\n attrs?: BlockAttrs,\n): Y.Map<unknown> {\n if (type === \"table\") {\n // Callers that need a table should use createTableBlock(rows, cols).\n // We honor any rows/cols passed via attrs but default to 1x1 to keep the\n // invariant `cells.length === rows * cols` non-zero.\n const merged = { ...defaultAttrsFor(\"table\"), ...(attrs ?? {}) };\n const rows = typeof merged.rows === \"number\" && merged.rows > 0 ? Math.trunc(merged.rows) : 1;\n const cols = typeof merged.cols === \"number\" && merged.cols > 0 ? Math.trunc(merged.cols) : 1;\n return createTableBlock(rows, cols);\n }\n\n const block = new Y.Map<unknown>();\n block.set(\"id\", newBlockId());\n block.set(\"type\", type);\n const yText = new Y.Text();\n if (initialText.length > 0) yText.insert(0, initialText);\n block.set(\"text\", yText);\n const attrsMap = new Y.Map<unknown>();\n const merged = { ...defaultAttrsFor(type), ...(attrs ?? {}) };\n for (const [k, v] of Object.entries(merged)) {\n if (v !== undefined) attrsMap.set(k, v);\n }\n block.set(\"attrs\", attrsMap);\n return block;\n}\n\n/**\n * Build a table block with `rows × cols` empty cells.\n * Cells are stored in row-major order: `cell[row * cols + col]`.\n */\nexport function createTableBlock(rows: number, cols: number): Y.Map<unknown> {\n const r = Math.max(1, Math.trunc(rows));\n const c = Math.max(1, Math.trunc(cols));\n const block = new Y.Map<unknown>();\n block.set(\"id\", newBlockId());\n block.set(\"type\", \"table\");\n const attrsMap = new Y.Map<unknown>();\n attrsMap.set(\"rows\", r);\n attrsMap.set(\"cols\", c);\n block.set(\"attrs\", attrsMap);\n const cells = new Y.Array<Y.Map<unknown>>();\n const total = r * c;\n const fresh: Y.Map<unknown>[] = [];\n for (let i = 0; i < total; i++) fresh.push(createCell());\n cells.push(fresh);\n block.set(\"cells\", cells);\n return block;\n}\n\nexport function createCell(attrs?: CellAttrs): Y.Map<unknown> {\n const m = new Y.Map<unknown>();\n m.set(\"text\", new Y.Text());\n const attrsMap = new Y.Map<unknown>();\n if (attrs) {\n for (const [k, v] of Object.entries(attrs)) {\n if (v === undefined) continue;\n attrsMap.set(k, v);\n }\n }\n m.set(\"attrs\", attrsMap);\n return m;\n}\n\nfunction makeEmptyParagraphSource(): SerializedBlock {\n return { type: \"paragraph\", text: \"\", delta: [], attrs: {} };\n}\n\nfunction buildEmptyBlockFromSerialized(block: SerializedBlock): Y.Map<unknown> {\n if (block.type === \"table\") {\n const rows =\n typeof block.attrs.rows === \"number\" ? Math.max(1, Math.trunc(block.attrs.rows)) : 1;\n const cols =\n typeof block.attrs.cols === \"number\" ? Math.max(1, Math.trunc(block.attrs.cols)) : 1;\n const yBlock = new Y.Map<unknown>();\n yBlock.set(\"id\", typeof block.id === \"string\" ? block.id : newBlockId());\n yBlock.set(\"type\", \"table\");\n const attrsMap = new Y.Map<unknown>();\n attrsMap.set(\"rows\", rows);\n attrsMap.set(\"cols\", cols);\n for (const [k, v] of Object.entries(block.attrs)) {\n if (k === \"rows\" || k === \"cols\") continue;\n if (v === undefined) continue;\n attrsMap.set(k, v);\n }\n yBlock.set(\"attrs\", attrsMap);\n const cellsArr = new Y.Array<Y.Map<unknown>>();\n const total = rows * cols;\n const fresh: Y.Map<unknown>[] = [];\n const cells = block.cells ?? [];\n for (let i = 0; i < total; i++) {\n const src = cells[i];\n fresh.push(createCell((src?.attrs ?? undefined) as CellAttrs | undefined));\n }\n cellsArr.push(fresh);\n yBlock.set(\"cells\", cellsArr);\n return yBlock;\n }\n const yb = createBlock(block.type, \"\", block.attrs);\n // Preserva o id serializado (round-trip JSON), senão usa o gerado em createBlock.\n if (typeof block.id === \"string\") yb.set(\"id\", block.id);\n return yb;\n}\n\nfunction applyDeltaIntoBlock(yBlock: Y.Map<unknown> | undefined, src: SerializedBlock): void {\n if (!yBlock) return;\n if (src.type === \"table\") {\n const cellsArr = yBlock.get(\"cells\") as Y.Array<Y.Map<unknown>> | undefined;\n if (!cellsArr) return;\n const cells = src.cells ?? [];\n for (let i = 0; i < cellsArr.length; i++) {\n const cellSrc = cells[i];\n if (!cellSrc || !cellSrc.delta || cellSrc.delta.length === 0) continue;\n const cell = cellsArr.get(i);\n const yText = cell.get(\"text\") as Y.Text | undefined;\n if (!yText) continue;\n yText.applyDelta(cellSrc.delta as unknown as Array<{ insert: unknown; attributes?: unknown }>);\n }\n return;\n }\n if (!src.delta || src.delta.length === 0) return;\n const yText = yBlock.get(\"text\") as Y.Text | undefined;\n if (!yText) return;\n yText.applyDelta(src.delta as unknown as Array<{ insert: unknown; attributes?: unknown }>);\n}\n\n/** Coerce a `rowspan`/`colspan` attribute value into a positive integer. */\nexport function spanOf(value: unknown): number {\n if (typeof value !== \"number\" || !Number.isFinite(value)) return 1;\n return Math.max(1, Math.trunc(value));\n}\n","import * as Y from \"yjs\";\nimport type { EditorDocument } from \"./document\";\nimport { getBlockId } from \"./document\";\nimport type { Position, Selection } from \"./types\";\n\n/**\n * Codificação de cursor colaborativo resiliente a edição concorrente.\n *\n * Posições do editor são ABSOLUTAS ({blockIndex, offset}) — quebram quando\n * blocos/texto são inseridos/removidos acima por outro usuário. Aqui usamos\n * `Y.RelativePosition`, que ancora no caractere exato dentro do `Y.Text` e\n * sobrevive a moves/edições (é o que o Google Docs faz). O `blockId` é um\n * fallback: se o caractere ancorado foi apagado, posicionamos no início do\n * bloco original.\n */\n\n// ---------- base64 de Uint8Array (browser + node) ----------\nfunction toBase64(bytes: Uint8Array): string {\n if (typeof Buffer !== \"undefined\") return Buffer.from(bytes).toString(\"base64\");\n let s = \"\";\n for (let i = 0; i < bytes.length; i++) s += String.fromCharCode(bytes[i]);\n return btoa(s);\n}\nfunction fromBase64(b64: string): Uint8Array {\n if (typeof Buffer !== \"undefined\") return new Uint8Array(Buffer.from(b64, \"base64\"));\n const s = atob(b64);\n const out = new Uint8Array(s.length);\n for (let i = 0; i < s.length; i++) out[i] = s.charCodeAt(i);\n return out;\n}\n\n/** Y.Text que contém a posição (texto do bloco, ou de uma célula de tabela). */\nfunction yTextAt(doc: EditorDocument, pos: Position): Y.Text | null {\n const block = doc.blocks.get(pos.blockIndex);\n if (!block) return null;\n if (typeof pos.cellIndex === \"number\") {\n const cells = block.get(\"cells\") as Y.Array<Y.Map<unknown>> | undefined;\n const cell = cells?.get(pos.cellIndex);\n const t = cell?.get(\"text\");\n return t instanceof Y.Text ? t : null;\n }\n const t = block.get(\"text\");\n return t instanceof Y.Text ? t : null;\n}\n\n/** Localiza {blockIndex, cellIndex?} de um Y.Text já resolvido. O(n) nos blocos. */\nfunction locateYText(\n doc: EditorDocument,\n target: Y.Text,\n): { blockIndex: number; cellIndex?: number } | null {\n const blocks = doc.blocks;\n for (let i = 0; i < blocks.length; i++) {\n const block = blocks.get(i);\n if (block.get(\"text\") === target) return { blockIndex: i };\n const cells = block.get(\"cells\") as Y.Array<Y.Map<unknown>> | undefined;\n if (cells) {\n for (let c = 0; c < cells.length; c++) {\n if (cells.get(c)?.get(\"text\") === target) {\n return { blockIndex: i, cellIndex: c };\n }\n }\n }\n }\n return null;\n}\n\nexport interface EncodedCursorPoint {\n /** base64 de Y.encodeRelativePosition — rastreia o caractere exato. */\n rel: string;\n /** Fallback: id do bloco original (ancora no início se o char sumiu). */\n blockId?: string;\n /** Fallback: célula da tabela, se aplicável. */\n cellIndex?: number;\n}\n\nexport interface EncodedCursor {\n anchor: EncodedCursorPoint;\n focus: EncodedCursorPoint;\n}\n\nfunction encodePoint(doc: EditorDocument, pos: Position): EncodedCursorPoint | null {\n const yText = yTextAt(doc, pos);\n if (!yText) return null;\n const offset = Math.max(0, Math.min(pos.offset, yText.length));\n const rel = Y.createRelativePositionFromTypeIndex(yText, offset);\n const block = doc.blocks.get(pos.blockIndex);\n const point: EncodedCursorPoint = { rel: toBase64(Y.encodeRelativePosition(rel)) };\n const blockId = block ? getBlockId(block) : undefined;\n if (blockId) point.blockId = blockId;\n if (typeof pos.cellIndex === \"number\") point.cellIndex = pos.cellIndex;\n return point;\n}\n\nfunction decodePoint(doc: EditorDocument, enc: EncodedCursorPoint): Position | null {\n // 1) Primário: RelativePosition (rastreia o char mesmo após edições/moves).\n try {\n const rel = Y.decodeRelativePosition(fromBase64(enc.rel));\n const abs = Y.createAbsolutePositionFromRelativePosition(rel, doc.ydoc);\n if (abs && abs.type instanceof Y.Text) {\n const loc = locateYText(doc, abs.type);\n if (loc) return { ...loc, offset: abs.index };\n }\n } catch {\n /* cai no fallback */\n }\n // 2) Fallback: acha o bloco pelo id e ancora no início.\n if (enc.blockId) {\n for (let i = 0; i < doc.blocks.length; i++) {\n if (getBlockId(doc.blocks.get(i)) === enc.blockId) {\n const p: Position = { blockIndex: i, offset: 0 };\n if (typeof enc.cellIndex === \"number\") p.cellIndex = enc.cellIndex;\n return p;\n }\n }\n }\n return null;\n}\n\n/** Codifica a seleção local em um descritor portável (para o awareness). */\nexport function encodeSelection(\n doc: EditorDocument,\n sel: Selection,\n): EncodedCursor | null {\n const anchor = encodePoint(doc, sel.anchor);\n const focus = encodePoint(doc, sel.focus);\n if (!anchor || !focus) return null;\n return { anchor, focus };\n}\n\n/** Decodifica um descritor remoto para uma seleção absoluta no doc atual. */\nexport function decodeSelection(\n doc: EditorDocument,\n enc: EncodedCursor,\n): Selection | null {\n const anchor = decodePoint(doc, enc.anchor);\n const focus = decodePoint(doc, enc.focus);\n if (!anchor || !focus) return null;\n return { anchor, focus };\n}\n","import type { Position, Selection } from \"./types\";\n\nexport function isCollapsed(sel: Selection): boolean {\n return positionsEqual(sel.anchor, sel.focus);\n}\n\nexport function positionsEqual(a: Position, b: Position): boolean {\n return (\n a.blockIndex === b.blockIndex &&\n (a.cellIndex ?? -1) === (b.cellIndex ?? -1) &&\n a.offset === b.offset\n );\n}\n\nexport function comparePositions(a: Position, b: Position): number {\n if (a.blockIndex !== b.blockIndex) return a.blockIndex - b.blockIndex;\n const ac = a.cellIndex ?? -1;\n const bc = b.cellIndex ?? -1;\n if (ac !== bc) return ac - bc;\n return a.offset - b.offset;\n}\n\nexport function orderedRange(sel: Selection): { start: Position; end: Position } {\n if (comparePositions(sel.anchor, sel.focus) <= 0) {\n return { start: sel.anchor, end: sel.focus };\n }\n return { start: sel.focus, end: sel.anchor };\n}\n\nexport function collapsedSelection(pos: Position): Selection {\n return { anchor: pos, focus: pos };\n}\n\n/**\n * Two positions are in the same \"editable run\" (same Y.Text) when they share\n * the block index AND the cellIndex (treating absent and present-with-undefined\n * the same way: a non-table position has cellIndex === undefined for both).\n */\nexport function sameTextRun(a: Position, b: Position): boolean {\n return a.blockIndex === b.blockIndex && (a.cellIndex ?? -1) === (b.cellIndex ?? -1);\n}\n","import type * as Y from \"yjs\";\nimport type { DeltaOp, MarkAttrs, MarkName } from \"./types\";\n\n/**\n * Helpers for reading mark attributes off a Y.Text by inspecting its delta.\n * Writing is done with `yText.format(...)` directly in commands.ts.\n */\n\n/**\n * Every mark name as a runtime record. Typed as `Record<MarkName, true>` so the\n * object is compiler-enforced to stay complete: adding a new `MarkName` fails to\n * compile until it's listed here.\n */\nconst ALL_MARKS: Record<MarkName, true> = {\n bold: true,\n italic: true,\n underline: true,\n strike: true,\n color: true,\n highlight: true,\n fontFamily: true,\n fontSize: true,\n link: true,\n comment: true,\n};\n\n/**\n * Attributes object that explicitly clears every mark (sets each to `null`).\n * Spread your desired marks on top to insert text carrying EXACTLY those marks,\n * overriding any formatting Y.Text would otherwise inherit from an adjacent run.\n */\nexport const CLEAR_ALL_MARKS: Record<string, null> = Object.fromEntries(\n Object.keys(ALL_MARKS).map((k) => [k, null]),\n);\n\nfunction iterateRunsInRange(\n yText: Y.Text,\n start: number,\n end: number,\n visit: (run: DeltaOp, runStart: number, runEnd: number) => void,\n): void {\n if (start >= end) return;\n const delta = yText.toDelta() as DeltaOp[];\n let cursor = 0;\n for (const op of delta) {\n if (typeof op.insert !== \"string\") {\n // Embed: advance cursor (counts as 1 char) but don't visit — mark queries\n // are about text runs, not embed attributes.\n if (op.insert == null) continue;\n cursor += 1;\n if (cursor > end) break;\n continue;\n }\n const opStart = cursor;\n const opEnd = cursor + op.insert.length;\n cursor = opEnd;\n if (opEnd <= start) continue;\n if (opStart >= end) break;\n const runStart = Math.max(opStart, start);\n const runEnd = Math.min(opEnd, end);\n visit(op, runStart, runEnd);\n }\n}\n\n/**\n * Returns the marks observed across `[start, end)`. For each mark name encountered:\n * - if every covered character has the same value, returns that value\n * - if values differ OR some characters lack the mark, returns \"mixed\"\n */\nexport function getMarksInRange(\n yText: Y.Text,\n start: number,\n end: number,\n): Partial<Record<MarkName, MarkAttrs[MarkName] | \"mixed\">> {\n const result: Partial<Record<MarkName, MarkAttrs[MarkName] | \"mixed\">> = {};\n if (start >= end) return result;\n\n // Track total covered length and per-mark covered length to detect \"some chars lacked it\".\n const total = end - start;\n const coveredByName: Partial<Record<MarkName, number>> = {};\n\n iterateRunsInRange(yText, start, end, (run, runStart, runEnd) => {\n const len = runEnd - runStart;\n const attrs = (run.attributes ?? {}) as MarkAttrs;\n (Object.keys(attrs) as MarkName[]).forEach((name) => {\n const value = attrs[name];\n if (value === undefined || value === null) return;\n const prev = result[name];\n if (prev === undefined) {\n result[name] = value;\n } else if (prev !== \"mixed\" && !sameMarkValue(prev, value)) {\n result[name] = \"mixed\";\n }\n coveredByName[name] = (coveredByName[name] ?? 0) + len;\n });\n });\n\n (Object.keys(result) as MarkName[]).forEach((name) => {\n if ((coveredByName[name] ?? 0) < total) {\n result[name] = \"mixed\";\n }\n });\n\n return result;\n}\n\nexport function isMarkUniformInRange(\n yText: Y.Text,\n start: number,\n end: number,\n name: MarkName,\n value?: MarkAttrs[MarkName],\n): boolean {\n if (start >= end) return false;\n const total = end - start;\n let covered = 0;\n let observed: MarkAttrs[MarkName] | undefined;\n let ok = true;\n iterateRunsInRange(yText, start, end, (run, runStart, runEnd) => {\n if (!ok) return;\n const len = runEnd - runStart;\n const attr = (run.attributes ?? {})[name];\n if (attr === undefined || attr === null) {\n ok = false;\n return;\n }\n if (value !== undefined && !sameMarkValue(value, attr)) {\n ok = false;\n return;\n }\n if (observed === undefined) {\n observed = attr;\n } else if (!sameMarkValue(observed, attr)) {\n ok = false;\n return;\n }\n covered += len;\n });\n return ok && covered === total;\n}\n\n/** Total number of inserted characters. Embeds (non-string inserts) count as 1. */\nexport function deltaLength(delta: DeltaOp[]): number {\n let sum = 0;\n for (const op of delta) {\n if (typeof op.insert === \"string\") sum += op.insert.length;\n else if (op.insert != null) sum += 1;\n }\n return sum;\n}\n\n/**\n * Return the subset of `delta` covering `[start, end)` characters.\n * Embeds are atomic length-1 ops: included whole if their slot intersects the range.\n */\nexport function sliceDelta(delta: DeltaOp[], start: number, end: number): DeltaOp[] {\n if (end <= start) return [];\n const out: DeltaOp[] = [];\n let cursor = 0;\n for (const op of delta) {\n if (typeof op.insert === \"string\") {\n const opStart = cursor;\n const opEnd = cursor + op.insert.length;\n cursor = opEnd;\n if (opEnd <= start) continue;\n if (opStart >= end) break;\n const sliceFrom = Math.max(opStart, start) - opStart;\n const sliceTo = Math.min(opEnd, end) - opStart;\n out.push({\n insert: op.insert.slice(sliceFrom, sliceTo),\n attributes: op.attributes,\n });\n } else if (op.insert != null) {\n const opStart = cursor;\n const opEnd = cursor + 1;\n cursor = opEnd;\n if (opEnd <= start) continue;\n if (opStart >= end) break;\n out.push({ insert: op.insert, attributes: op.attributes });\n }\n }\n return out;\n}\n\nfunction sameMarkValue(a: unknown, b: unknown): boolean {\n if (a === b) return true;\n if (typeof a === \"object\" && typeof b === \"object\" && a && b) {\n const aKeys = Object.keys(a);\n const bKeys = Object.keys(b);\n if (aKeys.length !== bKeys.length) return false;\n return aKeys.every((k) => (a as Record<string, unknown>)[k] === (b as Record<string, unknown>)[k]);\n }\n return false;\n}\n","/**\n * Helpers puros de decoração visual, compartilhados pelos DOIS renderizadores\n * (`@sofereditor/react` e `@sofereditor/export-pdf`).\n *\n * Ficam aqui, e não dentro de cada renderizador, porque decoração divergente\n * entre editor e PDF é exatamente o modo de falha que a fidelidade de impressão\n * do projeto existe para impedir.\n */\n\nimport type { BlockAttrs } from \"./types\";\n\n/** Estilo CSS em camelCase — compatível com `CSSProperties` do React. */\nexport type StyleRecord = Record<string, string>;\n\n/** Mínimo de underlines consecutivos que viram lacuna. */\nexport const BLANK_MIN_RUN = 3;\n\n/**\n * Segmenta um texto em trechos normais e corridas de `BLANK_MIN_RUN`+ underlines.\n *\n * INVARIANTE: a concatenação dos segmentos reconstrói o texto original\n * caractere a caractere. Os offsets do modelo dependem disso — `dom-bridge`\n * mapeia posição de DOM para offset somando `textContent.length`, então dividir\n * uma run em sub-spans é seguro, mas introduzir ou remover caracteres não é.\n */\nexport function splitUnderscoreRuns(text: string): Array<{ text: string; blank: boolean }> {\n if (text.length === 0) return [];\n // Regex local: `lastIndex` de um literal com /g é estado compartilhado entre\n // chamadas se a instância for reaproveitada.\n const re = new RegExp(`_{${BLANK_MIN_RUN},}`, \"g\");\n const out: Array<{ text: string; blank: boolean }> = [];\n let last = 0;\n let match: RegExpExecArray | null;\n while ((match = re.exec(text)) !== null) {\n if (match.index > last) out.push({ text: text.slice(last, match.index), blank: false });\n out.push({ text: match[0], blank: true });\n last = match.index + match[0].length;\n }\n if (last < text.length) out.push({ text: text.slice(last), blank: false });\n return out;\n}\n\n/**\n * Estilo da lacuna: uma corrida de underlines vira um traço contínuo, sem\n * serrilhado, com a largura exata da sequência digitada.\n *\n * `-webkit-text-fill-color` apaga o GLIFO mas preserva `color`.\n *\n * O traço é `border-bottom`, e NÃO `text-decoration: underline`: no Chrome o\n * `-webkit-text-fill-color` também apaga a decoração de texto — inclusive com\n * `text-decoration-color: currentColor`, que resolve para a cor de\n * PREENCHIMENTO, não para `color`. Verificado no navegador: a variante com\n * `underline` renderiza uma lacuna completamente invisível. `border-bottom`\n * com `currentColor` resolve para `color` e acompanha a mark de cor do run.\n *\n * PROIBIDO acrescentar aqui: `display`, `padding`, `margin`, `letterSpacing`,\n * `width`. Qualquer um desloca métricas e a paginação diverge do PDF. Bordas de\n * elemento inline não afetam a altura da linha — medido: linha com e sem\n * lacuna tem exatamente a mesma altura e a mesma largura.\n */\nexport const BLANK_STYLE: StyleRecord = {\n WebkitTextFillColor: \"transparent\",\n borderBottom: \"1px solid currentColor\",\n};\n\n/** Cor da régua da linha de resposta. Preto: é uma linha para escrever à caneta. */\nexport const ANSWER_LINE_COLOR = \"#000000\";\n\n/**\n * Estilo do parágrafo pautado. `undefined` quando o bloco não é linha de\n * resposta, para o renderizador não emitir atributo `style` à toa.\n *\n * Diferente das bordas de tabela (cuja geometria é invariante por construção),\n * `lineHeight` muda a altura medida do bloco DE PROPÓSITO — a paginação precisa\n * medir o resultado, não presumir a entrelinha.\n */\nexport function answerLineStyle(attrs: BlockAttrs): StyleRecord | undefined {\n if (attrs.answerLine !== true) return undefined;\n const spacing = attrs.answerLineSpacing ?? 1;\n return {\n borderBottom: `1px solid ${ANSWER_LINE_COLOR}`,\n lineHeight: String(spacing),\n // `minHeight` casado com a entrelinha, e NÃO redundante: o CSS do\n // consumidor costuma trazer `min-height` em parágrafo (o playground usa\n // 1.5em \"para manter parágrafo vazio visível\"). Sem esta linha, \"Simples\"\n // e \"1,5\" renderizariam com a mesma altura.\n minHeight: `${spacing}em`,\n };\n}\n\n/** Converte um `StyleRecord` camelCase em texto CSS (`a:b;c:d`). */\nexport function styleToCssText(style: StyleRecord): string {\n return Object.entries(style)\n .map(([k, v]) => `${kebab(k)}:${v}`)\n .join(\";\");\n}\n\nfunction kebab(prop: string): string {\n // Custom properties (`--x`) já vêm no formato final.\n if (prop.startsWith(\"--\")) return prop;\n // `WebkitTextFillColor` → `-webkit-text-fill-color` (o W inicial vira `-w`).\n return prop.replace(/[A-Z]/g, (c) => `-${c.toLowerCase()}`);\n}\n","import type { StyleRecord } from \"./decorations\";\nimport type { TableBorderPreset } from \"./types\";\n\n/** Cor da grade. Mesmo valor que o CSS de `.ed-cell` já usa. */\nexport const TABLE_BORDER_COLOR = \"#cbd5e1\";\n\n/**\n * Guia de tela para lados de borda desligados por preset.\n *\n * É uma custom property com fallback `transparent`: sem a variável definida\n * (consumidor sem CSS próprio, ou dentro de `@media print`), o lado\n * simplesmente não aparece — que é o correto para impressão. Nunca muda a\n * geometria: o lado continua com 1px, só sem cor.\n */\nexport const TABLE_GUIDE_COLOR = \"var(--ed-guide-color, transparent)\";\n\nexport interface CellBorderPos {\n /** Linha absoluta da célula na tabela lógica. */\n row: number;\n /** Coluna absoluta. */\n col: number;\n rowspan: number;\n colspan: number;\n /** Total de colunas da tabela. */\n cols: number;\n /** Primeira linha do fragmento renderizado. Tabela inteira = 0. */\n rowStart: number;\n /** Fim exclusivo do fragmento. Tabela inteira = `rows`. */\n rowEnd: number;\n}\n\nexport interface CellBorderColors {\n top: string;\n right: string;\n bottom: string;\n left: string;\n}\n\n/**\n * Cor de cada lado da célula segundo o preset.\n *\n * NUNCA devolve espessura. Trocar de preset muda só cor, então nenhuma linha\n * reflui e a paginação já validada não se mexe. Como todas as bordas têm a\n * mesma espessura e o mesmo estilo em toda a tabela, também não há conflito de\n * `border-collapse` para resolver.\n *\n * As bordas externas seguem os limites do FRAGMENTO, não da tabela lógica: numa\n * tabela quebrada entre páginas, cada página fecha a própria caixa — o\n * comportamento do Word.\n *\n * O teste de \"toca a borda\" usa row/col + spans em vez dos seletores CSS\n * `:first-child`/`:last-child`, que quebram assim que uma célula `covered` some\n * do DOM por causa de um rowspan.\n */\nexport function cellBorderColors(\n preset: TableBorderPreset | undefined,\n pos: CellBorderPos,\n variant: \"screen\" | \"print\",\n color?: string,\n): CellBorderColors {\n // String vazia cai no default: apagar a borda é papel do preset \"none\",\n // não de uma cor vazia.\n const on = color && color.length > 0 ? color : TABLE_BORDER_COLOR;\n // `off` NUNCA recebe a cor escolhida. Pintar a guia com ela faria um preset\n // \"none\" com borda preta desenhar linhas na tela e nada no PDF — a divergência\n // tela↔papel que o projeto existe para evitar.\n const off = variant === \"screen\" ? TABLE_GUIDE_COLOR : \"transparent\";\n switch (preset ?? \"all\") {\n case \"horizontal\":\n return { top: on, right: off, bottom: on, left: off };\n case \"vertical\":\n return { top: off, right: on, bottom: off, left: on };\n case \"none\":\n return { top: off, right: off, bottom: off, left: off };\n case \"outer\": {\n const isTop = pos.row === pos.rowStart;\n const isBottom = pos.row + Math.max(1, pos.rowspan) - 1 === pos.rowEnd - 1;\n const isLeft = pos.col === 0;\n const isRight = pos.col + Math.max(1, pos.colspan) - 1 === pos.cols - 1;\n return {\n top: isTop ? on : off,\n right: isRight ? on : off,\n bottom: isBottom ? on : off,\n left: isLeft ? on : off,\n };\n }\n case \"all\":\n default:\n return { top: on, right: on, bottom: on, left: on };\n }\n}\n\n/** `cellBorderColors` no formato de estilo inline consumido pelos renderizadores. */\nexport function cellBorderStyle(\n preset: TableBorderPreset | undefined,\n pos: CellBorderPos,\n variant: \"screen\" | \"print\",\n color?: string,\n): StyleRecord {\n const c = cellBorderColors(preset, pos, variant, color);\n return {\n borderTopColor: c.top,\n borderRightColor: c.right,\n borderBottomColor: c.bottom,\n borderLeftColor: c.left,\n };\n}\n","import * as Y from \"yjs\";\nimport { EditorDocument, createBlock, createCell, createTableBlock, spanOf } from \"./document\";\nimport { CLEAR_ALL_MARKS, deltaLength, isMarkUniformInRange, sliceDelta } from \"./marks\";\nimport { sliceToInlineDelta, type ClipboardSlice } from \"./clipboard\";\nimport { defaultAttrsFor } from \"./schema\";\nimport { collapsedSelection, isCollapsed, orderedRange, sameTextRun } from \"./selection\";\nimport type {\n AnswerLineSpacing,\n BlockAttrs,\n BlockType,\n CellAttrs,\n DeltaOp,\n ImageEmbed,\n ListKind,\n MarkAttrs,\n MarkName,\n Position,\n Selection,\n} from \"./types\";\nimport { isImageEmbed, MAX_LIST_LEVEL } from \"./types\";\n\nexport const COMMAND_ORIGIN: unique symbol = Symbol(\"editor-command\");\n\nexport interface CommandContext {\n doc: EditorDocument;\n getSelection: () => Selection;\n setSelection: (sel: Selection) => void;\n}\n\nfunction transact(doc: EditorDocument, fn: () => void): void {\n doc.ydoc.transact(fn, COMMAND_ORIGIN);\n}\n\n/**\n * Insert text at the current selection.\n *\n * `marks` is an explicit override map applied to the freshly inserted range.\n * - Entry value: apply that mark value.\n * - Entry value `null`: clear that mark (used when the UI just toggled it off\n * with a collapsed caret and the next typed char must NOT inherit the\n * surrounding run's attribute).\n * - When `marks` is undefined, Y.Text's default inheritance applies (good for\n * normal typing inside a marked run).\n */\nexport function insertText(\n ctx: CommandContext,\n text: string,\n marks?: Partial<Record<MarkName, MarkAttrs[MarkName] | null>>,\n): void {\n if (text.length === 0) return;\n // Rectangular cell selection: clear all selected cells, collapse to top-left,\n // then insert into the owner like a normal call.\n const collapsedFromRect = clearRectCells(ctx);\n transact(ctx.doc, () => {\n const sel = collapsedFromRect ?? ctx.getSelection();\n let cursor = sel;\n if (!isCollapsed(sel)) {\n cursor = deleteRange(ctx.doc, sel);\n }\n const pos = cursor.focus;\n const yText = ctx.doc.textAt(pos.blockIndex, pos.cellIndex);\n if (!yText) return;\n yText.insert(pos.offset, text);\n if (marks && Object.keys(marks).length > 0) {\n yText.format(pos.offset, text.length, marks as Record<string, unknown>);\n }\n const newPos: Position = {\n blockIndex: pos.blockIndex,\n cellIndex: pos.cellIndex,\n offset: pos.offset + text.length,\n };\n ctx.setSelection(collapsedSelection(newPos));\n });\n}\n\nexport function insertParagraph(ctx: CommandContext): void {\n // Rectangular selection: collapse + clear first.\n clearRectCells(ctx);\n transact(ctx.doc, () => {\n const sel = ctx.getSelection();\n let cursor = sel;\n if (!isCollapsed(sel)) {\n cursor = deleteRange(ctx.doc, sel);\n }\n const pos = cursor.focus;\n // Inside a table cell, Enter inserts a literal newline rather than splitting\n // the cell into two paragraphs. Cells in 4.1 are single-text containers; we\n // rely on `white-space: pre-wrap` in CSS to render the line break visibly.\n if (pos.cellIndex != null) {\n const yText = ctx.doc.getCellText(pos.blockIndex, pos.cellIndex);\n if (!yText) return;\n yText.insert(pos.offset, \"\\n\");\n ctx.setSelection(\n collapsedSelection({\n blockIndex: pos.blockIndex,\n cellIndex: pos.cellIndex,\n offset: pos.offset + 1,\n }),\n );\n return;\n }\n const yText = ctx.doc.getBlockText(pos.blockIndex);\n if (!yText) return;\n\n const totalLen = yText.length;\n // Read the tail's delta (preserves marks) before mutating yText.\n const tailDelta = totalLen > pos.offset\n ? sliceDelta(yText.toDelta() as DeltaOp[], pos.offset, totalLen)\n : [];\n\n if (totalLen > pos.offset) {\n yText.delete(pos.offset, totalLen - pos.offset);\n }\n\n const newBlock = createBlock(\"paragraph\");\n ctx.doc.blocks.insert(pos.blockIndex + 1, [newBlock]);\n if (tailDelta.length > 0) {\n const newYText = newBlock.get(\"text\") as Y.Text;\n writeDeltaInto(newYText, 0, tailDelta);\n }\n\n const newPos: Position = { blockIndex: pos.blockIndex + 1, offset: 0 };\n ctx.setSelection(collapsedSelection(newPos));\n });\n}\n\nexport function deleteBackward(ctx: CommandContext): void {\n // Rectangular selection: clear text of every selected cell and collapse to\n // the rect's top-left, then return — no further character delete needed.\n if (clearRectCells(ctx)) return;\n transact(ctx.doc, () => {\n const sel = ctx.getSelection();\n if (!isCollapsed(sel)) {\n const cursor = deleteRange(ctx.doc, sel);\n ctx.setSelection(cursor);\n return;\n }\n const pos = sel.focus;\n if (pos.offset > 0) {\n const yText = ctx.doc.textAt(pos.blockIndex, pos.cellIndex);\n if (!yText) return;\n yText.delete(pos.offset - 1, 1);\n ctx.setSelection(\n collapsedSelection({\n blockIndex: pos.blockIndex,\n cellIndex: pos.cellIndex,\n offset: pos.offset - 1,\n }),\n );\n return;\n }\n // offset === 0\n // Inside a table cell, backspace at the cell start is a no-op — the user\n // cannot escape the table by pressing backspace.\n if (pos.cellIndex != null) return;\n // At offset 0: if it's a listItem, dedent (or convert to paragraph at level 0)\n // before falling back to merging with the previous block.\n const blockType = ctx.doc.getBlockType(pos.blockIndex);\n if (blockType === \"listItem\") {\n const block = ctx.doc.getBlock(pos.blockIndex);\n const attrsMap = block?.get(\"attrs\") as Y.Map<unknown> | undefined;\n const rawLevel = attrsMap?.get(\"listLevel\") as number | undefined;\n const level = typeof rawLevel === \"number\" && Number.isFinite(rawLevel)\n ? Math.max(0, Math.min(MAX_LIST_LEVEL, Math.trunc(rawLevel)))\n : 0;\n if (level > 0) {\n attrsMap!.set(\"listLevel\", level - 1);\n ctx.setSelection(collapsedSelection(pos));\n return;\n }\n // Level 0 listItem → convert to paragraph (escape the list).\n setBlockTypeAtIndex(ctx.doc, pos.blockIndex, \"paragraph\", {});\n ctx.setSelection(collapsedSelection(pos));\n return;\n }\n if (pos.blockIndex > 0) {\n const prevType = ctx.doc.getBlockType(pos.blockIndex - 1);\n if (prevType === \"table\") {\n // Can't merge with a table; move caret to the table's last cell instead.\n const tableIdx = pos.blockIndex - 1;\n const { rows, cols } = ctx.doc.getTableSize(tableIdx);\n const lastCell = rows * cols - 1;\n const cellText = ctx.doc.getCellText(tableIdx, lastCell);\n const off = cellText?.length ?? 0;\n ctx.setSelection(\n collapsedSelection({ blockIndex: tableIdx, cellIndex: lastCell, offset: off }),\n );\n return;\n }\n mergeWithPrevious(ctx, pos.blockIndex);\n }\n });\n}\n\nexport function deleteForward(ctx: CommandContext): void {\n if (clearRectCells(ctx)) return;\n transact(ctx.doc, () => {\n const sel = ctx.getSelection();\n if (!isCollapsed(sel)) {\n const cursor = deleteRange(ctx.doc, sel);\n ctx.setSelection(cursor);\n return;\n }\n const pos = sel.focus;\n const yText = ctx.doc.textAt(pos.blockIndex, pos.cellIndex);\n if (!yText) return;\n if (pos.offset < yText.length) {\n yText.delete(pos.offset, 1);\n ctx.setSelection(collapsedSelection(pos));\n return;\n }\n // at end of editable run\n // Inside a table cell, forward-delete at the cell end is a no-op.\n if (pos.cellIndex != null) return;\n // at end of block: merge next into current (but tables are atomic)\n if (pos.blockIndex + 1 < ctx.doc.blockCount()) {\n const nextType = ctx.doc.getBlockType(pos.blockIndex + 1);\n if (nextType === \"table\") {\n // Jump caret into the table's first cell.\n const tableIdx = pos.blockIndex + 1;\n ctx.setSelection(collapsedSelection({ blockIndex: tableIdx, cellIndex: 0, offset: 0 }));\n return;\n }\n const nextText = ctx.doc.getBlockText(pos.blockIndex + 1);\n if (!nextText) return;\n const tail = nextText.toString();\n if (tail.length > 0) yText.insert(yText.length, tail);\n ctx.doc.blocks.delete(pos.blockIndex + 1, 1);\n ctx.setSelection(collapsedSelection(pos));\n }\n });\n}\n\n// ---------- Marks ----------\n\nconst booleanMarks: Set<MarkName> = new Set([\"bold\", \"italic\", \"underline\", \"strike\"]);\n\n/**\n * Toggle a mark across the current selection.\n * - If the selection is collapsed: no-op (the UI layer handles pendingMarks).\n * - Boolean marks (bold/italic/underline/strike): if every character already has\n * the mark, remove it; otherwise apply.\n * - Parametric marks (color, fontFamily, fontSize, link): require `value` to apply;\n * when uniform with that value across the range, remove instead (acts like toggle).\n */\nexport function toggleMark(\n ctx: CommandContext,\n name: MarkName,\n value?: MarkAttrs[MarkName],\n): void {\n const sel = ctx.getSelection();\n if (isCollapsed(sel)) return;\n transact(ctx.doc, () => {\n const { start, end } = orderedRange(sel);\n forEachBlockTextInRange(ctx.doc, start, end, (yText, localStart, localEnd) => {\n const uniform = isMarkUniformInRange(yText, localStart, localEnd, name, value);\n const attrs: Record<string, unknown> = {};\n if (uniform) {\n attrs[name] = null;\n } else {\n attrs[name] = value ?? (booleanMarks.has(name) ? true : null);\n }\n if (attrs[name] === null && !uniform) return;\n yText.format(localStart, localEnd - localStart, attrs);\n });\n ctx.setSelection(sel);\n });\n}\n\nexport function setMark(\n ctx: CommandContext,\n name: MarkName,\n value: MarkAttrs[MarkName],\n): void {\n const sel = ctx.getSelection();\n if (isCollapsed(sel)) return;\n transact(ctx.doc, () => {\n const { start, end } = orderedRange(sel);\n forEachBlockTextInRange(ctx.doc, start, end, (yText, localStart, localEnd) => {\n yText.format(localStart, localEnd - localStart, { [name]: value });\n });\n ctx.setSelection(sel);\n });\n}\n\nexport function removeMark(ctx: CommandContext, name: MarkName): void {\n const sel = ctx.getSelection();\n if (isCollapsed(sel)) return;\n transact(ctx.doc, () => {\n const { start, end } = orderedRange(sel);\n forEachBlockTextInRange(ctx.doc, start, end, (yText, localStart, localEnd) => {\n yText.format(localStart, localEnd - localStart, { [name]: null });\n });\n ctx.setSelection(sel);\n });\n}\n\n// ---------- Block-level commands (Sub-phase 2.2) ----------\n\n/**\n * Change the type of every block covered by the current selection.\n * When `attrs` is provided, merges those on top of the new type's defaults.\n * Preserves `Y.Text` content (and therefore all inline marks) and the selection.\n */\nexport function setBlockType(\n ctx: CommandContext,\n type: BlockType,\n attrs?: BlockAttrs,\n): void {\n transact(ctx.doc, () => {\n const sel = ctx.getSelection();\n // Inert when the caret is inside a cell — block-level operations only\n // apply to top-level blocks (the table itself), and changing a table's\n // block type is not exposed in 4.1.\n if (sel.anchor.cellIndex != null || sel.focus.cellIndex != null) return;\n const indices = selectedBlockIndices(sel, ctx.doc.blockCount());\n for (const i of indices) {\n const block = ctx.doc.getBlock(i);\n if (!block) continue;\n block.set(\"type\", type);\n const attrsMap = (block.get(\"attrs\") as Y.Map<unknown> | undefined) ?? new Y.Map<unknown>();\n if (!block.get(\"attrs\")) block.set(\"attrs\", attrsMap);\n // Reset attrs to the new type's defaults, then layer caller overrides.\n // Strategy: clear keys that aren't in either map, then write new ones.\n const next = { ...defaultAttrsFor(type), ...(attrs ?? {}) };\n const keep = new Set(Object.keys(next));\n for (const k of Array.from(attrsMap.keys())) {\n if (!keep.has(k)) attrsMap.delete(k);\n }\n for (const [k, v] of Object.entries(next)) {\n if (v === undefined) continue;\n if (attrsMap.get(k) !== v) attrsMap.set(k, v);\n }\n }\n ctx.setSelection(sel);\n });\n}\n\n/**\n * Set a single attribute on every block covered by the selection.\n * Passing `value === null` deletes the key.\n */\nexport function setBlockAttr<K extends keyof BlockAttrs>(\n ctx: CommandContext,\n key: K,\n value: BlockAttrs[K] | null,\n): void {\n transact(ctx.doc, () => {\n const sel = ctx.getSelection();\n if (sel.anchor.cellIndex != null || sel.focus.cellIndex != null) return;\n const indices = selectedBlockIndices(sel, ctx.doc.blockCount());\n for (const i of indices) {\n const block = ctx.doc.getBlock(i);\n if (!block) continue;\n const attrsMap = (block.get(\"attrs\") as Y.Map<unknown> | undefined) ?? new Y.Map<unknown>();\n if (!block.get(\"attrs\")) block.set(\"attrs\", attrsMap);\n if (value === null || value === undefined) {\n attrsMap.delete(key as string);\n } else {\n attrsMap.set(key as string, value);\n }\n }\n ctx.setSelection(sel);\n });\n}\n\n/**\n * Como `setBlockAttr`, mas em um bloco específico por índice.\n *\n * Existe porque `setBlockAttr` opera sobre a seleção e é INERTE quando o caret\n * está dentro de uma célula — que é exatamente a situação em que se quer mudar\n * um atributo da tabela (ex.: preset de borda).\n */\nexport function setBlockAttrAtIndex<K extends keyof BlockAttrs>(\n ctx: CommandContext,\n blockIndex: number,\n key: K,\n value: BlockAttrs[K] | null,\n): void {\n transact(ctx.doc, () => {\n const block = ctx.doc.getBlock(blockIndex);\n if (!block) return;\n const attrsMap = (block.get(\"attrs\") as Y.Map<unknown> | undefined) ?? new Y.Map<unknown>();\n if (!block.get(\"attrs\")) block.set(\"attrs\", attrsMap);\n if (value === null || value === undefined) attrsMap.delete(key as string);\n else attrsMap.set(key as string, value);\n });\n}\n\n/**\n * Set a single attribute on the table cell(s) under the selection.\n * - Caret numa única célula → essa célula (tableRectSelection retorna null\n * para seleção colapsada (ou âncora/foco no mesmo owner), então usamos\n * a célula focada (redirecionada ao owner real).\n * - Seleção retangular de várias células → todas as células reais do rect.\n * Células `covered` são puladas. `value === null` apaga a key.\n * No-op se a seleção não estiver dentro de uma tabela.\n */\nexport function setCellAttr<K extends keyof CellAttrs>(\n ctx: CommandContext,\n key: K,\n value: CellAttrs[K] | null,\n): void {\n transact(ctx.doc, () => {\n const sel = ctx.getSelection();\n const { blockIndex, cellIndex } = sel.focus;\n if (cellIndex == null || !ctx.doc.isTable(blockIndex)) return;\n const { cols } = ctx.doc.getTableSize(blockIndex);\n if (cols <= 0) return;\n const rect = tableRectSelection(ctx.doc, sel);\n const targets: number[] = [];\n if (rect) {\n for (let r = rect.top; r <= rect.bottom; r++)\n for (let c = rect.left; c <= rect.right; c++) targets.push(r * cols + c);\n } else {\n const real = ctx.doc.realCellIndex(blockIndex, cellIndex);\n if (real != null) targets.push(real);\n }\n for (const flat of targets) {\n if (ctx.doc.getCellAttrs(blockIndex, flat).covered) continue;\n const m = ctx.doc.getCellAttrsMap(blockIndex, flat);\n if (!m) continue;\n if (value === null || value === undefined) m.delete(key as string);\n else m.set(key as string, value);\n }\n ctx.setSelection(sel);\n });\n}\n\n/** Delete the current selection range and collapse the caret. Used by cut. */\nexport function deleteSelection(ctx: CommandContext): void {\n transact(ctx.doc, () => {\n const s = deleteRange(ctx.doc, ctx.getSelection());\n ctx.setSelection(s);\n });\n}\n\n/**\n * Replace the current selection with a clipboard slice (A1).\n * - Single-block slice → inline splice (Dhead + S0 + Dtail), target keeps its type.\n * - Multi-block slice → openStart merges S0 inline; middle/last blocks inserted\n * discretely; openEnd appends the post-caret tail onto the last pasted block.\n * - Target inside a table cell → slice flattened to inline (no block structure).\n */\nexport function insertSlice(ctx: CommandContext, slice: ClipboardSlice): void {\n if (!slice.blocks || slice.blocks.length === 0) return;\n transact(ctx.doc, () => {\n let sel = ctx.getSelection();\n if (!isCollapsed(sel)) sel = deleteRange(ctx.doc, sel);\n const { blockIndex, cellIndex, offset } = sel.focus;\n\n if (cellIndex != null) {\n const cellText = ctx.doc.textAt(blockIndex, cellIndex);\n if (!cellText) return;\n const after = writeDeltaInto(cellText, offset, sliceToInlineDelta(slice));\n ctx.setSelection(collapsedSelection({ blockIndex, cellIndex, offset: after }));\n return;\n }\n\n const targetText = ctx.doc.getBlockText(blockIndex);\n if (!targetText) return;\n\n const full = targetText.toDelta() as DeltaOp[];\n const tailDelta = sliceDelta(full, offset, deltaLength(full));\n targetText.delete(offset, targetText.length - offset);\n\n const blocks = slice.blocks;\n\n if (blocks.length === 1) {\n const afterS0 = writeDeltaInto(targetText, offset, blocks[0].delta);\n writeDeltaInto(targetText, afterS0, tailDelta);\n ctx.setSelection(collapsedSelection({ blockIndex, offset: afterS0 }));\n return;\n }\n\n // Multi-block. Capture the target's original type/attrs BEFORE any mutation,\n // for the !openEnd tail block.\n const originalType = ctx.doc.getBlockType(blockIndex);\n const originalAttrs = ctx.doc.getBlockAttrs(blockIndex);\n let insertAt = blockIndex;\n\n // First block.\n if (slice.openStart) {\n // Partial fragment → merge S0 inline into the target (Dhead already present);\n // target keeps its own type.\n writeDeltaInto(targetText, offset, blocks[0].delta);\n } else if (offset === 0) {\n // Whole-block fragment pasted into an empty Dhead → reuse the empty target\n // AS S0 in place (adopt S0's type/attrs), avoiding a stray leading block.\n const blk = ctx.doc.blocks.get(blockIndex) as Y.Map<unknown>;\n blk.set(\"type\", blocks[0].type);\n const am = blk.get(\"attrs\") as Y.Map<unknown>;\n am.clear();\n for (const [k, v] of Object.entries(blocks[0].attrs)) {\n if (v !== undefined) am.set(k, v);\n }\n writeDeltaInto(targetText, 0, blocks[0].delta);\n } else {\n // Whole-block fragment after a non-empty Dhead → S0 as its own block.\n const b = createBlock(blocks[0].type, \"\", blocks[0].attrs);\n ctx.doc.blocks.insert(++insertAt, [b]);\n writeDeltaInto(b.get(\"text\") as Y.Text, 0, blocks[0].delta);\n }\n\n // Middle blocks (whole).\n for (let i = 1; i < blocks.length - 1; i++) {\n const b = createBlock(blocks[i].type, \"\", blocks[i].attrs);\n ctx.doc.blocks.insert(++insertAt, [b]);\n writeDeltaInto(b.get(\"text\") as Y.Text, 0, blocks[i].delta);\n }\n\n // Last block.\n const last = blocks[blocks.length - 1];\n if (slice.openEnd) {\n const b = createBlock(last.type, \"\", last.attrs);\n ctx.doc.blocks.insert(++insertAt, [b]);\n const t = b.get(\"text\") as Y.Text;\n const caretPos = writeDeltaInto(t, 0, last.delta);\n writeDeltaInto(t, caretPos, tailDelta);\n ctx.setSelection(collapsedSelection({ blockIndex: insertAt, offset: caretPos }));\n } else {\n const b = createBlock(last.type, \"\", last.attrs);\n ctx.doc.blocks.insert(++insertAt, [b]);\n const lastLen = writeDeltaInto(b.get(\"text\") as Y.Text, 0, last.delta);\n const lastIdx = insertAt;\n // Only materialize the tail block when there's actually a tail (avoids a\n // stray empty block when pasting at end-of-line).\n if (tailDelta.length > 0) {\n const tb = createBlock(originalType ?? \"paragraph\", \"\", originalAttrs);\n ctx.doc.blocks.insert(++insertAt, [tb]);\n writeDeltaInto(tb.get(\"text\") as Y.Text, 0, tailDelta);\n }\n ctx.setSelection(collapsedSelection({ blockIndex: lastIdx, offset: lastLen }));\n }\n });\n}\n\nfunction selectedBlockIndices(sel: Selection, blockCount: number): number[] {\n const { start, end } = orderedRange(sel);\n const out: number[] = [];\n const last = Math.min(end.blockIndex, blockCount - 1);\n for (let i = Math.max(start.blockIndex, 0); i <= last; i++) out.push(i);\n return out;\n}\n\nfunction forEachBlockTextInRange(\n doc: EditorDocument,\n start: Position,\n end: Position,\n visit: (yText: Y.Text, localStart: number, localEnd: number) => void,\n): void {\n // Same text-run (block or cell): straightforward.\n if (sameTextRun(start, end)) {\n const yText = doc.textAt(start.blockIndex, start.cellIndex);\n if (!yText) return;\n if (start.offset < end.offset) visit(yText, start.offset, end.offset);\n return;\n }\n // Cross-run selections involving a cell are currently treated as inert for\n // mark application; the UI surfaces them as \"no-op\" rather than partially\n // applying marks across mismatched runs.\n if (start.cellIndex != null || end.cellIndex != null) return;\n\n for (let i = start.blockIndex; i <= end.blockIndex; i++) {\n const yText = doc.getBlockText(i);\n if (!yText) continue;\n const localStart = i === start.blockIndex ? start.offset : 0;\n const localEnd = i === end.blockIndex ? end.offset : yText.length;\n if (localStart < localEnd) visit(yText, localStart, localEnd);\n }\n}\n\n/**\n * Deletes the content of a non-collapsed selection.\n * Returns the new collapsed selection at the deletion point.\n * Must be called inside a Y.Doc transaction.\n *\n * Selections that span DIFFERENT text-runs (different blocks, or two cells of\n * the same table) are bridged conservatively:\n * - Same text-run (block+cell): delete the range normally.\n * - Different runs but both outside tables (i.e. cellIndex undefined on both):\n * delete and merge blocks as before.\n * - Otherwise (one endpoint is in a table cell): no destructive cross-cell\n * delete in 4.1; collapse to `start` instead.\n */\nfunction deleteRange(doc: EditorDocument, sel: Selection): Selection {\n const { start, end } = orderedRange(sel);\n\n if (sameTextRun(start, end)) {\n const yText = doc.textAt(start.blockIndex, start.cellIndex);\n if (yText) yText.delete(start.offset, end.offset - start.offset);\n return collapsedSelection(start);\n }\n\n // Reject cross-cell / cross-table-to-paragraph multi-run deletions for now.\n if (start.cellIndex != null || end.cellIndex != null) {\n return collapsedSelection(start);\n }\n\n const startText = doc.getBlockText(start.blockIndex);\n const endText = doc.getBlockText(end.blockIndex);\n if (!startText || !endText) return collapsedSelection(start);\n\n // Trim tail of start block\n startText.delete(start.offset, startText.length - start.offset);\n // Read remaining tail from end block, after the deleted prefix\n const remainingTail = endText.toString().slice(end.offset);\n if (remainingTail.length > 0) {\n startText.insert(startText.length, remainingTail);\n }\n // Remove all blocks between start (exclusive) and end (inclusive)\n doc.blocks.delete(start.blockIndex + 1, end.blockIndex - start.blockIndex);\n return collapsedSelection(start);\n}\n\nfunction mergeWithPrevious(ctx: CommandContext, blockIndex: number): void {\n const prevText = ctx.doc.getBlockText(blockIndex - 1);\n const currText = ctx.doc.getBlockText(blockIndex);\n if (!prevText || !currText) return;\n const prevLen = prevText.length;\n const tail = currText.toString();\n if (tail.length > 0) prevText.insert(prevLen, tail);\n ctx.doc.blocks.delete(blockIndex, 1);\n ctx.setSelection(collapsedSelection({ blockIndex: blockIndex - 1, offset: prevLen }));\n}\n\n// ---------- List commands (Sub-phase 2.3) ----------\n\n/**\n * Convert every block in the selection to/from a `listItem` of `kind`.\n * If every covered block is already a `listItem` of `kind` → convert them all to paragraphs.\n * Otherwise → convert them all to `listItem` (keeping existing `listLevel` when already\n * a listItem, defaulting to 0 otherwise).\n */\nexport function toggleList(ctx: CommandContext, kind: ListKind): void {\n transact(ctx.doc, () => {\n const sel = ctx.getSelection();\n if (sel.anchor.cellIndex != null || sel.focus.cellIndex != null) return;\n const indices = selectedBlockIndices(sel, ctx.doc.blockCount());\n const allMatching = indices.every((i) => {\n const block = ctx.doc.getBlock(i);\n if (!block) return false;\n if (block.get(\"type\") !== \"listItem\") return false;\n const attrs = ctx.doc.getBlockAttrs(i);\n return attrs.listKind === kind;\n });\n for (const i of indices) {\n if (allMatching) {\n // Strip list → paragraph (defaults reset).\n setBlockTypeAtIndex(ctx.doc, i, \"paragraph\", {});\n } else {\n const prev = ctx.doc.getBlockAttrs(i);\n const level = clampLevel(prev.listLevel);\n setBlockTypeAtIndex(ctx.doc, i, \"listItem\", { listKind: kind, listLevel: level });\n }\n }\n ctx.setSelection(sel);\n });\n}\n\n/** Increase nesting of every listItem in the selection (clamped to MAX_LIST_LEVEL). */\nexport function indentList(ctx: CommandContext): void {\n transact(ctx.doc, () => {\n const sel = ctx.getSelection();\n if (sel.anchor.cellIndex != null || sel.focus.cellIndex != null) return;\n const indices = selectedBlockIndices(sel, ctx.doc.blockCount());\n for (const i of indices) {\n const block = ctx.doc.getBlock(i);\n if (!block || block.get(\"type\") !== \"listItem\") continue;\n const attrsMap = block.get(\"attrs\") as Y.Map<unknown>;\n const current = clampLevel((attrsMap.get(\"listLevel\") as number | undefined) ?? 0);\n const next = Math.min(current + 1, MAX_LIST_LEVEL);\n if (next !== current) attrsMap.set(\"listLevel\", next);\n }\n ctx.setSelection(sel);\n });\n}\n\n/**\n * Decrease nesting of every listItem in the selection.\n * When level was 0, demote to paragraph (escape from the list).\n */\nexport function dedentList(ctx: CommandContext): void {\n transact(ctx.doc, () => {\n const sel = ctx.getSelection();\n if (sel.anchor.cellIndex != null || sel.focus.cellIndex != null) return;\n const indices = selectedBlockIndices(sel, ctx.doc.blockCount());\n for (const i of indices) {\n const block = ctx.doc.getBlock(i);\n if (!block || block.get(\"type\") !== \"listItem\") continue;\n const attrsMap = block.get(\"attrs\") as Y.Map<unknown>;\n const current = clampLevel((attrsMap.get(\"listLevel\") as number | undefined) ?? 0);\n if (current > 0) {\n attrsMap.set(\"listLevel\", current - 1);\n } else {\n // Escape from the list at level 0.\n setBlockTypeAtIndex(ctx.doc, i, \"paragraph\", {});\n }\n }\n ctx.setSelection(sel);\n });\n}\n\n/**\n * Enter behavior inside a listItem.\n * - Empty listItem at level > 0 → dedent (stays a listItem, one level out).\n * - Empty listItem at level 0 → convert to paragraph (exit the list).\n * - Non-empty → split: tail moves to a new listItem with same kind/level.\n *\n * Returns `true` when it handled the event; `false` to let the default `insertParagraph` run.\n */\nexport function splitListItem(ctx: CommandContext): boolean {\n const sel = ctx.getSelection();\n if (!isCollapsed(sel)) return false;\n const pos = sel.focus;\n // Inside a table cell, Enter is handled by insertParagraph (newline within cell).\n if (pos.cellIndex != null) return false;\n const block = ctx.doc.getBlock(pos.blockIndex);\n if (!block || block.get(\"type\") !== \"listItem\") return false;\n const yText = ctx.doc.getBlockText(pos.blockIndex);\n if (!yText) return false;\n\n const attrs = ctx.doc.getBlockAttrs(pos.blockIndex);\n const kind = (attrs.listKind ?? \"bullet\") as ListKind;\n const level = clampLevel(attrs.listLevel ?? 0);\n\n transact(ctx.doc, () => {\n if (yText.length === 0) {\n if (level > 0) {\n const m = block.get(\"attrs\") as Y.Map<unknown>;\n m.set(\"listLevel\", level - 1);\n } else {\n setBlockTypeAtIndex(ctx.doc, pos.blockIndex, \"paragraph\", {});\n }\n ctx.setSelection(collapsedSelection({ blockIndex: pos.blockIndex, offset: 0 }));\n return;\n }\n const tail = yText.toString().slice(pos.offset);\n if (tail.length > 0) yText.delete(pos.offset, tail.length);\n ctx.doc.blocks.insert(pos.blockIndex + 1, [\n createBlock(\"listItem\", tail, { listKind: kind, listLevel: level }),\n ]);\n ctx.setSelection(collapsedSelection({ blockIndex: pos.blockIndex + 1, offset: 0 }));\n });\n return true;\n}\n\n/**\n * Internal: reset a single block's type + attrs (used by list commands).\n * Same merge rules as the public `setBlockType` but scoped to one block and\n * intended to run already inside a transaction.\n */\nfunction setBlockTypeAtIndex(\n doc: EditorDocument,\n index: number,\n type: BlockType,\n attrs: BlockAttrs,\n): void {\n const block = doc.getBlock(index);\n if (!block) return;\n block.set(\"type\", type);\n const attrsMap = (block.get(\"attrs\") as Y.Map<unknown> | undefined) ?? new Y.Map<unknown>();\n if (!block.get(\"attrs\")) block.set(\"attrs\", attrsMap);\n const next = { ...defaultAttrsFor(type), ...attrs };\n const keep = new Set(Object.keys(next));\n for (const k of Array.from(attrsMap.keys())) {\n if (!keep.has(k)) attrsMap.delete(k);\n }\n for (const [k, v] of Object.entries(next)) {\n if (v === undefined) continue;\n if (attrsMap.get(k) !== v) attrsMap.set(k, v);\n }\n}\n\nfunction clampLevel(l: number | undefined): number {\n if (typeof l !== \"number\" || !Number.isFinite(l)) return 0;\n return Math.max(0, Math.min(MAX_LIST_LEVEL, Math.trunc(l)));\n}\n\n// ---------- Table commands (Sub-phase 4.1 / 4.2) ----------\n\n/**\n * Insert a fresh `rows × cols` table after the block currently holding the\n * caret (or at the end of the document if the selection is somehow invalid),\n * and place the caret in the table's first cell.\n *\n * Sub-phase 4.1 doesn't try to be clever: it does NOT replace an empty\n * preceding paragraph. Callers can clean that up themselves; an extra empty\n * paragraph above a table is a small price for predictable behavior.\n */\n/** Teto de linhas por inserção — protege contra digitar 5000 no popover. */\nexport const ANSWER_LINE_MAX = 50;\n\n/**\n * Insere `count` parágrafos pautados depois do bloco focado, numa única\n * transação (um passo de undo desfaz todos).\n *\n * Se o caret estiver dentro de uma célula, `focus.blockIndex` já aponta para a\n * TABELA, então as linhas entram depois dela — nunca dentro.\n */\nexport function insertAnswerLines(\n ctx: CommandContext,\n count: number,\n spacing: AnswerLineSpacing,\n): void {\n const n = Math.max(1, Math.min(ANSWER_LINE_MAX, Math.trunc(count)));\n transact(ctx.doc, () => {\n const sel = ctx.getSelection();\n const focusBlock = Math.max(0, Math.min(sel.focus.blockIndex, ctx.doc.blockCount() - 1));\n const insertAt = focusBlock + 1;\n const attrs: BlockAttrs = { answerLine: true, answerLineSpacing: spacing };\n const blocks = Array.from({ length: n }, () => createBlock(\"paragraph\", \"\", attrs));\n ctx.doc.blocks.insert(insertAt, blocks);\n ctx.setSelection(collapsedSelection({ blockIndex: insertAt, offset: 0 }));\n });\n}\n\nexport function insertTable(ctx: CommandContext, rows: number, cols: number): void {\n const r = Math.max(1, Math.trunc(rows));\n const c = Math.max(1, Math.trunc(cols));\n transact(ctx.doc, () => {\n const sel = ctx.getSelection();\n // Anchor point: the block holding the focus. If focus is inside a cell of\n // an existing table, insert AFTER that table.\n const focusBlock = Math.max(0, Math.min(sel.focus.blockIndex, ctx.doc.blockCount() - 1));\n const insertAt = focusBlock + 1;\n ctx.doc.blocks.insert(insertAt, [createTableBlock(r, c)]);\n // Invariante: documento nunca termina em tabela — o caret precisa de um\n // destino editável abaixo dela. Só acrescenta quando a tabela virou o último bloco.\n if (insertAt === ctx.doc.blockCount() - 1) {\n ctx.doc.blocks.insert(insertAt + 1, [createBlock(\"paragraph\")]);\n }\n ctx.setSelection(\n collapsedSelection({ blockIndex: insertAt, cellIndex: 0, offset: 0 }),\n );\n });\n}\n\n/** Remove the entire table at `blockIndex` and place the caret at the start of the next block (or the previous one if removal would leave the doc empty). */\nexport function deleteTable(ctx: CommandContext, blockIndex: number): void {\n if (!ctx.doc.isTable(blockIndex)) return;\n transact(ctx.doc, () => {\n ctx.doc.blocks.delete(blockIndex, 1);\n if (ctx.doc.blocks.length === 0) {\n ctx.doc.blocks.push([createBlock(\"paragraph\")]);\n ctx.setSelection(collapsedSelection({ blockIndex: 0, offset: 0 }));\n return;\n }\n const targetIdx = Math.max(0, Math.min(blockIndex, ctx.doc.blockCount() - 1));\n const targetType = ctx.doc.getBlockType(targetIdx);\n if (targetType === \"table\") {\n ctx.setSelection(collapsedSelection({ blockIndex: targetIdx, cellIndex: 0, offset: 0 }));\n } else {\n ctx.setSelection(collapsedSelection({ blockIndex: targetIdx, offset: 0 }));\n }\n });\n}\n\n/**\n * Sub-phase 4.1 has no rowspan/colspan, so row/col operations are pure splice\n * on the flat `cells` array. The flat index of `(r, c)` is `r * cols + c`.\n */\n\nexport interface TableLocation {\n blockIndex: number;\n row: number;\n col: number;\n}\n\n/**\n * Derive `{row, col}` from a position inside a table — always pointing at the\n * owner of the targeted cell (covered cells redirect to their owner). Returns\n * null when the position isn't inside a table cell.\n */\nexport function tableLocationOf(\n doc: EditorDocument,\n pos: Position,\n): TableLocation | null {\n if (pos.cellIndex == null) return null;\n if (!doc.isTable(pos.blockIndex)) return null;\n const { cols } = doc.getTableSize(pos.blockIndex);\n if (cols <= 0) return null;\n const real = doc.realCellIndex(pos.blockIndex, pos.cellIndex);\n if (real == null) return null;\n const row = Math.floor(real / cols);\n const col = real - row * cols;\n return { blockIndex: pos.blockIndex, row, col };\n}\n\n/**\n * Insert a fresh row above (`where === \"before\"`) or below (`\"after\"`) the\n * given row. Spans that previously crossed the insertion boundary are extended\n * by 1; the corresponding columns of the new row become `covered: true`.\n */\nexport function insertTableRow(\n ctx: CommandContext,\n blockIndex: number,\n row: number,\n where: \"before\" | \"after\",\n): void {\n if (!ctx.doc.isTable(blockIndex)) return;\n const { rows, cols } = ctx.doc.getTableSize(blockIndex);\n if (rows <= 0 || cols <= 0) return;\n const targetRow = Math.max(0, Math.min(row, rows - 1));\n const P = where === \"before\" ? targetRow : targetRow + 1;\n transact(ctx.doc, () => {\n const cells = ctx.doc.getCells(blockIndex);\n const attrs = ctx.doc.getBlockAttrsMap(blockIndex);\n if (!cells || !attrs) return;\n\n // Snapshot: for each column, does a span crossing the [P-1, P] boundary\n // cover this column at row P? Compute BEFORE mutating spans.\n const newRowCovered: boolean[] = new Array(cols).fill(false);\n if (P > 0 && P < rows) {\n // Walk row P-1 to find spans crossing into row P (i.e., or < P and or+rs > P).\n for (let r = 0; r < P; r++) {\n for (let c = 0; c < cols; c++) {\n const a = ctx.doc.getCellAttrs(blockIndex, r * cols + c);\n if (a.covered === true) continue;\n const rs = spanOf(a.rowspan);\n const cs = spanOf(a.colspan);\n if (r < P && r + rs > P) {\n for (let cc = c; cc < c + cs && cc < cols; cc++) newRowCovered[cc] = true;\n }\n }\n }\n // Now extend those spans' rowspan by 1.\n for (let r = 0; r < P; r++) {\n for (let c = 0; c < cols; c++) {\n const idx = r * cols + c;\n const a = ctx.doc.getCellAttrs(blockIndex, idx);\n if (a.covered === true) continue;\n const rs = spanOf(a.rowspan);\n if (r < P && r + rs > P) {\n const m = ctx.doc.getCellAttrsMap(blockIndex, idx);\n m?.set(\"rowspan\", rs + 1);\n }\n }\n }\n }\n\n const fresh: Y.Map<unknown>[] = [];\n for (let c = 0; c < cols; c++) {\n fresh.push(createCell(newRowCovered[c] ? { covered: true } : undefined));\n }\n cells.insert(P * cols, fresh);\n attrs.set(\"rows\", rows + 1);\n // Caret on the first non-covered cell of the new row (falls back to flat-0\n // if every column is covered — pathologically possible only with bad data).\n const firstReal = newRowCovered.findIndex((v) => !v);\n const targetCellIdx = P * cols + (firstReal < 0 ? 0 : firstReal);\n ctx.setSelection(\n collapsedSelection({ blockIndex, cellIndex: targetCellIdx, offset: 0 }),\n );\n });\n}\n\n/**\n * Remove `row` from the table. Spans that pass through the row are shortened\n * by one; spans that START at the row are removed AND the cell at row R+1 (in\n * each affected column) is promoted to be the new owner with `rowspan - 1`.\n * When it was the last row, deletes the whole table.\n */\nexport function deleteTableRow(ctx: CommandContext, blockIndex: number, row: number): void {\n if (!ctx.doc.isTable(blockIndex)) return;\n const { rows, cols } = ctx.doc.getTableSize(blockIndex);\n if (rows <= 0 || cols <= 0) return;\n if (rows === 1) {\n deleteTable(ctx, blockIndex);\n return;\n }\n const R = Math.max(0, Math.min(row, rows - 1));\n transact(ctx.doc, () => {\n const cells = ctx.doc.getCells(blockIndex);\n const attrs = ctx.doc.getBlockAttrsMap(blockIndex);\n if (!cells || !attrs) return;\n\n // Phase 1: spans crossing R (started above, end at or after R): shorten by 1.\n for (let r = 0; r < R; r++) {\n for (let c = 0; c < cols; c++) {\n const idx = r * cols + c;\n const a = ctx.doc.getCellAttrs(blockIndex, idx);\n if (a.covered === true) continue;\n const rs = spanOf(a.rowspan);\n if (r < R && r + rs > R) {\n const m = ctx.doc.getCellAttrsMap(blockIndex, idx);\n m?.set(\"rowspan\", rs - 1);\n if (rs - 1 === 1) m?.delete(\"rowspan\");\n }\n }\n }\n\n // Phase 2: spans starting AT row R with rowspan > 1: promote the cell at\n // (R+1, c) to be the new owner. Capture the promotion list FIRST so we\n // can apply changes after the row delete (since indices shift).\n interface Promotion {\n // Flat index AFTER the row delete.\n flatNew: number;\n rowspan: number;\n colspan: number;\n }\n const promotions: Promotion[] = [];\n for (let c = 0; c < cols; c++) {\n const a = ctx.doc.getCellAttrs(blockIndex, R * cols + c);\n if (a.covered === true) continue;\n const rs = spanOf(a.rowspan);\n const cs = spanOf(a.colspan);\n if (rs > 1 && R + 1 < rows) {\n // After delete, what was (R+1, c) becomes (R, c).\n promotions.push({ flatNew: R * cols + c, rowspan: rs - 1, colspan: cs });\n }\n }\n\n cells.delete(R * cols, cols);\n attrs.set(\"rows\", rows - 1);\n\n for (const p of promotions) {\n const m = ctx.doc.getCellAttrsMap(blockIndex, p.flatNew);\n if (!m) continue;\n m.delete(\"covered\");\n if (p.rowspan > 1) m.set(\"rowspan\", p.rowspan); else m.delete(\"rowspan\");\n if (p.colspan > 1) m.set(\"colspan\", p.colspan); else m.delete(\"colspan\");\n }\n\n const newRow = Math.min(R, rows - 2);\n const target = findNextRealCell(ctx.doc, blockIndex, newRow * cols, (rows - 1) * cols) ?? 0;\n ctx.setSelection(\n collapsedSelection({ blockIndex, cellIndex: target, offset: 0 }),\n );\n });\n}\n\n/**\n * Insert a fresh column to the left (`\"before\"`) or right (`\"after\"`) of `col`.\n * Spans crossing the insertion column have `colspan += 1`; the new column's\n * cells in covered rows are themselves `covered: true`.\n *\n * Also resizes `colWidths` (if defined) by inserting a default width.\n */\nexport function insertTableColumn(\n ctx: CommandContext,\n blockIndex: number,\n col: number,\n where: \"before\" | \"after\",\n): void {\n if (!ctx.doc.isTable(blockIndex)) return;\n const { rows, cols } = ctx.doc.getTableSize(blockIndex);\n if (rows <= 0 || cols <= 0) return;\n const targetCol = Math.max(0, Math.min(col, cols - 1));\n const C = where === \"before\" ? targetCol : targetCol + 1;\n transact(ctx.doc, () => {\n const cells = ctx.doc.getCells(blockIndex);\n const attrs = ctx.doc.getBlockAttrsMap(blockIndex);\n if (!cells || !attrs) return;\n\n // Snapshot covered rows BEFORE mutating spans.\n const newColCovered: boolean[] = new Array(rows).fill(false);\n if (C > 0 && C < cols) {\n for (let r = 0; r < rows; r++) {\n for (let c = 0; c < C; c++) {\n const a = ctx.doc.getCellAttrs(blockIndex, r * cols + c);\n if (a.covered === true) continue;\n const rs = spanOf(a.rowspan);\n const cs = spanOf(a.colspan);\n if (c < C && c + cs > C) {\n for (let rr = r; rr < r + rs && rr < rows; rr++) newColCovered[rr] = true;\n }\n }\n }\n // Extend colspans.\n for (let r = 0; r < rows; r++) {\n for (let c = 0; c < C; c++) {\n const idx = r * cols + c;\n const a = ctx.doc.getCellAttrs(blockIndex, idx);\n if (a.covered === true) continue;\n const cs = spanOf(a.colspan);\n if (c < C && c + cs > C) {\n const m = ctx.doc.getCellAttrsMap(blockIndex, idx);\n m?.set(\"colspan\", cs + 1);\n }\n }\n }\n }\n\n // Walk rows LAST→FIRST so insert indices stay correct.\n for (let r = rows - 1; r >= 0; r--) {\n const at = r * cols + C;\n cells.insert(at, [createCell(newColCovered[r] ? { covered: true } : undefined)]);\n }\n attrs.set(\"cols\", cols + 1);\n\n // Resize colWidths if present — insert a 100px placeholder for the new col.\n const widths = attrs.get(\"colWidths\") as number[] | undefined;\n if (Array.isArray(widths) && widths.length === cols) {\n const next = widths.slice();\n next.splice(C, 0, 100);\n attrs.set(\"colWidths\", next);\n }\n\n const newCols = cols + 1;\n const focusRow = 0;\n const firstReal = newColCovered.findIndex((_, r) => r === focusRow && !newColCovered[r]);\n ctx.setSelection(\n collapsedSelection({\n blockIndex,\n cellIndex: focusRow * newCols + C + (firstReal < 0 ? 0 : 0),\n offset: 0,\n }),\n );\n });\n}\n\n/**\n * Remove `col` from the table. Spans that pass through the column are\n * shortened by one; spans that START at the column with `colspan > 1` get\n * their owner promoted from (r, C+1) to take over with `colspan - 1`.\n *\n * Also shrinks `colWidths` (if defined). When it was the last column, deletes\n * the whole table.\n */\nexport function deleteTableColumn(ctx: CommandContext, blockIndex: number, col: number): void {\n if (!ctx.doc.isTable(blockIndex)) return;\n const { rows, cols } = ctx.doc.getTableSize(blockIndex);\n if (rows <= 0 || cols <= 0) return;\n if (cols === 1) {\n deleteTable(ctx, blockIndex);\n return;\n }\n const C = Math.max(0, Math.min(col, cols - 1));\n transact(ctx.doc, () => {\n const cells = ctx.doc.getCells(blockIndex);\n const attrs = ctx.doc.getBlockAttrsMap(blockIndex);\n if (!cells || !attrs) return;\n\n // Phase 1: spans crossing C — colspan -= 1.\n for (let r = 0; r < rows; r++) {\n for (let c = 0; c < C; c++) {\n const idx = r * cols + c;\n const a = ctx.doc.getCellAttrs(blockIndex, idx);\n if (a.covered === true) continue;\n const cs = spanOf(a.colspan);\n if (c < C && c + cs > C) {\n const m = ctx.doc.getCellAttrsMap(blockIndex, idx);\n m?.set(\"colspan\", cs - 1);\n if (cs - 1 === 1) m?.delete(\"colspan\");\n }\n }\n }\n\n // Phase 2: capture promotions for spans starting at column C with colspan > 1.\n // After deletion, what was (r, C+1) becomes (r, C). Capture both the\n // FUTURE flat index in the post-delete (rows x (cols-1)) grid and the\n // attrs to apply.\n interface Promotion {\n flatNew: number;\n rowspan: number;\n colspan: number;\n }\n const promotions: Promotion[] = [];\n const newCols = cols - 1;\n for (let r = 0; r < rows; r++) {\n const a = ctx.doc.getCellAttrs(blockIndex, r * cols + C);\n if (a.covered === true) continue;\n const rs = spanOf(a.rowspan);\n const cs = spanOf(a.colspan);\n if (cs > 1 && C + 1 < cols) {\n promotions.push({\n flatNew: r * newCols + C,\n rowspan: rs,\n colspan: cs - 1,\n });\n }\n }\n\n // Walk rows LAST→FIRST so deletions don't perturb indices we still need.\n for (let r = rows - 1; r >= 0; r--) {\n const at = r * cols + C;\n cells.delete(at, 1);\n }\n attrs.set(\"cols\", newCols);\n\n for (const p of promotions) {\n const m = ctx.doc.getCellAttrsMap(blockIndex, p.flatNew);\n if (!m) continue;\n m.delete(\"covered\");\n if (p.rowspan > 1) m.set(\"rowspan\", p.rowspan); else m.delete(\"rowspan\");\n if (p.colspan > 1) m.set(\"colspan\", p.colspan); else m.delete(\"colspan\");\n }\n\n // Trim colWidths.\n const widths = attrs.get(\"colWidths\") as number[] | undefined;\n if (Array.isArray(widths) && widths.length === cols) {\n const next = widths.slice();\n next.splice(C, 1);\n attrs.set(\"colWidths\", next);\n }\n\n const newCol = Math.min(C, newCols - 1);\n const target = findNextRealCell(ctx.doc, blockIndex, newCol, rows * newCols) ?? 0;\n ctx.setSelection(\n collapsedSelection({ blockIndex, cellIndex: target, offset: 0 }),\n );\n });\n}\n\n// ---------- Rectangular cell selection (Sub-phase 4.5) ----------\n\nexport interface TableRect {\n blockIndex: number;\n /** Inclusive bounds in OWNER coordinates. */\n top: number;\n left: number;\n bottom: number;\n right: number;\n}\n\n/**\n * Interpret a `Selection` as a rectangular cell range when:\n * - Both endpoints carry `cellIndex`.\n * - They live in the same table block.\n * - They point to DIFFERENT owner cells.\n *\n * The naive bounds are then EXPANDED until every span fully fits inside —\n * essential so that operations like `mergeSelection` can never produce a\n * non-rectangular shape, and so visual highlights always cover whole spans.\n */\nexport function tableRectSelection(\n doc: EditorDocument,\n sel: Selection,\n): TableRect | null {\n if (sel.anchor.blockIndex !== sel.focus.blockIndex) return null;\n if (sel.anchor.cellIndex == null || sel.focus.cellIndex == null) return null;\n const blockIndex = sel.anchor.blockIndex;\n if (!doc.isTable(blockIndex)) return null;\n const aLoc = tableLocationOf(doc, sel.anchor);\n const fLoc = tableLocationOf(doc, sel.focus);\n if (!aLoc || !fLoc) return null;\n // After redirection to owners, anchor and focus may collapse to the same\n // owner cell (e.g. anchor in an owner, focus in one of its covered cells).\n if (aLoc.row === fLoc.row && aLoc.col === fLoc.col) return null;\n return expandTableRect(\n doc,\n blockIndex,\n Math.min(aLoc.row, fLoc.row),\n Math.min(aLoc.col, fLoc.col),\n Math.max(aLoc.row, fLoc.row),\n Math.max(aLoc.col, fLoc.col),\n );\n}\n\n/**\n * Grow a candidate rect until every owner whose span starts within the rect\n * fits entirely, and every covered cell inside it has its owner inside too.\n * Converges in O(rows × cols) iterations in the worst case (each pass either\n * grows a bound or terminates).\n */\nexport function expandTableRect(\n doc: EditorDocument,\n blockIndex: number,\n initTop: number,\n initLeft: number,\n initBottom: number,\n initRight: number,\n): TableRect {\n const { rows, cols } = doc.getTableSize(blockIndex);\n let top = Math.max(0, initTop);\n let left = Math.max(0, initLeft);\n let bottom = Math.min(rows - 1, initBottom);\n let right = Math.min(cols - 1, initRight);\n\n let changed = true;\n let guard = rows * cols + 1;\n while (changed && guard-- > 0) {\n changed = false;\n for (let r = top; r <= bottom; r++) {\n for (let c = left; c <= right; c++) {\n const idx = r * cols + c;\n const a = doc.getCellAttrs(blockIndex, idx);\n if (a.covered === true) {\n const owner = doc.realCellIndex(blockIndex, idx);\n if (owner == null) continue;\n const oRow = Math.floor(owner / cols);\n const oCol = owner - oRow * cols;\n if (oRow < top) { top = oRow; changed = true; }\n if (oCol < left) { left = oCol; changed = true; }\n // Owner's far edge:\n const oAttrs = doc.getCellAttrs(blockIndex, owner);\n const oRs = spanOf(oAttrs.rowspan);\n const oCs = spanOf(oAttrs.colspan);\n if (oRow + oRs - 1 > bottom) { bottom = oRow + oRs - 1; changed = true; }\n if (oCol + oCs - 1 > right) { right = oCol + oCs - 1; changed = true; }\n } else {\n const rs = spanOf(a.rowspan);\n const cs = spanOf(a.colspan);\n if (r + rs - 1 > bottom) { bottom = r + rs - 1; changed = true; }\n if (c + cs - 1 > right) { right = c + cs - 1; changed = true; }\n }\n }\n }\n }\n return { blockIndex, top, left, bottom, right };\n}\n\n/** Enumerate every cell-index (real or covered) contained in `rect`. */\nexport function cellsInRect(doc: EditorDocument, rect: TableRect): number[] {\n const { cols } = doc.getTableSize(rect.blockIndex);\n const out: number[] = [];\n for (let r = rect.top; r <= rect.bottom; r++) {\n for (let c = rect.left; c <= rect.right; c++) out.push(r * cols + c);\n }\n return out;\n}\n\n/**\n * Merge every cell in the current rectangular selection into one owner at the\n * rect's top-left. The owner's text is the concatenation of all non-empty\n * inner texts (space-separated, mark-preserving). Returns true on success, false\n * when there is no rect selection.\n */\nexport function mergeSelection(ctx: CommandContext): boolean {\n const sel = ctx.getSelection();\n const rect = tableRectSelection(ctx.doc, sel);\n if (!rect) return false;\n const { blockIndex, top, left, bottom, right } = rect;\n const { cols } = ctx.doc.getTableSize(blockIndex);\n const ownerIdx = top * cols + left;\n\n transact(ctx.doc, () => {\n const ownerText = ctx.doc.getCellText(blockIndex, ownerIdx);\n if (!ownerText) return;\n\n // Walk every cell in the rect (skip the owner itself). For real cells with\n // non-empty text, append to owner.\n for (let r = top; r <= bottom; r++) {\n for (let c = left; c <= right; c++) {\n const idx = r * cols + c;\n if (idx === ownerIdx) continue;\n const a = ctx.doc.getCellAttrs(blockIndex, idx);\n if (a.covered !== true) {\n const t = ctx.doc.getCellText(blockIndex, idx);\n if (t && t.length > 0) {\n const sep = ownerText.length > 0 ? \" \" : \"\";\n const delta = t.toDelta() as DeltaOp[];\n let pos = ownerText.length;\n if (sep) {\n ownerText.insert(pos, sep);\n pos += 1;\n }\n writeDeltaInto(ownerText, pos, delta);\n t.delete(0, t.length);\n }\n }\n // Reset attrs to \"covered\" — drops any prior rowspan/colspan.\n const m = ctx.doc.getCellAttrsMap(blockIndex, idx);\n if (m) {\n m.delete(\"rowspan\");\n m.delete(\"colspan\");\n m.set(\"covered\", true);\n }\n }\n }\n // Update owner spans.\n const oMap = ctx.doc.getCellAttrsMap(blockIndex, ownerIdx);\n if (oMap) {\n const newRs = bottom - top + 1;\n const newCs = right - left + 1;\n if (newRs > 1) oMap.set(\"rowspan\", newRs); else oMap.delete(\"rowspan\");\n if (newCs > 1) oMap.set(\"colspan\", newCs); else oMap.delete(\"colspan\");\n oMap.delete(\"covered\");\n }\n ctx.setSelection(\n collapsedSelection({ blockIndex, cellIndex: ownerIdx, offset: 0 }),\n );\n });\n return true;\n}\n\n/**\n * Clears the text of every cell in the current rectangular selection (no\n * structural mutation — spans stay intact). Returns the collapsed selection\n * at the rect's top-left when something was cleared, otherwise null.\n */\nexport function clearRectCells(ctx: CommandContext): Selection | null {\n const sel = ctx.getSelection();\n const rect = tableRectSelection(ctx.doc, sel);\n if (!rect) return null;\n const { blockIndex, top, left, bottom, right } = rect;\n const { cols } = ctx.doc.getTableSize(blockIndex);\n const ownerIdx = top * cols + left;\n let result: Selection | null = null;\n transact(ctx.doc, () => {\n for (let r = top; r <= bottom; r++) {\n for (let c = left; c <= right; c++) {\n const idx = r * cols + c;\n const a = ctx.doc.getCellAttrs(blockIndex, idx);\n if (a.covered === true) continue;\n const t = ctx.doc.getCellText(blockIndex, idx);\n if (t && t.length > 0) t.delete(0, t.length);\n }\n }\n result = collapsedSelection({ blockIndex, cellIndex: ownerIdx, offset: 0 });\n ctx.setSelection(result);\n });\n return result;\n}\n\n// ---------- Merge / split ----------\n\n/**\n * Merge the cell at `(row, col)` with its immediate right neighbor. The right\n * neighbor must be a real cell with matching `rowspan` (otherwise the merge\n * would form a non-rectangle). Returns true on success, false on shape\n * mismatch or when there is no neighbor.\n *\n * After: the owner's `colspan` grows by the neighbor's `colspan`; the\n * neighbor and all its formerly-covered cells in the merged rectangle are\n * marked `covered: true`. The neighbor's text is appended to the owner with a\n * single space delimiter (when both sides had content).\n */\nexport function mergeRight(ctx: CommandContext, blockIndex: number, row: number, col: number): boolean {\n if (!ctx.doc.isTable(blockIndex)) return false;\n const { rows, cols } = ctx.doc.getTableSize(blockIndex);\n if (row < 0 || row >= rows || col < 0 || col >= cols) return false;\n const ownerIdx = row * cols + col;\n const ownerAttrs = ctx.doc.getCellAttrs(blockIndex, ownerIdx);\n if (ownerAttrs.covered === true) return false;\n const ownerRs = spanOf(ownerAttrs.rowspan);\n const ownerCs = spanOf(ownerAttrs.colspan);\n const nbCol = col + ownerCs;\n if (nbCol >= cols) return false;\n const nbIdx = row * cols + nbCol;\n const nbAttrs = ctx.doc.getCellAttrs(blockIndex, nbIdx);\n if (nbAttrs.covered === true) return false;\n const nbRs = spanOf(nbAttrs.rowspan);\n const nbCs = spanOf(nbAttrs.colspan);\n if (nbRs !== ownerRs) return false;\n\n transact(ctx.doc, () => {\n // Append neighbor's text into the owner.\n const ownerText = ctx.doc.getCellText(blockIndex, ownerIdx);\n const nbText = ctx.doc.getCellText(blockIndex, nbIdx);\n if (ownerText && nbText && nbText.length > 0) {\n const sep = ownerText.length > 0 ? \" \" : \"\";\n // Re-apply delta with marks and embeds preserved.\n const delta = nbText.toDelta() as DeltaOp[];\n let pos = ownerText.length;\n if (sep) {\n ownerText.insert(pos, sep);\n pos += 1;\n }\n writeDeltaInto(ownerText, pos, delta);\n }\n // Clear neighbor text.\n if (nbText && nbText.length > 0) nbText.delete(0, nbText.length);\n\n // Owner gets the widened colspan.\n const ownerMap = ctx.doc.getCellAttrsMap(blockIndex, ownerIdx);\n if (ownerMap) ownerMap.set(\"colspan\", ownerCs + nbCs);\n\n // Mark all cells in the neighbor's old rectangle as covered (in case nbCs > 1,\n // they were already covered — flag still applies).\n for (let r = row; r < row + ownerRs; r++) {\n for (let c = nbCol; c < nbCol + nbCs; c++) {\n const m = ctx.doc.getCellAttrsMap(blockIndex, r * cols + c);\n if (!m) continue;\n m.delete(\"rowspan\");\n m.delete(\"colspan\");\n m.set(\"covered\", true);\n }\n }\n ctx.setSelection(collapsedSelection({ blockIndex, cellIndex: ownerIdx, offset: 0 }));\n });\n return true;\n}\n\n/** Merge with the immediate bottom neighbor. Mirror of `mergeRight`. */\nexport function mergeDown(ctx: CommandContext, blockIndex: number, row: number, col: number): boolean {\n if (!ctx.doc.isTable(blockIndex)) return false;\n const { rows, cols } = ctx.doc.getTableSize(blockIndex);\n if (row < 0 || row >= rows || col < 0 || col >= cols) return false;\n const ownerIdx = row * cols + col;\n const ownerAttrs = ctx.doc.getCellAttrs(blockIndex, ownerIdx);\n if (ownerAttrs.covered === true) return false;\n const ownerRs = spanOf(ownerAttrs.rowspan);\n const ownerCs = spanOf(ownerAttrs.colspan);\n const nbRow = row + ownerRs;\n if (nbRow >= rows) return false;\n const nbIdx = nbRow * cols + col;\n const nbAttrs = ctx.doc.getCellAttrs(blockIndex, nbIdx);\n if (nbAttrs.covered === true) return false;\n const nbRs = spanOf(nbAttrs.rowspan);\n const nbCs = spanOf(nbAttrs.colspan);\n if (nbCs !== ownerCs) return false;\n\n transact(ctx.doc, () => {\n const ownerText = ctx.doc.getCellText(blockIndex, ownerIdx);\n const nbText = ctx.doc.getCellText(blockIndex, nbIdx);\n if (ownerText && nbText && nbText.length > 0) {\n const sep = ownerText.length > 0 ? \" \" : \"\";\n const delta = nbText.toDelta() as DeltaOp[];\n let pos = ownerText.length;\n if (sep) {\n ownerText.insert(pos, sep);\n pos += 1;\n }\n writeDeltaInto(ownerText, pos, delta);\n }\n if (nbText && nbText.length > 0) nbText.delete(0, nbText.length);\n\n const ownerMap = ctx.doc.getCellAttrsMap(blockIndex, ownerIdx);\n if (ownerMap) ownerMap.set(\"rowspan\", ownerRs + nbRs);\n\n for (let r = nbRow; r < nbRow + nbRs; r++) {\n for (let c = col; c < col + ownerCs; c++) {\n const m = ctx.doc.getCellAttrsMap(blockIndex, r * cols + c);\n if (!m) continue;\n m.delete(\"rowspan\");\n m.delete(\"colspan\");\n m.set(\"covered\", true);\n }\n }\n ctx.setSelection(collapsedSelection({ blockIndex, cellIndex: ownerIdx, offset: 0 }));\n });\n return true;\n}\n\n/**\n * Split a merged cell back into a `rowspan × colspan` grid of independent real\n * cells. Each formerly-covered cell becomes empty and real. Returns true when\n * something was split. No-op (returns false) on a cell with no spans.\n */\nexport function splitCell(ctx: CommandContext, blockIndex: number, row: number, col: number): boolean {\n if (!ctx.doc.isTable(blockIndex)) return false;\n const { rows, cols } = ctx.doc.getTableSize(blockIndex);\n if (row < 0 || row >= rows || col < 0 || col >= cols) return false;\n const idx = row * cols + col;\n const attrs = ctx.doc.getCellAttrs(blockIndex, idx);\n if (attrs.covered === true) return false;\n const rs = spanOf(attrs.rowspan);\n const cs = spanOf(attrs.colspan);\n if (rs === 1 && cs === 1) return false;\n\n transact(ctx.doc, () => {\n const ownerMap = ctx.doc.getCellAttrsMap(blockIndex, idx);\n if (ownerMap) {\n ownerMap.delete(\"rowspan\");\n ownerMap.delete(\"colspan\");\n }\n for (let r = row; r < row + rs; r++) {\n for (let c = col; c < col + cs; c++) {\n if (r === row && c === col) continue;\n const m = ctx.doc.getCellAttrsMap(blockIndex, r * cols + c);\n if (!m) continue;\n m.delete(\"covered\");\n m.delete(\"rowspan\");\n m.delete(\"colspan\");\n }\n }\n ctx.setSelection(collapsedSelection({ blockIndex, cellIndex: idx, offset: 0 }));\n });\n return true;\n}\n\n// ---------- Column widths (Sub-phase 4.4) ----------\n\n/** Set the width (in CSS px) of a specific column. Auto-initializes `colWidths`. */\nexport function setColumnWidth(\n ctx: CommandContext,\n blockIndex: number,\n col: number,\n widthPx: number,\n): void {\n if (!ctx.doc.isTable(blockIndex)) return;\n const { cols } = ctx.doc.getTableSize(blockIndex);\n if (col < 0 || col >= cols) return;\n const w = Math.max(20, Math.round(widthPx));\n transact(ctx.doc, () => {\n const attrsMap = ctx.doc.getBlockAttrsMap(blockIndex);\n if (!attrsMap) return;\n const current = attrsMap.get(\"colWidths\") as number[] | undefined;\n const next = Array.isArray(current) && current.length === cols\n ? current.slice()\n : new Array<number>(cols).fill(120);\n next[col] = w;\n attrsMap.set(\"colWidths\", next);\n });\n}\n\n/**\n * Move the caret to the next cell of the same table (Tab). At the last cell of\n * the last row, creates a new row and lands in its first cell. Returns true\n * when handled. Caret must be inside a table for this to act.\n */\nexport function moveToNextCell(ctx: CommandContext): boolean {\n const sel = ctx.getSelection();\n const loc = tableLocationOf(ctx.doc, sel.focus);\n if (!loc) return false;\n const { rows, cols } = ctx.doc.getTableSize(loc.blockIndex);\n if (rows <= 0 || cols <= 0) return false;\n\n // Walk forward starting at the cell immediately following the owner's bottom-right.\n // For a non-spanning cell that's `flat + 1`; for a span, it's `(loc.row, loc.col + colspan)`\n // — but conceptually the owner's \"next\" sibling is simply the next real cell in row-major\n // order after the owner's flat index, since covered cells get skipped by the loop below.\n const startFlat = loc.row * cols + loc.col + 1;\n const next = findNextRealCell(ctx.doc, loc.blockIndex, startFlat, rows * cols);\n if (next == null) {\n // No more cells in the table — append a new row and land in its first cell.\n insertTableRow(ctx, loc.blockIndex, rows - 1, \"after\");\n return true;\n }\n ctx.setSelection(\n collapsedSelection({ blockIndex: loc.blockIndex, cellIndex: next, offset: 0 }),\n );\n return true;\n}\n\n/** Move the caret to the previous cell (Shift+Tab). At the first cell, no-op (returns true). */\nexport function moveToPrevCell(ctx: CommandContext): boolean {\n const sel = ctx.getSelection();\n const loc = tableLocationOf(ctx.doc, sel.focus);\n if (!loc) return false;\n const { rows, cols } = ctx.doc.getTableSize(loc.blockIndex);\n if (rows <= 0 || cols <= 0) return false;\n const startFlat = loc.row * cols + loc.col - 1;\n if (startFlat < 0) return true; // at (0,0) — handled but no-op\n const prev = findPrevRealCell(ctx.doc, loc.blockIndex, startFlat);\n if (prev == null) return true;\n const cellText = ctx.doc.getCellText(loc.blockIndex, prev);\n const off = cellText?.length ?? 0;\n ctx.setSelection(\n collapsedSelection({ blockIndex: loc.blockIndex, cellIndex: prev, offset: off }),\n );\n return true;\n}\n\nfunction findNextRealCell(\n doc: EditorDocument,\n blockIndex: number,\n startFlat: number,\n total: number,\n): number | null {\n for (let i = startFlat; i < total; i++) {\n if (doc.getCellAttrs(blockIndex, i).covered !== true) return i;\n }\n return null;\n}\n\nfunction findPrevRealCell(\n doc: EditorDocument,\n blockIndex: number,\n startFlat: number,\n): number | null {\n for (let i = startFlat; i >= 0; i--) {\n if (doc.getCellAttrs(blockIndex, i).covered !== true) return i;\n }\n return null;\n}\n\n/**\n * Append/write a delta's ops into `yText` starting at `pos`, preserving marks\n * AND image embeds. Returns the position right after the last write.\n */\nfunction writeDeltaInto(yText: Y.Text, pos: number, delta: DeltaOp[]): number {\n let cursor = pos;\n for (const op of delta) {\n if (typeof op.insert === \"string\") {\n if (op.insert.length === 0) continue;\n // Always pass an explicit attributes object that clears every mark, then\n // layers the op's own marks on top. Without this, `Y.Text.insert` lets the\n // new text inherit the formatting of the adjacent run (e.g. a plain run\n // pasted right after a bold run would turn bold). See CLEAR_ALL_MARKS.\n yText.insert(cursor, op.insert, {\n ...CLEAR_ALL_MARKS,\n ...((op.attributes as Record<string, unknown> | undefined) ?? {}),\n });\n cursor += op.insert.length;\n } else if (op.insert != null) {\n // Embed (e.g. ImageEmbed). Y.Text accepts arbitrary JSON-serializable\n // objects as length-1 inserts.\n if (op.attributes && Object.keys(op.attributes).length > 0) {\n yText.insert(\n cursor,\n op.insert as unknown as string,\n op.attributes as Record<string, unknown>,\n );\n } else {\n yText.insert(cursor, op.insert as unknown as string);\n }\n cursor += 1;\n }\n }\n return cursor;\n}\n\n// ---------- Inline embeds (Fase 5: imagens) ----------\n\n/**\n * Insert an inline image embed at the current selection. Embeds occupy 1 char\n * in offset arithmetic (Y.Text treats them as length-1 inserts).\n */\nexport function insertImage(ctx: CommandContext, embed: ImageEmbed): void {\n clearRectCells(ctx);\n transact(ctx.doc, () => {\n const sel0 = ctx.getSelection();\n let cursor = sel0;\n if (!isCollapsed(sel0)) cursor = deleteRange(ctx.doc, sel0);\n const pos = cursor.focus;\n const yText = ctx.doc.textAt(pos.blockIndex, pos.cellIndex);\n if (!yText) return;\n // Y.Text accepts non-string inserts natively.\n yText.insert(pos.offset, embed as unknown as string);\n const newPos: Position = {\n blockIndex: pos.blockIndex,\n cellIndex: pos.cellIndex,\n offset: pos.offset + 1,\n };\n ctx.setSelection(collapsedSelection(newPos));\n });\n}\n\n/**\n * Update attributes of an existing image embed at `(blockIndex, embedOffset)`.\n * Implementation: delete the 1-char slot and re-insert the merged embed in the\n * SAME transaction — Y.UndoManager coalesces delete+insert in one transact, so\n * undo treats it as a single step.\n *\n * If `newOffset` is provided and differs from `embedOffset`, the embed is moved\n * to that offset within the same block/cell. Used by wrap-left/wrap-right\n * layouts which must anchor the image at the block start so floated text wraps\n * around it (CSS float only flows text that comes AFTER the float in DOM order).\n */\nexport function setImageAttrs(\n ctx: CommandContext,\n blockIndex: number,\n embedOffset: number,\n partial: Partial<ImageEmbed>,\n cellIndex?: number,\n newOffset?: number,\n): void {\n transact(ctx.doc, () => {\n const yText = ctx.doc.textAt(blockIndex, cellIndex);\n if (!yText) return;\n const delta = yText.toDelta() as DeltaOp[];\n let cursor = 0;\n let prev: ImageEmbed | null = null;\n for (const op of delta) {\n if (typeof op.insert === \"string\") {\n cursor += op.insert.length;\n continue;\n }\n if (cursor === embedOffset && isImageEmbed(op.insert)) {\n prev = op.insert;\n break;\n }\n cursor += 1;\n }\n if (!prev) return;\n const merged: ImageEmbed = { ...prev, ...partial };\n yText.delete(embedOffset, 1);\n const insertAt =\n newOffset != null && newOffset !== embedOffset\n ? Math.max(0, Math.min(newOffset, yText.length))\n : embedOffset;\n yText.insert(insertAt, merged as unknown as string);\n });\n}\n\n/** Location of an embed in the model (block or table cell). */\nexport interface EmbedLoc {\n blockIndex: number;\n offset: number;\n cellIndex?: number;\n}\n\n/**\n * Layouts whose embed is re-anchorable between Y.Texts. Only `front`/`behind`\n * use absolute `left`/`top`, so only they can be re-anchored. Inline embeds are\n * not positioned absolutely, and `wrap-left`/`wrap-right` are governed by float\n * margins (not absolute coordinates) — both are EXCLUDED and stay on the\n * same-page `setImageAttrs` path (see RESOLVED DECISION at plan header).\n */\nconst REANCHORABLE_LAYOUTS: ReadonlySet<string> = new Set([\"front\", \"behind\"]);\n\n/**\n * Move a floating image embed from `from` to `to` in a SINGLE Y.Doc\n * transaction, applying new positional offsets. Atomic delete+insert keeps the\n * CRDT consistent for collab peers and coalesces into one undo step.\n *\n * Guard: only non-inline (re-anchorable) image embeds are moved; everything\n * else is a no-op. When `from` and `to` resolve to the SAME Y.Text, the insert\n * index is adjusted for the prior delete (mirrors `setImageAttrs`'s clamp at\n * lines 1709-1714). Sets the selection to the embed's new 1-char home so the\n * resize overlay stays attached.\n */\nexport function moveEmbedAnchor(\n ctx: CommandContext,\n from: EmbedLoc,\n to: EmbedLoc,\n newOffsetX: number,\n newOffsetY: number,\n): void {\n transact(ctx.doc, () => {\n const srcText = ctx.doc.textAt(from.blockIndex, from.cellIndex);\n if (!srcText) return;\n\n // Locate the embed at from.offset via the same delta scan as setImageAttrs.\n const delta = srcText.toDelta() as DeltaOp[];\n let cursor = 0;\n let prev: ImageEmbed | null = null;\n for (const op of delta) {\n if (typeof op.insert === \"string\") {\n cursor += op.insert.length;\n continue;\n }\n if (cursor === from.offset && isImageEmbed(op.insert)) {\n prev = op.insert;\n break;\n }\n cursor += 1;\n }\n if (!prev) return;\n\n // Guard: only re-anchor non-inline layouts.\n const layout = prev.layout ?? \"inline\";\n if (!REANCHORABLE_LAYOUTS.has(layout)) return;\n\n const dstText = ctx.doc.textAt(to.blockIndex, to.cellIndex);\n if (!dstText) return;\n\n const merged: ImageEmbed = { ...prev, offsetX: newOffsetX, offsetY: newOffsetY };\n\n const sameRun = srcText === dstText;\n\n // Delete the source slot first.\n srcText.delete(from.offset, 1);\n\n // Compute the landing offset. When same run, the delete shifts indices that\n // were AFTER from.offset down by one. Clamp to the (post-delete) length.\n let landed = to.offset;\n if (sameRun && to.offset > from.offset) {\n landed = to.offset - 1;\n }\n landed = Math.max(0, Math.min(landed, dstText.length));\n\n dstText.insert(landed, merged as unknown as string);\n\n ctx.setSelection({\n anchor: { blockIndex: to.blockIndex, cellIndex: to.cellIndex, offset: landed },\n focus: { blockIndex: to.blockIndex, cellIndex: to.cellIndex, offset: landed + 1 },\n });\n });\n}\n\n// Expose the Y origin so consumers (e.g. UndoManager) can filter on it.\nexport function isCommandOrigin(origin: unknown): boolean {\n return origin === COMMAND_ORIGIN;\n}\n\n// Allow Y.UndoManager.trackedOrigins to include the symbol.\nexport const TRACKED_ORIGINS: Set<unknown> = new Set([COMMAND_ORIGIN]);\n\n// Re-export Y for downstream type checks if needed.\nexport { Y };\n","import type { EditorDocument } from \"./document\";\nimport type { DeltaOp, Selection, SerializedBlock } from \"./types\";\nimport { sliceDelta } from \"./marks\";\nimport { isCollapsed, orderedRange } from \"./selection\";\n\n/** MIME custom que carrega o slice serializado no clipboard. */\nexport const SOFER_MIME = \"application/x-sofer-slice\";\n\nexport interface ClipboardSlice {\n /** 1..n blocos; cada delta carrega marks + embeds de imagem. */\n blocks: SerializedBlock[];\n /** 1º bloco é fragmento parcial → mescla inline no alvo da colagem. */\n openStart: boolean;\n /** último bloco é fragmento parcial → conteúdo após o caret continua nele. */\n openEnd: boolean;\n}\n\n/** Texto puro de um delta (embeds não contribuem caractere visível). */\nfunction deltaToText(delta: DeltaOp[]): string {\n let s = \"\";\n for (const op of delta) if (typeof op.insert === \"string\") s += op.insert;\n return s;\n}\n\n/** Monta um SerializedBlock inline a partir de um delta já fatiado.\n * Para conteúdo vindo de célula (cellIndex != null) o bloco vira \"paragraph\". */\nfunction blockFromDelta(\n doc: EditorDocument,\n blockIndex: number,\n cellIndex: number | undefined,\n delta: DeltaOp[],\n): SerializedBlock {\n if (cellIndex != null) {\n return { type: \"paragraph\", text: deltaToText(delta), delta, attrs: {} };\n }\n return {\n type: doc.getBlockType(blockIndex) ?? \"paragraph\",\n text: deltaToText(delta),\n delta,\n attrs: doc.getBlockAttrs(blockIndex),\n };\n}\n\n/**\n * Lê a seleção e produz um ClipboardSlice, ou null se:\n * - colapsada; - âncora/foco em células diferentes; - multi-bloco com tabela.\n */\nexport function serializeSelection(\n doc: EditorDocument,\n sel: Selection,\n): ClipboardSlice | null {\n if (isCollapsed(sel)) return null;\n const { start, end } = orderedRange(sel);\n if ((start.cellIndex ?? -1) !== (end.cellIndex ?? -1)) return null;\n\n if (start.blockIndex === end.blockIndex) {\n const yText = doc.textAt(start.blockIndex, start.cellIndex);\n if (!yText) return null;\n const delta = sliceDelta(yText.toDelta() as DeltaOp[], start.offset, end.offset);\n return {\n blocks: [blockFromDelta(doc, start.blockIndex, start.cellIndex, delta)],\n openStart: start.offset > 0,\n openEnd: end.offset < yText.length,\n };\n }\n\n if (start.cellIndex != null || end.cellIndex != null) return null;\n for (let i = start.blockIndex; i <= end.blockIndex; i++) {\n if (doc.getBlockType(i) === \"table\") return null;\n }\n const startText = doc.getBlockText(start.blockIndex);\n const endText = doc.getBlockText(end.blockIndex);\n if (!startText || !endText) return null;\n\n const blocks: SerializedBlock[] = [];\n blocks.push(\n blockFromDelta(doc, start.blockIndex, undefined,\n sliceDelta(startText.toDelta() as DeltaOp[], start.offset, startText.length)),\n );\n for (let i = start.blockIndex + 1; i < end.blockIndex; i++) {\n const t = doc.getBlockText(i);\n blocks.push(blockFromDelta(doc, i, undefined, (t?.toDelta() as DeltaOp[]) ?? []));\n }\n blocks.push(\n blockFromDelta(doc, end.blockIndex, undefined,\n sliceDelta(endText.toDelta() as DeltaOp[], 0, end.offset)),\n );\n return {\n blocks,\n openStart: start.offset > 0,\n openEnd: end.offset < endText.length,\n };\n}\n\n/** Fallback texto puro: textos dos blocos unidos por \"\\n\". */\nexport function sliceToText(slice: ClipboardSlice): string {\n return slice.blocks.map((b) => deltaToText(b.delta)).join(\"\\n\");\n}\n\n/** Achata o slice num único delta inline (para colar dentro de uma célula).\n * Fronteiras de bloco viram quebra de linha \"\\n\" (células renderizam pre-wrap),\n * para não grudar palavras de parágrafos distintos. */\nexport function sliceToInlineDelta(slice: ClipboardSlice): DeltaOp[] {\n const out: DeltaOp[] = [];\n slice.blocks.forEach((b, i) => {\n if (i > 0) out.push({ insert: \"\\n\" });\n out.push(...b.delta);\n });\n return out;\n}\n","import * as Y from \"yjs\";\nimport type { EditorDocument } from \"./document\";\nimport { TRACKED_ORIGINS } from \"./commands\";\n\nexport class EditorHistory {\n readonly undoManager: Y.UndoManager;\n\n constructor(doc: EditorDocument) {\n this.undoManager = new Y.UndoManager(doc.blocks, {\n trackedOrigins: TRACKED_ORIGINS,\n captureTimeout: 400,\n });\n }\n\n undo(): boolean {\n return this.undoManager.undo() != null;\n }\n\n redo(): boolean {\n return this.undoManager.redo() != null;\n }\n\n destroy(): void {\n this.undoManager.destroy();\n }\n}\n"],"mappings":"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","names":["Y","merged","yText","Y","t","Y","yText","Y"]}
|