diff --git a/README.md b/README.md index f059b0aa..d48bc362 100644 --- a/README.md +++ b/README.md @@ -2,12 +2,29 @@ [![Build Status][travis-image]][travis-url] [![npm version][npm-image]][npm-url] -![gzipped size](https://img.shields.io/badge/gzipped-~36.7k-blue.svg) +![gzipped size](https://img.shields.io/badge/gzipped-~41.0k-blue.svg) [React Native][react-native-url] components and APIs for the Web. Browser support: Chrome, Firefox, Safari >= 7, IE 10, Edge. +## Overview + +"React Native for Web" is a project to bring React Native's building blocks and +touch handling to the Web. + +React Native provides a foundational layer to support interoperable, +zero-configuration React component development. This is missing from React's +web ecosystem where OSS components rely on inline styles (usually without +vendor prefixes), or require build tool configuration. This project allows +components built upon React Native to be run on the Web, and it manages all +component styling out-of-the-box. + +For example, the [`View`](docs/apis/View.md) component makes it easy to build +cross-browser layouts with flexbox, such as stacked and nested boxes with +margin and padding. And the [`StyleSheet`](docs/guides/style.md) API converts +styles defined in JavaScript into "Atomic CSS". + ## Quick start To install in your app: @@ -18,17 +35,6 @@ npm install --save react@0.14 react-dom@0.14 react-native-web Read the [Client and Server rendering](docs/guides/rendering.md) guide. -## Overview - -This is a web implementation of React Native components and APIs. The React -Native components are good web application building blocks, and provide a common -foundation for component libraries. - -For example, the [`View`](docs/apis/View.md) component makes it easy to build -common layouts with flexbox, such as stacked and nested boxes with margin and -padding. And the [`StyleSheet`](docs/guides/style.md) API converts styles -defined in JavaScript to "atomic" CSS. - ## Examples Demos: @@ -37,7 +43,7 @@ Demos: * [TicTacToe](http://codepen.io/necolas/full/eJaLZd/) * [2048](http://codepen.io/necolas/full/wMVvxj/) -Example: +Sample: ```js import React, { AppRegistry, Image, StyleSheet, Text, View } from 'react-native' @@ -53,10 +59,6 @@ const App = () => ( ) -// App registration and rendering -AppRegistry.registerComponent('MyApp', () => App) -AppRegistry.runApplication('MyApp', { rootTag: document.getElementById('react-root') }) - // Styles const styles = StyleSheet.create({ card: { @@ -73,6 +75,10 @@ const styles = StyleSheet.create({ width: 40 } }) + +// App registration and rendering +AppRegistry.registerComponent('MyApp', () => App) +AppRegistry.runApplication('MyApp', { rootTag: document.getElementById('react-root') }) ``` ## Documentation @@ -96,8 +102,8 @@ Exported modules: * [`ScrollView`](docs/components/ScrollView.md) * [`Text`](docs/components/Text.md) * [`TextInput`](docs/components/TextInput.md) - * [`TouchableHighlight`](docs/components/TouchableHighlight.md) - * [`TouchableOpacity`](docs/components/TouchableOpacity.md) + * [`TouchableHighlight`](http://facebook.github.io/react-native/releases/0.22/docs/touchablehighlight.html) (mirrors React Native) + * [`TouchableOpacity`](http://facebook.github.io/react-native/releases/0.22/docs/touchableopacity.html) (mirrors React Native) * [`TouchableWithoutFeedback`](docs/components/TouchableWithoutFeedback.md) * [`View`](docs/components/View.md) * APIs diff --git a/docs/components/Image.md b/docs/components/Image.md index 5b9de0c6..d88debd8 100644 --- a/docs/components/Image.md +++ b/docs/components/Image.md @@ -58,20 +58,22 @@ could be an http address or a base64 encoded image. **style**: style + ...[View#style](View.md) - -Defaults: - -```js -{ - alignSelf: 'flex-start', - backgroundColor: 'transparent' -} -``` ++ `resizeMode` **testID**: string Used to locate a view in end-to-end tests. +## Properties + +static **resizeMode**: Object + +Example usage: + +``` + +``` + ## Examples ```js diff --git a/docs/components/ScrollView.md b/docs/components/ScrollView.md index a0b8667e..25cfed27 100644 --- a/docs/components/ScrollView.md +++ b/docs/components/ScrollView.md @@ -1,13 +1,13 @@ # ScrollView -Scrollable `View` for use with bounded height, either by setting the height of -the view directly (discouraged) or by bounding the height of ancestor views. +A scrollable `View` that provides itegration with the touch-locking "responder" +system. `ScrollView`'s must have a bounded height: either set the height of the +view directly (discouraged) or make sure all parent views have bounded height +(e.g., transfer `{ flex: 1}` down the view stack). ## Props -**children**: any - -Child content. +[...View props](./View.md) **contentContainerStyle**: style @@ -19,11 +19,34 @@ all of the child views. When true, the scroll view's children are arranged horizontally in a row instead of vertically in a column. +**keyboardDismissMode**: oneOf('none', 'on-drag') = 'none' + +Determines whether the keyboard gets dismissed in response to a scroll drag. + +* `none` (the default), drags do not dismiss the keyboard. +* `on-drag`, the keyboard is dismissed when a drag begins. +* `interactive` (not supported on web; same as `none`) + +**onContentSizeChange**: function + +TODO + +Called when scrollable content view of the `ScrollView` changes. It's +implemented using the `onLayout` handler attached to the content container +which this `ScrollView` renders. + **onScroll**: function Fires at most once per frame during scrolling. The frequency of the events can be contolled using the `scrollEventThrottle` prop. +**refreshControl**: element + +TODO + +A [RefreshControl](../RefreshControl) component, used to provide +pull-to-refresh functionality for the `ScrollView`. + **scrollEnabled**: bool = true When false, the content does not scroll. @@ -36,9 +59,26 @@ tracking the scroll position, but can lead to scroll performance problems. The default value is `0`, which means the scroll event will be sent only once each time the view is scrolled. -**style**: style +## Instance methods -+ ...[View#style](View.md) +**getInnerViewNode()**: any + +Returns a reference to the underlying content container DOM node within the `ScrollView`. + +**getScrollableNode()**: any + +Returns a reference to the underlying scrollable DOM node. + +**getScrollResponder()**: Component + +Returns a reference to the underlying scroll responder, which supports +operations like `scrollTo`. All `ScrollView`-like components should implement +this method so that they can be composed while providing access to the +underlying scroll responder's methods. + +**scrollTo(options: { x: number = 0; y: number = 0; animated: boolean = true })** + +Scrolls to a given `x`, `y` offset (animation is not currently supported). ## Examples @@ -50,7 +90,7 @@ export default class ScrollViewExample extends Component { constructor(props, context) { super(props, context) this.state = { - items: Array.from({ length: 20 }).map((_, i) => ({ id: i })) + items: Array.from(new Array(20)).map((_, i) => ({ id: i })) } } diff --git a/docs/components/TextInput.md b/docs/components/TextInput.md index f9d53060..bea85c3f 100644 --- a/docs/components/TextInput.md +++ b/docs/components/TextInput.md @@ -147,6 +147,20 @@ Read about how [React form components](https://facebook.github.io/react/docs/forms.html) work. To prevent user edits to the value set `editable={false}`. +## Instance methods + +**blur()** + +Blur the underlying DOM input. + +**clear()** + +Clear the text from the underlying DOM input. + +**focus()** + +Focus the underlying DOM input. + ## Examples ```js diff --git a/docs/components/Touchable.md b/docs/components/Touchable.md deleted file mode 100644 index e4b89b3f..00000000 --- a/docs/components/Touchable.md +++ /dev/null @@ -1,100 +0,0 @@ -# Touchable - -A wrapper for making views respond to mouse, keyboard, and touch presses. On -press in, the touchable area can display a highlight color, and the opacity of -the wrapped view can be decreased. - -This component combines the various `Touchable*` components from React Native. - -Unsupported React Native props: -`accessibilityComponentType` (android) – use `accessibilityRole`, -`accessibilityTraits` (ios) – use `accessibilityRole`, -`onHideUnderlay` – use `onPressOut`, -`onShowUnderlay` – use `onPressIn`, -`underlayColor` – use `activeUnderlayColor` - -## Props - -**accessibilityLabel**: string - -Overrides the text that's read by the screen reader when the user interacts -with the element. - -(web) **accessibilityRole**: oneOf(roles) = 'button' - -Allows assistive technologies to present and support interaction with the view -in a manner that is consistent with user expectations for similar views of that -type. For example, marking a touchable view with an `accessibilityRole` of -`button`. (This is implemented using [ARIA roles](http://www.w3.org/TR/wai-aria/roles#role_definitions)). - -Note: Avoid changing `accessibilityRole` values over time or after user -actions. Generally, accessibility APIs do not provide a means of notifying -assistive technologies of a `role` value change. - -**accessible**: bool = true - -When `false`, the view is hidden from screenreaders. - -**activeOpacity**: number = 0.8 - -Sets the opacity of the child view when `onPressIn` is called. The opacity is -reset when `onPressOut` is called. - -(web) **activeUnderlayColor**: string = 'black' - -Sets the color of the background highlight when `onPressIn` is called. The -highlight is removed when `onPressOut` is called. - -**children**: element - -A single child element. - -**delayLongPress**: number = 500 - -Delay in ms, from `onPressIn`, before `onLongPress` is called. - -**delayPressIn**: number = 0 - -(TODO) - -Delay in ms, from the start of the touch, before `onPressIn` is called. - -**delayPressOut**: number = 100 - -(TODO) - -Delay in ms, from the release of the touch, before `onPressOut` is called. - -**onLayout**: function - -(TODO) - -**onLongPress**: function - -**onPress**: function - -**onPressIn**: function - -**onPressOut**: function - -**style**: style - -+ ...[View#style](View.md) - -## Examples - -```js -import React, { Component, PropTypes, Touchable } from 'react-native' - -export default class Example extends Component { - static propTypes = {} - - static defaultProps = {} - - render() { - return ( - - ) - } -} -``` diff --git a/docs/components/TouchableWithoutFeedback.md b/docs/components/TouchableWithoutFeedback.md new file mode 100644 index 00000000..10f399a3 --- /dev/null +++ b/docs/components/TouchableWithoutFeedback.md @@ -0,0 +1,70 @@ +# TouchableWithoutFeedback + +Do not use unless you have a very good reason. All the elements that respond to +press should have a visual feedback when touched. This is one of the primary +reason a "web" app doesn't feel "native". + +**NOTE: `TouchableWithoutFeedback` supports only one child**. If you wish to have +several child components, wrap them in a View. + +## Props + +**accessibilityLabel**: string + +Overrides the text that's read by the screen reader when the user interacts +with the element. + +(web) **accessibilityRole**: oneOf(roles) = 'button' + +Allows assistive technologies to present and support interaction with the view + +**accessible**: bool = true + +When `false`, the view is hidden from screenreaders. + +**delayLongPress**: number + +Delay in ms, from `onPressIn`, before `onLongPress` is called. + +**delayPressIn**: number + +Delay in ms, from the start of the touch, before `onPressIn` is called. + +**delayPressOut**: number + +Delay in ms, from the release of the touch, before `onPressOut` is called. + +**disabled**: bool + +If true, disable all interactions for this component. + +**hitSlop**: `{top: number, left: number, bottom: number, right: number}` + +This defines how far your touch can start away from the button. This is added +to `pressRetentionOffset` when moving off of the button. **NOTE**: The touch +area never extends past the parent view bounds and the z-index of sibling views +always takes precedence if a touch hits two overlapping views. + +**onLayout**: function + +Invoked on mount and layout changes with. + +`{nativeEvent: {layout: {x, y, width, height}}}` + +**onLongPress**: function + +**onPress**: function + +Called when the touch is released, but not if cancelled (e.g. by a scroll that steals the responder lock). + +**onPressIn**: function + +**onPressOut**: function + +**pressRetentionOffset**: `{top: number, left: number, bottom: number, right: number}` + +When the scroll view is disabled, this defines how far your touch may move off +of the button, before deactivating the button. Once deactivated, try moving it +back and you'll see that the button is once again reactivated! Move it back and +forth several times while the scroll view is disabled. Ensure you pass in a +constant to reduce memory allocations. diff --git a/docs/components/View.md b/docs/components/View.md index 4015caa2..42efd35b 100644 --- a/docs/components/View.md +++ b/docs/components/View.md @@ -4,21 +4,13 @@ style, layout with flexbox, and accessibility controls. It can be nested inside another `View` and has 0-to-many children of any type. +Also, refer to React Native's documentation about the [Gesture Responder +System](http://facebook.github.io/react-native/releases/0.22/docs/gesture-responder-system.html). + Unsupported React Native props: -`accessibilityComponentType` (android) – use `accessibilityRole`, -`accessibilityTraits` (ios) – use `accessibilityRole`, -`collapsable` (android), -`importantForAccessibility` (android), -`needsOffscreenAlphaCompositing` (android), `onAccessibilityTap`, -`onMagicTap`, -`onMoveShouldSetResponder`, -`onResponder*`, -`onStartShouldSetResponder`, -`onStartShouldSetResponderCapture` -`removeClippedSubviews` (ios), -`renderToHardwareTextureAndroid` (android), -`shouldRasterizeIOS` (ios) +`hitSlop`, +`onMagicTap` ## Props @@ -58,6 +50,29 @@ implemented using `aria-hidden`.) (TODO) +**onMoveShouldSetResponder**: function + +**onMoveShouldSetResponderCapture**: function + +**onResponderGrant**: function + +For most touch interactions, you'll simply want to wrap your component in +`TouchableHighlight` or `TouchableOpacity`. + +**onResponderMove**: function + +**onResponderReject**: function + +**onResponderRelease**: function + +**onResponderTerminate**: function + +**onResponderTerminationRequest**: function + +**onStartShouldSetResponder**: function + +**onStartShouldSetResponderCapture**: function + **pointerEvents**: oneOf('auto', 'box-only', 'box-none', 'none') = 'auto' Configure the `pointerEvents` of the view. The enhanced `pointerEvents` modes @@ -136,6 +151,7 @@ from `style`. + `right` + `top` + `transform` ++ `transformMatrix` + `userSelect` + `visibility` + `width` diff --git a/docs/guides/rendering.md b/docs/guides/rendering.md index f192d454..ffb9cc77 100644 --- a/docs/guides/rendering.md +++ b/docs/guides/rendering.md @@ -18,45 +18,53 @@ module.exports = { ## Client-side rendering +Rendering without using the `AppRegistry`: + +```js +import React from 'react-native' + +// DOM render +React.render(
, document.getElementById('react-app')) + +// Server render +React.renderToString(
) +React.renderToStaticMarkup(
) +``` + +Rendering using the `AppRegistry`: + +``` +// App.js + +import React, { AppRegistry } from 'react-native' + +// component that renders the app +const AppContainer = (props) => { /* ... */ } +export default AppContainer +``` + ```js // client.js import React, { AppRegistry } from 'react-native' -import MyApp from './MyApp' +import App from './App' -// register the app -AppRegistry.registerApp('MyApp', () => MyApp) +// registers the app +AppRegistry.registerComponent('App', () => App) -// mount the app within the `rootTag` and run it -AppRegistry.runApplication('MyApp', { initialProps, rootTag: document.getElementById('react-root') }) - -// DOM render -React.render(
, document.getElementById('sidebar-app')) - -// Server render -React.renderToString(
) +// mounts and runs the app within the `rootTag` DOM node +AppRegistry.runApplication('App', { initialProps, rootTag: document.getElementById('react-app') }) ``` -## Server-side rendering - -Pre-rendering React apps on the server is a key feature for Web applications. React Native for Web extends `AppRegistry` to provide support for server-side rendering. ```js -// server.js +// AppShell.js -import React, { AppRegistry } from 'react-native' -import MyApp from './MyApp' +import React from 'react-native' -// register the app -AppRegistry.registerApp('MyApp', () => MyApp) - -// prerender the app -const { html, style } = AppRegistry.prerenderApplication('MyApp', { initialProps }) - -// construct full page markup -const HtmlShell = (html, style) => ( +const AppShell = (html, style) => ( @@ -64,10 +72,26 @@ const HtmlShell = (html, style) => ( {style} -
+
) - -React.renderToStaticMarkup() +export default AppShell +``` + +```js +// server.js + +import React, { AppRegistry } from 'react-native' +import App from './App' +import AppShell from './AppShell' + +// registers the app +AppRegistry.registerComponent('App', () => App) + +// prerenders the app +const { html, style } = AppRegistry.prerenderApplication('App', { initialProps }) + +// renders the full-page markup +const renderedApplicationHTML = React.renderToString() ```