Skip to content

Commit 6095e29

Browse files
devversionandrewseguin
authored andcommitted
feat: report warning if duplicate theme styles are generated
As of the new theming API refactorings, a theme by default includes density styles for the zero density-scale. This means that the common pattern of using the `angular-material-theme` for secondary themes in a project could cause duplicated styles when the new API is explicitly used. Generally, we want to detect if theme styles are duplicated. This will be helpful for developers defining multiple themes as we can notify them if similar theme styles end up multiple times in an application. If the duplicate styles are intentional, the warning can be explicitly disabled. docs: improvements to guide changes docs: add description for individual theme mixins refactor: add duplicated theme styles check to all individual theme mixins Adds the duplicated theme styles check to all individual theme mixins. Also, adds a lint rule that enforces that the theme styles check is included in every theme mixin w/ autofix. build: do not build test sass files in legacy output Looks like the exclude glob does not work as expected. Hence the new theming bundle test fails as there is no theming bundle when the legacy gulp tasks process Sass files. Address feedback as per team meeting Address feedback (cleanup stylelint rule) More obvious error if theme variables are named incorrectly Also ran clang-format refactor: all-theme file should transitively provide `mat-core` mixin. Partially reverts commit 9c97cf3 so that we don't need to perform a large migration in g3 to land the density API changes. refactor: convert new theme-mixin-api stylelint rule to typescript We recently refactored all stylelint rules to TypeScript. Similarly we should migrate the new rule that has been added in the density feature branch. build: include mdc-color and mdc-density entry-points in release (#19141) The new `mdc-color` and `mdc-density` entry-points should be included in the `@angular/material-experimental` package.
1 parent 5063e5c commit 6095e29

File tree

95 files changed

+1330
-422
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

95 files changed

+1330
-422
lines changed

