@sofereditor/core 0.7.0 → 0.10.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.d.cts CHANGED
@@ -128,11 +128,24 @@ interface BlockAttrs {
128
128
  /** Only meaningful when `type === "table"`. */
129
129
  cols?: number;
130
130
  /**
131
- * Only meaningful when `type === "table"`. Per-column widths in CSS px.
132
- * Length should equal `cols` when set; missing or short arrays fall back to
133
- * an auto distribution at render time.
131
+ * Only meaningful when `type === "table"`. Per-column widths in
132
+ * **proportion**, summing to 100. Old documents have absolute px and are
133
+ * normalized on read — see `normalizarLarguras`.
134
134
  */
135
135
  colWidths?: number[];
136
+ /**
137
+ * Only meaningful when `type === "table"`. Total table width as a
138
+ * percentage of the available page width. Missing = 100, so existing
139
+ * documents don't change appearance.
140
+ */
141
+ tableWidth?: number;
142
+ /**
143
+ * Only meaningful when `type === "table"`. Per-row height in px, one entry
144
+ * per row. It's a MINIMUM, not fixed — the row grows past it when content
145
+ * needs more room (same posture as `w:trHeight hRule="atLeast"` in DOCX).
146
+ * Missing = rows size to content, exactly like today.
147
+ */
148
+ rowHeights?: number[];
136
149
  /**
137
150
  * Só relevante quando `type === "table"`. Onde as linhas da grade aparecem.
138
151
  * Ausente = "all" — documentos existentes não mudam de aparência.
@@ -178,6 +191,20 @@ interface CellAttrs {
178
191
  align?: AlignValue;
179
192
  /** Cor de fundo da célula (CSS color, ex. `#ffe58f`). Ausente = sem fundo. */
180
193
  bgColor?: string;
194
+ /**
195
+ * Quando presente, a célula renderiza como lista e cada linha separada por
196
+ * `\n` vira um item. Ausente = texto normal com quebras visuais.
197
+ *
198
+ * Não existe `listLevel` aqui de propósito: `Y.Text` plano não guarda
199
+ * atributo por linha, então recuo seria um nível para a célula inteira, não
200
+ * por item. Aninhamento dentro de célula exigiria blocos de verdade dentro
201
+ * dela — ver o spec de 2026-08-24.
202
+ */
203
+ listKind?: ListKind;
204
+ /** Só relevante com `listKind === "ordered"`. Primeiro número da lista. */
205
+ listStart?: number;
206
+ /** Só relevante com `listKind === "ordered"`. Sobrepõe o marcador padrão. */
207
+ listStyle?: ListStyleType;
181
208
  }
182
209
  interface Position {
183
210
  blockIndex: number;
@@ -274,9 +301,46 @@ interface ImageEmbed {
274
301
  * caption using the paragraph's own alignment.
275
302
  */
276
303
  captionAlign?: "left" | "center" | "right";
304
+ /**
305
+ * Presente ⇒ este embed é uma fórmula. A imagem (`src`) é o RENDER; isto é
306
+ * a fonte. Reabrir o editor de fórmula relê `latex` daqui.
307
+ */
308
+ formula?: {
309
+ /** Fonte da verdade. O que o professor escreveu. */
310
+ latex: string;
311
+ /**
312
+ * Bloco (`\displaystyle`, centrado) em vez de inline. Guardado explícito
313
+ * em vez de derivado de `align === "center"`: derivar acoplaria o modo da
314
+ * fórmula a um campo de layout que o usuário mexe pelos botões de
315
+ * alinhamento da toolbar, e reabrir o modal cairia no modo errado.
316
+ */
317
+ display: boolean;
318
+ /**
319
+ * Alinhamento de base para fórmula inline, no formato que o MathJax
320
+ * devolve (ex.: "-0.781ex"). Aplicado como `vertical-align` no WRAPPER
321
+ * (<figure>) para a fórmula sentar na linha do texto. Ausente quando
322
+ * `display` é true.
323
+ */
324
+ vAlign?: string;
325
+ };
326
+ /**
327
+ * PNG data URL. Só o `export-docx` consome: o `ImageRun` de `type: "svg"`
328
+ * exige um `fallback` raster. Vale para qualquer embed cujo `src` seja SVG —
329
+ * não é exclusivo de fórmula.
330
+ */
331
+ svgFallback?: string;
277
332
  }
278
333
  type InsertContent = string | ImageEmbed;
279
334
  declare function isImageEmbed(v: unknown): v is ImageEmbed;
335
+ /**
336
+ * Um embed de fórmula é um embed de IMAGEM que carrega seu LaTeX. Só dois
337
+ * lugares precisam distinguir: a toolbar (trocar "Legenda" por "Editar
338
+ * fórmula") e o duplo clique que reabre o modal. Todo o resto trata como
339
+ * imagem, de propósito.
340
+ */
341
+ declare function isFormulaEmbed(v: unknown): v is ImageEmbed & {
342
+ formula: NonNullable<ImageEmbed["formula"]>;
343
+ };
280
344
  interface DeltaOp {
281
345
  insert: InsertContent;
282
346
  attributes?: MarkAttrs;
@@ -481,6 +545,19 @@ declare function deltaLength(delta: DeltaOp[]): number;
481
545
  * Embeds are atomic length-1 ops: included whole if their slot intersects the range.
482
546
  */
483
547
  declare function sliceDelta(delta: DeltaOp[], start: number, end: number): DeltaOp[];
548
+ /**
549
+ * Fatia um delta em uma lista por linha, quebrando nos `\n`.
550
+ *
551
+ * Usado pelo render de célula-lista: a célula é um `Y.Text` plano, e quando ela
552
+ * carrega `listKind` cada linha vira um `<li>`. As marcas de cada trecho são
553
+ * preservadas; embeds ficam na linha corrente e nunca separam.
554
+ *
555
+ * Devolve SEMPRE ao menos uma linha — delta vazio vira `[[]]`, não `[]`.
556
+ * Linha vazia no meio (`"a\n\nb"`) é preservada como delta vazio, senão o
557
+ * número de itens da lista não bateria com o número de `\n` do modelo, e o
558
+ * mapeamento de cursor do `dom-bridge` sairia do lugar.
559
+ */
560
+ declare function splitDeltaByLines(delta: DeltaOp[]): DeltaOp[][];
484
561
 
485
562
  /**
486
563
  * Helpers puros de decoração visual, compartilhados pelos DOIS renderizadores
@@ -876,8 +953,81 @@ declare function mergeDown(ctx: CommandContext, blockIndex: number, row: number,
876
953
  * something was split. No-op (returns false) on a cell with no spans.
877
954
  */
878
955
  declare function splitCell(ctx: CommandContext, blockIndex: number, row: number, col: number): boolean;
879
- /** Set the width (in CSS px) of a specific column. Auto-initializes `colWidths`. */
880
- declare function setColumnWidth(ctx: CommandContext, blockIndex: number, col: number, widthPx: number): void;
956
+ /**
957
+ * Devolve proporções somando 100.
958
+ *
959
+ * Documento antigo grava px absoluto. Como a tabela sempre renderiza em
960
+ * `width: 100%`, esses px já eram interpretados PROPORCIONALMENTE pelo
961
+ * navegador — então normalizar preserva exatamente o que o professor via.
962
+ * Não é conversão destrutiva.
963
+ *
964
+ * A heurística "a soma já é ~100, então já é proporção" é segura na prática:
965
+ * para uma tabela em px cair nela, a média por coluna teria que ser 100/n —
966
+ * 25 px cada em 4 colunas. O código antigo gravava largura renderizada, que
967
+ * numa A4 dá ~150 px por coluna. É heurística, não prova.
968
+ */
969
+ declare function normalizarLarguras(widths: number[] | undefined, cols: number): number[];
970
+ /**
971
+ * Move a divisa `boundary` (entre a coluna `boundary` e a `boundary+1`) por
972
+ * `deltaPct` pontos percentuais: uma cresce, a vizinha encolhe na mesma
973
+ * medida. A soma permanece 100 **por construção**, não por normalização —
974
+ * é o que faz o arrasto colar no cursor.
975
+ *
976
+ * A divisa da última coluna não tem vizinha: ela é a borda direita da tabela
977
+ * e é tratada por `setTableWidth`, não aqui.
978
+ */
979
+ declare function setColumnBoundary(ctx: CommandContext, blockIndex: number, boundary: number, deltaPct: number,
980
+ /**
981
+ * Proporções do início do arrasto. O overlay lê o modelo UMA vez no
982
+ * `pointerdown` e passa aqui a cada movimento, para o delta ser sempre
983
+ * relativo àquele instante. Sem a base, cada `pointermove` aplicaria o
984
+ * delta sobre o resultado do anterior e o arrasto aceleraria.
985
+ */
986
+ base?: number[]): void;
987
+ /** Piso arbitrário e assumido: com `table-layout: fixed` a tabela encolhe
988
+ * abaixo do conteúdo sem resistência, então não há "mínimo do conteúdo"
989
+ * para ancorar. */
990
+ declare const MIN_TABELA_PCT = 20;
991
+ /** Teto: a tabela não passa da margem da página. */
992
+ declare const MAX_TABELA_PCT = 100;
993
+ /**
994
+ * Trava `pct` na faixa válida. Exportada porque o import de DOCX precisa da
995
+ * MESMA faixa que o comando: o Word aceita largura de tabela maior que a
996
+ * página, e sem esta trava um `w:tblW` de 7500 pct entrava como 150% — a
997
+ * tabela transbordava a área imprimível e a última coluna sumia do papel.
998
+ */
999
+ declare function travaLarguraTabela(pct: number): number;
1000
+ /**
1001
+ * Define a largura total da tabela como percentual da largura útil da
1002
+ * página. Ausente = 100 (comportamento de hoje).
1003
+ */
1004
+ declare function setTableWidth(ctx: CommandContext, blockIndex: number, pct: number): void;
1005
+ /** Piso de altura de linha, em px. Abaixo disso a linha some da tela. */
1006
+ declare const MIN_LINHA_PX = 16;
1007
+ /**
1008
+ * Grava a altura de UMA linha, em px. É um MÍNIMO, não fixo — o CSS trata
1009
+ * `height` do `<tr>` como piso, e conteúdo maior empurra a linha para além
1010
+ * do valor gravado (mesma postura de `w:trHeight hRule="atLeast"` no DOCX).
1011
+ *
1012
+ * Só materializa `rowHeights` quando o array já existe ou está sendo
1013
+ * inicializado aqui — uma tabela nunca redimensionada não ganha o atributo
1014
+ * à toa, senão suas linhas parariam de crescer livremente com o conteúdo.
1015
+ */
1016
+ declare function setRowHeight(ctx: CommandContext, blockIndex: number, row: number, px: number): void;
1017
+ /**
1018
+ * Grava o array de alturas INTEIRO numa única transação — para o arrasto da
1019
+ * Task 5 escrever, a cada `pointermove`, o resultado final calculado a
1020
+ * partir da base do `pointerdown` (mesmo padrão de `setColumnBoundary`),
1021
+ * numa chamada só, em vez de N chamadas de `setRowHeight` que teriam que ser
1022
+ * reconciliadas depois. NÃO verificado aqui se isso muda o agrupamento de
1023
+ * undo do `Y.UndoManager` (que já agrupa por `captureTimeout` independente
1024
+ * de quantas transações ocorrem) — só a exportação e a escrita atômica do
1025
+ * array são o que este teste cobre.
1026
+ *
1027
+ * Cada altura passa pelo mesmo piso de `setRowHeight`. O array precisa
1028
+ * cobrir todas as linhas da tabela; tamanho errado é rejeitado (no-op).
1029
+ */
1030
+ declare function setRowHeights(ctx: CommandContext, blockIndex: number, heights: number[]): void;
881
1031
  /**
882
1032
  * Move the caret to the next cell of the same table (Tab). At the last cell of
883
1033
  * the last row, creates a new row and lands in its first cell. Returns true
@@ -932,4 +1082,24 @@ declare class EditorHistory {
932
1082
  destroy(): void;
933
1083
  }
934
1084
 
935
- export { ANSWER_LINE_COLOR, ANSWER_LINE_MAX, type AlignValue, type AnswerLineSpacing, BLANK_MIN_RUN, BLANK_STYLE, BLOCK_SPECS, type BlockAttrs, type BlockType, CLEAR_ALL_MARKS, COMMAND_ORIGIN, type CellAttrs, type CellBorderColors, type CellBorderPos, type ClipboardSlice, type CommandContext, type CommentAttr, DEFAULT_PAGE_SETTINGS, type DeltaOp, type DirValue, EditorDocument, EditorHistory, type EmbedLoc, type EncodedCursor, type EncodedCursorPoint, type ImageEmbed, type ImageLayout, type InsertContent, type LegacySerializedDocument, type LinkAttr, type ListKind, type ListStyleType, MARGIN_PRESETS, MAX_LIST_LEVEL, type MarkAttrs, type MarkName, type MarkValue, PAGE_PRESETS, type PagePreset, type PageSettings, type Position, SOFER_MIME, type Selection, type SerializedBlock, type SerializedCell, type SerializedDocument, type StyleRecord, TABLE_BORDER_COLOR, TABLE_GUIDE_COLOR, TRACKED_ORIGINS, type TableBorderPreset, type TableLocation, type TableRect, answerLineStyle, cellBorderColors, cellBorderStyle, cellsInRect, clearRectCells, collapsedSelection, comparePositions, createBlock, createCell, createTableBlock, decodeSelection, dedentList, defaultAttrsFor, deleteBackward, deleteForward, deleteSelection, deleteTable, deleteTableColumn, deleteTableRow, deltaLength, detectPreset, encodeSelection, expandTableRect, getBlockId, getMarksInRange, indentList, insertAnswerLines, insertImage, insertParagraph, insertSlice, insertTable, insertTableColumn, insertTableRow, insertText, isCollapsed, isCommandOrigin, isEmbedAdjacentToCaret, isImageEmbed, isKnownBlockType, isLegacySerializedDocument, isMarkUniformInRange, mergeDown, mergeRight, mergeSelection, mmToPx, moveEmbedAnchor, moveToNextCell, moveToPrevCell, newBlockId, orderedRange, positionsEqual, pxToMm, removeMark, sameTextRun, serializeSelection, setBlockAttr, setBlockAttrAtIndex, setBlockType, setCellAttr, setColumnWidth, setImageAttrs, setMark, sliceDelta, sliceToInlineDelta, sliceToText, spanOf, splitCell, splitListItem, splitUnderscoreRuns, styleToCssText, tableLocationOf, tableRectSelection, toggleList, toggleMark, withDefaults };
1085
+ /**
1086
+ * Remove toda marca `fontFamily` do documento — de blocos e de células de
1087
+ * tabela. Remove **todas**, não só as de valor conhecido: com o dropdown de
1088
+ * fonte fora da toolbar, nenhuma marca legítima pode existir.
1089
+ *
1090
+ * Idempotente e observável: conta antes de escrever e só abre transação se
1091
+ * houver o que limpar. Documento já migrado não gera update no Y.Doc, logo não
1092
+ * dispara o autosave e não regrava o `htmlSnapshot`.
1093
+ *
1094
+ * A transação usa origin `"migration"`, seguindo a convenção de `"pageSettings"`
1095
+ * e `"import"` (`document.ts:106`) — origens que o `UndoManager` não rastreia.
1096
+ * Sem isso, o primeiro Ctrl+Z do professor desfaria a migração em vez da edição
1097
+ * dele.
1098
+ *
1099
+ * @returns número de runs que carregavam a marca. 0 = nenhuma escrita.
1100
+ */
1101
+ declare function stripFontFamilyMarks(doc: EditorDocument, opts?: {
1102
+ dryRun?: boolean;
1103
+ }): number;
1104
+
1105
+ export { ANSWER_LINE_COLOR, ANSWER_LINE_MAX, type AlignValue, type AnswerLineSpacing, BLANK_MIN_RUN, BLANK_STYLE, BLOCK_SPECS, type BlockAttrs, type BlockType, CLEAR_ALL_MARKS, COMMAND_ORIGIN, type CellAttrs, type CellBorderColors, type CellBorderPos, type ClipboardSlice, type CommandContext, type CommentAttr, DEFAULT_PAGE_SETTINGS, type DeltaOp, type DirValue, EditorDocument, EditorHistory, type EmbedLoc, type EncodedCursor, type EncodedCursorPoint, type ImageEmbed, type ImageLayout, type InsertContent, type LegacySerializedDocument, type LinkAttr, type ListKind, type ListStyleType, MARGIN_PRESETS, MAX_LIST_LEVEL, MAX_TABELA_PCT, MIN_LINHA_PX, MIN_TABELA_PCT, type MarkAttrs, type MarkName, type MarkValue, PAGE_PRESETS, type PagePreset, type PageSettings, type Position, SOFER_MIME, type Selection, type SerializedBlock, type SerializedCell, type SerializedDocument, type StyleRecord, TABLE_BORDER_COLOR, TABLE_GUIDE_COLOR, TRACKED_ORIGINS, type TableBorderPreset, type TableLocation, type TableRect, answerLineStyle, cellBorderColors, cellBorderStyle, cellsInRect, clearRectCells, collapsedSelection, comparePositions, createBlock, createCell, createTableBlock, decodeSelection, dedentList, defaultAttrsFor, deleteBackward, deleteForward, deleteSelection, deleteTable, deleteTableColumn, deleteTableRow, deltaLength, detectPreset, encodeSelection, expandTableRect, getBlockId, getMarksInRange, indentList, insertAnswerLines, insertImage, insertParagraph, insertSlice, insertTable, insertTableColumn, insertTableRow, insertText, isCollapsed, isCommandOrigin, isEmbedAdjacentToCaret, isFormulaEmbed, isImageEmbed, isKnownBlockType, isLegacySerializedDocument, isMarkUniformInRange, mergeDown, mergeRight, mergeSelection, mmToPx, moveEmbedAnchor, moveToNextCell, moveToPrevCell, newBlockId, normalizarLarguras, orderedRange, positionsEqual, pxToMm, removeMark, sameTextRun, serializeSelection, setBlockAttr, setBlockAttrAtIndex, setBlockType, setCellAttr, setColumnBoundary, setImageAttrs, setMark, setRowHeight, setRowHeights, setTableWidth, sliceDelta, sliceToInlineDelta, sliceToText, spanOf, splitCell, splitDeltaByLines, splitListItem, splitUnderscoreRuns, stripFontFamilyMarks, styleToCssText, tableLocationOf, tableRectSelection, toggleList, toggleMark, travaLarguraTabela, withDefaults };
package/dist/index.d.ts CHANGED
@@ -128,11 +128,24 @@ interface BlockAttrs {
128
128
  /** Only meaningful when `type === "table"`. */
129
129
  cols?: number;
130
130
  /**
131
- * Only meaningful when `type === "table"`. Per-column widths in CSS px.
132
- * Length should equal `cols` when set; missing or short arrays fall back to
133
- * an auto distribution at render time.
131
+ * Only meaningful when `type === "table"`. Per-column widths in
132
+ * **proportion**, summing to 100. Old documents have absolute px and are
133
+ * normalized on read — see `normalizarLarguras`.
134
134
  */
135
135
  colWidths?: number[];
136
+ /**
137
+ * Only meaningful when `type === "table"`. Total table width as a
138
+ * percentage of the available page width. Missing = 100, so existing
139
+ * documents don't change appearance.
140
+ */
141
+ tableWidth?: number;
142
+ /**
143
+ * Only meaningful when `type === "table"`. Per-row height in px, one entry
144
+ * per row. It's a MINIMUM, not fixed — the row grows past it when content
145
+ * needs more room (same posture as `w:trHeight hRule="atLeast"` in DOCX).
146
+ * Missing = rows size to content, exactly like today.
147
+ */
148
+ rowHeights?: number[];
136
149
  /**
137
150
  * Só relevante quando `type === "table"`. Onde as linhas da grade aparecem.
138
151
  * Ausente = "all" — documentos existentes não mudam de aparência.
@@ -178,6 +191,20 @@ interface CellAttrs {
178
191
  align?: AlignValue;
179
192
  /** Cor de fundo da célula (CSS color, ex. `#ffe58f`). Ausente = sem fundo. */
180
193
  bgColor?: string;
194
+ /**
195
+ * Quando presente, a célula renderiza como lista e cada linha separada por
196
+ * `\n` vira um item. Ausente = texto normal com quebras visuais.
197
+ *
198
+ * Não existe `listLevel` aqui de propósito: `Y.Text` plano não guarda
199
+ * atributo por linha, então recuo seria um nível para a célula inteira, não
200
+ * por item. Aninhamento dentro de célula exigiria blocos de verdade dentro
201
+ * dela — ver o spec de 2026-08-24.
202
+ */
203
+ listKind?: ListKind;
204
+ /** Só relevante com `listKind === "ordered"`. Primeiro número da lista. */
205
+ listStart?: number;
206
+ /** Só relevante com `listKind === "ordered"`. Sobrepõe o marcador padrão. */
207
+ listStyle?: ListStyleType;
181
208
  }
182
209
  interface Position {
183
210
  blockIndex: number;
@@ -274,9 +301,46 @@ interface ImageEmbed {
274
301
  * caption using the paragraph's own alignment.
275
302
  */
276
303
  captionAlign?: "left" | "center" | "right";
304
+ /**
305
+ * Presente ⇒ este embed é uma fórmula. A imagem (`src`) é o RENDER; isto é
306
+ * a fonte. Reabrir o editor de fórmula relê `latex` daqui.
307
+ */
308
+ formula?: {
309
+ /** Fonte da verdade. O que o professor escreveu. */
310
+ latex: string;
311
+ /**
312
+ * Bloco (`\displaystyle`, centrado) em vez de inline. Guardado explícito
313
+ * em vez de derivado de `align === "center"`: derivar acoplaria o modo da
314
+ * fórmula a um campo de layout que o usuário mexe pelos botões de
315
+ * alinhamento da toolbar, e reabrir o modal cairia no modo errado.
316
+ */
317
+ display: boolean;
318
+ /**
319
+ * Alinhamento de base para fórmula inline, no formato que o MathJax
320
+ * devolve (ex.: "-0.781ex"). Aplicado como `vertical-align` no WRAPPER
321
+ * (<figure>) para a fórmula sentar na linha do texto. Ausente quando
322
+ * `display` é true.
323
+ */
324
+ vAlign?: string;
325
+ };
326
+ /**
327
+ * PNG data URL. Só o `export-docx` consome: o `ImageRun` de `type: "svg"`
328
+ * exige um `fallback` raster. Vale para qualquer embed cujo `src` seja SVG —
329
+ * não é exclusivo de fórmula.
330
+ */
331
+ svgFallback?: string;
277
332
  }
278
333
  type InsertContent = string | ImageEmbed;
279
334
  declare function isImageEmbed(v: unknown): v is ImageEmbed;
335
+ /**
336
+ * Um embed de fórmula é um embed de IMAGEM que carrega seu LaTeX. Só dois
337
+ * lugares precisam distinguir: a toolbar (trocar "Legenda" por "Editar
338
+ * fórmula") e o duplo clique que reabre o modal. Todo o resto trata como
339
+ * imagem, de propósito.
340
+ */
341
+ declare function isFormulaEmbed(v: unknown): v is ImageEmbed & {
342
+ formula: NonNullable<ImageEmbed["formula"]>;
343
+ };
280
344
  interface DeltaOp {
281
345
  insert: InsertContent;
282
346
  attributes?: MarkAttrs;
@@ -481,6 +545,19 @@ declare function deltaLength(delta: DeltaOp[]): number;
481
545
  * Embeds are atomic length-1 ops: included whole if their slot intersects the range.
482
546
  */
483
547
  declare function sliceDelta(delta: DeltaOp[], start: number, end: number): DeltaOp[];
548
+ /**
549
+ * Fatia um delta em uma lista por linha, quebrando nos `\n`.
550
+ *
551
+ * Usado pelo render de célula-lista: a célula é um `Y.Text` plano, e quando ela
552
+ * carrega `listKind` cada linha vira um `<li>`. As marcas de cada trecho são
553
+ * preservadas; embeds ficam na linha corrente e nunca separam.
554
+ *
555
+ * Devolve SEMPRE ao menos uma linha — delta vazio vira `[[]]`, não `[]`.
556
+ * Linha vazia no meio (`"a\n\nb"`) é preservada como delta vazio, senão o
557
+ * número de itens da lista não bateria com o número de `\n` do modelo, e o
558
+ * mapeamento de cursor do `dom-bridge` sairia do lugar.
559
+ */
560
+ declare function splitDeltaByLines(delta: DeltaOp[]): DeltaOp[][];
484
561
 
485
562
  /**
486
563
  * Helpers puros de decoração visual, compartilhados pelos DOIS renderizadores
@@ -876,8 +953,81 @@ declare function mergeDown(ctx: CommandContext, blockIndex: number, row: number,
876
953
  * something was split. No-op (returns false) on a cell with no spans.
877
954
  */
878
955
  declare function splitCell(ctx: CommandContext, blockIndex: number, row: number, col: number): boolean;
879
- /** Set the width (in CSS px) of a specific column. Auto-initializes `colWidths`. */
880
- declare function setColumnWidth(ctx: CommandContext, blockIndex: number, col: number, widthPx: number): void;
956
+ /**
957
+ * Devolve proporções somando 100.
958
+ *
959
+ * Documento antigo grava px absoluto. Como a tabela sempre renderiza em
960
+ * `width: 100%`, esses px já eram interpretados PROPORCIONALMENTE pelo
961
+ * navegador — então normalizar preserva exatamente o que o professor via.
962
+ * Não é conversão destrutiva.
963
+ *
964
+ * A heurística "a soma já é ~100, então já é proporção" é segura na prática:
965
+ * para uma tabela em px cair nela, a média por coluna teria que ser 100/n —
966
+ * 25 px cada em 4 colunas. O código antigo gravava largura renderizada, que
967
+ * numa A4 dá ~150 px por coluna. É heurística, não prova.
968
+ */
969
+ declare function normalizarLarguras(widths: number[] | undefined, cols: number): number[];
970
+ /**
971
+ * Move a divisa `boundary` (entre a coluna `boundary` e a `boundary+1`) por
972
+ * `deltaPct` pontos percentuais: uma cresce, a vizinha encolhe na mesma
973
+ * medida. A soma permanece 100 **por construção**, não por normalização —
974
+ * é o que faz o arrasto colar no cursor.
975
+ *
976
+ * A divisa da última coluna não tem vizinha: ela é a borda direita da tabela
977
+ * e é tratada por `setTableWidth`, não aqui.
978
+ */
979
+ declare function setColumnBoundary(ctx: CommandContext, blockIndex: number, boundary: number, deltaPct: number,
980
+ /**
981
+ * Proporções do início do arrasto. O overlay lê o modelo UMA vez no
982
+ * `pointerdown` e passa aqui a cada movimento, para o delta ser sempre
983
+ * relativo àquele instante. Sem a base, cada `pointermove` aplicaria o
984
+ * delta sobre o resultado do anterior e o arrasto aceleraria.
985
+ */
986
+ base?: number[]): void;
987
+ /** Piso arbitrário e assumido: com `table-layout: fixed` a tabela encolhe
988
+ * abaixo do conteúdo sem resistência, então não há "mínimo do conteúdo"
989
+ * para ancorar. */
990
+ declare const MIN_TABELA_PCT = 20;
991
+ /** Teto: a tabela não passa da margem da página. */
992
+ declare const MAX_TABELA_PCT = 100;
993
+ /**
994
+ * Trava `pct` na faixa válida. Exportada porque o import de DOCX precisa da
995
+ * MESMA faixa que o comando: o Word aceita largura de tabela maior que a
996
+ * página, e sem esta trava um `w:tblW` de 7500 pct entrava como 150% — a
997
+ * tabela transbordava a área imprimível e a última coluna sumia do papel.
998
+ */
999
+ declare function travaLarguraTabela(pct: number): number;
1000
+ /**
1001
+ * Define a largura total da tabela como percentual da largura útil da
1002
+ * página. Ausente = 100 (comportamento de hoje).
1003
+ */
1004
+ declare function setTableWidth(ctx: CommandContext, blockIndex: number, pct: number): void;
1005
+ /** Piso de altura de linha, em px. Abaixo disso a linha some da tela. */
1006
+ declare const MIN_LINHA_PX = 16;
1007
+ /**
1008
+ * Grava a altura de UMA linha, em px. É um MÍNIMO, não fixo — o CSS trata
1009
+ * `height` do `<tr>` como piso, e conteúdo maior empurra a linha para além
1010
+ * do valor gravado (mesma postura de `w:trHeight hRule="atLeast"` no DOCX).
1011
+ *
1012
+ * Só materializa `rowHeights` quando o array já existe ou está sendo
1013
+ * inicializado aqui — uma tabela nunca redimensionada não ganha o atributo
1014
+ * à toa, senão suas linhas parariam de crescer livremente com o conteúdo.
1015
+ */
1016
+ declare function setRowHeight(ctx: CommandContext, blockIndex: number, row: number, px: number): void;
1017
+ /**
1018
+ * Grava o array de alturas INTEIRO numa única transação — para o arrasto da
1019
+ * Task 5 escrever, a cada `pointermove`, o resultado final calculado a
1020
+ * partir da base do `pointerdown` (mesmo padrão de `setColumnBoundary`),
1021
+ * numa chamada só, em vez de N chamadas de `setRowHeight` que teriam que ser
1022
+ * reconciliadas depois. NÃO verificado aqui se isso muda o agrupamento de
1023
+ * undo do `Y.UndoManager` (que já agrupa por `captureTimeout` independente
1024
+ * de quantas transações ocorrem) — só a exportação e a escrita atômica do
1025
+ * array são o que este teste cobre.
1026
+ *
1027
+ * Cada altura passa pelo mesmo piso de `setRowHeight`. O array precisa
1028
+ * cobrir todas as linhas da tabela; tamanho errado é rejeitado (no-op).
1029
+ */
1030
+ declare function setRowHeights(ctx: CommandContext, blockIndex: number, heights: number[]): void;
881
1031
  /**
882
1032
  * Move the caret to the next cell of the same table (Tab). At the last cell of
883
1033
  * the last row, creates a new row and lands in its first cell. Returns true
@@ -932,4 +1082,24 @@ declare class EditorHistory {
932
1082
  destroy(): void;
933
1083
  }
934
1084
 
935
- export { ANSWER_LINE_COLOR, ANSWER_LINE_MAX, type AlignValue, type AnswerLineSpacing, BLANK_MIN_RUN, BLANK_STYLE, BLOCK_SPECS, type BlockAttrs, type BlockType, CLEAR_ALL_MARKS, COMMAND_ORIGIN, type CellAttrs, type CellBorderColors, type CellBorderPos, type ClipboardSlice, type CommandContext, type CommentAttr, DEFAULT_PAGE_SETTINGS, type DeltaOp, type DirValue, EditorDocument, EditorHistory, type EmbedLoc, type EncodedCursor, type EncodedCursorPoint, type ImageEmbed, type ImageLayout, type InsertContent, type LegacySerializedDocument, type LinkAttr, type ListKind, type ListStyleType, MARGIN_PRESETS, MAX_LIST_LEVEL, type MarkAttrs, type MarkName, type MarkValue, PAGE_PRESETS, type PagePreset, type PageSettings, type Position, SOFER_MIME, type Selection, type SerializedBlock, type SerializedCell, type SerializedDocument, type StyleRecord, TABLE_BORDER_COLOR, TABLE_GUIDE_COLOR, TRACKED_ORIGINS, type TableBorderPreset, type TableLocation, type TableRect, answerLineStyle, cellBorderColors, cellBorderStyle, cellsInRect, clearRectCells, collapsedSelection, comparePositions, createBlock, createCell, createTableBlock, decodeSelection, dedentList, defaultAttrsFor, deleteBackward, deleteForward, deleteSelection, deleteTable, deleteTableColumn, deleteTableRow, deltaLength, detectPreset, encodeSelection, expandTableRect, getBlockId, getMarksInRange, indentList, insertAnswerLines, insertImage, insertParagraph, insertSlice, insertTable, insertTableColumn, insertTableRow, insertText, isCollapsed, isCommandOrigin, isEmbedAdjacentToCaret, isImageEmbed, isKnownBlockType, isLegacySerializedDocument, isMarkUniformInRange, mergeDown, mergeRight, mergeSelection, mmToPx, moveEmbedAnchor, moveToNextCell, moveToPrevCell, newBlockId, orderedRange, positionsEqual, pxToMm, removeMark, sameTextRun, serializeSelection, setBlockAttr, setBlockAttrAtIndex, setBlockType, setCellAttr, setColumnWidth, setImageAttrs, setMark, sliceDelta, sliceToInlineDelta, sliceToText, spanOf, splitCell, splitListItem, splitUnderscoreRuns, styleToCssText, tableLocationOf, tableRectSelection, toggleList, toggleMark, withDefaults };
1085
+ /**
1086
+ * Remove toda marca `fontFamily` do documento — de blocos e de células de
1087
+ * tabela. Remove **todas**, não só as de valor conhecido: com o dropdown de
1088
+ * fonte fora da toolbar, nenhuma marca legítima pode existir.
1089
+ *
1090
+ * Idempotente e observável: conta antes de escrever e só abre transação se
1091
+ * houver o que limpar. Documento já migrado não gera update no Y.Doc, logo não
1092
+ * dispara o autosave e não regrava o `htmlSnapshot`.
1093
+ *
1094
+ * A transação usa origin `"migration"`, seguindo a convenção de `"pageSettings"`
1095
+ * e `"import"` (`document.ts:106`) — origens que o `UndoManager` não rastreia.
1096
+ * Sem isso, o primeiro Ctrl+Z do professor desfaria a migração em vez da edição
1097
+ * dele.
1098
+ *
1099
+ * @returns número de runs que carregavam a marca. 0 = nenhuma escrita.
1100
+ */
1101
+ declare function stripFontFamilyMarks(doc: EditorDocument, opts?: {
1102
+ dryRun?: boolean;
1103
+ }): number;
1104
+
1105
+ export { ANSWER_LINE_COLOR, ANSWER_LINE_MAX, type AlignValue, type AnswerLineSpacing, BLANK_MIN_RUN, BLANK_STYLE, BLOCK_SPECS, type BlockAttrs, type BlockType, CLEAR_ALL_MARKS, COMMAND_ORIGIN, type CellAttrs, type CellBorderColors, type CellBorderPos, type ClipboardSlice, type CommandContext, type CommentAttr, DEFAULT_PAGE_SETTINGS, type DeltaOp, type DirValue, EditorDocument, EditorHistory, type EmbedLoc, type EncodedCursor, type EncodedCursorPoint, type ImageEmbed, type ImageLayout, type InsertContent, type LegacySerializedDocument, type LinkAttr, type ListKind, type ListStyleType, MARGIN_PRESETS, MAX_LIST_LEVEL, MAX_TABELA_PCT, MIN_LINHA_PX, MIN_TABELA_PCT, type MarkAttrs, type MarkName, type MarkValue, PAGE_PRESETS, type PagePreset, type PageSettings, type Position, SOFER_MIME, type Selection, type SerializedBlock, type SerializedCell, type SerializedDocument, type StyleRecord, TABLE_BORDER_COLOR, TABLE_GUIDE_COLOR, TRACKED_ORIGINS, type TableBorderPreset, type TableLocation, type TableRect, answerLineStyle, cellBorderColors, cellBorderStyle, cellsInRect, clearRectCells, collapsedSelection, comparePositions, createBlock, createCell, createTableBlock, decodeSelection, dedentList, defaultAttrsFor, deleteBackward, deleteForward, deleteSelection, deleteTable, deleteTableColumn, deleteTableRow, deltaLength, detectPreset, encodeSelection, expandTableRect, getBlockId, getMarksInRange, indentList, insertAnswerLines, insertImage, insertParagraph, insertSlice, insertTable, insertTableColumn, insertTableRow, insertText, isCollapsed, isCommandOrigin, isEmbedAdjacentToCaret, isFormulaEmbed, isImageEmbed, isKnownBlockType, isLegacySerializedDocument, isMarkUniformInRange, mergeDown, mergeRight, mergeSelection, mmToPx, moveEmbedAnchor, moveToNextCell, moveToPrevCell, newBlockId, normalizarLarguras, orderedRange, positionsEqual, pxToMm, removeMark, sameTextRun, serializeSelection, setBlockAttr, setBlockAttrAtIndex, setBlockType, setCellAttr, setColumnBoundary, setImageAttrs, setMark, setRowHeight, setRowHeights, setTableWidth, sliceDelta, sliceToInlineDelta, sliceToText, spanOf, splitCell, splitDeltaByLines, splitListItem, splitUnderscoreRuns, stripFontFamilyMarks, styleToCssText, tableLocationOf, tableRectSelection, toggleList, toggleMark, travaLarguraTabela, withDefaults };