fix: a heading in a table cell keeps the spacing its file gives it
No style name reaches a cell, so the editor draws the level's own 12pt/6pt margins there — but a Word heading whose style chain sets no spacing has none, and the chain is baked into the cell's blocks, so its silence is a real 0. It is written as one now; a cell paragraph's 0 stays unset, as it was. A subtitle under a heading came out 4.2mm low, and everything under it with it. Claude-Session: https://claude.ai/code/session_01Wzs2qG6Y5qm7mKmJHfu44G
This commit is contained in:
1 parent
b233f0e160
commit
1e7d38e561
2 files changed
+21
-2
No files matched your search
@@ -115,6 +115,12 @@ 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 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
|
||||
written as an explicit 0 (`convertParaLike`, the `kind === 'cell'` branch), while a cell
|
||||
*paragraph*'s 0 stays unset as before. Missing it put every such heading 4.2mm low.
|
||||
|
||||
**A `w:numStyleLink` abstract carries no levels** — it defers to its numbering style's own
|
||||
numbering, so `DocxStyles.level()` resolves through the link (style → its `w:numPr` → the
|
||||
`w:styleLink` abstract); unresolved it read as `{}` and every linked list silently imported
|
||||
|
||||
+15
-2
@@ -133,6 +133,10 @@ const BODY_FONT_SIZE_PT = 12;
|
||||
// Rounded to half points: that is all Word can store, so it is what our own export
|
||||
// writes and what an imported heading must be compared against.
|
||||
const HEADING_SIZES = HEADING_STYLE_OVERRIDES.map((h) => Math.round(lengthToPt(h.fontSize)! * 2) / 2);
|
||||
// The vertical margins a heading renders with when the block carries none of its own.
|
||||
const HEADING_MARGINS = HEADING_STYLE_OVERRIDES.map((h) => ({
|
||||
topPt: lengthToPt(h.marginTop)!, bottomPt: lengthToPt(h.marginBottom)!,
|
||||
}));
|
||||
const HEADING_ITALIC = HEADING_STYLE_OVERRIDES.map((h) => h.italic === true);
|
||||
const DEFAULT_FONTS = new Set(['times new roman', 'liberation serif']);
|
||||
// Headings render sans (HEADING_FONT); Word writes Arial, LibreOffice Liberation Sans.
|
||||
@@ -1123,8 +1127,17 @@ function convertParagraph(el: Element, ctx: Ctx, kind: BlockKind, boldByDefault:
|
||||
// unset spacing renders 0/0 (no word processor passes the default style's spacing
|
||||
// into a cell), and single line height is only kept over a non-single default.
|
||||
if (kind === 'cell') {
|
||||
if (attrs.spaceBefore === 0) delete attrs.spaceBefore;
|
||||
if (attrs.spaceAfter === 0) delete attrs.spaceAfter;
|
||||
// A heading is the other way round: no style name reaches a cell, so the editor
|
||||
// draws its level's own 12pt/6pt margins (styles/headings.ts) there — the chain's
|
||||
// silence is a real 0 and has to be written, or that pair lands in every heading a
|
||||
// cell holds. Word's own spacing at this point is the chain's, baked in above.
|
||||
if (level) {
|
||||
const hm = HEADING_MARGINS[level - 1];
|
||||
if (hm?.topPt) attrs.spaceBefore ??= 0;
|
||||
if (hm?.bottomPt) attrs.spaceAfter ??= 0;
|
||||
}
|
||||
if (attrs.spaceBefore === 0 && !level) delete attrs.spaceBefore;
|
||||
if (attrs.spaceAfter === 0 && !level) delete attrs.spaceAfter;
|
||||
const def = ctx.styles.paragraphSpacing(null);
|
||||
const defSingle = (def.line ?? 240) === 240 && (!def.lineRule || def.lineRule === 'auto');
|
||||
if (attrs.lineHeight === '1' && defSingle) delete attrs.lineHeight;
|
||||
|
||||
Reference in new issue
Block a user