Skip to content

Commit

Permalink
feat(multiple): fallback to system level variables (#29480)
Browse files Browse the repository at this point in the history
* feat(multiple): fallback to system level variables

* feat(multiple): create sass util for checking css var name

* feat(multiple): add docs for generate-tokens density param

* feat(multiple): make some properties/functions private

* feat(multiple): lint fixes

* feat(multiple): add todo for weird param

* feat(multiple): add check for using color mix
  • Loading branch information
andrewseguin authored Jul 31, 2024
1 parent 5403b2b commit db5b8dc
Show file tree
Hide file tree
Showing 7 changed files with 209 additions and 57 deletions.
4 changes: 3 additions & 1 deletion src/material/_index.scss
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,9 @@
@forward './core/typography/typography' show typography-hierarchy;
@forward './core/typography/typography-utils' show font-shorthand;
@forward './core/tokens/m2' show m2-tokens-from-theme;
@forward './core/tokens/m3-tokens' show system-level-colors, system-level-typography;
@forward './core/tokens/m3-tokens' show system-level-colors,
system-level-typography, system-level-elevation, system-level-shape,
system-level-motion, system-level-state;

// Private/Internal
@forward './core/density/private/all-density' show all-component-densities;
Expand Down
5 changes: 5 additions & 0 deletions src/material/core/style/_elevation.scss
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
@use 'sass:meta';
@use 'sass:string';
@use './variables';
@use './sass-utils';

$_umbra-opacity: 0.2;
$_penumbra-opacity: 0.14;
Expand Down Expand Up @@ -143,6 +144,10 @@ $prefix: 'mat-elevation-z';
@return null;
}

@if (sass-utils.is-css-var-name($zValue)) {
@return $zValue;
}

@if meta.type-of($zValue) != number or not math.is-unitless($zValue) {
@error '$zValue must be a unitless number, but received `#{$zValue}`';
}
Expand Down
22 changes: 20 additions & 2 deletions src/material/core/style/_sass-utils.scss
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
@use 'sass:color';
@use 'sass:string';
@use 'sass:list';
@use 'sass:map';
@use 'sass:meta';
Expand Down Expand Up @@ -64,12 +65,23 @@ $use-system-typography-variables: false;
/// A version of the Sass `color.change` function that is safe ot use with CSS variables.
@function safe-color-change($color, $args...) {
$args: meta.keywords($args);
$use-color-mix: $use-system-color-variables or
(is-css-var-name($color) and string.index($color, '--mat') == 1);
@if (meta.type-of($color) == 'color') {
@return color.change($color, $args...);
}
@else if ($color != null and map.get($args, alpha) != null and $use-system-color-variables) {
@else if ($color != null and
map.get($args, alpha) != null and $use-color-mix) {
$opacity: map.get($args, alpha);
@return #{color-mix(in srgb, #{$color} #{($opacity * 100) + '%'}, transparent)};
@if meta.type-of($opacity) == number {
$opacity: ($opacity * 100) + '%';
}

@if (is-css-var-name($color)) {
$color: var($color);
}

@return #{color-mix(in srgb, #{$color} #{$opacity}, transparent)};
}
@return $color;
}
Expand All @@ -91,3 +103,9 @@ $use-system-typography-variables: false;
}
@return $kwargs;
}

// Returns whether the $value is a CSS variable name based on whether it's a string prefixed
// by "--".
@function is-css-var-name($value) {
@return meta.type-of($value) == string and string.index($value, '--') == 1;
}
118 changes: 106 additions & 12 deletions src/material/core/tokens/_m3-tokens.scss
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,17 @@
@use './m3';
@use './m3/definitions' as m3-token-definitions;
@use '../tokens/m2' as m2-tokens;
@use '../style/elevation';
@use './density';
@use './format-tokens';

// Default system level prefix to use when directly calling the `system-level-*` mixins
$_system-level-prefix: sys;

// Prefix used for component token fallback variables, e.g.
// `color: var(--mdc-text-button-label-text-color, var(--mat-app-primary));`
$_system-fallback-prefix: mat-app;

