diff --git a/docs/apis/StyleSheet.md b/docs/apis/StyleSheet.md
index 4cc94d49..d4a340a3 100644
--- a/docs/apis/StyleSheet.md
+++ b/docs/apis/StyleSheet.md
@@ -9,6 +9,8 @@ outside of the render loop and are applied as inline styles. Read more about to
**create**(obj: {[key: string]: any})
+Each key of the object passed to `create` must define a style object.
+
## Example
```js
@@ -24,12 +26,25 @@ const styles = StyleSheet.create({
},
activeTitle: {
color: 'red',
- },
+ }
})
```
Use styles:
+```js
+
+
+
+```
+
+Or:
+
```js
)
}
diff --git a/docs/components/Text.md b/docs/components/Text.md
index 82a3ae1f..90eeb876 100644
--- a/docs/components/Text.md
+++ b/docs/components/Text.md
@@ -82,14 +82,14 @@ export default class PrettyText extends Component {
color: PropTypes.oneOf(['white', 'gray', 'red']),
size: PropTypes.oneOf(['small', 'normal', 'large']),
weight: PropTypes.oneOf(['light', 'normal', 'bold'])
- }
+ };
static defaultProps = {
...Text.defaultProps,
color: 'gray',
size: 'normal',
weight: 'normal'
- }
+ };
render() {
const { color, size, style, weight, ...other } = this.props;
@@ -97,32 +97,32 @@ export default class PrettyText extends Component {
return (
);
}
}
-const styles = StyleSheet.create({
- color: {
- white: { color: 'white' },
- gray: { color: 'gray' },
- red: { color: 'red' }
- },
- size: {
- small: { fontSize: '0.85rem', padding: '0.5rem' },
- normal: { fontSize: '1rem', padding: '0.75rem' },
- large: { fontSize: '1.5rem', padding: '1rem' }
- },
- weight: {
- light: { fontWeight: '300' },
- normal: { fontWeight: '400' },
- bold: { fontWeight: '700' }
- }
+const colorStyles = StyleSheet.create({
+ white: { color: 'white' },
+ gray: { color: 'gray' },
+ red: { color: 'red' }
+})
+
+const sizeStyles = StyleSheet.create({
+ small: { fontSize: '0.85rem', padding: '0.5rem' },
+ normal: { fontSize: '1rem', padding: '0.75rem' },
+ large: { fontSize: '1.5rem', padding: '1rem' }
+})
+
+const weightStyles = StyleSheet.create({
+ light: { fontWeight: '300' },
+ normal: { fontWeight: '400' },
+ bold: { fontWeight: '700' }
})
```
diff --git a/docs/components/TextInput.md b/docs/components/TextInput.md
index 51301b5a..f9d53060 100644
--- a/docs/components/TextInput.md
+++ b/docs/components/TextInput.md
@@ -176,10 +176,10 @@ export default class TextInputExample extends Component {
onBlur={this._onBlur.bind(this)}
onFocus={this._onFocus.bind(this)}
placeholder={`What's happening?`}
- style={{
- ...styles.default
- ...(this.state.isFocused && styles.focused)
- }}
+ style={[
+ styles.default
+ this.state.isFocused && styles.focused
+ ]}
/>
);
}
diff --git a/docs/guides/style.md b/docs/guides/style.md
index 93c24822..9ae1b920 100644
--- a/docs/guides/style.md
+++ b/docs/guides/style.md
@@ -1,8 +1,8 @@
# Style
-React Native for Web relies on JavaScript to let you style your application.
-Along with a novel JS-to-CSS conversion strategy, this allows you to avoid
-issues arising from the [7 deadly sins of
+React Native for Web relies on JavaScript to define styles for your
+application. Along with a novel JS-to-CSS conversion strategy, this allows you
+to avoid issues arising from the [7 deadly sins of
CSS](https://speakerdeck.com/vjeux/react-css-in-js):
1. Global namespace
@@ -53,16 +53,16 @@ A common pattern is to conditionally add style based on a condition:
```js
// either
-
-
-// or
+
+// or
+
```
## Composing styles
@@ -82,7 +82,7 @@ class List extends React.Component {
return (
{elements.map((element) =>
-
+
)}
);
diff --git a/examples/components/App.js b/examples/components/App.js
index 06f81a4c..81d9d849 100644
--- a/examples/components/App.js
+++ b/examples/components/App.js
@@ -18,15 +18,15 @@ export default class App extends React.Component {
render() {
const { mediaQuery } = this.props
- const rootStyles = {
- ...(styles.root.common),
- ...(mediaQuery.small.matches && styles.root.mqSmall),
- ...(mediaQuery.large.matches && styles.root.mqLarge)
- }
+ const finalRootStyles = [
+ rootStyles.common,
+ mediaQuery.small.matches && rootStyles.mqSmall,
+ mediaQuery.large.matches && rootStyles.mqLarge
+ ]
return (
-
+
React Native for Web
React Native Web takes the core components from React
@@ -200,7 +200,7 @@ export default class App extends React.Component {
style={styles.scrollViewStyle}
>
{Array.from({ length: 50 }).map((item, i) => (
-
+
{i}
))}
@@ -212,19 +212,20 @@ export default class App extends React.Component {
}
}
-const styles = StyleSheet.create({
- root: {
- common: {
- marginVertical: 0,
- marginHorizontal: 'auto'
- },
- mqSmall: {
- maxWidth: '400px'
- },
- mqLarge: {
- maxWidth: '600px'
- }
+const rootStyles = StyleSheet.create({
+ common: {
+ marginVertical: 0,
+ marginHorizontal: 'auto'
},
+ mqSmall: {
+ maxWidth: '400px'
+ },
+ mqLarge: {
+ maxWidth: '600px'
+ }
+})
+
+const styles = StyleSheet.create({
row: {
flexDirection: 'row',
flexWrap: 'wrap'
diff --git a/examples/components/Heading.js b/examples/components/Heading.js
index a5dcf22e..cee5ad3f 100644
--- a/examples/components/Heading.js
+++ b/examples/components/Heading.js
@@ -1,24 +1,25 @@
import React, { StyleSheet, Text } from '../../src'
+const sizeStyles = StyleSheet.create({
+ xlarge: {
+ fontSize: '2rem',
+ marginBottom: '1em'
+ },
+ large: {
+ fontSize: '1.5rem',
+ marginBottom: '1em',
+ marginTop: '1em'
+ },
+ normal: {
+ fontSize: '1.25rem',
+ marginBottom: '0.5em',
+ marginTop: '0.5em'
+ }
+})
+
const styles = StyleSheet.create({
root: {
fontFamily: '"Helvetica Neue", arial, sans-serif'
- },
- size: {
- xlarge: {
- fontSize: '2rem',
- marginBottom: '1em'
- },
- large: {
- fontSize: '1.5rem',
- marginBottom: '1em',
- marginTop: '1em'
- },
- normal: {
- fontSize: '1.25rem',
- marginBottom: '0.5em',
- marginTop: '0.5em'
- }
}
})
@@ -26,7 +27,7 @@ const Heading = ({ children, size = 'normal' }) => (
)
diff --git a/examples/components/MediaQueryWidget.js b/examples/components/MediaQueryWidget.js
index 487024eb..acbbb20e 100644
--- a/examples/components/MediaQueryWidget.js
+++ b/examples/components/MediaQueryWidget.js
@@ -5,12 +5,15 @@ const styles = StyleSheet.create({
alignItems: 'center',
borderWidth: 1,
marginVertical: 10,
- padding: 10,
- textAlign: 'center'
+ padding: 10
},
heading: {
fontWeight: 'bold',
- padding: 5
+ padding: 5,
+ textAlign: 'center'
+ },
+ text: {
+ textAlign: 'center'
}
})
@@ -28,7 +31,7 @@ const MediaQueryWidget = ({ mediaQuery = {} }) => {
return (
Active Media Query
- {`"${active.alias}"`} {active.mql && active.mql.media}
+ {`"${active.alias}"`} {active.mql && active.mql.media}
)
}
diff --git a/src/apis/AppRegistry/renderApplication.js b/src/apis/AppRegistry/renderApplication.js
index f82c8286..844eeaf0 100644
--- a/src/apis/AppRegistry/renderApplication.js
+++ b/src/apis/AppRegistry/renderApplication.js
@@ -13,14 +13,13 @@ import ReactDOMServer from 'react-dom/server'
import ReactNativeApp from './ReactNativeApp'
import StyleSheet from '../../apis/StyleSheet'
-const STYLESHEET_ID = 'react-stylesheet'
-const renderStyleSheetToString = () => ``
+const renderStyleSheetToString = () => ``
export default function renderApplication(RootComponent: Component, initialProps: Object, rootTag: any) {
invariant(rootTag, 'Expect to have a valid rootTag, instead got ', rootTag)
// insert style sheet if needed
- const styleElement = document.getElementById(STYLESHEET_ID)
+ const styleElement = document.getElementById(StyleSheet.elementId)
if (!styleElement) { rootTag.insertAdjacentHTML('beforebegin', renderStyleSheetToString()) }
const component = (
diff --git a/src/apis/StyleSheet/BorderPropTypes.js b/src/apis/StyleSheet/BorderPropTypes.js
new file mode 100644
index 00000000..715baffb
--- /dev/null
+++ b/src/apis/StyleSheet/BorderPropTypes.js
@@ -0,0 +1,25 @@
+import { PropTypes } from 'react'
+import ColorPropType from '../../apis/StyleSheet/ColorPropType'
+
+const numberOrString = PropTypes.oneOfType([ PropTypes.number, PropTypes.string ])
+const BorderStylePropType = PropTypes.oneOf([ 'solid', 'dotted', 'dashed' ])
+
+const BorderPropTypes = {
+ borderColor: ColorPropType,
+ borderTopColor: ColorPropType,
+ borderRightColor: ColorPropType,
+ borderBottomColor: ColorPropType,
+ borderLeftColor: ColorPropType,
+ borderRadius: numberOrString,
+ borderTopLeftRadius: numberOrString,
+ borderTopRightRadius: numberOrString,
+ borderBottomLeftRadius: numberOrString,
+ borderBottomRightRadius: numberOrString,
+ borderStyle: BorderStylePropType,
+ borderTopStyle: BorderStylePropType,
+ borderRightStyle: BorderStylePropType,
+ borderBottomStyle: BorderStylePropType,
+ borderLeftStyle: BorderStylePropType
+}
+
+export default BorderPropTypes
diff --git a/src/apis/StyleSheet/ColorPropType.js b/src/apis/StyleSheet/ColorPropType.js
new file mode 100644
index 00000000..9cbe37dc
--- /dev/null
+++ b/src/apis/StyleSheet/ColorPropType.js
@@ -0,0 +1,5 @@
+import { PropTypes } from 'react'
+
+const ColorPropType = PropTypes.string
+
+export default ColorPropType
diff --git a/src/apis/StyleSheet/LayoutPropTypes.js b/src/apis/StyleSheet/LayoutPropTypes.js
new file mode 100644
index 00000000..734a7724
--- /dev/null
+++ b/src/apis/StyleSheet/LayoutPropTypes.js
@@ -0,0 +1,54 @@
+import { PropTypes } from 'react'
+
+const { number, oneOf, oneOfType, string } = PropTypes
+const numberOrString = oneOfType([ number, string ])
+
+const LayoutPropTypes = {
+ // box model
+ borderWidth: numberOrString,
+ borderBottomWidth: numberOrString,
+ borderLeftWidth: numberOrString,
+ borderRightWidth: numberOrString,
+ borderTopWidth: numberOrString,
+ boxSizing: string,
+ height: numberOrString,
+ margin: numberOrString,
+ marginBottom: numberOrString,
+ marginHorizontal: numberOrString,
+ marginLeft: numberOrString,
+ marginRight: numberOrString,
+ marginTop: numberOrString,
+ marginVertical: numberOrString,
+ maxHeight: numberOrString,
+ maxWidth: numberOrString,
+ minHeight: numberOrString,
+ minWidth: numberOrString,
+ padding: numberOrString,
+ paddingBottom: numberOrString,
+ paddingHorizontal: numberOrString,
+ paddingLeft: numberOrString,
+ paddingRight: numberOrString,
+ paddingTop: numberOrString,
+ paddingVertical: numberOrString,
+ width: numberOrString,
+ // flexbox
+ alignContent: oneOf([ 'center', 'flex-end', 'flex-start', 'space-around', 'space-between', 'stretch' ]),
+ alignItems: oneOf([ 'baseline', 'center', 'flex-end', 'flex-start', 'stretch' ]),
+ alignSelf: oneOf([ 'auto', 'baseline', 'center', 'flex-end', 'flex-start', 'stretch' ]),
+ flex: number,
+ flexBasis: string,
+ flexDirection: oneOf([ 'column', 'column-reverse', 'row', 'row-reverse' ]),
+ flexGrow: number,
+ flexShrink: number,
+ flexWrap: oneOf([ 'nowrap', 'wrap', 'wrap-reverse' ]),
+ justifyContent: oneOf([ 'center', 'flex-end', 'flex-start', 'space-around', 'space-between' ]),
+ order: number,
+ // position
+ bottom: numberOrString,
+ left: numberOrString,
+ position: oneOf([ 'absolute', 'fixed', 'relative', 'static' ]),
+ right: numberOrString,
+ top: numberOrString
+}
+
+export default LayoutPropTypes
diff --git a/src/apis/StyleSheet/Store.js b/src/apis/StyleSheet/Store.js
index 5f23c37f..01353ec2 100644
--- a/src/apis/StyleSheet/Store.js
+++ b/src/apis/StyleSheet/Store.js
@@ -1,5 +1,4 @@
import hyphenate from './hyphenate'
-import normalizeValue from './normalizeValue'
import prefixer from './prefixer'
export default class Store {
@@ -14,18 +13,16 @@ export default class Store {
}
get(property, value) {
- const normalizedValue = normalizeValue(property, value)
- const key = this._getDeclarationKey(property, normalizedValue)
+ const key = this._getDeclarationKey(property, value)
return this._classNames[key]
}
set(property, value) {
if (value != null) {
- const normalizedValue = normalizeValue(property, value)
const values = this._getPropertyValues(property) || []
- if (values.indexOf(normalizedValue) === -1) {
- values.push(normalizedValue)
- this._setClassName(property, normalizedValue)
+ if (values.indexOf(value) === -1) {
+ values.push(value)
+ this._setClassName(property, value)
this._setPropertyValues(property, values)
}
}
@@ -80,7 +77,7 @@ export default class Store {
}
_setPropertyValues(property, values) {
- this._declarations[property] = values.map(value => normalizeValue(property, value))
+ this._declarations[property] = values.map(value => value)
}
_setClassName(property, value) {
diff --git a/src/apis/StyleSheet/StylePropTypes.js b/src/apis/StyleSheet/StylePropTypes.js
deleted file mode 100644
index 42bf8231..00000000
--- a/src/apis/StyleSheet/StylePropTypes.js
+++ /dev/null
@@ -1,112 +0,0 @@
-import { PropTypes } from 'react'
-
-const { number, oneOf, oneOfType, string } = PropTypes
-const numberOrString = oneOfType([ number, string ])
-
-/**
- * Any properties marked @private are used internally in resets or property
- * mappings.
- *
- * https://developer.mozilla.org/en-US/docs/Web/CSS/Reference
- */
-export default {
- alignContent: oneOf([ 'center', 'flex-end', 'flex-start', 'space-around', 'space-between', 'stretch' ]),
- alignItems: oneOf([ 'baseline', 'center', 'flex-end', 'flex-start', 'stretch' ]),
- alignSelf: oneOf([ 'auto', 'baseline', 'center', 'flex-end', 'flex-start', 'stretch' ]),
- appearance: string,
- backfaceVisibility: string,
- backgroundAttachment: oneOf([ 'fixed', 'local', 'scroll' ]),
- backgroundClip: string,
- backgroundColor: string,
- backgroundImage: string,
- backgroundOrigin: oneOf([ 'border-box', 'content-box', 'padding-box' ]),
- backgroundPosition: string,
- backgroundRepeat: string,
- backgroundSize: string,
- borderColor: string,
- borderBottomColor: string,
- borderLeftColor: string,
- borderRightColor: string,
- borderTopColor: string,
- borderRadius: numberOrString,
- borderTopLeftRadius: numberOrString,
- borderTopRightRadius: numberOrString,
- borderBottomLeftRadius: numberOrString,
- borderBottomRightRadius: numberOrString,
- borderStyle: string,
- borderBottomStyle: string,
- borderLeftStyle: string,
- borderRightStyle: string,
- borderTopStyle: string,
- borderWidth: numberOrString,
- borderBottomWidth: numberOrString,
- borderLeftWidth: numberOrString,
- borderRightWidth: numberOrString,
- borderTopWidth: numberOrString,
- bottom: numberOrString,
- boxShadow: string,
- boxSizing: oneOf([ 'border-box', 'content-box' ]),
- clear: string,
- color: string,
- cursor: string,
- display: string,
- direction: string, /* @private */
- flex: number,
- flexBasis: string,
- flexDirection: oneOf([ 'column', 'column-reverse', 'row', 'row-reverse' ]),
- flexGrow: number,
- flexShrink: number,
- flexWrap: oneOf([ 'nowrap', 'wrap', 'wrap-reverse' ]),
- float: oneOf([ 'left', 'none', 'right' ]),
- font: string, /* @private */
- fontFamily: string,
- fontSize: numberOrString,
- fontStyle: string,
- fontWeight: string,
- height: numberOrString,
- justifyContent: oneOf([ 'center', 'flex-end', 'flex-start', 'space-around', 'space-between' ]),
- left: numberOrString,
- letterSpacing: string,
- lineHeight: numberOrString,
- listStyle: string,
- margin: numberOrString,
- marginBottom: numberOrString,
- marginHorizontal: numberOrString,
- marginLeft: numberOrString,
- marginRight: numberOrString,
- marginTop: numberOrString,
- marginVertical: numberOrString,
- maxHeight: numberOrString,
- maxWidth: numberOrString,
- minHeight: numberOrString,
- minWidth: numberOrString,
- opacity: numberOrString,
- order: numberOrString,
- outline: string,
- overflow: string,
- overflowX: string,
- overflowY: string,
- padding: numberOrString,
- paddingBottom: numberOrString,
- paddingHorizontal: numberOrString,
- paddingLeft: numberOrString,
- paddingRight: numberOrString,
- paddingTop: numberOrString,
- paddingVertical: numberOrString,
- position: oneOf([ 'absolute', 'fixed', 'relative', 'static' ]),
- right: numberOrString,
- textAlign: oneOf([ 'center', 'inherit', 'justify', 'justify-all', 'left', 'right' ]),
- textDecoration: string,
- textOverflow: string,
- textShadow: string,
- textTransform: oneOf([ 'capitalize', 'lowercase', 'none', 'uppercase' ]),
- top: numberOrString,
- userSelect: string,
- verticalAlign: string,
- visibility: oneOf([ 'hidden', 'visible' ]),
- whiteSpace: string,
- width: numberOrString,
- wordWrap: string,
- writingDirection: string,
- zIndex: numberOrString
-}
diff --git a/src/apis/StyleSheet/StyleSheetPropType.js b/src/apis/StyleSheet/StyleSheetPropType.js
new file mode 100644
index 00000000..0e2467f6
--- /dev/null
+++ b/src/apis/StyleSheet/StyleSheetPropType.js
@@ -0,0 +1,22 @@
+/**
+ * Copyright (c) 2015-present, Facebook, Inc.
+ * All rights reserved.
+ *
+ * @flow
+ */
+
+import createStrictShapeTypeChecker from './createStrictShapeTypeChecker'
+import flattenStyle from './flattenStyle'
+
+export default function StyleSheetPropType(shape) {
+ const shapePropType = createStrictShapeTypeChecker(shape)
+ return function (props, propName, componentName, location?) {
+ let newProps = props
+ if (props[propName]) {
+ // Just make a dummy prop object with only the flattened style
+ newProps = {}
+ newProps[propName] = flattenStyle(props[propName])
+ }
+ return shapePropType(newProps, propName, componentName, location)
+ }
+}
diff --git a/src/apis/StyleSheet/StyleSheetRegistry.js b/src/apis/StyleSheet/StyleSheetRegistry.js
new file mode 100644
index 00000000..87275546
--- /dev/null
+++ b/src/apis/StyleSheet/StyleSheetRegistry.js
@@ -0,0 +1,46 @@
+/**
+ * Copyright (c) 2016-present, Nicolas Gallagher.
+ * Copyright (c) 2015-present, Facebook, Inc.
+ * All rights reserved.
+ *
+ * @flow
+ */
+
+import flattenStyle from './flattenStyle'
+import prefixer from './prefixer'
+
+export default class StyleSheetRegistry {
+ static registerStyle(style: Object, store): number {
+ if (process.env.NODE_ENV !== 'production') {
+ Object.freeze(style)
+ }
+
+ const normalizedStyle = flattenStyle(style)
+ Object.keys(normalizedStyle).forEach((prop) => {
+ // add each declaration to the store
+ store.set(prop, normalizedStyle[prop])
+ })
+ }
+
+ static getStyleAsNativeProps(style, store) {
+ let _className
+ let _style = {}
+ const classList = []
+ const normalizedStyle = flattenStyle(style)
+
+ for (const prop in normalizedStyle) {
+ let styleClass = store.get(prop, normalizedStyle[prop])
+
+ if (styleClass) {
+ classList.push(styleClass)
+ } else {
+ _style[prop] = normalizedStyle[prop]
+ }
+ }
+
+ _className = classList.join(' ')
+ _style = prefixer.prefix(_style)
+
+ return { className: _className, style: _style }
+ }
+}
diff --git a/src/apis/StyleSheet/StyleSheetValidation.js b/src/apis/StyleSheet/StyleSheetValidation.js
new file mode 100644
index 00000000..2b5fa8ee
--- /dev/null
+++ b/src/apis/StyleSheet/StyleSheetValidation.js
@@ -0,0 +1,68 @@
+/**
+ * Copyright (c) 2016-present, Nicolas Gallagher.
+ * Copyright (c) 2015-present, Facebook, Inc.
+ * All rights reserved.
+
+ * @flow
+ */
+
+import { PropTypes } from 'react'
+import ImageStylePropTypes from '../../components/Image/ImageStylePropTypes'
+import TextStylePropTypes from '../../components/Text/TextStylePropTypes'
+import ViewStylePropTypes from '../../components/View/ViewStylePropTypes'
+import invariant from 'invariant'
+
+export default class StyleSheetValidation {
+ static validateStyleProp(prop, style, caller) {
+ if (process.env.NODE_ENV !== 'production') {
+ if (allStylePropTypes[prop] === undefined) {
+ const message1 = `"${prop}" is not a valid style property.`
+ const message2 = '\nValid style props: ' + JSON.stringify(Object.keys(allStylePropTypes).sort(), null, ' ')
+ styleError(message1, style, caller, message2)
+ }
+ const error = allStylePropTypes[prop](style, prop, caller, 'prop')
+ if (error) {
+ styleError(error.message, style, caller)
+ }
+ }
+ }
+
+ static validateStyle(name, styles) {
+ if (process.env.NODE_ENV !== 'production') {
+ for (const prop in styles[name]) {
+ StyleSheetValidation.validateStyleProp(prop, styles[name], 'StyleSheet ' + name)
+ }
+ }
+ }
+
+ static addValidStylePropTypes(stylePropTypes) {
+ for (const key in stylePropTypes) {
+ allStylePropTypes[key] = stylePropTypes[key]
+ }
+ }
+}
+
+const styleError = (message1, style, caller, message2) => {
+ invariant(
+ false,
+ message1 + '\n' + (caller || '<>') + ': ' +
+ JSON.stringify(style, null, ' ') + (message2 || '')
+ )
+}
+
+const allStylePropTypes = {}
+
+StyleSheetValidation.addValidStylePropTypes(ImageStylePropTypes)
+StyleSheetValidation.addValidStylePropTypes(TextStylePropTypes)
+StyleSheetValidation.addValidStylePropTypes(ViewStylePropTypes)
+StyleSheetValidation.addValidStylePropTypes({
+ appearance: PropTypes.string,
+ clear: PropTypes.string,
+ cursor: PropTypes.string,
+ display: PropTypes.string,
+ direction: PropTypes.string, /* @private */
+ float: PropTypes.oneOf([ 'left', 'none', 'right' ]),
+ font: PropTypes.string, /* @private */
+ listStyle: PropTypes.string,
+ verticalAlign: PropTypes.string
+})
diff --git a/src/apis/StyleSheet/TransformPropTypes.js b/src/apis/StyleSheet/TransformPropTypes.js
new file mode 100644
index 00000000..53b933c5
--- /dev/null
+++ b/src/apis/StyleSheet/TransformPropTypes.js
@@ -0,0 +1,47 @@
+/**
+ * Copyright (c) 2015-present, Facebook, Inc.
+ * All rights reserved.
+ *
+ * @flow
+ */
+
+import { PropTypes } from 'react'
+
+const ArrayOfNumberPropType = PropTypes.arrayOf(PropTypes.number)
+const numberOrString = PropTypes.oneOfType([ PropTypes.number, PropTypes.string ])
+
+const TransformMatrixPropType = function (
+ props : Object,
+ propName : string,
+ componentName : string
+) : ?Error {
+ if (props.transform && props.transformMatrix) {
+ return new Error(
+ 'transformMatrix and transform styles cannot be used on the same ' +
+ 'component'
+ )
+ }
+ return ArrayOfNumberPropType(props, propName, componentName)
+}
+
+const TransformPropTypes = {
+ transform: PropTypes.arrayOf(
+ PropTypes.oneOfType([
+ PropTypes.shape({ perspective: numberOrString }),
+ PropTypes.shape({ rotate: numberOrString }),
+ PropTypes.shape({ rotateX: numberOrString }),
+ PropTypes.shape({ rotateY: numberOrString }),
+ PropTypes.shape({ rotateZ: numberOrString }),
+ PropTypes.shape({ scale: numberOrString }),
+ PropTypes.shape({ scaleX: numberOrString }),
+ PropTypes.shape({ scaleY: numberOrString }),
+ PropTypes.shape({ skewX: numberOrString }),
+ PropTypes.shape({ skewY: numberOrString }),
+ PropTypes.shape({ translateX: numberOrString }),
+ PropTypes.shape({ translateY: numberOrString })
+ ])
+ ),
+ transformMatrix: TransformMatrixPropType
+}
+
+export default TransformPropTypes
diff --git a/src/apis/StyleSheet/__tests__/Store-test.js b/src/apis/StyleSheet/__tests__/Store-test.js
index 6922220f..b83cdf0c 100644
--- a/src/apis/StyleSheet/__tests__/Store-test.js
+++ b/src/apis/StyleSheet/__tests__/Store-test.js
@@ -66,20 +66,6 @@ suite('apis/StyleSheet/Store', () => {
})
})
- test('value normalization', () => {
- const store = new Store()
- store.set('flexGrow', 0)
- store.set('margin', 0)
- assert.deepEqual(store._declarations, {
- flexGrow: [ 0 ],
- margin: [ '0px' ]
- })
- assert.deepEqual(store._classNames, {
- 'flexGrow:0': 'flexGrow:0',
- 'margin:0px': 'margin:0px'
- })
- })
-
test('replaces space characters', () => {
const store = new Store()
@@ -95,7 +81,7 @@ suite('apis/StyleSheet/Store', () => {
store.set('backgroundColor', 'rgba(0,0,0,0)')
store.set('color', '#fff')
store.set('fontFamily', '"Helvetica Neue", Arial, sans-serif')
- store.set('marginBottom', 0)
+ store.set('marginBottom', '0px')
store.set('width', '100%')
const expected = '/* 6 unique declarations */\n' +
@@ -112,10 +98,10 @@ suite('apis/StyleSheet/Store', () => {
test('obfuscated style sheet', () => {
const store = new Store({}, { obfuscateClassNames: true })
store.set('alignItems', 'center')
- store.set('marginBottom', 0)
- store.set('margin', 1)
- store.set('margin', 2)
- store.set('margin', 3)
+ store.set('marginBottom', '0px')
+ store.set('margin', '1px')
+ store.set('margin', '2px')
+ store.set('margin', '3px')
const expected = '/* 5 unique declarations */\n' +
'._s_1{align-items:center;}\n' +
diff --git a/src/apis/StyleSheet/__tests__/expandStyle-test.js b/src/apis/StyleSheet/__tests__/expandStyle-test.js
index 521e29bb..74df33b1 100644
--- a/src/apis/StyleSheet/__tests__/expandStyle-test.js
+++ b/src/apis/StyleSheet/__tests__/expandStyle-test.js
@@ -14,14 +14,14 @@ suite('apis/StyleSheet/expandStyle', () => {
}
const expected = {
- borderTopWidth: 1,
- borderLeftWidth: 2,
- borderRightWidth: 2,
- borderBottomWidth: 2,
- marginTop: 50,
- marginBottom: 25,
- marginLeft: 10,
- marginRight: 10
+ borderTopWidth: '1px',
+ borderLeftWidth: '2px',
+ borderRightWidth: '2px',
+ borderBottomWidth: '2px',
+ marginTop: '50px',
+ marginBottom: '25px',
+ marginLeft: '10px',
+ marginRight: '10px'
}
assert.deepEqual(expandStyle(initial), expected)
diff --git a/src/apis/StyleSheet/__tests__/flattenStyle-test.js b/src/apis/StyleSheet/__tests__/flattenStyle-test.js
new file mode 100644
index 00000000..0ebaa74c
--- /dev/null
+++ b/src/apis/StyleSheet/__tests__/flattenStyle-test.js
@@ -0,0 +1,51 @@
+/* eslint-env mocha */
+
+/**
+ * Copyright (c) 2015-present, Facebook, Inc.
+ * All rights reserved.
+ *
+ * This source code is licensed under the BSD-style license found in the
+ * LICENSE file in the root directory of this source tree. An additional grant
+ * of patent rights can be found in the PATENTS file in the same directory.
+ */
+
+import assert from 'assert'
+import flattenStyle from '../flattenStyle'
+
+suite('flattenStyle', () => {
+ test('should merge style objects', () => {
+ const style1 = {opacity: 1}
+ const style2 = {order: 2}
+ const flatStyle = flattenStyle([style1, style2])
+ assert.equal(flatStyle.opacity, 1)
+ assert.equal(flatStyle.order, 2)
+ })
+
+ test('should override style properties', () => {
+ const style1 = {backgroundColor: '#000', order: 1}
+ const style2 = {backgroundColor: '#023c69', order: null}
+ const flatStyle = flattenStyle([style1, style2])
+ assert.equal(flatStyle.backgroundColor, '#023c69')
+ assert.strictEqual(flatStyle.order, null)
+ })
+
+ test('should overwrite properties with `undefined`', () => {
+ const style1 = {backgroundColor: '#000'}
+ const style2 = {backgroundColor: undefined}
+ const flatStyle = flattenStyle([style1, style2])
+ assert.strictEqual(flatStyle.backgroundColor, undefined)
+ })
+
+ test('should not fail on falsy values', () => {
+ assert.doesNotThrow(() => flattenStyle([null, false, undefined]))
+ })
+
+ test('should recursively flatten arrays', () => {
+ const style1 = {order: 2}
+ const style2 = {opacity: 1}
+ const style3 = {order: 3}
+ const flatStyle = flattenStyle([null, [], [style1, style2], style3])
+ assert.equal(flatStyle.order, 3)
+ assert.equal(flatStyle.opacity, 1)
+ })
+})
diff --git a/src/apis/StyleSheet/__tests__/getStyleObjects-test.js b/src/apis/StyleSheet/__tests__/getStyleObjects-test.js
deleted file mode 100644
index b29759a1..00000000
--- a/src/apis/StyleSheet/__tests__/getStyleObjects-test.js
+++ /dev/null
@@ -1,36 +0,0 @@
-/* eslint-env mocha */
-
-import assert from 'assert'
-import getStyleObjects from '../getStyleObjects'
-
-const fixture = {
- rule: {
- margin: 0,
- padding: 0
- },
- nested: {
- auto: {
- backgroundSize: 'auto'
- },
- contain: {
- backgroundSize: 'contain'
- }
- },
- position: {
- left: { left: 0 },
- right: { right: 0 }
- }
-}
-
-suite('apis/StyleSheet/getStyleObjects', () => {
- test('returns only style objects', () => {
- const actual = getStyleObjects(fixture)
- assert.deepEqual(actual, [
- { margin: 0, padding: 0 },
- { backgroundSize: 'auto' },
- { backgroundSize: 'contain' },
- { left: 0 },
- { right: 0 }
- ])
- })
-})
diff --git a/src/apis/StyleSheet/__tests__/index-test.js b/src/apis/StyleSheet/__tests__/index-test.js
index da00a625..cfbbad37 100644
--- a/src/apis/StyleSheet/__tests__/index-test.js
+++ b/src/apis/StyleSheet/__tests__/index-test.js
@@ -17,7 +17,7 @@ suite('apis/StyleSheet', () => {
setup(() => {
document.body.appendChild(div)
StyleSheet.create(styles)
- div.innerHTML = ``
+ div.innerHTML = ``
})
teardown(() => {
@@ -32,7 +32,7 @@ suite('apis/StyleSheet', () => {
StyleSheet.create({ root: { color: 'red' } })
assert.equal(
- document.getElementById('react-stylesheet').textContent,
+ document.getElementById(StyleSheet.elementId).textContent,
`${resetCSS}\n${predefinedCSS}\n` +
`/* 5 unique declarations */\n` +
`.borderBottomWidth\\:1px{border-bottom-width:1px;}\n` +
@@ -45,8 +45,8 @@ suite('apis/StyleSheet', () => {
})
test('resolve', () => {
- const props = { className: 'className', style: styles.root }
- const expected = { className: 'className borderTopWidth:1px borderRightWidth:1px borderBottomWidth:1px borderLeftWidth:1px', style: {} }
+ const props = { style: styles.root }
+ const expected = { className: 'borderTopWidth:1px borderRightWidth:1px borderBottomWidth:1px borderLeftWidth:1px', style: {} }
StyleSheet.create(styles)
assert.deepEqual(StyleSheet.resolve(props), expected)
})
diff --git a/src/apis/StyleSheet/__tests__/isObject-test.js b/src/apis/StyleSheet/__tests__/isObject-test.js
deleted file mode 100644
index 756216c0..00000000
--- a/src/apis/StyleSheet/__tests__/isObject-test.js
+++ /dev/null
@@ -1,15 +0,0 @@
-/* eslint-env mocha */
-
-import assert from 'assert'
-import isObject from '../isObject'
-
-suite('apis/StyleSheet/isObject', () => {
- test('returns "true" for objects', () => {
- assert.ok(isObject({}) === true)
- })
- test('returns "false" for non-objects', () => {
- assert.ok(isObject(function () {}) === false)
- assert.ok(isObject([]) === false)
- assert.ok(isObject('') === false)
- })
-})
diff --git a/src/apis/StyleSheet/__tests__/isStyleObject-test.js b/src/apis/StyleSheet/__tests__/isStyleObject-test.js
deleted file mode 100644
index aded3cc0..00000000
--- a/src/apis/StyleSheet/__tests__/isStyleObject-test.js
+++ /dev/null
@@ -1,29 +0,0 @@
-/* eslint-env mocha */
-
-import assert from 'assert'
-import isStyleObject from '../isStyleObject'
-
-const styles = {
- root: {
- margin: 0
- },
- align: {
- left: {
- textAlign: 'left'
- },
- right: {
- textAlign: 'right'
- }
- }
-}
-
-suite('apis/StyleSheet/isStyleObject', () => {
- test('returns "false" for non-style objects', () => {
- assert.ok(isStyleObject(styles) === false)
- assert.ok(isStyleObject(styles.align) === false)
- })
- test('returns "true" for style objects', () => {
- assert.ok(isStyleObject(styles.root) === true)
- assert.ok(isStyleObject(styles.align.left) === true)
- })
-})
diff --git a/src/apis/StyleSheet/createStrictShapeTypeChecker.js b/src/apis/StyleSheet/createStrictShapeTypeChecker.js
new file mode 100644
index 00000000..3fa66f8d
--- /dev/null
+++ b/src/apis/StyleSheet/createStrictShapeTypeChecker.js
@@ -0,0 +1,70 @@
+/**
+ * Copyright (c) 2015-present, Facebook, Inc.
+ * All rights reserved.
+ *
+ * This source code is licensed under the BSD-style license found in the
+ * LICENSE file in the root directory of this source tree. An additional grant
+ * of patent rights can be found in the PATENTS file in the same directory.
+ *
+ * @flow
+ */
+
+import ReactPropTypeLocationNames from 'react/lib/ReactPropTypeLocationNames'
+import invariant from 'invariant'
+
+export default function createStrictShapeTypeChecker(shapeTypes) {
+ function checkType(isRequired, props, propName, componentName, location?) {
+ if (!props[propName]) {
+ if (isRequired) {
+ invariant(
+ false,
+ `Required object \`${propName}\` was not specified in ` +
+ `\`${componentName}\`.`
+ )
+ }
+ return
+ }
+ const propValue = props[propName]
+ const propType = typeof propValue
+ const locationName = location && ReactPropTypeLocationNames[location] || '(unknown)'
+ if (propType !== 'object') {
+ invariant(
+ false,
+ `Invalid ${locationName} \`${propName}\` of type \`${propType}\` ` +
+ `supplied to \`${componentName}\`, expected \`object\`.`
+ )
+ }
+ // We need to check all keys in case some are required but missing from
+ // props.
+ const allKeys = { ...props[propName], ...shapeTypes }
+ for (const key in allKeys) {
+ const checker = shapeTypes[key]
+ if (!checker) {
+ invariant(
+ false,
+ `Invalid props.${propName} key \`${key}\` supplied to \`${componentName}\`.` +
+ `\nBad object: ` + JSON.stringify(props[propName], null, ' ') +
+ `\nValid keys: ` + JSON.stringify(Object.keys(shapeTypes), null, ' ')
+ )
+ }
+ const error = checker(propValue, key, componentName, location)
+ if (error) {
+ invariant(
+ false,
+ error.message + `\nBad object: ` + JSON.stringify(props[propName], null, ' ')
+ )
+ }
+ }
+ }
+
+ function chainedCheckType(
+ props: {[key: string]: any},
+ propName: string,
+ componentName: string,
+ location?: string
+ ): ?Error {
+ return checkType(false, props, propName, componentName, location)
+ }
+ chainedCheckType.isRequired = checkType.bind(null, true)
+ return chainedCheckType
+}
diff --git a/src/apis/StyleSheet/expandStyle.js b/src/apis/StyleSheet/expandStyle.js
index 31b2c6c6..6937dece 100644
--- a/src/apis/StyleSheet/expandStyle.js
+++ b/src/apis/StyleSheet/expandStyle.js
@@ -1,3 +1,5 @@
+import normalizeValue from './normalizeValue'
+
const styleShortHands = {
borderColor: [ 'borderTopColor', 'borderRightColor', 'borderBottomColor', 'borderLeftColor' ],
borderRadius: [ 'borderTopLeftRadius', 'borderTopRightRadius', 'borderBottomRightRadius', 'borderBottomLeftRadius' ],
@@ -37,7 +39,8 @@ const expandStyle = (style) => {
return sortedProps.reduce((resolvedStyle, key) => {
const expandedProps = styleShortHands[key]
- const value = style[key]
+ const value = normalizeValue(key, style[key])
+
if (expandedProps) {
expandedProps.forEach((prop, i) => {
resolvedStyle[expandedProps[i]] = value
diff --git a/src/apis/StyleSheet/flattenStyle.js b/src/apis/StyleSheet/flattenStyle.js
new file mode 100644
index 00000000..82fe814b
--- /dev/null
+++ b/src/apis/StyleSheet/flattenStyle.js
@@ -0,0 +1,34 @@
+/**
+ * Copyright (c) 2016-present, Nicolas Gallagher.
+ * Copyright (c) 2015-present, Facebook, Inc.
+ * All rights reserved.
+ *
+ * @flow
+ */
+import invariant from 'invariant'
+import expandStyle from './expandStyle'
+
+export default function flattenStyle(style): ?Object {
+ if (!style) {
+ return undefined
+ }
+
+ invariant(style !== true, 'style may be false but not true')
+
+ if (!Array.isArray(style)) {
+ // we must expand styles during the flattening because expanded styles
+ // override shorthands
+ return expandStyle(style)
+ }
+
+ const result = {}
+ for (let i = 0; i < style.length; ++i) {
+ const computedStyle = flattenStyle(style[i])
+ if (computedStyle) {
+ for (const key in computedStyle) {
+ result[key] = computedStyle[key]
+ }
+ }
+ }
+ return result
+}
diff --git a/src/apis/StyleSheet/getStyleObjects.js b/src/apis/StyleSheet/getStyleObjects.js
deleted file mode 100644
index ebec0aba..00000000
--- a/src/apis/StyleSheet/getStyleObjects.js
+++ /dev/null
@@ -1,22 +0,0 @@
-import isObject from './isObject'
-import isStyleObject from './isStyleObject'
-
-/**
- * Recursively check for objects that are style rules.
- */
-const getStyleObjects = (styles: Object): Array => {
- const keys = Object.keys(styles)
- return keys.reduce((rules, key) => {
- const possibleRule = styles[key]
- if (isObject(possibleRule)) {
- if (isStyleObject(possibleRule)) {
- rules.push(possibleRule)
- } else {
- rules = rules.concat(getStyleObjects(possibleRule))
- }
- }
- return rules
- }, [])
-}
-
-export default getStyleObjects
diff --git a/src/apis/StyleSheet/index.js b/src/apis/StyleSheet/index.js
index 1507d7fd..a39f0f7a 100644
--- a/src/apis/StyleSheet/index.js
+++ b/src/apis/StyleSheet/index.js
@@ -1,9 +1,12 @@
import { resetCSS, predefinedCSS, predefinedClassNames } from './predefs'
-import expandStyle from './expandStyle'
-import getStyleObjects from './getStyleObjects'
-import prefixer from './prefixer'
+import flattenStyle from './flattenStyle'
import Store from './Store'
-import StylePropTypes from './StylePropTypes'
+import StyleSheetRegistry from './StyleSheetRegistry'
+import StyleSheetValidation from './StyleSheetValidation'
+
+const ELEMENT_ID = 'react-stylesheet'
+let isRendered = false
+let lastStyleSheet = ''
/**
* Initialize the store with pointer-event styles mapping to our custom pointer
@@ -13,7 +16,6 @@ const initialState = { classNames: predefinedClassNames }
const options = { obfuscateClassNames: !(process.env.NODE_ENV !== 'production') }
const createStore = () => new Store(initialState, options)
let store = createStore()
-let isRendered = false
/**
* Destroy existing styles
@@ -32,51 +34,26 @@ const _renderToString = () => {
return `${resetCSS}\n${predefinedCSS}\n${css}`
}
-/**
- * Process all unique declarations
- */
const create = (styles: Object): Object => {
- const rules = getStyleObjects(styles)
-
- rules.forEach((rule) => {
- const style = expandStyle(rule)
-
- Object.keys(style).forEach((property) => {
- if (!StylePropTypes[property]) {
- console.error(`ReactNativeWeb: the style property "${property}" is not supported`)
- } else {
- const value = style[property]
- // add each declaration to the store
- store.set(property, value)
- }
- })
- })
+ for (const key in styles) {
+ StyleSheetValidation.validateStyle(key, styles)
+ StyleSheetRegistry.registerStyle(styles[key], store)
+ }
// update the style sheet in place
if (isRendered) {
- const stylesheet = document.getElementById('react-stylesheet')
+ const stylesheet = document.getElementById(ELEMENT_ID)
if (stylesheet) {
- stylesheet.textContent = _renderToString()
+ const newStyleSheet = _renderToString()
+ if (lastStyleSheet !== newStyleSheet) {
+ stylesheet.textContent = newStyleSheet
+ lastStyleSheet = newStyleSheet
+ }
} else if (process.env.NODE_ENV !== 'production') {
console.error('ReactNative: cannot find "react-stylesheet" element')
}
}
- if (process.env.NODE_ENV !== 'production') {
- const deepFreeze = (obj) => {
- const propNames = Object.getOwnPropertyNames(obj)
- propNames.forEach((name) => {
- const prop = obj[name]
- if (typeof prop === 'object' && prop !== null && !Object.isFrozen(prop)) {
- deepFreeze(prop)
- }
- })
- return Object.freeze(obj)
- }
-
- deepFreeze(styles)
- }
-
return styles
}
@@ -84,34 +61,15 @@ const create = (styles: Object): Object => {
* Accepts React props and converts inline styles to single purpose classes
* where possible.
*/
-const resolve = ({ className = '', style = {} }) => {
- let _className
- let _style = {}
- const expandedStyle = expandStyle(style)
-
- const classList = [ className ]
- for (const prop in expandedStyle) {
- if (!StylePropTypes[prop]) {
- continue
- }
- let styleClass = store.get(prop, expandedStyle[prop])
-
- if (styleClass) {
- classList.push(styleClass)
- } else {
- _style[prop] = expandedStyle[prop]
- }
- }
-
- _className = classList.join(' ')
- _style = prefixer.prefix(_style)
-
- return { className: _className, style: _style }
+const resolve = ({ style = {} }) => {
+ return StyleSheetRegistry.getStyleAsNativeProps(style, store)
}
export default {
_destroy,
_renderToString,
create,
+ elementId: ELEMENT_ID,
+ flatten: flattenStyle,
resolve
}
diff --git a/src/apis/StyleSheet/isObject.js b/src/apis/StyleSheet/isObject.js
deleted file mode 100644
index 056792fd..00000000
--- a/src/apis/StyleSheet/isObject.js
+++ /dev/null
@@ -1,5 +0,0 @@
-const isObject = (obj) => {
- return Object.prototype.toString.call(obj) === '[object Object]'
-}
-
-export default isObject
diff --git a/src/apis/StyleSheet/isStyleObject.js b/src/apis/StyleSheet/isStyleObject.js
deleted file mode 100644
index 96341815..00000000
--- a/src/apis/StyleSheet/isStyleObject.js
+++ /dev/null
@@ -1,11 +0,0 @@
-import isObject from './isObject'
-
-const isStyleObject = (obj) => {
- const values = Object.keys(obj).map((key) => obj[key])
- for (let i = 0; i < values.length; i += 1) {
- if (isObject(values[i])) { return false }
- }
- return true
-}
-
-export default isStyleObject
diff --git a/src/apis/StyleSheet/normalizeValue.js b/src/apis/StyleSheet/normalizeValue.js
index c91e9698..31f2e2ae 100644
--- a/src/apis/StyleSheet/normalizeValue.js
+++ b/src/apis/StyleSheet/normalizeValue.js
@@ -23,11 +23,11 @@ const unitlessNumbers = {
strokeWidth: true
}
-const normalizeValues = (property, value) => {
+const normalizeValue = (property, value) => {
if (!unitlessNumbers[property] && typeof value === 'number') {
value = `${value}px`
}
return value
}
-export default normalizeValues
+export default normalizeValue
diff --git a/src/components/ActivityIndicator/index.js b/src/components/ActivityIndicator/index.js
index a9c16e5b..a26c5215 100644
--- a/src/components/ActivityIndicator/index.js
+++ b/src/components/ActivityIndicator/index.js
@@ -24,7 +24,7 @@ export default class ActivityIndicator extends Component {
color: PropTypes.string,
hidesWhenStopped: PropTypes.bool,
size: PropTypes.oneOf(['small', 'large']),
- style: PropTypes.object
+ style: View.propTypes.style
};
static defaultProps = {
@@ -65,25 +65,20 @@ export default class ActivityIndicator extends Component {
} = this.props
return (
-
+
{ this._indicatorRef = c }}
- style={{
- ...styles.indicator[size],
- ...(hidesWhenStopped && !animating && styles.hidesWhenStopped),
- borderColor: color
- }}
+ style={[
+ indicatorStyles[size],
+ hidesWhenStopped && !animating && styles.hidesWhenStopped,
+ { borderColor: color }
+ ]}
/>
)
}
}
-const indicatorStyle = StyleSheet.create({
- borderRadius: 100,
- borderWidth: 3
-})
-
const styles = StyleSheet.create({
container: {
alignItems: 'center',
@@ -91,18 +86,20 @@ const styles = StyleSheet.create({
},
hidesWhenStopped: {
visibility: 'hidden'
- },
- indicator: {
- small: {
- ...indicatorStyle,
- width: 20,
- height: 20
- },
- large: {
- ...indicatorStyle,
- borderWidth: 4,
- width: 36,
- height: 36
- }
+ }
+})
+
+const indicatorStyles = StyleSheet.create({
+ small: {
+ borderRadius: 100,
+ borderWidth: 3,
+ width: 20,
+ height: 20
+ },
+ large: {
+ borderRadius: 100,
+ borderWidth: 4,
+ width: 36,
+ height: 36
}
})
diff --git a/src/components/CoreComponent/index.js b/src/components/CoreComponent/index.js
index e786d00a..323bc163 100644
--- a/src/components/CoreComponent/index.js
+++ b/src/components/CoreComponent/index.js
@@ -1,5 +1,4 @@
import React, { Component, PropTypes } from 'react'
-import StylePropTypes from '../../apis/StyleSheet/StylePropTypes'
import StyleSheet from '../../apis/StyleSheet'
const roleComponents = {
@@ -24,9 +23,8 @@ export default class CoreComponent extends Component {
accessibilityLiveRegion: PropTypes.oneOf([ 'assertive', 'off', 'polite' ]),
accessibilityRole: PropTypes.string,
accessible: PropTypes.bool,
- className: PropTypes.string,
component: PropTypes.oneOfType([ PropTypes.func, PropTypes.string ]),
- style: PropTypes.object,
+ style: PropTypes.oneOfType([ PropTypes.array, PropTypes.object ]),
testID: PropTypes.string,
type: PropTypes.string
};
@@ -36,8 +34,6 @@ export default class CoreComponent extends Component {
component: 'div'
};
- static stylePropTypes = StylePropTypes;
-
render() {
const {
accessibilityLabel,
diff --git a/src/components/Image/ImageStylePropTypes.js b/src/components/Image/ImageStylePropTypes.js
index 699761fa..79aedfb2 100644
--- a/src/components/Image/ImageStylePropTypes.js
+++ b/src/components/Image/ImageStylePropTypes.js
@@ -1,4 +1,23 @@
-import View from '../View'
+import { PropTypes } from 'react'
+import ColorPropType from '../../apis/StyleSheet/ColorPropType'
+import LayoutPropTypes from '../../apis/StyleSheet/LayoutPropTypes'
+import TransformPropTypes from '../../apis/StyleSheet/TransformPropTypes'
+
+const hiddenOrVisible = PropTypes.oneOf([ 'hidden', 'visible' ])
+
export default {
- ...(View.stylePropTypes)
+ ...LayoutPropTypes,
+ ...TransformPropTypes,
+ backfaceVisibility: hiddenOrVisible,
+ backgroundColor: ColorPropType,
+ /**
+ * @platform web
+ */
+ boxShadow: PropTypes.string,
+ opacity: PropTypes.number,
+ overflow: hiddenOrVisible,
+ /**
+ * @platform web
+ */
+ visibility: hiddenOrVisible
}
diff --git a/src/components/Image/__tests__/index-test.js b/src/components/Image/__tests__/index-test.js
index 6c388d36..63789762 100644
--- a/src/components/Image/__tests__/index-test.js
+++ b/src/components/Image/__tests__/index-test.js
@@ -65,10 +65,6 @@ suite('components/Image', () => {
test('prop "source"')
- test('prop "style"', () => {
- utils.assertProps.style(Image)
- })
-
test('prop "testID"', () => {
const testID = 'testID'
const result = utils.shallowRender()
diff --git a/src/components/Image/index.js b/src/components/Image/index.js
index 975e1369..463c540a 100644
--- a/src/components/Image/index.js
+++ b/src/components/Image/index.js
@@ -1,9 +1,9 @@
/* global window */
-import { pickProps } from '../../modules/filterObjectProps'
import StyleSheet from '../../apis/StyleSheet'
import CoreComponent from '../CoreComponent'
import ImageStylePropTypes from './ImageStylePropTypes'
import React, { Component, PropTypes } from 'react'
+import StyleSheetPropType from '../../apis/StyleSheet/StyleSheetPropType'
import View from '../View'
const STATUS_ERRORED = 'ERRORED'
@@ -12,46 +12,6 @@ const STATUS_LOADING = 'LOADING'
const STATUS_PENDING = 'PENDING'
const STATUS_IDLE = 'IDLE'
-const imageStyleKeys = Object.keys(ImageStylePropTypes)
-
-const styles = StyleSheet.create({
- initial: {
- alignSelf: 'flex-start',
- backgroundColor: 'transparent',
- backgroundPosition: 'center',
- backgroundRepeat: 'no-repeat',
- backgroundSize: 'cover'
- },
- img: {
- borderWidth: 0,
- height: 'auto',
- maxHeight: '100%',
- maxWidth: '100%',
- opacity: 0
- },
- children: {
- bottom: 0,
- left: 0,
- position: 'absolute',
- right: 0,
- top: 0
- },
- resizeMode: {
- contain: {
- backgroundSize: 'contain'
- },
- cover: {
- backgroundSize: 'cover'
- },
- none: {
- backgroundSize: 'auto'
- },
- stretch: {
- backgroundSize: '100% 100%'
- }
- }
-})
-
export default class Image extends Component {
constructor(props, context) {
super(props, context)
@@ -74,18 +34,15 @@ export default class Image extends Component {
onLoadStart: PropTypes.func,
resizeMode: PropTypes.oneOf(['contain', 'cover', 'none', 'stretch']),
source: PropTypes.object,
- style: PropTypes.shape(ImageStylePropTypes),
+ style: StyleSheetPropType(ImageStylePropTypes),
testID: CoreComponent.propTypes.testID
};
- static stylePropTypes = ImageStylePropTypes;
-
static defaultProps = {
accessible: true,
defaultSource: {},
resizeMode: 'cover',
- source: {},
- style: styles.initial
+ source: {}
};
_createImageLoader() {
@@ -177,7 +134,6 @@ export default class Image extends Component {
const isLoaded = this.state.status === STATUS_LOADED
const defaultImage = defaultSource.uri || null
const displayImage = !isLoaded ? defaultImage : source.uri
- const resolvedStyle = pickProps(style, imageStyleKeys)
const backgroundImage = displayImage ? `url("${displayImage}")` : null
/**
@@ -189,16 +145,15 @@ export default class Image extends Component {
*/
return (
@@ -209,3 +164,42 @@ export default class Image extends Component {
)
}
}
+
+const styles = StyleSheet.create({
+ initial: {
+ alignSelf: 'flex-start',
+ backgroundColor: 'transparent',
+ backgroundPosition: 'center',
+ backgroundRepeat: 'no-repeat',
+ backgroundSize: 'cover'
+ },
+ img: {
+ borderWidth: 0,
+ height: 'auto',
+ maxHeight: '100%',
+ maxWidth: '100%',
+ opacity: 0
+ },
+ children: {
+ bottom: 0,
+ left: 0,
+ position: 'absolute',
+ right: 0,
+ top: 0
+ }
+})
+
+const resizeModeStyles = StyleSheet.create({
+ contain: {
+ backgroundSize: 'contain'
+ },
+ cover: {
+ backgroundSize: 'cover'
+ },
+ none: {
+ backgroundSize: 'auto'
+ },
+ stretch: {
+ backgroundSize: '100% 100%'
+ }
+})
diff --git a/src/components/ListView/index.js b/src/components/ListView/index.js
index 841c66e9..01896c75 100644
--- a/src/components/ListView/index.js
+++ b/src/components/ListView/index.js
@@ -4,7 +4,7 @@ import ScrollView from '../ScrollView'
export default class ListView extends Component {
static propTypes = {
children: PropTypes.any,
- style: PropTypes.style
+ style: ScrollView.propTypes.style
};
static defaultProps = {
diff --git a/src/components/ScrollView/ScrollViewStylePropTypes.js b/src/components/ScrollView/ScrollViewStylePropTypes.js
deleted file mode 100644
index 699761fa..00000000
--- a/src/components/ScrollView/ScrollViewStylePropTypes.js
+++ /dev/null
@@ -1,4 +0,0 @@
-import View from '../View'
-export default {
- ...(View.stylePropTypes)
-}
diff --git a/src/components/ScrollView/__tests__/index-test.js b/src/components/ScrollView/__tests__/index-test.js
index 5f162ce2..c6c9bc72 100644
--- a/src/components/ScrollView/__tests__/index-test.js
+++ b/src/components/ScrollView/__tests__/index-test.js
@@ -1,11 +1,5 @@
/* eslint-env mocha */
-import * as utils from '../../../modules/specHelpers'
-
-import ScrollView from '../'
-
suite('components/ScrollView', () => {
- test('prop "style"', () => {
- utils.assertProps.style(ScrollView)
- })
+ test('NO TEST COVERAGE')
})
diff --git a/src/components/ScrollView/index.js b/src/components/ScrollView/index.js
index dde78b45..4c9fef3a 100644
--- a/src/components/ScrollView/index.js
+++ b/src/components/ScrollView/index.js
@@ -1,21 +1,15 @@
-import { pickProps } from '../../modules/filterObjectProps'
import debounce from 'lodash.debounce'
import React, { Component, PropTypes } from 'react'
-import ScrollViewStylePropTypes from './ScrollViewStylePropTypes'
import StyleSheet from '../../apis/StyleSheet'
import View from '../View'
-const scrollViewStyleKeys = Object.keys(ScrollViewStylePropTypes)
-
const styles = StyleSheet.create({
initial: {
- flexGrow: 1,
- flexShrink: 1,
+ flex: 1,
overflow: 'auto'
},
initialContentContainer: {
- flexGrow: 1,
- flexShrink: 1
+ flex: 1
},
row: {
flexDirection: 'row'
@@ -25,20 +19,20 @@ const styles = StyleSheet.create({
export default class ScrollView extends Component {
static propTypes = {
children: PropTypes.any,
- contentContainerStyle: PropTypes.shape(ScrollViewStylePropTypes),
+ contentContainerStyle: View.propTypes.style,
horizontal: PropTypes.bool,
onScroll: PropTypes.func,
scrollEnabled: PropTypes.bool,
scrollEventThrottle: PropTypes.number,
- style: PropTypes.shape(ScrollViewStylePropTypes)
+ style: View.propTypes.style
};
static defaultProps = {
- contentContainerStyle: styles.initialContentContainer,
+ contentContainerStyle: {},
horizontal: false,
scrollEnabled: true,
scrollEventThrottle: 0,
- style: styles.initial
+ style: {}
};
constructor(...args) {
@@ -108,28 +102,25 @@ export default class ScrollView extends Component {
style
} = this.props
- const resolvedStyle = pickProps(style, scrollViewStyleKeys)
- const resolvedContentContainerStyle = pickProps(contentContainerStyle, scrollViewStyleKeys)
-
return (
this._onScroll(e)}
onTouchMove={(e) => this._maybePreventScroll(e)}
onWheel={(e) => this._maybePreventScroll(e)}
- style={{
- ...styles.initial,
- ...resolvedStyle
- }}
+ style={[
+ styles.initial,
+ style
+ ]}
>
{children ? (
) : null}
diff --git a/src/components/Text/TextStylePropTypes.js b/src/components/Text/TextStylePropTypes.js
index 9751dabc..afd3a27a 100644
--- a/src/components/Text/TextStylePropTypes.js
+++ b/src/components/Text/TextStylePropTypes.js
@@ -1,23 +1,28 @@
-import { pickProps } from '../../modules/filterObjectProps'
-import CoreComponent from '../CoreComponent'
-import View from '../View'
+import { PropTypes } from 'react'
+import ColorPropType from '../../apis/StyleSheet/ColorPropType'
+import ViewStylePropTypes from '../View/ViewStylePropTypes'
+
+const { number, oneOf, oneOfType, string } = PropTypes
+const numberOrString = oneOfType([ number, string ])
export default {
- ...View.stylePropTypes,
- ...pickProps(CoreComponent.stylePropTypes, [
- 'color',
- 'fontFamily',
- 'fontSize',
- 'fontStyle',
- 'fontWeight',
- 'letterSpacing',
- 'lineHeight',
- 'textAlign',
- 'textDecoration',
- 'textShadow',
- 'textTransform',
- 'whiteSpace',
- 'wordWrap',
- 'writingDirection'
- ])
+ ...ViewStylePropTypes,
+ color: ColorPropType,
+ fontFamily: string,
+ fontSize: numberOrString,
+ fontStyle: string,
+ fontWeight: string,
+ letterSpacing: numberOrString,
+ lineHeight: numberOrString,
+ textAlign: oneOf([ 'center', 'inherit', 'justify', 'justify-all', 'left', 'right' ]),
+ /**
+ * @platform web
+ */
+ textDecoration: string,
+ textOverflow: string,
+ textShadow: string,
+ textTransform: oneOf([ 'capitalize', 'lowercase', 'none', 'uppercase' ]),
+ whiteSpace: string,
+ wordWrap: string,
+ writingDirection: string
}
diff --git a/src/components/Text/__tests__/index-test.js b/src/components/Text/__tests__/index-test.js
index a816641c..b455af05 100644
--- a/src/components/Text/__tests__/index-test.js
+++ b/src/components/Text/__tests__/index-test.js
@@ -43,10 +43,6 @@ suite('components/Text', () => {
}
})
- test('prop "style"', () => {
- utils.assertProps.style(Text)
- })
-
test('prop "testID"', () => {
const testID = 'testID'
const result = utils.shallowRender()
diff --git a/src/components/Text/index.js b/src/components/Text/index.js
index 15e0965f..f1189fa3 100644
--- a/src/components/Text/index.js
+++ b/src/components/Text/index.js
@@ -1,11 +1,9 @@
-import { pickProps } from '../../modules/filterObjectProps'
import CoreComponent from '../CoreComponent'
import React, { Component, PropTypes } from 'react'
import StyleSheet from '../../apis/StyleSheet'
+import StyleSheetPropType from '../../apis/StyleSheet/StyleSheetPropType'
import TextStylePropTypes from './TextStylePropTypes'
-const textStyleKeys = Object.keys(TextStylePropTypes)
-
const styles = StyleSheet.create({
initial: {
color: 'inherit',
@@ -26,23 +24,18 @@ const styles = StyleSheet.create({
export default class Text extends Component {
static propTypes = {
- _className: PropTypes.string, // escape-hatch for code migrations
accessibilityLabel: CoreComponent.propTypes.accessibilityLabel,
accessibilityRole: CoreComponent.propTypes.accessibilityRole,
accessible: CoreComponent.propTypes.accessible,
children: PropTypes.any,
numberOfLines: PropTypes.number,
onPress: PropTypes.func,
- style: PropTypes.shape(TextStylePropTypes),
+ style: StyleSheetPropType(TextStylePropTypes),
testID: CoreComponent.propTypes.testID
};
- static stylePropTypes = TextStylePropTypes;
-
static defaultProps = {
- _className: '',
- accessible: true,
- style: styles.initial
+ accessible: true
};
_onPress(e) {
@@ -51,27 +44,22 @@ export default class Text extends Component {
render() {
const {
- _className,
numberOfLines,
onPress,
style,
...other
} = this.props
- const className = `${_className} Text`.trim()
- const resolvedStyle = pickProps(style, textStyleKeys)
-
return (
)
}
diff --git a/src/components/TextInput/TextInputStylePropTypes.js b/src/components/TextInput/TextInputStylePropTypes.js
deleted file mode 100644
index e36cd937..00000000
--- a/src/components/TextInput/TextInputStylePropTypes.js
+++ /dev/null
@@ -1,7 +0,0 @@
-import React from 'react'
-import Text from '../Text'
-
-export default {
- ...Text.stylePropTypes,
- outline: React.PropTypes.string
-}
diff --git a/src/components/TextInput/__tests__/index-test.js b/src/components/TextInput/__tests__/index-test.js
index bf5f65a6..63f37012 100644
--- a/src/components/TextInput/__tests__/index-test.js
+++ b/src/components/TextInput/__tests__/index-test.js
@@ -4,6 +4,7 @@ import * as utils from '../../../modules/specHelpers'
import assert from 'assert'
import React from 'react'
import ReactTestUtils from 'react-addons-test-utils'
+import StyleSheet from '../../../apis/StyleSheet'
import TextInput from '../'
@@ -192,10 +193,10 @@ suite('components/TextInput', () => {
const placeholder = 'placeholder'
let result = findShallowPlaceholder(utils.shallowRender())
- assert.equal(result.props.style.color, 'darkgray')
+ assert.equal(StyleSheet.flatten(result.props.style).color, 'darkgray')
result = findShallowPlaceholder(utils.shallowRender())
- assert.equal(result.props.style.color, 'red')
+ assert.equal(StyleSheet.flatten(result.props.style).color, 'red')
})
test('prop "secureTextEntry"', () => {
@@ -220,10 +221,6 @@ suite('components/TextInput', () => {
assert.equal(input.selectionStart, 0)
})
- test('prop "style"', () => {
- utils.assertProps.style(TextInput)
- })
-
test('prop "testID"', () => {
const testID = 'testID'
const result = utils.shallowRender()
diff --git a/src/components/TextInput/index.js b/src/components/TextInput/index.js
index 9492f82d..5f9737e7 100644
--- a/src/components/TextInput/index.js
+++ b/src/components/TextInput/index.js
@@ -1,44 +1,11 @@
-import { pickProps } from '../../modules/filterObjectProps'
import CoreComponent from '../CoreComponent'
import React, { Component, PropTypes } from 'react'
import ReactDOM from 'react-dom'
import StyleSheet from '../../apis/StyleSheet'
import Text from '../Text'
import TextareaAutosize from 'react-textarea-autosize'
-import TextInputStylePropTypes from './TextInputStylePropTypes'
import View from '../View'
-const textInputStyleKeys = Object.keys(TextInputStylePropTypes)
-
-const styles = StyleSheet.create({
- initial: {
- ...View.defaultProps.style,
- borderColor: 'black',
- borderWidth: 1
- },
- input: {
- appearance: 'none',
- backgroundColor: 'transparent',
- borderWidth: 0,
- boxSizing: 'border-box',
- color: 'inherit',
- flexGrow: 1,
- font: 'inherit',
- padding: 0,
- zIndex: 1
- },
- placeholder: {
- bottom: 0,
- color: 'darkgray',
- left: 0,
- overflow: 'hidden',
- position: 'absolute',
- right: 0,
- top: 0,
- whiteSpace: 'pre'
- }
-})
-
export default class TextInput extends Component {
constructor(props, context) {
super(props, context)
@@ -66,20 +33,18 @@ export default class TextInput extends Component {
placeholderTextColor: PropTypes.string,
secureTextEntry: PropTypes.bool,
selectTextOnFocus: PropTypes.bool,
- style: PropTypes.shape(TextInputStylePropTypes),
+ style: Text.propTypes.style,
testID: CoreComponent.propTypes.testID,
value: PropTypes.string
};
- static stylePropTypes = TextInputStylePropTypes;
-
static defaultProps = {
editable: true,
keyboardType: 'default',
multiline: false,
numberOfLines: 2,
secureTextEntry: false,
- style: styles.initial
+ style: {}
};
_onBlur(e) {
@@ -142,7 +107,6 @@ export default class TextInput extends Component {
value
} = this.props
- const resolvedStyle = pickProps(style, textInputStyleKeys)
let type
switch (keyboardType) {
@@ -198,26 +162,56 @@ export default class TextInput extends Component {
const props = multiline ? propsMultiline : propsSingleline
return (
-
-
+
{placeholder && this.state.showPlaceholder && {placeholder}}
-
+
)
}
}
+
+const styles = StyleSheet.create({
+ initial: {
+ borderColor: 'black',
+ borderWidth: 1
+ },
+ wrapper: {
+ flexGrow: 1
+ },
+ input: {
+ appearance: 'none',
+ backgroundColor: 'transparent',
+ borderWidth: 0,
+ boxSizing: 'border-box',
+ color: 'inherit',
+ flexGrow: 1,
+ font: 'inherit',
+ padding: 0,
+ zIndex: 1
+ },
+ placeholder: {
+ bottom: 0,
+ color: 'darkgray',
+ left: 0,
+ overflow: 'hidden',
+ position: 'absolute',
+ right: 0,
+ top: 0,
+ whiteSpace: 'pre'
+ }
+})
diff --git a/src/components/Touchable/__tests__/index-test.js b/src/components/Touchable/__tests__/index-test.js
index 634b50a9..1c4e489f 100644
--- a/src/components/Touchable/__tests__/index-test.js
+++ b/src/components/Touchable/__tests__/index-test.js
@@ -30,6 +30,6 @@ suite('components/Touchable', () => {
test('prop "children"', () => {
const result = utils.shallowRender()
- assert.deepEqual(result.props.children, children)
+ assert.deepEqual(result.props.children, children)
})
})
diff --git a/src/components/Touchable/index.js b/src/components/Touchable/index.js
index 438e8d7e..8f68fa27 100644
--- a/src/components/Touchable/index.js
+++ b/src/components/Touchable/index.js
@@ -1,15 +1,7 @@
import React, { Component, PropTypes } from 'react'
+import StyleSheet from '../../apis/StyleSheet'
import Tappable from 'react-tappable'
import View from '../View'
-import StyleSheet from '../../apis/StyleSheet'
-
-const styles = StyleSheet.create({
- initial: {
- ...View.defaultProps.style,
- cursor: 'pointer',
- userSelect: undefined
- }
-})
export default class Touchable extends Component {
constructor(props, context) {
@@ -48,16 +40,16 @@ export default class Touchable extends Component {
delayLongPress: 500,
delayPressIn: 0,
delayPressOut: 100,
- style: styles.initial
+ style: {}
};
_getChildren() {
const { activeOpacity, children } = this.props
return React.cloneElement(React.Children.only(children), {
- style: {
- ...children.props.style,
- ...(this.state.isActive && { opacity: activeOpacity })
- }
+ style: [
+ children.props.style,
+ this.state.isActive && { opacity: activeOpacity }
+ ]
})
}
@@ -97,7 +89,7 @@ export default class Touchable extends Component {
} = this.props
/**
- * Creates a wrapping element that can receive beyboard focus. The
+ * Creates a wrapping element that can receive keyboard focus. The
* highlight is applied as a background color on this wrapper. The opacity
* is set on the child element, allowing it to have its own background
* color.
@@ -120,13 +112,20 @@ export default class Touchable extends Component {
onTouchStart={this._onPressIn}
pressDelay={delayLongPress}
pressMoveThreshold={5}
- style={{
- ...styles.initial,
- ...style,
- backgroundColor: this.state.isActive ? activeUnderlayColor : style.backgroundColor
- }}
+ style={StyleSheet.flatten([
+ styles.initial,
+ style,
+ activeUnderlayColor && this.state.isActive && { backgroundColor: activeUnderlayColor }
+ ])}
tabIndex='0'
/>
)
}
}
+
+const styles = StyleSheet.create({
+ initial: {
+ cursor: 'pointer',
+ userSelect: undefined
+ }
+})
diff --git a/src/components/View/ViewStylePropTypes.js b/src/components/View/ViewStylePropTypes.js
index c1b07e6d..22400739 100644
--- a/src/components/View/ViewStylePropTypes.js
+++ b/src/components/View/ViewStylePropTypes.js
@@ -1,91 +1,37 @@
-import { pickProps } from '../../modules/filterObjectProps'
-import CoreComponent from '../CoreComponent'
+import { PropTypes } from 'react'
+import BorderPropTypes from '../../apis/StyleSheet/BorderPropTypes'
+import ColorPropType from '../../apis/StyleSheet/ColorPropType'
+import LayoutPropTypes from '../../apis/StyleSheet/LayoutPropTypes'
+import TransformPropTypes from '../../apis/StyleSheet/TransformPropTypes'
+
+const { number, oneOf, string } = PropTypes
+const autoOrHiddenOrVisible = oneOf([ 'auto', 'hidden', 'visible' ])
+const hiddenOrVisible = oneOf([ 'hidden', 'visible' ])
export default {
- ...pickProps(CoreComponent.stylePropTypes, [
- 'alignContent',
- 'alignItems',
- 'alignSelf',
- 'backfaceVisibility',
- // background
- 'backgroundAttachment',
- 'backgroundClip',
- 'backgroundColor',
- 'backgroundImage',
- 'backgroundPosition',
- 'backgroundOrigin',
- 'backgroundRepeat',
- 'backgroundSize',
- // border-color
- 'borderColor',
- 'borderTopColor',
- 'borderRightColor',
- 'borderBottomColor',
- 'borderLeftColor',
- // border-radius
- 'borderRadius',
- 'borderTopLeftRadius',
- 'borderTopRightRadius',
- 'borderBottomLeftRadius',
- 'borderBottomRightRadius',
- // border style
- 'borderStyle',
- 'borderBottomStyle',
- 'borderLeftStyle',
- 'borderRightStyle',
- 'borderTopStyle',
- // border width
- 'borderWidth',
- 'borderBottomWidth',
- 'borderLeftWidth',
- 'borderRightWidth',
- 'borderTopWidth',
- 'bottom',
- 'boxShadow',
- 'boxSizing',
- 'cursor',
- 'flex',
- 'flexBasis',
- 'flexDirection',
- 'flexGrow',
- 'flexShrink',
- 'flexWrap',
- 'height',
- 'justifyContent',
- 'left',
- // margin
- 'margin',
- 'marginHorizontal',
- 'marginVertical',
- 'marginBottom',
- 'marginLeft',
- 'marginRight',
- 'marginTop',
- // max/min
- 'maxHeight',
- 'maxWidth',
- 'minHeight',
- 'minWidth',
- 'opacity',
- 'order',
- 'overflow',
- 'overflowX',
- 'overflowY',
- // padding
- 'padding',
- 'paddingHorizontal',
- 'paddingVertical',
- 'paddingBottom',
- 'paddingLeft',
- 'paddingRight',
- 'paddingTop',
- 'position',
- 'right',
- 'top',
- 'transform',
- 'userSelect',
- 'visibility',
- 'width',
- 'zIndex'
- ])
+ ...BorderPropTypes,
+ ...LayoutPropTypes,
+ ...TransformPropTypes,
+ backfaceVisibility: hiddenOrVisible,
+ backgroundColor: ColorPropType,
+ opacity: number,
+ overflow: autoOrHiddenOrVisible,
+ /*
+ * @platform web
+ */
+ backgroundAttachment: string,
+ backgroundClip: string,
+ backgroundImage: string,
+ backgroundPosition: string,
+ backgroundOrigin: oneOf([ 'border-box', 'content-box', 'padding-box' ]),
+ backgroundRepeat: string,
+ backgroundSize: string,
+ boxShadow: string,
+ cursor: string,
+ outline: string,
+ overflowX: autoOrHiddenOrVisible,
+ overflowY: autoOrHiddenOrVisible,
+ userSelect: string,
+ visibility: hiddenOrVisible,
+ zIndex: number
}
diff --git a/src/components/View/__tests__/index-test.js b/src/components/View/__tests__/index-test.js
index 3c199776..a30fb45b 100644
--- a/src/components/View/__tests__/index-test.js
+++ b/src/components/View/__tests__/index-test.js
@@ -3,6 +3,7 @@
import * as utils from '../../../modules/specHelpers'
import assert from 'assert'
import React from 'react'
+import StyleSheet from '../../../apis/StyleSheet'
import View from '../'
@@ -39,11 +40,7 @@ suite('components/View', () => {
test('prop "pointerEvents"', () => {
const result = utils.shallowRender()
- assert.equal(result.props.style.pointerEvents, 'box-only')
- })
-
- test('prop "style"', () => {
- utils.assertProps.style(View)
+ assert.equal(StyleSheet.flatten(result.props.style).pointerEvents, 'box-only')
})
test('prop "testID"', () => {
diff --git a/src/components/View/index.js b/src/components/View/index.js
index cb482a3c..939ddf91 100644
--- a/src/components/View/index.js
+++ b/src/components/View/index.js
@@ -1,10 +1,46 @@
-import { pickProps } from '../../modules/filterObjectProps'
import CoreComponent from '../CoreComponent'
import React, { Component, PropTypes } from 'react'
import StyleSheet from '../../apis/StyleSheet'
+import StyleSheetPropType from '../../apis/StyleSheet/StyleSheetPropType'
import ViewStylePropTypes from './ViewStylePropTypes'
-const viewStyleKeys = Object.keys(ViewStylePropTypes)
+export default class View extends Component {
+ static propTypes = {
+ accessibilityLabel: CoreComponent.propTypes.accessibilityLabel,
+ accessibilityLiveRegion: CoreComponent.propTypes.accessibilityLiveRegion,
+ accessibilityRole: CoreComponent.propTypes.accessibilityRole,
+ accessible: CoreComponent.propTypes.accessible,
+ children: PropTypes.any,
+ pointerEvents: PropTypes.oneOf(['auto', 'box-none', 'box-only', 'none']),
+ style: StyleSheetPropType(ViewStylePropTypes),
+ testID: CoreComponent.propTypes.testID
+ };
+
+ static defaultProps = {
+ accessible: true
+ };
+
+ render() {
+ const {
+ pointerEvents,
+ style,
+ ...other
+ } = this.props
+
+ const pointerEventsStyle = pointerEvents && { pointerEvents }
+
+ return (
+
+ )
+ }
+}
const styles = StyleSheet.create({
// https://github.com/facebook/css-layout#default-values
@@ -29,50 +65,3 @@ const styles = StyleSheet.create({
textAlign: 'inherit'
}
})
-
-export default class View extends Component {
- static propTypes = {
- _className: PropTypes.string, // escape-hatch for code migrations
- accessibilityLabel: CoreComponent.propTypes.accessibilityLabel,
- accessibilityLiveRegion: CoreComponent.propTypes.accessibilityLiveRegion,
- accessibilityRole: CoreComponent.propTypes.accessibilityRole,
- accessible: CoreComponent.propTypes.accessible,
- children: PropTypes.any,
- pointerEvents: PropTypes.oneOf(['auto', 'box-none', 'box-only', 'none']),
- style: PropTypes.shape(ViewStylePropTypes),
- testID: CoreComponent.propTypes.testID
- };
-
- static stylePropTypes = ViewStylePropTypes;
-
- static defaultProps = {
- _className: '',
- accessible: true,
- style: styles.initial
- };
-
- render() {
- const {
- _className,
- pointerEvents,
- style,
- ...other
- } = this.props
-
- const className = `${_className} View`.trim()
- const pointerEventsStyle = pointerEvents && { pointerEvents }
- const resolvedStyle = pickProps(style, viewStyleKeys)
-
- return (
-
- )
- }
-}
diff --git a/src/modules/filterObjectProps/__tests__/index-test.js b/src/modules/filterObjectProps/__tests__/index-test.js
deleted file mode 100644
index f70dd06a..00000000
--- a/src/modules/filterObjectProps/__tests__/index-test.js
+++ /dev/null
@@ -1,26 +0,0 @@
-/* eslint-env mocha */
-
-import { omitProps, pickProps } from '..'
-import assert from 'assert'
-
-suite('pickProps', () => {
- test('return value', () => {
- const obj = { a: 1, b: 2, c: { cc: { ccc: 3 } } }
- const props = [ 'a', 'b' ]
- const expected = { a: 1, b: 2 }
- const actual = pickProps(obj, props)
-
- assert.deepEqual(actual, expected)
- })
-})
-
-suite('omitProps', () => {
- test('return value', () => {
- const obj = { a: 1, b: 2, c: { cc: { ccc: 3 } } }
- const props = [ 'a', 'b' ]
- const expected = { c: { cc: { ccc: 3 } } }
- const actual = omitProps(obj, props)
-
- assert.deepEqual(actual, expected)
- })
-})
diff --git a/src/modules/filterObjectProps/index.js b/src/modules/filterObjectProps/index.js
deleted file mode 100644
index 7f8e0785..00000000
--- a/src/modules/filterObjectProps/index.js
+++ /dev/null
@@ -1,25 +0,0 @@
-function filterProps(obj, propKeys: Array, excluded = false) {
- const filtered = {}
- for (const prop in obj) {
- if (Object.prototype.hasOwnProperty.call(obj, prop)) {
- const isMatch = propKeys.indexOf(prop) > -1
- if (excluded && isMatch) {
- continue
- } else if (!excluded && !isMatch) {
- continue
- }
-
- filtered[prop] = obj[prop]
- }
- }
-
- return filtered
-}
-
-export function pickProps(obj, propKeys) {
- return filterProps(obj, propKeys)
-}
-
-export function omitProps(obj, propKeys) {
- return filterProps(obj, propKeys, true)
-}