mirror of
https://github.com/zhigang1992/react-native-web.git
synced 2026-04-27 21:07:26 +08:00
Simplify StyleSheet's expandStyle
This commit is contained in:
@@ -3,45 +3,58 @@
|
||||
import resolveBoxShadow from '../resolveBoxShadow';
|
||||
|
||||
describe('apis/StyleSheet/resolveBoxShadow', () => {
|
||||
test('missing shadowColor', () => {
|
||||
const style = {
|
||||
shadowOffset: { width: 1, height: 2 }
|
||||
};
|
||||
|
||||
expect(resolveBoxShadow(style)).toEqual({});
|
||||
});
|
||||
|
||||
test('shadowColor only', () => {
|
||||
const style = {
|
||||
shadowColor: 'red'
|
||||
};
|
||||
const resolvedStyle = {};
|
||||
const style = { shadowColor: 'red' };
|
||||
resolveBoxShadow(resolvedStyle, style);
|
||||
|
||||
expect(resolveBoxShadow(style)).toEqual({
|
||||
expect(resolvedStyle).toEqual({
|
||||
boxShadow: '0px 0px 0px rgba(255,0,0,1)'
|
||||
});
|
||||
});
|
||||
|
||||
test('shadowColor and shadowOpacity only', () => {
|
||||
const style = {
|
||||
shadowColor: 'red',
|
||||
shadowOpacity: 0.5
|
||||
};
|
||||
const resolvedStyle = {};
|
||||
const style = { shadowColor: 'red', shadowOpacity: 0.5 };
|
||||
resolveBoxShadow(resolvedStyle, style);
|
||||
|
||||
expect(resolveBoxShadow(style)).toEqual({
|
||||
expect(resolvedStyle).toEqual({
|
||||
boxShadow: '0px 0px 0px rgba(255,0,0,0.5)'
|
||||
});
|
||||
});
|
||||
|
||||
test('shadowOffset, shadowRadius, shadowSpread', () => {
|
||||
test('shadowOffset only', () => {
|
||||
const resolvedStyle = {};
|
||||
const style = { shadowOffset: { width: 1, height: 2 } };
|
||||
resolveBoxShadow(resolvedStyle, style);
|
||||
|
||||
expect(resolvedStyle).toEqual({
|
||||
boxShadow: '1px 2px 0px rgba(0,0,0,0)'
|
||||
});
|
||||
});
|
||||
|
||||
test('shadowRadius only', () => {
|
||||
const resolvedStyle = {};
|
||||
const style = { shadowRadius: 5 };
|
||||
resolveBoxShadow(resolvedStyle, style);
|
||||
|
||||
expect(resolvedStyle).toEqual({
|
||||
boxShadow: '0px 0px 5px rgba(0,0,0,0)'
|
||||
});
|
||||
});
|
||||
|
||||
test('shadowOffset, shadowRadius, shadowColor', () => {
|
||||
const resolvedStyle = {};
|
||||
const style = {
|
||||
shadowColor: 'rgba(50,60,70,0.5)',
|
||||
shadowOffset: { width: 1, height: 2 },
|
||||
shadowOpacity: 0.5,
|
||||
shadowRadius: 3
|
||||
};
|
||||
resolveBoxShadow(resolvedStyle, style);
|
||||
|
||||
expect(resolveBoxShadow(style)).toEqual({
|
||||
boxShadow: '2px 1px 3px rgba(50,60,70,0.25)'
|
||||
expect(resolvedStyle).toEqual({
|
||||
boxShadow: '1px 2px 3px rgba(50,60,70,0.25)'
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@@ -4,17 +4,16 @@ import resolveTextShadow from '../resolveTextShadow';
|
||||
|
||||
describe('apis/StyleSheet/resolveTextShadow', () => {
|
||||
test('textShadowOffset', () => {
|
||||
const resolvedStyle = {};
|
||||
const style = {
|
||||
textShadowColor: 'red',
|
||||
textShadowOffset: { width: 2, height: 2 },
|
||||
textShadowOffset: { width: 1, height: 2 },
|
||||
textShadowRadius: 5
|
||||
};
|
||||
resolveTextShadow(resolvedStyle, style);
|
||||
|
||||
expect(resolveTextShadow(style)).toEqual({
|
||||
textShadow: '2px 2px 5px red',
|
||||
textShadowColor: null,
|
||||
textShadowOffset: null,
|
||||
textShadowRadius: null
|
||||
expect(resolvedStyle).toEqual({
|
||||
textShadow: '1px 2px 5px red'
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@@ -4,6 +4,7 @@ import resolveTransform from '../resolveTransform';
|
||||
|
||||
describe('apis/StyleSheet/resolveTransform', () => {
|
||||
test('transform', () => {
|
||||
const resolvedStyle = {};
|
||||
const style = {
|
||||
transform: [
|
||||
{ scaleX: 20 },
|
||||
@@ -11,18 +12,19 @@ describe('apis/StyleSheet/resolveTransform', () => {
|
||||
{ rotate: '20deg' }
|
||||
]
|
||||
};
|
||||
resolveTransform(resolvedStyle, style);
|
||||
|
||||
expect(resolveTransform(style)).toEqual({ transform: 'scaleX(20) translateX(20px) rotate(20deg)' });
|
||||
expect(resolvedStyle).toEqual({
|
||||
transform: 'scaleX(20) translateX(20px) rotate(20deg)' });
|
||||
});
|
||||
|
||||
test('transformMatrix', () => {
|
||||
const style = {
|
||||
transformMatrix: [ 1, 2, 3, 4, 5, 6 ]
|
||||
};
|
||||
const resolvedStyle = {};
|
||||
const style = { transformMatrix: [ 1, 2, 3, 4, 5, 6 ] };
|
||||
resolveTransform(resolvedStyle, style);
|
||||
|
||||
expect(resolveTransform(style)).toEqual({
|
||||
transform: 'matrix3d(1,2,3,4,5,6)',
|
||||
transformMatrix: null
|
||||
expect(resolvedStyle).toEqual({
|
||||
transform: 'matrix3d(1,2,3,4,5,6)'
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@@ -1,21 +1,9 @@
|
||||
import expandStyle from './expandStyle';
|
||||
import flattenStyle from './flattenStyle';
|
||||
import i18nStyle from './i18nStyle';
|
||||
import resolveBoxShadow from './resolveBoxShadow';
|
||||
import resolveTextShadow from './resolveTextShadow';
|
||||
import resolveTransform from './resolveTransform';
|
||||
import resolveVendorPrefixes from './resolveVendorPrefixes';
|
||||
|
||||
const processors = [
|
||||
resolveBoxShadow,
|
||||
resolveTextShadow,
|
||||
resolveTransform,
|
||||
resolveVendorPrefixes
|
||||
];
|
||||
|
||||
const applyProcessors = (style) => processors.reduce((style, processor) => processor(style), style);
|
||||
|
||||
const createReactDOMStyle = (reactNativeStyle) => applyProcessors(
|
||||
const createReactDOMStyle = (reactNativeStyle) => resolveVendorPrefixes(
|
||||
expandStyle(i18nStyle(flattenStyle(reactNativeStyle)))
|
||||
);
|
||||
|
||||
|
||||
@@ -10,6 +10,9 @@
|
||||
*/
|
||||
|
||||
import normalizeValue from './normalizeValue';
|
||||
import resolveBoxShadow from './resolveBoxShadow';
|
||||
import resolveTextShadow from './resolveTextShadow';
|
||||
import resolveTransform from './resolveTransform';
|
||||
|
||||
const emptyObject = {};
|
||||
const styleShortFormProperties = {
|
||||
@@ -28,46 +31,83 @@ const styleShortFormProperties = {
|
||||
writingDirection: [ 'direction' ]
|
||||
};
|
||||
|
||||
const alphaSort = (arr) => arr.sort((a, b) => {
|
||||
const alphaSortProps = (propsArray) => propsArray.sort((a, b) => {
|
||||
if (a < b) { return -1; }
|
||||
if (a > b) { return 1; }
|
||||
return 0;
|
||||
});
|
||||
|
||||
const createStyleReducer = (originalStyle) => {
|
||||
const originalStyleProps = Object.keys(originalStyle);
|
||||
const expandStyle = (style) => {
|
||||
if (!style) { return emptyObject; }
|
||||
const styleProps = Object.keys(style);
|
||||
const sortedStyleProps = alphaSortProps(styleProps);
|
||||
let hasResolvedBoxShadow = false;
|
||||
let hasResolvedTextShadow = false;
|
||||
|
||||
return (style, prop) => {
|
||||
const value = normalizeValue(prop, originalStyle[prop]);
|
||||
const longFormProperties = styleShortFormProperties[prop];
|
||||
const reducer = (resolvedStyle, prop) => {
|
||||
const value = normalizeValue(prop, style[prop]);
|
||||
if (value == null) { return resolvedStyle; }
|
||||
|
||||
// React Native treats `flex:1` like `flex:1 1 auto`
|
||||
if (prop === 'flex') {
|
||||
style.flexGrow = value;
|
||||
style.flexShrink = 1;
|
||||
style.flexBasis = 'auto';
|
||||
// React Native accepts 'center' as a value
|
||||
} else if (prop === 'textAlignVertical') {
|
||||
style.verticalAlign = (value === 'center' ? 'middle' : value);
|
||||
} else if (longFormProperties) {
|
||||
longFormProperties.forEach((longForm, i) => {
|
||||
// the value of any longform property in the original styles takes
|
||||
// precedence over the shortform's value
|
||||
if (originalStyleProps.indexOf(longForm) === -1) {
|
||||
style[longForm] = value;
|
||||
switch (prop) {
|
||||
// ignore React Native styles
|
||||
case 'elevation':
|
||||
case 'resizeMode': {
|
||||
break;
|
||||
}
|
||||
case 'flex': {
|
||||
resolvedStyle.flexGrow = value;
|
||||
resolvedStyle.flexShrink = 1;
|
||||
resolvedStyle.flexBasis = 'auto';
|
||||
break;
|
||||
}
|
||||
case 'shadowColor':
|
||||
case 'shadowOffset':
|
||||
case 'shadowOpacity':
|
||||
case 'shadowRadius': {
|
||||
if (!hasResolvedBoxShadow) {
|
||||
resolveBoxShadow(resolvedStyle, style);
|
||||
}
|
||||
});
|
||||
} else {
|
||||
style[prop] = value;
|
||||
hasResolvedBoxShadow = true;
|
||||
break;
|
||||
}
|
||||
case 'textAlignVertical': {
|
||||
resolvedStyle.verticalAlign = (value === 'center' ? 'middle' : value);
|
||||
break;
|
||||
}
|
||||
case 'textShadowColor':
|
||||
case 'textShadowOffset':
|
||||
case 'textShadowRadius': {
|
||||
if (!hasResolvedTextShadow) {
|
||||
resolveTextShadow(resolvedStyle, style);
|
||||
}
|
||||
hasResolvedTextShadow = true;
|
||||
break;
|
||||
}
|
||||
case 'transform': {
|
||||
resolveTransform(resolvedStyle, style);
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
const longFormProperties = styleShortFormProperties[prop];
|
||||
if (longFormProperties) {
|
||||
longFormProperties.forEach((longForm, i) => {
|
||||
// the value of any longform property in the original styles takes
|
||||
// precedence over the shortform's value
|
||||
if (styleProps.indexOf(longForm) === -1) {
|
||||
resolvedStyle[longForm] = value;
|
||||
}
|
||||
});
|
||||
} else {
|
||||
resolvedStyle[prop] = value;
|
||||
}
|
||||
}
|
||||
}
|
||||
return style;
|
||||
};
|
||||
};
|
||||
|
||||
const expandStyle = (style = emptyObject) => {
|
||||
const sortedStyleProps = alphaSort(Object.keys(style));
|
||||
const styleReducer = createStyleReducer(style);
|
||||
return sortedStyleProps.reduce(styleReducer, {});
|
||||
return resolvedStyle;
|
||||
};
|
||||
|
||||
const resolvedStyle = sortedStyleProps.reduce(reducer, {});
|
||||
return resolvedStyle;
|
||||
};
|
||||
|
||||
module.exports = expandStyle;
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
import normalizeColor from '../../modules/normalizeColor';
|
||||
import normalizeValue from './normalizeValue';
|
||||
|
||||
const applyOpacity = (color, opacity) => {
|
||||
const normalizedColor = normalizeColor(color);
|
||||
const colorNumber = normalizedColor === null ? 0x00000000 : normalizedColor;
|
||||
const defaultOffset = { height: 0, width: 0 };
|
||||
|
||||
const applyOpacity = (colorNumber, opacity) => {
|
||||
const r = (colorNumber & 0xff000000) >>> 24;
|
||||
const g = (colorNumber & 0x00ff0000) >>> 16;
|
||||
const b = (colorNumber & 0x0000ff00) >>> 8;
|
||||
@@ -12,22 +12,18 @@ const applyOpacity = (color, opacity) => {
|
||||
};
|
||||
|
||||
// TODO: add inset and spread support
|
||||
const resolveBoxShadow = (style) => {
|
||||
if (style && style.shadowColor) {
|
||||
const { height, width } = style.shadowOffset || {};
|
||||
const opacity = style.shadowOpacity != null ? style.shadowOpacity : 1;
|
||||
const color = applyOpacity(style.shadowColor, opacity);
|
||||
const blurRadius = normalizeValue(null, style.shadowRadius || 0);
|
||||
const offsetX = normalizeValue(null, height || 0);
|
||||
const offsetY = normalizeValue(null, width || 0);
|
||||
const boxShadow = `${offsetX} ${offsetY} ${blurRadius} ${color}`;
|
||||
style.boxShadow = style.boxShadow ? `${style.boxShadow}, ${boxShadow}` : boxShadow;
|
||||
}
|
||||
delete style.shadowColor;
|
||||
delete style.shadowOffset;
|
||||
delete style.shadowOpacity;
|
||||
delete style.shadowRadius;
|
||||
return style;
|
||||
const resolveBoxShadow = (resolvedStyle, style) => {
|
||||
const { height, width } = style.shadowOffset || defaultOffset;
|
||||
const offsetX = normalizeValue(null, width);
|
||||
const offsetY = normalizeValue(null, height);
|
||||
const blurRadius = normalizeValue(null, style.shadowRadius || 0);
|
||||
// rgba color
|
||||
const opacity = style.shadowOpacity != null ? style.shadowOpacity : 1;
|
||||
const colorNumber = normalizeColor(style.shadowColor) || 0x00000000;
|
||||
const color = applyOpacity(colorNumber, opacity);
|
||||
|
||||
const boxShadow = `${offsetX} ${offsetY} ${blurRadius} ${color}`;
|
||||
resolvedStyle.boxShadow = style.boxShadow ? `${style.boxShadow}, ${boxShadow}` : boxShadow;
|
||||
};
|
||||
|
||||
module.exports = resolveBoxShadow;
|
||||
|
||||
@@ -1,19 +1,15 @@
|
||||
import normalizeValue from './normalizeValue';
|
||||
|
||||
const resolveTextShadow = (style) => {
|
||||
if (style && style.textShadowOffset) {
|
||||
const { height, width } = style.textShadowOffset;
|
||||
const offsetX = normalizeValue(null, height || 0);
|
||||
const offsetY = normalizeValue(null, width || 0);
|
||||
const blurRadius = normalizeValue(null, style.textShadowRadius || 0);
|
||||
const color = style.textShadowColor || 'currentcolor';
|
||||
const defaultOffset = { height: 0, width: 0 };
|
||||
|
||||
style.textShadow = `${offsetX} ${offsetY} ${blurRadius} ${color}`;
|
||||
style.textShadowColor = null;
|
||||
style.textShadowOffset = null;
|
||||
style.textShadowRadius = null;
|
||||
}
|
||||
return style;
|
||||
const resolveTextShadow = (resolvedStyle, style) => {
|
||||
const { height, width } = style.textShadowOffset || defaultOffset;
|
||||
const offsetX = normalizeValue(null, width);
|
||||
const offsetY = normalizeValue(null, height);
|
||||
const blurRadius = normalizeValue(null, style.textShadowRadius || 0);
|
||||
const color = style.textShadowColor || 'currentcolor';
|
||||
|
||||
resolvedStyle.textShadow = `${offsetX} ${offsetY} ${blurRadius} ${color}`;
|
||||
};
|
||||
|
||||
module.exports = resolveTextShadow;
|
||||
|
||||
@@ -14,16 +14,14 @@ const convertTransformMatrix = (transformMatrix) => {
|
||||
return `matrix3d(${matrix})`;
|
||||
};
|
||||
|
||||
const resolveTransform = (style) => {
|
||||
if (style) {
|
||||
if (style.transform && Array.isArray(style.transform)) {
|
||||
style.transform = style.transform.map(mapTransform).join(' ');
|
||||
} else if (style.transformMatrix) {
|
||||
style.transform = convertTransformMatrix(style.transformMatrix);
|
||||
style.transformMatrix = null;
|
||||
}
|
||||
const resolveTransform = (resolvedStyle, style) => {
|
||||
if (Array.isArray(style.transform)) {
|
||||
const transform = style.transform.map(mapTransform).join(' ');
|
||||
resolvedStyle.transform = transform;
|
||||
} else if (style.transformMatrix) {
|
||||
const transform = convertTransformMatrix(style.transformMatrix)
|
||||
resolvedStyle.transform = transform;
|
||||
}
|
||||
return style;
|
||||
};
|
||||
|
||||
module.exports = resolveTransform;
|
||||
|
||||
@@ -2,14 +2,16 @@ import prefixAll from 'inline-style-prefixer/static';
|
||||
|
||||
const resolveVendorPrefixes = (style) => {
|
||||
const prefixedStyles = prefixAll(style);
|
||||
|
||||
// React@15 removed undocumented support for fallback values in
|
||||
// inline-styles. Revert array values to the standard CSS value
|
||||
for (const prop in prefixedStyles) {
|
||||
Object.keys(prefixedStyles).forEach((prop) => {
|
||||
const value = prefixedStyles[prop];
|
||||
if (Array.isArray(value)) {
|
||||
prefixedStyles[prop] = value[value.length - 1];
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
return prefixedStyles;
|
||||
};
|
||||
|
||||
|
||||
@@ -438,7 +438,6 @@ exports[`components/Image prop "defaultSource" sets background image when value
|
||||
"flexDirection": "column",
|
||||
"flexShrink": 0,
|
||||
"font": "inherit",
|
||||
"height": undefined,
|
||||
"listStyle": "none",
|
||||
"marginBottom": "0px",
|
||||
"marginLeft": "0px",
|
||||
@@ -457,7 +456,6 @@ exports[`components/Image prop "defaultSource" sets background image when value
|
||||
"position": "relative",
|
||||
"textAlign": "inherit",
|
||||
"textDecoration": "none",
|
||||
"width": undefined,
|
||||
}
|
||||
} />
|
||||
`;
|
||||
|
||||
Reference in New Issue
Block a user