diff --git a/examples/components/View/ViewExample.js b/examples/components/View/ViewExample.js
index 18f3a6e8..87a8eb04 100644
--- a/examples/components/View/ViewExample.js
+++ b/examples/components/View/ViewExample.js
@@ -31,6 +31,17 @@ var styles = StyleSheet.create({
borderColor: '#000033',
borderWidth: 1,
},
+ shadowBox: {
+ width: 100,
+ height: 100,
+ borderWidth: 2,
+ },
+ shadow: {
+ shadowOpacity: 0.5,
+ shadowColor: 'red',
+ shadowRadius: 3,
+ shadowOffset: { width: 3, height: 3 },
+ },
zIndex: {
justifyContent: 'space-around',
width: 100,
@@ -242,6 +253,19 @@ const examples = [
return ;
},
},
+ {
+ title: 'Basic shadow',
+ render() {
+ return ;
+ }
+ },
+ {
+ title: 'Shaped shadow',
+ description: 'borderRadius: 50',
+ render() {
+ return ;
+ }
+ }
];
examples.forEach((example) => {
diff --git a/src/apis/StyleSheet/__tests__/processBoxShadow-test.js b/src/apis/StyleSheet/__tests__/processBoxShadow-test.js
new file mode 100644
index 00000000..74707a8a
--- /dev/null
+++ b/src/apis/StyleSheet/__tests__/processBoxShadow-test.js
@@ -0,0 +1,47 @@
+/* eslint-env jasmine, jest */
+
+import processBoxShadow from '../processBoxShadow';
+
+describe('apis/StyleSheet/processBoxShadow', () => {
+ test('missing shadowColor', () => {
+ const style = {
+ shadowOffset: { width: 1, height: 2 }
+ };
+
+ expect(processBoxShadow(style)).toEqual({});
+ });
+
+ test('shadowColor only', () => {
+ const style = {
+ shadowColor: 'red'
+ };
+
+ expect(processBoxShadow(style)).toEqual({
+ boxShadow: '0px 0px 0px rgba(255,0,0,1)'
+ });
+ });
+
+ test('shadowColor and shadowOpacity only', () => {
+ const style = {
+ shadowColor: 'red',
+ shadowOpacity: 0.5
+ };
+
+ expect(processBoxShadow(style)).toEqual({
+ boxShadow: '0px 0px 0px rgba(255,0,0,0.5)'
+ });
+ });
+
+ test('shadowOffset, shadowRadius, shadowSpread', () => {
+ const style = {
+ shadowColor: 'rgba(50,60,70,0.5)',
+ shadowOffset: { width: 1, height: 2 },
+ shadowOpacity: 0.5,
+ shadowRadius: 3
+ };
+
+ expect(processBoxShadow(style)).toEqual({
+ boxShadow: '2px 1px 3px rgba(50,60,70,0.25)'
+ });
+ });
+});
diff --git a/src/apis/StyleSheet/createReactStyleObject.js b/src/apis/StyleSheet/createReactStyleObject.js
index f0ce3159..e0092e31 100644
--- a/src/apis/StyleSheet/createReactStyleObject.js
+++ b/src/apis/StyleSheet/createReactStyleObject.js
@@ -1,11 +1,13 @@
import expandStyle from './expandStyle';
import flattenStyle from '../../modules/flattenStyle';
import i18nStyle from './i18nStyle';
+import processBoxShadow from './processBoxShadow';
import processTextShadow from './processTextShadow';
import processTransform from './processTransform';
import processVendorPrefixes from './processVendorPrefixes';
const processors = [
+ processBoxShadow,
processTextShadow,
processTransform,
processVendorPrefixes
diff --git a/src/apis/StyleSheet/normalizeValue.js b/src/apis/StyleSheet/normalizeValue.js
index 889446d4..cb4c2421 100644
--- a/src/apis/StyleSheet/normalizeValue.js
+++ b/src/apis/StyleSheet/normalizeValue.js
@@ -24,7 +24,9 @@ const unitlessNumbers = {
scale: true,
scaleX: true,
scaleY: true,
- scaleZ: true
+ scaleZ: true,
+ // RN properties
+ shadowOpacity: true
};
const normalizeValue = (property, value) => {
diff --git a/src/apis/StyleSheet/processBoxShadow.js b/src/apis/StyleSheet/processBoxShadow.js
new file mode 100644
index 00000000..843121f3
--- /dev/null
+++ b/src/apis/StyleSheet/processBoxShadow.js
@@ -0,0 +1,33 @@
+import normalizeColor from '../../modules/normalizeColor';
+import normalizeValue from './normalizeValue';
+
+const applyOpacity = (color, opacity) => {
+ const normalizedColor = normalizeColor(color);
+ const colorNumber = normalizedColor === null ? 0x00000000 : normalizedColor;
+ const r = (colorNumber & 0xff000000) >>> 24;
+ const g = (colorNumber & 0x00ff0000) >>> 16;
+ const b = (colorNumber & 0x0000ff00) >>> 8;
+ const a = (((colorNumber & 0x000000ff) >>> 0) / 255).toFixed(2);
+ return `rgba(${r},${g},${b},${a * opacity})`;
+};
+
+// TODO: add inset and spread support
+const processBoxShadow = (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;
+};
+
+module.exports = processBoxShadow;
diff --git a/src/components/View/ViewStylePropTypes.js b/src/components/View/ViewStylePropTypes.js
index 07677223..5cf1500a 100644
--- a/src/components/View/ViewStylePropTypes.js
+++ b/src/components/View/ViewStylePropTypes.js
@@ -2,6 +2,7 @@ import BorderPropTypes from '../../propTypes/BorderPropTypes';
import ColorPropType from '../../propTypes/ColorPropType';
import LayoutPropTypes from '../../propTypes/LayoutPropTypes';
import { PropTypes } from 'react';
+import ShadowPropTypes from '../../propTypes/ShadowPropTypes';
import TransformPropTypes from '../../propTypes/TransformPropTypes';
const { number, oneOf, string } = PropTypes;
@@ -11,6 +12,7 @@ const hiddenOrVisible = oneOf([ 'hidden', 'visible' ]);
module.exports = process.env.NODE_ENV !== 'production' ? {
...BorderPropTypes,
...LayoutPropTypes,
+ ...ShadowPropTypes,
...TransformPropTypes,
backfaceVisibility: hiddenOrVisible,
backgroundColor: ColorPropType,
diff --git a/src/propTypes/ShadowPropTypes.js b/src/propTypes/ShadowPropTypes.js
new file mode 100644
index 00000000..80b4dd1e
--- /dev/null
+++ b/src/propTypes/ShadowPropTypes.js
@@ -0,0 +1,18 @@
+import ColorPropType from './ColorPropType';
+import { PropTypes } from 'react';
+
+const { number, oneOfType, shape, string } = PropTypes;
+const numberOrString = oneOfType([ number, string ]);
+
+const ShadowPropTypes = {
+ shadowColor: ColorPropType,
+ shadowOffset: shape({
+ width: numberOrString,
+ height: numberOrString
+ }),
+ shadowOpacity: number,
+ shadowRadius: numberOrString,
+ shadowSpread: numberOrString
+};
+
+module.exports = ShadowPropTypes;