mirror of
https://github.com/zhigang1992/react-native-web.git
synced 2026-04-04 22:57:38 +08:00
Compare commits
60 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
dfa8087f9a | ||
|
|
eaccd8799d | ||
|
|
85b2afc313 | ||
|
|
4865c7bcce | ||
|
|
9e9ab78130 | ||
|
|
00b795a87e | ||
|
|
1edf5241a1 | ||
|
|
4cfcdef264 | ||
|
|
a264c0b956 | ||
|
|
0d8aa24ff3 | ||
|
|
1b77ac4b2f | ||
|
|
44b185ed4c | ||
|
|
d1d570268a | ||
|
|
997c92f841 | ||
|
|
8e60690877 | ||
|
|
7bab19ae6c | ||
|
|
c7f287b207 | ||
|
|
02cfbf8987 | ||
|
|
6203a3fec6 | ||
|
|
d1d5461b29 | ||
|
|
b0ff4489a9 | ||
|
|
635fda8d63 | ||
|
|
5a5eb5425f | ||
|
|
44d59f4996 | ||
|
|
868ab55bac | ||
|
|
65d5a89040 | ||
|
|
deb0a85440 | ||
|
|
19381da37f | ||
|
|
47ba46780c | ||
|
|
88ddeca0c6 | ||
|
|
a61f71133e | ||
|
|
dad2888f7e | ||
|
|
5e9e81eafe | ||
|
|
7ae2a5e188 | ||
|
|
d13f78622b | ||
|
|
6ae68e948f | ||
|
|
b1b70a420d | ||
|
|
43d297bf59 | ||
|
|
060d96b42d | ||
|
|
dd5f8cf641 | ||
|
|
7f256c6423 | ||
|
|
05069253a1 | ||
|
|
f10ac058b6 | ||
|
|
6aa2ac1f70 | ||
|
|
79e6dbaab5 | ||
|
|
fc86c876e0 | ||
|
|
1f25ef82ae | ||
|
|
5b60dcf0ff | ||
|
|
1cf152e8a0 | ||
|
|
d034a0c6ec | ||
|
|
33d1cdf193 | ||
|
|
483a76cb5c | ||
|
|
65055028c6 | ||
|
|
93f425e414 | ||
|
|
ce4cc8a946 | ||
|
|
77fd867421 | ||
|
|
22999d7e5b | ||
|
|
3c400a662b | ||
|
|
e78ce713cb | ||
|
|
70282cb4ca |
@@ -3,6 +3,7 @@
|
||||
.*/benchmarks/.*
|
||||
.*/docs/.*
|
||||
.*/node_modules/animated/*
|
||||
.*/node_modules/babel-plugin-transform-react-remove-prop-types/*
|
||||
|
||||
[include]
|
||||
|
||||
|
||||
44
.github/CONTRIBUTING.md
vendored
44
.github/CONTRIBUTING.md
vendored
@@ -23,67 +23,79 @@ Install dependencies (requires [yarn](https://yarnpkg.com/en/docs/install):
|
||||
yarn
|
||||
```
|
||||
|
||||
## Unit tests
|
||||
## Automated tests
|
||||
|
||||
To run flow:
|
||||
|
||||
```
|
||||
yarn flow
|
||||
```
|
||||
|
||||
To run the unit tests:
|
||||
|
||||
```
|
||||
npm test
|
||||
yarn jest
|
||||
```
|
||||
|
||||
…in watch mode:
|
||||
|
||||
```
|
||||
npm run test:watch
|
||||
yarn jest:watch
|
||||
```
|
||||
|
||||
To run all automated tests:
|
||||
|
||||
```
|
||||
yarn test
|
||||
```
|
||||
|
||||
## Visual tests
|
||||
|
||||
Run the interactive storybook:
|
||||
To run the interactive storybook:
|
||||
|
||||
```
|
||||
npm run docs:start
|
||||
yarn docs:start
|
||||
```
|
||||
|
||||
Run generate a static build of the storybook:
|
||||
To generate a static build of the storybook:
|
||||
|
||||
```
|
||||
npm run docs:build
|
||||
yarn docs:build
|
||||
```
|
||||
|
||||
Run the performance benchmarks in a browser (opening `./performance/index.html`):
|
||||
To run the performance benchmarks in a browser (opening `./benchmarks/index.html`):
|
||||
|
||||
```
|
||||
npm run benchmarks
|
||||
yarn benchmarks
|
||||
```
|
||||
|
||||
## Compile and build
|
||||
|
||||
Compile the source code to `dist`:
|
||||
To compile the source code to `dist`:
|
||||
|
||||
```
|
||||
npm run compile
|
||||
yarn compile
|
||||
```
|
||||
|
||||
To create a UMD bundle of the library:
|
||||
|
||||
```
|
||||
npm run build
|
||||
yarn build
|
||||
```
|
||||
|
||||
### Pre-commit
|
||||
|
||||
Before creating a commit run:
|
||||
To format and lint code before commit:
|
||||
|
||||
```
|
||||
npm run precommit
|
||||
yarn precommit
|
||||
```
|
||||
|
||||
To format and lint the entire project:
|
||||
|
||||
```
|
||||
npm run fmt
|
||||
npm run lint
|
||||
yarn fmt
|
||||
yarn lint
|
||||
```
|
||||
|
||||
### New Features
|
||||
|
||||
29
README.md
29
README.md
@@ -16,7 +16,7 @@ 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. [Read more](#why).
|
||||
touch handling to the Web.
|
||||
|
||||
Browse the [UI Explorer](https://necolas.github.io/react-native-web/storybook/)
|
||||
to see React Native examples running on Web. Or try it out online with [React
|
||||
@@ -27,9 +27,11 @@ Native for Web: Playground](https://www.webpackbin.com/bins/-KgucwxRbn7HRU-V-3Bc
|
||||
To install in your app:
|
||||
|
||||
```
|
||||
npm install --save react@15.5 react-dom@15.5 react-native-web
|
||||
npm install --save react@15.6 react-dom@15.6 react-native-web
|
||||
```
|
||||
|
||||
NOTE: React Native for Web supports React/ReactDOM 15.4, 15.5, or 15.6.
|
||||
|
||||
Read the [Getting Started](docs/guides/getting-started.md) guide.
|
||||
|
||||
## Documentation
|
||||
@@ -50,7 +52,6 @@ Exported modules:
|
||||
* [`ActivityIndicator`](docs/components/ActivityIndicator.md)
|
||||
* [`Button`](docs/components/Button.md)
|
||||
* [`Image`](docs/components/Image.md)
|
||||
* [`ListView`](docs/components/ListView.md)
|
||||
* [`ProgressBar`](docs/components/ProgressBar.md)
|
||||
* [`ScrollView`](docs/components/ScrollView.md)
|
||||
* [`Switch`](docs/components/Switch.md)
|
||||
@@ -68,7 +69,6 @@ Exported modules:
|
||||
* [`Clipboard`](docs/apis/Clipboard.md)
|
||||
* [`Dimensions`](docs/apis/Dimensions.md)
|
||||
* [`I18nManager`](docs/apis/I18nManager.md)
|
||||
* [`NativeMethods`](docs/apis/NativeMethods.md)
|
||||
* [`NetInfo`](docs/apis/NetInfo.md)
|
||||
* [`PanResponder`](http://facebook.github.io/react-native/releases/0.20/docs/panresponder.html#content) (mirrors React Native)
|
||||
* [`PixelRatio`](docs/apis/PixelRatio.md)
|
||||
@@ -76,24 +76,6 @@ Exported modules:
|
||||
* [`StyleSheet`](docs/apis/StyleSheet.md)
|
||||
* [`Vibration`](docs/apis/Vibration.md)
|
||||
|
||||
<span id="#why"></span>
|
||||
|
||||
## Why?
|
||||
|
||||
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
|
||||
the OSS community tries to do. At our scale, this involves dealing with
|
||||
multiple, inter-related problems including: component styles, animation, touch
|
||||
interactions, layout adaptation, accessibility, RTL layout, theming, and build-
|
||||
or server-rendering.
|
||||
|
||||
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
|
||||
avoids, solves, or can solve almost all these problems. Central to this is
|
||||
React Native's JavaScript style API (not strictly "CSS-in-JS") which avoids the
|
||||
key [problems with CSS](https://speakerdeck.com/vjeux/react-css-in-js) by
|
||||
giving up some of the complexity of CSS.
|
||||
|
||||
## Example code
|
||||
|
||||
```js
|
||||
@@ -135,11 +117,12 @@ AppRegistry.runApplication('MyApp', { rootTag: document.getElementById('react-ro
|
||||
|
||||
## Related projects
|
||||
|
||||
* [react-primitives](https://github.com/lelandrichardson/react-primitives/)
|
||||
* [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)
|
||||
* [react-web](https://github.com/taobaofed/react-web)
|
||||
* [reactxp](https://github.com/microsoft/reactxp)
|
||||
|
||||
## License
|
||||
|
||||
|
||||
@@ -3,7 +3,7 @@ import React from 'react';
|
||||
import View from '../View/aphrodite';
|
||||
import { StyleSheet } from 'aphrodite';
|
||||
|
||||
const Box = ({ color, fixed = false, layout = 'column', outer = false, ...other }) => (
|
||||
const Box = ({ color, fixed = false, layout = 'column', outer = false, ...other }) =>
|
||||
<View
|
||||
{...other}
|
||||
style={[
|
||||
@@ -12,8 +12,7 @@ const Box = ({ color, fixed = false, layout = 'column', outer = false, ...other
|
||||
layout === 'row' && styles.row,
|
||||
outer && styles.outer
|
||||
]}
|
||||
/>
|
||||
);
|
||||
/>;
|
||||
|
||||
const styles = StyleSheet.create({
|
||||
outer: {
|
||||
|
||||
@@ -4,7 +4,7 @@ import React from 'react';
|
||||
import View from '../View/css-modules';
|
||||
import styles from './styles.css';
|
||||
|
||||
const Box = ({ color, fixed = false, layout = 'column', outer = false, ...other }) => (
|
||||
const Box = ({ color, fixed = false, layout = 'column', outer = false, ...other }) =>
|
||||
<View
|
||||
{...other}
|
||||
className={classnames(styles[`color${color}`], {
|
||||
@@ -12,7 +12,6 @@ const Box = ({ color, fixed = false, layout = 'column', outer = false, ...other
|
||||
[styles.outer]: outer,
|
||||
[styles.row]: layout === 'row'
|
||||
})}
|
||||
/>
|
||||
);
|
||||
/>;
|
||||
|
||||
module.exports = Box;
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
import React from 'react';
|
||||
import View from '../View/glamor';
|
||||
|
||||
const Box = ({ color, fixed = false, layout = 'column', outer = false, ...other }) => (
|
||||
const Box = ({ color, fixed = false, layout = 'column', outer = false, ...other }) =>
|
||||
<View
|
||||
{...other}
|
||||
style={[
|
||||
@@ -11,8 +11,7 @@ const Box = ({ color, fixed = false, layout = 'column', outer = false, ...other
|
||||
layout === 'row' && styles.row,
|
||||
outer && styles.outer
|
||||
]}
|
||||
/>
|
||||
);
|
||||
/>;
|
||||
|
||||
const styles = {
|
||||
outer: {
|
||||
|
||||
@@ -4,7 +4,7 @@ import injectSheet from 'react-jss';
|
||||
import React from 'react';
|
||||
import View from '../View/jss';
|
||||
|
||||
const Box = ({ classes, color, fixed = false, layout = 'column', outer = false, ...other }) => (
|
||||
const Box = ({ classes, color, fixed = false, layout = 'column', outer = false, ...other }) =>
|
||||
<View
|
||||
{...other}
|
||||
className={classnames({
|
||||
@@ -13,8 +13,7 @@ const Box = ({ classes, color, fixed = false, layout = 'column', outer = false,
|
||||
[classes.row]: layout === 'row',
|
||||
[classes.outer]: outer
|
||||
})}
|
||||
/>
|
||||
);
|
||||
/>;
|
||||
|
||||
const styles = {
|
||||
outer: {
|
||||
|
||||
@@ -3,7 +3,7 @@ import React from 'react';
|
||||
import StyleSheet from 'react-native/apis/StyleSheet';
|
||||
import View from '../View/react-native-stylesheet';
|
||||
|
||||
const Box = ({ color, fixed = false, layout = 'column', outer = false, ...other }) => (
|
||||
const Box = ({ color, fixed = false, layout = 'column', outer = false, ...other }) =>
|
||||
<View
|
||||
{...other}
|
||||
style={[
|
||||
@@ -12,8 +12,7 @@ const Box = ({ color, fixed = false, layout = 'column', outer = false, ...other
|
||||
layout === 'row' && styles.row,
|
||||
outer && styles.outer
|
||||
]}
|
||||
/>
|
||||
);
|
||||
/>;
|
||||
|
||||
const styles = StyleSheet.create({
|
||||
outer: {
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
import React from 'react';
|
||||
import { StyleSheet, View } from 'react-native';
|
||||
|
||||
const Box = ({ color, fixed = false, layout = 'column', outer = false, ...other }) => (
|
||||
const Box = ({ color, fixed = false, layout = 'column', outer = false, ...other }) =>
|
||||
<View
|
||||
{...other}
|
||||
style={[
|
||||
@@ -11,8 +11,7 @@ const Box = ({ color, fixed = false, layout = 'column', outer = false, ...other
|
||||
layout === 'row' && styles.row,
|
||||
outer && styles.outer
|
||||
]}
|
||||
/>
|
||||
);
|
||||
/>;
|
||||
|
||||
const styles = StyleSheet.create({
|
||||
outer: {
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
import React from 'react';
|
||||
import { Styles, View } from 'reactxp';
|
||||
|
||||
const Box = ({ color, fixed = false, layout = 'column', outer = false, ...other }) => (
|
||||
const Box = ({ color, fixed = false, layout = 'column', outer = false, ...other }) =>
|
||||
<View
|
||||
{...other}
|
||||
style={[
|
||||
@@ -11,8 +11,7 @@ const Box = ({ color, fixed = false, layout = 'column', outer = false, ...other
|
||||
layout === 'row' && styles.row,
|
||||
outer && styles.outer
|
||||
]}
|
||||
/>
|
||||
);
|
||||
/>;
|
||||
|
||||
const styles = {
|
||||
outer: Styles.createViewStyle({
|
||||
|
||||
@@ -3,7 +3,7 @@ import { injectStylePrefixed } from 'styletron-utils';
|
||||
import React from 'react';
|
||||
import View, { styletron } from '../View/styletron';
|
||||
|
||||
const Box = ({ color, fixed = false, layout = 'column', outer = false, ...other }) => (
|
||||
const Box = ({ color, fixed = false, layout = 'column', outer = false, ...other }) =>
|
||||
<View
|
||||
{...other}
|
||||
style={[
|
||||
@@ -12,8 +12,7 @@ const Box = ({ color, fixed = false, layout = 'column', outer = false, ...other
|
||||
layout === 'row' && styles.row,
|
||||
outer && styles.outer
|
||||
]}
|
||||
/>
|
||||
);
|
||||
/>;
|
||||
|
||||
const styles = {
|
||||
outer: injectStylePrefixed(styletron, {
|
||||
|
||||
@@ -17,7 +17,7 @@ class DeepTree extends Component {
|
||||
<Box color={id % 3} components={components} layout={depth % 2 === 0 ? 'column' : 'row'} outer>
|
||||
{depth === 0 && <Box color={id % 3 + 3} components={components} fixed />}
|
||||
{depth !== 0 &&
|
||||
Array.from({ length: breadth }).map((el, i) => (
|
||||
Array.from({ length: breadth }).map((el, i) =>
|
||||
<DeepTree
|
||||
breadth={breadth}
|
||||
components={components}
|
||||
@@ -26,7 +26,7 @@ class DeepTree extends Component {
|
||||
key={i}
|
||||
wrap={wrap}
|
||||
/>
|
||||
))}
|
||||
)}
|
||||
</Box>
|
||||
);
|
||||
for (let i = 0; i < wrap; i++) {
|
||||
|
||||
@@ -24,7 +24,7 @@ export default class TweetActionsBar extends PureComponent {
|
||||
/* eslint-disable react/jsx-handler-names */
|
||||
return (
|
||||
<View style={[styles.root, style]}>
|
||||
{actions.map((action, i) => (
|
||||
{actions.map((action, i) =>
|
||||
<TweetAction
|
||||
accessibilityLabel={actions.label}
|
||||
count={action.count}
|
||||
@@ -34,7 +34,7 @@ export default class TweetActionsBar extends PureComponent {
|
||||
onPress={action.onPress}
|
||||
style={styles.action}
|
||||
/>
|
||||
))}
|
||||
)}
|
||||
</View>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -17,9 +17,9 @@ class TweetText extends React.Component {
|
||||
|
||||
return (
|
||||
<AppText {...other} lang={lang} numberOfLines={numberOfLines}>
|
||||
{textParts.map((part, i) => (
|
||||
{textParts.map((part, i) =>
|
||||
<TweetTextPart displayMode={displayMode} key={i} part={part} />
|
||||
))}
|
||||
)}
|
||||
</AppText>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -5,14 +5,13 @@ import theme from '../theme';
|
||||
|
||||
const createTextEntity = ({ part }) => <Text>{`${part.prefix}${part.text}`}</Text>;
|
||||
|
||||
const createTwemojiEntity = ({ part }) => (
|
||||
const createTwemojiEntity = ({ part }) =>
|
||||
<Image
|
||||
accessibilityLabel={part.text}
|
||||
draggable={false}
|
||||
source={{ uri: part.emoji }}
|
||||
style={styles.twemoji}
|
||||
/>
|
||||
);
|
||||
/>;
|
||||
|
||||
// @mention, #hashtag, $cashtag
|
||||
const createSymbolEntity = ({ displayMode, part }) => {
|
||||
|
||||
@@ -25,8 +25,9 @@ const fontSize = {
|
||||
|
||||
module.exports = {
|
||||
colors,
|
||||
fontFamily: '-apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Ubuntu, "Helvetica Neue", sans-serif, ' +
|
||||
'"Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol"', // emoji fonts
|
||||
fontFamily:
|
||||
'-apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Ubuntu, "Helvetica Neue", sans-serif, ' +
|
||||
'"Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol"', // emoji fonts
|
||||
fontSize,
|
||||
lineHeight: 1.3125,
|
||||
spaceX: 0.6,
|
||||
|
||||
@@ -14,8 +14,7 @@ into `runApplication`. These should always be used as a pair.
|
||||
(web) static **getApplication**(appKey:string, appParameters: object)
|
||||
|
||||
Returns the given application element. Use this for server-side rendering.
|
||||
Return object is of type `{ element: ReactElement; stylesheet: ReactElement }`.
|
||||
It's recommended that you use `sheetsheet` to render the style sheet in an app
|
||||
Return object is of type `{ element: ReactElement; stylesheets: [ ReactElement ] }`.
|
||||
|
||||
static **registerConfig**(config: Array<AppConfig>)
|
||||
|
||||
@@ -41,6 +40,9 @@ Runs the application that was registered under `appKey`. The `appParameters`
|
||||
must include the `rootTag` into which the application is rendered, and
|
||||
optionally any `initialProps`.
|
||||
|
||||
On web, if the `rootTag` is a sub-section of your application it should be
|
||||
styled as `position:relative` and given an explicit height.
|
||||
|
||||
static **unmountApplicationComponentAtRootTag**(rootTag: HTMLElement)
|
||||
|
||||
To "stop" an application when a view should be destroyed, call
|
||||
|
||||
@@ -1,42 +0,0 @@
|
||||
# NativeMethods
|
||||
|
||||
React Native for Web provides several methods to directly access the underlying
|
||||
DOM node. This can be useful in cases when you want to focus a view or measure
|
||||
its on-screen dimensions, for example.
|
||||
|
||||
The methods described are available on most of the default components provided
|
||||
by React Native for Web. Note, however, that they are *not* available on the
|
||||
composite components that you define in your own app. For more information, see
|
||||
[Direct Manipulation](../guides/direct-manipulation.md).
|
||||
|
||||
## Methods
|
||||
|
||||
**blur**()
|
||||
|
||||
Removes focus from an input or view. This is the opposite of `focus()`.
|
||||
|
||||
**focus**()
|
||||
|
||||
Requests focus for the given input or view. The exact behavior triggered will
|
||||
depend the type of view.
|
||||
|
||||
**measure**(callback: (x, y, width, height, pageX, pageY) => void)
|
||||
|
||||
For a given view, `measure` determines the offset relative to the parent view,
|
||||
width, height, and the offset relative to the viewport. Returns the values via
|
||||
an async callback.
|
||||
|
||||
Note that these measurements are not available until after the rendering has
|
||||
been completed.
|
||||
|
||||
**measureLayout**(relativeToNativeNode: DOMNode, onSuccess: (x, y, width, height) => void)
|
||||
|
||||
Like `measure`, but measures the view relative to another view, specified as
|
||||
`relativeToNativeNode`. This means that the returned `x`, `y` are relative to
|
||||
the origin `x`, `y` of the ancestor view.
|
||||
|
||||
**setNativeProps**(nativeProps: Object)
|
||||
|
||||
This function sends props straight to the underlying DOM node. See the [direct
|
||||
manipulation](../guides/direct-manipulation.md) guide for cases where
|
||||
`setNativeProps` should be used.
|
||||
@@ -16,9 +16,10 @@ Each key of the object passed to `create` must define a style object.
|
||||
|
||||
Flattens an array of styles into a single style object.
|
||||
|
||||
(web) **renderToString**: function
|
||||
(web) **getStyleSheets**: function
|
||||
|
||||
Returns a string of the stylesheet for use in server-side rendering.
|
||||
Returns an array of stylesheets (`{ id, textContent }`). Useful for
|
||||
compile-time or server-side rendering.
|
||||
|
||||
## Properties
|
||||
|
||||
|
||||
@@ -1,34 +0,0 @@
|
||||
# ListView
|
||||
|
||||
TODO
|
||||
|
||||
## Props
|
||||
|
||||
[...ScrollView props](./ScrollView.md)
|
||||
|
||||
**children**: any
|
||||
|
||||
Content to display over the image.
|
||||
|
||||
**style**: style
|
||||
|
||||
+ ...[View#style](View.md)
|
||||
|
||||
## Examples
|
||||
|
||||
```js
|
||||
import React, { Component, PropTypes } from 'react'
|
||||
import { ListView } from 'react-native'
|
||||
|
||||
export default class ListViewExample extends Component {
|
||||
static propTypes = {}
|
||||
|
||||
static defaultProps = {}
|
||||
|
||||
render() {
|
||||
return (
|
||||
<ListView />
|
||||
)
|
||||
}
|
||||
}
|
||||
```
|
||||
@@ -103,8 +103,10 @@ Callback that is called when the text input is focused.
|
||||
|
||||
**onKeyPress**: ?function
|
||||
|
||||
Callback that is called when a key is pressed. Pressed key value is passed as
|
||||
an argument to the callback handler. Fires before `onChange` callbacks.
|
||||
Callback that is called when a key is pressed. This will be called with `{
|
||||
nativeEvent: { key: keyValue } }` where keyValue is 'Enter` or 'Backspace' for
|
||||
respective keys and the typed-in character otherwise including ' ' for space.
|
||||
Fires before onChange callbacks.
|
||||
|
||||
**onSelectionChange**: ?function
|
||||
|
||||
|
||||
@@ -18,7 +18,7 @@ NOTE: `View` will transfer all other props to the rendered HTML element.
|
||||
Overrides the text that's read by a screen reader when the user interacts
|
||||
with the element. (This is implemented using `aria-label`.)
|
||||
|
||||
See the [Accessibility guide](../guides/accessibility) for more information.
|
||||
See the [Accessibility guide](../guides/accessibility.md) for more information.
|
||||
|
||||
**accessibilityLiveRegion**: ?enum('assertive', 'none', 'polite')
|
||||
|
||||
@@ -29,7 +29,7 @@ priority. When regions are specified as `assertive`, assistive technologies
|
||||
will interrupt and immediately notify the user. (This is implemented using
|
||||
[`aria-live`](http://www.w3.org/TR/wai-aria/states_and_properties#aria-live).)
|
||||
|
||||
See the [Accessibility guide](../guides/accessibility) for more information.
|
||||
See the [Accessibility guide](../guides/accessibility.md) for more information.
|
||||
|
||||
(web) **accessibilityRole**: ?enum(roles)
|
||||
|
||||
@@ -38,7 +38,7 @@ 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)).
|
||||
|
||||
See the [Accessibility guide](../guides/accessibility) for more information.
|
||||
See the [Accessibility guide](../guides/accessibility.md) for more information.
|
||||
|
||||
**accessible**: ?boolean
|
||||
|
||||
@@ -47,7 +47,7 @@ focusable) and groups its child content. By default, all the touchable elements
|
||||
and elements with `accessibilityRole` of `button` and `link` are accessible.
|
||||
(This is implemented using `tabindex`.)
|
||||
|
||||
See the [Accessibility guide](../guides/accessibility) for more information.
|
||||
See the [Accessibility guide](../guides/accessibility.md) for more information.
|
||||
|
||||
**children**: ?element
|
||||
|
||||
@@ -69,7 +69,7 @@ A value of `no` will remove the element from the tab flow.
|
||||
A value of `no-hide-descendants` will hide the element and its children from
|
||||
assistive technologies. (This is implemented using `aria-hidden`.)
|
||||
|
||||
See the [Accessibility guide](../guides/accessibility) for more information.
|
||||
See the [Accessibility guide](../guides/accessibility.md) for more information.
|
||||
|
||||
**onLayout**: ?function
|
||||
|
||||
@@ -132,15 +132,15 @@ Controls whether the View can be the target of touch events. The enhanced
|
||||
`box-none` is the equivalent of:
|
||||
|
||||
```css
|
||||
.box-none { pointer-events: none }
|
||||
.box-none * { pointer-events: auto }
|
||||
.box-none { pointer-events: none !important; }
|
||||
.box-none > * { pointer-events: auto; }
|
||||
```
|
||||
|
||||
`box-only` is the equivalent of:
|
||||
|
||||
```css
|
||||
.box-only { pointer-events: auto }
|
||||
.box-only * { pointer-events: none }
|
||||
.box-only { pointer-events: auto !important; }
|
||||
.box-only > * { pointer-events: none; }
|
||||
```
|
||||
|
||||
**style**: ?style
|
||||
@@ -158,6 +158,7 @@ Controls whether the View can be the target of touch events. The enhanced
|
||||
+ `animationTimingFunction` ‡
|
||||
+ `backfaceVisibility`
|
||||
+ `backgroundAttachment` ‡
|
||||
+ `backgroundBlendMode` ‡
|
||||
+ `backgroundClip` ‡
|
||||
+ `backgroundColor`
|
||||
+ `backgroundImage` ‡
|
||||
@@ -279,7 +280,7 @@ Default:
|
||||
};
|
||||
```
|
||||
|
||||
(See [facebook/css-layout](https://github.com/facebook/css-layout)).
|
||||
(See [facebook/yoga](https://github.com/facebook/yoga)).
|
||||
|
||||
**testID**: ?string
|
||||
|
||||
|
||||
@@ -1,27 +1,68 @@
|
||||
# Direct manipulation
|
||||
|
||||
It is sometimes necessary to make changes directly to a component without using
|
||||
state/props to trigger a re-render of the entire subtree – in the browser, this
|
||||
is done by directly modifying a DOM node. `setNativeProps` is the React Native
|
||||
equivalent to setting properties directly on a DOM node. Use direct
|
||||
manipulation when frequent re-rendering creates a performance bottleneck. Direct
|
||||
manipulation will not be a tool that you reach for frequently.
|
||||
React Native for Web provides several methods to directly access the underlying
|
||||
DOM node. This can be useful when you need to make changes directly to a
|
||||
component without using state/props to trigger a re-render of the entire
|
||||
subtree, or when you want to focus a view or measure its on-screen dimensions.
|
||||
|
||||
## `setNativeProps` and `shouldComponentUpdate`
|
||||
The methods described are available on most of the default components provided
|
||||
by React Native for Web. Note, however, that they are *not* available on the
|
||||
composite components that you define in your own app.
|
||||
|
||||
## Instance methods
|
||||
|
||||
**blur**()
|
||||
|
||||
Removes focus from an input or view. This is the opposite of `focus()`.
|
||||
|
||||
**focus**()
|
||||
|
||||
Requests focus for the given input or view. The exact behavior triggered will
|
||||
depend the type of view.
|
||||
|
||||
**measure**(callback: (x, y, width, height, pageX, pageY) => void)
|
||||
|
||||
For a given view, `measure` determines the offset relative to the parent view,
|
||||
width, height, and the offset relative to the viewport. Returns the values via
|
||||
an async callback.
|
||||
|
||||
Note that these measurements are not available until after the rendering has
|
||||
been completed.
|
||||
|
||||
**measureLayout**(relativeToNativeNode: DOMNode, onSuccess: (x, y, width, height) => void)
|
||||
|
||||
Like `measure`, but measures the view relative to another view, specified as
|
||||
`relativeToNativeNode`. This means that the returned `x`, `y` are relative to
|
||||
the origin `x`, `y` of the ancestor view.
|
||||
|
||||
**setNativeProps**(nativeProps: Object)
|
||||
|
||||
This function sends props straight to the underlying DOM node. See the [direct
|
||||
manipulation](../guides/direct-manipulation.md) guide for cases where
|
||||
`setNativeProps` should be used.
|
||||
|
||||
## About `setNativeProps`
|
||||
|
||||
`setNativeProps` is the React Native equivalent to setting properties directly
|
||||
on a DOM node. Use direct manipulation when frequent re-rendering creates a
|
||||
performance bottleneck. Direct manipulation will not be a tool that you reach
|
||||
for frequently.
|
||||
|
||||
### `setNativeProps` and `shouldComponentUpdate`
|
||||
|
||||
`setNativeProps` is imperative and stores state in the native layer (DOM,
|
||||
UIView, etc.) and not within your React components, which makes your code more
|
||||
difficult to reason about. Before you use it, try to solve your problem with
|
||||
`setState` and `shouldComponentUpdate`.
|
||||
|
||||
## Avoiding conflicts with the render function
|
||||
### Avoiding conflicts with the render function
|
||||
|
||||
If you update a property that is also managed by the render function, you might
|
||||
end up with some unpredictable and confusing bugs because anytime the component
|
||||
re-renders and that property changes, whatever value was previously set from
|
||||
`setNativeProps` will be completely ignored and overridden.
|
||||
|
||||
## Why use `setNativeProps` on Web?
|
||||
### Why use `setNativeProps` on Web?
|
||||
|
||||
Using `setNativeProps` in web-specific code is required when making changes to
|
||||
`className` or `style`, as these properties are controlled by React Native for
|
||||
@@ -35,7 +76,7 @@ setOpacityTo(value) {
|
||||
}
|
||||
```
|
||||
|
||||
## Composite components and `setNativeProps`
|
||||
### Composite components and `setNativeProps`
|
||||
|
||||
Composite components are not backed by a DOM node, so you cannot call
|
||||
`setNativeProps` on them. Consider this example:
|
||||
@@ -63,7 +104,7 @@ prop on it and have that work - you would need to pass the style prop down to a
|
||||
child, unless you are wrapping a native component. Similarly, we are going to
|
||||
forward `setNativeProps` to a native-backed child component.
|
||||
|
||||
## Forward `setNativeProps` to a child
|
||||
### Forward `setNativeProps` to a child
|
||||
|
||||
All we need to do is provide a `setNativeProps` method on our component that
|
||||
calls `setNativeProps` on the appropriate child with the given arguments.
|
||||
@@ -86,7 +127,7 @@ class MyButton extends React.Component {
|
||||
|
||||
You can now use `MyButton` inside of `TouchableOpacity`!
|
||||
|
||||
## `setNativeProps` to clear `TextInput` value
|
||||
### `setNativeProps` to clear `TextInput` value
|
||||
|
||||
Another very common use case of `setNativeProps` is to clear the value of a
|
||||
`TextInput`. For example, the following code demonstrates clearing the input
|
||||
|
||||
@@ -14,7 +14,7 @@ polyfill.
|
||||
|
||||
## Webpack and Babel
|
||||
|
||||
[Webpack](webpack.js.org) is a popular build tool for web apps. Below is an
|
||||
[Webpack](https://webpack.js.org) is a popular build tool for web apps. Below is an
|
||||
example of how to configure a build that uses [Babel](https://babeljs.io/) to
|
||||
compile your JavaScript for the web.
|
||||
|
||||
@@ -187,15 +187,16 @@ const AppContainer = (props) => { /* ... */ }
|
||||
AppRegistry.registerComponent('App', () => AppContainer)
|
||||
|
||||
// prerender the app
|
||||
const { element, stylesheet } = AppRegistry.getApplication('App', { initialProps });
|
||||
const { element, stylesheets } = AppRegistry.getApplication('App', { initialProps });
|
||||
const initialHTML = ReactDOMServer.renderToString(element);
|
||||
const initialStyles = stylesheets.map((sheet) => ReactDOMServer.renderToString(sheet)).join('\n');
|
||||
|
||||
// construct HTML document
|
||||
const document = `
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
${stylesheet}
|
||||
${initialStyles}
|
||||
</head>
|
||||
<body>
|
||||
${initialHTML}
|
||||
|
||||
@@ -225,7 +225,8 @@ 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.
|
||||
|
||||
### What about using DevTools?
|
||||
### What about using Dev Tools?
|
||||
|
||||
It's recommended that you rely more on React DevTools and live/hot-reloading
|
||||
rather than inspecting and editing the DOM directly.
|
||||
React Dev Tools supports inspecting and editing of React Native styles. It's
|
||||
recommended that you rely more on React Dev Tools and live/hot-reloading rather
|
||||
than inspecting and editing the DOM directly.
|
||||
|
||||
@@ -3,15 +3,13 @@ import { StyleSheet, View } from 'react-native';
|
||||
|
||||
const styles = StyleSheet.create({
|
||||
root: {
|
||||
alignItems: 'center',
|
||||
height: '100vh',
|
||||
justifyContent: 'center'
|
||||
minHeight: '100vh'
|
||||
}
|
||||
});
|
||||
|
||||
export default function(renderStory) {
|
||||
return (
|
||||
<View style={[StyleSheet.absoluteFill, styles.root]}>
|
||||
<View style={styles.root}>
|
||||
{renderStory()}
|
||||
</View>
|
||||
);
|
||||
|
||||
84
docs/storybook/UIExplorer.js
Normal file
84
docs/storybook/UIExplorer.js
Normal file
@@ -0,0 +1,84 @@
|
||||
/* eslint-disable react/prop-types */
|
||||
|
||||
import React from 'react';
|
||||
import { StyleSheet, Text, View } from 'react-native';
|
||||
|
||||
/**
|
||||
* Examples explorer
|
||||
*/
|
||||
const AppText = ({ style, ...rest }) => <Text {...rest} style={[styles.baseText, style]} />;
|
||||
const Link = ({ uri }) =>
|
||||
<AppText accessibilityRole="link" href={uri} style={styles.link} target="_blank">
|
||||
API documentation
|
||||
</AppText>;
|
||||
const Title = ({ children }) => <AppText style={styles.title}>{children}</AppText>;
|
||||
const Description = ({ children }) => <AppText style={styles.description}>{children}</AppText>;
|
||||
|
||||
const Example = ({ example: { description, render, title } }) =>
|
||||
<View style={styles.example}>
|
||||
<AppText style={styles.exampleTitle}>{title}</AppText>
|
||||
{description && <AppText style={styles.exampleDescription}>{description}</AppText>}
|
||||
{render &&
|
||||
<View style={styles.exampleRenderBox}>
|
||||
<AppText style={styles.exampleText}>Example</AppText>
|
||||
<View>{render()}</View>
|
||||
</View>}
|
||||
</View>;
|
||||
|
||||
const UIExplorer = ({ description, examples, title, url }) =>
|
||||
<View style={styles.root}>
|
||||
<Title>{title}</Title>
|
||||
{description && <Description>{description}</Description>}
|
||||
{url && <Link uri={url} />}
|
||||
{examples.map((example, i) => <Example example={example} key={i} />)}
|
||||
</View>;
|
||||
|
||||
const styles = StyleSheet.create({
|
||||
root: {
|
||||
padding: '1rem',
|
||||
flex: 1
|
||||
},
|
||||
baseText: {
|
||||
fontFamily:
|
||||
'-apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Ubuntu, "Helvetica Neue", sans-serif, ' +
|
||||
'"Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol"', // emoji fonts
|
||||
lineHeight: '1.3125em'
|
||||
},
|
||||
title: {
|
||||
fontSize: '2rem'
|
||||
},
|
||||
description: {
|
||||
color: '#657786',
|
||||
fontSize: '1.3125rem',
|
||||
marginTop: 'calc(0.5 * 1.3125rem)'
|
||||
},
|
||||
link: {
|
||||
color: '#1B95E0',
|
||||
marginTop: 'calc(0.5 * 1.3125rem)'
|
||||
},
|
||||
example: {
|
||||
marginTop: 'calc(2 * 1.3125rem)'
|
||||
},
|
||||
exampleTitle: {
|
||||
fontSize: '1.3125rem'
|
||||
},
|
||||
exampleDescription: {
|
||||
fontSize: '1rem',
|
||||
marginTop: 'calc(0.5 * 1.3125rem)'
|
||||
},
|
||||
exampleRenderBox: {
|
||||
borderColor: '#E6ECF0',
|
||||
borderWidth: 1,
|
||||
padding: '1.3125rem',
|
||||
marginTop: '1.3125rem'
|
||||
},
|
||||
exampleText: {
|
||||
color: '#AAB8C2',
|
||||
fontSize: '0.8rem',
|
||||
fontWeight: 'bold',
|
||||
marginBottom: 'calc(0.5 * 1.3125rem)',
|
||||
textTransform: 'uppercase'
|
||||
}
|
||||
});
|
||||
|
||||
export default UIExplorer;
|
||||
@@ -1,34 +1,61 @@
|
||||
import { Clipboard, Text, TextInput, View } from 'react-native';
|
||||
import React, { Component } from 'react';
|
||||
import { storiesOf } from '@kadira/storybook';
|
||||
import UIExplorer from '../../UIExplorer';
|
||||
import { Button, Clipboard, StyleSheet, TextInput, View } from 'react-native';
|
||||
import React, { Component } from 'react';
|
||||
|
||||
const styles = StyleSheet.create({
|
||||
buttonBox: {
|
||||
maxWidth: 300
|
||||
},
|
||||
textInput: {
|
||||
borderColor: '#AAB8C2',
|
||||
borderWidth: 1,
|
||||
height: 200,
|
||||
marginTop: 20,
|
||||
padding: 10
|
||||
}
|
||||
});
|
||||
|
||||
class ClipboardExample extends Component {
|
||||
render() {
|
||||
return (
|
||||
<View style={{ minWidth: 300 }}>
|
||||
<Text onPress={this._handleSet}>Copy to clipboard</Text>
|
||||
<View>
|
||||
<View style={styles.buttonBox}>
|
||||
<Button onPress={this._handleSet} title="Copy to clipboard" />
|
||||
</View>
|
||||
<TextInput
|
||||
multiline={true}
|
||||
placeholder={'Try pasting here afterwards'}
|
||||
style={{ borderWidth: 1, height: 200, marginVertical: 20 }}
|
||||
style={styles.textInput}
|
||||
/>
|
||||
<Text onPress={this._handleGet}>
|
||||
(Clipboard.getString returns a Promise that always resolves to an empty string on web)
|
||||
</Text>
|
||||
</View>
|
||||
);
|
||||
}
|
||||
|
||||
_handleGet() {
|
||||
Clipboard.getString().then(value => {
|
||||
console.log(`Clipboard value: ${value}`);
|
||||
});
|
||||
}
|
||||
|
||||
_handleSet() {
|
||||
const success = Clipboard.setString('This text was copied to the clipboard by React Native');
|
||||
console.log(`Clipboard.setString success? ${success}`);
|
||||
}
|
||||
}
|
||||
|
||||
storiesOf('api: Clipboard', module).add('setString', () => <ClipboardExample />);
|
||||
const examples = [
|
||||
{
|
||||
title: 'Clipboard.setString',
|
||||
description:
|
||||
'(Note that `Clipboard.getString` returns a Promise that always resolves to an empty string on web.)',
|
||||
render: () => <ClipboardExample />
|
||||
},
|
||||
{
|
||||
title: 'Clipboard.getString',
|
||||
description:
|
||||
'Not properly supported on Web. Returns a Promise that always resolves to an empty string on web.'
|
||||
}
|
||||
];
|
||||
|
||||
storiesOf('APIs', module).add('Clipboard', () =>
|
||||
<UIExplorer
|
||||
description="Clipboard gives you an interface for setting to the clipboard."
|
||||
examples={examples}
|
||||
title="Clipboard"
|
||||
/>
|
||||
);
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import { storiesOf } from '@kadira/storybook';
|
||||
import UIExplorer from '../../UIExplorer';
|
||||
import { I18nManager, StyleSheet, TouchableHighlight, Text, View } from 'react-native';
|
||||
import React, { Component } from 'react';
|
||||
|
||||
@@ -14,7 +15,8 @@ class I18nManagerExample extends Component {
|
||||
LTR/RTL layout example!
|
||||
</Text>
|
||||
<Text style={styles.text}>
|
||||
The writing direction of text is automatically determined by the browser, independent of the global writing direction of the app.
|
||||
The writing direction of text is automatically determined by the browser, independent of
|
||||
the global writing direction of the app.
|
||||
</Text>
|
||||
<Text style={[styles.text, styles.rtlText]}>
|
||||
أحب اللغة العربية
|
||||
@@ -84,4 +86,13 @@ const styles = StyleSheet.create({
|
||||
}
|
||||
});
|
||||
|
||||
storiesOf('api: I18nManager', module).add('RTL layout', () => <I18nManagerExample />);
|
||||
const examples = [
|
||||
{
|
||||
title: 'RTL toggle',
|
||||
render: () => <I18nManagerExample />
|
||||
}
|
||||
];
|
||||
|
||||
storiesOf('APIs', module).add('I18nManager', () =>
|
||||
<UIExplorer examples={examples} title="I18nManager" />
|
||||
);
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import { storiesOf } from '@kadira/storybook';
|
||||
import UIExplorer from '../../UIExplorer';
|
||||
import { Linking, StyleSheet, Text, View } from 'react-native';
|
||||
import React, { Component } from 'react';
|
||||
import { storiesOf } from '@kadira/storybook';
|
||||
|
||||
const url = 'https://mathiasbynens.github.io/rel-noopener/malicious.html';
|
||||
|
||||
@@ -36,4 +37,11 @@ const styles = StyleSheet.create({
|
||||
}
|
||||
});
|
||||
|
||||
storiesOf('api: Linking', module).add('Safe linking', () => <LinkingExample />);
|
||||
const examples = [
|
||||
{
|
||||
title: 'Safe external links',
|
||||
render: () => <LinkingExample />
|
||||
}
|
||||
];
|
||||
|
||||
storiesOf('APIs', module).add('Linking', () => <UIExplorer examples={examples} title="Linking" />);
|
||||
|
||||
@@ -1,8 +1,9 @@
|
||||
/* eslint-disable react/jsx-no-bind */
|
||||
/* eslint-disable react/jsx-no-bind, react/prefer-es6-class */
|
||||
|
||||
import createReactClass from 'create-react-class';
|
||||
import React from 'react';
|
||||
import { storiesOf } from '@kadira/storybook';
|
||||
import UIExplorer from '../../UIExplorer';
|
||||
import { PanResponder, StyleSheet, View } from 'react-native';
|
||||
|
||||
const CIRCLE_SIZE = 80;
|
||||
@@ -97,12 +98,23 @@ const styles = StyleSheet.create({
|
||||
height: CIRCLE_SIZE,
|
||||
borderRadius: CIRCLE_SIZE / 2,
|
||||
position: 'absolute',
|
||||
left: 0,
|
||||
top: 0
|
||||
},
|
||||
container: {
|
||||
flex: 1,
|
||||
minHeight: 400,
|
||||
paddingTop: 64
|
||||
}
|
||||
});
|
||||
|
||||
storiesOf('api: PanResponder', module).add('example', () => <PanResponderExample />);
|
||||
const examples = [
|
||||
{
|
||||
title: 'Draggable circle',
|
||||
render: () => <PanResponderExample />
|
||||
}
|
||||
];
|
||||
|
||||
storiesOf('APIs', module).add('PanResponder', () =>
|
||||
<UIExplorer examples={examples} title="PanResponder" />
|
||||
);
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
/* eslint-disable react/prefer-es6-class, react/prop-types */
|
||||
|
||||
/**
|
||||
* Copyright (c) 2013-present, Facebook, Inc.
|
||||
* All rights reserved.
|
||||
@@ -24,8 +26,9 @@
|
||||
import createReactClass from 'create-react-class';
|
||||
import React from 'react';
|
||||
import { storiesOf } from '@kadira/storybook';
|
||||
import { ActivityIndicator, StyleSheet, View } from 'react-native';
|
||||
import TimerMixin from 'react-timer-mixin';
|
||||
import UIExplorer from '../../UIExplorer';
|
||||
import { ActivityIndicator, StyleSheet, View } from 'react-native';
|
||||
|
||||
const ToggleAnimatingActivityIndicator = createReactClass({
|
||||
mixins: [TimerMixin],
|
||||
@@ -62,62 +65,59 @@ const ToggleAnimatingActivityIndicator = createReactClass({
|
||||
const examples = [
|
||||
{
|
||||
title: 'Default',
|
||||
description: 'Renders small and blue',
|
||||
render() {
|
||||
return <ActivityIndicator style={[styles.centering]} />;
|
||||
return (
|
||||
<View style={styles.horizontal}>
|
||||
<ActivityIndicator />
|
||||
</View>
|
||||
);
|
||||
}
|
||||
},
|
||||
{
|
||||
title: 'Custom colors',
|
||||
description: 'Any color value is supported',
|
||||
render() {
|
||||
return (
|
||||
<View style={styles.horizontal}>
|
||||
<ActivityIndicator color="#0000ff" />
|
||||
<ActivityIndicator color="#aa00aa" />
|
||||
<ActivityIndicator color="#aa3300" />
|
||||
<ActivityIndicator color="#00aa00" />
|
||||
<ActivityIndicator color="#1DA1F2" style={styles.rightPadding} />
|
||||
<ActivityIndicator color="#17BF63" style={styles.rightPadding} />
|
||||
<ActivityIndicator color="#F45D22" style={styles.rightPadding} />
|
||||
<ActivityIndicator color="#794BC4" style={styles.rightPadding} />
|
||||
<ActivityIndicator color="#E0245E" style={styles.rightPadding} />
|
||||
<ActivityIndicator color="#FFAD1F" style={styles.rightPadding} />
|
||||
</View>
|
||||
);
|
||||
}
|
||||
},
|
||||
{
|
||||
title: 'Large',
|
||||
render() {
|
||||
return (
|
||||
<ActivityIndicator color="white" size="large" style={[styles.centering, styles.gray]} />
|
||||
);
|
||||
}
|
||||
},
|
||||
{
|
||||
title: 'Large, custom colors',
|
||||
title: 'Custom sizes',
|
||||
description:
|
||||
'There are 2 predefined sizes: "small" and "large". The size can be further customized as a number (pixels) or using scale transforms',
|
||||
render() {
|
||||
return (
|
||||
<View style={styles.horizontal}>
|
||||
<ActivityIndicator color="#0000ff" size="large" />
|
||||
<ActivityIndicator color="#aa00aa" size="large" />
|
||||
<ActivityIndicator color="#aa3300" size="large" />
|
||||
<ActivityIndicator color="#00aa00" size="large" />
|
||||
<ActivityIndicator size={20} style={styles.rightPadding} />
|
||||
<ActivityIndicator size="small" style={styles.rightPadding} />
|
||||
<ActivityIndicator size={36} style={styles.rightPadding} />
|
||||
<ActivityIndicator size="large" style={styles.rightPadding} />
|
||||
<ActivityIndicator size={60} style={styles.rightPadding} />
|
||||
<ActivityIndicator
|
||||
size="large"
|
||||
style={{ marginLeft: 20, transform: [{ scale: 1.75 }] }}
|
||||
/>
|
||||
</View>
|
||||
);
|
||||
}
|
||||
},
|
||||
{
|
||||
title: 'Start/stop',
|
||||
title: 'Animation controls (start, pause, hide)',
|
||||
description: 'The animation can be paused, and the component hidden',
|
||||
render() {
|
||||
return (
|
||||
<View style={[styles.horizontal, styles.centering]}>
|
||||
<View style={[styles.horizontal]}>
|
||||
<ToggleAnimatingActivityIndicator hidesWhenStopped={false} style={styles.rightPadding} />
|
||||
<ToggleAnimatingActivityIndicator />
|
||||
<ToggleAnimatingActivityIndicator hidesWhenStopped={false} />
|
||||
</View>
|
||||
);
|
||||
}
|
||||
},
|
||||
{
|
||||
title: 'Custom size',
|
||||
render() {
|
||||
return (
|
||||
<View style={[styles.horizontal, styles.centering]}>
|
||||
<ActivityIndicator size={40} />
|
||||
<ActivityIndicator size="large" style={{ marginLeft: 20, transform: [{ scale: 1.5 }] }} />
|
||||
</View>
|
||||
);
|
||||
}
|
||||
@@ -125,21 +125,23 @@ const examples = [
|
||||
];
|
||||
|
||||
const styles = StyleSheet.create({
|
||||
centering: {
|
||||
alignItems: 'center',
|
||||
justifyContent: 'center',
|
||||
padding: 8
|
||||
},
|
||||
gray: {
|
||||
backgroundColor: '#cccccc'
|
||||
},
|
||||
horizontal: {
|
||||
flexDirection: 'row',
|
||||
justifyContent: 'space-around',
|
||||
padding: 8
|
||||
alignItems: 'center',
|
||||
flexDirection: 'row'
|
||||
},
|
||||
rightPadding: {
|
||||
paddingRight: 10
|
||||
}
|
||||
});
|
||||
|
||||
examples.forEach(example => {
|
||||
storiesOf('component: ActivityIndicator', module).add(example.title, () => example.render());
|
||||
});
|
||||
storiesOf('Components', module).add('ActivityIndicator', () =>
|
||||
<UIExplorer
|
||||
description="Displays a customizable activity indicator"
|
||||
examples={examples}
|
||||
title="ActivityIndicator"
|
||||
url="https://github.com/necolas/react-native-web/blob/master/docs/components/ActivityIndicator.md"
|
||||
/>
|
||||
);
|
||||
|
||||
@@ -1,52 +1,66 @@
|
||||
import React from 'react';
|
||||
import UIExplorer from '../../UIExplorer';
|
||||
import { action, storiesOf } from '@kadira/storybook';
|
||||
import { Button, View } from 'react-native';
|
||||
import { Button, StyleSheet, View } from 'react-native';
|
||||
|
||||
const onButtonPress = action('Button has been pressed!');
|
||||
|
||||
const examples = [
|
||||
{
|
||||
title: 'Simple Button',
|
||||
description: 'The title and onPress handler are required. It is ' +
|
||||
'recommended to set accessibilityLabel to help make your app usable by ' +
|
||||
'everyone.',
|
||||
render: function() {
|
||||
title: 'Default',
|
||||
description:
|
||||
'The title and onPress handler are required. It is ' +
|
||||
'recommended to set "accessibilityLabel" to help make your app usable by ' +
|
||||
'everyone.',
|
||||
render() {
|
||||
return (
|
||||
<Button
|
||||
accessibilityLabel="See an informative alert"
|
||||
onPress={onButtonPress}
|
||||
title="Press Me"
|
||||
title="Press me"
|
||||
/>
|
||||
);
|
||||
}
|
||||
},
|
||||
{
|
||||
title: 'Adjusted color',
|
||||
description: 'Adjusts the color in a way that looks standard on each ' +
|
||||
'platform. On iOS, the color prop controls the color of the text. On ' +
|
||||
'Android, the color adjusts the background color of the button.',
|
||||
render: function() {
|
||||
title: 'Custom colors',
|
||||
description:
|
||||
'Adjusts the color in a way that looks standard on each ' +
|
||||
'platform. On iOS, the color prop controls the color of the text. On ' +
|
||||
'Android, the color adjusts the background color of the button.',
|
||||
render() {
|
||||
return (
|
||||
<Button
|
||||
accessibilityLabel="Learn more about purple"
|
||||
color="#841584"
|
||||
onPress={onButtonPress}
|
||||
title="Press Purple"
|
||||
/>
|
||||
<View>
|
||||
<Button color="#17BF63" onPress={onButtonPress} title="Press me" />
|
||||
<View style={styles.verticalDivider} />
|
||||
<Button color="#F45D22" onPress={onButtonPress} title="Press me" />
|
||||
<View style={styles.verticalDivider} />
|
||||
<Button color="#794BC4" onPress={onButtonPress} title="Press me" />
|
||||
<View style={styles.verticalDivider} />
|
||||
<Button color="#E0245E" onPress={onButtonPress} title="Press me" />
|
||||
</View>
|
||||
);
|
||||
}
|
||||
},
|
||||
{
|
||||
title: 'Disabled',
|
||||
description: 'All interactions for the component are disabled.',
|
||||
render() {
|
||||
return <Button disabled onPress={onButtonPress} title="Disabled button" />;
|
||||
}
|
||||
},
|
||||
{
|
||||
title: 'Fit to text layout',
|
||||
description: 'This layout strategy lets the title define the width of the button',
|
||||
render: function() {
|
||||
render() {
|
||||
return (
|
||||
<View style={{ flexDirection: 'row', justifyContent: 'space-between' }}>
|
||||
<View style={styles.horizontal}>
|
||||
<Button
|
||||
accessibilityLabel="This sounds great!"
|
||||
onPress={onButtonPress}
|
||||
title="This looks great!"
|
||||
/>
|
||||
<View style={styles.horizontalDivider} />
|
||||
<Button
|
||||
accessibilityLabel="Ok, Great!"
|
||||
color="#841584"
|
||||
@@ -56,23 +70,26 @@ const examples = [
|
||||
</View>
|
||||
);
|
||||
}
|
||||
},
|
||||
{
|
||||
title: 'Disabled Button',
|
||||
description: 'All interactions for the component are disabled.',
|
||||
render: function() {
|
||||
return (
|
||||
<Button
|
||||
accessibilityLabel="See an informative alert"
|
||||
disabled
|
||||
onPress={onButtonPress}
|
||||
title="I Am Disabled"
|
||||
/>
|
||||
);
|
||||
}
|
||||
}
|
||||
];
|
||||
|
||||
examples.forEach(example => {
|
||||
storiesOf('component: Button', module).add(example.title, () => example.render());
|
||||
const styles = StyleSheet.create({
|
||||
horizontalDivider: {
|
||||
width: '0.6rem'
|
||||
},
|
||||
horizontal: {
|
||||
flexDirection: 'row'
|
||||
},
|
||||
verticalDivider: {
|
||||
height: '1.3125rem'
|
||||
}
|
||||
});
|
||||
|
||||
storiesOf('Components', module).add('Button', () =>
|
||||
<UIExplorer
|
||||
description="A basic button component. Supports a minimal level of customization. You can build your own custom button using "TouchableOpacity" or "TouchableNativeFeedback""
|
||||
examples={examples}
|
||||
title="Button"
|
||||
url="https://github.com/necolas/react-native-web/blob/master/docs/components/Button.md"
|
||||
/>
|
||||
);
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/* eslint-disable react/jsx-no-bind */
|
||||
/* eslint-disable react/jsx-no-bind, react/prefer-es6-class, react/prop-types */
|
||||
|
||||
/**
|
||||
* Copyright (c) 2013-present, Facebook, Inc.
|
||||
@@ -23,32 +23,34 @@
|
||||
* @flow
|
||||
*/
|
||||
|
||||
import createReactClass from 'create-react-class';
|
||||
import React from 'react';
|
||||
import UIExplorer from '../../UIExplorer';
|
||||
import { storiesOf } from '@kadira/storybook';
|
||||
import { ActivityIndicator, Image, StyleSheet, Text, View } from 'react-native';
|
||||
|
||||
const base64Icon =
|
||||
'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAEsAAABLCAQAAACSR7JhAAADtUlEQVR4Ac3YA2Bj6QLH0XPT1Fzbtm29tW3btm3bfLZtv7e2ObZnms7d8Uw098tuetPzrxv8wiISrtVudrG2JXQZ4VOv+qUfmqCGGl1mqLhoA52oZlb0mrjsnhKpgeUNEs91Z0pd1kvihA3ULGVHiQO2narKSHKkEMulm9VgUyE60s1aWoMQUbpZOWE+kaqs4eLEjdIlZTcFZB0ndc1+lhB1lZrIuk5P2aib1NBpZaL+JaOGIt0ls47SKzLC7CqrlGF6RZ09HGoNy1lYl2aRSWL5GuzqWU1KafRdoRp0iOQEiDzgZPnG6DbldcomadViflnl/cL93tOoVbsOLVM2jylvdWjXolWX1hmfZbGR/wjypDjFLSZIRov09BgYmtUqPQPlQrPapecLgTIy0jMgPKtTeob2zWtrGH3xvjUkPCtNg/tm1rjwrMa+mdUkPd3hWbH0jArPGiU9ufCsNNWFZ40wpwn+62/66R2RUtoso1OB34tnLOcy7YB1fUdc9e0q3yru8PGM773vXsuZ5YIZX+5xmHwHGVvlrGPN6ZSiP1smOsMMde40wKv2VmwPPVXNut4sVpUreZiLBHi0qln/VQeI/LTMYXpsJtFiclUN+5HVZazim+Ky+7sAvxWnvjXrJFneVtLWLyPJu9K3cXLWeOlbMTlrIelbMDlrLenrjEQOtIF+fuI9xRp9ZBFp6+b6WT8RrxEpdK64BuvHgDk+vUy+b5hYk6zfyfs051gRoNO1usU12WWRWL73/MMEy9pMi9qIrR4ZpV16Rrvduxazmy1FSvuFXRkqTnE7m2kdb5U8xGjLw/spRr1uTov4uOgQE+0N/DvFrG/Jt7i/FzwxbA9kDanhf2w+t4V97G8lrT7wc08aA2QNUkuTfW/KimT01wdlfK4yEw030VfT0RtZbzjeMprNq8m8tnSTASrTLti64oBNdpmMQm0eEwvfPwRbUBywG5TzjPCsdwk3IeAXjQblLCoXnDVeoAz6SfJNk5TTzytCNZk/POtTSV40NwOFWzw86wNJRpubpXsn60NJFlHeqlYRbslqZm2jnEZ3qcSKgm0kTli3zZVS7y/iivZTweYXJ26Y+RTbV1zh3hYkgyFGSTKPfRVbRqWWVReaxYeSLarYv1Qqsmh1s95S7G+eEWK0f3jYKTbV6bOwepjfhtafsvUsqrQvrGC8YhmnO9cSCk3yuY984F1vesdHYhWJ5FvASlacshUsajFt2mUM9pqzvKGcyNJW0arTKN1GGGzQlH0tXwLDgQTurS8eIQAAAABJRU5ErkJggg==';
|
||||
const dataSvg =
|
||||
'data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 841.9 595.3"><g fill="#61DAFB"><path d="M666.3 296.5c0-32.5-40.7-63.3-103.1-82.4 14.4-63.6 8-114.2-20.2-130.4-6.5-3.8-14.1-5.6-22.4-5.6v22.3c4.6 0 8.3.9 11.4 2.6 13.6 7.8 19.5 37.5 14.9 75.7-1.1 9.4-2.9 19.3-5.1 29.4-19.6-4.8-41-8.5-63.5-10.9-13.5-18.5-27.5-35.3-41.6-50 32.6-30.3 63.2-46.9 84-46.9V78c-27.5 0-63.5 19.6-99.9 53.6-36.4-33.8-72.4-53.2-99.9-53.2v22.3c20.7 0 51.4 16.5 84 46.6-14 14.7-28 31.4-41.3 49.9-22.6 2.4-44 6.1-63.6 11-2.3-10-4-19.7-5.2-29-4.7-38.2 1.1-67.9 14.6-75.8 3-1.8 6.9-2.6 11.5-2.6V78.5c-8.4 0-16 1.8-22.6 5.6-28.1 16.2-34.4 66.7-19.9 130.1-62.2 19.2-102.7 49.9-102.7 82.3 0 32.5 40.7 63.3 103.1 82.4-14.4 63.6-8 114.2 20.2 130.4 6.5 3.8 14.1 5.6 22.5 5.6 27.5 0 63.5-19.6 99.9-53.6 36.4 33.8 72.4 53.2 99.9 53.2 8.4 0 16-1.8 22.6-5.6 28.1-16.2 34.4-66.7 19.9-130.1 62-19.1 102.5-49.9 102.5-82.3zm-130.2-66.7c-3.7 12.9-8.3 26.2-13.5 39.5-4.1-8-8.4-16-13.1-24-4.6-8-9.5-15.8-14.4-23.4 14.2 2.1 27.9 4.7 41 7.9zm-45.8 106.5c-7.8 13.5-15.8 26.3-24.1 38.2-14.9 1.3-30 2-45.2 2-15.1 0-30.2-.7-45-1.9-8.3-11.9-16.4-24.6-24.2-38-7.6-13.1-14.5-26.4-20.8-39.8 6.2-13.4 13.2-26.8 20.7-39.9 7.8-13.5 15.8-26.3 24.1-38.2 14.9-1.3 30-2 45.2-2 15.1 0 30.2.7 45 1.9 8.3 11.9 16.4 24.6 24.2 38 7.6 13.1 14.5 26.4 20.8 39.8-6.3 13.4-13.2 26.8-20.7 39.9zm32.3-13c5.4 13.4 10 26.8 13.8 39.8-13.1 3.2-26.9 5.9-41.2 8 4.9-7.7 9.8-15.6 14.4-23.7 4.6-8 8.9-16.1 13-24.1zM421.2 430c-9.3-9.6-18.6-20.3-27.8-32 9 .4 18.2.7 27.5.7 9.4 0 18.7-.2 27.8-.7-9 11.7-18.3 22.4-27.5 32zm-74.4-58.9c-14.2-2.1-27.9-4.7-41-7.9 3.7-12.9 8.3-26.2 13.5-39.5 4.1 8 8.4 16 13.1 24 4.7 8 9.5 15.8 14.4 23.4zM420.7 163c9.3 9.6 18.6 20.3 27.8 32-9-.4-18.2-.7-27.5-.7-9.4 0-18.7.2-27.8.7 9-11.7 18.3-22.4 27.5-32zm-74 58.9c-4.9 7.7-9.8 15.6-14.4 23.7-4.6 8-8.9 16-13 24-5.4-13.4-10-26.8-13.8-39.8 13.1-3.1 26.9-5.8 41.2-7.9zm-90.5 125.2c-35.4-15.1-58.3-34.9-58.3-50.6 0-15.7 22.9-35.6 58.3-50.6 8.6-3.7 18-7 27.7-10.1 5.7 19.6 13.2 40 22.5 60.9-9.2 20.8-16.6 41.1-22.2 60.6-9.9-3.1-19.3-6.5-28-10.2zM310 490c-13.6-7.8-19.5-37.5-14.9-75.7 1.1-9.4 2.9-19.3 5.1-29.4 19.6 4.8 41 8.5 63.5 10.9 13.5 18.5 27.5 35.3 41.6 50-32.6 30.3-63.2 46.9-84 46.9-4.5-.1-8.3-1-11.3-2.7zm237.2-76.2c4.7 38.2-1.1 67.9-14.6 75.8-3 1.8-6.9 2.6-11.5 2.6-20.7 0-51.4-16.5-84-46.6 14-14.7 28-31.4 41.3-49.9 22.6-2.4 44-6.1 63.6-11 2.3 10.1 4.1 19.8 5.2 29.1zm38.5-66.7c-8.6 3.7-18 7-27.7 10.1-5.7-19.6-13.2-40-22.5-60.9 9.2-20.8 16.6-41.1 22.2-60.6 9.9 3.1 19.3 6.5 28.1 10.2 35.4 15.1 58.3 34.9 58.3 50.6-.1 15.7-23 35.6-58.4 50.6zM320.8 78.4z"/><circle cx="420.9" cy="296.5" r="45.7"/><path d="M520.5 78.1z"/></g></svg>';
|
||||
|
||||
//var ImageCapInsetsExample = require('./ImageCapInsetsExample');
|
||||
const IMAGE_PREFETCH_URL = 'http://origami.design/public/images/bird-logo.png?r=1&t=' + Date.now();
|
||||
const prefetchTask = Image.prefetch(IMAGE_PREFETCH_URL);
|
||||
|
||||
const NetworkImageCallbackExample = createReactClass({
|
||||
getInitialState: function() {
|
||||
return {
|
||||
class NetworkImageCallbackExample extends React.Component {
|
||||
constructor(props, context) {
|
||||
super(props, context);
|
||||
this.state = {
|
||||
events: [],
|
||||
startLoadPrefetched: false,
|
||||
mountTime: new Date()
|
||||
};
|
||||
},
|
||||
}
|
||||
|
||||
componentWillMount() {
|
||||
this.setState({ mountTime: new Date() });
|
||||
},
|
||||
}
|
||||
|
||||
render: function() {
|
||||
render() {
|
||||
const { mountTime } = this.state;
|
||||
|
||||
return (
|
||||
@@ -90,24 +92,21 @@ const NetworkImageCallbackExample = createReactClass({
|
||||
</Text>
|
||||
</View>
|
||||
);
|
||||
},
|
||||
|
||||
_loadEventFired(event) {
|
||||
this.setState(state => {
|
||||
return (state.events = [...state.events, event]);
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
const NetworkImageExample = createReactClass({
|
||||
getInitialState: function() {
|
||||
return {
|
||||
error: false,
|
||||
loading: false,
|
||||
progress: 0
|
||||
};
|
||||
},
|
||||
render: function() {
|
||||
_loadEventFired = event => {
|
||||
this.setState(state => (state.events = [...state.events, event]));
|
||||
};
|
||||
}
|
||||
|
||||
class NetworkImageExample extends React.Component {
|
||||
state = {
|
||||
error: false,
|
||||
loading: false,
|
||||
progress: 0
|
||||
};
|
||||
|
||||
render() {
|
||||
const loader = this.state.loading
|
||||
? <View style={styles.progress}>
|
||||
<Text>{this.state.progress}%</Text>
|
||||
@@ -130,21 +129,21 @@ const NetworkImageExample = createReactClass({
|
||||
{loader}
|
||||
</Image>;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
const ImageSizeExample = createReactClass({
|
||||
getInitialState: function() {
|
||||
return {
|
||||
width: 0,
|
||||
height: 0
|
||||
};
|
||||
},
|
||||
componentDidMount: function() {
|
||||
class ImageSizeExample extends React.Component {
|
||||
state = {
|
||||
width: 0,
|
||||
height: 0
|
||||
};
|
||||
|
||||
componentDidMount() {
|
||||
Image.getSize(this.props.source.uri, (width, height) => {
|
||||
this.setState({ width, height });
|
||||
});
|
||||
},
|
||||
render: function() {
|
||||
}
|
||||
|
||||
render() {
|
||||
return (
|
||||
<View>
|
||||
<Text>
|
||||
@@ -163,7 +162,7 @@ const ImageSizeExample = createReactClass({
|
||||
</View>
|
||||
);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/*
|
||||
var MultipleSourcesExample = createReactClass({
|
||||
@@ -226,9 +225,10 @@ var MultipleSourcesExample = createReactClass({
|
||||
|
||||
const examples = [
|
||||
{
|
||||
title: 'Plain Network Image',
|
||||
description: 'If the `source` prop `uri` property is prefixed with ' +
|
||||
'"http", then it will be downloaded from the network.',
|
||||
title: 'Plain network image',
|
||||
description:
|
||||
'If the `source` prop `uri` property is prefixed with ' +
|
||||
'"http", then it will be downloaded from the network.',
|
||||
render: function() {
|
||||
return (
|
||||
<Image
|
||||
@@ -243,9 +243,10 @@ const examples = [
|
||||
}
|
||||
},
|
||||
{
|
||||
title: 'Plain Static Image',
|
||||
description: 'Static assets should be placed in the source code tree, and ' +
|
||||
'required in the same way as JavaScript modules.',
|
||||
title: 'Plain static image',
|
||||
description:
|
||||
'Static assets should be placed in the source code tree, and ' +
|
||||
'required in the same way as JavaScript modules.',
|
||||
render: function() {
|
||||
return (
|
||||
<View style={styles.horizontal}>
|
||||
@@ -258,8 +259,8 @@ const examples = [
|
||||
}
|
||||
},
|
||||
{
|
||||
title: 'Image Loading Events',
|
||||
render: function() {
|
||||
title: 'Image loading events',
|
||||
render() {
|
||||
return (
|
||||
<NetworkImageCallbackExample
|
||||
prefetchedSource={{ uri: IMAGE_PREFETCH_URL }}
|
||||
@@ -269,31 +270,19 @@ const examples = [
|
||||
}
|
||||
},
|
||||
{
|
||||
title: 'Error Handler',
|
||||
render: function() {
|
||||
title: 'Error handler',
|
||||
render() {
|
||||
return (
|
||||
<NetworkImageExample
|
||||
source={{ uri: 'http://TYPO_ERROR_facebook.github.io/react/img/logo_og.png' }}
|
||||
/>
|
||||
);
|
||||
},
|
||||
platform: 'ios'
|
||||
},
|
||||
{
|
||||
title: 'Image Download Progress',
|
||||
render: function() {
|
||||
return (
|
||||
<NetworkImageExample
|
||||
source={{ uri: 'http://origami.design/public/images/bird-logo.png?r=1' }}
|
||||
/>
|
||||
);
|
||||
},
|
||||
platform: 'ios'
|
||||
}
|
||||
},
|
||||
{
|
||||
title: 'defaultSource',
|
||||
description: 'Show a placeholder image when a network image is loading',
|
||||
render: function() {
|
||||
render() {
|
||||
return (
|
||||
<Image
|
||||
defaultSource={require('./bunny.png')}
|
||||
@@ -301,38 +290,51 @@ const examples = [
|
||||
style={styles.base}
|
||||
/>
|
||||
);
|
||||
},
|
||||
platform: 'ios'
|
||||
}
|
||||
},
|
||||
{
|
||||
title: 'Border Color',
|
||||
render: function() {
|
||||
title: 'Border color',
|
||||
render() {
|
||||
return (
|
||||
<View style={styles.horizontal}>
|
||||
<Image
|
||||
source={smallImage}
|
||||
style={[styles.base, styles.background, { borderWidth: 3, borderColor: '#f099f0' }]}
|
||||
style={[
|
||||
styles.base,
|
||||
styles.background,
|
||||
{
|
||||
borderColor: '#f099f0',
|
||||
borderWidth: 3
|
||||
}
|
||||
]}
|
||||
/>
|
||||
</View>
|
||||
);
|
||||
}
|
||||
},
|
||||
{
|
||||
title: 'Border Width',
|
||||
render: function() {
|
||||
title: 'Border width',
|
||||
render() {
|
||||
return (
|
||||
<View style={styles.horizontal}>
|
||||
<Image
|
||||
source={smallImage}
|
||||
style={[styles.base, styles.background, { borderWidth: 5, borderColor: '#f099f0' }]}
|
||||
style={[
|
||||
styles.base,
|
||||
styles.background,
|
||||
{
|
||||
borderColor: '#f099f0',
|
||||
borderWidth: 5
|
||||
}
|
||||
]}
|
||||
/>
|
||||
</View>
|
||||
);
|
||||
}
|
||||
},
|
||||
{
|
||||
title: 'Border Radius',
|
||||
render: function() {
|
||||
title: 'Border radius',
|
||||
render() {
|
||||
return (
|
||||
<View style={styles.horizontal}>
|
||||
<Image source={fullImage} style={[styles.base, { borderRadius: 5 }]} />
|
||||
@@ -345,8 +347,8 @@ const examples = [
|
||||
}
|
||||
},
|
||||
{
|
||||
title: 'Background Color',
|
||||
render: function() {
|
||||
title: 'Background color',
|
||||
render() {
|
||||
return (
|
||||
<View style={styles.horizontal}>
|
||||
<Image source={smallImage} style={styles.base} />
|
||||
@@ -368,7 +370,7 @@ const examples = [
|
||||
},
|
||||
{
|
||||
title: 'Opacity',
|
||||
render: function() {
|
||||
render() {
|
||||
return (
|
||||
<View style={styles.horizontal}>
|
||||
<Image source={fullImage} style={[styles.base, { opacity: 1 }]} />
|
||||
@@ -383,7 +385,7 @@ const examples = [
|
||||
},
|
||||
{
|
||||
title: 'Nesting',
|
||||
render: function() {
|
||||
render() {
|
||||
return (
|
||||
<Image source={fullImage} style={{ width: 60, height: 60, backgroundColor: 'transparent' }}>
|
||||
<Text style={styles.nestedText}>
|
||||
@@ -393,63 +395,10 @@ const examples = [
|
||||
);
|
||||
}
|
||||
},
|
||||
/*
|
||||
{
|
||||
title: 'Tint Color',
|
||||
description: 'The `tintColor` style prop changes all the non-alpha ' +
|
||||
'pixels to the tint color.',
|
||||
render: function() {
|
||||
return (
|
||||
<View>
|
||||
<View style={styles.horizontal}>
|
||||
<Image
|
||||
source={require('./uie_thumb_normal@2x.png')}
|
||||
style={[styles.icon, {borderRadius: 5, tintColor: '#5ac8fa' }]}
|
||||
/>
|
||||
<Image
|
||||
source={require('./uie_thumb_normal@2x.png')}
|
||||
style={[styles.icon, styles.leftMargin, {borderRadius: 5, tintColor: '#4cd964' }]}
|
||||
/>
|
||||
<Image
|
||||
source={require('./uie_thumb_normal@2x.png')}
|
||||
style={[styles.icon, styles.leftMargin, {borderRadius: 5, tintColor: '#ff2d55' }]}
|
||||
/>
|
||||
<Image
|
||||
source={require('./uie_thumb_normal@2x.png')}
|
||||
style={[styles.icon, styles.leftMargin, {borderRadius: 5, tintColor: '#8e8e93' }]}
|
||||
/>
|
||||
</View>
|
||||
<Text style={styles.sectionText}>
|
||||
It also works with downloaded images:
|
||||
</Text>
|
||||
<View style={styles.horizontal}>
|
||||
<Image
|
||||
source={smallImage}
|
||||
style={[styles.base, {borderRadius: 5, tintColor: '#5ac8fa' }]}
|
||||
/>
|
||||
<Image
|
||||
source={smallImage}
|
||||
style={[styles.base, styles.leftMargin, {borderRadius: 5, tintColor: '#4cd964' }]}
|
||||
/>
|
||||
<Image
|
||||
source={smallImage}
|
||||
style={[styles.base, styles.leftMargin, {borderRadius: 5, tintColor: '#ff2d55' }]}
|
||||
/>
|
||||
<Image
|
||||
source={smallImage}
|
||||
style={[styles.base, styles.leftMargin, {borderRadius: 5, tintColor: '#8e8e93' }]}
|
||||
/>
|
||||
</View>
|
||||
</View>
|
||||
);
|
||||
},
|
||||
},
|
||||
*/
|
||||
{
|
||||
title: 'Resize Mode',
|
||||
description: 'The `resizeMode` style prop controls how the image is ' +
|
||||
'rendered within the frame.',
|
||||
render: function() {
|
||||
title: 'Resize mode',
|
||||
description: 'The `resizeMode` style prop controls how the image is rendered within the frame.',
|
||||
render() {
|
||||
return (
|
||||
<View>
|
||||
{[smallImage, fullImage].map((image, index) => {
|
||||
@@ -510,42 +459,35 @@ const examples = [
|
||||
},
|
||||
{
|
||||
title: 'Animated GIF',
|
||||
render: function() {
|
||||
render() {
|
||||
return (
|
||||
<Image
|
||||
source={{
|
||||
uri: 'http://38.media.tumblr.com/9e9bd08c6e2d10561dd1fb4197df4c4e/tumblr_mfqekpMktw1rn90umo1_500.gif'
|
||||
uri:
|
||||
'http://38.media.tumblr.com/9e9bd08c6e2d10561dd1fb4197df4c4e/tumblr_mfqekpMktw1rn90umo1_500.gif'
|
||||
}}
|
||||
style={styles.gif}
|
||||
/>
|
||||
);
|
||||
},
|
||||
platform: 'ios'
|
||||
}
|
||||
},
|
||||
{
|
||||
title: 'Base64 image',
|
||||
render: function() {
|
||||
render() {
|
||||
return <Image source={{ uri: base64Icon, scale: 3 }} style={styles.base64} />;
|
||||
},
|
||||
platform: 'ios'
|
||||
}
|
||||
},
|
||||
/*
|
||||
{
|
||||
title: 'Cap Insets',
|
||||
title: 'Data SVG',
|
||||
render() {
|
||||
return <Image source={{ uri: dataSvg, scale: 3 }} style={styles.base64} />;
|
||||
}
|
||||
},
|
||||
{
|
||||
title: 'Image dimensions',
|
||||
description:
|
||||
'When the image is resized, the corners of the size specified ' +
|
||||
'by capInsets will stay a fixed size, but the center content and ' +
|
||||
'borders of the image will be stretched. This is useful for creating ' +
|
||||
'resizable rounded buttons, shadows, and other resizable assets.',
|
||||
render: function() {
|
||||
return <ImageCapInsetsExample />;
|
||||
},
|
||||
platform: 'ios',
|
||||
},
|
||||
*/
|
||||
{
|
||||
title: 'Image Size',
|
||||
render: function() {
|
||||
'`Image.getSize` provides the dimensions of an image as soon as they are available (i.e., before loading is complete)',
|
||||
render() {
|
||||
return (
|
||||
<ImageSizeExample
|
||||
source={{
|
||||
@@ -555,18 +497,6 @@ const examples = [
|
||||
);
|
||||
}
|
||||
}
|
||||
/*
|
||||
{
|
||||
title: 'MultipleSourcesExample',
|
||||
description:
|
||||
'The `source` prop allows passing in an array of uris, so that native to choose which image ' +
|
||||
'to diplay based on the size of the of the target image',
|
||||
render: function() {
|
||||
return <MultipleSourcesExample />;
|
||||
},
|
||||
platform: 'android',
|
||||
},
|
||||
*/
|
||||
];
|
||||
|
||||
const fullImage = { uri: 'http://facebook.github.io/react/img/logo_og.png' };
|
||||
@@ -574,12 +504,12 @@ const smallImage = { uri: 'http://facebook.github.io/react/img/logo_small_2x.png
|
||||
|
||||
const styles = StyleSheet.create({
|
||||
base: {
|
||||
width: 38,
|
||||
height: 38
|
||||
height: 38,
|
||||
width: 38
|
||||
},
|
||||
progress: {
|
||||
flex: 1,
|
||||
alignItems: 'center',
|
||||
flex: 1,
|
||||
flexDirection: 'row',
|
||||
width: 100
|
||||
},
|
||||
@@ -593,24 +523,24 @@ const styles = StyleSheet.create({
|
||||
marginVertical: 6
|
||||
},
|
||||
nestedText: {
|
||||
marginLeft: 12,
|
||||
marginTop: 20,
|
||||
backgroundColor: 'transparent',
|
||||
color: 'white'
|
||||
color: 'white',
|
||||
marginLeft: 12,
|
||||
marginTop: 20
|
||||
},
|
||||
resizeMode: {
|
||||
width: 90,
|
||||
height: 60,
|
||||
borderColor: 'black',
|
||||
borderWidth: 0.5,
|
||||
borderColor: 'black'
|
||||
height: 60,
|
||||
width: 90
|
||||
},
|
||||
resizeModeText: {
|
||||
fontSize: 11,
|
||||
marginBottom: 3
|
||||
},
|
||||
icon: {
|
||||
width: 15,
|
||||
height: 15
|
||||
height: 15,
|
||||
width: 15
|
||||
},
|
||||
horizontal: {
|
||||
flexDirection: 'row'
|
||||
@@ -625,13 +555,16 @@ const styles = StyleSheet.create({
|
||||
resizeMode: 'contain'
|
||||
},
|
||||
touchableText: {
|
||||
fontWeight: '500',
|
||||
color: 'blue'
|
||||
color: 'blue',
|
||||
fontWeight: '500'
|
||||
}
|
||||
});
|
||||
|
||||
examples.forEach(example => {
|
||||
storiesOf('component: Image', module)
|
||||
.addDecorator(renderStory => <View style={{ width: '100%' }}>{renderStory()}</View>)
|
||||
.add(example.title, () => example.render());
|
||||
});
|
||||
storiesOf('Components', module).add('Image', () =>
|
||||
<UIExplorer
|
||||
description="An accessibile image component with support for image resizing, default image, and child content."
|
||||
examples={examples}
|
||||
title="Image"
|
||||
url="https://github.com/necolas/react-native-web/blob/master/docs/components/Image.md"
|
||||
/>
|
||||
);
|
||||
|
||||
@@ -1,80 +0,0 @@
|
||||
import React from 'react';
|
||||
import { storiesOf } from '@kadira/storybook';
|
||||
import { ListView, StyleSheet, Text, View } from 'react-native';
|
||||
|
||||
const generateData = length => Array.from({ length }).map((item, i) => i);
|
||||
const dataSource = new ListView.DataSource({ rowHasChanged: (r1, r2) => r1 !== r2 });
|
||||
|
||||
storiesOf('component: ListView', module)
|
||||
.add('vertical', () => (
|
||||
<View style={styles.scrollViewContainer}>
|
||||
<ListView
|
||||
contentContainerStyle={styles.scrollViewContentContainerStyle}
|
||||
dataSource={dataSource.cloneWithRows(generateData(100))}
|
||||
initialListSize={100}
|
||||
// eslint-disable-next-line react/jsx-no-bind
|
||||
onScroll={e => {
|
||||
console.log('ScrollView.onScroll', e);
|
||||
}}
|
||||
// eslint-disable-next-line react/jsx-no-bind
|
||||
renderRow={row => <View><Text>{row}</Text></View>}
|
||||
scrollEventThrottle={1000} // 1 event per second
|
||||
style={styles.scrollViewStyle}
|
||||
/>
|
||||
</View>
|
||||
))
|
||||
.add('incremental rendering - large pageSize', () => (
|
||||
<View style={styles.scrollViewContainer}>
|
||||
<ListView
|
||||
contentContainerStyle={styles.scrollViewContentContainerStyle}
|
||||
dataSource={dataSource.cloneWithRows(generateData(5000))}
|
||||
initialListSize={100}
|
||||
// eslint-disable-next-line react/jsx-no-bind
|
||||
onScroll={e => {
|
||||
console.log('ScrollView.onScroll', e);
|
||||
}}
|
||||
pageSize={50}
|
||||
// eslint-disable-next-line react/jsx-no-bind
|
||||
renderRow={row => <View><Text>{row}</Text></View>}
|
||||
scrollEventThrottle={1000} // 1 event per second
|
||||
style={styles.scrollViewStyle}
|
||||
/>
|
||||
</View>
|
||||
))
|
||||
.add('incremental rendering - small pageSize', () => (
|
||||
<View style={styles.scrollViewContainer}>
|
||||
<ListView
|
||||
contentContainerStyle={styles.scrollViewContentContainerStyle}
|
||||
dataSource={dataSource.cloneWithRows(generateData(5000))}
|
||||
initialListSize={5}
|
||||
// eslint-disable-next-line react/jsx-no-bind
|
||||
onScroll={e => {
|
||||
console.log('ScrollView.onScroll', e);
|
||||
}}
|
||||
pageSize={1}
|
||||
// eslint-disable-next-line react/jsx-no-bind
|
||||
renderRow={row => <View><Text>{row}</Text></View>}
|
||||
scrollEventThrottle={1000} // 1 event per second
|
||||
style={styles.scrollViewStyle}
|
||||
/>
|
||||
</View>
|
||||
));
|
||||
|
||||
const styles = StyleSheet.create({
|
||||
box: {
|
||||
flexGrow: 1,
|
||||
justifyContent: 'center',
|
||||
borderWidth: 1
|
||||
},
|
||||
scrollViewContainer: {
|
||||
height: '200px',
|
||||
width: 300
|
||||
},
|
||||
scrollViewStyle: {
|
||||
borderWidth: '1px'
|
||||
},
|
||||
scrollViewContentContainerStyle: {
|
||||
backgroundColor: '#eee',
|
||||
padding: '10px'
|
||||
}
|
||||
});
|
||||
@@ -1,8 +1,4 @@
|
||||
import createReactClass from 'create-react-class';
|
||||
import { ProgressBar, StyleSheet, View } from 'react-native';
|
||||
import React from 'react';
|
||||
import { storiesOf } from '@kadira/storybook';
|
||||
import TimerMixin from 'react-timer-mixin';
|
||||
/* eslint-disable react/prefer-es6-class */
|
||||
|
||||
/**
|
||||
* Copyright (c) 2013-present, Facebook, Inc.
|
||||
@@ -27,6 +23,13 @@ import TimerMixin from 'react-timer-mixin';
|
||||
* @flow
|
||||
*/
|
||||
|
||||
import createReactClass from 'create-react-class';
|
||||
import { ProgressBar, StyleSheet, View } from 'react-native';
|
||||
import React from 'react';
|
||||
import { storiesOf } from '@kadira/storybook';
|
||||
import TimerMixin from 'react-timer-mixin';
|
||||
import UIExplorer from '../../UIExplorer';
|
||||
|
||||
const ProgressBarExample = createReactClass({
|
||||
mixins: [TimerMixin],
|
||||
|
||||
@@ -54,10 +57,7 @@ const ProgressBarExample = createReactClass({
|
||||
render() {
|
||||
return (
|
||||
<View style={styles.container}>
|
||||
<ProgressBar color="purple" progress={this.getProgress(0.2)} style={styles.progressView} />
|
||||
<ProgressBar color="red" progress={this.getProgress(0.4)} style={styles.progressView} />
|
||||
<ProgressBar color="orange" progress={this.getProgress(0.6)} style={styles.progressView} />
|
||||
<ProgressBar color="yellow" progress={this.getProgress(0.8)} style={styles.progressView} />
|
||||
<ProgressBar color="#794BC4" progress={this.getProgress(0.2)} style={styles.progressView} />
|
||||
</View>
|
||||
);
|
||||
}
|
||||
@@ -65,16 +65,76 @@ const ProgressBarExample = createReactClass({
|
||||
|
||||
const examples = [
|
||||
{
|
||||
title: 'progress',
|
||||
title: 'Default',
|
||||
render() {
|
||||
return <ProgressBar progress={0.5} />;
|
||||
}
|
||||
},
|
||||
{
|
||||
title: 'Controlled',
|
||||
render() {
|
||||
return <ProgressBarExample />;
|
||||
}
|
||||
},
|
||||
{
|
||||
title: 'indeterminate',
|
||||
title: 'Indeterminate',
|
||||
render() {
|
||||
return <ProgressBar indeterminate style={styles.progressView} trackColor="#D1E3F6" />;
|
||||
}
|
||||
},
|
||||
{
|
||||
title: 'Custom colors',
|
||||
render() {
|
||||
return (
|
||||
<View>
|
||||
<ProgressBar color="#1DA1F2" progress={1} />
|
||||
<View style={styles.verticalDivider} />
|
||||
<ProgressBar color="#17BF63" progress={0.8} />
|
||||
<View style={styles.verticalDivider} />
|
||||
<ProgressBar color="#F45D22" progress={0.6} />
|
||||
<View style={styles.verticalDivider} />
|
||||
<ProgressBar color="#794BC4" progress={0.4} />
|
||||
<View style={styles.verticalDivider} />
|
||||
<ProgressBar color="#E0245E" progress={0.2} />
|
||||
</View>
|
||||
);
|
||||
}
|
||||
},
|
||||
{
|
||||
title: 'Custom track colors',
|
||||
render() {
|
||||
return (
|
||||
<View>
|
||||
<ProgressBar color="#1DA1F2" progress={0.1} trackColor="#D1E3F6" />
|
||||
<View style={styles.verticalDivider} />
|
||||
<ProgressBar color="#1DA1F2" progress={0.2} trackColor="rgba(121, 74, 196, 0.34)" />
|
||||
<View style={styles.verticalDivider} />
|
||||
<ProgressBar color="#1DA1F2" progress={0.3} trackColor="rgba(224, 36, 94, 0.35)" />
|
||||
</View>
|
||||
);
|
||||
}
|
||||
},
|
||||
{
|
||||
title: 'Custom sizes',
|
||||
render() {
|
||||
return (
|
||||
<View>
|
||||
<ProgressBar
|
||||
color="#1DA1F2"
|
||||
progress={0.33}
|
||||
style={{ height: 10 }}
|
||||
trackColor="#D1E3F6"
|
||||
/>
|
||||
<View style={styles.verticalDivider} />
|
||||
<ProgressBar
|
||||
color="#1DA1F2"
|
||||
progress={0.33}
|
||||
style={{ height: 15 }}
|
||||
trackColor="#D1E3F6"
|
||||
/>
|
||||
</View>
|
||||
);
|
||||
}
|
||||
}
|
||||
];
|
||||
|
||||
@@ -87,9 +147,17 @@ const styles = StyleSheet.create({
|
||||
progressView: {
|
||||
marginTop: 20,
|
||||
minWidth: 200
|
||||
},
|
||||
verticalDivider: {
|
||||
height: '1.3125rem'
|
||||
}
|
||||
});
|
||||
|
||||
examples.forEach(example => {
|
||||
storiesOf('component: ProgressBar', module).add(example.title, () => example.render());
|
||||
});
|
||||
storiesOf('Components', module).add('ProgressBar', () =>
|
||||
<UIExplorer
|
||||
description="Display an activity progress bar"
|
||||
examples={examples}
|
||||
title="ProgressBar"
|
||||
url="https://github.com/necolas/react-native-web/blob/master/docs/components/ProgressBar.md"
|
||||
/>
|
||||
);
|
||||
|
||||
@@ -1,45 +1,51 @@
|
||||
/* eslint-disable react/jsx-no-bind */
|
||||
|
||||
import React from 'react';
|
||||
import UIExplorer from '../../UIExplorer';
|
||||
import { action, storiesOf } from '@kadira/storybook';
|
||||
import { ScrollView, StyleSheet, Text, TouchableHighlight, View } from 'react-native';
|
||||
|
||||
const onScroll = action('ScrollView.onScroll');
|
||||
|
||||
storiesOf('component: ScrollView', module)
|
||||
.add('vertical', () => (
|
||||
<View style={styles.scrollViewContainer}>
|
||||
<ScrollView
|
||||
contentContainerStyle={styles.scrollViewContentContainerStyle}
|
||||
onScroll={onScroll}
|
||||
scrollEventThrottle={1000} // 1 event per second
|
||||
style={styles.scrollViewStyle}
|
||||
>
|
||||
{Array.from({ length: 50 }).map((item, i) => (
|
||||
<View key={i} style={styles.box}>
|
||||
<TouchableHighlight onPress={() => {}}><Text>{i}</Text></TouchableHighlight>
|
||||
</View>
|
||||
))}
|
||||
</ScrollView>
|
||||
</View>
|
||||
))
|
||||
.add('horizontal', () => (
|
||||
<View style={styles.scrollViewContainer}>
|
||||
<ScrollView
|
||||
contentContainerStyle={styles.scrollViewContentContainerStyle}
|
||||
horizontal
|
||||
onScroll={onScroll}
|
||||
scrollEventThrottle={16} // ~60 events per second
|
||||
style={styles.scrollViewStyle}
|
||||
>
|
||||
{Array.from({ length: 50 }).map((item, i) => (
|
||||
<View key={i} style={[styles.box, styles.horizontalBox]}>
|
||||
<Text>{i}</Text>
|
||||
</View>
|
||||
))}
|
||||
</ScrollView>
|
||||
</View>
|
||||
));
|
||||
const examples = [
|
||||
{
|
||||
title: 'vertical',
|
||||
render: () =>
|
||||
<View style={styles.scrollViewContainer}>
|
||||
<ScrollView
|
||||
contentContainerStyle={styles.scrollViewContentContainerStyle}
|
||||
onScroll={onScroll}
|
||||
scrollEventThrottle={1000} // 1 event per second
|
||||
style={styles.scrollViewStyle}
|
||||
>
|
||||
{Array.from({ length: 50 }).map((item, i) =>
|
||||
<View key={i} style={styles.box}>
|
||||
<TouchableHighlight onPress={() => {}}><Text>{i}</Text></TouchableHighlight>
|
||||
</View>
|
||||
)}
|
||||
</ScrollView>
|
||||
</View>
|
||||
},
|
||||
{
|
||||
title: 'horizontal',
|
||||
render: () =>
|
||||
<View style={styles.scrollViewContainer}>
|
||||
<ScrollView
|
||||
contentContainerStyle={styles.scrollViewContentContainerStyle}
|
||||
horizontal
|
||||
onScroll={onScroll}
|
||||
scrollEventThrottle={16} // ~60 events per second
|
||||
style={styles.scrollViewStyle}
|
||||
>
|
||||
{Array.from({ length: 50 }).map((item, i) =>
|
||||
<View key={i} style={[styles.box, styles.horizontalBox]}>
|
||||
<Text>{i}</Text>
|
||||
</View>
|
||||
)}
|
||||
</ScrollView>
|
||||
</View>
|
||||
}
|
||||
];
|
||||
|
||||
const styles = StyleSheet.create({
|
||||
box: {
|
||||
@@ -48,7 +54,7 @@ const styles = StyleSheet.create({
|
||||
borderWidth: 1
|
||||
},
|
||||
scrollViewContainer: {
|
||||
height: '200px',
|
||||
height: 200,
|
||||
width: 300
|
||||
},
|
||||
scrollViewStyle: {
|
||||
@@ -59,3 +65,11 @@ const styles = StyleSheet.create({
|
||||
padding: 10
|
||||
}
|
||||
});
|
||||
|
||||
storiesOf('Components', module).add('ScrollView', () =>
|
||||
<UIExplorer
|
||||
examples={examples}
|
||||
title="ScrollView"
|
||||
url="https://github.com/necolas/react-native-web/blob/master/docs/components/ScrollView.md"
|
||||
/>
|
||||
);
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/* eslint-disable react/jsx-no-bind */
|
||||
/* eslint-disable react/jsx-no-bind, react/prefer-es6-class */
|
||||
|
||||
/**
|
||||
* Copyright (c) 2013-present, Facebook, Inc.
|
||||
@@ -27,6 +27,7 @@ import createReactClass from 'create-react-class';
|
||||
import { Switch, Text, View } from 'react-native';
|
||||
import React from 'react';
|
||||
import { storiesOf } from '@kadira/storybook';
|
||||
import UIExplorer from '../../UIExplorer';
|
||||
|
||||
const BasicSwitchExample = createReactClass({
|
||||
getInitialState() {
|
||||
@@ -198,6 +199,10 @@ const examples = [
|
||||
}
|
||||
];
|
||||
|
||||
examples.forEach(example => {
|
||||
storiesOf('component: Switch', module).add(example.title, () => example.render());
|
||||
});
|
||||
storiesOf('Components', module).add('Switch', () =>
|
||||
<UIExplorer
|
||||
examples={examples}
|
||||
title="Switch"
|
||||
url="https://github.com/necolas/react-native-web/blob/master/docs/components/Switch.md"
|
||||
/>
|
||||
);
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/* eslint-disable react/jsx-no-bind */
|
||||
/* eslint-disable react/jsx-no-bind, react/prefer-es6-class, react/prop-types */
|
||||
|
||||
/**
|
||||
* Copyright (c) 2013-present, Facebook, Inc.
|
||||
@@ -26,6 +26,7 @@
|
||||
import createReactClass from 'create-react-class';
|
||||
import React from 'react';
|
||||
import { storiesOf } from '@kadira/storybook';
|
||||
import UIExplorer from '../../UIExplorer';
|
||||
import { Image, Text, View } from 'react-native';
|
||||
|
||||
const Entity = createReactClass({
|
||||
@@ -268,9 +269,10 @@ const examples = [
|
||||
},
|
||||
{
|
||||
title: 'Nested',
|
||||
description: 'Nested text components will inherit the styles of their ' +
|
||||
'parents (only backgroundColor is inherited from non-Text parents). ' +
|
||||
'<Text> only supports other <Text> and raw text (strings) as children.',
|
||||
description:
|
||||
'Nested text components will inherit the styles of their ' +
|
||||
'parents (only backgroundColor is inherited from non-Text parents). ' +
|
||||
'<Text> only supports other <Text> and raw text (strings) as children.',
|
||||
render: function() {
|
||||
return (
|
||||
<View>
|
||||
@@ -362,7 +364,7 @@ const examples = [
|
||||
render: function() {
|
||||
return (
|
||||
<Text>
|
||||
A {'generated'} {' '} {'string'} and some spaces
|
||||
A {'generated'} {' '} {'string'} and some spaces
|
||||
</Text>
|
||||
);
|
||||
}
|
||||
@@ -453,7 +455,8 @@ const examples = [
|
||||
style={{ backgroundColor: 'white', textDecorationLine: 'underline', color: 'blue' }}
|
||||
suppressHighlighting={false}
|
||||
>
|
||||
consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud
|
||||
consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore
|
||||
magna aliqua. Ut enim ad minim veniam, quis nostrud
|
||||
</Text>
|
||||
{' '}
|
||||
exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat.
|
||||
@@ -469,7 +472,8 @@ const examples = [
|
||||
<View>
|
||||
<Text>
|
||||
By default, text will respect Text Size accessibility setting on iOS.
|
||||
It means that all font sizes will be increased or descreased depending on the value of Text Size setting in
|
||||
It means that all font sizes will be increased or descreased depending on the value of
|
||||
Text Size setting in
|
||||
{' '}
|
||||
<Text style={{ fontWeight: 'bold' }}>
|
||||
Settings.app - Display & Brightness - Text Size
|
||||
@@ -558,8 +562,10 @@ const examples = [
|
||||
}
|
||||
];
|
||||
|
||||
examples.forEach(example => {
|
||||
storiesOf('component: Text', module)
|
||||
.addDecorator(renderStory => <View style={{ width: 320 }}>{renderStory()}</View>)
|
||||
.add(example.title, () => example.render());
|
||||
});
|
||||
storiesOf('Components', module).add('Text', () =>
|
||||
<UIExplorer
|
||||
examples={examples}
|
||||
title="Text"
|
||||
url="https://github.com/necolas/react-native-web/blob/master/docs/components/Text.md"
|
||||
/>
|
||||
);
|
||||
|
||||
@@ -25,8 +25,9 @@
|
||||
|
||||
import React from 'react';
|
||||
import { storiesOf } from '@kadira/storybook';
|
||||
import { any, bool, object, string } from 'prop-types';
|
||||
import { StyleSheet, Text, TextInput, View } from 'react-native';
|
||||
import UIExplorer from '../../UIExplorer';
|
||||
import { any, bool, string } from 'prop-types';
|
||||
import { StyleSheet, Text, TextInput, TextPropTypes, View } from 'react-native';
|
||||
|
||||
class WithLabel extends React.Component {
|
||||
static propTypes = {
|
||||
@@ -107,7 +108,8 @@ class AutoExpandingTextInput extends React.Component {
|
||||
constructor(props) {
|
||||
super(props);
|
||||
this.state = {
|
||||
text: 'React Native enables you to build world-class application experiences on native platforms using a consistent developer experience based on JavaScript and React. The focus of React Native is on developer efficiency across all the platforms you care about — learn once, write anywhere. Facebook uses React Native in multiple production apps and will continue investing in React Native.',
|
||||
text:
|
||||
'React Native enables you to build world-class application experiences on native platforms using a consistent developer experience based on JavaScript and React. The focus of React Native is on developer efficiency across all the platforms you care about — learn once, write anywhere. Facebook uses React Native in multiple production apps and will continue investing in React Native.',
|
||||
height: 0
|
||||
};
|
||||
}
|
||||
@@ -318,7 +320,7 @@ class SelectionExample extends React.Component {
|
||||
|
||||
static propTypes = {
|
||||
multiline: bool,
|
||||
style: object,
|
||||
style: TextPropTypes.style,
|
||||
value: string
|
||||
};
|
||||
|
||||
@@ -463,7 +465,7 @@ const styles = StyleSheet.create({
|
||||
const examples = [
|
||||
{
|
||||
title: 'Auto-focus',
|
||||
render: function() {
|
||||
render() {
|
||||
return (
|
||||
<View>
|
||||
<TextInput
|
||||
@@ -477,19 +479,19 @@ const examples = [
|
||||
},
|
||||
{
|
||||
title: "Live Re-Write (<sp> -> '_') + maxLength",
|
||||
render: function() {
|
||||
render() {
|
||||
return <RewriteExample />;
|
||||
}
|
||||
},
|
||||
{
|
||||
title: 'Live Re-Write (no spaces allowed)',
|
||||
render: function() {
|
||||
render() {
|
||||
return <RewriteExampleInvalidCharacters />;
|
||||
}
|
||||
},
|
||||
{
|
||||
title: 'Auto-capitalize',
|
||||
render: function() {
|
||||
render() {
|
||||
return (
|
||||
<View>
|
||||
<WithLabel label="none">
|
||||
@@ -510,7 +512,7 @@ const examples = [
|
||||
},
|
||||
{
|
||||
title: 'Auto-correct',
|
||||
render: function() {
|
||||
render() {
|
||||
return (
|
||||
<View>
|
||||
<WithLabel label="true">
|
||||
@@ -525,7 +527,7 @@ const examples = [
|
||||
},
|
||||
{
|
||||
title: 'Keyboard types',
|
||||
render: function() {
|
||||
render() {
|
||||
const keyboardTypes = [
|
||||
'default',
|
||||
//'ascii-capable',
|
||||
@@ -552,7 +554,7 @@ const examples = [
|
||||
},
|
||||
{
|
||||
title: 'Keyboard appearance',
|
||||
render: function() {
|
||||
render() {
|
||||
const keyboardAppearance = ['default', 'light', 'dark'];
|
||||
const examples = keyboardAppearance.map(type => {
|
||||
return (
|
||||
@@ -566,7 +568,7 @@ const examples = [
|
||||
},
|
||||
{
|
||||
title: 'Return key types',
|
||||
render: function() {
|
||||
render() {
|
||||
const returnKeyTypes = [
|
||||
'default',
|
||||
'go',
|
||||
@@ -592,7 +594,7 @@ const examples = [
|
||||
},
|
||||
{
|
||||
title: 'Enable return key automatically',
|
||||
render: function() {
|
||||
render() {
|
||||
return (
|
||||
<View>
|
||||
<WithLabel label="true">
|
||||
@@ -604,7 +606,7 @@ const examples = [
|
||||
},
|
||||
{
|
||||
title: 'Secure text entry',
|
||||
render: function() {
|
||||
render() {
|
||||
return (
|
||||
<View>
|
||||
<WithLabel label="true">
|
||||
@@ -616,13 +618,13 @@ const examples = [
|
||||
},
|
||||
{
|
||||
title: 'Event handling',
|
||||
render: function(): React.Element<any> {
|
||||
render(): React.Element<any> {
|
||||
return <TextEventsExample />;
|
||||
}
|
||||
},
|
||||
{
|
||||
title: 'Colored input text',
|
||||
render: function() {
|
||||
render() {
|
||||
return (
|
||||
<View>
|
||||
<TextInput defaultValue="Blue" style={[styles.default, { color: 'blue' }]} />
|
||||
@@ -633,7 +635,7 @@ const examples = [
|
||||
},
|
||||
{
|
||||
title: 'Colored highlight/cursor for text input',
|
||||
render: function() {
|
||||
render() {
|
||||
return (
|
||||
<View>
|
||||
<TextInput defaultValue="Highlight me" selectionColor={'green'} style={styles.default} />
|
||||
@@ -648,7 +650,7 @@ const examples = [
|
||||
},
|
||||
{
|
||||
title: 'Clear button mode',
|
||||
render: function() {
|
||||
render() {
|
||||
return (
|
||||
<View>
|
||||
<WithLabel label="never">
|
||||
@@ -669,7 +671,7 @@ const examples = [
|
||||
},
|
||||
{
|
||||
title: 'Clear and select',
|
||||
render: function() {
|
||||
render() {
|
||||
return (
|
||||
<View>
|
||||
<WithLabel label="clearTextOnFocus">
|
||||
@@ -694,13 +696,13 @@ const examples = [
|
||||
},
|
||||
{
|
||||
title: 'Blur on submit',
|
||||
render: function(): React.Element<any> {
|
||||
render(): React.Element<any> {
|
||||
return <BlurOnSubmitExample />;
|
||||
}
|
||||
},
|
||||
{
|
||||
title: 'Multiline blur on submit',
|
||||
render: function() {
|
||||
render() {
|
||||
return (
|
||||
<View>
|
||||
<TextInput
|
||||
@@ -719,7 +721,7 @@ const examples = [
|
||||
},
|
||||
{
|
||||
title: 'Multiline',
|
||||
render: function() {
|
||||
render() {
|
||||
return (
|
||||
<View>
|
||||
<TextInput multiline={true} placeholder="multiline text input" style={styles.multiline} />
|
||||
@@ -758,7 +760,7 @@ const examples = [
|
||||
},
|
||||
{
|
||||
title: 'Number of lines',
|
||||
render: function() {
|
||||
render() {
|
||||
return (
|
||||
<View>
|
||||
<TextInput
|
||||
@@ -772,7 +774,7 @@ const examples = [
|
||||
},
|
||||
{
|
||||
title: 'Auto-expanding',
|
||||
render: function() {
|
||||
render() {
|
||||
return (
|
||||
<View>
|
||||
<AutoExpandingTextInput
|
||||
@@ -786,13 +788,13 @@ const examples = [
|
||||
},
|
||||
{
|
||||
title: 'Attributed text',
|
||||
render: function() {
|
||||
render() {
|
||||
return <TokenizedTextExample />;
|
||||
}
|
||||
},
|
||||
{
|
||||
title: 'Text selection & cursor placement',
|
||||
render: function() {
|
||||
render() {
|
||||
return (
|
||||
<View>
|
||||
<SelectionExample style={styles.default} value="text selection can be changed" />
|
||||
@@ -807,7 +809,7 @@ const examples = [
|
||||
},
|
||||
{
|
||||
title: 'TextInput maxLength',
|
||||
render: function() {
|
||||
render() {
|
||||
return (
|
||||
<View>
|
||||
<WithLabel label="maxLength: 5">
|
||||
@@ -828,6 +830,10 @@ const examples = [
|
||||
}
|
||||
];
|
||||
|
||||
examples.forEach(example => {
|
||||
storiesOf('component: TextInput', module).add(example.title, () => example.render());
|
||||
});
|
||||
storiesOf('Components', module).add('TextInput', () =>
|
||||
<UIExplorer
|
||||
examples={examples}
|
||||
title="TextInput"
|
||||
url="https://github.com/necolas/react-native-web/blob/master/docs/components/TextInput.md"
|
||||
/>
|
||||
);
|
||||
|
||||
@@ -24,7 +24,8 @@
|
||||
*/
|
||||
|
||||
import React from 'react';
|
||||
import { storiesOf, action } from '@kadira/storybook';
|
||||
import UIExplorer from '../../UIExplorer';
|
||||
import { action, storiesOf } from '@kadira/storybook';
|
||||
import {
|
||||
Image,
|
||||
StyleSheet,
|
||||
@@ -36,90 +37,6 @@ import {
|
||||
View
|
||||
} from 'react-native';
|
||||
|
||||
const examples = [
|
||||
{
|
||||
title: '<TouchableHighlight>',
|
||||
description: 'TouchableHighlight works by adding an extra view with a ' +
|
||||
'black background under the single child view. This works best when the ' +
|
||||
'child view is fully opaque, although it can be made to work as a simple ' +
|
||||
'background color change as well with the activeOpacity and ' +
|
||||
'underlayColor props.',
|
||||
render: function() {
|
||||
return (
|
||||
<View>
|
||||
<View style={styles.row}>
|
||||
<TouchableHighlight
|
||||
onPress={() => console.log('stock THW image - highlight')}
|
||||
style={styles.wrapper}
|
||||
>
|
||||
<Image source={heartImage} style={styles.image} />
|
||||
</TouchableHighlight>
|
||||
<TouchableHighlight
|
||||
activeOpacity={1}
|
||||
onPress={() => console.log('custom THW text - highlight')}
|
||||
style={styles.wrapper}
|
||||
underlayColor="rgb(210, 230, 255)"
|
||||
>
|
||||
<View style={styles.wrapperCustom}>
|
||||
<Text style={styles.text}>
|
||||
Tap Here For Custom Highlight!
|
||||
</Text>
|
||||
</View>
|
||||
</TouchableHighlight>
|
||||
</View>
|
||||
</View>
|
||||
);
|
||||
}
|
||||
},
|
||||
{
|
||||
title: '<Text onPress={fn}> with highlight',
|
||||
render: function() {
|
||||
return <TextOnPressBox />;
|
||||
}
|
||||
},
|
||||
{
|
||||
title: 'Touchable feedback events',
|
||||
description: '<Touchable*> components accept onPress, onPressIn, ' +
|
||||
'onPressOut, and onLongPress as props.',
|
||||
render: function() {
|
||||
return <TouchableFeedbackEvents />;
|
||||
}
|
||||
},
|
||||
{
|
||||
title: 'Touchable delay for events',
|
||||
description: '<Touchable*> components also accept delayPressIn, ' +
|
||||
'delayPressOut, and delayLongPress as props. These props impact the ' +
|
||||
'timing of feedback events.',
|
||||
render: function() {
|
||||
return <TouchableDelayEvents />;
|
||||
}
|
||||
},
|
||||
{
|
||||
title: '3D Touch / Force Touch',
|
||||
description: 'iPhone 6s and 6s plus support 3D touch, which adds a force property to touches',
|
||||
render: function() {
|
||||
return <ForceTouchExample />;
|
||||
},
|
||||
platform: 'ios'
|
||||
},
|
||||
{
|
||||
title: 'Touchable Hit Slop',
|
||||
description: '<Touchable*> components accept hitSlop prop which extends the touch area ' +
|
||||
'without changing the view bounds.',
|
||||
render: function() {
|
||||
return <TouchableHitSlop />;
|
||||
}
|
||||
},
|
||||
{
|
||||
title: 'Disabled Touchable*',
|
||||
description: '<Touchable*> components accept disabled prop which prevents ' +
|
||||
'any interaction with component',
|
||||
render: function() {
|
||||
return <TouchableDisabled />;
|
||||
}
|
||||
}
|
||||
];
|
||||
|
||||
class TextOnPressBox extends React.Component {
|
||||
constructor(props) {
|
||||
super(props);
|
||||
@@ -393,6 +310,66 @@ class TouchableDisabled extends React.Component {
|
||||
}
|
||||
}
|
||||
|
||||
class TouchableStyling extends React.Component {
|
||||
constructor(props, context) {
|
||||
super(props, context);
|
||||
this.buttons = ['a', 'b', 'c'];
|
||||
this.state = {};
|
||||
this.select = this.select.bind(this);
|
||||
}
|
||||
|
||||
select(selectedButton) {
|
||||
const newState = {};
|
||||
this.buttons.forEach(button => {
|
||||
newState[button] = selectedButton === button;
|
||||
});
|
||||
this.setState(newState);
|
||||
}
|
||||
|
||||
render() {
|
||||
return (
|
||||
<View style={touchableStylingStyles.container}>
|
||||
{this.buttons.map(button => {
|
||||
const tstyle = [
|
||||
touchableStylingStyles.textInput,
|
||||
this.state[button] && touchableStylingStyles.blue
|
||||
];
|
||||
return (
|
||||
<TouchableHighlight
|
||||
key={button}
|
||||
onPress={this.select.bind(this, button)}
|
||||
style={tstyle}
|
||||
>
|
||||
<Text style={[this.state[button] && touchableStylingStyles.white]}>
|
||||
Button {button} {this.state[button] ? 'On' : 'Off'}
|
||||
</Text>
|
||||
</TouchableHighlight>
|
||||
);
|
||||
})}
|
||||
</View>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
const touchableStylingStyles = StyleSheet.create({
|
||||
blue: {
|
||||
backgroundColor: 'rgb(100, 100, 200)',
|
||||
borderColor: 'white'
|
||||
},
|
||||
white: {
|
||||
color: 'white'
|
||||
},
|
||||
container: {
|
||||
backgroundColor: '#f6f6f6'
|
||||
},
|
||||
textInput: {
|
||||
borderWidth: 3,
|
||||
borderColor: 'black',
|
||||
padding: 20,
|
||||
width: 200
|
||||
}
|
||||
});
|
||||
|
||||
const heartImage = { uri: 'https://pbs.twimg.com/media/BlXBfT3CQAA6cVZ.png:small' };
|
||||
|
||||
const styles = StyleSheet.create({
|
||||
@@ -468,6 +445,105 @@ const styles = StyleSheet.create({
|
||||
}
|
||||
});
|
||||
|
||||
examples.forEach(example => {
|
||||
storiesOf('component: Touchable*', module).add(example.title, () => example.render());
|
||||
});
|
||||
const examples = [
|
||||
{
|
||||
title: '<TouchableHighlight>',
|
||||
description:
|
||||
'TouchableHighlight works by adding an extra view with a ' +
|
||||
'black background under the single child view. This works best when the ' +
|
||||
'child view is fully opaque, although it can be made to work as a simple ' +
|
||||
'background color change as well with the activeOpacity and ' +
|
||||
'underlayColor props.',
|
||||
render() {
|
||||
return (
|
||||
<View>
|
||||
<View style={styles.row}>
|
||||
<TouchableHighlight
|
||||
onPress={() => console.log('stock THW image - highlight')}
|
||||
style={styles.wrapper}
|
||||
>
|
||||
<Image source={heartImage} style={styles.image} />
|
||||
</TouchableHighlight>
|
||||
<TouchableHighlight
|
||||
activeOpacity={1}
|
||||
onPress={() => console.log('custom THW text - highlight')}
|
||||
style={styles.wrapper}
|
||||
underlayColor="rgb(210, 230, 255)"
|
||||
>
|
||||
<View style={styles.wrapperCustom}>
|
||||
<Text style={styles.text}>
|
||||
Tap Here For Custom Highlight!
|
||||
</Text>
|
||||
</View>
|
||||
</TouchableHighlight>
|
||||
</View>
|
||||
</View>
|
||||
);
|
||||
}
|
||||
},
|
||||
{
|
||||
title: '<Text onPress={fn}> with highlight',
|
||||
render() {
|
||||
return <TextOnPressBox />;
|
||||
}
|
||||
},
|
||||
{
|
||||
title: 'Touchable feedback events',
|
||||
description:
|
||||
'<Touchable*> components accept onPress, onPressIn, ' +
|
||||
'onPressOut, and onLongPress as props.',
|
||||
render() {
|
||||
return <TouchableFeedbackEvents />;
|
||||
}
|
||||
},
|
||||
{
|
||||
title: 'Touchable delay for events',
|
||||
description:
|
||||
'<Touchable*> components also accept delayPressIn, ' +
|
||||
'delayPressOut, and delayLongPress as props. These props impact the ' +
|
||||
'timing of feedback events.',
|
||||
render() {
|
||||
return <TouchableDelayEvents />;
|
||||
}
|
||||
},
|
||||
{
|
||||
title: 'Touchable styling',
|
||||
render() {
|
||||
return <TouchableStyling />;
|
||||
}
|
||||
},
|
||||
{
|
||||
title: '3D Touch / Force Touch',
|
||||
description: 'iPhone 6s and 6s plus support 3D touch, which adds a force property to touches',
|
||||
render() {
|
||||
return <ForceTouchExample />;
|
||||
},
|
||||
platform: 'ios'
|
||||
},
|
||||
{
|
||||
title: 'Touchable Hit Slop',
|
||||
description:
|
||||
'<Touchable*> components accept hitSlop prop which extends the touch area ' +
|
||||
'without changing the view bounds.',
|
||||
render() {
|
||||
return <TouchableHitSlop />;
|
||||
}
|
||||
},
|
||||
{
|
||||
title: 'Disabled Touchable*',
|
||||
description:
|
||||
'<Touchable*> components accept disabled prop which prevents ' +
|
||||
'any interaction with component',
|
||||
render() {
|
||||
return <TouchableDisabled />;
|
||||
}
|
||||
}
|
||||
];
|
||||
|
||||
storiesOf('Components', module).add('Touchables', () =>
|
||||
<UIExplorer
|
||||
examples={examples}
|
||||
title="Touchables"
|
||||
url="https://github.com/necolas/react-native-web/blob/master/docs/components/TouchableWithoutFeedback.md"
|
||||
/>
|
||||
);
|
||||
|
||||
@@ -1,8 +1,3 @@
|
||||
import createReactClass from 'create-react-class';
|
||||
import React from 'react';
|
||||
import { storiesOf } from '@kadira/storybook';
|
||||
import { StyleSheet, Text, TouchableWithoutFeedback, View } from 'react-native';
|
||||
|
||||
/**
|
||||
* Copyright (c) 2013-present, Facebook, Inc.
|
||||
* All rights reserved.
|
||||
@@ -26,6 +21,16 @@ import { StyleSheet, Text, TouchableWithoutFeedback, View } from 'react-native';
|
||||
* @flow
|
||||
*/
|
||||
|
||||
import React from 'react';
|
||||
import { storiesOf } from '@kadira/storybook';
|
||||
import UIExplorer from '../../UIExplorer';
|
||||
import ViewTransformsExample from './ViewTransformsExample';
|
||||
import { StyleSheet, Text, TouchableHighlight, TouchableWithoutFeedback, View } from 'react-native';
|
||||
|
||||
const logger = e => {
|
||||
console.log(e.nativeEvent);
|
||||
};
|
||||
|
||||
const styles = StyleSheet.create({
|
||||
box: {
|
||||
backgroundColor: '#527FE4',
|
||||
@@ -51,12 +56,10 @@ const styles = StyleSheet.create({
|
||||
}
|
||||
});
|
||||
|
||||
const ViewBorderStyleExample = createReactClass({
|
||||
getInitialState() {
|
||||
return {
|
||||
showBorder: true
|
||||
};
|
||||
},
|
||||
class ViewBorderStyleExample extends React.Component {
|
||||
state = {
|
||||
showBorder: true
|
||||
};
|
||||
|
||||
render() {
|
||||
return (
|
||||
@@ -89,19 +92,17 @@ const ViewBorderStyleExample = createReactClass({
|
||||
</View>
|
||||
</TouchableWithoutFeedback>
|
||||
);
|
||||
},
|
||||
}
|
||||
|
||||
_handlePress() {
|
||||
this.setState({ showBorder: !this.state.showBorder });
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
const ZIndexExample = createReactClass({
|
||||
getInitialState() {
|
||||
return {
|
||||
flipped: false
|
||||
};
|
||||
},
|
||||
class ZIndexExample extends React.Component {
|
||||
state = {
|
||||
flipped: false
|
||||
};
|
||||
|
||||
render() {
|
||||
const indices = this.state.flipped ? [-1, 0, 1, 2] : [2, 1, 0, -1];
|
||||
@@ -144,17 +145,17 @@ const ZIndexExample = createReactClass({
|
||||
</View>
|
||||
</TouchableWithoutFeedback>
|
||||
);
|
||||
},
|
||||
}
|
||||
|
||||
_handlePress() {
|
||||
this.setState({ flipped: !this.state.flipped });
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
const examples = [
|
||||
{
|
||||
title: 'Background Color',
|
||||
render: function() {
|
||||
render() {
|
||||
return (
|
||||
<View style={{ backgroundColor: '#527FE4', padding: 5 }}>
|
||||
<Text style={{ fontSize: 11 }}>
|
||||
@@ -166,7 +167,7 @@ const examples = [
|
||||
},
|
||||
{
|
||||
title: 'Border',
|
||||
render: function() {
|
||||
render() {
|
||||
return (
|
||||
<View style={{ borderColor: '#527FE4', borderWidth: 5, padding: 10 }}>
|
||||
<Text style={{ fontSize: 11 }}>5px blue border</Text>
|
||||
@@ -176,7 +177,7 @@ const examples = [
|
||||
},
|
||||
{
|
||||
title: 'Padding/Margin',
|
||||
render: function() {
|
||||
render() {
|
||||
return (
|
||||
<View style={{ borderColor: '#bb0000', borderWidth: 0.5 }}>
|
||||
<View style={[styles.box, { padding: 5 }]}>
|
||||
@@ -199,7 +200,7 @@ const examples = [
|
||||
},
|
||||
{
|
||||
title: 'Border Radius',
|
||||
render: function() {
|
||||
render() {
|
||||
return (
|
||||
<View style={{ borderWidth: 0.5, borderRadius: 5, padding: 5 }}>
|
||||
<Text style={{ fontSize: 11 }}>
|
||||
@@ -213,19 +214,19 @@ const examples = [
|
||||
},
|
||||
{
|
||||
title: 'Border Style',
|
||||
render: function() {
|
||||
render() {
|
||||
return <ViewBorderStyleExample />;
|
||||
}
|
||||
},
|
||||
{
|
||||
title: 'Circle with Border Radius',
|
||||
render: function() {
|
||||
render() {
|
||||
return <View style={{ borderRadius: 10, borderWidth: 1, width: 20, height: 20 }} />;
|
||||
}
|
||||
},
|
||||
{
|
||||
title: 'Overflow',
|
||||
render: function() {
|
||||
render() {
|
||||
return (
|
||||
<View style={{ flexDirection: 'row' }}>
|
||||
<View
|
||||
@@ -253,7 +254,7 @@ const examples = [
|
||||
},
|
||||
{
|
||||
title: 'Opacity',
|
||||
render: function() {
|
||||
render() {
|
||||
return (
|
||||
<View>
|
||||
<View style={{ opacity: 0 }}><Text>Opacity 0</Text></View>
|
||||
@@ -269,10 +270,31 @@ const examples = [
|
||||
},
|
||||
{
|
||||
title: 'ZIndex',
|
||||
render: function() {
|
||||
render() {
|
||||
return <ZIndexExample />;
|
||||
}
|
||||
},
|
||||
{
|
||||
title: 'Pointer Events',
|
||||
render() {
|
||||
return (
|
||||
<View pointerEvents="box-none">
|
||||
<View pointerEvents="box-none">
|
||||
<View pointerEvents="none"><Text onPress={logger}>none</Text></View>
|
||||
<TouchableHighlight onPress={logger} pointerEvents="auto">
|
||||
<Text>auto</Text>
|
||||
</TouchableHighlight>
|
||||
<TouchableHighlight onPress={logger} pointerEvents="box-only">
|
||||
<Text>box-only</Text>
|
||||
</TouchableHighlight>
|
||||
<TouchableHighlight onPress={logger} pointerEvents="box-none">
|
||||
<Text>box-none</Text>
|
||||
</TouchableHighlight>
|
||||
</View>
|
||||
</View>
|
||||
);
|
||||
}
|
||||
},
|
||||
{
|
||||
title: 'Basic shadow',
|
||||
render() {
|
||||
@@ -286,8 +308,12 @@ const examples = [
|
||||
return <View style={[styles.shadowBox, styles.shadow, { borderRadius: 50 }]} />;
|
||||
}
|
||||
}
|
||||
];
|
||||
].concat(ViewTransformsExample);
|
||||
|
||||
examples.forEach(example => {
|
||||
storiesOf('component: View', module).add(example.title, () => example.render());
|
||||
});
|
||||
storiesOf('Components', module).add('View', () =>
|
||||
<UIExplorer
|
||||
examples={examples}
|
||||
title="View"
|
||||
url="https://github.com/necolas/react-native-web/blob/master/docs/components/View.md"
|
||||
/>
|
||||
);
|
||||
|
||||
@@ -1,7 +1,4 @@
|
||||
import createReactClass from 'create-react-class';
|
||||
import React from 'react';
|
||||
import { storiesOf } from '@kadira/storybook';
|
||||
import { Animated, StyleSheet, Text, View } from 'react-native';
|
||||
/* eslint-disable react/prefer-es6-class */
|
||||
|
||||
/**
|
||||
* Copyright (c) 2013-present, Facebook, Inc.
|
||||
@@ -25,24 +22,28 @@ import { Animated, StyleSheet, Text, View } from 'react-native';
|
||||
* @flow
|
||||
*/
|
||||
|
||||
const Flip = createReactClass({
|
||||
getInitialState() {
|
||||
return {
|
||||
import React from 'react';
|
||||
import { Animated, StyleSheet, Text, View } from 'react-native';
|
||||
|
||||
class Flip extends React.Component {
|
||||
constructor(props, context) {
|
||||
super(props, context);
|
||||
this.state = {
|
||||
theta: new Animated.Value(45)
|
||||
};
|
||||
},
|
||||
}
|
||||
|
||||
componentDidMount() {
|
||||
this._animate();
|
||||
},
|
||||
}
|
||||
|
||||
_animate() {
|
||||
_animate = () => {
|
||||
this.state.theta.setValue(0);
|
||||
Animated.timing(this.state.theta, {
|
||||
toValue: 360,
|
||||
duration: 5000
|
||||
}).start(this._animate);
|
||||
},
|
||||
};
|
||||
|
||||
render() {
|
||||
return (
|
||||
@@ -93,7 +94,7 @@ const Flip = createReactClass({
|
||||
</View>
|
||||
);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
const styles = StyleSheet.create({
|
||||
box1: {
|
||||
@@ -254,6 +255,4 @@ const examples = [
|
||||
}
|
||||
];
|
||||
|
||||
examples.forEach(example => {
|
||||
storiesOf('component: View (transforms)', module).add(example.title, () => example.render());
|
||||
});
|
||||
export default examples;
|
||||
|
||||
441
docs/storybook/demos/Calculator/Calculator.js
Normal file
441
docs/storybook/demos/Calculator/Calculator.js
Normal file
@@ -0,0 +1,441 @@
|
||||
/* eslint-disable react/jsx-no-bind, react/prop-types */
|
||||
|
||||
// React Native version of https://codepen.io/mjijackson/pen/xOzyGX
|
||||
import React from 'react';
|
||||
import { StyleSheet, Text, TouchableHighlight, View } from 'react-native';
|
||||
|
||||
/**
|
||||
* KeyboardInput
|
||||
*/
|
||||
class KeyboardInput extends React.Component {
|
||||
componentDidMount() {
|
||||
document.addEventListener('keydown', this.handleKeyDown);
|
||||
}
|
||||
|
||||
componentWillUnmount() {
|
||||
document.removeEventListener('keydown', this.handleKeyDown);
|
||||
}
|
||||
|
||||
render() {
|
||||
return null;
|
||||
}
|
||||
|
||||
handleKeyDown = event => {
|
||||
if (this.props.onKeyDown) {
|
||||
this.props.onKeyDown(event);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* CalculatorDisplay
|
||||
*/
|
||||
class CalculatorDisplay extends React.Component {
|
||||
constructor(props, context) {
|
||||
super(props, context);
|
||||
this.state = {
|
||||
scale: 1
|
||||
};
|
||||
}
|
||||
|
||||
handleTextLayout = e => {
|
||||
const { width, x } = e.nativeEvent.layout;
|
||||
const maxWidth = width + x;
|
||||
const newScale = maxWidth / width;
|
||||
if (x < 0) {
|
||||
this.setState({ scale: newScale });
|
||||
} else if (x > width) {
|
||||
this.setState({ scale: 1 });
|
||||
}
|
||||
};
|
||||
|
||||
render() {
|
||||
const { value } = this.props;
|
||||
const { scale } = this.state;
|
||||
|
||||
const language = navigator.language || 'en-US';
|
||||
let formattedValue = parseFloat(value).toLocaleString(language, {
|
||||
useGrouping: true,
|
||||
maximumFractionDigits: 6
|
||||
});
|
||||
|
||||
const trailingZeros = value.match(/\.0*$/);
|
||||
|
||||
if (trailingZeros) {
|
||||
formattedValue += trailingZeros;
|
||||
}
|
||||
|
||||
return (
|
||||
<View style={calculatorDisplayStyles.root}>
|
||||
<Text
|
||||
children={formattedValue}
|
||||
onLayout={this.handleTextLayout}
|
||||
style={[calculatorDisplayStyles.text, { transform: [{ scale }] }]}
|
||||
/>
|
||||
</View>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
const calculatorDisplayStyles = StyleSheet.create({
|
||||
root: {
|
||||
backgroundColor: '#1c191c',
|
||||
flex: 1,
|
||||
justifyContent: 'center'
|
||||
},
|
||||
text: {
|
||||
alignSelf: 'flex-end',
|
||||
color: 'white',
|
||||
//lineHeight: 130,
|
||||
fontSize: '5.25em',
|
||||
fontWeight: '100',
|
||||
fontFamily: 'Roboto, sans-serif',
|
||||
paddingHorizontal: 30,
|
||||
//position: 'absolute',
|
||||
right: 0,
|
||||
transformOrigin: 'right'
|
||||
}
|
||||
});
|
||||
|
||||
/**
|
||||
* CalculatorKey
|
||||
*/
|
||||
class CalculatorKey extends React.Component {
|
||||
render() {
|
||||
const { children, onPress, style, textStyle } = this.props;
|
||||
|
||||
return (
|
||||
<TouchableHighlight
|
||||
accessibilityRole="button"
|
||||
onPress={onPress}
|
||||
style={[calculatorKeyStyles.root, style]}
|
||||
underlayColor="rgba(0,0,0,0.25)"
|
||||
>
|
||||
<Text children={children} style={[calculatorKeyStyles.text, textStyle]} />
|
||||
</TouchableHighlight>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
const calculatorKeyStyles = StyleSheet.create({
|
||||
root: {
|
||||
width: 80,
|
||||
height: 80,
|
||||
borderTopWidth: 1,
|
||||
borderTopColor: '#777',
|
||||
borderTopStyle: 'solid',
|
||||
borderRightWidth: 1,
|
||||
borderRightColor: '#666',
|
||||
borderRightStyle: 'solid',
|
||||
outline: 'none'
|
||||
},
|
||||
text: {
|
||||
fontWeight: '100',
|
||||
fontFamily: 'Roboto, sans-serif',
|
||||
lineHeight: 80,
|
||||
textAlign: 'center'
|
||||
}
|
||||
});
|
||||
|
||||
const CalculatorOperations = {
|
||||
'/': (prevValue, nextValue) => prevValue / nextValue,
|
||||
'*': (prevValue, nextValue) => prevValue * nextValue,
|
||||
'+': (prevValue, nextValue) => prevValue + nextValue,
|
||||
'-': (prevValue, nextValue) => prevValue - nextValue,
|
||||
'=': (prevValue, nextValue) => nextValue
|
||||
};
|
||||
|
||||
/**
|
||||
* Calculator
|
||||
*/
|
||||
class Calculator extends React.Component {
|
||||
constructor(props, context) {
|
||||
super(props, context);
|
||||
|
||||
this.state = {
|
||||
value: null,
|
||||
displayValue: '0',
|
||||
operator: null,
|
||||
waitingForOperand: false
|
||||
};
|
||||
}
|
||||
|
||||
clearAll() {
|
||||
this.setState({
|
||||
value: null,
|
||||
displayValue: '0',
|
||||
operator: null,
|
||||
waitingForOperand: false
|
||||
});
|
||||
}
|
||||
|
||||
clearDisplay() {
|
||||
this.setState({
|
||||
displayValue: '0'
|
||||
});
|
||||
}
|
||||
|
||||
clearLastChar() {
|
||||
const { displayValue } = this.state;
|
||||
|
||||
this.setState({
|
||||
displayValue: displayValue.substring(0, displayValue.length - 1) || '0'
|
||||
});
|
||||
}
|
||||
|
||||
toggleSign() {
|
||||
const { displayValue } = this.state;
|
||||
const newValue = parseFloat(displayValue) * -1;
|
||||
|
||||
this.setState({
|
||||
displayValue: String(newValue)
|
||||
});
|
||||
}
|
||||
|
||||
inputPercent() {
|
||||
const { displayValue } = this.state;
|
||||
const currentValue = parseFloat(displayValue);
|
||||
|
||||
if (currentValue === 0) return;
|
||||
|
||||
const fixedDigits = displayValue.replace(/^-?\d*\.?/, '');
|
||||
const newValue = parseFloat(displayValue) / 100;
|
||||
|
||||
this.setState({
|
||||
displayValue: String(newValue.toFixed(fixedDigits.length + 2))
|
||||
});
|
||||
}
|
||||
|
||||
inputDot() {
|
||||
const { displayValue } = this.state;
|
||||
|
||||
if (!/\./.test(displayValue)) {
|
||||
this.setState({
|
||||
displayValue: displayValue + '.',
|
||||
waitingForOperand: false
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
inputDigit(digit) {
|
||||
const { displayValue, waitingForOperand } = this.state;
|
||||
|
||||
if (waitingForOperand) {
|
||||
this.setState({
|
||||
displayValue: String(digit),
|
||||
waitingForOperand: false
|
||||
});
|
||||
} else {
|
||||
this.setState({
|
||||
displayValue: displayValue === '0' ? String(digit) : displayValue + digit
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
performOperation(nextOperator) {
|
||||
const { value, displayValue, operator } = this.state;
|
||||
const inputValue = parseFloat(displayValue);
|
||||
|
||||
if (value == null) {
|
||||
this.setState({
|
||||
value: inputValue
|
||||
});
|
||||
} else if (operator) {
|
||||
const currentValue = value || 0;
|
||||
const newValue = CalculatorOperations[operator](currentValue, inputValue);
|
||||
|
||||
this.setState({
|
||||
value: newValue,
|
||||
displayValue: String(newValue)
|
||||
});
|
||||
}
|
||||
|
||||
this.setState({
|
||||
waitingForOperand: true,
|
||||
operator: nextOperator
|
||||
});
|
||||
}
|
||||
|
||||
handleKeyDown(event) {
|
||||
let { key } = event;
|
||||
|
||||
if (key === 'Enter') key = '=';
|
||||
|
||||
if (/\d/.test(key)) {
|
||||
event.preventDefault();
|
||||
this.inputDigit(parseInt(key, 10));
|
||||
} else if (key in CalculatorOperations) {
|
||||
event.preventDefault();
|
||||
this.performOperation(key);
|
||||
} else if (key === '.') {
|
||||
event.preventDefault();
|
||||
this.inputDot();
|
||||
} else if (key === '%') {
|
||||
event.preventDefault();
|
||||
this.inputPercent();
|
||||
} else if (key === 'Backspace') {
|
||||
event.preventDefault();
|
||||
this.clearLastChar();
|
||||
} else if (key === 'Clear') {
|
||||
event.preventDefault();
|
||||
|
||||
if (this.state.displayValue !== '0') {
|
||||
this.clearDisplay();
|
||||
} else {
|
||||
this.clearAll();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
render() {
|
||||
const { displayValue } = this.state;
|
||||
|
||||
const clearDisplay = displayValue !== '0';
|
||||
const clearText = clearDisplay ? 'C' : 'AC';
|
||||
|
||||
return (
|
||||
<View style={calculatorStyles.root}>
|
||||
<KeyboardInput onKeyDown={event => this.handleKeyDown(event)} />
|
||||
<CalculatorDisplay value={displayValue} />
|
||||
<View style={calculatorStyles.keypad}>
|
||||
<View style={calculatorStyles.inputKeys}>
|
||||
<View style={calculatorStyles.functionKeys}>
|
||||
<FunctionKey onPress={() => (clearDisplay ? this.clearDisplay() : this.clearAll())}>
|
||||
{clearText}
|
||||
</FunctionKey>
|
||||
<FunctionKey onPress={() => this.toggleSign()} style={calculatorStyles.keySign}>
|
||||
±
|
||||
</FunctionKey>
|
||||
<FunctionKey onPress={() => this.inputPercent()} style={calculatorStyles.keyPercent}>
|
||||
%
|
||||
</FunctionKey>
|
||||
</View>
|
||||
<View style={calculatorStyles.digitKeys}>
|
||||
<DigitKey
|
||||
onPress={() => this.inputDigit(0)}
|
||||
style={calculatorStyles.key0}
|
||||
textStyle={{ textAlign: 'left' }}
|
||||
>
|
||||
0
|
||||
</DigitKey>
|
||||
<DigitKey
|
||||
onPress={() => this.inputDot()}
|
||||
style={calculatorStyles.keyDot}
|
||||
textStyle={calculatorStyles.keyDotText}
|
||||
>
|
||||
.
|
||||
</DigitKey>
|
||||
<DigitKey onPress={() => this.inputDigit(1)}>1</DigitKey>
|
||||
<DigitKey onPress={() => this.inputDigit(2)}>2</DigitKey>
|
||||
<DigitKey onPress={() => this.inputDigit(3)}>3</DigitKey>
|
||||
<DigitKey onPress={() => this.inputDigit(4)}>4</DigitKey>
|
||||
<DigitKey onPress={() => this.inputDigit(5)}>5</DigitKey>
|
||||
<DigitKey onPress={() => this.inputDigit(6)}>6</DigitKey>
|
||||
<DigitKey onPress={() => this.inputDigit(7)}>7</DigitKey>
|
||||
<DigitKey onPress={() => this.inputDigit(8)}>8</DigitKey>
|
||||
<DigitKey onPress={() => this.inputDigit(9)}>9</DigitKey>
|
||||
</View>
|
||||
</View>
|
||||
<View style={calculatorStyles.operatorKeys}>
|
||||
<OperatorKey onPress={() => this.performOperation('/')}>÷</OperatorKey>
|
||||
<OperatorKey onPress={() => this.performOperation('*')}>×</OperatorKey>
|
||||
<OperatorKey onPress={() => this.performOperation('-')}>−</OperatorKey>
|
||||
<OperatorKey onPress={() => this.performOperation('+')}>+</OperatorKey>
|
||||
<OperatorKey onPress={() => this.performOperation('=')}>=</OperatorKey>
|
||||
</View>
|
||||
</View>
|
||||
</View>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
const DigitKey = props =>
|
||||
<CalculatorKey
|
||||
{...props}
|
||||
style={[calculatorStyles.digitKey, props.style]}
|
||||
textStyle={[calculatorStyles.digitKeyText, props.textStyle]}
|
||||
/>;
|
||||
|
||||
const FunctionKey = props =>
|
||||
<CalculatorKey
|
||||
{...props}
|
||||
style={[calculatorStyles.functionKey, props.style]}
|
||||
textStyle={[calculatorStyles.functionKeyText, props.textStyle]}
|
||||
/>;
|
||||
|
||||
const OperatorKey = props =>
|
||||
<CalculatorKey
|
||||
{...props}
|
||||
style={[calculatorStyles.operatorKey, props.style]}
|
||||
textStyle={[calculatorStyles.operatorKeyText, props.textStyle]}
|
||||
/>;
|
||||
|
||||
const calculatorStyles = StyleSheet.create({
|
||||
root: {
|
||||
width: 320,
|
||||
height: 520,
|
||||
backgroundColor: 'black',
|
||||
boxShadow: '0px 0px 20px 0px #aaa'
|
||||
},
|
||||
keypad: {
|
||||
height: 400,
|
||||
flexDirection: 'row'
|
||||
},
|
||||
inputKeys: {
|
||||
width: 240
|
||||
},
|
||||
calculatorKeyText: {
|
||||
fontFamily: 'Roboto, sans-serif',
|
||||
fontSize: '1.75em',
|
||||
fontWeight: '100'
|
||||
},
|
||||
functionKeys: {
|
||||
backgroundImage: 'linear-gradient(to bottom, rgba(202,202,204,1) 0%, rgba(196,194,204,1) 100%)',
|
||||
flexDirection: 'row'
|
||||
},
|
||||
functionKeyText: {
|
||||
fontFamily: 'Roboto, sans-serif',
|
||||
fontSize: '1.75em',
|
||||
fontWeight: '100'
|
||||
},
|
||||
digitKeys: {
|
||||
backgroundColor: '#e0e0e7',
|
||||
flexDirection: 'row',
|
||||
flexWrap: 'wrap-reverse'
|
||||
},
|
||||
digitKeyText: {
|
||||
fontFamily: 'Roboto, sans-serif',
|
||||
fontSize: '2em',
|
||||
fontWeight: '100'
|
||||
},
|
||||
operatorKeys: {
|
||||
backgroundImage: 'linear-gradient(to bottom, rgba(252,156,23,1) 0%, rgba(247,126,27,1) 100%)'
|
||||
},
|
||||
operatorKey: {
|
||||
borderRightWidth: 0
|
||||
},
|
||||
operatorKeyText: {
|
||||
color: 'white',
|
||||
fontFamily: 'Roboto, sans-serif',
|
||||
fontSize: '2.65em',
|
||||
fontWeight: '100'
|
||||
},
|
||||
keyMultiplyText: {
|
||||
lineHeight: 50
|
||||
},
|
||||
key0: {
|
||||
paddingLeft: 32,
|
||||
width: 160
|
||||
},
|
||||
keyDot: {
|
||||
overflow: 'hidden'
|
||||
},
|
||||
keyDotText: {
|
||||
fontFamily: 'Roboto, sans-serif',
|
||||
fontSize: '4.375em',
|
||||
fontWeight: '100',
|
||||
marginTop: -10
|
||||
}
|
||||
});
|
||||
|
||||
export default Calculator;
|
||||
14
docs/storybook/demos/Calculator/CalculatorExample.js
Normal file
14
docs/storybook/demos/Calculator/CalculatorExample.js
Normal file
@@ -0,0 +1,14 @@
|
||||
import React from 'react';
|
||||
import { storiesOf } from '@kadira/storybook';
|
||||
import Calculator from './Calculator';
|
||||
import { StyleSheet, View } from 'react-native';
|
||||
|
||||
const styles = StyleSheet.create({
|
||||
container: { alignItems: 'center', justifyContent: 'center', flex: 1 }
|
||||
});
|
||||
|
||||
storiesOf('Example apps', module).add('Calculator', () =>
|
||||
<View style={styles.container}>
|
||||
<Calculator />
|
||||
</View>
|
||||
);
|
||||
@@ -323,4 +323,4 @@ const styles = StyleSheet.create({
|
||||
|
||||
AppRegistry.registerComponent('Game2048', () => Game2048);
|
||||
|
||||
module.exports = Game2048;
|
||||
export default Game2048;
|
||||
|
||||
@@ -2,4 +2,4 @@ import React from 'react';
|
||||
import { storiesOf } from '@kadira/storybook';
|
||||
import Game2048 from './Game2048';
|
||||
|
||||
storiesOf('demo: Game2048', module).add('the game', () => <Game2048 />);
|
||||
storiesOf('Example apps', module).add('Game2048', () => <Game2048 />);
|
||||
|
||||
@@ -207,4 +207,4 @@ Board.prototype.hasLost = function() {
|
||||
return !canMove;
|
||||
};
|
||||
|
||||
module.exports = Board;
|
||||
export default Board;
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/* eslint-disable react/jsx-no-bind */
|
||||
/* eslint-disable react/jsx-no-bind, react/prefer-es6-class, react/prop-types */
|
||||
|
||||
/**
|
||||
* The examples provided by Facebook are for non-commercial testing and
|
||||
@@ -211,17 +211,17 @@ const TicTacToeApp = createReactClass({
|
||||
},
|
||||
|
||||
render() {
|
||||
const rows = this.state.board.grid.map((cells, row) => (
|
||||
const rows = this.state.board.grid.map((cells, row) =>
|
||||
<View key={'row' + row} style={styles.row}>
|
||||
{cells.map((player, col) => (
|
||||
{cells.map((player, col) =>
|
||||
<Cell
|
||||
key={'cell' + col}
|
||||
onPress={this.handleCellPress.bind(this, row, col)}
|
||||
player={player}
|
||||
/>
|
||||
))}
|
||||
)}
|
||||
</View>
|
||||
));
|
||||
);
|
||||
|
||||
return (
|
||||
<View style={styles.container}>
|
||||
@@ -325,4 +325,4 @@ const styles = StyleSheet.create({
|
||||
|
||||
AppRegistry.registerComponent('TicTacToeApp', () => TicTacToeApp);
|
||||
|
||||
module.exports = TicTacToeApp;
|
||||
export default TicTacToeApp;
|
||||
|
||||
@@ -2,4 +2,4 @@ import React from 'react';
|
||||
import { storiesOf } from '@kadira/storybook';
|
||||
import TicTacToe from './TicTacToe';
|
||||
|
||||
storiesOf('demo: TicTacToe', module).add('the game', () => <TicTacToe />);
|
||||
storiesOf('Example apps', module).add('TicTacToe', () => <TicTacToe />);
|
||||
|
||||
74
package.json
74
package.json
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "react-native-web",
|
||||
"version": "0.0.96",
|
||||
"version": "0.0.106",
|
||||
"description": "React Native for Web",
|
||||
"main": "dist/index.js",
|
||||
"files": [
|
||||
@@ -14,23 +14,29 @@
|
||||
"compile": "del ./dist && mkdir dist && babel src -d dist --ignore **/__tests__",
|
||||
"docs:build": "build-storybook -o ./docs/dist -c ./docs/storybook/.storybook",
|
||||
"docs:start": "start-storybook -p 9001 -c ./docs/storybook/.storybook --dont-track",
|
||||
"docs:publish": "git checkout gh-pages && rm -rf ./storybook && mv docs/dist storybook && git add -A && git commit -m \"Storybook deploy\" && git push origin gh-pages && git checkout -",
|
||||
"docs:publish": "yarn docs:build && git checkout gh-pages && rm -rf ./storybook && mv docs/dist storybook && git add -A && git commit -m \"Storybook deploy\" && git push origin gh-pages && git checkout -",
|
||||
"flow": "flow",
|
||||
"fmt": "find benchmarks docs src -name '*.js' | grep -v -E '(node_modules|dist)' | xargs npm run fmt:cmd",
|
||||
"fmt": "find benchmarks docs src -name '*.js' | grep -v -E '(node_modules|dist)' | xargs yarn fmt:cmd",
|
||||
"fmt:cmd": "prettier --print-width=100 --single-quote --write",
|
||||
"lint": "npm run lint:cmd -- benchmarks docs src",
|
||||
"jest": "jest",
|
||||
"jest:watch": "yarn test -- --watch",
|
||||
"lint": "yarn lint:cmd -- benchmarks docs src",
|
||||
"lint:cmd": "eslint --fix --ignore-path .gitignore",
|
||||
"precommit": "lint-staged",
|
||||
"release": "npm run compile && npm run build && npm publish",
|
||||
"test": "jest",
|
||||
"test:watch": "npm run test -- --watch"
|
||||
"release": "yarn lint && yarn test && yarn compile && yarn build && npm publish",
|
||||
"test": "flow && jest"
|
||||
},
|
||||
"babel": {
|
||||
"presets": [
|
||||
"react-native"
|
||||
],
|
||||
"plugins": [
|
||||
[ "transform-react-remove-prop-types", { "mode": "wrap" } ]
|
||||
[
|
||||
"transform-react-remove-prop-types",
|
||||
{
|
||||
"mode": "wrap"
|
||||
}
|
||||
]
|
||||
]
|
||||
},
|
||||
"jest": {
|
||||
@@ -51,48 +57,46 @@
|
||||
"animated": "^0.2.0",
|
||||
"array-find-index": "^1.0.2",
|
||||
"babel-runtime": "^6.23.0",
|
||||
"create-react-class": "^15.5.2",
|
||||
"create-react-class": "^15.6.0",
|
||||
"debounce": "1.0.2",
|
||||
"deep-assign": "^2.0.0",
|
||||
"fbjs": "^0.8.12",
|
||||
"hyphenate-style-name": "^1.0.2",
|
||||
"inline-style-prefixer": "^3.0.3",
|
||||
"inline-style-prefixer": "^3.0.6",
|
||||
"normalize-css-color": "^1.0.2",
|
||||
"prop-types": "^15.5.8",
|
||||
"prop-types": "^15.5.10",
|
||||
"react-timer-mixin": "^0.13.3"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@kadira/storybook": "^2.5.1",
|
||||
"babel-cli": "^6.24.1",
|
||||
"babel-core": "^6.24.1",
|
||||
"babel-eslint": "^7.2.2",
|
||||
"babel-loader": "^6.4.1",
|
||||
"babel-plugin-transform-react-remove-prop-types": "^0.4.2",
|
||||
"babel-preset-react-native": "^1.9.1",
|
||||
"del-cli": "^0.2.1",
|
||||
"babel-core": "^6.25.0",
|
||||
"babel-eslint": "^7.2.3",
|
||||
"babel-loader": "^7.1.0",
|
||||
"babel-plugin-transform-react-remove-prop-types": "^0.4.6",
|
||||
"babel-preset-react-native": "^2.0.0",
|
||||
"del-cli": "^1.0.0",
|
||||
"enzyme": "^2.8.2",
|
||||
"enzyme-to-json": "^1.5.1",
|
||||
"eslint": "^3.19.0",
|
||||
"eslint-config-prettier": "^1.7.0",
|
||||
"eslint": "^4.0.0",
|
||||
"eslint-config-prettier": "^2.2.0",
|
||||
"eslint-plugin-promise": "^3.5.0",
|
||||
"eslint-plugin-react": "^6.10.3",
|
||||
"file-loader": "^0.11.1",
|
||||
"flow-bin": "^0.46.0",
|
||||
"jest": "^19.0.2",
|
||||
"lint-staged": "^3.4.2",
|
||||
"node-libs-browser": "^0.5.3",
|
||||
"prettier": "^1.3.1",
|
||||
"react": "^15.5.4",
|
||||
"react-addons-test-utils": "^15.5.1",
|
||||
"react-dom": "^15.5.4",
|
||||
"react-test-renderer": "^15.5.4",
|
||||
"url-loader": "^0.5.8",
|
||||
"webpack": "^2.5.0",
|
||||
"webpack-bundle-analyzer": "^2.4.0"
|
||||
"eslint-plugin-react": "^7.1.0",
|
||||
"file-loader": "^0.11.2",
|
||||
"flow-bin": "^0.48.0",
|
||||
"jest": "^20.0.4",
|
||||
"lint-staged": "^4.0.0",
|
||||
"prettier": "^1.4.4",
|
||||
"react": "^15.6.1",
|
||||
"react-dom": "^15.6.1",
|
||||
"react-test-renderer": "^15.6.1",
|
||||
"url-loader": "^0.5.9",
|
||||
"webpack": "^3.0.0",
|
||||
"webpack-bundle-analyzer": "^2.8.2"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"react": "15.4.x || 15.5.x",
|
||||
"react-dom": "15.4.x || 15.5.x"
|
||||
"react": "15.4.x || 15.5.x || 15.6.x",
|
||||
"react-dom": "15.4.x || 15.5.x || 15.6.x"
|
||||
},
|
||||
"author": "Nicolas Gallagher",
|
||||
"license": "BSD-3-Clause",
|
||||
|
||||
@@ -1,3 +1,14 @@
|
||||
/**
|
||||
* Copyright (c) 2016-present, Nicolas Gallagher.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This source code is licensed under the BSD-style license found in the
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
*
|
||||
* @providesModule Animated
|
||||
* @noflow
|
||||
*/
|
||||
|
||||
import Animated from 'animated';
|
||||
import Image from '../../components/Image';
|
||||
import ScrollView from '../../components/ScrollView';
|
||||
@@ -7,10 +18,12 @@ import View from '../../components/View';
|
||||
|
||||
Animated.inject.FlattenStyle(StyleSheet.flatten);
|
||||
|
||||
module.exports = {
|
||||
const AnimatedImplementation = {
|
||||
...Animated,
|
||||
Image: Animated.createAnimatedComponent(Image),
|
||||
ScrollView: Animated.createAnimatedComponent(ScrollView),
|
||||
Text: Animated.createAnimatedComponent(Text),
|
||||
View: Animated.createAnimatedComponent(View)
|
||||
};
|
||||
|
||||
export default AnimatedImplementation;
|
||||
|
||||
70
src/apis/AppRegistry/AppContainer.js
Normal file
70
src/apis/AppRegistry/AppContainer.js
Normal file
@@ -0,0 +1,70 @@
|
||||
/**
|
||||
* Copyright (c) 2016-present, Nicolas Gallagher.
|
||||
* Copyright (c) 2015-present, Facebook, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This source code is licensed under the BSD-style license found in the
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
*
|
||||
* @flow
|
||||
*/
|
||||
|
||||
import StyleSheet from '../StyleSheet';
|
||||
import View from '../../components/View';
|
||||
import { any, node } from 'prop-types';
|
||||
import React, { Component } from 'react';
|
||||
|
||||
type Context = {
|
||||
rootTag: any
|
||||
};
|
||||
|
||||
type Props = {
|
||||
children?: React.Children,
|
||||
rootTag: any
|
||||
};
|
||||
|
||||
type State = {
|
||||
mainKey: number
|
||||
};
|
||||
|
||||
export default class AppContainer extends Component {
|
||||
props: Props;
|
||||
state: State = { mainKey: 1 };
|
||||
|
||||
static childContextTypes = {
|
||||
rootTag: any
|
||||
};
|
||||
|
||||
static propTypes = {
|
||||
children: node,
|
||||
rootTag: any.isRequired
|
||||
};
|
||||
|
||||
getChildContext(): Context {
|
||||
return {
|
||||
rootTag: this.props.rootTag
|
||||
};
|
||||
}
|
||||
|
||||
render() {
|
||||
return (
|
||||
<View pointerEvents="box-none" style={[styles.appContainer, StyleSheet.absoluteFill]}>
|
||||
<View
|
||||
children={this.props.children}
|
||||
key={this.state.mainKey}
|
||||
pointerEvents="box-none"
|
||||
style={styles.appContainer}
|
||||
/>
|
||||
</View>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
const styles = StyleSheet.create({
|
||||
/**
|
||||
* Ensure that the application covers the whole screen.
|
||||
*/
|
||||
appContainer: {
|
||||
flex: 1
|
||||
}
|
||||
});
|
||||
@@ -1,41 +0,0 @@
|
||||
/**
|
||||
* @flow
|
||||
*/
|
||||
|
||||
import StyleSheet from '../StyleSheet';
|
||||
import View from '../../components/View';
|
||||
import { any, object } from 'prop-types';
|
||||
import React, { Component } from 'react';
|
||||
|
||||
class ReactNativeApp extends Component {
|
||||
static propTypes = {
|
||||
initialProps: object,
|
||||
rootComponent: any.isRequired,
|
||||
rootTag: any
|
||||
};
|
||||
|
||||
render() {
|
||||
const { initialProps, rootComponent: RootComponent, rootTag } = this.props;
|
||||
|
||||
return (
|
||||
<View style={styles.appContainer}>
|
||||
<RootComponent {...initialProps} rootTag={rootTag} />
|
||||
</View>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
const styles = StyleSheet.create({
|
||||
/**
|
||||
* Ensure that the application covers the whole screen.
|
||||
*/
|
||||
appContainer: {
|
||||
position: 'absolute',
|
||||
left: 0,
|
||||
top: 0,
|
||||
right: 0,
|
||||
bottom: 0
|
||||
}
|
||||
});
|
||||
|
||||
module.exports = ReactNativeApp;
|
||||
@@ -1,59 +1,77 @@
|
||||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||
|
||||
exports[`apis/AppRegistry/renderApplication getApplication 1`] = `
|
||||
"<style id=\\"react-native-stylesheet-static\\">
|
||||
html{font-family:sans-serif;-ms-text-size-adjust:100%;-webkit-text-size-adjust:100%;-webkit-tap-highlight-color:rgba(0,0,0,0);}
|
||||
body{margin:0;}
|
||||
button::-moz-focus-inner,input::-moz-focus-inner{border:0;padding:0;}
|
||||
input::-webkit-inner-spin-button,input::-webkit-outer-spin-button,input::-webkit-search-cancel-button,input::-webkit-search-decoration,input::-webkit-search-results-button,input::-webkit-search-results-decoration{display:none;}
|
||||
@keyframes rn-ActivityIndicator-animation{0%{-webkit-transform:rotate(0deg);transform:rotate(0deg);}100%{-webkit-transform:rotate(360deg);transform:rotate(360deg);}}
|
||||
@keyframes rn-ProgressBar-animation{0%{-webkit-transform:translateX(-100%);transform:translateX(-100%);}100%{-webkit-transform:translateX(400%);transform:translateX(400%);}}
|
||||
.rn-pointerEvents-105ug2t{pointer-events:auto;}
|
||||
.rn-pointerEvents-12vffkv{pointer-events:none;}
|
||||
.rn-pointerEvents-12vffkv *{pointer-events:auto;}
|
||||
.rn-pointerEvents-ah5dr5{pointer-events:auto;}
|
||||
.rn-pointerEvents-ah5dr5 *{pointer-events:none;}
|
||||
.rn-pointerEvents-633pao{pointer-events:none;}
|
||||
</style>
|
||||
<style id=\\"react-native-stylesheet\\">
|
||||
.rn-bottom-1p0dtai{bottom:0px}
|
||||
.rn-left-1d2f490{left:0px}
|
||||
.rn-position-u8s1d{position:absolute}
|
||||
.rn-position-bnwqim{position:relative}
|
||||
.rn-right-zchlnj{right:0px}
|
||||
.rn-top-ipm5af{top:0px}
|
||||
.rn-appearance-30o5oe{-moz-appearance:none;-webkit-appearance:none;appearance:none}
|
||||
.rn-backgroundColor-wib322{background-color:transparent}
|
||||
.rn-color-homxoj{color:inherit}
|
||||
.rn-font-1lw9tu2{font:inherit}
|
||||
.rn-textAlign-1ttztb7{text-align:inherit}
|
||||
.rn-textDecoration-bauka4{text-decoration:none}
|
||||
.rn-listStyle-1ebb2ja{list-style:none}
|
||||
.rn-alignItems-1oszu61{-webkit-align-items:stretch;-webkit-box-align:stretch;align-items:stretch}
|
||||
.rn-borderTopStyle-1efd50x{border-top-style:solid}
|
||||
.rn-borderRightStyle-14skgim{border-right-style:solid}
|
||||
.rn-borderBottomStyle-rull8r{border-bottom-style:solid}
|
||||
.rn-borderLeftStyle-mm0ijv{border-left-style:solid}
|
||||
.rn-borderTopWidth-13yce4e{border-top-width:0px}
|
||||
.rn-borderRightWidth-fnigne{border-right-width:0px}
|
||||
.rn-borderBottomWidth-ndvcnb{border-bottom-width:0px}
|
||||
.rn-borderLeftWidth-gxnn5r{border-left-width:0px}
|
||||
.rn-boxSizing-deolkf{box-sizing:border-box}
|
||||
.rn-display-6koalj{display:-webkit-box;display:-moz-box;display:-ms-flexbox;display:-webkit-flex;display:flex}
|
||||
.rn-flexShrink-1qe8dj5{-webkit-flex-shrink:0;flex-shrink:0}
|
||||
.rn-flexBasis-1mlwlqe{-webkit-flex-basis:auto;flex-basis:auto}
|
||||
.rn-flexDirection-eqz5dr{-webkit-box-direction:normal;-webkit-box-orient:vertical;-webkit-flex-direction:column;flex-direction:column}
|
||||
.rn-marginTop-1mnahxq{margin-top:0px}
|
||||
.rn-marginRight-61z16t{margin-right:0px}
|
||||
.rn-marginBottom-p1pxzi{margin-bottom:0px}
|
||||
.rn-marginLeft-11wrixw{margin-left:0px}
|
||||
.rn-minHeight-ifefl9{min-height:0px}
|
||||
.rn-minWidth-bcqeeo{min-width:0px}
|
||||
.rn-paddingTop-wk8lta{padding-top:0px}
|
||||
.rn-paddingRight-9aemit{padding-right:0px}
|
||||
.rn-paddingBottom-1mdbw0j{padding-bottom:0px}
|
||||
.rn-paddingLeft-gy4na3{padding-left:0px}
|
||||
.rn-zIndex-1lgpqti{z-index:0}
|
||||
.rn-zIndex-1wyyakw{z-index:-1}
|
||||
</style>"
|
||||
<AppContainer
|
||||
rootTag={Object {}}
|
||||
>
|
||||
<RootComponent />
|
||||
</AppContainer>
|
||||
`;
|
||||
|
||||
exports[`apis/AppRegistry/renderApplication getApplication 2`] = `
|
||||
Array [
|
||||
<style
|
||||
id="react-native-stylesheet-static"
|
||||
>
|
||||
html{font-family:sans-serif;-ms-text-size-adjust:100%;-webkit-text-size-adjust:100%;-webkit-tap-highlight-color:rgba(0,0,0,0);}
|
||||
body{margin:0;}
|
||||
button::-moz-focus-inner,input::-moz-focus-inner{border:0;padding:0;}
|
||||
input::-webkit-inner-spin-button,input::-webkit-outer-spin-button,input::-webkit-search-cancel-button,input::-webkit-search-decoration,input::-webkit-search-results-button,input::-webkit-search-results-decoration{display:none;}
|
||||
@keyframes rn-ActivityIndicator-animation{0%{-webkit-transform:rotate(0deg);transform:rotate(0deg);}100%{-webkit-transform:rotate(360deg);transform:rotate(360deg);}}
|
||||
@keyframes rn-ProgressBar-animation{0%{-webkit-transform:translateX(-100%);transform:translateX(-100%);}100%{-webkit-transform:translateX(400%);transform:translateX(400%);}}
|
||||
.rn-pointerEvents-105ug2t{pointer-events:auto !important;}
|
||||
.rn-pointerEvents-ah5dr5{pointer-events:auto !important;}
|
||||
.rn-pointerEvents-633pao{pointer-events:none !important;}
|
||||
.rn-pointerEvents-12vffkv{pointer-events:none !important;}
|
||||
.rn-pointerEvents-12vffkv > *{pointer-events:auto;}
|
||||
.rn-pointerEvents-ah5dr5 > *{pointer-events:none;}
|
||||
</style>,
|
||||
<style
|
||||
id="react-native-stylesheet"
|
||||
>
|
||||
.rn-bottom-1p0dtai{bottom:0px}
|
||||
.rn-left-1d2f490{left:0px}
|
||||
.rn-position-u8s1d{position:absolute}
|
||||
.rn-position-bnwqim{position:relative}
|
||||
.rn-right-zchlnj{right:0px}
|
||||
.rn-top-ipm5af{top:0px}
|
||||
.rn-appearance-30o5oe{-moz-appearance:none;-webkit-appearance:none;appearance:none}
|
||||
.rn-backgroundColor-wib322{background-color:transparent}
|
||||
.rn-color-homxoj{color:inherit}
|
||||
.rn-font-1lw9tu2{font:inherit}
|
||||
.rn-textAlign-1ttztb7{text-align:inherit}
|
||||
.rn-textDecoration-bauka4{text-decoration:none}
|
||||
.rn-listStyle-1ebb2ja{list-style:none}
|
||||
.rn-alignItems-1oszu61{-webkit-align-items:stretch;-webkit-box-align:stretch;align-items:stretch}
|
||||
.rn-borderTopStyle-1efd50x{border-top-style:solid}
|
||||
.rn-borderRightStyle-14skgim{border-right-style:solid}
|
||||
.rn-borderBottomStyle-rull8r{border-bottom-style:solid}
|
||||
.rn-borderLeftStyle-mm0ijv{border-left-style:solid}
|
||||
.rn-borderTopWidth-13yce4e{border-top-width:0px}
|
||||
.rn-borderRightWidth-fnigne{border-right-width:0px}
|
||||
.rn-borderBottomWidth-ndvcnb{border-bottom-width:0px}
|
||||
.rn-borderLeftWidth-gxnn5r{border-left-width:0px}
|
||||
.rn-boxSizing-deolkf{box-sizing:border-box}
|
||||
.rn-display-6koalj{display:-webkit-box;display:-moz-box;display:-ms-flexbox;display:-webkit-flex;display:flex}
|
||||
.rn-display-xoduu5{display:-webkit-inline-box;display:-moz-inline-box;display:-ms-inline-flexbox;display:-webkit-inline-flex;display:inline-flex}
|
||||
.rn-flexShrink-1qe8dj5{-webkit-flex-shrink:0;flex-shrink:0}
|
||||
.rn-flexShrink-1wbh5a2{-webkit-flex-shrink:1;flex-shrink:1}
|
||||
.rn-flexBasis-1mlwlqe{-webkit-flex-basis:auto;flex-basis:auto}
|
||||
.rn-flexBasis-1ro0kt6{-webkit-flex-basis:0%;flex-basis:0%}
|
||||
.rn-flexDirection-eqz5dr{-webkit-box-direction:normal;-webkit-box-orient:vertical;-webkit-flex-direction:column;flex-direction:column}
|
||||
.rn-marginTop-1mnahxq{margin-top:0px}
|
||||
.rn-marginRight-61z16t{margin-right:0px}
|
||||
.rn-marginBottom-p1pxzi{margin-bottom:0px}
|
||||
.rn-marginLeft-11wrixw{margin-left:0px}
|
||||
.rn-minHeight-ifefl9{min-height:0px}
|
||||
.rn-minWidth-bcqeeo{min-width:0px}
|
||||
.rn-paddingTop-wk8lta{padding-top:0px}
|
||||
.rn-paddingRight-9aemit{padding-right:0px}
|
||||
.rn-paddingBottom-1mdbw0j{padding-bottom:0px}
|
||||
.rn-paddingLeft-gy4na3{padding-left:0px}
|
||||
.rn-zIndex-1lgpqti{z-index:0}
|
||||
.rn-zIndex-1wyyakw{z-index:-1}
|
||||
.rn-flexGrow-16y2uox{-webkit-flex-grow:1;flex-grow:1}
|
||||
</style>,
|
||||
]
|
||||
`;
|
||||
|
||||
@@ -3,13 +3,13 @@
|
||||
import { getApplication } from '../renderApplication';
|
||||
import React from 'react';
|
||||
|
||||
const component = () => <div />;
|
||||
const RootComponent = () => <div />;
|
||||
|
||||
describe('apis/AppRegistry/renderApplication', () => {
|
||||
test('getApplication', () => {
|
||||
const { element, stylesheet } = getApplication(component, {});
|
||||
const { element, stylesheets } = getApplication(RootComponent, {});
|
||||
|
||||
expect(element).toBeTruthy();
|
||||
expect(stylesheet).toMatchSnapshot();
|
||||
expect(element).toMatchSnapshot();
|
||||
expect(stylesheets).toMatchSnapshot();
|
||||
});
|
||||
});
|
||||
|
||||
@@ -3,10 +3,13 @@
|
||||
* Copyright (c) 2015-present, Facebook, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This source code is licensed under the BSD-style license found in the
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
*
|
||||
* @providesModule AppRegistry
|
||||
* @flow
|
||||
*/
|
||||
|
||||
import { Component } from 'react';
|
||||
import invariant from 'fbjs/lib/invariant';
|
||||
import { unmountComponentAtNode } from 'react-dom';
|
||||
import renderApplication, { getApplication } from './renderApplication';
|
||||
@@ -14,9 +17,9 @@ import renderApplication, { getApplication } from './renderApplication';
|
||||
const emptyObject = {};
|
||||
const runnables = {};
|
||||
|
||||
type ComponentProvider = () => Component<any, any, any>;
|
||||
export type ComponentProvider = () => ReactClass<any>;
|
||||
|
||||
type AppConfig = {
|
||||
export type AppConfig = {
|
||||
appKey: string,
|
||||
component?: ComponentProvider,
|
||||
run?: Function
|
||||
@@ -25,7 +28,7 @@ type AppConfig = {
|
||||
/**
|
||||
* `AppRegistry` is the JS entry point to running all React Native apps.
|
||||
*/
|
||||
class AppRegistry {
|
||||
export default class AppRegistry {
|
||||
static getAppKeys(): Array<string> {
|
||||
return Object.keys(runnables);
|
||||
}
|
||||
@@ -91,5 +94,3 @@ class AppRegistry {
|
||||
unmountComponentAtNode(rootTag);
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = AppRegistry;
|
||||
|
||||
@@ -3,30 +3,41 @@
|
||||
* Copyright (c) 2015-present, Facebook, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This source code is licensed under the BSD-style license found in the
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
*
|
||||
* @flow
|
||||
*/
|
||||
|
||||
import invariant from 'fbjs/lib/invariant';
|
||||
import { render } from 'react-dom';
|
||||
import ReactNativeApp from './ReactNativeApp';
|
||||
import AppContainer from './AppContainer';
|
||||
import StyleSheet from '../../apis/StyleSheet';
|
||||
import React, { Component } from 'react';
|
||||
import React from 'react';
|
||||
|
||||
export default function renderApplication(
|
||||
RootComponent: Component,
|
||||
RootComponent: ReactClass<Object>,
|
||||
initialProps: Object,
|
||||
rootTag: any
|
||||
) {
|
||||
invariant(rootTag, 'Expect to have a valid rootTag, instead got ', rootTag);
|
||||
|
||||
const component = (
|
||||
<ReactNativeApp initialProps={initialProps} rootComponent={RootComponent} rootTag={rootTag} />
|
||||
render(
|
||||
<AppContainer rootTag={rootTag}>
|
||||
<RootComponent {...initialProps} />
|
||||
</AppContainer>,
|
||||
rootTag
|
||||
);
|
||||
render(component, rootTag);
|
||||
}
|
||||
|
||||
export function getApplication(RootComponent: Component, initialProps: Object): Object {
|
||||
const element = <ReactNativeApp initialProps={initialProps} rootComponent={RootComponent} />;
|
||||
const stylesheet = StyleSheet.renderToString();
|
||||
return { element, stylesheet };
|
||||
export function getApplication(RootComponent: ReactClass<Object>, initialProps: Object): Object {
|
||||
const element = (
|
||||
<AppContainer rootTag={{}}>
|
||||
<RootComponent {...initialProps} />
|
||||
</AppContainer>
|
||||
);
|
||||
const stylesheets = StyleSheet.getStyleSheets().map(sheet =>
|
||||
<style id={sheet.id}>{sheet.textContent}</style>
|
||||
);
|
||||
return { element, stylesheets };
|
||||
}
|
||||
|
||||
@@ -1,4 +1,12 @@
|
||||
/**
|
||||
* Copyright (c) 2016-present, Nicolas Gallagher.
|
||||
* Copyright (c) 2015-present, Facebook, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This source code is licensed under the BSD-style license found in the
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
*
|
||||
* @providesModule AppRegistry
|
||||
* @flow
|
||||
*/
|
||||
|
||||
@@ -16,7 +24,7 @@ const AppStates = {
|
||||
|
||||
const listeners = [];
|
||||
|
||||
class AppState {
|
||||
export default class AppState {
|
||||
static isAvailable = ExecutionEnvironment.canUseDOM && document.visibilityState;
|
||||
|
||||
static get currentState() {
|
||||
@@ -65,5 +73,3 @@ class AppState {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = AppState;
|
||||
|
||||
@@ -3,8 +3,13 @@
|
||||
* Copyright (c) 2015-present, Facebook, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This source code is licensed under the BSD-style license found in the
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
*
|
||||
* @providesModule AppRegistry
|
||||
* @flow
|
||||
*/
|
||||
|
||||
import merge from 'deep-assign';
|
||||
|
||||
const mergeLocalStorageItem = (key, value) => {
|
||||
@@ -46,7 +51,7 @@ const createPromiseAll = (promises, callback, processResult) => {
|
||||
);
|
||||
};
|
||||
|
||||
class AsyncStorage {
|
||||
export default class AsyncStorage {
|
||||
/**
|
||||
* Erases *all* AsyncStorage for the domain.
|
||||
*/
|
||||
@@ -147,5 +152,3 @@ class AsyncStorage {
|
||||
return createPromiseAll(promises, callback);
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = AsyncStorage;
|
||||
|
||||
@@ -1,13 +1,12 @@
|
||||
/**
|
||||
* Copyright (c) 2016-present, Nicolas Gallagher.
|
||||
* Copyright (c) 2015-present, Facebook, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This source code is licensed under the BSD-style license found in the
|
||||
* LICENSE file in the root directory of this source tree. An additional grant
|
||||
* of patent rights can be found in the PATENTS file in the same directory.
|
||||
*
|
||||
* web stub for BackAndroid.android.js
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
*
|
||||
* @providesModule BackHandler
|
||||
* @flow
|
||||
*/
|
||||
|
||||
@@ -23,4 +22,4 @@ const BackAndroid = {
|
||||
removeEventListener: emptyFunction
|
||||
};
|
||||
|
||||
module.exports = BackAndroid;
|
||||
export default BackAndroid;
|
||||
|
||||
@@ -1,10 +1,17 @@
|
||||
/* global window */
|
||||
/**
|
||||
* Copyright (c) 2016-present, Nicolas Gallagher.
|
||||
* Copyright (c) 2015-present, Facebook, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This source code is licensed under the BSD-style license found in the
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
*
|
||||
* @providesModule Clipboard
|
||||
* @flow
|
||||
*/
|
||||
|
||||
class Clipboard {
|
||||
static isSupported() {
|
||||
export default class Clipboard {
|
||||
static isAvailable() {
|
||||
return (
|
||||
typeof document.queryCommandSupported === 'function' && document.queryCommandSupported('copy')
|
||||
);
|
||||
@@ -16,33 +23,34 @@ class Clipboard {
|
||||
|
||||
static setString(text) {
|
||||
let success = false;
|
||||
const body = document.body;
|
||||
|
||||
// add the text to a hidden node
|
||||
const node = document.createElement('span');
|
||||
node.textContent = text;
|
||||
node.style.position = 'absolute';
|
||||
node.style.opacity = '0';
|
||||
document.body.appendChild(node);
|
||||
if (body) {
|
||||
// add the text to a hidden node
|
||||
const node = document.createElement('span');
|
||||
node.textContent = text;
|
||||
node.style.position = 'absolute';
|
||||
node.style.opacity = '0';
|
||||
body.appendChild(node);
|
||||
|
||||
// select the text
|
||||
const selection = window.getSelection();
|
||||
selection.removeAllRanges();
|
||||
const range = document.createRange();
|
||||
range.selectNodeContents(node);
|
||||
selection.addRange(range);
|
||||
// select the text
|
||||
const selection = window.getSelection();
|
||||
selection.removeAllRanges();
|
||||
const range = document.createRange();
|
||||
range.selectNodeContents(node);
|
||||
selection.addRange(range);
|
||||
|
||||
// attempt to copy
|
||||
try {
|
||||
document.execCommand('copy');
|
||||
success = true;
|
||||
} catch (e) {}
|
||||
// attempt to copy
|
||||
try {
|
||||
document.execCommand('copy');
|
||||
success = true;
|
||||
} catch (e) {}
|
||||
|
||||
// remove selection and node
|
||||
selection.removeAllRanges();
|
||||
document.body.removeChild(node);
|
||||
// remove selection and node
|
||||
selection.removeAllRanges();
|
||||
body.removeChild(node);
|
||||
}
|
||||
|
||||
return success;
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = Clipboard;
|
||||
|
||||
@@ -3,6 +3,10 @@
|
||||
* Copyright (c) 2015-present, Facebook, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This source code is licensed under the BSD-style license found in the
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
*
|
||||
* @providesModule Dimensions
|
||||
* @flow
|
||||
*/
|
||||
|
||||
@@ -24,7 +28,7 @@ const win = canUseDOM
|
||||
|
||||
const dimensions = {};
|
||||
|
||||
class Dimensions {
|
||||
export default class Dimensions {
|
||||
static get(dimension: string): Object {
|
||||
invariant(dimensions[dimension], `No dimension set for key ${dimension}`);
|
||||
return dimensions[dimension];
|
||||
@@ -52,5 +56,3 @@ Dimensions.set();
|
||||
if (canUseDOM) {
|
||||
window.addEventListener('resize', debounce(Dimensions.set, 16), false);
|
||||
}
|
||||
|
||||
module.exports = Dimensions;
|
||||
|
||||
@@ -1,4 +1,12 @@
|
||||
/**
|
||||
* Copyright (c) 2016-present, Nicolas Gallagher.
|
||||
* Copyright (c) 2015-present, Facebook, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This source code is licensed under the BSD-style license found in the
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
*
|
||||
* @providesModule I18nManager
|
||||
* @flow
|
||||
*/
|
||||
|
||||
@@ -24,7 +32,9 @@ const isRTL = () => {
|
||||
|
||||
const onChange = () => {
|
||||
if (ExecutionEnvironment.canUseDOM) {
|
||||
document.documentElement.setAttribute('dir', isRTL() ? 'rtl' : 'ltr');
|
||||
if (document.documentElement && document.documentElement.setAttribute) {
|
||||
document.documentElement.setAttribute('dir', isRTL() ? 'rtl' : 'ltr');
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
@@ -46,4 +56,4 @@ const I18nManager: I18nManagerStatus = {
|
||||
}
|
||||
};
|
||||
|
||||
module.exports = I18nManager;
|
||||
export default I18nManager;
|
||||
|
||||
@@ -1,7 +1,12 @@
|
||||
/**
|
||||
* Copyright (c) 2016-present, Nicolas Gallagher.
|
||||
* Copyright (c) 2015-present, Facebook, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This source code is licensed under the BSD-style license found in the
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
*
|
||||
* @providesModule InteractionManager
|
||||
* @flow
|
||||
*/
|
||||
|
||||
@@ -38,4 +43,4 @@ const InteractionManager = {
|
||||
addListener: () => {}
|
||||
};
|
||||
|
||||
module.exports = InteractionManager;
|
||||
export default InteractionManager;
|
||||
|
||||
@@ -1,7 +1,19 @@
|
||||
/**
|
||||
* Copyright (c) 2016-present, Nicolas Gallagher.
|
||||
* Copyright (c) 2015-present, Facebook, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This source code is licensed under the BSD-style license found in the
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
*
|
||||
* @providesModule Linking
|
||||
* @flow
|
||||
*/
|
||||
|
||||
import { canUseDOM } from 'fbjs/lib/ExecutionEnvironment';
|
||||
|
||||
const initialURL = canUseDOM ? window.location.href : '';
|
||||
|
||||
const Linking = {
|
||||
addEventListener() {},
|
||||
removeEventListener() {},
|
||||
@@ -9,7 +21,7 @@ const Linking = {
|
||||
return Promise.resolve(true);
|
||||
},
|
||||
getInitialURL() {
|
||||
return Promise.resolve('');
|
||||
return Promise.resolve(initialURL);
|
||||
},
|
||||
openURL(url: string) {
|
||||
try {
|
||||
@@ -33,19 +45,25 @@ const Linking = {
|
||||
*/
|
||||
const iframeOpen = url => {
|
||||
const noOpener = url.indexOf('mailto:') !== 0;
|
||||
const iframe = document.createElement('iframe');
|
||||
iframe.style.display = 'none';
|
||||
document.body.appendChild(iframe);
|
||||
const body = document.body;
|
||||
if (body) {
|
||||
const iframe = document.createElement('iframe');
|
||||
iframe.style.display = 'none';
|
||||
body.appendChild(iframe);
|
||||
|
||||
const iframeDoc = iframe.contentDocument || iframe.contentWindow.document;
|
||||
const script = iframeDoc.createElement('script');
|
||||
const openerExpression = noOpener ? 'child.opener = null' : '';
|
||||
script.text = `
|
||||
window.parent = null; window.top = null; window.frameElement = null;
|
||||
var child = window.open("${url}"); ${openerExpression};
|
||||
`;
|
||||
iframeDoc.body.appendChild(script);
|
||||
document.body.removeChild(iframe);
|
||||
const iframeDoc = iframe.contentDocument || iframe.contentWindow.document;
|
||||
const iframeBody = iframeDoc.body;
|
||||
if (iframeBody) {
|
||||
const script = iframeDoc.createElement('script');
|
||||
const openerExpression = noOpener ? 'child.opener = null' : '';
|
||||
script.text = `
|
||||
window.parent = null; window.top = null; window.frameElement = null;
|
||||
var child = window.open("${url}"); ${openerExpression};
|
||||
`;
|
||||
iframeBody.appendChild(script);
|
||||
}
|
||||
body.removeChild(iframe);
|
||||
}
|
||||
};
|
||||
|
||||
module.exports = Linking;
|
||||
export default Linking;
|
||||
|
||||
@@ -3,6 +3,10 @@
|
||||
* Copyright (c) 2015-present, Facebook, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This source code is licensed under the BSD-style license found in the
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
*
|
||||
* @providesModule NetInfo
|
||||
* @flow
|
||||
*/
|
||||
|
||||
@@ -111,4 +115,4 @@ const NetInfo = {
|
||||
}
|
||||
};
|
||||
|
||||
module.exports = NetInfo;
|
||||
export default NetInfo;
|
||||
|
||||
@@ -1,21 +1,27 @@
|
||||
/* eslint-disable */
|
||||
/**
|
||||
* Copyright (c) 2016-present, Nicolas Gallagher.
|
||||
* Copyright (c) 2015-present, Facebook, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This source code is licensed under the BSD-style license found in the
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
*
|
||||
* @providesModule PanResponder
|
||||
* @noflow
|
||||
*/
|
||||
|
||||
'use strict';
|
||||
import TouchHistoryMath from '../../vendor/TouchHistoryMath';
|
||||
|
||||
var TouchHistoryMath = require('../../vendor/TouchHistoryMath');
|
||||
|
||||
var currentCentroidXOfTouchesChangedAfter = TouchHistoryMath.currentCentroidXOfTouchesChangedAfter;
|
||||
var currentCentroidYOfTouchesChangedAfter = TouchHistoryMath.currentCentroidYOfTouchesChangedAfter;
|
||||
var previousCentroidXOfTouchesChangedAfter =
|
||||
const currentCentroidXOfTouchesChangedAfter =
|
||||
TouchHistoryMath.currentCentroidXOfTouchesChangedAfter;
|
||||
const currentCentroidYOfTouchesChangedAfter =
|
||||
TouchHistoryMath.currentCentroidYOfTouchesChangedAfter;
|
||||
const previousCentroidXOfTouchesChangedAfter =
|
||||
TouchHistoryMath.previousCentroidXOfTouchesChangedAfter;
|
||||
var previousCentroidYOfTouchesChangedAfter =
|
||||
const previousCentroidYOfTouchesChangedAfter =
|
||||
TouchHistoryMath.previousCentroidYOfTouchesChangedAfter;
|
||||
var currentCentroidX = TouchHistoryMath.currentCentroidX;
|
||||
var currentCentroidY = TouchHistoryMath.currentCentroidY;
|
||||
const currentCentroidX = TouchHistoryMath.currentCentroidX;
|
||||
const currentCentroidY = TouchHistoryMath.currentCentroidY;
|
||||
|
||||
/**
|
||||
* `PanResponder` reconciles several touches into a single gesture. It makes
|
||||
@@ -112,7 +118,7 @@ var currentCentroidY = TouchHistoryMath.currentCentroidY;
|
||||
* [PanResponder example in UIExplorer](https://github.com/facebook/react-native/blob/master/Examples/UIExplorer/PanResponderExample.js)
|
||||
*/
|
||||
|
||||
var PanResponder = {
|
||||
const PanResponder = {
|
||||
/**
|
||||
*
|
||||
* A graphical explanation of the touch data flow:
|
||||
@@ -224,16 +230,16 @@ var PanResponder = {
|
||||
touchHistory,
|
||||
gestureState._accountsForMovesUpTo
|
||||
);
|
||||
var movedAfter = gestureState._accountsForMovesUpTo;
|
||||
var prevX = previousCentroidXOfTouchesChangedAfter(touchHistory, movedAfter);
|
||||
var x = currentCentroidXOfTouchesChangedAfter(touchHistory, movedAfter);
|
||||
var prevY = previousCentroidYOfTouchesChangedAfter(touchHistory, movedAfter);
|
||||
var y = currentCentroidYOfTouchesChangedAfter(touchHistory, movedAfter);
|
||||
var nextDX = gestureState.dx + (x - prevX);
|
||||
var nextDY = gestureState.dy + (y - prevY);
|
||||
const movedAfter = gestureState._accountsForMovesUpTo;
|
||||
const prevX = previousCentroidXOfTouchesChangedAfter(touchHistory, movedAfter);
|
||||
const x = currentCentroidXOfTouchesChangedAfter(touchHistory, movedAfter);
|
||||
const prevY = previousCentroidYOfTouchesChangedAfter(touchHistory, movedAfter);
|
||||
const y = currentCentroidYOfTouchesChangedAfter(touchHistory, movedAfter);
|
||||
const nextDX = gestureState.dx + (x - prevX);
|
||||
const nextDY = gestureState.dy + (y - prevY);
|
||||
|
||||
// TODO: This must be filtered intelligently.
|
||||
var dt = touchHistory.mostRecentTimeStamp - gestureState._accountsForMovesUpTo;
|
||||
const dt = touchHistory.mostRecentTimeStamp - gestureState._accountsForMovesUpTo;
|
||||
gestureState.vx = (nextDX - gestureState.dx) / dt;
|
||||
gestureState.vy = (nextDY - gestureState.dy) / dt;
|
||||
|
||||
@@ -275,12 +281,12 @@ var PanResponder = {
|
||||
* are the responder.
|
||||
*/
|
||||
create: function(config) {
|
||||
var gestureState = {
|
||||
const gestureState = {
|
||||
// Useful for debugging
|
||||
stateID: Math.random()
|
||||
};
|
||||
PanResponder._initializeGestureState(gestureState);
|
||||
var panHandlers = {
|
||||
const panHandlers = {
|
||||
onStartShouldSetResponder: function(e) {
|
||||
return config.onStartShouldSetPanResponder === undefined
|
||||
? false
|
||||
@@ -311,7 +317,7 @@ var PanResponder = {
|
||||
},
|
||||
|
||||
onMoveShouldSetResponderCapture: function(e) {
|
||||
var touchHistory = e.touchHistory;
|
||||
const touchHistory = e.touchHistory;
|
||||
// Responder system incorrectly dispatches should* to current responder
|
||||
// Filter out any touch moves past the first one - we would have
|
||||
// already processed multi-touch geometry during the first event.
|
||||
@@ -346,13 +352,13 @@ var PanResponder = {
|
||||
},
|
||||
|
||||
onResponderStart: function(e) {
|
||||
var touchHistory = e.touchHistory;
|
||||
const touchHistory = e.touchHistory;
|
||||
gestureState.numberActiveTouches = touchHistory.numberActiveTouches;
|
||||
config.onPanResponderStart && config.onPanResponderStart(e, gestureState);
|
||||
},
|
||||
|
||||
onResponderMove: function(e) {
|
||||
var touchHistory = e.touchHistory;
|
||||
const touchHistory = e.touchHistory;
|
||||
// Guard against the dispatch of two touch moves when there are two
|
||||
// simultaneously changed touches.
|
||||
if (gestureState._accountsForMovesUpTo === touchHistory.mostRecentTimeStamp) {
|
||||
@@ -365,7 +371,7 @@ var PanResponder = {
|
||||
},
|
||||
|
||||
onResponderEnd: function(e) {
|
||||
var touchHistory = e.touchHistory;
|
||||
const touchHistory = e.touchHistory;
|
||||
gestureState.numberActiveTouches = touchHistory.numberActiveTouches;
|
||||
config.onPanResponderEnd && config.onPanResponderEnd(e, gestureState);
|
||||
},
|
||||
@@ -385,4 +391,4 @@ var PanResponder = {
|
||||
}
|
||||
};
|
||||
|
||||
module.exports = PanResponder;
|
||||
export default PanResponder;
|
||||
|
||||
@@ -3,6 +3,10 @@
|
||||
* Copyright (c) 2015-present, Facebook, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This source code is licensed under the BSD-style license found in the
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
*
|
||||
* @providesModule PixelRatio
|
||||
* @flow
|
||||
*/
|
||||
|
||||
@@ -11,7 +15,7 @@ import Dimensions from '../Dimensions';
|
||||
/**
|
||||
* PixelRatio gives access to the device pixel density.
|
||||
*/
|
||||
class PixelRatio {
|
||||
export default class PixelRatio {
|
||||
/**
|
||||
* Returns the device pixel density.
|
||||
*/
|
||||
@@ -45,5 +49,3 @@ class PixelRatio {
|
||||
return Math.round(layoutSize * ratio) / ratio;
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = PixelRatio;
|
||||
|
||||
@@ -1,4 +1,12 @@
|
||||
/**
|
||||
* Copyright (c) 2016-present, Nicolas Gallagher.
|
||||
* Copyright (c) 2015-present, Facebook, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This source code is licensed under the BSD-style license found in the
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
*
|
||||
* @providesModule Platform
|
||||
* @flow
|
||||
*/
|
||||
|
||||
@@ -7,4 +15,4 @@ const Platform = {
|
||||
select: (obj: Object) => ('web' in obj ? obj.web : obj.default)
|
||||
};
|
||||
|
||||
module.exports = Platform;
|
||||
export default Platform;
|
||||
|
||||
@@ -1,7 +1,16 @@
|
||||
/**
|
||||
* Copyright (c) 2016-present, Nicolas Gallagher.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This source code is licensed under the BSD-style license found in the
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
*
|
||||
* @noflow
|
||||
*/
|
||||
|
||||
import { canUseDOM } from 'fbjs/lib/ExecutionEnvironment';
|
||||
import generateCss from './generateCss';
|
||||
import hash from './hash';
|
||||
import requestAnimationFrame from 'fbjs/lib/requestAnimationFrame';
|
||||
import hash from '../../vendor/hash';
|
||||
import staticCss from './staticCss';
|
||||
|
||||
const emptyObject = {};
|
||||
@@ -25,15 +34,19 @@ const pointerEvents = {
|
||||
none: createClassName('pointerEvents', 'none')
|
||||
};
|
||||
|
||||
// See #513
|
||||
const pointerEventsCss =
|
||||
`.${pointerEvents.auto}{pointer-events:auto;}\n` +
|
||||
`.${pointerEvents.boxNone}{pointer-events:none;}\n` +
|
||||
`.${pointerEvents.boxNone} *{pointer-events:auto;}\n` +
|
||||
`.${pointerEvents.boxOnly}{pointer-events:auto;}\n` +
|
||||
`.${pointerEvents.boxOnly} *{pointer-events:none;}\n` +
|
||||
`.${pointerEvents.none}{pointer-events:none;}`;
|
||||
`.${pointerEvents.auto}{pointer-events:auto !important;}\n` +
|
||||
`.${pointerEvents.boxOnly}{pointer-events:auto !important;}\n` +
|
||||
`.${pointerEvents.none}{pointer-events:none !important;}\n` +
|
||||
`.${pointerEvents.boxNone}{pointer-events:none !important;}\n` +
|
||||
`.${pointerEvents.boxNone} > *{pointer-events:auto;}\n` +
|
||||
`.${pointerEvents.boxOnly} > *{pointer-events:none;}`;
|
||||
|
||||
export default class StyleManager {
|
||||
cache = null;
|
||||
mainSheet = null;
|
||||
|
||||
class StyleManager {
|
||||
constructor() {
|
||||
// custom pointer event values are implemented using descendent selectors,
|
||||
// so we manually create the CSS and pre-register the declarations
|
||||
@@ -84,6 +97,15 @@ class StyleManager {
|
||||
}
|
||||
|
||||
getStyleSheetHtml() {
|
||||
const styleSheets = this.getStyleSheets();
|
||||
return styleSheets
|
||||
.map(sheet => {
|
||||
return `<style id="${sheet.id}">\n${sheet.textContent}\n</style>`;
|
||||
})
|
||||
.join('\n');
|
||||
}
|
||||
|
||||
getStyleSheets() {
|
||||
const cache = this.cache.byProp;
|
||||
|
||||
const mainSheetTextContext = Object.keys(cache)
|
||||
@@ -98,9 +120,16 @@ class StyleManager {
|
||||
}, [])
|
||||
.join('\n');
|
||||
|
||||
const staticSheet = `<style id="react-native-stylesheet-static">\n${staticCss}\n${pointerEventsCss}\n</style>`;
|
||||
const mainSheet = `<style id="${STYLE_ELEMENT_ID}">\n${mainSheetTextContext}\n</style>`;
|
||||
return `${staticSheet}\n${mainSheet}`;
|
||||
return [
|
||||
{
|
||||
id: 'react-native-stylesheet-static',
|
||||
textContent: `${staticCss}\n${pointerEventsCss}`
|
||||
},
|
||||
{
|
||||
id: STYLE_ELEMENT_ID,
|
||||
textContent: `${mainSheetTextContext}`
|
||||
}
|
||||
];
|
||||
}
|
||||
|
||||
setDeclaration(prop, value) {
|
||||
@@ -109,14 +138,12 @@ class StyleManager {
|
||||
className = createClassName(prop, value);
|
||||
this._addToCache(className, prop, value);
|
||||
if (canUseDOM) {
|
||||
requestAnimationFrame(() => {
|
||||
const sheet = this.mainSheet.sheet;
|
||||
// avoid injecting if the rule already exists (e.g., server rendered, hot reload)
|
||||
if (this.mainSheet.textContent.indexOf(className) === -1) {
|
||||
const rule = createCssRule(className, prop, value);
|
||||
sheet.insertRule(rule, sheet.cssRules.length);
|
||||
}
|
||||
});
|
||||
const sheet = this.mainSheet.sheet;
|
||||
// avoid injecting if the rule already exists (e.g., server rendered, hot reload)
|
||||
if (this.mainSheet.textContent.indexOf(className) === -1) {
|
||||
const rule = createCssRule(className, prop, value);
|
||||
sheet.insertRule(rule, sheet.cssRules.length);
|
||||
}
|
||||
}
|
||||
}
|
||||
return className;
|
||||
@@ -131,5 +158,3 @@ class StyleManager {
|
||||
cache.byClassName[className] = { prop, value };
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = StyleManager;
|
||||
|
||||
@@ -1,7 +1,16 @@
|
||||
/**
|
||||
* Copyright (c) 2016-present, Nicolas Gallagher.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This source code is licensed under the BSD-style license found in the
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
*
|
||||
* WARNING: changes to this file in particular can cause significant changes to
|
||||
* the results of render performance benchmarks.
|
||||
*
|
||||
* @noflow
|
||||
*/
|
||||
|
||||
import createReactDOMStyle from './createReactDOMStyle';
|
||||
import flattenArray from '../../modules/flattenArray';
|
||||
import flattenStyle from './flattenStyle';
|
||||
@@ -20,14 +29,12 @@ const createCacheKey = id => {
|
||||
|
||||
const classListToString = list => list.join(' ').trim();
|
||||
|
||||
class StyleRegistry {
|
||||
constructor() {
|
||||
this.cache = { ltr: {}, rtl: {} };
|
||||
this.styleManager = new StyleManager();
|
||||
}
|
||||
export default class StyleRegistry {
|
||||
cache = { ltr: {}, rtl: {} };
|
||||
styleManager = new StyleManager();
|
||||
|
||||
getStyleSheetHtml() {
|
||||
return this.styleManager.getStyleSheetHtml();
|
||||
getStyleSheets() {
|
||||
return this.styleManager.getStyleSheets();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -189,5 +196,3 @@ class StyleRegistry {
|
||||
return this._resolveStyle(style, options);
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = StyleRegistry;
|
||||
|
||||
@@ -1,62 +1,68 @@
|
||||
/* eslint-disable */
|
||||
/**
|
||||
* Copyright (c) 2016-present, Nicolas Gallagher.
|
||||
* Copyright (c) 2015-present, Facebook, Inc.
|
||||
* All rights reserved.
|
||||
|
||||
*
|
||||
* This source code is licensed under the BSD-style license found in the
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
*
|
||||
* @providesModule StyleSheetValidation
|
||||
* @flow
|
||||
*/
|
||||
|
||||
import ImageStylePropTypes from '../../components/Image/ImageStylePropTypes';
|
||||
import ReactPropTypeLocationNames from '../../vendor/ReactPropTypeLocationNames';
|
||||
import ReactPropTypesSecret from '../../vendor/ReactPropTypesSecret';
|
||||
import TextInputStylePropTypes from '../../components/TextInput/TextInputStylePropTypes';
|
||||
import TextStylePropTypes from '../../components/Text/TextStylePropTypes';
|
||||
import ViewStylePropTypes from '../../components/View/ViewStylePropTypes';
|
||||
import warning from 'fbjs/lib/warning';
|
||||
import { oneOf, string } from 'prop-types';
|
||||
|
||||
class StyleSheetValidation {
|
||||
// Hardcoded because this is a legit case but we don't want to load it from
|
||||
// a private API. We might likely want to unify style sheet creation with how it
|
||||
// is done in the DOM so this might move into React. I know what I'm doing so
|
||||
// plz don't fire me.
|
||||
const ReactPropTypesSecret = 'SECRET_DO_NOT_PASS_THIS_OR_YOU_WILL_BE_FIRED';
|
||||
|
||||
export default class StyleSheetValidation {
|
||||
static validateStyleProp(prop, style, caller) {
|
||||
if (process.env.NODE_ENV !== 'production') {
|
||||
if (allStylePropTypes[prop] === undefined) {
|
||||
var message1 = '"' + prop + '" is not a valid style property.';
|
||||
var message2 =
|
||||
const message1 = '"' + prop + '" is not a valid style property.';
|
||||
const message2 =
|
||||
'\nValid style props: ' +
|
||||
JSON.stringify(Object.keys(allStylePropTypes).sort(), null, ' ');
|
||||
styleError(message1, style, caller, message2);
|
||||
} else {
|
||||
var error = allStylePropTypes[prop](
|
||||
style,
|
||||
prop,
|
||||
caller,
|
||||
ReactPropTypeLocationNames.prop,
|
||||
null,
|
||||
ReactPropTypesSecret
|
||||
);
|
||||
if (error) {
|
||||
styleError(error.message, style, caller);
|
||||
}
|
||||
}
|
||||
const error = allStylePropTypes[prop](
|
||||
style,
|
||||
prop,
|
||||
caller,
|
||||
'prop',
|
||||
null,
|
||||
ReactPropTypesSecret
|
||||
);
|
||||
if (error) {
|
||||
styleError(error.message, style, caller);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static validateStyle(name, styles) {
|
||||
if (process.env.NODE_ENV !== 'production') {
|
||||
for (var prop in styles[name]) {
|
||||
for (const prop in styles[name]) {
|
||||
StyleSheetValidation.validateStyleProp(prop, styles[name], 'StyleSheet ' + name);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static addValidStylePropTypes(stylePropTypes) {
|
||||
for (var key in stylePropTypes) {
|
||||
for (const key in stylePropTypes) {
|
||||
allStylePropTypes[key] = stylePropTypes[key];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var styleError = function(message1, style, caller?, message2?) {
|
||||
const styleError = function(message1, style, caller?, message2?) {
|
||||
warning(
|
||||
false,
|
||||
message1 +
|
||||
@@ -68,7 +74,7 @@ var styleError = function(message1, style, caller?, message2?) {
|
||||
);
|
||||
};
|
||||
|
||||
var allStylePropTypes = {};
|
||||
const allStylePropTypes = {};
|
||||
|
||||
StyleSheetValidation.addValidStylePropTypes(ImageStylePropTypes);
|
||||
StyleSheetValidation.addValidStylePropTypes(TextStylePropTypes);
|
||||
@@ -83,5 +89,3 @@ StyleSheetValidation.addValidStylePropTypes({
|
||||
listStyle: string,
|
||||
pointerEvents: string
|
||||
});
|
||||
|
||||
module.exports = StyleSheetValidation;
|
||||
|
||||
@@ -10,12 +10,12 @@ button::-moz-focus-inner,input::-moz-focus-inner{border:0;padding:0;}
|
||||
input::-webkit-inner-spin-button,input::-webkit-outer-spin-button,input::-webkit-search-cancel-button,input::-webkit-search-decoration,input::-webkit-search-results-button,input::-webkit-search-results-decoration{display:none;}
|
||||
@keyframes rn-ActivityIndicator-animation{0%{-webkit-transform:rotate(0deg);transform:rotate(0deg);}100%{-webkit-transform:rotate(360deg);transform:rotate(360deg);}}
|
||||
@keyframes rn-ProgressBar-animation{0%{-webkit-transform:translateX(-100%);transform:translateX(-100%);}100%{-webkit-transform:translateX(400%);transform:translateX(400%);}}
|
||||
.rn-pointerEvents-105ug2t{pointer-events:auto;}
|
||||
.rn-pointerEvents-12vffkv{pointer-events:none;}
|
||||
.rn-pointerEvents-12vffkv *{pointer-events:auto;}
|
||||
.rn-pointerEvents-ah5dr5{pointer-events:auto;}
|
||||
.rn-pointerEvents-ah5dr5 *{pointer-events:none;}
|
||||
.rn-pointerEvents-633pao{pointer-events:none;}
|
||||
.rn-pointerEvents-105ug2t{pointer-events:auto !important;}
|
||||
.rn-pointerEvents-ah5dr5{pointer-events:auto !important;}
|
||||
.rn-pointerEvents-633pao{pointer-events:none !important;}
|
||||
.rn-pointerEvents-12vffkv{pointer-events:none !important;}
|
||||
.rn-pointerEvents-12vffkv > *{pointer-events:auto;}
|
||||
.rn-pointerEvents-ah5dr5 > *{pointer-events:none;}
|
||||
</style>
|
||||
<style id=\\"react-native-stylesheet\\">
|
||||
|
||||
@@ -30,12 +30,12 @@ button::-moz-focus-inner,input::-moz-focus-inner{border:0;padding:0;}
|
||||
input::-webkit-inner-spin-button,input::-webkit-outer-spin-button,input::-webkit-search-cancel-button,input::-webkit-search-decoration,input::-webkit-search-results-button,input::-webkit-search-results-decoration{display:none;}
|
||||
@keyframes rn-ActivityIndicator-animation{0%{-webkit-transform:rotate(0deg);transform:rotate(0deg);}100%{-webkit-transform:rotate(360deg);transform:rotate(360deg);}}
|
||||
@keyframes rn-ProgressBar-animation{0%{-webkit-transform:translateX(-100%);transform:translateX(-100%);}100%{-webkit-transform:translateX(400%);transform:translateX(400%);}}
|
||||
.rn-pointerEvents-105ug2t{pointer-events:auto;}
|
||||
.rn-pointerEvents-12vffkv{pointer-events:none;}
|
||||
.rn-pointerEvents-12vffkv *{pointer-events:auto;}
|
||||
.rn-pointerEvents-ah5dr5{pointer-events:auto;}
|
||||
.rn-pointerEvents-ah5dr5 *{pointer-events:none;}
|
||||
.rn-pointerEvents-633pao{pointer-events:none;}
|
||||
.rn-pointerEvents-105ug2t{pointer-events:auto !important;}
|
||||
.rn-pointerEvents-ah5dr5{pointer-events:auto !important;}
|
||||
.rn-pointerEvents-633pao{pointer-events:none !important;}
|
||||
.rn-pointerEvents-12vffkv{pointer-events:none !important;}
|
||||
.rn-pointerEvents-12vffkv > *{pointer-events:auto;}
|
||||
.rn-pointerEvents-ah5dr5 > *{pointer-events:none;}
|
||||
</style>
|
||||
<style id=\\"react-native-stylesheet\\">
|
||||
.rn-width-b8lwoo{width:100px}
|
||||
|
||||
@@ -1,25 +1,29 @@
|
||||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||
|
||||
exports[`apis/StyleSheet renderToString 1`] = `
|
||||
"<style id=\\"react-native-stylesheet-static\\">
|
||||
html{font-family:sans-serif;-ms-text-size-adjust:100%;-webkit-text-size-adjust:100%;-webkit-tap-highlight-color:rgba(0,0,0,0);}
|
||||
exports[`apis/StyleSheet getStyleSheets 1`] = `
|
||||
Array [
|
||||
Object {
|
||||
"id": "react-native-stylesheet-static",
|
||||
"textContent": "html{font-family:sans-serif;-ms-text-size-adjust:100%;-webkit-text-size-adjust:100%;-webkit-tap-highlight-color:rgba(0,0,0,0);}
|
||||
body{margin:0;}
|
||||
button::-moz-focus-inner,input::-moz-focus-inner{border:0;padding:0;}
|
||||
input::-webkit-inner-spin-button,input::-webkit-outer-spin-button,input::-webkit-search-cancel-button,input::-webkit-search-decoration,input::-webkit-search-results-button,input::-webkit-search-results-decoration{display:none;}
|
||||
@keyframes rn-ActivityIndicator-animation{0%{-webkit-transform:rotate(0deg);transform:rotate(0deg);}100%{-webkit-transform:rotate(360deg);transform:rotate(360deg);}}
|
||||
@keyframes rn-ProgressBar-animation{0%{-webkit-transform:translateX(-100%);transform:translateX(-100%);}100%{-webkit-transform:translateX(400%);transform:translateX(400%);}}
|
||||
.rn-pointerEvents-105ug2t{pointer-events:auto;}
|
||||
.rn-pointerEvents-12vffkv{pointer-events:none;}
|
||||
.rn-pointerEvents-12vffkv *{pointer-events:auto;}
|
||||
.rn-pointerEvents-ah5dr5{pointer-events:auto;}
|
||||
.rn-pointerEvents-ah5dr5 *{pointer-events:none;}
|
||||
.rn-pointerEvents-633pao{pointer-events:none;}
|
||||
</style>
|
||||
<style id=\\"react-native-stylesheet\\">
|
||||
.rn-bottom-1p0dtai{bottom:0px}
|
||||
.rn-pointerEvents-105ug2t{pointer-events:auto !important;}
|
||||
.rn-pointerEvents-ah5dr5{pointer-events:auto !important;}
|
||||
.rn-pointerEvents-633pao{pointer-events:none !important;}
|
||||
.rn-pointerEvents-12vffkv{pointer-events:none !important;}
|
||||
.rn-pointerEvents-12vffkv > *{pointer-events:auto;}
|
||||
.rn-pointerEvents-ah5dr5 > *{pointer-events:none;}",
|
||||
},
|
||||
Object {
|
||||
"id": "react-native-stylesheet",
|
||||
"textContent": ".rn-bottom-1p0dtai{bottom:0px}
|
||||
.rn-left-1d2f490{left:0px}
|
||||
.rn-position-u8s1d{position:absolute}
|
||||
.rn-right-zchlnj{right:0px}
|
||||
.rn-top-ipm5af{top:0px}
|
||||
</style>"
|
||||
.rn-top-ipm5af{top:0px}",
|
||||
},
|
||||
]
|
||||
`;
|
||||
|
||||
@@ -22,36 +22,63 @@ describe('apis/StyleSheet/createReactDOMStyle', () => {
|
||||
expect(firstStyle).toEqual(secondStyle);
|
||||
});
|
||||
|
||||
test('flex', () => {
|
||||
expect(createReactDOMStyle({ display: 'flex' })).toEqual({
|
||||
display: 'flex',
|
||||
flexShrink: 0
|
||||
describe('flexbox styles', () => {
|
||||
test('flex defaults', () => {
|
||||
expect(createReactDOMStyle({ display: 'flex' })).toEqual({
|
||||
display: 'flex',
|
||||
flexShrink: 0,
|
||||
flexBasis: 'auto'
|
||||
});
|
||||
});
|
||||
|
||||
expect(createReactDOMStyle({ display: 'flex', flex: 1 })).toEqual({
|
||||
display: 'flex',
|
||||
flexGrow: 1,
|
||||
flexShrink: 1,
|
||||
flexBasis: 'auto'
|
||||
test('flex property expansion', () => {
|
||||
expect(createReactDOMStyle({ display: 'flex', flex: 1 })).toEqual({
|
||||
display: 'flex',
|
||||
flexGrow: 1,
|
||||
flexShrink: 1,
|
||||
flexBasis: '0%'
|
||||
});
|
||||
|
||||
expect(createReactDOMStyle({ display: 'flex', flex: 10 })).toEqual({
|
||||
display: 'flex',
|
||||
flexGrow: 10,
|
||||
flexShrink: 1,
|
||||
flexBasis: '0%'
|
||||
});
|
||||
});
|
||||
|
||||
expect(createReactDOMStyle({ display: 'flex', flex: 10 })).toEqual({
|
||||
display: 'flex',
|
||||
flexGrow: 10,
|
||||
flexShrink: 1,
|
||||
flexBasis: 'auto'
|
||||
test('flexBasis', () => {
|
||||
// is flex-basis applied?
|
||||
expect(createReactDOMStyle({ display: 'flex', flexBasis: '25%' })).toEqual({
|
||||
display: 'flex',
|
||||
flexShrink: 0,
|
||||
flexBasis: '25%'
|
||||
});
|
||||
|
||||
// can flex-basis override the 'flex' expansion?
|
||||
expect(createReactDOMStyle({ display: 'flex', flex: 1, flexBasis: '25%' })).toEqual({
|
||||
display: 'flex',
|
||||
flexGrow: 1,
|
||||
flexShrink: 1,
|
||||
flexBasis: '25%'
|
||||
});
|
||||
});
|
||||
|
||||
expect(createReactDOMStyle({ display: 'flex', flexShrink: 1 })).toEqual({
|
||||
display: 'flex',
|
||||
flexShrink: 1
|
||||
});
|
||||
test('flexShrink overrides', () => {
|
||||
// is flex-shrink applied?
|
||||
expect(createReactDOMStyle({ display: 'flex', flexShrink: 1 })).toEqual({
|
||||
display: 'flex',
|
||||
flexShrink: 1,
|
||||
flexBasis: 'auto'
|
||||
});
|
||||
|
||||
expect(createReactDOMStyle({ display: 'flex', flex: 1, flexShrink: 2 })).toEqual({
|
||||
display: 'flex',
|
||||
flexGrow: 1,
|
||||
flexShrink: 2,
|
||||
flexBasis: 'auto'
|
||||
// can flex-shrink override the 'flex' expansion?
|
||||
expect(createReactDOMStyle({ display: 'flex', flex: 1, flexShrink: 2 })).toEqual({
|
||||
display: 'flex',
|
||||
flexGrow: 1,
|
||||
flexShrink: 2,
|
||||
flexBasis: '0%'
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
@@ -37,7 +37,7 @@ describe('apis/StyleSheet', () => {
|
||||
expect(Number.isInteger(StyleSheet.hairlineWidth) === true).toBeTruthy();
|
||||
});
|
||||
|
||||
test('renderToString', () => {
|
||||
expect(StyleSheet.renderToString()).toMatchSnapshot();
|
||||
test('getStyleSheets', () => {
|
||||
expect(StyleSheet.getStyleSheets()).toMatchSnapshot();
|
||||
});
|
||||
});
|
||||
|
||||
@@ -1,12 +1,20 @@
|
||||
/**
|
||||
* Copyright (c) 2016-present, Nicolas Gallagher.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This source code is licensed under the BSD-style license found in the
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
*
|
||||
* The browser implements the CSS cascade, where the order of properties is a
|
||||
* factor in determining which styles to paint. React Native is different in
|
||||
* giving precedence to the more specific styles. For example, the value of
|
||||
* `paddingTop` takes precedence over that of `padding`.
|
||||
* factor in determining which styles to paint. React Native is different. It
|
||||
* gives giving precedence to the more specific style property. For example,
|
||||
* the value of `paddingTop` takes precedence over that of `padding`.
|
||||
*
|
||||
* This module creates mutally exclusive style declarations by expanding all of
|
||||
* React Native's supported shortform properties (e.g. `padding`) to their
|
||||
* longfrom equivalents.
|
||||
*
|
||||
* @noflow
|
||||
*/
|
||||
|
||||
import normalizeValue from './normalizeValue';
|
||||
@@ -138,9 +146,14 @@ const createReducer = (style, styleProps) => {
|
||||
switch (prop) {
|
||||
case 'display': {
|
||||
resolvedStyle.display = value;
|
||||
// default of 'flexShrink:0' has lowest precedence
|
||||
if (style.display === 'flex' && style.flex == null && style.flexShrink == null) {
|
||||
resolvedStyle.flexShrink = 0;
|
||||
// defaults of 'flexBasis:auto' and 'flexShrink:0' have lowest precedence
|
||||
if (style.display === 'flex' && style.flex == null) {
|
||||
if (style.flexShrink == null) {
|
||||
resolvedStyle.flexShrink = 0;
|
||||
}
|
||||
if (style.flexBasis == null) {
|
||||
resolvedStyle.flexBasis = 'auto';
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
@@ -155,7 +168,7 @@ const createReducer = (style, styleProps) => {
|
||||
case 'flex': {
|
||||
resolvedStyle.flexGrow = value;
|
||||
resolvedStyle.flexShrink = 1;
|
||||
resolvedStyle.flexBasis = 'auto';
|
||||
resolvedStyle.flexBasis = '0%';
|
||||
break;
|
||||
}
|
||||
case 'shadowColor':
|
||||
@@ -223,4 +236,4 @@ const createReactDOMStyle = style => {
|
||||
return resolvedStyle;
|
||||
};
|
||||
|
||||
module.exports = createReactDOMStyle;
|
||||
export default createReactDOMStyle;
|
||||
|
||||
@@ -1,14 +1,15 @@
|
||||
/**
|
||||
* Copyright (c) 2015-present, Nicolas Gallagher.
|
||||
* Copyright (c) 2015-present, Facebook, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This source code is licensed under the BSD-style license found in the
|
||||
* LICENSE file in the root directory of this source tree. An additional grant
|
||||
* of patent rights can be found in the PATENTS file in the same directory.
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
*
|
||||
* @providesModule flattenStyle
|
||||
* @flow
|
||||
*/
|
||||
|
||||
import ReactNativePropRegistry from '../../modules/ReactNativePropRegistry';
|
||||
import invariant from 'fbjs/lib/invariant';
|
||||
|
||||
@@ -23,7 +24,7 @@ function getStyle(style) {
|
||||
}
|
||||
|
||||
function flattenStyle(style: ?StyleObj): ?Object {
|
||||
if (!style) {
|
||||
if (style == null || typeof style === 'boolean') {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
@@ -48,4 +49,4 @@ function flattenStyle(style: ?StyleObj): ?Object {
|
||||
return result;
|
||||
}
|
||||
|
||||
module.exports = flattenStyle;
|
||||
export default flattenStyle;
|
||||
|
||||
@@ -1,3 +1,13 @@
|
||||
/**
|
||||
* Copyright (c) 2016-present, Nicolas Gallagher.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This source code is licensed under the BSD-style license found in the
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
*
|
||||
* @noflow
|
||||
*/
|
||||
|
||||
import hyphenateStyleName from 'hyphenate-style-name';
|
||||
import mapKeyValue from '../../modules/mapKeyValue';
|
||||
import normalizeValue from './normalizeValue';
|
||||
@@ -21,4 +31,4 @@ const createDeclarationString = (prop, val) => {
|
||||
const generateCss = style =>
|
||||
mapKeyValue(prefixStyles(style), createDeclarationString).sort().join(';');
|
||||
|
||||
module.exports = generateCss;
|
||||
export default generateCss;
|
||||
|
||||
@@ -1,3 +1,13 @@
|
||||
/**
|
||||
* Copyright (c) 2016-present, Nicolas Gallagher.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This source code is licensed under the BSD-style license found in the
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
*
|
||||
* @noflow
|
||||
*/
|
||||
|
||||
import I18nManager from '../I18nManager';
|
||||
import multiplyStyleLengthValue from '../../modules/multiplyStyleLengthValue';
|
||||
|
||||
@@ -78,4 +88,4 @@ const i18nStyle = originalStyle => {
|
||||
return nextStyle;
|
||||
};
|
||||
|
||||
module.exports = i18nStyle;
|
||||
export default i18nStyle;
|
||||
|
||||
@@ -1,6 +1,25 @@
|
||||
/**
|
||||
* Copyright (c) 2016-present, Nicolas Gallagher.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This source code is licensed under the BSD-style license found in the
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
*
|
||||
* @providesModule StyleSheet
|
||||
* @noflow
|
||||
*/
|
||||
|
||||
import flattenStyle from './flattenStyle';
|
||||
import StyleRegistry from './registry';
|
||||
|
||||
// allow component styles to be editable in React Dev Tools
|
||||
if (process.env.NODE_ENV !== 'production') {
|
||||
const { canUseDOM } = require('fbjs/lib/ExecutionEnvironment');
|
||||
if (canUseDOM && window.__REACT_DEVTOOLS_GLOBAL_HOOK__) {
|
||||
window.__REACT_DEVTOOLS_GLOBAL_HOOK__.resolveRNStyle = flattenStyle;
|
||||
}
|
||||
}
|
||||
|
||||
const absoluteFillObject = {
|
||||
position: 'absolute',
|
||||
left: 0,
|
||||
@@ -10,22 +29,25 @@ const absoluteFillObject = {
|
||||
};
|
||||
const absoluteFill = StyleRegistry.register(absoluteFillObject);
|
||||
|
||||
module.exports = {
|
||||
const StyleSheet = {
|
||||
absoluteFill,
|
||||
absoluteFillObject,
|
||||
create(styles) {
|
||||
const result = {};
|
||||
Object.keys(styles).forEach(key => {
|
||||
if (process.env.NODE_ENV !== 'production') {
|
||||
require('./StyleSheetValidation').validateStyle(key, styles);
|
||||
const StyleSheetValidation = require('./StyleSheetValidation').default;
|
||||
StyleSheetValidation.validateStyle(key, styles);
|
||||
}
|
||||
result[key] = StyleRegistry.register(styles[key]);
|
||||
});
|
||||
return result;
|
||||
},
|
||||
hairlineWidth: 1,
|
||||
flatten: flattenStyle,
|
||||
renderToString() {
|
||||
return StyleRegistry.getStyleSheetHtml();
|
||||
}
|
||||
getStyleSheets() {
|
||||
return StyleRegistry.getStyleSheets();
|
||||
},
|
||||
hairlineWidth: 1
|
||||
};
|
||||
|
||||
export default StyleSheet;
|
||||
|
||||
@@ -1,10 +1,20 @@
|
||||
/**
|
||||
* Copyright (c) 2016-present, Nicolas Gallagher.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This source code is licensed under the BSD-style license found in the
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
*
|
||||
* @noflow
|
||||
*/
|
||||
|
||||
import unitlessNumbers from '../../modules/unitlessNumbers';
|
||||
|
||||
const normalizeValue = (property, value) => {
|
||||
const normalizeValue = (property: string, value) => {
|
||||
if (!unitlessNumbers[property] && typeof value === 'number') {
|
||||
value = `${value}px`;
|
||||
}
|
||||
return value;
|
||||
};
|
||||
|
||||
module.exports = normalizeValue;
|
||||
export default normalizeValue;
|
||||
|
||||
@@ -1,3 +1,13 @@
|
||||
/**
|
||||
* Copyright (c) 2016-present, Nicolas Gallagher.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This source code is licensed under the BSD-style license found in the
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
*
|
||||
* @flow
|
||||
*/
|
||||
|
||||
import StyleRegistry from './StyleRegistry';
|
||||
const registry = new StyleRegistry();
|
||||
module.exports = registry;
|
||||
export default registry;
|
||||
|
||||
@@ -1,5 +1,14 @@
|
||||
module.exports =
|
||||
'html{' + // css reset
|
||||
/**
|
||||
* Copyright (c) 2016-present, Nicolas Gallagher.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This source code is licensed under the BSD-style license found in the
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
*
|
||||
* @flow
|
||||
*/
|
||||
|
||||
export default 'html{' + // css reset
|
||||
'font-family:sans-serif;-ms-text-size-adjust:100%;-webkit-text-size-adjust:100%;' +
|
||||
'-webkit-tap-highlight-color:rgba(0,0,0,0);' +
|
||||
'}\n' +
|
||||
|
||||
@@ -1,3 +1,14 @@
|
||||
/**
|
||||
* Copyright (c) 2016-present, Nicolas Gallagher.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This source code is licensed under the BSD-style license found in the
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
*
|
||||
* @providesModule UIManager
|
||||
* @noflow
|
||||
*/
|
||||
|
||||
import requestAnimationFrame from 'fbjs/lib/requestAnimationFrame';
|
||||
import setImmediate from 'fbjs/lib/setImmediate';
|
||||
import setValueForStyles from '../../vendor/setValueForStyles';
|
||||
@@ -19,7 +30,7 @@ let hasRequestedAnimationFrame = false;
|
||||
const measureLayoutQueue = [];
|
||||
|
||||
const processLayoutQueue = () => {
|
||||
measureLayoutQueue.splice(0, 250).forEach((item) => {
|
||||
measureLayoutQueue.splice(0, 250).forEach(item => {
|
||||
const [node, relativeToNativeNode, callback] = item;
|
||||
const relativeNode = relativeToNativeNode || (node && node.parentNode);
|
||||
|
||||
@@ -30,12 +41,12 @@ const processLayoutQueue = () => {
|
||||
const y = top - relativeRect.top;
|
||||
callback(x, y, width, height, left, top);
|
||||
}
|
||||
})
|
||||
});
|
||||
|
||||
if (measureLayoutQueue.length > 0) {
|
||||
setImmediate(processLayoutQueue);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
const measureLayout = (node, relativeToNativeNode, callback) => {
|
||||
if (!hasRequestedAnimationFrame) {
|
||||
@@ -108,4 +119,4 @@ const UIManager = {
|
||||
}
|
||||
};
|
||||
|
||||
module.exports = UIManager;
|
||||
export default UIManager;
|
||||
|
||||
@@ -1,4 +1,12 @@
|
||||
/**
|
||||
* Copyright (c) 2016-present, Nicolas Gallagher.
|
||||
* Copyright (c) 2015-present, Facebook, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This source code is licensed under the BSD-style license found in the
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
*
|
||||
* @providesModule Vibration
|
||||
* @flow
|
||||
*/
|
||||
|
||||
@@ -23,4 +31,4 @@ const Vibration = {
|
||||
}
|
||||
};
|
||||
|
||||
module.exports = Vibration;
|
||||
export default Vibration;
|
||||
|
||||
@@ -1,4 +1,12 @@
|
||||
/**
|
||||
* Copyright (c) 2016-present, Nicolas Gallagher.
|
||||
* Copyright (c) 2015-present, Facebook, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This source code is licensed under the BSD-style license found in the
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
*
|
||||
* @providesModule ActivityIndicator
|
||||
* @flow
|
||||
*/
|
||||
|
||||
@@ -110,4 +118,4 @@ const indicatorSizes = StyleSheet.create({
|
||||
}
|
||||
});
|
||||
|
||||
module.exports = applyNativeMethods(ActivityIndicator);
|
||||
export default applyNativeMethods(ActivityIndicator);
|
||||
|
||||
@@ -1,4 +1,12 @@
|
||||
/**
|
||||
* Copyright (c) 2016-present, Nicolas Gallagher.
|
||||
* Copyright (c) 2015-present, Facebook, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This source code is licensed under the BSD-style license found in the
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
*
|
||||
* @providesModule Button
|
||||
* @flow
|
||||
*/
|
||||
|
||||
@@ -62,4 +70,4 @@ const styles = StyleSheet.create({
|
||||
}
|
||||
});
|
||||
|
||||
module.exports = Button;
|
||||
export default Button;
|
||||
|
||||
2
src/components/FlatList/index.js
Normal file
2
src/components/FlatList/index.js
Normal file
@@ -0,0 +1,2 @@
|
||||
import UnimplementedView from '../UnimplementedView';
|
||||
export default UnimplementedView;
|
||||
@@ -11,4 +11,4 @@ const ImageResizeMode = {
|
||||
stretch: 'stretch'
|
||||
};
|
||||
|
||||
module.exports = ImageResizeMode;
|
||||
export default ImageResizeMode;
|
||||
|
||||
@@ -10,7 +10,7 @@ import ShadowPropTypes from '../../propTypes/ShadowPropTypes';
|
||||
import TransformPropTypes from '../../propTypes/TransformPropTypes';
|
||||
import { number, oneOf, string } from 'prop-types';
|
||||
|
||||
module.exports = {
|
||||
const ImageStylePropTypes = {
|
||||
...BorderPropTypes,
|
||||
...LayoutPropTypes,
|
||||
...ShadowPropTypes,
|
||||
@@ -28,3 +28,5 @@ module.exports = {
|
||||
*/
|
||||
boxShadow: string
|
||||
};
|
||||
|
||||
export default ImageStylePropTypes;
|
||||
|
||||
@@ -2,13 +2,15 @@
|
||||
* @flow
|
||||
*/
|
||||
|
||||
class ImageUriCache {
|
||||
const dataUriPattern = /^data:/;
|
||||
|
||||
export default class ImageUriCache {
|
||||
static _maximumEntries: number = 256;
|
||||
static _entries = {};
|
||||
|
||||
static has(uri: string) {
|
||||
const entries = ImageUriCache._entries;
|
||||
const isDataUri = /^data:/.test(uri);
|
||||
const isDataUri = dataUriPattern.test(uri);
|
||||
return isDataUri || Boolean(entries[uri]);
|
||||
}
|
||||
|
||||
@@ -61,5 +63,3 @@ class ImageUriCache {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = ImageUriCache;
|
||||
|
||||
@@ -1,5 +1,12 @@
|
||||
/* global window */
|
||||
/**
|
||||
* Copyright (c) 2016-present, Nicolas Gallagher.
|
||||
* Copyright (c) 2015-present, Facebook, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This source code is licensed under the BSD-style license found in the
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
*
|
||||
* @providesModule Image
|
||||
* @flow
|
||||
*/
|
||||
|
||||
@@ -14,7 +21,7 @@ import StyleSheet from '../../apis/StyleSheet';
|
||||
import StyleSheetPropType from '../../propTypes/StyleSheetPropType';
|
||||
import View from '../View';
|
||||
import ViewPropTypes from '../View/ViewPropTypes';
|
||||
import { any, func, number, oneOf, oneOfType, shape, string } from 'prop-types';
|
||||
import { any, bool, func, number, oneOf, oneOfType, shape, string } from 'prop-types';
|
||||
import React, { Component } from 'react';
|
||||
|
||||
const emptyObject = {};
|
||||
@@ -45,8 +52,17 @@ const resolveAssetDimensions = source => {
|
||||
}
|
||||
};
|
||||
|
||||
const svgDataUriPattern = /^data:image\/svg\+xml;/;
|
||||
const resolveAssetSource = source => {
|
||||
return (typeof source === 'object' ? source.uri : source) || '';
|
||||
const uri = typeof source === 'object' ? source.uri : source || '';
|
||||
// SVG data may contain characters (e.g., #, ") that need to be escaped
|
||||
if (svgDataUriPattern.test(uri)) {
|
||||
const parts = uri.split('<svg');
|
||||
const [prefix, ...svgFragment] = parts;
|
||||
const svg = encodeURIComponent(`<svg${svgFragment}`);
|
||||
return `${prefix}${svg}`;
|
||||
}
|
||||
return uri;
|
||||
};
|
||||
|
||||
class Image extends Component {
|
||||
@@ -54,6 +70,10 @@ class Image extends Component {
|
||||
|
||||
static displayName = 'Image';
|
||||
|
||||
static contextTypes = {
|
||||
isInAParentText: bool
|
||||
};
|
||||
|
||||
static propTypes = {
|
||||
...ViewPropTypes,
|
||||
children: any,
|
||||
@@ -158,6 +178,7 @@ class Image extends Component {
|
||||
imageSizeStyle,
|
||||
originalStyle,
|
||||
resizeModeStyles[finalResizeMode],
|
||||
this.context.isInAParentText && styles.inline,
|
||||
backgroundImage && { backgroundImage }
|
||||
]);
|
||||
// View doesn't support 'resizeMode' as a style
|
||||
@@ -267,6 +288,9 @@ const styles = StyleSheet.create({
|
||||
backgroundSize: 'cover',
|
||||
zIndex: 0
|
||||
},
|
||||
inline: {
|
||||
display: 'inline-flex'
|
||||
},
|
||||
img: {
|
||||
height: '100%',
|
||||
opacity: 0,
|
||||
@@ -298,4 +322,4 @@ const resizeModeStyles = StyleSheet.create({
|
||||
}
|
||||
});
|
||||
|
||||
module.exports = applyNativeMethods(Image);
|
||||
export default applyNativeMethods(Image);
|
||||
|
||||
@@ -27,11 +27,10 @@
|
||||
* @typechecks
|
||||
* @flow
|
||||
*/
|
||||
'use strict';
|
||||
|
||||
var invariant = require('fbjs/lib/invariant');
|
||||
var isEmpty = require('fbjs/lib/isEmpty');
|
||||
var warning = require('fbjs/lib/warning');
|
||||
import invariant from 'fbjs/lib/invariant';
|
||||
import isEmpty from 'fbjs/lib/isEmpty';
|
||||
import warning from 'fbjs/lib/warning';
|
||||
|
||||
function defaultGetRowData(dataBlob: any, sectionID: number | string, rowID: number | string): any {
|
||||
return dataBlob[sectionID][rowID];
|
||||
@@ -392,4 +391,4 @@ function keyedDictionaryFromArray(arr) {
|
||||
return result;
|
||||
}
|
||||
|
||||
module.exports = ListViewDataSource;
|
||||
export default ListViewDataSource;
|
||||
|
||||
@@ -441,4 +441,4 @@ class ListView extends Component {
|
||||
};
|
||||
}
|
||||
|
||||
module.exports = applyNativeMethods(ListView);
|
||||
export default applyNativeMethods(ListView);
|
||||
|
||||
2
src/components/Modal/index.js
Normal file
2
src/components/Modal/index.js
Normal file
@@ -0,0 +1,2 @@
|
||||
import UnimplementedView from '../UnimplementedView';
|
||||
export default UnimplementedView;
|
||||
2
src/components/Picker/index.js
Normal file
2
src/components/Picker/index.js
Normal file
@@ -0,0 +1,2 @@
|
||||
import UnimplementedView from '../UnimplementedView';
|
||||
export default UnimplementedView;
|
||||
@@ -1,4 +1,11 @@
|
||||
/**
|
||||
* Copyright (c) 2016-present, Nicolas Gallagher.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This source code is licensed under the BSD-style license found in the
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
*
|
||||
* @providesModule ProgressBar
|
||||
* @flow
|
||||
*/
|
||||
|
||||
@@ -11,6 +18,8 @@ import React, { Component } from 'react';
|
||||
import { bool, number } from 'prop-types';
|
||||
|
||||
class ProgressBar extends Component {
|
||||
_progressElement: View;
|
||||
|
||||
static displayName = 'ProgressBar';
|
||||
|
||||
static propTypes = {
|
||||
@@ -58,17 +67,19 @@ class ProgressBar extends Component {
|
||||
);
|
||||
}
|
||||
|
||||
_setProgressRef = component => {
|
||||
this._progressRef = component;
|
||||
_setProgressRef = element => {
|
||||
this._progressElement = element;
|
||||
};
|
||||
|
||||
_updateProgressWidth = () => {
|
||||
const { indeterminate, progress } = this.props;
|
||||
const percentageProgress = indeterminate ? 50 : progress * 100;
|
||||
const width = indeterminate ? '25%' : `${percentageProgress}%`;
|
||||
this._progressRef.setNativeProps({
|
||||
style: { width }
|
||||
});
|
||||
if (this._progressElement) {
|
||||
this._progressElement.setNativeProps({
|
||||
style: { width }
|
||||
});
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
@@ -76,10 +87,12 @@ const styles = StyleSheet.create({
|
||||
track: {
|
||||
height: 5,
|
||||
overflow: 'hidden',
|
||||
userSelect: 'none'
|
||||
userSelect: 'none',
|
||||
zIndex: 0
|
||||
},
|
||||
progress: {
|
||||
height: '100%'
|
||||
height: '100%',
|
||||
zIndex: -1
|
||||
},
|
||||
animation: {
|
||||
animationDuration: '1s',
|
||||
@@ -89,4 +102,4 @@ const styles = StyleSheet.create({
|
||||
}
|
||||
});
|
||||
|
||||
module.exports = applyNativeMethods(ProgressBar);
|
||||
export default applyNativeMethods(ProgressBar);
|
||||
|
||||
2
src/components/RefreshControl/index.js
Normal file
2
src/components/RefreshControl/index.js
Normal file
@@ -0,0 +1,2 @@
|
||||
import UnimplementedView from '../UnimplementedView';
|
||||
export default UnimplementedView;
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user