Operand

do no harem.

gram: docs

> ./packages/core/src/layout-bridge/cellBlockLayout.ts

/**
* Vertical layout of a table cell's stacked blocks.
*
* Single source of truth for *where the lines of a cell's content sit*, used by
* the row-break paginator (`tableRowBreak`), the selection-rect mapper
* (`selectionRects`), and — by construction — matching what the painter
* (`renderCellContent`) renders. Adjacent paragraphs' before/after spacing
* collapses to the larger of the two (CSS margin-collapse / the body
* paginator's rule); a paragraph's lines stack from its content top with no
* before/after between them. Keeping these consumers on one model is what
* prevents page breaks and selection highlights from drifting off the rendered
* lines.
*/
import type { FlowBlock, Measure } from '../layout-engine/types';
export interface CellContentLayout {
/** Per block, the top y of each line (relative to `startY`). Atomic/non-paragraph blocks → []. */
lineTops: number[][];
/**
* All line bottoms in document order, plus one entry per atomic block (its
* bottom) — the clean break points for the paginator.
*/
flatBottoms: number[];
/** Total stacked height incl. the last block's trailing space-after. */
contentHeight: number;
}
/**
* Compute the collapsed vertical layout of a cell's blocks starting at `startY`.
*/
export function layoutCellContent(
blocks: readonly FlowBlock[] | undefined,
blockMeasures: readonly Measure[] | undefined,
startY: number
): CellContentLayout {
const lineTops: number[][] = [];
const flatBottoms: number[] = [];
let y = startY;
let prevAfter = 0;
const n = blockMeasures?.length ?? 0;
for (let i = 0; i < n; i++) {
const measure = blockMeasures![i];
const block = blocks?.[i];
if (block?.kind === 'paragraph' && measure?.kind === 'paragraph') {
const spacing = block.attrs?.spacing;
y += Math.max(prevAfter, spacing?.before ?? 0);
const tops: number[] = [];
for (const line of measure.lines) {
y += line.floatSkipBefore ?? 0;
tops.push(y);
y += line.lineHeight;
flatBottoms.push(y);
}
lineTops.push(tops);
prevAfter = spacing?.after ?? 0;
} else if (measure && 'totalHeight' in measure && typeof measure.totalHeight === 'number') {
// Nested table / non-paragraph: one atomic block (break only at its bottom).
y += prevAfter + measure.totalHeight;
lineTops.push([]);
flatBottoms.push(y);
prevAfter = 0;
} else {
lineTops.push([]);
}
}
// The painter renders the final block's trailing space-after as paddingBottom.
return { lineTops, flatBottoms, contentHeight: y - startY + prevAfter };
}