Skip to content

Commit

Permalink
refactor(material/form-field): switch color styles to tokens (#27581)
Browse files Browse the repository at this point in the history
Reworks our custom color styles on top of MDC to use tokens.
  • Loading branch information
crisbeto authored Aug 4, 2023
1 parent 03a773a commit 98f610d
Show file tree
Hide file tree
Showing 11 changed files with 128 additions and 231 deletions.
35 changes: 34 additions & 1 deletion src/material/core/tokens/m2/mat/_form-field.scss
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
@use 'sass:map';
@use '../../token-utils';
@use '../../../style/sass-utils';
@use '../../../theming/theming';
@use '../../../theming/palette';

// The prefix used to generate the fully qualified name for tokens in this file.
$prefix: (mat, form-field);
Expand All @@ -13,12 +15,43 @@ $prefix: (mat, form-field);

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

@return (
@return map.merge($color-tokens, (
// MDC has a token for the enabled placeholder, but not for the disabled one.
disabled-input-text-placeholder-color: rgba($on-surface, 0.38),
state-layer-color: rgba($on-surface, 0.87),
error-text-color: theming.get-color-from-palette($warn),

// On dark themes we set the native `select` color to some shade of white,
// however the color propagates to all of the `option` elements, which are
// always on a white background inside the dropdown, causing them to blend in.
// Since we can't change background of the dropdown, we need to explicitly
// reset the color of the options to something dark.
select-option-text-color: if($is-dark, palette.$dark-primary-text, inherit),
// Note the spelling of the `GrayText` here which is a system color. See:
// https://developer.mozilla.org/en-US/docs/Web/CSS/system-color
select-disabled-option-text-color: if($is-dark, palette.$dark-disabled-text, GrayText),

// These values are taken from the MDC select implementation:
// https://github.com/material-components/material-components-web/blob/master/packages/mdc-select/_select-theme.scss
enabled-select-arrow-color: rgba($on-surface, 0.54),
disabled-select-arrow-color: rgba($on-surface, 0.38),

hover-state-layer-opacity: if($is-dark, 0.08, 0.04),
focus-state-layer-opacity: if($is-dark, 0.24, 0.12),
));
}

// Generates the mapping for the properties that change based on the form field color.
@function private-get-color-palette-color-tokens($config, $palette-name) {
$palette: map.get($config, $palette-name);

@return (
focus-select-arrow-color: theming.get-color-from-palette($palette, default, 0.87),
);
}

Expand Down
2 changes: 1 addition & 1 deletion src/material/core/tokens/m2/mdc/_filled-text-field.scss
Original file line number Diff line number Diff line change
Expand Up @@ -133,7 +133,7 @@ $prefix: (mdc, filled-text-field);
@return $first-color;
}

// Generates the mapping for the properties that change based on the slide toggle color.
// Generates the mapping for the properties that change based on the text field color.
@function private-get-color-palette-color-tokens($config, $palette-name) {
$palette: map.get($config, $palette-name);
$palette-color: theming.get-color-from-palette($palette);
Expand Down
2 changes: 1 addition & 1 deletion src/material/core/tokens/m2/mdc/_outlined-text-field.scss
Original file line number Diff line number Diff line change
Expand Up @@ -116,7 +116,7 @@ $prefix: (mdc, outlined-text-field);
));
}

