@use 'sass:list'; @use 'sass:map'; @use '../style/validation'; @use './m2-inspection'; $internals: _mat-theming-internals-do-not-access; $_m3-typescales: ( display-large, display-medium, display-small, headline-large, headline-medium, headline-small, title-large, title-medium, title-small, label-large, label-medium, label-small, body-large, body-medium, body-small, ); $_typography-properties: (font, font-family, line-height, font-size, letter-spacing, font-weight); /// Validates that the given value is a versioned theme object. /// @param {Any} $theme The theme object to validate. /// @return {Boolean|Null} true if the theme has errors, else null. @function _validate-theme-object($theme) { $err: validation.validate-type($theme, 'map') or map.get($theme, $internals, theme-version) == null; @return if($err, true, null); } /// Gets the version number of a theme object. A theme that is not a valid versioned theme object is /// considered to be version 0. /// @param {Map} $theme The theme to check the version of /// @return {Number} The version number of the theme (0 if unknown). @function get-theme-version($theme) { $err: _validate-theme-object($theme); @return if($err, 0, map.get($theme, $internals, theme-version) or 0); } /// 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) { $version: get-theme-version($theme); @if $version == 0 { @return m2-inspection.get-theme-type($theme); } @else if $version == 1 { @if not theme-has($theme, color) { @error 'Color information is not available on this theme.'; } @return map.get($theme, $internals, theme-type) or light; } @else { @error #{'Unrecognized theme version:'} $version; } } /// Gets a color from a theme object. This function take a different amount of arguments depending /// on if it's working with an M2 or M3 theme: /// - With an M3 theme it accepts either 2 or 3 arguments. If 2 arguments are passed, the second /// argument is treated as the name of a color role. If 3 arguments are passed, the second argument /// is treated as the name of a color palette (primary, secondary, etc.) and the third is treated /// as the palette hue (10, 50, etc.). /// - With an M2 theme theme it accepts between 2 and 4 arguments, or the equivalent of calling /// the `m2-get-theme-color` function. The first argument is the theme, the second one is the /// palette from which to extract the color, the third one is the hue within the palette and the /// fourth is the opacity of the returned color. /// the second one is the /// @param {Map} $theme The theme /// @param {String} $color-role-or-palette-name The name of the color role to get, or the name of a /// color palette. /// @param {Number} $hue The palette hue to get (passing this argument means the second argument is /// interpreted as a palette name). /// @return {Color} The requested theme color. @function get-theme-color($theme, $args...) { $version: get-theme-version($theme); $args-count: list.length($args) + 1; // M2 theme @if $version == 0 { @if $args-count < 2 or $args-count > 4 { @error 'Expected between 2 and 4 arguments when working with an M2 theme. ' + 'Got: #{$args-count}'; } @return m2-inspection.get-theme-color($theme, $args...); } // M3 theme @if $version == 1 { @if $args-count < 2 or $args-count > 3 { @error 'Expected either 2 or 3 arguments when working with an M3 theme. Got: #{$args-count}'; } @return if($args-count == 2, _get-theme-role-color($theme, $args...), _get-theme-palette-color($theme, $args...) ); } @error 'Unrecognized theme version: #{$version}'; } /// Gets a role color from a theme object. /// @param {Map} $theme The theme /// @param {String} $color-role-name The name of the color role to get. /// @return {Color} The requested role color. @function _get-theme-role-color($theme, $color-role-name) { $err: _validate-theme-object($theme); @if $err { // TODO(mmalerba): implement for old style theme objects. @error #{'get-theme-color does not support legacy theme objects.'}; } @if not theme-has($theme, color) { @error 'Color information is not available on this theme.'; } $color-roles: map.get($theme, $internals, color-tokens, (mat, theme)); $result: map.get($color-roles, $color-role-name); @if not $result { @error #{'Valid color roles are: #{map.keys($color-roles)}. Got:'} $color-role-name; } @return $result; } /// Gets a palette color from a theme object. /// @param {Map} $theme The theme /// @param {String} $palette-name The name of the palette to get the color from. /// @param {Number} $hue The hue to read from the palette. /// @return {Color} The requested palette color. @function _get-theme-palette-color($theme, $palette-name, $hue) { $err: _validate-theme-object($theme); @if $err { // TODO(mmalerba): implement for old style theme objects. @error #{'get-theme-color does not support legacy theme objects.'}; } @if not theme-has($theme, color) { @error 'Color information is not available on this theme.'; } $palettes: map.get($theme, $internals, palettes); $palette: map.get($palettes, $palette-name); @if not $palette { $supported-palettes: map.keys($palettes); @error #{'Valid palettes are: #{$supported-palettes}. Got:'} $palette-name; } $result: map.get($palette, $hue); @if not $result { $supported-hues: map.keys($palette); @error #{'Valid hues for'} $palette-name #{'are: #{$supported-hues}. Got:'} $hue; } @return $result; } /// Gets a typography value from a theme object. /// @param {Map} $theme The theme /// @param {String} $typescale The typescale name. /// @param {String} $property The CSS font property to get /// (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: font) { $version: get-theme-version($theme); @if $version == 0 { @return m2-inspection.get-theme-typography($theme, $typescale, $property); } @else if $version == 1 { @if not theme-has($theme, typography) { @error 'Typography information is not available on this theme.'; } @if not list.index($_m3-typescales, $typescale) { @error #{'Valid typescales are: #{$_m3-typescales}. Got:'} $typescale; } @if not list.index($_typography-properties, $property) { @error #{'Valid typography properties are: #{$_typography-properties}. Got:'} $property; } $property-key: map.get(( font: '', font-family: '-font', line-height: '-line-height', font-size: '-size', letter-spacing: '-tracking', font-weight: '-weight' ), $property); $token-name: '#{$typescale}#{$property-key}'; @return map.get($theme, $internals, typography-tokens, (mat, typography), $token-name); } @else { @error #{'Unrecognized theme version:'} $version; } } /// Gets the density scale from a theme object. /// @param {Map} $theme The theme /// @return {Number} The density scale. @function get-theme-density($theme) { $version: get-theme-version($theme); @if $version == 0 { @return m2-inspection.get-theme-density($theme); } @else if $version == 1 { @if not theme-has($theme, density) { @error 'Density information is not available on this theme.'; } @return map.get($theme, $internals, density-scale); } @else { @error #{'Unrecognized theme version:'} $version; } } /// 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) { $version: get-theme-version($theme); @if $version == 0 { @return m2-inspection.theme-has($theme, $system); } @else if $version == 1 { @if $system == base { @return map.get($theme, $internals, base-tokens) != null; } @if $system == color { @return map.get($theme, $internals, color-tokens) != null and map.get($theme, $internals, theme-type) != null and map.get($theme, $internals, palettes) != null; } @if $system == typography { @return map.get($theme, $internals, typography-tokens) != null; } @if $system == density { @return map.get($theme, $internals, density-scale) != null; } @error 'Valid systems are: base, color, typography, density. Got:' $system; } @else { @error #{'Unrecognized theme version:'} $version; } } /// Removes the information about the given theming system(s) from the given theme. /// @param {Map} $theme The theme to remove information from /// @param {String...} $systems The systems to remove /// @return {Map} A version of the theme without the removed theming systems. @function theme-remove($theme, $systems...) { $err: validation.validate-allowed-values($systems, color, typography, density, base); @if $err { @error #{'Expected $systems to contain valid system names (color, typography, density, or'} #{'base). Got invalid system names:'} $err; } $version: get-theme-version($theme); @if $version == 0 { @return m2-inspection.theme-remove($theme, $systems...); } @else if $version == 1 { @each $system in $systems { @if $system == base { $theme: map.deep-remove($theme, $internals, base-tokens); } @else if $system == color { $theme: map.deep-remove($theme, $internals, color-tokens); $theme: map.deep-remove($theme, $internals, theme-type); $theme: map.deep-remove($theme, $internals, palettes); } @else if $system == typography { $theme: map.deep-remove($theme, $internals, typography-tokens); } @else if $system == density { $theme: map.deep-remove($theme, $internals, density-scale); $theme: map.deep-remove($theme, $internals, density-tokens); } } @return $theme; } } /// Gets a version of the theme with a modified typography config that preserves old behavior in /// some components that previously used `private-typography-to-2014-config`. /// Do not introduce new usages of this, it should be cleaned up and removed. /// @deprecated @function private-get-typography-back-compat-theme($theme) { @return if( get-theme-version($theme) == 0, m2-inspection.private-get-typography-back-compat-theme($theme), $theme ); }