New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Scope styles even if the rendered value is not a TemplateResult. #910
Conversation
src/lib/shady-render.ts
Outdated
} | ||
const template = part.value instanceof TemplateInstance ? | ||
part.value.template : | ||
new Template(html``, document.createElement('template')); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What's this part for? Add a comment.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Added, let me know what you think.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is this really going to work? prepareTemplateStyles
might insert styles into this template, but for what purpose if the template is never rendered anywhere?
I get the feeling that this isn't going to work with the original use-case of rendering undefined
, then rendering a TemplateResult
. Can we add a test specifically for that, using shady-render?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think the gist is that the styling we are about in this case was sent to ShadyCSS via prepareAdoptedCssText
. Styling in the non-template result would just not be supported.
So it seems like all we need to do in this case is ensure that (1) styles are removed from any lit template for the scope (would there be any if no TemplateResult is being rendered?, (2) ensure that prepareTemplate
is called (because this is necessary to apply any styles defined with prepareAdoptedCssText
). Why not change prepareTemplateStyles
to optionally take a Template rather than creating a dummy one here?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is this really going to work?
prepareTemplateStyles
might insert styles into this template, but for what purpose if the template is never rendered anywhere?I get the feeling that this isn't going to work with the original use-case of rendering
undefined
, then rendering aTemplateResult
. Can we add a test specifically for that, using shady-render?
Ok, I added another test specifically for this case.
I think the gist is that the styling we are about in this case was sent to ShadyCSS via
prepareAdoptedCssText
. Styling in the non-template result would just not be supported.
AFAICT, the current setup seems to be that all styles in the first render are scoped and any styles that appear later aren't. So I think that even styles inserted into NodeParts of a top-level TemplateInstance were collected / scoped / removed from their rendered position on the first render.
Am I correct in thinking that (local) prepareTemplateStyles
' renderedDOM
contains the complete rendered output of the first render by the time it runs?
So it seems like all we need to do in this case is ensure that (1) styles are removed from any lit template for the scope (would there be any if no TemplateResult is being rendered?, (2) ensure that
prepareTemplate
is called (because this is necessary to apply any styles defined withprepareAdoptedCssText
). Why not changeprepareTemplateStyles
to optionally take a Template rather than creating a dummy one here?
I was avoiding this because it seemed difficult to pry apart the Template editing parts of (local) prepareTemplateStyles
from the parts that were dealing with changing the output of the first render but it seems necessary at this point to match the earlier behavior - I'll update.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I made prepareTemplateStyles
' template
parameter optional and updated the logic in there to work with a new, empty template if it isn't passed. Also, I added a couple extra tests that ShadyCSS mixins and scoping are applied to styles that are part of an initial render for a scope of a non-TemplateInstance value.
src/lib/shady-render.ts
Outdated
} | ||
const template = part.value instanceof TemplateInstance ? | ||
part.value.template : | ||
new Template(html``, document.createElement('template')); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is this really going to work? prepareTemplateStyles
might insert styles into this template, but for what purpose if the template is never rendered anywhere?
I get the feeling that this isn't going to work with the original use-case of rendering undefined
, then rendering a TemplateResult
. Can we add a test specifically for that, using shady-render?
src/lib/shady-render.ts
Outdated
} | ||
const template = part.value instanceof TemplateInstance ? | ||
part.value.template : | ||
new Template(html``, document.createElement('template')); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think the gist is that the styling we are about in this case was sent to ShadyCSS via prepareAdoptedCssText
. Styling in the non-template result would just not be supported.
So it seems like all we need to do in this case is ensure that (1) styles are removed from any lit template for the scope (would there be any if no TemplateResult is being rendered?, (2) ensure that prepareTemplate
is called (because this is necessary to apply any styles defined with prepareAdoptedCssText
). Why not change prepareTemplateStyles
to optionally take a Template rather than creating a dummy one here?
… rendered value was not a TemplateInstance.
…(...) - Adds a test that ShadyCSS mixins are processed when the first render is of a non-TemplateInstance value. - Adds a test that ShadyCSS scoping is applied when the first render is of a non-TemplateInstance value.
The PR now has unrelated changes in it from master. Can you rebase? |
I guess that's the merge of #904 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM. @sorvell ?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It's unclear why styling is incorrect after you eventually render a TemplateResult (without this modification). Perhaps the underlying issue is that the user expects :host
styles to render initially (when rendering something like undefined
)?
if (template) { | ||
insertNodeIntoTemplate(template, condensedStyle, content.firstChild); | ||
} else { | ||
content.insertBefore(condensedStyle, content.firstChild); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Because of the comment below this, I think this case breaks support for @apply
when using native Shadow DOM. That might be ok, but at the least we need to document it.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We should be able to add a test that demonstrates this.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I added the comment we were working on in offline discussion.
src/lib/shady-render.ts
Outdated
// into the document if `prepareTemplateStyles` has already been called | ||
// for the given scope name. `prepareTemplateStyles` requires a | ||
// template element (and the local wrapper requires a Template), so we | ||
// create an empty one here to satisfy it. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Update this comment since we're not creating an empty template here.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Updated.
// tests are really just a sanity check that they are accepted by `render`. | ||
// Tests about rendering behavior for specific values should generally be | ||
// grouped with those of `NodePart#setValue` and `#commit`. | ||
suite('accepts types other than TemplateResult', () => { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Let's add a test for accepting a Node since that seems like it might not be uncommon.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Added at the bottom.
da05c41
to
bf1373b
Compare
Yeah, the |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks for the additional comments
src/lib/shady-render.ts
Outdated
// Template's underlying template element. Otherwise, we create one here | ||
// to give to ShadyCSS, which still requires one while scoping. | ||
const templateElement = | ||
template ? template.element : document.createElement('template'); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Always prefer explicit comparisons over implicity ToBoolean conversions, here and in two if
statements below.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ok, these are explicit now.
…#910) * Scope styles even if the rendered value is not a TemplateResult. * Add a comment about why an empty Template is passed to `prepareTemplateStyles`. * Test that adopted styles still apply after later renders if the first rendered value was not a TemplateInstance. * shady-render: `prepareTemplateStyles` no longer requires a Template. (...) - Adds a test that ShadyCSS mixins are processed when the first render is of a non-TemplateInstance value. - Adds a test that ShadyCSS scoping is applied when the first render is of a non-TemplateInstance value. * Revert "Revert "Allow `render` to accept any type. (lit#904)" (lit#913)" This reverts commit 86412ca. * Add / update comments. * Test that `render` accepts a node. * Add a comment about interaction with @apply. * Explicitly convert to boolean in conditions.
This should have been part of #904. The ShadyDOM/CSS-aware renderer will only take the actions to scope styles if the value being rendered is a TemplateResult. Before #904, the rendered value was always assumed to be a TemplateResult and these checks were redundant. However, to implement lit/lit-element#618, the style-scoping steps need to happen even if the value isn't a TemplateResult because some user (e.g. lit-element) might have added adopted style sheets for the render container.