// Generates the mapping for the properties that change based on the slide toggle color.
// Generates the mapping for the properties that change based on the text field color.
@function private-get-color-palette-color-tokens($config, $palette-name) {
$palette: map.get($config, $palette-name);
$palette-color: theming.get-color-from-palette($palette);
Expand Down
1 change: 0 additions & 1 deletion src/material/form-field/BUILD.bazel
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,6 @@ sass_library(
name = "form_field_scss_lib",
srcs = [
"_form-field-theme.scss",
"_mdc-text-field-theme-variable-refresh.scss",
],
deps = [
":form_field_partials",
Expand Down
31 changes: 13 additions & 18 deletions src/material/form-field/_form-field-focus-overlay.scss
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
@use '@material/ripple/functions' as mdc-ripple-functions;
@use '@material/textfield' as mdc-textfield;
@use '../core/tokens/m2/mat/form-field' as tokens-mat-form-field;
@use '../core/tokens/token-utils';
@use '../core/style/layout-common';

// MDC text-field uses `@material/ripple` in order to show a focus and hover effect for
Expand All @@ -13,24 +13,19 @@
.mat-mdc-form-field-focus-overlay {
@include layout-common.fill;
opacity: 0;
// Make sure we don't block click on the prefix/suffix.
pointer-events: none;
}
}

@mixin private-form-field-focus-overlay-color() {
$focus-opacity: mdc-ripple-functions.states-opacity(mdc-textfield.$ink-color, focus);
$hover-opacity: mdc-ripple-functions.states-opacity(mdc-textfield.$ink-color, hover);
pointer-events: none; // Make sure we don't block click on the prefix/suffix.

.mat-mdc-form-field-focus-overlay {
background-color: mdc-textfield.$ink-color;
}
@include token-utils.use-tokens(
tokens-mat-form-field.$prefix, tokens-mat-form-field.get-token-slots()) {
@include token-utils.create-token-slot(background-color, state-layer-color);

.mat-mdc-form-field:hover .mat-mdc-form-field-focus-overlay {
opacity: $hover-opacity;
}
.mat-mdc-form-field:hover & {
@include token-utils.create-token-slot(opacity, hover-state-layer-opacity);
}

.mat-mdc-form-field.mat-focused .mat-mdc-form-field-focus-overlay {
opacity: $focus-opacity;
.mat-mdc-form-field.mat-focused & {
@include token-utils.create-token-slot(opacity, focus-state-layer-opacity);
}
}
}
}
97 changes: 30 additions & 67 deletions src/material/form-field/_form-field-native-select.scss
Original file line number Diff line number Diff line change
@@ -1,8 +1,6 @@
@use 'sass:map';
@use 'sass:math';
@use '@material/theme/theme-color' as mdc-theme-color;
@use '../core/theming/palette';
@use '../core/mdc-helpers/mdc-helpers';
@use '../core/tokens/m2/mat/form-field' as tokens-mat-form-field;
@use '../core/tokens/token-utils';

// Width of the Material Design form-field select arrow.
$mat-form-field-select-arrow-width: 10px;
Expand All @@ -12,6 +10,8 @@ $mat-form-field-select-arrow-height: 5px;
// that the absolute positioned arrow does not overlap the select content.
$mat-form-field-select-horizontal-end-padding: $mat-form-field-select-arrow-width + 5px;

$_tokens: tokens-mat-form-field.$prefix, tokens-mat-form-field.get-token-slots();

// Mixin that creates styles for native select controls in a form-field.
@mixin private-form-field-native-select() {
// Remove the native select down arrow and ensure that the native appearance
Expand All @@ -30,6 +30,18 @@ $mat-form-field-select-horizontal-end-padding: $mat-form-field-select-arrow-widt
&:not(:disabled) {
cursor: pointer;
}

&:not(.mat-mdc-native-select-inline) {
@include token-utils.use-tokens($_tokens...) {
option {
@include token-utils.create-token-slot(color, select-option-text-color);
}

option:disabled {
@include token-utils.create-token-slot(color, select-disabled-option-text-color);
}
}
}
}

// Native select elements with the `matInput` directive should have Material Design
Expand All @@ -52,12 +64,26 @@ $mat-form-field-select-horizontal-end-padding: $mat-form-field-select-arrow-widt
// Make the arrow non-clickable so the user can click on the form control under it.
pointer-events: none;

@include token-utils.use-tokens($_tokens...) {
@include token-utils.create-token-slot(color, enabled-select-arrow-color);
}

[dir='rtl'] & {
right: auto;
left: 0;
}
}

@include token-utils.use-tokens($_tokens...) {
&.mat-focused .mat-mdc-form-field-infix::after {
@include token-utils.create-token-slot(color, focus-select-arrow-color);
}

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

// Add padding on the end of the native select so that the content does not
// overlap with the Material Design arrow.
.mat-mdc-form-field-input-control {
Expand All @@ -69,66 +95,3 @@ $mat-form-field-select-horizontal-end-padding: $mat-form-field-select-arrow-widt
}
}
}

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

