Skip to content

Commit 575c21c

Browse files
authored
refactor(material/select): switch to tokens API (#27310)
Reworks the select to use the new tokens-based theming API.
1 parent c86e1ef commit 575c21c

File tree

3 files changed

+167
-74
lines changed

3 files changed

+167
-74
lines changed
Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,72 @@
1+
@use 'sass:map';
2+
@use '../../token-utils';
3+
@use '../../../typography/typography-utils';
4+
@use '../../../mdc-helpers/mdc-helpers';
5+
@use '../../../theming/theming';
6+
@use '../../../style/sass-utils';
7+
8+
// The prefix used to generate the fully qualified name for tokens in this file.
9+
$prefix: (mat, select);
10+
11+
// Tokens that can't be configured through Angular Material's current theming API,
12+
// but may be in a future version of the theming API.
13+
@function get-unthemable-tokens() {
14+
@return ();
15+
}
16+
17+
// Tokens that can be configured through Angular Material's color theming API.
18+
@function get-color-tokens($config) {
19+
$is-dark: map.get($config, is-dark);
20+
$foreground: map.get($config, foreground);
21+
$background: map.get($config, background);
22+
$primary: map.get($config, primary);
23+
$warn: map.get($config, warn);
24+
$on-surface: if($is-dark, #fff, #000);
25+
26+
@return (
27+
panel-background-color: theming.get-color-from-palette($background, card),
28+
enabled-trigger-color: rgba($on-surface, 0.87),
29+
disabled-trigger-color: rgba($on-surface, 0.38),
30+
placeholder-color: rgba($on-surface, 0.6),
31+
enabled-arrow-color: rgba($on-surface, 0.54),
32+
disabled-arrow-color: rgba($on-surface, 0.38),
33+
focused-arrow-color: theming.get-color-from-palette($primary, default, 0.87),
34+
invalid-arrow-color: theming.get-color-from-palette($warn, default, 0.87),
35+
);
36+
}
37+
38+
// Tokens that can be configured through Angular Material's typography theming API.
39+
@function get-typography-tokens($config) {
40+
// TODO(crisbeto): The earlier implementation of the select used MDC's APIs to create the
41+
// typography tokens. As a result, we unintentionally allowed `null` typography configs to be
42+
// passed in. Since there a lot of apps that now depend on this pattern, we need this temporary
43+
// fallback.
44+
@if ($config == null) {
45+
$config: mdc-helpers.private-fallback-typography-from-mdc();
46+
}
47+
48+
@return (
49+
trigger-font: typography-utils.font-family($config, body-1) or
50+
typography-utils.font-family($config),
51+
trigger-line-height: typography-utils.line-height($config, body-1),
52+
trigger-size: typography-utils.font-size($config, body-1),
53+
trigger-tracking: typography-utils.letter-spacing($config, body-1),
54+
trigger-weight: typography-utils.font-weight($config, body-1)
55+
);
56+
}
57+
58+
// Tokens that can be configured through Angular Material's density theming API.
59+
@function get-density-tokens($config) {
60+
@return ();
61+
}
62+
63+
// Combines the tokens generated by the above functions into a single map with placeholder values.
64+
// This is used to create token slots.
65+
@function get-token-slots() {
66+
@return sass-utils.deep-merge-all(
67+
get-unthemable-tokens(),
68+
get-color-tokens(token-utils.$placeholder-color-config),
69+
get-typography-tokens(token-utils.$placeholder-typography-config),
70+
get-density-tokens(token-utils.$placeholder-density-config)
71+
);
72+
}

src/material/select/_select-theme.scss

Lines changed: 25 additions & 60 deletions
Original file line numberDiff line numberDiff line change
@@ -1,83 +1,43 @@
1-
@use '@material/theme/theme-color' as mdc-theme-color;
2-
@use '@material/menu-surface' as mdc-menu-surface;
3-
@use '@material/list/evolution-mixins' as mdc-list;
4-
@use '@material/typography' as mdc-typography;
1+
@use 'sass:map';
52
@use '@material/density' as mdc-density;
63
@use '@material/textfield' as mdc-textfield;
4+
@use '../core/tokens/m2/mat/select' as tokens-mat-select;
5+
@use '../core/tokens/token-utils';
6+
@use '../core/style/sass-utils';
77

88
@use '../core/theming/theming';
99
@use '../core/typography/typography';
10-
@use '../core/mdc-helpers/mdc-helpers';
11-
12-
13-
// Gets the color to use for some text that is highlighted while a select has focus.
14-
@function _get-mdc-focused-text-color($palette) {
15-
@return rgba(mdc-theme-color.prop-value($palette), 0.87);
16-
}
1710

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

21-
@include mdc-helpers.using-mdc-theme($config) {
22-
$disabled-color: rgba(mdc-theme-color.prop-value(on-surface), 0.38);
23-
@include mdc-menu-surface.core-styles(mdc-helpers.$mdc-theme-styles-query);
24-
@include mdc-list.without-ripple(mdc-helpers.$mdc-theme-styles-query);
25-
26-
.mat-mdc-select-value {
27-
color: rgba(mdc-theme-color.prop-value(on-surface), 0.87);
28-
}
29-
30-
.mat-mdc-select-placeholder {
31-
color: rgba(mdc-theme-color.prop-value(on-surface), 0.6);
32-
}
33-
34-
.mat-mdc-select-disabled .mat-mdc-select-value {
35-
color: $disabled-color;
36-
}
14+
@include sass-utils.current-selector-or-root() {
15+
@include token-utils.create-token-values(tokens-mat-select.$prefix,
16+
tokens-mat-select.get-color-tokens($config));
3717

38-
.mat-mdc-select-arrow {
39-
color: rgba(mdc-theme-color.prop-value(on-surface), 0.54);
18+
.mat-mdc-form-field.mat-accent {
19+
$accent: map.get($config, accent);
20+
$accent-config: map.merge($config, (primary: $accent));
21+
@include token-utils.create-token-values(tokens-mat-select.$prefix,
22+
tokens-mat-select.get-color-tokens($accent-config));
4023
}
4124

42-
.mat-mdc-form-field {
43-
&.mat-focused {
44-
&.mat-primary .mat-mdc-select-arrow {
45-
color: _get-mdc-focused-text-color(primary);
46-
}
47-
48-
&.mat-accent .mat-mdc-select-arrow {
49-
color: _get-mdc-focused-text-color(secondary);
50-
}
51-
52-
&.mat-warn .mat-mdc-select-arrow {
53-
color: _get-mdc-focused-text-color(error);
54-
}
55-
}
56-
57-
.mat-mdc-select.mat-mdc-select-invalid .mat-mdc-select-arrow {
58-
color: _get-mdc-focused-text-color(error);
59-
}
60-
61-
.mat-mdc-select.mat-mdc-select-disabled .mat-mdc-select-arrow {
62-
color: $disabled-color;
63-
}
25+
.mat-mdc-form-field.mat-warn {
26+
$warn: map.get($config, warn);
27+
$warn-config: map.merge($config, (primary: $warn));
28+
@include token-utils.create-token-values(tokens-mat-select.$prefix,
29+
tokens-mat-select.get-color-tokens($warn-config));
6430
}
6531
}
6632
}
6733

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

74-
.mat-mdc-select-panel {
75-
@include mdc-list.list-base(mdc-helpers.$mdc-typography-styles-query);
76-
}
77-
78-
.mat-mdc-select {
79-
@include mdc-typography.typography(body1, $query: mdc-helpers.$mdc-typography-styles-query);
80-
}
38+
@include sass-utils.current-selector-or-root() {
39+
@include token-utils.create-token-values(tokens-mat-select.$prefix,
40+
tokens-mat-select.get-typography-tokens($config));
8141
}
8242
}
8343

@@ -98,6 +58,11 @@
9858
transform: none;
9959
}
10060
}
61+
62+
@include sass-utils.current-selector-or-root() {
63+
@include token-utils.create-token-values(tokens-mat-select.$prefix,
64+
tokens-mat-select.get-density-tokens($density-scale));
65+
}
10166
}
10267

