mirror of
https://github.com/zhigang1992/react-native-web.git
synced 2026-04-17 12:19:52 +08:00
Compare commits
47 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
1190ca20a7 | ||
|
|
8f4bed8cb9 | ||
|
|
5a5d142100 | ||
|
|
fb999b5467 | ||
|
|
8b06f28281 | ||
|
|
9376c72a40 | ||
|
|
d4b1fde9cf | ||
|
|
f237fc3094 | ||
|
|
8777e25d8e | ||
|
|
18d60047d2 | ||
|
|
535a7b7027 | ||
|
|
bdaeac964c | ||
|
|
20257afe88 | ||
|
|
99348eaedb | ||
|
|
6cb16d059d | ||
|
|
3c660e2ad7 | ||
|
|
e9101abefe | ||
|
|
dfa8087f9a | ||
|
|
eaccd8799d | ||
|
|
85b2afc313 | ||
|
|
4865c7bcce | ||
|
|
9e9ab78130 | ||
|
|
00b795a87e | ||
|
|
1edf5241a1 | ||
|
|
4cfcdef264 | ||
|
|
a264c0b956 | ||
|
|
0d8aa24ff3 | ||
|
|
1b77ac4b2f | ||
|
|
44b185ed4c | ||
|
|
d1d570268a | ||
|
|
997c92f841 | ||
|
|
8e60690877 | ||
|
|
7bab19ae6c | ||
|
|
c7f287b207 | ||
|
|
02cfbf8987 | ||
|
|
6203a3fec6 | ||
|
|
d1d5461b29 | ||
|
|
b0ff4489a9 | ||
|
|
635fda8d63 | ||
|
|
5a5eb5425f | ||
|
|
44d59f4996 | ||
|
|
868ab55bac | ||
|
|
65d5a89040 | ||
|
|
deb0a85440 | ||
|
|
19381da37f | ||
|
|
47ba46780c | ||
|
|
88ddeca0c6 |
24
.github/CONTRIBUTING.md
vendored
24
.github/CONTRIBUTING.md
vendored
@@ -28,25 +28,25 @@ yarn
|
||||
To run flow:
|
||||
|
||||
```
|
||||
npm run flow
|
||||
yarn flow
|
||||
```
|
||||
|
||||
To run the unit tests:
|
||||
|
||||
```
|
||||
npm run jest
|
||||
yarn jest
|
||||
```
|
||||
|
||||
…in watch mode:
|
||||
|
||||
```
|
||||
npm run jest:watch
|
||||
yarn jest:watch
|
||||
```
|
||||
|
||||
To run all automated tests:
|
||||
|
||||
```
|
||||
npm test
|
||||
yarn test
|
||||
```
|
||||
|
||||
## Visual tests
|
||||
@@ -54,19 +54,19 @@ npm test
|
||||
To run the interactive storybook:
|
||||
|
||||
```
|
||||
npm run docs:start
|
||||
yarn docs:start
|
||||
```
|
||||
|
||||
To generate a static build of the storybook:
|
||||
|
||||
```
|
||||
npm run docs:build
|
||||
yarn docs:build
|
||||
```
|
||||
|
||||
To run the performance benchmarks in a browser (opening `./benchmarks/index.html`):
|
||||
|
||||
```
|
||||
npm run benchmarks
|
||||
yarn benchmarks
|
||||
```
|
||||
|
||||
## Compile and build
|
||||
@@ -74,13 +74,13 @@ npm run benchmarks
|
||||
To compile the source code to `dist`:
|
||||
|
||||
```
|
||||
npm run compile
|
||||
yarn compile
|
||||
```
|
||||
|
||||
To create a UMD bundle of the library:
|
||||
|
||||
```
|
||||
npm run build
|
||||
yarn build
|
||||
```
|
||||
|
||||
### Pre-commit
|
||||
@@ -88,14 +88,14 @@ npm run build
|
||||
To format and lint code before commit:
|
||||
|
||||
```
|
||||
npm run precommit
|
||||
yarn precommit
|
||||
```
|
||||
|
||||
To format and lint the entire project:
|
||||
|
||||
```
|
||||
npm run fmt
|
||||
npm run lint
|
||||
yarn fmt
|
||||
yarn lint
|
||||
```
|
||||
|
||||
### New Features
|
||||
|
||||
40
README.md
40
README.md
@@ -27,13 +27,18 @@ Native for Web: Playground](https://www.webpackbin.com/bins/-KgucwxRbn7HRU-V-3Bc
|
||||
To install in your app:
|
||||
|
||||
```
|
||||
npm install --save react@15.5 react-dom@15.5 react-native-web
|
||||
npm install --save react@15.6 react-dom@15.6 react-native-web
|
||||
```
|
||||
|
||||
Read the [Getting Started](docs/guides/getting-started.md) guide.
|
||||
NOTE: React Native for Web supports React/ReactDOM 15.4, 15.5, or 15.6.
|
||||
|
||||
Then read the [Getting Started](docs/guides/getting-started.md) guide.
|
||||
|
||||
## Documentation
|
||||
|
||||
The [UI Explorer](https://necolas.github.io/react-native-web/storybook/)
|
||||
interactively documents all the APIs and Components.
|
||||
|
||||
Guides:
|
||||
|
||||
* [Getting started](docs/guides/getting-started.md)
|
||||
@@ -44,36 +49,6 @@ Guides:
|
||||
* [Advanced use](docs/guides/advanced.md)
|
||||
* [Known issues](docs/guides/known-issues.md)
|
||||
|
||||
Exported modules:
|
||||
|
||||
* Components
|
||||
* [`ActivityIndicator`](docs/components/ActivityIndicator.md)
|
||||
* [`Button`](docs/components/Button.md)
|
||||
* [`Image`](docs/components/Image.md)
|
||||
* [`ProgressBar`](docs/components/ProgressBar.md)
|
||||
* [`ScrollView`](docs/components/ScrollView.md)
|
||||
* [`Switch`](docs/components/Switch.md)
|
||||
* [`Text`](docs/components/Text.md)
|
||||
* [`TextInput`](docs/components/TextInput.md)
|
||||
* [`TouchableHighlight`](http://facebook.github.io/react-native/releases/0.22/docs/touchablehighlight.html) (mirrors React Native)
|
||||
* [`TouchableOpacity`](http://facebook.github.io/react-native/releases/0.22/docs/touchableopacity.html) (mirrors React Native)
|
||||
* [`TouchableWithoutFeedback`](docs/components/TouchableWithoutFeedback.md)
|
||||
* [`View`](docs/components/View.md)
|
||||
* APIs
|
||||
* [`Animated`](http://facebook.github.io/react-native/releases/0.20/docs/animated.html) (mirrors React Native)
|
||||
* [`AppRegistry`](docs/apis/AppRegistry.md)
|
||||
* [`AppState`](docs/apis/AppState.md)
|
||||
* [`AsyncStorage`](docs/apis/AsyncStorage.md)
|
||||
* [`Clipboard`](docs/apis/Clipboard.md)
|
||||
* [`Dimensions`](docs/apis/Dimensions.md)
|
||||
* [`I18nManager`](docs/apis/I18nManager.md)
|
||||
* [`NetInfo`](docs/apis/NetInfo.md)
|
||||
* [`PanResponder`](http://facebook.github.io/react-native/releases/0.20/docs/panresponder.html#content) (mirrors React Native)
|
||||
* [`PixelRatio`](docs/apis/PixelRatio.md)
|
||||
* [`Platform`](docs/apis/Platform.md)
|
||||
* [`StyleSheet`](docs/apis/StyleSheet.md)
|
||||
* [`Vibration`](docs/apis/Vibration.md)
|
||||
|
||||
## Example code
|
||||
|
||||
```js
|
||||
@@ -119,6 +94,7 @@ AppRegistry.runApplication('MyApp', { rootTag: document.getElementById('react-ro
|
||||
* [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)
|
||||
* [react-sketchapp](https://github.com/airbnb/react-sketchapp)
|
||||
* [react-web](https://github.com/taobaofed/react-web)
|
||||
* [reactxp](https://github.com/microsoft/reactxp)
|
||||
|
||||
|
||||
@@ -11,30 +11,37 @@ open ./performance/index.html
|
||||
|
||||
The components used in the render benchmarks are simple enough to be
|
||||
implemented by multiple UI or style libraries. The implementations are not
|
||||
equivalent in functionality.
|
||||
equivalent in functionality. For example, React Native for Web's stylesheet is
|
||||
unique in that it also converts React Native styles to DOM styles, has
|
||||
deterministic resolution, and supports RTL layout.
|
||||
|
||||
`react-native-web/stylesheet` is a comparative baseline that implements a
|
||||
simple `View` without much of React Native's functionality.
|
||||
|
||||
## Benchmark results
|
||||
|
||||
Typical render timings*: mean ± two standard deviations
|
||||
Typical render timings*: mean ± two standard deviations.
|
||||
|
||||
| Implementation | Deep tree (ms) | Wide tree (ms) | Tweets (ms) |
|
||||
| Implementation | Deep tree (ms) | Wide tree (ms) | Tweets (ms) |
|
||||
| :--- | ---: | ---: | ---: |
|
||||
| `css-modules` | `87.67` `±15.22` | `170.85` `±16.87` | |
|
||||
| `react-native-web/stylesheet@0.0.84` | `90.02` `±13.16` | `186.66` `±19.23` | |
|
||||
| `react-native-web@0.0.84` | `102.72` `±19.26` | `222.35` `±18.95` | `12.81` `±5.45ms` |
|
||||
| `css-modules` | `94.96` `±31.01` | `200.43` `±38.90` | |
|
||||
| `react-native-web/stylesheet@0.0.107` | `98.58` `±10.83` | `218.59` `±36.52` | |
|
||||
| `react-native-web@0.0.107` | `117.45` `±18.76` | `288.27` `±33.50` | `15.10` `±5.45ms` |
|
||||
|
||||
Other libraries
|
||||
|
||||
| Implementation | Deep tree (ms) | Wide tree (ms) |
|
||||
| :--- | ---: | ---: |
|
||||
| `styletron@2.5.1` | `88.48` `±12.00` | `171.89` `±13.28` |
|
||||
| `aphrodite@1.2.0` | `101.32` `±20.33` | `220.33` `±31.41` |
|
||||
| `glamor@3.0.0-1` | `129.00` `±14.92` | `264.57` `±28.54` |
|
||||
| `react-jss@5.4.1` | `137.33` `±21.55` | `314.91` `±29.03` |
|
||||
| `reactxp@0.34.3` | `223.82` `±32.77` | `461.56` `±34.43` |
|
||||
| `styled-components@2.0.0-11` | `277.53` `±28.83` | `627.91` `±43.13` |
|
||||
| `styletron@2.5.1` | `90.38` `±15.15` | `197.40` `±29.02` |
|
||||
| `aphrodite@1.2.0` | `88.65` `±19.62` | `187.35` `±24.60` |
|
||||
| `glamor@3.0.0-1` | `145.64` `±21.93` | `283.60` `±23.26` |
|
||||
| `react-jss@5.4.1` | `143.17` `±19.14` | `361.80` `±33.39` |
|
||||
| `reactxp@0.34.3` | `227.18` `±28.75` | `496.08` `±59.96` |
|
||||
| `styled-components@2.1.0` | `262.85` `±46.12` | `578.43` `±35.86` |
|
||||
| `styled-components/primitives@2.1.0` | `261.43` `±44.14` | `569.65` `±22.19` |
|
||||
|
||||
*MacBook Pro (13-inch, Early 2011); 2.7 GHz Intel Core i7; 16 GB 1600 MHz DDR3. Google Chrome 56.
|
||||
These results indicate that render performance is not a significant
|
||||
differentiating factor between `aphrodite`, `styletron`, and
|
||||
`react-native-web/stylesheet`.
|
||||
|
||||
*MacBook Pro (13-inch, Early 2015); 3.1 GHz Intel Core i7; 16 GB 1867 MHz DDR3. Google Chrome 58 (2x CPU slowdown).
|
||||
|
||||
@@ -5,6 +5,7 @@ import jss from './src/jss';
|
||||
import reactNative from './src/react-native';
|
||||
import reactNativeStyleSheet from './src/react-native-stylesheet';
|
||||
import styledComponents from './src/styled-components';
|
||||
import styledComponentsPrimitives from './src/styled-components-primitives';
|
||||
import styletron from './src/styletron';
|
||||
import xp from './src/reactxp';
|
||||
|
||||
@@ -40,7 +41,9 @@ const extraTests = [
|
||||
() => renderDeepTree('reactxp', xp),
|
||||
() => renderWideTree('reactxp', xp),
|
||||
() => renderDeepTree('styled-components', styledComponents),
|
||||
() => renderWideTree('styled-components', styledComponents)
|
||||
() => renderWideTree('styled-components', styledComponents),
|
||||
() => renderDeepTree('styled-components/primitives', styledComponentsPrimitives),
|
||||
() => renderWideTree('styled-components/primitives', styledComponentsPrimitives)
|
||||
];
|
||||
|
||||
const tests = testAll ? coreTests.concat(extraTests) : coreTests;
|
||||
|
||||
@@ -7,14 +7,15 @@
|
||||
"glamor": "2.20.25",
|
||||
"marky": "^1.2.0",
|
||||
"react-jss": "^6.1.1",
|
||||
"react-primitives": "^0.4.2",
|
||||
"reactxp": "^0.34.3",
|
||||
"styled-components": "2.0.0-17",
|
||||
"styled-components": "^2.1.0",
|
||||
"styletron-client": "^2.5.7",
|
||||
"styletron-utils": "^2.5.4"
|
||||
},
|
||||
"devDependencies": {
|
||||
"css-loader": "^0.28.1",
|
||||
"css-loader": "^0.28.4",
|
||||
"react-addons-perf": "^15.4.2",
|
||||
"style-loader": "^0.17.0"
|
||||
"style-loader": "^0.18.2"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,30 @@
|
||||
import styled from 'styled-components/primitives';
|
||||
|
||||
const getColor = color => {
|
||||
switch (color) {
|
||||
case 0:
|
||||
return '#222';
|
||||
case 1:
|
||||
return '#666';
|
||||
case 2:
|
||||
return '#999';
|
||||
case 3:
|
||||
return 'blue';
|
||||
case 4:
|
||||
return 'orange';
|
||||
case 5:
|
||||
return 'red';
|
||||
default:
|
||||
return 'transparent';
|
||||
}
|
||||
};
|
||||
|
||||
const Box = styled.View`
|
||||
flex-direction: ${props => (props.layout === 'column' ? 'column' : 'row')};
|
||||
padding: ${props => (props.outer ? '4px' : '0')};
|
||||
height: ${props => (props.fixed ? '20px' : 'auto')};
|
||||
width: ${props => (props.fixed ? '20px' : 'auto')};
|
||||
background-color: ${props => getColor(props.color)};
|
||||
`;
|
||||
|
||||
module.exports = Box;
|
||||
7
benchmarks/src/styled-components-primitives.js
Normal file
7
benchmarks/src/styled-components-primitives.js
Normal file
@@ -0,0 +1,7 @@
|
||||
import Box from './components/Box/styled-components';
|
||||
import styled from 'styled-components/primitives';
|
||||
|
||||
export default {
|
||||
Box,
|
||||
View: styled.View
|
||||
};
|
||||
@@ -2,10 +2,33 @@
|
||||
# yarn lockfile v1
|
||||
|
||||
|
||||
ajv@^5.0.0:
|
||||
version "5.2.0"
|
||||
resolved "https://registry.yarnpkg.com/ajv/-/ajv-5.2.0.tgz#c1735024c5da2ef75cc190713073d44f098bf486"
|
||||
dependencies:
|
||||
co "^4.6.0"
|
||||
fast-deep-equal "^0.1.0"
|
||||
json-schema-traverse "^0.3.0"
|
||||
json-stable-stringify "^1.0.1"
|
||||
|
||||
alphanum-sort@^1.0.1, alphanum-sort@^1.0.2:
|
||||
version "1.0.2"
|
||||
resolved "https://registry.yarnpkg.com/alphanum-sort/-/alphanum-sort-1.0.2.tgz#97a1119649b211ad33691d9f9f486a8ec9fbe0a3"
|
||||
|
||||
animated@^0.1.5:
|
||||
version "0.1.5"
|
||||
resolved "https://registry.yarnpkg.com/animated/-/animated-0.1.5.tgz#83df8dc443d57abab7b0bb04818b0b655b31c9b9"
|
||||
dependencies:
|
||||
invariant "^2.2.0"
|
||||
normalize-css-color "^1.0.1"
|
||||
|
||||
animated@^0.2.0:
|
||||
version "0.2.0"
|
||||
resolved "https://registry.yarnpkg.com/animated/-/animated-0.2.0.tgz#1a0e96f097b3fbc5b64d7eddc723bcc0a6f97633"
|
||||
dependencies:
|
||||
invariant "^2.2.0"
|
||||
normalize-css-color "^1.0.1"
|
||||
|
||||
ansi-regex@^2.0.0:
|
||||
version "2.1.1"
|
||||
resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-2.1.1.tgz#c3b33ab5ee360d86e0e628f0468ae7ef27d654df"
|
||||
@@ -28,7 +51,11 @@ argparse@^1.0.7:
|
||||
dependencies:
|
||||
sprintf-js "~1.0.2"
|
||||
|
||||
asap@^2.0.3, asap@~2.0.3:
|
||||
array-find-index@^1.0.2:
|
||||
version "1.0.2"
|
||||
resolved "https://registry.yarnpkg.com/array-find-index/-/array-find-index-1.0.2.tgz#df010aa1287e164bbda6f9723b0a96a1ec4187a1"
|
||||
|
||||
asap@^2.0.3, asap@^2.0.5, asap@~2.0.3:
|
||||
version "2.0.5"
|
||||
resolved "https://registry.yarnpkg.com/asap/-/asap-2.0.5.tgz#522765b50c3510490e52d7dcfe085ef9ba96958f"
|
||||
|
||||
@@ -57,7 +84,7 @@ babel-code-frame@^6.11.0:
|
||||
esutils "^2.0.2"
|
||||
js-tokens "^3.0.0"
|
||||
|
||||
babel-runtime@^6.18.0:
|
||||
babel-runtime@^6.18.0, babel-runtime@^6.23.0:
|
||||
version "6.23.0"
|
||||
resolved "https://registry.yarnpkg.com/babel-runtime/-/babel-runtime-6.23.0.tgz#0a9489f144de70efb3ce4300accdb329e2fc543b"
|
||||
dependencies:
|
||||
@@ -131,6 +158,10 @@ clone@^1.0.2:
|
||||
version "1.0.2"
|
||||
resolved "https://registry.yarnpkg.com/clone/-/clone-1.0.2.tgz#260b7a99ebb1edfe247538175f783243cb19d149"
|
||||
|
||||
co@^4.6.0:
|
||||
version "4.6.0"
|
||||
resolved "https://registry.yarnpkg.com/co/-/co-4.6.0.tgz#6ea6bdf3d853ae54ccb8e47bfa0bf3f9031fb184"
|
||||
|
||||
coa@~1.0.1:
|
||||
version "1.0.1"
|
||||
resolved "https://registry.yarnpkg.com/coa/-/coa-1.0.1.tgz#7f959346cfc8719e3f7233cd6852854a7c67d8a3"
|
||||
@@ -181,6 +212,14 @@ core-js@^2.4.0:
|
||||
version "2.4.1"
|
||||
resolved "https://registry.yarnpkg.com/core-js/-/core-js-2.4.1.tgz#4de911e667b0eae9124e34254b53aea6fc618d3e"
|
||||
|
||||
create-react-class@^15.6.0:
|
||||
version "15.6.0"
|
||||
resolved "https://registry.yarnpkg.com/create-react-class/-/create-react-class-15.6.0.tgz#ab448497c26566e1e29413e883207d57cfe7bed4"
|
||||
dependencies:
|
||||
fbjs "^0.8.9"
|
||||
loose-envify "^1.3.1"
|
||||
object-assign "^4.1.1"
|
||||
|
||||
css-color-keywords@^1.0.0:
|
||||
version "1.0.0"
|
||||
resolved "https://registry.yarnpkg.com/css-color-keywords/-/css-color-keywords-1.0.0.tgz#fea2616dc676b2962686b3af8dbdbe180b244e05"
|
||||
@@ -195,13 +234,14 @@ css-in-js-utils@^1.0.3:
|
||||
dependencies:
|
||||
hyphenate-style-name "^1.0.2"
|
||||
|
||||
css-loader@^0.28.1:
|
||||
version "0.28.1"
|
||||
resolved "https://registry.yarnpkg.com/css-loader/-/css-loader-0.28.1.tgz#220325599f8f00452d9ceb4c3ca6c8a66798642d"
|
||||
css-loader@^0.28.4:
|
||||
version "0.28.4"
|
||||
resolved "https://registry.yarnpkg.com/css-loader/-/css-loader-0.28.4.tgz#6cf3579192ce355e8b38d5f42dd7a1f2ec898d0f"
|
||||
dependencies:
|
||||
babel-code-frame "^6.11.0"
|
||||
css-selector-tokenizer "^0.7.0"
|
||||
cssnano ">=2.6.1 <4"
|
||||
icss-utils "^2.1.0"
|
||||
loader-utils "^1.0.2"
|
||||
lodash.camelcase "^4.3.0"
|
||||
object-assign "^4.0.1"
|
||||
@@ -291,14 +331,28 @@ csso@~2.3.1:
|
||||
clap "^1.0.9"
|
||||
source-map "^0.5.3"
|
||||
|
||||
debounce@1.0.2:
|
||||
version "1.0.2"
|
||||
resolved "https://registry.yarnpkg.com/debounce/-/debounce-1.0.2.tgz#503cc674d8d7f737099664fb75ddbd36b9626dc6"
|
||||
|
||||
decamelize@^1.1.2:
|
||||
version "1.2.0"
|
||||
resolved "https://registry.yarnpkg.com/decamelize/-/decamelize-1.2.0.tgz#f6534d15148269b20352e7bee26f501f9a191290"
|
||||
|
||||
deep-assign@^2.0.0:
|
||||
version "2.0.0"
|
||||
resolved "https://registry.yarnpkg.com/deep-assign/-/deep-assign-2.0.0.tgz#ebe06b1f07f08dae597620e3dd1622f371a1c572"
|
||||
dependencies:
|
||||
is-obj "^1.0.0"
|
||||
|
||||
defined@^1.0.0:
|
||||
version "1.0.0"
|
||||
resolved "https://registry.yarnpkg.com/defined/-/defined-1.0.0.tgz#c98d9bcef75674188e110969151199e39b1fa693"
|
||||
|
||||
deline@^1.0.4:
|
||||
version "1.0.4"
|
||||
resolved "https://registry.yarnpkg.com/deline/-/deline-1.0.4.tgz#6c05c87836926e1a1c63e47882f3d2eb2c6f14c9"
|
||||
|
||||
electron-to-chromium@^1.2.3:
|
||||
version "1.2.4"
|
||||
resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.2.4.tgz#9751cbea89fa120bf88c226ba41eb8d0b6f1b597"
|
||||
@@ -325,10 +379,26 @@ esutils@^2.0.2:
|
||||
version "2.0.2"
|
||||
resolved "https://registry.yarnpkg.com/esutils/-/esutils-2.0.2.tgz#0abf4f1caa5bcb1f7a9d8acc6dea4faaa04bac9b"
|
||||
|
||||
fast-deep-equal@^0.1.0:
|
||||
version "0.1.0"
|
||||
resolved "https://registry.yarnpkg.com/fast-deep-equal/-/fast-deep-equal-0.1.0.tgz#5c6f4599aba6b333ee3342e2ed978672f1001f8d"
|
||||
|
||||
fastparse@^1.1.1:
|
||||
version "1.1.1"
|
||||
resolved "https://registry.yarnpkg.com/fastparse/-/fastparse-1.1.1.tgz#d1e2643b38a94d7583b479060e6c4affc94071f8"
|
||||
|
||||
fbjs@^0.8.12:
|
||||
version "0.8.12"
|
||||
resolved "https://registry.yarnpkg.com/fbjs/-/fbjs-0.8.12.tgz#10b5d92f76d45575fd63a217d4ea02bea2f8ed04"
|
||||
dependencies:
|
||||
core-js "^1.0.0"
|
||||
isomorphic-fetch "^2.1.1"
|
||||
loose-envify "^1.0.0"
|
||||
object-assign "^4.1.0"
|
||||
promise "^7.1.1"
|
||||
setimmediate "^1.0.5"
|
||||
ua-parser-js "^0.7.9"
|
||||
|
||||
fbjs@^0.8.4, fbjs@^0.8.5, fbjs@^0.8.8, fbjs@^0.8.9:
|
||||
version "0.8.9"
|
||||
resolved "https://registry.yarnpkg.com/fbjs/-/fbjs-0.8.9.tgz#180247fbd347dcc9004517b904f865400a0c8f14"
|
||||
@@ -345,6 +415,10 @@ flatten@^1.0.2:
|
||||
version "1.0.2"
|
||||
resolved "https://registry.yarnpkg.com/flatten/-/flatten-1.0.2.tgz#dae46a9d78fbe25292258cc1e780a41d95c03782"
|
||||
|
||||
flexibility@^2.0.1:
|
||||
version "2.0.1"
|
||||
resolved "https://registry.yarnpkg.com/flexibility/-/flexibility-2.0.1.tgz#ad323aafc40f469ce624286518fc4d7cd72b7c77"
|
||||
|
||||
function-bind@^1.0.2:
|
||||
version "1.1.0"
|
||||
resolved "https://registry.yarnpkg.com/function-bind/-/function-bind-1.1.0.tgz#16176714c801798e4e8f2cf7f7529467bb4a5771"
|
||||
@@ -368,6 +442,10 @@ has-flag@^1.0.0:
|
||||
version "1.0.0"
|
||||
resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-1.0.0.tgz#9d9e793165ce017a00f00418c43f942a7b1d11fa"
|
||||
|
||||
has-flag@^2.0.0:
|
||||
version "2.0.0"
|
||||
resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-2.0.0.tgz#e8207af1cc7b30d446cc70b734b5e8be18f88d51"
|
||||
|
||||
has@^1.0.1:
|
||||
version "1.0.1"
|
||||
resolved "https://registry.yarnpkg.com/has/-/has-1.0.1.tgz#8461733f538b0837c9361e39a9ab9e9704dc2f28"
|
||||
@@ -394,6 +472,12 @@ icss-replace-symbols@^1.0.2:
|
||||
version "1.0.2"
|
||||
resolved "https://registry.yarnpkg.com/icss-replace-symbols/-/icss-replace-symbols-1.0.2.tgz#cb0b6054eb3af6edc9ab1d62d01933e2d4c8bfa5"
|
||||
|
||||
icss-utils@^2.1.0:
|
||||
version "2.1.0"
|
||||
resolved "https://registry.yarnpkg.com/icss-utils/-/icss-utils-2.1.0.tgz#83f0a0ec378bf3246178b6c2ad9136f135b1c962"
|
||||
dependencies:
|
||||
postcss "^6.0.1"
|
||||
|
||||
ieee754@^1.1.4:
|
||||
version "1.1.8"
|
||||
resolved "https://registry.yarnpkg.com/ieee754/-/ieee754-1.1.8.tgz#be33d40ac10ef1926701f6f08a2d86fbfd1ad3e4"
|
||||
@@ -424,6 +508,19 @@ inline-style-prefixer@^3.0.1:
|
||||
bowser "^1.6.0"
|
||||
css-in-js-utils "^1.0.3"
|
||||
|
||||
inline-style-prefixer@^3.0.6:
|
||||
version "3.0.6"
|
||||
resolved "https://registry.yarnpkg.com/inline-style-prefixer/-/inline-style-prefixer-3.0.6.tgz#b27fe309b4168a31eaf38c8e8c60ab9e7c11731f"
|
||||
dependencies:
|
||||
bowser "^1.6.0"
|
||||
css-in-js-utils "^1.0.3"
|
||||
|
||||
invariant@^2.2.0, invariant@^2.2.1:
|
||||
version "2.2.2"
|
||||
resolved "https://registry.yarnpkg.com/invariant/-/invariant-2.2.2.tgz#9e1f56ac0acdb6bf303306f338be3b204ae60360"
|
||||
dependencies:
|
||||
loose-envify "^1.0.0"
|
||||
|
||||
is-absolute-url@^2.0.0:
|
||||
version "2.1.0"
|
||||
resolved "https://registry.yarnpkg.com/is-absolute-url/-/is-absolute-url-2.1.0.tgz#50530dfb84fcc9aa7dbe7852e83a37b93b9f2aa6"
|
||||
@@ -436,6 +533,10 @@ is-in-browser@1.0.2, is-in-browser@^1.0.2:
|
||||
version "1.0.2"
|
||||
resolved "https://registry.yarnpkg.com/is-in-browser/-/is-in-browser-1.0.2.tgz#f688bea8f1e5aadc3244ebc870d188cfb9b613cf"
|
||||
|
||||
is-obj@^1.0.0:
|
||||
version "1.0.1"
|
||||
resolved "https://registry.yarnpkg.com/is-obj/-/is-obj-1.0.1.tgz#3e4729ac1f5fde025cd7d83a896dab9f4f67db0f"
|
||||
|
||||
is-plain-obj@^1.0.0:
|
||||
version "1.1.0"
|
||||
resolved "https://registry.yarnpkg.com/is-plain-obj/-/is-plain-obj-1.1.0.tgz#71a50c8429dfca773c92a390a4a03b39fcd51d3e"
|
||||
@@ -486,10 +587,24 @@ jsesc@~0.5.0:
|
||||
version "0.5.0"
|
||||
resolved "https://registry.yarnpkg.com/jsesc/-/jsesc-0.5.0.tgz#e7dee66e35d6fc16f710fe91d5cf69f70f08911d"
|
||||
|
||||
json-schema-traverse@^0.3.0:
|
||||
version "0.3.1"
|
||||
resolved "https://registry.yarnpkg.com/json-schema-traverse/-/json-schema-traverse-0.3.1.tgz#349a6d44c53a51de89b40805c5d5e59b417d3340"
|
||||
|
||||
json-stable-stringify@^1.0.1:
|
||||
version "1.0.1"
|
||||
resolved "https://registry.yarnpkg.com/json-stable-stringify/-/json-stable-stringify-1.0.1.tgz#9a759d39c5f2ff503fd5300646ed445f88c4f9af"
|
||||
dependencies:
|
||||
jsonify "~0.0.0"
|
||||
|
||||
json5@^0.5.0:
|
||||
version "0.5.1"
|
||||
resolved "https://registry.yarnpkg.com/json5/-/json5-0.5.1.tgz#1eade7acc012034ad84e2396767ead9fa5495821"
|
||||
|
||||
jsonify@~0.0.0:
|
||||
version "0.0.0"
|
||||
resolved "https://registry.yarnpkg.com/jsonify/-/jsonify-0.0.0.tgz#2c74b6ee41d93ca51b7b5aaee8f503631d252a73"
|
||||
|
||||
jss-camel-case@^4.0.0:
|
||||
version "4.0.0"
|
||||
resolved "https://registry.yarnpkg.com/jss-camel-case/-/jss-camel-case-4.0.0.tgz#39ef2a137aaa1e2f160ab826845305f8efabcfd5"
|
||||
@@ -579,7 +694,7 @@ lodash@^4.17.1:
|
||||
version "4.17.4"
|
||||
resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.4.tgz#78203a4d1c328ae1d86dca6460e369b57f4055ae"
|
||||
|
||||
loose-envify@^1.0.0:
|
||||
loose-envify@^1.0.0, loose-envify@^1.3.1:
|
||||
version "1.3.1"
|
||||
resolved "https://registry.yarnpkg.com/loose-envify/-/loose-envify-1.3.1.tgz#d1a8ad33fa9ce0e713d65fdd0ac8b748d478c848"
|
||||
dependencies:
|
||||
@@ -614,6 +729,10 @@ node-fetch@^1.0.1:
|
||||
encoding "^0.1.11"
|
||||
is-stream "^1.0.1"
|
||||
|
||||
normalize-css-color@^1.0.1, normalize-css-color@^1.0.2:
|
||||
version "1.0.2"
|
||||
resolved "https://registry.yarnpkg.com/normalize-css-color/-/normalize-css-color-1.0.2.tgz#02991e97cccec6623fe573afbbf0de6a1f3e9f8d"
|
||||
|
||||
normalize-range@^0.1.2:
|
||||
version "0.1.2"
|
||||
resolved "https://registry.yarnpkg.com/normalize-range/-/normalize-range-0.1.2.tgz#2d10c06bdfd312ea9777695a4d28439456b75942"
|
||||
@@ -631,7 +750,7 @@ num2fraction@^1.2.2:
|
||||
version "1.2.2"
|
||||
resolved "https://registry.yarnpkg.com/num2fraction/-/num2fraction-1.2.2.tgz#6f682b6a027a4e9ddfa4564cd2589d1d4e669ede"
|
||||
|
||||
object-assign@^4.0.1, object-assign@^4.1.0:
|
||||
object-assign@^4.0.1, object-assign@^4.1.0, object-assign@^4.1.1:
|
||||
version "4.1.1"
|
||||
resolved "https://registry.yarnpkg.com/object-assign/-/object-assign-4.1.1.tgz#2109adc7965887cfc05cbbd442cac8bfbb360863"
|
||||
|
||||
@@ -873,6 +992,14 @@ postcss@^5.0.10, postcss@^5.0.11, postcss@^5.0.12, postcss@^5.0.13, postcss@^5.0
|
||||
source-map "^0.5.6"
|
||||
supports-color "^3.2.3"
|
||||
|
||||
postcss@^6.0.1:
|
||||
version "6.0.3"
|
||||
resolved "https://registry.yarnpkg.com/postcss/-/postcss-6.0.3.tgz#b7f565b3d956fbb8565ca7c1e239d0506e427d8b"
|
||||
dependencies:
|
||||
chalk "^1.1.3"
|
||||
source-map "^0.5.6"
|
||||
supports-color "^4.0.0"
|
||||
|
||||
prepend-http@^1.0.0:
|
||||
version "1.0.4"
|
||||
resolved "https://registry.yarnpkg.com/prepend-http/-/prepend-http-1.0.4.tgz#d4f4562b0ce3696e41ac52d0e002e57a635dc6dc"
|
||||
@@ -883,6 +1010,13 @@ promise@^7.1.1:
|
||||
dependencies:
|
||||
asap "~2.0.3"
|
||||
|
||||
prop-types@^15.5.10:
|
||||
version "15.5.10"
|
||||
resolved "https://registry.yarnpkg.com/prop-types/-/prop-types-15.5.10.tgz#2797dfc3126182e3a95e3dfbb2e893ddd7456154"
|
||||
dependencies:
|
||||
fbjs "^0.8.9"
|
||||
loose-envify "^1.3.1"
|
||||
|
||||
prop-types@^15.5.4, prop-types@^15.5.8:
|
||||
version "15.5.8"
|
||||
resolved "https://registry.yarnpkg.com/prop-types/-/prop-types-15.5.8.tgz#6b7b2e141083be38c8595aa51fc55775c7199394"
|
||||
@@ -916,6 +1050,43 @@ react-jss@^6.1.1:
|
||||
jss-preset-default "^2.0.0"
|
||||
prop-types "^15.5.8"
|
||||
|
||||
react-native-web@0.0.x:
|
||||
version "0.0.106"
|
||||
resolved "https://registry.yarnpkg.com/react-native-web/-/react-native-web-0.0.106.tgz#928427320b5963548b372a32b62459154f1e1d7e"
|
||||
dependencies:
|
||||
animated "^0.2.0"
|
||||
array-find-index "^1.0.2"
|
||||
babel-runtime "^6.23.0"
|
||||
create-react-class "^15.6.0"
|
||||
debounce "1.0.2"
|
||||
deep-assign "^2.0.0"
|
||||
fbjs "^0.8.12"
|
||||
hyphenate-style-name "^1.0.2"
|
||||
inline-style-prefixer "^3.0.6"
|
||||
normalize-css-color "^1.0.2"
|
||||
prop-types "^15.5.10"
|
||||
react-timer-mixin "^0.13.3"
|
||||
|
||||
react-primitives@^0.4.2:
|
||||
version "0.4.2"
|
||||
resolved "https://registry.yarnpkg.com/react-primitives/-/react-primitives-0.4.2.tgz#cb001c1122734f177559f5bf590aadd5129b0914"
|
||||
dependencies:
|
||||
animated "^0.1.5"
|
||||
asap "^2.0.5"
|
||||
deline "^1.0.4"
|
||||
flexibility "^2.0.1"
|
||||
inline-style-prefixer "^2.0.5"
|
||||
invariant "^2.2.1"
|
||||
normalize-css-color "^1.0.1"
|
||||
prop-types "^15.5.10"
|
||||
react-native-web "0.0.x"
|
||||
react-timer-mixin "^0.13.3"
|
||||
string-hash "^1.1.3"
|
||||
|
||||
react-timer-mixin@^0.13.3:
|
||||
version "0.13.3"
|
||||
resolved "https://registry.yarnpkg.com/react-timer-mixin/-/react-timer-mixin-0.13.3.tgz#0da8b9f807ec07dc3e854d082c737c65605b3d22"
|
||||
|
||||
reactxp@^0.34.3:
|
||||
version "0.34.3"
|
||||
resolved "https://registry.yarnpkg.com/reactxp/-/reactxp-0.34.3.tgz#6481992e57758ae6ffffbfde3d497527bb495032"
|
||||
@@ -974,6 +1145,12 @@ sax@~1.2.1:
|
||||
version "1.2.2"
|
||||
resolved "https://registry.yarnpkg.com/sax/-/sax-1.2.2.tgz#fd8631a23bc7826bef5d871bdb87378c95647828"
|
||||
|
||||
schema-utils@^0.3.0:
|
||||
version "0.3.0"
|
||||
resolved "https://registry.yarnpkg.com/schema-utils/-/schema-utils-0.3.0.tgz#f5877222ce3e931edae039f17eb3716e7137f8cf"
|
||||
dependencies:
|
||||
ajv "^5.0.0"
|
||||
|
||||
setimmediate@^1.0.5:
|
||||
version "1.0.5"
|
||||
resolved "https://registry.yarnpkg.com/setimmediate/-/setimmediate-1.0.5.tgz#290cbb232e306942d7d7ea9b83732ab7856f8285"
|
||||
@@ -1010,25 +1187,25 @@ strip-ansi@^3.0.0:
|
||||
dependencies:
|
||||
ansi-regex "^2.0.0"
|
||||
|
||||
style-loader@^0.17.0:
|
||||
version "0.17.0"
|
||||
resolved "https://registry.yarnpkg.com/style-loader/-/style-loader-0.17.0.tgz#e8254bccdb7af74bd58274e36107b4d5ab4df310"
|
||||
style-loader@^0.18.2:
|
||||
version "0.18.2"
|
||||
resolved "https://registry.yarnpkg.com/style-loader/-/style-loader-0.18.2.tgz#cc31459afbcd6d80b7220ee54b291a9fd66ff5eb"
|
||||
dependencies:
|
||||
loader-utils "^1.0.2"
|
||||
schema-utils "^0.3.0"
|
||||
|
||||
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"
|
||||
styled-components@^2.1.0:
|
||||
version "2.1.0"
|
||||
resolved "https://registry.yarnpkg.com/styled-components/-/styled-components-2.1.0.tgz#425805fca7efa5880aad2171f986bfd8a2f0808f"
|
||||
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"
|
||||
prop-types "^15.5.4"
|
||||
stylis "^2.0.0"
|
||||
stylis "^3.0.19"
|
||||
supports-color "^3.2.3"
|
||||
|
||||
styletron-client@^2.5.7:
|
||||
@@ -1047,9 +1224,9 @@ styletron-utils@^2.5.4:
|
||||
dependencies:
|
||||
inline-style-prefixer "^2.0.1"
|
||||
|
||||
stylis@^2.0.0:
|
||||
version "2.0.3"
|
||||
resolved "https://registry.yarnpkg.com/stylis/-/stylis-2.0.3.tgz#054b0ad1f636181664246c103adf506c84b502e7"
|
||||
stylis@^3.0.19:
|
||||
version "3.1.9"
|
||||
resolved "https://registry.yarnpkg.com/stylis/-/stylis-3.1.9.tgz#638370451f980437f57c59e58d2e296be29fafb7"
|
||||
|
||||
supports-color@^2.0.0:
|
||||
version "2.0.0"
|
||||
@@ -1061,6 +1238,12 @@ supports-color@^3.2.3:
|
||||
dependencies:
|
||||
has-flag "^1.0.0"
|
||||
|
||||
supports-color@^4.0.0:
|
||||
version "4.0.0"
|
||||
resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-4.0.0.tgz#33a7c680aa512c9d03ef929cacbb974d203d2790"
|
||||
dependencies:
|
||||
has-flag "^2.0.0"
|
||||
|
||||
svgo@^0.7.0:
|
||||
version "0.7.2"
|
||||
resolved "https://registry.yarnpkg.com/svgo/-/svgo-0.7.2.tgz#9f5772413952135c6fefbf40afe6a4faa88b4bb5"
|
||||
|
||||
@@ -14,8 +14,7 @@ into `runApplication`. These should always be used as a pair.
|
||||
(web) static **getApplication**(appKey:string, appParameters: object)
|
||||
|
||||
Returns the given application element. Use this for server-side rendering.
|
||||
Return object is of type `{ element: ReactElement; stylesheet: ReactElement }`.
|
||||
It's recommended that you use `sheetsheet` to render the style sheet in an app
|
||||
Return object is of type `{ element: ReactElement; stylesheets: [ ReactElement ] }`.
|
||||
|
||||
static **registerConfig**(config: Array<AppConfig>)
|
||||
|
||||
@@ -41,6 +40,9 @@ Runs the application that was registered under `appKey`. The `appParameters`
|
||||
must include the `rootTag` into which the application is rendered, and
|
||||
optionally any `initialProps`.
|
||||
|
||||
On web, if the `rootTag` is a sub-section of your application it should be
|
||||
styled as `position:relative` and given an explicit height.
|
||||
|
||||
static **unmountApplicationComponentAtRootTag**(rootTag: HTMLElement)
|
||||
|
||||
To "stop" an application when a view should be destroyed, call
|
||||
|
||||
@@ -32,7 +32,7 @@ static **removeEventListener**(eventName: ChangeEventName, handler: Function)
|
||||
**isConnected**: bool = true
|
||||
|
||||
Available on all user agents. Asynchronously fetch a boolean to determine
|
||||
internet connectivity.
|
||||
internet connectivity. Use this if you are only interested with whether the device has internet connectivity.
|
||||
|
||||
**isConnected.addEventListener**(eventName: ChangeEventName, handler: Function)
|
||||
|
||||
|
||||
@@ -16,9 +16,10 @@ Each key of the object passed to `create` must define a style object.
|
||||
|
||||
Flattens an array of styles into a single style object.
|
||||
|
||||
(web) **renderToString**: function
|
||||
(web) **getStyleSheets**: function
|
||||
|
||||
Returns a string of the stylesheet for use in server-side rendering.
|
||||
Returns an array of stylesheets (`{ id, textContent }`). Useful for
|
||||
compile-time or server-side rendering.
|
||||
|
||||
## Properties
|
||||
|
||||
|
||||
@@ -103,8 +103,11 @@ Callback that is called when the text input is focused.
|
||||
|
||||
**onKeyPress**: ?function
|
||||
|
||||
Callback that is called when a key is pressed. Pressed key value is passed as
|
||||
an argument to the callback handler. Fires before `onChange` callbacks.
|
||||
Callback that is called when a key is pressed. This will be called with `{
|
||||
nativeEvent: { key: keyValue } }` where keyValue is 'Enter` or 'Backspace' for
|
||||
respective keys and the typed-in character otherwise including ' ' for space.
|
||||
Modifier keys are also included in the nativeEvent. Fires before onChange
|
||||
callbacks.
|
||||
|
||||
**onSelectionChange**: ?function
|
||||
|
||||
|
||||
@@ -158,6 +158,7 @@ Controls whether the View can be the target of touch events. The enhanced
|
||||
+ `animationTimingFunction` ‡
|
||||
+ `backfaceVisibility`
|
||||
+ `backgroundAttachment` ‡
|
||||
+ `backgroundBlendMode` ‡
|
||||
+ `backgroundClip` ‡
|
||||
+ `backgroundColor`
|
||||
+ `backgroundImage` ‡
|
||||
|
||||
@@ -187,15 +187,16 @@ const AppContainer = (props) => { /* ... */ }
|
||||
AppRegistry.registerComponent('App', () => AppContainer)
|
||||
|
||||
// prerender the app
|
||||
const { element, stylesheet } = AppRegistry.getApplication('App', { initialProps });
|
||||
const { element, stylesheets } = AppRegistry.getApplication('App', { initialProps });
|
||||
const initialHTML = ReactDOMServer.renderToString(element);
|
||||
const initialStyles = stylesheets.map((sheet) => ReactDOMServer.renderToStaticMarkup(sheet)).join('\n');
|
||||
|
||||
// construct HTML document
|
||||
const document = `
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
${stylesheet}
|
||||
${initialStyles}
|
||||
</head>
|
||||
<body>
|
||||
${initialHTML}
|
||||
|
||||
@@ -225,7 +225,8 @@ User Agent styles from (pseudo-)elements beyond the reach of React (e.g.,
|
||||
`html`, `body`) or inline styles (e.g., `::-moz-focus-inner`). The rest is
|
||||
handled at the component-level.
|
||||
|
||||
### What about using DevTools?
|
||||
### What about using Dev Tools?
|
||||
|
||||
It's recommended that you rely more on React DevTools and live/hot-reloading
|
||||
rather than inspecting and editing the DOM directly.
|
||||
React Dev Tools supports inspecting and editing of React Native styles. It's
|
||||
recommended that you rely more on React Dev Tools and live/hot-reloading rather
|
||||
than inspecting and editing the DOM directly.
|
||||
|
||||
1
docs/storybook/.storybook/addons.js
Normal file
1
docs/storybook/.storybook/addons.js
Normal file
@@ -0,0 +1 @@
|
||||
import '@kadira/storybook-addon-options/register';
|
||||
@@ -1,10 +1,21 @@
|
||||
import { configure, addDecorator } from '@kadira/storybook';
|
||||
import { setOptions } from '@kadira/storybook-addon-options';
|
||||
import centered from './decorator-centered';
|
||||
import { configure, addDecorator } from '@kadira/storybook';
|
||||
|
||||
const context = require.context('../', true, /Example\.js$/);
|
||||
const context = require.context('../', true, /Docs\.js$/);
|
||||
|
||||
addDecorator(centered);
|
||||
|
||||
setOptions({
|
||||
name: 'React Native Web',
|
||||
url: 'https://necolas.github.io/react-native-web',
|
||||
goFullScreen: false,
|
||||
showLeftPanel: true,
|
||||
showDownPanel: false,
|
||||
showSearchBox: false,
|
||||
downPanelInRight: false
|
||||
});
|
||||
|
||||
function loadStories() {
|
||||
context.keys().forEach(context);
|
||||
}
|
||||
|
||||
@@ -3,7 +3,9 @@ import { StyleSheet, View } from 'react-native';
|
||||
|
||||
const styles = StyleSheet.create({
|
||||
root: {
|
||||
minHeight: '100vh'
|
||||
minHeight: '100vh',
|
||||
maxWidth: 680,
|
||||
marginHorizontal: 'auto'
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
@@ -0,0 +1,67 @@
|
||||
/* eslint-disable react/jsx-sort-props */
|
||||
|
||||
/**
|
||||
* @flow
|
||||
*/
|
||||
|
||||
import PropAnimating from './examples/PropAnimating';
|
||||
import PropColor from './examples/PropColor';
|
||||
import PropHidesWhenStopped from './examples/PropHidesWhenStopped';
|
||||
import PropSize from './examples/PropSize';
|
||||
import React from 'react';
|
||||
import { storiesOf } from '@kadira/storybook';
|
||||
import UIExplorer, { DocItem } from '../../ui-explorer';
|
||||
|
||||
const sections = [
|
||||
{
|
||||
title: 'Props',
|
||||
entries: [
|
||||
<DocItem name="...View props" />,
|
||||
|
||||
<DocItem
|
||||
name="animating"
|
||||
typeInfo="?boolean = true"
|
||||
description="Whether to show the indicator or hide it."
|
||||
example={{
|
||||
render: () => <PropAnimating />
|
||||
}}
|
||||
/>,
|
||||
|
||||
<DocItem
|
||||
name="color"
|
||||
typeInfo="?color = #1976D2"
|
||||
description="The foreground color of the spinner."
|
||||
example={{
|
||||
render: () => <PropColor />
|
||||
}}
|
||||
/>,
|
||||
|
||||
<DocItem
|
||||
name="hidesWhenStopped"
|
||||
typeInfo="?boolean = true"
|
||||
description="Whether the indicator should hide when not animating."
|
||||
example={{
|
||||
render: () => <PropHidesWhenStopped />
|
||||
}}
|
||||
/>,
|
||||
|
||||
<DocItem
|
||||
name="size"
|
||||
typeInfo="?enum('small', 'large') | number = 'small'"
|
||||
description="Size of the indicator. Small has a height of 20px, large has a height of 36px."
|
||||
example={{
|
||||
render: () => <PropSize />
|
||||
}}
|
||||
/>
|
||||
]
|
||||
}
|
||||
];
|
||||
|
||||
storiesOf('Components', module).add('ActivityIndicator', () =>
|
||||
<UIExplorer
|
||||
description="Displays a customizable activity indicator"
|
||||
sections={sections}
|
||||
title="ActivityIndicator"
|
||||
url="components/ActivityIndicator"
|
||||
/>
|
||||
);
|
||||
@@ -0,0 +1,21 @@
|
||||
/**
|
||||
* @flow
|
||||
*/
|
||||
|
||||
import { ActivityIndicator, StyleSheet, View } from 'react-native';
|
||||
import React from 'react';
|
||||
|
||||
const ActivityIndicatorAnimatingExample = () =>
|
||||
<View style={styles.horizontal}>
|
||||
<ActivityIndicator />
|
||||
<ActivityIndicator animating={false} />
|
||||
</View>;
|
||||
|
||||
const styles = StyleSheet.create({
|
||||
horizontal: {
|
||||
alignItems: 'center',
|
||||
flexDirection: 'row'
|
||||
}
|
||||
});
|
||||
|
||||
export default ActivityIndicatorAnimatingExample;
|
||||
@@ -0,0 +1,33 @@
|
||||
/**
|
||||
* @flow
|
||||
*/
|
||||
|
||||
import React from 'react';
|
||||
import { ActivityIndicator, StyleSheet, View } from 'react-native';
|
||||
|
||||
const ActivityIndicatorColorExample = () =>
|
||||
<View style={styles.horizontal}>
|
||||
<ActivityIndicator color="#1DA1F2" style={styles.rightPadding} />
|
||||
<ActivityIndicator color="#17BF63" style={styles.rightPadding} />
|
||||
<ActivityIndicator color="#F45D22" style={styles.rightPadding} />
|
||||
<ActivityIndicator color="#794BC4" style={styles.rightPadding} />
|
||||
<ActivityIndicator color="#E0245E" style={styles.rightPadding} />
|
||||
<ActivityIndicator color="#FFAD1F" style={styles.rightPadding} />
|
||||
</View>;
|
||||
|
||||
const styles = StyleSheet.create({
|
||||
horizontal: {
|
||||
alignItems: 'center',
|
||||
flexDirection: 'row'
|
||||
},
|
||||
rightPadding: {
|
||||
paddingRight: 10
|
||||
}
|
||||
});
|
||||
|
||||
ActivityIndicatorColorExample.metadata = {
|
||||
id: 'ActivityIndicator.props.color',
|
||||
description: ''
|
||||
};
|
||||
|
||||
export default ActivityIndicatorColorExample;
|
||||
@@ -0,0 +1,67 @@
|
||||
/**
|
||||
* @flow
|
||||
*/
|
||||
|
||||
import { ActivityIndicator, StyleSheet, View } from 'react-native';
|
||||
import { bool } from 'prop-types';
|
||||
import React, { PureComponent } from 'react';
|
||||
|
||||
class ToggleAnimatingActivityIndicator extends PureComponent {
|
||||
static propTypes = {
|
||||
hidesWhenStopped: bool,
|
||||
style: ActivityIndicator.propTypes.style
|
||||
};
|
||||
|
||||
state = {
|
||||
animating: true
|
||||
};
|
||||
|
||||
setToggleTimeout = () => {
|
||||
this._timer = setTimeout(() => {
|
||||
this.setState({ animating: !this.state.animating });
|
||||
this.setToggleTimeout();
|
||||
}, 2000);
|
||||
};
|
||||
|
||||
componentDidMount() {
|
||||
this.setToggleTimeout();
|
||||
}
|
||||
|
||||
componentWillUnmount() {
|
||||
clearTimeout(this._timer);
|
||||
}
|
||||
|
||||
render() {
|
||||
return (
|
||||
<ActivityIndicator
|
||||
animating={this.state.animating}
|
||||
hidesWhenStopped={this.props.hidesWhenStopped}
|
||||
size="large"
|
||||
style={[styles.centering, this.props.style]}
|
||||
/>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
const ActivityIndicatorHidesWhenStoppedExample = () =>
|
||||
<View style={[styles.horizontal]}>
|
||||
<ToggleAnimatingActivityIndicator hidesWhenStopped={false} style={styles.rightPadding} />
|
||||
<ToggleAnimatingActivityIndicator />
|
||||
</View>;
|
||||
|
||||
const styles = StyleSheet.create({
|
||||
horizontal: {
|
||||
alignItems: 'center',
|
||||
flexDirection: 'row'
|
||||
},
|
||||
rightPadding: {
|
||||
paddingRight: 10
|
||||
}
|
||||
});
|
||||
|
||||
ActivityIndicatorHidesWhenStoppedExample.metadata = {
|
||||
id: 'ActivityIndicator.props.hidesWhenStopped',
|
||||
description: ''
|
||||
};
|
||||
|
||||
export default ActivityIndicatorHidesWhenStoppedExample;
|
||||
@@ -0,0 +1,32 @@
|
||||
/**
|
||||
* @flow
|
||||
*/
|
||||
|
||||
import React from 'react';
|
||||
import { ActivityIndicator, StyleSheet, View } from 'react-native';
|
||||
|
||||
const sizes = [20, 'small', 36, 'large', 60];
|
||||
|
||||
const ActivityIndicatorSizeExample = () =>
|
||||
<View style={styles.horizontal}>
|
||||
{sizes.map((size, i) => <ActivityIndicator key={i} size={size} style={styles.rightPadding} />)}
|
||||
<ActivityIndicator size="large" style={styles.large} />
|
||||
</View>;
|
||||
|
||||
const styles = StyleSheet.create({
|
||||
horizontal: {
|
||||
alignItems: 'center',
|
||||
flexDirection: 'row'
|
||||
},
|
||||
rightPadding: {
|
||||
paddingRight: 10
|
||||
},
|
||||
large: { marginLeft: 20, transform: [{ scale: 1.75 }] }
|
||||
});
|
||||
|
||||
ActivityIndicatorSizeExample.metadata = {
|
||||
id: 'ActivityIndicator.props.size',
|
||||
description: ''
|
||||
};
|
||||
|
||||
export default ActivityIndicatorSizeExample;
|
||||
75
docs/storybook/1-components/Button/ButtonDocs.js
Normal file
75
docs/storybook/1-components/Button/ButtonDocs.js
Normal file
@@ -0,0 +1,75 @@
|
||||
/* eslint-disable react/jsx-sort-props */
|
||||
|
||||
/**
|
||||
* @flow
|
||||
*/
|
||||
|
||||
import React from 'react';
|
||||
import PropColor from './examples/PropColor';
|
||||
import PropDisabled from './examples/PropDisabled';
|
||||
import PropOnPress from './examples/PropOnPress';
|
||||
import UIExplorer, { AppText, Code, DocItem } from '../../ui-explorer';
|
||||
import { storiesOf } from '@kadira/storybook';
|
||||
|
||||
const sections = [
|
||||
{
|
||||
title: 'Props',
|
||||
entries: [
|
||||
<DocItem
|
||||
name="accessibilityLabel"
|
||||
typeInfo="?string"
|
||||
description="Overrides the text that's read by a screen reader when the user interacts with the element."
|
||||
/>,
|
||||
|
||||
<DocItem
|
||||
name="color"
|
||||
typeInfo="?string"
|
||||
description="Background color of the button."
|
||||
example={{
|
||||
render: () => <PropColor />
|
||||
}}
|
||||
/>,
|
||||
|
||||
<DocItem
|
||||
name="disabled"
|
||||
typeInfo="?boolean"
|
||||
description="If `true`, disable all interactions for this element."
|
||||
example={{
|
||||
render: () => <PropDisabled />
|
||||
}}
|
||||
/>,
|
||||
|
||||
<DocItem
|
||||
name="onPress"
|
||||
typeInfo="function"
|
||||
description="This function is called on press."
|
||||
example={{
|
||||
render: () => <PropOnPress />
|
||||
}}
|
||||
/>,
|
||||
|
||||
<DocItem
|
||||
name="testID"
|
||||
typeInfo="?string"
|
||||
description="Used to locate this view in end-to-end tests."
|
||||
/>,
|
||||
|
||||
<DocItem name="title" typeInfo="string" description="Text to display inside the button." />
|
||||
]
|
||||
}
|
||||
];
|
||||
|
||||
storiesOf('Components', module).add('Button', () =>
|
||||
<UIExplorer
|
||||
description={[
|
||||
<AppText>
|
||||
A basic button component. Supports a minimal level of customization.
|
||||
You can build your own custom button using <Code>TouchableOpacity</Code>
|
||||
or <Code>TouchableNativeFeedback</Code>.
|
||||
</AppText>
|
||||
]}
|
||||
sections={sections}
|
||||
title="Button"
|
||||
url="components/Button"
|
||||
/>
|
||||
);
|
||||
22
docs/storybook/1-components/Button/examples/PropColor.js
Normal file
22
docs/storybook/1-components/Button/examples/PropColor.js
Normal file
@@ -0,0 +1,22 @@
|
||||
/**
|
||||
* @flow
|
||||
*/
|
||||
|
||||
import React from 'react';
|
||||
import { DividerVertical } from '../helpers';
|
||||
import { Button, View } from 'react-native';
|
||||
|
||||
const emptyFunction = () => {};
|
||||
|
||||
const ButtonColorExample = () =>
|
||||
<View>
|
||||
<Button color="#17BF63" onPress={emptyFunction} title="Press me" />
|
||||
<DividerVertical />
|
||||
<Button color="#F45D22" onPress={emptyFunction} title="Press me" />
|
||||
<DividerVertical />
|
||||
<Button color="#794BC4" onPress={emptyFunction} title="Press me" />
|
||||
<DividerVertical />
|
||||
<Button color="#E0245E" onPress={emptyFunction} title="Press me" />
|
||||
</View>;
|
||||
|
||||
export default ButtonColorExample;
|
||||
13
docs/storybook/1-components/Button/examples/PropDisabled.js
Normal file
13
docs/storybook/1-components/Button/examples/PropDisabled.js
Normal file
@@ -0,0 +1,13 @@
|
||||
/**
|
||||
* @flow
|
||||
*/
|
||||
|
||||
import React from 'react';
|
||||
import { Button } from 'react-native';
|
||||
|
||||
const onPress = () => {
|
||||
console.error('Disabled button should not trigger onPress!');
|
||||
};
|
||||
const ButtonDisabledExample = () => <Button disabled onPress={onPress} title="Disabled button" />;
|
||||
|
||||
export default ButtonDisabledExample;
|
||||
28
docs/storybook/1-components/Button/examples/PropOnPress.js
Normal file
28
docs/storybook/1-components/Button/examples/PropOnPress.js
Normal file
@@ -0,0 +1,28 @@
|
||||
/**
|
||||
* @flow
|
||||
*/
|
||||
|
||||
import React from 'react';
|
||||
import { DividerHorizontal } from '../helpers';
|
||||
import { Button, StyleSheet, View } from 'react-native';
|
||||
|
||||
const emptyFunction = () => {};
|
||||
|
||||
const ButtonOnPressExample = () =>
|
||||
<View style={styles.horizontal}>
|
||||
<Button
|
||||
accessibilityLabel="This sounds great!"
|
||||
onPress={emptyFunction}
|
||||
title="This looks great!"
|
||||
/>
|
||||
<DividerHorizontal />
|
||||
<Button color="#841584" onPress={emptyFunction} title="Ok!" />
|
||||
</View>;
|
||||
|
||||
const styles = StyleSheet.create({
|
||||
horizontal: {
|
||||
flexDirection: 'row'
|
||||
}
|
||||
});
|
||||
|
||||
export default ButtonOnPressExample;
|
||||
20
docs/storybook/1-components/Button/helpers.js
Normal file
20
docs/storybook/1-components/Button/helpers.js
Normal file
@@ -0,0 +1,20 @@
|
||||
/**
|
||||
* @flow
|
||||
*/
|
||||
|
||||
import React from 'react';
|
||||
import { StyleSheet, View } from 'react-native';
|
||||
|
||||
const DividerHorizontal = () => <View style={styles.horizontalDivider} />;
|
||||
const DividerVertical = () => <View style={styles.verticalDivider} />;
|
||||
|
||||
const styles = StyleSheet.create({
|
||||
horizontalDivider: {
|
||||
width: '0.6rem'
|
||||
},
|
||||
verticalDivider: {
|
||||
height: '1.3125rem'
|
||||
}
|
||||
});
|
||||
|
||||
export { DividerHorizontal, DividerVertical };
|
||||
158
docs/storybook/1-components/Image/ImageDocs.js
Normal file
158
docs/storybook/1-components/Image/ImageDocs.js
Normal file
@@ -0,0 +1,158 @@
|
||||
/* eslint-disable react/jsx-sort-props */
|
||||
|
||||
/**
|
||||
* @flow
|
||||
*/
|
||||
|
||||
import React from 'react';
|
||||
import PropChildren from './examples/PropChildren';
|
||||
import PropDefaultSource from './examples/PropDefaultSource';
|
||||
import PropDraggable from './examples/PropDraggable';
|
||||
import PropOnError from './examples/PropOnError';
|
||||
import PropOnLoad from './examples/PropOnLoad';
|
||||
import PropOnLoadEnd from './examples/PropOnLoadEnd';
|
||||
import PropOnLoadStart from './examples/PropOnLoadStart';
|
||||
import PropResizeMode from './examples/PropResizeMode';
|
||||
import PropSource from './examples/PropSource';
|
||||
import StaticGetSizeExample from './examples/StaticGetSize';
|
||||
import StaticPrefetchExample from './examples/StaticPrefetch';
|
||||
import { storiesOf } from '@kadira/storybook';
|
||||
import UIExplorer, { DocItem } from '../../ui-explorer';
|
||||
|
||||
const sections = [
|
||||
{
|
||||
title: 'Props',
|
||||
entries: [
|
||||
<DocItem name="...View props" />,
|
||||
|
||||
<DocItem
|
||||
name="children"
|
||||
typeInfo="?any"
|
||||
description="Content to display over the image."
|
||||
example={{
|
||||
render: () => <PropChildren />
|
||||
}}
|
||||
/>,
|
||||
|
||||
<DocItem
|
||||
name="defaultSource"
|
||||
typeInfo="?object"
|
||||
description="An image to display as a placeholder while downloading the final image off the network. `{ uri: string, width, height }`"
|
||||
example={{
|
||||
render: () => <PropDefaultSource />
|
||||
}}
|
||||
/>,
|
||||
|
||||
<DocItem
|
||||
name="draggable"
|
||||
typeInfo="?boolean = true"
|
||||
description="When false, the image will not be draggable"
|
||||
example={{
|
||||
render: () => <PropDraggable />
|
||||
}}
|
||||
/>,
|
||||
|
||||
<DocItem
|
||||
name="onError"
|
||||
typeInfo="?function"
|
||||
description="Invoked on load error with `{nativeEvent: {error}}`."
|
||||
example={{
|
||||
render: () => <PropOnError />
|
||||
}}
|
||||
/>,
|
||||
|
||||
<DocItem
|
||||
name="onLoad"
|
||||
typeInfo="?function"
|
||||
description="Invoked when load completes successfully."
|
||||
example={{
|
||||
render: () => <PropOnLoad />
|
||||
}}
|
||||
/>,
|
||||
|
||||
<DocItem
|
||||
name="onLoadEnd"
|
||||
typeInfo="?function"
|
||||
description="Invoked when load either succeeds or fails."
|
||||
example={{
|
||||
render: () => <PropOnLoadEnd />
|
||||
}}
|
||||
/>,
|
||||
|
||||
<DocItem
|
||||
name="onLoadStart"
|
||||
typeInfo="?function"
|
||||
description="Invoked on load start."
|
||||
example={{
|
||||
render: () => <PropOnLoadStart />
|
||||
}}
|
||||
/>,
|
||||
|
||||
<DocItem
|
||||
name="resizeMode"
|
||||
typeInfo="?enum('center', 'contain', 'cover', 'none', 'repeat', 'stretch') = 'cover';"
|
||||
description="Determines how to resize the image when the frame doesn't match the raw image dimensions."
|
||||
example={{
|
||||
render: () => <PropResizeMode />
|
||||
}}
|
||||
/>,
|
||||
|
||||
<DocItem
|
||||
name="source"
|
||||
typeInfo="?object"
|
||||
description="`uri` is a string representing the resource identifier for the image, which could be an http address or a base64 encoded image. `{ uri: string, width, height }`"
|
||||
example={{
|
||||
code: '',
|
||||
render: () => <PropSource />
|
||||
}}
|
||||
/>,
|
||||
|
||||
<DocItem name="style" typeInfo="?style" />
|
||||
]
|
||||
},
|
||||
|
||||
{
|
||||
title: 'Properties',
|
||||
entries: [
|
||||
<DocItem
|
||||
name="static resizeMode"
|
||||
typeInfo="object"
|
||||
example={{
|
||||
code: '<Image resizeMode={Image.resizeMode.contain} />'
|
||||
}}
|
||||
/>
|
||||
]
|
||||
},
|
||||
|
||||
{
|
||||
title: 'Methods',
|
||||
entries: [
|
||||
<DocItem
|
||||
name="static getSize"
|
||||
typeInfo="(uri: string, success: (width, height) => {}, failure: function) => void"
|
||||
description="Retrieve the width and height (in pixels) of an image prior to displaying it. This method can fail if the image cannot be found, or fails to download.\n\n(In order to retrieve the image dimensions, the image may first need to be loaded or downloaded, after which it will be cached. This means that in principle you could use this method to preload images, however it is not optimized for that purpose, and may in future be implemented in a way that does not fully load/download the image data.)"
|
||||
example={{
|
||||
render: () => <StaticGetSizeExample />
|
||||
}}
|
||||
/>,
|
||||
|
||||
<DocItem
|
||||
name="static prefetch"
|
||||
typeInfo="(url: string) => Promise"
|
||||
description="Prefetches a remote image for later use by downloading it."
|
||||
example={{
|
||||
render: () => <StaticPrefetchExample />
|
||||
}}
|
||||
/>
|
||||
]
|
||||
}
|
||||
];
|
||||
|
||||
storiesOf('Components', module).add('Image', () =>
|
||||
<UIExplorer
|
||||
description="An accessibile image component with support for image resizing, default image, and child content."
|
||||
sections={sections}
|
||||
title="Image"
|
||||
url="components/Image"
|
||||
/>
|
||||
);
|
||||
@@ -0,0 +1,72 @@
|
||||
/**
|
||||
* @flow
|
||||
*/
|
||||
|
||||
/*
|
||||
import React, { PureComponent } from 'react';
|
||||
import { Image, StyleSheet, Text, View } from 'react-native';
|
||||
|
||||
export default class MultipleSourcesExample extends PureComponent {
|
||||
state = {
|
||||
width: 30,
|
||||
height: 30
|
||||
};
|
||||
|
||||
render() {
|
||||
return (
|
||||
<View style={styles.container}>
|
||||
<View style={{ flexDirection: 'row', justifyContent: 'space-between' }}>
|
||||
<Text style={styles.touchableText} onPress={this.decreaseImageSize}>
|
||||
Decrease image size
|
||||
</Text>
|
||||
<Text style={styles.touchableText} onPress={this.increaseImageSize}>
|
||||
Increase image size
|
||||
</Text>
|
||||
</View>
|
||||
<Text>Container image size: {this.state.width}x{this.state.height} </Text>
|
||||
<View style={{ height: this.state.height, width: this.state.width }}>
|
||||
<Image
|
||||
style={{ flex: 1 }}
|
||||
source={[
|
||||
{ uri: 'http://facebook.github.io/react/img/logo_small.png', width: 38, height: 38 },
|
||||
{
|
||||
uri: 'http://facebook.github.io/react/img/logo_small_2x.png',
|
||||
width: 76,
|
||||
height: 76
|
||||
},
|
||||
{ uri: 'http://facebook.github.io/react/img/logo_og.png', width: 400, height: 400 }
|
||||
]}
|
||||
/>
|
||||
</View>
|
||||
</View>
|
||||
);
|
||||
}
|
||||
|
||||
increaseImageSize = () => {
|
||||
if (this.state.width >= 100) {
|
||||
return;
|
||||
}
|
||||
this.setState(state => ({
|
||||
width: state.width + 10,
|
||||
height: state.height + 10
|
||||
}));
|
||||
};
|
||||
|
||||
decreaseImageSize = () => {
|
||||
if (this.state.width <= 10) {
|
||||
return;
|
||||
}
|
||||
this.setState(state => ({
|
||||
width: state.width - 10,
|
||||
height: state.height - 10
|
||||
}));
|
||||
};
|
||||
}
|
||||
|
||||
const styles = StyleSheet.create({
|
||||
touchableText: {
|
||||
color: 'blue',
|
||||
fontWeight: '500'
|
||||
}
|
||||
});
|
||||
*/
|
||||
84
docs/storybook/1-components/Image/examples/NetworkImage.js
Normal file
84
docs/storybook/1-components/Image/examples/NetworkImage.js
Normal file
@@ -0,0 +1,84 @@
|
||||
/**
|
||||
* @flow
|
||||
*/
|
||||
|
||||
import * as helpers from '../helpers';
|
||||
import { oneOf } from 'prop-types';
|
||||
import sources from '../sources';
|
||||
import React, { PureComponent } from 'react';
|
||||
import { ActivityIndicator, Image, Text, View } from 'react-native';
|
||||
|
||||
class NetworkImageExample extends PureComponent {
|
||||
state = {
|
||||
error: false,
|
||||
loading: false
|
||||
};
|
||||
|
||||
static propTypes = {
|
||||
logMethod: oneOf(['onError', 'onLoad', 'onLoadEnd', 'onLoadStart']),
|
||||
source: Image.propTypes.source
|
||||
};
|
||||
|
||||
static defaultProps = {
|
||||
logList: []
|
||||
};
|
||||
|
||||
render() {
|
||||
const loader = this.state.loading
|
||||
? <View>
|
||||
<ActivityIndicator />
|
||||
</View>
|
||||
: null;
|
||||
|
||||
return (
|
||||
<View style={[helpers.styles.row, helpers.styles.centerRow]}>
|
||||
<Image
|
||||
defaultSource={sources.placeholder}
|
||||
onError={this._handleError}
|
||||
onLoad={this._handleLoad}
|
||||
onLoadEnd={this._handleLoadEnd}
|
||||
onLoadStart={this._handleLoadStart}
|
||||
source={this.props.source}
|
||||
style={helpers.styles.base}
|
||||
>
|
||||
{loader}
|
||||
</Image>
|
||||
{this.state.message && <Text style={helpers.styles.marginLeft}>{this.state.message}</Text>}
|
||||
</View>
|
||||
);
|
||||
}
|
||||
|
||||
_handleError = e => {
|
||||
const nextState = { loading: false };
|
||||
if (this.props.logMethod === 'onError') {
|
||||
nextState.message = `✘ onError ${JSON.stringify(e.nativeEvent)}`;
|
||||
}
|
||||
this.setState(() => nextState);
|
||||
};
|
||||
|
||||
_handleLoad = () => {
|
||||
const nextState = { loading: false };
|
||||
if (this.props.logMethod === 'onLoad') {
|
||||
nextState.message = '✔ onLoad';
|
||||
}
|
||||
this.setState(() => nextState);
|
||||
};
|
||||
|
||||
_handleLoadEnd = () => {
|
||||
const nextState = { loading: false };
|
||||
if (this.props.logMethod === 'onLoadEnd') {
|
||||
nextState.message = '✔ onLoadEnd';
|
||||
}
|
||||
this.setState(() => nextState);
|
||||
};
|
||||
|
||||
_handleLoadStart = () => {
|
||||
const nextState = { loading: true };
|
||||
if (this.props.logMethod === 'onLoadStart') {
|
||||
nextState.message = '✔ onLoadStart';
|
||||
}
|
||||
this.setState(() => nextState);
|
||||
};
|
||||
}
|
||||
|
||||
export default NetworkImageExample;
|
||||
30
docs/storybook/1-components/Image/examples/PropChildren.js
Normal file
30
docs/storybook/1-components/Image/examples/PropChildren.js
Normal file
@@ -0,0 +1,30 @@
|
||||
/**
|
||||
* @flow
|
||||
*/
|
||||
|
||||
import sources from '../sources';
|
||||
import React from 'react';
|
||||
import { Image, StyleSheet, Text } from 'react-native';
|
||||
|
||||
const ImageChildrenExample = () =>
|
||||
<Image source={sources.large} style={styles.image}>
|
||||
<Text style={styles.text}>
|
||||
React
|
||||
</Text>
|
||||
</Image>;
|
||||
|
||||
const styles = StyleSheet.create({
|
||||
image: {
|
||||
width: 60,
|
||||
height: 60,
|
||||
backgroundColor: 'transparent',
|
||||
justifyContent: 'center',
|
||||
alignItems: 'center'
|
||||
},
|
||||
text: {
|
||||
backgroundColor: 'transparent',
|
||||
color: 'white'
|
||||
}
|
||||
});
|
||||
|
||||
export default ImageChildrenExample;
|
||||
@@ -0,0 +1,17 @@
|
||||
/**
|
||||
* @flow
|
||||
*/
|
||||
|
||||
import * as helpers from '../helpers';
|
||||
import sources from '../sources';
|
||||
import React from 'react';
|
||||
import { Image } from 'react-native';
|
||||
|
||||
const ImageDefaultSourceExample = () =>
|
||||
<Image
|
||||
defaultSource={sources.placeholder}
|
||||
source={sources.largeAlt}
|
||||
style={helpers.styles.base}
|
||||
/>;
|
||||
|
||||
export default ImageDefaultSourceExample;
|
||||
26
docs/storybook/1-components/Image/examples/PropDraggable.js
Normal file
26
docs/storybook/1-components/Image/examples/PropDraggable.js
Normal file
@@ -0,0 +1,26 @@
|
||||
/**
|
||||
* @flow
|
||||
*/
|
||||
|
||||
import sources from '../sources';
|
||||
import React from 'react';
|
||||
import { Image, StyleSheet, View } from 'react-native';
|
||||
|
||||
const ImageDraggableExample = () =>
|
||||
<View style={styles.container}>
|
||||
<Image draggable={false} source={sources.large} style={styles.image} />
|
||||
</View>;
|
||||
|
||||
const styles = StyleSheet.create({
|
||||
container: {
|
||||
flexDirection: 'row'
|
||||
},
|
||||
image: {
|
||||
width: 60,
|
||||
height: 60,
|
||||
backgroundColor: 'transparent',
|
||||
marginRight: 10
|
||||
}
|
||||
});
|
||||
|
||||
export default ImageDraggableExample;
|
||||
11
docs/storybook/1-components/Image/examples/PropOnError.js
Normal file
11
docs/storybook/1-components/Image/examples/PropOnError.js
Normal file
@@ -0,0 +1,11 @@
|
||||
/**
|
||||
* @flow
|
||||
*/
|
||||
|
||||
import NetworkImage from './NetworkImage';
|
||||
import React from 'react';
|
||||
import sources from '../sources';
|
||||
|
||||
const ImageOnErrorExample = () => <NetworkImage logMethod="onError" source={sources.broken} />;
|
||||
|
||||
export default ImageOnErrorExample;
|
||||
13
docs/storybook/1-components/Image/examples/PropOnLoad.js
Normal file
13
docs/storybook/1-components/Image/examples/PropOnLoad.js
Normal file
@@ -0,0 +1,13 @@
|
||||
/**
|
||||
* @flow
|
||||
*/
|
||||
|
||||
import { createUncachedURI } from '../helpers';
|
||||
import NetworkImage from './NetworkImage';
|
||||
import React from 'react';
|
||||
import sources from '../sources';
|
||||
|
||||
const ImageOnLoadExample = () =>
|
||||
<NetworkImage logMethod="onLoad" source={createUncachedURI(sources.small)} />;
|
||||
|
||||
export default ImageOnLoadExample;
|
||||
13
docs/storybook/1-components/Image/examples/PropOnLoadEnd.js
Normal file
13
docs/storybook/1-components/Image/examples/PropOnLoadEnd.js
Normal file
@@ -0,0 +1,13 @@
|
||||
/**
|
||||
* @flow
|
||||
*/
|
||||
|
||||
import { createUncachedURI } from '../helpers';
|
||||
import NetworkImage from './NetworkImage';
|
||||
import React from 'react';
|
||||
import sources from '../sources';
|
||||
|
||||
const ImageOnLoadEndExample = () =>
|
||||
<NetworkImage logMethod="onLoadEnd" source={createUncachedURI(sources.small)} />;
|
||||
|
||||
export default ImageOnLoadEndExample;
|
||||
@@ -0,0 +1,13 @@
|
||||
/**
|
||||
* @flow
|
||||
*/
|
||||
|
||||
import { createUncachedURI } from '../helpers';
|
||||
import NetworkImage from './NetworkImage';
|
||||
import React from 'react';
|
||||
import sources from '../sources';
|
||||
|
||||
const ImageOnLoadStartExample = () =>
|
||||
<NetworkImage logMethod="onLoadStart" source={createUncachedURI(sources.small)} />;
|
||||
|
||||
export default ImageOnLoadStartExample;
|
||||
84
docs/storybook/1-components/Image/examples/PropResizeMode.js
Normal file
84
docs/storybook/1-components/Image/examples/PropResizeMode.js
Normal file
@@ -0,0 +1,84 @@
|
||||
/**
|
||||
* @flow
|
||||
*/
|
||||
|
||||
import React from 'react';
|
||||
import sources from '../sources';
|
||||
import { Image, StyleSheet, Text, View } from 'react-native';
|
||||
|
||||
const ImageResizeModeExample = () =>
|
||||
<View>
|
||||
{[sources.small, sources.large].map((source, i) => {
|
||||
return (
|
||||
<View key={i}>
|
||||
<View style={styles.horizontal}>
|
||||
<View>
|
||||
<Text style={[styles.resizeModeText]}>
|
||||
Contain
|
||||
</Text>
|
||||
<Image
|
||||
resizeMode={Image.resizeMode.contain}
|
||||
source={source}
|
||||
style={styles.resizeMode}
|
||||
/>
|
||||
</View>
|
||||
<View>
|
||||
<Text style={[styles.resizeModeText]}>
|
||||
Cover
|
||||
</Text>
|
||||
<Image
|
||||
resizeMode={Image.resizeMode.cover}
|
||||
source={source}
|
||||
style={styles.resizeMode}
|
||||
/>
|
||||
</View>
|
||||
<View>
|
||||
<Text style={[styles.resizeModeText]}>
|
||||
Stretch
|
||||
</Text>
|
||||
<Image
|
||||
resizeMode={Image.resizeMode.stretch}
|
||||
source={source}
|
||||
style={styles.resizeMode}
|
||||
/>
|
||||
</View>
|
||||
<View>
|
||||
<Text style={[styles.resizeModeText]}>
|
||||
Repeat
|
||||
</Text>
|
||||
<Image resizeMode={'repeat'} source={source} style={styles.resizeMode} />
|
||||
</View>
|
||||
<View>
|
||||
<Text style={[styles.resizeModeText]}>
|
||||
Center
|
||||
</Text>
|
||||
<Image resizeMode={'center'} source={source} style={styles.resizeMode} />
|
||||
</View>
|
||||
</View>
|
||||
</View>
|
||||
);
|
||||
})}
|
||||
</View>;
|
||||
|
||||
const styles = StyleSheet.create({
|
||||
horizontal: {
|
||||
flexDirection: 'row',
|
||||
flexWrap: 'wrap',
|
||||
justifyContent: 'space-between'
|
||||
},
|
||||
resizeMode: {
|
||||
borderColor: 'black',
|
||||
borderWidth: 0.5,
|
||||
height: 60,
|
||||
width: 90
|
||||
},
|
||||
resizeModeText: {
|
||||
fontSize: 11,
|
||||
marginBottom: 3
|
||||
},
|
||||
leftMargin: {
|
||||
marginLeft: 10
|
||||
}
|
||||
});
|
||||
|
||||
export default ImageResizeModeExample;
|
||||
47
docs/storybook/1-components/Image/examples/PropSource.js
Normal file
47
docs/storybook/1-components/Image/examples/PropSource.js
Normal file
@@ -0,0 +1,47 @@
|
||||
/**
|
||||
* @flow
|
||||
*/
|
||||
|
||||
import sources from '../sources';
|
||||
import React from 'react';
|
||||
import { Image, StyleSheet, Text, View } from 'react-native';
|
||||
|
||||
const ImageSourceExample = () =>
|
||||
<View style={styles.row}>
|
||||
<View style={styles.column}>
|
||||
<Text style={styles.text}>Static image</Text>
|
||||
<Image source={sources.static} style={styles.image} />
|
||||
</View>
|
||||
<View style={styles.column}>
|
||||
<Text style={styles.text}>Animated GIF</Text>
|
||||
<Image source={sources.animatedGif} style={styles.image} />
|
||||
</View>
|
||||
<View style={styles.column}>
|
||||
<Text style={styles.text}>Data PNG</Text>
|
||||
<Image source={sources.dataPng} style={styles.image} />
|
||||
</View>
|
||||
<View style={styles.column}>
|
||||
<Text style={styles.text}>Data SVG</Text>
|
||||
<Image source={sources.dataSvg} style={styles.image} />
|
||||
</View>
|
||||
</View>;
|
||||
|
||||
const styles = StyleSheet.create({
|
||||
row: {
|
||||
flexDirection: 'row',
|
||||
flexWrap: 'wrap'
|
||||
},
|
||||
column: {
|
||||
marginRight: '1rem'
|
||||
},
|
||||
text: {
|
||||
marginBottom: '0.5rem'
|
||||
},
|
||||
image: {
|
||||
flex: 1,
|
||||
height: 50,
|
||||
resizeMode: 'contain'
|
||||
}
|
||||
});
|
||||
|
||||
export default ImageSourceExample;
|
||||
66
docs/storybook/1-components/Image/examples/StaticGetSize.js
Normal file
66
docs/storybook/1-components/Image/examples/StaticGetSize.js
Normal file
@@ -0,0 +1,66 @@
|
||||
/**
|
||||
* @flow
|
||||
*/
|
||||
|
||||
import { createUncachedURI } from '../helpers';
|
||||
import sources from '../sources';
|
||||
import React, { PureComponent } from 'react';
|
||||
import { Button, Image, StyleSheet, Text, View } from 'react-native';
|
||||
|
||||
class ImageGetSizeExample extends PureComponent {
|
||||
static propTypes = {
|
||||
source: Image.propTypes.source
|
||||
};
|
||||
|
||||
state = {
|
||||
showButton: true,
|
||||
startLoad: false,
|
||||
width: 0,
|
||||
height: 0
|
||||
};
|
||||
|
||||
render() {
|
||||
const { showButton, startLoad } = this.state;
|
||||
|
||||
return (
|
||||
<View>
|
||||
{showButton
|
||||
? <View style={styles.button}>
|
||||
<Button onPress={this._handlePress} title="(4.7MB) Get image dimensions" />
|
||||
</View>
|
||||
: null}
|
||||
{startLoad
|
||||
? <View>
|
||||
<Text>
|
||||
Source dimensions:{' '}
|
||||
{JSON.stringify({ width: this.state.width, height: this.state.height })}
|
||||
</Text>
|
||||
<Image source={createUncachedURI(this.props.source.uri)} style={styles.image} />
|
||||
</View>
|
||||
: null}
|
||||
</View>
|
||||
);
|
||||
}
|
||||
|
||||
_handlePress = () => {
|
||||
Image.getSize(this.props.source.uri, (width, height) => {
|
||||
this.setState({ startLoad: true, showButton: false, width, height });
|
||||
});
|
||||
};
|
||||
}
|
||||
|
||||
const styles = StyleSheet.create({
|
||||
button: {
|
||||
maxWidth: 300
|
||||
},
|
||||
image: {
|
||||
backgroundColor: '#eee',
|
||||
height: 227,
|
||||
marginTop: 10,
|
||||
width: 323
|
||||
}
|
||||
});
|
||||
|
||||
const StaticGetSizeExample = () => <ImageGetSizeExample source={sources.huge} />;
|
||||
|
||||
export default StaticGetSizeExample;
|
||||
96
docs/storybook/1-components/Image/examples/StaticPrefetch.js
Normal file
96
docs/storybook/1-components/Image/examples/StaticPrefetch.js
Normal file
@@ -0,0 +1,96 @@
|
||||
/**
|
||||
* @flow
|
||||
*/
|
||||
|
||||
import { createUncachedURI } from '../helpers';
|
||||
import sources from '../sources';
|
||||
import React, { PureComponent } from 'react';
|
||||
import { Button, Image, StyleSheet, Text, View } from 'react-native';
|
||||
|
||||
class ImagePrefetchExample extends PureComponent {
|
||||
static propTypes = {
|
||||
source: Image.propTypes.source
|
||||
};
|
||||
|
||||
state = {
|
||||
events: [],
|
||||
showButton: true,
|
||||
startLoad: false
|
||||
};
|
||||
|
||||
render() {
|
||||
const { showButton, startLoad } = this.state;
|
||||
|
||||
return (
|
||||
<View>
|
||||
{showButton
|
||||
? <View style={styles.button}>
|
||||
<Button onPress={this._handlePress} title="Prefetch image" />
|
||||
</View>
|
||||
: null}
|
||||
{startLoad
|
||||
? <View>
|
||||
<Text>{this.state.events.join('\n')}</Text>
|
||||
<Image
|
||||
onLoad={this._handleLoad}
|
||||
onLoadEnd={this._handleLoadEnd}
|
||||
onLoadStart={this._handleLoadStart}
|
||||
source={this.props.source}
|
||||
style={styles.image}
|
||||
/>
|
||||
</View>
|
||||
: null}
|
||||
</View>
|
||||
);
|
||||
}
|
||||
|
||||
_handleLoad = () => {
|
||||
const startTime = this._startTime;
|
||||
this._loadEventFired(`✔ (prefetched) onLoad (+${Date.now() - startTime}ms)`);
|
||||
};
|
||||
|
||||
_handleLoadEnd = () => {
|
||||
const startTime = this._startTime;
|
||||
this._loadEventFired(`✔ (prefetched) onLoadEnd (+${Date.now() - startTime}ms)`);
|
||||
};
|
||||
|
||||
_handleLoadStart = () => {
|
||||
const startTime = this._startTime;
|
||||
this._loadEventFired(`✔ (prefetched) onLoadStart (+${Date.now() - startTime}ms)`);
|
||||
};
|
||||
|
||||
_handlePress = () => {
|
||||
this._startTime = this._startTime || Date.now();
|
||||
|
||||
Image.prefetch(createUncachedURI(this.props.source.uri)).then(
|
||||
() => {
|
||||
this._loadEventFired('✔ Prefetch OK');
|
||||
this.setState(() => ({ startLoad: true }));
|
||||
},
|
||||
error => {
|
||||
this._loadEventFired(`✘ Prefetch failed (+${Date.now() - this._startTime}ms)`);
|
||||
console.log(error);
|
||||
}
|
||||
);
|
||||
};
|
||||
|
||||
_loadEventFired = event => {
|
||||
this.setState(state => ({ events: [...state.events, event], showButton: false }));
|
||||
};
|
||||
}
|
||||
|
||||
const styles = StyleSheet.create({
|
||||
button: {
|
||||
maxWidth: 300
|
||||
},
|
||||
image: {
|
||||
backgroundColor: '#eee',
|
||||
height: 150,
|
||||
marginTop: 10,
|
||||
width: 150
|
||||
}
|
||||
});
|
||||
|
||||
const StaticPrefetchExample = () => <ImagePrefetchExample source={sources.prefetchable} />;
|
||||
|
||||
export default StaticPrefetchExample;
|
||||
30
docs/storybook/1-components/Image/helpers.js
Normal file
30
docs/storybook/1-components/Image/helpers.js
Normal file
@@ -0,0 +1,30 @@
|
||||
/**
|
||||
* @flow
|
||||
*/
|
||||
|
||||
// import React from 'react';
|
||||
import { StyleSheet } from 'react-native';
|
||||
|
||||
const createUncachedURI = source => {
|
||||
const helper = str => `${str}?t=${Date.now()}`;
|
||||
const uri = typeof source === 'string' ? source : source.uri;
|
||||
return typeof source === 'string' ? helper(uri) : { ...source, uri: helper(uri) };
|
||||
};
|
||||
|
||||
const styles = StyleSheet.create({
|
||||
base: {
|
||||
height: 38,
|
||||
width: 38
|
||||
},
|
||||
row: {
|
||||
flexDirection: 'row'
|
||||
},
|
||||
centerRow: {
|
||||
alignItems: 'center'
|
||||
},
|
||||
marginLeft: {
|
||||
marginLeft: '1rem'
|
||||
}
|
||||
});
|
||||
|
||||
export { createUncachedURI, styles };
|
||||
|
Before Width: | Height: | Size: 18 KiB After Width: | Height: | Size: 18 KiB |
28
docs/storybook/1-components/Image/sources/index.js
Normal file
28
docs/storybook/1-components/Image/sources/index.js
Normal file
@@ -0,0 +1,28 @@
|
||||
import placeholder from './bunny.png';
|
||||
import staticImage from './uie_thumb_normal@2x.png';
|
||||
|
||||
const dataPng =
|
||||
'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAEsAAABLCAQAAACSR7JhAAADtUlEQVR4Ac3YA2Bj6QLH0XPT1Fzbtm29tW3btm3bfLZtv7e2ObZnms7d8Uw098tuetPzrxv8wiISrtVudrG2JXQZ4VOv+qUfmqCGGl1mqLhoA52oZlb0mrjsnhKpgeUNEs91Z0pd1kvihA3ULGVHiQO2narKSHKkEMulm9VgUyE60s1aWoMQUbpZOWE+kaqs4eLEjdIlZTcFZB0ndc1+lhB1lZrIuk5P2aib1NBpZaL+JaOGIt0ls47SKzLC7CqrlGF6RZ09HGoNy1lYl2aRSWL5GuzqWU1KafRdoRp0iOQEiDzgZPnG6DbldcomadViflnl/cL93tOoVbsOLVM2jylvdWjXolWX1hmfZbGR/wjypDjFLSZIRov09BgYmtUqPQPlQrPapecLgTIy0jMgPKtTeob2zWtrGH3xvjUkPCtNg/tm1rjwrMa+mdUkPd3hWbH0jArPGiU9ufCsNNWFZ40wpwn+62/66R2RUtoso1OB34tnLOcy7YB1fUdc9e0q3yru8PGM773vXsuZ5YIZX+5xmHwHGVvlrGPN6ZSiP1smOsMMde40wKv2VmwPPVXNut4sVpUreZiLBHi0qln/VQeI/LTMYXpsJtFiclUN+5HVZazim+Ky+7sAvxWnvjXrJFneVtLWLyPJu9K3cXLWeOlbMTlrIelbMDlrLenrjEQOtIF+fuI9xRp9ZBFp6+b6WT8RrxEpdK64BuvHgDk+vUy+b5hYk6zfyfs051gRoNO1usU12WWRWL73/MMEy9pMi9qIrR4ZpV16Rrvduxazmy1FSvuFXRkqTnE7m2kdb5U8xGjLw/spRr1uTov4uOgQE+0N/DvFrG/Jt7i/FzwxbA9kDanhf2w+t4V97G8lrT7wc08aA2QNUkuTfW/KimT01wdlfK4yEw030VfT0RtZbzjeMprNq8m8tnSTASrTLti64oBNdpmMQm0eEwvfPwRbUBywG5TzjPCsdwk3IeAXjQblLCoXnDVeoAz6SfJNk5TTzytCNZk/POtTSV40NwOFWzw86wNJRpubpXsn60NJFlHeqlYRbslqZm2jnEZ3qcSKgm0kTli3zZVS7y/iivZTweYXJ26Y+RTbV1zh3hYkgyFGSTKPfRVbRqWWVReaxYeSLarYv1Qqsmh1s95S7G+eEWK0f3jYKTbV6bOwepjfhtafsvUsqrQvrGC8YhmnO9cSCk3yuY984F1vesdHYhWJ5FvASlacshUsajFt2mUM9pqzvKGcyNJW0arTKN1GGGzQlH0tXwLDgQTurS8eIQAAAABJRU5ErkJggg==';
|
||||
const dataSvg =
|
||||
'data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 841.9 595.3"><g fill="#61DAFB"><path d="M666.3 296.5c0-32.5-40.7-63.3-103.1-82.4 14.4-63.6 8-114.2-20.2-130.4-6.5-3.8-14.1-5.6-22.4-5.6v22.3c4.6 0 8.3.9 11.4 2.6 13.6 7.8 19.5 37.5 14.9 75.7-1.1 9.4-2.9 19.3-5.1 29.4-19.6-4.8-41-8.5-63.5-10.9-13.5-18.5-27.5-35.3-41.6-50 32.6-30.3 63.2-46.9 84-46.9V78c-27.5 0-63.5 19.6-99.9 53.6-36.4-33.8-72.4-53.2-99.9-53.2v22.3c20.7 0 51.4 16.5 84 46.6-14 14.7-28 31.4-41.3 49.9-22.6 2.4-44 6.1-63.6 11-2.3-10-4-19.7-5.2-29-4.7-38.2 1.1-67.9 14.6-75.8 3-1.8 6.9-2.6 11.5-2.6V78.5c-8.4 0-16 1.8-22.6 5.6-28.1 16.2-34.4 66.7-19.9 130.1-62.2 19.2-102.7 49.9-102.7 82.3 0 32.5 40.7 63.3 103.1 82.4-14.4 63.6-8 114.2 20.2 130.4 6.5 3.8 14.1 5.6 22.5 5.6 27.5 0 63.5-19.6 99.9-53.6 36.4 33.8 72.4 53.2 99.9 53.2 8.4 0 16-1.8 22.6-5.6 28.1-16.2 34.4-66.7 19.9-130.1 62-19.1 102.5-49.9 102.5-82.3zm-130.2-66.7c-3.7 12.9-8.3 26.2-13.5 39.5-4.1-8-8.4-16-13.1-24-4.6-8-9.5-15.8-14.4-23.4 14.2 2.1 27.9 4.7 41 7.9zm-45.8 106.5c-7.8 13.5-15.8 26.3-24.1 38.2-14.9 1.3-30 2-45.2 2-15.1 0-30.2-.7-45-1.9-8.3-11.9-16.4-24.6-24.2-38-7.6-13.1-14.5-26.4-20.8-39.8 6.2-13.4 13.2-26.8 20.7-39.9 7.8-13.5 15.8-26.3 24.1-38.2 14.9-1.3 30-2 45.2-2 15.1 0 30.2.7 45 1.9 8.3 11.9 16.4 24.6 24.2 38 7.6 13.1 14.5 26.4 20.8 39.8-6.3 13.4-13.2 26.8-20.7 39.9zm32.3-13c5.4 13.4 10 26.8 13.8 39.8-13.1 3.2-26.9 5.9-41.2 8 4.9-7.7 9.8-15.6 14.4-23.7 4.6-8 8.9-16.1 13-24.1zM421.2 430c-9.3-9.6-18.6-20.3-27.8-32 9 .4 18.2.7 27.5.7 9.4 0 18.7-.2 27.8-.7-9 11.7-18.3 22.4-27.5 32zm-74.4-58.9c-14.2-2.1-27.9-4.7-41-7.9 3.7-12.9 8.3-26.2 13.5-39.5 4.1 8 8.4 16 13.1 24 4.7 8 9.5 15.8 14.4 23.4zM420.7 163c9.3 9.6 18.6 20.3 27.8 32-9-.4-18.2-.7-27.5-.7-9.4 0-18.7.2-27.8.7 9-11.7 18.3-22.4 27.5-32zm-74 58.9c-4.9 7.7-9.8 15.6-14.4 23.7-4.6 8-8.9 16-13 24-5.4-13.4-10-26.8-13.8-39.8 13.1-3.1 26.9-5.8 41.2-7.9zm-90.5 125.2c-35.4-15.1-58.3-34.9-58.3-50.6 0-15.7 22.9-35.6 58.3-50.6 8.6-3.7 18-7 27.7-10.1 5.7 19.6 13.2 40 22.5 60.9-9.2 20.8-16.6 41.1-22.2 60.6-9.9-3.1-19.3-6.5-28-10.2zM310 490c-13.6-7.8-19.5-37.5-14.9-75.7 1.1-9.4 2.9-19.3 5.1-29.4 19.6 4.8 41 8.5 63.5 10.9 13.5 18.5 27.5 35.3 41.6 50-32.6 30.3-63.2 46.9-84 46.9-4.5-.1-8.3-1-11.3-2.7zm237.2-76.2c4.7 38.2-1.1 67.9-14.6 75.8-3 1.8-6.9 2.6-11.5 2.6-20.7 0-51.4-16.5-84-46.6 14-14.7 28-31.4 41.3-49.9 22.6-2.4 44-6.1 63.6-11 2.3 10.1 4.1 19.8 5.2 29.1zm38.5-66.7c-8.6 3.7-18 7-27.7 10.1-5.7-19.6-13.2-40-22.5-60.9 9.2-20.8 16.6-41.1 22.2-60.6 9.9 3.1 19.3 6.5 28.1 10.2 35.4 15.1 58.3 34.9 58.3 50.6-.1 15.7-23 35.6-58.4 50.6zM320.8 78.4z"/><circle cx="420.9" cy="296.5" r="45.7"/><path d="M520.5 78.1z"/></g></svg>';
|
||||
|
||||
const sources = {
|
||||
animatedGif: {
|
||||
uri:
|
||||
'http://38.media.tumblr.com/9e9bd08c6e2d10561dd1fb4197df4c4e/tumblr_mfqekpMktw1rn90umo1_500.gif'
|
||||
},
|
||||
broken: { uri: 'http://TYPO_ERROR.github.io/image.png' },
|
||||
small: { uri: 'http://facebook.github.io/react/img/logo_small_2x.png' },
|
||||
large: { uri: 'http://facebook.github.io/react/img/logo_og.png' },
|
||||
largeAlt: { uri: 'http://facebook.github.io/origami/public/images/birds.jpg' },
|
||||
placeholder,
|
||||
prefetchable: { uri: 'http://origami.design/public/images/bird-logo.png' },
|
||||
static: staticImage,
|
||||
huge: {
|
||||
uri: 'https://upload.wikimedia.org/wikipedia/commons/d/d7/Chestnut-mandibled_Toucan.jpg'
|
||||
},
|
||||
dataPng,
|
||||
dataSvg
|
||||
};
|
||||
|
||||
export default sources;
|
||||
|
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 |
78
docs/storybook/1-components/ProgressBar/ProgressDocs.js
Normal file
78
docs/storybook/1-components/ProgressBar/ProgressDocs.js
Normal file
@@ -0,0 +1,78 @@
|
||||
/**
|
||||
* @flow
|
||||
*/
|
||||
|
||||
import PropColor from './examples/PropColor';
|
||||
import CustomSize from './examples/CustomSize';
|
||||
import PropIndeterminate from './examples/PropIndeterminate';
|
||||
import PropProgress from './examples/PropProgress';
|
||||
import PropTrackColor from './examples/PropTrackColor';
|
||||
import React from 'react';
|
||||
import { storiesOf } from '@kadira/storybook';
|
||||
import UIExplorer, { DocItem } from '../../ui-explorer';
|
||||
|
||||
const sections = [
|
||||
{
|
||||
title: 'Props',
|
||||
entries: [
|
||||
<DocItem name="...View props" />,
|
||||
|
||||
<DocItem
|
||||
description="Color of the progress bar."
|
||||
example={{
|
||||
render: () => <PropColor />
|
||||
}}
|
||||
name="color"
|
||||
typeInfo="?string = #1976D2"
|
||||
/>,
|
||||
|
||||
<DocItem
|
||||
description="Whether the progress bar will show indeterminate progress."
|
||||
example={{
|
||||
render: () => <PropIndeterminate />
|
||||
}}
|
||||
name="indeterminate"
|
||||
typeInfo="?boolean = true"
|
||||
/>,
|
||||
|
||||
<DocItem
|
||||
description="The progress value (between 0 and 1)."
|
||||
example={{
|
||||
render: () => <PropProgress />
|
||||
}}
|
||||
name="progress"
|
||||
typeInfo="?number"
|
||||
/>,
|
||||
|
||||
<DocItem
|
||||
description="Color of the track bar."
|
||||
example={{
|
||||
render: () => <PropTrackColor />
|
||||
}}
|
||||
name="trackColor"
|
||||
typeInfo="?string = 'transparent'"
|
||||
/>
|
||||
]
|
||||
},
|
||||
{
|
||||
title: 'More examples',
|
||||
entries: [
|
||||
<DocItem
|
||||
description="Custom sizes can be created using styles"
|
||||
example={{
|
||||
code: '<ProgressBar style={{ borderRadius: 10, height: 10 }} trackColor="#D1E3F6" />',
|
||||
render: () => <CustomSize />
|
||||
}}
|
||||
/>
|
||||
]
|
||||
}
|
||||
];
|
||||
|
||||
storiesOf('Components', module).add('ProgressBar', () =>
|
||||
<UIExplorer
|
||||
description="Display an activity progress bar"
|
||||
sections={sections}
|
||||
title="ProgressBar"
|
||||
url="components/ProgressBar"
|
||||
/>
|
||||
);
|
||||
@@ -0,0 +1,27 @@
|
||||
/**
|
||||
* @flow
|
||||
*/
|
||||
|
||||
import { DividerVertical } from '../helpers';
|
||||
import React from 'react';
|
||||
import { ProgressBar, StyleSheet, View } from 'react-native';
|
||||
|
||||
const ProgressBarCustomSizeExample = () =>
|
||||
<View>
|
||||
<ProgressBar color="#1DA1F2" progress={0.33} style={styles.one} trackColor="#D1E3F6" />
|
||||
<DividerVertical />
|
||||
<ProgressBar color="#1DA1F2" progress={0.33} style={styles.two} trackColor="#D1E3F6" />
|
||||
</View>;
|
||||
|
||||
const styles = StyleSheet.create({
|
||||
one: {
|
||||
borderRadius: 10,
|
||||
height: 10
|
||||
},
|
||||
two: {
|
||||
borderRadius: 10,
|
||||
height: 20
|
||||
}
|
||||
});
|
||||
|
||||
export default ProgressBarCustomSizeExample;
|
||||
@@ -0,0 +1,22 @@
|
||||
/**
|
||||
* @flow
|
||||
*/
|
||||
|
||||
import React from 'react';
|
||||
import { DividerVertical } from '../helpers';
|
||||
import { ProgressBar, View } from 'react-native';
|
||||
|
||||
const ProgressBarColorExample = () =>
|
||||
<View>
|
||||
<ProgressBar color="#1DA1F2" progress={0.2} />
|
||||
<DividerVertical />
|
||||
<ProgressBar color="#17BF63" progress={0.4} />
|
||||
<DividerVertical />
|
||||
<ProgressBar color="#F45D22" progress={0.6} />
|
||||
<DividerVertical />
|
||||
<ProgressBar color="#794BC4" progress={0.8} />
|
||||
<DividerVertical />
|
||||
<ProgressBar color="#E0245E" progress={1.0} />
|
||||
</View>;
|
||||
|
||||
export default ProgressBarColorExample;
|
||||
@@ -0,0 +1,10 @@
|
||||
/**
|
||||
* @flow
|
||||
*/
|
||||
|
||||
import React from 'react';
|
||||
import { ProgressBar } from 'react-native';
|
||||
|
||||
const ProgressBarIndeterminateExample = () => <ProgressBar indeterminate trackColor="#D1E3F6" />;
|
||||
|
||||
export default ProgressBarIndeterminateExample;
|
||||
@@ -0,0 +1,48 @@
|
||||
/**
|
||||
* @flow
|
||||
*/
|
||||
|
||||
import { DividerVertical } from '../helpers';
|
||||
import React, { PureComponent } from 'react';
|
||||
import { ProgressBar, StyleSheet, View } from 'react-native';
|
||||
|
||||
class ProgressBarProgressExample extends PureComponent {
|
||||
state = { progress: 0 };
|
||||
|
||||
componentDidMount() {
|
||||
this._updateProgress();
|
||||
}
|
||||
|
||||
componentWillUnmount() {
|
||||
window.cancelAnimationFrame(this._frame);
|
||||
}
|
||||
|
||||
render() {
|
||||
return (
|
||||
<View>
|
||||
<ProgressBar color="#794BC4" progress={0.2} style={styles.progress} />
|
||||
<DividerVertical />
|
||||
<ProgressBar color="#794BC4" progress={this._getProgress(0.2)} style={styles.progress} />
|
||||
</View>
|
||||
);
|
||||
}
|
||||
|
||||
_getProgress(offset) {
|
||||
const progress = this.state.progress + offset;
|
||||
return Math.sin(progress % Math.PI) % 1;
|
||||
}
|
||||
|
||||
_updateProgress() {
|
||||
const progress = this.state.progress + 0.01;
|
||||
this.setState(() => ({ progress }));
|
||||
this._frame = window.requestAnimationFrame(() => this._updateProgress());
|
||||
}
|
||||
}
|
||||
|
||||
const styles = StyleSheet.create({
|
||||
progress: {
|
||||
minWidth: 200
|
||||
}
|
||||
});
|
||||
|
||||
export default ProgressBarProgressExample;
|
||||
@@ -0,0 +1,18 @@
|
||||
/**
|
||||
* @flow
|
||||
*/
|
||||
|
||||
import { DividerVertical } from '../helpers';
|
||||
import React from 'react';
|
||||
import { ProgressBar, View } from 'react-native';
|
||||
|
||||
const ProgressBarTrackColorExample = () =>
|
||||
<View>
|
||||
<ProgressBar color="#1DA1F2" progress={0.1} trackColor="#17BF63" />
|
||||
<DividerVertical />
|
||||
<ProgressBar color="#1DA1F2" progress={0.2} trackColor="#F45D22" />
|
||||
<DividerVertical />
|
||||
<ProgressBar color="#1DA1F2" progress={0.3} trackColor="#794BC4" />
|
||||
</View>;
|
||||
|
||||
export default ProgressBarTrackColorExample;
|
||||
20
docs/storybook/1-components/ProgressBar/helpers.js
Normal file
20
docs/storybook/1-components/ProgressBar/helpers.js
Normal file
@@ -0,0 +1,20 @@
|
||||
/**
|
||||
* @flow
|
||||
*/
|
||||
|
||||
import React from 'react';
|
||||
import { StyleSheet, View } from 'react-native';
|
||||
|
||||
const DividerHorizontal = () => <View style={styles.horizontalDivider} />;
|
||||
const DividerVertical = () => <View style={styles.verticalDivider} />;
|
||||
|
||||
const styles = StyleSheet.create({
|
||||
horizontalDivider: {
|
||||
width: '0.6rem'
|
||||
},
|
||||
verticalDivider: {
|
||||
height: '1.3125rem'
|
||||
}
|
||||
});
|
||||
|
||||
export { DividerHorizontal, DividerVertical };
|
||||
172
docs/storybook/1-components/ScrollView/ScrollViewDocs.js
Normal file
172
docs/storybook/1-components/ScrollView/ScrollViewDocs.js
Normal file
@@ -0,0 +1,172 @@
|
||||
/* eslint-disable react/jsx-no-bind, react/jsx-sort-props */
|
||||
|
||||
/**
|
||||
* @flow
|
||||
*/
|
||||
|
||||
import { HorizontalExample } from './examples/Horizontal';
|
||||
import ScrollToExample from './examples/ScrollTo';
|
||||
import ScrollToEndExample from './examples/ScrollToEnd';
|
||||
import React from 'react';
|
||||
import { storiesOf } from '@kadira/storybook';
|
||||
import UIExplorer, { AppText, Code, DocItem, TextList } from '../../ui-explorer';
|
||||
|
||||
const sections = [
|
||||
{
|
||||
title: 'Props',
|
||||
entries: [
|
||||
<DocItem name="...View props" />,
|
||||
|
||||
<DocItem
|
||||
name="contentContainerStyle"
|
||||
typeInfo="?style"
|
||||
description="These styles will be applied to the scroll view content container which wraps all of the child views."
|
||||
/>,
|
||||
|
||||
<DocItem
|
||||
name="horizontal"
|
||||
typeInfo="?boolean = false"
|
||||
description="When `true`, the scroll view's children are arranged horizontally in a row instead of vertically in a column."
|
||||
example={{
|
||||
render: () => <HorizontalExample />
|
||||
}}
|
||||
/>,
|
||||
|
||||
<DocItem
|
||||
name="keyboardDismissMode"
|
||||
typeInfo="?enum('none', 'on-drag') = 'none'"
|
||||
description={[
|
||||
<AppText>
|
||||
Determines whether the keyboard gets dismissed in response to a scroll drag.
|
||||
</AppText>,
|
||||
<TextList
|
||||
items={[
|
||||
'`none` (the default), drags do not dismiss the keyboard.',
|
||||
'`on-drag`, the keyboard is dismissed when a drag begins.',
|
||||
'`interactive` (not supported on web; same as `none`)'
|
||||
]}
|
||||
/>
|
||||
]}
|
||||
/>,
|
||||
|
||||
<DocItem
|
||||
name="onContentSizeChange"
|
||||
typeInfo="?function"
|
||||
description={
|
||||
<AppText>
|
||||
Called when scrollable content view of the <Code>ScrollView</Code>
|
||||
changes. It's implemented using the <Code>onLayout</Code> handler
|
||||
attached to the content container which this <Code>ScrollView</Code> renders.
|
||||
</AppText>
|
||||
}
|
||||
/>,
|
||||
|
||||
<DocItem
|
||||
name="onScroll"
|
||||
typeInfo="?function"
|
||||
description={[
|
||||
<AppText>
|
||||
Fires at most once per frame during scrolling. The frequency of the events can
|
||||
be contolled using the <Code>scrollEventThrottle</Code> prop.
|
||||
</AppText>,
|
||||
<AppText>
|
||||
Invoked on scroll with the following event:
|
||||
</AppText>,
|
||||
<Code>{`{
|
||||
nativeEvent: {
|
||||
contentOffset: { x, y },
|
||||
contentSize: { height, width },
|
||||
layoutMeasurement: { height, width }
|
||||
}
|
||||
}`}</Code>
|
||||
]}
|
||||
/>,
|
||||
|
||||
<DocItem
|
||||
name="scrollEnabled"
|
||||
typeInfo="?boolean = true"
|
||||
description="When false, the content does not scroll."
|
||||
/>,
|
||||
|
||||
<DocItem
|
||||
name="scrollEventThrottle"
|
||||
typeInfo="?number = 0"
|
||||
description={
|
||||
<AppText>
|
||||
This controls how often the scroll event will be fired while scrolling (as a
|
||||
time interval in ms). A lower number yields better accuracy for code that is
|
||||
tracking the scroll position, but can lead to scroll performance problems. The
|
||||
default value is <Code>0</Code>, which means the scroll event will be sent only once
|
||||
each
|
||||
time the view is scrolled.
|
||||
</AppText>
|
||||
}
|
||||
/>
|
||||
]
|
||||
},
|
||||
{
|
||||
title: 'Instance methods',
|
||||
entries: [
|
||||
<DocItem
|
||||
name="getInnerViewNode"
|
||||
typeInfo="() => node"
|
||||
description="Returns a reference to the underlying content container DOM node within the ScrollView."
|
||||
/>,
|
||||
|
||||
<DocItem
|
||||
name="getScrollableNode"
|
||||
typeInfo="() => node"
|
||||
description="Returns a reference to the underlying scrollable DOM node."
|
||||
/>,
|
||||
|
||||
<DocItem
|
||||
name="getScrollResponder"
|
||||
typeInfo="() => ScrollResponder"
|
||||
description={
|
||||
<AppText>
|
||||
Returns a reference to the underlying scroll responder, which supports
|
||||
operations like <Code>scrollTo</Code>. All <Code>ScrollView</Code>-like components
|
||||
should implement
|
||||
this method so that they can be composed while providing access to the
|
||||
underlying scroll responder's methods.
|
||||
</AppText>
|
||||
}
|
||||
/>,
|
||||
|
||||
<DocItem
|
||||
name="scrollTo"
|
||||
typeInfo="(options: { x: number = 0; y: number = 0; animated: boolean = true }) => void"
|
||||
description="Scrolls to a given `x`, `y` offset (animation is not currently supported)."
|
||||
example={{
|
||||
render: () => <ScrollToExample />
|
||||
}}
|
||||
/>,
|
||||
|
||||
<DocItem
|
||||
name="scrollToEnd"
|
||||
typeInfo="(options: { animated: boolean = true }) => void"
|
||||
description="Scrolls to the end of the scroll view."
|
||||
example={{
|
||||
render: () => <ScrollToEndExample />
|
||||
}}
|
||||
/>
|
||||
]
|
||||
}
|
||||
];
|
||||
|
||||
storiesOf('Components', module).add('ScrollView', () =>
|
||||
<UIExplorer
|
||||
description={
|
||||
<AppText>
|
||||
A scrollable <Code>View</Code> that provides itegration with the touch-locking responder
|
||||
system. <Code>ScrollView</Code>'s
|
||||
must have a bounded height: either set the height of the view directly (discouraged) or make
|
||||
sure all parent views have
|
||||
bounded height (e.g., transfer <Code>{'{ flex: 1}'}</Code> down the view stack).
|
||||
</AppText>
|
||||
}
|
||||
sections={sections}
|
||||
title="ScrollView"
|
||||
url="components/ScrollView"
|
||||
/>
|
||||
);
|
||||
@@ -0,0 +1,65 @@
|
||||
/* eslint-disable react/jsx-no-bind */
|
||||
|
||||
/**
|
||||
* @flow
|
||||
*/
|
||||
|
||||
import React from 'react';
|
||||
import { action } from '@kadira/storybook';
|
||||
import { ScrollView, StyleSheet, Text, View } from 'react-native';
|
||||
|
||||
const onScroll = action('ScrollView.onScroll');
|
||||
|
||||
const VerticalExample = () =>
|
||||
<View style={styles.scrollViewContainer}>
|
||||
<ScrollView
|
||||
contentContainerStyle={styles.scrollViewContentContainerStyle}
|
||||
onScroll={onScroll}
|
||||
scrollEventThrottle={16} // ~60 events per second
|
||||
style={styles.scrollViewStyle}
|
||||
>
|
||||
{Array.from({ length: 50 }).map((item, i) =>
|
||||
<View key={i} style={[styles.box, styles.horizontalBox]}>
|
||||
<Text>{i}</Text>
|
||||
</View>
|
||||
)}
|
||||
</ScrollView>
|
||||
</View>;
|
||||
|
||||
const HorizontalExample = () =>
|
||||
<View style={styles.scrollViewContainer}>
|
||||
<ScrollView
|
||||
contentContainerStyle={styles.scrollViewContentContainerStyle}
|
||||
horizontal
|
||||
onScroll={onScroll}
|
||||
scrollEventThrottle={16} // ~60 events per second
|
||||
style={styles.scrollViewStyle}
|
||||
>
|
||||
{Array.from({ length: 50 }).map((item, i) =>
|
||||
<View key={i} style={[styles.box, styles.horizontalBox]}>
|
||||
<Text>{i}</Text>
|
||||
</View>
|
||||
)}
|
||||
</ScrollView>
|
||||
</View>;
|
||||
|
||||
export { HorizontalExample, VerticalExample };
|
||||
|
||||
const styles = StyleSheet.create({
|
||||
box: {
|
||||
flexGrow: 1,
|
||||
justifyContent: 'center',
|
||||
borderWidth: 1
|
||||
},
|
||||
scrollViewContainer: {
|
||||
height: 200,
|
||||
width: 300
|
||||
},
|
||||
scrollViewStyle: {
|
||||
borderWidth: 1
|
||||
},
|
||||
scrollViewContentContainerStyle: {
|
||||
backgroundColor: '#eee',
|
||||
padding: 10
|
||||
}
|
||||
});
|
||||
57
docs/storybook/1-components/ScrollView/examples/ScrollTo.js
Normal file
57
docs/storybook/1-components/ScrollView/examples/ScrollTo.js
Normal file
@@ -0,0 +1,57 @@
|
||||
/* eslint-disable react/jsx-no-bind */
|
||||
|
||||
/**
|
||||
* @flow
|
||||
*/
|
||||
|
||||
import React, { PureComponent } from 'react';
|
||||
import { Button, ScrollView, StyleSheet, Text, View } from 'react-native';
|
||||
|
||||
export default class ScrollToExample extends PureComponent {
|
||||
render() {
|
||||
return (
|
||||
<View style={styles.scrollViewContainer}>
|
||||
<ScrollView
|
||||
contentContainerStyle={styles.scrollViewContentContainerStyle}
|
||||
ref={scrollview => {
|
||||
this.scrollview = scrollview;
|
||||
}}
|
||||
scrollEventThrottle={16} // ~60 events per second
|
||||
style={styles.scrollViewStyle}
|
||||
>
|
||||
{Array.from({ length: 50 }).map((item, i) =>
|
||||
<View key={i} style={[styles.box, styles.horizontalBox]}>
|
||||
<Text>{i}</Text>
|
||||
</View>
|
||||
)}
|
||||
</ScrollView>
|
||||
<Button
|
||||
onPress={() => {
|
||||
this.scrollview.scrollTo({ y: 100 });
|
||||
}}
|
||||
title="Scroll to 100px"
|
||||
/>
|
||||
</View>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
const styles = StyleSheet.create({
|
||||
box: {
|
||||
flexGrow: 1,
|
||||
justifyContent: 'center',
|
||||
borderWidth: 1
|
||||
},
|
||||
scrollViewContainer: {
|
||||
height: 150,
|
||||
width: 300
|
||||
},
|
||||
scrollViewStyle: {
|
||||
borderWidth: 1,
|
||||
marginBottom: '1.3125rem'
|
||||
},
|
||||
scrollViewContentContainerStyle: {
|
||||
backgroundColor: '#eee',
|
||||
padding: 10
|
||||
}
|
||||
});
|
||||
@@ -0,0 +1,57 @@
|
||||
/* eslint-disable react/jsx-no-bind */
|
||||
|
||||
/**
|
||||
* @flow
|
||||
*/
|
||||
|
||||
import React, { PureComponent } from 'react';
|
||||
import { Button, ScrollView, StyleSheet, Text, View } from 'react-native';
|
||||
|
||||
export default class ScrollToEndExample extends PureComponent {
|
||||
render() {
|
||||
return (
|
||||
<View style={styles.scrollViewContainer}>
|
||||
<ScrollView
|
||||
contentContainerStyle={styles.scrollViewContentContainerStyle}
|
||||
ref={scrollview => {
|
||||
this.scrollview = scrollview;
|
||||
}}
|
||||
scrollEventThrottle={16} // ~60 events per second
|
||||
style={styles.scrollViewStyle}
|
||||
>
|
||||
{Array.from({ length: 50 }).map((item, i) =>
|
||||
<View key={i} style={[styles.box, styles.horizontalBox]}>
|
||||
<Text>{i}</Text>
|
||||
</View>
|
||||
)}
|
||||
</ScrollView>
|
||||
<Button
|
||||
onPress={() => {
|
||||
this.scrollview.scrollToEnd();
|
||||
}}
|
||||
title="Scroll to end"
|
||||
/>
|
||||
</View>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
const styles = StyleSheet.create({
|
||||
box: {
|
||||
flexGrow: 1,
|
||||
justifyContent: 'center',
|
||||
borderWidth: 1
|
||||
},
|
||||
scrollViewContainer: {
|
||||
height: 150,
|
||||
width: 300
|
||||
},
|
||||
scrollViewStyle: {
|
||||
borderWidth: 1,
|
||||
marginBottom: '1.3125rem'
|
||||
},
|
||||
scrollViewContentContainerStyle: {
|
||||
backgroundColor: '#eee',
|
||||
padding: 10
|
||||
}
|
||||
});
|
||||
139
docs/storybook/1-components/Switch/SwitchDocs.js
Normal file
139
docs/storybook/1-components/Switch/SwitchDocs.js
Normal file
@@ -0,0 +1,139 @@
|
||||
/* eslint-disable react/jsx-sort-props */
|
||||
|
||||
/**
|
||||
* @flow
|
||||
*/
|
||||
|
||||
import CustomSize from './examples/CustomSize';
|
||||
import PropActiveThumbColor from './examples/PropActiveThumbColor';
|
||||
import PropActiveTrackColor from './examples/PropActiveTrackColor';
|
||||
import PropDisabled from './examples/PropDisabled';
|
||||
import PropOnValueChange from './examples/PropOnValueChange';
|
||||
import PropThumbColor from './examples/PropThumbColor';
|
||||
import PropTrackColor from './examples/PropTrackColor';
|
||||
import PropValue from './examples/PropValue';
|
||||
import React from 'react';
|
||||
import { storiesOf } from '@kadira/storybook';
|
||||
import UIExplorer, { AppText, Code, DocItem } from '../../ui-explorer';
|
||||
|
||||
const sections = [
|
||||
{
|
||||
title: 'Props',
|
||||
entries: [
|
||||
<DocItem name="...View props" />,
|
||||
|
||||
<DocItem
|
||||
description="The color of the thumb grip when the switch is turned on."
|
||||
example={{
|
||||
render: () => <PropActiveThumbColor />
|
||||
}}
|
||||
name="activeThumbColor"
|
||||
typeInfo="?color = #009688"
|
||||
/>,
|
||||
|
||||
<DocItem
|
||||
description="The color of the track when the switch is turned on."
|
||||
example={{
|
||||
render: () => <PropActiveTrackColor />
|
||||
}}
|
||||
name="activeTrackColor"
|
||||
typeInfo="?color = #A3D3CF"
|
||||
/>,
|
||||
|
||||
<DocItem
|
||||
description="If `true` the user won't be able to interact with the switch."
|
||||
example={{
|
||||
render: () => <PropDisabled />
|
||||
}}
|
||||
name="disabled"
|
||||
typeInfo="?boolean = false"
|
||||
/>,
|
||||
|
||||
<DocItem
|
||||
description="Invoked with the new value when the value changes."
|
||||
example={{
|
||||
render: () => <PropOnValueChange />
|
||||
}}
|
||||
name="onValueChange"
|
||||
typeInfo="?function"
|
||||
/>,
|
||||
|
||||
<DocItem
|
||||
description="The color of the thumb grip when the switch is turned off."
|
||||
example={{
|
||||
render: () => <PropThumbColor />
|
||||
}}
|
||||
name="thumbColor"
|
||||
typeInfo="?color = #FAFAFA"
|
||||
/>,
|
||||
|
||||
<DocItem
|
||||
description="The color of the track when the switch is turned off."
|
||||
example={{
|
||||
render: () => <PropTrackColor />
|
||||
}}
|
||||
name="trackColor"
|
||||
typeInfo="?color = #939393"
|
||||
/>,
|
||||
|
||||
<DocItem
|
||||
description="The value of the switch. If `true` the switch will be turned on."
|
||||
example={{
|
||||
render: () => <PropValue />
|
||||
}}
|
||||
name="value"
|
||||
typeInfo="?boolean = false"
|
||||
/>,
|
||||
|
||||
<DocItem
|
||||
description="(For compatibility with React Native. Equivalent to "activeTrackColor")"
|
||||
label="compat"
|
||||
name="onTintColor"
|
||||
typeInfo="?color"
|
||||
/>,
|
||||
|
||||
<DocItem
|
||||
description="(For compatibility with React Native. Equivalent to "trackColor")"
|
||||
label="compat"
|
||||
name="tintColor"
|
||||
typeInfo="?color"
|
||||
/>,
|
||||
|
||||
<DocItem
|
||||
description="(For compatibility with React Native. Equivalent to "thumbColor")"
|
||||
label="compat"
|
||||
name="thumbTintColor"
|
||||
typeInfo="?color"
|
||||
/>
|
||||
]
|
||||
},
|
||||
|
||||
{
|
||||
title: 'More examples',
|
||||
entries: [
|
||||
<DocItem
|
||||
description="Custom sizes can be created using styles"
|
||||
example={{
|
||||
code: '<Switch style={{ height: 30 }} />',
|
||||
render: () => <CustomSize />
|
||||
}}
|
||||
/>
|
||||
]
|
||||
}
|
||||
];
|
||||
|
||||
storiesOf('Components', module).add('Switch', () =>
|
||||
<UIExplorer
|
||||
description={
|
||||
<AppText>
|
||||
This is a controlled component that requires an <Code>onValueChange</Code> callback
|
||||
that updates the value prop in order for the component to reflect user actions. If
|
||||
the <Code>value</Code> prop is not updated, the component will continue to render the
|
||||
supplied <Code>value</Code> prop instead of the expected result of any user actions.
|
||||
</AppText>
|
||||
}
|
||||
sections={sections}
|
||||
title="Switch"
|
||||
url="components/Switch"
|
||||
/>
|
||||
);
|
||||
42
docs/storybook/1-components/Switch/examples/CustomSize.js
Normal file
42
docs/storybook/1-components/Switch/examples/CustomSize.js
Normal file
@@ -0,0 +1,42 @@
|
||||
/**
|
||||
* @flow
|
||||
*/
|
||||
|
||||
import React, { PureComponent } from 'react';
|
||||
import { Switch, View } from 'react-native';
|
||||
|
||||
class CustomSizeExample extends PureComponent {
|
||||
state = {
|
||||
firstIsOn: true,
|
||||
secondIsOn: false
|
||||
};
|
||||
|
||||
render() {
|
||||
const { firstIsOn, secondIsOn } = this.state;
|
||||
|
||||
return (
|
||||
<View>
|
||||
<Switch
|
||||
onValueChange={this._handleFirst}
|
||||
style={{ marginBottom: 10, height: 30 }}
|
||||
value={firstIsOn}
|
||||
/>
|
||||
<Switch
|
||||
onValueChange={this._handleSecond}
|
||||
style={{ height: 30, width: 150 }}
|
||||
value={secondIsOn}
|
||||
/>
|
||||
</View>
|
||||
);
|
||||
}
|
||||
|
||||
_handleFirst = value => {
|
||||
this.setState({ firstIsOn: value });
|
||||
};
|
||||
|
||||
_handleSecond = value => {
|
||||
this.setState({ secondIsOn: value });
|
||||
};
|
||||
}
|
||||
|
||||
export default CustomSizeExample;
|
||||
@@ -0,0 +1,24 @@
|
||||
/**
|
||||
* @flow
|
||||
*/
|
||||
|
||||
import React from 'react';
|
||||
import { styles } from '../helpers';
|
||||
import { Switch, View } from 'react-native';
|
||||
|
||||
const colors = ['#1DA1F2', '#17BF63', '#F45D22', '#794BC4', '#E0245E'];
|
||||
const itemStyle = [styles.marginVertical, styles.marginRight];
|
||||
|
||||
const SwitchActiveThumbColorExample = () =>
|
||||
<View style={styles.row}>
|
||||
<View style={itemStyle}>
|
||||
<Switch value={true} />
|
||||
</View>
|
||||
{colors.map((color, i) =>
|
||||
<View key={i} style={itemStyle}>
|
||||
<Switch activeThumbColor={color} activeTrackColor="#ccc" value={true} />
|
||||
</View>
|
||||
)}
|
||||
</View>;
|
||||
|
||||
export default SwitchActiveThumbColorExample;
|
||||
@@ -0,0 +1,24 @@
|
||||
/**
|
||||
* @flow
|
||||
*/
|
||||
|
||||
import React from 'react';
|
||||
import { styles } from '../helpers';
|
||||
import { Switch, View } from 'react-native';
|
||||
|
||||
const colors = ['#1DA1F2', '#17BF63', '#F45D22', '#794BC4', '#E0245E'];
|
||||
const itemStyle = [styles.marginVertical, styles.marginRight];
|
||||
|
||||
const SwitchActiveTrackColorExample = () =>
|
||||
<View style={styles.row}>
|
||||
<View style={itemStyle}>
|
||||
<Switch value={true} />
|
||||
</View>
|
||||
{colors.map((color, i) =>
|
||||
<View key={i} style={itemStyle}>
|
||||
<Switch activeThumbColor="#ccc" activeTrackColor={color} value={true} />
|
||||
</View>
|
||||
)}
|
||||
</View>;
|
||||
|
||||
export default SwitchActiveTrackColorExample;
|
||||
19
docs/storybook/1-components/Switch/examples/PropDisabled.js
Normal file
19
docs/storybook/1-components/Switch/examples/PropDisabled.js
Normal file
@@ -0,0 +1,19 @@
|
||||
/**
|
||||
* @flow
|
||||
*/
|
||||
|
||||
import React from 'react';
|
||||
import { styles } from '../helpers';
|
||||
import { Switch, View } from 'react-native';
|
||||
|
||||
const SwitchDisabledExample = () =>
|
||||
<View style={styles.row}>
|
||||
<View style={styles.marginRight}>
|
||||
<Switch disabled={true} value={false} />
|
||||
</View>
|
||||
<View style={styles.marginRight}>
|
||||
<Switch disabled={true} value={true} />
|
||||
</View>
|
||||
</View>;
|
||||
|
||||
export default SwitchDisabledExample;
|
||||
@@ -0,0 +1,59 @@
|
||||
/**
|
||||
* @flow
|
||||
*/
|
||||
|
||||
import { styles } from '../helpers';
|
||||
import React, { PureComponent } from 'react';
|
||||
import { Switch, Text, View } from 'react-native';
|
||||
|
||||
class SwitchOnValueChangeExample extends PureComponent {
|
||||
state = {
|
||||
eventSwitchIsOn: false,
|
||||
eventSwitchRegressionIsOn: true
|
||||
};
|
||||
|
||||
render() {
|
||||
const { eventSwitchIsOn, eventSwitchRegressionIsOn } = this.state;
|
||||
|
||||
return (
|
||||
<View style={styles.row}>
|
||||
<View style={[styles.alignCenter, styles.marginRight]}>
|
||||
<Switch
|
||||
onValueChange={this._handleEventSwitch}
|
||||
style={styles.marginBottom}
|
||||
value={eventSwitchIsOn}
|
||||
/>
|
||||
<Switch
|
||||
onValueChange={this._handleEventSwitch}
|
||||
style={styles.marginBottom}
|
||||
value={eventSwitchIsOn}
|
||||
/>
|
||||
<Text>{eventSwitchIsOn ? 'On' : 'Off'}</Text>
|
||||
</View>
|
||||
<View style={styles.alignCenter}>
|
||||
<Switch
|
||||
onValueChange={this._handleEventSwitchRegression}
|
||||
style={styles.marginBottom}
|
||||
value={eventSwitchRegressionIsOn}
|
||||
/>
|
||||
<Switch
|
||||
onValueChange={this._handleEventSwitchRegression}
|
||||
style={styles.marginBottom}
|
||||
value={eventSwitchRegressionIsOn}
|
||||
/>
|
||||
<Text>{eventSwitchRegressionIsOn ? 'On' : 'Off'}</Text>
|
||||
</View>
|
||||
</View>
|
||||
);
|
||||
}
|
||||
|
||||
_handleEventSwitch = value => {
|
||||
this.setState({ eventSwitchIsOn: value });
|
||||
};
|
||||
|
||||
_handleEventSwitchRegression = value => {
|
||||
this.setState({ eventSwitchRegressionIsOn: value });
|
||||
};
|
||||
}
|
||||
|
||||
export default SwitchOnValueChangeExample;
|
||||
@@ -0,0 +1,24 @@
|
||||
/**
|
||||
* @flow
|
||||
*/
|
||||
|
||||
import React from 'react';
|
||||
import { styles } from '../helpers';
|
||||
import { Switch, View } from 'react-native';
|
||||
|
||||
const colors = ['#ddd', '#aaa', '#999', '#666', '#000'];
|
||||
const itemStyle = [styles.marginVertical, styles.marginRight];
|
||||
|
||||
const SwitchThumbColorExample = () =>
|
||||
<View style={styles.row}>
|
||||
<View style={itemStyle}>
|
||||
<Switch value={false} />
|
||||
</View>
|
||||
{colors.map((color, i) =>
|
||||
<View key={i} style={itemStyle}>
|
||||
<Switch thumbColor={color} value={false} />
|
||||
</View>
|
||||
)}
|
||||
</View>;
|
||||
|
||||
export default SwitchThumbColorExample;
|
||||
@@ -0,0 +1,24 @@
|
||||
/**
|
||||
* @flow
|
||||
*/
|
||||
|
||||
import React from 'react';
|
||||
import { styles } from '../helpers';
|
||||
import { Switch, View } from 'react-native';
|
||||
|
||||
const colors = ['#ddd', '#aaa', '#999', '#666', '#000'];
|
||||
const itemStyle = [styles.marginVertical, styles.marginRight];
|
||||
|
||||
const SwitchTrackColorExample = () =>
|
||||
<View style={styles.row}>
|
||||
<View style={itemStyle}>
|
||||
<Switch value={false} />
|
||||
</View>
|
||||
{colors.map((color, i) =>
|
||||
<View key={i} style={itemStyle}>
|
||||
<Switch trackColor={color} value={false} />
|
||||
</View>
|
||||
)}
|
||||
</View>;
|
||||
|
||||
export default SwitchTrackColorExample;
|
||||
19
docs/storybook/1-components/Switch/examples/PropValue.js
Normal file
19
docs/storybook/1-components/Switch/examples/PropValue.js
Normal file
@@ -0,0 +1,19 @@
|
||||
/**
|
||||
* @flow
|
||||
*/
|
||||
|
||||
import { styles } from '../helpers';
|
||||
import React from 'react';
|
||||
import { Switch, View } from 'react-native';
|
||||
|
||||
const SwitchValueExample = () =>
|
||||
<View style={styles.row}>
|
||||
<View style={styles.marginRight}>
|
||||
<Switch value={false} />
|
||||
</View>
|
||||
<View style={styles.marginRight}>
|
||||
<Switch value={true} />
|
||||
</View>
|
||||
</View>;
|
||||
|
||||
export default SwitchValueExample;
|
||||
36
docs/storybook/1-components/Switch/helpers.js
Normal file
36
docs/storybook/1-components/Switch/helpers.js
Normal file
@@ -0,0 +1,36 @@
|
||||
/**
|
||||
* @flow
|
||||
*/
|
||||
|
||||
import React from 'react';
|
||||
import { StyleSheet, View } from 'react-native';
|
||||
|
||||
const DividerHorizontal = () => <View style={styles.horizontalDivider} />;
|
||||
const DividerVertical = () => <View style={styles.verticalDivider} />;
|
||||
|
||||
export const styles = StyleSheet.create({
|
||||
horizontalDivider: {
|
||||
width: '0.6rem'
|
||||
},
|
||||
verticalDivider: {
|
||||
height: '1.3125rem'
|
||||
},
|
||||
row: {
|
||||
flexDirection: 'row',
|
||||
flexWrap: 'wrap'
|
||||
},
|
||||
marginRight: {
|
||||
marginRight: 10
|
||||
},
|
||||
marginBottom: {
|
||||
marginBottom: 10
|
||||
},
|
||||
marginVertical: {
|
||||
marginVertical: 5
|
||||
},
|
||||
alignCenter: {
|
||||
alignItems: 'center'
|
||||
}
|
||||
});
|
||||
|
||||
export { DividerHorizontal, DividerVertical };
|
||||
265
docs/storybook/1-components/Text/TextDocs.js
Normal file
265
docs/storybook/1-components/Text/TextDocs.js
Normal file
@@ -0,0 +1,265 @@
|
||||
/* eslint-disable react/jsx-sort-props */
|
||||
|
||||
/**
|
||||
* @flow
|
||||
*/
|
||||
|
||||
import PropChildren from './examples/PropChildren';
|
||||
import PropNumberOfLines from './examples/PropNumberOfLines';
|
||||
import PropOnPress from './examples/PropOnPress';
|
||||
import React from 'react';
|
||||
import { storiesOf } from '@kadira/storybook';
|
||||
import UIExplorer, { AppText, Code, DocItem, StyleList } from '../../ui-explorer';
|
||||
|
||||
const stylePropTypes = [
|
||||
{
|
||||
name: '...View#style'
|
||||
},
|
||||
{
|
||||
name: 'color',
|
||||
typeInfo: 'color'
|
||||
},
|
||||
{
|
||||
name: 'fontFamily',
|
||||
typeInfo: 'string'
|
||||
},
|
||||
{
|
||||
label: 'web',
|
||||
name: 'fontFeatureSettings',
|
||||
typeInfo: 'string'
|
||||
},
|
||||
{
|
||||
name: 'fontSize',
|
||||
typeInfo: 'number | string'
|
||||
},
|
||||
{
|
||||
name: 'fontStyle',
|
||||
typeInfo: 'string'
|
||||
},
|
||||
{
|
||||
name: 'fontWeight',
|
||||
typeInfo: 'string'
|
||||
},
|
||||
{
|
||||
name: 'letterSpacing',
|
||||
typeInfo: 'string'
|
||||
},
|
||||
{
|
||||
name: 'lineHeight',
|
||||
typeInfo: 'string'
|
||||
},
|
||||
{
|
||||
name: 'textAlign',
|
||||
typeInfo: 'string'
|
||||
},
|
||||
{
|
||||
name: 'textAlignVertical',
|
||||
typeInfo: 'string'
|
||||
},
|
||||
{
|
||||
name: 'textDecorationLine',
|
||||
typeInfo: 'string'
|
||||
},
|
||||
{
|
||||
label: 'web',
|
||||
name: 'textIndent',
|
||||
typeInfo: 'string'
|
||||
},
|
||||
{
|
||||
label: 'web',
|
||||
name: 'textOverflow',
|
||||
typeInfo: 'string'
|
||||
},
|
||||
{
|
||||
label: 'web',
|
||||
name: 'textRendering',
|
||||
typeInfo: 'string'
|
||||
},
|
||||
{
|
||||
name: 'textShadowColor',
|
||||
typeInfo: 'color'
|
||||
},
|
||||
{
|
||||
name: 'textShadowOffset',
|
||||
typeInfo: '{ height: number, width: number }'
|
||||
},
|
||||
{
|
||||
name: 'textShadowRadius',
|
||||
typeInfo: 'number | string'
|
||||
},
|
||||
{
|
||||
label: 'web',
|
||||
name: 'textTransform',
|
||||
typeInfo: 'string'
|
||||
},
|
||||
{
|
||||
label: 'web',
|
||||
name: 'unicodeBidi',
|
||||
typeInfo: 'string'
|
||||
},
|
||||
{
|
||||
name: 'whiteSpace',
|
||||
typeInfo: 'string'
|
||||
},
|
||||
{
|
||||
label: 'web',
|
||||
name: 'wordWrap',
|
||||
typeInfo: 'string'
|
||||
},
|
||||
{
|
||||
name: 'writingDirection',
|
||||
typeInfo: 'string'
|
||||
}
|
||||
];
|
||||
|
||||
const sections = [
|
||||
{
|
||||
title: 'Props',
|
||||
entries: [
|
||||
<DocItem
|
||||
name="accessibilityLabel"
|
||||
typeInfo="?string"
|
||||
description="Overrides the text that is read by a screen reader when the user interacts with the element. (This is implemented using 'aria-label'.)"
|
||||
/>,
|
||||
|
||||
<DocItem
|
||||
name="accessibilityLiveRegion"
|
||||
typeInfo="?enum('assertive', 'none', 'polite')"
|
||||
description={
|
||||
<AppText>
|
||||
Indicates to assistive technologies whether to notify the user when the view changes.
|
||||
The values of
|
||||
this attribute are expressed in degrees of importance. When regions are specified as{
|
||||
' '
|
||||
}
|
||||
<Code>polite</Code> (recommended),
|
||||
updates take low priority. When regions are specified as <Code>assertive</Code>,
|
||||
assistive technologies will
|
||||
interrupt and immediately notify the user. (This is implemented using 'aria-live'.)
|
||||
</AppText>
|
||||
}
|
||||
/>,
|
||||
|
||||
<DocItem
|
||||
label="web"
|
||||
name="accessibilityRole"
|
||||
typeInfo="?enum(roles)"
|
||||
description={
|
||||
<AppText>
|
||||
Allows assistive technologies to present and support interaction with the view in a
|
||||
manner that is
|
||||
consistent with user expectations for similar views of that type. For example, marking a
|
||||
touchable
|
||||
view with an <Code>accessibilityRole</Code> of <Code>button</Code>. For compatibility
|
||||
with React
|
||||
Native <Code>accessibilityTraits</Code> and <Code>accessibilityComponentType</Code> are
|
||||
mapped
|
||||
to <Code>accessibilityRole</Code>. (This is implemented using ARIA roles.)
|
||||
</AppText>
|
||||
}
|
||||
/>,
|
||||
|
||||
<DocItem
|
||||
name="accessible"
|
||||
typeInfo="?boolean"
|
||||
description={
|
||||
<AppText>
|
||||
When <Code>true</Code>, indicates that the view is an accessibility element (i.e.,
|
||||
focusable) and
|
||||
groups its child content. By default, all the touchable elements and elements
|
||||
with <Code>accessibilityRole</Code> of <Code>button</Code> and <Code>link</Code> are
|
||||
accessible.
|
||||
(This is implemented using 'tabindex'.)
|
||||
</AppText>
|
||||
}
|
||||
/>,
|
||||
|
||||
<DocItem
|
||||
name="children"
|
||||
typeInfo="?any"
|
||||
description={`Child content. 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.`}
|
||||
example={{
|
||||
code: '',
|
||||
render: () => <PropChildren />
|
||||
}}
|
||||
/>,
|
||||
|
||||
<DocItem
|
||||
name="importantForAccessibility"
|
||||
typeInfo="?enum('auto', 'no', 'no-hide-descendants', 'yes')"
|
||||
description={
|
||||
'A value of `no` will remove the element from the tab flow.\n\nA value of `no-hide-descendants` will hide the element and its children from assistive technologies. (This is implemented using `aria-hidden`.)'
|
||||
}
|
||||
/>,
|
||||
|
||||
<DocItem
|
||||
name="numberOfLines"
|
||||
typeInfo="?number"
|
||||
description="Truncates the text with an ellipsis after this many lines. Currently only supports `1`."
|
||||
example={{
|
||||
code: '',
|
||||
render: () => <PropNumberOfLines />
|
||||
}}
|
||||
/>,
|
||||
|
||||
<DocItem
|
||||
name="onLayout"
|
||||
typeInfo="?function"
|
||||
description="Invoked on mount and layout changes with `{ nativeEvent: { layout: { x, y, width, height } } }`, where `x` and `y` are the offsets from the parent node."
|
||||
/>,
|
||||
|
||||
<DocItem
|
||||
name="onPress"
|
||||
typeInfo="?function"
|
||||
description="Called when the Text is pressed"
|
||||
example={{
|
||||
code: '',
|
||||
render: () => <PropOnPress />
|
||||
}}
|
||||
/>,
|
||||
|
||||
<DocItem
|
||||
name="selectable"
|
||||
typeInfo="?boolean"
|
||||
description="When `false`, the text is not selectable."
|
||||
/>,
|
||||
|
||||
<DocItem
|
||||
name="style"
|
||||
typeInfo="?style"
|
||||
description={<StyleList stylePropTypes={stylePropTypes} />}
|
||||
/>,
|
||||
|
||||
<DocItem
|
||||
name="testID"
|
||||
typeInfo="?string"
|
||||
description="Used to locate this view in end-to-end tests. The test ID is rendered to a `data-testid` DOM attribute"
|
||||
/>
|
||||
]
|
||||
}
|
||||
];
|
||||
|
||||
storiesOf('Components', module).add('Text', () =>
|
||||
<UIExplorer
|
||||
description={[
|
||||
<AppText>
|
||||
Text is component for displaying text. It supports style, basic touch handling, and inherits
|
||||
typographic
|
||||
styles from ancestor elements.
|
||||
</AppText>,
|
||||
<AppText>
|
||||
Text is unique relative to layout: child elements use text layout ("inline") rather than
|
||||
flexbox layout.
|
||||
This means that elements inside of a Text are not rectangles, as they wrap when reaching the
|
||||
edge of
|
||||
their container.
|
||||
</AppText>,
|
||||
<AppText>NOTE: Text will transfer all other props to the rendered HTML element.</AppText>
|
||||
]}
|
||||
sections={sections}
|
||||
title="Text"
|
||||
url="components/Text"
|
||||
/>
|
||||
);
|
||||
66
docs/storybook/1-components/Text/examples/PropChildren.js
Normal file
66
docs/storybook/1-components/Text/examples/PropChildren.js
Normal file
@@ -0,0 +1,66 @@
|
||||
/* eslint-disable react/prop-types */
|
||||
|
||||
/**
|
||||
* @flow
|
||||
*/
|
||||
|
||||
import React from 'react';
|
||||
import { Image, Text, View } from 'react-native';
|
||||
|
||||
const Entity = ({ children }) =>
|
||||
<Text style={{ fontWeight: '500', color: '#527fe4' }}>
|
||||
{children}
|
||||
</Text>;
|
||||
|
||||
const TextChildrenExample = () =>
|
||||
<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>
|
||||
<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>
|
||||
|
||||
</View>;
|
||||
|
||||
export default TextChildrenExample;
|
||||
@@ -0,0 +1,27 @@
|
||||
/**
|
||||
* @flow
|
||||
*/
|
||||
|
||||
import React from 'react';
|
||||
import { Text, View } from 'react-native';
|
||||
|
||||
const TextNumberOfLinesExample = () =>
|
||||
<View style={{ maxWidth: 320 }}>
|
||||
<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>;
|
||||
|
||||
export default TextNumberOfLinesExample;
|
||||
10
docs/storybook/1-components/Text/examples/PropOnLayout.js
Normal file
10
docs/storybook/1-components/Text/examples/PropOnLayout.js
Normal file
@@ -0,0 +1,10 @@
|
||||
/**
|
||||
* @flow
|
||||
*/
|
||||
|
||||
import React from 'react';
|
||||
import { Text } from 'react-native';
|
||||
|
||||
const TextOnLayoutExample = () => <Text />;
|
||||
|
||||
export default TextOnLayoutExample;
|
||||
52
docs/storybook/1-components/Text/examples/PropOnPress.js
Normal file
52
docs/storybook/1-components/Text/examples/PropOnPress.js
Normal file
@@ -0,0 +1,52 @@
|
||||
/**
|
||||
* @flow
|
||||
*/
|
||||
|
||||
import React from 'react';
|
||||
import { StyleSheet, Text, View } from 'react-native';
|
||||
|
||||
class TextOnPressExample extends React.Component {
|
||||
state = { timesPressed: 0 };
|
||||
|
||||
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>
|
||||
);
|
||||
}
|
||||
|
||||
_handlePress = () => {
|
||||
this.setState({
|
||||
timesPressed: this.state.timesPressed + 1
|
||||
});
|
||||
};
|
||||
}
|
||||
|
||||
const styles = StyleSheet.create({
|
||||
logBox: {
|
||||
padding: 20,
|
||||
marginTop: 10,
|
||||
borderWidth: StyleSheet.hairlineWidth,
|
||||
borderColor: '#f0f0f0',
|
||||
backgroundColor: '#f9f9f9'
|
||||
},
|
||||
textBlock: {
|
||||
fontWeight: '500',
|
||||
color: 'blue'
|
||||
}
|
||||
});
|
||||
|
||||
export default TextOnPressExample;
|
||||
12
docs/storybook/1-components/Text/examples/PropSelectable.js
Normal file
12
docs/storybook/1-components/Text/examples/PropSelectable.js
Normal file
@@ -0,0 +1,12 @@
|
||||
/**
|
||||
* @flow
|
||||
*/
|
||||
|
||||
/*
|
||||
import React from 'react';
|
||||
import { View } from 'react-native';
|
||||
|
||||
const ViewStyleExample = () => null;
|
||||
|
||||
export default ViewStyleExample;
|
||||
*/
|
||||
@@ -1,44 +1,14 @@
|
||||
/* eslint-disable react/jsx-no-bind, react/prefer-es6-class, react/prop-types */
|
||||
|
||||
/**
|
||||
* 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 UIExplorer from '../../UIExplorer';
|
||||
import UIExplorer, { PropText, StyleList } from '../../ui-explorer';
|
||||
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 };
|
||||
@@ -267,48 +237,6 @@ const examples = [
|
||||
);
|
||||
}
|
||||
},
|
||||
{
|
||||
title: 'Nested',
|
||||
description:
|
||||
'Nested text components will inherit the styles of their ' +
|
||||
'parents (only backgroundColor is inherited from non-Text parents). ' +
|
||||
'<Text> only supports other <Text> and raw text (strings) as children.',
|
||||
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() {
|
||||
@@ -418,30 +346,6 @@ const examples = [
|
||||
);
|
||||
}
|
||||
},
|
||||
{
|
||||
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() {
|
||||
@@ -497,29 +401,6 @@ const examples = [
|
||||
);
|
||||
}
|
||||
},
|
||||
{
|
||||
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() {
|
||||
@@ -561,11 +442,4 @@ const examples = [
|
||||
}
|
||||
}
|
||||
];
|
||||
|
||||
storiesOf('Components', module).add('Text', () =>
|
||||
<UIExplorer
|
||||
examples={examples}
|
||||
title="Text"
|
||||
url="https://github.com/necolas/react-native-web/blob/master/docs/components/Text.md"
|
||||
/>
|
||||
);
|
||||
*/
|
||||
367
docs/storybook/1-components/TextInput/TextInputDocs.js
Normal file
367
docs/storybook/1-components/TextInput/TextInputDocs.js
Normal file
@@ -0,0 +1,367 @@
|
||||
/* eslint-disable react/jsx-sort-props */
|
||||
|
||||
/**
|
||||
* @flow
|
||||
*/
|
||||
|
||||
import PropAutoCapitalize from './examples/PropAutoCapitalize';
|
||||
import PropBlurOnSubmit from './examples/PropBlurOnSubmit';
|
||||
import PropClearTextOnFocus from './examples/PropClearTextOnFocus';
|
||||
import PropEditable from './examples/PropEditable';
|
||||
import PropKeyboardType from './examples/PropKeyboardType';
|
||||
import PropMaxLength from './examples/PropMaxLength';
|
||||
import PropMultiline from './examples/PropMultiline';
|
||||
import PropNumberOfLines from './examples/PropNumberOfLines';
|
||||
import PropOnSelectionChange from './examples/PropOnSelectionChange';
|
||||
import PropPlaceholder from './examples/PropPlaceholder';
|
||||
import PropSecureTextEntry from './examples/PropSecureTextEntry';
|
||||
import PropSelectTextOnFocus from './examples/PropSelectTextOnFocus';
|
||||
import TextInputEvents from './examples/TextInputEvents';
|
||||
import TextInputRewrite, { TextInputRewriteInvalidCharacters } from './examples/Rewrite';
|
||||
import React from 'react';
|
||||
import { storiesOf } from '@kadira/storybook';
|
||||
import UIExplorer, { AppText, Code, DocItem, StyleList, TextList } from '../../ui-explorer';
|
||||
|
||||
const sections = [
|
||||
{
|
||||
title: 'Props',
|
||||
entries: [
|
||||
<DocItem name="...View props" />,
|
||||
|
||||
<DocItem
|
||||
name="autoCapitalize"
|
||||
typeInfo="?enum('characters', 'none', 'sentences', 'words') = 'sentences'"
|
||||
description={[
|
||||
<AppText key={1}>
|
||||
Automatically capitalize certain characters (only available in Chrome and iOS Safari).
|
||||
</AppText>,
|
||||
<TextList
|
||||
key={2}
|
||||
items={[
|
||||
<AppText><Code>characters</Code>: Automatically capitalize all characters.</AppText>,
|
||||
<AppText><Code>none</Code>: Completely disables automatic capitalization.</AppText>,
|
||||
<AppText>
|
||||
<Code>sentences</Code>: Automatically capitalize the first letter of sentences.
|
||||
</AppText>,
|
||||
<AppText>
|
||||
<Code>words</Code>: Automatically capitalize the first letter of words.
|
||||
</AppText>
|
||||
]}
|
||||
/>
|
||||
]}
|
||||
example={{
|
||||
code: '',
|
||||
render: () => <PropAutoCapitalize />
|
||||
}}
|
||||
/>,
|
||||
|
||||
<DocItem
|
||||
label="web"
|
||||
name="autoComplete"
|
||||
typeInfo="?string"
|
||||
description={
|
||||
<AppText>
|
||||
Indicates whether the value of the control can be automatically
|
||||
completed by the browser.{' '}
|
||||
<AppText
|
||||
href="https://developer.mozilla.org/en-US/docs/Web/HTML/Element/input"
|
||||
target="_blank"
|
||||
>
|
||||
Accepted
|
||||
values.
|
||||
</AppText>
|
||||
</AppText>
|
||||
}
|
||||
/>,
|
||||
|
||||
<DocItem
|
||||
name="autoCorrect"
|
||||
typeInfo="?boolean = true"
|
||||
description="Automatically correct spelling mistakes (only available in iOS Safari)."
|
||||
/>,
|
||||
|
||||
<DocItem
|
||||
name="autoFocus"
|
||||
typeInfo="?boolean = false"
|
||||
description="If `true`, focuses the input on `componentDidMount`. Only the first form element in a document with `autofocus` is focused."
|
||||
/>,
|
||||
|
||||
<DocItem
|
||||
name="blurOnSubmit"
|
||||
typeInfo="?boolean"
|
||||
description={
|
||||
<AppText>
|
||||
If <Code>true</Code>, the text field will blur when submitted. The
|
||||
default value is <Code>true</Code> for single-line fields and
|
||||
{' '}<Code>false</Code> for multiline fields. Note, for multiline fields
|
||||
setting <Code>blurOnSubmit</Code> to <Code>true</Code> means that
|
||||
pressing return will blur the field and trigger the <Code>onSubmitEditing</Code>{' '}
|
||||
event instead of inserting a newline
|
||||
into the field.
|
||||
</AppText>
|
||||
}
|
||||
example={{
|
||||
render: () => <PropBlurOnSubmit />
|
||||
}}
|
||||
/>,
|
||||
|
||||
<DocItem
|
||||
name="clearTextOnFocus"
|
||||
typeInfo="?boolean = false"
|
||||
description="If `true`, clears the text field automatically when focused."
|
||||
example={{
|
||||
render: () => <PropClearTextOnFocus />
|
||||
}}
|
||||
/>,
|
||||
|
||||
<DocItem
|
||||
name="defaultValue"
|
||||
typeInfo="?string"
|
||||
description={
|
||||
<AppText>
|
||||
Provides an initial value that will change when the user starts typing. Useful
|
||||
for simple use-cases where you don't want to deal with listening to events and
|
||||
updating the <Code>value</Code> prop to keep the controlled state in sync.
|
||||
</AppText>
|
||||
}
|
||||
/>,
|
||||
|
||||
<DocItem
|
||||
name="editable"
|
||||
typeInfo="?boolean = true"
|
||||
description="If `false`, text is not editable (i.e., read-only). "
|
||||
example={{
|
||||
code: '',
|
||||
render: () => <PropEditable />
|
||||
}}
|
||||
/>,
|
||||
|
||||
<DocItem
|
||||
name="keyboardType"
|
||||
typeInfo="enum('default', 'email-address', 'numeric', 'phone-pad', 'search', 'url', 'web-search') = 'default'"
|
||||
description="Determines which keyboard to open on devices with a virtual keyboard. Safari iOS requires an ancestral `<form action>` element to display the `search` keyboard). (Not available when `multiline` is `true`.)"
|
||||
example={{
|
||||
code: '',
|
||||
render: () => <PropKeyboardType />
|
||||
}}
|
||||
/>,
|
||||
|
||||
<DocItem
|
||||
name="maxLength"
|
||||
typeInfo="?number"
|
||||
description="Limits the maximum number of characters that can be entered."
|
||||
example={{
|
||||
code: '',
|
||||
render: () => <PropMaxLength />
|
||||
}}
|
||||
/>,
|
||||
|
||||
<DocItem
|
||||
name="multiline"
|
||||
typeInfo="?boolean = false"
|
||||
description="If true, the text input can be multiple lines."
|
||||
example={{
|
||||
code: '',
|
||||
render: () => <PropMultiline />
|
||||
}}
|
||||
/>,
|
||||
|
||||
<DocItem
|
||||
name="numberOfLines"
|
||||
typeInfo="?number"
|
||||
description="Sets the number of lines for a multiline `TextInput`. (Requires `multiline` to be `true`.)"
|
||||
example={{
|
||||
code: '',
|
||||
render: () => <PropNumberOfLines />
|
||||
}}
|
||||
/>,
|
||||
|
||||
<DocItem
|
||||
name="onBlur"
|
||||
typeInfo="?function"
|
||||
description="Callback that is called when the text input is blurred."
|
||||
/>,
|
||||
|
||||
<DocItem
|
||||
name="onChange"
|
||||
typeInfo="?function"
|
||||
description="Callback that is called when the text input's text changes."
|
||||
/>,
|
||||
|
||||
<DocItem
|
||||
name="onChangeText"
|
||||
typeInfo="?function"
|
||||
description="Callback that is called when the text input's text changes. The text is passed as an argument to the callback handler."
|
||||
/>,
|
||||
|
||||
<DocItem
|
||||
name="onFocus"
|
||||
typeInfo="?function"
|
||||
description="Callback that is called when the text input is focused."
|
||||
/>,
|
||||
|
||||
<DocItem
|
||||
name="onKeyPress"
|
||||
typeInfo="?function"
|
||||
description={
|
||||
<AppText>
|
||||
Callback that is called when a key is pressed. This will be called with{' '}
|
||||
<Code>{`{
|
||||
nativeEvent: { key: keyValue } }`}</Code>{' '}
|
||||
where keyValue is <Code>Enter</Code> or <Code>Backspace</Code> for
|
||||
respective keys and the typed-in character otherwise including <Code>' '</Code>
|
||||
for space. Modifier keys (e.g., <Code>shiftKey</Code>) are also included in
|
||||
the <Code>nativeEvent</Code>. Fires before <Code>onChange</Code> callbacks.
|
||||
</AppText>
|
||||
}
|
||||
/>,
|
||||
|
||||
<DocItem
|
||||
name="onSelectionChange"
|
||||
typeInfo="?function"
|
||||
description={
|
||||
<AppText>
|
||||
Callback that is called when the text input's selection changes. This will be called
|
||||
with <Code>{'{ nativeEvent: { selection: { start, end } } }'}</Code>.
|
||||
</AppText>
|
||||
}
|
||||
example={{
|
||||
render: () => <PropOnSelectionChange />
|
||||
}}
|
||||
/>,
|
||||
|
||||
<DocItem
|
||||
name="onSubmitEditing"
|
||||
typeInfo="?function"
|
||||
description="Callback that is called when the keyboard's submit button is pressed. When multiline={true}, this is only called if blurOnSubmit={true}."
|
||||
/>,
|
||||
|
||||
<DocItem
|
||||
name="placeholder"
|
||||
typeInfo="?string"
|
||||
description="The string that will be rendered in an empty `TextInput` before text has been entered."
|
||||
example={{
|
||||
code: '',
|
||||
render: () => <PropPlaceholder />
|
||||
}}
|
||||
/>,
|
||||
|
||||
<DocItem
|
||||
name="secureTextEntry"
|
||||
typeInfo="?boolean = false"
|
||||
description="If true, the text input obscures the text entered so that sensitive text like passwords stay secure. (Not available when `multiline` is `true`.)"
|
||||
example={{
|
||||
code: '',
|
||||
render: () => <PropSecureTextEntry />
|
||||
}}
|
||||
/>,
|
||||
|
||||
<DocItem
|
||||
name="selection"
|
||||
typeInfo="?{ start: number, end: ?number }"
|
||||
description="The start and end of the text input's selection. Set start and end to the same value to position the cursor."
|
||||
/>,
|
||||
|
||||
<DocItem
|
||||
name="selectTextOnFocus"
|
||||
typeInfo="?boolean = false"
|
||||
description="If `true`, all text will automatically be selected on focus."
|
||||
example={{
|
||||
code: '',
|
||||
render: () => <PropSelectTextOnFocus />
|
||||
}}
|
||||
/>,
|
||||
|
||||
<DocItem
|
||||
name="style"
|
||||
typeInfo="?style"
|
||||
description={
|
||||
<StyleList
|
||||
stylePropTypes={[
|
||||
{
|
||||
name: '...Text#style'
|
||||
},
|
||||
{
|
||||
label: 'web',
|
||||
name: 'resize',
|
||||
typeInfo: 'string'
|
||||
}
|
||||
]}
|
||||
/>
|
||||
}
|
||||
/>,
|
||||
|
||||
<DocItem
|
||||
name="value"
|
||||
typeInfo="?string"
|
||||
description={
|
||||
<AppText>
|
||||
The value to show for the text input. <Code>TextInput</Code> is a controlled component,
|
||||
which means the native <Code>value</Code> will be forced to match this prop if provided.
|
||||
Read about how{' '}
|
||||
<AppText
|
||||
children="React form components"
|
||||
href="https://facebook.github.io/react/docs/forms.html"
|
||||
target="_blank"
|
||||
/>{' '}
|
||||
work. To prevent
|
||||
user edits to the value set <Code>{'editable={false}'}</Code>.
|
||||
</AppText>
|
||||
}
|
||||
/>
|
||||
]
|
||||
},
|
||||
|
||||
{
|
||||
title: 'Instance methods',
|
||||
entries: [
|
||||
<DocItem name="blur" typeInfo="() => void" description="Blur the underlying DOM input." />,
|
||||
<DocItem
|
||||
name="clear"
|
||||
typeInfo="() => void"
|
||||
description="Clear the text from the underlying DOM input."
|
||||
/>,
|
||||
<DocItem name="focus" typeInfo="() => void" description="Focus the underlying DOM input." />,
|
||||
<DocItem
|
||||
name="isFocused"
|
||||
typeInfo="() => boolean"
|
||||
description="Returns `true` if the input is currently focused; `false` otherwise."
|
||||
/>
|
||||
]
|
||||
},
|
||||
|
||||
{
|
||||
title: 'More examples',
|
||||
entries: [
|
||||
<DocItem
|
||||
description="TextInput events"
|
||||
example={{
|
||||
render: () => <TextInputEvents />
|
||||
}}
|
||||
/>,
|
||||
|
||||
<DocItem
|
||||
description="Rewrite (<sp> to '_' with maxLength)"
|
||||
example={{
|
||||
render: () => <TextInputRewrite />
|
||||
}}
|
||||
/>,
|
||||
|
||||
<DocItem
|
||||
description="Rewrite (no spaces allowed)"
|
||||
example={{
|
||||
render: () => <TextInputRewriteInvalidCharacters />
|
||||
}}
|
||||
/>
|
||||
]
|
||||
}
|
||||
];
|
||||
|
||||
storiesOf('Components', module).add('TextInput', () =>
|
||||
<UIExplorer
|
||||
description="Accessible single- and multi-line text input via a keyboard. Supports features such as auto-complete, auto-focus, placeholder text, and event callbacks. Note: some props are exclusive to or excluded from `multiline`."
|
||||
sections={sections}
|
||||
title="TextInput"
|
||||
url="components/TextInput"
|
||||
/>
|
||||
);
|
||||
@@ -0,0 +1,62 @@
|
||||
/**
|
||||
* @flow
|
||||
*/
|
||||
|
||||
/*
|
||||
import React from 'react';
|
||||
import { StyleSheet, TextInput } from 'react-native';
|
||||
|
||||
class AutoExpandingTextInput extends React.Component {
|
||||
state: any;
|
||||
|
||||
constructor(props) {
|
||||
super(props);
|
||||
this.state = {
|
||||
text:
|
||||
'React Native enables you to build world-class application experiences on native platforms using a consistent developer experience based on JavaScript and React. The focus of React Native is on developer efficiency across all the platforms you care about — learn once, write anywhere. Facebook uses React Native in multiple production apps and will continue investing in React Native.',
|
||||
height: 0
|
||||
};
|
||||
}
|
||||
|
||||
render() {
|
||||
return (
|
||||
<TextInput
|
||||
{...this.props}
|
||||
multiline={true}
|
||||
onChangeText={text => {
|
||||
this.setState({ text });
|
||||
}}
|
||||
onContentSizeChange={event => {
|
||||
this.setState({ height: event.nativeEvent.contentSize.height });
|
||||
}}
|
||||
style={[styles.default, { height: Math.max(35, this.state.height) }]}
|
||||
value={this.state.text}
|
||||
/>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
const styles = StyleSheet.create({
|
||||
default: {
|
||||
height: 26,
|
||||
borderWidth: 0.5,
|
||||
borderColor: '#0f0f0f',
|
||||
flex: 1,
|
||||
fontSize: 13,
|
||||
padding: 4
|
||||
},
|
||||
eventLabel: {
|
||||
margin: 3,
|
||||
fontSize: 12
|
||||
}
|
||||
});
|
||||
|
||||
const AutoExpandingTextInputExample = () =>
|
||||
<AutoExpandingTextInput
|
||||
enablesReturnKeyAutomatically={true}
|
||||
placeholder="height increases with content"
|
||||
returnKeyType="default"
|
||||
/>;
|
||||
|
||||
export default AutoExpandingTextInputExample;
|
||||
*/
|
||||
@@ -0,0 +1,25 @@
|
||||
/**
|
||||
* @flow
|
||||
*/
|
||||
|
||||
import React from 'react';
|
||||
import { WithLabel, styles } from '../helpers';
|
||||
import { TextInput, View } from 'react-native';
|
||||
|
||||
const TextInputAutoCapitalizeExample = () =>
|
||||
<View>
|
||||
<WithLabel label="none">
|
||||
<TextInput autoCapitalize="none" style={styles.textinput} />
|
||||
</WithLabel>
|
||||
<WithLabel label="sentences">
|
||||
<TextInput autoCapitalize="sentences" style={styles.textinput} />
|
||||
</WithLabel>
|
||||
<WithLabel label="words">
|
||||
<TextInput autoCapitalize="words" style={styles.textinput} />
|
||||
</WithLabel>
|
||||
<WithLabel label="characters">
|
||||
<TextInput autoCapitalize="characters" style={styles.textinput} />
|
||||
</WithLabel>
|
||||
</View>;
|
||||
|
||||
export default TextInputAutoCapitalizeExample;
|
||||
@@ -0,0 +1,11 @@
|
||||
/**
|
||||
* @flow
|
||||
*/
|
||||
|
||||
import React from 'react';
|
||||
import { styles } from '../helpers';
|
||||
import { TextInput } from 'react-native';
|
||||
|
||||
const TextInputAutoFocusExample = () => <TextInput autoFocus={true} style={styles.default} />;
|
||||
|
||||
export default TextInputAutoFocusExample;
|
||||
@@ -0,0 +1,55 @@
|
||||
/* eslint-disable react/jsx-no-bind */
|
||||
|
||||
/**
|
||||
* @flow
|
||||
*/
|
||||
|
||||
import React from 'react';
|
||||
import { styles } from '../helpers';
|
||||
import { TextInput, View } from 'react-native';
|
||||
|
||||
class TextInputBlurOnSubmitExample extends React.Component {
|
||||
_nodes = {};
|
||||
|
||||
focusNextField = nextField => {
|
||||
this._nodes[nextField].focus();
|
||||
};
|
||||
|
||||
render() {
|
||||
return (
|
||||
<View>
|
||||
<TextInput
|
||||
blurOnSubmit={false}
|
||||
placeholder="blurOnSubmit = false"
|
||||
ref={c => {
|
||||
this._nodes['1'] = c;
|
||||
}}
|
||||
style={styles.textinput}
|
||||
/>
|
||||
<TextInput
|
||||
blurOnSubmit={true}
|
||||
onSubmitEditing={() => this.focusNextField('3')}
|
||||
placeholder="blurOnSubmit = true"
|
||||
ref={c => {
|
||||
this._nodes['2'] = c;
|
||||
}}
|
||||
style={styles.textinput}
|
||||
/>
|
||||
<TextInput
|
||||
blurOnSubmit={true}
|
||||
multiline={true}
|
||||
onSubmitEditing={e => {
|
||||
console.log(e.nativeEvent);
|
||||
}}
|
||||
placeholder="blurOnSubmit = true"
|
||||
ref={c => {
|
||||
this._nodes['3'] = c;
|
||||
}}
|
||||
style={styles.multiline}
|
||||
/>
|
||||
</View>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export default TextInputBlurOnSubmitExample;
|
||||
@@ -0,0 +1,25 @@
|
||||
/**
|
||||
* @flow
|
||||
*/
|
||||
|
||||
import React from 'react';
|
||||
import { styles, WithLabel } from '../helpers';
|
||||
import { TextInput, View } from 'react-native';
|
||||
|
||||
const TextInputClearButtonModeExample = () =>
|
||||
<View>
|
||||
<WithLabel label="never">
|
||||
<TextInput clearButtonMode="never" style={styles.textinput} />
|
||||
</WithLabel>
|
||||
<WithLabel label="while editing">
|
||||
<TextInput clearButtonMode="while-editing" style={styles.textinput} />
|
||||
</WithLabel>
|
||||
<WithLabel label="unless editing">
|
||||
<TextInput clearButtonMode="unless-editing" style={styles.textinput} />
|
||||
</WithLabel>
|
||||
<WithLabel label="always">
|
||||
<TextInput clearButtonMode="always" style={styles.textinput} />
|
||||
</WithLabel>
|
||||
</View>;
|
||||
|
||||
export default TextInputClearButtonModeExample;
|
||||
@@ -0,0 +1,26 @@
|
||||
/**
|
||||
* @flow
|
||||
*/
|
||||
|
||||
import React from 'react';
|
||||
import { styles } from '../helpers';
|
||||
import { TextInput, View } from 'react-native';
|
||||
|
||||
const TextInputClearTextOnFocusExample = () =>
|
||||
<View>
|
||||
<TextInput
|
||||
clearTextOnFocus={true}
|
||||
defaultValue="text is cleared on focus"
|
||||
placeholder="text is cleared on focus"
|
||||
style={styles.textinput}
|
||||
/>
|
||||
<TextInput
|
||||
clearTextOnFocus={true}
|
||||
defaultValue="text is cleared on focus"
|
||||
multiline={true}
|
||||
placeholder="text is cleared on focus"
|
||||
style={styles.multiline}
|
||||
/>
|
||||
</View>;
|
||||
|
||||
export default TextInputClearTextOnFocusExample;
|
||||
@@ -0,0 +1,20 @@
|
||||
/**
|
||||
* @flow
|
||||
*/
|
||||
|
||||
import React from 'react';
|
||||
import { styles } from '../helpers';
|
||||
import { TextInput, View } from 'react-native';
|
||||
|
||||
const TextInputEditableExample = () =>
|
||||
<View>
|
||||
<TextInput defaultValue="uneditable text input" editable={false} style={styles.textinput} />
|
||||
<TextInput
|
||||
defaultValue="uneditable multiline text input"
|
||||
editable={false}
|
||||
multiline={true}
|
||||
style={styles.multiline}
|
||||
/>
|
||||
</View>;
|
||||
|
||||
export default TextInputEditableExample;
|
||||
@@ -0,0 +1,33 @@
|
||||
/**
|
||||
* @flow
|
||||
*/
|
||||
|
||||
import React from 'react';
|
||||
import { styles, WithLabel } from '../helpers';
|
||||
import { TextInput, View } from 'react-native';
|
||||
|
||||
const keyboardTypes = [
|
||||
'default',
|
||||
//'ascii-capable',
|
||||
//'numbers-and-punctuation',
|
||||
'url',
|
||||
'number-pad',
|
||||
'phone-pad',
|
||||
//'name-phone-pad',
|
||||
'email-address',
|
||||
//'decimal-pad',
|
||||
//'twitter',
|
||||
'web-search',
|
||||
'numeric'
|
||||
];
|
||||
|
||||
const TextInputKeyboardTypeExample = () =>
|
||||
<View>
|
||||
{keyboardTypes.map(type =>
|
||||
<WithLabel key={type} label={type}>
|
||||
<TextInput keyboardType={type} style={styles.textinput} />
|
||||
</WithLabel>
|
||||
)}
|
||||
</View>;
|
||||
|
||||
export default TextInputKeyboardTypeExample;
|
||||
@@ -0,0 +1,25 @@
|
||||
/**
|
||||
* @flow
|
||||
*/
|
||||
|
||||
import React from 'react';
|
||||
import { styles, WithLabel } from '../helpers';
|
||||
import { TextInput, View } from 'react-native';
|
||||
|
||||
const TextInputMaxLengthExample = () =>
|
||||
<View>
|
||||
<WithLabel label="maxLength: 5">
|
||||
<TextInput maxLength={5} style={styles.textinput} />
|
||||
</WithLabel>
|
||||
<WithLabel label="maxLength: 5 with placeholder">
|
||||
<TextInput maxLength={5} placeholder="ZIP code entry" style={styles.textinput} />
|
||||
</WithLabel>
|
||||
<WithLabel label="maxLength: 5 with default value already set">
|
||||
<TextInput defaultValue="94025" maxLength={5} style={styles.textinput} />
|
||||
</WithLabel>
|
||||
<WithLabel label="maxLength: 5 with very long default value already set">
|
||||
<TextInput defaultValue="9402512345" maxLength={5} style={styles.textinput} />
|
||||
</WithLabel>
|
||||
</View>;
|
||||
|
||||
export default TextInputMaxLengthExample;
|
||||
@@ -0,0 +1,15 @@
|
||||
/**
|
||||
* @flow
|
||||
*/
|
||||
|
||||
import React from 'react';
|
||||
import { styles } from '../helpers';
|
||||
import { TextInput, View } from 'react-native';
|
||||
|
||||
const TextInputMultilineExample = () =>
|
||||
<View>
|
||||
<TextInput multiline={true} style={styles.multiline} />
|
||||
<TextInput multiline={true} style={styles.multiline} />
|
||||
</View>;
|
||||
|
||||
export default TextInputMultilineExample;
|
||||
@@ -0,0 +1,25 @@
|
||||
/**
|
||||
* @flow
|
||||
*/
|
||||
|
||||
import React from 'react';
|
||||
import { styles } from '../helpers';
|
||||
import { TextInput, View } from 'react-native';
|
||||
|
||||
const TextInputNumberOfLinesExample = () =>
|
||||
<View>
|
||||
<TextInput
|
||||
multiline={true}
|
||||
numberOfLines={2}
|
||||
placeholder="numberOfLines = 2"
|
||||
style={[styles.multiline, { height: 'auto' }]}
|
||||
/>
|
||||
<TextInput
|
||||
multiline={true}
|
||||
numberOfLines={3}
|
||||
placeholder="numberOfLines = 3"
|
||||
style={[styles.multiline, { height: 'auto' }]}
|
||||
/>
|
||||
</View>;
|
||||
|
||||
export default TextInputNumberOfLinesExample;
|
||||
12
docs/storybook/1-components/TextInput/examples/PropOnBlur.js
Normal file
12
docs/storybook/1-components/TextInput/examples/PropOnBlur.js
Normal file
@@ -0,0 +1,12 @@
|
||||
/**
|
||||
* @flow
|
||||
*/
|
||||
|
||||
/*
|
||||
import React from 'react';
|
||||
import { TextInput, View } from 'react-native';
|
||||
|
||||
const TextInputOnBlurExample = () => null;
|
||||
|
||||
export default TextInputOnBlurExample;
|
||||
*/
|
||||
@@ -0,0 +1,12 @@
|
||||
/**
|
||||
* @flow
|
||||
*/
|
||||
|
||||
/*
|
||||
import React from 'react';
|
||||
import { TextInput, View } from 'react-native';
|
||||
|
||||
const TextInputOnChangeExample = () => null;
|
||||
|
||||
export default TextInputOnChangeExample;
|
||||
*/
|
||||
@@ -0,0 +1,12 @@
|
||||
/**
|
||||
* @flow
|
||||
*/
|
||||
|
||||
/*
|
||||
import React from 'react';
|
||||
import { TextInput, View } from 'react-native';
|
||||
|
||||
const TextInputOnChangeTextExample = () => null;
|
||||
|
||||
export default TextInputOnChangeTextExample;
|
||||
*/
|
||||
@@ -0,0 +1,12 @@
|
||||
/**
|
||||
* @flow
|
||||
*/
|
||||
|
||||
/*
|
||||
import React from 'react';
|
||||
import { TextInput, View } from 'react-native';
|
||||
|
||||
const TextInputOnFocusExample = () => null;
|
||||
|
||||
export default TextInputOnFocusExample;
|
||||
*/
|
||||
@@ -0,0 +1,12 @@
|
||||
/**
|
||||
* @flow
|
||||
*/
|
||||
|
||||
/*
|
||||
import React from 'react';
|
||||
import { TextInput, View } from 'react-native';
|
||||
|
||||
const TextInputOnKeyPressExample = () => null;
|
||||
|
||||
export default TextInputOnKeyPressExample;
|
||||
*/
|
||||
@@ -0,0 +1,121 @@
|
||||
/**
|
||||
* @flow
|
||||
*/
|
||||
|
||||
import React from 'react';
|
||||
import { any, bool, string } from 'prop-types';
|
||||
import { styles } from '../helpers';
|
||||
import { Text, TextInput, View } from 'react-native';
|
||||
|
||||
type SelectionExampleState = {
|
||||
selection: {
|
||||
start: number,
|
||||
end?: number
|
||||
},
|
||||
value: string
|
||||
};
|
||||
|
||||
class OnSelectionChangeExample extends React.Component {
|
||||
state: SelectionExampleState;
|
||||
|
||||
_textInput: any;
|
||||
|
||||
static propTypes = {
|
||||
multiline: bool,
|
||||
style: any,
|
||||
value: string
|
||||
};
|
||||
|
||||
constructor(props) {
|
||||
super(props);
|
||||
this.state = {
|
||||
selection: { start: 0, end: 0 },
|
||||
value: props.value
|
||||
};
|
||||
}
|
||||
|
||||
onSelectionChange = ({ nativeEvent: { selection } }) => {
|
||||
this.setState({ selection });
|
||||
};
|
||||
|
||||
onChangeText = value => {
|
||||
this.setState({ value });
|
||||
};
|
||||
|
||||
getRandomPosition() {
|
||||
const length = this.state.value.length;
|
||||
return Math.round(Math.random() * length);
|
||||
}
|
||||
|
||||
select = (start, end) => () => {
|
||||
this._textInput.focus();
|
||||
this.setState({ selection: { start, end } });
|
||||
};
|
||||
|
||||
selectRandom = () => {
|
||||
const positions = [this.getRandomPosition(), this.getRandomPosition()].sort();
|
||||
this.select(...positions)();
|
||||
};
|
||||
|
||||
placeAt = position => () => {
|
||||
this.select(position, position)();
|
||||
};
|
||||
|
||||
placeAtRandom = () => {
|
||||
this.placeAt(this.getRandomPosition())();
|
||||
};
|
||||
|
||||
setRef = textInput => {
|
||||
this._textInput = textInput;
|
||||
};
|
||||
|
||||
render() {
|
||||
const length = this.state.value.length;
|
||||
|
||||
return (
|
||||
<View>
|
||||
<TextInput
|
||||
multiline={this.props.multiline}
|
||||
onChangeText={this.onChangeText}
|
||||
onSelectionChange={this.onSelectionChange}
|
||||
ref={this.setRef}
|
||||
selection={this.state.selection}
|
||||
style={this.props.style}
|
||||
value={this.state.value}
|
||||
/>
|
||||
<View>
|
||||
<Text>
|
||||
selection = {JSON.stringify(this.state.selection)}
|
||||
</Text>
|
||||
<Text onPress={this.placeAt(0)}>
|
||||
Place at Start (0, 0)
|
||||
</Text>
|
||||
<Text onPress={this.placeAt(length)}>
|
||||
Place at End ({length}, {length})
|
||||
</Text>
|
||||
<Text onPress={this.placeAtRandom}>
|
||||
Place at Random
|
||||
</Text>
|
||||
<Text onPress={this.select(0, length)}>
|
||||
Select All
|
||||
</Text>
|
||||
<Text onPress={this.selectRandom}>
|
||||
Select Random
|
||||
</Text>
|
||||
</View>
|
||||
</View>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
const TextInputOnSelectionChangeExample = () =>
|
||||
<View>
|
||||
<OnSelectionChangeExample style={styles.textinput} value="text selection can be changed" />
|
||||
<OnSelectionChangeExample
|
||||
multiline
|
||||
style={styles.multiline}
|
||||
value={'multiline text selection\ncan also be changed'}
|
||||
/>
|
||||
</View>;
|
||||
|
||||
export default TextInputOnSelectionChangeExample;
|
||||
@@ -0,0 +1,12 @@
|
||||
/**
|
||||
* @flow
|
||||
*/
|
||||
|
||||
/*
|
||||
import React from 'react';
|
||||
import { TextInput, View } from 'react-native';
|
||||
|
||||
const TextInputOnSubmitEditingExample = () => null;
|
||||
|
||||
export default TextInputOnSubmitEditingExample;
|
||||
*/
|
||||
@@ -0,0 +1,15 @@
|
||||
/**
|
||||
* @flow
|
||||
*/
|
||||
|
||||
import React from 'react';
|
||||
import { styles } from '../helpers';
|
||||
import { TextInput, View } from 'react-native';
|
||||
|
||||
const TextInputPlaceholderExample = () =>
|
||||
<View>
|
||||
<TextInput placeholder="This is placeholder text" style={styles.textinput} />
|
||||
<TextInput multiline={true} placeholder="This is placeholder text" style={styles.multiline} />
|
||||
</View>;
|
||||
|
||||
export default TextInputPlaceholderExample;
|
||||
@@ -0,0 +1,17 @@
|
||||
/**
|
||||
* @flow
|
||||
*/
|
||||
|
||||
import React from 'react';
|
||||
import { styles } from '../helpers';
|
||||
import { TextInput } from 'react-native';
|
||||
|
||||
const TextInputSecureTextEntryExample = () =>
|
||||
<TextInput
|
||||
defaultValue="abc"
|
||||
numberOfLines={2}
|
||||
secureTextEntry={true}
|
||||
style={styles.textinput}
|
||||
/>;
|
||||
|
||||
export default TextInputSecureTextEntryExample;
|
||||
@@ -0,0 +1,26 @@
|
||||
/**
|
||||
* @flow
|
||||
*/
|
||||
|
||||
import React from 'react';
|
||||
import { styles } from '../helpers';
|
||||
import { TextInput, View } from 'react-native';
|
||||
|
||||
const TextInputSelectTextOnFocusExample = () =>
|
||||
<View>
|
||||
<TextInput
|
||||
defaultValue="text is selected on focus"
|
||||
placeholder="text is selected on focus"
|
||||
selectTextOnFocus={true}
|
||||
style={styles.textinput}
|
||||
/>
|
||||
<TextInput
|
||||
defaultValue="text is selected on focus"
|
||||
multiline={true}
|
||||
placeholder="text is selected on focus"
|
||||
selectTextOnFocus={true}
|
||||
style={styles.multiline}
|
||||
/>
|
||||
</View>;
|
||||
|
||||
export default TextInputSelectTextOnFocusExample;
|
||||
@@ -0,0 +1,12 @@
|
||||
/**
|
||||
* @flow
|
||||
*/
|
||||
|
||||
/*
|
||||
import React from 'react';
|
||||
import { TextInput, View } from 'react-native';
|
||||
|
||||
const TextInputSelectionExample = () => null;
|
||||
|
||||
export default TextInputSelectionExample;
|
||||
*/
|
||||
12
docs/storybook/1-components/TextInput/examples/PropStyle.js
Normal file
12
docs/storybook/1-components/TextInput/examples/PropStyle.js
Normal file
@@ -0,0 +1,12 @@
|
||||
/**
|
||||
* @flow
|
||||
*/
|
||||
|
||||
/*
|
||||
import React from 'react';
|
||||
import { TextInput, View } from 'react-native';
|
||||
|
||||
const TextInputStyleExample = () => null;
|
||||
|
||||
export default TextInputStyleExample;
|
||||
*/
|
||||
69
docs/storybook/1-components/TextInput/examples/Rewrite.js
Normal file
69
docs/storybook/1-components/TextInput/examples/Rewrite.js
Normal file
@@ -0,0 +1,69 @@
|
||||
/**
|
||||
* @flow
|
||||
*/
|
||||
|
||||
import React from 'react';
|
||||
import { styles as helperStyles } from '../helpers';
|
||||
import { StyleSheet, Text, TextInput, View } from 'react-native';
|
||||
|
||||
export default class TextInputRewrite extends React.Component {
|
||||
state = { text: '' };
|
||||
|
||||
handleChangeText = text => {
|
||||
text = text.replace(/ /g, '_');
|
||||
this.setState({ text });
|
||||
};
|
||||
|
||||
render() {
|
||||
const limit = 20;
|
||||
const remainder = limit - this.state.text.length;
|
||||
const remainderColor = remainder > 5 ? 'blue' : 'red';
|
||||
return (
|
||||
<View style={styles.rewriteContainer}>
|
||||
<TextInput
|
||||
maxLength={limit}
|
||||
multiline={false}
|
||||
onChangeText={this.handleChangeText}
|
||||
style={helperStyles.textinput}
|
||||
value={this.state.text}
|
||||
/>
|
||||
<Text style={[styles.remainder, { color: remainderColor }]}>
|
||||
{remainder}
|
||||
</Text>
|
||||
</View>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export class TextInputRewriteInvalidCharacters extends React.Component {
|
||||
state = { text: '' };
|
||||
|
||||
handleChangeText = text => {
|
||||
text = text.replace(/\s/g, '_');
|
||||
this.setState({ text });
|
||||
};
|
||||
|
||||
render() {
|
||||
return (
|
||||
<View style={styles.rewriteContainer}>
|
||||
<TextInput
|
||||
multiline={false}
|
||||
onChangeText={this.handleChangeText}
|
||||
style={helperStyles.textinput}
|
||||
value={this.state.text}
|
||||
/>
|
||||
</View>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
const styles = StyleSheet.create({
|
||||
rewriteContainer: {
|
||||
flexDirection: 'row',
|
||||
alignItems: 'center'
|
||||
},
|
||||
remainder: {
|
||||
textAlign: 'right',
|
||||
width: 24
|
||||
}
|
||||
});
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user