Add 'advanced use' and 'style' docs

Fix #450
This commit is contained in:
Nicolas Gallagher
2017-05-06 16:01:14 +01:00
parent 7aef8f04c1
commit 124de7562d
7 changed files with 294 additions and 92 deletions
+15 -20
View File
@@ -18,35 +18,31 @@ Browser support: Chrome, Firefox, Safari >= 7, IE 10, Edge.
"React Native for Web" is a project to bring React Native's building blocks and "React Native for Web" is a project to bring React Native's building blocks and
touch handling to the Web. [Read more](#why). touch handling to the Web. [Read more](#why).
Browse the UI Explorer to see React Native [examples running on Browse the [UI Explorer](https://necolas.github.io/react-native-web/storybook/)
Web](https://necolas.github.io/react-native-web/storybook/). Or try it out to see React Native examples running on Web. Or try it out online with [React
online with [React Native for Web: Playground](https://www.webpackbin.com/bins/-KgucwxRbn7HRU-V-3Bc). Native for Web: Playground](https://www.webpackbin.com/bins/-KgucwxRbn7HRU-V-3Bc).
## Quick start ## Quick start
To install in your app: To install in your app:
``` ```
npm install --save react@15.4 react-dom@15.4 react-native-web npm install --save react@15.5 react-dom@15.5 react-native-web
``` ```
Read the [Getting Started](docs/guides/getting-started.md) guide. Read the [Getting Started](docs/guides/getting-started.md) guide.
Alternatively, you can quickly setup a local project
using [create-react-app](https://github.com/facebookincubator/create-react-app)
(which supports `react-native-web` out-of-the-box once installed) and
[react-native-web-starter](https://github.com/grabcode/react-native-web-starter).
## Documentation ## Documentation
Guides: Guides:
* [Getting started](docs/guides/getting-started.md) * [Getting started](docs/guides/getting-started.md)
* [Style](docs/guides/style.md)
* [Accessibility](docs/guides/accessibility.md) * [Accessibility](docs/guides/accessibility.md)
* [Direct manipulation](docs/guides/direct-manipulation.md) * [Direct manipulation](docs/guides/direct-manipulation.md)
* [Internationalization](docs/guides/internationalization.md) * [Internationalization](docs/guides/internationalization.md)
* [Advanced use](docs/guides/advanced.md)
* [Known issues](docs/guides/known-issues.md) * [Known issues](docs/guides/known-issues.md)
* [Style](docs/guides/style.md)
Exported modules: Exported modules:
@@ -87,17 +83,16 @@ Exported modules:
There are many different teams at Twitter building web applications with React. There are many different teams at Twitter building web applications with React.
We want to share React components, libraries, and APIs between teams…much like We want to share React components, libraries, and APIs between teams…much like
the OSS community tries to do. At our scale, this involves dealing with the OSS community tries to do. At our scale, this involves dealing with
multiple, inter-related problems including: a common way to handle style, multiple, inter-related problems including: component styles, animation, touch
animation, touch, viewport adaptation, accessibility, themes, RTL layout, and interactions, layout adaptation, accessibility, RTL layout, theming, and build-
server-rendering. or server-rendering.
This is hard to do with React DOM, as the components are essentially the same This is hard to do with React DOM, as the components are essentially the same
low-level building blocks that the browser provides. However, React Native low-level building blocks that the browser provides. However, React Native
avoids, solves, or can solve almost all these problems facing Web teams. avoids, solves, or can solve almost all these problems. Central to this is
Central to this is React Native's JavaScript style API (not strictly React Native's JavaScript style API (not strictly "CSS-in-JS") which avoids the
"CSS-in-JS") which avoids the key [problems with key [problems with CSS](https://speakerdeck.com/vjeux/react-css-in-js) by
CSS](https://speakerdeck.com/vjeux/react-css-in-js) by giving up some of the giving up some of the complexity of CSS.
complexity of CSS.
## Example code ## Example code
@@ -140,11 +135,11 @@ AppRegistry.runApplication('MyApp', { rootTag: document.getElementById('react-ro
## Related projects ## Related projects
* [react-native-web-starter](https://github.com/grabcode/react-native-web-starter)
* [react-native-web-player](https://github.com/dabbott/react-native-web-player) * [react-native-web-player](https://github.com/dabbott/react-native-web-player)
* [react-native-web-starter](https://github.com/grabcode/react-native-web-starter)
* [react-native-web-webpack](https://github.com/ndbroadbent/react-native-web-webpack)
* [reactxp](https://github.com/microsoft/reactxp) * [reactxp](https://github.com/microsoft/reactxp)
* [react-web](https://github.com/taobaofed/react-web) * [react-web](https://github.com/taobaofed/react-web)
* [react-native-web-webpack](https://github.com/ndbroadbent/react-native-web-webpack)
## License ## License
+5 -4
View File
@@ -1,9 +1,10 @@
# StyleSheet # StyleSheet
The `StyleSheet` abstraction converts predefined styles to (vendor-prefixed) The `StyleSheet` abstraction converts predefined styles to (vendor-prefixed)
CSS without requiring a compile-time step. Some styles cannot be resolved CSS without requiring a compile-time step. Styles that cannot be resolved
outside of the render loop and are applied as inline styles. Read more about outside of the render loop (e.g., dynamic positioning) are usually applied as
[how to style your application](../guides/style.md). inline styles. Read more about [how to style your
application](../guides/style.md).
## Methods ## Methods
@@ -15,7 +16,7 @@ Each key of the object passed to `create` must define a style object.
Flattens an array of styles into a single style object. Flattens an array of styles into a single style object.
**renderToString**: function (web) **renderToString**: function
Returns a string of the stylesheet for use in server-side rendering. Returns a string of the stylesheet for use in server-side rendering.
+104
View File
@@ -0,0 +1,104 @@
# Advanced use
## Use with existing React DOM components
React Native for Web exports a web-specific module called `createDOMElement`,
which can be used to wrap React DOM components. This allows you to use React
Native's accessibility and style optimizations.
In the example below, `Video` will now accept common React Native props such as
`accessibilityLabel`, `accessible`, `style`, and even the Responder event
props.
```js
import { createDOMElement } from 'react-native';
const Video = (props) => createDOMElement('video', props);
```
This also works with composite components defined in your existing component
gallery or dependencies ([live example](https://www.webpackbin.com/bins/-KiTSGFw3fB9Szg7quLI)).
```js
import RaisedButton from 'material-ui/RaisedButton';
import { createDOMElement, StyleSheet } from 'react-native';
const CustomButton = (props) => createDOMElement(RaisedButton, {
...props,
style: [ styles.button, props.style ]
});
const styles = StyleSheet.create({
button: {
padding: 20
}
});
```
Remember that React Native styles are not the same as React DOM styles, and
care needs to be taken not to pass React DOM styles into your React Native
wrapped components.
## Use as a library framework
The React Native (for Web) building blocks can be used to create higher-level
components and abstractions. In the example below, a `styled` function provides
an API inspired by styled-components ([live
example](https://www.webpackbin.com/bins/-KjT9ziwv4O7FDZdvsnX)).
```js
const { createDOMElement, StyleSheet } = ReactNative;
/**
* styled API
*/
const styled = (Component, styler) => {
const isDOMComponent = typeof Component === 'string';
class Styled extends React.Component {
static contextTypes = {
getTheme: React.PropTypes.func
};
render() {
const theme = this.context.getTheme && this.context.getTheme();
const localProps = { ...this.props, theme };
const nextProps = { ...this.props }
const style = typeof styler === 'function' ? styler(localProps) : styler;
nextProps.style = [ style, this.props.style ];
return (
isDOMComponent
? createDOMElement(Component, nextProps)
: <Component {...nextProps} />
);
}
}
return Styled;
}
const styles = StyleSheet.create({
container: {
alignItems: 'center',
backgroundColor: '#2196F3',
flex: 1,
justifyContent: 'center'
}
});
const StyledView = styled(View, styles.container);
```
## Use with react-sketchapp
Use with [react-sketchapp](http://airbnb.io/react-sketchapp/) requires that you
alias `react-native` to `react-sketchapp`. This will allow you to render your
existing React Native components in Sketch. Sketch-specific components like
`Artboard` should be imported from `react-sketchapp`.
If you're using `skpm`, you can rely on an [undocumented
feature](https://github.com/sketch-pm/skpm/blob/master/lib/utils/webpackConfig.js)
which will merge your `webpack.config.js`, `.babelrc`, or `package.json` Babel
config into its internal webpack config. The simplest option may be to use the
[babel-plugin-module-alias](https://www.npmjs.com/package/babel-plugin-module-alias)
and configure it in your `package.json`.
+22 -6
View File
@@ -1,5 +1,14 @@
# Getting started # Getting started
This guide will help you to correctly configure build and test tools to work
with React Native for Web.
Alternatively, you can quickly setup a local project using
[create-react-app](https://github.com/facebookincubator/create-react-app)
(which supports `react-native-web` out-of-the-box once installed),
[react-native-web-starter](https://github.com/grabcode/react-native-web-starter),
or [react-native-web-webpack](https://github.com/ndbroadbent/react-native-web-webpack).
It is recommended that your application provide a `Promise` and `Array.from` It is recommended that your application provide a `Promise` and `Array.from`
polyfill. polyfill.
@@ -76,10 +85,6 @@ module.exports = {
} }
``` ```
A more complex example setup for web apps can be found in various starter kits
(e.g., create-react-app and
[react-native-web-webpack](https://github.com/ndbroadbent/react-native-web-webpack))
Please refer to the Webpack documentation for more information. Please refer to the Webpack documentation for more information.
## Jest ## Jest
@@ -144,8 +149,8 @@ AppRegistry.runApplication('App', {
}) })
``` ```
Rendering within `ReactDOM.render` also works when introduce `react-native-web` Rendering within `ReactDOM.render` also works when introducing
to an existing web app, but it is not recommended oherwise. `react-native-web` to an existing web app, but otherwise it is not recommended.
## Server-side rendering ## Server-side rendering
@@ -164,4 +169,15 @@ AppRegistry.registerComponent('App', () => AppContainer)
// prerender the app // prerender the app
const { element, stylesheet } = AppRegistry.getApplication('App', { initialProps }); const { element, stylesheet } = AppRegistry.getApplication('App', { initialProps });
const initialHTML = ReactDOMServer.renderToString(element); const initialHTML = ReactDOMServer.renderToString(element);
// construct HTML document
const document = `
<!DOCTYPE html>
<html>
<head>
${stylesheet}
</head>
<body>
${initialHTML}
`
``` ```
+148 -62
View File
@@ -1,73 +1,90 @@
# Style # Style
React Native for Web relies on JavaScript to define styles for your React Native relies on JavaScript to define and resolve the styles of your
application. This allows you to avoid issues arising from the [7 deadly sins of application. React Native for Web implements the React Native style API in a
CSS](https://speakerdeck.com/vjeux/react-css-in-js): way that avoids *all* the [problems with CSS at
scale](https://speakerdeck.com/vjeux/react-css-in-js):
1. Global namespace 1. No local variables
2. Dependency hell 2. Implicit dependencies
3. No dead code elimination 3. No dead code elimination
4. No code minification 4. No code minification
5. No sharing of constants 5. No sharing of constants
6. Non-deterministic resolution 6. Non-deterministic resolution
7. Lack of isolation 7. No isolation
At the same time, it has several benefits:
1. Simple API and expressive subset of CSS
2. Generates CSS; the minimum required
3. Good runtime performance
4. Support for static and dynamic styles
5. Support for RTL layouts
6. Easy pre-rendering of critical CSS
## Defining styles ## Defining styles
Styles should be defined outside of the component: Styles should be defined outside of the component. Using `StyleSheet.create` is
optional but provides the best performance (by relying on generated CSS
stylesheets). Avoid creating unregistered style objects.
```js ```js
class Example extends React.Component {}
const styles = StyleSheet.create({ const styles = StyleSheet.create({
heading: { heading: {
color: 'gray', color: 'gray',
fontSize: '2rem' fontSize: '2rem'
}, },
text: { text: {
color: 'gray', marginTop: '1rem',
fontSize: '1.25rem' margin: 10
} }
}) })
``` ```
Using `StyleSheet.create` is optional but provides the best performance See the `style` documentation of individual components for supported properties.
(`style` is resolved to CSS stylesheets). Avoid creating unregistered style
objects.
The attribute names and values are a subset of CSS. See the `style`
documentation of individual components.
## Using styles ## Using styles
All the React Native components accept a `style` attribute. All the React Native components accept a `style` property. The value can be a
registered object, a plain object, or an array.
```js ```js
<Text style={styles.text} /> // registered object
<View style={styles.view} /> <View style={styles.view} />
// plain object
<View style={{ transform: [ { translateX } ] }} />
// array of registered or plain objects
<View style={[ styles.container, this.props.style ]} />
``` ```
A common pattern is to conditionally add style based on a condition: The array syntax will merge styles from left-to-right as normal JavaScript
objects, and can be used to conditionally apply styles:
```js ```js
// either
<View style={[ <View style={[
styles.base, styles.container,
this.state.active && styles.active this.state.active && styles.active
]} /> ]} />
``` ```
When styles are registered with `StyleSheet.create`, the return value is a
number and not a style object. This is important for performance optimizations,
but still allows you to merge styles in a deterministic manner at runtime. If
you need access to the underlying style objects you need to use
`StyleSheet.flatten` (but be aware that this is not the optimized path).
## Composing styles ## Composing styles
In order to let a call site customize the style of your component children, you To let other components customize the style of a component's children you can
can pass styles around. Use `View.propTypes.style` and `Text.propTypes.style` in expose a prop so styles can be explicitly passed into the component.
order to make sure only valid styles are being passed.
```js ```js
class List extends React.Component { class List extends React.Component {
static propTypes = { static propTypes = {
style: View.propTypes.style, style: ViewPropTypes.style,
elementStyle: View.propTypes.style, elementStyle: ViewPropTypes.style,
} }
render() { render() {
@@ -90,56 +107,125 @@ In another file:
You also have much greater control over how styles are composed when compared You also have much greater control over how styles are composed when compared
to using class names. For example, you may choose to accept a limited subset to using class names. For example, you may choose to accept a limited subset
of style props in the component's API, and control when they are applied: of style props in the component's API, and control when they are applied.
```js ## How styles are resolved
class List extends React.Component {
static propTypes = {
children: React.PropTypes.any,
// limit which styles are accepted
style: React.PropTypes.shape({
borderColor: View.propTypes.borderColor,
borderWidth: View.propTypes.borderWidth
})
}
render() { React Native style resolution is deterministic and slightly different from CSS.
return (
<View In the following HTML/CSS example, the `.margin` selector is defined last in
children={children} the CSS and takes precedence over the previous rules, resulting in a margin of
style={[ `0, 0, 0, 0`.
this.props.style,
// override border-color when scrolling ```html
isScrolling && { borderColor: 'transparent' } <style>
]} .marginTop { margin-top: 10px; }
/> .marginBottom { margin-bottom: 20px; }
) .margin { margin: 0; }
} </style>
} <div class="marginTop marginBottom margin"></div>
``` ```
## Media Queries But in React Native the most *specific* style property takes precedence,
resulting in margins of `10, 0, 20, 0`.
```js
const style = [
{ marginTop: 10 },
{ marginBottom: 20 },
{ margin: 0 }
];
const Box = () => <View style={style} />
```
## Implementation details
React Native for Web transforms React Native styles into React DOM styles. Any
styles defined using `StyleSheet.create` will ultimately be rendered using CSS
class names.
React Native for Web introduced a novel strategy to achieve this. Each rule is
broken down into declarations, properties are expanded to their long-form, and
the resulting key-value pairs are mapped to unique "atomic CSS" class names.
Input:
```js
const Box = () => <View style={styles.box} />
const styles = StyleSheet.create({
box: {
margin: 0
}
});
```
Output:
```html
<style>
.rn-1mnahxq { margin-top: 0px; }
.rn-61z16t { margin-right: 0px; }
.rn-p1pxzi { margin-bottom: 0px; }
.rn-11wrixw { margin-left: 0px; }
</style>
<div class="rn-156q2ks rn-61z16t rn-p1pxzi rn-11wrixw"></div>
```
This ensures that CSS order doesn't impact rendering and CSS rules are
efficiently deduplicated. Rather than the total CSS growing in proportion to
the number of *rules*, it grows in proportion to the number of *unique
declarations*. As a result, the DOM style sheet is only written to when new
unique declarations are defined and it is usually small enough to be
pre-rendered and inlined.
Class names are deterministic, which means that the resulting CSS and HTML is
consistent across builds important for large apps using code-splitting and
deploying incremental updates.
At runtime registered styles are resolved to DOM style props and memoized.
Any dynamic styles that contain declarations previously registered as static
styles can also be converted to CSS class names. Otherwise, they render as
inline styles.
All this allows React Native for Web to support the rich functionality of React
Native styles (including RTL layouts and `setNativeProps`) while providing one
of the [fastest](https://github.com/necolas/react-native-web/blob/master/performance/README.md),
safest, and most efficient styles-in-JavaScript solutions.
## FAQs
### What about Media Queries?
`StyleSheet.create` is a way of defining the styles your application requires; `StyleSheet.create` is a way of defining the styles your application requires;
it does not concern itself with _where_ or _when_ those styles are applied to it does not concern itself with _where_ or _when_ those styles are applied to
elements. elements.
There are various React libraries wrapping JavaScript Media Query API's, e.g., Media Queries may not be most appropriate for component-based designs. React
Native provides the `Dimensions` API and `onLayout` props. If you do need Media
Queries, using the `matchMedia` DOM API has the benefit of allowing you to swap
out entire components, not just styles. There are also many React libraries
wrapping JavaScript Media Query API's, e.g.,
[react-media](https://github.com/reacttraining/react-media),
[react-media-queries](https://github.com/bloodyowl/react-media-queries), [react-media-queries](https://github.com/bloodyowl/react-media-queries),
[media-query-fascade](https://github.com/tanem/media-query-facade), or [media-query-fascade](https://github.com/tanem/media-query-facade), or
[react-responsive](https://github.com/contra/react-responsive). This has the [react-responsive](https://github.com/contra/react-responsive).
benefit of co-locating breakpoint-specific DOM and style changes.
## Pseudo-classes and pseudo-elements ### What about pseudo-classes and pseudo-elements?
Pseudo-classes like `:hover` and `:focus` can be implemented with events (e.g. Pseudo-classes like `:hover` and `:focus` can be implemented with events (e.g.
`onFocus`). Pseudo-elements are not supported; elements should be used instead. `onFocus`). Pseudo-elements are not supported; elements should be used instead.
### Reset ### Do I need a CSS reset?
You **do not** need to include a CSS reset or No. React Native for Web includes a very small CSS reset that removes unwanted
[normalize.css](https://necolas.github.io/normalize.css/). User Agent styles from (pseudo-)elements beyond the reach of React (e.g.,
`html`, `body`) or inline styles (e.g., `::-moz-focus-inner`). The rest is
handled at the component-level.
React Native for Web includes a very small CSS reset taken from normalize.css. ### What about using DevTools?
It removes unwanted User Agent styles from (pseudo-)elements beyond the reach
of React (e.g., `html`, `body`) or inline styles (e.g., `::-moz-focus-inner`). It's recommended that you rely more on React DevTools and live/hot-reloading
rather than inspecting and editing the DOM directly.
BIN
View File
Binary file not shown.

Before

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 38 KiB