Skip to content
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

Merged
merged 14 commits into from Jun 12, 2019

Conversation

bicknellr
Copy link
Member

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.

}
const template = part.value instanceof TemplateInstance ?
part.value.template :
new Template(html``, document.createElement('template'));
Copy link
Collaborator

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.

Copy link
Member Author

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.

Copy link
Collaborator

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?

Copy link
Member

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?

Copy link
Member Author

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?

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 with prepareAdoptedCssText). Why not change prepareTemplateStyles 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.

Copy link
Member Author

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.

@bicknellr bicknellr requested a review from dfreedm May 13, 2019 23:58
}
const template = part.value instanceof TemplateInstance ?
part.value.template :
new Template(html``, document.createElement('template'));
Copy link
Collaborator

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?

}
const template = part.value instanceof TemplateInstance ?
part.value.template :
new Template(html``, document.createElement('template'));
Copy link
Member

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?

…(...)

- 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.
@justinfagnani
Copy link
Collaborator

The PR now has unrelated changes in it from master. Can you rebase?

@justinfagnani
Copy link
Collaborator

I guess that's the merge of #904

justinfagnani
justinfagnani previously approved these changes Jun 3, 2019
Copy link
Collaborator

@justinfagnani justinfagnani left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM. @sorvell ?

Copy link
Member

@sorvell sorvell left a 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)?

src/lib/parts.ts Show resolved Hide resolved
if (template) {
insertNodeIntoTemplate(template, condensedStyle, content.firstChild);
} else {
content.insertBefore(condensedStyle, content.firstChild);
Copy link
Member

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.

Copy link
Member

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.

Copy link
Member Author

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.

// 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.
Copy link
Member

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.

Copy link
Member Author

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', () => {
Copy link
Member

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.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Added at the bottom.

sorvell
sorvell previously approved these changes Jun 6, 2019
@bicknellr
Copy link
Member Author

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)?

Yeah, the :host styles should render when the first result is undefined. (Trying to remember our offline chat about this...) Particularly, this is a problem when Shadow DOM is supported but adoptedStyleSheets is not. Assuming this check for TemplateResult in lit-element was removed, then lit-html's checks for TemplateResult and for TemplateInstance will prevent it from running ShadyCSS scoping on the first actual render if the rendered result was undefined, but lit-element still inserts the styles it created to simulate adoptedStyleSheets. Then, the first time that a TemplateResult is produced by render, it will run the scoping but also remove all of the content of renderContainer, which contained the styles that were inserted by lit-element.

justinfagnani
justinfagnani previously approved these changes Jun 7, 2019
Copy link
Collaborator

@justinfagnani justinfagnani left a 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

// 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');
Copy link
Collaborator

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.

Copy link
Member Author

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.

@bicknellr bicknellr dismissed stale reviews from justinfagnani and sorvell via 572c103 June 7, 2019 20:28
@bicknellr bicknellr merged commit 8655aa5 into master Jun 12, 2019
@bicknellr bicknellr deleted the shady-non-template-result branch June 12, 2019 20:52
bicknellr added a commit that referenced this pull request Jun 12, 2019
bicknellr added a commit that referenced this pull request Jun 12, 2019
neuronetio pushed a commit to neuronetio/lit-html that referenced this pull request Dec 2, 2019
…#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.
neuronetio pushed a commit to neuronetio/lit-html that referenced this pull request Dec 2, 2019
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

3 participants