diff --git a/src/lib/import/CLAUDE.md b/src/lib/import/CLAUDE.md index 2638b33..41b2da1 100644 --- a/src/lib/import/CLAUDE.md +++ b/src/lib/import/CLAUDE.md @@ -75,6 +75,11 @@ docDefaults ← the table style ← the cell paragraph's own style chain ← dir style name; read as an override the way a table style zeroing `w:after` reads, every table loses the space after its cells' paragraphs and a long document comes out pages short. +**A `w:cols` gap the section's text cannot hold is no gap at all.** `w:space` is twips, and +a producer writing EMU there (360000 = 1cm in EMU, 635cm read as twips) would otherwise +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. + Body text with no resolved font falls back to the *document's own theme minor font* (`docx.ts` `runMarks`), not the editor default — Word's implicit body default. Headings don't (they keep the editor heading default); DOCX page margins default to Word's 2.54cm. diff --git a/src/lib/import/docx.ts b/src/lib/import/docx.ts index e6989c9..5cc0b5c 100644 --- a/src/lib/import/docx.ts +++ b/src/lib/import/docx.ts @@ -23,6 +23,7 @@ import { applyUniformRunFont, pairAlignedFrames, sinkOffsetFrames, type OdtImpor import { chartDataUrl } from './chart'; import { deobfuscateOdttf, type EmbeddedFont } from '../fonts/embeddedFonts'; import { cellPaddingAttr, DEFAULT_CELL_PADDING, type CellPadding } from '../editor/extensions/tableCellPadding'; +import { clampColumnGap } from '../editor/extensions/columns'; import { astToLatex } from '../math/latex'; import { parseOmml, OMML_NS } from '../math/omml'; @@ -2089,7 +2090,12 @@ function sectPrColumns(sectPr: Element | null, ctx: Ctx): { count: number; gapCm count = 3; } const space = intAttr(cols, W, 'space') ?? (colEls[0] ? intAttr(colEls[0], W, 'space') : null) ?? 283; - return { count, gapCm: Math.min(5, Math.max(0, round2(twipToCm(space)))) }; + // A gap the section's text has no room for is a producer's unit slip — EMU written into + // a twips attribute — and lays out as no gap at all, not as columns too narrow to hold a + // word. Below that LibreOffice honours the declared value literally (probed). + const gapCm = round2(twipToCm(space)); + const fits = gapCm > 0 && (count - 1) * gapCm < sectionContentWidthCm(sectPr); + return { count, gapCm: fits ? clampColumnGap(gapCm) : 0 }; } // Block types a columns node can contain (mirrors import/odt.ts).