10368
@mixin theme($theme-or-color-config) {

src/material/select/select.scss

Lines changed: 70 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,11 @@
11
@use 'sass:math';
22
@use '@angular/cdk';
3-
@use '@material/menu-surface' as mdc-menu-surface;
4-
@use '@material/list/evolution-mixins' as mdc-list;
3+
@use '@material/typography/typography' as mdc-typography;
4+
@use '../core/style/elevation';
55
@use '../core/style/vendor-prefixes';
66
@use '../core/style/variables';
7+
@use '../core/tokens/token-utils';
8+
@use '../core/tokens/m2/mat/select' as tokens-mat-select;
79

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

16-
// We base the select panel styling on top of MDC's menu styles and we
17-
// implement the trigger ourselves since MDC doesn't provide an equivalent.
18-
19-
@include mdc-menu-surface.core-styles($query: structure);
2018

2119
.mat-mdc-select {
2220
display: inline-block;
2321
width: 100%;
2422
outline: none;
23+
24+
@include token-utils.use-tokens(
25+
tokens-mat-select.$prefix, tokens-mat-select.get-token-slots()) {
26+
@include mdc-typography.smooth-font();
27+
@include token-utils.create-token-slot(color, enabled-trigger-color);
28+
@include token-utils.create-token-slot(font-family, trigger-font);
29+
@include token-utils.create-token-slot(line-height, trigger-line-height);
30+
@include token-utils.create-token-slot(font-size, trigger-size);
31+
@include token-utils.create-token-slot(font-weight, trigger-weight);
32+
@include token-utils.create-token-slot(letter-spacing, trigger-tracking);
33+
}
34+
}
35+
36+
.mat-mdc-select-disabled {
37+
@include token-utils.use-tokens(
38+
tokens-mat-select.$prefix, tokens-mat-select.get-token-slots()) {
39+
@include token-utils.create-token-slot(color, disabled-trigger-color);
40+
}
2541
}
2642

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

35-
.mat-mdc-select-disabled & {
36-
@include vendor-prefixes.user-select(none);
37-
cursor: default;
51+
@include token-utils.use-tokens(
52+
tokens-mat-select.$prefix, tokens-mat-select.get-token-slots()) {
53+
@include token-utils.create-token-slot(color, enabled-trigger-color);
54+
55+
.mat-mdc-select-disabled & {
56+
@include vendor-prefixes.user-select(none);
57+
@include token-utils.create-token-slot(color, disabled-trigger-color);
58+
cursor: default;
59+
}
3860
}
3961
}
4062

@@ -72,6 +94,23 @@ $scale: 0.75 !default;
7294
height: $mat-select-arrow-size;
7395
position: relative;
7496

97+
@include token-utils.use-tokens(
98+
tokens-mat-select.$prefix, tokens-mat-select.get-token-slots()) {
99+
@include token-utils.create-token-slot(color, enabled-arrow-color);
100+
101+
.mat-mdc-form-field.mat-focused & {
102+
@include token-utils.create-token-slot(color, focused-arrow-color);
103+
}
104+
105+
.mat-mdc-form-field .mat-mdc-select.mat-mdc-select-invalid & {
106+
@include token-utils.create-token-slot(color, invalid-arrow-color);
107+
}
108+
109+
.mat-mdc-form-field .mat-mdc-select.mat-mdc-select-disabled & {
110+
@include token-utils.create-token-slot(color, disabled-arrow-color);
111+
}
112+
}
113+
75114
svg {
76115
fill: currentColor;
77116
position: absolute;
@@ -91,15 +130,27 @@ $scale: 0.75 !default;
91130
}
92131
}
93132

