Skip to content

Commit d9698fe

Browse files
devversionandrewseguin
authored andcommitted
refactor: fixes for theming api refactor and introduction of a theming API test
With the initial commits for the density system, a function for retrieving the color configuration from the theme object has been introduced. This function is currently flawed since it always uses the theme object as color configuration if the theme does not have a `color` property. This is incorrect because the `color` config can be explicitly set to `null`, or omitted if no color styles are desired.
1 parent 7b1a978 commit d9698fe

File tree

8 files changed

+249
-32
lines changed

8 files changed

+249
-32
lines changed

src/material/core/BUILD.bazel

Lines changed: 0 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -138,11 +138,3 @@ filegroup(
138138
name = "source-files",
139139
srcs = glob(["**/*.ts"]),
140140
)
141-
142-
# Test theme used to ensure that our themes will compile using CSS variables in the palettes.
143-
sass_binary(
144-
name = "test-css-variables-theme",
145-
testonly = True,
146-
src = "theming/test-css-variables-theme.scss",
147-
deps = [":theming_scss_lib"],
148-
)

src/material/core/_core.scss

Lines changed: 25 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -19,38 +19,44 @@
1919
@include cdk-text-field();
2020
}
2121

22-
// Mixin that renders all of the core styles that depend on the theme.
23-
@mixin mat-core-theme($theme) {
24-
$color: mat-get-color-config($theme);
25-
@include mat-ripple-theme($theme);
26-
@include mat-option-theme($theme);
27-
@include mat-optgroup-theme($theme);
28-
@include mat-pseudo-checkbox-theme($theme);
29-
30-
// Provides external CSS classes for each elevation value. Each CSS class is formatted as
31-
// `mat-elevation-z$zValue` where `$zValue` corresponds to the z-space to which the element is
32-
// elevated.
33-
@for $zValue from 0 through 24 {
34-
.#{$_mat-elevation-prefix}#{$zValue} {
35-
@include _mat-theme-elevation($zValue, $color);
36-
}
37-
}
38-
22+
@mixin mat-core-color($config) {
3923
// Wrapper element that provides the theme background when the user's content isn't
4024
// inside of a `mat-sidenav-container`. Note that we need to exclude the ampersand
4125
// selector in case the mixin is included at the top level.
4226
.mat-app-background#{if(&, ', &.mat-app-background', '')} {
43-
$background: map-get($color, background);
44-
$foreground: map-get($color, foreground);
27+
$background: map-get($config, background);
28+
$foreground: map-get($config, foreground);
4529

4630
background-color: mat-color($background, background);
4731
color: mat-color($foreground, text);
4832
}
4933

34+
// Provides external CSS classes for each elevation value. Each CSS class is formatted as
35+
// `mat-elevation-z$zValue` where `$zValue` corresponds to the z-space to which the element is
36+
// elevated.
37+
@for $zValue from 0 through 24 {
38+
.#{$_mat-elevation-prefix}#{$zValue} {
39+
@include _mat-theme-elevation($zValue, $config);
40+
}
41+
}
42+
5043
// Marker that is used to determine whether the user has added a theme to their page.
5144
@at-root {
5245
.mat-theme-loaded-marker {
5346
display: none;
5447
}
5548
}
5649
}
50+
51+
// Mixin that renders all of the core styles that depend on the theme.
52+
@mixin mat-core-theme($theme) {
53+
@include mat-ripple-theme($theme);
54+
@include mat-option-theme($theme);
55+
@include mat-optgroup-theme($theme);
56+
@include mat-pseudo-checkbox-theme($theme);
57+
58+
$color: mat-get-color-config($theme);
59+
@if $color != null {
60+
@include mat-core-color($color);
61+
}
62+
}

src/material/core/theming/_theming.scss

