-
Notifications
You must be signed in to change notification settings - Fork 69
fix(layout): per-section footer constraints for multi-section docs (SD-1837) #2022
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -174,6 +174,41 @@ function resolveTableFrame( | |
| return applyTableIndent(baseX, width, tableIndent); | ||
| } | ||
|
|
||
| /** | ||
| * Rescales column widths when a table is clamped to fit a narrower section. | ||
| * | ||
| * In mixed-orientation documents, tables are measured at the widest section's | ||
| * content width but may render in narrower sections. When the measured total | ||
| * width exceeds the fragment width, column widths must be proportionally | ||
| * rescaled so cells don't overflow the fragment container (SD-1859). | ||
| * | ||
| * @returns Rescaled column widths if clamping occurred, undefined otherwise. | ||
| */ | ||
| function rescaleColumnWidths( | ||
| measureColumnWidths: number[] | undefined, | ||
| measureTotalWidth: number, | ||
| fragmentWidth: number, | ||
| ): number[] | undefined { | ||
| if (!measureColumnWidths || measureColumnWidths.length === 0) { | ||
| return undefined; | ||
| } | ||
| // When the table fits within the fragment, return original widths unchanged. | ||
| // This ensures every table fragment is self-contained with its own column widths, | ||
| // which is critical for header/footer tables where multiple sections share the same | ||
| // blockId but have different content widths (SD-1837). | ||
| if (measureTotalWidth <= fragmentWidth || measureTotalWidth <= 0) { | ||
| return measureColumnWidths; | ||
| } | ||
| const scale = fragmentWidth / measureTotalWidth; | ||
| const scaled = measureColumnWidths.map((w) => Math.max(1, Math.round(w * scale))); | ||
| const scaledSum = scaled.reduce((a, b) => a + b, 0); | ||
| const target = Math.round(fragmentWidth); | ||
| if (scaledSum !== target && scaled.length > 0) { | ||
| scaled[scaled.length - 1] = Math.max(1, scaled[scaled.length - 1] + (target - scaledSum)); | ||
| } | ||
| return scaled; | ||
| } | ||
|
|
||
| /** | ||
| * Calculate minimum width for a table column. | ||
| * | ||
|
|
@@ -986,6 +1021,7 @@ function layoutMonolithicTable(context: TableLayoutContext): void { | |
| y: state.cursorY, | ||
| width, | ||
| height, | ||
| columnWidths: rescaleColumnWidths(context.measure.columnWidths, context.measure.totalWidth, width), | ||
| metadata, | ||
| }; | ||
| applyTableFragmentPmRange(fragment, context.block, context.measure); | ||
|
|
@@ -1133,6 +1169,7 @@ export function layoutTableBlock({ | |
| y: state.cursorY, | ||
| width, | ||
| height, | ||
| columnWidths: rescaleColumnWidths(measure.columnWidths, measure.totalWidth, width), | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
This writes resized widths into Useful? React with 👍 / 👎. |
||
| metadata, | ||
| }; | ||
| applyTableFragmentPmRange(fragment, block, measure); | ||
|
|
@@ -1219,6 +1256,7 @@ export function layoutTableBlock({ | |
| continuesOnNext: hasRemainingLinesAfterContinuation || rowIndex + 1 < block.rows.length, | ||
| repeatHeaderCount, | ||
| partialRow: continuationPartialRow, | ||
| columnWidths: rescaleColumnWidths(measure.columnWidths, measure.totalWidth, width), | ||
| metadata: generateFragmentMetadata(measure, rowIndex, rowIndex + 1, repeatHeaderCount), | ||
| }; | ||
|
|
||
|
|
@@ -1282,6 +1320,7 @@ export function layoutTableBlock({ | |
| continuesOnNext: !forcedPartialRow.isLastPart || forcedEndRow < block.rows.length, | ||
| repeatHeaderCount, | ||
| partialRow: forcedPartialRow, | ||
| columnWidths: rescaleColumnWidths(measure.columnWidths, measure.totalWidth, width), | ||
| metadata: generateFragmentMetadata(measure, bodyStartRow, forcedEndRow, repeatHeaderCount), | ||
| }; | ||
|
|
||
|
|
@@ -1323,6 +1362,7 @@ export function layoutTableBlock({ | |
| continuesOnNext: endRow < block.rows.length || (partialRow ? !partialRow.isLastPart : false), | ||
| repeatHeaderCount, | ||
| partialRow: partialRow || undefined, | ||
| columnWidths: rescaleColumnWidths(measure.columnWidths, measure.totalWidth, width), | ||
| metadata: generateFragmentMetadata(measure, bodyStartRow, endRow, repeatHeaderCount), | ||
| }; | ||
|
|
||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The JSDoc says this helper returns “Rescaled column widths if clamping occurred, undefined otherwise,” but the implementation returns the original
measureColumnWidthswhen the table fits. Either update the docstring to reflect the actual behavior (always returns widths when available) or change the implementation to returnundefinedwhen no rescaling occurs—whichever the callers expect.