mirror of
https://github.com/zhigang1992/react-native-web.git
synced 2026-04-24 04:25:27 +08:00
Compare commits
289 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
4bbe1a40aa | ||
|
|
6942e4e417 | ||
|
|
63daff7f80 | ||
|
|
662b7c3d6e | ||
|
|
12fb588596 | ||
|
|
5cb09b1a9e | ||
|
|
c03cfdf8bd | ||
|
|
997b598de8 | ||
|
|
6fe796f9da | ||
|
|
0ad6ab948b | ||
|
|
32a23136af | ||
|
|
96f48226cb | ||
|
|
f1ef0f21af | ||
|
|
d42e8907ca | ||
|
|
90724b2cef | ||
|
|
dd0f1de3d1 | ||
|
|
fc751ed715 | ||
|
|
917b06a690 | ||
|
|
80cb7baf82 | ||
|
|
f08515b1f1 | ||
|
|
8591bf7ce5 | ||
|
|
b7c8f00fcc | ||
|
|
ed81b985a9 | ||
|
|
441dc8efff | ||
|
|
7e8ef5b72c | ||
|
|
641c8c47e0 | ||
|
|
87ead7f64e | ||
|
|
5ed2127175 | ||
|
|
e802026298 | ||
|
|
5d24f4c8fa | ||
|
|
a9f1afc07c | ||
|
|
d185d81560 | ||
|
|
66fa09da8e | ||
|
|
bae4dd806a | ||
|
|
4a680fd9b6 | ||
|
|
e34e4e38d3 | ||
|
|
b23a4f55dc | ||
|
|
26bdf44a4c | ||
|
|
5e98107617 | ||
|
|
86ea0e5eff | ||
|
|
6e02c5690c | ||
|
|
c50d808a2b | ||
|
|
130b10c3f7 | ||
|
|
03ddf074ea | ||
|
|
f201a0347d | ||
|
|
fffbdff6ca | ||
|
|
23e5c8479c | ||
|
|
17e5e374ee | ||
|
|
ef907dce22 | ||
|
|
586f134f76 | ||
|
|
70e2a75b43 | ||
|
|
8756c20ade | ||
|
|
4081d17f25 | ||
|
|
4fa6f77d25 | ||
|
|
17d723559d | ||
|
|
8d80885f5d | ||
|
|
3ca4becc41 | ||
|
|
cc077e9019 | ||
|
|
1225b00cdb | ||
|
|
ed70617e91 | ||
|
|
134114de83 | ||
|
|
08ee7c83bb | ||
|
|
5fad78dcad | ||
|
|
e04343e48e | ||
|
|
5e3a946f8b | ||
|
|
4e3d8dbb02 | ||
|
|
fee909d26a | ||
|
|
9e58a7b5f1 | ||
|
|
20e1febe21 | ||
|
|
ef209ca281 | ||
|
|
a35949fa71 | ||
|
|
f5ac856c2d | ||
|
|
4b557b1e0b | ||
|
|
d4e9d9d256 | ||
|
|
0ff3e91592 | ||
|
|
092d5d12f7 | ||
|
|
507e0d41f5 | ||
|
|
9e863d5402 | ||
|
|
1364b1dfdf | ||
|
|
7f81e313ed | ||
|
|
a1892ec8b8 | ||
|
|
e6232d5980 | ||
|
|
e93a2eb478 | ||
|
|
44ecf1fe87 | ||
|
|
faec2b4a83 | ||
|
|
3677f0dd57 | ||
|
|
36d161a959 | ||
|
|
1ca18ab056 | ||
|
|
b43717e797 | ||
|
|
801d5f8c68 | ||
|
|
30f2ec9bf5 | ||
|
|
6f3e29f630 | ||
|
|
2607cb25ab | ||
|
|
8f56454ed7 | ||
|
|
d03e06632e | ||
|
|
66732394cb | ||
|
|
077d2f3e63 | ||
|
|
f6ad9c3afb | ||
|
|
f91ecaa81d | ||
|
|
ad3dee0204 | ||
|
|
1a0a40d9be | ||
|
|
0bf6e893c6 | ||
|
|
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 | ||
|
|
a61f71133e | ||
|
|
dad2888f7e | ||
|
|
5e9e81eafe | ||
|
|
7ae2a5e188 | ||
|
|
d13f78622b | ||
|
|
6ae68e948f | ||
|
|
b1b70a420d | ||
|
|
43d297bf59 | ||
|
|
060d96b42d | ||
|
|
dd5f8cf641 | ||
|
|
7f256c6423 | ||
|
|
05069253a1 | ||
|
|
f10ac058b6 | ||
|
|
6aa2ac1f70 | ||
|
|
79e6dbaab5 | ||
|
|
fc86c876e0 | ||
|
|
1f25ef82ae | ||
|
|
5b60dcf0ff | ||
|
|
1cf152e8a0 | ||
|
|
d034a0c6ec | ||
|
|
33d1cdf193 | ||
|
|
483a76cb5c | ||
|
|
65055028c6 | ||
|
|
93f425e414 | ||
|
|
ce4cc8a946 | ||
|
|
77fd867421 | ||
|
|
22999d7e5b | ||
|
|
3c400a662b | ||
|
|
e78ce713cb | ||
|
|
70282cb4ca | ||
|
|
7abdb33a1d | ||
|
|
a9c7b38df9 | ||
|
|
d57fb6407a | ||
|
|
bcdeda5dab | ||
|
|
edef737249 | ||
|
|
9163b974db | ||
|
|
a388ef3e26 | ||
|
|
a84ecefa5d | ||
|
|
54af7e9da2 | ||
|
|
be3c78f317 | ||
|
|
6b85f5a22a | ||
|
|
875a2c98b3 | ||
|
|
6525d9d84a | ||
|
|
61356a786b | ||
|
|
864250f34d | ||
|
|
7ee570f0ed | ||
|
|
118b64a932 | ||
|
|
3cc1e480a7 | ||
|
|
124de7562d | ||
|
|
7aef8f04c1 | ||
|
|
08a353fbef | ||
|
|
51557d306b | ||
|
|
6b910166b2 | ||
|
|
668d389035 | ||
|
|
79a6a5a486 | ||
|
|
1c37a42566 | ||
|
|
c38369ac0f | ||
|
|
03769f7d45 | ||
|
|
eb43a8f3e7 | ||
|
|
cdf13b880d | ||
|
|
47fad1ef58 | ||
|
|
5f69c8e8b8 | ||
|
|
21550db5f2 | ||
|
|
1cae5d55a1 | ||
|
|
11d23f850a | ||
|
|
d994a25017 | ||
|
|
756df70154 | ||
|
|
f0b06419f9 | ||
|
|
60ff75705e | ||
|
|
5e8ad67296 | ||
|
|
ba24a882be | ||
|
|
c7686209cd | ||
|
|
f1b281ae32 | ||
|
|
b676fbd5e0 | ||
|
|
51aef6c791 | ||
|
|
ae9a9cde5f | ||
|
|
beb907b180 | ||
|
|
a3362e1f38 | ||
|
|
64d2d34367 | ||
|
|
d83cd45b6f | ||
|
|
227971d22c | ||
|
|
4822cf4620 | ||
|
|
91e4528eac | ||
|
|
1ee64d8285 | ||
|
|
66a4c13bf3 | ||
|
|
9012e98ba7 | ||
|
|
046e01dfa9 | ||
|
|
6e71e1e058 | ||
|
|
d5a9f3e779 | ||
|
|
f16f5f21ce | ||
|
|
0bb7e67e63 | ||
|
|
c6b54930b6 | ||
|
|
599f1fcaf5 | ||
|
|
3f7a4e455f | ||
|
|
1f3e9cc6ee | ||
|
|
17ed63129f | ||
|
|
769334d04e | ||
|
|
dad80d5718 | ||
|
|
d8e93058da | ||
|
|
4ae894313f | ||
|
|
438f398022 | ||
|
|
630ee24fdd | ||
|
|
ae13873c2c | ||
|
|
7705f521c8 | ||
|
|
cbd98a8bd7 | ||
|
|
1f80e4c105 | ||
|
|
dbc8f31be6 | ||
|
|
ed994dc670 | ||
|
|
a57e58607a | ||
|
|
03ea259d70 | ||
|
|
e39b58fd04 | ||
|
|
ab45211401 | ||
|
|
32183bb92a | ||
|
|
761c42301d | ||
|
|
0863894f40 | ||
|
|
8f736ddefe | ||
|
|
ab686e2a07 | ||
|
|
2c14bdab2e | ||
|
|
0b8b064757 | ||
|
|
93eadb734b | ||
|
|
8d561d7309 | ||
|
|
cdca9e1e2b | ||
|
|
170bab659d | ||
|
|
941c628445 | ||
|
|
547c375bd6 | ||
|
|
aa85876eb2 | ||
|
|
50b168cc41 | ||
|
|
25a11e673d | ||
|
|
e846054f4e | ||
|
|
d6854abd7d | ||
|
|
1b172319b9 | ||
|
|
e81394c26e | ||
|
|
d33aa3eee2 | ||
|
|
5d78c73e8c | ||
|
|
7735d304ef | ||
|
|
b7c72308ea | ||
|
|
5fee075774 | ||
|
|
25204eeff0 | ||
|
|
9c61fe58d3 | ||
|
|
782125d169 |
8
.babelrc
8
.babelrc
@@ -1,8 +0,0 @@
|
|||||||
{
|
|
||||||
"presets": [
|
|
||||||
"react-native"
|
|
||||||
],
|
|
||||||
"plugins": [
|
|
||||||
[ "transform-react-remove-prop-types", { "mode": "wrap" } ]
|
|
||||||
]
|
|
||||||
}
|
|
||||||
@@ -1,9 +0,0 @@
|
|||||||
# EditorConfig: http://editorconfig.org
|
|
||||||
|
|
||||||
root = true
|
|
||||||
|
|
||||||
[*]
|
|
||||||
end_of_line = lf
|
|
||||||
insert_final_newline = true
|
|
||||||
indent_style = space
|
|
||||||
indent_size = 2
|
|
||||||
38
.eslintrc
38
.eslintrc
@@ -14,7 +14,6 @@
|
|||||||
"prettier/react"
|
"prettier/react"
|
||||||
],
|
],
|
||||||
"plugins": [
|
"plugins": [
|
||||||
"jsx-a11y",
|
|
||||||
"promise",
|
"promise",
|
||||||
"react"
|
"react"
|
||||||
],
|
],
|
||||||
@@ -25,7 +24,16 @@
|
|||||||
"globals": {
|
"globals": {
|
||||||
"document": false,
|
"document": false,
|
||||||
"navigator": false,
|
"navigator": false,
|
||||||
"window": false
|
"window": false,
|
||||||
|
// Flow global types
|
||||||
|
"HTMLInputElement": false,
|
||||||
|
"ReactClass": false,
|
||||||
|
"ReactComponent": false,
|
||||||
|
"ReactElement": false,
|
||||||
|
"ReactPropsChainableTypeChecker": false,
|
||||||
|
"ReactPropsCheckType": false,
|
||||||
|
"ReactPropTypes": false,
|
||||||
|
"SyntheticEvent": false
|
||||||
},
|
},
|
||||||
"rules": {
|
"rules": {
|
||||||
"camelcase": 0,
|
"camelcase": 0,
|
||||||
@@ -48,7 +56,6 @@
|
|||||||
"no-dupe-class-members": 2,
|
"no-dupe-class-members": 2,
|
||||||
"no-dupe-keys": 2,
|
"no-dupe-keys": 2,
|
||||||
"no-duplicate-case": 2,
|
"no-duplicate-case": 2,
|
||||||
"no-duplicate-imports": 2,
|
|
||||||
"no-empty-character-class": 2,
|
"no-empty-character-class": 2,
|
||||||
"no-empty-pattern": 2,
|
"no-empty-pattern": 2,
|
||||||
"no-eval": 2,
|
"no-eval": 2,
|
||||||
@@ -119,33 +126,8 @@
|
|||||||
// promise
|
// promise
|
||||||
"promise/param-names": 2,
|
"promise/param-names": 2,
|
||||||
|
|
||||||
// jsx accessibility
|
|
||||||
"jsx-a11y/aria-props": 2,
|
|
||||||
"jsx-a11y/aria-proptypes": 2,
|
|
||||||
"jsx-a11y/aria-role": 2,
|
|
||||||
"jsx-a11y/aria-unsupported-elements": 2,
|
|
||||||
"jsx-a11y/heading-has-content": 2,
|
|
||||||
"jsx-a11y/href-no-hash": 2,
|
|
||||||
"jsx-a11y/html-has-lang": 2,
|
|
||||||
"jsx-a11y/img-has-alt": 2,
|
|
||||||
"jsx-a11y/img-redundant-alt": 2,
|
|
||||||
"jsx-a11y/label-has-for": 2,
|
|
||||||
"jsx-a11y/mouse-events-have-key-events": 2,
|
|
||||||
"jsx-a11y/no-access-key": 2,
|
|
||||||
"jsx-a11y/no-marquee": 2,
|
|
||||||
"jsx-a11y/no-onchange": 0,
|
|
||||||
"jsx-a11y/onclick-has-focus": 2,
|
|
||||||
"jsx-a11y/onclick-has-role": 2,
|
|
||||||
"jsx-a11y/role-has-required-aria-props": 2,
|
|
||||||
"jsx-a11y/role-supports-aria-props": 2,
|
|
||||||
"jsx-a11y/scope": 2,
|
|
||||||
"jsx-a11y/tabindex-no-positive": 2,
|
|
||||||
|
|
||||||
// react
|
// react
|
||||||
"react/display-name": 0,
|
"react/display-name": 0,
|
||||||
"react/jsx-handler-names": [2, {
|
|
||||||
"eventHandlerPrefix": "_handle"
|
|
||||||
}],
|
|
||||||
"react/jsx-no-bind": 2,
|
"react/jsx-no-bind": 2,
|
||||||
"react/jsx-no-duplicate-props": 2,
|
"react/jsx-no-duplicate-props": 2,
|
||||||
"react/jsx-no-undef": 2,
|
"react/jsx-no-undef": 2,
|
||||||
|
|||||||
14
.flowconfig
Normal file
14
.flowconfig
Normal file
@@ -0,0 +1,14 @@
|
|||||||
|
[ignore]
|
||||||
|
.*/__tests__/.*
|
||||||
|
.*/benchmarks/.*
|
||||||
|
.*/docs/.*
|
||||||
|
.*/node_modules/animated/*
|
||||||
|
.*/node_modules/babel-plugin-transform-react-remove-prop-types/*
|
||||||
|
|
||||||
|
[include]
|
||||||
|
|
||||||
|
[libs]
|
||||||
|
types
|
||||||
|
|
||||||
|
[options]
|
||||||
|
unsafe.enable_getters_and_setters=true
|
||||||
125
.github/CONTRIBUTING.md
vendored
Normal file
125
.github/CONTRIBUTING.md
vendored
Normal file
@@ -0,0 +1,125 @@
|
|||||||
|
# Contributing
|
||||||
|
|
||||||
|
## Reporting Issues and Asking Questions
|
||||||
|
|
||||||
|
Before opening an issue, please search the [issue
|
||||||
|
tracker](https://github.com/necolas/react-native-web/issues) to make sure your
|
||||||
|
issue hasn't already been reported.
|
||||||
|
|
||||||
|
## Getting started
|
||||||
|
|
||||||
|
Visit the [Issue tracker](https://github.com/necolas/react-native-web/issues)
|
||||||
|
to find a list of open issues that need attention.
|
||||||
|
|
||||||
|
Fork, then clone the repo:
|
||||||
|
|
||||||
|
```
|
||||||
|
git clone https://github.com/your-username/react-native-web.git
|
||||||
|
```
|
||||||
|
|
||||||
|
Install dependencies (requires [yarn](https://yarnpkg.com/en/docs/install):
|
||||||
|
|
||||||
|
```
|
||||||
|
yarn
|
||||||
|
```
|
||||||
|
|
||||||
|
## Automated tests
|
||||||
|
|
||||||
|
To run flow:
|
||||||
|
|
||||||
|
```
|
||||||
|
yarn flow
|
||||||
|
```
|
||||||
|
|
||||||
|
To run the unit tests:
|
||||||
|
|
||||||
|
```
|
||||||
|
yarn jest
|
||||||
|
```
|
||||||
|
|
||||||
|
…in watch mode:
|
||||||
|
|
||||||
|
```
|
||||||
|
yarn jest:watch
|
||||||
|
```
|
||||||
|
|
||||||
|
To run all automated tests:
|
||||||
|
|
||||||
|
```
|
||||||
|
yarn test
|
||||||
|
```
|
||||||
|
|
||||||
|
## Visual tests
|
||||||
|
|
||||||
|
To run the interactive storybook:
|
||||||
|
|
||||||
|
```
|
||||||
|
yarn docs:start
|
||||||
|
```
|
||||||
|
|
||||||
|
To generate a static build of the storybook:
|
||||||
|
|
||||||
|
```
|
||||||
|
yarn docs:build
|
||||||
|
```
|
||||||
|
|
||||||
|
To run the performance benchmarks in a browser (opening `./benchmarks/index.html`):
|
||||||
|
|
||||||
|
```
|
||||||
|
yarn benchmark
|
||||||
|
```
|
||||||
|
|
||||||
|
## Compile and build
|
||||||
|
|
||||||
|
To compile the source code to `dist`:
|
||||||
|
|
||||||
|
```
|
||||||
|
yarn compile
|
||||||
|
```
|
||||||
|
|
||||||
|
To create a UMD bundle of the library:
|
||||||
|
|
||||||
|
```
|
||||||
|
yarn build
|
||||||
|
```
|
||||||
|
|
||||||
|
### Pre-commit
|
||||||
|
|
||||||
|
To format and lint code before commit:
|
||||||
|
|
||||||
|
```
|
||||||
|
yarn precommit
|
||||||
|
```
|
||||||
|
|
||||||
|
To format and lint the entire project:
|
||||||
|
|
||||||
|
```
|
||||||
|
yarn fmt
|
||||||
|
yarn lint
|
||||||
|
```
|
||||||
|
|
||||||
|
### New Features
|
||||||
|
|
||||||
|
Please open an issue with a proposal for a new feature or refactoring before
|
||||||
|
starting on the work. We don't want you to waste your efforts on a pull request
|
||||||
|
that we won't want to accept.
|
||||||
|
|
||||||
|
## Pull requests
|
||||||
|
|
||||||
|
**Before submitting a pull request,** please make sure the following is done:
|
||||||
|
|
||||||
|
1. Fork the repository and create your branch from `master`.
|
||||||
|
2. If you've added code that should be tested, add tests!
|
||||||
|
3. If you've changed APIs, update the documentation.
|
||||||
|
4. Ensure the tests pass (`yarn test`).
|
||||||
|
5. Lint and format your code (`yarn fmt && yarn lint`).
|
||||||
|
|
||||||
|
You can now submit a pull request, referencing any issues it addresses.
|
||||||
|
|
||||||
|
Please try to keep your pull request focused in scope and avoid including
|
||||||
|
unrelated commits.
|
||||||
|
|
||||||
|
After you have submitted your pull request, we'll try to get back to you as
|
||||||
|
soon as possible. We may suggest some changes or improvements.
|
||||||
|
|
||||||
|
Thank you for contributing!
|
||||||
34
.github/ISSUE_TEMPLATE.md
vendored
34
.github/ISSUE_TEMPLATE.md
vendored
@@ -1,30 +1,20 @@
|
|||||||
<!--
|
**Do you want to request a *feature* or report a *bug*?**
|
||||||
React Native for Web is an implementation of React Native. If you have feature
|
|
||||||
requests, you should post them to https://productpains.com/product/react-native/.
|
|
||||||
|
|
||||||
GitHub issues should only be used for bugs or Web-specific features you believe
|
|
||||||
React Native requires.
|
|
||||||
|
|
||||||
Make sure to add ALL the information needed to understand the bug so that
|
|
||||||
someone can help. If the info is missing we'll add the 'needs more information'
|
|
||||||
label and close the issue until there is enough information.
|
|
||||||
-->
|
|
||||||
|
|
||||||
**What is the current behavior?**
|
**What is the current behavior?**
|
||||||
|
|
||||||
Link to minimal test case: (template: [codepen](https://codepen.io/necolas/pen/PZzwBR?editors=0010))
|
**If the current behavior is a bug, please provide the steps to reproduce and
|
||||||
|
if a minimal demo of the problem via Glitch or similar (template:
|
||||||
**What is the expected behaviour?**
|
https://glitch.com/edit/#!/react-native-web-playground).**
|
||||||
|
|
||||||
**Steps to reproduce**
|
|
||||||
|
|
||||||
1.
|
1.
|
||||||
2.
|
2.
|
||||||
|
|
||||||
**Environment (include versions)**
|
**What is the expected behavior?**
|
||||||
|
|
||||||
OS:
|
**Environment (include versions). Did this work in previous versions?**
|
||||||
Device:
|
|
||||||
Browser:
|
* OS:
|
||||||
React Native for Web (version):
|
* Device:
|
||||||
React (version):
|
* Browser:
|
||||||
|
* React Native for Web (version):
|
||||||
|
* React (version):
|
||||||
|
|||||||
19
.github/PULL_REQUEST_TEMPLATE.md
vendored
19
.github/PULL_REQUEST_TEMPLATE.md
vendored
@@ -1,18 +1 @@
|
|||||||
<!--
|
**Before submitting a pull request,** please make sure you have followed the steps the CONTRIBUTING guide.
|
||||||
Thanks for submitting a pull request! Make sure the PR does only one thing.
|
|
||||||
Please provide enough information so that others can review your pull
|
|
||||||
request. Make sure you have read the Contributing Guidelines -
|
|
||||||
https://github.com/necolas/react-native-web/CONTRIBUTING.md
|
|
||||||
-->
|
|
||||||
|
|
||||||
**This patch solves the following problem**
|
|
||||||
|
|
||||||
**Test plan**
|
|
||||||
|
|
||||||
**This pull request**
|
|
||||||
|
|
||||||
- [ ] includes documentation
|
|
||||||
- [ ] includes tests
|
|
||||||
- [ ] includes benchmark reports
|
|
||||||
- [ ] includes an interactive example
|
|
||||||
- [ ] includes screenshots/videos
|
|
||||||
|
|||||||
1
.gitignore
vendored
1
.gitignore
vendored
@@ -1,3 +1,2 @@
|
|||||||
node_modules
|
node_modules
|
||||||
dist
|
dist
|
||||||
dist-examples
|
|
||||||
|
|||||||
@@ -5,4 +5,5 @@ before_script:
|
|||||||
- export DISPLAY=:99.0
|
- export DISPLAY=:99.0
|
||||||
- sh -e /etc/init.d/xvfb start
|
- sh -e /etc/init.d/xvfb start
|
||||||
script:
|
script:
|
||||||
|
- npm run lint
|
||||||
- npm test
|
- npm test
|
||||||
|
|||||||
@@ -1,88 +0,0 @@
|
|||||||
# Contributing
|
|
||||||
|
|
||||||
## Reporting Issues and Asking Questions
|
|
||||||
|
|
||||||
Before opening an issue, please search the [issue
|
|
||||||
tracker](https://github.com/necolas/react-native-web/issues) to make sure your
|
|
||||||
issue hasn't already been reported.
|
|
||||||
|
|
||||||
## Development
|
|
||||||
|
|
||||||
Visit the [Issue tracker](https://github.com/necolas/react-native-web/issues)
|
|
||||||
to find a list of open issues that need attention.
|
|
||||||
|
|
||||||
Fork, then clone the repo:
|
|
||||||
|
|
||||||
```
|
|
||||||
git clone https://github.com/your-username/react-native-web.git
|
|
||||||
```
|
|
||||||
|
|
||||||
Install dependencies (requires [yarn](https://yarnpkg.com/en/docs/install):
|
|
||||||
|
|
||||||
```
|
|
||||||
yarn
|
|
||||||
```
|
|
||||||
|
|
||||||
Run the examples:
|
|
||||||
|
|
||||||
```
|
|
||||||
npm run examples
|
|
||||||
```
|
|
||||||
|
|
||||||
Run the benchmarks in a browser by opening `./performance/index.html` after running:
|
|
||||||
|
|
||||||
```
|
|
||||||
npm run build:performance
|
|
||||||
```
|
|
||||||
|
|
||||||
### Building
|
|
||||||
|
|
||||||
```
|
|
||||||
npm run build
|
|
||||||
```
|
|
||||||
|
|
||||||
To create a UMD build:
|
|
||||||
|
|
||||||
```
|
|
||||||
npm run build:umd
|
|
||||||
```
|
|
||||||
|
|
||||||
### Testing and Linting
|
|
||||||
|
|
||||||
To run the tests:
|
|
||||||
|
|
||||||
```
|
|
||||||
npm run test
|
|
||||||
```
|
|
||||||
|
|
||||||
To continuously watch and run tests, run the following:
|
|
||||||
|
|
||||||
```
|
|
||||||
npm run test:watch
|
|
||||||
```
|
|
||||||
|
|
||||||
To perform only linting, run the following:
|
|
||||||
|
|
||||||
```
|
|
||||||
npm run lint
|
|
||||||
```
|
|
||||||
|
|
||||||
### New Features
|
|
||||||
|
|
||||||
Please open an issue with a proposal for a new feature or refactoring before
|
|
||||||
starting on the work. We don't want you to waste your efforts on a pull request
|
|
||||||
that we won't want to accept.
|
|
||||||
|
|
||||||
## Submitting Changes
|
|
||||||
|
|
||||||
* Open a new issue in the [Issue tracker](https://github.com/necolas/react-native-web/issues).
|
|
||||||
* Fork the repo.
|
|
||||||
* Create a new feature branch based off the `master` branch.
|
|
||||||
* Make sure all tests pass and there are no linting errors.
|
|
||||||
* Submit a pull request, referencing any issues it addresses.
|
|
||||||
|
|
||||||
Please try to keep your pull request focused in scope and avoid including unrelated commits.
|
|
||||||
|
|
||||||
After you have submitted your pull request, we'll try to get back to you as soon as possible. We may suggest some changes or improvements.
|
|
||||||
|
|
||||||
Thank you for contributing!
|
|
||||||
132
README.md
132
README.md
@@ -3,102 +3,73 @@
|
|||||||
[![Build Status][travis-image]][travis-url]
|
[![Build Status][travis-image]][travis-url]
|
||||||
[![npm version][npm-image]][npm-url]
|
[![npm version][npm-image]][npm-url]
|
||||||
|
|
||||||
[React Native][react-native-url] components and APIs for the Web.
|
"React Native for Web" brings the platform-agnostic Components and APIs of
|
||||||
|
[React Native][react-native-url] to the Web.
|
||||||
|
|
||||||
Browser support: Chrome, Firefox, Safari >= 7, IE 10, Edge.
|
Browse the [interactive
|
||||||
|
documentation](https://necolas.github.io/react-native-web/storybook/) or [try
|
||||||
|
it out](https://glitch.com/edit/#!/react-native-web-playground) on Glitch.
|
||||||
|
|
||||||
[npm-image]: https://badge.fury.io/js/react-native-web.svg
|
## Features
|
||||||
[npm-url]: https://npmjs.org/package/react-native-web
|
|
||||||
[react-native-url]: https://facebook.github.io/react-native/
|
|
||||||
[travis-image]: https://travis-ci.org/necolas/react-native-web.svg?branch=master
|
|
||||||
[travis-url]: https://travis-ci.org/necolas/react-native-web
|
|
||||||
|
|
||||||
## Overview
|
* Interoperability with ReactDOM components.
|
||||||
|
* Native-like touch handling.
|
||||||
"React Native for Web" is a project to bring React Native's building blocks and
|
* Built-in integration with web accessibility APIs.
|
||||||
touch handling to the Web. [Read more](#why).
|
* Built-in support for LTR and RTL layouts.
|
||||||
|
* Built-in expressive and reliable subset of CSS.
|
||||||
Browse the UI Explorer to see React Native [examples running on
|
* Optimized, vendor-prefixed CSS with [good runtime performance](benchmarks/README.md).
|
||||||
Web](https://necolas.github.io/react-native-web/storybook/). Or try it out
|
* Server-side rendering of HTML and critical CSS.
|
||||||
online with [React Native for Web: Playground](http://codepen.io/necolas/pen/PZzwBR).
|
* Browser support: Chrome, Firefox, Safari >= 7, IE 10, Edge.
|
||||||
|
|
||||||
## Quick start
|
## Quick start
|
||||||
|
|
||||||
To install in your app:
|
NOTE: React Native for Web supports React/ReactDOM 15.4, 15.5, or 15.6.
|
||||||
|
|
||||||
|
Install in your existing app using `yarn` or `npm`:
|
||||||
|
|
||||||
```
|
```
|
||||||
npm install --save react@15.4 react-native-web
|
yarn add react@15.6 react-dom@15.6 react-native-web
|
||||||
```
|
```
|
||||||
|
|
||||||
Read the [Client and Server rendering](docs/guides/rendering.md) guide.
|
Add the `react-native-web/babel` plugin to your Babel configuration. This will
|
||||||
|
alias `react-native` to `react-native-web` and exclude any modules not required
|
||||||
|
by the app.
|
||||||
|
|
||||||
Alternatively, you can quickly setup a local project
|
```json
|
||||||
using [create-react-app](https://github.com/facebookincubator/create-react-app)
|
{
|
||||||
(which supports `react-native-web` out-of-the-box once installed) and
|
"plugins": [
|
||||||
[react-native-web-starter](https://github.com/grabcode/react-native-web-starter).
|
"react-native-web/babel"
|
||||||
|
],
|
||||||
|
"presets": [
|
||||||
|
"react-native"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
See the [Getting Started](docs/guides/getting-started.md) guide for more details.
|
||||||
|
|
||||||
## Documentation
|
## Documentation
|
||||||
|
|
||||||
|
The [interactive
|
||||||
|
documentation](https://necolas.github.io/react-native-web/storybook/) shows all
|
||||||
|
the supported APIs and Components.
|
||||||
|
|
||||||
Guides:
|
Guides:
|
||||||
|
|
||||||
|
* [Getting started](docs/guides/getting-started.md)
|
||||||
|
* [Style](docs/guides/style.md)
|
||||||
* [Accessibility](docs/guides/accessibility.md)
|
* [Accessibility](docs/guides/accessibility.md)
|
||||||
* [Client and server rendering](docs/guides/rendering.md)
|
|
||||||
* [Direct manipulation](docs/guides/direct-manipulation.md)
|
* [Direct manipulation](docs/guides/direct-manipulation.md)
|
||||||
* [Internationalization](docs/guides/internationalization.md)
|
* [Internationalization](docs/guides/internationalization.md)
|
||||||
|
* [Advanced use](docs/guides/advanced.md)
|
||||||
* [Known issues](docs/guides/known-issues.md)
|
* [Known issues](docs/guides/known-issues.md)
|
||||||
* [React Native](docs/guides/react-native.md)
|
|
||||||
* [Style](docs/guides/style.md)
|
|
||||||
|
|
||||||
Exported modules:
|
## Starter kits
|
||||||
|
|
||||||
* Components
|
* [Glitch](https://glitch.com/edit/#!/react-native-web-playground)
|
||||||
* [`ActivityIndicator`](docs/components/ActivityIndicator.md)
|
* [create-react-app](https://github.com/facebookincubator/create-react-app)
|
||||||
* [`Button`](docs/components/Button.md)
|
* [react-native-web-starter](https://github.com/grabcode/react-native-web-starter)
|
||||||
* [`Image`](docs/components/Image.md)
|
* [react-native-web-webpack](https://github.com/ndbroadbent/react-native-web-webpack)
|
||||||
* [`ListView`](docs/components/ListView.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)
|
|
||||||
* [`NativeMethods`](docs/apis/NativeMethods.md)
|
|
||||||
* [`NetInfo`](docs/apis/NetInfo.md)
|
|
||||||
* [`PanResponder`](http://facebook.github.io/react-native/releases/0.20/docs/panresponder.html#content) (mirrors React Native)
|
|
||||||
* [`PixelRatio`](docs/apis/PixelRatio.md)
|
|
||||||
* [`Platform`](docs/apis/Platform.md)
|
|
||||||
* [`StyleSheet`](docs/apis/StyleSheet.md)
|
|
||||||
* [`Vibration`](docs/apis/Vibration.md)
|
|
||||||
|
|
||||||
<span id="#why"></span>
|
|
||||||
|
|
||||||
## Why?
|
|
||||||
|
|
||||||
There are many different teams at Twitter building web applications with React.
|
|
||||||
We want to share React components, libraries, and APIs between teams…much like
|
|
||||||
the OSS community tries to do. At our scale, this involves dealing with
|
|
||||||
multiple, inter-related problems including: a common way to handle style,
|
|
||||||
animation, touch, viewport adaptation, accessibility, themes, RTL layout, and
|
|
||||||
server-rendering.
|
|
||||||
|
|
||||||
This is hard to do with React DOM, as the components are essentially the same
|
|
||||||
low-level building blocks that the browser provides. However, React Native
|
|
||||||
avoids, solves, or can solve almost all these problems facing Web teams.
|
|
||||||
Central to this is React Native's JavaScript style API (not strictly
|
|
||||||
"CSS-in-JS") which avoids the key [problems with
|
|
||||||
CSS](https://speakerdeck.com/vjeux/react-css-in-js) by giving up some of the
|
|
||||||
complexity of CSS.
|
|
||||||
|
|
||||||
## Example code
|
## Example code
|
||||||
|
|
||||||
@@ -141,12 +112,17 @@ AppRegistry.runApplication('MyApp', { rootTag: document.getElementById('react-ro
|
|||||||
|
|
||||||
## Related projects
|
## Related projects
|
||||||
|
|
||||||
* [react-native-web-starter](https://github.com/grabcode/react-native-web-starter)
|
* [react-primitives](https://github.com/lelandrichardson/react-primitives/)
|
||||||
|
* [react-sketchapp](https://github.com/airbnb/react-sketchapp)
|
||||||
|
* [reactxp](https://github.com/microsoft/reactxp)
|
||||||
* [react-native-web-player](https://github.com/dabbott/react-native-web-player)
|
* [react-native-web-player](https://github.com/dabbott/react-native-web-player)
|
||||||
* [react-web](https://github.com/taobaofed/react-web)
|
|
||||||
* [react-native-for-web](https://github.com/KodersLab/react-native-for-web)
|
|
||||||
* [rhinos-app](https://github.com/rhinos-app/rhinos-app-dev)
|
|
||||||
|
|
||||||
## License
|
## License
|
||||||
|
|
||||||
React Native for Web is [BSD licensed](LICENSE).
|
React Native for Web is [BSD licensed](LICENSE).
|
||||||
|
|
||||||
|
[npm-image]: https://badge.fury.io/js/react-native-web.svg
|
||||||
|
[npm-url]: https://npmjs.org/package/react-native-web
|
||||||
|
[react-native-url]: https://facebook.github.io/react-native/
|
||||||
|
[travis-image]: https://travis-ci.org/necolas/react-native-web.svg?branch=master
|
||||||
|
[travis-url]: https://travis-ci.org/necolas/react-native-web
|
||||||
|
|||||||
104
babel/__tests__/__snapshots__/index-test.js.snap
Normal file
104
babel/__tests__/__snapshots__/index-test.js.snap
Normal file
@@ -0,0 +1,104 @@
|
|||||||
|
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||||
|
|
||||||
|
exports[`1. Rewrite react-native paths for react-native-web 1`] = `
|
||||||
|
"
|
||||||
|
import { View } from 'react-native';
|
||||||
|
|
||||||
|
↓ ↓ ↓ ↓ ↓ ↓
|
||||||
|
|
||||||
|
import View from 'react-native-web/dist/components/View';
|
||||||
|
"
|
||||||
|
`;
|
||||||
|
|
||||||
|
exports[`2. Rewrite react-native paths for react-native-web 1`] = `
|
||||||
|
"
|
||||||
|
import { Switch, Text, View as MyView } from 'react-native';
|
||||||
|
|
||||||
|
↓ ↓ ↓ ↓ ↓ ↓
|
||||||
|
|
||||||
|
import Switch from 'react-native-web/dist/components/Switch';
|
||||||
|
import Text from 'react-native-web/dist/components/Text';
|
||||||
|
import MyView from 'react-native-web/dist/components/View';
|
||||||
|
"
|
||||||
|
`;
|
||||||
|
|
||||||
|
exports[`3. Rewrite react-native paths for react-native-web 1`] = `
|
||||||
|
"
|
||||||
|
import { createElement, Switch, StyleSheet } from 'react-native';
|
||||||
|
|
||||||
|
↓ ↓ ↓ ↓ ↓ ↓
|
||||||
|
|
||||||
|
import createElement from 'react-native-web/dist/modules/createElement';
|
||||||
|
import Switch from 'react-native-web/dist/components/Switch';
|
||||||
|
import StyleSheet from 'react-native-web/dist/apis/StyleSheet';
|
||||||
|
"
|
||||||
|
`;
|
||||||
|
|
||||||
|
exports[`4. Rewrite react-native paths for react-native-web 1`] = `
|
||||||
|
"
|
||||||
|
import { InvalidThing, TouchableOpacity } from 'react-native';
|
||||||
|
|
||||||
|
↓ ↓ ↓ ↓ ↓ ↓
|
||||||
|
|
||||||
|
import { InvalidThing } from 'react-native-web';
|
||||||
|
import TouchableOpacity from 'react-native-web/dist/components/Touchable/TouchableOpacity';
|
||||||
|
"
|
||||||
|
`;
|
||||||
|
|
||||||
|
exports[`5. Rewrite react-native paths for react-native-web 1`] = `
|
||||||
|
"
|
||||||
|
import * as RNW from 'react-native';
|
||||||
|
|
||||||
|
↓ ↓ ↓ ↓ ↓ ↓
|
||||||
|
|
||||||
|
import * as RNW from 'react-native-web';
|
||||||
|
"
|
||||||
|
`;
|
||||||
|
|
||||||
|
exports[`6. Rewrite react-native paths for react-native-web 1`] = `
|
||||||
|
"
|
||||||
|
const { View } = require('react-native');
|
||||||
|
|
||||||
|
↓ ↓ ↓ ↓ ↓ ↓
|
||||||
|
|
||||||
|
const View = require('react-native-web/dist/components/View');
|
||||||
|
"
|
||||||
|
`;
|
||||||
|
|
||||||
|
exports[`7. Rewrite react-native paths for react-native-web 1`] = `
|
||||||
|
"
|
||||||
|
let { Switch, Text, View: MyView } = require('react-native');
|
||||||
|
|
||||||
|
↓ ↓ ↓ ↓ ↓ ↓
|
||||||
|
|
||||||
|
let Switch = require('react-native-web/dist/components/Switch');
|
||||||
|
|
||||||
|
let Text = require('react-native-web/dist/components/Text');
|
||||||
|
|
||||||
|
let MyView = require('react-native-web/dist/components/View');
|
||||||
|
"
|
||||||
|
`;
|
||||||
|
|
||||||
|
exports[`8. Rewrite react-native paths for react-native-web 1`] = `
|
||||||
|
"
|
||||||
|
var { createElement, Switch, StyleSheet } = require('react-native');
|
||||||
|
|
||||||
|
↓ ↓ ↓ ↓ ↓ ↓
|
||||||
|
|
||||||
|
var createElement = require('react-native-web/dist/modules/createElement');
|
||||||
|
|
||||||
|
var Switch = require('react-native-web/dist/components/Switch');
|
||||||
|
|
||||||
|
var StyleSheet = require('react-native-web/dist/apis/StyleSheet');
|
||||||
|
"
|
||||||
|
`;
|
||||||
|
|
||||||
|
exports[`9. Rewrite react-native paths for react-native-web 1`] = `
|
||||||
|
"
|
||||||
|
const { InvalidThing, TouchableOpacity } = require('react-native');
|
||||||
|
|
||||||
|
↓ ↓ ↓ ↓ ↓ ↓
|
||||||
|
|
||||||
|
const TouchableOpacity = require('react-native-web/dist/components/Touchable/TouchableOpacity');
|
||||||
|
"
|
||||||
|
`;
|
||||||
39
babel/__tests__/index-test.js
Normal file
39
babel/__tests__/index-test.js
Normal file
@@ -0,0 +1,39 @@
|
|||||||
|
const plugin = require('..');
|
||||||
|
const pluginTester = require('babel-plugin-tester');
|
||||||
|
|
||||||
|
pluginTester({
|
||||||
|
plugin,
|
||||||
|
snapshot: true,
|
||||||
|
tests: [
|
||||||
|
// import react-native
|
||||||
|
"import { View } from 'react-native';",
|
||||||
|
"import { Switch, Text, View as MyView } from 'react-native';",
|
||||||
|
"import { createElement, Switch, StyleSheet } from 'react-native';",
|
||||||
|
"import { InvalidThing, TouchableOpacity } from 'react-native';",
|
||||||
|
"import * as RNW from 'react-native';",
|
||||||
|
|
||||||
|
// import react-native-web
|
||||||
|
// "import { View } from 'react-native-web';",
|
||||||
|
// "import { Switch, Text, View as MyView } from 'react-native-web';",
|
||||||
|
// "import { createElement, Switch, StyleSheet } from 'react-native-web';",
|
||||||
|
// "import { InvalidThing, TouchableOpacity } from 'react-native-web';",
|
||||||
|
// "import * as RNW from 'react-native-web';",
|
||||||
|
|
||||||
|
// require react-native
|
||||||
|
"const { View } = require('react-native');",
|
||||||
|
"let { Switch, Text, View: MyView } = require('react-native');",
|
||||||
|
"var { createElement, Switch, StyleSheet } = require('react-native');",
|
||||||
|
"const { InvalidThing, TouchableOpacity } = require('react-native');",
|
||||||
|
|
||||||
|
// require react-native-web
|
||||||
|
// "const { View } = require('react-native-web');",
|
||||||
|
// "let { Switch, Text, View: MyView } = require('react-native-web');",
|
||||||
|
// "var { createElement, Switch, StyleSheet } = require('react-native-web');",
|
||||||
|
// "const { InvalidThing, TouchableOpacity } = require('react-native-web');",
|
||||||
|
{
|
||||||
|
code: "const RNW = require('react-native');",
|
||||||
|
output: "const RNW = require('react-native');",
|
||||||
|
snapshot: false
|
||||||
|
}
|
||||||
|
]
|
||||||
|
});
|
||||||
148
babel/index.js
Normal file
148
babel/index.js
Normal file
@@ -0,0 +1,148 @@
|
|||||||
|
const getDistLocation = importName => {
|
||||||
|
const root = 'react-native-web/dist';
|
||||||
|
|
||||||
|
switch (importName) {
|
||||||
|
// apis
|
||||||
|
case 'Animated':
|
||||||
|
case 'AppRegistry':
|
||||||
|
case 'AppState':
|
||||||
|
case 'AsyncStorage':
|
||||||
|
case 'BackAndroid':
|
||||||
|
case 'Clipboard':
|
||||||
|
case 'Dimensions':
|
||||||
|
case 'Easing':
|
||||||
|
case 'I18nManager':
|
||||||
|
case 'InteractionManager':
|
||||||
|
case 'Keyboard':
|
||||||
|
case 'Linking':
|
||||||
|
case 'NetInfo':
|
||||||
|
case 'PanResponder':
|
||||||
|
case 'PixelRatio':
|
||||||
|
case 'Platform':
|
||||||
|
case 'StyleSheet':
|
||||||
|
case 'UIManager':
|
||||||
|
case 'Vibration': {
|
||||||
|
return `${root}/apis/${importName}`;
|
||||||
|
}
|
||||||
|
|
||||||
|
// components
|
||||||
|
case 'ActivityIndicator':
|
||||||
|
case 'Button':
|
||||||
|
case 'FlatList':
|
||||||
|
case 'Image':
|
||||||
|
case 'KeyboardAvoidingView':
|
||||||
|
case 'ListView':
|
||||||
|
case 'Modal':
|
||||||
|
case 'Picker':
|
||||||
|
case 'ProgressBar':
|
||||||
|
case 'RefreshControl':
|
||||||
|
case 'ScrollView':
|
||||||
|
case 'SectionList':
|
||||||
|
case 'Slider':
|
||||||
|
case 'StatusBar':
|
||||||
|
case 'Switch':
|
||||||
|
case 'Text':
|
||||||
|
case 'TextInput':
|
||||||
|
case 'View':
|
||||||
|
case 'VirtualizedList': {
|
||||||
|
return `${root}/components/${importName}`;
|
||||||
|
}
|
||||||
|
|
||||||
|
case 'Touchable':
|
||||||
|
case 'TouchableHighlight':
|
||||||
|
case 'TouchableNativeFeedback':
|
||||||
|
case 'TouchableOpacity':
|
||||||
|
case 'TouchableWithoutFeedback': {
|
||||||
|
return `${root}/components/Touchable/${importName}`;
|
||||||
|
}
|
||||||
|
|
||||||
|
// modules
|
||||||
|
case 'createElement':
|
||||||
|
case 'findNodeHandle':
|
||||||
|
case 'NativeModules':
|
||||||
|
case 'processColor':
|
||||||
|
case 'render':
|
||||||
|
case 'unmountComponentAtNode': {
|
||||||
|
return `${root}/modules/${importName}`;
|
||||||
|
}
|
||||||
|
|
||||||
|
// propTypes
|
||||||
|
case 'ColorPropType':
|
||||||
|
case 'EdgeInsetsPropType':
|
||||||
|
case 'PointPropType':
|
||||||
|
case 'TextPropTypes':
|
||||||
|
case 'ViewPropTypes': {
|
||||||
|
return `${root}/propTypes/${importName}`;
|
||||||
|
}
|
||||||
|
|
||||||
|
default:
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const isReactNativeRequire = (t, node) => {
|
||||||
|
const { declarations } = node;
|
||||||
|
if (declarations.length > 1) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
const { id, init } = declarations[0];
|
||||||
|
return (
|
||||||
|
t.isObjectPattern(id) &&
|
||||||
|
t.isCallExpression(init) &&
|
||||||
|
t.isIdentifier(init.callee) &&
|
||||||
|
init.callee.name === 'require' &&
|
||||||
|
init.arguments.length === 1 &&
|
||||||
|
init.arguments[0].value === 'react-native'
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
module.exports = function({ types: t }) {
|
||||||
|
return {
|
||||||
|
name: 'Rewrite react-native paths for react-native-web',
|
||||||
|
visitor: {
|
||||||
|
ImportDeclaration(path) {
|
||||||
|
const { source, specifiers } = path.node;
|
||||||
|
if (source.value === 'react-native' && specifiers.length) {
|
||||||
|
const imports = specifiers
|
||||||
|
.map(specifier => {
|
||||||
|
if (t.isImportSpecifier(specifier)) {
|
||||||
|
const importName = specifier.imported.name;
|
||||||
|
const distLocation = getDistLocation(importName);
|
||||||
|
|
||||||
|
if (distLocation) {
|
||||||
|
return t.importDeclaration(
|
||||||
|
[t.importDefaultSpecifier(t.identifier(specifier.local.name))],
|
||||||
|
t.stringLiteral(distLocation)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return t.importDeclaration([specifier], t.stringLiteral('react-native-web'));
|
||||||
|
})
|
||||||
|
.filter(Boolean);
|
||||||
|
|
||||||
|
path.replaceWithMultiple(imports);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
VariableDeclaration(path) {
|
||||||
|
if (isReactNativeRequire(t, path.node)) {
|
||||||
|
const { id } = path.node.declarations[0];
|
||||||
|
const imports = id.properties
|
||||||
|
.map(identifier => {
|
||||||
|
const distLocation = getDistLocation(identifier.key.name);
|
||||||
|
if (distLocation) {
|
||||||
|
return t.variableDeclaration(path.node.kind, [
|
||||||
|
t.variableDeclarator(
|
||||||
|
t.identifier(identifier.value.name),
|
||||||
|
t.callExpression(t.identifier('require'), [t.stringLiteral(distLocation)])
|
||||||
|
)
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.filter(Boolean);
|
||||||
|
|
||||||
|
path.replaceWithMultiple(imports);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
};
|
||||||
52
benchmarks/README.md
Normal file
52
benchmarks/README.md
Normal file
@@ -0,0 +1,52 @@
|
|||||||
|
# Performance
|
||||||
|
|
||||||
|
To run these benchmarks:
|
||||||
|
|
||||||
|
```
|
||||||
|
npm run build:performance
|
||||||
|
open ./performance/index.html
|
||||||
|
```
|
||||||
|
|
||||||
|
Append `?fastest` to the URL to include the fastest "other libraries", and
|
||||||
|
`?all` to include all the "other libraries".
|
||||||
|
|
||||||
|
## Notes
|
||||||
|
|
||||||
|
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. 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.
|
||||||
|
|
||||||
|
| Implementation | Deep tree (ms) | Wide tree (ms) | Tweets (ms) |
|
||||||
|
| :--- | ---: | ---: | ---: |
|
||||||
|
| `css-modules` | `88.83` `±18.63` | `198.79` `±22.98` | |
|
||||||
|
| `react-native-web/stylesheet@0.0.121` | `91.17` `±19.29` | `209.67` `±32.38` | |
|
||||||
|
| `react-native-web@0.0.121` | `124.21` `±16.84` | `264.55` `±38.75` | `16.90` `±7.30ms` |
|
||||||
|
|
||||||
|
Other libraries
|
||||||
|
|
||||||
|
| Implementation | Deep tree (ms) | Wide tree (ms) |
|
||||||
|
| :--- | ---: | ---: |
|
||||||
|
| `aphrodite@1.2.3` | `91.73` `±41.63` | `197.72` `±44.90` |
|
||||||
|
| `styletron@2.5.1` | `94.73` `±37.58` | `201.81` `±57.93` |
|
||||||
|
| `glamor@2.20.40` | `146.60` `±26.73` | `277.46` `±29.17` |
|
||||||
|
| `emotion@7.2.2` | `150.79` `±38.29` | `282.18` `±41.79` |
|
||||||
|
| `react-jss@7.1.0` | `201.83` `±34.65` | `428.61` `±47.8` |
|
||||||
|
| `reactxp@0.42.1` | `262.69` `±24.14` | `595.20` `±66.17` |
|
||||||
|
| `styled-components@2.1.2` | `280.59` `±31.77` | `599.00` `±62.99` |
|
||||||
|
| `styled-components/primitives@2.1.2` | `291.74` `±48.96` | `606.57` `±78.18` |
|
||||||
|
| `radium@0.19.4` | `563.94` `±69.91` | `1139.18` `±152.59` |
|
||||||
|
|
||||||
|
These results indicate that style render performance is not a significant
|
||||||
|
differentiating factor between `aphrodite`, `css-modules`, `react-native-web`,
|
||||||
|
and `styletron`.
|
||||||
|
|
||||||
|
*MacBook Pro (13-inch, Early 2015); 3.1 GHz Intel Core i7; 16 GB 1867 MHz DDR3. Google Chrome 58 (2x CPU slowdown).
|
||||||
@@ -23,7 +23,7 @@ const median = values => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const numbers = [...values].sort((a, b) => a - b);
|
const numbers = [...values].sort((a, b) => a - b);
|
||||||
return (numbers[numbers.length - 1 >> 1] + numbers[numbers.length >> 1]) / 2;
|
return (numbers[(numbers.length - 1) >> 1] + numbers[numbers.length >> 1]) / 2;
|
||||||
};
|
};
|
||||||
|
|
||||||
const standardDeviation = values => {
|
const standardDeviation = values => {
|
||||||
@@ -5,7 +5,9 @@ const node = document.querySelector('.root');
|
|||||||
|
|
||||||
const createRenderBenchmark = ({ description, getElement, name, runs }) => () => {
|
const createRenderBenchmark = ({ description, getElement, name, runs }) => () => {
|
||||||
const setup = () => {};
|
const setup = () => {};
|
||||||
const teardown = () => ReactDOM.unmountComponentAtNode(node);
|
const teardown = () => {
|
||||||
|
ReactDOM.unmountComponentAtNode(node);
|
||||||
|
};
|
||||||
|
|
||||||
return benchmark({
|
return benchmark({
|
||||||
name,
|
name,
|
||||||
@@ -13,7 +15,9 @@ const createRenderBenchmark = ({ description, getElement, name, runs }) => () =>
|
|||||||
runs,
|
runs,
|
||||||
setup,
|
setup,
|
||||||
teardown,
|
teardown,
|
||||||
task: () => ReactDOM.render(getElement(), node)
|
task: () => {
|
||||||
|
ReactDOM.render(getElement(), node);
|
||||||
|
}
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -2,7 +2,7 @@
|
|||||||
<html lang="en">
|
<html lang="en">
|
||||||
<head>
|
<head>
|
||||||
<meta charset="UTF-8">
|
<meta charset="UTF-8">
|
||||||
<title>Title</title>
|
<title>Performance tests</title>
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
<div class="root"></div>
|
<div class="root"></div>
|
||||||
69
benchmarks/index.js
Normal file
69
benchmarks/index.js
Normal file
@@ -0,0 +1,69 @@
|
|||||||
|
import aphrodite from './src/aphrodite';
|
||||||
|
import cssModules from './src/css-modules';
|
||||||
|
import emotion from './src/emotion';
|
||||||
|
import glamor from './src/glamor';
|
||||||
|
import jss from './src/jss';
|
||||||
|
import radium from './src/radium';
|
||||||
|
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';
|
||||||
|
|
||||||
|
import renderDeepTree from './tests/renderDeepTree';
|
||||||
|
import renderTweet from './tests/renderTweet';
|
||||||
|
import renderWideTree from './tests/renderWideTree';
|
||||||
|
|
||||||
|
const testAll = window.location.search === '?all';
|
||||||
|
const testFastest = window.location.search === '?fastest';
|
||||||
|
|
||||||
|
const coreTests = [
|
||||||
|
() => renderTweet('react-native-web', reactNative),
|
||||||
|
|
||||||
|
() => renderDeepTree('css-modules', cssModules),
|
||||||
|
() => renderWideTree('css-modules', cssModules),
|
||||||
|
() => renderDeepTree('react-native-web/stylesheet', reactNativeStyleSheet),
|
||||||
|
() => renderWideTree('react-native-web/stylesheet', reactNativeStyleSheet),
|
||||||
|
() => renderDeepTree('react-native-web', reactNative),
|
||||||
|
() => renderWideTree('react-native-web', reactNative)
|
||||||
|
];
|
||||||
|
|
||||||
|
const fastestTests = [
|
||||||
|
() => renderDeepTree('aphrodite', aphrodite),
|
||||||
|
() => renderWideTree('aphrodite', aphrodite),
|
||||||
|
() => renderDeepTree('styletron', styletron),
|
||||||
|
() => renderWideTree('styletron', styletron)
|
||||||
|
];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Optionally run tests using other libraries
|
||||||
|
*/
|
||||||
|
const restTests = [
|
||||||
|
() => renderDeepTree('emotion', emotion),
|
||||||
|
() => renderWideTree('emotion', emotion),
|
||||||
|
() => renderDeepTree('glamor', glamor),
|
||||||
|
() => renderWideTree('glamor', glamor),
|
||||||
|
() => renderDeepTree('radium', radium),
|
||||||
|
() => renderWideTree('radium', radium),
|
||||||
|
() => renderDeepTree('reactxp', xp),
|
||||||
|
() => renderWideTree('reactxp', xp),
|
||||||
|
() => renderDeepTree('react-jss', jss),
|
||||||
|
() => renderWideTree('react-jss', jss),
|
||||||
|
() => renderDeepTree('styled-components', styledComponents),
|
||||||
|
() => renderWideTree('styled-components', styledComponents),
|
||||||
|
() => renderDeepTree('styled-components/primitives', styledComponentsPrimitives),
|
||||||
|
() => renderWideTree('styled-components/primitives', styledComponentsPrimitives)
|
||||||
|
];
|
||||||
|
|
||||||
|
const tests = [...coreTests];
|
||||||
|
if (testFastest) {
|
||||||
|
tests.push(...fastestTests);
|
||||||
|
}
|
||||||
|
if (testAll) {
|
||||||
|
tests.push(...fastestTests);
|
||||||
|
tests.push(...restTests);
|
||||||
|
}
|
||||||
|
|
||||||
|
// run benchmarks
|
||||||
|
tests.reduce((promise, test) => promise.then(test()), Promise.resolve());
|
||||||
22
benchmarks/package.json
Normal file
22
benchmarks/package.json
Normal file
@@ -0,0 +1,22 @@
|
|||||||
|
{
|
||||||
|
"name": "benchmarks",
|
||||||
|
"private": true,
|
||||||
|
"dependencies": {
|
||||||
|
"aphrodite": "^1.2.3",
|
||||||
|
"classnames": "^2.2.5",
|
||||||
|
"emotion": "^7.2.2",
|
||||||
|
"glamor": "^2.20.40",
|
||||||
|
"marky": "^1.2.0",
|
||||||
|
"radium": "^0.19.4",
|
||||||
|
"react-jss": "^7.1.0",
|
||||||
|
"react-primitives": "^0.4.3",
|
||||||
|
"reactxp": "^0.42.1",
|
||||||
|
"styled-components": "^2.1.2",
|
||||||
|
"styletron-client": "^2.5.7",
|
||||||
|
"styletron-utils": "^2.5.4"
|
||||||
|
},
|
||||||
|
"devDependencies": {
|
||||||
|
"css-loader": "^0.28.7",
|
||||||
|
"style-loader": "^0.18.2"
|
||||||
|
}
|
||||||
|
}
|
||||||
7
benchmarks/src/aphrodite.js
Normal file
7
benchmarks/src/aphrodite.js
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
import Box from './components/Box/aphrodite';
|
||||||
|
import View from './components/View/aphrodite';
|
||||||
|
|
||||||
|
export default {
|
||||||
|
Box,
|
||||||
|
View
|
||||||
|
};
|
||||||
108
benchmarks/src/components/AppText/index.js
Normal file
108
benchmarks/src/components/AppText/index.js
Normal file
@@ -0,0 +1,108 @@
|
|||||||
|
import PropTypes from 'prop-types';
|
||||||
|
import theme from '../theme';
|
||||||
|
import React, { PureComponent } from 'react';
|
||||||
|
import { StyleSheet, Text } from 'react-native';
|
||||||
|
|
||||||
|
class AppText extends PureComponent {
|
||||||
|
static displayName = 'AppText';
|
||||||
|
|
||||||
|
static propTypes = {
|
||||||
|
align: PropTypes.oneOf(['center', 'left', 'right']),
|
||||||
|
color: PropTypes.oneOf(['blue', 'deepGray', 'normal', 'red', 'white']),
|
||||||
|
fontStyle: PropTypes.oneOf(['normal', 'italic']),
|
||||||
|
size: PropTypes.oneOf(['small', 'normal', 'large']),
|
||||||
|
uppercase: PropTypes.bool,
|
||||||
|
weight: PropTypes.oneOf(['normal', 'bold'])
|
||||||
|
};
|
||||||
|
|
||||||
|
render() {
|
||||||
|
const { align, color, fontStyle, size, uppercase, weight, ...other } = this.props;
|
||||||
|
|
||||||
|
const style = [
|
||||||
|
styles.root,
|
||||||
|
align && alignStyles[align],
|
||||||
|
color && colorStyles[color],
|
||||||
|
fontStyle && fontStyles[fontStyle],
|
||||||
|
size && sizeStyles[size],
|
||||||
|
weight && weightStyles[weight],
|
||||||
|
uppercase === true && styles.uppercase
|
||||||
|
];
|
||||||
|
|
||||||
|
return <Text {...other} style={style} />;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const styles = StyleSheet.create({
|
||||||
|
root: {
|
||||||
|
fontFamily: theme.fontFamily,
|
||||||
|
fontSize: theme.fontSize.normal,
|
||||||
|
fontWeight: 'normal',
|
||||||
|
lineHeight: theme.createLength(theme.lineHeight),
|
||||||
|
wordWrap: 'break-word'
|
||||||
|
},
|
||||||
|
uppercase: {
|
||||||
|
textTransform: 'uppercase'
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
const alignStyles = StyleSheet.create({
|
||||||
|
center: {
|
||||||
|
textAlign: 'center'
|
||||||
|
},
|
||||||
|
left: {
|
||||||
|
textAlign: 'left'
|
||||||
|
},
|
||||||
|
right: {
|
||||||
|
textAlign: 'right'
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
const colorStyles = StyleSheet.create({
|
||||||
|
blue: {
|
||||||
|
color: theme.colors.blue
|
||||||
|
},
|
||||||
|
deepGray: {
|
||||||
|
color: theme.colors.deepGray
|
||||||
|
},
|
||||||
|
normal: {
|
||||||
|
color: theme.colors.textBlack
|
||||||
|
},
|
||||||
|
red: {
|
||||||
|
color: theme.colors.red
|
||||||
|
},
|
||||||
|
white: {
|
||||||
|
color: theme.colors.white
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
const fontStyles = StyleSheet.create({
|
||||||
|
normal: {
|
||||||
|
fontStyle: 'normal'
|
||||||
|
},
|
||||||
|
italic: {
|
||||||
|
fontStyle: 'italic'
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
const sizeStyles = StyleSheet.create({
|
||||||
|
small: {
|
||||||
|
fontSize: theme.fontSize.small
|
||||||
|
},
|
||||||
|
normal: {
|
||||||
|
fontSize: theme.fontSize.normal
|
||||||
|
},
|
||||||
|
large: {
|
||||||
|
fontSize: theme.fontSize.large
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
const weightStyles = StyleSheet.create({
|
||||||
|
normal: {
|
||||||
|
fontWeight: '400'
|
||||||
|
},
|
||||||
|
bold: {
|
||||||
|
fontWeight: 'bold'
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
export default AppText;
|
||||||
41
benchmarks/src/components/AspectRatio/index.js
Normal file
41
benchmarks/src/components/AspectRatio/index.js
Normal file
@@ -0,0 +1,41 @@
|
|||||||
|
import PropTypes from 'prop-types';
|
||||||
|
import React, { PureComponent } from 'react';
|
||||||
|
import { StyleSheet, View } from 'react-native';
|
||||||
|
|
||||||
|
class AspectRatio extends PureComponent {
|
||||||
|
static displayName = 'AspectRatio';
|
||||||
|
|
||||||
|
static propTypes = {
|
||||||
|
children: PropTypes.any,
|
||||||
|
ratio: PropTypes.number,
|
||||||
|
style: PropTypes.object
|
||||||
|
};
|
||||||
|
|
||||||
|
static defaultProps = {
|
||||||
|
ratio: 1
|
||||||
|
};
|
||||||
|
|
||||||
|
render() {
|
||||||
|
const { children, ratio, style } = this.props;
|
||||||
|
const percentage = 100 / ratio;
|
||||||
|
|
||||||
|
return (
|
||||||
|
<View style={[styles.root, style]}>
|
||||||
|
<View style={[styles.shim, { paddingBottom: `${percentage}%` }]} />
|
||||||
|
<View style={StyleSheet.absoluteFill}>{children}</View>
|
||||||
|
</View>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const styles = StyleSheet.create({
|
||||||
|
root: {
|
||||||
|
overflow: 'hidden'
|
||||||
|
},
|
||||||
|
shim: {
|
||||||
|
display: 'block',
|
||||||
|
width: '100%'
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
export default AspectRatio;
|
||||||
49
benchmarks/src/components/Box/aphrodite.js
Normal file
49
benchmarks/src/components/Box/aphrodite.js
Normal file
@@ -0,0 +1,49 @@
|
|||||||
|
/* eslint-disable react/prop-types */
|
||||||
|
import React from 'react';
|
||||||
|
import View from '../View/aphrodite';
|
||||||
|
import { StyleSheet } from 'aphrodite';
|
||||||
|
|
||||||
|
const Box = ({ color, fixed = false, layout = 'column', outer = false, ...other }) => (
|
||||||
|
<View
|
||||||
|
{...other}
|
||||||
|
style={[
|
||||||
|
styles[`color${color}`],
|
||||||
|
fixed && styles.fixed,
|
||||||
|
layout === 'row' && styles.row,
|
||||||
|
outer && styles.outer
|
||||||
|
]}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
|
||||||
|
const styles = StyleSheet.create({
|
||||||
|
outer: {
|
||||||
|
padding: 4
|
||||||
|
},
|
||||||
|
row: {
|
||||||
|
flexDirection: 'row'
|
||||||
|
},
|
||||||
|
color0: {
|
||||||
|
backgroundColor: '#222'
|
||||||
|
},
|
||||||
|
color1: {
|
||||||
|
backgroundColor: '#666'
|
||||||
|
},
|
||||||
|
color2: {
|
||||||
|
backgroundColor: '#999'
|
||||||
|
},
|
||||||
|
color3: {
|
||||||
|
backgroundColor: 'blue'
|
||||||
|
},
|
||||||
|
color4: {
|
||||||
|
backgroundColor: 'orange'
|
||||||
|
},
|
||||||
|
color5: {
|
||||||
|
backgroundColor: 'red'
|
||||||
|
},
|
||||||
|
fixed: {
|
||||||
|
width: 20,
|
||||||
|
height: 20
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
export default Box;
|
||||||
@@ -1,7 +1,7 @@
|
|||||||
/* eslint-disable react/prop-types */
|
/* eslint-disable react/prop-types */
|
||||||
import classnames from 'classnames';
|
import classnames from 'classnames';
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import View from '../View';
|
import View from '../View/css-modules';
|
||||||
import styles from './styles.css';
|
import styles from './styles.css';
|
||||||
|
|
||||||
const Box = ({ color, fixed = false, layout = 'column', outer = false, ...other }) => (
|
const Box = ({ color, fixed = false, layout = 'column', outer = false, ...other }) => (
|
||||||
@@ -15,4 +15,4 @@ const Box = ({ color, fixed = false, layout = 'column', outer = false, ...other
|
|||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
|
|
||||||
module.exports = Box;
|
export default Box;
|
||||||
@@ -1,7 +1,6 @@
|
|||||||
/* eslint-disable react/prop-types */
|
/* eslint-disable react/prop-types */
|
||||||
import { css } from 'glamor';
|
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import View from '../View';
|
import View from '../View/emotion';
|
||||||
|
|
||||||
const Box = ({ color, fixed = false, layout = 'column', outer = false, ...other }) => (
|
const Box = ({ color, fixed = false, layout = 'column', outer = false, ...other }) => (
|
||||||
<View
|
<View
|
||||||
@@ -16,34 +15,34 @@ const Box = ({ color, fixed = false, layout = 'column', outer = false, ...other
|
|||||||
);
|
);
|
||||||
|
|
||||||
const styles = {
|
const styles = {
|
||||||
outer: css({
|
outer: {
|
||||||
padding: 4
|
padding: 4
|
||||||
}),
|
},
|
||||||
row: css({
|
row: {
|
||||||
flexDirection: 'row'
|
flexDirection: 'row'
|
||||||
}),
|
},
|
||||||
color0: css({
|
color0: {
|
||||||
backgroundColor: '#222'
|
backgroundColor: '#222'
|
||||||
}),
|
},
|
||||||
color1: css({
|
color1: {
|
||||||
backgroundColor: '#666'
|
backgroundColor: '#666'
|
||||||
}),
|
},
|
||||||
color2: css({
|
color2: {
|
||||||
backgroundColor: '#999'
|
backgroundColor: '#999'
|
||||||
}),
|
},
|
||||||
color3: css({
|
color3: {
|
||||||
backgroundColor: 'blue'
|
backgroundColor: 'blue'
|
||||||
}),
|
},
|
||||||
color4: css({
|
color4: {
|
||||||
backgroundColor: 'orange'
|
backgroundColor: 'orange'
|
||||||
}),
|
},
|
||||||
color5: css({
|
color5: {
|
||||||
backgroundColor: 'red'
|
backgroundColor: 'red'
|
||||||
}),
|
},
|
||||||
fixed: css({
|
fixed: {
|
||||||
width: 20,
|
width: 20,
|
||||||
height: 20
|
height: 20
|
||||||
})
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
module.exports = Box;
|
export default Box;
|
||||||
48
benchmarks/src/components/Box/glamor.js
Normal file
48
benchmarks/src/components/Box/glamor.js
Normal file
@@ -0,0 +1,48 @@
|
|||||||
|
/* eslint-disable react/prop-types */
|
||||||
|
import React from 'react';
|
||||||
|
import View from '../View/glamor';
|
||||||
|
|
||||||
|
const Box = ({ color, fixed = false, layout = 'column', outer = false, ...other }) => (
|
||||||
|
<View
|
||||||
|
{...other}
|
||||||
|
style={[
|
||||||
|
styles[`color${color}`],
|
||||||
|
fixed && styles.fixed,
|
||||||
|
layout === 'row' && styles.row,
|
||||||
|
outer && styles.outer
|
||||||
|
]}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
|
||||||
|
const styles = {
|
||||||
|
outer: {
|
||||||
|
padding: 4
|
||||||
|
},
|
||||||
|
row: {
|
||||||
|
flexDirection: 'row'
|
||||||
|
},
|
||||||
|
color0: {
|
||||||
|
backgroundColor: '#222'
|
||||||
|
},
|
||||||
|
color1: {
|
||||||
|
backgroundColor: '#666'
|
||||||
|
},
|
||||||
|
color2: {
|
||||||
|
backgroundColor: '#999'
|
||||||
|
},
|
||||||
|
color3: {
|
||||||
|
backgroundColor: 'blue'
|
||||||
|
},
|
||||||
|
color4: {
|
||||||
|
backgroundColor: 'orange'
|
||||||
|
},
|
||||||
|
color5: {
|
||||||
|
backgroundColor: 'red'
|
||||||
|
},
|
||||||
|
fixed: {
|
||||||
|
width: 20,
|
||||||
|
height: 20
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
export default Box;
|
||||||
50
benchmarks/src/components/Box/jss.js
Normal file
50
benchmarks/src/components/Box/jss.js
Normal file
@@ -0,0 +1,50 @@
|
|||||||
|
/* eslint-disable react/prop-types */
|
||||||
|
import classnames from 'classnames';
|
||||||
|
import injectSheet from 'react-jss';
|
||||||
|
import React from 'react';
|
||||||
|
import View from '../View/jss';
|
||||||
|
|
||||||
|
const Box = ({ classes, color, fixed = false, layout = 'column', outer = false, ...other }) => (
|
||||||
|
<View
|
||||||
|
{...other}
|
||||||
|
className={classnames({
|
||||||
|
[classes[`color${color}`]]: true,
|
||||||
|
[classes.fixed]: fixed,
|
||||||
|
[classes.row]: layout === 'row',
|
||||||
|
[classes.outer]: outer
|
||||||
|
})}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
|
||||||
|
const styles = {
|
||||||
|
outer: {
|
||||||
|
padding: 4
|
||||||
|
},
|
||||||
|
row: {
|
||||||
|
flexDirection: 'row'
|
||||||
|
},
|
||||||
|
color0: {
|
||||||
|
backgroundColor: '#222'
|
||||||
|
},
|
||||||
|
color1: {
|
||||||
|
backgroundColor: '#666'
|
||||||
|
},
|
||||||
|
color2: {
|
||||||
|
backgroundColor: '#999'
|
||||||
|
},
|
||||||
|
color3: {
|
||||||
|
backgroundColor: 'blue'
|
||||||
|
},
|
||||||
|
color4: {
|
||||||
|
backgroundColor: 'orange'
|
||||||
|
},
|
||||||
|
color5: {
|
||||||
|
backgroundColor: 'red'
|
||||||
|
},
|
||||||
|
fixed: {
|
||||||
|
width: 20,
|
||||||
|
height: 20
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
export default injectSheet(styles)(Box);
|
||||||
49
benchmarks/src/components/Box/radium.js
Normal file
49
benchmarks/src/components/Box/radium.js
Normal file
@@ -0,0 +1,49 @@
|
|||||||
|
/* eslint-disable react/prop-types */
|
||||||
|
import Radium from 'radium';
|
||||||
|
import React from 'react';
|
||||||
|
import View from '../View/radium';
|
||||||
|
|
||||||
|
const Box = ({ color, fixed = false, layout = 'column', outer = false, ...other }) => (
|
||||||
|
<View
|
||||||
|
{...other}
|
||||||
|
style={[
|
||||||
|
styles[`color${color}`],
|
||||||
|
fixed && styles.fixed,
|
||||||
|
layout === 'row' && styles.row,
|
||||||
|
outer && styles.outer
|
||||||
|
]}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
|
||||||
|
const styles = {
|
||||||
|
outer: {
|
||||||
|
padding: 4
|
||||||
|
},
|
||||||
|
row: {
|
||||||
|
flexDirection: 'row'
|
||||||
|
},
|
||||||
|
color0: {
|
||||||
|
backgroundColor: '#222'
|
||||||
|
},
|
||||||
|
color1: {
|
||||||
|
backgroundColor: '#666'
|
||||||
|
},
|
||||||
|
color2: {
|
||||||
|
backgroundColor: '#999'
|
||||||
|
},
|
||||||
|
color3: {
|
||||||
|
backgroundColor: 'blue'
|
||||||
|
},
|
||||||
|
color4: {
|
||||||
|
backgroundColor: 'orange'
|
||||||
|
},
|
||||||
|
color5: {
|
||||||
|
backgroundColor: 'red'
|
||||||
|
},
|
||||||
|
fixed: {
|
||||||
|
width: 20,
|
||||||
|
height: 20
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
export default Radium(Box);
|
||||||
@@ -1,7 +1,7 @@
|
|||||||
/* eslint-disable react/prop-types */
|
/* eslint-disable react/prop-types */
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import StyleSheet from 'react-native/apis/StyleSheet';
|
import StyleSheet from 'react-native/apis/StyleSheet';
|
||||||
import View from '../View';
|
import View from '../View/react-native-stylesheet';
|
||||||
|
|
||||||
const Box = ({ color, fixed = false, layout = 'column', outer = false, ...other }) => (
|
const Box = ({ color, fixed = false, layout = 'column', outer = false, ...other }) => (
|
||||||
<View
|
<View
|
||||||
@@ -46,4 +46,4 @@ const styles = StyleSheet.create({
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
module.exports = Box;
|
export default Box;
|
||||||
48
benchmarks/src/components/Box/react-native.js
vendored
Normal file
48
benchmarks/src/components/Box/react-native.js
vendored
Normal file
@@ -0,0 +1,48 @@
|
|||||||
|
/* eslint-disable react/prop-types */
|
||||||
|
import React from 'react';
|
||||||
|
import { StyleSheet, View } from 'react-native';
|
||||||
|
|
||||||
|
const Box = ({ color, fixed = false, layout = 'column', outer = false, ...other }) => (
|
||||||
|
<View
|
||||||
|
{...other}
|
||||||
|
style={[
|
||||||
|
styles[`color${color}`],
|
||||||
|
fixed && styles.fixed,
|
||||||
|
layout === 'row' && styles.row,
|
||||||
|
outer && styles.outer
|
||||||
|
]}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
|
||||||
|
const styles = StyleSheet.create({
|
||||||
|
outer: {
|
||||||
|
padding: 4
|
||||||
|
},
|
||||||
|
row: {
|
||||||
|
flexDirection: 'row'
|
||||||
|
},
|
||||||
|
color0: {
|
||||||
|
backgroundColor: '#222'
|
||||||
|
},
|
||||||
|
color1: {
|
||||||
|
backgroundColor: '#666'
|
||||||
|
},
|
||||||
|
color2: {
|
||||||
|
backgroundColor: '#999'
|
||||||
|
},
|
||||||
|
color3: {
|
||||||
|
backgroundColor: 'blue'
|
||||||
|
},
|
||||||
|
color4: {
|
||||||
|
backgroundColor: 'orange'
|
||||||
|
},
|
||||||
|
color5: {
|
||||||
|
backgroundColor: 'red'
|
||||||
|
},
|
||||||
|
fixed: {
|
||||||
|
width: 20,
|
||||||
|
height: 20
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
export default Box;
|
||||||
48
benchmarks/src/components/Box/reactxp.js
Normal file
48
benchmarks/src/components/Box/reactxp.js
Normal file
@@ -0,0 +1,48 @@
|
|||||||
|
/* eslint-disable react/prop-types */
|
||||||
|
import React from 'react';
|
||||||
|
import { Styles, View } from 'reactxp';
|
||||||
|
|
||||||
|
const Box = ({ color, fixed = false, layout = 'column', outer = false, ...other }) => (
|
||||||
|
<View
|
||||||
|
{...other}
|
||||||
|
style={[
|
||||||
|
styles[`color${color}`],
|
||||||
|
fixed && styles.fixed,
|
||||||
|
layout === 'row' && styles.row,
|
||||||
|
outer && styles.outer
|
||||||
|
]}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
|
||||||
|
const styles = {
|
||||||
|
outer: Styles.createViewStyle({
|
||||||
|
padding: 4
|
||||||
|
}),
|
||||||
|
row: Styles.createViewStyle({
|
||||||
|
flexDirection: 'row'
|
||||||
|
}),
|
||||||
|
color0: Styles.createViewStyle({
|
||||||
|
backgroundColor: '#222'
|
||||||
|
}),
|
||||||
|
color1: Styles.createViewStyle({
|
||||||
|
backgroundColor: '#666'
|
||||||
|
}),
|
||||||
|
color2: Styles.createViewStyle({
|
||||||
|
backgroundColor: '#999'
|
||||||
|
}),
|
||||||
|
color3: Styles.createViewStyle({
|
||||||
|
backgroundColor: 'blue'
|
||||||
|
}),
|
||||||
|
color4: Styles.createViewStyle({
|
||||||
|
backgroundColor: 'orange'
|
||||||
|
}),
|
||||||
|
color5: Styles.createViewStyle({
|
||||||
|
backgroundColor: 'red'
|
||||||
|
}),
|
||||||
|
fixed: Styles.createViewStyle({
|
||||||
|
width: 20,
|
||||||
|
height: 20
|
||||||
|
})
|
||||||
|
};
|
||||||
|
|
||||||
|
export default Box;
|
||||||
@@ -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)};
|
||||||
|
`;
|
||||||
|
|
||||||
|
export default Box;
|
||||||
@@ -1,5 +1,5 @@
|
|||||||
import styled from 'styled-components';
|
import styled from 'styled-components';
|
||||||
import View from '../View';
|
import View from '../View/styled-components';
|
||||||
|
|
||||||
const getColor = color => {
|
const getColor = color => {
|
||||||
switch (color) {
|
switch (color) {
|
||||||
@@ -21,11 +21,11 @@ const getColor = color => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
const Box = styled(View)`
|
const Box = styled(View)`
|
||||||
flex-direction: ${props => props.layout === 'column' ? 'column' : 'row'};
|
flex-direction: ${props => (props.layout === 'column' ? 'column' : 'row')};
|
||||||
padding: ${props => props.outer ? '4px' : '0'};
|
padding: ${props => (props.outer ? '4px' : '0')};
|
||||||
height: ${props => props.fixed ? '20px' : 'auto'};
|
height: ${props => (props.fixed ? '20px' : 'auto')};
|
||||||
width: ${props => props.fixed ? '20px' : 'auto'};
|
width: ${props => (props.fixed ? '20px' : 'auto')};
|
||||||
background-color: ${props => getColor(props.color)};
|
background-color: ${props => getColor(props.color)};
|
||||||
`;
|
`;
|
||||||
|
|
||||||
module.exports = Box;
|
export default Box;
|
||||||
49
benchmarks/src/components/Box/styletron.js
Normal file
49
benchmarks/src/components/Box/styletron.js
Normal file
@@ -0,0 +1,49 @@
|
|||||||
|
/* eslint-disable react/prop-types */
|
||||||
|
import { injectStylePrefixed } from 'styletron-utils';
|
||||||
|
import React from 'react';
|
||||||
|
import View, { styletron } from '../View/styletron';
|
||||||
|
|
||||||
|
const Box = ({ color, fixed = false, layout = 'column', outer = false, ...other }) => (
|
||||||
|
<View
|
||||||
|
{...other}
|
||||||
|
style={[
|
||||||
|
styles[`color${color}`],
|
||||||
|
fixed && styles.fixed,
|
||||||
|
layout === 'row' && styles.row,
|
||||||
|
outer && styles.outer
|
||||||
|
]}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
|
||||||
|
const styles = {
|
||||||
|
outer: injectStylePrefixed(styletron, {
|
||||||
|
padding: '4px'
|
||||||
|
}),
|
||||||
|
row: injectStylePrefixed(styletron, {
|
||||||
|
flexDirection: 'row'
|
||||||
|
}),
|
||||||
|
color0: injectStylePrefixed(styletron, {
|
||||||
|
backgroundColor: '#222'
|
||||||
|
}),
|
||||||
|
color1: injectStylePrefixed(styletron, {
|
||||||
|
backgroundColor: '#666'
|
||||||
|
}),
|
||||||
|
color2: injectStylePrefixed(styletron, {
|
||||||
|
backgroundColor: '#999'
|
||||||
|
}),
|
||||||
|
color3: injectStylePrefixed(styletron, {
|
||||||
|
backgroundColor: 'blue'
|
||||||
|
}),
|
||||||
|
color4: injectStylePrefixed(styletron, {
|
||||||
|
backgroundColor: 'orange'
|
||||||
|
}),
|
||||||
|
color5: injectStylePrefixed(styletron, {
|
||||||
|
backgroundColor: 'red'
|
||||||
|
}),
|
||||||
|
fixed: injectStylePrefixed(styletron, {
|
||||||
|
width: '20px',
|
||||||
|
height: '20px'
|
||||||
|
})
|
||||||
|
};
|
||||||
|
|
||||||
|
export default Box;
|
||||||
53
benchmarks/src/components/GridView/index.js
Normal file
53
benchmarks/src/components/GridView/index.js
Normal file
@@ -0,0 +1,53 @@
|
|||||||
|
import PropTypes from 'prop-types';
|
||||||
|
import { StyleSheet, View } from 'react-native';
|
||||||
|
import React, { Component } from 'react';
|
||||||
|
import theme from '../theme';
|
||||||
|
|
||||||
|
class GridView extends Component {
|
||||||
|
static displayName = 'GridView';
|
||||||
|
|
||||||
|
static propTypes = {
|
||||||
|
children: PropTypes.node,
|
||||||
|
hasGap: PropTypes.bool,
|
||||||
|
style: PropTypes.object
|
||||||
|
};
|
||||||
|
|
||||||
|
render() {
|
||||||
|
const { children, hasGap, style, ...other } = this.props;
|
||||||
|
|
||||||
|
return (
|
||||||
|
<View {...other} style={[style, styles.root, hasGap && styles.hasGap]}>
|
||||||
|
{React.Children.map(children, child => {
|
||||||
|
return (
|
||||||
|
child &&
|
||||||
|
React.cloneElement(child, {
|
||||||
|
style: [child.props.style, styles.column, hasGap && styles.hasGapColumn]
|
||||||
|
})
|
||||||
|
);
|
||||||
|
})}
|
||||||
|
</View>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const styles = StyleSheet.create({
|
||||||
|
root: {
|
||||||
|
flexDirection: 'row'
|
||||||
|
},
|
||||||
|
/**
|
||||||
|
* 1. Distribute all space (rather than extra space)
|
||||||
|
* 2. Prevent wide content from forcing wider flex columns
|
||||||
|
*/
|
||||||
|
column: {
|
||||||
|
flexBasis: 0, // 1
|
||||||
|
minWidth: 0 // 2
|
||||||
|
},
|
||||||
|
hasGap: {
|
||||||
|
marginHorizontal: theme.createLength(theme.spaceX * -0.5, 'rem')
|
||||||
|
},
|
||||||
|
hasGapColumn: {
|
||||||
|
marginHorizontal: theme.createLength(theme.spaceX * 0.5, 'rem')
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
export default GridView;
|
||||||
20
benchmarks/src/components/Icons/DirectMessage.js
Normal file
20
benchmarks/src/components/Icons/DirectMessage.js
Normal file
@@ -0,0 +1,20 @@
|
|||||||
|
/* eslint-disable react/prop-types */
|
||||||
|
import { createElement } from 'react-native';
|
||||||
|
import React from 'react';
|
||||||
|
import styles from './styles';
|
||||||
|
|
||||||
|
const IconDirectMessage = props =>
|
||||||
|
createElement('svg', {
|
||||||
|
children: (
|
||||||
|
<g>
|
||||||
|
<path d="M43.34 14H12.66L28 27.946z" />
|
||||||
|
<path d="M51.392 14.789L30.018 34.22c-.009.008-.028.006-.039.012-.563.5-1.266.768-1.98.768-.72 0-1.442-.258-2.017-.78L4.609 14.79A3.957 3.957 0 0 0 3 18v37a1.998 1.998 0 0 0 2 2c.464 0 .924-.162 1.292-.473L19 46h30c2.243 0 4-1.757 4-4V18a3.96 3.96 0 0 0-1.608-3.211z" />
|
||||||
|
</g>
|
||||||
|
),
|
||||||
|
style: [styles.icon, props.style],
|
||||||
|
viewBox: '0 0 56 72'
|
||||||
|
});
|
||||||
|
|
||||||
|
IconDirectMessage.metadata = { height: 72, width: 56 };
|
||||||
|
|
||||||
|
export default IconDirectMessage;
|
||||||
19
benchmarks/src/components/Icons/Heart.js
Normal file
19
benchmarks/src/components/Icons/Heart.js
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
/* eslint-disable react/prop-types */
|
||||||
|
import { createElement } from 'react-native';
|
||||||
|
import React from 'react';
|
||||||
|
import styles from './styles';
|
||||||
|
|
||||||
|
const IconHeart = props =>
|
||||||
|
createElement('svg', {
|
||||||
|
children: (
|
||||||
|
<g>
|
||||||
|
<path d="M38.723 12c-7.187 0-11.16 7.306-11.723 8.131C26.437 19.306 22.504 12 15.277 12 8.791 12 3.533 18.163 3.533 24.647 3.533 39.964 21.891 55.907 27 56c5.109-.093 23.467-16.036 23.467-31.353C50.467 18.163 45.209 12 38.723 12z" />
|
||||||
|
</g>
|
||||||
|
),
|
||||||
|
style: [styles.icon, props.style],
|
||||||
|
viewBox: '0 0 54 72'
|
||||||
|
});
|
||||||
|
|
||||||
|
IconHeart.metadata = { height: 72, width: 54 };
|
||||||
|
|
||||||
|
export default IconHeart;
|
||||||
19
benchmarks/src/components/Icons/Reply.js
Normal file
19
benchmarks/src/components/Icons/Reply.js
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
/* eslint-disable react/prop-types */
|
||||||
|
import { createElement } from 'react-native';
|
||||||
|
import React from 'react';
|
||||||
|
import styles from './styles';
|
||||||
|
|
||||||
|
const IconReply = props =>
|
||||||
|
createElement('svg', {
|
||||||
|
children: (
|
||||||
|
<g>
|
||||||
|
<path d="M41 31h-9V19a2.999 2.999 0 0 0-4.817-2.386l-21 16a3 3 0 0 0-.001 4.773l21 16a3.006 3.006 0 0 0 3.15.301A2.997 2.997 0 0 0 32 51V39h9c5.514 0 10 4.486 10 10a4 4 0 0 0 8 0c0-9.925-8.075-18-18-18z" />
|
||||||
|
</g>
|
||||||
|
),
|
||||||
|
style: [styles.icon, props.style],
|
||||||
|
viewBox: '0 0 62 72'
|
||||||
|
});
|
||||||
|
|
||||||
|
IconReply.metadata = { height: 72, width: 62 };
|
||||||
|
|
||||||
|
export default IconReply;
|
||||||
19
benchmarks/src/components/Icons/Retweet.js
Normal file
19
benchmarks/src/components/Icons/Retweet.js
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
/* eslint-disable react/prop-types */
|
||||||
|
import { createElement } from 'react-native';
|
||||||
|
import React from 'react';
|
||||||
|
import styles from './styles';
|
||||||
|
|
||||||
|
const IconRetweet = props =>
|
||||||
|
createElement('svg', {
|
||||||
|
children: (
|
||||||
|
<g>
|
||||||
|
<path d="M70.676 36.644A3 3 0 0 0 68 35h-7V19a4 4 0 0 0-4-4H34a4 4 0 0 0 0 8h18a1 1 0 0 1 1 .998V35h-7a3.001 3.001 0 0 0-2.419 4.775l11 15a3.003 3.003 0 0 0 4.839-.001l11-15a3.001 3.001 0 0 0 .256-3.13zM40.001 48H22a.995.995 0 0 1-.992-.96L21.001 36h7a3.001 3.001 0 0 0 2.419-4.775l-11-15a3.003 3.003 0 0 0-4.839.001l-11 15A3 3 0 0 0 6.001 36h7l.011 16.003a4 4 0 0 0 4 3.997h22.989a4 4 0 0 0 0-8z" />
|
||||||
|
</g>
|
||||||
|
),
|
||||||
|
style: [styles.icon, props.style],
|
||||||
|
viewBox: '0 0 74 72'
|
||||||
|
});
|
||||||
|
|
||||||
|
IconRetweet.metadata = { height: 72, width: 74 };
|
||||||
|
|
||||||
|
export default IconRetweet;
|
||||||
15
benchmarks/src/components/Icons/styles.js
Normal file
15
benchmarks/src/components/Icons/styles.js
Normal file
@@ -0,0 +1,15 @@
|
|||||||
|
import { StyleSheet } from 'react-native';
|
||||||
|
|
||||||
|
const styles = StyleSheet.create({
|
||||||
|
icon: {
|
||||||
|
display: 'inline-block',
|
||||||
|
fill: 'currentcolor',
|
||||||
|
height: '1.25em',
|
||||||
|
maxWidth: '100%',
|
||||||
|
position: 'relative',
|
||||||
|
userSelect: 'none',
|
||||||
|
verticalAlign: 'text-bottom'
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
export default styles;
|
||||||
58
benchmarks/src/components/NestedTree/index.js
Normal file
58
benchmarks/src/components/NestedTree/index.js
Normal file
@@ -0,0 +1,58 @@
|
|||||||
|
import PropTypes from 'prop-types';
|
||||||
|
import React, { Component } from 'react';
|
||||||
|
|
||||||
|
class DeepTree extends Component {
|
||||||
|
static propTypes = {
|
||||||
|
breadth: PropTypes.number.isRequired,
|
||||||
|
components: PropTypes.object,
|
||||||
|
depth: PropTypes.number.isRequired,
|
||||||
|
id: PropTypes.number.isRequired,
|
||||||
|
wrap: PropTypes.number.isRequired
|
||||||
|
};
|
||||||
|
|
||||||
|
/* necessary for reactxp to work without errors */
|
||||||
|
static childContextTypes = {
|
||||||
|
focusManager: PropTypes.object
|
||||||
|
};
|
||||||
|
|
||||||
|
getChildContext() {
|
||||||
|
return {
|
||||||
|
focusManager: {
|
||||||
|
addFocusableComponent() {},
|
||||||
|
removeFocusableComponent() {},
|
||||||
|
restrictFocusWithin() {},
|
||||||
|
removeFocusRestriction() {},
|
||||||
|
limitFocusWithin() {},
|
||||||
|
removeFocusLimitation() {}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
render() {
|
||||||
|
const { breadth, components, depth, id, wrap } = this.props;
|
||||||
|
const { Box } = components;
|
||||||
|
|
||||||
|
let result = (
|
||||||
|
<Box color={id % 3} components={components} layout={depth % 2 === 0 ? 'column' : 'row'} outer>
|
||||||
|
{depth === 0 && <Box color={id % 3 + 3} components={components} fixed />}
|
||||||
|
{depth !== 0 &&
|
||||||
|
Array.from({ length: breadth }).map((el, i) => (
|
||||||
|
<DeepTree
|
||||||
|
breadth={breadth}
|
||||||
|
components={components}
|
||||||
|
depth={depth - 1}
|
||||||
|
id={i}
|
||||||
|
key={i}
|
||||||
|
wrap={wrap}
|
||||||
|
/>
|
||||||
|
))}
|
||||||
|
</Box>
|
||||||
|
);
|
||||||
|
for (let i = 0; i < wrap; i++) {
|
||||||
|
result = <Box components={components}>{result}</Box>;
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export default DeepTree;
|
||||||
144
benchmarks/src/components/Tweet/index.js
Normal file
144
benchmarks/src/components/Tweet/index.js
Normal file
@@ -0,0 +1,144 @@
|
|||||||
|
import AspectRatio from '../AspectRatio';
|
||||||
|
import GridView from '../GridView';
|
||||||
|
import PropTypes from 'prop-types';
|
||||||
|
import TweetActionsBar from '../TweetActionsBar';
|
||||||
|
import TweetText from '../TweetText';
|
||||||
|
import UserAvatar from '../UserAvatar';
|
||||||
|
import UserNames from '../UserNames';
|
||||||
|
import { Image, StyleSheet, Text, View } from 'react-native';
|
||||||
|
import React, { Component } from 'react';
|
||||||
|
import theme from '../theme';
|
||||||
|
|
||||||
|
export class Tweet extends Component {
|
||||||
|
static displayName = 'Tweet';
|
||||||
|
|
||||||
|
static propTypes = {
|
||||||
|
tweet: PropTypes.object.isRequired
|
||||||
|
};
|
||||||
|
|
||||||
|
render() {
|
||||||
|
const { tweet } = this.props;
|
||||||
|
const { id, lang, media, textParts, timestamp, user } = tweet;
|
||||||
|
const { fullName, profileImageUrl, screenName } = user;
|
||||||
|
|
||||||
|
return (
|
||||||
|
<View accessibilityRole="article" accessible style={styles.root}>
|
||||||
|
<GridView hasGap>
|
||||||
|
<View style={styles.avatarColumn}>
|
||||||
|
<View
|
||||||
|
accessibilityRole="link"
|
||||||
|
accessible
|
||||||
|
href={`/${screenName}`}
|
||||||
|
style={styles.avatarLink}
|
||||||
|
>
|
||||||
|
<UserAvatar style={styles.avatar} uri={profileImageUrl} />
|
||||||
|
</View>
|
||||||
|
</View>
|
||||||
|
|
||||||
|
<View style={styles.bodyColumn}>
|
||||||
|
<View style={styles.body}>
|
||||||
|
<View style={styles.row}>
|
||||||
|
<Text
|
||||||
|
accessibilityRole="link"
|
||||||
|
children={timestamp}
|
||||||
|
href={`/${screenName}/status/${id}`}
|
||||||
|
style={styles.timestamp}
|
||||||
|
/>
|
||||||
|
<UserNames fullName={fullName} screenName={screenName} />
|
||||||
|
</View>
|
||||||
|
|
||||||
|
<View accessibilityRole="heading" aria-level="4">
|
||||||
|
<TweetText displayMode={'links'} lang={lang} textParts={textParts} />
|
||||||
|
</View>
|
||||||
|
|
||||||
|
{media ? (
|
||||||
|
<View style={styles.richContent}>
|
||||||
|
<AspectRatio ratio={16 / 9}>
|
||||||
|
<Image
|
||||||
|
resizeMode={Image.resizeMode.cover}
|
||||||
|
source={media.source}
|
||||||
|
style={styles.media}
|
||||||
|
/>
|
||||||
|
</AspectRatio>
|
||||||
|
</View>
|
||||||
|
) : null}
|
||||||
|
</View>
|
||||||
|
|
||||||
|
<TweetActionsBar
|
||||||
|
actions={[
|
||||||
|
{ name: 'reply', label: 'Reply' },
|
||||||
|
{
|
||||||
|
name: 'retweet',
|
||||||
|
label: 'Retweet',
|
||||||
|
count: tweet.retweet_count,
|
||||||
|
highlighted: tweet.retweeted
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'like',
|
||||||
|
label: 'Like',
|
||||||
|
count: tweet.favorite_count,
|
||||||
|
highlighted: tweet.favorited
|
||||||
|
},
|
||||||
|
{ name: 'directMessage', label: 'Direct Message' }
|
||||||
|
]}
|
||||||
|
style={styles.actionBar}
|
||||||
|
/>
|
||||||
|
</View>
|
||||||
|
</GridView>
|
||||||
|
</View>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const styles = StyleSheet.create({
|
||||||
|
root: {
|
||||||
|
paddingVertical: theme.createLength(theme.spaceY * 0.75, 'rem'),
|
||||||
|
paddingHorizontal: theme.createLength(theme.spaceX, 'rem')
|
||||||
|
},
|
||||||
|
avatarColumn: {
|
||||||
|
flexGrow: 1,
|
||||||
|
minWidth: 32
|
||||||
|
},
|
||||||
|
bodyColumn: {
|
||||||
|
flexGrow: 7
|
||||||
|
},
|
||||||
|
row: {
|
||||||
|
flexDirection: 'row',
|
||||||
|
justifyContent: 'space-between'
|
||||||
|
},
|
||||||
|
avatarLink: {
|
||||||
|
display: 'block',
|
||||||
|
flexShrink: 1,
|
||||||
|
flexGrow: 0,
|
||||||
|
width: '100%'
|
||||||
|
},
|
||||||
|
avatar: {
|
||||||
|
width: '100%'
|
||||||
|
},
|
||||||
|
body: {
|
||||||
|
marginTop: '-0.15rem'
|
||||||
|
},
|
||||||
|
timestamp: {
|
||||||
|
color: theme.colors.deepGray,
|
||||||
|
marginLeft: theme.createLength(theme.spaceX, 'rem'),
|
||||||
|
order: 1,
|
||||||
|
textDecorationLine: 'none',
|
||||||
|
whiteSpace: 'nowrap'
|
||||||
|
},
|
||||||
|
actionBar: {
|
||||||
|
marginTop: theme.createLength(theme.spaceY * 0.5, 'rem')
|
||||||
|
},
|
||||||
|
richContent: {
|
||||||
|
borderRadius: '0.35rem',
|
||||||
|
marginTop: theme.createLength(theme.spaceY * 0.5, 'rem'),
|
||||||
|
overflow: 'hidden'
|
||||||
|
},
|
||||||
|
media: {
|
||||||
|
...StyleSheet.absoluteFillObject,
|
||||||
|
margin: 'auto',
|
||||||
|
width: 'auto',
|
||||||
|
height: 'auto'
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
export default Tweet;
|
||||||
78
benchmarks/src/components/TweetAction/index.js
Normal file
78
benchmarks/src/components/TweetAction/index.js
Normal file
@@ -0,0 +1,78 @@
|
|||||||
|
import IconReply from '../Icons/Reply';
|
||||||
|
import IconHeart from '../Icons/Heart';
|
||||||
|
import IconRetweet from '../Icons/Retweet';
|
||||||
|
import IconDirectMessage from '../Icons/DirectMessage';
|
||||||
|
import PropTypes from 'prop-types';
|
||||||
|
import React from 'react';
|
||||||
|
import theme from '../theme';
|
||||||
|
import { Text, View, StyleSheet } from 'react-native';
|
||||||
|
|
||||||
|
const getIcon = (icon, highlighted) => {
|
||||||
|
switch (icon) {
|
||||||
|
case 'like':
|
||||||
|
return <IconHeart />;
|
||||||
|
case 'reply':
|
||||||
|
return <IconReply />;
|
||||||
|
case 'retweet':
|
||||||
|
return <IconRetweet />;
|
||||||
|
case 'directMessage':
|
||||||
|
return <IconDirectMessage />;
|
||||||
|
default:
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
export default class TweetAction extends React.Component {
|
||||||
|
static displayName = 'TweetAction';
|
||||||
|
|
||||||
|
static propTypes = {
|
||||||
|
count: PropTypes.number,
|
||||||
|
displayMode: PropTypes.oneOf(['like', 'reply', 'retweet', 'directMessage']),
|
||||||
|
highlighted: PropTypes.bool,
|
||||||
|
onPress: PropTypes.func,
|
||||||
|
style: PropTypes.object
|
||||||
|
};
|
||||||
|
|
||||||
|
render() {
|
||||||
|
const { count, displayMode, highlighted, onPress, style } = this.props;
|
||||||
|
|
||||||
|
return (
|
||||||
|
<View accessibilityRole="button" onPress={onPress} style={[styles.root, style]}>
|
||||||
|
<Text
|
||||||
|
style={[
|
||||||
|
styles.inner,
|
||||||
|
displayMode === 'like' && highlighted && styles.likedColor,
|
||||||
|
displayMode === 'retweet' && highlighted && styles.retweetedColor
|
||||||
|
]}
|
||||||
|
>
|
||||||
|
{getIcon(displayMode, highlighted)}
|
||||||
|
{count > 0 ? <Text style={styles.count}>{count}</Text> : null}
|
||||||
|
</Text>
|
||||||
|
</View>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const styles = StyleSheet.create({
|
||||||
|
root: {
|
||||||
|
minHeight: theme.createLength(theme.lineHeight, 'rem'),
|
||||||
|
overflow: 'visible',
|
||||||
|
userSelect: 'none',
|
||||||
|
whiteSpace: 'nowrap'
|
||||||
|
},
|
||||||
|
inner: {
|
||||||
|
alignItems: 'center',
|
||||||
|
color: theme.colors.deepGray,
|
||||||
|
display: 'flex',
|
||||||
|
flexDirection: 'row'
|
||||||
|
},
|
||||||
|
count: {
|
||||||
|
marginLeft: '0.25em'
|
||||||
|
},
|
||||||
|
retweetedColor: {
|
||||||
|
color: theme.colors.green
|
||||||
|
},
|
||||||
|
likedColor: {
|
||||||
|
color: theme.colors.red
|
||||||
|
}
|
||||||
|
});
|
||||||
52
benchmarks/src/components/TweetActionsBar/index.js
Normal file
52
benchmarks/src/components/TweetActionsBar/index.js
Normal file
@@ -0,0 +1,52 @@
|
|||||||
|
import PropTypes from 'prop-types';
|
||||||
|
import TweetAction from '../TweetAction';
|
||||||
|
import { View, StyleSheet } from 'react-native';
|
||||||
|
import React, { PureComponent } from 'react';
|
||||||
|
|
||||||
|
const actionNames = ['reply', 'retweet', 'like', 'directMessage'];
|
||||||
|
|
||||||
|
export default class TweetActionsBar extends PureComponent {
|
||||||
|
static propTypes = {
|
||||||
|
actions: PropTypes.arrayOf(
|
||||||
|
PropTypes.shape({
|
||||||
|
count: PropTypes.number,
|
||||||
|
label: PropTypes.string,
|
||||||
|
highlighted: PropTypes.bool,
|
||||||
|
name: PropTypes.oneOf(actionNames).isRequired,
|
||||||
|
onPress: PropTypes.func
|
||||||
|
})
|
||||||
|
),
|
||||||
|
style: PropTypes.object
|
||||||
|
};
|
||||||
|
|
||||||
|
render() {
|
||||||
|
const { actions, style } = this.props;
|
||||||
|
|
||||||
|
/* eslint-disable react/jsx-handler-names */
|
||||||
|
return (
|
||||||
|
<View style={[styles.root, style]}>
|
||||||
|
{actions.map((action, i) => (
|
||||||
|
<TweetAction
|
||||||
|
accessibilityLabel={actions.label}
|
||||||
|
count={action.count}
|
||||||
|
displayMode={action.name}
|
||||||
|
highlighted={action.highlighted}
|
||||||
|
key={i}
|
||||||
|
onPress={action.onPress}
|
||||||
|
style={styles.action}
|
||||||
|
/>
|
||||||
|
))}
|
||||||
|
</View>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const styles = StyleSheet.create({
|
||||||
|
root: {
|
||||||
|
flexDirection: 'row'
|
||||||
|
},
|
||||||
|
action: {
|
||||||
|
display: 'block',
|
||||||
|
marginRight: '10%'
|
||||||
|
}
|
||||||
|
});
|
||||||
29
benchmarks/src/components/TweetText/index.js
Normal file
29
benchmarks/src/components/TweetText/index.js
Normal file
@@ -0,0 +1,29 @@
|
|||||||
|
import AppText from '../AppText';
|
||||||
|
import React from 'react';
|
||||||
|
import TweetTextPart from '../TweetTextPart';
|
||||||
|
import { array, number, string } from 'prop-types';
|
||||||
|
|
||||||
|
class TweetText extends React.Component {
|
||||||
|
static displayName = 'TweetText';
|
||||||
|
|
||||||
|
static propTypes = {
|
||||||
|
displayMode: TweetTextPart.propTypes.displayMode,
|
||||||
|
lang: string,
|
||||||
|
numberOfLines: number,
|
||||||
|
textParts: array.isRequired
|
||||||
|
};
|
||||||
|
|
||||||
|
render() {
|
||||||
|
const { displayMode, lang, numberOfLines, textParts, ...other } = this.props;
|
||||||
|
|
||||||
|
return (
|
||||||
|
<AppText {...other} lang={lang} numberOfLines={numberOfLines}>
|
||||||
|
{textParts.map((part, i) => (
|
||||||
|
<TweetTextPart displayMode={displayMode} key={i} part={part} />
|
||||||
|
))}
|
||||||
|
</AppText>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export default TweetText;
|
||||||
113
benchmarks/src/components/TweetTextPart/index.js
Normal file
113
benchmarks/src/components/TweetTextPart/index.js
Normal file
@@ -0,0 +1,113 @@
|
|||||||
|
/* eslint-disable react/prop-types */
|
||||||
|
import { Image, StyleSheet, Text } from 'react-native';
|
||||||
|
import PropTypes from 'prop-types';
|
||||||
|
import React from 'react';
|
||||||
|
import theme from '../theme';
|
||||||
|
|
||||||
|
const createTextEntity = ({ part }) => <Text>{`${part.prefix}${part.text}`}</Text>;
|
||||||
|
|
||||||
|
const createTwemojiEntity = ({ part }) => (
|
||||||
|
<Image
|
||||||
|
accessibilityLabel={part.text}
|
||||||
|
draggable={false}
|
||||||
|
source={{ uri: part.emoji }}
|
||||||
|
style={styles.twemoji}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
|
||||||
|
// @mention, #hashtag, $cashtag
|
||||||
|
const createSymbolEntity = ({ displayMode, part }) => {
|
||||||
|
const links = displayMode === 'links';
|
||||||
|
return (
|
||||||
|
<Text accessibilityRole={links ? 'link' : null} href={part.url} style={[links && styles.link]}>
|
||||||
|
{`${part.prefix}${part.text}`}
|
||||||
|
</Text>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
// internal links
|
||||||
|
const createLinkEntity = ({ displayMode, part }) => {
|
||||||
|
const { displayUrl, linkRelation, url } = part;
|
||||||
|
const links = displayMode === 'links';
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Text
|
||||||
|
accessibilityRole={links ? 'link' : null}
|
||||||
|
href={url}
|
||||||
|
rel={links ? linkRelation : null}
|
||||||
|
style={[links && styles.link]}
|
||||||
|
>
|
||||||
|
{displayUrl}
|
||||||
|
</Text>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
// external links
|
||||||
|
const createExternalLinkEntity = ({ displayMode, part }) => {
|
||||||
|
const { displayUrl, linkRelation, url } = part;
|
||||||
|
const links = displayMode === 'links';
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Text
|
||||||
|
accessibilityRole={links ? 'link' : null}
|
||||||
|
href={url}
|
||||||
|
rel={links ? linkRelation : null}
|
||||||
|
style={[links && styles.link]}
|
||||||
|
target="_blank"
|
||||||
|
>
|
||||||
|
{displayUrl}
|
||||||
|
</Text>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
class TweetTextPart extends React.Component {
|
||||||
|
static displayName = 'TweetTextPart';
|
||||||
|
|
||||||
|
static propTypes = {
|
||||||
|
displayMode: PropTypes.oneOf(['links', 'no-links']),
|
||||||
|
part: PropTypes.object
|
||||||
|
};
|
||||||
|
|
||||||
|
static defaultProps = {
|
||||||
|
displayMode: 'links'
|
||||||
|
};
|
||||||
|
|
||||||
|
render() {
|
||||||
|
let renderer;
|
||||||
|
const { isEmoji, isEntity, isHashtag, isMention, isMedia, isUrl } = this.props.part;
|
||||||
|
|
||||||
|
if (isEmoji || isEntity || isUrl || isMedia) {
|
||||||
|
if (isUrl) {
|
||||||
|
renderer = createExternalLinkEntity;
|
||||||
|
} else if (isHashtag || isMention) {
|
||||||
|
renderer = createSymbolEntity;
|
||||||
|
} else if (isEmoji) {
|
||||||
|
renderer = createTwemojiEntity;
|
||||||
|
} else {
|
||||||
|
renderer = createLinkEntity;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
renderer = createTextEntity;
|
||||||
|
}
|
||||||
|
|
||||||
|
return renderer(this.props);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const styles = StyleSheet.create({
|
||||||
|
link: {
|
||||||
|
color: theme.colors.blue,
|
||||||
|
textDecorationLine: 'none',
|
||||||
|
unicodeBidi: 'embed'
|
||||||
|
},
|
||||||
|
twemoji: {
|
||||||
|
display: 'inline-block',
|
||||||
|
height: '1.25em',
|
||||||
|
width: '1.25em',
|
||||||
|
paddingRight: '0.05em',
|
||||||
|
paddingLeft: '0.1em',
|
||||||
|
verticalAlign: '-0.2em'
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
export default TweetTextPart;
|
||||||
65
benchmarks/src/components/UserAvatar/index.js
Normal file
65
benchmarks/src/components/UserAvatar/index.js
Normal file
@@ -0,0 +1,65 @@
|
|||||||
|
import AspectRatio from '../AspectRatio';
|
||||||
|
import PropTypes from 'prop-types';
|
||||||
|
import { Image, StyleSheet } from 'react-native';
|
||||||
|
import React, { PureComponent } from 'react';
|
||||||
|
import theme from '../theme';
|
||||||
|
|
||||||
|
class UserAvatar extends PureComponent {
|
||||||
|
static displayName = 'UserAvatar';
|
||||||
|
|
||||||
|
static propTypes = {
|
||||||
|
accessibilityLabel: PropTypes.string,
|
||||||
|
circle: PropTypes.bool,
|
||||||
|
style: PropTypes.object,
|
||||||
|
uri: PropTypes.string
|
||||||
|
};
|
||||||
|
|
||||||
|
static defaultProps = {
|
||||||
|
circle: false
|
||||||
|
};
|
||||||
|
|
||||||
|
render() {
|
||||||
|
const { accessibilityLabel, circle, style, uri } = this.props;
|
||||||
|
|
||||||
|
return (
|
||||||
|
<AspectRatio ratio={1} style={[styles.root, style]}>
|
||||||
|
{uri ? (
|
||||||
|
<Image
|
||||||
|
accessibilityLabel={accessibilityLabel}
|
||||||
|
onLoad={this._handleLoad}
|
||||||
|
ref={this._setImageRef}
|
||||||
|
source={{ uri }}
|
||||||
|
style={[styles.image, circle && styles.circle]}
|
||||||
|
/>
|
||||||
|
) : null}
|
||||||
|
</AspectRatio>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
_handleLoad = () => {
|
||||||
|
this._imageRef && this._imageRef.setNativeProps(nativeProps);
|
||||||
|
};
|
||||||
|
|
||||||
|
_setImageRef = component => {
|
||||||
|
this._imageRef = component;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
const nativeProps = { style: { backgroundColor: '#fff' } };
|
||||||
|
|
||||||
|
const styles = StyleSheet.create({
|
||||||
|
root: {
|
||||||
|
borderRadius: '0.35rem'
|
||||||
|
},
|
||||||
|
circle: {
|
||||||
|
borderRadius: '9999px'
|
||||||
|
},
|
||||||
|
image: {
|
||||||
|
backgroundColor: theme.colors.fadedGray,
|
||||||
|
display: 'block',
|
||||||
|
height: '100%',
|
||||||
|
width: '100%'
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
export default UserAvatar;
|
||||||
52
benchmarks/src/components/UserNames/index.js
Normal file
52
benchmarks/src/components/UserNames/index.js
Normal file
@@ -0,0 +1,52 @@
|
|||||||
|
import AppText from '../AppText';
|
||||||
|
import PropTypes from 'prop-types';
|
||||||
|
import { StyleSheet } from 'react-native';
|
||||||
|
import React, { PureComponent } from 'react';
|
||||||
|
|
||||||
|
class UserNames extends PureComponent {
|
||||||
|
static displayName = 'UserNames';
|
||||||
|
|
||||||
|
static propTypes = {
|
||||||
|
fullName: PropTypes.string,
|
||||||
|
layout: PropTypes.oneOf(['nowrap', 'stack']),
|
||||||
|
onPress: PropTypes.func,
|
||||||
|
screenName: PropTypes.string,
|
||||||
|
style: PropTypes.object
|
||||||
|
};
|
||||||
|
|
||||||
|
static defaultProps = {
|
||||||
|
layout: 'nowrap'
|
||||||
|
};
|
||||||
|
|
||||||
|
render() {
|
||||||
|
const { fullName, layout, onPress, screenName, style, ...other } = this.props;
|
||||||
|
|
||||||
|
return (
|
||||||
|
<AppText
|
||||||
|
{...other}
|
||||||
|
color="deepGray"
|
||||||
|
numberOfLines={layout === 'nowrap' ? 1 : null}
|
||||||
|
onPress={onPress}
|
||||||
|
style={[styles.root, style]}
|
||||||
|
>
|
||||||
|
<AppText color="normal" weight="bold">
|
||||||
|
{fullName}
|
||||||
|
</AppText>
|
||||||
|
{layout === 'stack' ? ' \u000A' : ' '}
|
||||||
|
<AppText color="deepGray" style={styles.screenName}>{`@${screenName}`}</AppText>
|
||||||
|
</AppText>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const styles = StyleSheet.create({
|
||||||
|
root: {
|
||||||
|
display: 'inline-block'
|
||||||
|
},
|
||||||
|
screenName: {
|
||||||
|
unicodeBidi: 'embed',
|
||||||
|
writingDirection: 'ltr'
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
export default UserNames;
|
||||||
31
benchmarks/src/components/View/aphrodite.js
Normal file
31
benchmarks/src/components/View/aphrodite.js
Normal file
@@ -0,0 +1,31 @@
|
|||||||
|
/* eslint-disable react/prop-types */
|
||||||
|
import React from 'react';
|
||||||
|
import { css, StyleSheet } from 'aphrodite';
|
||||||
|
|
||||||
|
class View extends React.Component {
|
||||||
|
render() {
|
||||||
|
const { style, ...other } = this.props;
|
||||||
|
return <div {...other} className={css(styles.root, style)} />;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const styles = StyleSheet.create({
|
||||||
|
root: {
|
||||||
|
alignItems: 'stretch',
|
||||||
|
borderWidth: 0,
|
||||||
|
borderStyle: 'solid',
|
||||||
|
boxSizing: 'border-box',
|
||||||
|
display: 'flex',
|
||||||
|
flexBasis: 'auto',
|
||||||
|
flexDirection: 'column',
|
||||||
|
flexShrink: 0,
|
||||||
|
margin: 0,
|
||||||
|
padding: 0,
|
||||||
|
position: 'relative',
|
||||||
|
// fix flexbox bugs
|
||||||
|
minHeight: 0,
|
||||||
|
minWidth: 0
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
export default View;
|
||||||
13
benchmarks/src/components/View/css-modules.js
Normal file
13
benchmarks/src/components/View/css-modules.js
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
/* eslint-disable react/prop-types */
|
||||||
|
import classnames from 'classnames';
|
||||||
|
import React from 'react';
|
||||||
|
import styles from './styles.css';
|
||||||
|
|
||||||
|
class View extends React.Component {
|
||||||
|
render() {
|
||||||
|
const props = this.props;
|
||||||
|
return <div {...props} className={classnames(styles.initial, props.className)} />;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export default View;
|
||||||
29
benchmarks/src/components/View/emotion.js
Normal file
29
benchmarks/src/components/View/emotion.js
Normal file
@@ -0,0 +1,29 @@
|
|||||||
|
/* eslint-disable react/prop-types */
|
||||||
|
import { css } from 'emotion';
|
||||||
|
import React from 'react';
|
||||||
|
|
||||||
|
class View extends React.Component {
|
||||||
|
render() {
|
||||||
|
const { style, ...other } = this.props;
|
||||||
|
return <div {...other} className={css([viewStyle, ...style])} />;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const viewStyle = {
|
||||||
|
alignItems: 'stretch',
|
||||||
|
borderWidth: 0,
|
||||||
|
borderStyle: 'solid',
|
||||||
|
boxSizing: 'border-box',
|
||||||
|
display: 'flex',
|
||||||
|
flexBasis: 'auto',
|
||||||
|
flexDirection: 'column',
|
||||||
|
flexShrink: 0,
|
||||||
|
margin: 0,
|
||||||
|
padding: 0,
|
||||||
|
position: 'relative',
|
||||||
|
// fix flexbox bugs
|
||||||
|
minHeight: 0,
|
||||||
|
minWidth: 0
|
||||||
|
};
|
||||||
|
|
||||||
|
export default View;
|
||||||
@@ -2,7 +2,12 @@
|
|||||||
import { css } from 'glamor';
|
import { css } from 'glamor';
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
|
|
||||||
const View = props => <div {...props} className={css(viewStyle, props.style)} />;
|
class View extends React.Component {
|
||||||
|
render() {
|
||||||
|
const { style, ...other } = this.props;
|
||||||
|
return <div {...other} className={css(viewStyle, ...style)} />;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
const viewStyle = {
|
const viewStyle = {
|
||||||
alignItems: 'stretch',
|
alignItems: 'stretch',
|
||||||
@@ -16,17 +21,9 @@ const viewStyle = {
|
|||||||
margin: 0,
|
margin: 0,
|
||||||
padding: 0,
|
padding: 0,
|
||||||
position: 'relative',
|
position: 'relative',
|
||||||
// button and anchor reset
|
|
||||||
backgroundColor: 'transparent',
|
|
||||||
color: 'inherit',
|
|
||||||
font: 'inherit',
|
|
||||||
textAlign: 'inherit',
|
|
||||||
textDecorationLine: 'none',
|
|
||||||
// list reset
|
|
||||||
listStyle: 'none',
|
|
||||||
// fix flexbox bugs
|
// fix flexbox bugs
|
||||||
minHeight: 0,
|
minHeight: 0,
|
||||||
minWidth: 0
|
minWidth: 0
|
||||||
};
|
};
|
||||||
|
|
||||||
module.exports = View;
|
export default View;
|
||||||
32
benchmarks/src/components/View/jss.js
Normal file
32
benchmarks/src/components/View/jss.js
Normal file
@@ -0,0 +1,32 @@
|
|||||||
|
/* eslint-disable react/prop-types */
|
||||||
|
import classnames from 'classnames';
|
||||||
|
import injectSheet from 'react-jss';
|
||||||
|
import React from 'react';
|
||||||
|
|
||||||
|
class View extends React.Component {
|
||||||
|
render() {
|
||||||
|
const { classes, className, ...other } = this.props;
|
||||||
|
return <div {...other} className={classnames(classes.root, className)} />;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const styles = {
|
||||||
|
root: {
|
||||||
|
alignItems: 'stretch',
|
||||||
|
borderWidth: 0,
|
||||||
|
borderStyle: 'solid',
|
||||||
|
boxSizing: 'border-box',
|
||||||
|
display: 'flex',
|
||||||
|
flexBasis: 'auto',
|
||||||
|
flexDirection: 'column',
|
||||||
|
flexShrink: 0,
|
||||||
|
margin: 0,
|
||||||
|
padding: 0,
|
||||||
|
position: 'relative',
|
||||||
|
// fix flexbox bugs
|
||||||
|
minHeight: 0,
|
||||||
|
minWidth: 0
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
export default injectSheet(styles)(View);
|
||||||
31
benchmarks/src/components/View/radium.js
Normal file
31
benchmarks/src/components/View/radium.js
Normal file
@@ -0,0 +1,31 @@
|
|||||||
|
/* eslint-disable react/prop-types */
|
||||||
|
import Radium from 'radium';
|
||||||
|
import React from 'react';
|
||||||
|
|
||||||
|
class View extends React.Component {
|
||||||
|
render() {
|
||||||
|
const { style, ...other } = this.props;
|
||||||
|
return <div {...other} style={[styles.root, style]} />;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const styles = {
|
||||||
|
root: {
|
||||||
|
alignItems: 'stretch',
|
||||||
|
borderWidth: 0,
|
||||||
|
borderStyle: 'solid',
|
||||||
|
boxSizing: 'border-box',
|
||||||
|
display: 'flex',
|
||||||
|
flexBasis: 'auto',
|
||||||
|
flexDirection: 'column',
|
||||||
|
flexShrink: 0,
|
||||||
|
margin: 0,
|
||||||
|
padding: 0,
|
||||||
|
position: 'relative',
|
||||||
|
// fix flexbox bugs
|
||||||
|
minHeight: 0,
|
||||||
|
minWidth: 0
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
export default Radium(View);
|
||||||
35
benchmarks/src/components/View/react-native-stylesheet.js
vendored
Normal file
35
benchmarks/src/components/View/react-native-stylesheet.js
vendored
Normal file
@@ -0,0 +1,35 @@
|
|||||||
|
/* eslint-disable react/prop-types */
|
||||||
|
import React from 'react';
|
||||||
|
import StyleSheet from 'react-native/apis/StyleSheet';
|
||||||
|
import registry from 'react-native/apis/StyleSheet/registry';
|
||||||
|
|
||||||
|
const emptyObject = {};
|
||||||
|
|
||||||
|
class View extends React.Component {
|
||||||
|
render() {
|
||||||
|
const { style, ...other } = this.props;
|
||||||
|
const styleProps = registry.resolve([styles.root, style]) || emptyObject;
|
||||||
|
return <div {...other} {...styleProps} />;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const styles = StyleSheet.create({
|
||||||
|
root: {
|
||||||
|
alignItems: 'stretch',
|
||||||
|
borderWidth: 0,
|
||||||
|
borderStyle: 'solid',
|
||||||
|
boxSizing: 'border-box',
|
||||||
|
display: 'flex',
|
||||||
|
flexBasis: 'auto',
|
||||||
|
flexDirection: 'column',
|
||||||
|
flexShrink: 0,
|
||||||
|
margin: 0,
|
||||||
|
padding: 0,
|
||||||
|
position: 'relative',
|
||||||
|
// fix flexbox bugs
|
||||||
|
minHeight: 0,
|
||||||
|
minWidth: 0
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
export default View;
|
||||||
@@ -12,14 +12,8 @@ const View = styled.div`
|
|||||||
margin: 0;
|
margin: 0;
|
||||||
padding: 0;
|
padding: 0;
|
||||||
position: relative;
|
position: relative;
|
||||||
background-color: transparent;
|
|
||||||
color: inherit;
|
|
||||||
font: inherit;
|
|
||||||
text-align: inherit;
|
|
||||||
text-decoration: none;
|
|
||||||
list-style: none;
|
|
||||||
min-height: 0;
|
min-height: 0;
|
||||||
min-width: 0;
|
min-width: 0;
|
||||||
`;
|
`;
|
||||||
|
|
||||||
module.exports = View;
|
export default View;
|
||||||
@@ -10,12 +10,6 @@
|
|||||||
margin: 0;
|
margin: 0;
|
||||||
padding: 0;
|
padding: 0;
|
||||||
position: relative;
|
position: relative;
|
||||||
background-color: transparent;
|
|
||||||
color: inherit;
|
|
||||||
font: inherit;
|
|
||||||
text-align: inherit;
|
|
||||||
text-decoration: none;
|
|
||||||
list-style: none;
|
|
||||||
min-height: 0;
|
min-height: 0;
|
||||||
min-width: 0;
|
min-width: 0;
|
||||||
};
|
}
|
||||||
33
benchmarks/src/components/View/styletron.js
Normal file
33
benchmarks/src/components/View/styletron.js
Normal file
@@ -0,0 +1,33 @@
|
|||||||
|
/* eslint-disable react/prop-types */
|
||||||
|
import classnames from 'classnames';
|
||||||
|
import Styletron from 'styletron-client';
|
||||||
|
import { injectStylePrefixed } from 'styletron-utils';
|
||||||
|
import React from 'react';
|
||||||
|
|
||||||
|
export const styletron = new Styletron();
|
||||||
|
|
||||||
|
class View extends React.Component {
|
||||||
|
render() {
|
||||||
|
const { style, ...other } = this.props;
|
||||||
|
return <div {...other} className={classnames(viewStyle, ...style)} />;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const viewStyle = injectStylePrefixed(styletron, {
|
||||||
|
alignItems: 'stretch',
|
||||||
|
borderWidth: '0px',
|
||||||
|
borderStyle: 'solid',
|
||||||
|
boxSizing: 'border-box',
|
||||||
|
display: 'flex',
|
||||||
|
flexBasis: 'auto',
|
||||||
|
flexDirection: 'column',
|
||||||
|
flexShrink: '0',
|
||||||
|
margin: '0px',
|
||||||
|
padding: '0px',
|
||||||
|
position: 'relative',
|
||||||
|
// fix flexbox bugs
|
||||||
|
minHeight: '0px',
|
||||||
|
minWidth: '0px'
|
||||||
|
});
|
||||||
|
|
||||||
|
export default View;
|
||||||
40
benchmarks/src/components/theme.js
Normal file
40
benchmarks/src/components/theme.js
Normal file
@@ -0,0 +1,40 @@
|
|||||||
|
const colors = {
|
||||||
|
blue: '#1B95E0',
|
||||||
|
lightBlue: '#71C9F8',
|
||||||
|
green: '#17BF63',
|
||||||
|
orange: '#F45D22',
|
||||||
|
purple: '#794BC4',
|
||||||
|
red: '#E0245E',
|
||||||
|
white: '#FFFFFF',
|
||||||
|
yellow: '#FFAD1F',
|
||||||
|
deepGray: '#657786',
|
||||||
|
fadedGray: '#E6ECF0',
|
||||||
|
faintGray: '#F5F8FA',
|
||||||
|
gray: '#AAB8C2',
|
||||||
|
lightGray: '#CCD6DD',
|
||||||
|
textBlack: '#14171A'
|
||||||
|
};
|
||||||
|
|
||||||
|
const fontSize = {
|
||||||
|
root: '14px',
|
||||||
|
// font scale
|
||||||
|
small: '0.85rem',
|
||||||
|
normal: '1rem',
|
||||||
|
large: '1.25rem'
|
||||||
|
};
|
||||||
|
|
||||||
|
const theme = {
|
||||||
|
colors,
|
||||||
|
fontFamily:
|
||||||
|
'-apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Ubuntu, "Helvetica Neue", sans-serif, ' +
|
||||||
|
'"Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol"', // emoji fonts
|
||||||
|
fontSize,
|
||||||
|
lineHeight: 1.3125,
|
||||||
|
spaceX: 0.6,
|
||||||
|
spaceY: 1.3125,
|
||||||
|
createLength(num, unit) {
|
||||||
|
return `${num}${unit}`;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
export default theme;
|
||||||
9
benchmarks/src/css-modules.js
Normal file
9
benchmarks/src/css-modules.js
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
import Box from './components/Box/css-modules';
|
||||||
|
import View from './components/View/css-modules';
|
||||||
|
|
||||||
|
const api = {
|
||||||
|
Box,
|
||||||
|
View
|
||||||
|
};
|
||||||
|
|
||||||
|
export default api;
|
||||||
7
benchmarks/src/emotion.js
Normal file
7
benchmarks/src/emotion.js
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
import Box from './components/Box/emotion';
|
||||||
|
import View from './components/View/emotion';
|
||||||
|
|
||||||
|
export default {
|
||||||
|
Box,
|
||||||
|
View
|
||||||
|
};
|
||||||
7
benchmarks/src/glamor.js
Normal file
7
benchmarks/src/glamor.js
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
import Box from './components/Box/glamor';
|
||||||
|
import View from './components/View/glamor';
|
||||||
|
|
||||||
|
export default {
|
||||||
|
Box,
|
||||||
|
View
|
||||||
|
};
|
||||||
9
benchmarks/src/jss.js
Normal file
9
benchmarks/src/jss.js
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
import Box from './components/Box/jss';
|
||||||
|
import View from './components/View/jss';
|
||||||
|
|
||||||
|
const api = {
|
||||||
|
Box,
|
||||||
|
View
|
||||||
|
};
|
||||||
|
|
||||||
|
export default api;
|
||||||
9
benchmarks/src/radium.js
Normal file
9
benchmarks/src/radium.js
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
import Box from './components/Box/radium';
|
||||||
|
import View from './components/View/radium';
|
||||||
|
|
||||||
|
const api = {
|
||||||
|
Box,
|
||||||
|
View
|
||||||
|
};
|
||||||
|
|
||||||
|
export default api;
|
||||||
9
benchmarks/src/react-native-stylesheet.js
vendored
Normal file
9
benchmarks/src/react-native-stylesheet.js
vendored
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
import Box from './components/Box/react-native-stylesheet';
|
||||||
|
import View from './components/View/react-native-stylesheet';
|
||||||
|
|
||||||
|
const api = {
|
||||||
|
Box,
|
||||||
|
View
|
||||||
|
};
|
||||||
|
|
||||||
|
export default api;
|
||||||
9
benchmarks/src/react-native.js
vendored
Normal file
9
benchmarks/src/react-native.js
vendored
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
import Box from './components/Box/react-native';
|
||||||
|
import Tweet from './components/Tweet';
|
||||||
|
import { View } from 'react-native';
|
||||||
|
|
||||||
|
export default {
|
||||||
|
Box,
|
||||||
|
Tweet,
|
||||||
|
View
|
||||||
|
};
|
||||||
7
benchmarks/src/reactxp.js
Normal file
7
benchmarks/src/reactxp.js
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
import Box from './components/Box/reactxp';
|
||||||
|
import { View } from 'reactxp';
|
||||||
|
|
||||||
|
export default {
|
||||||
|
Box,
|
||||||
|
View
|
||||||
|
};
|
||||||
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
|
||||||
|
};
|
||||||
7
benchmarks/src/styled-components.js
Normal file
7
benchmarks/src/styled-components.js
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
import Box from './components/Box/styled-components';
|
||||||
|
import View from './components/View/styled-components';
|
||||||
|
|
||||||
|
export default {
|
||||||
|
Box,
|
||||||
|
View
|
||||||
|
};
|
||||||
7
benchmarks/src/styletron.js
Normal file
7
benchmarks/src/styletron.js
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
import Box from './components/Box/styletron';
|
||||||
|
import View from './components/View/styletron';
|
||||||
|
|
||||||
|
export default {
|
||||||
|
Box,
|
||||||
|
View
|
||||||
|
};
|
||||||
14
benchmarks/tests/renderDeepTree.js
Normal file
14
benchmarks/tests/renderDeepTree.js
Normal file
@@ -0,0 +1,14 @@
|
|||||||
|
import createRenderBenchmark from '../createRenderBenchmark';
|
||||||
|
import NestedTree from '../src/components/NestedTree';
|
||||||
|
import React from 'react';
|
||||||
|
|
||||||
|
const renderDeepTree = (label, components) =>
|
||||||
|
createRenderBenchmark({
|
||||||
|
name: `Deep tree [${label}]`,
|
||||||
|
runs: 20,
|
||||||
|
getElement() {
|
||||||
|
return <NestedTree breadth={3} components={components} depth={6} id={0} wrap={1} />;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
export default renderDeepTree;
|
||||||
113
benchmarks/tests/renderTweet.js
Normal file
113
benchmarks/tests/renderTweet.js
Normal file
@@ -0,0 +1,113 @@
|
|||||||
|
import createRenderBenchmark from '../createRenderBenchmark';
|
||||||
|
import Tweet from '../src/components/Tweet';
|
||||||
|
import React from 'react';
|
||||||
|
|
||||||
|
const tweet1 = {
|
||||||
|
favorite_count: 30,
|
||||||
|
favorited: true,
|
||||||
|
id: '834889712556875776',
|
||||||
|
lang: 'en',
|
||||||
|
retweet_count: 6,
|
||||||
|
retweeted: false,
|
||||||
|
textParts: [
|
||||||
|
{
|
||||||
|
prefix: '',
|
||||||
|
text: 'Living burrito to burrito '
|
||||||
|
},
|
||||||
|
{
|
||||||
|
emoji: 'https://abs-0.twimg.com/emoji/v2/svg/1f32f.svg',
|
||||||
|
isEmoji: true,
|
||||||
|
prefix: '',
|
||||||
|
text: '🌯'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
emoji: 'https://abs-0.twimg.com/emoji/v2/svg/1f32f.svg',
|
||||||
|
isEmoji: true,
|
||||||
|
prefix: '',
|
||||||
|
text: '🌯'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
emoji: 'https://abs-0.twimg.com/emoji/v2/svg/1f32f.svg',
|
||||||
|
isEmoji: true,
|
||||||
|
prefix: '',
|
||||||
|
text: '🌯'
|
||||||
|
}
|
||||||
|
],
|
||||||
|
timestamp: 'Feb 23',
|
||||||
|
user: {
|
||||||
|
fullName: 'Nicolas',
|
||||||
|
screenName: 'necolas',
|
||||||
|
profileImageUrl: 'https://pbs.twimg.com/profile_images/804365942360719360/dQnPejph_normal.jpg'
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const tweet2 = {
|
||||||
|
favorite_count: 84,
|
||||||
|
favorited: false,
|
||||||
|
id: '730896800060579840',
|
||||||
|
lang: 'en',
|
||||||
|
media: {
|
||||||
|
source: {
|
||||||
|
uri: 'https://pbs.twimg.com/media/CiSqvsJVEAAtLZ1.jpg',
|
||||||
|
width: 600,
|
||||||
|
height: 338
|
||||||
|
}
|
||||||
|
},
|
||||||
|
retweet_count: 4,
|
||||||
|
retweeted: true,
|
||||||
|
textParts: [
|
||||||
|
{
|
||||||
|
prefix: '',
|
||||||
|
text: 'Presenting '
|
||||||
|
},
|
||||||
|
{
|
||||||
|
displayUrl: 'mobile.twitter.com',
|
||||||
|
expandedUrl: 'https://mobile.twitter.com',
|
||||||
|
isEntity: true,
|
||||||
|
isUrl: true,
|
||||||
|
linkRelation: 'nofollow',
|
||||||
|
prefix: '',
|
||||||
|
text: '',
|
||||||
|
textDirection: 'ltr',
|
||||||
|
url: 'https://t.co/4hRCAxiUUG'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
prefix: '',
|
||||||
|
text: ' with '
|
||||||
|
},
|
||||||
|
{
|
||||||
|
isEntity: true,
|
||||||
|
isMention: true,
|
||||||
|
prefix: '@',
|
||||||
|
text: 'davidbellona',
|
||||||
|
textDirection: 'ltr',
|
||||||
|
url: '/davidbellona'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
prefix: '',
|
||||||
|
text: " at Twitter's all hands meeting "
|
||||||
|
}
|
||||||
|
],
|
||||||
|
timestamp: 'May 12',
|
||||||
|
user: {
|
||||||
|
fullName: 'Nicolas',
|
||||||
|
screenName: 'necolas',
|
||||||
|
profileImageUrl: 'https://pbs.twimg.com/profile_images/804365942360719360/dQnPejph_normal.jpg'
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const renderTweet = label =>
|
||||||
|
createRenderBenchmark({
|
||||||
|
name: `Tweet [${label}]`,
|
||||||
|
runs: 10,
|
||||||
|
getElement() {
|
||||||
|
return (
|
||||||
|
<div style={{ width: 500 }}>
|
||||||
|
<Tweet tweet={tweet1} />
|
||||||
|
<Tweet tweet={tweet2} />
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
export default renderTweet;
|
||||||
14
benchmarks/tests/renderWideTree.js
Normal file
14
benchmarks/tests/renderWideTree.js
Normal file
@@ -0,0 +1,14 @@
|
|||||||
|
import createRenderBenchmark from '../createRenderBenchmark';
|
||||||
|
import NestedTree from '../src/components/NestedTree';
|
||||||
|
import React from 'react';
|
||||||
|
|
||||||
|
const renderWideTree = (label, components) =>
|
||||||
|
createRenderBenchmark({
|
||||||
|
name: `Wide tree [${label}]`,
|
||||||
|
runs: 20,
|
||||||
|
getElement() {
|
||||||
|
return <NestedTree breadth={10} components={components} depth={3} id={0} wrap={4} />;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
export default renderWideTree;
|
||||||
@@ -10,17 +10,25 @@ module.exports = {
|
|||||||
filename: 'performance.bundle.js'
|
filename: 'performance.bundle.js'
|
||||||
},
|
},
|
||||||
module: {
|
module: {
|
||||||
loaders: [
|
rules: [
|
||||||
{
|
{
|
||||||
test: /\.css$/,
|
test: /\.css$/,
|
||||||
loader: 'style-loader!css-loader?module&localIdentName=[hash:base64:8]'
|
use: [
|
||||||
|
'style-loader',
|
||||||
|
{
|
||||||
|
loader: 'css-loader',
|
||||||
|
options: { module: true, localIdentName: '[hash:base64:8]' }
|
||||||
|
}
|
||||||
|
]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
test: /\.js$/,
|
test: /\.js$/,
|
||||||
exclude: /node_modules/,
|
exclude: /node_modules/,
|
||||||
loader: 'babel-loader',
|
use: {
|
||||||
query: {
|
loader: 'babel-loader',
|
||||||
cacheDirectory: true
|
options: {
|
||||||
|
cacheDirectory: true
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
@@ -33,13 +41,11 @@ module.exports = {
|
|||||||
new webpack.DefinePlugin({
|
new webpack.DefinePlugin({
|
||||||
'process.env.NODE_ENV': JSON.stringify('production')
|
'process.env.NODE_ENV': JSON.stringify('production')
|
||||||
}),
|
}),
|
||||||
new webpack.optimize.DedupePlugin(),
|
|
||||||
new webpack.optimize.OccurenceOrderPlugin(),
|
|
||||||
new webpack.optimize.UglifyJsPlugin({
|
new webpack.optimize.UglifyJsPlugin({
|
||||||
compress: {
|
compress: {
|
||||||
dead_code: true,
|
dead_code: true,
|
||||||
screw_ie8: true,
|
screw_ie8: true,
|
||||||
warnings: true
|
warnings: false
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
],
|
],
|
||||||
File diff suppressed because it is too large
Load Diff
@@ -3,8 +3,7 @@
|
|||||||
`AppRegistry` is the control point for registering, running, prerendering, and
|
`AppRegistry` is the control point for registering, running, prerendering, and
|
||||||
unmounting all apps. App root components should register themselves with
|
unmounting all apps. App root components should register themselves with
|
||||||
`AppRegistry.registerComponent`. Apps can be run by invoking
|
`AppRegistry.registerComponent`. Apps can be run by invoking
|
||||||
`AppRegistry.runApplication` (see the [client and server rendering
|
`AppRegistry.runApplication` (see the [getting started guide](../guides/getting-started.md) for more details).
|
||||||
guide](../guides/rendering.md) for more details).
|
|
||||||
|
|
||||||
To "stop" an application when a view should be destroyed, call
|
To "stop" an application when a view should be destroyed, call
|
||||||
`AppRegistry.unmountApplicationComponentAtRootTag` with the tag that was passed
|
`AppRegistry.unmountApplicationComponentAtRootTag` with the tag that was passed
|
||||||
@@ -15,8 +14,7 @@ into `runApplication`. These should always be used as a pair.
|
|||||||
(web) static **getApplication**(appKey:string, appParameters: object)
|
(web) static **getApplication**(appKey:string, appParameters: object)
|
||||||
|
|
||||||
Returns the given application element. Use this for server-side rendering.
|
Returns the given application element. Use this for server-side rendering.
|
||||||
Return object is of type `{ element: ReactElement; stylesheet: ReactElement }`.
|
Return object is of type `{ element: ReactElement; stylesheets: [ ReactElement ] }`.
|
||||||
It's recommended that you use `sheetsheet` to render the style sheet in an app
|
|
||||||
|
|
||||||
static **registerConfig**(config: Array<AppConfig>)
|
static **registerConfig**(config: Array<AppConfig>)
|
||||||
|
|
||||||
@@ -42,6 +40,9 @@ Runs the application that was registered under `appKey`. The `appParameters`
|
|||||||
must include the `rootTag` into which the application is rendered, and
|
must include the `rootTag` into which the application is rendered, and
|
||||||
optionally any `initialProps`.
|
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)
|
static **unmountApplicationComponentAtRootTag**(rootTag: HTMLElement)
|
||||||
|
|
||||||
To "stop" an application when a view should be destroyed, call
|
To "stop" an application when a view should be destroyed, call
|
||||||
|
|||||||
@@ -1,42 +0,0 @@
|
|||||||
# NativeMethods
|
|
||||||
|
|
||||||
React Native for Web provides several methods to directly access the underlying
|
|
||||||
DOM node. This can be useful in cases when you want to focus a view or measure
|
|
||||||
its on-screen dimensions, for example.
|
|
||||||
|
|
||||||
The methods described are available on most of the default components provided
|
|
||||||
by React Native for Web. Note, however, that they are *not* available on the
|
|
||||||
composite components that you define in your own app. For more information, see
|
|
||||||
[Direct Manipulation](../guides/direct-manipulation.md).
|
|
||||||
|
|
||||||
## Methods
|
|
||||||
|
|
||||||
**blur**()
|
|
||||||
|
|
||||||
Removes focus from an input or view. This is the opposite of `focus()`.
|
|
||||||
|
|
||||||
**focus**()
|
|
||||||
|
|
||||||
Requests focus for the given input or view. The exact behavior triggered will
|
|
||||||
depend the type of view.
|
|
||||||
|
|
||||||
**measure**(callback: (x, y, width, height, pageX, pageY) => void)
|
|
||||||
|
|
||||||
For a given view, `measure` determines the offset relative to the parent view,
|
|
||||||
width, height, and the offset relative to the viewport. Returns the values via
|
|
||||||
an async callback.
|
|
||||||
|
|
||||||
Note that these measurements are not available until after the rendering has
|
|
||||||
been completed.
|
|
||||||
|
|
||||||
**measureLayout**(relativeToNativeNode: DOMNode, onSuccess: (x, y, width, height) => void)
|
|
||||||
|
|
||||||
Like `measure`, but measures the view relative to another view, specified as
|
|
||||||
`relativeToNativeNode`. This means that the returned `x`, `y` are relative to
|
|
||||||
the origin `x`, `y` of the ancestor view.
|
|
||||||
|
|
||||||
**setNativeProps**(nativeProps: Object)
|
|
||||||
|
|
||||||
This function sends props straight to the underlying DOM node. See the [direct
|
|
||||||
manipulation](../guides/direct-manipulation.md) guide for cases where
|
|
||||||
`setNativeProps` should be used.
|
|
||||||
@@ -32,7 +32,7 @@ static **removeEventListener**(eventName: ChangeEventName, handler: Function)
|
|||||||
**isConnected**: bool = true
|
**isConnected**: bool = true
|
||||||
|
|
||||||
Available on all user agents. Asynchronously fetch a boolean to determine
|
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)
|
**isConnected.addEventListener**(eventName: ChangeEventName, handler: Function)
|
||||||
|
|
||||||
|
|||||||
@@ -1,9 +1,10 @@
|
|||||||
# StyleSheet
|
# StyleSheet
|
||||||
|
|
||||||
The `StyleSheet` abstraction converts predefined styles to (vendor-prefixed)
|
The `StyleSheet` abstraction converts predefined styles to (vendor-prefixed)
|
||||||
CSS without requiring a compile-time step. Some styles cannot be resolved
|
CSS without requiring a compile-time step. Styles that cannot be resolved
|
||||||
outside of the render loop and are applied as inline styles. Read more about
|
outside of the render loop (e.g., dynamic positioning) are usually applied as
|
||||||
[how to style your application](../guides/style.md).
|
inline styles. Read more about [how to style your
|
||||||
|
application](../guides/style.md).
|
||||||
|
|
||||||
## Methods
|
## Methods
|
||||||
|
|
||||||
@@ -15,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.
|
Flattens an array of styles into a single style object.
|
||||||
|
|
||||||
**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
|
## Properties
|
||||||
|
|
||||||
|
|||||||
@@ -4,19 +4,19 @@
|
|||||||
|
|
||||||
[...View props](./View.md)
|
[...View props](./View.md)
|
||||||
|
|
||||||
**animating**: bool = true
|
**animating**: boolean = true
|
||||||
|
|
||||||
Whether to show the indicator or hide it.
|
Whether to show the indicator or hide it.
|
||||||
|
|
||||||
**color**: string = '#1976D2'
|
**color**: ?color = '#1976D2'
|
||||||
|
|
||||||
The foreground color of the spinner.
|
The foreground color of the spinner.
|
||||||
|
|
||||||
**hidesWhenStopped**: bool = true
|
**hidesWhenStopped**: ?boolean = true
|
||||||
|
|
||||||
Whether the indicator should hide when not animating.
|
Whether the indicator should hide when not animating.
|
||||||
|
|
||||||
**size**: oneOf('small, 'large') | number = 'small'
|
**size**: ?enum('small, 'large') | number = 'small'
|
||||||
|
|
||||||
Size of the indicator. Small has a height of `20`, large has a height of `36`.
|
Size of the indicator. Small has a height of `20`, large has a height of `36`.
|
||||||
|
|
||||||
|
|||||||
@@ -6,23 +6,27 @@ build your own custom button using `TouchableOpacity` or
|
|||||||
|
|
||||||
## Props
|
## Props
|
||||||
|
|
||||||
**accessibilityLabel**: string
|
**accessibilityLabel**: ?string
|
||||||
|
|
||||||
Defines the text available to assistive technologies upon interaction with the
|
Overrides the text that's read by a screen reader when the user interacts
|
||||||
element. (This is implemented using `aria-label`.)
|
with the element.
|
||||||
|
|
||||||
**color**: string
|
**color**: ?string
|
||||||
|
|
||||||
Background color of the button.
|
Background color of the button.
|
||||||
|
|
||||||
**disabled**: bool = false
|
**disabled**: ?boolean
|
||||||
|
|
||||||
If true, disable all interactions for this component
|
If `true`, disable all interactions for this element.
|
||||||
|
|
||||||
**onPress**: function
|
**onPress**: function
|
||||||
|
|
||||||
This function is called on press.
|
This function is called on press.
|
||||||
|
|
||||||
|
**testID**: ?string
|
||||||
|
|
||||||
|
Used to locate this view in end-to-end tests.
|
||||||
|
|
||||||
**title**: string
|
**title**: string
|
||||||
|
|
||||||
Text to display inside the button.
|
Text to display inside the button.
|
||||||
|
|||||||
@@ -9,65 +9,66 @@ Unsupported React Native props:
|
|||||||
|
|
||||||
## Props
|
## Props
|
||||||
|
|
||||||
**accessibilityLabel**: string
|
**accessibilityLabel**: ?string
|
||||||
|
|
||||||
The text that's read by a screenreader when someone interacts with the image.
|
The text that's read by a screenreader when someone interacts with the image.
|
||||||
|
|
||||||
**accessible**: bool
|
**accessible**: ?boolean
|
||||||
|
|
||||||
When `false`, the view is hidden from screenreaders. Default: `true`.
|
When `true`, indicates the image is an accessibility element.
|
||||||
|
|
||||||
**children**: any
|
**children**: ?any
|
||||||
|
|
||||||
Content to display over the image.
|
Content to display over the image.
|
||||||
|
|
||||||
**defaultSource**: { uri: string }
|
**defaultSource**: ?object
|
||||||
|
|
||||||
An image to display as a placeholder while downloading the final image off the network.
|
An image to display as a placeholder while downloading the final image off the
|
||||||
|
network. `{ uri: string, width, height }`
|
||||||
|
|
||||||
**onError**: function
|
**onError**: ?function
|
||||||
|
|
||||||
Invoked on load error with `{nativeEvent: {error}}`.
|
Invoked on load error with `{nativeEvent: {error}}`.
|
||||||
|
|
||||||
**onLayout**: function
|
**onLayout**: ?function
|
||||||
|
|
||||||
Invoked on mount and layout changes with `{ nativeEvent: { layout: { x, y, width,
|
Invoked on mount and layout changes with `{ nativeEvent: { layout: { x, y, width,
|
||||||
height } } }`, where `x` and `y` are the offsets from the parent node.
|
height } } }`, where `x` and `y` are the offsets from the parent node.
|
||||||
|
|
||||||
**onLoad**: function
|
**onLoad**: ?function
|
||||||
|
|
||||||
Invoked when load completes successfully.
|
Invoked when load completes successfully.
|
||||||
|
|
||||||
**onLoadEnd**: function
|
**onLoadEnd**: ?function
|
||||||
|
|
||||||
Invoked when load either succeeds or fails,
|
Invoked when load either succeeds or fails,
|
||||||
|
|
||||||
**onLoadStart**: function
|
**onLoadStart**: ?function
|
||||||
|
|
||||||
Invoked on load start.
|
Invoked on load start.
|
||||||
|
|
||||||
**resizeMode**: oneOf('center', 'contain', 'cover', 'none', 'repeat', 'stretch') = 'cover'
|
**resizeMode**: ?enum('center', 'contain', 'cover', 'none', 'repeat', 'stretch') = 'cover'
|
||||||
|
|
||||||
Determines how to resize the image when the frame doesn't match the raw image
|
Determines how to resize the image when the frame doesn't match the raw image
|
||||||
dimensions.
|
dimensions.
|
||||||
|
|
||||||
**source**: { uri: string }
|
**source**: ?object
|
||||||
|
|
||||||
`uri` is a string representing the resource identifier for the image, which
|
`uri` is a string representing the resource identifier for the image, which
|
||||||
could be an http address or a base64 encoded image.
|
could be an http address or a base64 encoded image. `{ uri: string, width, height }`
|
||||||
|
|
||||||
**style**: style
|
**style**: ?style
|
||||||
|
|
||||||
+ ...[View#style](./View.md)
|
+ ...[View#style](./View.md)
|
||||||
+ `resizeMode`
|
+ `resizeMode`
|
||||||
|
|
||||||
**testID**: string
|
**testID**: ?string
|
||||||
|
|
||||||
Used to locate a view in end-to-end tests.
|
Used to locate a view in end-to-end tests.
|
||||||
|
|
||||||
## Properties
|
## Properties
|
||||||
|
|
||||||
static **resizeMode**: Object
|
static **resizeMode**: object
|
||||||
|
|
||||||
Example usage:
|
Example usage:
|
||||||
|
|
||||||
|
|||||||
@@ -1,34 +0,0 @@
|
|||||||
# ListView
|
|
||||||
|
|
||||||
TODO
|
|
||||||
|
|
||||||
## Props
|
|
||||||
|
|
||||||
[...ScrollView props](./ScrollView.md)
|
|
||||||
|
|
||||||
**children**: any
|
|
||||||
|
|
||||||
Content to display over the image.
|
|
||||||
|
|
||||||
**style**: style
|
|
||||||
|
|
||||||
+ ...[View#style](View.md)
|
|
||||||
|
|
||||||
## Examples
|
|
||||||
|
|
||||||
```js
|
|
||||||
import React, { Component, PropTypes } from 'react'
|
|
||||||
import { ListView } from 'react-native'
|
|
||||||
|
|
||||||
export default class ListViewExample extends Component {
|
|
||||||
static propTypes = {}
|
|
||||||
|
|
||||||
static defaultProps = {}
|
|
||||||
|
|
||||||
render() {
|
|
||||||
return (
|
|
||||||
<ListView />
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
```
|
|
||||||
@@ -6,18 +6,22 @@ Display an activity progress bar.
|
|||||||
|
|
||||||
[...View props](./View.md)
|
[...View props](./View.md)
|
||||||
|
|
||||||
**color**: string = '#1976D2'
|
**color**: ?string = '#1976D2'
|
||||||
|
|
||||||
Color of the progress bar.
|
Color of the progress bar.
|
||||||
|
|
||||||
**indeterminate**: bool = true
|
**indeterminate**: ?boolean = true
|
||||||
|
|
||||||
Whether the progress bar will show indeterminate progress.
|
Whether the progress bar will show indeterminate progress.
|
||||||
|
|
||||||
**progress**: number
|
**progress**: ?number
|
||||||
|
|
||||||
The progress value (between 0 and 1).
|
The progress value (between 0 and 1).
|
||||||
|
|
||||||
(web) **trackColor**: string = 'transparent'
|
**testID**: ?string
|
||||||
|
|
||||||
|
Used to locate this view in end-to-end tests.
|
||||||
|
|
||||||
|
(web) **trackColor**: ?string = 'transparent'
|
||||||
|
|
||||||
Color of the track bar.
|
Color of the track bar.
|
||||||
|
|||||||
@@ -9,17 +9,17 @@ view directly (discouraged) or make sure all parent views have bounded height
|
|||||||
|
|
||||||
[...View props](./View.md)
|
[...View props](./View.md)
|
||||||
|
|
||||||
**contentContainerStyle**: style
|
**contentContainerStyle**: ?style
|
||||||
|
|
||||||
These styles will be applied to the scroll view content container which wraps
|
These styles will be applied to the scroll view content container which wraps
|
||||||
all of the child views.
|
all of the child views.
|
||||||
|
|
||||||
**horizontal**: bool = false
|
**horizontal**: ?boolean = false
|
||||||
|
|
||||||
When true, the scroll view's children are arranged horizontally in a row
|
When `true`, the scroll view's children are arranged horizontally in a row
|
||||||
instead of vertically in a column.
|
instead of vertically in a column.
|
||||||
|
|
||||||
**keyboardDismissMode**: oneOf('none', 'on-drag') = 'none'
|
**keyboardDismissMode**: ?enum('none', 'on-drag') = 'none'
|
||||||
|
|
||||||
Determines whether the keyboard gets dismissed in response to a scroll drag.
|
Determines whether the keyboard gets dismissed in response to a scroll drag.
|
||||||
|
|
||||||
@@ -27,13 +27,13 @@ Determines whether the keyboard gets dismissed in response to a scroll drag.
|
|||||||
* `on-drag`, the keyboard is dismissed when a drag begins.
|
* `on-drag`, the keyboard is dismissed when a drag begins.
|
||||||
* `interactive` (not supported on web; same as `none`)
|
* `interactive` (not supported on web; same as `none`)
|
||||||
|
|
||||||
**onContentSizeChange**: function
|
**onContentSizeChange**: ?function
|
||||||
|
|
||||||
Called when scrollable content view of the `ScrollView` changes. It's
|
Called when scrollable content view of the `ScrollView` changes. It's
|
||||||
implemented using the `onLayout` handler attached to the content container
|
implemented using the `onLayout` handler attached to the content container
|
||||||
which this `ScrollView` renders.
|
which this `ScrollView` renders.
|
||||||
|
|
||||||
**onScroll**: function
|
**onScroll**: ?function
|
||||||
|
|
||||||
Fires at most once per frame during scrolling. The frequency of the events can
|
Fires at most once per frame during scrolling. The frequency of the events can
|
||||||
be contolled using the `scrollEventThrottle` prop.
|
be contolled using the `scrollEventThrottle` prop.
|
||||||
@@ -50,18 +50,18 @@ Invoked on scroll with the following event:
|
|||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
**refreshControl**: element
|
**refreshControl**: ?element
|
||||||
|
|
||||||
TODO
|
TODO
|
||||||
|
|
||||||
A [RefreshControl](../RefreshControl) component, used to provide
|
A [RefreshControl](../RefreshControl) component, used to provide
|
||||||
pull-to-refresh functionality for the `ScrollView`.
|
pull-to-refresh functionality for the `ScrollView`.
|
||||||
|
|
||||||
**scrollEnabled**: bool = true
|
**scrollEnabled**: ?boolean = true
|
||||||
|
|
||||||
When false, the content does not scroll.
|
When false, the content does not scroll.
|
||||||
|
|
||||||
**scrollEventThrottle**: number = 0
|
**scrollEventThrottle**: ?number = 0
|
||||||
|
|
||||||
This controls how often the scroll event will be fired while scrolling (as a
|
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
|
time interval in ms). A lower number yields better accuracy for code that is
|
||||||
|
|||||||
@@ -9,31 +9,31 @@ supplied `value` prop instead of the expected result of any user actions.
|
|||||||
|
|
||||||
[...View props](./View.md)
|
[...View props](./View.md)
|
||||||
|
|
||||||
**disabled**: bool = false
|
**disabled**: ?boolean = false
|
||||||
|
|
||||||
If `true` the user won't be able to interact with the switch.
|
If `true` the user won't be able to interact with the switch.
|
||||||
|
|
||||||
**onValueChange**: func
|
**onValueChange**: ?function
|
||||||
|
|
||||||
Invoked with the new value when the value changes.
|
Invoked with the new value when the value changes.
|
||||||
|
|
||||||
**value**: bool = false
|
**value**: ?boolean = false
|
||||||
|
|
||||||
The value of the switch. If `true` the switch will be turned on.
|
The value of the switch. If `true` the switch will be turned on.
|
||||||
|
|
||||||
(web) **activeThumbColor**: color = #009688
|
(web) **activeThumbColor**: ?color = #009688
|
||||||
|
|
||||||
The color of the thumb grip when the switch is turned on.
|
The color of the thumb grip when the switch is turned on.
|
||||||
|
|
||||||
(web) **activeTrackColor**: color = #A3D3CF
|
(web) **activeTrackColor**: ?color = #A3D3CF
|
||||||
|
|
||||||
The color of the track when the switch is turned on.
|
The color of the track when the switch is turned on.
|
||||||
|
|
||||||
(web) **thumbColor**: color = #FAFAFA
|
(web) **thumbColor**: ?color = #FAFAFA
|
||||||
|
|
||||||
The color of the thumb grip when the switch is turned off.
|
The color of the thumb grip when the switch is turned off.
|
||||||
|
|
||||||
(web) **trackColor**: color = #939393
|
(web) **trackColor**: ?color = #939393
|
||||||
|
|
||||||
The color of the track when the switch is turned off.
|
The color of the track when the switch is turned off.
|
||||||
|
|
||||||
|
|||||||
@@ -16,49 +16,62 @@ Unsupported React Native props:
|
|||||||
|
|
||||||
NOTE: `Text` will transfer all other props to the rendered HTML element.
|
NOTE: `Text` will transfer all other props to the rendered HTML element.
|
||||||
|
|
||||||
(web) **accessibilityLabel**: string
|
(web) **accessibilityLabel**: ?string
|
||||||
|
|
||||||
Defines the text available to assistive technologies upon interaction with the
|
Overrides the text that's read by a screen reader when the user interacts
|
||||||
element. (This is implemented using `aria-label`.)
|
with the element. (This is implemented using `aria-label`.)
|
||||||
|
|
||||||
(web) **accessibilityRole**: oneOf(roles)
|
See the [Accessibility guide](../guides/accessibility) for more information.
|
||||||
|
|
||||||
|
(web) **accessibilityRole**: ?oneOf(roles)
|
||||||
|
|
||||||
Allows assistive technologies to present and support interaction with the view
|
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
|
in a manner that is consistent with user expectations for similar views of that
|
||||||
type. For example, marking a touchable view with an `accessibilityRole` of
|
type. For example, marking a touchable view with an `accessibilityRole` of
|
||||||
`button`. (This is implemented using [ARIA roles](http://www.w3.org/TR/wai-aria/roles#role_definitions)).
|
`button`. (This is implemented using [ARIA roles](http://www.w3.org/TR/wai-aria/roles#role_definitions)).
|
||||||
|
|
||||||
Note: Avoid changing `accessibilityRole` values over time or after user
|
See the [Accessibility guide](../guides/accessibility) for more information.
|
||||||
actions. Generally, accessibility APIs do not provide a means of notifying
|
|
||||||
assistive technologies of a `role` value change.
|
|
||||||
|
|
||||||
**accessible**: bool = true
|
**accessible**: ?boolean
|
||||||
|
|
||||||
When `false`, the text is hidden from assistive technologies. (This is
|
When `true`, indicates that the view is an accessibility element (i.e.,
|
||||||
implemented using `aria-hidden`.)
|
focusable) and groups its child content. By default, all the touchable elements
|
||||||
|
and elements with `accessibilityRole` of `button` and `link` are accessible.
|
||||||
|
(This is implemented using `tabindex`.)
|
||||||
|
|
||||||
**children**: any
|
See the [Accessibility guide](../guides/accessibility) for more information.
|
||||||
|
|
||||||
|
**children**: ?any
|
||||||
|
|
||||||
Child content.
|
Child content.
|
||||||
|
|
||||||
**numberOfLines**: number
|
**importantForAccessibility**: ?enum('auto', 'no-hide-descendants', 'yes')
|
||||||
|
|
||||||
|
A value of `no` will remove the element from the tab flow.
|
||||||
|
|
||||||
|
A value of `no-hide-descendants` will hide the element and its children from
|
||||||
|
assistive technologies. (This is implemented using `aria-hidden`.)
|
||||||
|
|
||||||
|
See the [Accessibility guide](../guides/accessibility) for more information.
|
||||||
|
|
||||||
|
**numberOfLines**: ?number
|
||||||
|
|
||||||
Truncates the text with an ellipsis after this many lines. Currently only supports `1`.
|
Truncates the text with an ellipsis after this many lines. Currently only supports `1`.
|
||||||
|
|
||||||
**onLayout**: function
|
**onLayout**: ?function
|
||||||
|
|
||||||
Invoked on mount and layout changes with `{ nativeEvent: { layout: { x, y, width,
|
Invoked on mount and layout changes with `{ nativeEvent: { layout: { x, y, width,
|
||||||
height } } }`, where `x` and `y` are the offsets from the parent node.
|
height } } }`, where `x` and `y` are the offsets from the parent node.
|
||||||
|
|
||||||
**onPress**: function
|
**onPress**: ?function
|
||||||
|
|
||||||
This function is called on press.
|
This function is called on press.
|
||||||
|
|
||||||
**selectable**: bool = true
|
**selectable**: ?boolean
|
||||||
|
|
||||||
Lets the user select the text.
|
When `false`, the text is not selectable.
|
||||||
|
|
||||||
**style**: style
|
**style**: ?style
|
||||||
|
|
||||||
+ ...[View#style](View.md)
|
+ ...[View#style](View.md)
|
||||||
+ `color`
|
+ `color`
|
||||||
@@ -72,6 +85,7 @@ Lets the user select the text.
|
|||||||
+ `textAlign`
|
+ `textAlign`
|
||||||
+ `textAlignVertical`
|
+ `textAlignVertical`
|
||||||
+ `textDecorationLine`
|
+ `textDecorationLine`
|
||||||
|
+ `textIndent` ‡
|
||||||
+ `textOverflow` ‡
|
+ `textOverflow` ‡
|
||||||
+ `textRendering` ‡
|
+ `textRendering` ‡
|
||||||
+ `textShadowColor`
|
+ `textShadowColor`
|
||||||
@@ -85,7 +99,7 @@ Lets the user select the text.
|
|||||||
|
|
||||||
‡ web only.
|
‡ web only.
|
||||||
|
|
||||||
**testID**: string
|
**testID**: ?string
|
||||||
|
|
||||||
Used to locate this view in end-to-end tests.
|
Used to locate this view in end-to-end tests.
|
||||||
|
|
||||||
|
|||||||
@@ -18,7 +18,7 @@ Unsupported React Native props:
|
|||||||
|
|
||||||
[...View props](./View.md)
|
[...View props](./View.md)
|
||||||
|
|
||||||
**autoCapitalize**: oneOf('characters', 'none', 'sentences', 'words') = 'sentences'
|
**autoCapitalize**: ?enum('characters', 'none', 'sentences', 'words') = 'sentences'
|
||||||
|
|
||||||
Automatically capitalize certain characters (only available in Chrome and iOS Safari).
|
Automatically capitalize certain characters (only available in Chrome and iOS Safari).
|
||||||
|
|
||||||
@@ -27,21 +27,21 @@ Automatically capitalize certain characters (only available in Chrome and iOS Sa
|
|||||||
* `sentences`: Automatically capitalize the first letter of sentences.
|
* `sentences`: Automatically capitalize the first letter of sentences.
|
||||||
* `words`: Automatically capitalize the first letter of words.
|
* `words`: Automatically capitalize the first letter of words.
|
||||||
|
|
||||||
(web) **autoComplete**: string
|
(web) **autoComplete**: ?string
|
||||||
|
|
||||||
Indicates whether the value of the control can be automatically completed by
|
Indicates whether the value of the control can be automatically completed by
|
||||||
the browser. [Accepted values](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/input).
|
the browser. [Accepted values](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/input).
|
||||||
|
|
||||||
**autoCorrect**: bool = true
|
**autoCorrect**: ?boolean = true
|
||||||
|
|
||||||
Automatically correct spelling mistakes (only available in iOS Safari).
|
Automatically correct spelling mistakes (only available in iOS Safari).
|
||||||
|
|
||||||
**autoFocus**: bool = false
|
**autoFocus**: ?boolean = false
|
||||||
|
|
||||||
If `true`, focuses the input on `componentDidMount`. Only the first form element
|
If `true`, focuses the input on `componentDidMount`. Only the first form element
|
||||||
in a document with `autofocus` is focused.
|
in a document with `autofocus` is focused.
|
||||||
|
|
||||||
**blurOnSubmit**: bool
|
**blurOnSubmit**: ?boolean
|
||||||
|
|
||||||
If `true`, the text field will blur when submitted. The default value is `true`
|
If `true`, the text field will blur when submitted. The default value is `true`
|
||||||
for single-line fields and `false` for multiline fields. Note, for multiline
|
for single-line fields and `false` for multiline fields. Note, for multiline
|
||||||
@@ -49,110 +49,107 @@ fields setting `blurOnSubmit` to `true` means that pressing return will blur
|
|||||||
the field and trigger the `onSubmitEditing` event instead of inserting a
|
the field and trigger the `onSubmitEditing` event instead of inserting a
|
||||||
newline into the field.
|
newline into the field.
|
||||||
|
|
||||||
**clearTextOnFocus**: bool = false
|
**clearTextOnFocus**: ?boolean = false
|
||||||
|
|
||||||
If `true`, clears the text field automatically when focused.
|
If `true`, clears the text field automatically when focused.
|
||||||
|
|
||||||
**defaultValue**: string
|
**defaultValue**: ?string
|
||||||
|
|
||||||
Provides an initial value that will change when the user starts typing. Useful
|
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
|
for simple use-cases where you don't want to deal with listening to events and
|
||||||
updating the `value` prop to keep the controlled state in sync.
|
updating the `value` prop to keep the controlled state in sync.
|
||||||
|
|
||||||
**editable**: bool = true
|
**editable**: ?boolean = true
|
||||||
|
|
||||||
If `false`, text is not editable (i.e., read-only).
|
If `false`, text is not editable (i.e., read-only).
|
||||||
|
|
||||||
**keyboardType**: oneOf('default', 'email-address', 'numeric', 'phone-pad', 'search', 'url', 'web-search') = 'default'
|
**keyboardType**: enum('default', 'email-address', 'numeric', 'phone-pad', 'search', 'url', 'web-search') = 'default'
|
||||||
|
|
||||||
Determines which keyboard to open. (NOTE: Safari iOS requires an ancestral
|
Determines which keyboard to open. (NOTE: Safari iOS requires an ancestral
|
||||||
`<form action>` element to display the `search` keyboard).
|
`<form action>` element to display the `search` keyboard).
|
||||||
|
|
||||||
(Not available when `multiline` is `true`.)
|
(Not available when `multiline` is `true`.)
|
||||||
|
|
||||||
**maxLength**: number
|
**maxLength**: ?number
|
||||||
|
|
||||||
Limits the maximum number of characters that can be entered.
|
Limits the maximum number of characters that can be entered.
|
||||||
|
|
||||||
(web) **maxNumberOfLines**: number = numberOfLines
|
**multiline**: ?boolean = false
|
||||||
|
|
||||||
Limits the maximum number of lines for a multiline `TextInput`.
|
|
||||||
|
|
||||||
(Requires `multiline` to be `true`.)
|
|
||||||
|
|
||||||
**multiline**: bool = false
|
|
||||||
|
|
||||||
If true, the text input can be multiple lines.
|
If true, the text input can be multiple lines.
|
||||||
|
|
||||||
**numberOfLines**: number = 2
|
**numberOfLines**: ?number = 2
|
||||||
|
|
||||||
Sets the initial number of lines for a multiline `TextInput`.
|
Sets the number of lines for a multiline `TextInput`.
|
||||||
|
|
||||||
(Requires `multiline` to be `true`.)
|
(Requires `multiline` to be `true`.)
|
||||||
|
|
||||||
**onBlur**: function
|
**onBlur**: ?function
|
||||||
|
|
||||||
Callback that is called when the text input is blurred.
|
Callback that is called when the text input is blurred.
|
||||||
|
|
||||||
**onChange**: function
|
**onChange**: ?function
|
||||||
|
|
||||||
Callback that is called when the text input's text changes.
|
Callback that is called when the text input's text changes.
|
||||||
|
|
||||||
**onChangeText**: function
|
**onChangeText**: ?function
|
||||||
|
|
||||||
Callback that is called when the text input's text changes. The text is passed
|
Callback that is called when the text input's text changes. The text is passed
|
||||||
as an argument to the callback handler.
|
as an argument to the callback handler.
|
||||||
|
|
||||||
**onFocus**: function
|
**onFocus**: ?function
|
||||||
|
|
||||||
Callback that is called when the text input is focused.
|
Callback that is called when the text input is focused.
|
||||||
|
|
||||||
**onKeyPress**: function
|
**onKeyPress**: ?function
|
||||||
|
|
||||||
Callback that is called when a key is pressed. Pressed key value is passed as
|
Callback that is called when a key is pressed. This will be called with `{
|
||||||
an argument to the callback handler. Fires before `onChange` callbacks.
|
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
|
**onSelectionChange**: ?function
|
||||||
|
|
||||||
Callback that is called when the text input's selection changes. This will be called with
|
Callback that is called when the text input's selection changes. This will be called with
|
||||||
`{ nativeEvent: { selection: { start, end } } }`.
|
`{ nativeEvent: { selection: { start, end } } }`.
|
||||||
|
|
||||||
**onSubmitEditing**: function
|
**onSubmitEditing**: ?function
|
||||||
|
|
||||||
Callback that is called when the keyboard's submit button is pressed.
|
Callback that is called when the keyboard's submit button is pressed.
|
||||||
|
|
||||||
**placeholder**: string
|
**placeholder**: ?string
|
||||||
|
|
||||||
The string that will be rendered in an empty `TextInput` before text has been
|
The string that will be rendered in an empty `TextInput` before text has been
|
||||||
entered.
|
entered.
|
||||||
|
|
||||||
**secureTextEntry**: bool = false
|
**secureTextEntry**: ?boolean = false
|
||||||
|
|
||||||
If true, the text input obscures the text entered so that sensitive text like
|
If true, the text input obscures the text entered so that sensitive text like
|
||||||
passwords stay secure.
|
passwords stay secure.
|
||||||
|
|
||||||
(Not available when `multiline` is `true`.)
|
(Not available when `multiline` is `true`.)
|
||||||
|
|
||||||
**selection**: { start: number, end: ?number }
|
**selection**: ?{ start: number, end: ?number }
|
||||||
|
|
||||||
The start and end of the text input's selection. Set start and end to the same value to position the cursor.
|
The start and end of the text input's selection. Set start and end to the same value to position the cursor.
|
||||||
|
|
||||||
**selectTextOnFocus**: bool = false
|
**selectTextOnFocus**: ?boolean = false
|
||||||
|
|
||||||
If `true`, all text will automatically be selected on focus.
|
If `true`, all text will automatically be selected on focus.
|
||||||
|
|
||||||
**style**: style
|
**style**: ?style
|
||||||
|
|
||||||
+ ...[Text#style](./Text.md)
|
+ ...[Text#style](./Text.md)
|
||||||
+ `resize` ‡
|
+ `resize` ‡
|
||||||
|
|
||||||
‡ web only.
|
‡ web only.
|
||||||
|
|
||||||
**testID**: string
|
**testID**: ?string
|
||||||
|
|
||||||
Used to locate this view in end-to-end tests.
|
Used to locate this view in end-to-end tests.
|
||||||
|
|
||||||
**value**: string
|
**value**: ?string
|
||||||
|
|
||||||
The value to show for the text input. `TextInput` is a controlled component,
|
The value to show for the text input. `TextInput` is a controlled component,
|
||||||
which means the native `value` will be forced to match this prop if provided.
|
which means the native `value` will be forced to match this prop if provided.
|
||||||
|
|||||||
@@ -11,60 +11,33 @@ several child components, wrap them in a View.
|
|||||||
|
|
||||||
[...View props](./View.md)
|
[...View props](./View.md)
|
||||||
|
|
||||||
**accessibilityLabel**: string
|
**delayLongPress**: ?number
|
||||||
|
|
||||||
Overrides the text that's read by the screen reader when the user interacts
|
|
||||||
with the element.
|
|
||||||
|
|
||||||
(web) **accessibilityRole**: oneOf(roles) = 'button'
|
|
||||||
|
|
||||||
Allows assistive technologies to present and support interaction with the view
|
|
||||||
|
|
||||||
**accessible**: bool = true
|
|
||||||
|
|
||||||
When `false`, the view is hidden from screenreaders.
|
|
||||||
|
|
||||||
**children**: View
|
|
||||||
|
|
||||||
**delayLongPress**: number
|
|
||||||
|
|
||||||
Delay in ms, from `onPressIn`, before `onLongPress` is called.
|
Delay in ms, from `onPressIn`, before `onLongPress` is called.
|
||||||
|
|
||||||
**delayPressIn**: number
|
**delayPressIn**: ?number
|
||||||
|
|
||||||
Delay in ms, from the start of the touch, before `onPressIn` is called.
|
Delay in ms, from the start of the touch, before `onPressIn` is called.
|
||||||
|
|
||||||
**delayPressOut**: number
|
**delayPressOut**: ?number
|
||||||
|
|
||||||
Delay in ms, from the release of the touch, before `onPressOut` is called.
|
Delay in ms, from the release of the touch, before `onPressOut` is called.
|
||||||
|
|
||||||
**disabled**: bool
|
**disabled**: ?boolean
|
||||||
|
|
||||||
If true, disable all interactions for this component.
|
If `true`, disable all interactions for this component.
|
||||||
|
|
||||||
**hitSlop**: `{top: number, left: number, bottom: number, right: number}`
|
**onLongPress**: ?function
|
||||||
|
|
||||||
This defines how far your touch can start away from the button. This is added
|
**onPress**: ?function
|
||||||
to `pressRetentionOffset` when moving off of the button. **NOTE**: The touch
|
|
||||||
area never extends past the parent view bounds and the z-index of sibling views
|
|
||||||
always takes precedence if a touch hits two overlapping views.
|
|
||||||
|
|
||||||
**onLayout**: function
|
|
||||||
|
|
||||||
Invoked on mount and layout changes with `{ nativeEvent: { layout: { x, y, width,
|
|
||||||
height } } }`, where `x` and `y` are the offsets from the parent node.
|
|
||||||
|
|
||||||
**onLongPress**: function
|
|
||||||
|
|
||||||
**onPress**: function
|
|
||||||
|
|
||||||
Called when the touch is released, but not if cancelled (e.g. by a scroll that steals the responder lock).
|
Called when the touch is released, but not if cancelled (e.g. by a scroll that steals the responder lock).
|
||||||
|
|
||||||
**onPressIn**: function
|
**onPressIn**: ?function
|
||||||
|
|
||||||
**onPressOut**: function
|
**onPressOut**: ?function
|
||||||
|
|
||||||
**pressRetentionOffset**: `{top: number, left: number, bottom: number, right: number}`
|
**pressRetentionOffset**: ?`{top: number, left: number, bottom: number, right: number}`
|
||||||
|
|
||||||
When the scroll view is disabled, this defines how far your touch may move off
|
When the scroll view is disabled, this defines how far your touch may move off
|
||||||
of the button, before deactivating the button. Once deactivated, try moving it
|
of the button, before deactivating the button. Once deactivated, try moving it
|
||||||
|
|||||||
@@ -7,21 +7,20 @@ inside another `View` and has 0-to-many children of any type.
|
|||||||
Also, refer to React Native's documentation about the [Gesture Responder
|
Also, refer to React Native's documentation about the [Gesture Responder
|
||||||
System](http://facebook.github.io/react-native/releases/0.22/docs/gesture-responder-system.html).
|
System](http://facebook.github.io/react-native/releases/0.22/docs/gesture-responder-system.html).
|
||||||
|
|
||||||
Unsupported React Native props:
|
Unsupported React Native props: `collapsable`, `onAccessibilityTap`, `onMagicTap`.
|
||||||
`onAccessibilityTap`,
|
|
||||||
`hitSlop`,
|
|
||||||
`onMagicTap`
|
|
||||||
|
|
||||||
## Props
|
## Props
|
||||||
|
|
||||||
NOTE: `View` will transfer all other props to the rendered HTML element.
|
NOTE: `View` will transfer all other props to the rendered HTML element.
|
||||||
|
|
||||||
**accessibilityLabel**: string
|
**accessibilityLabel**: ?string
|
||||||
|
|
||||||
Defines the text available to assistive technologies upon interaction with the
|
Overrides the text that's read by a screen reader when the user interacts
|
||||||
element. (This is implemented using `aria-label`.)
|
with the element. (This is implemented using `aria-label`.)
|
||||||
|
|
||||||
**accessibilityLiveRegion**: oneOf('assertive', 'off', 'polite') = 'off'
|
See the [Accessibility guide](../guides/accessibility.md) for more information.
|
||||||
|
|
||||||
|
**accessibilityLiveRegion**: ?enum('assertive', 'none', 'polite')
|
||||||
|
|
||||||
Indicates to assistive technologies whether to notify the user when the view
|
Indicates to assistive technologies whether to notify the user when the view
|
||||||
changes. The values of this attribute are expressed in degrees of importance.
|
changes. The values of this attribute are expressed in degrees of importance.
|
||||||
@@ -30,71 +29,121 @@ priority. When regions are specified as `assertive`, assistive technologies
|
|||||||
will interrupt and immediately notify the user. (This is implemented using
|
will interrupt and immediately notify the user. (This is implemented using
|
||||||
[`aria-live`](http://www.w3.org/TR/wai-aria/states_and_properties#aria-live).)
|
[`aria-live`](http://www.w3.org/TR/wai-aria/states_and_properties#aria-live).)
|
||||||
|
|
||||||
(web) **accessibilityRole**: oneOf(roles)
|
See the [Accessibility guide](../guides/accessibility.md) for more information.
|
||||||
|
|
||||||
|
(web) **accessibilityRole**: ?enum(roles)
|
||||||
|
|
||||||
Allows assistive technologies to present and support interaction with the view
|
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
|
in a manner that is consistent with user expectations for similar views of that
|
||||||
type. For example, marking a touchable view with an `accessibilityRole` of
|
type. For example, marking a touchable view with an `accessibilityRole` of
|
||||||
`button`. (This is implemented using [ARIA roles](http://www.w3.org/TR/wai-aria/roles#role_definitions)).
|
`button`. (This is implemented using [ARIA roles](http://www.w3.org/TR/wai-aria/roles#role_definitions)).
|
||||||
|
|
||||||
Note: Avoid changing `accessibilityRole` values over time or after user
|
See the [Accessibility guide](../guides/accessibility.md) for more information.
|
||||||
actions. Generally, accessibility APIs do not provide a means of notifying
|
|
||||||
assistive technologies of a `role` value change.
|
|
||||||
|
|
||||||
**accessible**: bool = true
|
**accessible**: ?boolean
|
||||||
|
|
||||||
When `false`, the view is hidden from assistive technologies. (This is
|
When `true`, indicates that the view is an accessibility element (i.e.,
|
||||||
implemented using `aria-hidden`.)
|
focusable) and groups its child content. By default, all the touchable elements
|
||||||
|
and elements with `accessibilityRole` of `button` and `link` are accessible.
|
||||||
|
(This is implemented using `tabindex`.)
|
||||||
|
|
||||||
**onLayout**: function
|
See the [Accessibility guide](../guides/accessibility.md) for more information.
|
||||||
|
|
||||||
|
**children**: ?element
|
||||||
|
|
||||||
|
Child content.
|
||||||
|
|
||||||
|
**hitSlop**: ?object
|
||||||
|
|
||||||
|
This defines how far a touch event can start away from the view (in pixels).
|
||||||
|
Typical interface guidelines recommend touch targets that are at least 30 - 40
|
||||||
|
points/density-independent pixels.
|
||||||
|
|
||||||
|
For example, if a touchable view has a height of `20` the touchable height can
|
||||||
|
be extended to `40` with `hitSlop={{top: 10, bottom: 10, left: 0, right: 0}}`.
|
||||||
|
|
||||||
|
**importantForAccessibility**: ?enum('auto', 'no', 'no-hide-descendants', 'yes')
|
||||||
|
|
||||||
|
A value of `no` will remove the element from the tab flow.
|
||||||
|
|
||||||
|
A value of `no-hide-descendants` will hide the element and its children from
|
||||||
|
assistive technologies. (This is implemented using `aria-hidden`.)
|
||||||
|
|
||||||
|
See the [Accessibility guide](../guides/accessibility.md) for more information.
|
||||||
|
|
||||||
|
**onLayout**: ?function
|
||||||
|
|
||||||
Invoked on mount and layout changes with `{ nativeEvent: { layout: { x, y, width,
|
Invoked on mount and layout changes with `{ nativeEvent: { layout: { x, y, width,
|
||||||
height } } }`, where `x` and `y` are the offsets from the parent node.
|
height } } }`, where `x` and `y` are the offsets from the parent node.
|
||||||
|
|
||||||
**onMoveShouldSetResponder**: function
|
**onMoveShouldSetResponder**: ?function => boolean
|
||||||
|
|
||||||
**onMoveShouldSetResponderCapture**: function
|
Does this view want to "claim" touch responsiveness? This is called for every
|
||||||
|
touch move on the `View` when it is not the responder.
|
||||||
|
|
||||||
**onResponderGrant**: function
|
**onMoveShouldSetResponderCapture**: ?function => boolean
|
||||||
|
|
||||||
For most touch interactions, you'll simply want to wrap your component in
|
If a parent `View` wants to prevent a child `View` from becoming responder on a
|
||||||
`TouchableHighlight` or `TouchableOpacity`.
|
move, it should have this handler return `true`.
|
||||||
|
|
||||||
**onResponderMove**: function
|
**onResponderGrant**: ?function
|
||||||
|
|
||||||
**onResponderReject**: function
|
The `View` is now responding to touch events. This is the time to highlight and
|
||||||
|
show the user what is happening. For most touch interactions, you'll simply
|
||||||
|
want to wrap your component in `TouchableHighlight` or `TouchableOpacity`.
|
||||||
|
|
||||||
**onResponderRelease**: function
|
**onResponderMove**: ?function
|
||||||
|
|
||||||
**onResponderTerminate**: function
|
The user is moving their finger.
|
||||||
|
|
||||||
**onResponderTerminationRequest**: function
|
**onResponderReject**: ?function
|
||||||
|
|
||||||
**onStartShouldSetResponder**: function
|
Another responder is already active and will not release it to the `View`
|
||||||
|
asking to be the responder.
|
||||||
|
|
||||||
**onStartShouldSetResponderCapture**: function
|
**onResponderRelease**: ?function
|
||||||
|
|
||||||
**pointerEvents**: oneOf('auto', 'box-only', 'box-none', 'none') = 'auto'
|
Fired at the end of the touch.
|
||||||
|
|
||||||
Configure the `pointerEvents` of the view. The enhanced `pointerEvents` modes
|
**onResponderTerminate**: ?function
|
||||||
provided are not part of the CSS spec, therefore, `pointerEvents` is excluded
|
|
||||||
from `style`.
|
The responder has been taken from the `View`.
|
||||||
|
|
||||||
|
**onResponderTerminationRequest**: ?function
|
||||||
|
|
||||||
|
Some other `View` wants to become responder and is asking this `View` to
|
||||||
|
release its responder. Returning `true` allows its release.
|
||||||
|
|
||||||
|
**onStartShouldSetResponder**: ?function => boolean
|
||||||
|
|
||||||
|
Does this view want to become responder on the start of a touch?
|
||||||
|
|
||||||
|
**onStartShouldSetResponderCapture**: ?function => boolean
|
||||||
|
|
||||||
|
If a parent `View` wants to prevent a child `View` from becoming the responder
|
||||||
|
on a touch start, it should have this handler return `true`.
|
||||||
|
|
||||||
|
**pointerEvents**: ?enum('auto', 'box-only', 'box-none', 'none') = 'auto'
|
||||||
|
|
||||||
|
Controls whether the View can be the target of touch events. The enhanced
|
||||||
|
`pointerEvents` modes provided are not part of the CSS spec, therefore,
|
||||||
|
`pointerEvents` is excluded from `style`.
|
||||||
|
|
||||||
`box-none` is the equivalent of:
|
`box-none` is the equivalent of:
|
||||||
|
|
||||||
```css
|
```css
|
||||||
.box-none { pointer-events: none }
|
.box-none { pointer-events: none !important; }
|
||||||
.box-none * { pointer-events: auto }
|
.box-none > * { pointer-events: auto; }
|
||||||
```
|
```
|
||||||
|
|
||||||
`box-only` is the equivalent of:
|
`box-only` is the equivalent of:
|
||||||
|
|
||||||
```css
|
```css
|
||||||
.box-only { pointer-events: auto }
|
.box-only { pointer-events: auto !important; }
|
||||||
.box-only * { pointer-events: none }
|
.box-only > * { pointer-events: none; }
|
||||||
```
|
```
|
||||||
|
|
||||||
**style**: style
|
**style**: ?style
|
||||||
|
|
||||||
+ `alignContent`
|
+ `alignContent`
|
||||||
+ `alignItems`
|
+ `alignItems`
|
||||||
@@ -109,6 +158,7 @@ from `style`.
|
|||||||
+ `animationTimingFunction` ‡
|
+ `animationTimingFunction` ‡
|
||||||
+ `backfaceVisibility`
|
+ `backfaceVisibility`
|
||||||
+ `backgroundAttachment` ‡
|
+ `backgroundAttachment` ‡
|
||||||
|
+ `backgroundBlendMode` ‡
|
||||||
+ `backgroundClip` ‡
|
+ `backgroundClip` ‡
|
||||||
+ `backgroundColor`
|
+ `backgroundColor`
|
||||||
+ `backgroundImage` ‡
|
+ `backgroundImage` ‡
|
||||||
@@ -137,16 +187,30 @@ from `style`.
|
|||||||
+ `borderRightWidth`
|
+ `borderRightWidth`
|
||||||
+ `borderTopWidth`
|
+ `borderTopWidth`
|
||||||
+ `bottom`
|
+ `bottom`
|
||||||
+ `boxShadow`
|
+ `boxShadow` ‡
|
||||||
+ `boxSizing`
|
+ `boxSizing`
|
||||||
|
+ `clip` ‡
|
||||||
+ `cursor` ‡
|
+ `cursor` ‡
|
||||||
+ `display` ‡
|
+ `display`
|
||||||
|
+ `filter` ‡
|
||||||
+ `flex` (number)
|
+ `flex` (number)
|
||||||
+ `flexBasis`
|
+ `flexBasis`
|
||||||
+ `flexDirection`
|
+ `flexDirection`
|
||||||
+ `flexGrow`
|
+ `flexGrow`
|
||||||
+ `flexShrink`
|
+ `flexShrink`
|
||||||
+ `flexWrap`
|
+ `flexWrap`
|
||||||
|
+ `gridAutoColumns` ‡
|
||||||
|
+ `gridAutoFlow` ‡
|
||||||
|
+ `gridAutoRows` ‡
|
||||||
|
+ `gridColumnEnd` ‡
|
||||||
|
+ `gridColumnGap` ‡
|
||||||
|
+ `gridColumnStart` ‡
|
||||||
|
+ `gridRowEnd` ‡
|
||||||
|
+ `gridRowGap` ‡
|
||||||
|
+ `gridRowStart` ‡
|
||||||
|
+ `gridTemplateColumns` ‡
|
||||||
|
+ `gridTemplateRows` ‡
|
||||||
|
+ `gridTemplateAreas` ‡
|
||||||
+ `height`
|
+ `height`
|
||||||
+ `justifyContent`
|
+ `justifyContent`
|
||||||
+ `left`
|
+ `left`
|
||||||
@@ -164,6 +228,7 @@ from `style`.
|
|||||||
+ `opacity`
|
+ `opacity`
|
||||||
+ `order`
|
+ `order`
|
||||||
+ `outline` ‡
|
+ `outline` ‡
|
||||||
|
+ `outlineColor` ‡
|
||||||
+ `overflow`
|
+ `overflow`
|
||||||
+ `overflowX` ‡
|
+ `overflowX` ‡
|
||||||
+ `overflowY` ‡
|
+ `overflowY` ‡
|
||||||
@@ -178,6 +243,10 @@ from `style`.
|
|||||||
+ `perspectiveOrigin` ‡
|
+ `perspectiveOrigin` ‡
|
||||||
+ `position`
|
+ `position`
|
||||||
+ `right`
|
+ `right`
|
||||||
|
+ `shadowColor`
|
||||||
|
+ `shadowOffset`
|
||||||
|
+ `shadowOpacity`
|
||||||
|
+ `shadowRadius`
|
||||||
+ `top`
|
+ `top`
|
||||||
+ `transform`
|
+ `transform`
|
||||||
+ `transformOrigin` ‡
|
+ `transformOrigin` ‡
|
||||||
@@ -211,9 +280,9 @@ Default:
|
|||||||
};
|
};
|
||||||
```
|
```
|
||||||
|
|
||||||
(See [facebook/css-layout](https://github.com/facebook/css-layout)).
|
(See [facebook/yoga](https://github.com/facebook/yoga)).
|
||||||
|
|
||||||
**testID**: string
|
**testID**: ?string
|
||||||
|
|
||||||
Used to locate this view in end-to-end tests.
|
Used to locate this view in end-to-end tests.
|
||||||
|
|
||||||
|
|||||||
@@ -1,32 +1,124 @@
|
|||||||
# Accessibility
|
# Accessibility
|
||||||
|
|
||||||
On the Web, assistive technologies derive useful information about the
|
On the Web, assistive technologies (e.g., VoiceOver, TalkBack screen readers)
|
||||||
structure, purpose, and interactivity of apps from their [HTML
|
derive useful information about the structure, purpose, and interactivity of
|
||||||
elements][html-accessibility-url], attributes, and [ARIA in
|
apps from their [HTML elements][html-accessibility-url], attributes, and [ARIA
|
||||||
HTML][aria-in-html-url].
|
in HTML][aria-in-html-url]. React Native for Web includes APIs designed to
|
||||||
|
provide developers with support for making apps more accessible. The most
|
||||||
|
common and best supported accessibility features of the Web are exposed as the
|
||||||
|
props: `accessible`, `accessibilityLabel`, `accessibilityLiveRegion`,
|
||||||
|
`accessibilityRole`, and `importantForAccessibility`.
|
||||||
|
|
||||||
The most common and best supported accessibility features of the Web are
|
## Accessibility properties
|
||||||
exposed as the props: `accessible`, `accessibilityLabel`,
|
|
||||||
`accessibilityLiveRegion`, and `accessibilityRole`.
|
|
||||||
|
|
||||||
React Native for Web does not provide a way to directly control the type of the
|
### accessible
|
||||||
rendered HTML element. The `accessibilityRole` prop is used to infer an
|
|
||||||
[analogous HTML element][html-aria-url] to use in addition to the resulting
|
When `true`, indicates that the view is an accessibility element. When a view
|
||||||
ARIA `role`, where possible. While this may contradict some ARIA
|
is an accessibility element, it groups its children into a single focusable
|
||||||
|
component. By default, all touchable elements, buttons, and links are
|
||||||
|
"accessible". Prefer using `accessibilityRole` (e.g., `button`, `link`) to
|
||||||
|
create focusable HTML elements wherever possible. On web, `accessible={true}`
|
||||||
|
is implemented using `tabIndex`.
|
||||||
|
|
||||||
|
### accessibilityLabel
|
||||||
|
|
||||||
|
When a view is marked as `accessible`, it is a good practice to set an
|
||||||
|
`accessibilityLabel` on the view, so that people who use screen readers know
|
||||||
|
what element they have selected. On web, `accessibilityLabel` is implemented
|
||||||
|
using `aria-label`.
|
||||||
|
|
||||||
|
```
|
||||||
|
<TouchableOpacity accessibilityLabel={'Tap me!'} accessible={true} onPress={this._onPress}>
|
||||||
|
<View style={styles.button}>
|
||||||
|
<Text style={styles.buttonText}>Press me!</Text>
|
||||||
|
</View>
|
||||||
|
</TouchableOpacity>
|
||||||
|
```
|
||||||
|
|
||||||
|
### accessibilityRole
|
||||||
|
|
||||||
|
In some cases, we also want to alert the end user of the type of selected
|
||||||
|
component (i.e., that it is a “button”). To provide more context to screen
|
||||||
|
readers, you should specify the `accessibilityRole` property. (Note that React
|
||||||
|
Native for Web also provides a compatibility mapping of equivalent
|
||||||
|
`accessibilityTraits` and `accessibilityComponentType` values to
|
||||||
|
`accessibilityRole`).
|
||||||
|
|
||||||
|
The `accessibilityRole` prop is used to infer an [analogous HTML
|
||||||
|
element][html-aria-url] and ARIA `role`, where possible. In most cases, both
|
||||||
|
the element and ARIA `role` are rendered. While this may contradict some ARIA
|
||||||
recommendations, it also helps avoid certain HTML5 conformance errors and
|
recommendations, it also helps avoid certain HTML5 conformance errors and
|
||||||
accessibility anti-patterns (e.g., giving a `heading` role to a `button`
|
accessibility anti-patterns (e.g., giving a `heading` role to a `button`
|
||||||
element).
|
element) and browser bugs.
|
||||||
|
|
||||||
For example:
|
For example:
|
||||||
|
|
||||||
* `<View accessibilityRole='article' />` => `<article role='article' />`.
|
* `<View accessibilityRole='article' />` => `<article role='article' />`.
|
||||||
* `<View accessibilityRole='banner' />` => `<header role='banner' />`.
|
* `<View accessibilityRole='banner' />` => `<header role='banner' />`.
|
||||||
* `<View accessibilityRole='button' />` => `<button type='button' role='button' />`.
|
* `<View accessibilityRole='button' />` => `<div role='button' tabIndex='0' />`.
|
||||||
|
* `<Text accessibilityRole='label' />` => `<label />`.
|
||||||
* `<Text accessibilityRole='link' href='/' />` => `<a role='link' href='/' />`.
|
* `<Text accessibilityRole='link' href='/' />` => `<a role='link' href='/' />`.
|
||||||
* `<View accessibilityRole='main' />` => `<main role='main' />`.
|
* `<View accessibilityRole='main' />` => `<main role='main' />`.
|
||||||
|
|
||||||
Other ARIA properties should be set via [direct
|
In the example below, the `TouchableHighlight` is announced by screen
|
||||||
manipulation](./direct-manipulation.md).
|
readers as a button.
|
||||||
|
|
||||||
|
```js
|
||||||
|
<TouchableHighlight accessibilityRole="button" onPress={this._handlePress}>
|
||||||
|
<View style={styles.button}>
|
||||||
|
<Text style={styles.buttonText}>Press me!</Text>
|
||||||
|
</View>
|
||||||
|
</TouchableHighlight>
|
||||||
|
```
|
||||||
|
|
||||||
|
Note: The `button` role is not implemented using the native `button` element
|
||||||
|
due to browsers limiting the use of flexbox layout on its children.
|
||||||
|
|
||||||
|
Note: Avoid changing `accessibilityRole` values over time or after user
|
||||||
|
actions. Generally, accessibility APIs do not provide a means of notifying
|
||||||
|
assistive technologies of a `role` value change.
|
||||||
|
|
||||||
|
### accessibilityLiveRegion
|
||||||
|
|
||||||
|
When components dynamically change we may need to inform the user. The
|
||||||
|
`accessibilityLiveRegion` property serves this purpose and can be set to
|
||||||
|
`none`, `polite` and `assertive`. On web, `accessibilityLiveRegion` is
|
||||||
|
implemented using `aria-live`.
|
||||||
|
|
||||||
|
* `none`: Accessibility services should not announce changes to this view.
|
||||||
|
* `polite`: Accessibility services should announce changes to this view.
|
||||||
|
* `assertive`: Accessibility services should interrupt ongoing speech to immediately announce changes to this view.
|
||||||
|
|
||||||
|
```
|
||||||
|
<TouchableWithoutFeedback onPress={this._addOne}>
|
||||||
|
<View style={styles.embedded}>
|
||||||
|
<Text>Click me</Text>
|
||||||
|
</View>
|
||||||
|
</TouchableWithoutFeedback>
|
||||||
|
|
||||||
|
<Text accessibilityLiveRegion="polite">
|
||||||
|
Clicked {this.state.count} times
|
||||||
|
</Text>
|
||||||
|
```
|
||||||
|
|
||||||
|
In the above example, method `_addOne` changes the `state.count` variable. As
|
||||||
|
soon as an end user clicks the `TouchableWithoutFeedback`, screen readers
|
||||||
|
announce text in the `Text` view because of its
|
||||||
|
`accessibilityLiveRegion="polite"` property.
|
||||||
|
|
||||||
|
### importantForAccessibility
|
||||||
|
|
||||||
|
The `importantForAccessibility` property controls if a view appears in the
|
||||||
|
accessibility tree and if it is reported to accessibility services. On web, a
|
||||||
|
value of `no` will remove a focusable element from the tab flow, and a value of
|
||||||
|
`no-hide-descendants` will also hide the entire subtree from assistive
|
||||||
|
technologies (this is implemented using `aria-hidden`).
|
||||||
|
|
||||||
|
### Other
|
||||||
|
|
||||||
|
Other ARIA properties can be set via [direct
|
||||||
|
manipulation](./direct-manipulation.md) or props (this may change in the
|
||||||
|
future).
|
||||||
|
|
||||||
[aria-in-html-url]: https://w3c.github.io/aria-in-html/
|
[aria-in-html-url]: https://w3c.github.io/aria-in-html/
|
||||||
[html-accessibility-url]: http://www.html5accessibility.com/
|
[html-accessibility-url]: http://www.html5accessibility.com/
|
||||||
|
|||||||
113
docs/guides/advanced.md
Normal file
113
docs/guides/advanced.md
Normal file
@@ -0,0 +1,113 @@
|
|||||||
|
# Advanced use
|
||||||
|
|
||||||
|
## Use with existing React DOM components
|
||||||
|
|
||||||
|
React Native for Web exports a web-specific module called `createElement`,
|
||||||
|
which can be used to wrap React DOM components. This allows you to use React
|
||||||
|
Native's accessibility and style optimizations.
|
||||||
|
|
||||||
|
In the example below, `Video` will now accept common React Native props such as
|
||||||
|
`accessibilityLabel`, `accessible`, `style`, and even the Responder event
|
||||||
|
props.
|
||||||
|
|
||||||
|
```js
|
||||||
|
import { createElement } from 'react-native-web';
|
||||||
|
const Video = (props) => createElement('video', props);
|
||||||
|
```
|
||||||
|
|
||||||
|
This also works with composite components defined in your existing component
|
||||||
|
gallery or dependencies ([live example](https://www.webpackbin.com/bins/-KiTSGFw3fB9Szg7quLI)).
|
||||||
|
|
||||||
|
```js
|
||||||
|
import RaisedButton from 'material-ui/RaisedButton';
|
||||||
|
import { createElement } from 'react-native-web';
|
||||||
|
import { StyleSheet } from 'react-native';
|
||||||
|
|
||||||
|
const CustomButton = (props) => createElement(RaisedButton, {
|
||||||
|
...props,
|
||||||
|
style: [ styles.button, props.style ]
|
||||||
|
});
|
||||||
|
|
||||||
|
const styles = StyleSheet.create({
|
||||||
|
button: {
|
||||||
|
padding: 20
|
||||||
|
}
|
||||||
|
});
|
||||||
|
```
|
||||||
|
|
||||||
|
And `createElement` can be used as drop-in replacement for `React.createElement`:
|
||||||
|
|
||||||
|
```js
|
||||||
|
/* @jsx createElement */
|
||||||
|
import { createElement } from 'react-native-web';
|
||||||
|
const Video = (props) => <video {...props} style={[ { marginVertical: 10 }, props.style ]} />
|
||||||
|
```
|
||||||
|
|
||||||
|
Remember that React Native styles are not the same as React DOM styles, and
|
||||||
|
care needs to be taken not to pass React DOM styles into your React Native
|
||||||
|
wrapped components.
|
||||||
|
|
||||||
|
## Use as a library framework
|
||||||
|
|
||||||
|
The React Native (for Web) building blocks can be used to create higher-level
|
||||||
|
components and abstractions. In the example below, a `styled` function provides
|
||||||
|
an API inspired by styled-components ([live
|
||||||
|
example](https://www.webpackbin.com/bins/-KjT9ziwv4O7FDZdvsnX)).
|
||||||
|
|
||||||
|
```js
|
||||||
|
import { createElement } from 'react-native-web';
|
||||||
|
import { StyleSheet } from 'react-native';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* styled API
|
||||||
|
*/
|
||||||
|
const styled = (Component, styler) => {
|
||||||
|
const isDOMComponent = typeof Component === 'string';
|
||||||
|
|
||||||
|
class Styled extends React.Component {
|
||||||
|
static contextTypes = {
|
||||||
|
getTheme: React.PropTypes.func
|
||||||
|
};
|
||||||
|
|
||||||
|
render() {
|
||||||
|
const theme = this.context.getTheme && this.context.getTheme();
|
||||||
|
const localProps = { ...this.props, theme };
|
||||||
|
const nextProps = { ...this.props }
|
||||||
|
const style = typeof styler === 'function' ? styler(localProps) : styler;
|
||||||
|
nextProps.style = [ style, this.props.style ];
|
||||||
|
|
||||||
|
return (
|
||||||
|
isDOMComponent
|
||||||
|
? createElement(Component, nextProps)
|
||||||
|
: <Component {...nextProps} />
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return Styled;
|
||||||
|
}
|
||||||
|
|
||||||
|
const styles = StyleSheet.create({
|
||||||
|
container: {
|
||||||
|
alignItems: 'center',
|
||||||
|
backgroundColor: '#2196F3',
|
||||||
|
flex: 1,
|
||||||
|
justifyContent: 'center'
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
const StyledView = styled(View, styles.container);
|
||||||
|
```
|
||||||
|
|
||||||
|
## Use with react-sketchapp
|
||||||
|
|
||||||
|
Use with [react-sketchapp](http://airbnb.io/react-sketchapp/) requires that you
|
||||||
|
alias `react-native` to `react-sketchapp`. This will allow you to render your
|
||||||
|
existing React Native components in Sketch. Sketch-specific components like
|
||||||
|
`Artboard` should be imported from `react-sketchapp`.
|
||||||
|
|
||||||
|
If you're using `skpm`, you can rely on an [undocumented
|
||||||
|
feature](https://github.com/sketch-pm/skpm/blob/master/lib/utils/webpackConfig.js)
|
||||||
|
which will merge your `webpack.config.js`, `.babelrc`, or `package.json` Babel
|
||||||
|
config into its internal webpack config. The simplest option may be to use the
|
||||||
|
[babel-plugin-module-alias](https://www.npmjs.com/package/babel-plugin-module-alias)
|
||||||
|
and configure it in your `package.json`.
|
||||||
@@ -1,27 +1,68 @@
|
|||||||
# Direct manipulation
|
# Direct manipulation
|
||||||
|
|
||||||
It is sometimes necessary to make changes directly to a component without using
|
React Native for Web provides several methods to directly access the underlying
|
||||||
state/props to trigger a re-render of the entire subtree – in the browser, this
|
DOM node. This can be useful when you need to make changes directly to a
|
||||||
is done by directly modifying a DOM node. `setNativeProps` is the React Native
|
component without using state/props to trigger a re-render of the entire
|
||||||
equivalent to setting properties directly on a DOM node. Use direct
|
subtree, or when you want to focus a view or measure its on-screen dimensions.
|
||||||
manipulation when frequent re-rendering creates a performance bottleneck. Direct
|
|
||||||
manipulation will not be a tool that you reach for frequently.
|
|
||||||
|
|
||||||
## `setNativeProps` and `shouldComponentUpdate`
|
The methods described are available on most of the default components provided
|
||||||
|
by React Native for Web. Note, however, that they are *not* available on the
|
||||||
|
composite components that you define in your own app.
|
||||||
|
|
||||||
|
## Instance methods
|
||||||
|
|
||||||
|
**blur**()
|
||||||
|
|
||||||
|
Removes focus from an input or view. This is the opposite of `focus()`.
|
||||||
|
|
||||||
|
**focus**()
|
||||||
|
|
||||||
|
Requests focus for the given input or view. The exact behavior triggered will
|
||||||
|
depend the type of view.
|
||||||
|
|
||||||
|
**measure**(callback: (x, y, width, height, pageX, pageY) => void)
|
||||||
|
|
||||||
|
For a given view, `measure` determines the offset relative to the parent view,
|
||||||
|
width, height, and the offset relative to the viewport. Returns the values via
|
||||||
|
an async callback.
|
||||||
|
|
||||||
|
Note that these measurements are not available until after the rendering has
|
||||||
|
been completed.
|
||||||
|
|
||||||
|
**measureLayout**(relativeToNativeNode: DOMNode, onSuccess: (x, y, width, height) => void)
|
||||||
|
|
||||||
|
Like `measure`, but measures the view relative to another view, specified as
|
||||||
|
`relativeToNativeNode`. This means that the returned `x`, `y` are relative to
|
||||||
|
the origin `x`, `y` of the ancestor view.
|
||||||
|
|
||||||
|
**setNativeProps**(nativeProps: Object)
|
||||||
|
|
||||||
|
This function sends props straight to the underlying DOM node. See the [direct
|
||||||
|
manipulation](../guides/direct-manipulation.md) guide for cases where
|
||||||
|
`setNativeProps` should be used.
|
||||||
|
|
||||||
|
## About `setNativeProps`
|
||||||
|
|
||||||
|
`setNativeProps` is the React Native equivalent to setting properties directly
|
||||||
|
on a DOM node. Use direct manipulation when frequent re-rendering creates a
|
||||||
|
performance bottleneck. Direct manipulation will not be a tool that you reach
|
||||||
|
for frequently.
|
||||||
|
|
||||||
|
### `setNativeProps` and `shouldComponentUpdate`
|
||||||
|
|
||||||
`setNativeProps` is imperative and stores state in the native layer (DOM,
|
`setNativeProps` is imperative and stores state in the native layer (DOM,
|
||||||
UIView, etc.) and not within your React components, which makes your code more
|
UIView, etc.) and not within your React components, which makes your code more
|
||||||
difficult to reason about. Before you use it, try to solve your problem with
|
difficult to reason about. Before you use it, try to solve your problem with
|
||||||
`setState` and `shouldComponentUpdate`.
|
`setState` and `shouldComponentUpdate`.
|
||||||
|
|
||||||
## Avoiding conflicts with the render function
|
### Avoiding conflicts with the render function
|
||||||
|
|
||||||
If you update a property that is also managed by the render function, you might
|
If you update a property that is also managed by the render function, you might
|
||||||
end up with some unpredictable and confusing bugs because anytime the component
|
end up with some unpredictable and confusing bugs because anytime the component
|
||||||
re-renders and that property changes, whatever value was previously set from
|
re-renders and that property changes, whatever value was previously set from
|
||||||
`setNativeProps` will be completely ignored and overridden.
|
`setNativeProps` will be completely ignored and overridden.
|
||||||
|
|
||||||
## Why use `setNativeProps` on Web?
|
### Why use `setNativeProps` on Web?
|
||||||
|
|
||||||
Using `setNativeProps` in web-specific code is required when making changes to
|
Using `setNativeProps` in web-specific code is required when making changes to
|
||||||
`className` or `style`, as these properties are controlled by React Native for
|
`className` or `style`, as these properties are controlled by React Native for
|
||||||
@@ -35,7 +76,7 @@ setOpacityTo(value) {
|
|||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
## Composite components and `setNativeProps`
|
### Composite components and `setNativeProps`
|
||||||
|
|
||||||
Composite components are not backed by a DOM node, so you cannot call
|
Composite components are not backed by a DOM node, so you cannot call
|
||||||
`setNativeProps` on them. Consider this example:
|
`setNativeProps` on them. Consider this example:
|
||||||
@@ -63,7 +104,7 @@ prop on it and have that work - you would need to pass the style prop down to a
|
|||||||
child, unless you are wrapping a native component. Similarly, we are going to
|
child, unless you are wrapping a native component. Similarly, we are going to
|
||||||
forward `setNativeProps` to a native-backed child component.
|
forward `setNativeProps` to a native-backed child component.
|
||||||
|
|
||||||
## Forward `setNativeProps` to a child
|
### Forward `setNativeProps` to a child
|
||||||
|
|
||||||
All we need to do is provide a `setNativeProps` method on our component that
|
All we need to do is provide a `setNativeProps` method on our component that
|
||||||
calls `setNativeProps` on the appropriate child with the given arguments.
|
calls `setNativeProps` on the appropriate child with the given arguments.
|
||||||
@@ -86,7 +127,7 @@ class MyButton extends React.Component {
|
|||||||
|
|
||||||
You can now use `MyButton` inside of `TouchableOpacity`!
|
You can now use `MyButton` inside of `TouchableOpacity`!
|
||||||
|
|
||||||
## `setNativeProps` to clear `TextInput` value
|
### `setNativeProps` to clear `TextInput` value
|
||||||
|
|
||||||
Another very common use case of `setNativeProps` is to clear the value of a
|
Another very common use case of `setNativeProps` is to clear the value of a
|
||||||
`TextInput`. For example, the following code demonstrates clearing the input
|
`TextInput`. For example, the following code demonstrates clearing the input
|
||||||
|
|||||||
210
docs/guides/getting-started.md
Normal file
210
docs/guides/getting-started.md
Normal file
@@ -0,0 +1,210 @@
|
|||||||
|
# Getting started
|
||||||
|
|
||||||
|
This guide will help you to correctly configure build and test tools to work
|
||||||
|
with React Native for Web. (Alternatively, you can quickly setup a local
|
||||||
|
project using the starter kits listed in the README.)
|
||||||
|
|
||||||
|
It is recommended that your application provide a `Promise` and `Array.from`
|
||||||
|
polyfill.
|
||||||
|
|
||||||
|
## Web packager
|
||||||
|
|
||||||
|
[Webpack](https://webpack.js.org) is a popular build tool for web apps. Below is an
|
||||||
|
example of how to configure a build that uses [Babel](https://babeljs.io/) to
|
||||||
|
compile your JavaScript for the web.
|
||||||
|
|
||||||
|
Create a `web/webpack.config.js` file:
|
||||||
|
|
||||||
|
```js
|
||||||
|
// web/webpack.config.js
|
||||||
|
|
||||||
|
// This is needed for webpack to compile JavaScript.
|
||||||
|
// Many OSS React Native packages are not compiled to ES5 before being
|
||||||
|
// published. If you depend on uncompiled packages they may cause webpack build
|
||||||
|
// errors. To fix this webpack can be configured to compile to the necessary
|
||||||
|
// `node_module`.
|
||||||
|
const babelLoaderConfiguration = {
|
||||||
|
test: /\.js$/,
|
||||||
|
// Add every directory that needs to be compiled by Babel during the build
|
||||||
|
include: [
|
||||||
|
path.resolve(__dirname, 'src'),
|
||||||
|
path.resolve(__dirname, 'node_modules/react-native-uncompiled')
|
||||||
|
],
|
||||||
|
use: {
|
||||||
|
loader: 'babel-loader',
|
||||||
|
options: {
|
||||||
|
cacheDirectory: true,
|
||||||
|
// This aliases 'react-native' to 'react-native-web' and includes only
|
||||||
|
// the modules needed by the app
|
||||||
|
plugins: ['react-native-web/babel']
|
||||||
|
// The 'react-native' preset is recommended (or use your own .babelrc)
|
||||||
|
presets: ['react-native']
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// This is needed for webpack to import static images in JavaScript files
|
||||||
|
const imageLoaderConfiguration = {
|
||||||
|
test: /\.(gif|jpe?g|png|svg)$/,
|
||||||
|
use: {
|
||||||
|
loader: 'url-loader',
|
||||||
|
options: {
|
||||||
|
name: '[name].[ext]'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
module.exports = {
|
||||||
|
// ...the rest of your config
|
||||||
|
|
||||||
|
module: {
|
||||||
|
rules: [
|
||||||
|
babelLoaderConfiguration,
|
||||||
|
imageLoaderConfiguration
|
||||||
|
]
|
||||||
|
},
|
||||||
|
|
||||||
|
plugins: [
|
||||||
|
// `process.env.NODE_ENV === 'production'` must be `true` for production
|
||||||
|
// builds to eliminate development checks and reduce build size. You may
|
||||||
|
// wish to include additional optimizations.
|
||||||
|
new webpack.DefinePlugin({
|
||||||
|
'process.env.NODE_ENV': JSON.stringify('production')
|
||||||
|
})
|
||||||
|
],
|
||||||
|
|
||||||
|
resolve: {
|
||||||
|
// If you're working on a multi-platform React Native app, web-specific
|
||||||
|
// module implementations should be written in files using the extension
|
||||||
|
// `.web.js`.
|
||||||
|
extensions: [ '.web.js', '.js' ]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
To run in development:
|
||||||
|
|
||||||
|
```
|
||||||
|
./node_modules/.bin/webpack-dev-server -d --config web/webpack.config.js --inline --hot --colors
|
||||||
|
```
|
||||||
|
|
||||||
|
To build for production:
|
||||||
|
|
||||||
|
```
|
||||||
|
./node_modules/.bin/webpack -p --config web/webpack.config.js
|
||||||
|
```
|
||||||
|
|
||||||
|
Please refer to the Webpack documentation for more information on configuration.
|
||||||
|
|
||||||
|
## Web entry
|
||||||
|
|
||||||
|
Create a `index.web.js` file (or simply `index.js` for web-only apps).
|
||||||
|
|
||||||
|
### Client-side rendering
|
||||||
|
|
||||||
|
Rendering using `AppRegistry`:
|
||||||
|
|
||||||
|
```js
|
||||||
|
// index.web.js
|
||||||
|
|
||||||
|
import App from './src/App';
|
||||||
|
import React from 'react';
|
||||||
|
import ReactNative, { AppRegistry } from 'react-native';
|
||||||
|
|
||||||
|
// register the app
|
||||||
|
AppRegistry.registerComponent('App', () => App);
|
||||||
|
|
||||||
|
AppRegistry.runApplication('App', {
|
||||||
|
initialProps: {},
|
||||||
|
rootTag: document.getElementById('react-app')
|
||||||
|
});
|
||||||
|
```
|
||||||
|
|
||||||
|
Rendering within existing web apps is also possible using `ReactNative`:
|
||||||
|
|
||||||
|
```js
|
||||||
|
import AppHeader from './src/AppHeader';
|
||||||
|
import React from 'react';
|
||||||
|
import ReactNative from 'react-native';
|
||||||
|
|
||||||
|
ReactNative.render(<AppHeader />, document.getElementById('react-app-header'))
|
||||||
|
```
|
||||||
|
|
||||||
|
And finally, `react-native-web` components will also be rendering within a tree
|
||||||
|
produced by calling `ReactDOM.render` (i.e., an existing web app), but
|
||||||
|
otherwise it is not recommended.
|
||||||
|
|
||||||
|
### Server-side rendering
|
||||||
|
|
||||||
|
Server-side rendering is supported using the `AppRegistry`:
|
||||||
|
|
||||||
|
```js
|
||||||
|
import App from './src/App';
|
||||||
|
import ReactDOMServer from 'react-dom/server'
|
||||||
|
import ReactNative, { AppRegistry } from 'react-native'
|
||||||
|
|
||||||
|
// register the app
|
||||||
|
AppRegistry.registerComponent('App', () => App)
|
||||||
|
|
||||||
|
// prerender the app
|
||||||
|
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>
|
||||||
|
${initialStyles}
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
${initialHTML}
|
||||||
|
`
|
||||||
|
```
|
||||||
|
|
||||||
|
## Web-specific code
|
||||||
|
|
||||||
|
Minor platform differences can use the `Platform` module.
|
||||||
|
|
||||||
|
```js
|
||||||
|
import { Platform } from 'react-native';
|
||||||
|
|
||||||
|
const styles = StyleSheet.create({
|
||||||
|
height: (Platform.OS === 'web') ? 200 : 100,
|
||||||
|
});
|
||||||
|
```
|
||||||
|
|
||||||
|
More significant platform differences should use platform-specific files (see
|
||||||
|
the webpack configuration above for resolving `*.web.js` files):
|
||||||
|
|
||||||
|
For example, with the following files in your project:
|
||||||
|
|
||||||
|
```
|
||||||
|
MyComponent.android.js
|
||||||
|
MyComponent.ios.js
|
||||||
|
MyComponent.web.js
|
||||||
|
```
|
||||||
|
|
||||||
|
And the following import:
|
||||||
|
|
||||||
|
```js
|
||||||
|
import MyComponent from './MyComponent';
|
||||||
|
```
|
||||||
|
|
||||||
|
React Native will automatically import the correct variant for each specific
|
||||||
|
target platform.
|
||||||
|
|
||||||
|
## Testing with Jest
|
||||||
|
|
||||||
|
[Jest](https://facebook.github.io/jest/) also needs to map `react-native` to `react-native-web`.
|
||||||
|
|
||||||
|
```
|
||||||
|
"jest": {
|
||||||
|
"moduleNameMapper": {
|
||||||
|
"react-native": "<rootDir>/node_modules/react-native-web"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
Please refer to the Jest documentation for more information.
|
||||||
@@ -1,10 +1,18 @@
|
|||||||
# Known issues
|
# Known issues
|
||||||
|
|
||||||
## Missing modules and Views
|
## Safari flexbox performance
|
||||||
|
|
||||||
This is an initial release of React Native for Web, therefore, not all of the
|
Safari version prior to 10.1 can suffer from extremely [poor flexbox
|
||||||
views present on iOS/Android are released on Web. We are very much interested in
|
performance](https://bugs.webkit.org/show_bug.cgi?id=150445). The recommended
|
||||||
the community's feedback on the next set of modules and views.
|
way to work around this issue (as used on mobile.twitter.com) is to set
|
||||||
|
`display:block` on Views in your element hierarchy that you know don't need
|
||||||
|
flexbox layout.
|
||||||
|
|
||||||
|
## Missing modules and components
|
||||||
|
|
||||||
|
Not all of the views present on iOS/Android are currently available on Web. We
|
||||||
|
are very much interested in the community's feedback on the next set of modules
|
||||||
|
and views.
|
||||||
|
|
||||||
Not all the modules or views for iOS/Android can be implemented on Web. In some
|
Not all the modules or views for iOS/Android can be implemented on Web. In some
|
||||||
cases it will be necessary to use a Web counterpart or to guard the use of a
|
cases it will be necessary to use a Web counterpart or to guard the use of a
|
||||||
|
|||||||
@@ -1,119 +0,0 @@
|
|||||||
# React Native
|
|
||||||
|
|
||||||
Use a module loader that supports package aliases (e.g., webpack), and alias
|
|
||||||
`react-native` to `react-native-web`.
|
|
||||||
|
|
||||||
```js
|
|
||||||
// webpack.config.js
|
|
||||||
|
|
||||||
module.exports = {
|
|
||||||
// ...
|
|
||||||
resolve: {
|
|
||||||
alias: {
|
|
||||||
'react-native': 'react-native-web'
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
## Image assets
|
|
||||||
|
|
||||||
In order to require image assets (e.g. `require('assets/myimage.png')`), add
|
|
||||||
the `url-loader` to the webpack config:
|
|
||||||
|
|
||||||
```js
|
|
||||||
// webpack.config.js
|
|
||||||
|
|
||||||
module.exports = {
|
|
||||||
// ...
|
|
||||||
module: {
|
|
||||||
loaders: [
|
|
||||||
{
|
|
||||||
test: /\.(gif|jpe?g|png|svg)$/,
|
|
||||||
loader: 'url-loader',
|
|
||||||
query: { name: '[name].[hash:16].[ext]' }
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
};
|
|
||||||
```
|
|
||||||
|
|
||||||
## Dependencies
|
|
||||||
|
|
||||||
Many OSS React Native packages are not compiled to ES5 before being published.
|
|
||||||
This can result in webpack build errors. To avoid this issue you should
|
|
||||||
configure webpack (or your bundler of choice) to run
|
|
||||||
`babel-preset-react-native` over the necessary `node_module`. For example:
|
|
||||||
|
|
||||||
```js
|
|
||||||
// webpack.config.js
|
|
||||||
|
|
||||||
module.exports = {
|
|
||||||
// ...
|
|
||||||
module: {
|
|
||||||
loaders: [
|
|
||||||
{
|
|
||||||
// transpile to ES5
|
|
||||||
test: /\.jsx?$/,
|
|
||||||
include: [
|
|
||||||
path.resolve(__dirname, 'src'),
|
|
||||||
path.resolve(__dirname, 'node_modules/react-native-something')
|
|
||||||
],
|
|
||||||
loader: 'babel-loader',
|
|
||||||
query: { cacheDirectory: true }
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
};
|
|
||||||
```
|
|
||||||
|
|
||||||
Please refer to the webpack documentation for more information.
|
|
||||||
|
|
||||||
## Web-specific code
|
|
||||||
|
|
||||||
Minor platform differences can use the `Platform` module.
|
|
||||||
|
|
||||||
```js
|
|
||||||
import { AppRegistry, Platform } from 'react-native'
|
|
||||||
|
|
||||||
AppRegistry.registerComponent('MyApp', () => MyApp)
|
|
||||||
|
|
||||||
if (Platform.OS === 'web') {
|
|
||||||
AppRegistry.runApplication('MyApp', {
|
|
||||||
rootTag: document.getElementById('react-root')
|
|
||||||
});
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
More substantial Web-specific implementation code should be written in files
|
|
||||||
with the extension `.web.js`. Webpack@1 will automatically resolve these files.
|
|
||||||
Webpack@2 requires additional configuration.
|
|
||||||
|
|
||||||
```js
|
|
||||||
// webpack.config.js
|
|
||||||
|
|
||||||
module.exports = {
|
|
||||||
// ...
|
|
||||||
resolve: {
|
|
||||||
extensions: [ '.web.js', '.js' ]
|
|
||||||
}
|
|
||||||
};
|
|
||||||
```
|
|
||||||
|
|
||||||
## Optimizations
|
|
||||||
|
|
||||||
Production builds can benefit from dead-code elimination by defining the
|
|
||||||
following variables:
|
|
||||||
|
|
||||||
```js
|
|
||||||
// webpack.config.js
|
|
||||||
|
|
||||||
module.exports = {
|
|
||||||
// ...
|
|
||||||
plugins: [
|
|
||||||
new webpack.DefinePlugin({
|
|
||||||
'process.env.NODE_ENV': JSON.stringify('production')
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
```
|
|
||||||
@@ -1,89 +0,0 @@
|
|||||||
# Client and Server rendering
|
|
||||||
|
|
||||||
It's recommended that you use a module loader that supports package aliases
|
|
||||||
(e.g., webpack), and alias `react-native` to `react-native-web`.
|
|
||||||
|
|
||||||
```js
|
|
||||||
// webpack.config.js
|
|
||||||
|
|
||||||
module.exports = {
|
|
||||||
// ...other configuration
|
|
||||||
resolve: {
|
|
||||||
alias: {
|
|
||||||
'react-native': 'react-native-web'
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
The `react-native-web` package also includes a `core` module that exports a
|
|
||||||
subset of modules: `ReactNative`, `I18nManager`, `Platform`, `StyleSheet`,
|
|
||||||
`Image`, `Text`, `TextInput`, `Touchable`, and `View`.
|
|
||||||
|
|
||||||
```js
|
|
||||||
// webpack.config.js
|
|
||||||
|
|
||||||
module.exports = {
|
|
||||||
// ...other configuration
|
|
||||||
resolve: {
|
|
||||||
alias: {
|
|
||||||
'react-native': 'react-native-web/core'
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
## Client-side rendering
|
|
||||||
|
|
||||||
Rendering without using the `AppRegistry`:
|
|
||||||
|
|
||||||
```js
|
|
||||||
import React from 'react'
|
|
||||||
import ReactNative from 'react-native'
|
|
||||||
|
|
||||||
// component that renders the app
|
|
||||||
const AppHeaderContainer = (props) => { /* ... */ }
|
|
||||||
|
|
||||||
ReactNative.render(<AppHeaderContainer />, document.getElementById('react-app-header'))
|
|
||||||
```
|
|
||||||
|
|
||||||
Rendering using the `AppRegistry`:
|
|
||||||
|
|
||||||
```js
|
|
||||||
import React from 'react'
|
|
||||||
import ReactNative, { AppRegistry } from 'react-native'
|
|
||||||
|
|
||||||
// component that renders the app
|
|
||||||
const AppContainer = (props) => { /* ... */ }
|
|
||||||
|
|
||||||
// register the app
|
|
||||||
AppRegistry.registerComponent('App', () => AppContainer)
|
|
||||||
|
|
||||||
AppRegistry.runApplication('App', {
|
|
||||||
initialProps: {},
|
|
||||||
rootTag: document.getElementById('react-app')
|
|
||||||
})
|
|
||||||
```
|
|
||||||
|
|
||||||
Setting `process.env.__REACT_NATIVE_DEBUG_ENABLED__` to `true` will expose some
|
|
||||||
debugging logs. This can help track down when you're rendering without the
|
|
||||||
performance benefit of cached styles.
|
|
||||||
|
|
||||||
## Server-side rendering
|
|
||||||
|
|
||||||
Rendering using the `AppRegistry`:
|
|
||||||
|
|
||||||
```js
|
|
||||||
import ReactDOMServer from 'react-dom/server'
|
|
||||||
import ReactNative, { AppRegistry } from 'react-native'
|
|
||||||
|
|
||||||
// component that renders the app
|
|
||||||
const AppContainer = (props) => { /* ... */ }
|
|
||||||
|
|
||||||
// register the app
|
|
||||||
AppRegistry.registerComponent('App', () => AppContainer)
|
|
||||||
|
|
||||||
// prerender the app
|
|
||||||
const { element, stylesheet } = AppRegistry.getApplication('App', { initialProps });
|
|
||||||
const initialHTML = ReactDOMServer.renderToString(element);
|
|
||||||
```
|
|
||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user