Skip to content

Commit e8fb85b

Browse files
committed
refactor(material/form-field): switch color styles to tokens (#27581)
Reworks our custom color styles on top of MDC to use tokens. (cherry picked from commit 98f610d)
1 parent 1bdf090 commit e8fb85b

11 files changed

+128
-231
lines changed

src/material/core/tokens/m2/mat/_form-field.scss

Lines changed: 34 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
@use 'sass:map';
22
@use '../../token-utils';
33
@use '../../../style/sass-utils';
4+
@use '../../../theming/theming';
5+
@use '../../../theming/palette';
46

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

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

19-
@return (
23+
@return map.merge($color-tokens, (
2024
// MDC has a token for the enabled placeholder, but not for the disabled one.
2125
disabled-input-text-placeholder-color: rgba($on-surface, 0.38),
26+
state-layer-color: rgba($on-surface, 0.87),
27+
error-text-color: theming.get-color-from-palette($warn),
28+
29+
// On dark themes we set the native `select` color to some shade of white,
30+
// however the color propagates to all of the `option` elements, which are
31+
// always on a white background inside the dropdown, causing them to blend in.
32+
// Since we can't change background of the dropdown, we need to explicitly
33+
// reset the color of the options to something dark.
34+
select-option-text-color: if($is-dark, palette.$dark-primary-text, inherit),
35+
// Note the spelling of the `GrayText` here which is a system color. See:
36+
// https://developer.mozilla.org/en-US/docs/Web/CSS/system-color
37+
select-disabled-option-text-color: if($is-dark, palette.$dark-disabled-text, GrayText),
38+
39+
// These values are taken from the MDC select implementation:
40+
// https://github.com/material-components/material-components-web/blob/master/packages/mdc-select/_select-theme.scss
41+
enabled-select-arrow-color: rgba($on-surface, 0.54),
42+
disabled-select-arrow-color: rgba($on-surface, 0.38),
43+
44+
hover-state-layer-opacity: if($is-dark, 0.08, 0.04),
45+
focus-state-layer-opacity: if($is-dark, 0.24, 0.12),
46+
));
47+
}
48+
49+
// Generates the mapping for the properties that change based on the form field color.
50+
@function private-get-color-palette-color-tokens($config, $palette-name) {
51+
$palette: map.get($config, $palette-name);
52+
53+
@return (
54+
focus-select-arrow-color: theming.get-color-from-palette($palette, default, 0.87),
2255
);
2356
}
2457

src/material/core/tokens/m2/mdc/_filled-text-field.scss

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -133,7 +133,7 @@ $prefix: (mdc, filled-text-field);
133133
@return $first-color;
134134
}
135135

136-
// Generates the mapping for the properties that change based on the slide toggle color.
136+
// Generates the mapping for the properties that change based on the text field color.
137137
@function private-get-color-palette-color-tokens($config, $palette-name) {
138138
$palette: map.get($config, $palette-name);
139139
$palette-color: theming.get-color-from-palette($palette);

src/material/core/tokens/m2/mdc/_outlined-text-field.scss

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -116,7 +116,7 @@ $prefix: (mdc, outlined-text-field);
116116
));
117117
}
118118

