Skip to content

Commit 3285ff2

Browse files
devversionandrewseguin
authored andcommitted
refactor: all-density, all-color and all-typography mixins should accept theme
With initial changes for the new density API, the individual mixins for `all-color`, `all-density` and `all-typography` started only accepting configurations for their actual theming system part. This makes sense conceptually, but in favor of a better developer experience, we also want to support that actual `$theme` objects can be specified. The mixins then extract the individual configs from the theme objects. This allows consumers to easily generate color styles for dark themes. e.g. ``` $my-theme: mat-light-theme((color: $color-config)); $my-dark-theme: mat-dark-theme((color: $color-confi)); // Includes color and default density. Typography is not included // by default for backwards compatibility. @include angular-material-theme($my-theme); .dark-enabled { // Note: Using the overall `theme` mixin here would cause // density styles to be duplicated unnecessarily. @include angular-material-color($my-dark-theme); } ``` docs: update documentation for new api refactor: update ng-add schematic refactor: add color mixin for material-experimental and add theme support in bulk mixins docs: guide edits refactor: all-typography mixin should use all-theme to avoid c… (#19021) As discussed in our team meeting, we want to get rid of the duplication of individual theme, color, density and typography mixins (similar to how we did it for all-density and all-color). We couldn't simplify the all-typography mixin because the `core-theme` mixin is stored in a file that relies on `all-typography`. This causes a circular dependency when `all-typography` would then rely on `all-theme`. To fix this, we split the `mat-core-theme` and `mat-core` mixin into separate files. This avoids the circular dependency. Additionally, a test has been created that ensures that the theming bundle still exposes the necessary mixins/variables as needed.
1 parent 1d7ba38 commit 3285ff2

27 files changed

+350
-202
lines changed

.github/CODEOWNERS

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -99,6 +99,7 @@
9999
/src/material-experimental/mdc-card/** @mmalerba
100100
/src/material-experimental/mdc-checkbox/** @mmalerba
101101
/src/material-experimental/mdc-chips/** @mmalerba
102+
/src/material-experimental/mdc-color/** @jelbourn @devversion
102103
/src/material-experimental/mdc-density/** @devversion
103104
/src/material-experimental/mdc-dialog/** @devversion
104105
/src/material-experimental/mdc-form-field/** @devversion @mmalerba

guides/theming-your-components.md

Lines changed: 36 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -3,31 +3,30 @@ In order to style your own components with Angular Material's tooling, the compo
33
be defined with Sass.
44

55
#### 1. Define all color and typography styles in a "theme file" for the component
6-
First, create a Sass mixin that accepts an Angular Material theme and outputs the color-specific
7-
styles for the component. An Angular Material theme definition is a Sass map.
6+
First, create a Sass mixin that accepts an Angular Material color configuration and
7+
outputs the color-specific styles for the component. A color configuration is a Sass map.
88

99
For example, if building a custom carousel component:
1010
```scss
1111
// Import library functions for theme creation.
1212
@import '~@angular/material/theming';
1313

14-
// Define a mixin that accepts a theme and outputs the theme-specific styles.
15-
@mixin candy-carousel-theme($theme) {
14+
@mixin candy-carousel-color($config) {
1615
// Extract the palettes you need from the theme definition.
17-
$primary: map-get($theme, primary);
18-
$accent: map-get($theme, accent);
16+
$primary: map-get($config, primary);
17+
$accent: map-get($config, accent);
1918

2019
// Define any styles affected by the theme.
2120
.candy-carousel {
2221
// Use mat-color to extract individual colors from a palette.
23-
background-color: mat-color($primary);
24-
border-color: mat-color($accent, A400);
22+
background-color: mat-color($config);
23+
border-color: mat-color($config, A400);
2524
}
2625
}
2726
```
2827

29-
Second, create another Sass mixin that accepts an Angular Material typography definition and outputs
30-
typographic styles. For example:
28+
Second, create another Sass mixin that accepts an Angular Material typography configuration
29+
and outputs typographic styles. For example:
3130

3231
```scss
3332
@mixin candy-carousel-typography($config) {
@@ -41,6 +40,27 @@ typographic styles. For example:
4140
}
4241
```
4342

43+
Finally, create a mixin that accepts an Angular Material theme, and delegates to the individual
44+
theming system mixins based on the configurations. A theme consists of configurations for
45+
individual theming systems (`color` and `typography`).
46+
47+
```scss
48+
@mixin candy-carousel-theme($theme) {
49+
// Extracts the color and typography configurations from the theme.
50+
$color: mat-get-color-config($theme);
51+
$typography: mat-get-typography-config($theme);
52+
53+
// Do not generate styles if configurations for individual theming
54+
// systems have been explicitly set to `null`.
55+
@if $color != null {
56+
@include candy-carousel-color($color);
57+
}
58+
@if $typography != null {
59+
@include candy-carousel-typography($typography);
60+
}
61+
}
62+
```
63+
4464
See the [typography guide](https://material.angular.io/guide/typography) for more information on
4565
typographic customization.
4666

@@ -63,7 +83,12 @@ including Angular Material's built-in theme mixins.
6383
// Define your application's custom theme.
6484
$primary: mat-palette($mat-indigo);
6585
$accent: mat-palette($mat-pink, A200, A100, A400);
66-
$theme: mat-light-theme($primary, $accent);
86+
$theme: mat-light-theme((
87+
color: (
88+
primary: $primary,
89+
accent: $accent,
90+
)
91+
));
6792

6893
// Include theme styles for Angular Material components.
6994
@include angular-material-theme($theme);

guides/theming.md

Lines changed: 60 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -2,21 +2,26 @@
22

33

44
### What is a theme?
5-
A **theme** is the set of colors that will be applied to the Angular Material components. The
6-
library's approach to theming is based on the guidance from the [Material Design spec][1].
75

8-
In Angular Material, a theme is created by composing multiple palettes. In particular,
9-
a theme consists of:
6+
Angular Material's theming system enables you to customize components to
7+
better reflect your product's brand. A theme consists of configurations for the individual
8+
`color` and `typography` systems in Angular Material. The library's approach to theming reflects
9+
the guidance from the [Material Design spec][1].
10+
11+
In Angular Material, you create a color configuration by composing multiple palettes. In
12+
particular, a color configuration consists of:
13+
1014
* A primary palette: colors most widely used across all screens and components.
1115
* An accent palette: colors used for the floating action button and interactive elements.
1216
* A warn palette: colors used to convey error state.
1317
* A foreground palette: colors for text and icons.
1418
* A background palette: colors used for element backgrounds.
1519

16-
In Angular Material, all theme styles are generated _statically_ at build-time so that your
17-
app doesn't have to spend cycles generating theme styles on startup.
20+
Additionally, in Angular Material, a configuration may optionally include `typography` settings.
21+
More information on how typography works can be [found in a dedicated guide][3].
1822

19-
[1]: https://material.io/archive/guidelines/style/color.html#color-color-palette
23+
Angular Material theme styles are generated _statically_ at build-time so that your
24+
app doesn't have to spend cycles generating theme styles on startup.
2025

2126
### Using a pre-built theme
2227
Angular Material comes prepackaged with several pre-built theme css files. These theme files also
@@ -57,10 +62,11 @@ A custom theme file does two things:
5762
1. Imports the `mat-core()` Sass mixin. This includes all common styles that are used by multiple
5863
components. **This should only be included once in your application.** If this mixin is included
5964
multiple times, your application will end up with multiple copies of these common styles.
60-
2. Defines a **theme** data structure as the composition of multiple palettes. This object can be
61-
created with either the `mat-light-theme` function or the `mat-dark-theme` function. The output of
62-
this function is then passed to the `angular-material-theme` mixin, which will output all of the
63-
corresponding styles for the theme.
65+
2. Defines a **theme** data structure as the composition of configurations for the individual
66+
theming systems (`color` and `typography`). This object can be created with either the
67+
`mat-light-theme` function or the `mat-dark-theme` function. The output of this function is then
68+
passed to the `angular-material-theme` mixin, which will output all of the corresponding styles
69+
for the theme.
6470

6571

6672
A typical theme file will look something like this:
@@ -82,8 +88,15 @@ $candy-app-accent: mat-palette($mat-pink, A200, A100, A400);
8288
// The warn palette is optional (defaults to red).
8389
$candy-app-warn: mat-palette($mat-red);
8490

85-
// Create the theme object (a Sass map containing all of the palettes).
86-
$candy-app-theme: mat-light-theme($candy-app-primary, $candy-app-accent, $candy-app-warn);
91+
// Create the theme object. A theme consists of configurations for individual
92+
// theming systems such as `color` or `typography`.
93+
$candy-app-theme: mat-light-theme((
94+
color: (
95+
primary: $candy-app-primary,
96+
accent: $candy-app-accent,
97+
warn: $candy-app-warn,
98+
)
99+
));
87100

88101
// Include theme styles for core and each component used in your app.
89102
// Alternatively, you can import and @include the theme mixins for each component
@@ -135,34 +148,49 @@ theme.
135148
// Define the default theme (same as the example above).
136149
$candy-app-primary: mat-palette($mat-indigo);
137150
$candy-app-accent: mat-palette($mat-pink, A200, A100, A400);
138-
$candy-app-theme: mat-light-theme($candy-app-primary, $candy-app-accent);
139-
140-
// Include the default theme styles.
151+
$candy-app-theme: mat-light-theme((
152+
color: (
153+
primary: $candy-app-primary,
154+
accent: $candy-app-accent,
155+
)
156+
));
157+
158+
// Include the default theme styles (color and default density)
141159
@include angular-material-theme($candy-app-theme);
142160

143161

144162
// Define an alternate dark theme.
145163
$dark-primary: mat-palette($mat-blue-grey);
146164
$dark-accent: mat-palette($mat-amber, A200, A100, A400);
147165
$dark-warn: mat-palette($mat-deep-orange);
148-
$dark-theme: mat-dark-theme($dark-primary, $dark-accent, $dark-warn);
149-
150-
// Include the alternative theme styles inside of a block with a CSS class. You can make this
166+
$dark-theme: mat-dark-theme((
167+
color: (
168+
primary: $dark-primary,
169+
accent: $dark-accent,
170+
warn: $dark-warn,
171+
)
172+
));
173+
174+
// Include the dark color styles inside of a block with a CSS class. You can make this
151175
// CSS class whatever you want. In this example, any component inside of an element with
152176
// `.unicorn-dark-theme` will be affected by this alternate dark theme instead of the default theme.
153177
.unicorn-dark-theme {
154-
@include angular-material-theme($dark-theme);
178+
@include angular-material-color($dark-theme);
155179
}
156180
```
157181

158182
In the above example, any component inside of a parent with the `unicorn-dark-theme` class will use
159183
the dark theme, while other components will fall back to the default `$candy-app-theme`.
160184

161-
You can include as many themes as you like in this manner. You can also `@include` the
162-
`angular-material-theme` in separate files and then lazily load them based on an end-user
185+
You can include as many color schemes as you like in this manner. You can also `@include` the
186+
`angular-material-color` in separate files and then lazily load them based on an end-user
163187
interaction (how to lazily load the CSS assets will vary based on your application).
164188

165189
It's important to remember, however, that the `mat-core` mixin should only ever be included _once_.
190+
Similarly, the `angular-material-theme` mixin should not be used multiple times as it generates
191+
styles for all configured theming system parts. For example, typography styles would be generated
192+
multiple times, even though the configuration did not change. Instead, use fine-grained mixins such
193+
as `angular-material-color` that only result in styles being generated for the [color system][2].
166194

167195
##### Multiple themes and overlay-based components
168196
Since certain components (e.g. menu, select, dialog, etc.) are inside of a global overlay container,
@@ -203,7 +231,12 @@ the `mat-core-theme` mixin as well, which contains theme-specific styles for com
203231
// Define the theme.
204232
$candy-app-primary: mat-palette($mat-indigo);
205233
$candy-app-accent: mat-palette($mat-pink, A200, A100, A400);
206-
$candy-app-theme: mat-light-theme($candy-app-primary, $candy-app-accent);
234+
$candy-app-theme: mat-light-theme((
235+
color: (
236+
primary: $candy-app-primary,
237+
accent: $candy-app-accent,
238+
)
239+
));
207240

208241
// Include the theme styles for only specified components.
209242
@include mat-core-theme($candy-app-theme);
@@ -251,3 +284,7 @@ function changeTheme(themeName) {
251284
### Theming your own components
252285
For more details about theming your own components,
253286
see [theming-your-components.md](./theming-your-components.md).
287+
288+
[1]: https://material.io/archive/guidelines/style/color.html#color-color-palette
289+
[2]: https://material.io/design/color
290+
[3]: ./typography.md

src/dev-app/theme.scss

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
@import '../material/core/core';
2+
@import '../material/core/theming/all-theme';
13
@import '../material/core/density/all-density';
24
@import '../material/core/focus-indicators/focus-indicators';
35
@import '../material/core/theming/all-theme';
@@ -82,6 +84,6 @@ $density-scales: (-1, -2, minimum, maximum);
8284
@each $density in$density-scales {
8385
.demo-density-#{$density} {
8486
@include _angular-material-density($density);
85-
@include angular-material-density-mdc($density);
87+
@include angular-material-mdc-density($density);
8688
}
8789
}

src/e2e-app/theme.scss

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
@import '../material/core/core';
12
@import '../material/core/theming/all-theme';
23
@import '../material-experimental/mdc-theming/all-theme';
34
@import '../material-experimental/mdc-typography/all-typography';
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
package(default_visibility = ["//visibility:public"])
2+
3+
load("//tools:defaults.bzl", "sass_library")
4+
5+
sass_library(
6+
name = "all_color",
7+
srcs = ["_all-color.scss"],
8+
deps = ["//src/material-experimental/mdc-theming:all_themes"],
9+
)
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
@import '../mdc-theming/all-theme';
2+
3+
@mixin angular-material-mdc-color($config-or-theme) {
4+
// In case a theme object has been passed instead of a configuration for
5+
// the color system, extract the color config from the theme object.
6+
$config: if(_mat-is-theme-object($config-or-theme),
7+
mat-get-color-config($config-or-theme), $config-or-theme);
8+
9+
@if $config == null {
10+
@error 'No color configuration specified.';
11+
}
12+
13+
@include angular-material-mdc-theme((
14+
color: $config,
15+
typography: null,
16+
density: null,
17+
));
18+
}

src/material-experimental/mdc-density/_all-density.scss

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,15 @@
11
@import '../mdc-theming/all-theme';
22

3-
@mixin angular-material-density-mdc($config: null) {
3+
@mixin angular-material-mdc-density($config-or-theme) {
4+
// In case a theme object has been passed instead of a configuration for
5+
// the density system, extract the density config from the theme object.
6+
$config: if(_mat-is-theme-object($config-or-theme),
7+
mat-get-density-config($config-or-theme), $config-or-theme);
8+
9+
@if $config == null {
10+
@error 'No density configuration specified.';
11+
}
12+
413
@include angular-material-mdc-theme((
514
color: null,
615
typography: null,

src/material-experimental/mdc-typography/_all-typography.scss

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,10 @@
11
@import '../mdc-theming/all-theme';
22

3-
@mixin angular-material-mdc-typography($config: null) {
3+
@mixin angular-material-mdc-typography($config-or-theme: null) {
4+
$config: if(_mat-is-theme-object($config-or-theme),
5+
mat-get-typography-config($config-or-theme), $config-or-theme);
6+
7+
// If no actual color configuration has been specified, create a default one.
48
@if $config == null {
59
$config: mat-typography-config();
610
}

src/material/core/_core-theme.scss

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
@import './theming/theming';
2+
@import './style/elevation';
3+
@import './ripple/ripple';
4+
@import './option/option-theme';
5+
@import './option/optgroup-theme';
6+
@import './selection/pseudo-checkbox/pseudo-checkbox-theme';
7+
8+
@mixin mat-core-color($config) {
9+
// Wrapper element that provides the theme background when the user's content isn't
10+
// inside of a `mat-sidenav-container`. Note that we need to exclude the ampersand
11+
// selector in case the mixin is included at the top level.
12+
.mat-app-background#{if(&, ', &.mat-app-background', '')} {
13+
$background: map-get($config, background);
14+
$foreground: map-get($config, foreground);
15+
16+
background-color: mat-color($background, background);
17+
color: mat-color($foreground, text);
18+
}
19+
20+
// Provides external CSS classes for each elevation value. Each CSS class is formatted as
21+
// `mat-elevation-z$zValue` where `$zValue` corresponds to the z-space to which the element is
22+
// elevated.
23+
@for $zValue from 0 through 24 {
24+
.#{$_mat-elevation-prefix}#{$zValue} {
25+
@include _mat-theme-elevation($zValue, $config);
26+
}
27+
}
28+
29+
// Marker that is used to determine whether the user has added a theme to their page.
30+
@at-root {
31+
.mat-theme-loaded-marker {
32+
display: none;
33+
}
34+
}
35+
}
36+
37+
// Mixin that renders all of the core styles that depend on the theme.
38+
@mixin mat-core-theme($theme) {
39+
@include mat-ripple-theme($theme);
40+
@include mat-option-theme($theme);
41+
@include mat-optgroup-theme($theme);
42+
@include mat-pseudo-checkbox-theme($theme);
43+
44+
$color: mat-get-color-config($theme);
45+
@if $color != null {
46+
@include mat-core-color($color);
47+
}
48+
}

0 commit comments

Comments
 (0)