[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
+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;