[fix] unitless values for vendor prefixed properties

Problem:

Numeric values are suffixed with 'px', unless the property supports
unitless values. However, vendor prefixed properties were ignored
resulting in invalid CSS values for properties like
'-webkit-flex-shrink'.

Solution:

Apply the upstream solution from React, which includes vendor prefixed
properties in the "unitless number" map. Also build a custom vendor
prefixer to ensure adequate browser support (i.e., Safari 7 and older
Chrome).
This commit is contained in:
Nicolas Gallagher
2017-07-26 15:46:18 -07:00
parent 507e0d41f5
commit 092d5d12f7
9 changed files with 239 additions and 4 deletions
+1
View File
@@ -74,6 +74,7 @@
"babel-loader": "^7.1.1",
"babel-plugin-transform-react-remove-prop-types": "^0.4.6",
"babel-preset-react-native": "^2.1.0",
"caniuse-api": "^2.0.0",
"del-cli": "^1.1.0",
"enzyme": "^2.9.1",
"enzyme-to-json": "^1.5.1",
+21
View File
@@ -0,0 +1,21 @@
const generateData = require('inline-style-prefixer/generator');
const path = require('path');
const browserList = {
chrome: 38,
android: 4,
firefox: 40,
ios_saf: 7,
safari: 7,
ie: 11,
ie_mob: 11,
edge: 12,
opera: 16,
op_mini: 12,
and_uc: 9,
and_chr: 38
};
generateData(browserList, {
staticPath: path.join(__dirname, '../src/modules/prefixStyles/static.js'),
});
+2 -1
View File
@@ -113,7 +113,8 @@ export default class StyleManager {
if (prop !== 'pointerEvents') {
Object.keys(cache[prop]).forEach(value => {
const className = this.getClassName(prop, value);
rules.push(createCssRule(className, prop, value));
const rule = createCssRule(className, prop, value);
rules.push(rule);
});
}
return rules;
@@ -28,4 +28,12 @@ describe('apis/StyleSheet/StyleManager', () => {
styleManager.setDeclaration('width', '100px');
expect(styleManager.getStyleSheetHtml()).toMatchSnapshot();
});
test('setDeclaration', () => {
styleManager.mainSheet.sheet.insertRule = (rule, position) => {
// check for regressions in CSS write path (e.g., 0 => 0px)
expect(rule.indexOf('-webkit-flex-shrink:0;')).not.toEqual(-1);
};
styleManager.setDeclaration('flexShrink', 0);
});
});
+2 -2
View File
@@ -103,8 +103,8 @@ function normalizeMouseEvent(nativeEvent) {
identifier: touches[0].identifier,
locationX: nativeEvent.offsetX,
locationY: nativeEvent.offsetY,
offsetX: nativeEvent.offsetX,
offsetY: nativeEvent.offsetY,
offsetX: nativeEvent.offsetX,
offsetY: nativeEvent.offsetY,
pageX: nativeEvent.pageX,
pageY: nativeEvent.pageY,
preventDefault: nativeEvent.preventDefault.bind(nativeEvent),
+4 -1
View File
@@ -8,7 +8,10 @@
* @flow
*/
import prefixAll from 'inline-style-prefixer/static';
import createPrefixer from 'inline-style-prefixer/static/createPrefixer';
import staticData from './static';
const prefixAll = createPrefixer(staticData);
export default prefixAll;
+155
View File
@@ -0,0 +1,155 @@
import crossFade from 'inline-style-prefixer/static/plugins/crossFade';
import cursor from 'inline-style-prefixer/static/plugins/cursor';
import filter from 'inline-style-prefixer/static/plugins/filter';
import flex from 'inline-style-prefixer/static/plugins/flex';
import flexboxOld from 'inline-style-prefixer/static/plugins/flexboxOld';
import gradient from 'inline-style-prefixer/static/plugins/gradient';
import imageSet from 'inline-style-prefixer/static/plugins/imageSet';
import position from 'inline-style-prefixer/static/plugins/position';
import sizing from 'inline-style-prefixer/static/plugins/sizing';
import transition from 'inline-style-prefixer/static/plugins/transition';
const w = ['Webkit'];
const m = ['Moz'];
const ms = ['ms'];
const wm = ['Webkit', 'Moz'];
const wms = ['Webkit', 'ms'];
const wmms = ['Webkit', 'Moz', 'ms'];
export default {
plugins: [
crossFade,
cursor,
filter,
flex,
flexboxOld,
gradient,
imageSet,
position,
sizing,
transition
],
prefixMap: {
animation: w,
animationDelay: w,
animationDirection: w,
animationFillMode: w,
animationDuration: w,
animationIterationCount: w,
animationName: w,
animationPlayState: w,
animationTimingFunction: w,
appearance: wm,
userSelect: wmms,
textEmphasisPosition: w,
textEmphasis: w,
textEmphasisStyle: w,
textEmphasisColor: w,
boxDecorationBreak: w,
clipPath: w,
maskImage: w,
maskMode: w,
maskRepeat: w,
maskPosition: w,
maskClip: w,
maskOrigin: w,
maskSize: w,
maskComposite: w,
mask: w,
maskBorderSource: w,
maskBorderMode: w,
maskBorderSlice: w,
maskBorderWidth: w,
maskBorderOutset: w,
maskBorderRepeat: w,
maskBorder: w,
maskType: w,
textDecorationStyle: w,
textDecorationSkip: w,
textDecorationLine: w,
textDecorationColor: w,
filter: w,
fontFeatureSettings: w,
breakAfter: wmms,
breakBefore: wmms,
breakInside: wmms,
columnCount: wm,
columnFill: wm,
columnGap: wm,
columnRule: wm,
columnRuleColor: wm,
columnRuleStyle: wm,
columnRuleWidth: wm,
columns: wm,
columnSpan: wm,
columnWidth: wm,
flex: w,
flexBasis: w,
flexDirection: w,
flexGrow: w,
flexFlow: w,
flexShrink: w,
flexWrap: w,
alignContent: w,
alignItems: w,
alignSelf: w,
justifyContent: w,
order: w,
transform: w,
transformOrigin: w,
transformOriginX: w,
transformOriginY: w,
backfaceVisibility: w,
perspective: w,
perspectiveOrigin: w,
transformStyle: w,
transformOriginZ: w,
backdropFilter: w,
fontKerning: w,
scrollSnapType: wms,
scrollSnapPointsX: wms,
scrollSnapPointsY: wms,
scrollSnapDestination: wms,
scrollSnapCoordinate: wms,
shapeImageThreshold: w,
shapeImageMargin: w,
shapeImageOutside: w,
hyphens: wmms,
flowInto: wms,
flowFrom: wms,
regionFragment: wms,
textAlignLast: m,
tabSize: m,
wrapFlow: ms,
wrapThrough: ms,
wrapMargin: ms,
gridTemplateColumns: ms,
gridTemplateRows: ms,
gridTemplateAreas: ms,
gridTemplate: ms,
gridAutoColumns: ms,
gridAutoRows: ms,
gridAutoFlow: ms,
grid: ms,
gridRowStart: ms,
gridColumnStart: ms,
gridRowEnd: ms,
gridRow: ms,
gridColumn: ms,
gridColumnEnd: ms,
gridColumnGap: ms,
gridRowGap: ms,
gridArea: ms,
gridGap: ms,
textSizeAdjust: wms,
borderImage: w,
borderImageOutset: w,
borderImageRepeat: w,
borderImageSlice: w,
borderImageSource: w,
borderImageWidth: w,
transitionDelay: w,
transitionDuration: w,
transitionProperty: w,
transitionTimingFunction: w
}
};
+14
View File
@@ -46,4 +46,18 @@ const unitlessNumbers = {
shadowOpacity: true
};
/**
* Support style names that may come passed in prefixed by adding permutations
* of vendor prefixes.
*/
const prefixes = ['ms', 'Moz', 'O', 'Webkit'];
const prefixKey = (prefix: string, key: string) => {
return prefix + key.charAt(0).toUpperCase() + key.substring(1);
};
Object.keys(unitlessNumbers).forEach(prop => {
prefixes.forEach(prefix => {
unitlessNumbers[prefixKey(prefix, prop)] = unitlessNumbers[prop];
});
});
export default unitlessNumbers;
+32
View File
@@ -894,6 +894,13 @@ browserify-zlib@^0.1.4:
dependencies:
pako "~0.2.0"
browserslist@^2.0.0:
version "2.2.2"
resolved "https://artifactory.twitter.biz:443/api/npm/js-virtual/browserslist/-/browserslist-2.2.2.tgz#e9b4618b8a01c193f9786beea09f6fd10dbe31c3"
dependencies:
caniuse-lite "^1.0.30000704"
electron-to-chromium "^1.3.16"
bser@^1.0.2:
version "1.0.2"
resolved "https://registry.yarnpkg.com/bser/-/bser-1.0.2.tgz#381116970b2a6deea5646dd15dd7278444b56169"
@@ -967,6 +974,19 @@ camelcase@^4.0.0:
version "4.1.0"
resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-4.1.0.tgz#d545635be1e33c542649c69173e5de6acfae34dd"
caniuse-api@^2.0.0:
version "2.0.0"
resolved "https://artifactory.twitter.biz:443/api/npm/js-virtual/caniuse-api/-/caniuse-api-2.0.0.tgz#b1ddb5a5966b16f48dc4998444d4bbc6c7d9d834"
dependencies:
browserslist "^2.0.0"
caniuse-lite "^1.0.0"
lodash.memoize "^4.1.2"
lodash.uniq "^4.5.0"
caniuse-lite@^1.0.0, caniuse-lite@^1.0.30000704:
version "1.0.30000706"
resolved "https://artifactory.twitter.biz:443/api/npm/js-virtual/caniuse-lite/-/caniuse-lite-1.0.30000706.tgz#bc59abc41ba7d4a3634dda95befded6114e1f24e"
capture-stack-trace@^1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/capture-stack-trace/-/capture-stack-trace-1.0.0.tgz#4a6fa07399c26bba47f0b2496b4d0fb408c5550d"
@@ -1553,6 +1573,10 @@ ejs@^2.5.6:
version "2.5.6"
resolved "https://registry.yarnpkg.com/ejs/-/ejs-2.5.6.tgz#479636bfa3fe3b1debd52087f0acb204b4f19c88"
electron-to-chromium@^1.3.16:
version "1.3.16"
resolved "https://artifactory.twitter.biz:443/api/npm/js-virtual/electron-to-chromium/-/electron-to-chromium-1.3.16.tgz#d0e026735754770901ae301a21664cba45d92f7d"
elegant-spinner@^1.0.1:
version "1.0.1"
resolved "https://registry.yarnpkg.com/elegant-spinner/-/elegant-spinner-1.0.1.tgz#db043521c95d7e303fd8f345bedc3349cfb0729e"
@@ -3291,6 +3315,10 @@ lodash.map@^4.4.0:
version "4.6.0"
resolved "https://registry.yarnpkg.com/lodash.map/-/lodash.map-4.6.0.tgz#771ec7839e3473d9c4cde28b19394c3562f4f6d3"
lodash.memoize@^4.1.2:
version "4.1.2"
resolved "https://artifactory.twitter.biz:443/api/npm/js-virtual/lodash.memoize/-/lodash.memoize-4.1.2.tgz#bcc6c49a42a2840ed997f323eada5ecd182e0bfe"
lodash.merge@^4.4.0:
version "4.6.0"
resolved "https://registry.yarnpkg.com/lodash.merge/-/lodash.merge-4.6.0.tgz#69884ba144ac33fe699737a6086deffadd0f89c5"
@@ -3319,6 +3347,10 @@ lodash.some@^4.4.0:
version "4.6.0"
resolved "https://registry.yarnpkg.com/lodash.some/-/lodash.some-4.6.0.tgz#1bb9f314ef6b8baded13b549169b2a945eb68e4d"
lodash.uniq@^4.5.0:
version "4.5.0"
resolved "https://artifactory.twitter.biz:443/api/npm/js-virtual/lodash.uniq/-/lodash.uniq-4.5.0.tgz#d0225373aeb652adc1bc82e4945339a842754773"
lodash@^4.0.0, lodash@^4.14.0, lodash@^4.17.4, lodash@^4.3.0, lodash@^4.6.1:
version "4.17.4"
resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.4.tgz#78203a4d1c328ae1d86dca6460e369b57f4055ae"