Skip to content

Commit 3fc1f9a

Browse files
authoredOct 23, 2024··
feat(material/schematics): Update custom theme schematic to work with light-dark and use theme-overrides mixin (#29911)
1 parent 4b49d73 commit 3fc1f9a

File tree

3 files changed

+95
-26
lines changed

3 files changed

+95
-26
lines changed
 

Diff for: ‎src/material/schematics/ng-generate/theme-color/README.md

+41-4
Original file line numberDiff line numberDiff line change
@@ -34,11 +34,47 @@ html {
3434
}
3535
```
3636

37-
High contrast override theme mixins are also generated in the file if specified
38-
(`high-contrast-light-theme-overrides` and `high-contrast-dark-theme-overrides`). These mixins
37+
## High contrast override mixins
38+
High contrast override theme mixins are also generated in the file if specified. These mixins
3939
override the system level variables with high contrast equivalent values from your theme. This is
4040
helpful for users who prefer more contrastful colors for either preference or accessibility reasons.
4141

42+
### Creating one theme for light and dark mode
43+
As of v19, the `theme` mixin can create one theme that detects and adapts to a user if they have
44+
light or dark theme with the [`light-dark` function](https://developer.mozilla.org/en-US/docs/Web/CSS/color_value/light-dark).
45+
46+
Apply the `high-contrast-overrides(color-scheme)` mixin wrapped inside `@media (prefers-contrast: more)`.
47+
48+
```scss
49+
@use '@angular/material';
50+
@use './path/to/my-theme'; // location of generated file
51+
52+
html {
53+
// Must specify color-scheme for theme mixin to automatically work
54+
color-scheme: light;
55+
56+
// Create one theme that works automatically for light and dark theme
57+
@include material.theme((
58+
color: (
59+
primary: my-theme.$primary-palette,
60+
tertiary: my-theme.$tertiary-palette,
61+
),
62+
typography: Roboto,
63+
density: 0,
64+
));
65+
66+
// Use high contrast values when users prefer contrast
67+
@media (prefers-contrast: more) {
68+
@include my-theme.high-contrast-overrides(color-scheme);
69+
}
70+
}
71+
```
72+
73+
### Creating separate themes for light and dark mode
74+
You can manually define the light theme and dark theme separately. This is recommended if you need
75+
granular control over when to show each specific theme in your application. Prior to v19, this was
76+
the only way to create light and dark themes.
77+
4278
```scss
4379
@use '@angular/material';
4480
@use './path/to/my-theme'; // location of generated file
@@ -49,14 +85,15 @@ html {
4985
color: (
5086
primary: my-theme.$primary-palette,
5187
tertiary: my-theme.$tertiary-palette,
88+
theme-type: light,
5289
),
5390
typography: Roboto,
5491
density: 0,
5592
));
5693

5794
// Use high contrast light theme colors when users prefer contrast
5895
@media (prefers-contrast: more) {
59-
@include my-theme.high-contrast-light-theme-overrides();
96+
@include my-theme.high-contrast-overrides(light);
6097
}
6198

6299
// Apply dark theme when users prefer a dark color scheme
@@ -71,7 +108,7 @@ html {
71108

72109
// Use high contrast dark theme colors when users prefers a dark color scheme and contrast
73110
@media (prefers-contrast: more) {
74-
@include my-theme.high-contrast-dark-theme-overrides();
111+
@include my-theme.high-contrast-overrides(dark);
75112
}
76113
}
77114
}

Diff for: ‎src/material/schematics/ng-generate/theme-color/index.spec.ts

+6-7
Original file line numberDiff line numberDiff line change
@@ -33,9 +33,9 @@ describe('material-theme-color-schematic', () => {
3333
),
3434
));
3535
36-
@if mixin-exists(high-contrast-light-theme-overrides) {
36+
@if mixin-exists(high-contrast-overrides) {
3737
& {
38-
@include high-contrast-light-theme-overrides();
38+
@include high-contrast-overrides(light);
3939
}
4040
}
4141
@@ -48,9 +48,9 @@ describe('material-theme-color-schematic', () => {
4848
),
4949
));
5050
51-
@if mixin-exists(high-contrast-dark-theme-overrides) {
51+
@if mixin-exists(high-contrast-overrides) {
5252
& {
53-
@include high-contrast-dark-theme-overrides();
53+
@include high-contrast-overrides(dark);
5454
}
5555
}
5656
}
@@ -213,16 +213,15 @@ describe('material-theme-color-schematic', () => {
213213
expect(transpileTheme(generatedSCSS)).toBe(transpileTheme(testSCSS));
214214
});
215215