/// Generates tokens for the given palette with the given prefix.
/// @param {Map} $palette The palette to generate tokens for
/// @param {String} $prefix The key prefix used to name the tokens
Expand Down Expand Up @@ -86,8 +94,9 @@ $_cached-token-slots: null;
/// Generates a set of namespaced tokens for all components.
/// @param {Map} $systems The MDC system tokens
/// @param {Boolean} $include-non-systemized Whether to include non-systemized tokens
/// @param {Boolean} $include-density Whether to include density tokens
/// @return {Map} A map of namespaced tokens
@function _generate-tokens($systems, $include-non-systemized: false) {
@function _generate-tokens($systems, $include-non-systemized: false, $include-density: false) {
$systems: map.merge((
md-sys-color: (),
md-sys-elevation: (),
Expand Down Expand Up @@ -116,16 +125,63 @@ $_cached-token-slots: null;
// Strip out tokens that are systemized by our made up density system.
@each $namespace, $tokens in $result {
@each $token, $value in $tokens {
@if density.is-systemized($namespace, $token) {
@if density.is-systemized($namespace, $token) and not $include-density {
$tokens: map.remove($tokens, $token);
}
}
$result: map.set($result, $namespace, $tokens);
}

@return $result;
}

@mixin system-level-colors($theme, $overrides: ()) {
// Return a new map where the values are the same as the provided map's
// keys, prefixed with "--mat-app-". For example:
// (key1: '', key2: '') --> (key1: --mat-app-key1, key2: --mat-app-key2)
@function _create-system-app-vars-map($map) {
$new-map: ();
@each $key, $value in $map {
$new-map: map.set($new-map, $key, --#{$_system-fallback-prefix}-#{$key});
}
@return $new-map;
}

// Create a components tokens map where values are based on
// system fallback variables referencing Material's system keys.
// Includes density token fallbacks where density is 0.
@function create-system-fallbacks() {
$app-vars: (
'md-sys-color':
_create-system-app-vars-map(m3-token-definitions.md-sys-color-values-light()),
'md-sys-typescale':
_create-system-app-vars-map(m3-token-definitions.md-sys-typescale-values()),
'md-sys-elevation':
_create-system-app-vars-map(m3-token-definitions.md-sys-elevation-values()),
'md-sys-state':
_create-system-app-vars-map(m3-token-definitions.md-sys-state-values()),
'md-sys-shape':
_create-system-app-vars-map(m3-token-definitions.md-sys-shape-values()),
);

@return sass-utils.deep-merge-all(
_generate-tokens($app-vars, true, true),
generate-density-tokens(0)
);
}

// Emits CSS variables for Material's system level values. Uses the
// namespace prefix in $_system-fallback-prefix.
// e.g. --mat-app-surface: #E5E5E5
@mixin theme($theme, $overrides: ()) {
@include system-level-colors($theme, $overrides, $_system-fallback-prefix);
@include system-level-typography($theme, $overrides, $_system-fallback-prefix);
@include system-level-elevation($theme, $overrides, $_system-fallback-prefix);
@include system-level-shape($theme, $overrides, $_system-fallback-prefix);
@include system-level-motion($theme, $overrides, $_system-fallback-prefix);
@include system-level-state($theme, $overrides, $_system-fallback-prefix);
}

@mixin system-level-colors($theme, $overrides: (), $prefix: null) {
$palettes: map.get($theme, _mat-theming-internals-do-not-access, palettes);
$base-palettes: (
neutral: map.get($palettes, neutral),
Expand All @@ -135,12 +191,15 @@ $_cached-token-slots: null;
);

$type: map.get($theme, _mat-theming-internals-do-not-access, theme-type);
$system-variables-prefix: map.get($theme, _mat-theming-internals-do-not-access,
color-system-variables-prefix) or sys;
$primary: map.merge(map.get($palettes, primary), $base-palettes);
$tertiary: map.merge(map.get($palettes, tertiary), $base-palettes);
$error: map.get($palettes, error);

@if (not $prefix) {
$prefix: map.get($theme, _mat-theming-internals-do-not-access,
color-system-variables-prefix) or $_system-level-prefix;
}

$ref: (
md-ref-palette: _generate-ref-palette-tokens($primary, $tertiary, $error)
);
Expand All @@ -150,27 +209,28 @@ $_cached-token-slots: null;
m3-token-definitions.md-sys-color-values-light($ref));

@each $name, $value in $sys-colors {
--#{$system-variables-prefix}-#{$name}: #{map.get($overrides, $name) or $value};
--#{$prefix}-#{$name}: #{map.get($overrides, $name) or $value};
}
}

@mixin system-level-typography($theme, $overrides: ()) {
@mixin system-level-typography($theme, $overrides: (), $prefix: null) {
$font-definition: map.get($theme, _mat-theming-internals-do-not-access, font-definition);
$brand: map.get($font-definition, brand);
$plain: map.get($font-definition, plain);
$bold: map.get($font-definition, bold);
$medium: map.get($font-definition, medium);
$regular: map.get($font-definition, regular);
$system-variables-prefix: map.get($theme, _mat-theming-internals-do-not-access,
typography-system-variables-prefix) or sys;
$ref: (
md-ref-typeface: _generate-ref-typeface-tokens($brand, $plain, $bold, $medium, $regular)
);

$sys-typescale: m3-token-definitions.md-sys-typescale-values($ref);
@if (not $prefix) {
$prefix: map.get($theme, _mat-theming-internals-do-not-access,
typography-system-variables-prefix) or $_system-level-prefix;
}

@each $name, $value in $sys-typescale {
--#{$system-variables-prefix}-#{$name}: #{map.get($overrides, $name) or $value};
@each $name, $value in m3-token-definitions.md-sys-typescale-values($ref) {
--#{$prefix}-#{$name}: #{map.get($overrides, $name) or $value};
}
}

Expand All @@ -182,6 +242,40 @@ $_cached-token-slots: null;
@return $result;
}

@mixin system-level-elevation($theme, $overrides: (), $prefix: $_system-level-prefix) {
$shadow-color: map.get(
$theme, _mat-theming-internals-do-not-access, color-tokens, (mdc, theme), shadow);

@for $level from 0 through 24 {
$value: elevation.get-box-shadow($level, $shadow-color);
--#{$prefix}-elevation-shadow-level-#{$level}: #{$value};
}

@each $name, $value in m3-token-definitions.md-sys-elevation-values() {
$level: map.get($overrides, $name) or $value;
$value: elevation.get-box-shadow($level, $shadow-color);
--#{$prefix}-#{$name}: #{$value};
}
}

@mixin system-level-shape($theme, $overrides: (), $prefix: $_system-level-prefix) {
@each $name, $value in m3-token-definitions.md-sys-shape-values() {
--#{$prefix}-#{$name}: #{map.get($overrides, $name) or $value};
}
}

@mixin system-level-state($theme, $overrides: (), $prefix: $_system-level-prefix) {
@each $name, $value in m3-token-definitions.md-sys-state-values() {
--#{$prefix}-#{$name}: #{map.get($overrides, $name) or $value};
}
}

@mixin system-level-motion($theme, $overrides: (), $prefix: $_system-level-prefix) {
@each $name, $value in m3-token-definitions.md-sys-motion-values() {
--#{$prefix}-#{$name}: #{map.get($overrides, $name) or $value};
}
}

@function _get-sys-color($type, $ref, $prefix) {
$mdc-sys-color: if($type == dark,
m3-token-definitions.md-sys-color-values-dark($ref),
Expand Down
6 changes: 6 additions & 0 deletions src/material/core/tokens/_token-definition.scss
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
@use '../m2/palette' as m2-palette;
@use '../m2/theming' as m2-theming;
@use '../m2/typography' as m2-typography;
@use '../style/sass-utils';
@use './m3/definitions' as m3-token-definitions;

// Indicates whether we're building internally. Used for backwards compatibility.
Expand Down Expand Up @@ -161,6 +162,11 @@ $_system-fallbacks: null;
$color-key: map.get($pair, color);
$opacity-key: map.get($pair, opacity);
$color: map.get($tokens, $color-key);

@if (sass-utils.is-css-var-name($color)) {
$color: var(#{$color});
}

$opacity: map.get($opacity-lookup, $opacity-key);

@if(meta.type-of($color) == 'color') {
Expand Down
Loading

0 comments on commit db5b8dc

Please sign in to comment.