diff --git a/src/material/_index.scss b/src/material/_index.scss index ee2748149dcb..e35f98f435a2 100644 --- a/src/material/_index.scss +++ b/src/material/_index.scss @@ -2,7 +2,7 @@ @forward './core/theming/theming' show define-light-theme, define-dark-theme, define-palette, get-contrast-color-from-palette, get-color-from-palette, get-color-config, get-typography-config, get-density-config, - $theme-ignore-duplication-warnings; + $theme-ignore-duplication-warnings, $theme-legacy-inspection-api-compatibility; @forward './core/theming/theming' as private-* show private-clamp-density; @forward './core/theming/palette' show $red-palette, $pink-palette, $indigo-palette, $purple-palette, $deep-purple-palette, $blue-palette, $light-blue-palette, $cyan-palette, diff --git a/src/material/core/theming/_m2-inspection.scss b/src/material/core/theming/_m2-inspection.scss index 39b1fe981d09..779ae0fdcbdf 100644 --- a/src/material/core/theming/_m2-inspection.scss +++ b/src/material/core/theming/_m2-inspection.scss @@ -5,10 +5,17 @@ $_typography-properties: (font, font-family, line-height, font-size, letter-spacing, font-weight); +/// Gets the m2-config from the theme. +@function _get-m2-config($theme) { + $internal: map.get($theme, _mat-theming-internals-do-not-access, m2-config); + @return $internal or $theme; +} + /// Gets the type of theme represented by a theme object (light or dark). /// @param {Map} $theme The theme /// @return {String} The type of theme (either `light` or `dark`). @function get-theme-type($theme) { + $theme: _get-m2-config($theme); @if not theme-has($theme, color) { @error 'Color information is not available on this theme.'; } @@ -26,6 +33,7 @@ $_typography-properties: (font, font-family, line-height, font-size, letter-spac /// interpreted as a palette name). /// @return {Color} The requested theme color. @function get-theme-color($theme, $palette-name, $args...) { + $theme: _get-m2-config($theme); @if not theme-has($theme, color) { @error 'Color information is not available on this theme.'; } @@ -44,6 +52,7 @@ $_typography-properties: (font, font-family, line-height, font-size, letter-spac /// (font, font-family, font-size, font-weight, line-height, or letter-spacing). /// @return {*} The value of the requested font property. @function get-theme-typography($theme, $typescale, $property) { + $theme: _get-m2-config($theme); @if not theme-has($theme, typography) { @error 'Typography information is not available on this theme.'; } @@ -79,6 +88,7 @@ $_typography-properties: (font, font-family, line-height, font-size, letter-spac /// @param {Map} $theme The theme /// @return {Number} The density scale. @function get-theme-density($theme) { + $theme: _get-m2-config($theme); @if not theme-has($theme, density) { @error 'Density information is not available on this theme.'; } @@ -86,7 +96,12 @@ $_typography-properties: (font, font-family, line-height, font-size, letter-spac @return theming.clamp-density($scale, -5); } +/// Checks whether the theme has information about given theming system. +/// @param {Map} $theme The theme +/// @param {String} $system The system to check +/// @param {Boolean} Whether the theme has information about the system. @function theme-has($theme, $system) { + $theme: _get-m2-config($theme); $theme: theming.private-legacy-get-theme($theme); @if $system == base { @return true; diff --git a/src/material/core/theming/_theming.scss b/src/material/core/theming/_theming.scss index 1861c746478b..bdfbc89027ee 100644 --- a/src/material/core/theming/_theming.scss +++ b/src/material/core/theming/_theming.scss @@ -5,6 +5,8 @@ @use 'palette'; @use '../density/private/compatibility'; +$theme-legacy-inspection-api-compatibility: true !default; + // Whether duplication warnings should be disabled. Warnings enabled by default. $theme-ignore-duplication-warnings: false !default; @@ -544,7 +546,14 @@ $_internals: _mat-theming-internals-do-not-access; @return $theme; } $color: map.get($theme, color); - @return map.merge($theme, $color); + $m2-config: map.merge($theme, $color); + $theme: ( + _mat-theming-internals-do-not-access: ( + theme-version: 0, + m2-config: $m2-config, + ) + ); + @return map.merge(if($theme-legacy-inspection-api-compatibility, $m2-config, ()), $theme); } // Gets the theme from the given value that is either already a theme, or a color configuration. 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 501587d9f277..793ec098580b 100644 --- a/src/material/core/theming/tests/theming-inspection-api.spec.ts +++ b/src/material/core/theming/tests/theming-inspection-api.spec.ts @@ -25,6 +25,7 @@ const mdcSassImporter = { function transpile(content: string) { return compileString( ` + @use 'sass:map'; @use '../../../index' as mat; @use '../../../../material-experimental/index' as matx; @@ -131,76 +132,112 @@ describe('theming inspection api', () => { it('should get density scale', () => { expect( transpile(` - $theme: mat.define-light-theme(( - density: -1 - )); - div { - --density-scale: #{mat.private-get-theme-density($theme)}; - } - `), + $theme: mat.define-light-theme(( + density: -1 + )); + div { + --density-scale: #{mat.private-get-theme-density($theme)}; + } + `), ).toMatch('--density-scale: -1;'); }); it('should check what information the theme has', () => { const css = transpile(` - $theme: mat.define-light-theme(( - color: ( - primary: mat.define-palette(mat.$red-palette), - accent: mat.define-palette(mat.$red-palette), - ), - typography: mat.define-typography-config(), - density: -1, - )); - $color-only: mat.define-light-theme(( - color: ( - primary: mat.define-palette(mat.$red-palette), - accent: mat.define-palette(mat.$red-palette), - ), - typography: null, - density: null, - )); - $typography-only: mat.define-light-theme(( - color: null, - typography: mat.define-typography-config(), - density: null, - )); - $density-only: mat.define-light-theme(( - color: null, - typography: null, - density: -1, - )); - div { - --base: #{( - mat.private-theme-has($theme, base), - mat.private-theme-has($color-only, base), - mat.private-theme-has($typography-only, base), - mat.private-theme-has($density-only, base), - )}; - --color: #{( - mat.private-theme-has($theme, color), - mat.private-theme-has($color-only, color), - mat.private-theme-has($typography-only, color), - mat.private-theme-has($density-only, color), - )}; - --typography: #{( - mat.private-theme-has($theme, typography), - mat.private-theme-has($color-only, typography), - mat.private-theme-has($typography-only, typography), - mat.private-theme-has($density-only, typography), - )}; - --density: #{( - mat.private-theme-has($theme, density), - mat.private-theme-has($color-only, density), - mat.private-theme-has($typography-only, density), - mat.private-theme-has($density-only, density), - )}; - } - `); + $theme: mat.define-light-theme(( + color: ( + primary: mat.define-palette(mat.$red-palette), + accent: mat.define-palette(mat.$red-palette), + ), + typography: mat.define-typography-config(), + density: -1, + )); + $color-only: mat.define-light-theme(( + color: ( + primary: mat.define-palette(mat.$red-palette), + accent: mat.define-palette(mat.$red-palette), + ), + typography: null, + density: null, + )); + $typography-only: mat.define-light-theme(( + color: null, + typography: mat.define-typography-config(), + density: null, + )); + $density-only: mat.define-light-theme(( + color: null, + typography: null, + density: -1, + )); + div { + --base: #{( + mat.private-theme-has($theme, base), + mat.private-theme-has($color-only, base), + mat.private-theme-has($typography-only, base), + mat.private-theme-has($density-only, base), + )}; + --color: #{( + mat.private-theme-has($theme, color), + mat.private-theme-has($color-only, color), + mat.private-theme-has($typography-only, color), + mat.private-theme-has($density-only, color), + )}; + --typography: #{( + mat.private-theme-has($theme, typography), + mat.private-theme-has($color-only, typography), + mat.private-theme-has($typography-only, typography), + mat.private-theme-has($density-only, typography), + )}; + --density: #{( + mat.private-theme-has($theme, density), + mat.private-theme-has($color-only, density), + mat.private-theme-has($typography-only, density), + mat.private-theme-has($density-only, density), + )}; + } + `); expect(css).toMatch(/--base: true, true, true, true;/); expect(css).toMatch(/--color: true, true, false, false;/); expect(css).toMatch(/--typography: true, false, true, false;/); expect(css).toMatch(/--density: true, false, false, true;/); }); + + it('should work with compatibility disabled', () => { + expect( + transpile(` + mat.$theme-legacy-inspection-api-compatibility: false; + $theme: mat.define-dark-theme(( + color: ( + primary: mat.define-palette(mat.$red-palette), + accent: mat.define-palette(mat.$red-palette), + ) + )); + div { + --theme-type: #{mat.private-get-theme-type($theme)}; + } + `), + ).toMatch('--theme-type: dark;'); + }); + + it('should not allow access via legacy APIs with compatibility disabled', () => { + expect(() => + transpile(` + mat.$theme-legacy-inspection-api-compatibility: false; + $theme: mat.define-dark-theme(( + color: ( + primary: mat.define-palette(mat.$red-palette), + accent: mat.define-palette(mat.$red-palette), + ) + )); + $color-config: mat.get-color-config($theme); + $primary: map.get($color-config, primary); + div { + color: #{mat.get-color-from-palette($primary)}; + } + `), + ).toThrow(); + }); }); describe('for m3 theme', () => { @@ -311,121 +348,121 @@ describe('theming inspection api', () => { expect(css).toMatch('line-height: 2.5rem;'); expect(css).toMatch('letter-spacing: 0rem;'); }); - }); - it('should error on invalid typescale', () => { - expect(() => - transpile(` - $theme: matx.define-theme(); - div { - font: mat.private-get-theme-typography($theme, subtitle-large); - } - `), - ).toThrowError(/Valid typescales are:.*Got: subtitle-large/); - }); + it('should error on invalid typescale', () => { + expect(() => + transpile(` + $theme: matx.define-theme(); + div { + font: mat.private-get-theme-typography($theme, subtitle-large); + } + `), + ).toThrowError(/Valid typescales are:.*Got: subtitle-large/); + }); - it('should error on invalid typography property', () => { - expect(() => - transpile(` - $theme: matx.define-theme(); - div { - text-transform: mat.private-get-theme-typography($theme, body-small, text-transform); - } - `), - ).toThrowError(/Valid typography properties are:.*Got: text-transform/); - }); + it('should error on invalid typography property', () => { + expect(() => + transpile(` + $theme: matx.define-theme(); + div { + text-transform: mat.private-get-theme-typography($theme, body-small, text-transform); + } + `), + ).toThrowError(/Valid typography properties are:.*Got: text-transform/); + }); + + it('should get density scale', () => { + expect( + transpile(` + $theme: matx.define-theme(); + div { + --density-scale: #{mat.private-get-theme-density($theme)}; + } + `), + ).toMatch('--density-scale: 0;'); + }); - it('should get density scale', () => { - expect( - transpile(` + it('should check what information the theme has', () => { + const css = transpile(` $theme: matx.define-theme(); + $color-only: matx.define-colors(); + $typography-only: matx.define-typography(); + $density-only: matx.define-density(); div { - --density-scale: #{mat.private-get-theme-density($theme)}; + --base: #{( + mat.private-theme-has($theme, base), + mat.private-theme-has($color-only, base), + mat.private-theme-has($typography-only, base), + mat.private-theme-has($density-only, base), + )}; + --color: #{( + mat.private-theme-has($theme, color), + mat.private-theme-has($color-only, color), + mat.private-theme-has($typography-only, color), + mat.private-theme-has($density-only, color), + )}; + --typography: #{( + mat.private-theme-has($theme, typography), + mat.private-theme-has($color-only, typography), + mat.private-theme-has($typography-only, typography), + mat.private-theme-has($density-only, typography), + )}; + --density: #{( + mat.private-theme-has($theme, density), + mat.private-theme-has($color-only, density), + mat.private-theme-has($typography-only, density), + mat.private-theme-has($density-only, density), + )}; } - `), - ).toMatch('--density-scale: 0;'); - }); - - it('should check what information the theme has', () => { - const css = transpile(` - $theme: matx.define-theme(); - $color-only: matx.define-colors(); - $typography-only: matx.define-typography(); - $density-only: matx.define-density(); - div { - --base: #{( - mat.private-theme-has($theme, base), - mat.private-theme-has($color-only, base), - mat.private-theme-has($typography-only, base), - mat.private-theme-has($density-only, base), - )}; - --color: #{( - mat.private-theme-has($theme, color), - mat.private-theme-has($color-only, color), - mat.private-theme-has($typography-only, color), - mat.private-theme-has($density-only, color), - )}; - --typography: #{( - mat.private-theme-has($theme, typography), - mat.private-theme-has($color-only, typography), - mat.private-theme-has($typography-only, typography), - mat.private-theme-has($density-only, typography), - )}; - --density: #{( - mat.private-theme-has($theme, density), - mat.private-theme-has($color-only, density), - mat.private-theme-has($typography-only, density), - mat.private-theme-has($density-only, density), - )}; - } - `); - expect(css).toMatch(/--base: true, false, false, false;/); - expect(css).toMatch(/--color: true, true, false, false;/); - expect(css).toMatch(/--typography: true, false, true, false;/); - expect(css).toMatch(/--density: true, false, false, true;/); - }); + `); + expect(css).toMatch(/--base: true, false, false, false;/); + expect(css).toMatch(/--color: true, true, false, false;/); + expect(css).toMatch(/--typography: true, false, true, false;/); + expect(css).toMatch(/--density: true, false, false, true;/); + }); - it('should error when reading theme type from a theme with no color information', () => { - expect(() => - transpile(` + it('should error when reading theme type from a theme with no color information', () => { + expect(() => + transpile(` $theme: matx.define-density(); div { color: mat.private-get-theme-type($theme); } `), - ).toThrowError(/Color information is not available on this theme/); - }); + ).toThrowError(/Color information is not available on this theme/); + }); - it('should error when reading color from a theme with no color information', () => { - expect(() => - transpile(` + it('should error when reading color from a theme with no color information', () => { + expect(() => + transpile(` $theme: matx.define-density(); div { color: mat.private-get-theme-color($theme, primary); } `), - ).toThrowError(/Color information is not available on this theme/); - }); + ).toThrowError(/Color information is not available on this theme/); + }); - it('should error when reading typography from a theme with no typography information', () => { - expect(() => - transpile(` - $theme: matx.define-density(); - div { - font: mat.private-get-theme-typography($theme, body-small); - } - `), - ).toThrowError(/Typography information is not available on this theme/); - }); + it('should error when reading typography from a theme with no typography information', () => { + expect(() => + transpile(` + $theme: matx.define-density(); + div { + font: mat.private-get-theme-typography($theme, body-small); + } + `), + ).toThrowError(/Typography information is not available on this theme/); + }); - it('should error when reading density from a theme with no density information', () => { - expect(() => - transpile(` - $theme: matx.define-colors(); - div { - --density: #{mat.private-get-theme-density($theme)}; - } - `), - ).toThrowError(/Density information is not available on this theme/); + it('should error when reading density from a theme with no density information', () => { + expect(() => + transpile(` + $theme: matx.define-colors(); + div { + --density: #{mat.private-get-theme-density($theme)}; + } + `), + ).toThrowError(/Density information is not available on this theme/); + }); }); });