216-
it('should be able to generate high contrast theme mixins', async () => {
216+
it('should be able to generate high contrast overrides mixin', async () => {
217217
const tree = await runM3ThemeSchematic(runner, {
218218
primaryColor: '#984061',
219219
includeHighContrast: true,
220220
});
221221

222222
const generatedSCSS = tree.readText('_theme-colors.scss');
223223

224-
expect(generatedSCSS).toContain(`@mixin high-contrast-light-theme-overrides`);
225-
expect(generatedSCSS).toContain(`@mixin high-contrast-dark-theme-overrides`);
224+
expect(generatedSCSS).toContain(`@mixin high-contrast-overrides`);
226225
});
227226

228227
it('should be able to generate high contrast themes overrides when provided a primary color', async () => {

Diff for: ‎src/material/schematics/ng-generate/theme-color/index.ts

+48-15
Original file line numberDiff line numberDiff line change
@@ -236,7 +236,6 @@ function getHighContrastOverides(
236236
overrides.set('surface-dim', hexFromArgb(scheme.surfaceDim));
237237
overrides.set('surface-bright', hexFromArgb(scheme.surfaceBright));
238238
overrides.set('surface-container-lowest', hexFromArgb(scheme.surfaceContainerLowest));
239-
overrides.set('surface-container-lowest', hexFromArgb(scheme.surfaceContainerLow));
240239
overrides.set('surface-container', hexFromArgb(scheme.surfaceContainer));
241240
overrides.set('surface-container-high', hexFromArgb(scheme.surfaceContainerHigh));
242241
overrides.set('surface-container-highest', hexFromArgb(scheme.surfaceContainerHighest));
@@ -278,22 +277,56 @@ function generateHighContrastOverrideMixinsSCSS(
278277
neutralPalette: TonalPalette,
279278
neutralVariantPalette: TonalPalette,
280279
): string {
280+
const lightOverrides = getHighContrastOverides(
281+
primaryPalette,
282+
secondaryPalette,
283+
tertiaryPalette,
284+
neutralPalette,
285+
neutralVariantPalette,
286+
/** isDark **/ false,
287+
);
288+
289+
const darkOverrides = getHighContrastOverides(
290+
primaryPalette,
291+
secondaryPalette,
292+
tertiaryPalette,
293+
neutralPalette,
294+
neutralVariantPalette,
295+
/** isDark **/ true,
296+
);
297+
298+
// Create private function to grab correct values based on theme-type
281299
let scss = '\n';
282-
for (const themeType of ['light', 'dark']) {
283-
const overrides = getHighContrastOverides(
284-
primaryPalette,
285-
secondaryPalette,
286-
tertiaryPalette,
287-
neutralPalette,
288-
neutralVariantPalette,
289-
themeType === 'dark',
290-
);
291-
scss += '\n@mixin high-contrast-' + themeType + '-theme-overrides {\n';
292-
for (const [key, value] of overrides!.entries()) {
293-
scss += ' --mat-sys-' + key + ': ' + value + ';\n';
294-
}
295-
scss += '};\n';
300+
scss += '\n@function _high-contrast-value($light, $dark, $theme-type) {\n';
301+
scss += ' @if ($theme-type == light) {\n';
302+
scss += ' @return $light;\n';
303+
scss += ' }\n';
304+
scss += ' @if ($theme-type == dark) {\n';
305+
scss += ' @return $dark;\n';
306+
scss += ' }\n';
307+
scss += ' @if ($theme-type == color-scheme) {\n';
308+
scss += ' @return light-dark(#{$light}, #{$dark});\n';
309+
scss += ' }\n';
310+
scss +=
311+
" \n @error 'Unknown theme-type #{$theme-type}. Expected light, dark, or color-scheme';\n";
312+
scss += '}\n';
313+
314+
// Create high contrast mixin with theme-type input that can be light, dark, or color-scheme.
315+
scss += '\n@mixin high-contrast-overrides($theme-type) {\n';
316+
scss += ' @include mat.theme-overrides((\n';
317+
for (const [key, value] of lightOverrides!.entries()) {
318+
scss +=
319+
' ' +
320+
key +
321+
': _high-contrast-value(' +
322+
value +
323+
', ' +
324+
darkOverrides.get(key) +
325+
', $theme-type),\n';
296326
}
327+
scss += ' ))\n';
328+
scss += ' }\n';
329+
297330
return scss;
298331
}
299332

0 commit comments

Comments
 (0)
Please sign in to comment.