refactor(painters/dom): unify SDT container rendering (SD-2838)#3322
Merged
harbournick merged 38 commits intoMay 26, 2026
Merged
Conversation
luccas-harbour
force-pushed
the
luccas/sd-2838-unify-sdt-rendering
branch
from
May 15, 2026 19:52
8f91a95 to
1ce01ee
Compare
luccas-harbour
requested review from
tupizz
and removed request for
a team and
caio-pizzol
May 20, 2026 18:45
VladaHarbour
approved these changes
May 21, 2026
VladaHarbour
left a comment
Contributor
There was a problem hiding this comment.
Just a minor suggestion
Approve
luccas-harbour
force-pushed
the
luccas/sd-2838-unify-sdt-rendering
branch
2 times, most recently
from
May 21, 2026 19:07
9c587c2 to
6308dac
Compare
…odule Move sdt-helpers from utils/ into a dedicated sdt/container.ts module and rename applySdtContainerStyling → applySdtContainerChrome. Introduce shouldRenderSdtContainerChrome, getSdtContainerKeyForBlock, and getSdtSiblingBoundaries so renderer.ts and renderTableCell.ts can share the same boundary/suppression logic instead of inlining metadata comparisons. Table cells now receive an ancestorTableSdtKey rather than the raw tableSdt object, making the duplicate-suppression contract explicit and key-based.
Move SDT boundary computation, dataset application, snapshot collection, and inline wrapper helpers out of renderer.ts into dedicated modules under sdt/. Renames runs/sdt.ts to sdt/inline.ts and re-exports remain stable. No behavior change.
Extract image <img> element creation, clip-path resolution, and hyperlink-anchor wrapping into shared helpers under `painters/dom/src/images/`, and route the renderer's block/drawing image paths plus renderTableCell's flowing, drawing, and anchored image paths through them. Eliminates five near-identical copies of the same img setup (objectFit, cover→left-top, clip-path, filters, hyperlink wrap) so behavior stays consistent across all image surfaces. Adds coverage for clip-path, filters, and hyperlinks on both flowing and anchored images inside table cells (SD-2838).
Removes the now-dead deriveBlockVersion machinery from renderer.ts (paragraph/image/drawing/table version hashing, SDT metadata helpers, list-marker guards) along with renderedBlockImageVersion in image-block.ts. No remaining call sites consume these helpers after the image-block rendering unification.
Move image fragment and drawing image creation out of renderer.ts into dedicated modules under images/. Renderer now delegates: - renderImageFragment → images/image-fragment.ts (with the buildImageGeometryTransform / applyImageGeometryTransform helpers it owned) - createDrawingImageElement, createShapeGroupImageElement, and the inline shape-text image element creation → images/drawing-image.ts No behavior change — pure extraction. Trims ~157 lines from renderer.ts.
Move image-clip-path and image-selectors (plus their tests) from utils/ into the images/ directory alongside image-block, drawing-image, hyperlink, and image-fragment. Update import paths in callers. No behavior change.
Updates the comment to reflect that the painter-dom copy has been removed — this is now the single source of truth, not a duplicate to keep in sync.
luccas-harbour
force-pushed
the
luccas/sd-2838-unify-paragraph-rendering
branch
from
May 22, 2026 18:49
3572c77 to
5e1e81b
Compare
luccas-harbour
force-pushed
the
luccas/sd-2838-unify-sdt-rendering
branch
from
May 22, 2026 18:49
6308dac to
01c2e2f
Compare
Contributor
Agent docs auditFound deterministic findings on 1 changed agent-doc item(s).
|
Contributor
Author
|
The broken paths in AGENTS.md were fixed in the top-most PR in this commit. |
…-block-rendering refactor(painters/dom): unify image block rendering (SD-2838)
harbournick
merged commit May 26, 2026
e01b30e
into
luccas/sd-2838-unify-paragraph-rendering
6 checks passed
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Consolidates SDT (Structured Document Tag) container rendering across paragraphs, tables, and nested tables into a single shared module, then fixes a long tail of nested/split-fragment chrome bugs that the unified pipeline made tractable.
Previously, the duplicate-suppression contract was implicit: cells were handed a raw
tableSdtreference and each renderer reimplemented its own metadata comparisons. With nested tables, idless SDT controls, and split fragments, this produced missing borders, duplicated chrome, clipped labels, and chrome that disappeared across page splits. The new pipeline uses a key-based ancestor chain and an upward chrome-rendered callback, so every renderer (paragraph, table fragment, table cell, embedded table) makes the same decisions from the same data.Changes
New shared module —
painters/dom/src/sdt/container.ts(replacesutils/sdt-helpers.ts)applySdtContainerStyling→applySdtContainerChromeshouldRenderSdtContainerChrome,getSdtContainerKeyForBlock,getSdtSiblingBoundariesSdtAncestorOptionstype —ancestorContainerKey(s)+ancestorContainerSdt(s)chains for explicit suppressionContracts (
contracts/src/sdt-container.ts) — new filegetSdtContainerKey,getSdtContainerMetadata,hasExplicitSdtContainerKey,isSdtContainerMetadatalayout-resolveddrops the localsdtContainerKey.tsand imports from contracts (single source of truth)idlessSdtContainerKeysWeakMap groups id-less sibling controls by identity, with anAIDEV-NOTEexplaining why alias/title matching is unsafeRenderer threading
renderTableFragment,renderTableRow,renderTableCell,renderEmbeddedTable, andrenderParagraphContentall accept theancestorContainerKey(s)/ancestorContainerSdt(s)chain and anonSdtContainerChromecallbackoverflow: visibleonly when a descendant actually renders chrome, not preemptively based on metadatasdtBoundarystart/end flags are now correctly narrowed at split points (paragraph mid-line splits, embedded table mid-row splits)Nested + split-fragment fixes (each is its own commit)
Tests
contracts/src/sdt-container.test.ts(42 lines) andpainters/dom/src/sdt/container.test.ts(200 lines)renderTableCell.test.tsexpanded with ~1.2k lines covering nested SDT casesrenderTableFragment.test.tsadds ~195 lines for ancestor/chrome-callback wiring