Skip to content

Commit

Permalink
build: update and fix vendor prefixes rule (#22704)
Browse files Browse the repository at this point in the history
The `no-prefixes` lint rule was tied to a very old version of Autoprefixer which wasn't detecting some properties. These changes update to the latest version, adjust our code account for some breaking changes and fix the previously-undetected issues.
  • Loading branch information
crisbeto committed May 21, 2021
1 parent 2f40a8d commit da57e01
Show file tree
Hide file tree
Showing 11 changed files with 86 additions and 91 deletions.
2 changes: 1 addition & 1 deletion .stylelintrc.json
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@
],
"rules": {
"material/no-prefixes": [true, {
"browsers": ["last 2 versions", "not ie <= 10", "not ie_mob <= 10"],
"browsers": ["last 2 versions", "not dead", "not and_qq > 0", "not OperaMini all"],
"filePattern": "**/!(*-example.css)"
}],
"material/theme-mixin-api": true,
Expand Down
3 changes: 1 addition & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -145,7 +145,6 @@
"@rollup/plugin-babel": "^5.3.0",
"@rollup/plugin-commonjs": "^18.0.0",
"@schematics/angular": "^12.0.0",
"@types/autoprefixer": "^9.7.2",
"@types/browser-sync": "^2.26.1",
"@types/fs-extra": "^9.0.5",
"@types/glob": "^7.1.3",
Expand All @@ -164,7 +163,7 @@
"@types/send": "^0.14.5",
"@types/stylelint": "^9.10.1",
"@types/yaml": "^1.9.7",
"autoprefixer": "^6.7.6",
"autoprefixer": "^10.2.5",
"browser-sync": "2.26.13",
"chalk": "^4.1.0",
"codelyzer": "^6.0.2",
Expand Down
6 changes: 3 additions & 3 deletions src/material-experimental/mdc-checkbox/checkbox.scss
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,8 @@
@use 'sass:map';
@use '../../cdk/a11y';
@use '../mdc-helpers/mdc-helpers';
@use '../../material/core/style/_layout-common.scss';
@use '../../material/core/style/layout-common';
@use '../../material/core/style/vendor-prefixes';

@include mdc-checkbox.without-ripple($query: mdc-helpers.$mat-base-styles-query);
@include mdc-form-field.core-styles($query: mdc-helpers.$mat-base-styles-query);
Expand Down Expand Up @@ -46,8 +47,7 @@

.mdc-checkbox__background {
// force browser to show background-color when using the print function
-webkit-print-color-adjust: exact;
color-adjust: exact;
@include vendor-prefixes.private-color-adjust(exact);
}

// Angular Material supports disabling all animations when NoopAnimationsModule is imported.
Expand Down
3 changes: 1 addition & 2 deletions src/material/checkbox/checkbox.scss
Original file line number Diff line number Diff line change
Expand Up @@ -287,8 +287,7 @@ $_mark-stroke-size: 2 / 15 * checkbox-common.$size !default;
variables.$linear-out-slow-in-timing-function;

// force browser to show background-color when using the print function
-webkit-print-color-adjust: exact;
color-adjust: exact;
@include vendor-prefixes.private-color-adjust(exact);

._mat-animation-noopable & {
transition: none;
Expand Down
10 changes: 10 additions & 0 deletions src/material/core/style/_vendor-prefixes.scss
Original file line number Diff line number Diff line change
Expand Up @@ -43,4 +43,14 @@
position: -webkit-sticky #{if($important, '!important', '')};
position: sticky #{if($important, '!important', '')};
}

@mixin private-color-adjust($value) {
-webkit-print-color-adjust: $value;
color-adjust: $value;
}

@mixin private-background-clip($value) {
-webkit-background-clip: $value;
background-clip: $value;
}
// stylelint-enable
2 changes: 2 additions & 0 deletions src/material/form-field/form-field.scss
Original file line number Diff line number Diff line change
Expand Up @@ -139,6 +139,7 @@ $default-infix-width: 180px !default;

// Server-side rendered matInput with focus or a placeholder attribute but placeholder not shown
// (used as a pure CSS stand-in for mat-form-field-should-float).
// stylelint-disable material/no-prefixes
.mat-input-server:focus + .mat-form-field-label-wrapper .mat-form-field-label,
.mat-input-server[placeholder]:not(:placeholder-shown) + .mat-form-field-label-wrapper
.mat-form-field-label {
Expand All @@ -148,6 +149,7 @@ $default-infix-width: 180px !default;
display: block;
}
}
// stylelint-enable material/no-prefixes

// Disable the label animation when the control is not empty (this prevents label
// animating up when the value is set programmatically).
Expand Down
3 changes: 1 addition & 2 deletions src/material/radio/radio.scss
Original file line number Diff line number Diff line change
Expand Up @@ -81,8 +81,7 @@ $ripple-radius: 20px;
transform: scale(0.001);

