From 9a5d84249a0fd6b5c2a77c7ab6cbf72d90c45ee3 Mon Sep 17 00:00:00 2001 From: dario-piotrowicz Date: Sun, 4 Dec 2022 21:26:59 +0000 Subject: [PATCH] fix(compiler): make sure selectors inside container queries are correctly scoped (#48353) improve the emulated shadowDom implementation so that it can correctly scope selectors present inside the @container at-rule (recently added to the css specs) resolves #48264 PR Close #48353 --- packages/compiler/src/shadow_css.ts | 3 +- .../test/shadow_css/container_queries_spec.ts | 55 +++++++++++++++++++ 2 files changed, 57 insertions(+), 1 deletion(-) create mode 100644 packages/compiler/test/shadow_css/container_queries_spec.ts diff --git a/packages/compiler/src/shadow_css.ts b/packages/compiler/src/shadow_css.ts index eab565fb6a875..f6332d878f0d7 100644 --- a/packages/compiler/src/shadow_css.ts +++ b/packages/compiler/src/shadow_css.ts @@ -571,7 +571,8 @@ export class ShadowCss { this._scopeSelector(rule.selector, scopeSelector, hostSelector, this.strictStyling); } else if ( rule.selector.startsWith('@media') || rule.selector.startsWith('@supports') || - rule.selector.startsWith('@document') || rule.selector.startsWith('@layer')) { + rule.selector.startsWith('@document') || rule.selector.startsWith('@layer') || + rule.selector.startsWith('@container')) { content = this._scopeSelectors(rule.content, scopeSelector, hostSelector); } else if (rule.selector.startsWith('@font-face') || rule.selector.startsWith('@page')) { content = this._stripScopingSelectors(rule.content); diff --git a/packages/compiler/test/shadow_css/container_queries_spec.ts b/packages/compiler/test/shadow_css/container_queries_spec.ts new file mode 100644 index 0000000000000..3b8c095f35a61 --- /dev/null +++ b/packages/compiler/test/shadow_css/container_queries_spec.ts @@ -0,0 +1,55 @@ +/** + * @license + * Copyright Google LLC All Rights Reserved. + * + * Use of this source code is governed by an MIT-style license that can be + * found in the LICENSE file at https://angular.io/license + */ + +import {ShadowCss} from '@angular/compiler/src/shadow_css'; + +describe('ShadowCss, container queries', () => { + function s(css: string, contentAttr: string, hostAttr: string = '') { + const shadowCss = new ShadowCss(); + return shadowCss.shimCssText(css, contentAttr, hostAttr); + } + + it('should scope normal selectors inside an unnamed container rules', () => { + const css = `@container max(max-width: 500px) { + .item { + color: red; + } + }`; + const result = s(css, 'host-a'); + expect(noIndentation(result)).toEqual(noIndentation(`@container max(max-width: 500px) { + .item[host-a] { + color: red; + } + }`)); + }); + + it('should scope normal selectors inside a named container rules', () => { + const css = `@container container max(max-width: 500px) { + .item { + color: red; + } + }`; + const result = s(css, 'host-a'); + // Note that for the time being we are not scoping the container name itself, + // this is something that may or may not be done in the future depending + // on how the css specs evolve. Currently as of Chrome 107 it looks like shadowDom + // boundaries don't effect container queries (thus the scoping wouldn't be needed) + // and this aspect of container queries seems to be still under active discussion: + // https://github.com/w3c/csswg-drafts/issues/5984 + expect(noIndentation(result)) + .toEqual(noIndentation(`@container container max(max-width: 500px) { + .item[host-a] { + color: red; + } + }`)); + }); +}); + +function noIndentation(str: string): string { + return str.replace(/\n\s+/g, '\n'); +}