119-
// Generates the mapping for the properties that change based on the slide toggle color.
119+
// Generates the mapping for the properties that change based on the text field color.
120120
@function private-get-color-palette-color-tokens($config, $palette-name) {
121121
$palette: map.get($config, $palette-name);
122122
$palette-color: theming.get-color-from-palette($palette);

src/material/form-field/BUILD.bazel

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,6 @@ sass_library(
3131
srcs = [
3232
"_form-field-theme.import.scss",
3333
"_form-field-theme.scss",
34-
"_mdc-text-field-theme-variable-refresh.scss",
3534
],
3635
deps = [
3736
":form_field_partials",
Lines changed: 13 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
1-
@use '@material/ripple/functions' as mdc-ripple-functions;
2-
@use '@material/textfield' as mdc-textfield;
1+
@use '../core/tokens/m2/mat/form-field' as tokens-mat-form-field;
2+
@use '../core/tokens/token-utils';
33
@use '../core/style/layout-common';
44

55
// MDC text-field uses `@material/ripple` in order to show a focus and hover effect for
@@ -13,24 +13,19 @@
1313
.mat-mdc-form-field-focus-overlay {
1414
@include layout-common.fill;
1515
opacity: 0;
16-
// Make sure we don't block click on the prefix/suffix.
17-
pointer-events: none;
18-
}
19-
}
20-
21-
@mixin private-form-field-focus-overlay-color() {
22-
$focus-opacity: mdc-ripple-functions.states-opacity(mdc-textfield.$ink-color, focus);
23-
$hover-opacity: mdc-ripple-functions.states-opacity(mdc-textfield.$ink-color, hover);
16+
pointer-events: none; // Make sure we don't block click on the prefix/suffix.
2417

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

29-
.mat-mdc-form-field:hover .mat-mdc-form-field-focus-overlay {
30-
opacity: $hover-opacity;
31-
}
22+
.mat-mdc-form-field:hover & {
23+
@include token-utils.create-token-slot(opacity, hover-state-layer-opacity);
24+
}
3225

33-
.mat-mdc-form-field.mat-focused .mat-mdc-form-field-focus-overlay {
34-
opacity: $focus-opacity;
26+
.mat-mdc-form-field.mat-focused & {
27+
@include token-utils.create-token-slot(opacity, focus-state-layer-opacity);
28+
}
29+
}
3530
}
3631
}
Lines changed: 30 additions & 67 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,6 @@
1-
@use 'sass:map';
21
@use 'sass:math';
3-
@use '@material/theme/theme-color' as mdc-theme-color;
4-
@use '../core/theming/palette';
5-
@use '../core/mdc-helpers/mdc-helpers';
2+
@use '../core/tokens/m2/mat/form-field' as tokens-mat-form-field;
3+
@use '../core/tokens/token-utils';
64

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

13+
$_tokens: tokens-mat-form-field.$prefix, tokens-mat-form-field.get-token-slots();
14+
1515
// Mixin that creates styles for native select controls in a form-field.
1616
@mixin private-form-field-native-select() {
1717
// Remove the native select down arrow and ensure that the native appearance
@@ -30,6 +30,18 @@ $mat-form-field-select-horizontal-end-padding: $mat-form-field-select-arrow-widt
3030
&:not(:disabled) {
3131
cursor: pointer;
3232
}
33+
34+
&:not(.mat-mdc-native-select-inline) {
35+
@include token-utils.use-tokens($_tokens...) {
36+
option {
37+
@include token-utils.create-token-slot(color, select-option-text-color);
38+
}
39+
40+
option:disabled {
41+
@include token-utils.create-token-slot(color, select-disabled-option-text-color);
42+
}
43+
}
44+
}
3345
}
3446

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

67+
@include token-utils.use-tokens($_tokens...) {
68+
@include token-utils.create-token-slot(color, enabled-select-arrow-color);
69+
}
70+
5571
[dir='rtl'] & {
5672
right: auto;
5773
left: 0;
5874
}
5975
}
6076

