Skip to content

Commit 5ae7d68

Browse files
authored
refactor: change mat-list to use MDC's token API (#26516)
* refactor: change mat-list to use MDC's token API * fixup! refactor: change mat-list to use MDC's token API * test: add token validation test
1 parent 6d89b9d commit 5ae7d68

12 files changed

+524
-89
lines changed

.github/CODEOWNERS

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -82,6 +82,7 @@
8282
/src/material/core/style/** @andrewseguin
8383
/src/material/core/testing/** @crisbeto
8484
/src/material/core/theming/** @andrewseguin @jelbourn
85+
/src/material/core/tokens/** @mmalerba
8586
/src/material/core/typography/** @crisbeto
8687
/src/material/core/util/** @andrewseguin
8788
/src/material/legacy-core/* @andrewseguin

src/material/core/theming/_theming.scss

Lines changed: 22 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
@use 'sass:list';
22
@use 'sass:map';
3+
@use 'sass:math';
34
@use 'sass:meta';
45
@use 'palette';
56
@use '../density/private/compatibility';
@@ -466,11 +467,31 @@ $_emitted-density: () !default;
466467
));
467468
}
468469

469-
470470
// Approximates an rgba color into a solid hex color, given a background color.
471471
@function private-rgba-to-hex($color, $background-color) {
472472
// We convert the rgba color into a solid one by taking the opacity from the rgba
473473
// value and using it to determine the percentage of the background to put
474474
// into foreground when mixing the colors together.
475475
@return mix($background-color, rgba($color, 1), (1 - opacity($color)) * 100%);
476476
}
477+
478+
// Clamps the density scale to a number between the given min and max.
479+
// 'minimum' and 'maximum' are converted to the given min or max number respectively.
480+
@function clamp-density($density-scale, $min, $max: 0) {
481+
@if $density-scale == minimum {
482+
@return $min;
483+
}
484+
@if $density-scale == maximum {
485+
@return $max;
486+
}
487+
@if meta.type-of($density-scale) != 'number' or not math.is-unitless($density-scale) {
488+
@return 0;
489+
}
490+
@if $density-scale < $min {
491+
@return $min;
492+
}
493+
@if $density-scale > $max {
494+
@return $max;
495+
}
496+
@return $density-scale;
497+
}
Lines changed: 80 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,80 @@
1+
@use 'sass:map';
2+
@use '@material/theme/custom-properties' as mdc-custom-properties;
3+
@use '@material/theme/theme' as mdc-theme;
4+
@use '../mdc-helpers/mdc-helpers';
5+
@use '../theming/palette';
6+
@use '../theming/theming';
7+
8+
$_placeholder-color-palette: theming.define-palette(palette.$red-palette);
9+
10+
// Placeholder color config that can be passed to token getter functions when generating token
11+
// slots.
12+
$placeholder-color-config: (
13+
primary: $_placeholder-color-palette,
14+
accent: $_placeholder-color-palette,
15+
warn: $_placeholder-color-palette,
16+
is-dark: false,
17+
foreground: palette.$light-theme-foreground-palette,
18+
background: palette.$light-theme-background-palette,
19+
);
20+
21+
$_placeholder-typography-level-config: mdc-helpers.typography-config-level-from-mdc(body1);
22+
23+
// Placeholder typography config that can be passed to token getter functions when generating token
24+
// slots.
25+
$placeholder-typography-config: (
26+
font-family: Roboto,
27+
headline-1: $_placeholder-typography-level-config,
28+
headline-2: $_placeholder-typography-level-config,
29+
headline-3: $_placeholder-typography-level-config,
30+
headline-4: $_placeholder-typography-level-config,
31+
headline-5: $_placeholder-typography-level-config,
32+
headline-6: $_placeholder-typography-level-config,
33+
subtitle-1: $_placeholder-typography-level-config,
34+
subtitle-2: $_placeholder-typography-level-config,
35+
body-1: $_placeholder-typography-level-config,
36+
body-2: $_placeholder-typography-level-config,
37+
caption: $_placeholder-typography-level-config,
38+
button: $_placeholder-typography-level-config,
39+
overline: $_placeholder-typography-level-config,
40+
);
41+
42+
// Placeholder density config that can be passed to token getter functions when generating token
43+
// slots.
44+
$placeholder-density-config: 0;
45+
46+
$_tokens: null;
47+
$_component-prefix: null;
48+
49+
@mixin _configure-token-prefix($first, $rest...) {
50+
$_component-prefix: '' !global;
51+
@each $item in $rest {
52+
$_component-prefix:
53+
if($_component-prefix == '', $item, '#{$_component-prefix}-#{$item}') !global;
54+
}
55+
@include mdc-custom-properties.configure($varname-prefix: $first) {
56+
@content;
57+
}
58+
$_component-prefix: null !global;
59+
}
60+
61+
// Sets the token prefix and map to use when creating token slots.
62+
@mixin use-tokens($prefix, $tokens) {
63+
$_tokens: $tokens !global;
64+
@include _configure-token-prefix($prefix...) {
65+
@content;
66+
}
67+
$_tokens: null !global;
68+
}
69+
70+
// Emits a slot for the given token, provided that it has a non-null value in the token map passed
71+
// to `use-tokens`.
72+
@mixin create-token-slot($property, $token) {
73+
@if $_component-prefix == null or $_tokens == null {
74+
@error '`create-token-slot` must be used within `use-tokens`';
75+
}
76+
@if map.get($_tokens, $token) != null {
77+
$value: mdc-custom-properties.create('#{$_component-prefix}-#{$token}');
78+
@include mdc-theme.property($property, $value);
79+
}
80+
}
Lines changed: 220 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,220 @@
1+
@use 'sass:map';
2+
@use '../../../theming/theming';
3+
@use '../../../typography/typography-utils';
4+
@use '../../token-utils';
5+
6+
// The prefix used to generate the fully qualified name for tokens in this file.
7+
$prefix: (mdc, list);
8+
9+
// Tokens that can't be configured through Angular Material's current theming API,
10+
// but may be in a future version of the theming API.
11+
//
12+
// Tokens that are available in MDC, but not used in Angular Material should be mapped to `null`.
13+
// `null` indicates that we are intentionally choosing not to emit a slot or value for the token in
14+
// our CSS.
15+
@function get-unthemable-tokens() {
16+
@return (
17+
// Border radius of list items.
18+
list-item-container-shape: 0,
19+
// Border radius of the list item's leading avatar.
20+
list-item-leading-avatar-shape: 50%,
21+
// Background color of list items.
22+
list-item-container-color: transparent,
23+
// Background color of list items when selected.
24+
list-item-selected-container-color: transparent,
25+
// Background color of the list item's leading avatar.
26+
list-item-leading-avatar-color: transparent,
27+
// Height & width of the list item's leading icon.
28+
list-item-leading-icon-size: 24px,
29+
// Height & width of the list item's leading avatar.
30+
list-item-leading-avatar-size: 40px,
31+
// Height & width of the list item's trailing icon.
32+
list-item-trailing-icon-size: 24px,
33+
// Color of the list item's overlay when the item is disabled.
34+
list-item-disabled-state-layer-color: transparent,
35+
// Opacity of the list item's overlay when the item is disabled.
36+
list-item-disabled-state-layer-opacity: 0,
37+
// Opacity of the list item's primary & supporting text when the item is disabled.
38+
list-item-disabled-label-text-opacity: 0.38,
39+
// Opacity of the list item's leading icon when the item is disabled.
40+
list-item-disabled-leading-icon-opacity: 0.38,
41+
// Opacity of the list item's trailing icon when the item is disabled.
42+
list-item-disabled-trailing-icon-opacity: 0.38,
43+
// =============================================================================================
44+
// = TOKENS NOT USED IN ANGULAR MATERIAL =
45+
// =============================================================================================
46+
// Overline not implemented in Angular Material.
47+
// TODO(mmalerba): Consider implementing in the future.
48+
list-item-overline-color: null,
49+
list-item-overline-font: null,
50+
list-item-overline-line-height: null,
51+
list-item-overline-size: null,
52+
list-item-overline-tracking: null,
53+
list-item-overline-weight: null,
54+
// Leading video not implemented in Angular Material.
55+
// TODO(mmalerba): Consider implementing in the future.
56+
list-item-leading-video-shape: null,
57+
list-item-leading-video-width: null,
58+
list-item-leading-video-height: null,
59+
// Leading image not implemented in Angular Material.
60+
// TODO(mmalerba): Consider implementing in the future.
61+
list-item-leading-image-width: null,
62+
list-item-leading-image-height: null,
63+
list-item-leading-image-shape: null,
64+
// List divider is not implemented in Angular Material.
65+
// TODO(mmalerba): Maybe mat-divider should be based on these tokens?
66+
divider-color: null,
67+
divider-height: null,
68+
// Redundant since it is always overridden by one- two- or three- line tokens, omitted to save
69+
// bytes.
70+
list-item-container-height: null,
71+
// MDC does not seem to emit any CSS variables for these tokens, may be use in the future.
72+
// TODO(mmalerba): Discuss with MDC if these should be added.
73+
list-item-container-elevation: null,
74+
list-item-leading-avatar-label-color: null,
75+
list-item-leading-avatar-label-font: null,
76+
list-item-leading-avatar-label-line-height: null,
77+
list-item-leading-avatar-label-size: null,
78+
list-item-leading-avatar-label-tracking: null,
79+
list-item-leading-avatar-label-weight: null,
80+
list-item-unselected-trailing-icon-color: null,
81+
);
82+
}
83+
84+
// Tokens that can be configured through Angular Material's color theming API.
85+
@function get-color-tokens($config) {
86+
$foreground: map.get($config, foreground);
87+
$is-dark: map.get($config, is-dark);
88+
$foreground-base: theming.get-color-from-palette($foreground, base);
89+
$text-icon-on-background:
90+
theming.get-color-from-palette($foreground, base, if($is-dark, 0.5, 0.38));
91+
92+
@return (
93+
// Text color of the list item primary text.
94+
list-item-label-text-color: theming.get-color-from-palette($foreground, text),
95+
// Text color of the list item supporting text.
96+
list-item-supporting-text-color: theming.get-color-from-palette($foreground, secondary-text),
97+
// Color of the list item's leading icon.
98+
list-item-leading-icon-color: $text-icon-on-background,
99+
// Text color of the list item's trailing text.
100+
list-item-trailing-supporting-text-color: theming.get-color-from-palette(
101+
$foreground, hint-text),
102+
// Color of the list item's trailing icon.
103+
list-item-trailing-icon-color: $text-icon-on-background,
104+
// Color of the list item's trailing icon when the item is selected.
105+
list-item-selected-trailing-icon-color: $text-icon-on-background,
106+
// Text color of the list item's primary text when the item is disabled.
107+
list-item-disabled-label-text-color: theming.get-color-from-palette($foreground, base),
108+
// Color of the list item's leading icon when the item is disabled.
109+
list-item-disabled-leading-icon-color: theming.get-color-from-palette($foreground, base),
110+
// Color of the list item's trailing icon when the item is disabled.
111+
list-item-disabled-trailing-icon-color: theming.get-color-from-palette($foreground, base),
112+
// Color of the list item's primary text when the item is being hovered.
113+
list-item-hover-label-text-color: theming.get-color-from-palette($foreground, text),
114+
// Color of the list item's leading icon when the item is being hovered.
115+
list-item-hover-leading-icon-color: $text-icon-on-background,
116+
// Color of the list item's trailing icon when the item is being hovered.
117+
list-item-hover-trailing-icon-color: $text-icon-on-background,
118+
// Color of the list item's primary text when the item is focused.
119+
list-item-focus-label-text-color: theming.get-color-from-palette($foreground, text),
120+
// Color of the list item's overlay when the item is hovered.
121+
list-item-hover-state-layer-color: theming.get-color-from-palette($foreground, base),
122+
// Opacity of the list item's overlay when the item is hovered.
123+
list-item-hover-state-layer-opacity: if($is-dark, 0.08, 0.04),
124+
// Color of the list item's overlay when the item is focused.
125+
list-item-focus-state-layer-color: theming.get-color-from-palette($foreground, base),
126+
// Opacity of the list item's overlay when the item is focused.
127+
list-item-focus-state-layer-opacity: if($is-dark, 0.24, 0.12),
128+
);
129+
}
130+
131+
// Tokens that can be configured through Angular Material's typography theming API.
132+
@function get-typography-tokens($config) {
133+
@return (
134+
// Font family of the list item primary text.
135+
list-item-label-text-font: typography-utils.font-family($config, body-1)
136+
or typography-utils.font-family($config),
137+
// Line height of the list item primary text.
138+
list-item-label-text-line-height: typography-utils.line-height($config, body-1),
139+
// Font size of the list item primary text.
140+
list-item-label-text-size: typography-utils.font-size($config, body-1),
141+
// Letter spacing of the list item primary text.
142+
list-item-label-text-tracking: typography-utils.letter-spacing($config, body-1),
143+
// Font weight of the list item primary text.
144+
list-item-label-text-weight: typography-utils.font-weight($config, body-1),
145+
// Font family of the list item supporting text.
146+
list-item-supporting-text-font: typography-utils.font-family($config, body-2)
147+
or typography-utils.font-family($config),
148+
// Line height of the list item supporting text.
149+
list-item-supporting-text-line-height: typography-utils.line-height($config, body-2),
150+
// Font size of the list item supporting text.
151+
list-item-supporting-text-size: typography-utils.font-size($config, body-2),
152+
// Letter spacing of the list item supporting text.
153+
list-item-supporting-text-tracking: typography-utils.letter-spacing($config, body-2),
154+
// Font weight of the list item supporting text.
155+
list-item-supporting-text-weight: typography-utils.font-weight($config, body-2),
156+
// Font family of the list item's trailing text.
157+
list-item-trailing-supporting-text-font: typography-utils.font-family($config, caption)
158+
or typography-utils.font-family($config),
159+
// Line height of the list item's trailing text.
160+
list-item-trailing-supporting-text-line-height: typography-utils.line-height(
161+
$config, caption),
162+
// Font size of the list item's trailing text.
163+
list-item-trailing-supporting-text-size: typography-utils.font-size($config, caption),
164+
// Letter spacing color of the list item's trailing text.
165+
list-item-trailing-supporting-text-tracking: typography-utils.letter-spacing(
166+
$config, caption),
167+
// Font weight of the list item's trailing text.
168+
list-item-trailing-supporting-text-weight: typography-utils.font-weight($config, caption),
169+
);
170+
}
171+
172+
// Tokens that can be configured through Angular Material's density theming API.
173+
@function get-density-tokens($config) {
174+
$scale: theming.clamp-density($config, -5);
175+
176+
@return (
177+
// Height of one line list items.
178+
list-item-one-line-container-height: map.get((
179+
0: 48px,
180+
-1: 44px,
181+
-2: 40px,
182+
-3: 36px,
183+
-4: 32px,
184+
-5: 24px,
185+
), $scale),
186+
// Height of two line list items.
187+
list-item-two-line-container-height: map.get((
188+
0: 64px,
189+
-1: 60px,
190+
-2: 56px,
191+
-3: 52px,
192+
-4: 48px,
193+
-5: 48px,
194+
), $scale),
195+
// Height of three line list items.
196+
list-item-three-line-container-height: map.get((
197+
0: 88px,
198+
-1: 84px,
199+
-2: 80px,
200+
-3: 76px,
201+
-4: 72px,
202+
-5: 56px,
203+
), $scale),
204+
);
205+
}
206+
207+
// Combines the tokens generated by the above functions into a single map with placeholder values.
208+
// This is used to create token slots.
209+
@function get-token-slots() {
210+
@return map.merge(
211+
get-unthemable-tokens(),
212+
map.merge(
213+
get-color-tokens(token-utils.$placeholder-color-config),
214+
map.merge(
215+
get-typography-tokens(token-utils.$placeholder-typography-config),
216+
get-density-tokens(token-utils.$placeholder-density-config)
217+
)
218+
)
219+
);
220+
}
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
load("//tools:defaults.bzl", "sass_binary")
2+
load("@bazel_skylib//rules:build_test.bzl", "build_test")
3+
4+
package(default_visibility = ["//visibility:public"])
5+
6+
# Test theme used to ensure that our themes will compile using CSS variables in
7+
# the palettes.
8+
sass_binary(
9+
name = "test-validate-tokens",
10+
testonly = True,
11+
src = "test-validate-tokens.scss",
12+
deps = [
13+
"//:mdc_sass_lib",
14+
"//src/material/core:core_scss_lib",
15+
],
16+
)
17+
18+
build_test(
19+
name = "sass_compile_tests",
20+
targets = [
21+
":test-validate-tokens",
22+
],
23+
)

0 commit comments

Comments
 (0)