mirror of
https://github.com/bulwarkmail/webmail.git
synced 2026-10-31 00:12:39 +00:00
fix: stop plugin frames from painting a white backdrop in dark themes
This commit is contained in:
@@ -95,6 +95,10 @@ export function PluginIframeSlot({ pluginId, slot, extraProps }: Props) {
|
||||
const activeThemeId = useThemeStore((s) => s.activeThemeId);
|
||||
useEffect(() => {
|
||||
instanceRef.current?.setTheme(snapshotHostTheme());
|
||||
// The store may apply the new theme to the page after this render: read
|
||||
// it again a frame later, so the frame never keeps the old values.
|
||||
const frame = requestAnimationFrame(() => instanceRef.current?.setTheme(snapshotHostTheme()));
|
||||
return () => cancelAnimationFrame(frame);
|
||||
}, [resolvedTheme, activeThemeId]);
|
||||
|
||||
if (show !== true) return null;
|
||||
|
||||
@@ -162,3 +162,25 @@ describe('plugin frame permissions', () => {
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
describe('plugin frame color scheme', () => {
|
||||
// A frame whose document says dark while the iframe element says light gets
|
||||
// an opaque white canvas from the browser: dark text tokens on white.
|
||||
it('gives the iframe element the color-scheme the frame declares, at start and on a theme change', () => {
|
||||
document.documentElement.classList.add('dark');
|
||||
try {
|
||||
const inst = createSlotInstance({
|
||||
plugin: plugin(), slot: 'plugin-dialog', code: '', locale: 'en', tier: 'untrusted', extraProps: {},
|
||||
hostContainer: document.body, onResize: () => {},
|
||||
});
|
||||
instances.push(inst);
|
||||
expect(inst.iframe.style.colorScheme).toBe('dark');
|
||||
inst.setTheme({ dark: false, fontFamily: 'sans-serif', vars: {} });
|
||||
expect(inst.iframe.style.colorScheme).toBe('light');
|
||||
inst.setTheme({ dark: true, fontFamily: 'sans-serif', vars: {} });
|
||||
expect(inst.iframe.style.colorScheme).toBe('dark');
|
||||
} finally {
|
||||
document.documentElement.classList.remove('dark');
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
@@ -172,6 +172,11 @@ export class SandboxInstance {
|
||||
this.iframe.setAttribute('allow', 'clipboard-write');
|
||||
this.iframe.title = `plugin-${plugin.id}-${initPayload.mode}`;
|
||||
this.iframe.style.border = 'none';
|
||||
// The frame's document declares the theme's color-scheme (themeSnapshotToCSS).
|
||||
// When the iframe element's own color-scheme differs, the browser paints
|
||||
// an opaque canvas behind the frame (white in a dark theme), so the two
|
||||
// are always set together.
|
||||
if (initPayload.mode === 'slot') this.iframe.style.colorScheme = initPayload.theme.dark ? 'dark' : 'light';
|
||||
this.iframe.style.display = 'block';
|
||||
if (initPayload.mode === 'background') {
|
||||
this.iframe.style.position = 'absolute';
|
||||
@@ -377,6 +382,7 @@ export class SandboxInstance {
|
||||
/** Push a new resolved theme so the slot iframe re-injects its theme CSS. */
|
||||
setTheme(theme: ThemeSnapshot): void {
|
||||
if (this.destroyed) return;
|
||||
this.iframe.style.colorScheme = theme.dark ? 'dark' : 'light';
|
||||
this.send({ type: 'theme-change', theme });
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user