// force browser to show background-color when using the print function
-webkit-print-color-adjust: exact;
color-adjust: exact;
@include vendor-prefixes.private-color-adjust(exact);

._mat-animation-noopable & {
transition: none;
Expand Down
8 changes: 3 additions & 5 deletions src/material/slider/slider.scss
Original file line number Diff line number Diff line change
Expand Up @@ -43,11 +43,9 @@ $focus-ring-size: 30px !default;
}

.mat-slider-wrapper {
position: absolute;

// force browser to show background-color when using the print function
-webkit-print-color-adjust: exact;
color-adjust: exact;
@include vendor-prefixes.private-color-adjust(exact);
position: absolute;
}

.mat-slider-track-wrapper {
Expand Down Expand Up @@ -81,8 +79,8 @@ $focus-ring-size: 30px !default;
}

.mat-slider-ticks {
@include vendor-prefixes.private-background-clip(content-box);
background-repeat: repeat;
background-clip: content-box;
box-sizing: border-box;
opacity: 0;
transition: opacity variables.$swift-ease-out-duration
Expand Down
12 changes: 8 additions & 4 deletions tools/stylelint/no-prefixes/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,10 @@ import {NeedsPrefix} from './needs-prefix';

const parseSelector = require('stylelint/lib/utils/parseSelector');
const ruleName = 'material/no-prefixes';
const messages = utils.ruleMessages(ruleName, {
property: property => `Unprefixed property "${property}".`,
const messages = utils.ruleMessages(ruleName, {
property: (property: string, browsers: string[]) => {
return `Unprefixed property "${property}" needs a prefix for browsers ${browsers.join(', ')}.`;
},
value: (property, value) => `Unprefixed value in "${property}: ${value}".`,
atRule: name => `Unprefixed @rule "${name}".`,
mediaFeature: value => `Unprefixed media feature "${value}".`,
Expand Down Expand Up @@ -38,11 +40,13 @@ const plugin = createPlugin(ruleName, (isEnabled: boolean, _options?) => {

// Check all of the `property: value` pairs.
root.walkDecls(decl => {
if (needsPrefix.property(decl.prop)) {
const propertyPrefixes = needsPrefix.property(decl.prop, decl.value);

if (propertyPrefixes.length) {
utils.report({
result,
ruleName,
message: messages.property(decl.prop),
message: messages.property(decl.prop, propertyPrefixes),
node: decl,
index: (decl.raws.before || '').length
});
Expand Down
26 changes: 15 additions & 11 deletions tools/stylelint/no-prefixes/needs-prefix.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,8 @@ const Prefixes = require('autoprefixer/lib/prefixes');
*/
export class NeedsPrefix {
private _prefixes: {
add: {[key: string]: any},
browsers: any
add: Record<string, any>,
browsers: {selected: string[]}
};

constructor(browsers: string[]) {
Expand All @@ -26,7 +26,7 @@ export class NeedsPrefix {

/** Checks whether an @-rule needs to be prefixed. */
atRule(identifier: string): boolean {
return this._prefixes.add[`@${identifier.toLowerCase()}`];
return !!this._prefixes.add[`@${identifier.toLowerCase()}`];
}

/** Checks whether a selector needs to be prefixed. */
Expand All @@ -42,20 +42,24 @@ export class NeedsPrefix {
}

/** Checks whether a property needs to be prefixed. */
property(identifier: string): boolean {
property(identifier: string, value: string): string[] {
// `fill` is an edge case since it was part of a proposal that got renamed to `stretch`.
// see: https://www.w3.org/TR/css-sizing-3/#changes
if (!identifier || identifier === 'fill') {
return false;
return [];
}

const needsPrefix = autoprefixer.data.prefixes[identifier.toLowerCase()];
const browsersThatNeedPrefix = needsPrefix ? needsPrefix.browsers : null;
// `text-decoration` is another edge case which is supported
// unprefixed everywhere, except for the shorthand which requires a
// prefix on iOS. See: https://developer.mozilla.org/en-US/docs/Web/CSS/text-decoration
if (identifier === 'text-decoration' && !value.includes(' ')) {
return [];
}

return !!browsersThatNeedPrefix &&
!!this._prefixes.browsers.selected.find((browser: string) => {
return browsersThatNeedPrefix.indexOf(browser) > -1;
});
const needsPrefix = autoprefixer.data.prefixes[identifier.toLowerCase()];
const browsersThatNeedPrefix = (needsPrefix as {browsers: string[]} | null)?.browsers || [];
return browsersThatNeedPrefix
.filter(browser => this._prefixes.browsers.selected.includes(browser));
}

/** Checks whether a CSS property value needs to be prefixed. */
Expand Down

0 comments on commit da57e01

Please sign in to comment.