feat: support paragraph bar borders#2736
Conversation
caio-pizzol
left a comment
There was a problem hiding this comment.
@iguit0 nice work — the bar rendering is the best of the three apps we tested. Word ignores bar borders entirely, Google Docs renders them but loses the color, SuperDoc gets it right.
one thing to look at: both Word and Google Docs ignore bar when deciding whether to group paragraphs together. right now SuperDoc breaks the group when bars differ, but the other two don't. left an inline comment with more detail.
couple of small cleanup suggestions in the other comments. tests look good.
| if (borders.right) parts.push(`r:[${hashParagraphBorder(borders.right)}]`); | ||
| if (borders.bottom) parts.push(`b:[${hashParagraphBorder(borders.bottom)}]`); | ||
| if (borders.left) parts.push(`l:[${hashParagraphBorder(borders.left)}]`); | ||
| if (borders.bar) parts.push(`bar:[${hashParagraphBorder(borders.bar)}]`); |
There was a problem hiding this comment.
we tested this file in Word and Google Docs — both still group paragraphs together even when their bar borders are different. including bar here breaks that grouping in SuperDoc. the bar should still trigger a re-render when it changes, but it shouldn't affect whether paragraphs are grouped for between borders. worth splitting those two?
There was a problem hiding this comment.
Fixed! Removed bar from this hash (grouping) and the layout-engine's local hashBorders. The layout-bridge copy keeps bar for cache invalidation, so there's now an intentional divergence between the two copies. Added a comment explaining why.
Fixed the grouping behavior: |
Codecov Report✅ All modified and coverable lines are covered by tests. 📢 Thoughts on this report? Let us know! |
|
Hey @iguit0, thanks for the work — the code and tests are solid. I tested the doc in Word and Word never draws these bars. It keeps them in the file on save but doesn't show them on screen. The spec says apps can skip them, and Word does. SuperDoc today doesn't draw them either, so main already matches Word. This PR would be the one thing that starts drawing them. Suggest closing for now. If a real doc needs bars drawn later, we can revisit with that context. If you have a doc in mind, share it and I'll take another look. Thank you for all the work still! We can add it in the future if relevant |
Summary
Adds support for Word paragraph bar borders (
w:pBdr/w:bar) in the layout/rendering pipeline.w:baris the vertical decorative line rendered on the left edge of a paragraph. It was already parsed upstream, but it never made it through the layout-engine path, so it could not render in DomPainter.Root cause
w:barwas being dropped innormalizeParagraphBorders()inside the pm-adapter layer.Because of that:
ParagraphBordersdid not exposebarbarbarbardata to renderWhat changed
Contracts
bar?: ParagraphBordertopackages/layout-engine/contracts/src/index.tsPM adapter
normalizeParagraphBorders()to preservebarbetweenspecial-case behavior scoped tobetweenonlybarnow normalizes like the other paragraph border sides:spacesupportHashing / invalidation / grouping
Updated the paragraph-border identity paths so bar-only changes are treated as real visual changes:
packages/layout-engine/layout-bridge/src/paragraph-hash-utils.tspackages/layout-engine/painters/dom/src/paragraph-hash-utils.tspackages/layout-engine/layout-bridge/src/diff.tspackages/layout-engine/layout-engine/src/layout-paragraph.tsThis ensures:
barchangesbardo not incorrectly group forbetweenrenderingDomPainter rendering
barrendering inpackages/layout-engine/painters/dom/src/features/paragraph-borders/border-layer.tsbaras a separate absolutely-positioned vertical rule on the left side of the paragraph border boxbarindependent from the normalleftborder so both can coexistbetweenbehaviorImplementation detail:
baris rendered as a dedicated child decoration element attached to the existing paragraph border layerbar.spacestyle,width, andcolorvaluesTest plan
.docxwith a paragraph using onlyw:bar; verify a left-side vertical bar renders..docxwith bothw:leftandw:bar; verify both render independently.w:bar+ paragraph shading renders correctly and the bar stays visible.between.barno longer group.baris a separate decoration element with pointer events disabled.Closes #2282