From 85036b9559068dc9652ca55982e847b8fb2576cf Mon Sep 17 00:00:00 2001 From: Steffen Becker Date: Fri, 11 Sep 2026 00:31:28 +0200 Subject: [PATCH] feat: opening a document says when a floating table was flattened MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Word's w:tblpPr takes a table out of the flow — a cover page's layout table is one — and the editor's block table cannot, so what follows it sits as far down as the table is tall, a frame anchored there with it. Nothing in the document said so; the import now warns, as it does for the other shapes it cannot hold. Claude-Session: https://claude.ai/code/session_01Wzs2qG6Y5qm7mKmJHfu44G --- src/lib/i18n/locales/de.ts | 1 + src/lib/i18n/locales/en.ts | 1 + src/lib/import/CLAUDE.md | 7 +++++++ src/lib/import/docx.ts | 6 ++++++ 4 files changed, 15 insertions(+) diff --git a/src/lib/i18n/locales/de.ts b/src/lib/i18n/locales/de.ts index c1eb288..3873144 100644 --- a/src/lib/i18n/locales/de.ts +++ b/src/lib/i18n/locales/de.ts @@ -1111,6 +1111,7 @@ const de: Messages = { hfFlattened: 'Listen/Tabellen in Kopf- oder Fußzeilen wurden in Text umgewandelt', textBoxFlattened: 'In Tabellenzellen oder anderen Textfeldern verschachtelte Textfelder wurden aufgelöst', nestedTables: 'Verschachtelte Tabellen wurden in Absätze umgewandelt', + floatingTable: 'Eine frei positionierte Tabelle steht jetzt im Textfluss — was ihr folgt, kann tiefer sitzen als in Word', comments: 'Kommentare wurden entfernt', missingFonts: (fonts) => `Diese Schriftarten sind nicht installiert und wurden durch Ersatzschriften dargestellt: ${fonts}`, }, diff --git a/src/lib/i18n/locales/en.ts b/src/lib/i18n/locales/en.ts index c2290b8..2102367 100644 --- a/src/lib/i18n/locales/en.ts +++ b/src/lib/i18n/locales/en.ts @@ -1119,6 +1119,7 @@ const en = { hfFlattened: 'Lists/tables in headers or footers were flattened to text', textBoxFlattened: 'Text boxes nested in table cells or other text boxes were flattened', nestedTables: 'Nested tables were flattened to paragraphs', + floatingTable: 'A floating table was placed in the text flow — what follows it may sit lower than in Word', comments: 'Comments were removed', missingFonts: (fonts: string) => `These fonts aren't installed and were shown with a substitute: ${fonts}`, }, diff --git a/src/lib/import/CLAUDE.md b/src/lib/import/CLAUDE.md index 4a1a10e..9eb561b 100644 --- a/src/lib/import/CLAUDE.md +++ b/src/lib/import/CLAUDE.md @@ -115,6 +115,13 @@ a producer writing EMU there (360000 = 1cm in EMU, 635cm read as twips) would ot leave columns of no width. Under that width LibreOffice lays the declared gap out literally — probed to 10.16cm on a 15.24cm text — so only the unholdable value is dropped. +**A floating table stays in the flow, with a warning.** Word's `w:tblpPr` takes a table +out of it — a cover page's layout table is one, and what follows starts where the table +does — which the editor's block table cannot do. So the blocks after it (and any frame +anchored to them) sit as far down as the table is tall; LibreOffice models the same table +as a text frame wrapping it, which is why its own layout of such a cover differs from +ours. + **A heading in a cell carries its own 0.** No style name reaches a cell, so the editor draws the level's 12pt/6pt margins (`styles/headings.ts`) there — where a Word heading whose style chain sets no spacing has none. The baked-in chain's silence is therefore diff --git a/src/lib/import/docx.ts b/src/lib/import/docx.ts index a369a97..225d90b 100644 --- a/src/lib/import/docx.ts +++ b/src/lib/import/docx.ts @@ -2746,6 +2746,12 @@ function buildTable(tbl: Element, ctx: Ctx): Node | null { rows.push(row); } if (rows.length === 0) return null; + // A floating table (w:tblpPr) is out of Word's flow: what follows it starts where the + // table does. The editor has no such table, so it stays in the flow — and a frame + // anchored to the paragraph after it lands as far down as the table is tall. + if (fc(fc(tbl, 'tblPr'), 'tblpPr')) { + ctx.warnings.add('A floating table was placed in the text flow — what follows it may sit lower than in Word'); + } const attrs: Record = { ...(tableMargins(tbl, useWeights, ctx, padBase[3]) ?? {}) }; if (pad) attrs.cellPadding = pad; // w:tblHeader on the first row: Word repeats it at the top of every page the table