@mixin private-form-field-native-select-color($config) {
@include mdc-helpers.using-mdc-theme($config) {
// These values are taken from the MDC select implementation:
// https://github.com/material-components/material-components-web/blob/master/packages/mdc-select/_select-theme.scss
$dropdown-icon-color: rgba(mdc-theme-color.prop-value(on-surface), 0.54);
$disabled-dropdown-icon-color: rgba(mdc-theme-color.prop-value(on-surface), 0.38);

select.mat-mdc-form-field-input-control:not(.mat-mdc-native-select-inline) {
// On dark themes we set the native `select` color to some shade of white,
// however the color propagates to all of the `option` elements, which are
// always on a white background inside the dropdown, causing them to blend in.
// Since we can't change background of the dropdown, we need to explicitly
// reset the color of the options to something dark.
@if (map.get($config, is-dark)) {
option {
color: palette.$dark-primary-text;
}

option:disabled {
color: palette.$dark-disabled-text;
}
}
}

.mat-mdc-form-field-type-mat-native-select {
.mat-mdc-form-field-infix::after {
color: $dropdown-icon-color;
}

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

&.mat-accent {
.mat-mdc-form-field-infix::after {
color: _get-focused-arrow-color(secondary);
}
}

&.mat-warn {
.mat-mdc-form-field-infix::after {
color: _get-focused-arrow-color(error);
}
}
}

&.mat-form-field-disabled {
.mat-mdc-form-field-infix::after {
color: $disabled-dropdown-icon-color;
}
}
}
}
}
14 changes: 6 additions & 8 deletions src/material/form-field/_form-field-subscript.scss
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
@use '@material/textfield' as mdc-textfield;
@use '@material/theme/theme' as mdc-theme;
@use '@material/typography' as mdc-typography;
@use '@material/textfield/variables' as mdc-textfield-variables;

@use '../core/tokens/m2/mat/form-field' as tokens-mat-form-field;
@use '../core/tokens/token-utils';
@use '../core/theming/theming';
@use '../core/mdc-helpers/mdc-helpers';
@use './form-field-sizing';
Expand Down Expand Up @@ -58,13 +58,11 @@
// Single error message displayed beneath the form field underline.
.mat-mdc-form-field-error {
display: block;
}
}

@mixin private-form-field-subscript-color() {
// MDC does not have built-in error treatment.
.mat-mdc-form-field-error {
@include mdc-theme.prop(color, mdc-textfield.$error);
@include token-utils.use-tokens(
tokens-mat-form-field.$prefix, tokens-mat-form-field.get-token-slots()) {
@include token-utils.create-token-slot(color, error-text-color);
}
}
}

Expand Down
61 changes: 15 additions & 46 deletions src/material/form-field/_form-field-theme.scss
Original file line number Diff line number Diff line change
Expand Up @@ -12,9 +12,6 @@
@use '../core/tokens/token-utils';
@use './form-field-density';
@use './form-field-subscript';
@use './form-field-focus-overlay';
@use './form-field-native-select';
@use './mdc-text-field-theme-variable-refresh';

@mixin color($config-or-theme) {
$config: theming.get-color-config($config-or-theme);
Expand All @@ -28,50 +25,22 @@
tokens-mat-form-field.get-color-tokens($config));
}

