diff --git a/src/material/core/_core-theme.scss b/src/material/core/_core-theme.scss index 1142b733770f..7883579a8923 100644 --- a/src/material/core/_core-theme.scss +++ b/src/material/core/_core-theme.scss @@ -16,6 +16,22 @@ @use './tokens/m2/mat/full-pseudo-checkbox' as tokens-mat-full-pseudo-checkbox; @use './tokens/m2/mat/minimal-pseudo-checkbox' as tokens-mat-minimal-pseudo-checkbox; +$_has-inserted-loaded-marker: false; + +@mixin _theme-loaded-marker { + @if not $_has-inserted-loaded-marker { + $_has-inserted-loaded-marker: true !global; + + // Marker that is used to determine whether the user has added a theme to their page. + // Needs to be generated at the root, because themes may be nested inside classes. + @at-root { + .mat-theme-loaded-marker { + display: none; + } + } + } +} + @mixin base($theme) { @if inspection.get-theme-version($theme) == 1 { @include _theme-from-tokens(inspection.get-theme-tokens($theme, base)); @@ -26,6 +42,9 @@ @include optgroup-theme.base($theme); @include pseudo-checkbox-theme.base($theme); } + + // The marker is a concrete style no matter which Material version we're targeting. + @include _theme-loaded-marker; } @mixin color($theme) { @@ -54,14 +73,6 @@ } } } - - // TODO(crisbeto): move this into the base. - // Marker that is used to determine whether the user has added a theme to their page. - @at-root { - .mat-theme-loaded-marker { - display: none; - } - } } @mixin typography($theme) { @@ -127,6 +138,9 @@ } } } + + // The marker is a concrete style no matter which Material version we're targeting. + @include _theme-loaded-marker; } @mixin _theme-from-tokens($tokens, $options...) { diff --git a/src/material/core/theming/tests/m3-theme.spec.ts b/src/material/core/theming/tests/m3-theme.spec.ts index f23544ec13b1..975fb105d426 100644 --- a/src/material/core/theming/tests/m3-theme.spec.ts +++ b/src/material/core/theming/tests/m3-theme.spec.ts @@ -1,4 +1,4 @@ -import {parse} from 'postcss'; +import {parse, Rule} from 'postcss'; import {compileString} from 'sass'; import {runfiles} from '@bazel/runfiles'; import * as path from 'path'; @@ -68,14 +68,18 @@ describe('M3 theme', () => { root.walkRules(rule => { selectors.push(rule.selector); }); - expect(selectors).toEqual(['html']); + expect(selectors).toEqual(['html', '.mat-theme-loaded-marker']); }); it('should only emit CSS variables', () => { const root = parse(transpile(`html { @include mat.all-component-themes($theme); }`)); const nonVarProps: string[] = []; root.walkDecls(decl => { - if (!decl.prop.startsWith('--')) { + if ( + !decl.prop.startsWith('--') && + // Skip the theme loaded marker since it can't be a variable. + (decl.parent as Rule).selector !== '.mat-theme-loaded-marker' + ) { nonVarProps.push(decl.prop); } }); diff --git a/src/material/core/theming/tests/theming-inspection-api.spec.ts b/src/material/core/theming/tests/theming-inspection-api.spec.ts index 43b1e807143f..212cdc38f66b 100644 --- a/src/material/core/theming/tests/theming-inspection-api.spec.ts +++ b/src/material/core/theming/tests/theming-inspection-api.spec.ts @@ -472,7 +472,14 @@ describe('theming inspection api', () => { div { @include mat.all-component-themes($theme); }`); - expect(css).toBe(''); + expect(css).toBe( + [ + // The marker is always included. + `.mat-theme-loaded-marker {`, + ` display: none;`, + `}`, + ].join('\n'), + ); }); }); });