diff --git a/.babelrc b/.babelrc
new file mode 100644
index 00000000..c6dc7972
--- /dev/null
+++ b/.babelrc
@@ -0,0 +1,6 @@
+{
+ "optional": [
+ "runtime"
+ ],
+ "stage": 1
+}
diff --git a/README.md b/README.md
new file mode 100644
index 00000000..5206c6f3
--- /dev/null
+++ b/README.md
@@ -0,0 +1,327 @@
+# react-web-sdk
+
+**Experimental / API proof of concept**
+
+Components for building web applications and SDKs. Based on `react-native`'s
+components.
+
+1. Styles are plain JavaScript objects.
+2. Styles are passed to a component's `style` prop.
+3. Non-dynamic styles rely on static CSS classes.
+4. Dynamic styles are written as inline styles on the DOM node.
+
+Each Component defines `StylePropTypes` and filters out any style properties
+that are not part of its style API. For example, `View` does not support any
+typographic properties. You must use `Text` to wrap and style any text strings.
+
+### Implementation notes
+
+The current implementation uses a prebuilt CSS library – 200+ single-purpose,
+obfuscated selectors. It provides a large number of common, knowable styles
+needed to build apps. This makes the foundational CSS fixed (~5KB gzipped) and
+highly cachable. Inline styles are used for anything the CSS library doesn't
+provide, but their use is significantly reduced.
+
+A better implementation would generate the CSS library from the declarations
+defined in the source code, replace static variables (use webpack's
+`DefinePlugin`?), and only use inline-styles for dynamic, instance-specific
+styles.
+
+What about media queries? Perhaps rely on `mediaMatch` and re-render when the
+`style` prop needs to change; works better with DOM-related changes that need
+to happen at breakpoints. And that would avoid the need for any additional
+CSS. Alternatively, rely on something similar to `react-style`'s approach and
+duplicate the single-purpose classes within static CSS media queries.
+
+## Example
+
+```js
+import React from 'react';
+import {Image, Text, View} from 'react-web-sdk';
+
+class Example extends React.Component {
+ render() {
+ return (
+
+
+ 0.5 && style.text) }}>
+ Example component
+
+
+ );
+ }
+}
+
+const style = {
+ common: {
+ backgroundColor: 'white',
+ borderRadius: '1em'
+ },
+ root: {
+ flexDirection: 'row',
+ justifyContent: 'space-between'
+ },
+ image: {
+ opacity: 0.5
+ },
+ text: {
+ fontWeight: '300'
+ }
+};
+
+export default Example;
+```
+
+## Component: `SDKComponent`
+
+A component that manages styles across the `className` and `style` properties.
+The building block upon which all other components in `react-web-sdk` are
+build.
+
+### PropTypes
+
+All other props are transferred directly to the `element`.
+
++ `className`: `string`
++ `element`: `func` or `string`
++ `style`: `object`
+
+### Examples
+
+```js
+const ViewStylePropTypes = {
+ opacity: PropTypes.number
+};
+
+const ViewStyleDefaultProps = {
+ opacity: 1
+};
+
+class ViewExample extends React.Component {
+ render() {
+ // filter other props
+ const other = ReactWebSDK.getOtherProps(this);
+ // exclude other styles
+ const supportedStyle = ReactWebSDK.objectWithProps(this.props.style, ViewStylePropTypes);
+ // merge defaults with instance styles
+ const style = { ...ViewStyleDefaultProps, ...supportedStyle }
+
+ return (
+
+ );
+ }
+}
+```
+
+
+## Component: `Image`
+
+TODO
+
+### PropTypes
+
+All other props are transferred directly to the `element`.
+
++ `alt`: `string`
++ `async`: `bool` (TODO)
++ `className`: `string`
++ `src`: `string`
++ `style`: `ImageStylePropTypes`
+
+### ImageStylePropTypes
+
++ `BackgroundPropTypes`
++ `BorderThemePropTypes`
++ `LayoutPropTypes`
++ `opacity`: `string`
+
+
+## Component: `Text`
+
+Text layout and styles.
+
+### PropTypes
+
+All other props are transferred directly to the `element`.
+
++ `className`: `string`
++ `element`: `func` or `string` (default `"div"`)
++ `style`: `TextStylePropTypes`
+
+### TextStylePropTypes
+
++ ViewStylePropTypes
++ TypographicPropTypes
+
+
+## Component: `View`
+
+`View` is a flexbox container and the fundamental building block for UI. It is
+designed to be nested inside other `View`'s and to have 0-to-many children of
+any type.
+
+### PropTypes
+
+All other props are transferred directly to the `element`.
+
++ `className`: `string`
++ `element`: `func` or `string` (default `"div"`)
++ `pointerEvents`: `oneOf('all', 'box-only', 'box-none', 'none')`
++ `style`: `ViewStylePropTypes`
+
+### ViewStylePropTypes
+
++ BackgroundPropTypes
++ BorderThemePropTypes
++ LayoutPropTypes
++ `boxShadow`: `string`
++ `color`: `string`
++ `opacity`: `number`
+
+### ViewStyleDefaultProps
+
+Implements the default styles from
+[facebook/css-layout](https://github.com/facebook/css-layout).
+
+```js
+const ViewStyleDefaultProps = {
+ alignItems: 'stretch', // 1
+ borderWidth: 0,
+ borderStyle: 'solid',
+ boxSizing: 'border-box', // 2
+ display: 'flex', // 3
+ flexBasis: 'auto', // 1
+ flexDirection: 'column', // 1
+ flexShrink: 0, // 1
+ listStyle: 'none',
+ margin: 0,
+ padding: 0,
+ position: 'relative' // 4
+};
+```
+
+1. All the flex elements are oriented from top-to-bottom, left-to-right and do
+ not shrink. This is how things are laid out using the default CSS settings
+ and what you'd expect.
+
+2. The most convenient way to express the relation between width and other
+ box-model properties.
+
+3. Everything is `display:flex` by default. All the behaviors of `block` and
+ `inline-block` can be expressed in term of flex but not the opposite.
+
+4. Everything is `position:relative`. This makes `position:absolute` target the
+ direct parent and not some parent which is either relative or absolute. If
+ you want to position an element relative to something else, you should move
+ it in the DOM instead of relying of CSS. It also makes `top`, `left`,
+ `right`, `bottom` do something when not specifying `position:absolute`.
+
+### Examples
+
+```js
+// TODO
+```
+
+## StylePropTypes
+
+### Background
+
++ `backgroundColor`: `string`
++ `backgroundImage`: `string`
++ `backgroundPosition`: `string`
++ `backgroundRepeat`: `string`
++ `backgroundSize`: `string`
+
+### BorderTheme
+
++ `borderColor`: `string`
++ `borderTopColor`: `string`
++ `borderRightColor`: `string`
++ `borderBottomColor`: `string`
++ `borderLeftColor`: `string`
++ `borderStyle`: `string`
++ `borderRadius`: `number` or `string`
++ `borderTopLeftRadius`: `number` or `string`
++ `borderTopRightRadius`: `number` or `string`
++ `borderBottomLeftRadius`: `number` or `string`
++ `borderBottomRightRadius`: `number` or `string`
+
+### BoxModel
+
++ `borderWidth`: `number` or `string`
++ `borderTopWidth`: `number` or `string`
++ `borderRightWidth`: `number` or `string`
++ `borderBottomWidth`: `number` or `string`
++ `borderLeftWidth`: `number` or `string`
++ `boxSizing`: `oneOf('border-box', 'content-box')`
++ `display`: `oneOf('block', 'flex', 'inline', 'inline-block', 'inline-flex')`
++ `height`: `number` or `string`
++ `margin`: `number` or `string`
++ `marginTop`: `number` or `string`
++ `marginRight`: `number` or `string`
++ `marginBottom`: `number` or `string`
++ `marginLeft`: `number` or `string`
++ `padding`: `number` or `string`
++ `paddingTop`: `number` or `string`
++ `paddingRight`: `number` or `string`
++ `paddingBottom`: `number` or `string`
++ `paddingLeft`: `number` or `string`
++ `width`: `number` or `string`
+
+### Flexbox
+
+* `alignContent`: `oneOf('center', 'flex-end', 'flex-start', 'stretch', 'space-around', 'space-between')`
+* `alignItems`: `oneOf('baseline', 'center', 'flex-end', 'flex-start', 'stretch')`
+* `alignSelf`: `oneOf('auto', 'baseline', 'center', 'flex-end', 'flex-start', 'stretch')`
+* `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`
+
+See this [guide to flexbox](https://css-tricks.com/snippets/css/a-guide-to-flexbox/).
+
+### Layout
+
+* BoxModel
+* Flexbox
+* Position
+
+### Position
+
+* `position`: `oneOf('absolute', 'fixed', 'relative')`
+* `bottom`: `number` or `string`
+* `left`: `number` or `string`
+* `right`: `number` or `string`
+* `top`: `number` or `string`
+* `zIndex`: `number`
+
+### Typographic
+
+* `direction`: `oneOf('auto', 'ltr', 'rtl')`
+* `fontFamily`: `string`
+* `fontSize`: `string`
+* `fontWeight`: `oneOf('100', '200', '300', '400', '500', '600', '700', '800', '900', 'bold', 'normal')`
+* `fontStyle`: `oneOf('normal', 'italic')`
+* `letterSpacing`: `string`
+* `lineHeight`: `number` or `string`
+* `textAlign`: `oneOf('auto', 'left', 'right', 'center')`
+* `textDecoration`: `oneOf('none', 'underline')`
+* `textTransform`: `oneOf('capitalize', 'lowercase', 'none', 'uppercase')`
+* `wordWrap`: `oneOf('break-word', 'normal')`
+
+## Development
+
+```
+npm run build
+npm run build:watch
+open index.html
+```
diff --git a/example.js b/example.js
new file mode 100644
index 00000000..2b155732
--- /dev/null
+++ b/example.js
@@ -0,0 +1,39 @@
+import React from 'react';
+import { Image, Text, View } from '.';
+
+class Example extends React.Component {
+ render() {
+ return (
+
+ {[1,2,3,4,5,6].map((item) => {
+ return (
+
+ {item}
+
+ );
+ })}
+
+ );
+ }
+}
+
+const style = {
+ root: {
+ flexDirection: 'row',
+ flexWrap: 'wrap',
+ height: '100px'
+ },
+ box: {
+ alignItems: 'center',
+ backgroundColor: 'lightblue',
+ flexGrow: 1,
+ justifyContent: 'center',
+ borderColor: 'blue',
+ borderWidth: '5px'
+ },
+ boxFull: {
+ width: '100%'
+ }
+}
+
+React.render(, document.getElementById('react-root'));
diff --git a/index.html b/index.html
new file mode 100644
index 00000000..a4ba6afe
--- /dev/null
+++ b/index.html
@@ -0,0 +1,4 @@
+
+
+
+
diff --git a/index.js b/index.js
new file mode 100644
index 00000000..283ef7c1
--- /dev/null
+++ b/index.js
@@ -0,0 +1,14 @@
+import getOtherProps, {objectWithProps} from './lib/getOtherProps';
+import Image from './lib/components/Image';
+import SDKComponent from './lib/components/SDKComponent';
+import Text from './lib/components/Text';
+import View from './lib/components/View';
+
+export default {
+ getOtherProps,
+ Image,
+ objectWithProps,
+ SDKComponent,
+ Text,
+ View
+};
diff --git a/lib/.gitkeep b/lib/.gitkeep
new file mode 100644
index 00000000..e69de29b
diff --git a/lib/StylePropTypes/Background.js b/lib/StylePropTypes/Background.js
new file mode 100644
index 00000000..c4d3a313
--- /dev/null
+++ b/lib/StylePropTypes/Background.js
@@ -0,0 +1,9 @@
+import {PropTypes} from 'react';
+
+export default {
+ backgroundColor: PropTypes.string,
+ backgroundImage: PropTypes.string,
+ backgroundPosition: PropTypes.string,
+ backgroundRepeat: PropTypes.string,
+ backgroundSize: PropTypes.string
+};
diff --git a/lib/StylePropTypes/BorderTheme.js b/lib/StylePropTypes/BorderTheme.js
new file mode 100644
index 00000000..09446508
--- /dev/null
+++ b/lib/StylePropTypes/BorderTheme.js
@@ -0,0 +1,28 @@
+import {PropTypes} from 'react';
+
+export default {
+ // border-color
+ borderColor: PropTypes.string,
+ borderTopColor: PropTypes.string,
+ borderRightColor: PropTypes.string,
+ borderBottomColor: PropTypes.string,
+ borderLeftColor: PropTypes.string,
+ // border-style
+ borderStyle: PropTypes.string,
+ // border-radius
+ borderRadius: PropTypes.oneOfType([
+ PropTypes.number, PropTypes.string
+ ]),
+ borderTopLeftRadius: PropTypes.oneOfType([
+ PropTypes.number, PropTypes.string
+ ]),
+ borderTopRightRadius: PropTypes.oneOfType([
+ PropTypes.number, PropTypes.string
+ ]),
+ borderBottomLeftRadius: PropTypes.oneOfType([
+ PropTypes.number, PropTypes.string
+ ]),
+ borderBottomRightRadius: PropTypes.oneOfType([
+ PropTypes.number, PropTypes.string
+ ])
+};
diff --git a/lib/StylePropTypes/BoxModel.js b/lib/StylePropTypes/BoxModel.js
new file mode 100644
index 00000000..fd989d73
--- /dev/null
+++ b/lib/StylePropTypes/BoxModel.js
@@ -0,0 +1,71 @@
+import {PropTypes} from 'react';
+
+export default {
+ boxSizing: PropTypes.oneOf([
+ 'border-box',
+ 'content-box'
+ ]),
+ // display
+ display: PropTypes.oneOf([
+ 'block',
+ 'flex',
+ 'inline',
+ 'inline-block',
+ 'inline-flex'
+ ]),
+ // dimensions
+ height: PropTypes.oneOfType([
+ PropTypes.string, PropTypes.number
+ ]),
+ width: PropTypes.oneOfType([
+ PropTypes.string, PropTypes.number
+ ]),
+ // border width
+ borderWidth: PropTypes.oneOfType([
+ PropTypes.string, PropTypes.number
+ ]),
+ borderTopWidth: PropTypes.oneOfType([
+ PropTypes.string, PropTypes.number
+ ]),
+ borderRightWidth: PropTypes.oneOfType([
+ PropTypes.string, PropTypes.number
+ ]),
+ borderBottomWidth: PropTypes.oneOfType([
+ PropTypes.string, PropTypes.number
+ ]),
+ borderLeftWidth: PropTypes.oneOfType([
+ PropTypes.string, PropTypes.number
+ ]),
+ // margin
+ margin: PropTypes.oneOfType([
+ PropTypes.string, PropTypes.number
+ ]),
+ marginTop: PropTypes.oneOfType([
+ PropTypes.string, PropTypes.number
+ ]),
+ marginBottom: PropTypes.oneOfType([
+ PropTypes.string, PropTypes.number
+ ]),
+ marginLeft: PropTypes.oneOfType([
+ PropTypes.string, PropTypes.number
+ ]),
+ marginRight: PropTypes.oneOfType([
+ PropTypes.string, PropTypes.number
+ ]),
+ // padding
+ padding: PropTypes.oneOfType([
+ PropTypes.string, PropTypes.number
+ ]),
+ paddingTop: PropTypes.oneOfType([
+ PropTypes.string, PropTypes.number
+ ]),
+ paddingBottom: PropTypes.oneOfType([
+ PropTypes.string, PropTypes.number
+ ]),
+ paddingLeft: PropTypes.oneOfType([
+ PropTypes.string, PropTypes.number
+ ]),
+ paddingRight: PropTypes.oneOfType([
+ PropTypes.string, PropTypes.number
+ ])
+};
diff --git a/lib/StylePropTypes/Flexbox.js b/lib/StylePropTypes/Flexbox.js
new file mode 100644
index 00000000..a95718c9
--- /dev/null
+++ b/lib/StylePropTypes/Flexbox.js
@@ -0,0 +1,49 @@
+import {PropTypes} from 'react';
+
+export default {
+ alignContent: PropTypes.oneOf([
+ 'center',
+ 'flex-end',
+ 'flex-start',
+ 'stretch',
+ 'space-around',
+ 'space-between'
+ ]),
+ alignItems: PropTypes.oneOf([
+ 'baseline',
+ 'center',
+ 'flex-end',
+ 'flex-start',
+ 'stretch'
+ ]),
+ alignSelf: PropTypes.oneOf([
+ 'auto',
+ 'baseline',
+ 'center',
+ 'flex-end',
+ 'flex-start',
+ 'stretch'
+ ]),
+ flexBasis: PropTypes.string,
+ flexDirection: PropTypes.oneOf([
+ 'column',
+ 'column-reverse',
+ 'row',
+ 'row-reverse'
+ ]),
+ flexGrow: PropTypes.number,
+ flexShrink: PropTypes.number,
+ flexWrap: PropTypes.oneOf([
+ 'nowrap',
+ 'wrap',
+ 'wrap-reverse'
+ ]),
+ justifyContent: PropTypes.oneOf([
+ 'center',
+ 'flex-end',
+ 'flex-start',
+ 'space-around',
+ 'space-between'
+ ]),
+ order: PropTypes.number
+};
diff --git a/lib/StylePropTypes/Layout.js b/lib/StylePropTypes/Layout.js
new file mode 100644
index 00000000..b2aebf7e
--- /dev/null
+++ b/lib/StylePropTypes/Layout.js
@@ -0,0 +1,9 @@
+import BoxModel from './BoxModel';
+import Flexbox from './Flexbox';
+import Position from './Position';
+
+export default {
+ ...BoxModel,
+ ...Flexbox,
+ ...Position
+};
diff --git a/lib/StylePropTypes/Position.js b/lib/StylePropTypes/Position.js
new file mode 100644
index 00000000..f984ecb6
--- /dev/null
+++ b/lib/StylePropTypes/Position.js
@@ -0,0 +1,14 @@
+import {PropTypes} from 'react';
+
+export default {
+ position: PropTypes.oneOf([
+ 'absolute',
+ 'fixed',
+ 'relative'
+ ]),
+ bottom: PropTypes.oneOfType([ PropTypes.string, PropTypes.number ]),
+ left: PropTypes.oneOfType([ PropTypes.string, PropTypes.number ]),
+ right: PropTypes.oneOfType([ PropTypes.string, PropTypes.number ]),
+ top: PropTypes.oneOfType([ PropTypes.string, PropTypes.number ]),
+ zIndex: PropTypes.number
+};
diff --git a/lib/StylePropTypes/Typographic.js b/lib/StylePropTypes/Typographic.js
new file mode 100644
index 00000000..ed19e6ae
--- /dev/null
+++ b/lib/StylePropTypes/Typographic.js
@@ -0,0 +1,30 @@
+import {PropTypes} from 'react';
+
+export default {
+ direction: PropTypes.oneOf([
+ 'auto', 'ltr', 'rtl'
+ ]),
+ fontFamily: PropTypes.string,
+ fontSize: PropTypes.string,
+ fontWeight: PropTypes.oneOf([
+ '100', '200', '300', '400', '500', '600', '700', '800', '900',
+ 'bold', 'normal'
+ ]),
+ fontStyle: PropTypes.oneOf([
+ 'normal', 'italic'
+ ]),
+ letterSpacing: PropTypes.string,
+ lineHeight: PropTypes.oneOfType([ PropTypes.string, PropTypes.number ]),
+ textAlign: PropTypes.oneOf([
+ 'auto', 'left', 'right', 'center'
+ ]),
+ textDecoration: PropTypes.oneOf([
+ 'none', 'underline'
+ ]),
+ textTransform: PropTypes.oneOf([
+ 'capitalize', 'lowercase', 'none', 'uppercase'
+ ]),
+ wordWrap: PropTypes.oneOf([
+ 'break-word', 'normal'
+ ])
+};
diff --git a/lib/StylePropTypes/index.js b/lib/StylePropTypes/index.js
new file mode 100644
index 00000000..accdfa81
--- /dev/null
+++ b/lib/StylePropTypes/index.js
@@ -0,0 +1,13 @@
+import BackgroundPropTypes from './Background';
+import BorderThemePropTypes from './BorderTheme';
+import FlexboxPropTypes from './Flexbox';
+import LayoutPropTypes from './Layout';
+import TypographicPropTypes from './Typographic';
+
+export default {
+ BackgroundPropTypes,
+ BorderThemePropTypes,
+ FlexboxPropTypes,
+ LayoutPropTypes,
+ TypographicPropTypes
+};
diff --git a/lib/autoprefix.js b/lib/autoprefix.js
new file mode 100644
index 00000000..930d9a7a
--- /dev/null
+++ b/lib/autoprefix.js
@@ -0,0 +1,47 @@
+export default function prefixStyles(style) {
+ if (style.hasOwnProperty('flexBasis')) {
+ style = {
+ WebkitFlexBasis: style.flexBasis,
+ msFlexBasis: style.flexBasis,
+ ...style
+ };
+ }
+
+ if (style.hasOwnProperty('flexGrow')) {
+ style = {
+ WebkitBoxFlex: style.flexGrow,
+ WebkitFlexGrow: style.flexGrow,
+ msFlexPositive: style.flexGrow,
+ ...style
+ };
+ }
+
+ if (style.hasOwnProperty('flexShrink')) {
+ style = {
+ WebkitFlexShrink: style.flexShrink,
+ msFlexNegative: style.flexShrink,
+ ...style
+ };
+ }
+
+ // NOTE: adding `;` to the string value prevents React from automatically
+ // adding a `px` suffix to the unitless value
+ if (style.hasOwnProperty('order')) {
+ style = {
+ WebkitBoxOrdinalGroup: `${parseInt(style.order, 10) + 1};`,
+ WebkitOrder: `${style.order}`,
+ msFlexOrder: `${style.order};`,
+ ...style
+ };
+ }
+
+ if (style.hasOwnProperty('transform')) {
+ style = {
+ WebkitTransform: style.transform,
+ msTransform: style.transform,
+ ...style
+ };
+ }
+
+ return style;
+}
diff --git a/lib/components/Image.js b/lib/components/Image.js
new file mode 100644
index 00000000..bb755cbd
--- /dev/null
+++ b/lib/components/Image.js
@@ -0,0 +1,61 @@
+import {objectWithProps} from '../getOtherProps';
+import React, {PropTypes} from 'react';
+import StylePropTypes from '../StylePropTypes';
+import SDKComponent from './SDKComponent';
+
+const ImageStyleDefaultProps = {
+ backgroundColor: 'lightGray',
+ borderWidth: 0,
+ maxWidth: '100%'
+};
+
+const ImageStylePropTypes = {
+ ...StylePropTypes.BorderThemePropTypes,
+ ...StylePropTypes.LayoutPropTypes,
+ backgroundColor: PropTypes.string,
+ opacity: PropTypes.string
+};
+
+class Image extends React.Component {
+ static _getPropTypes() {
+ return {
+ alt: PropTypes.string,
+ async: PropTypes.bool,
+ className: PropTypes.string,
+ src: PropTypes.string,
+ style: PropTypes.shape(ImageStylePropTypes)
+ };
+ }
+
+ static _getDefaultProps() {
+ return {
+ async: true,
+ className: '',
+ src: 'data:image/gif;base64,' +
+ 'R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7',
+ style: {}
+ };
+ }
+
+ render() {
+ const { alt, className, src, style, ...other } = this.props;
+ const filteredStyle = objectWithProps(style, Object.keys(ImageStylePropTypes));
+ const mergedStyle = { ...ImageStyleDefaultProps, ...filteredStyle };
+
+ return (
+
+ );
+ }
+}
+
+Image.propTypes = Image._getPropTypes();
+Image.defaultProps = Image._getDefaultProps();
+
+export default Image;
diff --git a/lib/components/SDKComponent.js b/lib/components/SDKComponent.js
new file mode 100644
index 00000000..c0f83fae
--- /dev/null
+++ b/lib/components/SDKComponent.js
@@ -0,0 +1,74 @@
+import autoprefix from '../autoprefix';
+import getOtherProps from '../getOtherProps';
+import React, {PropTypes} from 'react';
+
+// styles
+import styleMap from '../styleMap';
+
+class SDKComponent extends React.Component {
+ static _getPropTypes() {
+ return {
+ className: PropTypes.string,
+ element: PropTypes.oneOfType([
+ PropTypes.string, PropTypes.func
+ ]),
+ style: PropTypes.object
+ };
+ }
+
+ static _getDefaultProps() {
+ return {
+ className: '',
+ element: 'div',
+ style: {}
+ };
+ }
+
+ render() {
+ const other = getOtherProps(this);
+ const { classNames, inlineStyles } = this._separateClassNamesAndStyles();
+
+ return (
+
+ );
+ }
+
+ _getSinglePurposeClassName(prop, style) {
+ const uniqueClassName = `${prop}-${style[prop]}`;
+ if (
+ style.hasOwnProperty(prop) &&
+ styleMap[uniqueClassName]
+ ) {
+ return styleMap[uniqueClassName];
+ }
+ }
+
+ _separateClassNamesAndStyles() {
+ const classNameProp = this.props.className;
+ const styleProp = this.props.style;
+
+ let classNames = [ classNameProp ];
+ let inlineStyles = {};
+
+ for (let prop in styleProp) {
+ let singlePurposeClassName =
+ this._getSinglePurposeClassName(prop, styleProp);
+ if (singlePurposeClassName) {
+ classNames.push(singlePurposeClassName);
+ } else {
+ inlineStyles[prop] = styleProp[prop];
+ }
+ }
+
+ return { classNames, inlineStyles };
+ }
+}
+
+SDKComponent.propTypes = SDKComponent._getPropTypes();
+SDKComponent.defaultProps = SDKComponent._getDefaultProps();
+
+export default SDKComponent;
diff --git a/lib/components/Text.js b/lib/components/Text.js
new file mode 100644
index 00000000..f9b104be
--- /dev/null
+++ b/lib/components/Text.js
@@ -0,0 +1,65 @@
+import {objectWithProps} from '../getOtherProps';
+import React, {PropTypes} from 'react';
+import StylePropTypes from '../StylePropTypes';
+import SDKComponent from './SDKComponent';
+import {ViewStylePropTypes} from './View';
+
+const TextStyleDefaultProps = {
+ alignItems: 'stretch', /* 1 */
+ borderWidth: '0',
+ borderStyle: 'solid',
+ boxSizing: 'border-box', /* 2 */
+ display: 'flex', /* 3 */
+ flexBasis: 'auto', /* 1 */
+ flexDirection: 'column', /* 1 */
+ flexShrink: 0, /* 1 */
+ listStyle: 'none',
+ margin: '0',
+ padding: '0',
+ position: 'relative' /* 4 */
+};
+
+const TextStylePropTypes = {
+ ...ViewStylePropTypes,
+ ...StylePropTypes.TypographicPropTypes
+};
+
+class Text extends React.Component {
+ static _getPropTypes() {
+ return {
+ className: PropTypes.string,
+ element: PropTypes.oneOfType([
+ PropTypes.string, PropTypes.func
+ ]),
+ style: PropTypes.shape(TextStylePropTypes)
+ };
+ }
+
+ static _getDefaultProps() {
+ return {
+ className: '',
+ element: 'div',
+ style: {}
+ };
+ }
+
+ render() {
+ const { className, element, style, ...other } = this.props;
+ const filteredStyle = objectWithProps(style, Object.keys(TextStylePropTypes));
+ const mergedStyle = { ...TextStyleDefaultProps, ...filteredStyle };
+
+ return (
+
+ );
+ }
+}
+
+Text.propTypes = Text._getPropTypes();
+Text.defaultProps = Text._getDefaultProps();
+
+export default Text;
diff --git a/lib/components/View.js b/lib/components/View.js
new file mode 100644
index 00000000..9d978ca9
--- /dev/null
+++ b/lib/components/View.js
@@ -0,0 +1,81 @@
+import {objectWithProps} from '../getOtherProps';
+import React, {PropTypes} from 'react';
+import StylePropTypes from '../StylePropTypes';
+import SDKComponent from './SDKComponent';
+
+// https://github.com/facebook/css-layout#default-values
+const ViewStyleDefaultProps = {
+ alignItems: 'stretch',
+ borderWidth: 0,
+ borderStyle: 'solid',
+ boxSizing: 'border-box',
+ display: 'flex',
+ flexBasis: 'auto',
+ flexDirection: 'column',
+ flexShrink: 0,
+ listStyle: 'none',
+ margin: 0,
+ padding: 0,
+ position: 'relative'
+};
+
+const ViewStylePropTypes = {
+ ...StylePropTypes.BackgroundPropTypes,
+ ...StylePropTypes.BorderThemePropTypes,
+ ...StylePropTypes.LayoutPropTypes,
+ boxShadow: PropTypes.string,
+ opacity: PropTypes.number,
+ transform: PropTypes.string
+};
+
+class View extends React.Component {
+ static _getPropTypes() {
+ return {
+ className: PropTypes.string,
+ element: PropTypes.oneOfType([
+ PropTypes.string, PropTypes.func
+ ]),
+ pointerEvents: PropTypes.oneOf([
+ 'auto',
+ 'box-none',
+ 'box-only',
+ 'none'
+ ]),
+ style: PropTypes.shape(ViewStylePropTypes)
+ };
+ }
+
+ static _getDefaultProps() {
+ return {
+ className: '',
+ element: 'div',
+ style: {}
+ };
+ }
+
+ render() {
+ const { className, element, pointerEvents, style, ...other } = this.props;
+ const filteredStyle = objectWithProps(style, Object.keys(ViewStylePropTypes));
+ const pointerEventsStyle = pointerEvents && { pointerEvents };
+ const mergedStyle = {
+ ...ViewStyleDefaultProps,
+ ...filteredStyle,
+ ...pointerEventsStyle
+ };
+
+ return (
+
+ );
+ }
+}
+
+View.propTypes = View._getPropTypes();
+View.defaultProps = View._getDefaultProps();
+
+export default View;
+export {ViewStylePropTypes};
diff --git a/lib/css/.gitkeep b/lib/css/.gitkeep
new file mode 100644
index 00000000..e69de29b
diff --git a/lib/css/background.css b/lib/css/background.css
new file mode 100644
index 00000000..37ed2fb8
--- /dev/null
+++ b/lib/css/background.css
@@ -0,0 +1,13 @@
+:local .backgroundColor-#fff { background-color: #fff; }
+:local .backgroundColor-transparent { background-color: currentcolor; }
+
+:local .backgroundImage { background-image: none; }
+
+:local .backgroundPosition-center { background-position: center; }
+:local .backgroundSize-contain { background-size: contain; }
+:local .backgroundSize-cover { background-size: cover; }
+
+:local .backgroundRepeat-no-repeat { background-repeat: no-repeat; }
+:local .backgroundRepeat-repeat { background-repeat: repeat; }
+:local .backgroundRepeat-repeat-x { background-repeat: repeat-x; }
+:local .backgroundRepeat-repeat-y { background-repeat: repeat-y; }
diff --git a/lib/css/border.css b/lib/css/border.css
new file mode 100644
index 00000000..3be1fffb
--- /dev/null
+++ b/lib/css/border.css
@@ -0,0 +1,42 @@
+:local .borderColor-currentcolor { border-color: currentcolor; }
+:local .borderColor-transparent { border-color: transparent; }
+
+:local .borderStyle-dotted { border-style: dotted; }
+:local .borderStyle-dashed { border-style: dashed; }
+:local .borderStyle-solid { border-style: solid; }
+
+:local .borderWidth-0 { border-width: 0; }
+:local .borderTopWidth-0 { border-top-width: 0; }
+:local .borderRightWidth-0 { border-right-width: 0; }
+:local .borderBottomWidth-0 { border-bottom-width: 0; }
+:local .borderLeftWidth-0 { border-left-width: 0; }
+
+:local .borderWidth-1px { border-width: 1px; }
+:local .borderTopWidth-1px { border-top-width: 1px; }
+:local .borderRightWidth-1px { border-right-width: 1px; }
+:local .borderBottomWidth-1px { border-bottom-width: 1px; }
+:local .borderLeftWidth-1px { border-left-width: 1px; }
+
+:local .borderWidth-2px { border-width: 2px; }
+:local .borderTopWidth-2px { border-top-width: 2px; }
+:local .borderRightWidth-2px { border-right-width: 2px; }
+:local .borderBottomWidth-2px { border-bottom-width: 2px; }
+:local .borderLeftWidth-2px { border-left-width: 2px; }
+
+:local .borderWidth-3px { border-width: 3px; }
+:local .borderTopWidth-3px { border-top-width: 3px; }
+:local .borderRightWidth-3px { border-right-width: 3px; }
+:local .borderBottomWidth-3px { border-bottom-width: 3px; }
+:local .borderLeftWidth-3px { border-left-width: 3px; }
+
+:local .borderWidth-4px { border-width: 4px; }
+:local .borderTopWidth-4px { border-top-width: 4px; }
+:local .borderRightWidth-4px { border-right-width: 4px; }
+:local .borderBottomWidth-4px { border-bottom-width: 4px; }
+:local .borderLeftWidth-4px { border-left-width: 4px; }
+
+:local .borderWidth-5px { border-width: 5px; }
+:local .borderTopWidth-5px { border-top-width: 5px; }
+:local .borderRightWidth-5px { border-right-width: 5px; }
+:local .borderBottomWidth-5px { border-bottom-width: 5px; }
+:local .borderLeftWidth-5px { border-left-width: 5px; }
diff --git a/lib/css/boxSizing.css b/lib/css/boxSizing.css
new file mode 100644
index 00000000..e6eb38bf
--- /dev/null
+++ b/lib/css/boxSizing.css
@@ -0,0 +1,2 @@
+:local .boxSizing-border-box { box-sizing: border-box; }
+:local .boxSizing-content-box { box-sizing: content-box; }
diff --git a/lib/css/clear.css b/lib/css/clear.css
new file mode 100644
index 00000000..8ad9a6a9
--- /dev/null
+++ b/lib/css/clear.css
@@ -0,0 +1,4 @@
+:local .clear-both { clear: both; }
+:local .clear-left { clear: left; }
+:local .clear-none { clear: none; }
+:local .clear-right { clear: right; }
diff --git a/lib/css/color.css b/lib/css/color.css
new file mode 100644
index 00000000..35472915
--- /dev/null
+++ b/lib/css/color.css
@@ -0,0 +1,4 @@
+:local .color-\#fff { color: #fff; }
+:local .color-\#000 { color: #000; }
+:local .color-transparent { color: transparent; }
+:local .color-inherit { color: inherit; }
diff --git a/lib/css/direction.css b/lib/css/direction.css
new file mode 100644
index 00000000..977f2881
--- /dev/null
+++ b/lib/css/direction.css
@@ -0,0 +1,3 @@
+:local .direction-auto { direction: auto; }
+:local .direction-ltr { direction: ltr; }
+:local .direction-rtl { direction: rtl; }
diff --git a/lib/css/display.css b/lib/css/display.css
new file mode 100644
index 00000000..1dff8342
--- /dev/null
+++ b/lib/css/display.css
@@ -0,0 +1,12 @@
+:local .display-block { display: block; }
+:local .display-flex { display: flex; }
+:local .display-inline { display: inline; }
+:local .display-inline-block { display: inline-block; }
+:local .display-inline-flex { display: inline-flex; }
+:local .display-inline-table { display: inline-table; }
+:local .display-none { display: none; }
+:local .display-table { display: table; }
+:local .display-table-row { display: table-row; }
+:local .display-table-cell { display: table-cell; }
+:local .display-table-column { display: table-column; }
+:local .display-table-column-group { display: table-column-group; }
diff --git a/lib/css/flexbox.css b/lib/css/flexbox.css
new file mode 100644
index 00000000..86c92f84
--- /dev/null
+++ b/lib/css/flexbox.css
@@ -0,0 +1,70 @@
+:local .alignContent-center { align-content: center; }
+:local .alignContent-flex-end { align-content: flex-end; }
+:local .alignContent-flex-start { align-content: flex-start; }
+:local .alignContent-stretch { align-content: stretch; }
+:local .alignContent-space-around { align-content: space-around; }
+:local .alignContent-space-between { align-content: space-between; }
+
+:local .alignItems-center { align-items: center; }
+:local .alignItems-flex-end { align-items: flex-end; }
+:local .alignItems-flex-start { align-items: flex-start; }
+:local .alignItems-stretch { align-items: stretch; }
+:local .alignItems-space-around { align-items: space-around; }
+:local .alignItems-space-between { align-items: space-between; }
+
+:local .alignSelf-auto { align-self: auto; }
+:local .alignSelf-baseline { align-self: baseline; }
+:local .alignSelf-center { align-self: center; }
+:local .alignSelf-flex-end { align-self: flex-end; }
+:local .alignSelf-flex-start { align-self: flex-start; }
+:local .alignSelf-stretch { align-self: stretch; }
+
+:local .flexBasis-0 { flex-basis: 0%; }
+:local .flexBasis-auto { flex-basis: auto; }
+
+:local .flexDirection-column { flex-direction: column; }
+:local .flexDirection-column-reverse { flex-direction: column-reverse; }
+:local .flexDirection-row { flex-direction: row; }
+:local .flexDirection-row-reverse { flex-direction: row-reverse; }
+
+:local .flexGrow-0 { flex-grow: 0; }
+:local .flexGrow-1 { flex-grow: 1; }
+:local .flexGrow-2 { flex-grow: 2; }
+:local .flexGrow-3 { flex-grow: 3; }
+:local .flexGrow-4 { flex-grow: 4; }
+:local .flexGrow-5 { flex-grow: 5; }
+:local .flexGrow-6 { flex-grow: 6; }
+:local .flexGrow-7 { flex-grow: 7; }
+:local .flexGrow-8 { flex-grow: 8; }
+:local .flexGrow-9 { flex-grow: 9; }
+
+:local .flexShrink-0 { flex-shrink: 0; }
+:local .flexShrink-1 { flex-shrink: 1; }
+:local .flexShrink-2 { flex-shrink: 2; }
+:local .flexShrink-3 { flex-shrink: 3; }
+:local .flexShrink-4 { flex-shrink: 4; }
+:local .flexShrink-5 { flex-shrink: 5; }
+:local .flexShrink-6 { flex-shrink: 6; }
+:local .flexShrink-7 { flex-shrink: 7; }
+:local .flexShrink-8 { flex-shrink: 8; }
+:local .flexShrink-9 { flex-shrink: 9; }
+
+:local .flexWrap-nowrap { flex-wrap: nowrap; }
+:local .flexWrap-wrap { flex-wrap: wrap; }
+:local .flexWrap-wrap-reverse { flex-wrap: wrap-reverse; }
+
+:local .justifyContent-center { justify-content: center; }
+:local .justifyContent-flex-end { justify-content: flex-end; }
+:local .justifyContent-flex-start { justify-content: flex-start; }
+:local .justifyContent-space-around { justify-content: space-around; }
+:local .justifyContent-space-between { justify-content: space-between; }
+
+:local .order-1 { order: 1; }
+:local .order-2 { order: 2; }
+:local .order-3 { order: 3; }
+:local .order-4 { order: 4; }
+:local .order-5 { order: 5; }
+:local .order-6 { order: 6; }
+:local .order-7 { order: 7; }
+:local .order-8 { order: 8; }
+:local .order-9 { order: 9; }
diff --git a/lib/css/float.css b/lib/css/float.css
new file mode 100644
index 00000000..7d668754
--- /dev/null
+++ b/lib/css/float.css
@@ -0,0 +1,3 @@
+:local .float-left { float: left; }
+:local .float-none { float: none; }
+:local .float-right { float: right; }
diff --git a/lib/css/font.css b/lib/css/font.css
new file mode 100644
index 00000000..d8b8e446
--- /dev/null
+++ b/lib/css/font.css
@@ -0,0 +1,16 @@
+:local .font-inherit { font: inherit; }
+
+:local .fontStyle-italic { font-style: italic; }
+:local .fontStyle-normal { font-style: normal; }
+
+:local .fontWeight-100 { font-weight: 100; }
+:local .fontWeight-200 { font-weight: 200; }
+:local .fontWeight-300 { font-weight: 300; }
+:local .fontWeight-400 { font-weight: 400; }
+:local .fontWeight-500 { font-weight: 500; }
+:local .fontWeight-600 { font-weight: 600; }
+:local .fontWeight-700 { font-weight: 700; }
+:local .fontWeight-800 { font-weight: 800; }
+:local .fontWeight-900 { font-weight: 900; }
+:local .fontWeight-bold { font-weight: bold; }
+:local .fontWeight-normal { font-weight: normal; }
diff --git a/lib/css/height.css b/lib/css/height.css
new file mode 100644
index 00000000..c1e77d72
--- /dev/null
+++ b/lib/css/height.css
@@ -0,0 +1,3 @@
+:local .maxHeight-100\% { max-height: 100%; }
+:local .minHeight-100\% { min-height: 100%; }
+:local .height-100\% { height: 100%; }
diff --git a/lib/css/margin.css b/lib/css/margin.css
new file mode 100644
index 00000000..cae44d82
--- /dev/null
+++ b/lib/css/margin.css
@@ -0,0 +1,13 @@
+:local .margin-0 { margin: 0; }
+:local .margin-auto { margin: auto; }
+:local .marginTop-0 { margin-top: 0; }
+:local .marginTop-auto { margin-top: auto; }
+
+:local .marginRight-0 { margin-right: 0; }
+:local .marginRight-auto { margin-right: auto; }
+
+:local .marginBottom-0 { margin-bottom: 0; }
+:local .marginBottom-auto { margin-bottom: auto; }
+
+:local .marginLeft-0 { margin-left: 0; }
+:local .marginLeft-auto { margin-left: auto; }
diff --git a/lib/css/overflow.css b/lib/css/overflow.css
new file mode 100644
index 00000000..5bd8a1c6
--- /dev/null
+++ b/lib/css/overflow.css
@@ -0,0 +1,14 @@
+:local .overflow-auto { overflow: auto; }
+:local .overflow-hidden { overflow: hidden; }
+:local .overflow-scroll { overflow: scroll; }
+:local .overflow-visible { overflow: visible; }
+
+:local .overflowX-auto { overflow-x: auto; }
+:local .overflowX-hidden { overflow-x: hidden; }
+:local .overflowX-scroll { overflow-x: scroll; }
+:local .overflowX-visible { overflow-x: visible; }
+
+:local .overflowY-auto { overflow-y: auto; }
+:local .overflowY-hidden { overflow-y: hidden; }
+:local .overflowY-scroll { overflow-y: scroll; }
+:local .overflowY-visible { overflow-y: visible; }
diff --git a/lib/css/padding.css b/lib/css/padding.css
new file mode 100644
index 00000000..a3c6a823
--- /dev/null
+++ b/lib/css/padding.css
@@ -0,0 +1,17 @@
+:local .padding-0 { padding: 0; }
+:local .paddingTop-0 { padding-top: 0; }
+:local .paddingRight-0 { padding-right: 0; }
+:local .paddingBottom-0 { padding-bottom: 0; }
+:local .paddingLeft-0 { padding-left: 0; }
+
+:local .padding-1em { padding: 1em; }
+:local .paddingTop-1em { padding-top: 1em; }
+:local .paddingRight-1em { padding-right: 1em; }
+:local .paddingBottom-1em { padding-bottom: 1em; }
+:local .paddingLeft-1em { padding-left: 1em; }
+
+:local .padding-1rem { padding: 1rem; }
+:local .paddingTop-1rem { padding-top: 1rem; }
+:local .paddingRight-1rem { padding-right: 1rem; }
+:local .paddingBottom-1rem { padding-bottom: 1rem; }
+:local .paddingLeft-1rem { padding-left: 1rem; }
diff --git a/lib/css/pointerEvents.css b/lib/css/pointerEvents.css
new file mode 100644
index 00000000..3eebef75
--- /dev/null
+++ b/lib/css/pointerEvents.css
@@ -0,0 +1,6 @@
+:local .pointerEvents-auto { pointer-events: auto; }
+:local .pointerEvents-none { pointer-events: none; }
+:local .pointerEvents-box-none { pointer-events: none; }
+:local .pointerEvents-box-none * { pointer-events: auto;}
+:local .pointerEvents-box-only { pointer-events: auto; }
+:local .pointerEvents-box-only * { pointer-events: none; }
diff --git a/lib/css/position.css b/lib/css/position.css
new file mode 100644
index 00000000..680ae4a5
--- /dev/null
+++ b/lib/css/position.css
@@ -0,0 +1,13 @@
+:local .position-absolute { position: absolute; }
+:local .position-fixed { position: fixed; }
+:local .position-relative { position: relative; }
+
+:local .top-0 { top: 0; }
+:local .right-0 { right: 0; }
+:local .left-0 { left: 0; }
+:local .bottom-0 { bottom: 0; }
+
+:local .top-100\% { top: 100%; }
+:local .right-100\% { right: 100%; }
+:local .left-100\% { left: 100%; }
+:local .bottom-100\% { bottom: 100%; }
diff --git a/lib/css/text.css b/lib/css/text.css
new file mode 100644
index 00000000..8297842f
--- /dev/null
+++ b/lib/css/text.css
@@ -0,0 +1,14 @@
+:local .textAlign-center { text-align: center; }
+:local .textAlign-left { text-align: left; }
+:local .textAlign-right { text-align: right; }
+:local .textAlign-justify { text-align: justify; }
+
+:local .textDecoration-none { text-decoration: none; }
+:local .textDecoration-underline { text-decoration: underline; }
+
+:local .textOverflow-ellipsis { text-overflow: ellipsis }
+
+:local .textTransform-capitalize { text-transform: capitalize; }
+:local .textTransform-lowercase { text-transform: lowercase; }
+:local .textTransform-none { text-transform: none; }
+:local .textTransform-uppercase { text-transform: uppercase; }
diff --git a/lib/css/userSelect.css b/lib/css/userSelect.css
new file mode 100644
index 00000000..984d95ad
--- /dev/null
+++ b/lib/css/userSelect.css
@@ -0,0 +1,3 @@
+:local .userSelect-all { user-select: all; }
+:local .userSelect-inherit { user-select: inherit; }
+:local .userSelect-none { user-select: none; }
diff --git a/lib/css/visibility.css b/lib/css/visibility.css
new file mode 100644
index 00000000..503f317c
--- /dev/null
+++ b/lib/css/visibility.css
@@ -0,0 +1,2 @@
+:local .visibility-hidden { visibility: hidden; }
+:local .visibility-visible { visibility: visible; }
diff --git a/lib/css/whiteSpace.css b/lib/css/whiteSpace.css
new file mode 100644
index 00000000..8ec64086
--- /dev/null
+++ b/lib/css/whiteSpace.css
@@ -0,0 +1,3 @@
+:local .whiteSpace-normal { white-space: normal; }
+:local .whiteSpace-nowrap { white-space: nowrap; }
+:local .whiteSpace-pre { white-space: pre; }
diff --git a/lib/css/width.css b/lib/css/width.css
new file mode 100644
index 00000000..60788def
--- /dev/null
+++ b/lib/css/width.css
@@ -0,0 +1,3 @@
+:local .maxWidth-100\% { max-width: 100%; }
+:local .minWidth-100\% { min-width: 100%; }
+:local .width-100\% { width: 100%; }
diff --git a/lib/css/word.css b/lib/css/word.css
new file mode 100644
index 00000000..ac39c258
--- /dev/null
+++ b/lib/css/word.css
@@ -0,0 +1,2 @@
+:local .wordWrap-break-word { word-wrap: break-word; }
+:local .wordWrap-normal { word-wrap: normal; }
diff --git a/lib/css/zIndex.css b/lib/css/zIndex.css
new file mode 100644
index 00000000..a261fad3
--- /dev/null
+++ b/lib/css/zIndex.css
@@ -0,0 +1,12 @@
+:local .zIndex--1 { z-index: -1; }
+:local .zIndex-0 { z-index: 0; }
+:local .zIndex-1 { z-index: 1; }
+:local .zIndex-2 { z-index: 2; }
+:local .zIndex-3 { z-index: 3; }
+:local .zIndex-4 { z-index: 4; }
+:local .zIndex-5 { z-index: 5; }
+:local .zIndex-6 { z-index: 6; }
+:local .zIndex-7 { z-index: 7; }
+:local .zIndex-8 { z-index: 8; }
+:local .zIndex-9 { z-index: 9; }
+:local .zIndex-10 { z-index: 10; }
diff --git a/lib/getOtherProps.js b/lib/getOtherProps.js
new file mode 100644
index 00000000..a0cd4c6c
--- /dev/null
+++ b/lib/getOtherProps.js
@@ -0,0 +1,37 @@
+/**
+ * Extract all props that are not part of the React Component's 'propTypes'
+ */
+export default (componentInstance) => {
+ const excludedProps = Object.keys(componentInstance.constructor.propTypes);
+ return objectWithoutProps(componentInstance.props, excludedProps);
+};
+
+function objectFilterProps(obj, props, excluded=false) {
+ if (!Array.isArray(props)) {
+ throw new TypeError('props is not an Array');
+ }
+
+ let filtered = {};
+ for (let prop in obj) {
+ if (Object.prototype.hasOwnProperty.call(obj, prop)) {
+ let isMatch = props.indexOf(prop) > -1;
+ if (excluded && isMatch) {
+ continue;
+ } else if (!excluded && !isMatch) {
+ continue;
+ }
+
+ filtered[prop] = obj[prop];
+ }
+ }
+
+ return filtered;
+}
+
+export function objectWithProps(obj, props) {
+ return objectFilterProps(obj, props);
+}
+
+export function objectWithoutProps(obj, props) {
+ return objectFilterProps(obj, props, true);
+}
diff --git a/lib/styleMap.js b/lib/styleMap.js
new file mode 100644
index 00000000..e4c5ac75
--- /dev/null
+++ b/lib/styleMap.js
@@ -0,0 +1,47 @@
+import border from './css/border.css';
+import boxSizing from './css/boxSizing.css';
+import clear from './css/clear.css';
+import color from './css/color.css';
+import cssFloat from './css/float.css';
+import direction from './css/direction.css';
+import display from './css/display.css';
+import flexbox from './css/flexbox.css';
+import font from './css/font.css';
+import height from './css/height.css';
+import margin from './css/margin.css';
+import overflow from './css/overflow.css';
+import padding from './css/padding.css';
+import pointerEvents from './css/pointerEvents.css';
+import position from './css/position.css';
+import text from './css/text.css';
+import userSelect from './css/userSelect.css';
+import visibility from './css/visibility.css';
+import whiteSpace from './css/whiteSpace.css';
+import width from './css/width.css';
+import word from './css/word.css';
+
+const map = Object.assign({},
+ border,
+ boxSizing,
+ clear,
+ color,
+ cssFloat,
+ direction,
+ display,
+ flexbox,
+ font,
+ height,
+ margin,
+ overflow,
+ padding,
+ pointerEvents,
+ position,
+ text,
+ userSelect,
+ visibility,
+ whiteSpace,
+ width,
+ word
+);
+
+export default map;
diff --git a/package.json b/package.json
index 939647b2..8c307a44 100644
--- a/package.json
+++ b/package.json
@@ -3,6 +3,28 @@
"version": "0.0.1",
"description": "UI SDK based on react-native",
"main": "index.js",
+ "scripts": {
+ "build": "npm run build:package & npm run build:example",
+ "build:example": "webpack index.js dist/main.js --config webpack.config.js",
+ "build:example:watch": "npm run build:example -- --watch",
+ "build:package": "webpack example.js dist/example.js --config webpack.config.js",
+ "build:package:watch": "npm run build:package -- --watch",
+ "build:watch": "npm run build:package:watch & npm run build:example:watch"
+ },
"author": "Nicolas Gallagher",
- "license": "MIT"
+ "license": "MIT",
+ "devDependencies": {
+ "autoprefixer-core": "^5.2.0",
+ "babel-core": "^5.5.6",
+ "babel-loader": "^5.1.4",
+ "babel-runtime": "^5.5.6",
+ "css-loader": "^0.14.4",
+ "node-libs-browser": "^0.5.2",
+ "postcss-loader": "^0.4.4",
+ "style-loader": "^0.12.3",
+ "webpack": "^1.9.10"
+ },
+ "dependencies": {
+ "react": "^0.13.3"
+ }
}
diff --git a/webpack.config.js b/webpack.config.js
new file mode 100644
index 00000000..5950195f
--- /dev/null
+++ b/webpack.config.js
@@ -0,0 +1,19 @@
+var autoprefixer = require('autoprefixer-core');
+
+module.exports = {
+ module: {
+ loaders: [
+ {
+ test: /\.css$/,
+ loader: 'style-loader!css-loader?localIdentName=[hash:base64:5]!postcss-loader'
+ },
+ {
+ test: /\.jsx?$/,
+ exclude: /node_modules/,
+ loader: 'babel-loader',
+ query: { cacheDirectory: true }
+ }
+ ]
+ },
+ postcss: [ autoprefixer ]
+};