feat(ui): preview the dark styles an email defines - #3712
Open
creativoma wants to merge 4 commits into
Open
Conversation
`tsc --build` writes a .tsbuildinfo next to the tsconfig that produced it, which was showing up as an untracked file under apps/web.
The preview's dark mode toggle emulated forced color inversion, the way clients that ignore `prefers-color-scheme` recolor a light theme. Clients that honor it instead render whatever dark theme the email authored, and that half had no representation: an email shipping real `@media (prefers-color-scheme: dark)` rules could not be previewed at all. Split the control in two so both behaviors are reachable, and add `forceColorScheme`, which decides which of the email's color scheme rules apply rather than leaving it to the machine the preview runs on. Setting `color-scheme` on the frame covers this wherever the browser propagates it into the embedded document, but that is Firefox 105+ and Chromium 129+ only — Safari does not ship it yet. Where it is missing, every `prefers-color-scheme` condition has its value flipped, turning the queries the reader's setting matches into the ones it doesn't. Only the leaf value changes, so the browser still evaluates the surrounding operators and the query list. This also settles a case the toggle got wrong before: with dark mode off, an email's dark rules matched whenever the reader's own OS was set to dark, and the inversion emulation then recolored an already-dark theme. Only the live CSSOM is touched, never the `<style>` elements' text, so the markup shown in the source view stays the email as authored.
The color inversion only recolors values it finds inline, so it gives `<body>` the colors it already renders at to have something to invert. Those were recorded alongside the ones the email really declared, and so were written back when the inversion was undone, leaving an email that never painted a background of its own with a white one for as long as the frame lived. It went unnoticed while the toggle had two states, since turning dark mode off meant a white page anyway. Under the mode that renders an email's own dark theme it shows as a white page behind a dark email. Mark the properties the inversion adds so undoing removes them, and keep restoring the ones the email authored.
Contributor
|
@creativoma is attempting to deploy a commit to the resend Team on Vercel. A member of the Team first needs to authorize it. |
🦋 Changeset detectedLatest commit: 6fbc48f The changes in this PR will be included in the next version bump. This PR includes changesets to release 3 packages
Not sure what this means? Click here to learn what changesets are. Click here if you're a maintainer who wants to add another changeset to this PR |
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.
Closes #3707. Implements the proposal in #3609.
Problem
The preview's dark mode toggle emulates forced color inversion — what Gmail and Outlook.com do to a light theme. Clients that honor
prefers-color-scheme, such as Apple Mail and Outlook for Mac, instead render whatever dark theme the email authored, and that behavior had no representation in the preview.Because the inversion walks the DOM recoloring inline styles, it never evaluates a media query. An email shipping real
@media (prefers-color-scheme: dark)rules — which includes anything using Tailwind'sdark:variants — could not be previewed at all.Changes
The single toggle becomes two, so both client behaviors are reachable and each is labelled for what it does:
prefers-color-scheme(Gmail, Outlook.com)The existing
?darksearch param keeps meaning color inversion, so links written before this change resolve the same way.How the scheme is applied
Setting
color-schemeon the frame is enough wherever the browser propagates it into the embedded document, and there the email's own rules match untouched. That propagation is Firefox 105+ and Chromium 129+ only; Safari does not ship it yet (it landed in Safari Technology Preview 242). Left at that, an email would render one way on Chrome and another on Safari.So where the browser does not do it,
forceColorSchemeflips the value of everyprefers-color-schemecondition, turning the queries the reader's real setting matches into the ones it doesn't. Only the leaf value changes, so the browser still evaluates the surroundingand/or/notand the comma-separated query list. Rules keep their position in the cascade, andprefers-color-scheme: lightblocks are handled alongside the dark ones. Only the live CSSOM is touched, never the<style>elements' text, so the source view still shows the email as authored.Fixes along the way
<body>the colors it already renders at so it has something to invert; those were being written back as though the email had authored them.Testing
36 unit tests covering the condition rewriting, the URL state, and
syncDarkModeagainst a real frame.Verified end to end in Chromium 147, Chrome 151 and WebKit 26.4, across all three modes with the OS set to light and to dark — including the non-propagating path that Safari takes today.
Out of scope
Color inversion still only recolors inline styles; rules in a
<style>block are not inverted. That is unchanged behavior and separate from what this PR addresses.Summary by cubic
Adds a native dark‑mode preview and splits the dark‑mode control into two modes so both client behaviors are covered. Previously the preview only inverted a light theme; now it can render authored dark styles, avoids inheriting the reader’s OS setting, and removes seeded colors when exiting inversion.
EmulatedDarkModeTogglewithDarkModeToggleGroupexposing two options: “Emulated color inversion” and “Dark styles defined by the email.”forceColorSchemeandsyncDarkModeto decide whichprefers-color-schemerules apply, mirrorcolor-schemeto the iframe root, and flip media queries where browsers don’t propagatecolor-scheme(e.g., Safari).<body>colors are dropped, preventing a white background on emails that never set one.Rollout
?darkstill selects emulated inversion. Use?dark=nativefor native dark styles; omitdarkto turn dark mode off.Written for commit 6fbc48f. Summary will update on new commits.