Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions packages/layout-engine/contracts/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -990,6 +990,7 @@ export type SectionBreakBlock = {
gap: number;
widths?: number[];
equalWidth?: boolean;
lineBetween?: boolean;
};
/**
* Vertical alignment of content within the section's pages.
Expand Down Expand Up @@ -1478,6 +1479,7 @@ export type ColumnLayout = {
gap: number;
widths?: number[];
equalWidth?: boolean;
lineBetween?: boolean;
};

/** A measured line within a block, output by the measurer. */
Expand Down Expand Up @@ -1698,6 +1700,11 @@ export type Page = {
* where headers/footers don't affect vertical alignment.
*/
baseMargins?: { top: number; bottom: number };
/**
* Column layout for this page, if multi-column.
* Carried from the active section so the painter can render column separator lines.
*/
columns?: ColumnLayout;
/**
* Index of the section this page belongs to.
* Used for section-aware page numbering and header/footer selection.
Expand Down
4 changes: 4 additions & 0 deletions packages/layout-engine/layout-engine/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1071,6 +1071,10 @@ export function layoutDocument(blocks: FlowBlock[], measures: Measure[], options
bottom: activeSectionBaseBottomMargin,
};
}
// Carry column layout to the page for the painter (e.g. inter-column separator lines)
if (activeColumns && activeColumns.count > 1) {
page.columns = activeColumns;
Comment on lines +1075 to +1076
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge Preserve lineBetween when attaching columns to page

page.columns = activeColumns assumes the new lineBetween flag survives section-state cloning, but cloneColumnLayout currently drops that field (packages/layout-engine/contracts/src/column-layout.ts, function cloneColumnLayout). As a result, page.columns.lineBetween is typically undefined even when <w:cols w:sep="1"> is parsed, so the separator rendering path never activates. Please propagate lineBetween through the column clone/state pipeline before assigning it to the page.

Useful? React with 👍 / 👎.

}
return page;
};

Expand Down
39 changes: 39 additions & 0 deletions packages/layout-engine/painters/dom/src/renderer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2227,6 +2227,45 @@ export class DomPainter {
);
});
this.renderDecorationsForPage(el, page, pageIndex);

// Render vertical separator lines between columns when lineBetween is enabled
if (page.columns?.lineBetween && page.columns.count > 1 && page.margins && this.doc) {
const cols = page.columns;
Comment on lines +2231 to +2233
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge Draw column separators in the vertical rendering path

This separator logic was added only to renderPage, but the default vertical/non-book flow renders pages via fullRender/patchLayout/virtualization, which build DOM through createPageState instead of renderPage (same file). In those modes, separators are never created, so users in standard vertical mode won’t see the new line-between-columns feature. The separator rendering needs to be shared with or duplicated in the createPageState path.

Useful? React with 👍 / 👎.

const margins = page.margins;
const pageHeight = page.size?.h ?? height;
const contentTop = margins.top;
const contentBottom = pageHeight - margins.bottom;
const lineHeight = contentBottom - contentTop;

if (lineHeight > 0) {
const colWidths = Array.isArray(cols.widths) && cols.widths.length > 0 ? cols.widths : null;
for (let c = 0; c < cols.count - 1; c++) {
let lineX: number;
if (colWidths) {
let x = margins.left;
for (let j = 0; j <= c; j++) {
x += colWidths[j] ?? 0;
if (j < c) x += cols.gap;
}
lineX = x + cols.gap / 2;
} else {
const colWidth = (width - margins.left - margins.right - (cols.count - 1) * cols.gap) / cols.count;
lineX = margins.left + (c + 1) * colWidth + (c + 0.5) * cols.gap;
}

const line = this.doc.createElement('div');
line.style.position = 'absolute';
line.style.left = `${lineX}px`;
line.style.top = `${contentTop}px`;
line.style.width = '0px';
line.style.height = `${lineHeight}px`;
line.style.borderLeft = '1px solid #000';
line.style.pointerEvents = 'none';
el.appendChild(line);
}
}
}

return el;
}

Expand Down
8 changes: 7 additions & 1 deletion packages/layout-engine/pm-adapter/src/sections/extraction.ts
Original file line number Diff line number Diff line change
Expand Up @@ -211,7 +211,7 @@ function extractPageNumbering(elements: SectionElement[]):
*/
function extractColumns(
elements: SectionElement[],
): { count: number; gap: number; widths?: number[]; equalWidth?: boolean } | undefined {
): { count: number; gap: number; widths?: number[]; equalWidth?: boolean; lineBetween?: boolean } | undefined {
const cols = elements.find((el) => el?.name === 'w:cols');
if (!cols?.attributes) return undefined;

Expand All @@ -233,11 +233,17 @@ function extractColumns(
.filter((widthTwips) => Number.isFinite(widthTwips) && widthTwips > 0)
.map((widthTwips) => (widthTwips / 1440) * PX_PER_INCH);

const sepAttr = cols.attributes['w:sep'];
const hasSepChild = Array.isArray(cols.elements) && cols.elements.some((child) => child?.name === 'w:sep');
const lineBetween =
sepAttr === '1' || sepAttr === 1 || sepAttr === true || sepAttr === 'true' || hasSepChild ? true : undefined;

const result = {
count,
gap: gapInches * PX_PER_INCH,
...(widths.length > 0 ? { widths } : {}),
...(equalWidth !== undefined ? { equalWidth } : {}),
...(lineBetween !== undefined ? { lineBetween } : {}),
};

return result;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,17 @@ export function getSectPrColumns(sectPr) {
result.gap = twipsToInches(a['w:space']);
}

// w:sep = line between columns (attribute on w:cols)
if (a['w:sep'] === '1' || a['w:sep'] === 'true') {
result.lineBetween = true;
}

// Also check for w:sep child element (alternative OOXML form)
const sepChild = cols.elements?.find((el) => el?.name === 'w:sep');
if (sepChild) {
result.lineBetween = true;
}

return Object.keys(result).length > 0 ? result : undefined;
}

Expand Down
Loading