77+
@include token-utils.use-tokens($_tokens...) {
78+
&.mat-focused .mat-mdc-form-field-infix::after {
79+
@include token-utils.create-token-slot(color, focus-select-arrow-color);
80+
}
81+
82+
&.mat-form-field-disabled .mat-mdc-form-field-infix::after {
83+
@include token-utils.create-token-slot(color, disabled-select-arrow-color);
84+
}
85+
}
86+
6187
// Add padding on the end of the native select so that the content does not
6288
// overlap with the Material Design arrow.
6389
.mat-mdc-form-field-input-control {
@@ -69,66 +95,3 @@ $mat-form-field-select-horizontal-end-padding: $mat-form-field-select-arrow-widt
6995
}
7096
}
7197
}
72-
73-
// Gets the color to use for some text that is highlighted while a select has focus.
74-
@function _get-focused-arrow-color($palette) {
75-
@return rgba(mdc-theme-color.prop-value($palette), 0.87);
76-
}
77-
78-
@mixin private-form-field-native-select-color($config) {
79-
@include mdc-helpers.using-mdc-theme($config) {
80-
// These values are taken from the MDC select implementation:
81-
// https://github.com/material-components/material-components-web/blob/master/packages/mdc-select/_select-theme.scss
82-
$dropdown-icon-color: rgba(mdc-theme-color.prop-value(on-surface), 0.54);
83-
$disabled-dropdown-icon-color: rgba(mdc-theme-color.prop-value(on-surface), 0.38);
84-
85-
select.mat-mdc-form-field-input-control:not(.mat-mdc-native-select-inline) {
86-
// On dark themes we set the native `select` color to some shade of white,
87-
// however the color propagates to all of the `option` elements, which are
88-
// always on a white background inside the dropdown, causing them to blend in.
89-
// Since we can't change background of the dropdown, we need to explicitly
90-
// reset the color of the options to something dark.
91-
@if (map.get($config, is-dark)) {
92-
option {
93-
color: palette.$dark-primary-text;
94-
}
95-
96-
option:disabled {
97-
color: palette.$dark-disabled-text;
98-
}
99-
}
100-
}
101-
102-
.mat-mdc-form-field-type-mat-native-select {
103-
.mat-mdc-form-field-infix::after {
104-
color: $dropdown-icon-color;
105-
}
106-
107-
&.mat-focused {
108-
&.mat-primary {
109-
.mat-mdc-form-field-infix::after {
110-
color: _get-focused-arrow-color(primary);
111-
}
112-
}
113-
114-
&.mat-accent {
115-
.mat-mdc-form-field-infix::after {
116-
color: _get-focused-arrow-color(secondary);
117-
}
118-
}
119-
120-
&.mat-warn {
121-
.mat-mdc-form-field-infix::after {
122-
color: _get-focused-arrow-color(error);
123-
}
124-
}
125-
}
126-
127-
&.mat-form-field-disabled {
128-
.mat-mdc-form-field-infix::after {
129-
color: $disabled-dropdown-icon-color;
130-
}
131-
}
132-
}
133-
}
134-
}

src/material/form-field/_form-field-subscript.scss

Lines changed: 6 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
1-
@use '@material/textfield' as mdc-textfield;
2-
@use '@material/theme/theme' as mdc-theme;
31
@use '@material/typography' as mdc-typography;
42
@use '@material/textfield/variables' as mdc-textfield-variables;
53

4+
@use '../core/tokens/m2/mat/form-field' as tokens-mat-form-field;
5+
@use '../core/tokens/token-utils';
66
@use '../core/theming/theming';
77
@use '../core/mdc-helpers/mdc-helpers';
88
@use './form-field-sizing';
@@ -58,13 +58,11 @@
5858
// Single error message displayed beneath the form field underline.
5959
.mat-mdc-form-field-error {
6060
display: block;
61-
}
62-
}
6361

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

src/material/form-field/_form-field-theme.scss

Lines changed: 15 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -12,9 +12,6 @@
1212
@use '../core/tokens/token-utils';
1313
@use './form-field-density';
1414
@use './form-field-subscript';
15-
@use './form-field-focus-overlay';
16-
@use './form-field-native-select';
17-
@use './mdc-text-field-theme-variable-refresh';
1815

1916
@mixin color($config-or-theme) {
2017
$config: theming.get-color-config($config-or-theme);
@@ -28,50 +25,22 @@
2825
tokens-mat-form-field.get-color-tokens($config));
2926
}
3027

