fix: pagination measures the flow, not the paint correction
A block spaced above single is drawn half a leading above where it flows, and offsetTop reports the drawn position — so every block a break pushed to a page top landed that half low. Take the shift back off where the document is measured.
This commit is contained in:
1 parent
12f2e7a623
commit
3f6b64cd95
2 files changed
+7
-2
No files matched your search
@@ -20,7 +20,7 @@ Five topics are large enough to have their own deep-dive — read the file befor
|
||||
|
||||
- **`fontColor.ts`** (`FontColor`) — `color` attr on the TextStyle mark; also emits `data-color` so theme CSS (allBlack) can target color-bearing spans.
|
||||
- **`fontWeight.ts`** (`FontWeight`) — `fontWeight` attr on TextStyle (set `normal` to un-bold a heading without changing the node type).
|
||||
- **`lineHeight.ts`** (`LineHeight`) — `lineHeight` attr on paragraph/heading. `LINE_HEIGHT_RATIO = 1.15`: ODF line spacing multiplies the font's *natural* line height (Liberation Serif ≈1.15× em), CSS multiplies the font size — so the on-screen value is scaled to match what LibreOffice renders. A spacing above single puts **all** of its extra leading below each line (probed: at 150% LibreOffice starts line 1 flush under the block above and adds 6.9pt after every line, the last included); CSS half-leads it, so `editor.css` shifts the block up by that half with `position:relative; top:` — flow, and so pagination, unchanged.
|
||||
- **`lineHeight.ts`** (`LineHeight`) — `lineHeight` attr on paragraph/heading. `LINE_HEIGHT_RATIO = 1.15`: ODF line spacing multiplies the font's *natural* line height (Liberation Serif ≈1.15× em), CSS multiplies the font size — so the on-screen value is scaled to match what LibreOffice renders. A spacing above single puts **all** of its extra leading below each line (probed: at 150% LibreOffice starts line 1 flush under the block above and adds 6.9pt after every line, the last included); CSS half-leads it, so `editor.css` shifts the block up by that half with `position:relative; top:`, which leaves the flow alone — but **`offsetTop` reports the drawn position, not the flow one**, so `pageBreaks.ts` (`topWithin`) takes the shift back off; without that a block pushed to a page top landed half a leading low.
|
||||
- **`paragraphSpacing.ts`** (`ParagraphSpacing`) — `spaceBefore`/`spaceAfter` in **pt**, round-tripping 1:1 to `fo:margin-top`/`fo:margin-bottom`. Space after is a margin, space before rides `--space-before` (`storage/spacingModel.ts` decides padding vs margin); pageBreaks.ts drops it where a page break put the block at a page top, as LibreOffice does.
|
||||
- **`blockFontSize.ts`** — the font of the paragraph mark (Word `w:pPr/w:rPr`, ODF the paragraph's own text properties).
|
||||
- **`pageBreak.ts`** — the text-flow attrs of a paragraph/heading: `breakBefore: 'page'`, plus `keepNext`/`keepLines` (see `docs/architecture/pagination.md`). Owns `Mod-Enter`.
|
||||
|
||||
@@ -627,7 +627,12 @@ export const PageBreaks = Extension.create({
|
||||
let top = 0;
|
||||
let node: HTMLElement | null = el;
|
||||
while (node && node !== dom) {
|
||||
top += node.offsetTop;
|
||||
// A block spaced above single is drawn half a leading above its flow
|
||||
// position (editor.css), and offsetTop reports where it is drawn — so the
|
||||
// shift comes back off, or the flow inherits a paint correction.
|
||||
const cs = getComputedStyle(node);
|
||||
const shift = cs.position === 'relative' ? parseFloat(cs.top) : 0;
|
||||
top += node.offsetTop - (Number.isFinite(shift) ? shift : 0);
|
||||
node = node.offsetParent as HTMLElement | null;
|
||||
}
|
||||
return top;
|
||||
|
||||
Reference in new issue
Block a user