fix(ios): code block background border radius#411
Open
eszlamczyk wants to merge 6 commits into
Open
Conversation
eszlamczyk
commented
Jun 22, 2026
Collaborator
Author
There was a problem hiding this comment.
Nice, looks like some test also got fixed up
There was a problem hiding this comment.
Pull request overview
This PR fixes an iOS rendering edge case where the bottom rounded corners (and sometimes bottom padding) of a codeBlock background could be clipped depending on line count and padding, by ensuring the code block’s bottom padding spacer is laid out inside iOS’s normal text tiles rather than relying on background-rect compensation.
Changes:
- Added
isLastBlockACodeBlockto detect a trailing code block while ignoring trailing newline spacers. - Updated
removeTrailingSpacingto preserve the code block bottom padding spacer and keep a single trailing “tail” newline outside the code block range so iOS includes the padding spacer inusedRect/tiling.
Reviewed changes
Copilot reviewed 2 out of 7 changed files in this pull request and generated 3 comments.
| File | Description |
|---|---|
| packages/react-native-enriched-markdown/ios/utils/LastElementUtils.h | Adds a new helper for identifying when the last semantic block is a code block despite trailing spacer newlines. |
| packages/react-native-enriched-markdown/ios/renderer/AttributedRenderer.m | Adjusts trailing-trim logic to keep a non-code-block tail newline after code blocks to avoid iOS background clipping/tiling issues. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
Comment on lines
+132
to
+137
| NSParagraphStyle *style = [output attribute:NSParagraphStyleAttributeName atIndex:tailIdx effectiveRange:NULL]; | ||
| NSMutableParagraphStyle *mutableStyle = style ? [style mutableCopy] : [[NSMutableParagraphStyle alloc] init]; | ||
| mutableStyle.paragraphSpacing = 0; | ||
| mutableStyle.paragraphSpacingBefore = 0; | ||
| [output addAttribute:NSParagraphStyleAttributeName value:mutableStyle range:NSMakeRange(tailIdx, 1)]; | ||
| } |
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.
What/Why?
On iOS, the bottom rounded corner of a
codeBlockbackground would intermittently render as a square, depending on the exact number of lines and thepaddingvalue - and the visible bottom padding inside the block would sometimes collapse to ~0pt. Both symptoms had the same root cause.The renderer emits a "bottom padding spacer"
\n(paragraph style withminLineHeight = padding) at the end of every code block. Before this fix,removeTrailingSpacingwould treat any trailing\nafter the last visible character as deletable, so the bottom padding spacer got removed along with thecodeBlockMarginBottomspacer when the code block was the last element in the document.CodeBlockBackgroundthen compensated by extending the painted rect bycodeBlockPadding, but iOS dispatchesdrawBackgroundForGlyphRange:in ~128pt tiles clipped to the laid-out content area. When the compensated rect crossed the next tile boundary, the bottom rounded corner fell outside every tile's clip and got sliced off - toggling visibly with each line added or removed.The fix preserves the bottom padding spacer and keeps a single 1pt-tall tail
\nimmediately after it. With a non-padding\nas the trailing paragraph terminator, iOS lays the bottom padding spacer out as a normal interior line fragment (included inusedRect/boundingRectForGlyphRange:/ the drawing tiles), so no rect extension is needed and the corner is always inside the clip. The tail'sCodeBlockAttributeis stripped and itsparagraphSpacingzeroed so it neither extends the background nor introduces a visible margin.Testing
It is decently hard to test on playground, so the easiest way to verify the fix is to reproduce this:
Replace App.tsx with this
keep adding
// one more lineor changemarkdownStyleTested on IOS 26.3 (Iphone 17 pro) and IOS 18.6 (Iphone 16 Plus) simulators
Screenshots
All screenshots were made with
borderRadius: 12PR Checklist
closes #354