Skip to content

Commit da57e01

Browse files
authored
build: update and fix vendor prefixes rule (#22704)
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.
1 parent 2f40a8d commit da57e01

File tree

11 files changed

+86
-91
lines changed

11 files changed

+86
-91
lines changed

.stylelintrc.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@
1515
],
1616
"rules": {
1717
"material/no-prefixes": [true, {
18-
"browsers": ["last 2 versions", "not ie <= 10", "not ie_mob <= 10"],
18+
"browsers": ["last 2 versions", "not dead", "not and_qq > 0", "not OperaMini all"],
1919
"filePattern": "**/!(*-example.css)"
2020
}],
2121
"material/theme-mixin-api": true,

package.json

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -145,7 +145,6 @@
145145
"@rollup/plugin-babel": "^5.3.0",
146146
"@rollup/plugin-commonjs": "^18.0.0",
147147
"@schematics/angular": "^12.0.0",
148-
"@types/autoprefixer": "^9.7.2",
149148
"@types/browser-sync": "^2.26.1",
150149
"@types/fs-extra": "^9.0.5",
151150
"@types/glob": "^7.1.3",
@@ -164,7 +163,7 @@
164163
"@types/send": "^0.14.5",
165164
"@types/stylelint": "^9.10.1",
166165
"@types/yaml": "^1.9.7",
167-
"autoprefixer": "^6.7.6",
166+
"autoprefixer": "^10.2.5",
168167
"browser-sync": "2.26.13",
169168
"chalk": "^4.1.0",
170169
"codelyzer": "^6.0.2",

src/material-experimental/mdc-checkbox/checkbox.scss

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,8 @@
44
@use 'sass:map';
55
@use '../../cdk/a11y';
66
@use '../mdc-helpers/mdc-helpers';
7-
@use '../../material/core/style/_layout-common.scss';
7+
@use '../../material/core/style/layout-common';
8+
@use '../../material/core/style/vendor-prefixes';
89

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

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

5353
// Angular Material supports disabling all animations when NoopAnimationsModule is imported.

src/material/checkbox/checkbox.scss

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -287,8 +287,7 @@ $_mark-stroke-size: 2 / 15 * checkbox-common.$size !default;
287287
variables.$linear-out-slow-in-timing-function;
288288

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

293292
._mat-animation-noopable & {
294293
transition: none;

src/material/core/style/_vendor-prefixes.scss

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,4 +43,14 @@
4343
position: -webkit-sticky #{if($important, '!important', '')};
4444
position: sticky #{if($important, '!important', '')};
4545
}
46+
47+
@mixin private-color-adjust($value) {
48+
-webkit-print-color-adjust: $value;
49+
color-adjust: $value;
50+
}
51+
52+
@mixin private-background-clip($value) {
53+
-webkit-background-clip: $value;
54+
background-clip: $value;
55+
}
4656
// stylelint-enable

src/material/form-field/form-field.scss

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -139,6 +139,7 @@ $default-infix-width: 180px !default;
139139

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

152154
// Disable the label animation when the control is not empty (this prevents label
153155
// animating up when the value is set programmatically).

src/material/radio/radio.scss

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -81,8 +81,7 @@ $ripple-radius: 20px;
8181
transform: scale(0.001);
8282

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

8786
._mat-animation-noopable & {
8887
transition: none;

src/material/slider/slider.scss

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -43,11 +43,9 @@ $focus-ring-size: 30px !default;
4343
}
4444

4545
.mat-slider-wrapper {
46-
position: absolute;
47-
4846
// force browser to show background-color when using the print function
49-
-webkit-print-color-adjust: exact;
50-
color-adjust: exact;
47+
@include vendor-prefixes.private-color-adjust(exact);
48+
position: absolute;
5149
}
5250

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

8381
.mat-slider-ticks {
82+
@include vendor-prefixes.private-background-clip(content-box);
8483
background-repeat: repeat;
85-
background-clip: content-box;
8684
box-sizing: border-box;
8785
opacity: 0;
8886
transition: opacity variables.$swift-ease-out-duration

tools/stylelint/no-prefixes/index.ts

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,10 @@ import {NeedsPrefix} from './needs-prefix';
44

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

3941
// Check all of the `property: value` pairs.
4042
root.walkDecls(decl => {
41-
if (needsPrefix.property(decl.prop)) {
43+
const propertyPrefixes = needsPrefix.property(decl.prop, decl.value);
44+
45+
if (propertyPrefixes.length) {
4246
utils.report({
4347
result,
4448
ruleName,
45-
message: messages.property(decl.prop),
49+
message: messages.property(decl.prop, propertyPrefixes),
4650
node: decl,
4751
index: (decl.raws.before || '').length
4852
});

tools/stylelint/no-prefixes/needs-prefix.ts

Lines changed: 15 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -13,8 +13,8 @@ const Prefixes = require('autoprefixer/lib/prefixes');
1313
*/
1414
export class NeedsPrefix {
1515
private _prefixes: {
16-
add: {[key: string]: any},
17-
browsers: any
16+
add: Record<string, any>,
17+
browsers: {selected: string[]}
1818
};
1919

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

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

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

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

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

55-
return !!browsersThatNeedPrefix &&
56-
!!this._prefixes.browsers.selected.find((browser: string) => {
57-
return browsersThatNeedPrefix.indexOf(browser) > -1;
58-
});
59+
const needsPrefix = autoprefixer.data.prefixes[identifier.toLowerCase()];
60+
const browsersThatNeedPrefix = (needsPrefix as {browsers: string[]} | null)?.browsers || [];
61+
return browsersThatNeedPrefix
62+
.filter(browser => this._prefixes.browsers.selected.includes(browser));
5963
}
6064

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

0 commit comments

Comments
 (0)