Skip to content

Commit 32bd6fc

Browse files
authored
refactor(material/core): switch option and option group to tokens API (#27365)
Reworks the `mat-option` and `mat-optgroup` themes to use the new tokens theming API.
1 parent 65c7cad commit 32bd6fc

File tree

6 files changed

+221
-54
lines changed

6 files changed

+221
-54
lines changed

src/material/core/option/_optgroup-theme.scss

Lines changed: 11 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,24 +1,27 @@
1-
@use '@material/theme/theme' as mdc-theme;
1+
@use '../tokens/m2/mat/optgroup' as tokens-mat-optgroup;
2+
@use '../tokens/token-utils';
3+
@use '../style/sass-utils';
24

35
@use '../theming/theming';
46
@use '../typography/typography';
5-
@use '../mdc-helpers/mdc-helpers';
67

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

10-
@include mdc-helpers.using-mdc-theme($config) {
11-
.mat-mdc-optgroup-label {
12-
// Since this will usually be rendered in an overlay,
13-
// we have to explicitly set the default color.
14-
@include mdc-theme.prop(color, text-primary-on-background);
15-
}
11+
@include sass-utils.current-selector-or-root() {
12+
@include token-utils.create-token-values(tokens-mat-optgroup.$prefix,
13+
tokens-mat-optgroup.get-color-tokens($config));
1614
}
1715
}
1816

1917
@mixin typography($config-or-theme) {
2018
$config: typography.private-typography-to-2018-config(
2119
theming.get-typography-config($config-or-theme));
20+
21+
@include sass-utils.current-selector-or-root() {
22+
@include token-utils.create-token-values(tokens-mat-optgroup.$prefix,
23+
tokens-mat-optgroup.get-typography-tokens($config));
24+
}
2225
}
2326

2427
@mixin density($config-or-theme) {

src/material/core/option/_option-theme.scss

Lines changed: 14 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,7 @@
1-
@use '@material/theme/theme-color' as mdc-theme-color;
2-
@use '@material/theme/theme' as mdc-theme;
3-
@use '@material/list/evolution-mixins' as mdc-list-mixins;
4-
@use '@material/typography' as mdc-typography;
5-
@use '@material/ripple' as mdc-ripple;
1+
@use 'sass:map';
2+
@use '../tokens/m2/mat/option' as tokens-mat-option;
3+
@use '../tokens/token-utils';
4+
@use '../style/sass-utils';
65

76
@use '../theming/theming';
87
@use '../typography/typography';
@@ -12,42 +11,19 @@
1211
$config: theming.get-color-config($config-or-theme);
1312

1413
@include mdc-helpers.using-mdc-theme($config) {
15-
.mat-mdc-option {
16-
// Since this will usually be rendered in an overlay,
17-
// we have explicitly set the default color.
18-
@include mdc-theme.prop(color, text-primary-on-background);
19-
20-
// Increase specificity to override styles from list theme.
21-
&:hover:not(.mdc-list-item--disabled),
22-
&:focus.mdc-list-item,
23-
&.mat-mdc-option-active.mdc-list-item,
24-
25-
// In multiple mode there is a checkbox to show that the option is selected.
26-
&.mdc-list-item--selected:not(.mat-mdc-option-multiple):not(.mdc-list-item--disabled) {
27-
$color: mdc-theme-color.$on-surface;
28-
background: rgba($color, mdc-ripple.states-opacity($color, hover));
29-
}
30-
}
31-
32-
.mat-primary {
33-
.mat-mdc-option.mdc-list-item--selected:not(.mdc-list-item--disabled) {
34-
@include mdc-list-mixins.list-primary-text-ink-color(primary,
35-
$query: mdc-helpers.$mdc-theme-styles-query);
36-
}
14+
@include sass-utils.current-selector-or-root() {
15+
@include token-utils.create-token-values(tokens-mat-option.$prefix,
16+
tokens-mat-option.get-color-tokens($config));
3717
}
3818

3919
.mat-accent {
40-
.mat-mdc-option.mdc-list-item--selected:not(.mdc-list-item--disabled) {
41-
@include mdc-list-mixins.list-primary-text-ink-color(secondary,
42-
$query: mdc-helpers.$mdc-theme-styles-query);
43-
}
20+
@include token-utils.create-token-values(tokens-mat-option.$prefix,
21+
tokens-mat-option.private-get-color-palette-color-tokens(map.get($config, accent)));
4422
}
4523

4624
.mat-warn {
47-
.mat-mdc-option.mdc-list-item--selected:not(.mdc-list-item--disabled) {
48-
@include mdc-list-mixins.list-primary-text-ink-color(error,
49-
$query: mdc-helpers.$mdc-theme-styles-query);
50-
}
25+
@include token-utils.create-token-values(tokens-mat-option.$prefix,
26+
tokens-mat-option.private-get-color-palette-color-tokens(map.get($config, warn)));
5127
}
5228
}
5329
}
@@ -56,17 +32,9 @@
5632
$config: typography.private-typography-to-2018-config(
5733
theming.get-typography-config($config-or-theme));
5834

59-
@include mdc-helpers.using-mdc-typography($config) {
60-
// MDC uses the `subtitle1` level for list items, but
61-
// the spec shows `body1` as the correct level.
62-
.mat-mdc-option {
63-
@include mdc-typography.typography(body1,
64-
$query: mdc-helpers.$mdc-typography-styles-query,
65-
// Exclude these properties, because they cause some build
66-
// issues internally and they aren't used for anything.
67-
$exclude-props: (text-decoration, text-transform)
68-
);
69-
}
35+
@include sass-utils.current-selector-or-root() {
36+
@include token-utils.create-token-values(tokens-mat-option.$prefix,
37+
tokens-mat-option.get-typography-tokens($config));
7038
}
7139
}
7240

src/material/core/option/optgroup.scss

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,23 @@
11
@use 'sass:map';
22
@use '@material/list/evolution-mixins' as mdc-list-mixins;
33
@use '@material/list/evolution-variables' as mdc-list-variables;
4+
@use '../tokens/m2/mat/optgroup' as tokens-mat-optgroup;
5+
@use '../tokens/token-utils';
46
@use '../mdc-helpers/mdc-helpers';
57

8+
.mat-mdc-optgroup {
9+
// These tokens are set on the root option group to make them easier to override.
10+
@include token-utils.use-tokens(
11+
tokens-mat-optgroup.$prefix, tokens-mat-optgroup.get-token-slots()) {
12+
@include token-utils.create-token-slot(color, label-text-color);
13+
@include token-utils.create-token-slot(font-family, label-text-font);
14+
@include token-utils.create-token-slot(line-height, label-text-line-height);
15+
@include token-utils.create-token-slot(font-size, label-text-size);
16+
@include token-utils.create-token-slot(letter-spacing, label-text-tracking);
17+
@include token-utils.create-token-slot(font-weight, label-text-weight);
18+
}
19+
}
20+
621
.mat-mdc-optgroup-label {
722
@include mdc-list-mixins.item-base;
823
@include mdc-list-mixins.item-spacing(
@@ -23,6 +38,16 @@
2338
// Needs to be overwritten explicitly, because the style can
2439
// leak in from the list and cause the text to truncate.
2540
.mdc-list-item__primary-text {
41+
// MDC assigns the typography to this element, rather than the element itself, which will break
42+
// existing overrides. Set all of the typography-related properties to `inherit` so that any
43+
// styles set on the host can propagate down.
44+
font-size: inherit;
45+
font-weight: inherit;
46+
letter-spacing: inherit;
47+
line-height: inherit;
48+
font-family: inherit;
49+
text-decoration: inherit;
50+
text-transform: inherit;
2651
white-space: normal;
2752
}
2853
}

src/material/core/option/option.scss

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,10 @@
22
@use '@angular/cdk';
33
@use '@material/list/evolution-mixins' as mdc-list-mixins;
44
@use '@material/list/evolution-variables' as mdc-list-variables;
5+
@use '@material/typography/typography' as mdc-typography;
56

7+
@use '../tokens/m2/mat/option' as tokens-mat-option;
8+
@use '../tokens/token-utils';
69
@use '../mdc-helpers/mdc-helpers';
710
@use '../style/vendor-prefixes';
811
@use '../style/layout-common';
@@ -13,9 +16,42 @@
1316
@include mdc-list-mixins.item-spacing(
1417
mdc-list-variables.$side-padding, $query: mdc-helpers.$mdc-base-styles-query);
1518
@include vendor-prefixes.user-select(none);
19+
@include mdc-typography.smooth-font();
1620
cursor: pointer;
1721
-webkit-tap-highlight-color: transparent;
1822

23+
@include token-utils.use-tokens(
24+
tokens-mat-option.$prefix, tokens-mat-option.get-token-slots()) {
25+
@include token-utils.create-token-slot(color, label-text-color);
26+
@include token-utils.create-token-slot(font-family, label-text-font);
27+
@include token-utils.create-token-slot(line-height, label-text-line-height);
28+
@include token-utils.create-token-slot(font-size, label-text-size);
29+
@include token-utils.create-token-slot(letter-spacing, label-text-tracking);
30+
@include token-utils.create-token-slot(font-weight, label-text-weight);
31+
32+
// Increase specificity to override styles from list theme.
33+
&:hover:not(.mdc-list-item--disabled) {
34+
@include token-utils.create-token-slot(background-color, hover-state-layer-color);
35+
}
36+
37+
&:focus.mdc-list-item,
38+
&.mat-mdc-option-active.mdc-list-item {
39+
@include token-utils.create-token-slot(background-color, focus-state-layer-color);
40+
}
41+
42+
&.mdc-list-item--selected:not(.mdc-list-item--disabled) {
43+
.mdc-list-item__primary-text {
44+
@include token-utils.create-token-slot(color, selected-state-label-text-color);
45+
}
46+
47+
// We don't change the background in multiple mode since
48+
// it has the checkbox to show the selected state.
49+
&:not(.mat-mdc-option-multiple) {
50+
@include token-utils.create-token-slot(background-color, selected-state-layer-color);
51+
}
52+
}
53+
}
54+
1955
// If the MDC list is loaded after the option, this gets overwritten which breaks the text
2056
// alignment. Ideally we'd wrap all the MDC mixins above with this selector, but the increased
2157
// specificity breaks some internal overrides.
Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
@use 'sass:map';
2+
@use '../../token-utils';
3+
@use '../../../theming/theming';
4+
@use '../../../style/sass-utils';
5+
@use '../../../typography/typography-utils';
6+
@use '../../../mdc-helpers/mdc-helpers';
7+
8+
// The prefix used to generate the fully qualified name for tokens in this file.
9+
$prefix: (mat, optgroup);
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+
$foreground: map.get($config, foreground);
20+
21+
@return (
22+
label-text-color: theming.get-color-from-palette($foreground, text),
23+
);
24+
}
25+
26+
// Tokens that can be configured through Angular Material's typography theming API.
27+
@function get-typography-tokens($config) {
28+
// TODO(crisbeto): The earlier implementation of the option used MDC's APIs to create the
29+
// typography tokens. As a result, we unintentionally allowed `null` typography configs to be
30+
// passed in. Since there a lot of apps that now depend on this pattern, we need this temporary
31+
// fallback.
32+
@if ($config == null) {
33+
$config: mdc-helpers.private-fallback-typography-from-mdc();
34+
}
35+
36+
@return (
37+
label-text-font: typography-utils.font-family($config, body-1) or
38+
typography-utils.font-family($config),
39+
label-text-line-height: typography-utils.line-height($config, body-1),
40+
label-text-size: typography-utils.font-size($config, body-1),
41+
label-text-tracking: typography-utils.letter-spacing($config, body-1),
42+
label-text-weight: typography-utils.font-weight($config, body-1)
43+
);
44+
}
45+
46+
// Tokens that can be configured through Angular Material's density theming API.
47+
@function get-density-tokens($config) {
48+
@return ();
49+
}
50+
51+
// Combines the tokens generated by the above functions into a single map with placeholder values.
52+
// This is used to create token slots.
53+
@function get-token-slots() {
54+
@return sass-utils.deep-merge-all(
55+
get-unthemable-tokens(),
56+
get-color-tokens(token-utils.$placeholder-color-config),
57+
get-typography-tokens(token-utils.$placeholder-typography-config),
58+
get-density-tokens(token-utils.$placeholder-density-config)
59+
);
60+
}
Lines changed: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,75 @@
1+
@use 'sass:map';
2+
@use '../../token-utils';
3+
@use '../../../theming/theming';
4+
@use '../../../style/sass-utils';
5+
@use '../../../typography/typography-utils';
6+
@use '../../../mdc-helpers/mdc-helpers';
7+
8+
// The prefix used to generate the fully qualified name for tokens in this file.
9+
$prefix: (mat, option);
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+
$primary: map.get($config, primary);
22+
$on-surface: if($is-dark, #fff, #000);
23+
$active-state-layer-color: rgba($on-surface, if($is-dark, 0.08, 0.04));
24+
$palette-tokens: private-get-color-palette-color-tokens($primary);
25+
26+
@return map.merge($palette-tokens, (
27+
label-text-color: theming.get-color-from-palette($foreground, text),
28+
hover-state-layer-color: $active-state-layer-color,
29+
focus-state-layer-color: $active-state-layer-color,
30+
selected-state-layer-color: $active-state-layer-color,
31+
));
32+
}
33+
34+
// Tokens that can be configured through Angular Material's typography theming API.
35+
@function get-typography-tokens($config) {
36+
// TODO(crisbeto): The earlier implementation of the option used MDC's APIs to create the
37+
// typography tokens. As a result, we unintentionally allowed `null` typography configs to be
38+
// passed in. Since there a lot of apps that now depend on this pattern, we need this temporary
39+
// fallback.
40+
@if ($config == null) {
41+
$config: mdc-helpers.private-fallback-typography-from-mdc();
42+
}
43+
44+
@return (
45+
label-text-font: typography-utils.font-family($config, body-1) or
46+
typography-utils.font-family($config),
47+
label-text-line-height: typography-utils.line-height($config, body-1),
48+
label-text-size: typography-utils.font-size($config, body-1),
49+
label-text-tracking: typography-utils.letter-spacing($config, body-1),
50+
label-text-weight: typography-utils.font-weight($config, body-1)
51+
);
52+
}
53+
54+
// Generates the tokens used to theme the option based on a palette.
55+
@function private-get-color-palette-color-tokens($palette) {
56+
@return (
57+
selected-state-label-text-color: theming.get-color-from-palette($palette),
58+
);
59+
}
60+
61+
// Tokens that can be configured through Angular Material's density theming API.
62+
@function get-density-tokens($config) {
63+
@return ();
64+
}
65+
66+
// Combines the tokens generated by the above functions into a single map with placeholder values.
67+
// This is used to create token slots.
68+
@function get-token-slots() {
69+
@return sass-utils.deep-merge-all(
70+
get-unthemable-tokens(),
71+
get-color-tokens(token-utils.$placeholder-color-config),
72+
get-typography-tokens(token-utils.$placeholder-typography-config),
73+
get-density-tokens(token-utils.$placeholder-density-config)
74+
);
75+
}

0 commit comments

Comments
 (0)