Skip to content

Commit 877c0d2

Browse files
committed
Simplify StyleSheet's expandStyle
1 parent 3afc5d5 commit 877c0d2

File tree

10 files changed

+152
-120
lines changed

10 files changed

+152
-120
lines changed

src/apis/StyleSheet/__tests__/resolveBoxShadow-test.js

Lines changed: 33 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -3,45 +3,58 @@
33
import resolveBoxShadow from '../resolveBoxShadow';
44

55
describe('apis/StyleSheet/resolveBoxShadow', () => {
6-
test('missing shadowColor', () => {
7-
const style = {
8-
shadowOffset: { width: 1, height: 2 }
9-
};
10-
11-
expect(resolveBoxShadow(style)).toEqual({});
12-
});
13-
146
test('shadowColor only', () => {
15-
const style = {
16-
shadowColor: 'red'
17-
};
7+
const resolvedStyle = {};
8+
const style = { shadowColor: 'red' };
9+
resolveBoxShadow(resolvedStyle, style);
1810

19-
expect(resolveBoxShadow(style)).toEqual({
11+
expect(resolvedStyle).toEqual({
2012
boxShadow: '0px 0px 0px rgba(255,0,0,1)'
2113
});
2214
});
2315

2416
test('shadowColor and shadowOpacity only', () => {
25-
const style = {
26-
shadowColor: 'red',
27-
shadowOpacity: 0.5
28-
};
17+
const resolvedStyle = {};
18+
const style = { shadowColor: 'red', shadowOpacity: 0.5 };
19+
resolveBoxShadow(resolvedStyle, style);
2920

30-
expect(resolveBoxShadow(style)).toEqual({
21+
expect(resolvedStyle).toEqual({
3122
boxShadow: '0px 0px 0px rgba(255,0,0,0.5)'
3223
});
3324
});
3425

35-
test('shadowOffset, shadowRadius, shadowSpread', () => {
26+
test('shadowOffset only', () => {
27+
const resolvedStyle = {};
28+
const style = { shadowOffset: { width: 1, height: 2 } };
29+
resolveBoxShadow(resolvedStyle, style);
30+
31+
expect(resolvedStyle).toEqual({
32+
boxShadow: '1px 2px 0px rgba(0,0,0,0)'
33+
});
34+
});
35+
36+
test('shadowRadius only', () => {
37+
const resolvedStyle = {};
38+
const style = { shadowRadius: 5 };
39+
resolveBoxShadow(resolvedStyle, style);
40+
41+
expect(resolvedStyle).toEqual({
42+
boxShadow: '0px 0px 5px rgba(0,0,0,0)'
43+
});
44+
});
45+
46+
test('shadowOffset, shadowRadius, shadowColor', () => {
47+
const resolvedStyle = {};
3648
const style = {
3749
shadowColor: 'rgba(50,60,70,0.5)',
3850
shadowOffset: { width: 1, height: 2 },
3951
shadowOpacity: 0.5,
4052
shadowRadius: 3
4153
};
54+
resolveBoxShadow(resolvedStyle, style);
4255

43-
expect(resolveBoxShadow(style)).toEqual({
44-
boxShadow: '2px 1px 3px rgba(50,60,70,0.25)'
56+
expect(resolvedStyle).toEqual({
57+
boxShadow: '1px 2px 3px rgba(50,60,70,0.25)'
4558
});
4659
});
4760
});

src/apis/StyleSheet/__tests__/resolveTextShadow-test.js

Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -4,17 +4,16 @@ import resolveTextShadow from '../resolveTextShadow';
44

55
describe('apis/StyleSheet/resolveTextShadow', () => {
66
test('textShadowOffset', () => {
7+
const resolvedStyle = {};
78
const style = {
89
textShadowColor: 'red',
9-
textShadowOffset: { width: 2, height: 2 },
10+
textShadowOffset: { width: 1, height: 2 },
1011
textShadowRadius: 5
1112
};
13+
resolveTextShadow(resolvedStyle, style);
1214

13-
expect(resolveTextShadow(style)).toEqual({
14-
textShadow: '2px 2px 5px red',
15-
textShadowColor: null,
16-
textShadowOffset: null,
17-
textShadowRadius: null
15+
expect(resolvedStyle).toEqual({
16+
textShadow: '1px 2px 5px red'
1817
});
1918
});
2019
});

src/apis/StyleSheet/__tests__/resolveTransform-test.js

Lines changed: 9 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -4,25 +4,27 @@ import resolveTransform from '../resolveTransform';
44

55
describe('apis/StyleSheet/resolveTransform', () => {
66
test('transform', () => {
7+
const resolvedStyle = {};
78
const style = {
89
transform: [
910
{ scaleX: 20 },
1011
{ translateX: 20 },
1112
{ rotate: '20deg' }
1213
]
1314
};
15+
resolveTransform(resolvedStyle, style);
1416

15-
expect(resolveTransform(style)).toEqual({ transform: 'scaleX(20) translateX(20px) rotate(20deg)' });
17+
expect(resolvedStyle).toEqual({
18+
transform: 'scaleX(20) translateX(20px) rotate(20deg)' });
1619
});
1720

1821
test('transformMatrix', () => {
19-
const style = {
20-
transformMatrix: [ 1, 2, 3, 4, 5, 6 ]
21-
};
22+
const resolvedStyle = {};
23+
const style = { transformMatrix: [ 1, 2, 3, 4, 5, 6 ] };
24+
resolveTransform(resolvedStyle, style);
2225

23-
expect(resolveTransform(style)).toEqual({
24-
transform: 'matrix3d(1,2,3,4,5,6)',
25-
transformMatrix: null
26+
expect(resolvedStyle).toEqual({
27+
transform: 'matrix3d(1,2,3,4,5,6)'
2628
});
2729
});
2830
});

src/apis/StyleSheet/createReactDOMStyle.js

Lines changed: 1 addition & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,21 +1,9 @@
11
import expandStyle from './expandStyle';
22
import flattenStyle from './flattenStyle';
33
import i18nStyle from './i18nStyle';
4-
import resolveBoxShadow from './resolveBoxShadow';
5-
import resolveTextShadow from './resolveTextShadow';
6-
import resolveTransform from './resolveTransform';
74
import resolveVendorPrefixes from './resolveVendorPrefixes';
85

9-
const processors = [
10-
resolveBoxShadow,
11-
resolveTextShadow,
12-
resolveTransform,
13-
resolveVendorPrefixes
14-
];
15-
16-
const applyProcessors = (style) => processors.reduce((style, processor) => processor(style), style);
17-
18-
const createReactDOMStyle = (reactNativeStyle) => applyProcessors(
6+
const createReactDOMStyle = (reactNativeStyle) => resolveVendorPrefixes(
197
expandStyle(i18nStyle(flattenStyle(reactNativeStyle)))
208
);
219

src/apis/StyleSheet/expandStyle.js

Lines changed: 69 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,9 @@
1010
*/
1111

1212
import normalizeValue from './normalizeValue';
13+
import resolveBoxShadow from './resolveBoxShadow';
14+
import resolveTextShadow from './resolveTextShadow';
15+
import resolveTransform from './resolveTransform';
1316

1417
const emptyObject = {};
1518
const styleShortFormProperties = {
@@ -28,46 +31,83 @@ const styleShortFormProperties = {
2831
writingDirection: [ 'direction' ]
2932
};
3033

31-
const alphaSort = (arr) => arr.sort((a, b) => {
34+
const alphaSortProps = (propsArray) => propsArray.sort((a, b) => {
3235
if (a < b) { return -1; }
3336
if (a > b) { return 1; }
3437
return 0;
3538
});
3639

37-
const createStyleReducer = (originalStyle) => {
38-
const originalStyleProps = Object.keys(originalStyle);
40+
const expandStyle = (style) => {
41+
if (!style) { return emptyObject; }
42+
const styleProps = Object.keys(style);
43+
const sortedStyleProps = alphaSortProps(styleProps);
44+
let hasResolvedBoxShadow = false;
45+
let hasResolvedTextShadow = false;
3946

40-
return (style, prop) => {
41-
const value = normalizeValue(prop, originalStyle[prop]);
42-
const longFormProperties = styleShortFormProperties[prop];
47+
const reducer = (resolvedStyle, prop) => {
48+
const value = normalizeValue(prop, style[prop]);
49+
if (value == null) { return resolvedStyle; }
4350

44-
// React Native treats `flex:1` like `flex:1 1 auto`
45-
if (prop === 'flex') {
46-
style.flexGrow = value;
47-
style.flexShrink = 1;
48-
style.flexBasis = 'auto';
49-
// React Native accepts 'center' as a value
50-
} else if (prop === 'textAlignVertical') {
51-
style.verticalAlign = (value === 'center' ? 'middle' : value);
52-
} else if (longFormProperties) {
53-
longFormProperties.forEach((longForm, i) => {
54-
// the value of any longform property in the original styles takes
55-
// precedence over the shortform's value
56-
if (originalStyleProps.indexOf(longForm) === -1) {
57-
style[longForm] = value;
51+
switch (prop) {
52+
// ignore React Native styles
53+
case 'elevation':
54+
case 'resizeMode': {
55+
break;
56+
}
57+
case 'flex': {
58+
resolvedStyle.flexGrow = value;
59+
resolvedStyle.flexShrink = 1;
60+
resolvedStyle.flexBasis = 'auto';
61+
break;
62+
}
63+
case 'shadowColor':
64+
case 'shadowOffset':
65+
case 'shadowOpacity':
66+
case 'shadowRadius': {
67+
if (!hasResolvedBoxShadow) {
68+
resolveBoxShadow(resolvedStyle, style);
5869
}
59-
});
60-
} else {
61-
style[prop] = value;
70+
hasResolvedBoxShadow = true;
71+
break;
72+
}
73+
case 'textAlignVertical': {
74+
resolvedStyle.verticalAlign = (value === 'center' ? 'middle' : value);
75+
break;
76+
}
77+
case 'textShadowColor':
78+
case 'textShadowOffset':
79+
case 'textShadowRadius': {
80+
if (!hasResolvedTextShadow) {
81+
resolveTextShadow(resolvedStyle, style);
82+
}
83+
hasResolvedTextShadow = true;
84+
break;
85+
}
86+
case 'transform': {
87+
resolveTransform(resolvedStyle, style);
88+
break;
89+
}
90+
default: {
91+
const longFormProperties = styleShortFormProperties[prop];
92+
if (longFormProperties) {
93+
longFormProperties.forEach((longForm, i) => {
94+
// the value of any longform property in the original styles takes
95+
// precedence over the shortform's value
96+
if (styleProps.indexOf(longForm) === -1) {
97+
resolvedStyle[longForm] = value;
98+
}
99+
});
100+
} else {
101+
resolvedStyle[prop] = value;
102+
}
103+
}
62104
}
63-
return style;
105+
106+
return resolvedStyle;
64107
};
65-
};
66108

67-
const expandStyle = (style = emptyObject) => {
68-
const sortedStyleProps = alphaSort(Object.keys(style));
69-
const styleReducer = createStyleReducer(style);
70-
return sortedStyleProps.reduce(styleReducer, {});
109+
const resolvedStyle = sortedStyleProps.reduce(reducer, {});
110+
return resolvedStyle;
71111
};
72112

73113
module.exports = expandStyle;
Lines changed: 15 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
11
import normalizeColor from '../../modules/normalizeColor';
22
import normalizeValue from './normalizeValue';
33

4-
const applyOpacity = (color, opacity) => {
5-
const normalizedColor = normalizeColor(color);
6-
const colorNumber = normalizedColor === null ? 0x00000000 : normalizedColor;
4+
const defaultOffset = { height: 0, width: 0 };
5+
6+
const applyOpacity = (colorNumber, opacity) => {
77
const r = (colorNumber & 0xff000000) >>> 24;
88
const g = (colorNumber & 0x00ff0000) >>> 16;
99
const b = (colorNumber & 0x0000ff00) >>> 8;
@@ -12,22 +12,18 @@ const applyOpacity = (color, opacity) => {
1212
};
1313

1414
// TODO: add inset and spread support
15-
const resolveBoxShadow = (style) => {
16-
if (style && style.shadowColor) {
17-
const { height, width } = style.shadowOffset || {};
18-
const opacity = style.shadowOpacity != null ? style.shadowOpacity : 1;
19-
const color = applyOpacity(style.shadowColor, opacity);
20-
const blurRadius = normalizeValue(null, style.shadowRadius || 0);
21-
const offsetX = normalizeValue(null, height || 0);
22-
const offsetY = normalizeValue(null, width || 0);
23-
const boxShadow = `${offsetX} ${offsetY} ${blurRadius} ${color}`;
24-
style.boxShadow = style.boxShadow ? `${style.boxShadow}, ${boxShadow}` : boxShadow;
25-
}
26-
delete style.shadowColor;
27-
delete style.shadowOffset;
28-
delete style.shadowOpacity;
29-
delete style.shadowRadius;
30-
return style;
15+
const resolveBoxShadow = (resolvedStyle, style) => {
16+
const { height, width } = style.shadowOffset || defaultOffset;
17+
const offsetX = normalizeValue(null, width);
18+
const offsetY = normalizeValue(null, height);
19+
const blurRadius = normalizeValue(null, style.shadowRadius || 0);
20+
// rgba color
21+
const opacity = style.shadowOpacity != null ? style.shadowOpacity : 1;
22+
const colorNumber = normalizeColor(style.shadowColor) || 0x00000000;
23+
const color = applyOpacity(colorNumber, opacity);
24+
25+
const boxShadow = `${offsetX} ${offsetY} ${blurRadius} ${color}`;
26+
resolvedStyle.boxShadow = style.boxShadow ? `${style.boxShadow}, ${boxShadow}` : boxShadow;
3127
};
3228

3329
module.exports = resolveBoxShadow;
Lines changed: 9 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,15 @@
11
import normalizeValue from './normalizeValue';
22

3-
const resolveTextShadow = (style) => {
4-
if (style && style.textShadowOffset) {
5-
const { height, width } = style.textShadowOffset;
6-
const offsetX = normalizeValue(null, height || 0);
7-
const offsetY = normalizeValue(null, width || 0);
8-
const blurRadius = normalizeValue(null, style.textShadowRadius || 0);
9-
const color = style.textShadowColor || 'currentcolor';
3+
const defaultOffset = { height: 0, width: 0 };
104

11-
style.textShadow = `${offsetX} ${offsetY} ${blurRadius} ${color}`;
12-
style.textShadowColor = null;
13-
style.textShadowOffset = null;
14-
style.textShadowRadius = null;
15-
}
16-
return style;
5+
const resolveTextShadow = (resolvedStyle, style) => {
6+
const { height, width } = style.textShadowOffset || defaultOffset;
7+
const offsetX = normalizeValue(null, width);
8+
const offsetY = normalizeValue(null, height);
9+
const blurRadius = normalizeValue(null, style.textShadowRadius || 0);
10+
const color = style.textShadowColor || 'currentcolor';
11+
12+
resolvedStyle.textShadow = `${offsetX} ${offsetY} ${blurRadius} ${color}`;
1713
};
1814

1915
module.exports = resolveTextShadow;

src/apis/StyleSheet/resolveTransform.js

Lines changed: 7 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -14,16 +14,14 @@ const convertTransformMatrix = (transformMatrix) => {
1414
return `matrix3d(${matrix})`;
1515
};
1616

17-
const resolveTransform = (style) => {
18-
if (style) {
19-
if (style.transform && Array.isArray(style.transform)) {
20-
style.transform = style.transform.map(mapTransform).join(' ');
21-
} else if (style.transformMatrix) {
22-
style.transform = convertTransformMatrix(style.transformMatrix);
23-
style.transformMatrix = null;
24-
}
17+
const resolveTransform = (resolvedStyle, style) => {
18+
if (Array.isArray(style.transform)) {
19+
const transform = style.transform.map(mapTransform).join(' ');
20+
resolvedStyle.transform = transform;
21+
} else if (style.transformMatrix) {
22+
const transform = convertTransformMatrix(style.transformMatrix)
23+
resolvedStyle.transform = transform;
2524
}
26-
return style;
2725
};
2826

2927
module.exports = resolveTransform;

0 commit comments

Comments
 (0)