@include mdc-helpers.using-mdc-theme($config) {
@include mdc-text-field-theme-variable-refresh.private-text-field-refresh-theme-variables() {
@include form-field-subscript.private-form-field-subscript-color();
@include form-field-focus-overlay.private-form-field-focus-overlay-color();
@include form-field-native-select.private-form-field-native-select-color($config);

.mat-mdc-form-field.mat-accent {
@include mdc-filled-text-field-theme.theme(
tokens-mdc-filled-text-field.private-get-color-palette-color-tokens($config, accent));
@include mdc-outlined-text-field-theme.theme(
tokens-mdc-outlined-text-field.private-get-color-palette-color-tokens($config, accent));
}

.mat-mdc-form-field.mat-warn {
@include mdc-filled-text-field-theme.theme(
tokens-mdc-filled-text-field.private-get-color-palette-color-tokens($config, warn));
@include mdc-outlined-text-field-theme.theme(
tokens-mdc-outlined-text-field.private-get-color-palette-color-tokens($config, warn));
}

// This fixes an issue where the notch appears to be thicker than the rest of the outline when
// zoomed in on Chrome. The border inconsistency seems to be some kind of rendering artifact
// that arises from a combination of the fact that the notch contains text, while the leading
// and trailing outline do not, combined with the fact that the border is semi-transparent.
// Experimentally, I discovered that adding a transparent left border fixes the inconsistency.
// Note: class name is repeated to achieve sufficient specificity over the various MDC states.
// (hover, focus, etc.)
// TODO(mmalerba): port this fix into MDC
// TODO(crisbeto): move this into the structural styles
.mat-mdc-form-field.mat-mdc-form-field.mat-mdc-form-field.mat-mdc-form-field {
&.mat-mdc-form-field.mat-mdc-form-field .mdc-notched-outline__notch {
border-left: 1px solid transparent;
}
}
.mat-mdc-form-field.mat-accent {
@include mdc-filled-text-field-theme.theme(
tokens-mdc-filled-text-field.private-get-color-palette-color-tokens($config, accent));
@include mdc-outlined-text-field-theme.theme(
tokens-mdc-outlined-text-field.private-get-color-palette-color-tokens($config, accent));
@include token-utils.create-token-values(tokens-mat-form-field.$prefix,
tokens-mat-form-field.private-get-color-palette-color-tokens($config, accent));
}

[dir='rtl'] {
.mat-mdc-form-field.mat-mdc-form-field.mat-mdc-form-field.mat-mdc-form-field {
&.mat-mdc-form-field.mat-mdc-form-field .mdc-notched-outline__notch {
border-left: none;
border-right: 1px solid transparent;
}
}
}
}
.mat-mdc-form-field.mat-warn {
@include mdc-filled-text-field-theme.theme(
tokens-mdc-filled-text-field.private-get-color-palette-color-tokens($config, warn));
@include mdc-outlined-text-field-theme.theme(
tokens-mdc-outlined-text-field.private-get-color-palette-color-tokens($config, warn));
@include token-utils.create-token-values(tokens-mat-form-field.$prefix,
tokens-mat-form-field.private-get-color-palette-color-tokens($config, warn));
}
}

Expand Down
20 changes: 20 additions & 0 deletions src/material/form-field/_mdc-text-field-structure-overrides.scss
Original file line number Diff line number Diff line change
Expand Up @@ -154,4 +154,24 @@
content: none;
}

// This fixes an issue where the notch appears to be thicker than the rest of the outline when
// zoomed in on Chrome. The border inconsistency seems to be some kind of rendering artifact
// that arises from a combination of the fact that the notch contains text, while the leading
// and trailing outline do not, combined with the fact that the border is semi-transparent.
// Experimentally, I discovered that adding a transparent left border fixes the inconsistency.
// Note: class name is repeated to achieve sufficient specificity over the various MDC states.
// (hover, focus, etc.)
// TODO(mmalerba): port this fix into MDC
.mat-mdc-form-field.mat-mdc-form-field.mat-mdc-form-field.mat-mdc-form-field {
&.mat-mdc-form-field.mat-mdc-form-field .mdc-notched-outline__notch {
border-left: 1px solid transparent;
}
}

[dir='rtl'] .mat-mdc-form-field.mat-mdc-form-field.mat-mdc-form-field.mat-mdc-form-field {
&.mat-mdc-form-field.mat-mdc-form-field .mdc-notched-outline__notch {
border-left: none;
border-right: 1px solid transparent;
}
}
}
Loading

0 comments on commit 98f610d

Please sign in to comment.