Skip to content

Commit

Permalink
refactor(material/select): switch to tokens API (angular#27310)
Browse files Browse the repository at this point in the history
Reworks the select to use the new tokens-based theming API.
  • Loading branch information
crisbeto authored Jun 16, 2023
1 parent c86e1ef commit 575c21c
Show file tree
Hide file tree
Showing 3 changed files with 167 additions and 74 deletions.
72 changes: 72 additions & 0 deletions src/material/core/tokens/m2/mat/_select.scss
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
@use 'sass:map';
@use '../../token-utils';
@use '../../../typography/typography-utils';
@use '../../../mdc-helpers/mdc-helpers';
@use '../../../theming/theming';
@use '../../../style/sass-utils';

// The prefix used to generate the fully qualified name for tokens in this file.
$prefix: (mat, select);

// Tokens that can't be configured through Angular Material's current theming API,
// but may be in a future version of the theming API.
@function get-unthemable-tokens() {
@return ();
}

// Tokens that can be configured through Angular Material's color theming API.
@function get-color-tokens($config) {
$is-dark: map.get($config, is-dark);
$foreground: map.get($config, foreground);
$background: map.get($config, background);
$primary: map.get($config, primary);
$warn: map.get($config, warn);
$on-surface: if($is-dark, #fff, #000);

@return (
panel-background-color: theming.get-color-from-palette($background, card),
enabled-trigger-color: rgba($on-surface, 0.87),
disabled-trigger-color: rgba($on-surface, 0.38),
placeholder-color: rgba($on-surface, 0.6),
enabled-arrow-color: rgba($on-surface, 0.54),
disabled-arrow-color: rgba($on-surface, 0.38),
focused-arrow-color: theming.get-color-from-palette($primary, default, 0.87),
invalid-arrow-color: theming.get-color-from-palette($warn, default, 0.87),
);
}

// Tokens that can be configured through Angular Material's typography theming API.
@function get-typography-tokens($config) {
// TODO(crisbeto): The earlier implementation of the select used MDC's APIs to create the
// typography tokens. As a result, we unintentionally allowed `null` typography configs to be
// passed in. Since there a lot of apps that now depend on this pattern, we need this temporary
// fallback.
@if ($config == null) {
$config: mdc-helpers.private-fallback-typography-from-mdc();
}

@return (
trigger-font: typography-utils.font-family($config, body-1) or
typography-utils.font-family($config),
trigger-line-height: typography-utils.line-height($config, body-1),
trigger-size: typography-utils.font-size($config, body-1),
trigger-tracking: typography-utils.letter-spacing($config, body-1),
trigger-weight: typography-utils.font-weight($config, body-1)
);
}

// Tokens that can be configured through Angular Material's density theming API.
@function get-density-tokens($config) {
@return ();
}

// Combines the tokens generated by the above functions into a single map with placeholder values.
// This is used to create token slots.
@function get-token-slots() {
@return sass-utils.deep-merge-all(
get-unthemable-tokens(),
get-color-tokens(token-utils.$placeholder-color-config),
get-typography-tokens(token-utils.$placeholder-typography-config),
get-density-tokens(token-utils.$placeholder-density-config)
);
}
85 changes: 25 additions & 60 deletions src/material/select/_select-theme.scss
Original file line number Diff line number Diff line change
@@ -1,83 +1,43 @@
@use '@material/theme/theme-color' as mdc-theme-color;
@use '@material/menu-surface' as mdc-menu-surface;
@use '@material/list/evolution-mixins' as mdc-list;
@use '@material/typography' as mdc-typography;
@use 'sass:map';
@use '@material/density' as mdc-density;
@use '@material/textfield' as mdc-textfield;
@use '../core/tokens/m2/mat/select' as tokens-mat-select;
@use '../core/tokens/token-utils';
@use '../core/style/sass-utils';

@use '../core/theming/theming';
@use '../core/typography/typography';
@use '../core/mdc-helpers/mdc-helpers';


// Gets the color to use for some text that is highlighted while a select has focus.
@function _get-mdc-focused-text-color($palette) {
@return rgba(mdc-theme-color.prop-value($palette), 0.87);
}

@mixin color($config-or-theme) {
$config: theming.get-color-config($config-or-theme);

@include mdc-helpers.using-mdc-theme($config) {
$disabled-color: rgba(mdc-theme-color.prop-value(on-surface), 0.38);
@include mdc-menu-surface.core-styles(mdc-helpers.$mdc-theme-styles-query);
@include mdc-list.without-ripple(mdc-helpers.$mdc-theme-styles-query);

.mat-mdc-select-value {
color: rgba(mdc-theme-color.prop-value(on-surface), 0.87);
}

.mat-mdc-select-placeholder {
color: rgba(mdc-theme-color.prop-value(on-surface), 0.6);
}

.mat-mdc-select-disabled .mat-mdc-select-value {
color: $disabled-color;
}
@include sass-utils.current-selector-or-root() {
@include token-utils.create-token-values(tokens-mat-select.$prefix,
tokens-mat-select.get-color-tokens($config));

.mat-mdc-select-arrow {
color: rgba(mdc-theme-color.prop-value(on-surface), 0.54);
.mat-mdc-form-field.mat-accent {
$accent: map.get($config, accent);
$accent-config: map.merge($config, (primary: $accent));
@include token-utils.create-token-values(tokens-mat-select.$prefix,
tokens-mat-select.get-color-tokens($accent-config));
}

.mat-mdc-form-field {
&.mat-focused {
&.mat-primary .mat-mdc-select-arrow {
color: _get-mdc-focused-text-color(primary);
}

&.mat-accent .mat-mdc-select-arrow {
color: _get-mdc-focused-text-color(secondary);
}

&.mat-warn .mat-mdc-select-arrow {
color: _get-mdc-focused-text-color(error);
}
}

.mat-mdc-select.mat-mdc-select-invalid .mat-mdc-select-arrow {
color: _get-mdc-focused-text-color(error);
}

.mat-mdc-select.mat-mdc-select-disabled .mat-mdc-select-arrow {
color: $disabled-color;
}
.mat-mdc-form-field.mat-warn {
$warn: map.get($config, warn);
$warn-config: map.merge($config, (primary: $warn));
@include token-utils.create-token-values(tokens-mat-select.$prefix,
tokens-mat-select.get-color-tokens($warn-config));
}
}
}

@mixin typography($config-or-theme) {
$config: typography.private-typography-to-2018-config(
theming.get-typography-config($config-or-theme));
@include mdc-helpers.using-mdc-typography($config) {
@include mdc-menu-surface.core-styles(mdc-helpers.$mdc-typography-styles-query);

.mat-mdc-select-panel {
@include mdc-list.list-base(mdc-helpers.$mdc-typography-styles-query);
}

.mat-mdc-select {
@include mdc-typography.typography(body1, $query: mdc-helpers.$mdc-typography-styles-query);
}
@include sass-utils.current-selector-or-root() {
@include token-utils.create-token-values(tokens-mat-select.$prefix,
tokens-mat-select.get-typography-tokens($config));
}
}

Expand All @@ -98,6 +58,11 @@
transform: none;
}
}

@include sass-utils.current-selector-or-root() {
@include token-utils.create-token-values(tokens-mat-select.$prefix,
tokens-mat-select.get-density-tokens($density-scale));
}
}

@mixin theme($theme-or-color-config) {
Expand Down
84 changes: 70 additions & 14 deletions src/material/select/select.scss
Original file line number Diff line number Diff line change
@@ -1,9 +1,11 @@
@use 'sass:math';
@use '@angular/cdk';
@use '@material/menu-surface' as mdc-menu-surface;
@use '@material/list/evolution-mixins' as mdc-list;
@use '@material/typography/typography' as mdc-typography;
@use '../core/style/elevation';
@use '../core/style/vendor-prefixes';
@use '../core/style/variables';
@use '../core/tokens/token-utils';
@use '../core/tokens/m2/mat/select' as tokens-mat-select;

$mat-select-arrow-size: 5px !default;
$mat-select-arrow-margin: 4px !default;
Expand All @@ -13,15 +15,29 @@ $mat-select-placeholder-arrow-space: 2 *
$leading-width: 12px !default;
$scale: 0.75 !default;

// We base the select panel styling on top of MDC's menu styles and we
// implement the trigger ourselves since MDC doesn't provide an equivalent.

@include mdc-menu-surface.core-styles($query: structure);

.mat-mdc-select {
display: inline-block;
width: 100%;
outline: none;

@include token-utils.use-tokens(
tokens-mat-select.$prefix, tokens-mat-select.get-token-slots()) {
@include mdc-typography.smooth-font();
@include token-utils.create-token-slot(color, enabled-trigger-color);
@include token-utils.create-token-slot(font-family, trigger-font);
@include token-utils.create-token-slot(line-height, trigger-line-height);
@include token-utils.create-token-slot(font-size, trigger-size);
@include token-utils.create-token-slot(font-weight, trigger-weight);
@include token-utils.create-token-slot(letter-spacing, trigger-tracking);
}
}

.mat-mdc-select-disabled {
@include token-utils.use-tokens(
tokens-mat-select.$prefix, tokens-mat-select.get-token-slots()) {
@include token-utils.create-token-slot(color, disabled-trigger-color);
}
}

.mat-mdc-select-trigger {
Expand All @@ -32,9 +48,15 @@ $scale: 0.75 !default;
box-sizing: border-box;
width: 100%;

.mat-mdc-select-disabled & {
@include vendor-prefixes.user-select(none);
cursor: default;
@include token-utils.use-tokens(
tokens-mat-select.$prefix, tokens-mat-select.get-token-slots()) {
@include token-utils.create-token-slot(color, enabled-trigger-color);

.mat-mdc-select-disabled & {
@include vendor-prefixes.user-select(none);
@include token-utils.create-token-slot(color, disabled-trigger-color);
cursor: default;
}
}
}

Expand Down Expand Up @@ -72,6 +94,23 @@ $scale: 0.75 !default;
height: $mat-select-arrow-size;
position: relative;

@include token-utils.use-tokens(
tokens-mat-select.$prefix, tokens-mat-select.get-token-slots()) {
@include token-utils.create-token-slot(color, enabled-arrow-color);

.mat-mdc-form-field.mat-focused & {
@include token-utils.create-token-slot(color, focused-arrow-color);
}

.mat-mdc-form-field .mat-mdc-select.mat-mdc-select-invalid & {
@include token-utils.create-token-slot(color, invalid-arrow-color);
}

.mat-mdc-form-field .mat-mdc-select.mat-mdc-select-disabled & {
@include token-utils.create-token-slot(color, disabled-arrow-color);
}
}

svg {
fill: currentColor;
position: absolute;
Expand All @@ -91,15 +130,27 @@ $scale: 0.75 !default;
}
}

// Note that the `.mdc-menu-surface` is here in order to bump up the specificity
// and avoid interference with `mat-menu` which uses the same mixins from MDC.
.mdc-menu-surface.mat-mdc-select-panel {
// Even though we don't use the MDC styles, we need to keep the classes in the
// DOM for the Gmat versions to work. We need to bump up the specificity here
// so that it's higher than MDC's styles.
div.mat-mdc-select-panel {
@include elevation.elevation(8);
width: 100%; // Ensures that the panel matches the overlay width.
max-height: $mat-select-panel-max-height;
position: static; // MDC uses `absolute` by default which will throw off our positioning.
outline: 0;
overflow: auto;
padding: 8px 0;
border-radius: 4px;
box-sizing: border-box;

// Workaround in case other MDC menu surface styles bleed in.
position: static;

@include token-utils.use-tokens(
tokens-mat-select.$prefix, tokens-mat-select.get-token-slots()) {
@include token-utils.create-token-slot(background-color, panel-background-color);
}

@include mdc-list.list-base($query: structure);
@include cdk.high-contrast(active, off) {
outline: solid 1px;
}
Expand All @@ -124,6 +175,11 @@ $scale: 0.75 !default;
math.div(variables.$swift-ease-out-duration, 3)
variables.$swift-ease-out-timing-function;

@include token-utils.use-tokens(
tokens-mat-select.$prefix, tokens-mat-select.get-token-slots()) {
@include token-utils.create-token-slot(color, placeholder-color);
}

._mat-animation-noopable & {
transition: none;
}
Expand Down

0 comments on commit 575c21c

Please sign in to comment.