Compare commits
25 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
7abdb33a1d | ||
|
|
a9c7b38df9 | ||
|
|
d57fb6407a | ||
|
|
bcdeda5dab | ||
|
|
edef737249 | ||
|
|
9163b974db | ||
|
|
a388ef3e26 | ||
|
|
a84ecefa5d | ||
|
|
54af7e9da2 | ||
|
|
be3c78f317 | ||
|
|
6b85f5a22a | ||
|
|
875a2c98b3 | ||
|
|
6525d9d84a | ||
|
|
61356a786b | ||
|
|
864250f34d | ||
|
|
7ee570f0ed | ||
|
|
118b64a932 | ||
|
|
3cc1e480a7 | ||
|
|
124de7562d | ||
|
|
7aef8f04c1 | ||
|
|
08a353fbef | ||
|
|
51557d306b | ||
|
|
6b910166b2 | ||
|
|
668d389035 | ||
|
|
79a6a5a486 |
8
.babelrc
@@ -1,8 +0,0 @@
|
||||
{
|
||||
"presets": [
|
||||
"react-native"
|
||||
],
|
||||
"plugins": [
|
||||
[ "transform-react-remove-prop-types", { "mode": "wrap" } ]
|
||||
]
|
||||
}
|
||||
@@ -1,9 +0,0 @@
|
||||
# EditorConfig: http://editorconfig.org
|
||||
|
||||
root = true
|
||||
|
||||
[*]
|
||||
end_of_line = lf
|
||||
insert_final_newline = true
|
||||
indent_style = space
|
||||
indent_size = 2
|
||||
14
.eslintrc
@@ -24,7 +24,16 @@
|
||||
"globals": {
|
||||
"document": false,
|
||||
"navigator": false,
|
||||
"window": false
|
||||
"window": false,
|
||||
// Flow global types
|
||||
"HTMLInputElement": false,
|
||||
"ReactClass": false,
|
||||
"ReactComponent": false,
|
||||
"ReactElement": false,
|
||||
"ReactPropsChainableTypeChecker": false,
|
||||
"ReactPropsCheckType": false,
|
||||
"ReactPropTypes": false,
|
||||
"SyntheticEvent": false
|
||||
},
|
||||
"rules": {
|
||||
"camelcase": 0,
|
||||
@@ -120,9 +129,6 @@
|
||||
|
||||
// react
|
||||
"react/display-name": 0,
|
||||
"react/jsx-handler-names": [2, {
|
||||
"eventHandlerPrefix": "_handle"
|
||||
}],
|
||||
"react/jsx-no-bind": 2,
|
||||
"react/jsx-no-duplicate-props": 2,
|
||||
"react/jsx-no-undef": 2,
|
||||
|
||||
13
.flowconfig
Normal file
@@ -0,0 +1,13 @@
|
||||
[ignore]
|
||||
.*/__tests__/.*
|
||||
.*/benchmarks/.*
|
||||
.*/docs/.*
|
||||
.*/node_modules/animated/*
|
||||
|
||||
[include]
|
||||
|
||||
[libs]
|
||||
types
|
||||
|
||||
[options]
|
||||
unsafe.enable_getters_and_setters=true
|
||||
87
CONTRIBUTING.md → .github/CONTRIBUTING.md
vendored
@@ -6,7 +6,7 @@ Before opening an issue, please search the [issue
|
||||
tracker](https://github.com/necolas/react-native-web/issues) to make sure your
|
||||
issue hasn't already been reported.
|
||||
|
||||
## Development
|
||||
## Getting started
|
||||
|
||||
Visit the [Issue tracker](https://github.com/necolas/react-native-web/issues)
|
||||
to find a list of open issues that need attention.
|
||||
@@ -23,47 +23,66 @@ Install dependencies (requires [yarn](https://yarnpkg.com/en/docs/install):
|
||||
yarn
|
||||
```
|
||||
|
||||
Run the examples:
|
||||
## Unit tests
|
||||
|
||||
To run the unit tests:
|
||||
|
||||
```
|
||||
npm run examples
|
||||
npm test
|
||||
```
|
||||
|
||||
Run the benchmarks in a browser by opening `./performance/index.html` after running:
|
||||
|
||||
```
|
||||
npm run build:performance
|
||||
```
|
||||
|
||||
### Building
|
||||
|
||||
```
|
||||
npm run build
|
||||
```
|
||||
|
||||
To create a UMD build:
|
||||
|
||||
```
|
||||
npm run build:umd
|
||||
```
|
||||
|
||||
### Testing and Linting
|
||||
|
||||
To run the tests:
|
||||
|
||||
```
|
||||
npm run test
|
||||
```
|
||||
|
||||
To continuously watch and run tests, run the following:
|
||||
…in watch mode:
|
||||
|
||||
```
|
||||
npm run test:watch
|
||||
```
|
||||
|
||||
To perform only linting, run the following:
|
||||
## Visual tests
|
||||
|
||||
Run the interactive storybook:
|
||||
|
||||
```
|
||||
npm run docs:start
|
||||
```
|
||||
|
||||
Run generate a static build of the storybook:
|
||||
|
||||
```
|
||||
npm run docs:build
|
||||
```
|
||||
|
||||
Run the performance benchmarks in a browser (opening `./performance/index.html`):
|
||||
|
||||
```
|
||||
npm run benchmarks
|
||||
```
|
||||
|
||||
## Compile and build
|
||||
|
||||
Compile the source code to `dist`:
|
||||
|
||||
```
|
||||
npm run compile
|
||||
```
|
||||
|
||||
To create a UMD bundle of the library:
|
||||
|
||||
```
|
||||
npm run build
|
||||
```
|
||||
|
||||
### Pre-commit
|
||||
|
||||
Before creating a commit run:
|
||||
|
||||
```
|
||||
npm run precommit
|
||||
```
|
||||
|
||||
To format and lint the entire project:
|
||||
|
||||
```
|
||||
npm run fmt
|
||||
npm run lint
|
||||
```
|
||||
|
||||
@@ -81,8 +100,10 @@ that we won't want to accept.
|
||||
* Make sure all tests pass and there are no linting errors.
|
||||
* Submit a pull request, referencing any issues it addresses.
|
||||
|
||||
Please try to keep your pull request focused in scope and avoid including unrelated commits.
|
||||
Please try to keep your pull request focused in scope and avoid including
|
||||
unrelated commits.
|
||||
|
||||
After you have submitted your pull request, we'll try to get back to you as soon as possible. We may suggest some changes or improvements.
|
||||
After you have submitted your pull request, we'll try to get back to you as
|
||||
soon as possible. We may suggest some changes or improvements.
|
||||
|
||||
Thank you for contributing!
|
||||
1
.gitignore
vendored
@@ -1,3 +1,2 @@
|
||||
node_modules
|
||||
dist
|
||||
dist-examples
|
||||
|
||||
@@ -5,4 +5,5 @@ before_script:
|
||||
- export DISPLAY=:99.0
|
||||
- sh -e /etc/init.d/xvfb start
|
||||
script:
|
||||
- npm run lint
|
||||
- npm test
|
||||
|
||||
35
README.md
@@ -18,35 +18,31 @@ Browser support: Chrome, Firefox, Safari >= 7, IE 10, Edge.
|
||||
"React Native for Web" is a project to bring React Native's building blocks and
|
||||
touch handling to the Web. [Read more](#why).
|
||||
|
||||
Browse the UI Explorer to see React Native [examples running on
|
||||
Web](https://necolas.github.io/react-native-web/storybook/). Or try it out
|
||||
online with [React Native for Web: Playground](https://www.webpackbin.com/bins/-KgucwxRbn7HRU-V-3Bc).
|
||||
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
|
||||
Native for Web: Playground](https://www.webpackbin.com/bins/-KgucwxRbn7HRU-V-3Bc).
|
||||
|
||||
## Quick start
|
||||
|
||||
To install in your app:
|
||||
|
||||
```
|
||||
npm install --save react@15.4 react-dom@15.4 react-native-web
|
||||
npm install --save react@15.5 react-dom@15.5 react-native-web
|
||||
```
|
||||
|
||||
Read the [Getting Started](docs/guides/getting-started.md) guide.
|
||||
|
||||
Alternatively, you can quickly setup a local project
|
||||
using [create-react-app](https://github.com/facebookincubator/create-react-app)
|
||||
(which supports `react-native-web` out-of-the-box once installed) and
|
||||
[react-native-web-starter](https://github.com/grabcode/react-native-web-starter).
|
||||
|
||||
## Documentation
|
||||
|
||||
Guides:
|
||||
|
||||
* [Getting started](docs/guides/getting-started.md)
|
||||
* [Style](docs/guides/style.md)
|
||||
* [Accessibility](docs/guides/accessibility.md)
|
||||
* [Direct manipulation](docs/guides/direct-manipulation.md)
|
||||
* [Internationalization](docs/guides/internationalization.md)
|
||||
* [Advanced use](docs/guides/advanced.md)
|
||||
* [Known issues](docs/guides/known-issues.md)
|
||||
* [Style](docs/guides/style.md)
|
||||
|
||||
Exported modules:
|
||||
|
||||
@@ -87,17 +83,16 @@ Exported modules:
|
||||
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: a common way to handle style,
|
||||
animation, touch, viewport adaptation, accessibility, themes, RTL layout, and
|
||||
server-rendering.
|
||||
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 facing Web teams.
|
||||
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.
|
||||
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
|
||||
|
||||
@@ -140,11 +135,11 @@ AppRegistry.runApplication('MyApp', { rootTag: document.getElementById('react-ro
|
||||
|
||||
## Related projects
|
||||
|
||||
* [react-native-web-starter](https://github.com/grabcode/react-native-web-starter)
|
||||
* [react-native-web-player](https://github.com/dabbott/react-native-web-player)
|
||||
* [react-native-web-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)
|
||||
* [react-native-web-webpack](https://github.com/ndbroadbent/react-native-web-webpack)
|
||||
|
||||
## License
|
||||
|
||||
|
||||
@@ -2,19 +2,19 @@
|
||||
"name": "performance",
|
||||
"private": true,
|
||||
"dependencies": {
|
||||
"aphrodite": "^1.2.0",
|
||||
"aphrodite": "^1.2.1",
|
||||
"classnames": "^2.2.5",
|
||||
"glamor": "3.0.0-1",
|
||||
"glamor": "2.20.25",
|
||||
"marky": "^1.2.0",
|
||||
"react-jss": "^6.1.1",
|
||||
"reactxp": "^0.34.3",
|
||||
"styled-components": "2.0.0-15",
|
||||
"styletron-client": "^2.5.1",
|
||||
"styled-components": "2.0.0-17",
|
||||
"styletron-client": "^2.5.7",
|
||||
"styletron-utils": "^2.5.4"
|
||||
},
|
||||
"devDependencies": {
|
||||
"css-loader": "^0.28.0",
|
||||
"css-loader": "^0.28.1",
|
||||
"react-addons-perf": "^15.4.2",
|
||||
"style-loader": "^0.16.1"
|
||||
"style-loader": "^0.17.0"
|
||||
}
|
||||
}
|
||||
@@ -2,7 +2,12 @@
|
||||
import React from 'react';
|
||||
import { css, StyleSheet } from 'aphrodite';
|
||||
|
||||
const View = ({ style, ...other }) => <div {...other} className={css(styles.root, style)} />;
|
||||
class View extends React.Component {
|
||||
render() {
|
||||
const { style, ...other } = this.props;
|
||||
return <div {...other} className={css(styles.root, style)} />;
|
||||
}
|
||||
}
|
||||
|
||||
const styles = StyleSheet.create({
|
||||
root: {
|
||||
13
benchmarks/src/components/View/css-modules.js
Normal file
@@ -0,0 +1,13 @@
|
||||
/* eslint-disable react/prop-types */
|
||||
import classnames from 'classnames';
|
||||
import React from 'react';
|
||||
import styles from './styles.css';
|
||||
|
||||
class View extends React.Component {
|
||||
render() {
|
||||
const props = this.props;
|
||||
return <div {...props} className={classnames(styles.initial, props.className)} />;
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = View;
|
||||
@@ -2,7 +2,12 @@
|
||||
import { css } from 'glamor';
|
||||
import React from 'react';
|
||||
|
||||
const View = ({ style, ...other }) => <div {...other} className={css(viewStyle, ...style)} />;
|
||||
class View extends React.Component {
|
||||
render() {
|
||||
const { style, ...other } = this.props;
|
||||
return <div {...other} className={css(viewStyle, ...style)} />;
|
||||
}
|
||||
}
|
||||
|
||||
const viewStyle = {
|
||||
alignItems: 'stretch',
|
||||
@@ -3,9 +3,12 @@ import classnames from 'classnames';
|
||||
import injectSheet from 'react-jss';
|
||||
import React from 'react';
|
||||
|
||||
const View = ({ classes, className, ...other }) => (
|
||||
<div {...other} className={classnames(classes.root, className)} />
|
||||
);
|
||||
class View extends React.Component {
|
||||
render() {
|
||||
const { classes, className, ...other } = this.props;
|
||||
return <div {...other} className={classnames(classes.root, className)} />;
|
||||
}
|
||||
}
|
||||
|
||||
const styles = {
|
||||
root: {
|
||||
@@ -2,11 +2,16 @@
|
||||
import React from 'react';
|
||||
import StyleSheet from 'react-native/apis/StyleSheet';
|
||||
import registry from 'react-native/apis/StyleSheet/registry';
|
||||
import createDOMProps from 'react-native/modules/createDOMProps';
|
||||
|
||||
const View = props => (
|
||||
<div {...createDOMProps(props, style => registry.resolve([styles.root, style]))} />
|
||||
);
|
||||
const emptyObject = {};
|
||||
|
||||
class View extends React.Component {
|
||||
render() {
|
||||
const { style, ...other } = this.props;
|
||||
const styleProps = registry.resolve([styles.root, style]) || emptyObject;
|
||||
return <div {...other} {...styleProps} />;
|
||||
}
|
||||
}
|
||||
|
||||
const styles = StyleSheet.create({
|
||||
root: {
|
||||
@@ -6,9 +6,12 @@ import React from 'react';
|
||||
|
||||
export const styletron = new Styletron();
|
||||
|
||||
const View = ({ style, ...other }) => (
|
||||
<div {...other} className={classnames(viewStyle, ...style)} />
|
||||
);
|
||||
class View extends React.Component {
|
||||
render() {
|
||||
const { style, ...other } = this.props;
|
||||
return <div {...other} className={classnames(viewStyle, ...style)} />;
|
||||
}
|
||||
}
|
||||
|
||||
const viewStyle = injectStylePrefixed(styletron, {
|
||||
alignItems: 'stretch',
|
||||
@@ -14,9 +14,9 @@ ansi-styles@^2.2.1:
|
||||
version "2.2.1"
|
||||
resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-2.2.1.tgz#b432dd3358b634cf75e1e4664368240533c1ddbe"
|
||||
|
||||
aphrodite@^1.2.0:
|
||||
version "1.2.0"
|
||||
resolved "https://artifactory.twitter.biz:443/api/npm/js-virtual/aphrodite/-/aphrodite-1.2.0.tgz#c2f30bd1cdf6a550f4a29a0f1cf22ed10e825764"
|
||||
aphrodite@^1.2.1:
|
||||
version "1.2.1"
|
||||
resolved "https://registry.yarnpkg.com/aphrodite/-/aphrodite-1.2.1.tgz#a7b5066b198730be7b7a88f78dbefd77d4df5683"
|
||||
dependencies:
|
||||
asap "^2.0.3"
|
||||
inline-style-prefixer "^3.0.1"
|
||||
@@ -195,9 +195,9 @@ css-in-js-utils@^1.0.3:
|
||||
dependencies:
|
||||
hyphenate-style-name "^1.0.2"
|
||||
|
||||
css-loader@^0.28.0:
|
||||
version "0.28.0"
|
||||
resolved "https://registry.yarnpkg.com/css-loader/-/css-loader-0.28.0.tgz#417cfa9789f8cde59a30ccbf3e4da7a806889bad"
|
||||
css-loader@^0.28.1:
|
||||
version "0.28.1"
|
||||
resolved "https://registry.yarnpkg.com/css-loader/-/css-loader-0.28.1.tgz#220325599f8f00452d9ceb4c3ca6c8a66798642d"
|
||||
dependencies:
|
||||
babel-code-frame "^6.11.0"
|
||||
css-selector-tokenizer "^0.7.0"
|
||||
@@ -210,6 +210,7 @@ css-loader@^0.28.0:
|
||||
postcss-modules-local-by-default "^1.0.1"
|
||||
postcss-modules-scope "^1.0.0"
|
||||
postcss-modules-values "^1.1.0"
|
||||
postcss-value-parser "^3.3.0"
|
||||
source-list-map "^0.1.7"
|
||||
|
||||
css-selector-tokenizer@^0.6.0:
|
||||
@@ -348,13 +349,14 @@ function-bind@^1.0.2:
|
||||
version "1.1.0"
|
||||
resolved "https://registry.yarnpkg.com/function-bind/-/function-bind-1.1.0.tgz#16176714c801798e4e8f2cf7f7529467bb4a5771"
|
||||
|
||||
glamor@3.0.0-1:
|
||||
version "3.0.0-1"
|
||||
resolved "https://registry.yarnpkg.com/glamor/-/glamor-3.0.0-1.tgz#60f489e96d96c12620803d3677ac26413cb76a95"
|
||||
glamor@2.20.25:
|
||||
version "2.20.25"
|
||||
resolved "https://registry.yarnpkg.com/glamor/-/glamor-2.20.25.tgz#71b84b82b67a9327771ac59de53ee915d148a4a3"
|
||||
dependencies:
|
||||
babel-runtime "^6.18.0"
|
||||
fbjs "^0.8.8"
|
||||
object-assign "^4.1.0"
|
||||
prop-types "^15.5.8"
|
||||
|
||||
has-ansi@^2.0.0:
|
||||
version "2.0.0"
|
||||
@@ -1008,19 +1010,20 @@ strip-ansi@^3.0.0:
|
||||
dependencies:
|
||||
ansi-regex "^2.0.0"
|
||||
|
||||
style-loader@^0.16.1:
|
||||
version "0.16.1"
|
||||
resolved "https://registry.yarnpkg.com/style-loader/-/style-loader-0.16.1.tgz#50e325258d4e78421dd9680636b41e8661595d10"
|
||||
style-loader@^0.17.0:
|
||||
version "0.17.0"
|
||||
resolved "https://registry.yarnpkg.com/style-loader/-/style-loader-0.17.0.tgz#e8254bccdb7af74bd58274e36107b4d5ab4df310"
|
||||
dependencies:
|
||||
loader-utils "^1.0.2"
|
||||
|
||||
styled-components@2.0.0-15:
|
||||
version "2.0.0-15"
|
||||
resolved "https://registry.yarnpkg.com/styled-components/-/styled-components-2.0.0-15.tgz#77843c9f5267c60a97e28c97719d1ee89ea28be1"
|
||||
styled-components@2.0.0-17:
|
||||
version "2.0.0-17"
|
||||
resolved "https://registry.yarnpkg.com/styled-components/-/styled-components-2.0.0-17.tgz#9d49e5b351f2c3e13698ee00d189a3c951735088"
|
||||
dependencies:
|
||||
buffer "^5.0.3"
|
||||
css-to-react-native "^2.0.3"
|
||||
fbjs "^0.8.9"
|
||||
hoist-non-react-statics "^1.2.0"
|
||||
inline-style-prefixer "^2.0.5"
|
||||
is-function "^1.0.1"
|
||||
is-plain-object "^2.0.1"
|
||||
@@ -1028,15 +1031,15 @@ styled-components@2.0.0-15:
|
||||
stylis "^2.0.0"
|
||||
supports-color "^3.2.3"
|
||||
|
||||
styletron-client@^2.5.1:
|
||||
version "2.5.1"
|
||||
resolved "https://registry.yarnpkg.com/styletron-client/-/styletron-client-2.5.1.tgz#df0b6fd65965b035d2ff58df61b422aa80e23577"
|
||||
styletron-client@^2.5.7:
|
||||
version "2.5.7"
|
||||
resolved "https://registry.yarnpkg.com/styletron-client/-/styletron-client-2.5.7.tgz#104fa4dc564cd3fe78eb92488e5ef9039c9e242f"
|
||||
dependencies:
|
||||
styletron-core "^2.5.1"
|
||||
styletron-core "^2.5.7"
|
||||
|
||||
styletron-core@^2.5.1:
|
||||
version "2.5.1"
|
||||
resolved "https://registry.yarnpkg.com/styletron-core/-/styletron-core-2.5.1.tgz#bf9e8aebc41461b81fdd22b1062f6e25862286fd"
|
||||
styletron-core@^2.5.7:
|
||||
version "2.5.7"
|
||||
resolved "https://registry.yarnpkg.com/styletron-core/-/styletron-core-2.5.7.tgz#2c4a1fae537b42235462e438c24ab619bbf8993e"
|
||||
|
||||
styletron-utils@^2.5.4:
|
||||
version "2.5.4"
|
||||
2
core.js
@@ -1 +1 @@
|
||||
module.exports = require('./dist/core')
|
||||
module.exports = require('./dist/core');
|
||||
|
||||
@@ -3,8 +3,7 @@
|
||||
`AppRegistry` is the control point for registering, running, prerendering, and
|
||||
unmounting all apps. App root components should register themselves with
|
||||
`AppRegistry.registerComponent`. Apps can be run by invoking
|
||||
`AppRegistry.runApplication` (see the [client and server rendering
|
||||
guide](../guides/rendering.md) for more details).
|
||||
`AppRegistry.runApplication` (see the [getting started guide](../guides/getting-started.md) for more details).
|
||||
|
||||
To "stop" an application when a view should be destroyed, call
|
||||
`AppRegistry.unmountApplicationComponentAtRootTag` with the tag that was passed
|
||||
|
||||
@@ -1,9 +1,10 @@
|
||||
# StyleSheet
|
||||
|
||||
The `StyleSheet` abstraction converts predefined styles to (vendor-prefixed)
|
||||
CSS without requiring a compile-time step. Some styles cannot be resolved
|
||||
outside of the render loop and are applied as inline styles. Read more about
|
||||
[how to style your application](../guides/style.md).
|
||||
CSS without requiring a compile-time step. Styles that cannot be resolved
|
||||
outside of the render loop (e.g., dynamic positioning) are usually applied as
|
||||
inline styles. Read more about [how to style your
|
||||
application](../guides/style.md).
|
||||
|
||||
## Methods
|
||||
|
||||
@@ -15,7 +16,7 @@ Each key of the object passed to `create` must define a style object.
|
||||
|
||||
Flattens an array of styles into a single style object.
|
||||
|
||||
**renderToString**: function
|
||||
(web) **renderToString**: function
|
||||
|
||||
Returns a string of the stylesheet for use in server-side rendering.
|
||||
|
||||
|
||||
@@ -23,7 +23,7 @@ If `true`, disable all interactions for this element.
|
||||
|
||||
This function is called on press.
|
||||
|
||||
testID: ?string
|
||||
**testID**: ?string
|
||||
|
||||
Used to locate this view in end-to-end tests.
|
||||
|
||||
|
||||
104
docs/guides/advanced.md
Normal file
@@ -0,0 +1,104 @@
|
||||
# Advanced use
|
||||
|
||||
## Use with existing React DOM components
|
||||
|
||||
React Native for Web exports a web-specific module called `createDOMElement`,
|
||||
which can be used to wrap React DOM components. This allows you to use React
|
||||
Native's accessibility and style optimizations.
|
||||
|
||||
In the example below, `Video` will now accept common React Native props such as
|
||||
`accessibilityLabel`, `accessible`, `style`, and even the Responder event
|
||||
props.
|
||||
|
||||
```js
|
||||
import { createDOMElement } from 'react-native';
|
||||
|
||||
const Video = (props) => createDOMElement('video', props);
|
||||
```
|
||||
|
||||
This also works with composite components defined in your existing component
|
||||
gallery or dependencies ([live example](https://www.webpackbin.com/bins/-KiTSGFw3fB9Szg7quLI)).
|
||||
|
||||
```js
|
||||
import RaisedButton from 'material-ui/RaisedButton';
|
||||
import { createDOMElement, StyleSheet } from 'react-native';
|
||||
|
||||
const CustomButton = (props) => createDOMElement(RaisedButton, {
|
||||
...props,
|
||||
style: [ styles.button, props.style ]
|
||||
});
|
||||
|
||||
const styles = StyleSheet.create({
|
||||
button: {
|
||||
padding: 20
|
||||
}
|
||||
});
|
||||
```
|
||||
|
||||
Remember that React Native styles are not the same as React DOM styles, and
|
||||
care needs to be taken not to pass React DOM styles into your React Native
|
||||
wrapped components.
|
||||
|
||||
## Use as a library framework
|
||||
|
||||
The React Native (for Web) building blocks can be used to create higher-level
|
||||
components and abstractions. In the example below, a `styled` function provides
|
||||
an API inspired by styled-components ([live
|
||||
example](https://www.webpackbin.com/bins/-KjT9ziwv4O7FDZdvsnX)).
|
||||
|
||||
```js
|
||||
const { createDOMElement, StyleSheet } = ReactNative;
|
||||
|
||||
/**
|
||||
* styled API
|
||||
*/
|
||||
const styled = (Component, styler) => {
|
||||
const isDOMComponent = typeof Component === 'string';
|
||||
|
||||
class Styled extends React.Component {
|
||||
static contextTypes = {
|
||||
getTheme: React.PropTypes.func
|
||||
};
|
||||
|
||||
render() {
|
||||
const theme = this.context.getTheme && this.context.getTheme();
|
||||
const localProps = { ...this.props, theme };
|
||||
const nextProps = { ...this.props }
|
||||
const style = typeof styler === 'function' ? styler(localProps) : styler;
|
||||
nextProps.style = [ style, this.props.style ];
|
||||
|
||||
return (
|
||||
isDOMComponent
|
||||
? createDOMElement(Component, nextProps)
|
||||
: <Component {...nextProps} />
|
||||
);
|
||||
}
|
||||
}
|
||||
return Styled;
|
||||
}
|
||||
|
||||
const styles = StyleSheet.create({
|
||||
container: {
|
||||
alignItems: 'center',
|
||||
backgroundColor: '#2196F3',
|
||||
flex: 1,
|
||||
justifyContent: 'center'
|
||||
}
|
||||
});
|
||||
|
||||
const StyledView = styled(View, styles.container);
|
||||
```
|
||||
|
||||
## Use with react-sketchapp
|
||||
|
||||
Use with [react-sketchapp](http://airbnb.io/react-sketchapp/) requires that you
|
||||
alias `react-native` to `react-sketchapp`. This will allow you to render your
|
||||
existing React Native components in Sketch. Sketch-specific components like
|
||||
`Artboard` should be imported from `react-sketchapp`.
|
||||
|
||||
If you're using `skpm`, you can rely on an [undocumented
|
||||
feature](https://github.com/sketch-pm/skpm/blob/master/lib/utils/webpackConfig.js)
|
||||
which will merge your `webpack.config.js`, `.babelrc`, or `package.json` Babel
|
||||
config into its internal webpack config. The simplest option may be to use the
|
||||
[babel-plugin-module-alias](https://www.npmjs.com/package/babel-plugin-module-alias)
|
||||
and configure it in your `package.json`.
|
||||
@@ -1,5 +1,14 @@
|
||||
# Getting started
|
||||
|
||||
This guide will help you to correctly configure build and test tools to work
|
||||
with React Native for Web.
|
||||
|
||||
Alternatively, you can quickly setup a local project using
|
||||
[create-react-app](https://github.com/facebookincubator/create-react-app)
|
||||
(which supports `react-native-web` out-of-the-box once installed),
|
||||
[react-native-web-starter](https://github.com/grabcode/react-native-web-starter),
|
||||
or [react-native-web-webpack](https://github.com/ndbroadbent/react-native-web-webpack).
|
||||
|
||||
It is recommended that your application provide a `Promise` and `Array.from`
|
||||
polyfill.
|
||||
|
||||
@@ -76,10 +85,6 @@ module.exports = {
|
||||
}
|
||||
```
|
||||
|
||||
A more complex example setup for web apps can be found in various starter kits
|
||||
(e.g., create-react-app and
|
||||
[react-native-web-webpack](https://github.com/ndbroadbent/react-native-web-webpack))
|
||||
|
||||
Please refer to the Webpack documentation for more information.
|
||||
|
||||
## Jest
|
||||
@@ -112,6 +117,26 @@ if (Platform.OS === 'web') {
|
||||
}
|
||||
```
|
||||
|
||||
More significant platform differences should use platform-specific files (see
|
||||
the webpack configuration above for resolving `*.web.js` files):
|
||||
|
||||
For example, with the following files in your project:
|
||||
|
||||
```
|
||||
MyComponent.android.js
|
||||
MyComponent.ios.js
|
||||
MyComponent.web.js
|
||||
```
|
||||
|
||||
And the following import:
|
||||
|
||||
```js
|
||||
import MyComponent from './MyComponent';
|
||||
```
|
||||
|
||||
React Native will automatically import the correct variant for each specific
|
||||
target platform.
|
||||
|
||||
## Client-side rendering
|
||||
|
||||
Rendering using `ReactNative`:
|
||||
@@ -144,8 +169,8 @@ AppRegistry.runApplication('App', {
|
||||
})
|
||||
```
|
||||
|
||||
Rendering within `ReactDOM.render` also works when introduce `react-native-web`
|
||||
to an existing web app, but it is not recommended oherwise.
|
||||
Rendering within `ReactDOM.render` also works when introducing
|
||||
`react-native-web` to an existing web app, but otherwise it is not recommended.
|
||||
|
||||
## Server-side rendering
|
||||
|
||||
@@ -164,4 +189,15 @@ AppRegistry.registerComponent('App', () => AppContainer)
|
||||
// prerender the app
|
||||
const { element, stylesheet } = AppRegistry.getApplication('App', { initialProps });
|
||||
const initialHTML = ReactDOMServer.renderToString(element);
|
||||
|
||||
// construct HTML document
|
||||
const document = `
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
${stylesheet}
|
||||
</head>
|
||||
<body>
|
||||
${initialHTML}
|
||||
`
|
||||
```
|
||||
|
||||
@@ -1,73 +1,90 @@
|
||||
# Style
|
||||
|
||||
React Native for Web relies on JavaScript to define styles for your
|
||||
application. This allows you to avoid issues arising from the [7 deadly sins of
|
||||
CSS](https://speakerdeck.com/vjeux/react-css-in-js):
|
||||
React Native relies on JavaScript to define and resolve the styles of your
|
||||
application. React Native for Web implements the React Native style API in a
|
||||
way that avoids *all* the [problems with CSS at
|
||||
scale](https://speakerdeck.com/vjeux/react-css-in-js):
|
||||
|
||||
1. Global namespace
|
||||
2. Dependency hell
|
||||
1. No local variables
|
||||
2. Implicit dependencies
|
||||
3. No dead code elimination
|
||||
4. No code minification
|
||||
5. No sharing of constants
|
||||
6. Non-deterministic resolution
|
||||
7. Lack of isolation
|
||||
7. No isolation
|
||||
|
||||
At the same time, it has several benefits:
|
||||
|
||||
1. Simple API and expressive subset of CSS
|
||||
2. Generates CSS; the minimum required
|
||||
3. Good runtime performance
|
||||
4. Support for static and dynamic styles
|
||||
5. Support for RTL layouts
|
||||
6. Easy pre-rendering of critical CSS
|
||||
|
||||
## Defining styles
|
||||
|
||||
Styles should be defined outside of the component:
|
||||
Styles should be defined outside of the component. Using `StyleSheet.create` is
|
||||
optional but provides the best performance (by relying on generated CSS
|
||||
stylesheets). Avoid creating unregistered style objects.
|
||||
|
||||
```js
|
||||
class Example extends React.Component {}
|
||||
|
||||
const styles = StyleSheet.create({
|
||||
heading: {
|
||||
color: 'gray',
|
||||
fontSize: '2rem'
|
||||
},
|
||||
text: {
|
||||
color: 'gray',
|
||||
fontSize: '1.25rem'
|
||||
marginTop: '1rem',
|
||||
margin: 10
|
||||
}
|
||||
})
|
||||
```
|
||||
|
||||
Using `StyleSheet.create` is optional but provides the best performance
|
||||
(`style` is resolved to CSS stylesheets). Avoid creating unregistered style
|
||||
objects.
|
||||
|
||||
The attribute names and values are a subset of CSS. See the `style`
|
||||
documentation of individual components.
|
||||
See the `style` documentation of individual components for supported properties.
|
||||
|
||||
## Using styles
|
||||
|
||||
All the React Native components accept a `style` attribute.
|
||||
All the React Native components accept a `style` property. The value can be a
|
||||
registered object, a plain object, or an array.
|
||||
|
||||
```js
|
||||
<Text style={styles.text} />
|
||||
// registered object
|
||||
<View style={styles.view} />
|
||||
|
||||
// plain object
|
||||
<View style={{ transform: [ { translateX } ] }} />
|
||||
|
||||
// array of registered or plain objects
|
||||
<View style={[ styles.container, this.props.style ]} />
|
||||
```
|
||||
|
||||
A common pattern is to conditionally add style based on a condition:
|
||||
The array syntax will merge styles from left-to-right as normal JavaScript
|
||||
objects, and can be used to conditionally apply styles:
|
||||
|
||||
```js
|
||||
// either
|
||||
<View style={[
|
||||
styles.base,
|
||||
styles.container,
|
||||
this.state.active && styles.active
|
||||
]} />
|
||||
```
|
||||
|
||||
When styles are registered with `StyleSheet.create`, the return value is a
|
||||
number and not a style object. This is important for performance optimizations,
|
||||
but still allows you to merge styles in a deterministic manner at runtime. If
|
||||
you need access to the underlying style objects you need to use
|
||||
`StyleSheet.flatten` (but be aware that this is not the optimized path).
|
||||
|
||||
## Composing styles
|
||||
|
||||
In order to let a call site customize the style of your component children, you
|
||||
can pass styles around. Use `View.propTypes.style` and `Text.propTypes.style` in
|
||||
order to make sure only valid styles are being passed.
|
||||
To let other components customize the style of a component's children you can
|
||||
expose a prop so styles can be explicitly passed into the component.
|
||||
|
||||
```js
|
||||
class List extends React.Component {
|
||||
static propTypes = {
|
||||
style: View.propTypes.style,
|
||||
elementStyle: View.propTypes.style,
|
||||
style: ViewPropTypes.style,
|
||||
elementStyle: ViewPropTypes.style,
|
||||
}
|
||||
|
||||
render() {
|
||||
@@ -90,56 +107,125 @@ In another file:
|
||||
|
||||
You also have much greater control over how styles are composed when compared
|
||||
to using class names. For example, you may choose to accept a limited subset
|
||||
of style props in the component's API, and control when they are applied:
|
||||
of style props in the component's API, and control when they are applied.
|
||||
|
||||
```js
|
||||
class List extends React.Component {
|
||||
static propTypes = {
|
||||
children: React.PropTypes.any,
|
||||
// limit which styles are accepted
|
||||
style: React.PropTypes.shape({
|
||||
borderColor: View.propTypes.borderColor,
|
||||
borderWidth: View.propTypes.borderWidth
|
||||
})
|
||||
}
|
||||
## How styles are resolved
|
||||
|
||||
render() {
|
||||
return (
|
||||
<View
|
||||
children={children}
|
||||
style={[
|
||||
this.props.style,
|
||||
// override border-color when scrolling
|
||||
isScrolling && { borderColor: 'transparent' }
|
||||
]}
|
||||
/>
|
||||
)
|
||||
}
|
||||
}
|
||||
React Native style resolution is deterministic and slightly different from CSS.
|
||||
|
||||
In the following HTML/CSS example, the `.margin` selector is defined last in
|
||||
the CSS and takes precedence over the previous rules, resulting in a margin of
|
||||
`0, 0, 0, 0`.
|
||||
|
||||
```html
|
||||
<style>
|
||||
.marginTop { margin-top: 10px; }
|
||||
.marginBottom { margin-bottom: 20px; }
|
||||
.margin { margin: 0; }
|
||||
</style>
|
||||
<div class="marginTop marginBottom margin"></div>
|
||||
```
|
||||
|
||||
## Media Queries
|
||||
But in React Native the most *specific* style property takes precedence,
|
||||
resulting in margins of `10, 0, 20, 0`.
|
||||
|
||||
```js
|
||||
const style = [
|
||||
{ marginTop: 10 },
|
||||
{ marginBottom: 20 },
|
||||
{ margin: 0 }
|
||||
];
|
||||
|
||||
const Box = () => <View style={style} />
|
||||
```
|
||||
|
||||
## Implementation details
|
||||
|
||||
React Native for Web transforms React Native styles into React DOM styles. Any
|
||||
styles defined using `StyleSheet.create` will ultimately be rendered using CSS
|
||||
class names.
|
||||
|
||||
React Native for Web introduced a novel strategy to achieve this. Each rule is
|
||||
broken down into declarations, properties are expanded to their long-form, and
|
||||
the resulting key-value pairs are mapped to unique "atomic CSS" class names.
|
||||
|
||||
Input:
|
||||
|
||||
```js
|
||||
const Box = () => <View style={styles.box} />
|
||||
|
||||
const styles = StyleSheet.create({
|
||||
box: {
|
||||
margin: 0
|
||||
}
|
||||
});
|
||||
```
|
||||
|
||||
Output:
|
||||
|
||||
```html
|
||||
<style>
|
||||
.rn-1mnahxq { margin-top: 0px; }
|
||||
.rn-61z16t { margin-right: 0px; }
|
||||
.rn-p1pxzi { margin-bottom: 0px; }
|
||||
.rn-11wrixw { margin-left: 0px; }
|
||||
</style>
|
||||
|
||||
<div class="rn-156q2ks rn-61z16t rn-p1pxzi rn-11wrixw"></div>
|
||||
```
|
||||
|
||||
This ensures that CSS order doesn't impact rendering and CSS rules are
|
||||
efficiently deduplicated. Rather than the total CSS growing in proportion to
|
||||
the number of *rules*, it grows in proportion to the number of *unique
|
||||
declarations*. As a result, the DOM style sheet is only written to when new
|
||||
unique declarations are defined and it is usually small enough to be
|
||||
pre-rendered and inlined.
|
||||
|
||||
Class names are deterministic, which means that the resulting CSS and HTML is
|
||||
consistent across builds – important for large apps using code-splitting and
|
||||
deploying incremental updates.
|
||||
|
||||
At runtime registered styles are resolved to DOM style props and memoized.
|
||||
Any dynamic styles that contain declarations previously registered as static
|
||||
styles can also be converted to CSS class names. Otherwise, they render as
|
||||
inline styles.
|
||||
|
||||
All this allows React Native for Web to support the rich functionality of React
|
||||
Native styles (including RTL layouts and `setNativeProps`) while providing one
|
||||
of the [fastest](https://github.com/necolas/react-native-web/blob/master/benchmarks/README.md),
|
||||
safest, and most efficient styles-in-JavaScript solutions.
|
||||
|
||||
## FAQs
|
||||
|
||||
### What about Media Queries?
|
||||
|
||||
`StyleSheet.create` is a way of defining the styles your application requires;
|
||||
it does not concern itself with _where_ or _when_ those styles are applied to
|
||||
elements.
|
||||
|
||||
There are various React libraries wrapping JavaScript Media Query API's, e.g.,
|
||||
Media Queries may not be most appropriate for component-based designs. React
|
||||
Native provides the `Dimensions` API and `onLayout` props. If you do need Media
|
||||
Queries, using the `matchMedia` DOM API has the benefit of allowing you to swap
|
||||
out entire components, not just styles. There are also many React libraries
|
||||
wrapping JavaScript Media Query API's, e.g.,
|
||||
[react-media](https://github.com/reacttraining/react-media),
|
||||
[react-media-queries](https://github.com/bloodyowl/react-media-queries),
|
||||
[media-query-fascade](https://github.com/tanem/media-query-facade), or
|
||||
[react-responsive](https://github.com/contra/react-responsive). This has the
|
||||
benefit of co-locating breakpoint-specific DOM and style changes.
|
||||
[react-responsive](https://github.com/contra/react-responsive).
|
||||
|
||||
## Pseudo-classes and pseudo-elements
|
||||
### What about pseudo-classes and pseudo-elements?
|
||||
|
||||
Pseudo-classes like `:hover` and `:focus` can be implemented with events (e.g.
|
||||
`onFocus`). Pseudo-elements are not supported; elements should be used instead.
|
||||
|
||||
### Reset
|
||||
### Do I need a CSS reset?
|
||||
|
||||
You **do not** need to include a CSS reset or
|
||||
[normalize.css](https://necolas.github.io/normalize.css/).
|
||||
No. React Native for Web includes a very small CSS reset that removes unwanted
|
||||
User Agent styles from (pseudo-)elements beyond the reach of React (e.g.,
|
||||
`html`, `body`) or inline styles (e.g., `::-moz-focus-inner`). The rest is
|
||||
handled at the component-level.
|
||||
|
||||
React Native for Web includes a very small CSS reset taken from normalize.css.
|
||||
It removes unwanted User Agent styles from (pseudo-)elements beyond the reach
|
||||
of React (e.g., `html`, `body`) or inline styles (e.g., `::-moz-focus-inner`).
|
||||
### What about using DevTools?
|
||||
|
||||
It's recommended that you rely more on React DevTools and live/hot-reloading
|
||||
rather than inspecting and editing the DOM directly.
|
||||
|
||||
BIN
docs/static/components.png
vendored
|
Before Width: | Height: | Size: 12 KiB |
BIN
docs/static/styling-strategy.png
vendored
|
Before Width: | Height: | Size: 38 KiB |
12
docs/storybook/.storybook/config.js
Normal file
@@ -0,0 +1,12 @@
|
||||
import { configure, addDecorator } from '@kadira/storybook';
|
||||
import centered from './decorator-centered';
|
||||
|
||||
const context = require.context('../', true, /Example\.js$/);
|
||||
|
||||
addDecorator(centered);
|
||||
|
||||
function loadStories() {
|
||||
context.keys().forEach(context);
|
||||
}
|
||||
|
||||
configure(loadStories, module);
|
||||
@@ -1,5 +1,5 @@
|
||||
import React from 'react';
|
||||
import { StyleSheet, View } from 'react-native'
|
||||
import { StyleSheet, View } from 'react-native';
|
||||
|
||||
const styles = StyleSheet.create({
|
||||
root: {
|
||||
@@ -9,9 +9,9 @@ const styles = StyleSheet.create({
|
||||
}
|
||||
});
|
||||
|
||||
export default function (renderStory) {
|
||||
export default function(renderStory) {
|
||||
return (
|
||||
<View style={[ StyleSheet.absoluteFill, styles.root ]}>
|
||||
<View style={[StyleSheet.absoluteFill, styles.root]}>
|
||||
{renderStory()}
|
||||
</View>
|
||||
);
|
||||
@@ -1,5 +1,5 @@
|
||||
const path = require('path')
|
||||
const webpack = require('webpack')
|
||||
const path = require('path');
|
||||
const webpack = require('webpack');
|
||||
|
||||
const DEV = process.env.NODE_ENV !== 'production';
|
||||
|
||||
@@ -27,7 +27,7 @@ module.exports = {
|
||||
],
|
||||
resolve: {
|
||||
alias: {
|
||||
'react-native': path.join(__dirname, '../../src/module')
|
||||
'react-native': path.join(__dirname, '../../../src/module')
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
@@ -1,6 +1,6 @@
|
||||
import { Clipboard, Text, TextInput, View } from 'react-native'
|
||||
import { Clipboard, Text, TextInput, View } from 'react-native';
|
||||
import React, { Component } from 'react';
|
||||
import { action, storiesOf } from '@kadira/storybook';
|
||||
import { storiesOf } from '@kadira/storybook';
|
||||
|
||||
class ClipboardExample extends Component {
|
||||
render() {
|
||||
@@ -12,13 +12,17 @@ class ClipboardExample extends Component {
|
||||
placeholder={'Try pasting here afterwards'}
|
||||
style={{ borderWidth: 1, height: 200, marginVertical: 20 }}
|
||||
/>
|
||||
<Text onPress={this._handleGet}>(Clipboard.getString returns a Promise that always resolves to an empty string on web)</Text>
|
||||
<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}`) });
|
||||
Clipboard.getString().then(value => {
|
||||
console.log(`Clipboard value: ${value}`);
|
||||
});
|
||||
}
|
||||
|
||||
_handleSet() {
|
||||
@@ -27,7 +31,4 @@ class ClipboardExample extends Component {
|
||||
}
|
||||
}
|
||||
|
||||
storiesOf('api: Clipboard', module)
|
||||
.add('setString', () => (
|
||||
<ClipboardExample />
|
||||
));
|
||||
storiesOf('api: Clipboard', module).add('setString', () => <ClipboardExample />);
|
||||
@@ -1,50 +1,50 @@
|
||||
import { storiesOf } from '@kadira/storybook';
|
||||
import { I18nManager, StyleSheet, TouchableHighlight, Text, View } from 'react-native'
|
||||
import { I18nManager, StyleSheet, TouchableHighlight, Text, View } from 'react-native';
|
||||
import React, { Component } from 'react';
|
||||
|
||||
class I18nManagerExample extends Component {
|
||||
componentWillUnmount() {
|
||||
I18nManager.setPreferredLanguageRTL(false)
|
||||
I18nManager.setPreferredLanguageRTL(false);
|
||||
}
|
||||
|
||||
render() {
|
||||
return (
|
||||
<View style={styles.container}>
|
||||
<Text accessibilityRole='heading' style={styles.welcome}>
|
||||
<Text accessibilityRole="heading" style={styles.welcome}>
|
||||
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.
|
||||
</Text>
|
||||
<Text style={[ styles.text, styles.rtlText ]}>
|
||||
<Text style={[styles.text, styles.rtlText]}>
|
||||
أحب اللغة العربية
|
||||
</Text>
|
||||
<Text style={[ styles.text, styles.textAlign ]}>
|
||||
<Text style={[styles.text, styles.textAlign]}>
|
||||
textAlign toggles
|
||||
</Text>
|
||||
<View style={styles.horizontal}>
|
||||
<View style={[ styles.box, { backgroundColor: 'lightblue' } ]}>
|
||||
<View style={[styles.box, { backgroundColor: 'lightblue' }]}>
|
||||
<Text>One</Text>
|
||||
</View>
|
||||
<View style={[ styles.box ]}>
|
||||
<View style={[styles.box]}>
|
||||
<Text>Two</Text>
|
||||
</View>
|
||||
</View>
|
||||
<TouchableHighlight
|
||||
onPress={this._handleToggle}
|
||||
style={styles.toggle}
|
||||
underlayColor='rgba(0,0,0,0.25)'
|
||||
underlayColor="rgba(0,0,0,0.25)"
|
||||
>
|
||||
<Text>Toggle LTR/RTL</Text>
|
||||
</TouchableHighlight>
|
||||
</View>
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
_handleToggle = () => {
|
||||
I18nManager.setPreferredLanguageRTL(!I18nManager.isRTL)
|
||||
I18nManager.setPreferredLanguageRTL(!I18nManager.isRTL);
|
||||
this.forceUpdate();
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
const styles = StyleSheet.create({
|
||||
@@ -82,9 +82,6 @@ const styles = StyleSheet.create({
|
||||
marginTop: 10,
|
||||
padding: 10
|
||||
}
|
||||
})
|
||||
});
|
||||
|
||||
storiesOf('api: I18nManager', module)
|
||||
.add('RTL layout', () => (
|
||||
<I18nManagerExample />
|
||||
))
|
||||
storiesOf('api: I18nManager', module).add('RTL layout', () => <I18nManagerExample />);
|
||||
@@ -1,12 +1,12 @@
|
||||
import { Linking, StyleSheet, Text, View } from 'react-native'
|
||||
import { Linking, StyleSheet, Text, View } from 'react-native';
|
||||
import React, { Component } from 'react';
|
||||
import { storiesOf, action } from '@kadira/storybook';
|
||||
import { storiesOf } from '@kadira/storybook';
|
||||
|
||||
const url = 'https://mathiasbynens.github.io/rel-noopener/malicious.html';
|
||||
|
||||
class LinkingExample extends Component {
|
||||
handlePress() {
|
||||
Linking.canOpenURL(url).then((supported) => {
|
||||
Linking.canOpenURL(url).then(supported => {
|
||||
return Linking.openURL(url);
|
||||
});
|
||||
}
|
||||
@@ -17,7 +17,12 @@ class LinkingExample extends Component {
|
||||
<Text onPress={this.handlePress} style={styles.text}>
|
||||
Linking.openURL (Expect: "The previous tab is safe and intact")
|
||||
</Text>
|
||||
<Text accessibilityRole='link' href='https://mathiasbynens.github.io/rel-noopener/malicious.html' style={styles.text} target='_blank'>
|
||||
<Text
|
||||
accessibilityRole="link"
|
||||
href="https://mathiasbynens.github.io/rel-noopener/malicious.html"
|
||||
style={styles.text}
|
||||
target="_blank"
|
||||
>
|
||||
target="_blank" (Expect: "The previous tab is safe and intact")
|
||||
</Text>
|
||||
</View>
|
||||
@@ -31,7 +36,4 @@ const styles = StyleSheet.create({
|
||||
}
|
||||
});
|
||||
|
||||
storiesOf('api: Linking', module)
|
||||
.add('Safe linking', () => (
|
||||
<LinkingExample />
|
||||
));
|
||||
storiesOf('api: Linking', module).add('Safe linking', () => <LinkingExample />);
|
||||
@@ -1,24 +1,18 @@
|
||||
'use strict';
|
||||
/* eslint-disable react/jsx-no-bind */
|
||||
|
||||
import createReactClass from 'create-react-class';
|
||||
import { storiesOf, action } from '@kadira/storybook';
|
||||
import React from 'react';
|
||||
import { storiesOf } from '@kadira/storybook';
|
||||
import { PanResponder, StyleSheet, View } from 'react-native';
|
||||
|
||||
var React = require('react');
|
||||
var ReactNative = require('react-native');
|
||||
var {
|
||||
PanResponder,
|
||||
StyleSheet,
|
||||
View
|
||||
} = ReactNative;
|
||||
const CIRCLE_SIZE = 80;
|
||||
|
||||
var CIRCLE_SIZE = 80;
|
||||
|
||||
var PanResponderExample = createReactClass({
|
||||
const PanResponderExample = createReactClass({
|
||||
_panResponder: {},
|
||||
_previousLeft: 0,
|
||||
_previousTop: 0,
|
||||
_circleStyles: {},
|
||||
circle: (null : ?{ setNativeProps(props: Object): void }),
|
||||
circle: (null: ?{ setNativeProps(props: Object): void }),
|
||||
|
||||
componentWillMount: function() {
|
||||
this._panResponder = PanResponder.create({
|
||||
@@ -27,7 +21,7 @@ var PanResponderExample = createReactClass({
|
||||
onPanResponderGrant: this._handlePanResponderGrant,
|
||||
onPanResponderMove: this._handlePanResponderMove,
|
||||
onPanResponderRelease: this._handlePanResponderEnd,
|
||||
onPanResponderTerminate: this._handlePanResponderEnd,
|
||||
onPanResponderTerminate: this._handlePanResponderEnd
|
||||
});
|
||||
this._previousLeft = 20;
|
||||
this._previousTop = 84;
|
||||
@@ -35,7 +29,7 @@ var PanResponderExample = createReactClass({
|
||||
style: {
|
||||
left: this._previousLeft,
|
||||
top: this._previousTop,
|
||||
backgroundColor: 'green',
|
||||
backgroundColor: 'green'
|
||||
}
|
||||
};
|
||||
},
|
||||
@@ -46,10 +40,9 @@ var PanResponderExample = createReactClass({
|
||||
|
||||
render: function() {
|
||||
return (
|
||||
<View
|
||||
style={styles.container}>
|
||||
<View style={styles.container}>
|
||||
<View
|
||||
ref={(circle) => {
|
||||
ref={circle => {
|
||||
this.circle = circle;
|
||||
}}
|
||||
style={styles.circle}
|
||||
@@ -95,23 +88,21 @@ var PanResponderExample = createReactClass({
|
||||
this._unHighlight();
|
||||
this._previousLeft += gestureState.dx;
|
||||
this._previousTop += gestureState.dy;
|
||||
},
|
||||
}
|
||||
});
|
||||
|
||||
var styles = StyleSheet.create({
|
||||
const styles = StyleSheet.create({
|
||||
circle: {
|
||||
width: CIRCLE_SIZE,
|
||||
height: CIRCLE_SIZE,
|
||||
borderRadius: CIRCLE_SIZE / 2,
|
||||
position: 'absolute',
|
||||
top: 0,
|
||||
top: 0
|
||||
},
|
||||
container: {
|
||||
flex: 1,
|
||||
paddingTop: 64,
|
||||
},
|
||||
paddingTop: 64
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
storiesOf('api: PanResponder', module)
|
||||
.add('example', () => <PanResponderExample />)
|
||||
storiesOf('api: PanResponder', module).add('example', () => <PanResponderExample />);
|
||||
@@ -1,9 +1,3 @@
|
||||
import createReactClass from 'create-react-class';
|
||||
import React from 'react';
|
||||
import { storiesOf, action } from '@kadira/storybook';
|
||||
import { ActivityIndicator, StyleSheet, View } from 'react-native'
|
||||
import TimerMixin from 'react-timer-mixin';
|
||||
|
||||
/**
|
||||
* Copyright (c) 2013-present, Facebook, Inc.
|
||||
* All rights reserved.
|
||||
@@ -27,18 +21,24 @@ import TimerMixin from 'react-timer-mixin';
|
||||
* @flow
|
||||
*/
|
||||
|
||||
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';
|
||||
|
||||
const ToggleAnimatingActivityIndicator = createReactClass({
|
||||
mixins: [TimerMixin],
|
||||
|
||||
getInitialState() {
|
||||
return {
|
||||
animating: true,
|
||||
animating: true
|
||||
};
|
||||
},
|
||||
|
||||
setToggleTimeout() {
|
||||
this.setTimeout(() => {
|
||||
this.setState({animating: !this.state.animating});
|
||||
this.setState({ animating: !this.state.animating });
|
||||
this.setToggleTimeout();
|
||||
}, 2000);
|
||||
},
|
||||
@@ -51,9 +51,9 @@ const ToggleAnimatingActivityIndicator = createReactClass({
|
||||
return (
|
||||
<ActivityIndicator
|
||||
animating={this.state.animating}
|
||||
style={styles.centering}
|
||||
hidesWhenStopped={this.props.hidesWhenStopped}
|
||||
size="large"
|
||||
style={styles.centering}
|
||||
/>
|
||||
);
|
||||
}
|
||||
@@ -63,11 +63,7 @@ const examples = [
|
||||
{
|
||||
title: 'Default',
|
||||
render() {
|
||||
return (
|
||||
<ActivityIndicator
|
||||
style={[styles.centering]}
|
||||
/>
|
||||
);
|
||||
return <ActivityIndicator style={[styles.centering]} />;
|
||||
}
|
||||
},
|
||||
{
|
||||
@@ -87,11 +83,7 @@ const examples = [
|
||||
title: 'Large',
|
||||
render() {
|
||||
return (
|
||||
<ActivityIndicator
|
||||
style={[styles.centering, styles.gray]}
|
||||
color="white"
|
||||
size="large"
|
||||
/>
|
||||
<ActivityIndicator color="white" size="large" style={[styles.centering, styles.gray]} />
|
||||
);
|
||||
}
|
||||
},
|
||||
@@ -100,22 +92,10 @@ const examples = [
|
||||
render() {
|
||||
return (
|
||||
<View style={styles.horizontal}>
|
||||
<ActivityIndicator
|
||||
size="large"
|
||||
color="#0000ff"
|
||||
/>
|
||||
<ActivityIndicator
|
||||
size="large"
|
||||
color="#aa00aa"
|
||||
/>
|
||||
<ActivityIndicator
|
||||
size="large"
|
||||
color="#aa3300"
|
||||
/>
|
||||
<ActivityIndicator
|
||||
size="large"
|
||||
color="#00aa00"
|
||||
/>
|
||||
<ActivityIndicator color="#0000ff" size="large" />
|
||||
<ActivityIndicator color="#aa00aa" size="large" />
|
||||
<ActivityIndicator color="#aa3300" size="large" />
|
||||
<ActivityIndicator color="#00aa00" size="large" />
|
||||
</View>
|
||||
);
|
||||
}
|
||||
@@ -137,33 +117,29 @@ const examples = [
|
||||
return (
|
||||
<View style={[styles.horizontal, styles.centering]}>
|
||||
<ActivityIndicator size={40} />
|
||||
<ActivityIndicator
|
||||
style={{ marginLeft: 20, transform: [ {scale: 1.5} ] }}
|
||||
size="large"
|
||||
/>
|
||||
<ActivityIndicator size="large" style={{ marginLeft: 20, transform: [{ scale: 1.5 }] }} />
|
||||
</View>
|
||||
);
|
||||
}
|
||||
},
|
||||
}
|
||||
];
|
||||
|
||||
const styles = StyleSheet.create({
|
||||
centering: {
|
||||
alignItems: 'center',
|
||||
justifyContent: 'center',
|
||||
padding: 8,
|
||||
padding: 8
|
||||
},
|
||||
gray: {
|
||||
backgroundColor: '#cccccc',
|
||||
backgroundColor: '#cccccc'
|
||||
},
|
||||
horizontal: {
|
||||
flexDirection: 'row',
|
||||
justifyContent: 'space-around',
|
||||
padding: 8,
|
||||
},
|
||||
padding: 8
|
||||
}
|
||||
});
|
||||
|
||||
examples.forEach((example) => {
|
||||
storiesOf('component: ActivityIndicator', module)
|
||||
.add(example.title, () => example.render())
|
||||
})
|
||||
examples.forEach(example => {
|
||||
storiesOf('component: ActivityIndicator', module).add(example.title, () => example.render());
|
||||
});
|
||||
@@ -1,6 +1,6 @@
|
||||
import React from 'react';
|
||||
import { action, storiesOf } from '@kadira/storybook';
|
||||
import { Button, StyleSheet, View } from 'react-native';
|
||||
import { Button, View } from 'react-native';
|
||||
|
||||
const onButtonPress = action('Button has been pressed!');
|
||||
|
||||
@@ -13,12 +13,12 @@ const examples = [
|
||||
render: function() {
|
||||
return (
|
||||
<Button
|
||||
accessibilityLabel="See an informative alert"
|
||||
onPress={onButtonPress}
|
||||
title="Press Me"
|
||||
accessibilityLabel="See an informative alert"
|
||||
/>
|
||||
);
|
||||
},
|
||||
}
|
||||
},
|
||||
{
|
||||
title: 'Adjusted color',
|
||||
@@ -28,35 +28,34 @@ const examples = [
|
||||
render: function() {
|
||||
return (
|
||||
<Button
|
||||
accessibilityLabel="Learn more about purple"
|
||||
color="#841584"
|
||||
onPress={onButtonPress}
|
||||
title="Press Purple"
|
||||
color="#841584"
|
||||
accessibilityLabel="Learn more about purple"
|
||||
/>
|
||||
);
|
||||
},
|
||||
}
|
||||
},
|
||||
{
|
||||
title: 'Fit to text layout',
|
||||
description: 'This layout strategy lets the title define the width of ' +
|
||||
'the button',
|
||||
description: 'This layout strategy lets the title define the width of the button',
|
||||
render: function() {
|
||||
return (
|
||||
<View style={{flexDirection: 'row', justifyContent: 'space-between'}}>
|
||||
<View style={{ flexDirection: 'row', justifyContent: 'space-between' }}>
|
||||
<Button
|
||||
accessibilityLabel="This sounds great!"
|
||||
onPress={onButtonPress}
|
||||
title="This looks great!"
|
||||
accessibilityLabel="This sounds great!"
|
||||
/>
|
||||
<Button
|
||||
accessibilityLabel="Ok, Great!"
|
||||
color="#841584"
|
||||
onPress={onButtonPress}
|
||||
title="Ok!"
|
||||
color="#841584"
|
||||
accessibilityLabel="Ok, Great!"
|
||||
/>
|
||||
</View>
|
||||
);
|
||||
},
|
||||
}
|
||||
},
|
||||
{
|
||||
title: 'Disabled Button',
|
||||
@@ -64,17 +63,16 @@ const examples = [
|
||||
render: function() {
|
||||
return (
|
||||
<Button
|
||||
accessibilityLabel="See an informative alert"
|
||||
disabled
|
||||
onPress={onButtonPress}
|
||||
title="I Am Disabled"
|
||||
accessibilityLabel="See an informative alert"
|
||||
/>
|
||||
);
|
||||
},
|
||||
},
|
||||
}
|
||||
}
|
||||
];
|
||||
|
||||
examples.forEach((example) => {
|
||||
storiesOf('component: Button', module)
|
||||
.add(example.title, () => example.render());
|
||||
examples.forEach(example => {
|
||||
storiesOf('component: Button', module).add(example.title, () => example.render());
|
||||
});
|
||||
@@ -1,7 +1,4 @@
|
||||
import createReactClass from 'create-react-class';
|
||||
import React from 'react';
|
||||
import { storiesOf, action, addDecorator } from '@kadira/storybook';
|
||||
import { ActivityIndicator, Image, Platform, StyleSheet, Text, View } from 'react-native'
|
||||
/* eslint-disable react/jsx-no-bind */
|
||||
|
||||
/**
|
||||
* Copyright (c) 2013-present, Facebook, Inc.
|
||||
@@ -26,56 +23,69 @@ import { ActivityIndicator, Image, Platform, StyleSheet, Text, View } from 'reac
|
||||
* @flow
|
||||
*/
|
||||
|
||||
var 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==';
|
||||
import createReactClass from 'create-react-class';
|
||||
import React from 'react';
|
||||
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==';
|
||||
|
||||
//var ImageCapInsetsExample = require('./ImageCapInsetsExample');
|
||||
const IMAGE_PREFETCH_URL = 'http://origami.design/public/images/bird-logo.png?r=1&t=' + Date.now();
|
||||
var prefetchTask = Image.prefetch(IMAGE_PREFETCH_URL);
|
||||
const prefetchTask = Image.prefetch(IMAGE_PREFETCH_URL);
|
||||
|
||||
var NetworkImageCallbackExample = createReactClass({
|
||||
const NetworkImageCallbackExample = createReactClass({
|
||||
getInitialState: function() {
|
||||
return {
|
||||
events: [],
|
||||
startLoadPrefetched: false,
|
||||
mountTime: new Date(),
|
||||
mountTime: new Date()
|
||||
};
|
||||
},
|
||||
|
||||
componentWillMount() {
|
||||
this.setState({mountTime: new Date()});
|
||||
this.setState({ mountTime: new Date() });
|
||||
},
|
||||
|
||||
render: function() {
|
||||
var { mountTime } = this.state;
|
||||
const { mountTime } = this.state;
|
||||
|
||||
return (
|
||||
<View>
|
||||
<Image
|
||||
source={this.props.source}
|
||||
style={[styles.base, {overflow: 'visible'}]}
|
||||
onLoadStart={() => this._loadEventFired(`✔ onLoadStart (+${new Date() - mountTime}ms)`)}
|
||||
onLoad={() => this._loadEventFired(`✔ onLoad (+${new Date() - mountTime}ms)`)}
|
||||
onLoadEnd={() => {
|
||||
this._loadEventFired(`✔ onLoadEnd (+${new Date() - mountTime}ms)`);
|
||||
this.setState({startLoadPrefetched: true}, () => {
|
||||
prefetchTask.then(() => {
|
||||
this._loadEventFired(`✔ Prefetch OK (+${new Date() - mountTime}ms)`);
|
||||
}, error => {
|
||||
this._loadEventFired(`✘ Prefetch failed (+${new Date() - mountTime}ms)`);
|
||||
});
|
||||
this.setState({ startLoadPrefetched: true }, () => {
|
||||
prefetchTask.then(
|
||||
() => {
|
||||
this._loadEventFired(`✔ Prefetch OK (+${new Date() - mountTime}ms)`);
|
||||
},
|
||||
error => {
|
||||
this._loadEventFired(`✘ Prefetch failed (+${new Date() - mountTime}ms)`);
|
||||
console.log(error);
|
||||
}
|
||||
);
|
||||
});
|
||||
}}
|
||||
onLoadStart={() => this._loadEventFired(`✔ onLoadStart (+${new Date() - mountTime}ms)`)}
|
||||
source={this.props.source}
|
||||
style={[styles.base, { overflow: 'visible' }]}
|
||||
/>
|
||||
{this.state.startLoadPrefetched ?
|
||||
<Image
|
||||
source={this.props.prefetchedSource}
|
||||
style={[styles.base, {overflow: 'visible'}]}
|
||||
onLoadStart={() => this._loadEventFired(`✔ (prefetched) onLoadStart (+${new Date() - mountTime}ms)`)}
|
||||
onLoad={() => this._loadEventFired(`✔ (prefetched) onLoad (+${new Date() - mountTime}ms)`)}
|
||||
onLoadEnd={() => this._loadEventFired(`✔ (prefetched) onLoadEnd (+${new Date() - mountTime}ms)`)}
|
||||
/>
|
||||
{this.state.startLoadPrefetched
|
||||
? <Image
|
||||
onLoad={() =>
|
||||
this._loadEventFired(`✔ (prefetched) onLoad (+${new Date() - mountTime}ms)`)}
|
||||
onLoadEnd={() =>
|
||||
this._loadEventFired(`✔ (prefetched) onLoadEnd (+${new Date() - mountTime}ms)`)}
|
||||
onLoadStart={() =>
|
||||
this._loadEventFired(`✔ (prefetched) onLoadStart (+${new Date() - mountTime}ms)`)}
|
||||
source={this.props.prefetchedSource}
|
||||
style={[styles.base, { overflow: 'visible' }]}
|
||||
/>
|
||||
: null}
|
||||
<Text style={{marginTop: 20}}>
|
||||
<Text style={{ marginTop: 20 }}>
|
||||
{this.state.events.join('\n')}
|
||||
</Text>
|
||||
</View>
|
||||
@@ -83,13 +93,13 @@ var NetworkImageCallbackExample = createReactClass({
|
||||
},
|
||||
|
||||
_loadEventFired(event) {
|
||||
this.setState((state) => {
|
||||
return state.events = [...state.events, event];
|
||||
this.setState(state => {
|
||||
return (state.events = [...state.events, event]);
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
var NetworkImageExample = createReactClass({
|
||||
const NetworkImageExample = createReactClass({
|
||||
getInitialState: function() {
|
||||
return {
|
||||
error: false,
|
||||
@@ -98,35 +108,40 @@ var NetworkImageExample = createReactClass({
|
||||
};
|
||||
},
|
||||
render: function() {
|
||||
var loader = this.state.loading ?
|
||||
<View style={styles.progress}>
|
||||
<Text>{this.state.progress}%</Text>
|
||||
<ActivityIndicator style={{marginLeft:5}} />
|
||||
</View> : null;
|
||||
return this.state.error ?
|
||||
<Text>{this.state.error}</Text> :
|
||||
<Image
|
||||
source={this.props.source}
|
||||
style={[styles.base, {overflow: 'visible'}]}
|
||||
onLoadStart={(e) => this.setState({loading: true})}
|
||||
onError={(e) => this.setState({error: e.nativeEvent.error, loading: false})}
|
||||
onProgress={(e) => this.setState({progress: Math.round(100 * e.nativeEvent.loaded / e.nativeEvent.total)})}
|
||||
onLoad={() => this.setState({loading: false, error: false})}>
|
||||
{loader}
|
||||
</Image>;
|
||||
const loader = this.state.loading
|
||||
? <View style={styles.progress}>
|
||||
<Text>{this.state.progress}%</Text>
|
||||
<ActivityIndicator style={{ marginLeft: 5 }} />
|
||||
</View>
|
||||
: null;
|
||||
return this.state.error
|
||||
? <Text>{this.state.error}</Text>
|
||||
: <Image
|
||||
onError={e => this.setState({ error: e.nativeEvent.error, loading: false })}
|
||||
onLoad={() => this.setState({ loading: false, error: false })}
|
||||
onLoadStart={e => this.setState({ loading: true })}
|
||||
onProgress={e =>
|
||||
this.setState({
|
||||
progress: Math.round(100 * e.nativeEvent.loaded / e.nativeEvent.total)
|
||||
})}
|
||||
source={this.props.source}
|
||||
style={[styles.base, { overflow: 'visible' }]}
|
||||
>
|
||||
{loader}
|
||||
</Image>;
|
||||
}
|
||||
});
|
||||
|
||||
var ImageSizeExample = createReactClass({
|
||||
const ImageSizeExample = createReactClass({
|
||||
getInitialState: function() {
|
||||
return {
|
||||
width: 0,
|
||||
height: 0,
|
||||
height: 0
|
||||
};
|
||||
},
|
||||
componentDidMount: function() {
|
||||
Image.getSize(this.props.source.uri, (width, height) => {
|
||||
this.setState({width, height});
|
||||
this.setState({ width, height });
|
||||
});
|
||||
},
|
||||
render: function() {
|
||||
@@ -147,7 +162,7 @@ var ImageSizeExample = createReactClass({
|
||||
/>
|
||||
</View>
|
||||
);
|
||||
},
|
||||
}
|
||||
});
|
||||
|
||||
/*
|
||||
@@ -213,20 +228,24 @@ 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.',
|
||||
'"http", then it will be downloaded from the network.',
|
||||
render: function() {
|
||||
return (
|
||||
<Image
|
||||
source={{ uri: 'http://facebook.github.io/react/img/logo_og.png', width: 1200, height: 630 }}
|
||||
source={{
|
||||
uri: 'http://facebook.github.io/react/img/logo_og.png',
|
||||
width: 1200,
|
||||
height: 630
|
||||
}}
|
||||
style={styles.base}
|
||||
/>
|
||||
);
|
||||
},
|
||||
}
|
||||
},
|
||||
{
|
||||
title: 'Plain Static Image',
|
||||
description: 'Static assets should be placed in the source code tree, and ' +
|
||||
'required in the same way as JavaScript modules.',
|
||||
'required in the same way as JavaScript modules.',
|
||||
render: function() {
|
||||
return (
|
||||
<View style={styles.horizontal}>
|
||||
@@ -236,36 +255,40 @@ const examples = [
|
||||
{/*<Image source={require('./uie_comment_highlighted.png')} style={styles.icon} />*/}
|
||||
</View>
|
||||
);
|
||||
},
|
||||
}
|
||||
},
|
||||
{
|
||||
title: 'Image Loading Events',
|
||||
render: function() {
|
||||
return (
|
||||
<NetworkImageCallbackExample
|
||||
source={{uri: 'http://origami.design/public/images/bird-logo.png?r=1&t=' + Date.now()}}
|
||||
prefetchedSource={{uri: IMAGE_PREFETCH_URL}}
|
||||
prefetchedSource={{ uri: IMAGE_PREFETCH_URL }}
|
||||
source={{ uri: 'http://origami.design/public/images/bird-logo.png?r=1&t=' + Date.now() }}
|
||||
/>
|
||||
);
|
||||
},
|
||||
}
|
||||
},
|
||||
{
|
||||
title: 'Error Handler',
|
||||
render: function() {
|
||||
return (
|
||||
<NetworkImageExample source={{uri: 'http://TYPO_ERROR_facebook.github.io/react/img/logo_og.png'}} />
|
||||
<NetworkImageExample
|
||||
source={{ uri: 'http://TYPO_ERROR_facebook.github.io/react/img/logo_og.png' }}
|
||||
/>
|
||||
);
|
||||
},
|
||||
platform: 'ios',
|
||||
platform: 'ios'
|
||||
},
|
||||
{
|
||||
title: 'Image Download Progress',
|
||||
render: function() {
|
||||
return (
|
||||
<NetworkImageExample source={{uri: 'http://origami.design/public/images/bird-logo.png?r=1'}}/>
|
||||
<NetworkImageExample
|
||||
source={{ uri: 'http://origami.design/public/images/bird-logo.png?r=1' }}
|
||||
/>
|
||||
);
|
||||
},
|
||||
platform: 'ios',
|
||||
platform: 'ios'
|
||||
},
|
||||
{
|
||||
title: 'defaultSource',
|
||||
@@ -274,12 +297,12 @@ const examples = [
|
||||
return (
|
||||
<Image
|
||||
defaultSource={require('./bunny.png')}
|
||||
source={{uri: 'http://facebook.github.io/origami/public/images/birds.jpg'}}
|
||||
source={{ uri: 'http://facebook.github.io/origami/public/images/birds.jpg' }}
|
||||
style={styles.base}
|
||||
/>
|
||||
);
|
||||
},
|
||||
platform: 'ios',
|
||||
platform: 'ios'
|
||||
},
|
||||
{
|
||||
title: 'Border Color',
|
||||
@@ -288,15 +311,11 @@ const examples = [
|
||||
<View style={styles.horizontal}>
|
||||
<Image
|
||||
source={smallImage}
|
||||
style={[
|
||||
styles.base,
|
||||
styles.background,
|
||||
{borderWidth: 3, borderColor: '#f099f0'}
|
||||
]}
|
||||
style={[styles.base, styles.background, { borderWidth: 3, borderColor: '#f099f0' }]}
|
||||
/>
|
||||
</View>
|
||||
);
|
||||
},
|
||||
}
|
||||
},
|
||||
{
|
||||
title: 'Border Width',
|
||||
@@ -305,32 +324,25 @@ const examples = [
|
||||
<View style={styles.horizontal}>
|
||||
<Image
|
||||
source={smallImage}
|
||||
style={[
|
||||
styles.base,
|
||||
styles.background,
|
||||
{borderWidth: 5, borderColor: '#f099f0'}
|
||||
]}
|
||||
style={[styles.base, styles.background, { borderWidth: 5, borderColor: '#f099f0' }]}
|
||||
/>
|
||||
</View>
|
||||
);
|
||||
},
|
||||
}
|
||||
},
|
||||
{
|
||||
title: 'Border Radius',
|
||||
render: function() {
|
||||
return (
|
||||
<View style={styles.horizontal}>
|
||||
<Image source={fullImage} style={[styles.base, { borderRadius: 5 }]} />
|
||||
<Image
|
||||
style={[styles.base, {borderRadius: 5}]}
|
||||
source={fullImage}
|
||||
/>
|
||||
<Image
|
||||
style={[styles.base, styles.leftMargin, {borderRadius: 19}]}
|
||||
source={fullImage}
|
||||
style={[styles.base, styles.leftMargin, { borderRadius: 19 }]}
|
||||
/>
|
||||
</View>
|
||||
);
|
||||
},
|
||||
}
|
||||
},
|
||||
{
|
||||
title: 'Background Color',
|
||||
@@ -339,71 +351,47 @@ const examples = [
|
||||
<View style={styles.horizontal}>
|
||||
<Image source={smallImage} style={styles.base} />
|
||||
<Image
|
||||
style={[
|
||||
styles.base,
|
||||
styles.leftMargin,
|
||||
{backgroundColor: 'rgba(0, 0, 100, 0.25)'}
|
||||
]}
|
||||
source={smallImage}
|
||||
style={[styles.base, styles.leftMargin, { backgroundColor: 'rgba(0, 0, 100, 0.25)' }]}
|
||||
/>
|
||||
<Image
|
||||
style={[styles.base, styles.leftMargin, {backgroundColor: 'red'}]}
|
||||
source={smallImage}
|
||||
style={[styles.base, styles.leftMargin, { backgroundColor: 'red' }]}
|
||||
/>
|
||||
<Image
|
||||
style={[styles.base, styles.leftMargin, {backgroundColor: 'black'}]}
|
||||
source={smallImage}
|
||||
style={[styles.base, styles.leftMargin, { backgroundColor: 'black' }]}
|
||||
/>
|
||||
</View>
|
||||
);
|
||||
},
|
||||
}
|
||||
},
|
||||
{
|
||||
title: 'Opacity',
|
||||
render: function() {
|
||||
return (
|
||||
<View style={styles.horizontal}>
|
||||
<Image
|
||||
style={[styles.base, {opacity: 1}]}
|
||||
source={fullImage}
|
||||
/>
|
||||
<Image
|
||||
style={[styles.base, styles.leftMargin, {opacity: 0.8}]}
|
||||
source={fullImage}
|
||||
/>
|
||||
<Image
|
||||
style={[styles.base, styles.leftMargin, {opacity: 0.6}]}
|
||||
source={fullImage}
|
||||
/>
|
||||
<Image
|
||||
style={[styles.base, styles.leftMargin, {opacity: 0.4}]}
|
||||
source={fullImage}
|
||||
/>
|
||||
<Image
|
||||
style={[styles.base, styles.leftMargin, {opacity: 0.2}]}
|
||||
source={fullImage}
|
||||
/>
|
||||
<Image
|
||||
style={[styles.base, styles.leftMargin, {opacity: 0}]}
|
||||
source={fullImage}
|
||||
/>
|
||||
<Image source={fullImage} style={[styles.base, { opacity: 1 }]} />
|
||||
<Image source={fullImage} style={[styles.base, styles.leftMargin, { opacity: 0.8 }]} />
|
||||
<Image source={fullImage} style={[styles.base, styles.leftMargin, { opacity: 0.6 }]} />
|
||||
<Image source={fullImage} style={[styles.base, styles.leftMargin, { opacity: 0.4 }]} />
|
||||
<Image source={fullImage} style={[styles.base, styles.leftMargin, { opacity: 0.2 }]} />
|
||||
<Image source={fullImage} style={[styles.base, styles.leftMargin, { opacity: 0 }]} />
|
||||
</View>
|
||||
);
|
||||
},
|
||||
}
|
||||
},
|
||||
{
|
||||
title: 'Nesting',
|
||||
render: function() {
|
||||
return (
|
||||
<Image
|
||||
style={{width: 60, height: 60, backgroundColor: 'transparent'}}
|
||||
source={fullImage}>
|
||||
<Image source={fullImage} style={{ width: 60, height: 60, backgroundColor: 'transparent' }}>
|
||||
<Text style={styles.nestedText}>
|
||||
React
|
||||
</Text>
|
||||
</Image>
|
||||
);
|
||||
},
|
||||
}
|
||||
},
|
||||
/*
|
||||
{
|
||||
@@ -466,91 +454,80 @@ const examples = [
|
||||
<View>
|
||||
{[smallImage, fullImage].map((image, index) => {
|
||||
return (
|
||||
<View key={index}>
|
||||
<View style={styles.horizontal}>
|
||||
<View>
|
||||
<Text style={[styles.resizeModeText]}>
|
||||
Contain
|
||||
</Text>
|
||||
<Image
|
||||
style={styles.resizeMode}
|
||||
resizeMode={Image.resizeMode.contain}
|
||||
source={image}
|
||||
/>
|
||||
<View key={index}>
|
||||
<View style={styles.horizontal}>
|
||||
<View>
|
||||
<Text style={[styles.resizeModeText]}>
|
||||
Contain
|
||||
</Text>
|
||||
<Image
|
||||
resizeMode={Image.resizeMode.contain}
|
||||
source={image}
|
||||
style={styles.resizeMode}
|
||||
/>
|
||||
</View>
|
||||
<View style={styles.leftMargin}>
|
||||
<Text style={[styles.resizeModeText]}>
|
||||
Cover
|
||||
</Text>
|
||||
<Image
|
||||
resizeMode={Image.resizeMode.cover}
|
||||
source={image}
|
||||
style={styles.resizeMode}
|
||||
/>
|
||||
</View>
|
||||
</View>
|
||||
<View style={styles.leftMargin}>
|
||||
<Text style={[styles.resizeModeText]}>
|
||||
Cover
|
||||
</Text>
|
||||
<Image
|
||||
style={styles.resizeMode}
|
||||
resizeMode={Image.resizeMode.cover}
|
||||
source={image}
|
||||
/>
|
||||
<View style={styles.horizontal}>
|
||||
<View>
|
||||
<Text style={[styles.resizeModeText]}>
|
||||
Stretch
|
||||
</Text>
|
||||
<Image
|
||||
resizeMode={Image.resizeMode.stretch}
|
||||
source={image}
|
||||
style={styles.resizeMode}
|
||||
/>
|
||||
</View>
|
||||
<View style={styles.leftMargin}>
|
||||
<Text style={[styles.resizeModeText]}>
|
||||
Repeat
|
||||
</Text>
|
||||
<Image resizeMode={'repeat'} source={image} style={styles.resizeMode} />
|
||||
</View>
|
||||
<View style={styles.leftMargin}>
|
||||
<Text style={[styles.resizeModeText]}>
|
||||
Center
|
||||
</Text>
|
||||
<Image resizeMode={'center'} source={image} style={styles.resizeMode} />
|
||||
</View>
|
||||
</View>
|
||||
</View>
|
||||
<View style={styles.horizontal}>
|
||||
<View>
|
||||
<Text style={[styles.resizeModeText]}>
|
||||
Stretch
|
||||
</Text>
|
||||
<Image
|
||||
style={styles.resizeMode}
|
||||
resizeMode={Image.resizeMode.stretch}
|
||||
source={image}
|
||||
/>
|
||||
</View>
|
||||
<View style={styles.leftMargin}>
|
||||
<Text style={[styles.resizeModeText]}>
|
||||
Repeat
|
||||
</Text>
|
||||
<Image
|
||||
style={styles.resizeMode}
|
||||
resizeMode={'repeat'}
|
||||
source={image}
|
||||
/>
|
||||
</View>
|
||||
<View style={styles.leftMargin}>
|
||||
<Text style={[styles.resizeModeText]}>
|
||||
Center
|
||||
</Text>
|
||||
<Image
|
||||
style={styles.resizeMode}
|
||||
resizeMode={'center'}
|
||||
source={image}
|
||||
/>
|
||||
</View>
|
||||
</View>
|
||||
</View>
|
||||
);
|
||||
})}
|
||||
);
|
||||
})}
|
||||
</View>
|
||||
);
|
||||
},
|
||||
}
|
||||
},
|
||||
{
|
||||
title: 'Animated GIF',
|
||||
render: function() {
|
||||
return (
|
||||
<Image
|
||||
source={{
|
||||
uri: 'http://38.media.tumblr.com/9e9bd08c6e2d10561dd1fb4197df4c4e/tumblr_mfqekpMktw1rn90umo1_500.gif'
|
||||
}}
|
||||
style={styles.gif}
|
||||
source={{uri: 'http://38.media.tumblr.com/9e9bd08c6e2d10561dd1fb4197df4c4e/tumblr_mfqekpMktw1rn90umo1_500.gif'}}
|
||||
/>
|
||||
);
|
||||
},
|
||||
platform: 'ios',
|
||||
platform: 'ios'
|
||||
},
|
||||
{
|
||||
title: 'Base64 image',
|
||||
render: function() {
|
||||
return (
|
||||
<Image
|
||||
style={styles.base64}
|
||||
source={{uri: base64Icon, scale: 3}}
|
||||
/>
|
||||
);
|
||||
return <Image source={{ uri: base64Icon, scale: 3 }} style={styles.base64} />;
|
||||
},
|
||||
platform: 'ios',
|
||||
platform: 'ios'
|
||||
},
|
||||
/*
|
||||
{
|
||||
@@ -569,9 +546,15 @@ const examples = [
|
||||
{
|
||||
title: 'Image Size',
|
||||
render: function() {
|
||||
return <ImageSizeExample source={{ uri: 'https://upload.wikimedia.org/wikipedia/commons/d/d7/Chestnut-mandibled_Toucan.jpg' }} />;
|
||||
},
|
||||
},
|
||||
return (
|
||||
<ImageSizeExample
|
||||
source={{
|
||||
uri: 'https://upload.wikimedia.org/wikipedia/commons/d/d7/Chestnut-mandibled_Toucan.jpg'
|
||||
}}
|
||||
/>
|
||||
);
|
||||
}
|
||||
}
|
||||
/*
|
||||
{
|
||||
title: 'MultipleSourcesExample',
|
||||
@@ -586,13 +569,13 @@ const examples = [
|
||||
*/
|
||||
];
|
||||
|
||||
var fullImage = {uri: 'http://facebook.github.io/react/img/logo_og.png'};
|
||||
var smallImage = {uri: 'http://facebook.github.io/react/img/logo_small_2x.png'};
|
||||
const fullImage = { uri: 'http://facebook.github.io/react/img/logo_og.png' };
|
||||
const smallImage = { uri: 'http://facebook.github.io/react/img/logo_small_2x.png' };
|
||||
|
||||
var styles = StyleSheet.create({
|
||||
const styles = StyleSheet.create({
|
||||
base: {
|
||||
width: 38,
|
||||
height: 38,
|
||||
height: 38
|
||||
},
|
||||
progress: {
|
||||
flex: 1,
|
||||
@@ -601,13 +584,13 @@ var styles = StyleSheet.create({
|
||||
width: 100
|
||||
},
|
||||
leftMargin: {
|
||||
marginLeft: 10,
|
||||
marginLeft: 10
|
||||
},
|
||||
background: {
|
||||
backgroundColor: '#222222'
|
||||
},
|
||||
sectionText: {
|
||||
marginVertical: 6,
|
||||
marginVertical: 6
|
||||
},
|
||||
nestedText: {
|
||||
marginLeft: 12,
|
||||
@@ -623,32 +606,32 @@ var styles = StyleSheet.create({
|
||||
},
|
||||
resizeModeText: {
|
||||
fontSize: 11,
|
||||
marginBottom: 3,
|
||||
marginBottom: 3
|
||||
},
|
||||
icon: {
|
||||
width: 15,
|
||||
height: 15,
|
||||
height: 15
|
||||
},
|
||||
horizontal: {
|
||||
flexDirection: 'row',
|
||||
flexDirection: 'row'
|
||||
},
|
||||
gif: {
|
||||
flex: 1,
|
||||
height: 200,
|
||||
height: 200
|
||||
},
|
||||
base64: {
|
||||
flex: 1,
|
||||
height: 50,
|
||||
resizeMode: 'contain',
|
||||
resizeMode: 'contain'
|
||||
},
|
||||
touchableText: {
|
||||
fontWeight: '500',
|
||||
color: 'blue',
|
||||
},
|
||||
color: 'blue'
|
||||
}
|
||||
});
|
||||
|
||||
examples.forEach((example) => {
|
||||
examples.forEach(example => {
|
||||
storiesOf('component: Image', module)
|
||||
.addDecorator((renderStory) => <View style={{ width: '100%' }}>{renderStory()}</View>)
|
||||
.add(example.title, () => example.render())
|
||||
})
|
||||
.addDecorator(renderStory => <View style={{ width: '100%' }}>{renderStory()}</View>)
|
||||
.add(example.title, () => example.render());
|
||||
});
|
||||
|
Before Width: | Height: | Size: 18 KiB After Width: | Height: | Size: 18 KiB |
|
Before Width: | Height: | Size: 850 B After Width: | Height: | Size: 850 B |
|
Before Width: | Height: | Size: 1.1 KiB After Width: | Height: | Size: 1.1 KiB |
@@ -2,7 +2,7 @@ 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 generateData = length => Array.from({ length }).map((item, i) => i);
|
||||
const dataSource = new ListView.DataSource({ rowHasChanged: (r1, r2) => r1 !== r2 });
|
||||
|
||||
storiesOf('component: ListView', module)
|
||||
@@ -13,11 +13,11 @@ storiesOf('component: ListView', module)
|
||||
dataSource={dataSource.cloneWithRows(generateData(100))}
|
||||
initialListSize={100}
|
||||
// eslint-disable-next-line react/jsx-no-bind
|
||||
onScroll={(e) => { console.log('ScrollView.onScroll', e); } }
|
||||
onScroll={e => {
|
||||
console.log('ScrollView.onScroll', e);
|
||||
}}
|
||||
// eslint-disable-next-line react/jsx-no-bind
|
||||
renderRow={(row) => (
|
||||
<View><Text>{row}</Text></View>
|
||||
)}
|
||||
renderRow={row => <View><Text>{row}</Text></View>}
|
||||
scrollEventThrottle={1000} // 1 event per second
|
||||
style={styles.scrollViewStyle}
|
||||
/>
|
||||
@@ -30,12 +30,12 @@ storiesOf('component: ListView', module)
|
||||
dataSource={dataSource.cloneWithRows(generateData(5000))}
|
||||
initialListSize={100}
|
||||
// eslint-disable-next-line react/jsx-no-bind
|
||||
onScroll={(e) => { console.log('ScrollView.onScroll', e); } }
|
||||
onScroll={e => {
|
||||
console.log('ScrollView.onScroll', e);
|
||||
}}
|
||||
pageSize={50}
|
||||
// eslint-disable-next-line react/jsx-no-bind
|
||||
renderRow={(row) => (
|
||||
<View><Text>{row}</Text></View>
|
||||
)}
|
||||
renderRow={row => <View><Text>{row}</Text></View>}
|
||||
scrollEventThrottle={1000} // 1 event per second
|
||||
style={styles.scrollViewStyle}
|
||||
/>
|
||||
@@ -48,12 +48,12 @@ storiesOf('component: ListView', module)
|
||||
dataSource={dataSource.cloneWithRows(generateData(5000))}
|
||||
initialListSize={5}
|
||||
// eslint-disable-next-line react/jsx-no-bind
|
||||
onScroll={(e) => { console.log('ScrollView.onScroll', e); } }
|
||||
onScroll={e => {
|
||||
console.log('ScrollView.onScroll', e);
|
||||
}}
|
||||
pageSize={1}
|
||||
// eslint-disable-next-line react/jsx-no-bind
|
||||
renderRow={(row) => (
|
||||
<View><Text>{row}</Text></View>
|
||||
)}
|
||||
renderRow={row => <View><Text>{row}</Text></View>}
|
||||
scrollEventThrottle={1000} // 1 event per second
|
||||
style={styles.scrollViewStyle}
|
||||
/>
|
||||
@@ -1,7 +1,7 @@
|
||||
import createReactClass from 'create-react-class';
|
||||
import { ProgressBar, StyleSheet, View } from 'react-native'
|
||||
import { ProgressBar, StyleSheet, View } from 'react-native';
|
||||
import React from 'react';
|
||||
import { storiesOf, action } from '@kadira/storybook';
|
||||
import { storiesOf } from '@kadira/storybook';
|
||||
import TimerMixin from 'react-timer-mixin';
|
||||
|
||||
/**
|
||||
@@ -27,12 +27,12 @@ import TimerMixin from 'react-timer-mixin';
|
||||
* @flow
|
||||
*/
|
||||
|
||||
var ProgressBarExample = createReactClass({
|
||||
const ProgressBarExample = createReactClass({
|
||||
mixins: [TimerMixin],
|
||||
|
||||
getInitialState() {
|
||||
return {
|
||||
progress: 0,
|
||||
progress: 0
|
||||
};
|
||||
},
|
||||
|
||||
@@ -41,49 +41,48 @@ var ProgressBarExample = createReactClass({
|
||||
},
|
||||
|
||||
updateProgress() {
|
||||
var progress = this.state.progress + 0.01;
|
||||
const progress = this.state.progress + 0.01;
|
||||
this.setState({ progress });
|
||||
this.requestAnimationFrame(() => this.updateProgress());
|
||||
},
|
||||
|
||||
getProgress(offset) {
|
||||
var progress = this.state.progress + offset;
|
||||
const progress = this.state.progress + offset;
|
||||
return Math.sin(progress % Math.PI) % 1;
|
||||
},
|
||||
|
||||
render() {
|
||||
return (
|
||||
<View style={styles.container}>
|
||||
<ProgressBar style={styles.progressView} color="purple" progress={this.getProgress(0.2)} />
|
||||
<ProgressBar style={styles.progressView} color="red" progress={this.getProgress(0.4)} />
|
||||
<ProgressBar style={styles.progressView} color="orange" progress={this.getProgress(0.6)} />
|
||||
<ProgressBar style={styles.progressView} color="yellow" progress={this.getProgress(0.8)} />
|
||||
<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} />
|
||||
</View>
|
||||
);
|
||||
},
|
||||
}
|
||||
});
|
||||
|
||||
const examples = [{
|
||||
title: 'progress',
|
||||
render() {
|
||||
return (
|
||||
<ProgressBarExample />
|
||||
);
|
||||
const examples = [
|
||||
{
|
||||
title: 'progress',
|
||||
render() {
|
||||
return <ProgressBarExample />;
|
||||
}
|
||||
},
|
||||
}, {
|
||||
title: 'indeterminate',
|
||||
render() {
|
||||
return (
|
||||
<ProgressBar indeterminate style={styles.progressView} trackColor='#D1E3F6' />
|
||||
);
|
||||
{
|
||||
title: 'indeterminate',
|
||||
render() {
|
||||
return <ProgressBar indeterminate style={styles.progressView} trackColor="#D1E3F6" />;
|
||||
}
|
||||
}
|
||||
}];
|
||||
];
|
||||
|
||||
var styles = StyleSheet.create({
|
||||
const styles = StyleSheet.create({
|
||||
container: {
|
||||
minWidth: 200,
|
||||
marginTop: -20,
|
||||
backgroundColor: 'transparent',
|
||||
backgroundColor: 'transparent'
|
||||
},
|
||||
progressView: {
|
||||
marginTop: 20,
|
||||
@@ -91,7 +90,6 @@ var styles = StyleSheet.create({
|
||||
}
|
||||
});
|
||||
|
||||
examples.forEach((example) => {
|
||||
storiesOf('component: ProgressBar', module)
|
||||
.add(example.title, () => example.render())
|
||||
})
|
||||
examples.forEach(example => {
|
||||
storiesOf('component: ProgressBar', module).add(example.title, () => example.render());
|
||||
});
|
||||
@@ -1,6 +1,8 @@
|
||||
/* eslint-disable react/jsx-no-bind */
|
||||
|
||||
import React from 'react';
|
||||
import { action, storiesOf } from '@kadira/storybook';
|
||||
import { ScrollView, StyleSheet, Text, TouchableHighlight, View } from 'react-native'
|
||||
import { ScrollView, StyleSheet, Text, TouchableHighlight, View } from 'react-native';
|
||||
|
||||
const onScroll = action('ScrollView.onScroll');
|
||||
|
||||
@@ -31,13 +33,13 @@ storiesOf('component: ScrollView', module)
|
||||
style={styles.scrollViewStyle}
|
||||
>
|
||||
{Array.from({ length: 50 }).map((item, i) => (
|
||||
<View key={i} style={[ styles.box, styles.horizontalBox ]}>
|
||||
<View key={i} style={[styles.box, styles.horizontalBox]}>
|
||||
<Text>{i}</Text>
|
||||
</View>
|
||||
))}
|
||||
</ScrollView>
|
||||
</View>
|
||||
))
|
||||
));
|
||||
|
||||
const styles = StyleSheet.create({
|
||||
box: {
|
||||
@@ -56,4 +58,4 @@ const styles = StyleSheet.create({
|
||||
backgroundColor: '#eee',
|
||||
padding: 10
|
||||
}
|
||||
})
|
||||
});
|
||||
@@ -1,7 +1,4 @@
|
||||
import createReactClass from 'create-react-class';
|
||||
import { Platform, Switch, Text, View } from 'react-native'
|
||||
import React from 'react';
|
||||
import { storiesOf, action } from '@kadira/storybook';
|
||||
/* eslint-disable react/jsx-no-bind */
|
||||
|
||||
/**
|
||||
* Copyright (c) 2013-present, Facebook, Inc.
|
||||
@@ -26,23 +23,28 @@ import { storiesOf, action } from '@kadira/storybook';
|
||||
* @flow
|
||||
*/
|
||||
|
||||
var BasicSwitchExample = createReactClass({
|
||||
import createReactClass from 'create-react-class';
|
||||
import { Switch, Text, View } from 'react-native';
|
||||
import React from 'react';
|
||||
import { storiesOf } from '@kadira/storybook';
|
||||
|
||||
const BasicSwitchExample = createReactClass({
|
||||
getInitialState() {
|
||||
return {
|
||||
trueSwitchIsOn: true,
|
||||
falseSwitchIsOn: false,
|
||||
falseSwitchIsOn: false
|
||||
};
|
||||
},
|
||||
render() {
|
||||
return (
|
||||
<View>
|
||||
<Switch
|
||||
onValueChange={(value) => this.setState({falseSwitchIsOn: value})}
|
||||
style={{marginBottom: 10}}
|
||||
onValueChange={value => this.setState({ falseSwitchIsOn: value })}
|
||||
style={{ marginBottom: 10 }}
|
||||
value={this.state.falseSwitchIsOn}
|
||||
/>
|
||||
<Switch
|
||||
onValueChange={(value) => this.setState({trueSwitchIsOn: value})}
|
||||
onValueChange={value => this.setState({ trueSwitchIsOn: value })}
|
||||
value={this.state.trueSwitchIsOn}
|
||||
/>
|
||||
</View>
|
||||
@@ -50,27 +52,22 @@ var BasicSwitchExample = createReactClass({
|
||||
}
|
||||
});
|
||||
|
||||
var DisabledSwitchExample = createReactClass({
|
||||
const DisabledSwitchExample = createReactClass({
|
||||
render() {
|
||||
return (
|
||||
<View>
|
||||
<Switch
|
||||
disabled={true}
|
||||
style={{marginBottom: 10}}
|
||||
value={true} />
|
||||
<Switch
|
||||
disabled={true}
|
||||
value={false} />
|
||||
<Switch disabled={true} style={{ marginBottom: 10 }} value={true} />
|
||||
<Switch disabled={true} value={false} />
|
||||
</View>
|
||||
);
|
||||
},
|
||||
}
|
||||
});
|
||||
|
||||
var ColorSwitchExample = createReactClass({
|
||||
const ColorSwitchExample = createReactClass({
|
||||
getInitialState() {
|
||||
return {
|
||||
colorTrueSwitchIsOn: true,
|
||||
colorFalseSwitchIsOn: false,
|
||||
colorFalseSwitchIsOn: false
|
||||
};
|
||||
},
|
||||
render() {
|
||||
@@ -79,28 +76,28 @@ var ColorSwitchExample = createReactClass({
|
||||
<Switch
|
||||
activeThumbColor="#428bca"
|
||||
activeTrackColor="#A0C4E3"
|
||||
onValueChange={(value) => this.setState({colorFalseSwitchIsOn: value})}
|
||||
style={{marginBottom: 10}}
|
||||
onValueChange={value => this.setState({ colorFalseSwitchIsOn: value })}
|
||||
style={{ marginBottom: 10 }}
|
||||
value={this.state.colorFalseSwitchIsOn}
|
||||
/>
|
||||
<Switch
|
||||
activeThumbColor="#5CB85C"
|
||||
activeTrackColor="#ADDAAD"
|
||||
onValueChange={(value) => this.setState({colorTrueSwitchIsOn: value})}
|
||||
onValueChange={value => this.setState({ colorTrueSwitchIsOn: value })}
|
||||
thumbColor="#EBA9A7"
|
||||
trackColor="#D9534F"
|
||||
value={this.state.colorTrueSwitchIsOn}
|
||||
/>
|
||||
</View>
|
||||
);
|
||||
},
|
||||
}
|
||||
});
|
||||
|
||||
var EventSwitchExample = createReactClass({
|
||||
const EventSwitchExample = createReactClass({
|
||||
getInitialState() {
|
||||
return {
|
||||
eventSwitchIsOn: false,
|
||||
eventSwitchRegressionIsOn: true,
|
||||
eventSwitchRegressionIsOn: true
|
||||
};
|
||||
},
|
||||
render() {
|
||||
@@ -108,24 +105,28 @@ var EventSwitchExample = createReactClass({
|
||||
<View style={{ flexDirection: 'row', justifyContent: 'space-around' }}>
|
||||
<View>
|
||||
<Switch
|
||||
onValueChange={(value) => this.setState({eventSwitchIsOn: value})}
|
||||
style={{marginBottom: 10}}
|
||||
value={this.state.eventSwitchIsOn} />
|
||||
onValueChange={value => this.setState({ eventSwitchIsOn: value })}
|
||||
style={{ marginBottom: 10 }}
|
||||
value={this.state.eventSwitchIsOn}
|
||||
/>
|
||||
<Switch
|
||||
onValueChange={(value) => this.setState({eventSwitchIsOn: value})}
|
||||
style={{marginBottom: 10}}
|
||||
value={this.state.eventSwitchIsOn} />
|
||||
onValueChange={value => this.setState({ eventSwitchIsOn: value })}
|
||||
style={{ marginBottom: 10 }}
|
||||
value={this.state.eventSwitchIsOn}
|
||||
/>
|
||||
<Text>{this.state.eventSwitchIsOn ? 'On' : 'Off'}</Text>
|
||||
</View>
|
||||
<View>
|
||||
<Switch
|
||||
onValueChange={(value) => this.setState({eventSwitchRegressionIsOn: value})}
|
||||
style={{marginBottom: 10}}
|
||||
value={this.state.eventSwitchRegressionIsOn} />
|
||||
onValueChange={value => this.setState({ eventSwitchRegressionIsOn: value })}
|
||||
style={{ marginBottom: 10 }}
|
||||
value={this.state.eventSwitchRegressionIsOn}
|
||||
/>
|
||||
<Switch
|
||||
onValueChange={(value) => this.setState({eventSwitchRegressionIsOn: value})}
|
||||
style={{marginBottom: 10}}
|
||||
value={this.state.eventSwitchRegressionIsOn} />
|
||||
onValueChange={value => this.setState({ eventSwitchRegressionIsOn: value })}
|
||||
style={{ marginBottom: 10 }}
|
||||
value={this.state.eventSwitchRegressionIsOn}
|
||||
/>
|
||||
<Text>{this.state.eventSwitchRegressionIsOn ? 'On' : 'Off'}</Text>
|
||||
</View>
|
||||
</View>
|
||||
@@ -133,24 +134,24 @@ var EventSwitchExample = createReactClass({
|
||||
}
|
||||
});
|
||||
|
||||
var SizeSwitchExample = createReactClass({
|
||||
const SizeSwitchExample = createReactClass({
|
||||
getInitialState() {
|
||||
return {
|
||||
trueSwitchIsOn: true,
|
||||
falseSwitchIsOn: false,
|
||||
falseSwitchIsOn: false
|
||||
};
|
||||
},
|
||||
render() {
|
||||
return (
|
||||
<View>
|
||||
<Switch
|
||||
onValueChange={(value) => this.setState({falseSwitchIsOn: value})}
|
||||
style={{marginBottom: 10, height: '3rem' }}
|
||||
onValueChange={value => this.setState({ falseSwitchIsOn: value })}
|
||||
style={{ marginBottom: 10, height: '3rem' }}
|
||||
value={this.state.falseSwitchIsOn}
|
||||
/>
|
||||
<Switch
|
||||
onValueChange={(value) => this.setState({trueSwitchIsOn: value})}
|
||||
style={{marginBottom: 10, width: 150 }}
|
||||
onValueChange={value => this.setState({ trueSwitchIsOn: value })}
|
||||
style={{ marginBottom: 10, width: 150 }}
|
||||
value={this.state.trueSwitchIsOn}
|
||||
/>
|
||||
</View>
|
||||
@@ -158,34 +159,45 @@ var SizeSwitchExample = createReactClass({
|
||||
}
|
||||
});
|
||||
|
||||
var examples = [
|
||||
const examples = [
|
||||
{
|
||||
title: 'set to true or false',
|
||||
render(): ReactElement<any> { return <BasicSwitchExample />; }
|
||||
render() {
|
||||
return <BasicSwitchExample />;
|
||||
}
|
||||
},
|
||||
{
|
||||
title: 'disabled',
|
||||
render(): ReactElement<any> { return <DisabledSwitchExample />; }
|
||||
render() {
|
||||
return <DisabledSwitchExample />;
|
||||
}
|
||||
},
|
||||
{
|
||||
title: 'change events',
|
||||
render(): ReactElement<any> { return <EventSwitchExample />; }
|
||||
render() {
|
||||
return <EventSwitchExample />;
|
||||
}
|
||||
},
|
||||
{
|
||||
title: 'custom colors',
|
||||
render(): ReactElement<any> { return <ColorSwitchExample />; }
|
||||
render() {
|
||||
return <ColorSwitchExample />;
|
||||
}
|
||||
},
|
||||
{
|
||||
title: 'custom size',
|
||||
render(): ReactElement<any> { return <SizeSwitchExample />; }
|
||||
render() {
|
||||
return <SizeSwitchExample />;
|
||||
}
|
||||
},
|
||||
{
|
||||
title: 'controlled component',
|
||||
render(): ReactElement<any> { return <Switch />; }
|
||||
render() {
|
||||
return <Switch />;
|
||||
}
|
||||
}
|
||||
];
|
||||
|
||||
examples.forEach((example) => {
|
||||
storiesOf('component: Switch', module)
|
||||
.add(example.title, () => example.render())
|
||||
})
|
||||
examples.forEach(example => {
|
||||
storiesOf('component: Switch', module).add(example.title, () => example.render());
|
||||
});
|
||||
565
docs/storybook/components/Text/TextExample.js
Normal file
@@ -0,0 +1,565 @@
|
||||
/* eslint-disable react/jsx-no-bind */
|
||||
|
||||
/**
|
||||
* Copyright (c) 2013-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.
|
||||
*
|
||||
* The examples provided by Facebook are for non-commercial testing and
|
||||
* evaluation purposes only.
|
||||
*
|
||||
* Facebook reserves all rights not expressly granted.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
|
||||
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NON INFRINGEMENT. IN NO EVENT SHALL
|
||||
* FACEBOOK BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
|
||||
* AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*
|
||||
* @flow
|
||||
*/
|
||||
|
||||
import createReactClass from 'create-react-class';
|
||||
import React from 'react';
|
||||
import { storiesOf } from '@kadira/storybook';
|
||||
import { Image, Text, View } from 'react-native';
|
||||
|
||||
const Entity = createReactClass({
|
||||
render: function() {
|
||||
return (
|
||||
<Text style={{ fontWeight: '500', color: '#527fe4' }}>
|
||||
{this.props.children}
|
||||
</Text>
|
||||
);
|
||||
}
|
||||
});
|
||||
|
||||
const AttributeToggler = createReactClass({
|
||||
getInitialState: function() {
|
||||
return { fontWeight: 'bold', fontSize: 15 };
|
||||
},
|
||||
toggleWeight: function() {
|
||||
this.setState({
|
||||
fontWeight: this.state.fontWeight === 'bold' ? 'normal' : 'bold'
|
||||
});
|
||||
},
|
||||
increaseSize: function() {
|
||||
this.setState({
|
||||
fontSize: this.state.fontSize + 1
|
||||
});
|
||||
},
|
||||
render: function() {
|
||||
const curStyle = { fontWeight: this.state.fontWeight, fontSize: this.state.fontSize };
|
||||
return (
|
||||
<View>
|
||||
<Text style={curStyle}>
|
||||
Tap the controls below to change attributes.
|
||||
</Text>
|
||||
<Text>
|
||||
<Text>See how it will even work on <Text style={curStyle}>this nested text</Text></Text>
|
||||
</Text>
|
||||
<Text onPress={this.toggleWeight} style={{ backgroundColor: '#ffaaaa', marginTop: 5 }}>
|
||||
Toggle Weight
|
||||
</Text>
|
||||
<Text onPress={this.increaseSize} style={{ backgroundColor: '#aaaaff', marginTop: 5 }}>
|
||||
Increase Size
|
||||
</Text>
|
||||
</View>
|
||||
);
|
||||
}
|
||||
});
|
||||
|
||||
const examples = [
|
||||
{
|
||||
title: 'Wrap',
|
||||
render: function() {
|
||||
return (
|
||||
<Text style={{ WebkitFontSmoothing: 'antialiased' }}>
|
||||
The text should wrap if it goes on multiple lines. See, this is going to
|
||||
the next line.
|
||||
</Text>
|
||||
);
|
||||
}
|
||||
},
|
||||
{
|
||||
title: 'Padding',
|
||||
render: function() {
|
||||
return (
|
||||
<Text style={{ padding: 10 }}>
|
||||
This text is indented by 10px padding on all sides.
|
||||
</Text>
|
||||
);
|
||||
}
|
||||
},
|
||||
{
|
||||
title: 'Font Family',
|
||||
render: function() {
|
||||
return (
|
||||
<View>
|
||||
<Text style={{ fontFamily: 'Cochin' }}>
|
||||
Cochin
|
||||
</Text>
|
||||
<Text style={{ fontFamily: 'Cochin', fontWeight: 'bold' }}>
|
||||
Cochin bold
|
||||
</Text>
|
||||
<Text style={{ fontFamily: 'Helvetica' }}>
|
||||
Helvetica
|
||||
</Text>
|
||||
<Text style={{ fontFamily: 'Helvetica', fontWeight: 'bold' }}>
|
||||
Helvetica bold
|
||||
</Text>
|
||||
<Text style={{ fontFamily: 'Verdana' }}>
|
||||
Verdana
|
||||
</Text>
|
||||
<Text style={{ fontFamily: 'Verdana', fontWeight: 'bold' }}>
|
||||
Verdana bold
|
||||
</Text>
|
||||
</View>
|
||||
);
|
||||
}
|
||||
},
|
||||
{
|
||||
title: 'Font Size',
|
||||
render: function() {
|
||||
return (
|
||||
<View>
|
||||
<Text style={{ fontSize: 23 }}>
|
||||
Size 23
|
||||
</Text>
|
||||
<Text style={{ fontSize: 8 }}>
|
||||
Size 8
|
||||
</Text>
|
||||
</View>
|
||||
);
|
||||
}
|
||||
},
|
||||
{
|
||||
title: 'Color',
|
||||
render: function() {
|
||||
return (
|
||||
<View>
|
||||
<Text style={{ color: 'red' }}>
|
||||
Red color
|
||||
</Text>
|
||||
<Text style={{ color: 'blue' }}>
|
||||
Blue color
|
||||
</Text>
|
||||
</View>
|
||||
);
|
||||
}
|
||||
},
|
||||
{
|
||||
title: 'Font Weight',
|
||||
render: function() {
|
||||
return (
|
||||
<View>
|
||||
<Text style={{ fontSize: 20, fontWeight: '100' }}>
|
||||
Move fast and be ultralight
|
||||
</Text>
|
||||
<Text style={{ fontSize: 20, fontWeight: '200' }}>
|
||||
Move fast and be light
|
||||
</Text>
|
||||
<Text style={{ fontSize: 20, fontWeight: 'normal' }}>
|
||||
Move fast and be normal
|
||||
</Text>
|
||||
<Text style={{ fontSize: 20, fontWeight: 'bold' }}>
|
||||
Move fast and be bold
|
||||
</Text>
|
||||
<Text style={{ fontSize: 20, fontWeight: '900' }}>
|
||||
Move fast and be ultrabold
|
||||
</Text>
|
||||
</View>
|
||||
);
|
||||
}
|
||||
},
|
||||
{
|
||||
title: 'Font Style',
|
||||
render: function() {
|
||||
return (
|
||||
<View>
|
||||
<Text style={{ fontStyle: 'normal' }}>
|
||||
Normal text
|
||||
</Text>
|
||||
<Text style={{ fontStyle: 'italic' }}>
|
||||
Italic text
|
||||
</Text>
|
||||
</View>
|
||||
);
|
||||
}
|
||||
},
|
||||
{
|
||||
title: 'Text Decoration',
|
||||
render: function() {
|
||||
return (
|
||||
<View>
|
||||
<Text style={{ textDecorationLine: 'underline', textDecorationStyle: 'solid' }}>
|
||||
Solid underline
|
||||
</Text>
|
||||
<Text
|
||||
style={{
|
||||
textDecorationLine: 'underline',
|
||||
textDecorationStyle: 'double',
|
||||
textDecorationColor: '#ff0000'
|
||||
}}
|
||||
>
|
||||
Double underline with custom color
|
||||
</Text>
|
||||
<Text
|
||||
style={{
|
||||
textDecorationLine: 'underline',
|
||||
textDecorationStyle: 'dashed',
|
||||
textDecorationColor: '#9CDC40'
|
||||
}}
|
||||
>
|
||||
Dashed underline with custom color
|
||||
</Text>
|
||||
<Text
|
||||
style={{
|
||||
textDecorationLine: 'underline',
|
||||
textDecorationStyle: 'dotted',
|
||||
textDecorationColor: 'blue'
|
||||
}}
|
||||
>
|
||||
Dotted underline with custom color
|
||||
</Text>
|
||||
<Text style={{ textDecorationLine: 'none' }}>
|
||||
None textDecoration
|
||||
</Text>
|
||||
<Text style={{ textDecorationLine: 'line-through', textDecorationStyle: 'solid' }}>
|
||||
Solid line-through
|
||||
</Text>
|
||||
<Text
|
||||
style={{
|
||||
textDecorationLine: 'line-through',
|
||||
textDecorationStyle: 'double',
|
||||
textDecorationColor: '#ff0000'
|
||||
}}
|
||||
>
|
||||
Double line-through with custom color
|
||||
</Text>
|
||||
<Text
|
||||
style={{
|
||||
textDecorationLine: 'line-through',
|
||||
textDecorationStyle: 'dashed',
|
||||
textDecorationColor: '#9CDC40'
|
||||
}}
|
||||
>
|
||||
Dashed line-through with custom color
|
||||
</Text>
|
||||
<Text
|
||||
style={{
|
||||
textDecorationLine: 'line-through',
|
||||
textDecorationStyle: 'dotted',
|
||||
textDecorationColor: 'blue'
|
||||
}}
|
||||
>
|
||||
Dotted line-through with custom color
|
||||
</Text>
|
||||
<Text style={{ textDecorationLine: 'underline line-through' }}>
|
||||
Both underline and line-through
|
||||
</Text>
|
||||
</View>
|
||||
);
|
||||
}
|
||||
},
|
||||
{
|
||||
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.',
|
||||
render: function() {
|
||||
return (
|
||||
<View>
|
||||
<Text>
|
||||
(Normal text,
|
||||
<Text style={{ fontWeight: 'bold' }}>
|
||||
(and bold
|
||||
<Text style={{ fontSize: 11, color: '#527fe4' }}>
|
||||
(and tiny inherited bold blue)
|
||||
</Text>
|
||||
)
|
||||
</Text>
|
||||
)
|
||||
</Text>
|
||||
<Text style={{ opacity: 0.7 }}>
|
||||
(opacity
|
||||
<Text>
|
||||
(is inherited
|
||||
<Text style={{ opacity: 0.7 }}>
|
||||
(and accumulated
|
||||
<Text style={{ backgroundColor: '#ffaaaa' }}>
|
||||
(and also applies to the background)
|
||||
</Text>
|
||||
)
|
||||
</Text>
|
||||
)
|
||||
</Text>
|
||||
)
|
||||
</Text>
|
||||
<Text style={{ fontSize: 12 }}>
|
||||
<Entity>Entity Name</Entity>
|
||||
</Text>
|
||||
</View>
|
||||
);
|
||||
}
|
||||
},
|
||||
{
|
||||
title: 'Text Align',
|
||||
render: function() {
|
||||
return (
|
||||
<View>
|
||||
<Text>
|
||||
auto (default) - english LTR
|
||||
</Text>
|
||||
<Text>
|
||||
أحب اللغة العربية auto (default) - arabic RTL
|
||||
</Text>
|
||||
<Text style={{ textAlign: 'left' }}>
|
||||
left left left left left left left left left left left left left left left
|
||||
</Text>
|
||||
<Text style={{ textAlign: 'center' }}>
|
||||
center center center center center center center center center center center
|
||||
</Text>
|
||||
<Text style={{ textAlign: 'right' }}>
|
||||
right right right right right right right right right right right right right
|
||||
</Text>
|
||||
<Text style={{ textAlign: 'justify' }}>
|
||||
justify: this text component{"'"}s contents are laid out with "textAlign: justify"
|
||||
and as you can see all of the lines except the last one span the
|
||||
available width of the parent container.
|
||||
</Text>
|
||||
</View>
|
||||
);
|
||||
}
|
||||
},
|
||||
{
|
||||
title: 'Letter Spacing',
|
||||
render: function() {
|
||||
return (
|
||||
<View>
|
||||
<Text style={{ letterSpacing: 0 }}>
|
||||
letterSpacing = 0
|
||||
</Text>
|
||||
<Text style={{ letterSpacing: 2, marginTop: 5 }}>
|
||||
letterSpacing = 2
|
||||
</Text>
|
||||
<Text style={{ letterSpacing: 9, marginTop: 5 }}>
|
||||
letterSpacing = 9
|
||||
</Text>
|
||||
<Text style={{ letterSpacing: -1, marginTop: 5 }}>
|
||||
letterSpacing = -1
|
||||
</Text>
|
||||
</View>
|
||||
);
|
||||
}
|
||||
},
|
||||
{
|
||||
title: 'Spaces',
|
||||
render: function() {
|
||||
return (
|
||||
<Text>
|
||||
A {'generated'} {' '} {'string'} and some spaces
|
||||
</Text>
|
||||
);
|
||||
}
|
||||
},
|
||||
{
|
||||
title: 'Line Height',
|
||||
render: function() {
|
||||
return (
|
||||
<Text>
|
||||
<Text style={{ lineHeight: 35 }}>
|
||||
A lot of space between the lines of this long passage that should
|
||||
wrap once.
|
||||
</Text>
|
||||
</Text>
|
||||
);
|
||||
}
|
||||
},
|
||||
{
|
||||
title: 'Empty Text',
|
||||
description: "It's ok to have Text with zero or null children.",
|
||||
render: function() {
|
||||
return <Text />;
|
||||
}
|
||||
},
|
||||
{
|
||||
title: 'Toggling Attributes',
|
||||
render: function() {
|
||||
return <AttributeToggler />;
|
||||
}
|
||||
},
|
||||
{
|
||||
title: 'backgroundColor attribute',
|
||||
description: 'backgroundColor is inherited from all types of views.',
|
||||
render: function() {
|
||||
return (
|
||||
<Text style={{ backgroundColor: 'yellow' }}>
|
||||
Yellow container background,
|
||||
<Text style={{ backgroundColor: '#ffaaaa' }}>
|
||||
{' '}red background,
|
||||
<Text style={{ backgroundColor: '#aaaaff' }}>
|
||||
{' '}blue background,
|
||||
<Text>
|
||||
{' '}inherited blue background,
|
||||
<Text style={{ backgroundColor: '#aaffaa' }}>
|
||||
{' '}nested green background.
|
||||
</Text>
|
||||
</Text>
|
||||
</Text>
|
||||
</Text>
|
||||
</Text>
|
||||
);
|
||||
}
|
||||
},
|
||||
{
|
||||
title: 'numberOfLines attribute',
|
||||
render: function() {
|
||||
return (
|
||||
<View>
|
||||
<Text numberOfLines={1}>
|
||||
Maximum of one line, no matter how much I write here. If I keep writing, it
|
||||
{"'"}
|
||||
ll just truncate after one line.
|
||||
</Text>
|
||||
<Text numberOfLines={2} style={{ marginTop: 20 }}>
|
||||
Maximum of two lines, no matter how much I write here. If I keep writing, it
|
||||
{"'"}
|
||||
ll just truncate after two lines.
|
||||
</Text>
|
||||
<Text style={{ marginTop: 20 }}>
|
||||
No maximum lines specified, no matter how much I write here. If I keep writing, it
|
||||
{"'"}
|
||||
ll just keep going and going.
|
||||
</Text>
|
||||
</View>
|
||||
);
|
||||
}
|
||||
},
|
||||
{
|
||||
title: 'Text highlighting (tap the link to see highlight)',
|
||||
render: function() {
|
||||
return (
|
||||
<View>
|
||||
<Text>
|
||||
Lorem ipsum dolor sit amet,
|
||||
{' '}
|
||||
<Text
|
||||
onPress={() => null}
|
||||
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
|
||||
</Text>
|
||||
{' '}
|
||||
exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat.
|
||||
</Text>
|
||||
</View>
|
||||
);
|
||||
}
|
||||
},
|
||||
{
|
||||
title: 'allowFontScaling attribute',
|
||||
render: function() {
|
||||
return (
|
||||
<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
|
||||
{' '}
|
||||
<Text style={{ fontWeight: 'bold' }}>
|
||||
Settings.app - Display & Brightness - Text Size
|
||||
</Text>
|
||||
</Text>
|
||||
<Text style={{ marginTop: 10 }}>
|
||||
You can disable scaling for your Text component by passing
|
||||
{' '}
|
||||
{'"'}
|
||||
allowFontScaling=
|
||||
{'{'}
|
||||
false
|
||||
{'}"'}
|
||||
{' '}
|
||||
prop.
|
||||
</Text>
|
||||
<Text allowFontScaling={false} style={{ marginTop: 20 }}>
|
||||
This text will not scale.
|
||||
</Text>
|
||||
</View>
|
||||
);
|
||||
}
|
||||
},
|
||||
{
|
||||
title: 'Inline views',
|
||||
render: function() {
|
||||
return (
|
||||
<View>
|
||||
<Text>
|
||||
This text contains an inline blue view
|
||||
{' '}
|
||||
<View style={{ width: 25, height: 25, backgroundColor: 'steelblue' }} />
|
||||
{' '}
|
||||
and
|
||||
an inline image
|
||||
{' '}
|
||||
<Image
|
||||
source={{ uri: 'http://lorempixel.com/30/11' }}
|
||||
style={{ width: 30, height: 11, resizeMode: 'cover' }}
|
||||
/>
|
||||
. Neat, huh?
|
||||
</Text>
|
||||
</View>
|
||||
);
|
||||
}
|
||||
},
|
||||
{
|
||||
title: 'Text shadow',
|
||||
render: function() {
|
||||
return (
|
||||
<View>
|
||||
<Text
|
||||
style={{
|
||||
fontSize: 20,
|
||||
textShadowOffset: { width: 2, height: 2 },
|
||||
textShadowRadius: 1,
|
||||
textShadowColor: '#00cccc'
|
||||
}}
|
||||
>
|
||||
Demo text shadow
|
||||
</Text>
|
||||
</View>
|
||||
);
|
||||
}
|
||||
},
|
||||
{
|
||||
title: 'Line break mode',
|
||||
render: function() {
|
||||
return (
|
||||
<View>
|
||||
<Text numberOfLines={1}>
|
||||
This very long text should be truncated with dots in the end.
|
||||
</Text>
|
||||
<Text lineBreakMode="middle" numberOfLines={1}>
|
||||
This very long text should be truncated with dots in the middle.
|
||||
</Text>
|
||||
<Text lineBreakMode="head" numberOfLines={1}>
|
||||
This very long text should be truncated with dots in the beginning.
|
||||
</Text>
|
||||
<Text lineBreakMode="clip" numberOfLines={1}>
|
||||
This very looooooooooooooooooooooooooooong text should be clipped.
|
||||
</Text>
|
||||
</View>
|
||||
);
|
||||
}
|
||||
}
|
||||
];
|
||||
|
||||
examples.forEach(example => {
|
||||
storiesOf('component: Text', module)
|
||||
.addDecorator(renderStory => <View style={{ width: 320 }}>{renderStory()}</View>)
|
||||
.add(example.title, () => example.render());
|
||||
});
|
||||
@@ -1,6 +1,4 @@
|
||||
import React from 'react';
|
||||
import { storiesOf, action } from '@kadira/storybook';
|
||||
import { StyleSheet, Text, TextInput, View } from 'react-native'
|
||||
/* eslint-disable react/jsx-no-bind */
|
||||
|
||||
/**
|
||||
* Copyright (c) 2013-present, Facebook, Inc.
|
||||
@@ -25,7 +23,17 @@ import { StyleSheet, Text, TextInput, View } from 'react-native'
|
||||
* @flow
|
||||
*/
|
||||
|
||||
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';
|
||||
|
||||
class WithLabel extends React.Component {
|
||||
static propTypes = {
|
||||
children: any,
|
||||
label: string
|
||||
};
|
||||
|
||||
render() {
|
||||
return (
|
||||
<View style={styles.labelContainer}>
|
||||
@@ -43,16 +51,16 @@ class TextEventsExample extends React.Component {
|
||||
curText: '<No Event>',
|
||||
prevText: '<No Event>',
|
||||
prev2Text: '<No Event>',
|
||||
prev3Text: '<No Event>',
|
||||
prev3Text: '<No Event>'
|
||||
};
|
||||
|
||||
updateText = (text) => {
|
||||
this.setState((state) => {
|
||||
updateText = text => {
|
||||
this.setState(state => {
|
||||
return {
|
||||
curText: text,
|
||||
prevText: state.curText,
|
||||
prev2Text: state.prevText,
|
||||
prev3Text: state.prev2Text,
|
||||
prev3Text: state.prev2Text
|
||||
};
|
||||
});
|
||||
};
|
||||
@@ -62,28 +70,25 @@ class TextEventsExample extends React.Component {
|
||||
<View style={{ alignItems: 'center' }}>
|
||||
<TextInput
|
||||
autoCapitalize="none"
|
||||
placeholder="Enter text to see events"
|
||||
autoCorrect={false}
|
||||
onFocus={() => this.updateText('onFocus')}
|
||||
onBlur={() => this.updateText('onBlur')}
|
||||
onChange={(event) => this.updateText(
|
||||
'onChange text: ' + event.nativeEvent.text
|
||||
)}
|
||||
onEndEditing={(event) => this.updateText(
|
||||
'onEndEditing text: ' + event.nativeEvent.text
|
||||
)}
|
||||
onSubmitEditing={(event) => this.updateText(
|
||||
'onSubmitEditing text: ' + event.nativeEvent.text
|
||||
)}
|
||||
onSelectionChange={(event) => this.updateText(
|
||||
'onSelectionChange range: ' +
|
||||
event.nativeEvent.selection.start + ',' +
|
||||
event.nativeEvent.selection.end
|
||||
)}
|
||||
onKeyPress={(event) => {
|
||||
onChange={event => this.updateText('onChange text: ' + event.nativeEvent.text)}
|
||||
onEndEditing={event => this.updateText('onEndEditing text: ' + event.nativeEvent.text)}
|
||||
onFocus={() => this.updateText('onFocus')}
|
||||
onKeyPress={event => {
|
||||
this.updateText('onKeyPress key: ' + event.nativeEvent.key);
|
||||
}}
|
||||
style={[ styles.default, { maxWidth: 200 } ]}
|
||||
onSelectionChange={event =>
|
||||
this.updateText(
|
||||
'onSelectionChange range: ' +
|
||||
event.nativeEvent.selection.start +
|
||||
',' +
|
||||
event.nativeEvent.selection.end
|
||||
)}
|
||||
onSubmitEditing={event =>
|
||||
this.updateText('onSubmitEditing text: ' + event.nativeEvent.text)}
|
||||
placeholder="Enter text to see events"
|
||||
style={[styles.default, { maxWidth: 200 }]}
|
||||
/>
|
||||
<Text style={styles.eventLabel}>
|
||||
{this.state.curText}{'\n'}
|
||||
@@ -103,21 +108,22 @@ class AutoExpandingTextInput extends React.Component {
|
||||
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.',
|
||||
height: 0,
|
||||
height: 0
|
||||
};
|
||||
}
|
||||
|
||||
render() {
|
||||
return (
|
||||
<TextInput
|
||||
{...this.props}
|
||||
multiline={true}
|
||||
onChangeText={(text) => {
|
||||
this.setState({text});
|
||||
onChangeText={text => {
|
||||
this.setState({ text });
|
||||
}}
|
||||
onContentSizeChange={(event) => {
|
||||
this.setState({height: event.nativeEvent.contentSize.height});
|
||||
onContentSizeChange={event => {
|
||||
this.setState({ height: event.nativeEvent.contentSize.height });
|
||||
}}
|
||||
style={[styles.default, {height: Math.max(35, this.state.height)}]}
|
||||
style={[styles.default, { height: Math.max(35, this.state.height) }]}
|
||||
value={this.state.text}
|
||||
/>
|
||||
);
|
||||
@@ -129,25 +135,26 @@ class RewriteExample extends React.Component {
|
||||
|
||||
constructor(props) {
|
||||
super(props);
|
||||
this.state = {text: ''};
|
||||
this.state = { text: '' };
|
||||
}
|
||||
|
||||
render() {
|
||||
var limit = 20;
|
||||
var remainder = limit - this.state.text.length;
|
||||
var remainderColor = remainder > 5 ? 'blue' : 'red';
|
||||
const limit = 20;
|
||||
const remainder = limit - this.state.text.length;
|
||||
const remainderColor = remainder > 5 ? 'blue' : 'red';
|
||||
return (
|
||||
<View style={styles.rewriteContainer}>
|
||||
<TextInput
|
||||
multiline={false}
|
||||
maxLength={limit}
|
||||
onChangeText={(text) => {
|
||||
multiline={false}
|
||||
onChangeText={text => {
|
||||
text = text.replace(/ /g, '_');
|
||||
this.setState({text});
|
||||
this.setState({ text });
|
||||
}}
|
||||
style={styles.default}
|
||||
value={this.state.text}
|
||||
/>
|
||||
<Text style={[styles.remainder, {color: remainderColor}]}>
|
||||
<Text style={[styles.remainder, { color: remainderColor }]}>
|
||||
{remainder}
|
||||
</Text>
|
||||
</View>
|
||||
@@ -160,15 +167,16 @@ class RewriteExampleInvalidCharacters extends React.Component {
|
||||
|
||||
constructor(props) {
|
||||
super(props);
|
||||
this.state = {text: ''};
|
||||
this.state = { text: '' };
|
||||
}
|
||||
|
||||
render() {
|
||||
return (
|
||||
<View style={styles.rewriteContainer}>
|
||||
<TextInput
|
||||
multiline={false}
|
||||
onChangeText={(text) => {
|
||||
this.setState({text: text.replace(/\s/g, '')});
|
||||
onChangeText={text => {
|
||||
this.setState({ text: text.replace(/\s/g, '') });
|
||||
}}
|
||||
style={styles.default}
|
||||
value={this.state.text}
|
||||
@@ -183,16 +191,17 @@ class TokenizedTextExample extends React.Component {
|
||||
|
||||
constructor(props) {
|
||||
super(props);
|
||||
this.state = {text: 'Hello #World'};
|
||||
this.state = { text: 'Hello #World' };
|
||||
}
|
||||
render() {
|
||||
|
||||
render() {
|
||||
//define delimiter
|
||||
let delimiter = /\s+/;
|
||||
const delimiter = /\s+/;
|
||||
|
||||
//split string
|
||||
let _text = this.state.text;
|
||||
let token, index, parts = [];
|
||||
let token, index;
|
||||
const parts = [];
|
||||
while (_text) {
|
||||
delimiter.lastIndex = 0;
|
||||
token = delimiter.exec(_text);
|
||||
@@ -213,12 +222,12 @@ class TokenizedTextExample extends React.Component {
|
||||
return (
|
||||
<View>
|
||||
<TextInput
|
||||
value={parts.join('')}
|
||||
multiline={true}
|
||||
style={styles.multiline}
|
||||
onChangeText={(text) => {
|
||||
this.setState({text});
|
||||
onChangeText={text => {
|
||||
this.setState({ text });
|
||||
}}
|
||||
style={styles.multiline}
|
||||
value={parts.join('')}
|
||||
/>
|
||||
</View>
|
||||
);
|
||||
@@ -226,53 +235,68 @@ class TokenizedTextExample extends React.Component {
|
||||
}
|
||||
|
||||
class BlurOnSubmitExample extends React.Component {
|
||||
focusNextField = (nextField) => {
|
||||
this.refs[nextField].focus();
|
||||
constructor(props) {
|
||||
super(props);
|
||||
this._nodes = {};
|
||||
}
|
||||
|
||||
focusNextField = nextField => {
|
||||
this._nodes[nextField].focus();
|
||||
};
|
||||
|
||||
render() {
|
||||
return (
|
||||
<View>
|
||||
<TextInput
|
||||
ref="1"
|
||||
style={styles.default}
|
||||
placeholder="blurOnSubmit = false"
|
||||
returnKeyType="next"
|
||||
blurOnSubmit={false}
|
||||
onSubmitEditing={() => this.focusNextField('2')}
|
||||
placeholder="blurOnSubmit = false"
|
||||
ref={c => {
|
||||
this._nodes['1'] = c;
|
||||
}}
|
||||
returnKeyType="next"
|
||||
style={styles.default}
|
||||
/>
|
||||
<TextInput
|
||||
ref="2"
|
||||
style={styles.default}
|
||||
blurOnSubmit={false}
|
||||
keyboardType="email-address"
|
||||
placeholder="blurOnSubmit = false"
|
||||
returnKeyType="next"
|
||||
blurOnSubmit={false}
|
||||
onSubmitEditing={() => this.focusNextField('3')}
|
||||
/>
|
||||
<TextInput
|
||||
ref="3"
|
||||
style={styles.default}
|
||||
keyboardType="url"
|
||||
placeholder="blurOnSubmit = false"
|
||||
ref={c => {
|
||||
this._nodes['2'] = c;
|
||||
}}
|
||||
returnKeyType="next"
|
||||
style={styles.default}
|
||||
/>
|
||||
<TextInput
|
||||
blurOnSubmit={false}
|
||||
keyboardType="url"
|
||||
onSubmitEditing={() => this.focusNextField('4')}
|
||||
/>
|
||||
<TextInput
|
||||
ref="4"
|
||||
style={styles.default}
|
||||
keyboardType="numeric"
|
||||
placeholder="blurOnSubmit = false"
|
||||
blurOnSubmit={false}
|
||||
onSubmitEditing={() => this.focusNextField('5')}
|
||||
ref={c => {
|
||||
this._nodes['3'] = c;
|
||||
}}
|
||||
returnKeyType="next"
|
||||
style={styles.default}
|
||||
/>
|
||||
<TextInput
|
||||
ref="5"
|
||||
blurOnSubmit={false}
|
||||
keyboardType="numeric"
|
||||
onSubmitEditing={() => this.focusNextField('5')}
|
||||
placeholder="blurOnSubmit = false"
|
||||
ref={c => {
|
||||
this._nodes['4'] = c;
|
||||
}}
|
||||
style={styles.default}
|
||||
/>
|
||||
<TextInput
|
||||
keyboardType="numeric"
|
||||
placeholder="blurOnSubmit = true"
|
||||
ref={c => {
|
||||
this._nodes['5'] = c;
|
||||
}}
|
||||
returnKeyType="done"
|
||||
style={styles.default}
|
||||
/>
|
||||
</View>
|
||||
);
|
||||
@@ -281,10 +305,10 @@ class BlurOnSubmitExample extends React.Component {
|
||||
|
||||
type SelectionExampleState = {
|
||||
selection: {
|
||||
start: number;
|
||||
end?: number;
|
||||
};
|
||||
value: string;
|
||||
start: number,
|
||||
end?: number
|
||||
},
|
||||
value: string
|
||||
};
|
||||
|
||||
class SelectionExample extends React.Component {
|
||||
@@ -292,30 +316,36 @@ class SelectionExample extends React.Component {
|
||||
|
||||
_textInput: any;
|
||||
|
||||
static propTypes = {
|
||||
multiline: bool,
|
||||
style: object,
|
||||
value: string
|
||||
};
|
||||
|
||||
constructor(props) {
|
||||
super(props);
|
||||
this.state = {
|
||||
selection: {start: 0, end: 0},
|
||||
selection: { start: 0, end: 0 },
|
||||
value: props.value
|
||||
};
|
||||
}
|
||||
|
||||
onSelectionChange({nativeEvent: {selection}}) {
|
||||
this.setState({selection});
|
||||
onSelectionChange({ nativeEvent: { selection } }) {
|
||||
this.setState({ selection });
|
||||
}
|
||||
|
||||
getRandomPosition() {
|
||||
var length = this.state.value.length;
|
||||
const length = this.state.value.length;
|
||||
return Math.round(Math.random() * length);
|
||||
}
|
||||
|
||||
select(start, end) {
|
||||
this._textInput.focus();
|
||||
this.setState({selection: {start, end}});
|
||||
this.setState({ selection: { start, end } });
|
||||
}
|
||||
|
||||
selectRandom() {
|
||||
var positions = [this.getRandomPosition(), this.getRandomPosition()].sort();
|
||||
const positions = [this.getRandomPosition(), this.getRandomPosition()].sort();
|
||||
this.select(...positions);
|
||||
}
|
||||
|
||||
@@ -328,13 +358,13 @@ class SelectionExample extends React.Component {
|
||||
}
|
||||
|
||||
render() {
|
||||
var length = this.state.value.length;
|
||||
const length = this.state.value.length;
|
||||
|
||||
return (
|
||||
<View>
|
||||
<TextInput
|
||||
multiline={this.props.multiline}
|
||||
onChangeText={(value) => this.setState({value})}
|
||||
onChangeText={value => this.setState({ value })}
|
||||
onSelectionChange={this.onSelectionChange.bind(this)}
|
||||
ref={textInput => (this._textInput = textInput)}
|
||||
selection={this.state.selection}
|
||||
@@ -366,9 +396,9 @@ class SelectionExample extends React.Component {
|
||||
}
|
||||
}
|
||||
|
||||
var styles = StyleSheet.create({
|
||||
const styles = StyleSheet.create({
|
||||
page: {
|
||||
paddingBottom: 300,
|
||||
paddingBottom: 300
|
||||
},
|
||||
default: {
|
||||
height: 26,
|
||||
@@ -376,7 +406,7 @@ var styles = StyleSheet.create({
|
||||
borderColor: '#0f0f0f',
|
||||
flex: 1,
|
||||
fontSize: 13,
|
||||
padding: 4,
|
||||
padding: 4
|
||||
},
|
||||
multiline: {
|
||||
borderWidth: 0.5,
|
||||
@@ -385,49 +415,49 @@ var styles = StyleSheet.create({
|
||||
fontSize: 13,
|
||||
height: 50,
|
||||
padding: 4,
|
||||
marginBottom: 4,
|
||||
marginBottom: 4
|
||||
},
|
||||
multilineWithFontStyles: {
|
||||
color: 'blue',
|
||||
fontWeight: 'bold',
|
||||
fontSize: 18,
|
||||
fontFamily: 'Cochin',
|
||||
height: 60,
|
||||
height: 60
|
||||
},
|
||||
multilineChild: {
|
||||
width: 50,
|
||||
height: 40,
|
||||
position: 'absolute',
|
||||
right: 5,
|
||||
backgroundColor: 'red',
|
||||
backgroundColor: 'red'
|
||||
},
|
||||
eventLabel: {
|
||||
margin: 3,
|
||||
fontSize: 12,
|
||||
fontSize: 12
|
||||
},
|
||||
labelContainer: {
|
||||
flexDirection: 'row',
|
||||
marginVertical: 2,
|
||||
flex: 1,
|
||||
flex: 1
|
||||
},
|
||||
label: {
|
||||
width: 115,
|
||||
alignItems: 'flex-end',
|
||||
marginRight: 10,
|
||||
paddingTop: 2,
|
||||
paddingTop: 2
|
||||
},
|
||||
rewriteContainer: {
|
||||
flexDirection: 'row',
|
||||
alignItems: 'center',
|
||||
alignItems: 'center'
|
||||
},
|
||||
remainder: {
|
||||
textAlign: 'right',
|
||||
width: 24,
|
||||
width: 24
|
||||
},
|
||||
hashtag: {
|
||||
color: 'blue',
|
||||
fontWeight: 'bold',
|
||||
},
|
||||
fontWeight: 'bold'
|
||||
}
|
||||
});
|
||||
|
||||
const examples = [
|
||||
@@ -437,9 +467,9 @@ const examples = [
|
||||
return (
|
||||
<View>
|
||||
<TextInput
|
||||
accessibilityLabel="I am the accessibility label for text input"
|
||||
autoFocus={true}
|
||||
style={styles.default}
|
||||
accessibilityLabel="I am the accessibility label for text input"
|
||||
/>
|
||||
</View>
|
||||
);
|
||||
@@ -463,28 +493,16 @@ const examples = [
|
||||
return (
|
||||
<View>
|
||||
<WithLabel label="none">
|
||||
<TextInput
|
||||
autoCapitalize="none"
|
||||
style={styles.default}
|
||||
/>
|
||||
<TextInput autoCapitalize="none" style={styles.default} />
|
||||
</WithLabel>
|
||||
<WithLabel label="sentences">
|
||||
<TextInput
|
||||
autoCapitalize="sentences"
|
||||
style={styles.default}
|
||||
/>
|
||||
<TextInput autoCapitalize="sentences" style={styles.default} />
|
||||
</WithLabel>
|
||||
<WithLabel label="words">
|
||||
<TextInput
|
||||
autoCapitalize="words"
|
||||
style={styles.default}
|
||||
/>
|
||||
<TextInput autoCapitalize="words" style={styles.default} />
|
||||
</WithLabel>
|
||||
<WithLabel label="characters">
|
||||
<TextInput
|
||||
autoCapitalize="characters"
|
||||
style={styles.default}
|
||||
/>
|
||||
<TextInput autoCapitalize="characters" style={styles.default} />
|
||||
</WithLabel>
|
||||
</View>
|
||||
);
|
||||
@@ -508,7 +526,7 @@ const examples = [
|
||||
{
|
||||
title: 'Keyboard types',
|
||||
render: function() {
|
||||
var keyboardTypes = [
|
||||
const keyboardTypes = [
|
||||
'default',
|
||||
//'ascii-capable',
|
||||
//'numbers-and-punctuation',
|
||||
@@ -520,15 +538,12 @@ const examples = [
|
||||
//'decimal-pad',
|
||||
//'twitter',
|
||||
'web-search',
|
||||
'numeric',
|
||||
'numeric'
|
||||
];
|
||||
var examples = keyboardTypes.map((type) => {
|
||||
const examples = keyboardTypes.map(type => {
|
||||
return (
|
||||
<WithLabel key={type} label={type}>
|
||||
<TextInput
|
||||
keyboardType={type}
|
||||
style={styles.default}
|
||||
/>
|
||||
<TextInput keyboardType={type} style={styles.default} />
|
||||
</WithLabel>
|
||||
);
|
||||
});
|
||||
@@ -538,18 +553,11 @@ const examples = [
|
||||
{
|
||||
title: 'Keyboard appearance',
|
||||
render: function() {
|
||||
var keyboardAppearance = [
|
||||
'default',
|
||||
'light',
|
||||
'dark',
|
||||
];
|
||||
var examples = keyboardAppearance.map((type) => {
|
||||
const keyboardAppearance = ['default', 'light', 'dark'];
|
||||
const examples = keyboardAppearance.map(type => {
|
||||
return (
|
||||
<WithLabel key={type} label={type}>
|
||||
<TextInput
|
||||
keyboardAppearance={type}
|
||||
style={styles.default}
|
||||
/>
|
||||
<TextInput keyboardAppearance={type} style={styles.default} />
|
||||
</WithLabel>
|
||||
);
|
||||
});
|
||||
@@ -559,7 +567,7 @@ const examples = [
|
||||
{
|
||||
title: 'Return key types',
|
||||
render: function() {
|
||||
var returnKeyTypes = [
|
||||
const returnKeyTypes = [
|
||||
'default',
|
||||
'go',
|
||||
'google',
|
||||
@@ -570,15 +578,12 @@ const examples = [
|
||||
'send',
|
||||
'yahoo',
|
||||
'done',
|
||||
'emergency-call',
|
||||
'emergency-call'
|
||||
];
|
||||
var examples = returnKeyTypes.map((type) => {
|
||||
const examples = returnKeyTypes.map(type => {
|
||||
return (
|
||||
<WithLabel key={type} label={type}>
|
||||
<TextInput
|
||||
returnKeyType={type}
|
||||
style={styles.default}
|
||||
/>
|
||||
<TextInput returnKeyType={type} style={styles.default} />
|
||||
</WithLabel>
|
||||
);
|
||||
});
|
||||
@@ -603,7 +608,7 @@ const examples = [
|
||||
return (
|
||||
<View>
|
||||
<WithLabel label="true">
|
||||
<TextInput secureTextEntry={true} style={styles.default} defaultValue="abc" />
|
||||
<TextInput defaultValue="abc" secureTextEntry={true} style={styles.default} />
|
||||
</WithLabel>
|
||||
</View>
|
||||
);
|
||||
@@ -611,21 +616,17 @@ const examples = [
|
||||
},
|
||||
{
|
||||
title: 'Event handling',
|
||||
render: function(): React.Element<any> { return <TextEventsExample />; },
|
||||
render: function(): React.Element<any> {
|
||||
return <TextEventsExample />;
|
||||
}
|
||||
},
|
||||
{
|
||||
title: 'Colored input text',
|
||||
render: function() {
|
||||
return (
|
||||
<View>
|
||||
<TextInput
|
||||
style={[styles.default, {color: 'blue'}]}
|
||||
defaultValue="Blue"
|
||||
/>
|
||||
<TextInput
|
||||
style={[styles.default, {color: 'green'}]}
|
||||
defaultValue="Green"
|
||||
/>
|
||||
<TextInput defaultValue="Blue" style={[styles.default, { color: 'blue' }]} />
|
||||
<TextInput defaultValue="Green" style={[styles.default, { color: 'green' }]} />
|
||||
</View>
|
||||
);
|
||||
}
|
||||
@@ -635,15 +636,11 @@ const examples = [
|
||||
render: function() {
|
||||
return (
|
||||
<View>
|
||||
<TextInput defaultValue="Highlight me" selectionColor={'green'} style={styles.default} />
|
||||
<TextInput
|
||||
style={styles.default}
|
||||
selectionColor={"green"}
|
||||
defaultValue="Highlight me"
|
||||
/>
|
||||
<TextInput
|
||||
selectionColor={'rgba(86, 76, 205, 1)'}
|
||||
style={styles.default}
|
||||
selectionColor={"rgba(86, 76, 205, 1)"}
|
||||
defaultValue="Highlight me"
|
||||
/>
|
||||
</View>
|
||||
);
|
||||
@@ -651,32 +648,20 @@ const examples = [
|
||||
},
|
||||
{
|
||||
title: 'Clear button mode',
|
||||
render: function () {
|
||||
render: function() {
|
||||
return (
|
||||
<View>
|
||||
<WithLabel label="never">
|
||||
<TextInput
|
||||
style={styles.default}
|
||||
clearButtonMode="never"
|
||||
/>
|
||||
<TextInput clearButtonMode="never" style={styles.default} />
|
||||
</WithLabel>
|
||||
<WithLabel label="while editing">
|
||||
<TextInput
|
||||
style={styles.default}
|
||||
clearButtonMode="while-editing"
|
||||
/>
|
||||
<TextInput clearButtonMode="while-editing" style={styles.default} />
|
||||
</WithLabel>
|
||||
<WithLabel label="unless editing">
|
||||
<TextInput
|
||||
style={styles.default}
|
||||
clearButtonMode="unless-editing"
|
||||
/>
|
||||
<TextInput clearButtonMode="unless-editing" style={styles.default} />
|
||||
</WithLabel>
|
||||
<WithLabel label="always">
|
||||
<TextInput
|
||||
style={styles.default}
|
||||
clearButtonMode="always"
|
||||
/>
|
||||
<TextInput clearButtonMode="always" style={styles.default} />
|
||||
</WithLabel>
|
||||
</View>
|
||||
);
|
||||
@@ -689,18 +674,18 @@ const examples = [
|
||||
<View>
|
||||
<WithLabel label="clearTextOnFocus">
|
||||
<TextInput
|
||||
placeholder="text is cleared on focus"
|
||||
defaultValue="text is cleared on focus"
|
||||
style={styles.default}
|
||||
clearTextOnFocus={true}
|
||||
defaultValue="text is cleared on focus"
|
||||
placeholder="text is cleared on focus"
|
||||
style={styles.default}
|
||||
/>
|
||||
</WithLabel>
|
||||
<WithLabel label="selectTextOnFocus">
|
||||
<TextInput
|
||||
placeholder="text is selected on focus"
|
||||
defaultValue="text is selected on focus"
|
||||
style={styles.default}
|
||||
placeholder="text is selected on focus"
|
||||
selectTextOnFocus={true}
|
||||
style={styles.default}
|
||||
/>
|
||||
</WithLabel>
|
||||
</View>
|
||||
@@ -709,7 +694,9 @@ const examples = [
|
||||
},
|
||||
{
|
||||
title: 'Blur on submit',
|
||||
render: function(): React.Element<any> { return <BlurOnSubmitExample />; },
|
||||
render: function(): React.Element<any> {
|
||||
return <BlurOnSubmitExample />;
|
||||
}
|
||||
},
|
||||
{
|
||||
title: 'Multiline blur on submit',
|
||||
@@ -717,12 +704,14 @@ const examples = [
|
||||
return (
|
||||
<View>
|
||||
<TextInput
|
||||
style={styles.multiline}
|
||||
placeholder="blurOnSubmit = true"
|
||||
returnKeyType="next"
|
||||
blurOnSubmit={true}
|
||||
multiline={true}
|
||||
onSubmitEditing={event => alert(event.nativeEvent.text)}
|
||||
onSubmitEditing={event => {
|
||||
console.log(event.nativeEvent.text);
|
||||
}}
|
||||
placeholder="blurOnSubmit = true"
|
||||
returnKeyType="next"
|
||||
style={styles.multiline}
|
||||
/>
|
||||
</View>
|
||||
);
|
||||
@@ -733,39 +722,35 @@ const examples = [
|
||||
render: function() {
|
||||
return (
|
||||
<View>
|
||||
<TextInput multiline={true} placeholder="multiline text input" style={styles.multiline} />
|
||||
<TextInput
|
||||
placeholder="multiline text input"
|
||||
multiline={true}
|
||||
style={styles.multiline}
|
||||
/>
|
||||
<TextInput
|
||||
placeholder="multiline text input with font styles and placeholder"
|
||||
multiline={true}
|
||||
clearTextOnFocus={true}
|
||||
autoCorrect={true}
|
||||
autoCapitalize="words"
|
||||
placeholderTextColor="red"
|
||||
autoCorrect={true}
|
||||
clearTextOnFocus={true}
|
||||
keyboardType="url"
|
||||
multiline={true}
|
||||
placeholder="multiline text input with font styles and placeholder"
|
||||
placeholderTextColor="red"
|
||||
style={[styles.multiline, styles.multilineWithFontStyles]}
|
||||
/>
|
||||
<TextInput
|
||||
placeholder="multiline text input with max length"
|
||||
maxLength={5}
|
||||
multiline={true}
|
||||
placeholder="multiline text input with max length"
|
||||
style={styles.multiline}
|
||||
/>
|
||||
<TextInput
|
||||
placeholder="uneditable multiline text input"
|
||||
editable={false}
|
||||
multiline={true}
|
||||
placeholder="uneditable multiline text input"
|
||||
style={styles.multiline}
|
||||
/>
|
||||
<TextInput
|
||||
dataDetectorTypes="phoneNumber"
|
||||
defaultValue="uneditable multiline text input with phone number detection: 88888888."
|
||||
editable={false}
|
||||
multiline={true}
|
||||
style={styles.multiline}
|
||||
dataDetectorTypes="phoneNumber"
|
||||
/>
|
||||
</View>
|
||||
);
|
||||
@@ -779,7 +764,7 @@ const examples = [
|
||||
<TextInput
|
||||
multiline={true}
|
||||
numberOfLines={4}
|
||||
style={[ styles.multiline, { height: 'auto' } ]}
|
||||
style={[styles.multiline, { height: 'auto' }]}
|
||||
/>
|
||||
</View>
|
||||
);
|
||||
@@ -791,8 +776,8 @@ const examples = [
|
||||
return (
|
||||
<View>
|
||||
<AutoExpandingTextInput
|
||||
placeholder="height increases with content"
|
||||
enablesReturnKeyAutomatically={true}
|
||||
placeholder="height increases with content"
|
||||
returnKeyType="default"
|
||||
/>
|
||||
</View>
|
||||
@@ -810,14 +795,11 @@ const examples = [
|
||||
render: function() {
|
||||
return (
|
||||
<View>
|
||||
<SelectionExample
|
||||
style={styles.default}
|
||||
value="text selection can be changed"
|
||||
/>
|
||||
<SelectionExample style={styles.default} value="text selection can be changed" />
|
||||
<SelectionExample
|
||||
multiline
|
||||
style={styles.multiline}
|
||||
value={"multiline text selection\ncan also be changed"}
|
||||
value={'multiline text selection\ncan also be changed'}
|
||||
/>
|
||||
</View>
|
||||
);
|
||||
@@ -829,31 +811,16 @@ const examples = [
|
||||
return (
|
||||
<View>
|
||||
<WithLabel label="maxLength: 5">
|
||||
<TextInput
|
||||
maxLength={5}
|
||||
style={styles.default}
|
||||
/>
|
||||
<TextInput maxLength={5} style={styles.default} />
|
||||
</WithLabel>
|
||||
<WithLabel label="maxLength: 5 with placeholder">
|
||||
<TextInput
|
||||
maxLength={5}
|
||||
placeholder="ZIP code entry"
|
||||
style={styles.default}
|
||||
/>
|
||||
<TextInput maxLength={5} placeholder="ZIP code entry" style={styles.default} />
|
||||
</WithLabel>
|
||||
<WithLabel label="maxLength: 5 with default value already set">
|
||||
<TextInput
|
||||
maxLength={5}
|
||||
defaultValue="94025"
|
||||
style={styles.default}
|
||||
/>
|
||||
<TextInput defaultValue="94025" maxLength={5} style={styles.default} />
|
||||
</WithLabel>
|
||||
<WithLabel label="maxLength: 5 with very long default value already set">
|
||||
<TextInput
|
||||
maxLength={5}
|
||||
defaultValue="9402512345"
|
||||
style={styles.default}
|
||||
/>
|
||||
<TextInput defaultValue="9402512345" maxLength={5} style={styles.default} />
|
||||
</WithLabel>
|
||||
</View>
|
||||
);
|
||||
@@ -861,7 +828,6 @@ const examples = [
|
||||
}
|
||||
];
|
||||
|
||||
examples.forEach((example) => {
|
||||
storiesOf('component: TextInput', module)
|
||||
.add(example.title, () => example.render())
|
||||
examples.forEach(example => {
|
||||
storiesOf('component: TextInput', module).add(example.title, () => example.render());
|
||||
});
|
||||
473
docs/storybook/components/Touchable/TouchableExample.js
Normal file
@@ -0,0 +1,473 @@
|
||||
/* eslint-disable react/jsx-no-bind */
|
||||
|
||||
/**
|
||||
* Copyright (c) 2013-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.
|
||||
*
|
||||
* The examples provided by Facebook are for non-commercial testing and
|
||||
* evaluation purposes only.
|
||||
*
|
||||
* Facebook reserves all rights not expressly granted.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
|
||||
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NON INFRINGEMENT. IN NO EVENT SHALL
|
||||
* FACEBOOK BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
|
||||
* AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*
|
||||
* @flow
|
||||
*/
|
||||
|
||||
import React from 'react';
|
||||
import { storiesOf, action } from '@kadira/storybook';
|
||||
import {
|
||||
Image,
|
||||
StyleSheet,
|
||||
Text,
|
||||
TouchableHighlight,
|
||||
TouchableOpacity,
|
||||
Platform,
|
||||
TouchableNativeFeedback,
|
||||
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);
|
||||
this.state = { timesPressed: 0 };
|
||||
}
|
||||
|
||||
_handlePress = () => {
|
||||
this.setState({
|
||||
timesPressed: this.state.timesPressed + 1
|
||||
});
|
||||
};
|
||||
|
||||
render() {
|
||||
let textLog = '';
|
||||
if (this.state.timesPressed > 1) {
|
||||
textLog = this.state.timesPressed + 'x text onPress';
|
||||
} else if (this.state.timesPressed > 0) {
|
||||
textLog = 'text onPress';
|
||||
}
|
||||
|
||||
return (
|
||||
<View>
|
||||
<Text onPress={this._handlePress} style={styles.textBlock}>
|
||||
Text has built-in onPress handling
|
||||
</Text>
|
||||
<View style={styles.logBox}>
|
||||
<Text>{textLog}</Text>
|
||||
</View>
|
||||
</View>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class TouchableFeedbackEvents extends React.Component {
|
||||
constructor(props) {
|
||||
super(props);
|
||||
this.state = { eventLog: [] };
|
||||
}
|
||||
|
||||
render() {
|
||||
return (
|
||||
<View testID="touchable_feedback_events">
|
||||
<View style={[styles.row, { justifyContent: 'center' }]}>
|
||||
<TouchableOpacity
|
||||
accessibilityComponentType="button"
|
||||
accessibilityLabel="touchable feedback events"
|
||||
accessibilityTraits="button"
|
||||
onLongPress={this._createPressHandler('longPress')}
|
||||
onPress={this._createPressHandler('press')}
|
||||
onPressIn={this._createPressHandler('pressIn')}
|
||||
onPressOut={this._createPressHandler('pressOut')}
|
||||
style={styles.wrapper}
|
||||
testID="touchable_feedback_events_button"
|
||||
>
|
||||
<Text style={styles.button}>
|
||||
Press Me
|
||||
</Text>
|
||||
</TouchableOpacity>
|
||||
</View>
|
||||
<View style={styles.eventLogBox} testID="touchable_feedback_events_console">
|
||||
{this.state.eventLog.map((e, ii) => <Text key={ii}>{e}</Text>)}
|
||||
</View>
|
||||
</View>
|
||||
);
|
||||
}
|
||||
|
||||
_createPressHandler = eventName => {
|
||||
return () => {
|
||||
const limit = 6;
|
||||
const eventLog = this.state.eventLog.slice(0, limit - 1);
|
||||
eventLog.unshift(eventName);
|
||||
this.setState({ eventLog });
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
class TouchableDelayEvents extends React.Component {
|
||||
constructor(props) {
|
||||
super(props);
|
||||
this.state = { eventLog: [] };
|
||||
}
|
||||
|
||||
render() {
|
||||
return (
|
||||
<View testID="touchable_delay_events">
|
||||
<View style={[styles.row, { justifyContent: 'center' }]}>
|
||||
<TouchableOpacity
|
||||
delayLongPress={800}
|
||||
delayPressIn={400}
|
||||
delayPressOut={1000}
|
||||
onLongPress={this._createPressHandler('longPress - 800ms delay')}
|
||||
onPress={this._createPressHandler('press')}
|
||||
onPressIn={this._createPressHandler('pressIn - 400ms delay')}
|
||||
onPressOut={this._createPressHandler('pressOut - 1000ms delay')}
|
||||
style={styles.wrapper}
|
||||
testID="touchable_delay_events_button"
|
||||
>
|
||||
<Text style={styles.button}>
|
||||
Press Me
|
||||
</Text>
|
||||
</TouchableOpacity>
|
||||
</View>
|
||||
<View style={styles.eventLogBox} testID="touchable_delay_events_console">
|
||||
{this.state.eventLog.map((e, ii) => <Text key={ii}>{e}</Text>)}
|
||||
</View>
|
||||
</View>
|
||||
);
|
||||
}
|
||||
|
||||
_createPressHandler = eventName => {
|
||||
return () => {
|
||||
const limit = 6;
|
||||
const eventLog = this.state.eventLog.slice(0, limit - 1);
|
||||
eventLog.unshift(eventName);
|
||||
this.setState({ eventLog });
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
class ForceTouchExample extends React.Component {
|
||||
constructor(props) {
|
||||
super(props);
|
||||
this.state = { force: 0 };
|
||||
}
|
||||
|
||||
_renderConsoleText() {
|
||||
return View.forceTouchAvailable
|
||||
? 'Force: ' + this.state.force.toFixed(3)
|
||||
: '3D Touch is not available on this device';
|
||||
}
|
||||
|
||||
render() {
|
||||
return (
|
||||
<View testID="touchable_3dtouch_event">
|
||||
<View style={styles.forceTouchBox} testID="touchable_3dtouch_output">
|
||||
<Text>{this._renderConsoleText()}</Text>
|
||||
</View>
|
||||
<View style={[styles.row, { justifyContent: 'center' }]}>
|
||||
<View
|
||||
onResponderMove={event => this.setState({ force: event.nativeEvent.force })}
|
||||
onResponderRelease={event => this.setState({ force: 0 })}
|
||||
onStartShouldSetResponder={() => true}
|
||||
style={styles.wrapper}
|
||||
testID="touchable_3dtouch_button"
|
||||
>
|
||||
<Text style={styles.button}>
|
||||
Press Me
|
||||
</Text>
|
||||
</View>
|
||||
</View>
|
||||
</View>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class TouchableHitSlop extends React.Component {
|
||||
constructor(props) {
|
||||
super(props);
|
||||
this.state = { timesPressed: 0 };
|
||||
}
|
||||
|
||||
_handlePress = () => {
|
||||
this.setState({
|
||||
timesPressed: this.state.timesPressed + 1
|
||||
});
|
||||
};
|
||||
|
||||
render() {
|
||||
let log = '';
|
||||
if (this.state.timesPressed > 1) {
|
||||
log = this.state.timesPressed + 'x onPress';
|
||||
} else if (this.state.timesPressed > 0) {
|
||||
log = 'onPress';
|
||||
}
|
||||
|
||||
return (
|
||||
<View testID="touchable_hit_slop">
|
||||
<View style={[styles.row, { justifyContent: 'center' }]}>
|
||||
<TouchableOpacity
|
||||
hitSlop={{ top: 30, bottom: 30, left: 60, right: 60 }}
|
||||
onPress={this._handlePress}
|
||||
style={styles.hitSlopWrapper}
|
||||
testID="touchable_hit_slop_button"
|
||||
>
|
||||
<Text style={styles.hitSlopButton}>
|
||||
Press Outside This View
|
||||
</Text>
|
||||
</TouchableOpacity>
|
||||
</View>
|
||||
<View style={styles.logBox}>
|
||||
<Text>
|
||||
{log}
|
||||
</Text>
|
||||
</View>
|
||||
</View>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class TouchableDisabled extends React.Component {
|
||||
render() {
|
||||
return (
|
||||
<View>
|
||||
<TouchableOpacity
|
||||
disabled={true}
|
||||
onPress={action('TouchableOpacity')}
|
||||
style={[styles.row, styles.block]}
|
||||
>
|
||||
<Text style={styles.disabledButton}>Disabled TouchableOpacity</Text>
|
||||
</TouchableOpacity>
|
||||
|
||||
<TouchableOpacity
|
||||
disabled={false}
|
||||
onPress={action('TouchableOpacity')}
|
||||
style={[styles.row, styles.block]}
|
||||
>
|
||||
<Text style={styles.button}>Enabled TouchableOpacity</Text>
|
||||
</TouchableOpacity>
|
||||
|
||||
<TouchableHighlight
|
||||
activeOpacity={1}
|
||||
disabled={true}
|
||||
onPress={action('TouchableHighlight')}
|
||||
style={[styles.row, styles.block]}
|
||||
underlayColor="rgb(210, 230, 255)"
|
||||
>
|
||||
<Text style={styles.disabledButton}>
|
||||
Disabled TouchableHighlight
|
||||
</Text>
|
||||
</TouchableHighlight>
|
||||
|
||||
<TouchableHighlight
|
||||
activeOpacity={1}
|
||||
onPress={action('TouchableHighlight')}
|
||||
style={[styles.row, styles.block]}
|
||||
underlayColor="rgb(210, 230, 255)"
|
||||
>
|
||||
<Text style={styles.button}>
|
||||
Enabled TouchableHighlight
|
||||
</Text>
|
||||
</TouchableHighlight>
|
||||
|
||||
{Platform.OS === 'android' &&
|
||||
<TouchableNativeFeedback
|
||||
background={TouchableNativeFeedback.SelectableBackground()}
|
||||
onPress={() => console.log('custom TNF has been clicked')}
|
||||
style={[styles.row, styles.block]}
|
||||
>
|
||||
<View>
|
||||
<Text style={[styles.button, styles.nativeFeedbackButton]}>
|
||||
Enabled TouchableNativeFeedback
|
||||
</Text>
|
||||
</View>
|
||||
</TouchableNativeFeedback>}
|
||||
|
||||
{Platform.OS === 'android' &&
|
||||
<TouchableNativeFeedback
|
||||
background={TouchableNativeFeedback.SelectableBackground()}
|
||||
disabled={true}
|
||||
onPress={() => console.log('custom TNF has been clicked')}
|
||||
style={[styles.row, styles.block]}
|
||||
>
|
||||
<View>
|
||||
<Text style={[styles.disabledButton, styles.nativeFeedbackButton]}>
|
||||
Disabled TouchableNativeFeedback
|
||||
</Text>
|
||||
</View>
|
||||
</TouchableNativeFeedback>}
|
||||
</View>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
const heartImage = { uri: 'https://pbs.twimg.com/media/BlXBfT3CQAA6cVZ.png:small' };
|
||||
|
||||
const styles = StyleSheet.create({
|
||||
row: {
|
||||
justifyContent: 'center',
|
||||
flexDirection: 'row'
|
||||
},
|
||||
icon: {
|
||||
width: 24,
|
||||
height: 24
|
||||
},
|
||||
image: {
|
||||
width: 50,
|
||||
height: 50
|
||||
},
|
||||
text: {
|
||||
fontSize: 16
|
||||
},
|
||||
block: {
|
||||
padding: 10
|
||||
},
|
||||
button: {
|
||||
color: '#007AFF'
|
||||
},
|
||||
disabledButton: {
|
||||
color: '#007AFF',
|
||||
opacity: 0.5
|
||||
},
|
||||
nativeFeedbackButton: {
|
||||
textAlign: 'center',
|
||||
margin: 10
|
||||
},
|
||||
hitSlopButton: {
|
||||
color: 'white'
|
||||
},
|
||||
wrapper: {
|
||||
borderRadius: 8
|
||||
},
|
||||
wrapperCustom: {
|
||||
borderRadius: 8,
|
||||
padding: 6
|
||||
},
|
||||
hitSlopWrapper: {
|
||||
backgroundColor: 'red',
|
||||
marginVertical: 30
|
||||
},
|
||||
logBox: {
|
||||
padding: 20,
|
||||
margin: 10,
|
||||
borderWidth: StyleSheet.hairlineWidth,
|
||||
borderColor: '#f0f0f0',
|
||||
backgroundColor: '#f9f9f9'
|
||||
},
|
||||
eventLogBox: {
|
||||
padding: 10,
|
||||
margin: 10,
|
||||
height: 120,
|
||||
borderWidth: StyleSheet.hairlineWidth,
|
||||
borderColor: '#f0f0f0',
|
||||
backgroundColor: '#f9f9f9'
|
||||
},
|
||||
forceTouchBox: {
|
||||
padding: 10,
|
||||
margin: 10,
|
||||
borderWidth: StyleSheet.hairlineWidth,
|
||||
borderColor: '#f0f0f0',
|
||||
backgroundColor: '#f9f9f9',
|
||||
alignItems: 'center'
|
||||
},
|
||||
textBlock: {
|
||||
fontWeight: '500',
|
||||
color: 'blue'
|
||||
}
|
||||
});
|
||||
|
||||
examples.forEach(example => {
|
||||
storiesOf('component: Touchable*', module).add(example.title, () => example.render());
|
||||
});
|
||||
@@ -1,7 +1,7 @@
|
||||
import createReactClass from 'create-react-class';
|
||||
import React from 'react';
|
||||
import { storiesOf, action } from '@kadira/storybook';
|
||||
import { StyleSheet, Text, TouchableWithoutFeedback, View } from 'react-native'
|
||||
import { storiesOf } from '@kadira/storybook';
|
||||
import { StyleSheet, Text, TouchableWithoutFeedback, View } from 'react-native';
|
||||
|
||||
/**
|
||||
* Copyright (c) 2013-present, Facebook, Inc.
|
||||
@@ -26,32 +26,32 @@ import { StyleSheet, Text, TouchableWithoutFeedback, View } from 'react-native'
|
||||
* @flow
|
||||
*/
|
||||
|
||||
var styles = StyleSheet.create({
|
||||
const styles = StyleSheet.create({
|
||||
box: {
|
||||
backgroundColor: '#527FE4',
|
||||
borderColor: '#000033',
|
||||
borderWidth: 1,
|
||||
borderWidth: 1
|
||||
},
|
||||
shadowBox: {
|
||||
width: 100,
|
||||
height: 100,
|
||||
borderWidth: 2,
|
||||
borderWidth: 2
|
||||
},
|
||||
shadow: {
|
||||
shadowOpacity: 0.5,
|
||||
shadowColor: 'red',
|
||||
shadowRadius: 3,
|
||||
shadowOffset: { width: 3, height: 3 },
|
||||
shadowOffset: { width: 3, height: 3 }
|
||||
},
|
||||
zIndex: {
|
||||
justifyContent: 'space-around',
|
||||
width: 100,
|
||||
height: 50,
|
||||
marginTop: -10,
|
||||
},
|
||||
marginTop: -10
|
||||
}
|
||||
});
|
||||
|
||||
var ViewBorderStyleExample = createReactClass({
|
||||
const ViewBorderStyleExample = createReactClass({
|
||||
getInitialState() {
|
||||
return {
|
||||
showBorder: true
|
||||
@@ -62,23 +62,27 @@ var ViewBorderStyleExample = createReactClass({
|
||||
return (
|
||||
<TouchableWithoutFeedback onPress={this._handlePress}>
|
||||
<View>
|
||||
<View style={{
|
||||
borderWidth: 1,
|
||||
borderStyle: this.state.showBorder ? 'dashed' : null,
|
||||
padding: 5
|
||||
}}>
|
||||
<Text style={{fontSize: 11}}>
|
||||
<View
|
||||
style={{
|
||||
borderWidth: 1,
|
||||
borderStyle: this.state.showBorder ? 'dashed' : null,
|
||||
padding: 5
|
||||
}}
|
||||
>
|
||||
<Text style={{ fontSize: 11 }}>
|
||||
Dashed border style
|
||||
</Text>
|
||||
</View>
|
||||
<View style={{
|
||||
marginTop: 5,
|
||||
borderWidth: 1,
|
||||
borderRadius: 5,
|
||||
borderStyle: this.state.showBorder ? 'dotted' : null,
|
||||
padding: 5
|
||||
}}>
|
||||
<Text style={{fontSize: 11}}>
|
||||
<View
|
||||
style={{
|
||||
marginTop: 5,
|
||||
borderWidth: 1,
|
||||
borderRadius: 5,
|
||||
borderStyle: this.state.showBorder ? 'dotted' : null,
|
||||
padding: 5
|
||||
}}
|
||||
>
|
||||
<Text style={{ fontSize: 11 }}>
|
||||
Dotted border style
|
||||
</Text>
|
||||
</View>
|
||||
@@ -88,11 +92,11 @@ var ViewBorderStyleExample = createReactClass({
|
||||
},
|
||||
|
||||
_handlePress() {
|
||||
this.setState({showBorder: !this.state.showBorder});
|
||||
this.setState({ showBorder: !this.state.showBorder });
|
||||
}
|
||||
});
|
||||
|
||||
var ZIndexExample = createReactClass({
|
||||
const ZIndexExample = createReactClass({
|
||||
getInitialState() {
|
||||
return {
|
||||
flipped: false
|
||||
@@ -104,29 +108,37 @@ var ZIndexExample = createReactClass({
|
||||
return (
|
||||
<TouchableWithoutFeedback onPress={this._handlePress}>
|
||||
<View>
|
||||
<Text style={{paddingBottom: 10}}>Tap to flip sorting order</Text>
|
||||
<View style={[
|
||||
styles.zIndex,
|
||||
{marginTop: 0, backgroundColor: '#E57373', zIndex: indices[0]}
|
||||
]}>
|
||||
<Text style={{ paddingBottom: 10 }}>Tap to flip sorting order</Text>
|
||||
<View
|
||||
style={[
|
||||
styles.zIndex,
|
||||
{ marginTop: 0, backgroundColor: '#E57373', zIndex: indices[0] }
|
||||
]}
|
||||
>
|
||||
<Text>ZIndex {indices[0]}</Text>
|
||||
</View>
|
||||
<View style={[
|
||||
styles.zIndex,
|
||||
{marginLeft: 50, backgroundColor: '#FFF176', zIndex: indices[1]}
|
||||
]}>
|
||||
<View
|
||||
style={[
|
||||
styles.zIndex,
|
||||
{ marginLeft: 50, backgroundColor: '#FFF176', zIndex: indices[1] }
|
||||
]}
|
||||
>
|
||||
<Text>ZIndex {indices[1]}</Text>
|
||||
</View>
|
||||
<View style={[
|
||||
styles.zIndex,
|
||||
{marginLeft: 100, backgroundColor: '#81C784', zIndex: indices[2]}
|
||||
]}>
|
||||
<View
|
||||
style={[
|
||||
styles.zIndex,
|
||||
{ marginLeft: 100, backgroundColor: '#81C784', zIndex: indices[2] }
|
||||
]}
|
||||
>
|
||||
<Text>ZIndex {indices[2]}</Text>
|
||||
</View>
|
||||
<View style={[
|
||||
styles.zIndex,
|
||||
{marginLeft: 150, backgroundColor: '#64B5F6', zIndex: indices[3]}
|
||||
]}>
|
||||
<View
|
||||
style={[
|
||||
styles.zIndex,
|
||||
{ marginLeft: 150, backgroundColor: '#64B5F6', zIndex: indices[3] }
|
||||
]}
|
||||
>
|
||||
<Text>ZIndex {indices[3]}</Text>
|
||||
</View>
|
||||
</View>
|
||||
@@ -135,7 +147,7 @@ var ZIndexExample = createReactClass({
|
||||
},
|
||||
|
||||
_handlePress() {
|
||||
this.setState({flipped: !this.state.flipped});
|
||||
this.setState({ flipped: !this.state.flipped });
|
||||
}
|
||||
});
|
||||
|
||||
@@ -144,74 +156,78 @@ const examples = [
|
||||
title: 'Background Color',
|
||||
render: function() {
|
||||
return (
|
||||
<View style={{backgroundColor: '#527FE4', padding: 5}}>
|
||||
<Text style={{fontSize: 11}}>
|
||||
<View style={{ backgroundColor: '#527FE4', padding: 5 }}>
|
||||
<Text style={{ fontSize: 11 }}>
|
||||
Blue background
|
||||
</Text>
|
||||
</View>
|
||||
);
|
||||
},
|
||||
}, {
|
||||
}
|
||||
},
|
||||
{
|
||||
title: 'Border',
|
||||
render: function() {
|
||||
return (
|
||||
<View style={{borderColor: '#527FE4', borderWidth: 5, padding: 10}}>
|
||||
<Text style={{fontSize: 11}}>5px blue border</Text>
|
||||
<View style={{ borderColor: '#527FE4', borderWidth: 5, padding: 10 }}>
|
||||
<Text style={{ fontSize: 11 }}>5px blue border</Text>
|
||||
</View>
|
||||
);
|
||||
},
|
||||
}, {
|
||||
}
|
||||
},
|
||||
{
|
||||
title: 'Padding/Margin',
|
||||
render: function() {
|
||||
return (
|
||||
<View style={{borderColor: '#bb0000', borderWidth: 0.5}}>
|
||||
<View style={[styles.box, {padding: 5}]}>
|
||||
<Text style={{fontSize: 11}}>5px padding</Text>
|
||||
<View style={{ borderColor: '#bb0000', borderWidth: 0.5 }}>
|
||||
<View style={[styles.box, { padding: 5 }]}>
|
||||
<Text style={{ fontSize: 11 }}>5px padding</Text>
|
||||
</View>
|
||||
<View style={[styles.box, {margin: 5}]}>
|
||||
<Text style={{fontSize: 11}}>5px margin</Text>
|
||||
<View style={[styles.box, { margin: 5 }]}>
|
||||
<Text style={{ fontSize: 11 }}>5px margin</Text>
|
||||
</View>
|
||||
<View style={[styles.box, {margin: 5, padding: 5, alignSelf: 'flex-start'}]}>
|
||||
<Text style={{fontSize: 11}}>
|
||||
<View style={[styles.box, { margin: 5, padding: 5, alignSelf: 'flex-start' }]}>
|
||||
<Text style={{ fontSize: 11 }}>
|
||||
5px margin and padding,
|
||||
</Text>
|
||||
<Text style={{fontSize: 11}}>
|
||||
<Text style={{ fontSize: 11 }}>
|
||||
widthAutonomous=true
|
||||
</Text>
|
||||
</View>
|
||||
</View>
|
||||
);
|
||||
},
|
||||
}, {
|
||||
}
|
||||
},
|
||||
{
|
||||
title: 'Border Radius',
|
||||
render: function() {
|
||||
return (
|
||||
<View style={{borderWidth: 0.5, borderRadius: 5, padding: 5}}>
|
||||
<Text style={{fontSize: 11}}>
|
||||
<View style={{ borderWidth: 0.5, borderRadius: 5, padding: 5 }}>
|
||||
<Text style={{ fontSize: 11 }}>
|
||||
Too much use of `borderRadius` (especially large radii) on
|
||||
anything which is scrolling may result in dropped frames.
|
||||
Use sparingly.
|
||||
</Text>
|
||||
</View>
|
||||
);
|
||||
},
|
||||
}, {
|
||||
}
|
||||
},
|
||||
{
|
||||
title: 'Border Style',
|
||||
render: function() {
|
||||
return <ViewBorderStyleExample />;
|
||||
},
|
||||
}, {
|
||||
}
|
||||
},
|
||||
{
|
||||
title: 'Circle with Border Radius',
|
||||
render: function() {
|
||||
return (
|
||||
<View style={{borderRadius: 10, borderWidth: 1, width: 20, height: 20}} />
|
||||
);
|
||||
},
|
||||
}, {
|
||||
return <View style={{ borderRadius: 10, borderWidth: 1, width: 20, height: 20 }} />;
|
||||
}
|
||||
},
|
||||
{
|
||||
title: 'Overflow',
|
||||
render: function() {
|
||||
return (
|
||||
<View style={{flexDirection: 'row'}}>
|
||||
<View style={{ flexDirection: 'row' }}>
|
||||
<View
|
||||
style={{
|
||||
width: 95,
|
||||
@@ -219,57 +235,59 @@ const examples = [
|
||||
marginRight: 10,
|
||||
marginBottom: 5,
|
||||
overflow: 'hidden',
|
||||
borderWidth: 0.5,
|
||||
}}>
|
||||
<View style={{width: 200, height: 20}}>
|
||||
borderWidth: 0.5
|
||||
}}
|
||||
>
|
||||
<View style={{ width: 200, height: 20 }}>
|
||||
<Text>Overflow hidden</Text>
|
||||
</View>
|
||||
</View>
|
||||
<View style={{width: 95, height: 10, marginBottom: 5, borderWidth: 0.5}}>
|
||||
<View style={{width: 200, height: 20}}>
|
||||
<View style={{ width: 95, height: 10, marginBottom: 5, borderWidth: 0.5 }}>
|
||||
<View style={{ width: 200, height: 20 }}>
|
||||
<Text>Overflow visible</Text>
|
||||
</View>
|
||||
</View>
|
||||
</View>
|
||||
);
|
||||
},
|
||||
}, {
|
||||
}
|
||||
},
|
||||
{
|
||||
title: 'Opacity',
|
||||
render: function() {
|
||||
return (
|
||||
<View>
|
||||
<View style={{opacity: 0}}><Text>Opacity 0</Text></View>
|
||||
<View style={{opacity: 0.1}}><Text>Opacity 0.1</Text></View>
|
||||
<View style={{opacity: 0.3}}><Text>Opacity 0.3</Text></View>
|
||||
<View style={{opacity: 0.5}}><Text>Opacity 0.5</Text></View>
|
||||
<View style={{opacity: 0.7}}><Text>Opacity 0.7</Text></View>
|
||||
<View style={{opacity: 0.9}}><Text>Opacity 0.9</Text></View>
|
||||
<View style={{opacity: 1}}><Text>Opacity 1</Text></View>
|
||||
<View style={{ opacity: 0 }}><Text>Opacity 0</Text></View>
|
||||
<View style={{ opacity: 0.1 }}><Text>Opacity 0.1</Text></View>
|
||||
<View style={{ opacity: 0.3 }}><Text>Opacity 0.3</Text></View>
|
||||
<View style={{ opacity: 0.5 }}><Text>Opacity 0.5</Text></View>
|
||||
<View style={{ opacity: 0.7 }}><Text>Opacity 0.7</Text></View>
|
||||
<View style={{ opacity: 0.9 }}><Text>Opacity 0.9</Text></View>
|
||||
<View style={{ opacity: 1 }}><Text>Opacity 1</Text></View>
|
||||
</View>
|
||||
);
|
||||
},
|
||||
}, {
|
||||
}
|
||||
},
|
||||
{
|
||||
title: 'ZIndex',
|
||||
render: function() {
|
||||
return <ZIndexExample />;
|
||||
},
|
||||
}
|
||||
},
|
||||
{
|
||||
title: 'Basic shadow',
|
||||
render() {
|
||||
return <View style={[ styles.shadowBox, styles.shadow ]} />;
|
||||
return <View style={[styles.shadowBox, styles.shadow]} />;
|
||||
}
|
||||
},
|
||||
{
|
||||
title: 'Shaped shadow',
|
||||
description: 'borderRadius: 50',
|
||||
render() {
|
||||
return <View style={[ styles.shadowBox, styles.shadow, {borderRadius: 50} ]} />;
|
||||
return <View style={[styles.shadowBox, styles.shadow, { borderRadius: 50 }]} />;
|
||||
}
|
||||
}
|
||||
];
|
||||
|
||||
examples.forEach((example) => {
|
||||
storiesOf('component: View', module)
|
||||
.add(example.title, () => example.render())
|
||||
})
|
||||
examples.forEach(example => {
|
||||
storiesOf('component: View', module).add(example.title, () => example.render());
|
||||
});
|
||||
@@ -1,7 +1,7 @@
|
||||
import createReactClass from 'create-react-class';
|
||||
import React from 'react';
|
||||
import { storiesOf, action } from '@kadira/storybook';
|
||||
import { Animated, StyleSheet, Text, View } from 'react-native'
|
||||
import { storiesOf } from '@kadira/storybook';
|
||||
import { Animated, StyleSheet, Text, View } from 'react-native';
|
||||
|
||||
/**
|
||||
* Copyright (c) 2013-present, Facebook, Inc.
|
||||
@@ -25,10 +25,10 @@ import { Animated, StyleSheet, Text, View } from 'react-native'
|
||||
* @flow
|
||||
*/
|
||||
|
||||
var Flip = createReactClass({
|
||||
const Flip = createReactClass({
|
||||
getInitialState() {
|
||||
return {
|
||||
theta: new Animated.Value(45),
|
||||
theta: new Animated.Value(45)
|
||||
};
|
||||
},
|
||||
|
||||
@@ -40,37 +40,52 @@ var Flip = createReactClass({
|
||||
this.state.theta.setValue(0);
|
||||
Animated.timing(this.state.theta, {
|
||||
toValue: 360,
|
||||
duration: 5000,
|
||||
duration: 5000
|
||||
}).start(this._animate);
|
||||
},
|
||||
|
||||
render() {
|
||||
return (
|
||||
<View style={styles.flipCardContainer}>
|
||||
<Animated.View style={[
|
||||
styles.flipCard,
|
||||
{transform: [
|
||||
{perspective: 850},
|
||||
{rotateX: this.state.theta.interpolate({
|
||||
inputRange: [0, 180],
|
||||
outputRange: ['0deg', '180deg']
|
||||
})},
|
||||
]}]}>
|
||||
<Animated.View
|
||||
style={[
|
||||
styles.flipCard,
|
||||
{
|
||||
transform: [
|
||||
{ perspective: 850 },
|
||||
{
|
||||
rotateX: this.state.theta.interpolate({
|
||||
inputRange: [0, 180],
|
||||
outputRange: ['0deg', '180deg']
|
||||
})
|
||||
}
|
||||
]
|
||||
}
|
||||
]}
|
||||
>
|
||||
<Text style={styles.flipText}>
|
||||
This text is flipping great.
|
||||
</Text>
|
||||
</Animated.View>
|
||||
<Animated.View style={[styles.flipCard, {
|
||||
position: 'absolute',
|
||||
top: 0,
|
||||
backgroundColor: 'red',
|
||||
transform: [
|
||||
{perspective: 850},
|
||||
{rotateX: this.state.theta.interpolate({
|
||||
inputRange: [0, 180],
|
||||
outputRange: ['180deg', '360deg']
|
||||
})},
|
||||
]}]}>
|
||||
<Animated.View
|
||||
style={[
|
||||
styles.flipCard,
|
||||
{
|
||||
position: 'absolute',
|
||||
top: 0,
|
||||
backgroundColor: 'red',
|
||||
transform: [
|
||||
{ perspective: 850 },
|
||||
{
|
||||
rotateX: this.state.theta.interpolate({
|
||||
inputRange: [0, 180],
|
||||
outputRange: ['180deg', '360deg']
|
||||
})
|
||||
}
|
||||
]
|
||||
}
|
||||
]}
|
||||
>
|
||||
<Text style={styles.flipText}>
|
||||
On the flip side...
|
||||
</Text>
|
||||
@@ -80,20 +95,20 @@ var Flip = createReactClass({
|
||||
}
|
||||
});
|
||||
|
||||
var styles = StyleSheet.create({
|
||||
const styles = StyleSheet.create({
|
||||
box1: {
|
||||
left: 0,
|
||||
backgroundColor: 'green',
|
||||
height: 50,
|
||||
top: 0,
|
||||
transform: [
|
||||
{translateX: 100},
|
||||
{translateY: 50},
|
||||
{rotate: '30deg'},
|
||||
{scaleX: 2},
|
||||
{scaleY: 2},
|
||||
{ translateX: 100 },
|
||||
{ translateY: 50 },
|
||||
{ rotate: '30deg' },
|
||||
{ scaleX: 2 },
|
||||
{ scaleY: 2 }
|
||||
],
|
||||
width: 50,
|
||||
width: 50
|
||||
},
|
||||
box2: {
|
||||
left: 0,
|
||||
@@ -101,23 +116,21 @@ var styles = StyleSheet.create({
|
||||
height: 50,
|
||||
top: 0,
|
||||
transform: [
|
||||
{scaleX: 2},
|
||||
{scaleY: 2},
|
||||
{translateX: 100},
|
||||
{translateY: 50},
|
||||
{rotate: '30deg'},
|
||||
{ scaleX: 2 },
|
||||
{ scaleY: 2 },
|
||||
{ translateX: 100 },
|
||||
{ translateY: 50 },
|
||||
{ rotate: '30deg' }
|
||||
],
|
||||
width: 50,
|
||||
width: 50
|
||||
},
|
||||
box3step1: {
|
||||
left: 0,
|
||||
backgroundColor: 'lightpink',
|
||||
height: 50,
|
||||
top: 0,
|
||||
transform: [
|
||||
{rotate: '30deg'},
|
||||
],
|
||||
width: 50,
|
||||
transform: [{ rotate: '30deg' }],
|
||||
width: 50
|
||||
},
|
||||
box3step2: {
|
||||
left: 0,
|
||||
@@ -125,12 +138,8 @@ var styles = StyleSheet.create({
|
||||
height: 50,
|
||||
opacity: 0.5,
|
||||
top: 0,
|
||||
transform: [
|
||||
{rotate: '30deg'},
|
||||
{scaleX: 2},
|
||||
{scaleY: 2},
|
||||
],
|
||||
width: 50,
|
||||
transform: [{ rotate: '30deg' }, { scaleX: 2 }, { scaleY: 2 }],
|
||||
width: 50
|
||||
},
|
||||
box3step3: {
|
||||
left: 0,
|
||||
@@ -139,46 +148,36 @@ var styles = StyleSheet.create({
|
||||
opacity: 0.5,
|
||||
top: 0,
|
||||
transform: [
|
||||
{rotate: '30deg'},
|
||||
{scaleX: 2},
|
||||
{scaleY: 2},
|
||||
{translateX: 10},
|
||||
{translateY: 50},
|
||||
{ rotate: '30deg' },
|
||||
{ scaleX: 2 },
|
||||
{ scaleY: 2 },
|
||||
{ translateX: 10 },
|
||||
{ translateY: 50 }
|
||||
],
|
||||
width: 50,
|
||||
width: 50
|
||||
},
|
||||
box4: {
|
||||
left: 0,
|
||||
backgroundColor: 'darkorange',
|
||||
height: 50,
|
||||
top: 0,
|
||||
transform: [
|
||||
{translateX: 20},
|
||||
{translateY: 35},
|
||||
{scale: 2.5},
|
||||
{rotate: '-0.2rad'},
|
||||
],
|
||||
width: 100,
|
||||
transform: [{ translateX: 20 }, { translateY: 35 }, { scale: 2.5 }, { rotate: '-0.2rad' }],
|
||||
width: 100
|
||||
},
|
||||
box5: {
|
||||
backgroundColor: 'maroon',
|
||||
height: 50,
|
||||
right: 0,
|
||||
top: 0,
|
||||
width: 50,
|
||||
width: 50
|
||||
},
|
||||
box5Transform: {
|
||||
transform: [
|
||||
{translateX: -50},
|
||||
{translateY: 35},
|
||||
{rotate: '50deg'},
|
||||
{scale: 2},
|
||||
],
|
||||
transform: [{ translateX: -50 }, { translateY: 35 }, { rotate: '50deg' }, { scale: 2 }]
|
||||
},
|
||||
flipCardContainer: {
|
||||
marginVertical: 40,
|
||||
flex: 1,
|
||||
alignSelf: 'center',
|
||||
alignSelf: 'center'
|
||||
},
|
||||
flipCard: {
|
||||
width: 200,
|
||||
@@ -186,13 +185,13 @@ var styles = StyleSheet.create({
|
||||
alignItems: 'center',
|
||||
justifyContent: 'center',
|
||||
backgroundColor: 'blue',
|
||||
backfaceVisibility: 'hidden',
|
||||
backfaceVisibility: 'hidden'
|
||||
},
|
||||
flipText: {
|
||||
width: 90,
|
||||
fontSize: 20,
|
||||
color: 'white',
|
||||
fontWeight: 'bold',
|
||||
fontWeight: 'bold'
|
||||
}
|
||||
});
|
||||
|
||||
@@ -200,88 +199,61 @@ const examples = [
|
||||
{
|
||||
title: 'Perspective',
|
||||
description: 'perspective: 850, rotateX: Animated.timing(0 -> 360)',
|
||||
render(): ReactElement<any> { return <Flip />; }
|
||||
render() {
|
||||
return <Flip />;
|
||||
}
|
||||
},
|
||||
{
|
||||
title: 'Translate, Rotate, Scale',
|
||||
description: "translateX: 100, translateY: 50, rotate: '30deg', scaleX: 2, scaleY: 2",
|
||||
render() {
|
||||
return (
|
||||
|
||||
<View style={styles.box1} />
|
||||
|
||||
);
|
||||
return <View style={styles.box1} />;
|
||||
}
|
||||
},
|
||||
{
|
||||
title: 'Scale, Translate, Rotate, ',
|
||||
description: "scaleX: 2, scaleY: 2, translateX: 100, translateY: 50, rotate: '30deg'",
|
||||
render() {
|
||||
return (
|
||||
|
||||
<View style={styles.box2} />
|
||||
|
||||
);
|
||||
return <View style={styles.box2} />;
|
||||
}
|
||||
},
|
||||
{
|
||||
title: 'Rotate',
|
||||
description: "rotate: '30deg'",
|
||||
render() {
|
||||
return (
|
||||
|
||||
<View style={styles.box3step1} />
|
||||
|
||||
);
|
||||
return <View style={styles.box3step1} />;
|
||||
}
|
||||
},
|
||||
{
|
||||
title: 'Rotate, Scale',
|
||||
description: "rotate: '30deg', scaleX: 2, scaleY: 2",
|
||||
render() {
|
||||
return (
|
||||
|
||||
<View style={styles.box3step2} />
|
||||
|
||||
);
|
||||
return <View style={styles.box3step2} />;
|
||||
}
|
||||
},
|
||||
{
|
||||
title: 'Rotate, Scale, Translate ',
|
||||
description: "rotate: '30deg', scaleX: 2, scaleY: 2, translateX: 100, translateY: 50",
|
||||
render() {
|
||||
return (
|
||||
|
||||
<View style={styles.box3step3} />
|
||||
|
||||
);
|
||||
return <View style={styles.box3step3} />;
|
||||
}
|
||||
},
|
||||
{
|
||||
title: 'Translate, Scale, Rotate',
|
||||
description: "translate: [200, 350], scale: 2.5, rotate: '-0.2rad'",
|
||||
render() {
|
||||
return (
|
||||
|
||||
<View style={styles.box4} />
|
||||
|
||||
);
|
||||
return <View style={styles.box4} />;
|
||||
}
|
||||
},
|
||||
{
|
||||
title: 'Translate, Rotate, Scale',
|
||||
description: "translate: [-50, 35], rotate: '50deg', scale: 2",
|
||||
render() {
|
||||
return (
|
||||
|
||||
<View style={[styles.box5, styles.box5Transform]} />
|
||||
|
||||
);
|
||||
return <View style={[styles.box5, styles.box5Transform]} />;
|
||||
}
|
||||
}
|
||||
];
|
||||
|
||||
examples.forEach((example) => {
|
||||
storiesOf('component: View (transforms)', module)
|
||||
.add(example.title, () => example.render())
|
||||
})
|
||||
examples.forEach(example => {
|
||||
storiesOf('component: View (transforms)', module).add(example.title, () => example.render());
|
||||
});
|
||||
@@ -16,22 +16,14 @@
|
||||
*/
|
||||
'use strict';
|
||||
|
||||
var React = require('react');
|
||||
var ReactNative = require('react-native');
|
||||
var {
|
||||
Animated,
|
||||
AppRegistry,
|
||||
StyleSheet,
|
||||
Text,
|
||||
TouchableOpacity,
|
||||
View,
|
||||
} = ReactNative;
|
||||
import { any, func, object } from 'prop-types';
|
||||
import GameBoard from './GameBoard';
|
||||
import React from 'react';
|
||||
import { Animated, AppRegistry, StyleSheet, Text, TouchableOpacity, View } from 'react-native';
|
||||
|
||||
var GameBoard = require('./GameBoard');
|
||||
|
||||
var BOARD_PADDING = 3;
|
||||
var CELL_MARGIN = 4;
|
||||
var CELL_SIZE = 60;
|
||||
const BOARD_PADDING = 3;
|
||||
const CELL_MARGIN = 4;
|
||||
const CELL_SIZE = 60;
|
||||
|
||||
class Cell extends React.Component {
|
||||
render() {
|
||||
@@ -40,13 +32,17 @@ class Cell extends React.Component {
|
||||
}
|
||||
|
||||
class Board extends React.Component {
|
||||
static propTypes = {
|
||||
children: any
|
||||
};
|
||||
|
||||
render() {
|
||||
return (
|
||||
<View style={styles.board}>
|
||||
<View style={styles.row}><Cell/><Cell/><Cell/><Cell/></View>
|
||||
<View style={styles.row}><Cell/><Cell/><Cell/><Cell/></View>
|
||||
<View style={styles.row}><Cell/><Cell/><Cell/><Cell/></View>
|
||||
<View style={styles.row}><Cell/><Cell/><Cell/><Cell/></View>
|
||||
<View style={styles.row}><Cell /><Cell /><Cell /><Cell /></View>
|
||||
<View style={styles.row}><Cell /><Cell /><Cell /><Cell /></View>
|
||||
<View style={styles.row}><Cell /><Cell /><Cell /><Cell /></View>
|
||||
<View style={styles.row}><Cell /><Cell /><Cell /><Cell /></View>
|
||||
{this.props.children}
|
||||
</View>
|
||||
);
|
||||
@@ -56,6 +52,10 @@ class Board extends React.Component {
|
||||
class Tile extends React.Component {
|
||||
state: any;
|
||||
|
||||
static propTypes = {
|
||||
tile: object
|
||||
};
|
||||
|
||||
static _getPosition(index): number {
|
||||
return BOARD_PADDING + (index * (CELL_SIZE + CELL_MARGIN * 2) + CELL_MARGIN);
|
||||
}
|
||||
@@ -63,58 +63,54 @@ class Tile extends React.Component {
|
||||
constructor(props: {}) {
|
||||
super(props);
|
||||
|
||||
var tile = this.props.tile;
|
||||
const tile = this.props.tile;
|
||||
|
||||
this.state = {
|
||||
opacity: new Animated.Value(0),
|
||||
top: new Animated.Value(Tile._getPosition(tile.toRow())),
|
||||
left: new Animated.Value(Tile._getPosition(tile.toColumn())),
|
||||
left: new Animated.Value(Tile._getPosition(tile.toColumn()))
|
||||
};
|
||||
}
|
||||
|
||||
calculateOffset(): {top: number; left: number; opacity: number} {
|
||||
var tile = this.props.tile;
|
||||
calculateOffset(): { top: number, left: number, opacity: number } {
|
||||
const tile = this.props.tile;
|
||||
|
||||
var offset = {
|
||||
const offset = {
|
||||
top: this.state.top,
|
||||
left: this.state.left,
|
||||
opacity: this.state.opacity,
|
||||
opacity: this.state.opacity
|
||||
};
|
||||
|
||||
if (tile.isNew()) {
|
||||
Animated.timing(this.state.opacity, {
|
||||
duration: 100,
|
||||
toValue: 1,
|
||||
toValue: 1
|
||||
}).start();
|
||||
} else {
|
||||
Animated.parallel([
|
||||
Animated.timing(offset.top, {
|
||||
duration: 100,
|
||||
toValue: Tile._getPosition(tile.toRow()),
|
||||
toValue: Tile._getPosition(tile.toRow())
|
||||
}),
|
||||
Animated.timing(offset.left, {
|
||||
duration: 100,
|
||||
toValue: Tile._getPosition(tile.toColumn()),
|
||||
}),
|
||||
toValue: Tile._getPosition(tile.toColumn())
|
||||
})
|
||||
]).start();
|
||||
}
|
||||
return offset;
|
||||
}
|
||||
|
||||
render() {
|
||||
var tile = this.props.tile;
|
||||
const tile = this.props.tile;
|
||||
|
||||
var tileStyles = [
|
||||
styles.tile,
|
||||
styles['tile' + tile.value],
|
||||
this.calculateOffset(),
|
||||
];
|
||||
const tileStyles = [styles.tile, styles['tile' + tile.value], this.calculateOffset()];
|
||||
|
||||
var textStyles = [
|
||||
const textStyles = [
|
||||
styles.value,
|
||||
tile.value > 4 && styles.whiteText,
|
||||
tile.value > 100 && styles.threeDigits,
|
||||
tile.value > 1000 && styles.fourDigits,
|
||||
tile.value > 1000 && styles.fourDigits
|
||||
];
|
||||
|
||||
return (
|
||||
@@ -126,15 +122,19 @@ class Tile extends React.Component {
|
||||
}
|
||||
|
||||
class GameEndOverlay extends React.Component {
|
||||
static propTypes = {
|
||||
board: object,
|
||||
onRestart: func
|
||||
};
|
||||
|
||||
render() {
|
||||
var board = this.props.board;
|
||||
const board = this.props.board;
|
||||
|
||||
if (!board.hasWon() && !board.hasLost()) {
|
||||
return <View/>;
|
||||
return <View />;
|
||||
}
|
||||
|
||||
var message = board.hasWon() ?
|
||||
'Good Job!' : 'Game Over';
|
||||
const message = board.hasWon() ? 'Good Job!' : 'Game Over';
|
||||
|
||||
return (
|
||||
<View style={styles.overlay}>
|
||||
@@ -155,34 +155,34 @@ class Game2048 extends React.Component {
|
||||
constructor(props: {}) {
|
||||
super(props);
|
||||
this.state = {
|
||||
board: new GameBoard(),
|
||||
board: new GameBoard()
|
||||
};
|
||||
this.startX = 0;
|
||||
this.startY = 0;
|
||||
}
|
||||
|
||||
restartGame() {
|
||||
this.setState({board: new GameBoard()});
|
||||
}
|
||||
_handleRestart = () => {
|
||||
this.setState({ board: new GameBoard() });
|
||||
};
|
||||
|
||||
handleTouchStart(event: Object) {
|
||||
_handleTouchStart = (event: Object) => {
|
||||
if (this.state.board.hasWon()) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.startX = event.nativeEvent.pageX;
|
||||
this.startY = event.nativeEvent.pageY;
|
||||
}
|
||||
};
|
||||
|
||||
handleTouchEnd(event: Object) {
|
||||
_handleTouchEnd = (event: Object) => {
|
||||
if (this.state.board.hasWon()) {
|
||||
return;
|
||||
}
|
||||
|
||||
var deltaX = event.nativeEvent.pageX - this.startX;
|
||||
var deltaY = event.nativeEvent.pageY - this.startY;
|
||||
const deltaX = event.nativeEvent.pageX - this.startX;
|
||||
const deltaY = event.nativeEvent.pageY - this.startY;
|
||||
|
||||
var direction = -1;
|
||||
let direction = -1;
|
||||
if (Math.abs(deltaX) > 3 * Math.abs(deltaY) && Math.abs(deltaX) > 30) {
|
||||
direction = deltaX > 0 ? 2 : 0;
|
||||
} else if (Math.abs(deltaY) > 3 * Math.abs(deltaX) && Math.abs(deltaY) > 30) {
|
||||
@@ -190,39 +190,40 @@ class Game2048 extends React.Component {
|
||||
}
|
||||
|
||||
if (direction !== -1) {
|
||||
this.setState({board: this.state.board.move(direction)});
|
||||
this.setState({ board: this.state.board.move(direction) });
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
render() {
|
||||
var tiles = this.state.board.tiles
|
||||
.filter((tile) => tile.value)
|
||||
.map((tile) => <Tile ref={tile.id} key={tile.id} tile={tile} />);
|
||||
const tiles = this.state.board.tiles
|
||||
.filter(tile => tile.value)
|
||||
.map(tile => <Tile key={tile.id} ref={tile.id} tile={tile} />);
|
||||
|
||||
return (
|
||||
<View
|
||||
onTouchEnd={this._handleTouchEnd}
|
||||
onTouchStart={this._handleTouchStart}
|
||||
style={styles.container}
|
||||
onTouchStart={(event) => this.handleTouchStart(event)}
|
||||
onTouchEnd={(event) => this.handleTouchEnd(event)}>
|
||||
>
|
||||
<Board>
|
||||
{tiles}
|
||||
</Board>
|
||||
<GameEndOverlay board={this.state.board} onRestart={() => this.restartGame()} />
|
||||
<GameEndOverlay board={this.state.board} onRestart={this._handleRestart} />
|
||||
</View>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
var styles = StyleSheet.create({
|
||||
const styles = StyleSheet.create({
|
||||
container: {
|
||||
flex: 1,
|
||||
justifyContent: 'center',
|
||||
alignItems: 'center',
|
||||
alignItems: 'center'
|
||||
},
|
||||
board: {
|
||||
padding: BOARD_PADDING,
|
||||
backgroundColor: '#bbaaaa',
|
||||
borderRadius: 5,
|
||||
borderRadius: 5
|
||||
},
|
||||
overlay: {
|
||||
position: 'absolute',
|
||||
@@ -234,31 +235,31 @@ var styles = StyleSheet.create({
|
||||
flex: 1,
|
||||
flexDirection: 'column',
|
||||
justifyContent: 'center',
|
||||
alignItems: 'center',
|
||||
alignItems: 'center'
|
||||
},
|
||||
overlayMessage: {
|
||||
fontSize: 40,
|
||||
marginBottom: 20,
|
||||
marginBottom: 20
|
||||
},
|
||||
tryAgain: {
|
||||
backgroundColor: '#887761',
|
||||
padding: 20,
|
||||
borderRadius: 5,
|
||||
borderRadius: 5
|
||||
},
|
||||
tryAgainText: {
|
||||
color: '#ffffff',
|
||||
fontSize: 20,
|
||||
fontWeight: '500',
|
||||
fontWeight: '500'
|
||||
},
|
||||
cell: {
|
||||
width: CELL_SIZE,
|
||||
height: CELL_SIZE,
|
||||
borderRadius: 5,
|
||||
backgroundColor: '#ddccbb',
|
||||
margin: CELL_MARGIN,
|
||||
margin: CELL_MARGIN
|
||||
},
|
||||
row: {
|
||||
flexDirection: 'row',
|
||||
flexDirection: 'row'
|
||||
},
|
||||
tile: {
|
||||
position: 'absolute',
|
||||
@@ -268,56 +269,56 @@ var styles = StyleSheet.create({
|
||||
borderRadius: 5,
|
||||
flex: 1,
|
||||
justifyContent: 'center',
|
||||
alignItems: 'center',
|
||||
alignItems: 'center'
|
||||
},
|
||||
value: {
|
||||
fontSize: 24,
|
||||
color: '#776666',
|
||||
fontFamily: 'Verdana',
|
||||
fontWeight: '500',
|
||||
fontWeight: '500'
|
||||
},
|
||||
tile2: {
|
||||
backgroundColor: '#eeeeee',
|
||||
backgroundColor: '#eeeeee'
|
||||
},
|
||||
tile4: {
|
||||
backgroundColor: '#eeeecc',
|
||||
backgroundColor: '#eeeecc'
|
||||
},
|
||||
tile8: {
|
||||
backgroundColor: '#ffbb87',
|
||||
backgroundColor: '#ffbb87'
|
||||
},
|
||||
tile16: {
|
||||
backgroundColor: '#ff9966',
|
||||
backgroundColor: '#ff9966'
|
||||
},
|
||||
tile32: {
|
||||
backgroundColor: '#ff7755',
|
||||
backgroundColor: '#ff7755'
|
||||
},
|
||||
tile64: {
|
||||
backgroundColor: '#ff5533',
|
||||
backgroundColor: '#ff5533'
|
||||
},
|
||||
tile128: {
|
||||
backgroundColor: '#eecc77',
|
||||
backgroundColor: '#eecc77'
|
||||
},
|
||||
tile256: {
|
||||
backgroundColor: '#eecc66',
|
||||
backgroundColor: '#eecc66'
|
||||
},
|
||||
tile512: {
|
||||
backgroundColor: '#eecc55',
|
||||
backgroundColor: '#eecc55'
|
||||
},
|
||||
tile1024: {
|
||||
backgroundColor: '#eecc33',
|
||||
backgroundColor: '#eecc33'
|
||||
},
|
||||
tile2048: {
|
||||
backgroundColor: '#eecc22',
|
||||
backgroundColor: '#eecc22'
|
||||
},
|
||||
whiteText: {
|
||||
color: '#ffffff',
|
||||
color: '#ffffff'
|
||||
},
|
||||
threeDigits: {
|
||||
fontSize: 20,
|
||||
fontSize: 20
|
||||
},
|
||||
fourDigits: {
|
||||
fontSize: 18,
|
||||
},
|
||||
fontSize: 18
|
||||
}
|
||||
});
|
||||
|
||||
AppRegistry.registerComponent('Game2048', () => Game2048);
|
||||
5
docs/storybook/demos/Game2048/Game2048Example.js
Normal file
@@ -0,0 +1,5 @@
|
||||
import React from 'react';
|
||||
import { storiesOf } from '@kadira/storybook';
|
||||
import Game2048 from './Game2048';
|
||||
|
||||
storiesOf('demo: Game2048', module).add('the game', () => <Game2048 />);
|
||||
@@ -19,20 +19,20 @@
|
||||
// NB: Taken straight from: https://github.com/IvanVergiliev/2048-react/blob/master/src/board.js
|
||||
// with no modification except to format it for CommonJS and fix lint/flow errors
|
||||
|
||||
var rotateLeft = function (matrix) {
|
||||
var rows = matrix.length;
|
||||
var columns = matrix[0].length;
|
||||
var res = [];
|
||||
for (var row = 0; row < rows; ++row) {
|
||||
const rotateLeft = function(matrix) {
|
||||
const rows = matrix.length;
|
||||
const columns = matrix[0].length;
|
||||
const res = [];
|
||||
for (let row = 0; row < rows; ++row) {
|
||||
res.push([]);
|
||||
for (var column = 0; column < columns; ++column) {
|
||||
for (let column = 0; column < columns; ++column) {
|
||||
res[row][column] = matrix[column][columns - row - 1];
|
||||
}
|
||||
}
|
||||
return res;
|
||||
};
|
||||
|
||||
var Tile = function (value?: number, row?: number, column?: number) {
|
||||
const Tile = function(value?: number, row?: number, column?: number) {
|
||||
this.value = value || 0;
|
||||
this.row = row || -1;
|
||||
|
||||
@@ -46,42 +46,45 @@ var Tile = function (value?: number, row?: number, column?: number) {
|
||||
|
||||
Tile.id = 0;
|
||||
|
||||
Tile.prototype.moveTo = function (row, column) {
|
||||
Tile.prototype.moveTo = function(row, column) {
|
||||
this.oldRow = this.row;
|
||||
this.oldColumn = this.column;
|
||||
this.row = row;
|
||||
this.column = column;
|
||||
};
|
||||
|
||||
Tile.prototype.isNew = function () {
|
||||
Tile.prototype.isNew = function() {
|
||||
return this.oldRow === -1 && !this.mergedInto;
|
||||
};
|
||||
|
||||
Tile.prototype.hasMoved = function () {
|
||||
return (this.fromRow() !== -1 && (this.fromRow() !== this.toRow() || this.fromColumn() !== this.toColumn())) ||
|
||||
this.mergedInto;
|
||||
Tile.prototype.hasMoved = function() {
|
||||
return (
|
||||
(this.fromRow() !== -1 &&
|
||||
(this.fromRow() !== this.toRow() || this.fromColumn() !== this.toColumn())) ||
|
||||
this.mergedInto
|
||||
);
|
||||
};
|
||||
|
||||
Tile.prototype.fromRow = function () {
|
||||
Tile.prototype.fromRow = function() {
|
||||
return this.mergedInto ? this.row : this.oldRow;
|
||||
};
|
||||
|
||||
Tile.prototype.fromColumn = function () {
|
||||
Tile.prototype.fromColumn = function() {
|
||||
return this.mergedInto ? this.column : this.oldColumn;
|
||||
};
|
||||
|
||||
Tile.prototype.toRow = function () {
|
||||
Tile.prototype.toRow = function() {
|
||||
return this.mergedInto ? this.mergedInto.row : this.row;
|
||||
};
|
||||
|
||||
Tile.prototype.toColumn = function () {
|
||||
Tile.prototype.toColumn = function() {
|
||||
return this.mergedInto ? this.mergedInto.column : this.column;
|
||||
};
|
||||
|
||||
var Board = function () {
|
||||
const Board = function() {
|
||||
this.tiles = [];
|
||||
this.cells = [];
|
||||
for (var i = 0; i < Board.size; ++i) {
|
||||
for (let i = 0; i < Board.size; ++i) {
|
||||
this.cells[i] = [this.addTile(), this.addTile(), this.addTile(), this.addTile()];
|
||||
}
|
||||
this.addRandomTile();
|
||||
@@ -89,42 +92,44 @@ var Board = function () {
|
||||
this.won = false;
|
||||
};
|
||||
|
||||
Board.prototype.addTile = function () {
|
||||
var res = new Tile();
|
||||
Tile.apply(res, arguments);
|
||||
Board.prototype.addTile = function(...args) {
|
||||
const res = new Tile();
|
||||
Tile.apply(res, args);
|
||||
this.tiles.push(res);
|
||||
return res;
|
||||
};
|
||||
|
||||
Board.size = 4;
|
||||
|
||||
Board.prototype.moveLeft = function () {
|
||||
var hasChanged = false;
|
||||
for (var row = 0; row < Board.size; ++row) {
|
||||
var currentRow = this.cells[row].filter(function (tile) { return tile.value !== 0; });
|
||||
var resultRow = [];
|
||||
for (var target = 0; target < Board.size; ++target) {
|
||||
var targetTile = currentRow.length ? currentRow.shift() : this.addTile();
|
||||
Board.prototype.moveLeft = function() {
|
||||
let hasChanged = false;
|
||||
for (let row = 0; row < Board.size; ++row) {
|
||||
const currentRow = this.cells[row].filter(function(tile) {
|
||||
return tile.value !== 0;
|
||||
});
|
||||
const resultRow = [];
|
||||
for (let target = 0; target < Board.size; ++target) {
|
||||
let targetTile = currentRow.length ? currentRow.shift() : this.addTile();
|
||||
if (currentRow.length > 0 && currentRow[0].value === targetTile.value) {
|
||||
var tile1 = targetTile;
|
||||
const tile1 = targetTile;
|
||||
targetTile = this.addTile(targetTile.value);
|
||||
tile1.mergedInto = targetTile;
|
||||
var tile2 = currentRow.shift();
|
||||
const tile2 = currentRow.shift();
|
||||
tile2.mergedInto = targetTile;
|
||||
targetTile.value += tile2.value;
|
||||
}
|
||||
resultRow[target] = targetTile;
|
||||
this.won = this.won || (targetTile.value === 2048);
|
||||
hasChanged = hasChanged || (targetTile.value !== this.cells[row][target].value);
|
||||
this.won = this.won || targetTile.value === 2048;
|
||||
hasChanged = hasChanged || targetTile.value !== this.cells[row][target].value;
|
||||
}
|
||||
this.cells[row] = resultRow;
|
||||
}
|
||||
return hasChanged;
|
||||
};
|
||||
|
||||
Board.prototype.setPositions = function () {
|
||||
this.cells.forEach(function (row, rowIndex) {
|
||||
row.forEach(function (tile, columnIndex) {
|
||||
Board.prototype.setPositions = function() {
|
||||
this.cells.forEach(function(row, rowIndex) {
|
||||
row.forEach(function(tile, columnIndex) {
|
||||
tile.oldRow = tile.row;
|
||||
tile.oldColumn = tile.column;
|
||||
tile.row = rowIndex;
|
||||
@@ -136,29 +141,29 @@ Board.prototype.setPositions = function () {
|
||||
|
||||
Board.fourProbability = 0.1;
|
||||
|
||||
Board.prototype.addRandomTile = function () {
|
||||
var emptyCells = [];
|
||||
for (var r = 0; r < Board.size; ++r) {
|
||||
for (var c = 0; c < Board.size; ++c) {
|
||||
Board.prototype.addRandomTile = function() {
|
||||
const emptyCells = [];
|
||||
for (let r = 0; r < Board.size; ++r) {
|
||||
for (let c = 0; c < Board.size; ++c) {
|
||||
if (this.cells[r][c].value === 0) {
|
||||
emptyCells.push({r: r, c: c});
|
||||
emptyCells.push({ r: r, c: c });
|
||||
}
|
||||
}
|
||||
}
|
||||
var index = Math.floor(Math.random() * emptyCells.length);
|
||||
var cell = emptyCells[index];
|
||||
var newValue = Math.random() < Board.fourProbability ? 4 : 2;
|
||||
const index = Math.floor(Math.random() * emptyCells.length);
|
||||
const cell = emptyCells[index];
|
||||
const newValue = Math.random() < Board.fourProbability ? 4 : 2;
|
||||
this.cells[cell.r][cell.c] = this.addTile(newValue);
|
||||
};
|
||||
|
||||
Board.prototype.move = function (direction) {
|
||||
Board.prototype.move = function(direction) {
|
||||
// 0 -> left, 1 -> up, 2 -> right, 3 -> down
|
||||
this.clearOldTiles();
|
||||
for (var i = 0; i < direction; ++i) {
|
||||
for (let i = 0; i < direction; ++i) {
|
||||
this.cells = rotateLeft(this.cells);
|
||||
}
|
||||
var hasChanged = this.moveLeft();
|
||||
for (var i = direction; i < 4; ++i) {
|
||||
const hasChanged = this.moveLeft();
|
||||
for (let i = direction; i < 4; ++i) {
|
||||
this.cells = rotateLeft(this.cells);
|
||||
}
|
||||
if (hasChanged) {
|
||||
@@ -168,30 +173,34 @@ Board.prototype.move = function (direction) {
|
||||
return this;
|
||||
};
|
||||
|
||||
Board.prototype.clearOldTiles = function () {
|
||||
this.tiles = this.tiles.filter(function (tile) { return tile.markForDeletion === false; });
|
||||
this.tiles.forEach(function (tile) { tile.markForDeletion = true; });
|
||||
Board.prototype.clearOldTiles = function() {
|
||||
this.tiles = this.tiles.filter(function(tile) {
|
||||
return tile.markForDeletion === false;
|
||||
});
|
||||
this.tiles.forEach(function(tile) {
|
||||
tile.markForDeletion = true;
|
||||
});
|
||||
};
|
||||
|
||||
Board.prototype.hasWon = function () {
|
||||
Board.prototype.hasWon = function() {
|
||||
return this.won;
|
||||
};
|
||||
|
||||
Board.deltaX = [-1, 0, 1, 0];
|
||||
Board.deltaY = [0, -1, 0, 1];
|
||||
|
||||
Board.prototype.hasLost = function () {
|
||||
var canMove = false;
|
||||
for (var row = 0; row < Board.size; ++row) {
|
||||
for (var column = 0; column < Board.size; ++column) {
|
||||
canMove = canMove || (this.cells[row][column].value === 0);
|
||||
for (var dir = 0; dir < 4; ++dir) {
|
||||
var newRow = row + Board.deltaX[dir];
|
||||
var newColumn = column + Board.deltaY[dir];
|
||||
Board.prototype.hasLost = function() {
|
||||
let canMove = false;
|
||||
for (let row = 0; row < Board.size; ++row) {
|
||||
for (let column = 0; column < Board.size; ++column) {
|
||||
canMove = canMove || this.cells[row][column].value === 0;
|
||||
for (let dir = 0; dir < 4; ++dir) {
|
||||
const newRow = row + Board.deltaX[dir];
|
||||
const newColumn = column + Board.deltaY[dir];
|
||||
if (newRow < 0 || newRow >= Board.size || newColumn < 0 || newColumn >= Board.size) {
|
||||
continue;
|
||||
}
|
||||
canMove = canMove || (this.cells[row][column].value === this.cells[newRow][newColumn].value);
|
||||
canMove = canMove || this.cells[row][column].value === this.cells[newRow][newColumn].value;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,3 +1,5 @@
|
||||
/* eslint-disable react/jsx-no-bind */
|
||||
|
||||
/**
|
||||
* The examples provided by Facebook are for non-commercial testing and
|
||||
* evaluation purposes only.
|
||||
@@ -14,29 +16,21 @@
|
||||
* @providesModule TicTacToeApp
|
||||
* @flow
|
||||
*/
|
||||
'use strict';
|
||||
|
||||
import createReactClass from 'create-react-class';
|
||||
var React = require('react');
|
||||
var ReactNative = require('react-native');
|
||||
var {
|
||||
AppRegistry,
|
||||
StyleSheet,
|
||||
Text,
|
||||
TouchableHighlight,
|
||||
View,
|
||||
} = ReactNative;
|
||||
import React from 'react';
|
||||
import { AppRegistry, StyleSheet, Text, TouchableHighlight, View } from 'react-native';
|
||||
|
||||
class Board {
|
||||
grid: Array<Array<number>>;
|
||||
turn: number;
|
||||
|
||||
constructor() {
|
||||
var size = 3;
|
||||
var grid = Array(size);
|
||||
for (var i = 0; i < size; i++) {
|
||||
var row = Array(size);
|
||||
for (var j = 0; j < size; j++) {
|
||||
const size = 3;
|
||||
const grid = Array(size);
|
||||
for (let i = 0; i < size; i++) {
|
||||
const row = Array(size);
|
||||
for (let j = 0; j < size; j++) {
|
||||
row[j] = 0;
|
||||
}
|
||||
grid[i] = row;
|
||||
@@ -56,27 +50,39 @@ class Board {
|
||||
}
|
||||
|
||||
winner(): ?number {
|
||||
for (var i = 0; i < 3; i++) {
|
||||
if (this.grid[i][0] !== 0 && this.grid[i][0] === this.grid[i][1] &&
|
||||
this.grid[i][0] === this.grid[i][2]) {
|
||||
for (let i = 0; i < 3; i++) {
|
||||
if (
|
||||
this.grid[i][0] !== 0 &&
|
||||
this.grid[i][0] === this.grid[i][1] &&
|
||||
this.grid[i][0] === this.grid[i][2]
|
||||
) {
|
||||
return this.grid[i][0];
|
||||
}
|
||||
}
|
||||
|
||||
for (var i = 0; i < 3; i++) {
|
||||
if (this.grid[0][i] !== 0 && this.grid[0][i] === this.grid[1][i] &&
|
||||
this.grid[0][i] === this.grid[2][i]) {
|
||||
for (let i = 0; i < 3; i++) {
|
||||
if (
|
||||
this.grid[0][i] !== 0 &&
|
||||
this.grid[0][i] === this.grid[1][i] &&
|
||||
this.grid[0][i] === this.grid[2][i]
|
||||
) {
|
||||
return this.grid[0][i];
|
||||
}
|
||||
}
|
||||
|
||||
if (this.grid[0][0] !== 0 && this.grid[0][0] === this.grid[1][1] &&
|
||||
this.grid[0][0] === this.grid[2][2]) {
|
||||
if (
|
||||
this.grid[0][0] !== 0 &&
|
||||
this.grid[0][0] === this.grid[1][1] &&
|
||||
this.grid[0][0] === this.grid[2][2]
|
||||
) {
|
||||
return this.grid[0][0];
|
||||
}
|
||||
|
||||
if (this.grid[0][2] !== 0 && this.grid[0][2] === this.grid[1][1] &&
|
||||
this.grid[0][2] === this.grid[2][0]) {
|
||||
if (
|
||||
this.grid[0][2] !== 0 &&
|
||||
this.grid[0][2] === this.grid[1][1] &&
|
||||
this.grid[0][2] === this.grid[2][0]
|
||||
) {
|
||||
return this.grid[0][2];
|
||||
}
|
||||
|
||||
@@ -84,8 +90,8 @@ class Board {
|
||||
}
|
||||
|
||||
tie(): boolean {
|
||||
for (var i = 0; i < 3; i++) {
|
||||
for (var j = 0; j < 3; j++) {
|
||||
for (let i = 0; i < 3; i++) {
|
||||
for (let j = 0; j < 3; j++) {
|
||||
if (this.grid[i][j] === 0) {
|
||||
return false;
|
||||
}
|
||||
@@ -95,7 +101,7 @@ class Board {
|
||||
}
|
||||
}
|
||||
|
||||
var Cell = createReactClass({
|
||||
const Cell = createReactClass({
|
||||
cellStyle() {
|
||||
switch (this.props.player) {
|
||||
case 1:
|
||||
@@ -132,9 +138,10 @@ var Cell = createReactClass({
|
||||
render() {
|
||||
return (
|
||||
<TouchableHighlight
|
||||
activeOpacity={0.5}
|
||||
onPress={this.props.onPress}
|
||||
underlayColor="transparent"
|
||||
activeOpacity={0.5}>
|
||||
>
|
||||
<View style={[styles.cell, this.cellStyle()]}>
|
||||
<Text style={[styles.cellText, this.textStyle()]}>
|
||||
{this.textContents()}
|
||||
@@ -145,19 +152,19 @@ var Cell = createReactClass({
|
||||
}
|
||||
});
|
||||
|
||||
var GameEndOverlay = createReactClass({
|
||||
const GameEndOverlay = createReactClass({
|
||||
render() {
|
||||
var board = this.props.board;
|
||||
const board = this.props.board;
|
||||
|
||||
var tie = board.tie();
|
||||
var winner = board.winner();
|
||||
const tie = board.tie();
|
||||
const winner = board.winner();
|
||||
if (!winner && !tie) {
|
||||
return <View />;
|
||||
}
|
||||
|
||||
var message;
|
||||
let message;
|
||||
if (tie) {
|
||||
message = 'It\'s a tie!';
|
||||
message = "It's a tie!";
|
||||
} else {
|
||||
message = (winner === 1 ? 'X' : 'O') + ' wins!';
|
||||
}
|
||||
@@ -166,9 +173,10 @@ var GameEndOverlay = createReactClass({
|
||||
<View style={styles.overlay}>
|
||||
<Text style={styles.overlayMessage}>{message}</Text>
|
||||
<TouchableHighlight
|
||||
activeOpacity={0.5}
|
||||
onPress={this.props.onRestart}
|
||||
underlayColor="transparent"
|
||||
activeOpacity={0.5}>
|
||||
>
|
||||
<View style={styles.newGame}>
|
||||
<Text style={styles.newGameText}>New Game</Text>
|
||||
</View>
|
||||
@@ -178,7 +186,7 @@ var GameEndOverlay = createReactClass({
|
||||
}
|
||||
});
|
||||
|
||||
var TicTacToeApp = createReactClass({
|
||||
const TicTacToeApp = createReactClass({
|
||||
getInitialState() {
|
||||
return { board: new Board(), player: 1 };
|
||||
},
|
||||
@@ -198,22 +206,22 @@ var TicTacToeApp = createReactClass({
|
||||
|
||||
this.setState({
|
||||
board: this.state.board.mark(row, col, this.state.player),
|
||||
player: this.nextPlayer(),
|
||||
player: this.nextPlayer()
|
||||
});
|
||||
},
|
||||
|
||||
render() {
|
||||
var 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}
|
||||
player={player}
|
||||
onPress={this.handleCellPress.bind(this, row, col)}
|
||||
player={player}
|
||||
/>
|
||||
)}
|
||||
))}
|
||||
</View>
|
||||
);
|
||||
));
|
||||
|
||||
return (
|
||||
<View style={styles.container}>
|
||||
@@ -221,16 +229,13 @@ var TicTacToeApp = createReactClass({
|
||||
<View style={styles.board}>
|
||||
{rows}
|
||||
</View>
|
||||
<GameEndOverlay
|
||||
board={this.state.board}
|
||||
onRestart={this.restartGame}
|
||||
/>
|
||||
<GameEndOverlay board={this.state.board} onRestart={this.restartGame} />
|
||||
</View>
|
||||
);
|
||||
}
|
||||
});
|
||||
|
||||
var styles = StyleSheet.create({
|
||||
const styles = StyleSheet.create({
|
||||
container: {
|
||||
flex: 1,
|
||||
justifyContent: 'center',
|
||||
@@ -240,15 +245,15 @@ var styles = StyleSheet.create({
|
||||
title: {
|
||||
fontFamily: 'Chalkduster',
|
||||
fontSize: 39,
|
||||
marginBottom: 20,
|
||||
marginBottom: 20
|
||||
},
|
||||
board: {
|
||||
padding: 5,
|
||||
backgroundColor: '#47525d',
|
||||
borderRadius: 10,
|
||||
borderRadius: 10
|
||||
},
|
||||
row: {
|
||||
flexDirection: 'row',
|
||||
flexDirection: 'row'
|
||||
},
|
||||
|
||||
// CELL
|
||||
@@ -261,13 +266,13 @@ var styles = StyleSheet.create({
|
||||
margin: 5,
|
||||
flex: 1,
|
||||
justifyContent: 'center',
|
||||
alignItems: 'center',
|
||||
alignItems: 'center'
|
||||
},
|
||||
cellX: {
|
||||
backgroundColor: '#72d0eb',
|
||||
backgroundColor: '#72d0eb'
|
||||
},
|
||||
cellO: {
|
||||
backgroundColor: '#7ebd26',
|
||||
backgroundColor: '#7ebd26'
|
||||
},
|
||||
|
||||
// CELL TEXT
|
||||
@@ -275,13 +280,13 @@ var styles = StyleSheet.create({
|
||||
cellText: {
|
||||
borderRadius: 5,
|
||||
fontSize: 50,
|
||||
fontFamily: 'AvenirNext-Bold',
|
||||
fontFamily: 'AvenirNext-Bold'
|
||||
},
|
||||
cellTextX: {
|
||||
color: '#19a9e5',
|
||||
color: '#19a9e5'
|
||||
},
|
||||
cellTextO: {
|
||||
color: '#b9dc2f',
|
||||
color: '#b9dc2f'
|
||||
},
|
||||
|
||||
// GAME OVER
|
||||
@@ -296,7 +301,7 @@ var styles = StyleSheet.create({
|
||||
flex: 1,
|
||||
flexDirection: 'column',
|
||||
justifyContent: 'center',
|
||||
alignItems: 'center',
|
||||
alignItems: 'center'
|
||||
},
|
||||
overlayMessage: {
|
||||
fontSize: 40,
|
||||
@@ -304,18 +309,18 @@ var styles = StyleSheet.create({
|
||||
marginLeft: 20,
|
||||
marginRight: 20,
|
||||
fontFamily: 'AvenirNext-DemiBold',
|
||||
textAlign: 'center',
|
||||
textAlign: 'center'
|
||||
},
|
||||
newGame: {
|
||||
backgroundColor: '#887765',
|
||||
padding: 20,
|
||||
borderRadius: 5,
|
||||
borderRadius: 5
|
||||
},
|
||||
newGameText: {
|
||||
color: 'white',
|
||||
fontSize: 20,
|
||||
fontFamily: 'AvenirNext-DemiBold',
|
||||
},
|
||||
fontFamily: 'AvenirNext-DemiBold'
|
||||
}
|
||||
});
|
||||
|
||||
AppRegistry.registerComponent('TicTacToeApp', () => TicTacToeApp);
|
||||
5
docs/storybook/demos/TicTacToe/TicTacToeExample.js
Normal file
@@ -0,0 +1,5 @@
|
||||
import React from 'react';
|
||||
import { storiesOf } from '@kadira/storybook';
|
||||
import TicTacToe from './TicTacToe';
|
||||
|
||||
storiesOf('demo: TicTacToe', module).add('the game', () => <TicTacToe />);
|
||||
@@ -1,12 +0,0 @@
|
||||
import { configure, addDecorator } from '@kadira/storybook'
|
||||
import centered from './decorator-centered'
|
||||
|
||||
const context = require.context('../', true, /Example\.js$/)
|
||||
|
||||
addDecorator(centered)
|
||||
|
||||
function loadStories() {
|
||||
context.keys().forEach(context)
|
||||
}
|
||||
|
||||
configure(loadStories, module)
|
||||