From 355f8b7092f88885f0bcecaca56011b5b0c07d39 Mon Sep 17 00:00:00 2001 From: Kristiyan Kostadinov Date: Sat, 22 Apr 2017 00:46:25 +0200 Subject: [PATCH] fix(theming): fix broken sass expressions nested in theme classes (#4145) Fixes #4077. --- src/lib/input/_input-theme.scss | 21 +++++---- src/lib/radio/_radio-theme.scss | 20 ++++---- src/lib/select/_select-theme.scss | 5 ++ src/lib/slider/_slider-theme.scss | 45 ++++++++---------- src/lib/tabs/_tabs-theme.scss | 5 +- stylelint-config.json | 8 +++- .../selector-nested-pattern-scoped/index.js | 46 +++++++++++++++++++ 7 files changed, 101 insertions(+), 49 deletions(-) create mode 100644 tools/stylelint/selector-nested-pattern-scoped/index.js diff --git a/src/lib/input/_input-theme.scss b/src/lib/input/_input-theme.scss index d669d56642c8..e57be1583fb0 100644 --- a/src/lib/input/_input-theme.scss +++ b/src/lib/input/_input-theme.scss @@ -22,18 +22,19 @@ .mat-input-placeholder { color: $input-placeholder-color; + } - // :focus is applied to the input, but we apply mat-focused to the other elements - // that need to listen to it. - .mat-focused & { - color: $input-floating-placeholder-color; + // :focus is applied to the input, but we apply mat-focused to the other elements + // that need to listen to it. + .mat-focused .mat-input-placeholder { + color: $input-floating-placeholder-color; - &.mat-accent { - color: $input-underline-color-accent; - } - &.mat-warn { - color: $input-underline-color-warn; - } + &.mat-accent { + color: $input-underline-color-accent; + } + + &.mat-warn { + color: $input-underline-color-warn; } } diff --git a/src/lib/radio/_radio-theme.scss b/src/lib/radio/_radio-theme.scss index 78787b95d6f0..32154e124558 100644 --- a/src/lib/radio/_radio-theme.scss +++ b/src/lib/radio/_radio-theme.scss @@ -11,28 +11,26 @@ .mat-radio-outer-circle { border-color: mat-color($foreground, secondary-text); + } - .mat-radio-checked & { - border-color: mat-color($accent); - } + .mat-radio-checked .mat-radio-outer-circle { + border-color: mat-color($accent); + } - .mat-radio-disabled & { - border-color: mat-color($foreground, disabled); - } + .mat-radio-disabled .mat-radio-outer-circle { + border-color: mat-color($foreground, disabled); } .mat-radio-inner-circle { background-color: mat-color($accent); - - .mat-radio-disabled & { - background-color: mat-color($foreground, disabled); - } } .mat-radio-ripple .mat-ripple-element { background-color: mat-color($accent, 0.26); + } - .mat-radio-disabled & { + .mat-radio-disabled { + .mat-radio-ripple .mat-ripple-element, .mat-radio-inner-circle { background-color: mat-color($foreground, disabled); } } diff --git a/src/lib/select/_select-theme.scss b/src/lib/select/_select-theme.scss index d996f4de8165..9a4efc1cad41 100644 --- a/src/lib/select/_select-theme.scss +++ b/src/lib/select/_select-theme.scss @@ -20,6 +20,11 @@ $accent: map-get($theme, accent); $warn: map-get($theme, warn); + .mat-select-trigger, + .mat-select-arrow { + color: mat-color($foreground, hint-text); + } + .mat-select-underline { background-color: mat-color($foreground, divider); } diff --git a/src/lib/slider/_slider-theme.scss b/src/lib/slider/_slider-theme.scss index 87d83bbc8ca9..4216913f75f7 100644 --- a/src/lib/slider/_slider-theme.scss +++ b/src/lib/slider/_slider-theme.scss @@ -1,6 +1,17 @@ @import '../core/theming/palette'; @import '../core/theming/theming'; +@mixin _mat-slider-inner-content-theme($palette) { + .mat-slider-track-fill, + .mat-slider-thumb, + .mat-slider-thumb-label { + background-color: mat-color($palette); + } + + .mat-slider-thumb-label-text { + color: mat-color($palette, default-contrast); + } +} @mixin mat-slider-theme($theme) { $primary: map-get($theme, primary); @@ -19,40 +30,22 @@ background-color: $mat-slider-off-color; } - .mat-slider-track-fill, - .mat-slider-thumb, - .mat-slider-thumb-label { - .mat-primary & { - background-color: mat-color($primary); - } + .mat-primary { + @include _mat-slider-inner-content-theme($primary); + } - .mat-accent & { - background-color: mat-color($accent); - } + .mat-accent { + @include _mat-slider-inner-content-theme($accent); + } - .mat-warn & { - background-color: mat-color($warn); - } + .mat-warn { + @include _mat-slider-inner-content-theme($warn); } .mat-slider-focus-ring { background-color: $mat-slider-focus-ring-color; } - .mat-slider-thumb-label-text { - .mat-primary & { - color: mat-color($primary, default-contrast); - } - - .mat-accent & { - color: mat-color($accent, default-contrast); - } - - .mat-warn & { - color: mat-color($warn, default-contrast); - } - } - .mat-slider:hover, .cdk-focused { .mat-slider-track-background { diff --git a/src/lib/tabs/_tabs-theme.scss b/src/lib/tabs/_tabs-theme.scss index 3ef8625cb26e..30bdae6f3807 100644 --- a/src/lib/tabs/_tabs-theme.scss +++ b/src/lib/tabs/_tabs-theme.scss @@ -12,8 +12,11 @@ .mat-tab-nav-bar, .mat-tab-header { border-bottom: $header-border; + } - .mat-tab-group-inverted-header & { + .mat-tab-group-inverted-header { + .mat-tab-nav-bar, + .mat-tab-header { border-top: $header-border; border-bottom: none; } diff --git a/stylelint-config.json b/stylelint-config.json index 5451f05d3ad5..cde993a310c1 100644 --- a/stylelint-config.json +++ b/stylelint-config.json @@ -1,9 +1,15 @@ { "plugins": [ - "./tools/stylelint/no-prefixes/no-prefixes.js" + "./tools/stylelint/no-prefixes/no-prefixes.js", + "./tools/stylelint/selector-nested-pattern-scoped/index.js" ], "rules": { "material/no-prefixes": [["last 2 versions", "not ie <= 10", "not ie_mob <= 10"]], + "material/selector-nested-pattern-scoped": [".*[^&]$", { + "message": "The & operator is not allowed at the end of theme selectors.", + "filePattern": "-theme\\.scss$" + }], + "color-hex-case": "lower", "color-no-invalid-hex": true, diff --git a/tools/stylelint/selector-nested-pattern-scoped/index.js b/tools/stylelint/selector-nested-pattern-scoped/index.js new file mode 100644 index 000000000000..18f6d0d8481b --- /dev/null +++ b/tools/stylelint/selector-nested-pattern-scoped/index.js @@ -0,0 +1,46 @@ +const stylelint = require('stylelint'); +const path = require('path'); +const isStandardSyntaxRule = require('stylelint/lib/utils/isStandardSyntaxRule'); +const isStandardSyntaxSelector = require('stylelint/lib/utils/isStandardSyntaxSelector'); + +const ruleName = 'material/selector-nested-pattern-scoped'; +const messages = stylelint.utils.ruleMessages(ruleName, { + expected: selector => `Expected nested selector '${selector}' to match specified pattern`, +}); + +/** + * Re-implementation of the `selector-nested-pattern` Stylelint rule, allowing us + * to scope it to a particular set of files via the custom `filePattern` option. The + * primary use-case is to be able to apply the rule only to theme files. + * + * Reference: https://stylelint.io/user-guide/rules/selector-nested-pattern/ + * Source: https://github.com/stylelint/stylelint/blob/master/lib/rules/selector-nested-pattern/ + */ +const plugin = stylelint.createPlugin(ruleName, (pattern, options) => { + return (root, result) => { + const selectorPattern = new RegExp(pattern); + const filePattern = new RegExp(options.filePattern); + const fileName = path.basename(root.source.input.file); + + if (!filePattern.test(fileName)) return; + + root.walkRules(rule => { + if (rule.parent.type === 'rule' && + isStandardSyntaxRule(rule) && + isStandardSyntaxSelector(rule.selector) && + !selectorPattern.test(rule.selector)) { + + stylelint.utils.report({ + result, + ruleName, + message: messages.expected(rule.selector), + node: rule + }); + } + }); + }; +}); + +plugin.ruleName = ruleName; +plugin.messages = messages; +module.exports = plugin;