diff --git a/packages/react-native-web/src/exports/StyleSheet/__tests__/preprocess-test.js b/packages/react-native-web/src/exports/StyleSheet/__tests__/preprocess-test.js index 06bfd14d2..bedf9cf91 100644 --- a/packages/react-native-web/src/exports/StyleSheet/__tests__/preprocess-test.js +++ b/packages/react-native-web/src/exports/StyleSheet/__tests__/preprocess-test.js @@ -107,6 +107,43 @@ describe('StyleSheet/preprocess', () => { expect(preprocess({ aspectRatio: undefined })).toEqual({}); }); + describe('boxShadow', () => { + // passthrough if boxShadow value is ever a string + test('string', () => { + const boxShadow = '0 1px 2px rgba(0, 0, 0, 0.5)'; + const style = { boxShadow }; + const resolved = preprocess(style); + + expect(resolved).toEqual({ boxShadow }); + }); + + test('array', () => { + const boxShadow = [ + '0 1px 2px rgba(0, 0, 0, 0.5)', + { + offsetX: 1, + offsetY: 2, + blurRadius: 3 + }, + { + offsetX: 5, + offsetY: 6, + blurRadius: 7, + spreadDistance: 8, + color: 'rgba(0, 255, 0, 0.75)', + inset: true + } + ]; + const style = { boxShadow }; + const resolved = preprocess(style); + + expect(resolved).toEqual({ + boxShadow: + '0 1px 2px rgba(0, 0, 0, 0.5), 1px 2px 3px 0 black, inset 5px 6px 7px 8px rgba(0,255,0,0.75)' + }); + }); + }); + test('fontVariant', () => { expect( preprocess({ fontVariant: 'common-ligatures small-caps' }) @@ -190,6 +227,43 @@ describe('StyleSheet/preprocess', () => { boxShadow: '1px 2px 3px rgba(50,60,70,0.25)' }); }); + + test('shadow styles and string boxShadow together', () => { + expect( + preprocess({ + shadowColor: 'rgba(50,60,70,0.5)', + shadowOffset: { width: 1, height: 2 }, + shadowOpacity: 0.5, + shadowRadius: 3, + boxShadow: '4px 5px 6px black' + }) + ).toEqual({ + boxShadow: '4px 5px 6px black, 1px 2px 3px rgba(50,60,70,0.25)' + }); + }); + + test('shadow styles and array boxShadow together', () => { + expect( + preprocess({ + shadowColor: 'rgba(50,60,70,0.5)', + shadowOffset: { width: 1, height: 2 }, + shadowOpacity: 0.5, + shadowRadius: 3, + boxShadow: [ + { + offsetX: 2, + offsetY: 3, + spreadDistance: 5, + color: 'rgba(10,20,30,0.45)', + inset: true + } + ] + }) + ).toEqual({ + boxShadow: + 'inset 2px 3px 0 5px rgba(10,20,30,0.45), 1px 2px 3px rgba(50,60,70,0.25)' + }); + }); }); describe('preprocesses multiple textShadow styles into a single declaration', () => { diff --git a/packages/react-native-web/src/exports/StyleSheet/preprocess.js b/packages/react-native-web/src/exports/StyleSheet/preprocess.js index 32652289e..4374ab391 100644 --- a/packages/react-native-web/src/exports/StyleSheet/preprocess.js +++ b/packages/react-native-web/src/exports/StyleSheet/preprocess.js @@ -56,6 +56,25 @@ export const createTextShadowValue = (style: Object): void | string => { } }; +// { offsetX: 1, offsetY: 2, blurRadius: 3, spreadDistance: 4, color: 'rgba(255, 0, 0)', inset: true } +// => 'rgba(255, 0, 0) 1px 2px 3px 4px inset' +const mapBoxShadow = (boxShadow: Object | string): string => { + if (typeof boxShadow === 'string') { + return boxShadow; + } + const offsetX = normalizeValueWithProperty(boxShadow.offsetX) || 0; + const offsetY = normalizeValueWithProperty(boxShadow.offsetY) || 0; + const blurRadius = normalizeValueWithProperty(boxShadow.blurRadius) || 0; + const spreadDistance = + normalizeValueWithProperty(boxShadow.spreadDistance) || 0; + const color = normalizeColor(boxShadow.color) || 'black'; + const position = boxShadow.inset ? 'inset ' : ''; + return `${position}${offsetX} ${offsetY} ${blurRadius} ${spreadDistance} ${color}`; +}; +export const createBoxShadowArrayValue = (value: Array): string => { + return value.map(mapBoxShadow).join(', '); +}; + // { scale: 2 } => 'scale(2)' // { translateX: 20 } => 'translateX(20px)' // { matrix: [1,2,3,4,5,6] } => 'matrix(1,2,3,4,5,6)' @@ -126,12 +145,8 @@ export const preprocess = ( `"shadow*" style props are deprecated. Use "boxShadow".` ); const boxShadowValue = createBoxShadowValue(style); - if (boxShadowValue != null && nextStyle.boxShadow == null) { - const { boxShadow } = style; - const value = boxShadow - ? `${boxShadow}, ${boxShadowValue}` - : boxShadowValue; - nextStyle.boxShadow = value; + if (boxShadowValue != null) { + nextStyle.boxShadow = boxShadowValue; } } @@ -184,6 +199,12 @@ export const preprocess = ( if (prop === 'aspectRatio' && typeof value === 'number') { nextStyle[prop] = value.toString(); + } else if (prop === 'boxShadow') { + if (Array.isArray(value)) { + value = createBoxShadowArrayValue(value); + } + const { boxShadow } = nextStyle; + nextStyle.boxShadow = boxShadow ? `${value}, ${boxShadow}` : value; } else if (prop === 'fontVariant') { if (Array.isArray(value) && value.length > 0) { /*