feat(plugins): inject host theme variables into plugin iframes#204
Open
Vinyl-Davyl wants to merge 1 commit intoNetflix:masterfrom
Open
feat(plugins): inject host theme variables into plugin iframes#204Vinyl-Davyl wants to merge 1 commit intoNetflix:masterfrom
Vinyl-Davyl wants to merge 1 commit intoNetflix:masterfrom
Conversation
Author
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.
Requirements for a pull request
Description of the Change
Resolves the
// TODO: ADD VARIABLEScomment insrc/components/Plugins/PluginSlot.tsx.When a plugin sets
useApplicationStyles: true, the existing implementation injectsPLUGIN_STYLESHEET(the bundledtheme.csstext) into the iframe's<head>. However::rootthat overrides--color-bg-primary(the pattern that the in-flight dark-mode work in feat: theming, UI polish and dark mode integrations (#157) #190 will use), the iframe still sees the light default.This PR is a standalone fix for the
// TODO: ADD VARIABLESgap and does not depend on #190 being merged — but it is the missing piece that lets future runtime theme switches (including dark mode, once #190 lands) actually reach plugin iframes.Changes
src/components/Plugins/PluginSlot.tsxgetThemeCSSVariableshelper that walks accessible stylesheets, collects every--*custom property declared on:root/html, and resolves each to its currently computed value viagetComputedStyle(document.documentElement)— returning a:root { ... }CSS string. Cross-origin stylesheets are silently skipped. Recurses into@mediaand@supportsrule groups. PluginSlot then injects a second<style id="metaflow-plugin-theme-vars">block containing the resolved variables alongside the existingPLUGIN_STYLESHEET. AMutationObserverwatches<html>forclass,style, anddata-themeattribute changes; on any mutation, the iframe's variables<style>element has itstextContentrewritten with fresh values. The observer is disconnected on unmount.The helper is kept inline as a private module-scope function since it has a single call site and no other component needs it.
Why resolve at injection time instead of injecting raw CSS?
document.styleSheetsonly gives access to source declarations. To capture the value the host is actually rendering with (after cascade, runtime overrides, inline<html style>, etc.), we have to readgetComputedStyle(document.documentElement).getPropertyValue(...). This is the only way to honor runtime theme state.Alternate Designs
postMessage-based theme push. Would require defining a new plugin protocol message (THEME_UPDATE) and updating every plugin to listen for it. Rejected because plugins already opt-in to host styles viauseApplicationStyles: true; they should not need plugin-side code changes.<style>rewrite is non-destructive.theme.cssevolves; an allowlist would silently drift out of sync. Walking the actual stylesheets stays correct automatically.PluginSlot.tsxand is self-contained, keeping it inline reduces file count and keeps the related logic colocated.Possible Drawbacks
document.styleSheetsand computing variable values at registration time isO(rules + custom-props). In practice this is a few hundred properties resolved once per plugin mount and once per host theme change — well below any noticeable threshold.MutationObserveris scoped todocument.documentElementwith a narrowattributeFilter(class,style,data-theme), so it does not fire on unrelated DOM mutations.SecurityErrorwhen accessed viacssRules. The helper catches this silently — those sheets are skipped, which matches the existing behavior since the bundledtheme.cssis same-origin.Verification Process
npx tsc --noEmit— zero TypeScript errors.npx prettier --writeandnpx eslinton the modified file — clean.plugin-api/:yarn dev:plugin.<head>now contains two<style>elements: the existingPLUGIN_STYLESHEETand the newmetaflow-plugin-theme-varsblock.<style>element via DevTools — confirmed it contains:root { --color-bg-primary: ...; --color-text-primary: ...; ... }with values matchinggetComputedStyle(document.documentElement)on the host.<html>in DevTools and overriding a variable — confirmed the iframe's<style id="metaflow-plugin-theme-vars">element updates immediately, with no iframe reload and no lost plugin state.Quick Navigation Summary
<head>in DevTools<style id="metaflow-plugin-theme-vars">element<html class>in host DevTools<style>updates immediatelysrc/components/Plugins/PluginSlot.tsx// TODO: ADD VARIABLESuseApplicationStyles<head>unchangedRelease Notes
Plugins using
useApplicationStyles: truenow receive the host's resolved CSS theme variables and stay in sync when the host theme changes at runtime — enabling plugins to participate in future theme switches (including the dark mode being added in #190) without per-plugin code changes.