Lines changed: 18 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -67,7 +67,7 @@
6767
// Validates the specified theme by ensuring that the optional color config defines
6868
// a primary, accent and warn palette. Returns the theme if no failures were found.
6969
@function _mat-validate-theme($theme) {
70-
@if map_has_key($theme, color) {
70+
@if map_get($theme, color) {
7171
$color: map_get($theme, color);
7272
@if not map_get($color, primary) {
7373
@error 'Theme does not define a valid "primary" palette.';
@@ -82,6 +82,16 @@
8282
@return $theme;
8383
}
8484

85+
// Whether the specified object is a color configuration. This function is needed for backwards
86+
// compatibility of individual component theme mixins, because developers could pass in a color
87+
// configuration instead of a theme container object to a theme mixin.
88+
@function _mat-is-color-config($config) {
89+
@return map_has_key($config, primary) and
90+
map_has_key($config, accent) and map_has_key($config, warn) and
91+
map_has_key($config, is-dark) and map_has_key($config, foreground) and
92+
map_has_key($config, background);
93+
}
94+
8595
// Creates a light-themed color configuration from the specified
8696
// primary, accent and warn palettes.
8797
@function _mat-create-light-color-config($primary, $accent, $warn: null) {
@@ -176,12 +186,16 @@
176186
@return _mat-validate-theme($result);
177187
}
178188

179-
// Needed for backwards compatibility. If the passed `$theme` variable is not a
180-
// overall theme configuration, we use it as color config.
181-
@function mat-get-color-config($theme, $default: $theme) {
189+
@function mat-get-color-config($theme, $default: null) {
182190
@if map_has_key($theme, color) {
183191
@return map_get($theme, color);
184192
}
193+
// Before we introduced the new pattern for construcing a theme, developers passed the color
194+
// configuration to the theme mixins. This can be still the case if developers construct a
195+
// theme manually and pass it to a theme. We support this for backwards compatibility.
196+
@if _mat-is-color-config($theme) {
197+
@return $theme;
198+
}
185199
@return $default;
186200
}
187201

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
package(default_visibility = ["//visibility:public"])
2+
3+
load("//tools:defaults.bzl", "sass_binary")
4+
5+
# Test theme used to ensure that our themes will compile using CSS variables in
6+
# the palettes.
7+
sass_binary(
8+
name = "test-css-variables-theme",
9+
testonly = True,
10+
src = "test-css-variables-theme.scss",
11+
deps = ["//src/material/core:theming_scss_lib"],
12+
)
13+
14+
# Sass binary which is used to ensure that our themes will compile with the legacy and new
15+
# pattern for configuring themes. For more information on the legacy and new pattern, inspect
16+
# the `mat-light-theme` and `mat-dark-theme` theming functions.
17+
sass_binary(
18+
name = "test-theming-api",
19+
testonly = True,
20+
src = "test-theming-api.scss",
21+
deps = ["//src/material/core:theming_scss_lib"],
22+
)

src/material/core/theming/test-css-variables-theme.scss renamed to src/material/core/theming/tests/test-css-variables-theme.scss

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
@import './all-theme';
1+
@import '../all-theme';
22

33
// Recursively replaces all of the values inside a Sass map with a different value.
44
@function replace-all-values($palette, $replacement) {
Lines changed: 179 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,179 @@
1+
@import '../all-theme';
2+
3+
// A new way to configure themes has been introduced. This Sass file ensures that the theming
4+
// API is backwards compatible, so that the old pattern for configuring themes can be still
5+
// used. The Sass compilation of this file will fail if one of the tests/assertions fails.
6+
7+
$primary: mat-palette($mat-blue);
8+
$accent: mat-palette($mat-grey);
9+
$warn: mat-palette($mat-indigo);
10+
$default-warn: mat-palette($mat-red);
11+
12+
// Asserts that a given value matches the expected value. If not, an error is
13+
// thrown with the given error message.
14+
@mixin assert($value, $expected, $error-msg) {
15+
@if $value != $expected {
16+
@error 'Expected "#{$value}" to be "#{$expected}". #{$error-msg}';
17+
}
18+
}
19+
20+
// Asserts that the specified color configuration is configured properly.
21+
@mixin assert-color-config($config, $primary, $accent, $warn, $is-dark) {
22+
$color: map_get($config, color);
23+
@include assert(map_get($color, primary), $primary,
24+
'Primary palette does not match expected palette.');
25+
@include assert(map_get($color, accent), $accent,
26+
'Accent palette does not match expected palette.');
27+
@include assert(map_get($color, warn), $warn,
28+
'Warn palette does not match expected palette.');
29+
@include assert(map_get($color, is-dark), $is-dark,
30+
'Expected color config `is-dark` to be: #{$is-dark}');
31+
}
32+
33+
$legacy-light-theme: mat-light-theme($primary, $accent, $warn);
34+
$legacy-dark-theme: mat-dark-theme($primary, $accent, $warn);
35+
$legacy-light-theme-default-warn: mat-light-theme($primary, $accent);
36+
$legacy-dark-theme-default-warn: mat-dark-theme($primary, $accent);
37+
38+
$new-api-light-theme: mat-light-theme((
39+
color: (primary: $primary, accent: $accent, warn: $warn)
40+
));
41+
$new-api-dark-theme: mat-dark-theme((
42+
color: (primary: $primary, accent: $accent, warn: $warn)
43+
));
44+
$new-api-light-theme-default-warn: mat-light-theme((
45+
color: (primary: $primary, accent: $accent)
46+
));
47+
$new-api-dark-theme-default-warn: mat-dark-theme((
48+
color: (primary: $primary, accent: $accent)
49+
));
50+
51+
$light-theme-only-density: mat-light-theme((density: -3));
52+
$dark-theme-only-density: mat-dark-theme((density: -3));
53+
54+
$typography-config: mat-typography-config();
55+
$light-theme-only-typography: mat-light-theme((typography: $typography-config));
56+
$dark-theme-only-typography: mat-dark-theme((typography: $typography-config));
57+
58+
// Test which ensures that constructed themes by default do not set configurations
59+
// for the individual parts of the theming system (color, density, typography).
60+
@mixin test-default-theming-system-configs() {
61+
$themes: ($legacy-light-theme, $legacy-dark-theme, $new-api-light-theme, $new-api-dark-theme);
62+
@each $theme in $themes {
63+
@include assert(map_has_key($theme, color), true,
64+
'Expected color to be explicitly configured.');
65+
@include assert(map_has_key($theme, typography), false,
66+
'Expected typography to be not explicitly configured.');
67+
@include assert(map_has_key($theme, density), false,
68+
'Expected density to be not explicitly configured.');
69+
}
70+
@include assert(map_has_key($light-theme-only-density, color), false,
71+
'Expected color to be not explicitly configured.');
72+
@include assert(map_has_key($dark-theme-only-density, color), false,
73+
'Expected color to be not explicitly configured.');
74+
}
75+
76+
// Test which ensures that constructed themes have the proper color configurations
77+
// as specified in the `mat-light-theme` and `mat-dark-theme` functions.
78+
@mixin test-create-color-config() {
79+
@include assert-color-config($legacy-light-theme, $primary, $accent, $warn, false);
80+
@include assert-color-config($legacy-dark-theme, $primary, $accent, $warn, true);
81+
@include assert-color-config($legacy-light-theme-default-warn, $primary, $accent,
82+
$default-warn, false);
83+
@include assert-color-config($legacy-dark-theme-default-warn, $primary, $accent,
84+
$default-warn, true);
85+
@include assert-color-config($new-api-light-theme, $primary, $accent, $warn, false);
86+
@include assert-color-config($new-api-dark-theme, $primary, $accent, $warn, true);
87+
@include assert-color-config($new-api-light-theme-default-warn, $primary, $accent,
88+
$default-warn, false);
89+
@include assert-color-config($new-api-dark-theme-default-warn, $primary, $accent,
90+
$default-warn, true);
91+
}
92+
93+
// Test which ensures that constructed themes pass through the specified
94+
// density and typography configurations.
95+
@mixin test-density-typography-config-pass-through() {
96+
@include assert(map_get($light-theme-only-density, density), -3,
97+
'Expected density config to be included in theme.');
98+
@include assert(map_get($dark-theme-only-density, density), -3,
99+
'Expected density config to be included in theme.');
100+
@include assert(map_get($light-theme-only-typography, typography), $typography-config,
101+
'Expected typography config to be included in theme.');
102+
@include assert(map_get($dark-theme-only-typography, typography), $typography-config,
103+
'Expected typography config to be included in theme.');
104+
}
105+
106+
// Test which ensures that color configurations can be properly read from
107+
// theme objects passed to individual component theme mixins.
108+
@mixin test-get-color-config() {
109+
$color-config: map_get($legacy-light-theme, color);
110+
$no-color-light-theme: mat-light-theme((color: null));
111+
$no-color-dark-theme: mat-dark-theme((color: null));
112+
@include assert(mat-get-color-config($color-config), $color-config,
113+
'Expected that passing a color config to a theme will work for backwards compatibility.');
114+
@include assert(mat-get-color-config($legacy-light-theme), $color-config,
115+
'Expected that a color config can be read from a theme object.');
116+
@include assert(mat-get-color-config($light-theme-only-density), null,
117+
'Expected that by default, no color configuration is used.');
118+
@include assert(mat-get-color-config($no-color-light-theme), null,
119+
'Expected that no color configuration can be explicitly specified.');
120+
@include assert(mat-get-color-config($no-color-dark-theme), null,
121+
'Expected that no color configuration can be explicitly specified.');
122+
}
123+
124+
// Test which ensures that density configurations can be properly read from
125+
// theme objects passed to individual component theme mixins.
126+
@mixin test-get-density-config() {
127+
$density-config: map_get($light-theme-only-density, density);
128+
$no-density-light-theme: mat-light-theme((density: null));
129+
$no-density-dark-theme: mat-dark-theme((density: null));
130+
@include assert(mat-get-density-config($light-theme-only-density), -3,
131+
'Expected that a density config can be read from a theme object.');
132+
@include assert(mat-get-density-config($light-theme-only-typography), 0,
133+
'Expected that by default, the density system will be configured.');
134+
@include assert(mat-get-density-config($no-density-light-theme), null,
135+
'Expected that no density configuration can be explicitly specified.');
136+
@include assert(mat-get-density-config($no-density-dark-theme), null,
137+
'Expected that no density configuration can be explicitly specified.');
138+
}
139+
140+
// Test which ensures that typography configurations can be properly read from
141+
// theme objects passed to individual component theme mixins.
142+
@mixin test-get-typography-config() {
143+
$no-typography-light-theme: mat-light-theme((density: null));
144+
$no-typography-dark-theme: mat-dark-theme((density: null));
145+
@include assert(mat-get-typography-config($light-theme-only-typography), $typography-config,
146+
'Expected that a typography config can be read from a theme object.');
147+
@include assert(mat-get-typography-config($legacy-light-theme), null,
148+
'Expected that by default, no typography configuration is used.');
149+
@include assert(mat-get-typography-config($no-typography-light-theme), null,
150+
'Expected that no typography configuration can be explicitly specified.');
151+
@include assert(mat-get-typography-config($no-typography-dark-theme), null,
152+
'Expected that no typography configuration can be explicitly specified.');
153+
}
154+
155+
// Test which ensures that all Angular Material theme mixins accept a theme
156+
// object without throwing any exception.
157+
@mixin test-theme-mixins-successful-compilation() {
158+
@include angular-material-theme($legacy-light-theme);
159+
@include angular-material-theme($legacy-light-theme-default-warn);
160+
@include angular-material-theme($legacy-dark-theme);
161+
@include angular-material-theme($legacy-dark-theme-default-warn);
162+
@include angular-material-theme($new-api-light-theme);
163+
@include angular-material-theme($new-api-light-theme-default-warn);
164+
@include angular-material-theme($new-api-dark-theme);
165+
@include angular-material-theme($new-api-dark-theme-default-warn);
166+
@include angular-material-theme($light-theme-only-density);
167+
@include angular-material-theme($dark-theme-only-density);
168+
@include angular-material-theme($light-theme-only-typography);
169+
@include angular-material-theme($dark-theme-only-typography);
170+
}
171+
172+
// Include all tests. Sass will throw if one of the tests fails.
173+
@include test-create-color-config();
174+
@include test-default-theming-system-configs();
175+
@include test-density-typography-config-pass-through();
176+
@include test-theme-mixins-successful-compilation();
177+
@include test-get-color-config();
178+
@include test-get-density-config();
179+
@include test-get-typography-config();

src/material/core/typography/_all-typography.scss

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
@import '../../card/card-theme';
88
@import '../../checkbox/checkbox-theme';
99
@import '../../chips/chips-theme';
10+
@import '../../divider/divider-theme';
1011
@import '../../table/table-theme';
1112
@import '../../datepicker/datepicker-theme';
1213
@import '../../dialog/dialog-theme';
@@ -51,6 +52,7 @@
5152
@include mat-card-typography($config);
5253
@include mat-checkbox-typography($config);
5354
@include mat-chips-typography($config);
55+
@include mat-divider-typography($config);
5456
@include mat-table-typography($config);
5557
@include mat-datepicker-typography($config);
5658
@include mat-dialog-typography($config);

src/material/divider/_divider-theme.scss

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,8 @@
1414
}
1515
}
1616

17+
@mixin mat-divider-typography($config) {}
18+
1719
@mixin _mat-divider-density($density-scale) {}
1820

1921
@mixin mat-divider-theme($theme) {

0 commit comments

Comments
 (0)