Skip to content

Commit b73a44b

Browse files
authored
fix(styles): support rendering across documents (#6481)
* fix(styles): support rendering across documents Constructed stylesheets cannot be shared across documents (e.g. within an iframe). Check in which document the component is and use its own CSSStyleSheet. fixes: #6479 * test(cross-document-constructed-styles): added missing test Create an iframe with no stencil runtime, add a component and expect it to be rendered ok
1 parent d3b8b7a commit b73a44b

3 files changed

Lines changed: 71 additions & 10 deletions

File tree

src/runtime/styles.ts

Lines changed: 36 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -127,8 +127,12 @@ export const addStyle = (styleContainerNode: any, cmpMeta: d.ComponentRuntimeMet
127127
*
128128
* Note: order of how styles are adopted is important. The new stylesheet should be
129129
* adopted before the existing styles.
130+
*
131+
* Note: constructable stylesheets can't be shared between windows,
132+
* we need to create a new one for the current window if necessary
130133
*/
131-
const stylesheet = new CSSStyleSheet();
134+
const currentWindow = styleContainerNode.defaultView ?? styleContainerNode.ownerDocument.defaultView;
135+
const stylesheet = new currentWindow.CSSStyleSheet();
132136
stylesheet.replaceSync(style);
133137

134138
/**
@@ -179,15 +183,37 @@ export const addStyle = (styleContainerNode: any, cmpMeta: d.ComponentRuntimeMet
179183
appliedStyles.add(scopeId);
180184
}
181185
}
182-
} else if (BUILD.constructableCSS && !styleContainerNode.adoptedStyleSheets.includes(style)) {
183-
/**
184-
* > If the array needs to be modified, use in-place mutations like push().
185-
* https://developer.mozilla.org/en-US/docs/Web/API/Document/adoptedStyleSheets
186-
*/
187-
if (supportsMutableAdoptedStyleSheets) {
188-
styleContainerNode.adoptedStyleSheets.push(style);
189-
} else {
190-
styleContainerNode.adoptedStyleSheets = [...styleContainerNode.adoptedStyleSheets, style];
186+
} else if (BUILD.constructableCSS) {
187+
let appliedStyles = rootAppliedStyles.get(styleContainerNode);
188+
if (!appliedStyles) {
189+
rootAppliedStyles.set(styleContainerNode, (appliedStyles = new Set()));
190+
}
191+
if (!appliedStyles.has(scopeId)) {
192+
/**
193+
* Constructable stylesheets can't be shared between windows,
194+
* we need to create a new one for the current window if necessary
195+
*/
196+
const currentWindow = styleContainerNode.defaultView ?? styleContainerNode.ownerDocument.defaultView;
197+
let stylesheet: CSSStyleSheet;
198+
if (style.constructor === currentWindow.CSSStyleSheet) {
199+
stylesheet = style;
200+
} else {
201+
stylesheet = new currentWindow.CSSStyleSheet();
202+
for (let i = 0; i < style.cssRules.length; i++) {
203+
stylesheet.insertRule(style.cssRules[i].cssText, i);
204+
}
205+
}
206+
/**
207+
* > If the array needs to be modified, use in-place mutations like push().
208+
* https://developer.mozilla.org/en-US/docs/Web/API/Document/adoptedStyleSheets
209+
*/
210+
if (supportsMutableAdoptedStyleSheets) {
211+
styleContainerNode.adoptedStyleSheets.push(stylesheet);
212+
} else {
213+
styleContainerNode.adoptedStyleSheets = [...styleContainerNode.adoptedStyleSheets, stylesheet];
214+
}
215+
216+
appliedStyles.add(scopeId);
191217
}
192218
}
193219
}
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
import { h, render } from '@stencil/core';
2+
import { $, browser, expect } from '@wdio/globals';
3+
4+
describe('cross-document-style', () => {
5+
before(async () => {
6+
const iframe = document.createElement('iframe');
7+
document.body.appendChild(iframe);
8+
render(<cross-document-style></cross-document-style>, iframe.contentDocument.body);
9+
});
10+
11+
it('should render in across frames', async () => {
12+
await browser.switchFrame($('iframe'));
13+
await expect($('cross-document-style')).toHaveStyle({ color: 'rgb(255,0,0)' });
14+
});
15+
});
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
import { Component, h } from '@stencil/core';
2+
3+
@Component({
4+
tag: 'cross-document-style',
5+
styles: `
6+
:host {
7+
color: rgb(255, 0, 0);
8+
}
9+
`,
10+
shadow: true,
11+
})
12+
export class CrossDocumentStyleTestCmp {
13+
render() {
14+
return (
15+
<section>
16+
<div>I am rendered in red!</div>
17+
</section>
18+
);
19+
}
20+
}

0 commit comments

Comments
 (0)