Fix pasted text colors and Windows line spacing - #2796
Open
Mylosis wants to merge 4 commits into
Open
Conversation
The white-space: pre-wrap conversion lived in the shared parseHtml, so it ran for every convertFromHTML call, including draft loading, templates and ordinary quoted blocks, rather than only pasted clipboard HTML. Ordinary blockquote and .gmail_quote content are normal Slate blocks, so an edited draft could be reserialized with newly inserted <br> elements outside any paste. No reproducible clipboard payload demonstrates the newline failure it was meant to fix, so it is removed here rather than rescoped. Color specs now assert on the specific rejected value instead of the substring "color", which would have passed even if mark handling broke entirely. They also cover the near-black threshold and a value just outside it, alpha handling, transparent, and that dropping a neutral foreground leaves the source font family intact.
Mylosis
marked this pull request as ready for review
August 14, 2026 12:04
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
Problem
Mailspring's plain and rich paste paths can fail in opposite ways.
For plain paste on Windows, Slate's plain-text serializer splits input on
\nwithout first normalizing CRLF. This leaves a trailing\rin each block. A blank line becomes a block containing only\r, and Mailspring's existing HTML serialization workaround converts that block to . The composer can visually compress this structure, while receiving clients render the placeholder blocks at full height, producing recipient-side spacing that does not match the composition view.For rich paste, source pages using a dark color scheme can put their default near-white text color on the clipboard. Mailspring preserves that foreground color but not the page background, so the sent message can become unreadable in a light mail client. The inverse can happen when near-black defaults cross into a dark presentation.
Implementation
Plain paste is handled explicitly at the composer ingress: CRLF and lone CR are normalized to LF, then the existing Slate plain serializer is used with the current block and marks. This keeps blank lines as genuinely empty Slate blocks instead of
\rblocks.Color filtering treats a color as an inherited page default only when it is nearly neutral, meaning its lightest and darkest RGB channels differ by no more than 12, and it also sits at or below roughly
#202020or at or above roughly#dfdfdf. Namedblack,white, andtransparentare included. Saturated colors and mid-range greys are left alone, so#333and#dddboth survive.This is an intentional readability policy rather than a reliable distinction between inherited and deliberate colors. Mailspring has no background-color mark and block deserialization keeps only
className, so a copied dark background never survives conversion. Preserving a near-white foreground therefore already produces unreadable output on a light message background, and dropping it restores readable inherited text.Two behavior changes are worth calling out, and both are covered by specs:
rgbavalues are classified from their RGB channels alone.transparentwas previously preserved and is now dropped, which makes invisible pasted text visible rather than sending it hidden.Validation
npx tsc -p app/tsconfig.json --noEmitCtrl+Shift+V, and Paste and Match Style placeholder blocks from the plain and match-style sections, and a repeated near-white source text color in the rich-paste section placeholder blocks, while elements inside quoted history from the earlier message were left untouchedThe post-change message was not a controlled comparison of the same clipboard payload, so the color behavior is pinned by the regression specs rather than by that sample. The specs cover both thresholds, a value just outside the near-black threshold, alpha,
transparent, and that dropping a neutral foreground leaves the source font family intact.No message bodies or account data are included in the tests or this PR.
Removed from this branch
An earlier revision also converted literal newlines beneath
white-space: pre-wrapinto<br>elements. That change lived in the sharedparseHtml, so it ran for everyconvertFromHTMLcall, including draft loading, templates and ordinary quoted blocks, rather than only pasted clipboard HTML. Ordinaryblockquoteand.gmail_quotecontent are normal Slate blocks, so an edited draft could be reserialized with newly inserted<br>elements well outside any paste.I also have no reproducible clipboard payload that demonstrates the newline failure it was meant to fix. It has been removed rather than rescoped. If a payload turns up, it should get its own PR, applied to pasted rich HTML only, after
InlineStyleTransformer.runSync()and immediately beforeconvertFromHTML(), with its own tests.