[fix] cross-browser flex styles

Fix #616
Close #648
This commit is contained in:
Nicolas Gallagher
2017-09-18 19:15:02 -07:00
parent d762d64b49
commit fbba32defb
3 changed files with 68 additions and 40 deletions

View File

@@ -50,10 +50,9 @@ exports[`apis/AppRegistry/renderApplication getApplication 3`] = `
.rn-boxSizing-deolkf{box-sizing:border-box}
.rn-display-6koalj{display:-webkit-box;display:-moz-box;display:-ms-flexbox;display:-webkit-flex;display:flex}
.rn-display-xoduu5{display:-webkit-inline-box;display:-moz-inline-box;display:-ms-inline-flexbox;display:-webkit-inline-flex;display:inline-flex}
.rn-flexShrink-1qe8dj5{-webkit-flex-shrink:0;flex-shrink:0}
.rn-flexShrink-1wbh5a2{-webkit-flex-shrink:1;flex-shrink:1}
.rn-flexBasis-1mlwlqe{-webkit-flex-basis:auto;flex-basis:auto}
.rn-flexBasis-1ro0kt6{-webkit-flex-basis:0%;flex-basis:0%}
.rn-flexShrink-1pxmb3b{-webkit-flex-shrink:0 !important;flex-shrink:0 !important}
.rn-flexShrink-1awmn5t{-webkit-flex-shrink:1 !important;flex-shrink:1 !important}
.rn-flexBasis-7vfszb{-webkit-flex-basis:auto !important;flex-basis:auto !important}
.rn-flexDirection-eqz5dr{-webkit-box-direction:normal;-webkit-box-orient:vertical;-webkit-flex-direction:column;flex-direction:column}
.rn-marginTop-1mnahxq{margin-top:0px}
.rn-marginRight-61z16t{margin-right:0px}
@@ -67,5 +66,6 @@ exports[`apis/AppRegistry/renderApplication getApplication 3`] = `
.rn-paddingLeft-gy4na3{padding-left:0px}
.rn-zIndex-1lgpqti{z-index:0}
.rn-zIndex-1wyyakw{z-index:-1}
.rn-flexGrow-16y2uox{-webkit-flex-grow:1;flex-grow:1}</style>"
.rn-flex-13awgt0{-webkit-flex:1;flex:1}
.rn-flexGrow-1m1wadx{-webkit-flex-grow:1 !important;flex-grow:1 !important}</style>"
`;

View File

@@ -26,44 +26,44 @@ describe('apis/StyleSheet/createReactDOMStyle', () => {
test('flex defaults', () => {
expect(createReactDOMStyle({ display: 'flex' })).toEqual({
display: 'flex',
flexShrink: 0,
flexBasis: 'auto'
flexShrink: '0 !important',
flexBasis: 'auto !important'
});
});
test('flex: -1', () => {
expect(createReactDOMStyle({ display: 'flex', flex: -1 })).toEqual({
display: 'flex',
flexGrow: 0,
flexShrink: 1,
flexBasis: 'auto'
flexGrow: '0 !important',
flexShrink: '1 !important',
flexBasis: 'auto !important'
});
});
test('flex: 0', () => {
expect(createReactDOMStyle({ display: 'flex', flex: 0 })).toEqual({
display: 'flex',
flexGrow: 0,
flexShrink: 0,
flexBasis: 'auto'
flexGrow: '0 !important',
flexShrink: '0 !important',
flexBasis: 'auto !important'
});
});
test('flex: 1', () => {
expect(createReactDOMStyle({ display: 'flex', flex: 1 })).toEqual({
display: 'flex',
flexGrow: 1,
flexShrink: 1,
flexBasis: '0%'
flex: 1,
flexGrow: '1 !important',
flexShrink: '1 !important'
});
});
test('flex: 10', () => {
expect(createReactDOMStyle({ display: 'flex', flex: 10 })).toEqual({
display: 'flex',
flexGrow: 10,
flexShrink: 1,
flexBasis: '0%'
flex: 10,
flexGrow: '10 !important',
flexShrink: '1 !important'
});
});
@@ -71,16 +71,17 @@ describe('apis/StyleSheet/createReactDOMStyle', () => {
// is flex-basis applied?
expect(createReactDOMStyle({ display: 'flex', flexBasis: '25%' })).toEqual({
display: 'flex',
flexShrink: 0,
flexBasis: '25%'
flexShrink: '0 !important',
flexBasis: '25% !important'
});
// can flex-basis override the 'flex' expansion?
expect(createReactDOMStyle({ display: 'flex', flex: 1, flexBasis: '25%' })).toEqual({
display: 'flex',
flexGrow: 1,
flexShrink: 1,
flexBasis: '25%'
flex: 1,
flexGrow: '1 !important',
flexShrink: '1 !important',
flexBasis: '25% !important'
});
});
@@ -88,16 +89,16 @@ describe('apis/StyleSheet/createReactDOMStyle', () => {
// is flex-shrink applied?
expect(createReactDOMStyle({ display: 'flex', flexShrink: 1 })).toEqual({
display: 'flex',
flexShrink: 1,
flexBasis: 'auto'
flexShrink: '1 !important',
flexBasis: 'auto !important'
});
// can flex-shrink override the 'flex' expansion?
expect(createReactDOMStyle({ display: 'flex', flex: 1, flexShrink: 2 })).toEqual({
display: 'flex',
flexGrow: 1,
flexShrink: 2,
flexBasis: '0%'
flex: 1,
flexGrow: '1 !important',
flexShrink: '2 !important'
});
});
});

View File

@@ -158,29 +158,56 @@ const createReducer = (style, styleProps) => {
case 'display': {
resolvedStyle.display = value;
// defaults of 'flexBasis:auto' and 'flexShrink:0' have lowest precedence
if (style.display === 'flex') {
// A flex container in React Native has these defaults which should be
// set only if there is no otherwise supplied flex style.
if (style.display === 'flex' && style.flex == null) {
if (style.flexShrink == null) {
resolvedStyle.flexShrink = 0;
resolvedStyle.flexShrink = '0 !important';
}
if (style.flexBasis == null) {
resolvedStyle.flexBasis = 'auto';
resolvedStyle.flexBasis = 'auto !important';
}
}
break;
}
// The 'flex' property value in React Native must be a positive integer,
// 0, or -1.
//
// On the web, a positive integer value for 'flex' is complicated by
// browser differences. Although browsers render styles like 'flex:2'
// consistently, they don't all set the same value for the resulting
// 'flexBasis' (See #616). Expanding 'flex' in 'StyleSheet' would mean
// setting different values for different browsers.
//
// This fix instead relies on the browser expanding 'flex' itself. And
// because the 'flex' style is not being expanded the generated CSS is
// likely to contain source order "conflicts". To avoid the browser
// relying on source order to resolve the styles, all the longhand flex
// property values must use '!important'.
case 'flex': {
if (value > 0) {
resolvedStyle.flexGrow = value;
resolvedStyle.flexShrink = 1;
resolvedStyle.flexBasis = '0%';
resolvedStyle.flex = value;
resolvedStyle.flexGrow = `${value} !important`;
resolvedStyle.flexShrink = '1 !important';
} else if (value === 0) {
resolvedStyle.flexGrow = 0;
resolvedStyle.flexShrink = 0;
resolvedStyle.flexGrow = '0 !important';
resolvedStyle.flexShrink = '0 !important';
resolvedStyle.flexBasis = 'auto !important';
} else if (value === -1) {
resolvedStyle.flexGrow = 0;
resolvedStyle.flexShrink = 1;
resolvedStyle.flexGrow = '0 !important';
resolvedStyle.flexShrink = '1 !important';
resolvedStyle.flexBasis = 'auto !important';
}
break;
}
case 'flexGrow':
case 'flexShrink':
case 'flexBasis': {
if (value != null) {
const hasImportant = `${value}`.indexOf('!important') > -1;
resolvedStyle[prop] = hasImportant ? value : `${value} !important`;
}
break;
}