diff --git a/README.md b/README.md
index 62bc9e82..8e0cd18f 100644
--- a/README.md
+++ b/README.md
@@ -2,29 +2,67 @@
**Experimental / Proof of concept**
-A component-based React SDK for building and styling web applications and SDKs.
-Inspired by `react-native`.
+A React SDK for creating web applications and toolkits. Inspired by `react-native`.
-This library provides:
+It includes the following components:
-* An initial implementation of the `react-native` components `Image`, `Text`,
- and `View`.
-* An initial implementation of defining explicit and default `style` propTypes.
-* A proof of concept implementation for converting inline `style` definitions
- to CSS classes.
+* `View`: a flexbox primitive
+* `Text`: a text primitive
+* `Image`: an image primitive
+* (`Component`: base / implementation)
+
+And uses a [styling strategy](docs/styling-strategy.md) that maps inline styles
+to single-purpose CSS rules.
This proof of concept uses a ~3KB (gzipped) precomputed CSS bundle; a complete
implementation is likely to produce a slightly larger CSS file and fewer inline
styles.
-Other React styling strategies:
-[react-native](https://facebook.github.io/react-native/),
-[react-style](https://github.com/js-next/react-style),
-[jsxstyle](https://github.com/petehunt/jsxstyle),
-[react-inline](https://github.com/martinandert/react-inline), and
-[react-free-style](https://github.com/blakeembrey/react-free-style/)
+## Components
-### 1. Write styles using plain JavaScript objects
+All components define explicit `style` PropTypes according to the [`StyleProp`
+spec](docs/StyleProp.spec.md).
+
+### Component
+
+TODO
+
+[`Component`](docs/Component.md)
+
+### View
+
+TODO
+
+A flexbox container; foundational layout building block.
+
+[`View` spec](docs/View.spec.md)
+
+See this [guide to flexbox](https://css-tricks.com/snippets/css/a-guide-to-flexbox/).
+
+### Text
+
+TODO
+
+[`Text` spec](docs/View.spec.md)
+
+### Image
+
+TODO
+
+[`Image` spec](docs/View.spec.md)
+
+## Styling
+
+Styling is identical to using inline styles in React, but most inline styles
+are converted to unique CSS classes. **This is only true for the SDK
+components**.
+
+The companion stylesheet can be referenced as an external resource, inlined, or
+injected by JS.
+
+See the [styling strategy docs](docs/styling-strategy.md) for more details.
+
+### Use plain JavaScript objects
Use JavaScript to write style definitions in React components:
@@ -47,22 +85,23 @@ const style = {
};
```
-### 2. Set styles using the `style` attribute
+### Use the `style` attribute
The `style` attribute is a simple API for creating element-scoped styles.
```js
-...
+import {View} from 'react-web-sdk';
-
- ...
-...
+ );
+ }
+}
```
-It's easy to combine and override style objects:
+Combine and override style objects:
```js
import baseStyle from './baseStyle';
@@ -74,461 +113,20 @@ const buttonStyle = {
}
```
-So far, this is identical to using inline styles in a React component.
-
-### 3. Map inline styles to static CSS rules
-
-Using the `style` attribute would normally produce inline styles. Libraries
-like [react-style](https://github.com/js-next/react-style) implement a
-`Stylesheet.create` API and provide a means to extract styles to CSS at build
-time. The extraction maps whole style objects to multi-declaration CSS rules.
-
-For example:
-
-```js
-// relies on a new construct
-Stylesheet.create({
- root: {
- background: 'transparent',
- display: 'flex',
- flexGrow: 1,
- justifyContent: 'center'
- }
-});
-```
-
-Yields:
-
-```css
-/* produces new css for every new style rule */
-.foo {
- background: transparent;
- display: flex;
- flex-grow: 1;
- justify-content: center;
-}
-```
-
-Each component adds new rules to the stylesheet. This can lead the extracted
-stylesheet to become increasingly large and prone to change.
-
-Libraries like [Atomic CSS](http://acss.io/),
-[Basscss](http://www.basscss.com/), [SUIT CSS](https://suitcss.github.io/), and
-[tachyons](http://tachyons.io/) are attempts to limit style scope and limit
-stylesheet growth. But they are CSS utility libraries, each with a particular
-set of classes and features to learn. All of them require developers to
-manually connect CSS classes for given styles.
-
-The `react-web-sdk` library's implementation is a proof-of-concept for the
-strategy of automatically mapping style `key`-`value` pairs to
-single-declaration CSS rules.
-
-```css
-.background-transparent { background: transparent }
-.display-block { display: block }
-.flexGrow-1 { flex-grow: 1 }
-.justifyContent-center { justify-content: center }
-```
-
-Mapping declarations to single-purpose classes greatly reduces the total amount
-of CSS needed. It avoids the repetition of declarations between rules for
-unrelated elements, and prevents style collisions. A build step hashes the class names.
-
-```html
-
...
-```
-
-The current implementation uses a precomputed CSS library of known and common
-declarations – 200+ single-declaration rules, with obfuscated selectors. This
-handles a signficant portion of possible declarations. But it falls through to
-inline styles significantly more often than an better implementation using
-static analysis to generate the CSS library at build time.
-
-### 4. Use inline styles for dynamic values
-
-Inline styles are used for values that cannot be resolved at build time.
-
-```js
- 0.5 ? 'red' : 'black')}}>...
-```
-
-### 5. Add `style` prop types
-
-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.
-
-See the section below on `StylePropTypes`.
-
-### Media Queries?
-
-We can use `mediaMatch` to orchestrate both style and DOM changes. The
-component can be re-rendered when the styles change. This also avoids the need
-for additional CSS. Adding media queries as keys on the `style` object (like
-`react-style` does) might be a good, or it might not be. I'd prefer a solution
-that accomodates both style and DOM changes, rather than one or the other.
-Perhaps `this.context` or a higher-order component that passes viewport data to
-components via `props`.
-
----
-
-## Components
-
-### `Component`
-
-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
-import {Component, pickProps} from 'react-web-sdk';
-import React, {PropTypes} from 'react';
-
-const ExampleStylePropTypes = { opacity: PropTypes.number };
-const ExampleStyleDefaultProps = { opacity: 1 };
-
-class Example extends React.Component {
- static propTypes = {
- style: PropTypes.shape(ExampleStylePropTypes)
- }
-
- render() {
- // only apply supported styles
- const supportedStyle = pickProps(this.props.style, ExampleStylePropTypes);
- // merge with default styles
- const style = { ...ExampleStyleDefaultProps, ...supportedStyle }
-
- return (
-
- );
- }
-}
-```
-
-
-### `Image`
-
-TODO
-
-#### PropTypes
-
-All other props are transferred directly to the `element`.
-
-+ `accessibilityLabel`: `string`
-+ `async`: `bool` (TODO)
-+ `className`: `string`
-+ `source`: `string`
-+ `style`: `ImageStylePropTypes`
-
-#### ImageStylePropTypes
-
-+ `BackgroundPropTypes`
-+ `BorderThemePropTypes`
-+ `LayoutPropTypes`
-+ `opacity`: `string`
-
-#### Examples
-
-```js
-import {Image, StylePropTypes} from 'react-web-sdk';
-import React, {PropTypes} from 'react';
-
-const AvatarStylePropTypes = {
- ...StylePropTypes.BorderThemePropTypes
-};
-
-const AvatarStyleDefaultProps = {
- borderColor: 'white',
- borderWidth: '5px'
-};
-
-class Avatar extends React.Component {
- static propTypes = {
- size: PropTypes.oneOf(['small', 'normal', 'large']),
- style: PropTypes.shape(AvatarStylePropTypes),
- user: PropTypes.object
- }
-
- static defaultProps = {
- size: 'normal'
- }
-
- render() {
- const supportedStyle = pickProps(this.props.style, AvatarStylePropTypes);
- const style = { ...AvatarStyleDefaultProps, ...supportedStyle }
-
- return (
-
- );
- }
-}
-```
-
-
-### `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
-
-#### Examples
-
-```js
-import {StylePropTypes, Text} from 'react-web-sdk';
-import React, {PropTypes} from 'react';
-
-class PrettyText extends React.Component {
- static propTypes = {
- color: PropTypes.oneOf(['white', 'gray', 'red']),
- size: PropTypes.oneOf(['small', 'normal', 'large']),
- weight: PropTypes.oneOf(['light', 'normal', 'bold'])
- }
-
- static defaultProps = {
- color: 'gray',
- size: 'normal',
- weight: 'normal'
- }
-
- render() {
- const { color, size, style, weight, ...other } = this.props;
-
- return (
-
- );
- }
-}
-
-const localStyle = {
- 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' }
- }
-}
-```
-
-
-### `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
-```
-
----
-
## Utilities
-### Object property filtering
+#### `getOtherProps(reactComponentInstance)`
-Create a new object that includes or excludes a list of properties.
+Returns an object containing all the props from `this.props` that are not
+defined in `propTypes`.
-* `.getOtherProps(reactComponentInstance)` (strips propTypes from `this.props`)
-* `.pickProps(obj, arrayOfIncludedProps)`
-* `.omitProps(obj, arrayOfExcludedProps)`
+#### `omitProps(obj, arrayOfExcludedProps)`
----
+Returns an object with the specified props excluded.
-## StylePropTypes
+#### `pickProps(obj, arrayOfIncludedProps)`
-### 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')`
-
----
+Returns an object with the specified props included.
## Development
diff --git a/docs/Component.md b/docs/Component.md
new file mode 100644
index 00000000..c7183bf0
--- /dev/null
+++ b/docs/Component.md
@@ -0,0 +1,44 @@
+# `Component`
+
+This component is part of the implementation for managing styles across the
+`className` and `style` properties. It is the building block upon which all
+other components in `react-web-sdk` are built.
+
+## PropTypes
+
+All other props are transferred directly to the `element`.
+
++ `element`: `func` or `string`
++ `style`: `object`
+
+#### Examples
+
+```js
+import {Component, pickProps} from 'react-web-sdk';
+import React, {PropTypes} from 'react';
+
+const ExampleStylePropTypes = { opacity: PropTypes.number };
+const ExampleStyleDefaultProps = { opacity: 1 };
+
+class Example extends React.Component {
+ static propTypes = {
+ style: PropTypes.shape(ExampleStylePropTypes)
+ }
+
+ render() {
+ const { style, ...other } = this.props;
+ // only apply supported styles
+ const supportedStyle = pickProps(style, ExampleStylePropTypes);
+ // merge with default styles
+ const mergedStyle = { ...ExampleStyleDefaultProps, ...supportedStyle }
+
+ return (
+
+ );
+ }
+}
+```
diff --git a/docs/Image.spec.md b/docs/Image.spec.md
new file mode 100644
index 00000000..0cdf8fa6
--- /dev/null
+++ b/docs/Image.spec.md
@@ -0,0 +1,66 @@
+# Image spec
+
+#### PropTypes
+
+All other props are transferred directly to the `element`.
+
++ `accessibilityLabel`: `string`
++ `async`: `bool` (TODO)
++ `className`: `string`
++ `source`: `string`
++ `style`: `ImageStylePropTypes`
+
+#### ImageStylePropTypes
+
++ `BackgroundPropTypes`
++ `BorderThemePropTypes`
++ `LayoutPropTypes`
++ `opacity`: `string`
+
+#### Examples
+
+```js
+import {Image} from 'react-web-sdk';
+import React, {PropTypes} from 'react';
+
+class Avatar extends React.Component {
+ static propTypes = {
+ size: PropTypes.oneOf(['small', 'normal', 'large']),
+ user: PropTypes.object
+ }
+
+ static defaultProps = {
+ size: 'normal'
+ }
+
+ render() {
+ return (
+
+ );
+ }
+}
+
+const style = {
+ base: {
+ borderColor: 'white',
+ borderRadius: '5px',
+ borderWidth: '5px'
+ },
+ small: {
+ height: '32px',
+ width: '32px'
+ },
+ normal: {
+ height: '48px',
+ width: '48px'
+ },
+ large: {
+ height: '64px',
+ width: '32px'
+ }
+}
+```
diff --git a/docs/StyleProp.spec.md b/docs/StyleProp.spec.md
new file mode 100644
index 00000000..cf88300e
--- /dev/null
+++ b/docs/StyleProp.spec.md
@@ -0,0 +1,89 @@
+## StyleProp spec
+
+### 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')`
+* `flex`: `string`
+* `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`
+
+### 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')`
+
diff --git a/docs/Text.spec.md b/docs/Text.spec.md
new file mode 100644
index 00000000..08bef696
--- /dev/null
+++ b/docs/Text.spec.md
@@ -0,0 +1,70 @@
+# Text spec
+
+Text layout and styles.
+
+#### PropTypes
+
+All other props are transferred directly to the `element`.
+
++ `element`: `func` or `string` (default `"div"`)
++ `style`: `TextStylePropTypes`
+
+#### TextStylePropTypes
+
++ ViewStylePropTypes
++ TypographicPropTypes
+
+## Examples
+
+```js
+import {Text} from 'react-web-sdk';
+import React, {PropTypes} from 'react';
+
+class PrettyText extends React.Component {
+ static propTypes = {
+ color: PropTypes.oneOf(['white', 'gray', 'red']),
+ size: PropTypes.oneOf(['small', 'normal', 'large']),
+ weight: PropTypes.oneOf(['light', 'normal', 'bold'])
+ }
+
+ static defaultProps = {
+ color: 'gray',
+ size: 'normal',
+ weight: 'normal'
+ }
+
+ render() {
+ const { color, size, style, weight, ...other } = this.props;
+
+ return (
+
+ );
+ }
+}
+
+const localStyle = {
+ 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' }
+ }
+}
+```
diff --git a/docs/View.spec.md b/docs/View.spec.md
new file mode 100644
index 00000000..12c39fcc
--- /dev/null
+++ b/docs/View.spec.md
@@ -0,0 +1,66 @@
+# View spec
+
+`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`.
+
++ `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).
+
+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`.
+
+```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
+};
+```
+
+## Examples
+
+```js
+// TODO
+```
diff --git a/docs/sdk-components.png b/docs/sdk-components.png
new file mode 100644
index 00000000..66da579a
Binary files /dev/null and b/docs/sdk-components.png differ
diff --git a/docs/sdk-styling-strategy.png b/docs/sdk-styling-strategy.png
new file mode 100644
index 00000000..850ef677
Binary files /dev/null and b/docs/sdk-styling-strategy.png differ
diff --git a/docs/styling-strategy.md b/docs/styling-strategy.md
new file mode 100644
index 00000000..66f03c92
--- /dev/null
+++ b/docs/styling-strategy.md
@@ -0,0 +1,126 @@
+# Styling strategy
+
+Using the `style` attribute would normally produce inline styles. There are
+several existing approaches to using the `style` attribute, some of which
+convert inline styles to static CSS:
+[jsxstyle](https://github.com/petehunt/jsxstyle),
+[react-free-style](https://github.com/blakeembrey/react-free-style/),
+[react-inline](https://github.com/martinandert/react-inline),
+[react-native](https://facebook.github.io/react-native/),
+[react-style](https://github.com/js-next/react-style),
+[stilr](https://github.com/kodyl/stilr).
+
+## Style syntax: native vs proprietary data structure
+
+React Web SDK (in a divergence from React Native) represents style using plain
+JS objects:
+
+```js
+...
+
+const styles = {
+ root: {
+ background: 'transparent',
+ display: 'flex',
+ flexGrow: 1,
+ justifyContent: 'center'
+ }
+};
+```
+
+Most approaches to managing style in React introduce a proprietary data
+structure, often via an implementation of `Stylesheet.create`.
+
+```js
+...
+
+const styles = Stylesheet.create({
+ root: {
+ background: 'transparent',
+ display: 'flex',
+ flexGrow: 1,
+ justifyContent: 'center'
+ }
+});
+```
+
+## JS-to-CSS: conversion strategies
+
+One strategy for converting styles from JS to CSS is to map style objects to
+CSS rules. Another strategy is to map declarations to declarataions.
+
+
+
+Mapping entire `style` objects to CSS rules can lead to increasingly large CSS
+files. Each new component adds new rules to the stylesheet.
+
+React Web SDK includes a proof-of-concept for the strategy of automatically
+mapping unique declarations to declarations, via a unique selector for each
+declaration. This strategy results in smaller CSS files because an application
+has fewer unique declarations than total declarations. Creating a new
+component with no new unique declarations results in no change to the CSS file.
+
+For example:
+
+```js
+...
+
+const styles = {
+ root: {
+ background: 'transparent',
+ display: 'flex',
+ flexGrow: 1,
+ justifyContent: 'center'
+ }
+};
+```
+
+Yields:
+
+```html
+...
+```
+
+And is backed by:
+
+```css
+._abcde { background: transparent }
+._fghij { display: flex }
+._klmno { flex-grow: 1 }
+._pqrst { justify-content: center }
+```
+
+The current implementation uses a precomputed CSS library – 200+
+single-declaration rules, with obfuscated selectors. This handles a signficant
+portion of possible declarations. But a build-time implementation would produce
+more accurate CSS files and fall through to inline styles significantly less
+often.
+
+
+(CSS libraries like [Atomic CSS](http://acss.io/),
+[Basscss](http://www.basscss.com/), [SUIT CSS](https://suitcss.github.io/), and
+[tachyons](http://tachyons.io/) are attempts to limit style scope and limit
+stylesheet growth in a similar way. But they're CSS utility libraries, each with a
+particular set of classes and features to learn. All of them require developers
+to manually connect CSS classes for given styles.)
+
+## Dynamic styles: use inline styles
+
+Some styles cannot be resolved ahead of time and continue to rely on inline
+styles:
+
+```js
+ 0.5 ? 'red' : 'black') }}>...
+```
+
+## Media Queries, pseudo-classes, and pseudo-elements
+
+Media Queries could be replaced with `mediaMatch`. This would have the added
+benefit of co-locating breakpoint-specific DOM and style changes. Perhaps Media
+Query data could be accessed on `this.content`?
+
+Pseudo-classes like `:hover` and `:focus` can be handled with JavaScript.
+
+Pseudo-elements should be avoided in general, but for particular cases like
+`::placeholder` it might be necessary to reimplement it in the SDK's
+`TextInput` component (see React Native's API).
diff --git a/example.js b/example.js
index 2b155732..91fd0e1b 100644
--- a/example.js
+++ b/example.js
@@ -8,7 +8,7 @@ class Example extends React.Component {
{[1,2,3,4,5,6].map((item) => {
return (
- {item}
+ {item}
);
})}
diff --git a/lib/components/Component.js b/lib/components/Component.js
index f3d97661..14f5f01b 100644
--- a/lib/components/Component.js
+++ b/lib/components/Component.js
@@ -48,10 +48,8 @@ class Component extends React.Component {
}
_separateClassNamesAndStyles() {
- const classNameProp = this.props.className;
const styleProp = this.props.style;
-
- let classNames = [ classNameProp ];
+ let classNames = [ this.props.className ];
let inlineStyles = {};
for (let prop in styleProp) {