diff --git a/README.md b/README.md
index 1492b707..9d28151a 100644
--- a/README.md
+++ b/README.md
@@ -1,10 +1,10 @@
# React Native for Web
[![Build Status][travis-image]][travis-url]
-[![npm version][npm-image]][npm-url] (14 KB gzipped)
+[![npm version][npm-image]][npm-url]
-The core [React Native][react-native-url] components built for the web, backed
-by a precomputed CSS library.
+The core [React Native][react-native-url] components adapted and expanded upon
+for the web, backed by a precomputed CSS library. ~19KB minified and gzipped.
## Table of contents
@@ -50,19 +50,46 @@ const styles = {
## Components
-Partial implementations of…
+### [`Image`](docs/components/Image.md)
-* [`Image`](docs/components/Image.md)
-* [`Text`](docs/components/Text.md)
-* [`TextInput`](docs/components/TextInput.md)
-* [`View`](docs/components/View.md)
+An accessibile image component with support for image resizing, default image,
+and child content.
+
+### [`ListView`](docs/components/ListView.md)
+
+(TODO)
+
+### [`ScrollView`](docs/components/ListView.md)
+
+(TODO)
+
+### [`Swipeable`](docs/components/Swipeable.md)
+
+Touch bindings for swipe gestures.
+
+### [`Text`](docs/components/Text.md)
+
+Displays text as an inline block and supports basic press handling.
+
+### [`TextInput`](docs/components/TextInput.md)
+
+Accessible single- and multi-line text input via a keyboard. Supports features
+
+### [`Touchable`](docs/components/Touchable.md)
+
+Touch bindings for press and long press.
+
+### [`View`](docs/components/View.md)
+
+The fundamental UI building block: layout with flexbox, layout and positioning
+styles, and accessibility controls.
## Styling
-React Native Web provides a mechanism to declare all your styles and layout
-inline with the components that use them. The `View` component makes it easy
-to build common layouts with flexbox, such as stacked and nested boxes with
-margin and padding.
+React Native for Web provides a mechanism to declare all your styles and layout
+inline with the components that use them. The `View` component makes it easy to
+build common layouts with flexbox, such as stacked and nested boxes with margin
+and padding.
Styling is identical to using inline styles in React, but most inline styles
are converted to single-purpose classes. The current implementation includes
@@ -70,7 +97,7 @@ are converted to single-purpose classes. The current implementation includes
proportion of common styles. A more sophisticated build-time implementation may
produce a slightly larger CSS file for large apps, and fall back to fewer
inline styles. Read more about the [styling
-strategy](docs/react-native-web-style/styling.md).
+strategy](docs/style.md).
See this [guide to flexbox][flexbox-guide-url].
@@ -144,6 +171,11 @@ welcome!
Thanks to current and past members of the React and React Native teams (in
particular Vjeux and Pete Hunt), and Tobias Koppers for Webpack and CSS loader.
+Thanks to [react-swipeable](https://github.com/dogfessional/react-swipeable/)
+for the current implementation of `Swipeable`, and to
+[react-tappable](https://github.com/JedWatson/react-tappable) for backing the
+current implementation of `Touchable`.
+
## License
Copyright (c) 2015 Nicolas Gallagher. Released under the [MIT
diff --git a/docs/components/Image.md b/docs/components/Image.md
index 01ddbeec..0596f9d2 100644
--- a/docs/components/Image.md
+++ b/docs/components/Image.md
@@ -1,30 +1,82 @@
-# Image spec
+# Image
-#### PropTypes
+An accessibile image component with support for image resizing, default image,
+and child content.
-All other props are transferred to the resulting `img`.
+## Props
-+ `accessibilityLabel`: `string`
-+ `source`: `object`
-+ `style`: `ImageStylePropTypes`
+**accessibilityLabel** string
-#### ImageStylePropTypes
+The text that's read by the screen reader when the user interacts with the image.
-+ `BackgroundPropTypes`
-+ `BorderThemePropTypes`
-+ `LayoutPropTypes`
-+ `opacity`: `string`
+**children** any
-#### Examples
+Content to display over the image.
+
+**defaultSource** { uri: string }
+
+An image to display as a placeholder while downloading the final image off the network.
+
+**onError** function
+
+Invoked on load error with `{nativeEvent: {error}}`.
+
+**onLoad** function
+
+Invoked when load completes successfully.
+
+**onLoadEnd** function
+
+Invoked when load either succeeds or fails,
+
+**onLoadStart** function
+
+Invoked on load start.
+
+**resizeMode** oneOf('clip', 'contain', 'cover', 'stretch')
+
+Determines how to resize the image when the frame doesn't match the raw image
+dimensions. Default: `cover`.
+
+**source** { uri: string }
+
+`uri` is a string representing the resource identifier for the image, which
+could be an http address or a base64 encoded image.
+
+**style** style
+
+[View](docs/components/View) style
+
+Defaults:
```js
+{
+ alignSelf: 'flex-start',
+ backgroundColor: 'lightGray'
+}
+```
+
+**testID** string
+
+Used to locate a view in end-to-end tests.
+
+## Examples
+
+```js
+import placeholderAvatar from './placeholderAvatar.png'
import React, { Image } from 'react-native-web'
const { Component, PropTypes } = React;
class Avatar extends Component {
+ constructor(props, context) {
+ super(props, context)
+ this.state = { isLoaded: false }
+ }
+
static propTypes = {
size: PropTypes.oneOf(['small', 'normal', 'large']),
+ testID: Image.propTypes.testID,
user: PropTypes.object
}
@@ -32,12 +84,23 @@ class Avatar extends Component {
size: 'normal'
}
+ _onLoad(e) {
+ console.log('Avatar.onLoad', e)
+ this.setState({ isLoaded: true })
+ }
+
render() {
+ const { size, testID, user } = this.props
+ const { isLoaded } = this.state
+
return (
)
}
@@ -47,7 +110,8 @@ const style = {
base: {
borderColor: 'white',
borderRadius: '5px',
- borderWidth: '5px'
+ borderWidth: '5px',
+ opacity: 0.5,
},
small: {
height: '32px',
@@ -59,7 +123,10 @@ const style = {
},
large: {
height: '64px',
- width: '32px'
+ width: '64px'
+ }
+ isLoaded: {
+ opacity: 1
}
}
```
diff --git a/docs/components/ListView.md b/docs/components/ListView.md
new file mode 100644
index 00000000..8cbdbb3a
--- /dev/null
+++ b/docs/components/ListView.md
@@ -0,0 +1,41 @@
+# ListView
+
+## Props
+
+**children** any
+
+Content to display over the image.
+
+**style** style
+
++ `property` type
+
+Defaults:
+
+```js
+{
+}
+```
+
+
+## Examples
+
+```js
+import React, { ListView } from 'react-native-web'
+
+const { Component, PropTypes } = React;
+
+class Example extends Component {
+ static propTypes = {
+ }
+
+ static defaultProps = {
+ }
+
+ render() {
+ return (
+
+ )
+ }
+}
+```
diff --git a/docs/components/ScrollView.md b/docs/components/ScrollView.md
new file mode 100644
index 00000000..b2d58c3e
--- /dev/null
+++ b/docs/components/ScrollView.md
@@ -0,0 +1,40 @@
+# ScrollView
+
+## Props
+
+**children** any
+
+Content to display over the image.
+
+**style** style
+
++ `property` type
+
+Defaults:
+
+```js
+{
+}
+```
+
+
+## Examples
+
+```js
+import React, { ScrollView } from 'react-native-web'
+
+const { Component, PropTypes } = React;
+
+class Example extends Component {
+ static propTypes = {
+ }
+
+ static defaultProps = {
+ }
+
+ render() {
+ return (
+ )
+ }
+}
+```
diff --git a/docs/components/Swipeable.md b/docs/components/Swipeable.md
new file mode 100644
index 00000000..fce5a49d
--- /dev/null
+++ b/docs/components/Swipeable.md
@@ -0,0 +1,93 @@
+# Swipeable
+
+## Props
+
+**delta** number
+
+Number of pixels that must be swiped before events are dispatched. Default: `10`.
+
+**flickThreshold** number
+
+The velocity threshold at which a swipe is considered a flick. Default: `0.6`.
+
+**onSwiped** function
+
+(SyntheticTouchEvent, deltaX, deltaY, isFlick) => swipeHandler
+
+Called once a swipe has ended.
+
+**onSwipedDown** function
+
+(SyntheticTouchEvent, delta, isFlick) => swipeHandler
+
+Called once a swipe-down has ended.
+
+**onSwipedLeft** function
+
+(SyntheticTouchEvent, delta, isFlick) => swipeHandler
+
+Called once a swipe-left has ended.
+
+**onSwipedUp** function
+
+(SyntheticTouchEvent, delta, isFlick) => swipeHandler
+
+Called once a swipe-up has ended.
+
+**onSwipedRight** function
+
+(SyntheticTouchEvent, delta, isFlick) => swipeHandler
+
+Called once a swipe-right has ended.
+
+**onSwipingDown** function
+
+(SyntheticTouchEvent, delta, isFlick) => swipeHandler
+
+Called while a swipe-down is in progress.
+
+**onSwipingLeft** function
+
+(SyntheticTouchEvent, delta, isFlick) => swipeHandler
+
+Called while a swipe-left is in progress.
+
+**onSwipingRight** function
+
+(SyntheticTouchEvent, delta, isFlick) => swipeHandler
+
+Called while a swipe-right is in progress.
+
+**onSwipingUp** function
+
+(SyntheticTouchEvent, delta, isFlick) => swipeHandler
+
+Called while a swipe-up is in progress.
+
+## Examples
+
+```js
+import React, { Swipeable } from 'react-native-web'
+
+const { Component, PropTypes } = React;
+
+class Example extends Component {
+ static propTypes = {
+ }
+
+ static defaultProps = {
+ }
+
+ _onSwiped(event, x, y, isFlick) {
+
+ }
+
+ render() {
+ return (
+
+ )
+ }
+}
+```
diff --git a/docs/components/Text.md b/docs/components/Text.md
index 151c345b..03505a8e 100644
--- a/docs/components/Text.md
+++ b/docs/components/Text.md
@@ -1,18 +1,55 @@
-# Text spec
+# Text
-Text layout and styles.
+`Text` is component for displaying text. It supports style, basic touch
+handling, and inherits typographic styles from ancestor elements. In a
+divergence from React Native, components other than `Text` can be children of a
+`Text` component.
-#### PropTypes
+The `Text` is unique relative to layout: child elements use text layout
+(`inline-block`) rather than flexbox layout. This means that elements inside of
+a `Text` are not rectangles, as they wrap when reaching the edge of their
+container.
-All other props are transferred directly to the `component`.
+## Props
-+ `component`: `func` or `string` (default `'div'`)
-+ `style`: `TextStylePropTypes`
+**children** any
-#### TextStylePropTypes
+Child content
-+ ViewStylePropTypes
-+ TypographicPropTypes
+**component** function, string
+
+Default is `span`.
+
+**numberOfLines** number
+
+Truncates the text with an ellipsis after this many lines.
+
+**onPress** function
+
+This function is called on press.
+
+**style** style
+
++ `backgroundColor`
++ `color`
++ `direction`
++ `fontFamily`
++ `fontSize`
++ `fontStyle`
++ `fontWeight`
++ `letterSpacing`
++ `lineHeight`
++ `margin`
++ `padding`
++ `textAlign`
++ `textDecoration`
++ `textTransform`
++ `whiteSpace`
++ `wordWrap`
+
+**testID** string
+
+Used to locate this view in end-to-end tests.
## Examples
diff --git a/docs/components/TextInput.md b/docs/components/TextInput.md
index 7dbd296e..f5a12d44 100644
--- a/docs/components/TextInput.md
+++ b/docs/components/TextInput.md
@@ -1,15 +1,111 @@
-# TextInput spec
+# TextInput
-Text input layout and styles.
+Accessible single- and multi-line text input via a keyboard. Supports features
+such as auto-complete, auto-focus, placeholder text, and event callbacks.
-#### PropTypes
+Note: some props are exclusive to or excluded from `multiline`.
-All other props are transferred directly to the `component`.
+## Props
-+ `component`: `func` or `string` (default `"div"`)
-+ `style`: `TextStylePropTypes`
+**autoComplete** bool
-#### TextStylePropTypes
+Indicates whether the value of the control can be automatically completed by the browser.
-+ ViewStylePropTypes
-+ TypographicPropTypes
+**autoFocus** bool
+
+If true, focuses the input on `componentDidMount`. Only the first form element
+in a document with `autofocus` is focused. Default: `false`.
+
+**defaultValue** string
+
+Provides an initial value that will change when the user starts typing. Useful
+for simple use-cases where you don't want to deal with listening to events and
+updating the `value` prop to keep the controlled state in sync.
+
+**editable** bool
+
+If false, text is not editable. Default: `true`.
+
+**keyboardType** oneOf('default', 'email', 'numeric', 'search', 'tel', 'url')
+
+Determines which keyboard to open, e.g. `email`. Default: `default`. (Not
+available when `multiline` is `true`.)
+
+**multiline** bool
+
+If true, the text input can be multiple lines. Default: `false`.
+
+**onBlur** function
+
+Callback that is called when the text input is blurred.
+
+**onChange** function
+
+Callback that is called when the text input's text changes.
+
+**onChangeText** function
+
+Callback that is called when the text input's text changes. Changed text is
+passed as an argument to the callback handler.
+
+**onFocus** function
+
+Callback that is called when the text input is focused.
+
+**placeholder** string
+
+The string that will be rendered before text input has been entered.
+
+**placeholderTextColor** string
+
+The text color of the placeholder string.
+
+**secureTextEntry** bool
+
+If true, the text input obscures the text entered so that sensitive text like
+passwords stay secure. Default: `false`. (Not available when `multiline` is `true`.)
+
+**style** style
+
+[View](docs/components/View) style
+
++ `color`
++ `direction`
++ `fontFamily`
++ `fontSize`
++ `fontStyle`
++ `fontWeight`
++ `letterSpacing`
++ `lineHeight`
++ `textAlign`
++ `textDecoration`
++ `textTransform`
+
+**testID** string
+
+Used to locate this view in end-to-end tests.
+
+## Examples
+
+```js
+import React, { TextInput } from 'react-native-web'
+
+const { Component, PropTypes } = React
+
+class AppTextInput extends Component {
+ static propTypes = {
+ }
+
+ static defaultProps = {
+ }
+
+ render() {
+ return (
+
+ );
+ }
+}
+
+const styles = {
+}
+```
diff --git a/docs/components/Touchable.md b/docs/components/Touchable.md
new file mode 100644
index 00000000..b7db960a
--- /dev/null
+++ b/docs/components/Touchable.md
@@ -0,0 +1,59 @@
+# Touchable
+
+## Props
+
+**activeHighlight** string
+
+Sets the color of the background highlight when `onPressIn` is called. The
+highlight is removed when `onPressOut` is called. Default: `transparent`.
+
+**activeOpacity** number
+
+Sets the opacity of the child view when `onPressIn` is called. The opacity is
+reset when `onPressOut` is called. Default: `1`.
+
+**component** function or string
+
+The backing component. Default: `div`.
+
+**delayLongPress** number
+
+Delay in ms, from `onPressIn`, before `onLongPress` is called. Default: `1000`.
+
+**delayPressIn** number (TODO)
+
+Delay in ms, from the start of the touch, before `onPressIn` is called. Default: `0`.
+
+**delayPressOut** number (TODO)
+
+Delay in ms, from the release of the touch, before `onPressOut` is called. Default: `0`.
+
+**onLongPress** function
+
+**onPress** function
+
+**onPressIn** function
+
+**onPressOut** function
+
+## Examples
+
+```js
+import React, { Touchable } from 'react-native-web'
+
+const { Component, PropTypes } = React;
+
+class Example extends Component {
+ static propTypes = {
+ }
+
+ static defaultProps = {
+ }
+
+ render() {
+ return (
+
+ )
+ }
+}
+```
diff --git a/docs/components/View.md b/docs/components/View.md
index 9422cd6d..4347e85f 100644
--- a/docs/components/View.md
+++ b/docs/components/View.md
@@ -1,66 +1,141 @@
-# View spec
+# 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.
+`View` is the fundamental UI building block. It is a component that supports
+style, layout with flexbox, and accessibility controls. It can be nested
+inside another `View` and has 0-to-many children of any type.
-## PropTypes
+## Props
-All other props are transferred directly to the `element`.
+**accessibilityLabel** string
-+ `component`: `func` or `string` (default `'div'`)
-+ `pointerEvents`: `oneOf('all', 'box-only', 'box-none', 'none')`
-+ `style`: `ViewStylePropTypes`
+Overrides the text that's read by the screen reader when the user interacts
+with the element. This is implemented using `aria-label`.
-## ViewStylePropTypes
+**component** function, string
-+ BackgroundPropTypes
-+ BorderThemePropTypes
-+ LayoutPropTypes
-+ `boxShadow`: `string`
-+ `color`: `string`
-+ `opacity`: `number`
+Default is `div`.
-## ViewDefaultStyle
+**pointerEvents** oneOf('auto', 'box-only', 'box-none', 'none')
-Implements the default styles from
-[facebook/css-layout](https://github.com/facebook/css-layout).
+We deviate from the CSS spec by supporting additional `pointerEvents` modes,
+therefore `pointerEvents` is excluded from `style`.
-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.
+`box-none` is the equivalent of:
-2. The most convenient way to express the relation between width and other
- box-model properties.
+```css
+.box-none { pointer-events: none }
+.box-none * { pointer-events: auto }
+```
-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.
+`box-only` is the equivalent of:
-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`.
+```css
+.box-only { pointer-events: auto }
+.box-only * { pointer-events: none }
+```
+
+**style** style
+
++ `alignContent`
++ `alignItems`
++ `alignSelf`
++ `backfaceVisibility`
++ `backgroundAttachment`
++ `backgroundClip`
++ `backgroundColor`
++ `backgroundImage`
++ `backgroundOrigin`
++ `backgroundPosition`
++ `backgroundRepeat`
++ `backgroundSize`
++ `borderColor`
++ `borderRadius`
++ `borderStyle`
++ `borderWidth`
++ `bottom`
++ `boxShadow`
++ `boxSizing`
++ `flexBasis`
++ `flexDirection`
++ `flexGrow`
++ `flexShrink`
++ `flexWrap`
++ `height`
++ `justifyContent`
++ `left`
++ `margin`
++ `maxHeight`
++ `maxWidth`
++ `minHeight`
++ `minWidth`
++ `opacity`
++ `order`
++ `overflow`
++ `overflowX`
++ `overflowY`
++ `padding`
++ `position`
++ `right`
++ `top`
++ `transform`
++ `userSelect`
++ `visibility`
++ `width`
++ `zIndex`
+
+Default:
```js
-const ViewDefaultStyle = {
- alignItems: 'stretch', // 1
+{
+ alignItems: 'stretch',
borderWidth: 0,
borderStyle: 'solid',
- boxSizing: 'border-box', // 2
- display: 'flex', // 3
- flexBasis: 'auto', // 1
- flexDirection: 'column', // 1
- flexShrink: 0, // 1
- listStyle: 'none',
+ boxSizing: 'border-box',
+ display: 'flex',
+ flexBasis: 'auto',
+ flexDirection: 'column',
+ flexShrink: 0,
margin: 0,
padding: 0,
- position: 'relative' // 4
+ position: 'relative'
};
```
+(See [facebook/css-layout](https://github.com/facebook/css-layout)).
+
+**testID** string
+
+Used to locate this view in end-to-end tests.
+
## Examples
```js
-// TODO
+import React, { View } from 'react-native-web'
+
+const { Component, PropTypes } = React
+
+class Example extends Component {
+ render() {
+ return (
+
+ {
+ ['1', '2', '3', '4', '5'].map((value, i) => {
+ return
+ })
+ }
+
+ );
+ }
+}
+
+const styles = {
+ row: {
+ flexDirection: 'row'
+ },
+ cell: {
+ flexGrow: 1
+ }
+}
+
+export default Example
```
diff --git a/docs/react-native-web-style/style-props.md b/docs/react-native-web-style/style-props.md
deleted file mode 100644
index cf88300e..00000000
--- a/docs/react-native-web-style/style-props.md
+++ /dev/null
@@ -1,89 +0,0 @@
-## 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/react-native-web-style/styling.md b/docs/style.md
similarity index 100%
rename from docs/react-native-web-style/styling.md
rename to docs/style.md