.stylelintrc.json

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,13 +6,15 @@
66
"./tools/stylelint/selector-no-deep.ts",
77
"./tools/stylelint/no-nested-mixin.ts",
88
"./tools/stylelint/no-concrete-rules.ts",
9-
"./tools/stylelint/no-top-level-ampersand-in-mixin.ts"
9+
"./tools/stylelint/no-top-level-ampersand-in-mixin.ts",
10+
"./tools/stylelint/theme-mixin-api.ts"
1011
],
1112
"rules": {
1213
"material/no-prefixes": [true, {
1314
"browsers": ["last 2 versions", "not ie <= 10", "not ie_mob <= 10"],
1415
"filePattern": "**/!(*-example.css)"
1516
}],
17+
"material/theme-mixin-api": true,
1618
"material/selector-no-deep": true,
1719
"material/no-nested-mixin": true,
1820
"material/no-ampersand-beyond-selector-start": [true, {

guides/duplicate-theming-styles.md

Lines changed: 78 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,78 @@
1+
# Avoiding duplicated theming styles
2+
3+
As explained in the [theming guide](./theming.md), a theme in Angular Material consists of
4+
configurations for the `color`, `density` and `typography` systems. As some of these individual
5+
systems have default configurations, some usage patterns may cause duplication in the CSS output.
6+
7+
Below are examples of patterns that generate duplicative theme styles:
8+
9+
**Example #1**
10+
11+
```scss
12+
$light-theme: mat-light-theme((color: ...));
13+
$dark-theme: mat-dark-theme((color: ...));
14+
15+
// Generates styles for all systems configured in the theme. In this case, color styles
16+
// and default density styles are generated. Density is in themes by default.
17+
@include angular-material-theme($light-theme);
18+
19+
.dark-theme {
20+
// Generates styles for all systems configured in the theme. In this case, color styles
21+
// and the default density styles are generated. **Note** that this is a problem because it
22+
// means that density styles are generated *again*, even though only the color should change.
23+
@include angular-material-theme($dark-theme);
24+
}
25+
```
26+
27+
To fix this, you can use the dedicated mixin for color styles for the `.dark-theme`
28+
selector. Replace the `angular-material-theme` mixin and include the dark theme using the
29+
`angular-material-color` mixin. For example:
30+
31+
```scss
32+
...
33+
@include angular-material-theme($light-theme);
34+
35+
.dark-theme {
36+
// This mixin only generates the color styles now.
37+
@include angular-material-color($dark-theme);
38+
}
39+
```
40+
41+
Typography can also be configured via Sass mixin; see `angular-material-typography`.
42+
43+
**Example #2**
44+
45+
Theme styles could also be duplicated if individual theme mixins are used. For example:
46+
47+
```scss
48+
@include angular-material-theme($my-theme);
49+
50+
.my-custom-dark-button {
51+
// This will also generate the default density styles again.
52+
@include mat-button-theme($my-theme);
53+
}
54+
```
55+
56+
To avoid this duplication of styles, use the dedicated mixin for the color system and
57+
extract the configuration for the color system from the theme.
58+
59+
```scss
60+
.my-custom-dark-button {
61+
// This will only generate the color styles for `mat-button`.
62+
@include mat-button-color($my-theme);
63+
}
64+
```
65+
66+
#### Disabling duplication warnings
67+
68+
If your application intentionally duplicates styles, a global Sass variable can be
69+
set to disable duplication warnings from Angular Material. For example:
70+
71+
```scss
72+
$mat-theme-ignore-duplication-warnings: true;
73+
74+
// Include themes as usual.
75+
@include angular-material-theme($light-theme);
76+
77+
...
78+
```

guides/theming-your-components.md

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,10 @@ For example, if building a custom carousel component:
1111
// Import library functions for theme creation.
1212
@import '~@angular/material/theming';
1313

14-
@mixin candy-carousel-color($config) {
14+
@mixin candy-carousel-color($config-or-theme) {
15+
// Extract the color configuration in case a theme has been passed.
16+
// This allows consumers to either pass a theme object or a color configuration.
17+
$config: mat-get-color-config($config-or-theme);
1518
// Extract the palettes you need from the theme definition.
1619
$primary: map-get($config, primary);
1720
$accent: map-get($config, accent);
@@ -29,7 +32,10 @@ Second, create another Sass mixin that accepts an Angular Material typography co
2932
and outputs typographic styles. For example:
3033

3134
```scss
32-
@mixin candy-carousel-typography($config) {
35+
@mixin candy-carousel-typography($config-or-theme) {
36+
// Extract the typography configuration in case a theme has been passed.
37+
$config: mat-get-typography-config($config-or-theme);
38+
3339
.candy-carousel {
3440
font: {
3541
family: mat-font-family($config, body-1);

guides/theming.md

Lines changed: 13 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -192,6 +192,8 @@ styles for all configured theming system parts. For example, typography styles w
192192
multiple times, even though the configuration did not change. Instead, use fine-grained mixins such
193193
as `angular-material-color` that only result in styles being generated for the [color system][2].
194194

195+
Read more about duplicated theme styles in the [dedicated guide](./duplicate-theming-styles.md).
196+
195197
##### Multiple themes and overlay-based components
196198
Since certain components (e.g. menu, select, dialog, etc.) are inside of a global overlay container,
197199
an additional step is required for those components to be affected by the theme's css class selector
@@ -247,12 +249,20 @@ $candy-app-theme: mat-light-theme((
247249
#### Changing styles at run-time
248250

249251
##### Toggling classes
250-
You can use the mixins described above to define styles to customize any part of your application
251-
with standard CSS selectors. For example, let's say you want to toggle alternate colors on a button.
252+
You can use the theming mixins to customize any part of your application with standard
253+
CSS selectors. For example, let's say you want to toggle alternate colors on a button.
252254
You would first define a CSS class with the alternate colors.
255+
256+
Note that `mat-button-color` should be used instead of `mat-button-theme` as we only
257+
want to have alternate colors for the button. Using the theme mixin could result in
258+
duplicative theme styles if the `mat-button-theme` has been included before. Read more about
259+
this in the [dedicated guide](./duplicate-theming-styles.md).
260+
253261
```scss
254262
.alternate-button {
255-
@include mat-button-theme($alternate-theme);
263+
// Extract the color configuration from the theme and generate
264+
// the color theme styles for `mat-button`.
265+
@include mat-button-color($alternate-theme);
256266
}
257267
```
258268

src/dev-app/BUILD.bazel

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -96,6 +96,7 @@ sass_binary(
9696
],
9797
deps = [
9898
"//src/material-experimental/column-resize:column_resize_scss_lib",
99+
"//src/material-experimental/mdc-color:all_color",
99100
"//src/material-experimental/mdc-density:all_density",
100101
"//src/material-experimental/mdc-theming:all_themes",
101102
"//src/material-experimental/mdc-typography:all_typography",

src/dev-app/theme.scss

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,11 @@
1-
@import '../material/core/core';
2-
@import '../material/core/theming/all-theme';
1+
@import '../material/core/color/all-color';
32
@import '../material/core/density/all-density';
43
@import '../material/core/focus-indicators/focus-indicators';
54
@import '../material/core/theming/all-theme';
65
@import '../material-experimental/column-resize/column-resize';
76
@import '../material-experimental/mdc-helpers/mdc-helpers';
8-
@import '../material-experimental/mdc-helpers/focus-indicator';
7+
@import '../material-experimental/mdc-helpers/focus-indicators';
8+
@import '../material-experimental/mdc-color/all-color';
99
@import '../material-experimental/mdc-theming/all-theme';
1010
@import '../material-experimental/mdc-typography/all-typography';
1111
@import '../material-experimental/mdc-density/all-density';
@@ -65,16 +65,16 @@ $dark-theme: mat-dark-theme((
6565
// `.demo-unicorn-dark-theme` will be affected by this alternate dark theme instead of the
6666
// default theme.
6767
.demo-unicorn-dark-theme {
68-
@include angular-material-theme($dark-theme);
69-
@include angular-material-mdc-theme($dark-theme);
70-
@include mat-column-resize-theme($dark-theme);
71-
@include mat-popover-edit-theme($dark-theme);
68+
@include angular-material-color($dark-theme);
69+
@include angular-material-mdc-color($dark-theme);
70+
@include mat-column-resize-color($dark-theme);
71+
@include mat-popover-edit-color($dark-theme);
7272
}
7373

7474
// Include the dark theme for focus indicators.
7575
.demo-unicorn-dark-theme.demo-strong-focus {
76-
@include mat-strong-focus-indicators-theme($dark-theme);
77-
@include mat-mdc-strong-focus-indicators-theme($dark-theme);
76+
@include mat-strong-focus-indicators-color($dark-theme);
77+
@include mat-mdc-strong-focus-indicators-color($dark-theme);
7878
}
7979

8080
// Create classes for all density scales which are supported by all MDC-based components.

src/e2e-app/theme.scss

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,3 @@
1-
@import '../material/core/core';
21
@import '../material/core/theming/all-theme';
32
@import '../material-experimental/mdc-theming/all-theme';
43
@import '../material-experimental/mdc-typography/all-typography';

src/material-experimental/BUILD.bazel

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,8 @@ ng_package(
2424
name = "npm_package",
2525
srcs = ["package.json"],
2626
data = MATERIAL_EXPERIMENTAL_SCSS_LIBS + [
27+
"//src/material-experimental/mdc-color",
28+
"//src/material-experimental/mdc-density",
2729
"//src/material-experimental/mdc-helpers",
2830
"//src/material-experimental/mdc-theming",
2931
"//src/material-experimental/mdc-typography",

src/material-experimental/column-resize/_column-resize.scss

Lines changed: 11 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,8 @@
33
@import '../../material/core/theming/palette';
44
@import '../../material/core/theming/theming';
55

6-
@mixin mat-column-resize-color($config) {
6+
@mixin mat-column-resize-color($config-or-theme) {
7+
$config: mat-get-color-config($config-or-theme);
78
$primary: map-get($config, primary);
89
$foreground: map-get($config, foreground);
910

@@ -95,11 +96,17 @@
9596
}
9697
}
9798

98-
@mixin mat-column-resize-typography($config) {}
99+
@mixin mat-column-resize-typography($config-or-theme) {
100+
$config: mat-get-typography-config($config-or-theme);
101+
}
99102

100-
@mixin mat-column-resize-density($density-scale) {}
103+
@mixin mat-column-resize-density($config-or-theme) {
104+
$density-scale: mat-get-density-config($config-or-theme);
105+
}
101106

102-
@mixin mat-column-resize-theme($theme) {
107+
@mixin mat-column-resize-theme($theme-or-color-config) {
108+
$theme: _mat-legacy-get-theme($theme-or-color-config);
109+
@include _mat-check-duplicate-theme-styles($theme, 'mat-column-resize');
103110
$color: mat-get-color-config($theme);
104111
$density: mat-get-density-config($theme);
105112
$typography: mat-get-typography-config($theme);

src/material-experimental/mdc-autocomplete/_autocomplete-theme.scss

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,20 +1,26 @@
11
@import '../mdc-helpers/mdc-helpers';
22

3-
@mixin mat-mdc-autocomplete-color($config) {
3+
@mixin mat-mdc-autocomplete-color($config-or-theme) {
4+
$config: mat-get-color-config($config-or-theme);
45
@include mat-using-mdc-theme($config) {
56
// TODO: implement MDC-based autocomplete.
67
}
78
}
89

9-
@mixin mat-mdc-autocomplete-typography($config) {
10+
@mixin mat-mdc-autocomplete-typography($config-or-theme) {
11+
$config: mat-get-typography-config($config-or-theme);
1012
@include mat-using-mdc-typography($config) {
1113
// TODO: implement MDC-based autocomplete.
1214
}
1315
}
1416

15-
@mixin mat-mdc-autocomplete-density($density-scale) {}
17+
@mixin mat-mdc-autocomplete-density($config-or-theme) {
18+
$density-scale: mat-get-density-config($config-or-theme);
19+
}
1620

17-
@mixin mat-mdc-autocomplete-theme($theme) {
21+
@mixin mat-mdc-autocomplete-theme($theme-or-color-config) {
22+
$theme: _mat-legacy-get-theme($theme-or-color-config);
23+
@include _mat-check-duplicate-theme-styles($theme, 'mat-mdc-autocomplete');
1824
$color: mat-get-color-config($theme);
1925
$density: mat-get-density-config($theme);
2026
$typography: mat-get-typography-config($theme);

src/material-experimental/mdc-button/_button-theme.scss

Lines changed: 28 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,8 @@ $mat-button-state-target: '.mdc-button__ripple';
4949
}
5050

5151

52-
@mixin mat-mdc-button-color($config) {
52+
@mixin mat-mdc-button-color($config-or-theme) {
53+
$config: mat-get-color-config($config-or-theme);
5354
@include mat-using-mdc-theme($config) {
5455
// Add state interactions for hover, focus, press, active. Colors are changed based on
5556
// the mixin mdc-states-base-color
@@ -164,13 +165,15 @@ $mat-button-state-target: '.mdc-button__ripple';
164165
}
165166
}
166167

167-
@mixin mat-mdc-button-typography($config) {
168+
@mixin mat-mdc-button-typography($config-or-theme) {
169+
$config: mat-get-typography-config($config-or-theme);
168170
@include mat-using-mdc-typography($config) {
169171
@include mdc-button-without-ripple($query: $mat-typography-styles-query);
170172
}
171173
}
172174

173-
@mixin mat-mdc-button-density($density-scale) {
175+
@mixin mat-mdc-button-density($config-or-theme) {
176+
$density-scale: mat-get-density-config($config-or-theme);
174177
.mat-mdc-button,
175178
.mat-mdc-raised-button,
176179
.mat-mdc-unelevated-button,
@@ -179,7 +182,9 @@ $mat-button-state-target: '.mdc-button__ripple';
179182
}
180183
}
181184

182-
@mixin mat-mdc-button-theme($theme) {
185+
@mixin mat-mdc-button-theme($theme-or-color-config) {
186+
$theme: _mat-legacy-get-theme($theme-or-color-config);
187+
@include _mat-check-duplicate-theme-styles($theme, 'mat-mdc-button');
183188
$color: mat-get-color-config($theme);
184189
$density: mat-get-density-config($theme);
185190
$typography: mat-get-typography-config($theme);
@@ -195,7 +200,8 @@ $mat-button-state-target: '.mdc-button__ripple';
195200
}
196201
}
197202

198-
@mixin mat-mdc-fab-color($config) {
203+
@mixin mat-mdc-fab-color($config-or-theme) {
204+
$config: mat-get-color-config($config-or-theme);
199205
@include mat-using-mdc-theme($config) {
200206
.mat-mdc-fab, .mat-mdc-mini-fab {
201207
@include mdc-states(
@@ -244,15 +250,20 @@ $mat-button-state-target: '.mdc-button__ripple';
244250
}
245251
}
246252

247-
@mixin mat-mdc-fab-typography($config) {
253+
@mixin mat-mdc-fab-typography($config-or-theme) {
254+
$config: mat-get-typography-config($config-or-theme);
248255
@include mat-using-mdc-typography($config) {
249256
@include mdc-fab-without-ripple($query: $mat-typography-styles-query);
250257
}
251258
}
252259

253-
@mixin mat-mdc-fab-density($density-scale) {}
260+
@mixin mat-mdc-fab-density($config-or-theme) {
261+
$density-scale: mat-get-density-config($config-or-theme);
262+
}
254263

255-
@mixin mat-mdc-fab-theme($theme) {
264+
@mixin mat-mdc-fab-theme($theme-or-color-config) {
265+
$theme: _mat-legacy-get-theme($theme-or-color-config);
266+
@include _mat-check-duplicate-theme-styles($theme, 'mat-mdc-fab');
256267
$color: mat-get-color-config($theme);
257268
$density: mat-get-density-config($theme);
258269
$typography: mat-get-typography-config($theme);
@@ -269,7 +280,8 @@ $mat-button-state-target: '.mdc-button__ripple';
269280
}
270281

271282

272-
@mixin mat-mdc-icon-button-color($config) {
283+
@mixin mat-mdc-icon-button-color($config-or-theme) {
284+
$config: mat-get-color-config($config-or-theme);
273285
@include mat-using-mdc-theme($config) {
274286
.mat-mdc-icon-button {
275287
@include mdc-states(
@@ -312,19 +324,23 @@ $mat-button-state-target: '.mdc-button__ripple';
312324
}
313325
}
314326

315-
@mixin mat-mdc-icon-button-typography($config) {
327+
@mixin mat-mdc-icon-button-typography($config-or-theme) {
328+
$config: mat-get-typography-config($config-or-theme);
316329
@include mat-using-mdc-typography($config) {
317330
@include mdc-icon-button-without-ripple($query: $mat-typography-styles-query);
318331
}
319332
}
320333

321-
@mixin mat-mdc-icon-button-density($density-scale) {
334+
@mixin mat-mdc-icon-button-density($config-or-theme) {
335+
$density-scale: mat-get-density-config($config-or-theme);
322336
.mat-mdc-icon-button {
323337
@include mdc-icon-button-density($density-scale);
324338
}
325339
}
326340

327-
@mixin mat-mdc-icon-button-theme($theme) {
341+
@mixin mat-mdc-icon-button-theme($theme-or-color-config) {
342+
$theme: _mat-legacy-get-theme($theme-or-color-config);
343+
@include _mat-check-duplicate-theme-styles($theme, 'mat-mdc-icon-button');
328344
$color: mat-get-color-config($theme);
329345
$density: mat-get-density-config($theme);
330346
$typography: mat-get-typography-config($theme);

0 commit comments

Comments
 (0)