-
Notifications
You must be signed in to change notification settings - Fork 29.2k
fix(compiler): strip ::ng-deep from nested selectors #69959
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
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -31,4 +31,70 @@ describe('ShadowCss, ng-deep', () => { | |
| css = ':host > ::ng-deep > .x {}'; | ||
| expect(shim(css, 'contenta', 'h')).toEqualCss('[h] > > .x {}'); | ||
| }); | ||
|
|
||
| // TODO(crisbeto): this is temporary until we land #69885. | ||
| it('should strip ::ng-deep from nested selectors', () => { | ||
| const css = ` | ||
| .parent { | ||
| ::ng-deep .child { | ||
| color: red; | ||
| } | ||
|
|
||
| .wrapper { | ||
| &::ng-deep .inner { | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. These cases have been tricky for ACX in the past. Sometimes you have a Sass mixin like @mixin foo($sel) {
:host {
&$sel {
color: red;
}
}
}In this case if you call |
||
| color: blue; | ||
| } | ||
|
|
||
| &:hover ::ng-deep .inner-hover { | ||
| color: green; | ||
| } | ||
|
|
||
| .deep { | ||
| ::ng-deep .deepest { | ||
| color: yellow; | ||
| } | ||
| } | ||
| } | ||
| } | ||
|
|
||
| @media screen and (max-width: 600px) { | ||
| .media-parent { | ||
| ::ng-deep .media-child { | ||
| color: purple; | ||
| } | ||
| } | ||
| } | ||
| `; | ||
| expect(shim(css, 'contenta')).toEqualCss(` | ||
| .parent[contenta] { | ||
| .child { | ||
| color: red; | ||
| } | ||
|
|
||
| .wrapper { | ||
| & .inner { | ||
| color: blue; | ||
| } | ||
|
|
||
| &:hover .inner-hover { | ||
| color: green; | ||
| } | ||
|
|
||
| .deep { | ||
| .deepest { | ||
| color: yellow; | ||
| } | ||
| } | ||
| } | ||
| } | ||
|
|
||
| @media screen and (max-width: 600px) { | ||
| .media-parent[contenta] { | ||
| .media-child { | ||
| color: purple; | ||
| } | ||
| } | ||
| } | ||
| `); | ||
| }); | ||
| }); | ||
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'm not convinced by this approach. Happy to chat tomorrow if that's easier, but I'll try to express some of my thoughts. I've tested a bunch of this, but please feel free to check my assertions.
Take for example the input
:host { .foo {} }. Today we write[host] { .foo {} }, simply not encapsulating beyond the outer selector. It's my understanding that this change allows us to write CSS like:host { ::ng-deep .foo {} }to make the encapsulation opt-out explicit, so that once we support nesting we can land it without changing behavior.Couldn't we just use
:host ::ng-deep { .foo {} }today? I think onmaintoday this already compiles to[host] { .foo {} }. It seems like this isn't actually stable on #69885, but arguably it should be, since:host ::ng-deep { .foo {} }is semantically equivalent to:host ::ng-deep .foo {}. I think we need to update #69885 to fix this case rather than stripping::ng-deepin this PR. This should be safe for an LSC in g3 too.As an aside:
This gets tricky with selector lists, though. I think we want to make sure not to make a decision yet in cases like
::ng-deep, .foo { .bar {} }. Following CSS nesting rules, this actually desugars to:is(::ng-deep, .foo) .bar {}, which I suspect we should just produce an error for someday. This would be easier if/when we move to a real parser. That leaves us in a weird place for #69885 whatever we decide to do. In this case both encapsulating.barand not scoping.baris wrong. I'm leaning towards saying we should not encapsulate.bar, since that matches today's behavior of not encapsulating nested selectors. It's a little funky because:is()technically takes a forgiving selector list, but nested selectors don't actually map cleanly onto:is()semantics in that way. For example, the following produces red text, indicating that the nested rule is not forgiving in the way that:is()is.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.
Ah it makes sense that
:host ::ng-deep { .foo {} }should be treated as:host ::ng-deep .foo {}. I'll update the other PR and see if that helps me deal with the test failures.