94-
// Note that the `.mdc-menu-surface` is here in order to bump up the specificity
95-
// and avoid interference with `mat-menu` which uses the same mixins from MDC.
96-
.mdc-menu-surface.mat-mdc-select-panel {
133+
// Even though we don't use the MDC styles, we need to keep the classes in the
134+
// DOM for the Gmat versions to work. We need to bump up the specificity here
135+
// so that it's higher than MDC's styles.
136+
div.mat-mdc-select-panel {
137+
@include elevation.elevation(8);
97138
width: 100%; // Ensures that the panel matches the overlay width.
98139
max-height: $mat-select-panel-max-height;
99-
position: static; // MDC uses `absolute` by default which will throw off our positioning.
100140
outline: 0;
141+
overflow: auto;
142+
padding: 8px 0;
143+
border-radius: 4px;
144+
box-sizing: border-box;
145+
146+
// Workaround in case other MDC menu surface styles bleed in.
147+
position: static;
148+
149+
@include token-utils.use-tokens(
150+
tokens-mat-select.$prefix, tokens-mat-select.get-token-slots()) {
151+
@include token-utils.create-token-slot(background-color, panel-background-color);
152+
}
101153

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

178+
@include token-utils.use-tokens(
179+
tokens-mat-select.$prefix, tokens-mat-select.get-token-slots()) {
180+
@include token-utils.create-token-slot(color, placeholder-color);
181+
}
182+
127183
._mat-animation-noopable & {
128184
transition: none;
129185
}

0 commit comments

Comments
 (0)