31-
@include mdc-helpers.using-mdc-theme($config) {
32-
@include mdc-text-field-theme-variable-refresh.private-text-field-refresh-theme-variables() {
33-
@include form-field-subscript.private-form-field-subscript-color();
34-
@include form-field-focus-overlay.private-form-field-focus-overlay-color();
35-
@include form-field-native-select.private-form-field-native-select-color($config);
36-
37-
.mat-mdc-form-field.mat-accent {
38-
@include mdc-filled-text-field-theme.theme(
39-
tokens-mdc-filled-text-field.private-get-color-palette-color-tokens($config, accent));
40-
@include mdc-outlined-text-field-theme.theme(
41-
tokens-mdc-outlined-text-field.private-get-color-palette-color-tokens($config, accent));
42-
}
43-
44-
.mat-mdc-form-field.mat-warn {
45-
@include mdc-filled-text-field-theme.theme(
46-
tokens-mdc-filled-text-field.private-get-color-palette-color-tokens($config, warn));
47-
@include mdc-outlined-text-field-theme.theme(
48-
tokens-mdc-outlined-text-field.private-get-color-palette-color-tokens($config, warn));
49-
}
50-
51-
// This fixes an issue where the notch appears to be thicker than the rest of the outline when
52-
// zoomed in on Chrome. The border inconsistency seems to be some kind of rendering artifact
53-
// that arises from a combination of the fact that the notch contains text, while the leading
54-
// and trailing outline do not, combined with the fact that the border is semi-transparent.
55-
// Experimentally, I discovered that adding a transparent left border fixes the inconsistency.
56-
// Note: class name is repeated to achieve sufficient specificity over the various MDC states.
57-
// (hover, focus, etc.)
58-
// TODO(mmalerba): port this fix into MDC
59-
// TODO(crisbeto): move this into the structural styles
60-
.mat-mdc-form-field.mat-mdc-form-field.mat-mdc-form-field.mat-mdc-form-field {
61-
&.mat-mdc-form-field.mat-mdc-form-field .mdc-notched-outline__notch {
62-
border-left: 1px solid transparent;
63-
}
64-
}
28+
.mat-mdc-form-field.mat-accent {
29+
@include mdc-filled-text-field-theme.theme(
30+
tokens-mdc-filled-text-field.private-get-color-palette-color-tokens($config, accent));
31+
@include mdc-outlined-text-field-theme.theme(
32+
tokens-mdc-outlined-text-field.private-get-color-palette-color-tokens($config, accent));
33+
@include token-utils.create-token-values(tokens-mat-form-field.$prefix,
34+
tokens-mat-form-field.private-get-color-palette-color-tokens($config, accent));
35+
}
6536

66-
[dir='rtl'] {
67-
.mat-mdc-form-field.mat-mdc-form-field.mat-mdc-form-field.mat-mdc-form-field {
68-
&.mat-mdc-form-field.mat-mdc-form-field .mdc-notched-outline__notch {
69-
border-left: none;
70-
border-right: 1px solid transparent;
71-
}
72-
}
73-
}
74-
}
37+
.mat-mdc-form-field.mat-warn {
38+
@include mdc-filled-text-field-theme.theme(
39+
tokens-mdc-filled-text-field.private-get-color-palette-color-tokens($config, warn));
40+
@include mdc-outlined-text-field-theme.theme(
41+
tokens-mdc-outlined-text-field.private-get-color-palette-color-tokens($config, warn));
42+
@include token-utils.create-token-values(tokens-mat-form-field.$prefix,
43+
tokens-mat-form-field.private-get-color-palette-color-tokens($config, warn));
7544
}
7645
}
7746

src/material/form-field/_mdc-text-field-structure-overrides.scss

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -154,4 +154,24 @@
154154
content: none;
155155
}
156156

157+
// This fixes an issue where the notch appears to be thicker than the rest of the outline when
158+
// zoomed in on Chrome. The border inconsistency seems to be some kind of rendering artifact
159+
// that arises from a combination of the fact that the notch contains text, while the leading
160+
// and trailing outline do not, combined with the fact that the border is semi-transparent.
161+
// Experimentally, I discovered that adding a transparent left border fixes the inconsistency.
162+
// Note: class name is repeated to achieve sufficient specificity over the various MDC states.
163+
// (hover, focus, etc.)
164+
// TODO(mmalerba): port this fix into MDC
165+
.mat-mdc-form-field.mat-mdc-form-field.mat-mdc-form-field.mat-mdc-form-field {
166+
&.mat-mdc-form-field.mat-mdc-form-field .mdc-notched-outline__notch {
167+
border-left: 1px solid transparent;
168+
}
169+
}
170+
171+
[dir='rtl'] .mat-mdc-form-field.mat-mdc-form-field.mat-mdc-form-field.mat-mdc-form-field {
172+
&.mat-mdc-form-field.mat-mdc-form-field .mdc-notched-outline__notch {
173+
border-left: none;
174+
border-right: 1px solid transparent;
175+
}
176+
}
157177
}

0 commit comments

Comments
 (0)