Closed daKmoR closed 3 years ago
Well... this isn't really an intended use of render()
. Not that it's completely wrong, but lit-html hard-codes use of the main document for importing from templates. This is why you don't need to redefine the elements in the iframe - they're created in the main document, then moved to the iframe. This is also why the stylesheets are removed. Because constructible stylesheets have a base URL and origin that matches the document they're created in, it's not transparent or safe to move them to a frame with another origin, so they're removed by the browser.
I think the way to handle this is to implement and adoptedCallback()
and trigger re-attaching the constructible stylesheet, like:
adoptedCallback() {
this.adoptStyles();
}
I'm not sure that'll fully work because the css
tag caches the CSSStyleSheet instance and it might not be adoptable in the new document. This might also double up the styles in browsers that don't support adoptedStyleSheets because it resets _needsShimAdoptedStyleSheets
. Worth a try though.
@sorvell
that gives me 😅
Uncaught DOMException: Failed to set the 'adoptedStyleSheets' property on 'ShadowRoot': Sharing constructed stylesheets in multiple documents is not allowed
so I assume I need to find some way to "duplicate" them without being the same and then attach them somehow 🤔
I was afraid of that. @rakina, do you know of a way to create a CSSStyleSheet in one frame and adopt it in another?
@daKmoR can you define the elements in the iframe?
what I would like to archive is to have a demo shown in multiple iframes to simulate multiple devices...
I probably can analyse the code, find all imports and webcomponents and recreate them in the iframe... it's just way more complicated.
And creating the element and moving it later is actually very useful in this case... and it all works if you use the good old <style>
tag... I mean I could disable constructible stylesheets for the whole page... that would solve it... but then again this basically means you can never move any custom elements into another document (as you will always loose your styling)
is that a general limitation of constructible stylesheets? seems rather unfortunate 🤔
See https://github.com/WICG/construct-stylesheets/issues/23 and https://bugs.chromium.org/p/chromium/issues/detail?id=1111864 for some context; there are a lot of constraints at play afaiu.
Still, with some work, it seems like we might be able to have LitElement
/ReactiveElement
implement an adoptedCallback
does a better thing here (i.e. run a clone algorithm over the flattened styles list that re-generates them in the new document)
Just to see if this approach would work, something roughly like this?
adoptedCallback() {
if (supportsAdoptingStyleSheets) {
// Assumes styles are made with `css` tag (and thus s.cssText is available)
// To support `CSSStyleSheet` in static get styles would require generating the cssText from the CSSOM
// To make it efficient, would want some sort of document-based cache, based on the new
// `this.ownerDocument` after adoption
this.adoptedStylesheets = (this.constructor as typeof LitElement)._styles.map((s as CSSResult) => {
const sheet = new CSSStyleSheet();
sheet.replaceSync(s.cssText);
return s;
});
}
}
Hey, I expanded on @kevinpschaaf's example and have a working demo that could be helpful.
Here instead of using CSSStyleSheet
directly I accessed the object through this.ownerDocument.defaultView.CSSStyleSheet
. While it's a bit of a nuisance maybe the LitElement
class could use this reference instead of directly calling CSSStyleSheet
?
adoptedCallback() {
if ('adoptedStyleSheets' in document) {
const CSSStyleSheet = this.ownerDocument.defaultView.CSSStyleSheet;
this.shadowRoot.adoptedStyleSheets = this.constructor._styles.map(s => {
const sheet = new CSSStyleSheet();
sheet.replaceSync(s.cssText);
return sheet;
});
}
}
This has something broken in Firefox (I'm not going to mess with figuring out what's happening there), but figured I'd post it as a possibility any way.
Edit
I'd also like to see this addressed somehow because I'd like to make (or use if someone else wants to do the hard work) a web component version of SEEK's Playroom.
We're not inclined to address this in ReactiveElement
because this seems like a rare/advanced use case, and it would be a chunk of work to get this to work with ShadyCSS. We'd need polyfill support to put this into the core code.
Instead, we recommend either disabling constructible stylesheets in the main document or loading the code in the iframes and creating the elements there. Will one of those approaches work for you?
I went with loading the code in the iframes and creating the elements there
...
It's more complex to implement but you also gain isolated pages you can reload work with...
closing this as it's sort of a wont-fix
I'm rendering a component into multiple iframes
and I'm already amazed that I don't need to redefine all custom elements in those iframes... however due to LitElement using constructable stylesheets... those stylesheets are only available in the "parent" window... any way I can bring them along?
funny enough it works fine in browser that don't support constructable stylesheets as then it will create style tags in the shadow dom 😅
===> Live Demo at https://codepen.io/daKmoR/pen/XWjwdRb?editors=1000 <<===
Question
is that the intended behaviour? or should it register the stylesheet in every document it get's added 🤔