fix: errors when building theme using CSS variables (#15140)

* Adds an extra theme to the build that will allow us to verify that everything still works if somebody passes in the palette colors as CSS variables.
* Fixes a handful of places where Sass would either throw an error or would produce invalid CSS.

Fixes #15107.
This commit is contained in:
Kristiyan Kostadinov
2019-02-13 16:30:11 +01:00
committed by Jeremy Elbourn
parent 3163cc6d74
commit 35e89e5344
11 changed files with 202 additions and 105 deletions
+6 -7
View File
@@ -18,13 +18,12 @@
}
}
/**
* Applies styles for users in high contrast mode. Note that this only applies
* to Microsoft browsers. Chrome can be included by checking for the `html[hc]`
* attribute, however Chrome handles high contrast differently.
* @param target Which kind of high contrast setting to target. Defaults to `active`, can be
* `white-on-black` or `black-on-white`.
*/
// Applies styles for users in high contrast mode. Note that this only applies
// to Microsoft browsers. Chrome can be included by checking for the `html[hc]`
// attribute, however Chrome handles high contrast differently.
//
// @param target Which kind of high contrast setting to target. Defaults to `active`, can be
// `white-on-black` or `black-on-white`.
@mixin cdk-high-contrast($target: active) {
@media (-ms-high-contrast: $target) {
@content;
+14 -6
View File
@@ -130,14 +130,22 @@ $mat-badge-large-size: $mat-badge-default-size + 6;
.mat-badge-disabled {
.mat-badge-content {
// The disabled color usually has some kind of opacity, but because the badge is overlayed
// on top of something else, it won't look good if it's opaque. We convert it into a solid
// color by taking the opacity from the rgba value and using the value to determine the
// percentage of the background to put into foreground when mixing the colors together.
$app-background: mat-color($background, 'background');
$badge-color: mat-color($foreground, disabled-button);
$badge-opacity: opacity($badge-color);
background: mix($app-background, rgba($badge-color, 1), (1 - $badge-opacity) * 100%);
// The disabled color usually has some kind of opacity, but because the badge is overlayed
// on top of something else, it won't look good if it's opaque. If it is a color *type*,
// we convert it into a solid color by taking the opacity from the rgba value and using
// the value to determine the percentage of the background to put into foreground when
// mixing the colors together.
@if (type-of($badge-color) == color and type-of($app-background) == color) {
$badge-opacity: opacity($badge-color);
background: mix($app-background, rgba($badge-color, 1), (1 - $badge-opacity) * 100%);
}
@else {
background: $badge-color;
}
color: mat-color($foreground, disabled-text);
}
}
+8
View File
@@ -125,3 +125,11 @@ filegroup(
name = "source-files",
srcs = glob(["**/*.ts"]),
)
# Test theme used to ensure that our themes will compile using CSS variables in the palettes.
sass_binary(
name = "test-css-variables-theme",
src = "theming/test-css-variables-theme.scss",
deps = [":all_themes"],
testonly = True
)
+9 -1
View File
@@ -40,6 +40,14 @@ $mat-ripple-color-opacity: 0.1;
$foreground-base: map_get($foreground, base);
.mat-ripple-element {
background-color: rgba($foreground-base, $mat-ripple-color-opacity);
// If the ripple color is resolves to a color *type*, we can use it directly, otherwise
// (e.g. it resolves to a CSS variable) we fall back to using the color and setting an opacity.
@if (type-of($foreground-base) == color) {
background-color: rgba($foreground-base, $mat-ripple-color-opacity);
}
@else {
background-color: $foreground-base;
opacity: $mat-ripple-color-opacity;
}
}
}
+81 -75
View File
@@ -32,92 +32,98 @@
// all of the values between them.
@function _get-umbra-map($color, $opacity) {
$shadow-color: if(type-of($color) == color, rgba($color, $opacity * 0.2), $color);
@return (
0: '0px 0px 0px 0px #{rgba($color, $opacity * 0.2)}',
1: '0px 2px 1px -1px #{rgba($color, $opacity * 0.2)}',
2: '0px 3px 1px -2px #{rgba($color, $opacity * 0.2)}',
3: '0px 3px 3px -2px #{rgba($color, $opacity * 0.2)}',
4: '0px 2px 4px -1px #{rgba($color, $opacity * 0.2)}',
5: '0px 3px 5px -1px #{rgba($color, $opacity * 0.2)}',
6: '0px 3px 5px -1px #{rgba($color, $opacity * 0.2)}',
7: '0px 4px 5px -2px #{rgba($color, $opacity * 0.2)}',
8: '0px 5px 5px -3px #{rgba($color, $opacity * 0.2)}',
9: '0px 5px 6px -3px #{rgba($color, $opacity * 0.2)}',
10: '0px 6px 6px -3px #{rgba($color, $opacity * 0.2)}',
11: '0px 6px 7px -4px #{rgba($color, $opacity * 0.2)}',
12: '0px 7px 8px -4px #{rgba($color, $opacity * 0.2)}',
13: '0px 7px 8px -4px #{rgba($color, $opacity * 0.2)}',
14: '0px 7px 9px -4px #{rgba($color, $opacity * 0.2)}',
15: '0px 8px 9px -5px #{rgba($color, $opacity * 0.2)}',
16: '0px 8px 10px -5px #{rgba($color, $opacity * 0.2)}',
17: '0px 8px 11px -5px #{rgba($color, $opacity * 0.2)}',
18: '0px 9px 11px -5px #{rgba($color, $opacity * 0.2)}',
19: '0px 9px 12px -6px #{rgba($color, $opacity * 0.2)}',
20: '0px 10px 13px -6px #{rgba($color, $opacity * 0.2)}',
21: '0px 10px 13px -6px #{rgba($color, $opacity * 0.2)}',
22: '0px 10px 14px -6px #{rgba($color, $opacity * 0.2)}',
23: '0px 11px 14px -7px #{rgba($color, $opacity * 0.2)}',
24: '0px 11px 15px -7px #{rgba($color, $opacity * 0.2)}'
0: '0px 0px 0px 0px #{$shadow-color}',
1: '0px 2px 1px -1px #{$shadow-color}',
2: '0px 3px 1px -2px #{$shadow-color}',
3: '0px 3px 3px -2px #{$shadow-color}',
4: '0px 2px 4px -1px #{$shadow-color}',
5: '0px 3px 5px -1px #{$shadow-color}',
6: '0px 3px 5px -1px #{$shadow-color}',
7: '0px 4px 5px -2px #{$shadow-color}',
8: '0px 5px 5px -3px #{$shadow-color}',
9: '0px 5px 6px -3px #{$shadow-color}',
10: '0px 6px 6px -3px #{$shadow-color}',
11: '0px 6px 7px -4px #{$shadow-color}',
12: '0px 7px 8px -4px #{$shadow-color}',
13: '0px 7px 8px -4px #{$shadow-color}',
14: '0px 7px 9px -4px #{$shadow-color}',
15: '0px 8px 9px -5px #{$shadow-color}',
16: '0px 8px 10px -5px #{$shadow-color}',
17: '0px 8px 11px -5px #{$shadow-color}',
18: '0px 9px 11px -5px #{$shadow-color}',
19: '0px 9px 12px -6px #{$shadow-color}',
20: '0px 10px 13px -6px #{$shadow-color}',
21: '0px 10px 13px -6px #{$shadow-color}',
22: '0px 10px 14px -6px #{$shadow-color}',
23: '0px 11px 14px -7px #{$shadow-color}',
24: '0px 11px 15px -7px #{$shadow-color}'
);
}
@function _get-penumbra-map($color, $opacity) {
$shadow-color: if(type-of($color) == color, rgba($color, $opacity * 0.14), $color);
@return (
0: '0px 0px 0px 0px #{rgba($color, $opacity * 0.14)}',
1: '0px 1px 1px 0px #{rgba($color, $opacity * 0.14)}',
2: '0px 2px 2px 0px #{rgba($color, $opacity * 0.14)}',
3: '0px 3px 4px 0px #{rgba($color, $opacity * 0.14)}',
4: '0px 4px 5px 0px #{rgba($color, $opacity * 0.14)}',
5: '0px 5px 8px 0px #{rgba($color, $opacity * 0.14)}',
6: '0px 6px 10px 0px #{rgba($color, $opacity * 0.14)}',
7: '0px 7px 10px 1px #{rgba($color, $opacity * 0.14)}',
8: '0px 8px 10px 1px #{rgba($color, $opacity * 0.14)}',
9: '0px 9px 12px 1px #{rgba($color, $opacity * 0.14)}',
10: '0px 10px 14px 1px #{rgba($color, $opacity * 0.14)}',
11: '0px 11px 15px 1px #{rgba($color, $opacity * 0.14)}',
12: '0px 12px 17px 2px #{rgba($color, $opacity * 0.14)}',
13: '0px 13px 19px 2px #{rgba($color, $opacity * 0.14)}',
14: '0px 14px 21px 2px #{rgba($color, $opacity * 0.14)}',
15: '0px 15px 22px 2px #{rgba($color, $opacity * 0.14)}',
16: '0px 16px 24px 2px #{rgba($color, $opacity * 0.14)}',
17: '0px 17px 26px 2px #{rgba($color, $opacity * 0.14)}',
18: '0px 18px 28px 2px #{rgba($color, $opacity * 0.14)}',
19: '0px 19px 29px 2px #{rgba($color, $opacity * 0.14)}',
20: '0px 20px 31px 3px #{rgba($color, $opacity * 0.14)}',
21: '0px 21px 33px 3px #{rgba($color, $opacity * 0.14)}',
22: '0px 22px 35px 3px #{rgba($color, $opacity * 0.14)}',
23: '0px 23px 36px 3px #{rgba($color, $opacity * 0.14)}',
24: '0px 24px 38px 3px #{rgba($color, $opacity * 0.14)}'
0: '0px 0px 0px 0px #{$shadow-color}',
1: '0px 1px 1px 0px #{$shadow-color}',
2: '0px 2px 2px 0px #{$shadow-color}',
3: '0px 3px 4px 0px #{$shadow-color}',
4: '0px 4px 5px 0px #{$shadow-color}',
5: '0px 5px 8px 0px #{$shadow-color}',
6: '0px 6px 10px 0px #{$shadow-color}',
7: '0px 7px 10px 1px #{$shadow-color}',
8: '0px 8px 10px 1px #{$shadow-color}',
9: '0px 9px 12px 1px #{$shadow-color}',
10: '0px 10px 14px 1px #{$shadow-color}',
11: '0px 11px 15px 1px #{$shadow-color}',
12: '0px 12px 17px 2px #{$shadow-color}',
13: '0px 13px 19px 2px #{$shadow-color}',
14: '0px 14px 21px 2px #{$shadow-color}',
15: '0px 15px 22px 2px #{$shadow-color}',
16: '0px 16px 24px 2px #{$shadow-color}',
17: '0px 17px 26px 2px #{$shadow-color}',
18: '0px 18px 28px 2px #{$shadow-color}',
19: '0px 19px 29px 2px #{$shadow-color}',
20: '0px 20px 31px 3px #{$shadow-color}',
21: '0px 21px 33px 3px #{$shadow-color}',
22: '0px 22px 35px 3px #{$shadow-color}',
23: '0px 23px 36px 3px #{$shadow-color}',
24: '0px 24px 38px 3px #{$shadow-color}'
);
}
@function _get-ambient-map($color, $opacity) {
$shadow-color: if(type-of($color) == color, rgba($color, $opacity * 0.12), $color);
@return (
0: '0px 0px 0px 0px #{rgba($color, $opacity * 0.12)}',
1: '0px 1px 3px 0px #{rgba($color, $opacity * 0.12)}',
2: '0px 1px 5px 0px #{rgba($color, $opacity * 0.12)}',
3: '0px 1px 8px 0px #{rgba($color, $opacity * 0.12)}',
4: '0px 1px 10px 0px #{rgba($color, $opacity * 0.12)}',
5: '0px 1px 14px 0px #{rgba($color, $opacity * 0.12)}',
6: '0px 1px 18px 0px #{rgba($color, $opacity * 0.12)}',
7: '0px 2px 16px 1px #{rgba($color, $opacity * 0.12)}',
8: '0px 3px 14px 2px #{rgba($color, $opacity * 0.12)}',
9: '0px 3px 16px 2px #{rgba($color, $opacity * 0.12)}',
10: '0px 4px 18px 3px #{rgba($color, $opacity * 0.12)}',
11: '0px 4px 20px 3px #{rgba($color, $opacity * 0.12)}',
12: '0px 5px 22px 4px #{rgba($color, $opacity * 0.12)}',
13: '0px 5px 24px 4px #{rgba($color, $opacity * 0.12)}',
14: '0px 5px 26px 4px #{rgba($color, $opacity * 0.12)}',
15: '0px 6px 28px 5px #{rgba($color, $opacity * 0.12)}',
16: '0px 6px 30px 5px #{rgba($color, $opacity * 0.12)}',
17: '0px 6px 32px 5px #{rgba($color, $opacity * 0.12)}',
18: '0px 7px 34px 6px #{rgba($color, $opacity * 0.12)}',
19: '0px 7px 36px 6px #{rgba($color, $opacity * 0.12)}',
20: '0px 8px 38px 7px #{rgba($color, $opacity * 0.12)}',
21: '0px 8px 40px 7px #{rgba($color, $opacity * 0.12)}',
22: '0px 8px 42px 7px #{rgba($color, $opacity * 0.12)}',
23: '0px 9px 44px 8px #{rgba($color, $opacity * 0.12)}',
24: '0px 9px 46px 8px #{rgba($color, $opacity * 0.12)}'
0: '0px 0px 0px 0px #{$shadow-color}',
1: '0px 1px 3px 0px #{$shadow-color}',
2: '0px 1px 5px 0px #{$shadow-color}',
3: '0px 1px 8px 0px #{$shadow-color}',
4: '0px 1px 10px 0px #{$shadow-color}',
5: '0px 1px 14px 0px #{$shadow-color}',
6: '0px 1px 18px 0px #{$shadow-color}',
7: '0px 2px 16px 1px #{$shadow-color}',
8: '0px 3px 14px 2px #{$shadow-color}',
9: '0px 3px 16px 2px #{$shadow-color}',
10: '0px 4px 18px 3px #{$shadow-color}',
11: '0px 4px 20px 3px #{$shadow-color}',
12: '0px 5px 22px 4px #{$shadow-color}',
13: '0px 5px 24px 4px #{$shadow-color}',
14: '0px 5px 26px 4px #{$shadow-color}',
15: '0px 6px 28px 5px #{$shadow-color}',
16: '0px 6px 30px 5px #{$shadow-color}',
17: '0px 6px 32px 5px #{$shadow-color}',
18: '0px 7px 34px 6px #{$shadow-color}',
19: '0px 7px 36px 6px #{$shadow-color}',
20: '0px 8px 38px 7px #{$shadow-color}',
21: '0px 8px 40px 7px #{$shadow-color}',
22: '0px 8px 42px 7px #{$shadow-color}',
23: '0px 9px 44px 8px #{$shadow-color}',
24: '0px 9px 46px 8px #{$shadow-color}'
);
}
+8 -2
View File
@@ -52,9 +52,15 @@
}
$color: map-get($palette, $hue);
$opacity: if($opacity == null, opacity($color), $opacity);
@return rgba($color, $opacity);
@if (type-of($color) != color) {
// If the $color resolved to something different from a color (e.g. a CSS variable),
// we can't apply the opacity anyway so we return the value as is, otherwise Sass can
// throw an error or output something invalid.
@return $color;
}
@return rgba($color, if($opacity == null, opacity($color), $opacity));
}
@@ -0,0 +1,24 @@
@import './all-theme';
// Recursively replaces all of the values inside a Sass map with a different value.
@function replace-all-values($palette, $replacement) {
$output: ();
@each $key, $value in $palette {
@if (type-of($value) == 'map') {
$output: map-merge(($key: replace-all-values($value, $replacement)), $output);
}
@else {
$output: map-merge(($key: $replacement), $output);
}
}
@return $output;
}
// Theme used to test that our themes would compile if the colors were specified as CSS variables.
._demo-css-variables-theme {
$palette: mat-palette($mat-blue-grey);
$theme: mat-dark-theme($palette, $palette, $palette);
@include angular-material-theme(replace-all-values($theme, var(--test-var)));
}
+22 -2
View File
@@ -17,7 +17,16 @@ $mat-calendar-weekday-table-font-size: 11px !default;
}
.mat-calendar-body-disabled > .mat-calendar-body-selected {
background-color: fade-out(mat-color($palette), $mat-datepicker-selected-fade-amount);
$background: mat-color($palette);
@if (type-of($background) == color) {
background-color: fade-out($background, $mat-datepicker-selected-fade-amount);
}
@else {
// If we couldn't resolve to background to a color (e.g. it's a CSS variable),
// fall back to fading the content out via `opacity`.
opacity: $mat-datepicker-today-fade-amount;
}
}
.mat-calendar-body-today.mat-calendar-body-selected {
@@ -78,7 +87,18 @@ $mat-calendar-weekday-table-font-size: 11px !default;
}
.mat-calendar-body-disabled > .mat-calendar-body-today:not(.mat-calendar-body-selected) {
border-color: fade-out(mat-color($foreground, hint-text), $mat-datepicker-today-fade-amount);
$color: mat-color($foreground, hint-text);
@if (type-of($color) == color) {
border-color: fade-out($color, $mat-datepicker-today-fade-amount);
}
@else {
// If the color didn't resolve to a color value, but something like a CSS variable, we can't
// fade it out so we fall back to reducing the element opacity. Note that we don't use the
// $mat-datepicker-today-fade-amount, because hint text usually has some opacity applied
// to it already and we don't want them to stack on top of each other.
opacity: 0.5;
}
}
@include _mat-datepicker-color(map-get($theme, primary));
+15 -5
View File
@@ -10,10 +10,6 @@
$background: map-get($theme, background);
$foreground: map-get($theme, foreground);
// We use invert() here to have the darken the background color expected to be used. If the
// background is light, we use a dark backdrop. If the background is dark,
// we use a light backdrop.
$drawer-backdrop-color: invert(mat-color($background, card, 0.6));
$drawer-background-color: mat-color($background, dialog);
$drawer-container-background-color: mat-color($background, background);
$drawer-push-background-color: mat-color($background, dialog);
@@ -59,7 +55,21 @@
}
.mat-drawer-backdrop.mat-drawer-shown {
background-color: $drawer-backdrop-color;
$opacity: 0.6;
$backdrop-color: mat-color($background, card, $opacity);
@if (type-of($backdrop-color) == color) {
// We use invert() here to have the darken the background color expected to be used. If the
// background is light, we use a dark backdrop. If the background is dark,
// we use a light backdrop.
background-color: invert($backdrop-color);
}
@else {
// If we couldn't resolve the backdrop color to a color value, fall back to using
// `opacity` to make it opaque since its end value could be a solid color.
background-color: $backdrop-color;
opacity: $opacity;
}
}
}
+14 -6
View File
@@ -3,14 +3,22 @@
$foreground: map-get($theme, foreground);
.mat-sort-header-arrow {
// Because the arrow is made up of multiple elements that are stacked on top of each other,
// we can't use the semi-trasparent color from the theme directly. We convert it into a solid
// color by taking the opacity from the rgba value and using the value to determine the
// percentage of the background to put into foreground when mixing the colors together.
$table-background: mat-color($background, 'card');
$text-color: mat-color($foreground, secondary-text);
$text-opacity: opacity($text-color);
color: mix($table-background, rgba($text-color, 1), (1 - $text-opacity) * 100%);
// Because the arrow is made up of multiple elements that are stacked on top of each other,
// we can't use the semi-trasparent color from the theme directly. If the value is a color
// *type*, we convert it into a solid color by taking the opacity from the rgba value and
// using the value to determine the percentage of the background to put into foreground
// when mixing the colors together. Otherwise, if it resolves to something different
// (e.g. it resolves to a CSS variable), we use the color directly.
@if (type-of($table-background) == color and type-of($text-color) == color) {
$text-opacity: opacity($text-color);
color: mix($table-background, rgba($text-color, 1), (1 - $text-opacity) * 100%);
}
@else {
color: $text-color;
}
}
}
@@ -17,7 +17,7 @@ gulpSass.compiler = nodeSass;
/** Create a gulp task that builds SCSS files. */
export function buildScssPipeline(sourceDir: string, minifyOutput = false) {
return src(join(sourceDir, '**/*.scss'))
return src(join(sourceDir, '**/!(test-).scss'))
.pipe(gulpSass({includePaths: sassIncludePaths}).on('error', gulpSass.logError))
.pipe(gulpIf(minifyOutput, gulpCleanCss()));
}