Skip to content

feat(painter-dom): render nested block content-control chrome#3756

Draft
caio-pizzol wants to merge 5 commits into
caio/it-1188-fu2-resolve-sdt-chainfrom
caio/it-1188-fu3-painter-chrome
Draft

feat(painter-dom): render nested block content-control chrome#3756
caio-pizzol wants to merge 5 commits into
caio/it-1188-fu2-resolve-sdt-chainfrom
caio/it-1188-fu3-painter-chrome

Conversation

@caio-pizzol

@caio-pizzol caio-pizzol commented Jun 18, 2026

Copy link
Copy Markdown
Contributor

Third step of #3752, stacked on #3755 - the painter slice that renders nested content-control chrome.

How it works: each fragment's nearest control is drawn as before (paragraph/table via the existing border path; image/drawing via an overlay, since they have no border path). computeSdtBoundaryLayers groups fragments per nesting depth, and renderFragment adds one non-interactive overlay (renderSdtAncestorLayers) per enclosing control, so an outer control keeps a continuous outline and label around inner controls. Edges are shared with the inner box by default (Word-like), tunable via --sd-sdt-layer-offset.

Covered:

  • Paragraph, table, image, and drawing all get nearest + ancestor chrome.
  • Ancestor labels are self-contained and visible (they don't depend on editor selection/hover state).
  • Overlays honor widthOverride for multi-fragment run width.
  • Drawing chrome host stays overflow: visible (content clipping moved to an inner wrapper) so an ancestor label above a drawing is not clipped.
  • The drawing render path now stamps the SDT dataset it was missing.

Tested (CI): computeSdtBoundaryLayers grouping (outer/inner, image/drawing continuity, label dedupe, single-key fallback) and renderSdtAncestorLayers DOM output (ancestor-only vs media-all-layers, start/end attrs, label, widthOverride, chrome-none, hidden-appearance) via jsdom. Type-checks and prettier clean locally.

Needs visual QA before #3745 closes: this slice is fundamentally visual and not yet confirmed in a browser. Compare the nested "Item 8.1 / Item 8.2" region against Word: outer outline continuous around the inner table/section, both control labels visible at their region tops, no split or duplicate-suppressed label, drawing/image inside a control boxed correctly.

Remaining FU3 wiring (after the visual approach is confirmed): the patch/diff render path and a layer-aware shouldRebuildForSdtBoundary, so overlays update on incremental edits, not just full render.

Scope guard (FU4, not here): snapshot, dataset-chain consumers, selection/entity association, table ancestor cleanup, singular containerSdt migration.

Stacked on #3755 - retarget as the stack merges. Refs #3745.

Add computeSdtBoundaryLayers, which reads each resolved item's sdtContainerKeys
chain and groups contiguous items per nesting depth: an outer control spanning
[outer], [outer, inner], [outer] is one run at depth 0 and the inner control is
a run at depth 1. Image/drawing items that carry the chain stay in the run;
labels dedupe by key; falls back to the single sdtContainerKey for non-nested
content. Additive - the existing flat computeSdtBoundaries is unchanged.
Renderer wiring, image/drawing chrome, and layered CSS follow in this PR.

Refs #3745
…overlays

Wire computeSdtBoundaryLayers into the initial page render: each fragment's
nearest control is still drawn by the existing border path, and renderFragment
now adds one non-interactive overlay per ANCESTOR control (renderSdtAncestorLayers)
so an outer control keeps a continuous outline and label around inner controls.
Edges are shared by default (Word-like), tunable via --sd-sdt-layer-offset. Also
stamps the previously-missing SDT dataset on the drawing render path.

Scope: initial render path only. The patch/diff render path and the
shouldRebuildForSdtBoundary layer signature are the remaining FU3 wiring. Needs
visual QA on the nested fixture before #3745 closes.

Refs #3745
…, clipping

Address four gaps in the ancestor-overlay chrome:
- Image/drawing draw their nearest control too (renderFragment passes
  nearestDrawnByHost=false; they have no border path, so every layer is an overlay).
- Ancestor label is self-contained and visible (the nearest label class gates
  visibility on editor selection/hover state the overlay never has).
- Ancestor overlays honor widthOverride for multi-fragment run width.
- Drawing chrome host stays overflow:visible; content clipping moves to an inner
  wrapper, so an ancestor label above a drawing is not clipped.

Refs #3745
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant