mirror of
https://github.com/zhigang1992/react-native-web.git
synced 2026-03-27 01:34:17 +08:00
Compare commits
553 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
000b92e707 | ||
|
|
d5f5dbccdb | ||
|
|
79456d5920 | ||
|
|
2d1e303a6a | ||
|
|
209ff1fa40 | ||
|
|
34d8160a43 | ||
|
|
ada5651be2 | ||
|
|
9fe9d3c68a | ||
|
|
1e202b6bd5 | ||
|
|
2b77bfd853 | ||
|
|
d0ac55aa4f | ||
|
|
66dd1bd9ef | ||
|
|
6add18c6f0 | ||
|
|
30d7c31b65 | ||
|
|
f7e6b43422 | ||
|
|
4b3f6efb21 | ||
|
|
85e098deec | ||
|
|
c949b0145a | ||
|
|
86b4cf5a51 | ||
|
|
1b7ce4eec6 | ||
|
|
8c8978ff76 | ||
|
|
513b5de881 | ||
|
|
145f80409d | ||
|
|
6d92cc5ec3 | ||
|
|
ec6458c09d | ||
|
|
a84c2ac95e | ||
|
|
75db0e9183 | ||
|
|
4b9a5fd8b4 | ||
|
|
b6be677db9 | ||
|
|
91c9457392 | ||
|
|
006d315a1a | ||
|
|
220eb79357 | ||
|
|
5db9a765b0 | ||
|
|
931d666fcc | ||
|
|
40c433c6df | ||
|
|
9888c2a3c6 | ||
|
|
3fa18becc7 | ||
|
|
aafeb0adad | ||
|
|
89468b7d6e | ||
|
|
f66af5e04d | ||
|
|
2363524fa7 | ||
|
|
5855e55615 | ||
|
|
5033e12d18 | ||
|
|
d6e8530f4d | ||
|
|
ad188a7ad6 | ||
|
|
bfaeae904e | ||
|
|
a54bdeec09 | ||
|
|
8fa7dc63ec | ||
|
|
d841db2337 | ||
|
|
8e7d31cff5 | ||
|
|
0764687a8f | ||
|
|
d31bdf2cf8 | ||
|
|
1f3a77dada | ||
|
|
c3cbd53a8a | ||
|
|
4f5ee15e4b | ||
|
|
9a1cade1f0 | ||
|
|
506dba933c | ||
|
|
c0de9dddf3 | ||
|
|
96c9c06272 | ||
|
|
505e3faee8 | ||
|
|
1f06229289 | ||
|
|
fc743e6eee | ||
|
|
ef97adec6e | ||
|
|
f196335281 | ||
|
|
d29e31d9d6 | ||
|
|
c7c1f29016 | ||
|
|
b56a737d62 | ||
|
|
f062eded40 | ||
|
|
fcc4fbf678 | ||
|
|
a18d30c809 | ||
|
|
b9172ceb8e | ||
|
|
744aaa26d4 | ||
|
|
2b5ddf753e | ||
|
|
b84e3b938a | ||
|
|
9c8407162e | ||
|
|
16b9ec2917 | ||
|
|
d4af1eb981 | ||
|
|
405a3b79e8 | ||
|
|
afd5293172 | ||
|
|
e4831b7bd8 | ||
|
|
baffc9a9e6 | ||
|
|
4151b47005 | ||
|
|
96ec805f59 | ||
|
|
d2df2c296e | ||
|
|
af80b046fa | ||
|
|
1d01af57d0 | ||
|
|
e7613ca4d1 | ||
|
|
0e81c6ef27 | ||
|
|
7fa8940325 | ||
|
|
3e681bed3e | ||
|
|
ecd4b40c71 | ||
|
|
e7cb364b63 | ||
|
|
90bd23f783 | ||
|
|
47a281373a | ||
|
|
6a0302169c | ||
|
|
b195f2b1f5 | ||
|
|
7b81d2a7ec | ||
|
|
a1d8ea776e | ||
|
|
15b960f097 | ||
|
|
001be82178 | ||
|
|
5eeef9e3d2 | ||
|
|
6a310999d0 | ||
|
|
a9ad313a79 | ||
|
|
d0ca7585ab | ||
|
|
3f8624e25f | ||
|
|
8f0c39c2fe | ||
|
|
4f9216853b | ||
|
|
14f7dfd515 | ||
|
|
c336995952 | ||
|
|
2afa5a3cf7 | ||
|
|
9fb818cfd4 | ||
|
|
3153cd8213 | ||
|
|
026a92fd53 | ||
|
|
e0f010da47 | ||
|
|
b299eb6c59 | ||
|
|
da38e87b50 | ||
|
|
a40521f485 | ||
|
|
f62ed22a14 | ||
|
|
bfaca0557b | ||
|
|
c3eedabac4 | ||
|
|
cf43ffd700 | ||
|
|
a8e5d43db5 | ||
|
|
b4e3427fea | ||
|
|
a82cfbe504 | ||
|
|
0eae7bed2e | ||
|
|
b8f54f61f0 | ||
|
|
d5c6b98340 | ||
|
|
16b2fb9bd7 | ||
|
|
48e62fcd64 | ||
|
|
0816c40790 | ||
|
|
2756ab49c3 | ||
|
|
10407f3aa2 | ||
|
|
0ee3310290 | ||
|
|
19b356aaea | ||
|
|
ea744fe780 | ||
|
|
f254c8eae6 | ||
|
|
5fcb36fc21 | ||
|
|
377f23f725 | ||
|
|
fc0b81416a | ||
|
|
cb545b0dac | ||
|
|
f684a3656e | ||
|
|
45975d3a1e | ||
|
|
2d83ffbd6b | ||
|
|
64307c066a | ||
|
|
bb66639519 | ||
|
|
c00360491b | ||
|
|
4bc16fa3eb | ||
|
|
2237777341 | ||
|
|
6a2252891a | ||
|
|
206a236df2 | ||
|
|
ff5a928a50 | ||
|
|
61bf7e76b0 | ||
|
|
e3170623f1 | ||
|
|
392de22992 | ||
|
|
c84163d80e | ||
|
|
50442c4e7c | ||
|
|
eb0e0b8771 | ||
|
|
15d5e57e92 | ||
|
|
def873e9e3 | ||
|
|
9e9b40f155 | ||
|
|
4a45595b7a | ||
|
|
45095fd300 | ||
|
|
004c7ce478 | ||
|
|
96c3f09fac | ||
|
|
edc99e79eb | ||
|
|
e8f2c98786 | ||
|
|
dcdf1468f9 | ||
|
|
ee5e80064f | ||
|
|
3e4d8d6b2f | ||
|
|
d3a8270d55 | ||
|
|
18933724d6 | ||
|
|
e7f84a9228 | ||
|
|
8b1e6f816f | ||
|
|
02b6f3ff3c | ||
|
|
6f52007cc8 | ||
|
|
1e59e53e66 | ||
|
|
f6a65210ca | ||
|
|
2e9071eb0e | ||
|
|
8f25fcc05b | ||
|
|
1e8577fc9e | ||
|
|
c51f567d19 | ||
|
|
bce5957991 | ||
|
|
34d8409d43 | ||
|
|
8442f13e96 | ||
|
|
c6e2b584af | ||
|
|
38affa9bae | ||
|
|
f9ebdb6327 | ||
|
|
83a8758f68 | ||
|
|
e022d166dd | ||
|
|
1a225bc449 | ||
|
|
cf2612663b | ||
|
|
1aec803086 | ||
|
|
2050730b77 | ||
|
|
a67bf0f490 | ||
|
|
4529a4ac0a | ||
|
|
5a04d07a35 | ||
|
|
9427eea293 | ||
|
|
b9803e1e07 | ||
|
|
7a3a9a5c3f | ||
|
|
4c59343fd3 | ||
|
|
ce89b7e3ec | ||
|
|
23fa663a6e | ||
|
|
b96dd668d3 | ||
|
|
a9cacb2ef5 | ||
|
|
c122814591 | ||
|
|
efe18f1b7e | ||
|
|
e1b576e427 | ||
|
|
5d77d6e30f | ||
|
|
8fb9a88ee6 | ||
|
|
a7cda988ef | ||
|
|
b239cfb04d | ||
|
|
8e94d858b2 | ||
|
|
aa22b06359 | ||
|
|
2aa565c7c3 | ||
|
|
7b9b57960d | ||
|
|
eae3ee9dca | ||
|
|
74e1a196b6 | ||
|
|
48da9814e7 | ||
|
|
4d391ef57c | ||
|
|
780df69a80 | ||
|
|
6c229da01f | ||
|
|
ae7aa818fb | ||
|
|
306cf67932 | ||
|
|
619c2048be | ||
|
|
b9f9a4f8d7 | ||
|
|
58bc18c2f5 | ||
|
|
073940fc4e | ||
|
|
5c462303de | ||
|
|
5fb92da317 | ||
|
|
cafe10d851 | ||
|
|
b28581f44e | ||
|
|
9333e7e887 | ||
|
|
b28cbbb37e | ||
|
|
a53372ceb3 | ||
|
|
239a43978f | ||
|
|
b4e4bfbb3c | ||
|
|
893963a799 | ||
|
|
e5adc5a37c | ||
|
|
6d908189a7 | ||
|
|
31db333ba3 | ||
|
|
9fe089ca21 | ||
|
|
a314d5b2e4 | ||
|
|
fb845ebf44 | ||
|
|
0d0c7e6e27 | ||
|
|
f37003a079 | ||
|
|
f1fc2a9e37 | ||
|
|
92794cdc9f | ||
|
|
b754776373 | ||
|
|
155b34e495 | ||
|
|
00c9dc4236 | ||
|
|
b66aba1a06 | ||
|
|
17f8a674b8 | ||
|
|
b8080ba775 | ||
|
|
7265736545 | ||
|
|
399f465e59 | ||
|
|
9ee89bc7f7 | ||
|
|
748b2d0f3f | ||
|
|
fb4635e013 | ||
|
|
73b459e770 | ||
|
|
a41af0f65f | ||
|
|
96eecc0da3 | ||
|
|
69d5373222 | ||
|
|
538ab88eda | ||
|
|
21b3f39c0b | ||
|
|
998e275e65 | ||
|
|
31d428a649 | ||
|
|
240cf7e05f | ||
|
|
2ad710d83a | ||
|
|
dcce72b66e | ||
|
|
083769d642 | ||
|
|
a53dba8c62 | ||
|
|
670d43ba04 | ||
|
|
73a731f2da | ||
|
|
1542f1f369 | ||
|
|
6f58d7abe7 | ||
|
|
7e0fbf9691 | ||
|
|
865034e8f7 | ||
|
|
6e96ee4f3c | ||
|
|
16d98b49f0 | ||
|
|
d04721c75a | ||
|
|
8512709251 | ||
|
|
efeaea70a9 | ||
|
|
a403244e67 | ||
|
|
985c1d63b6 | ||
|
|
9d8d4057f6 | ||
|
|
ec8843fe90 | ||
|
|
935970156c | ||
|
|
e4e6147081 | ||
|
|
3e1b68d801 | ||
|
|
1b493c9914 | ||
|
|
6ecdc1a517 | ||
|
|
619079cedf | ||
|
|
bbf7674b43 | ||
|
|
f163e4f16f | ||
|
|
bd8c2d6f24 | ||
|
|
3906b6b41b | ||
|
|
753ef963f6 | ||
|
|
0721245b3e | ||
|
|
b7adfd5f32 | ||
|
|
a9342daee2 | ||
|
|
ed0cafac7c | ||
|
|
6e6fd4b5d0 | ||
|
|
5cd533e6cc | ||
|
|
d5e8d85ce9 | ||
|
|
e234568a34 | ||
|
|
19cf0711bc | ||
|
|
067e3f346f | ||
|
|
2117e44e9d | ||
|
|
902ba22877 | ||
|
|
60c2cd65df | ||
|
|
fde29326f1 | ||
|
|
44d795437e | ||
|
|
03598d869b | ||
|
|
a3e44a5c60 | ||
|
|
02b124eceb | ||
|
|
91472bc3d6 | ||
|
|
7f45c52ce7 | ||
|
|
b6ef1d3a36 | ||
|
|
fd6ccbcfb3 | ||
|
|
17614e348b | ||
|
|
c26ef0eb3b | ||
|
|
b78206d2f4 | ||
|
|
69e0396fb1 | ||
|
|
6d9154196e | ||
|
|
87fdd6c73b | ||
|
|
209bd3aee1 | ||
|
|
46e77d0b00 | ||
|
|
6f10f6be9c | ||
|
|
0d0fdc15ac | ||
|
|
bff3f50ae0 | ||
|
|
85aaa39206 | ||
|
|
b85a7062be | ||
|
|
af47d5f414 | ||
|
|
41d90e0238 | ||
|
|
86263a2fa0 | ||
|
|
f6d1caab9d | ||
|
|
1776891736 | ||
|
|
f52a851972 | ||
|
|
3026465ae3 | ||
|
|
14d87f4b30 | ||
|
|
5881f07323 | ||
|
|
b545fe47a7 | ||
|
|
4da4dd57c4 | ||
|
|
3e12ddfb2b | ||
|
|
3ecf5d2ed2 | ||
|
|
0a5acdb996 | ||
|
|
a712a58eba | ||
|
|
6de892c92b | ||
|
|
495defd69b | ||
|
|
1a20fcfce6 | ||
|
|
ed1e45a43d | ||
|
|
556dc8926e | ||
|
|
66cf45b90b | ||
|
|
d1e49e06e6 | ||
|
|
8bf28dbe43 | ||
|
|
9ae95d0797 | ||
|
|
321051b723 | ||
|
|
5f68542529 | ||
|
|
82c044ee33 | ||
|
|
9bcc67e73a | ||
|
|
f1ce6c2acb | ||
|
|
034108a2a0 | ||
|
|
f96d7b868f | ||
|
|
0dfe319d41 | ||
|
|
b7e970f4e6 | ||
|
|
02e62ad5d6 | ||
|
|
541d2458fb | ||
|
|
b1e860ab40 | ||
|
|
e8eab9b3ec | ||
|
|
6bc76c3c92 | ||
|
|
2acd8e477c | ||
|
|
ff2b0c9bdc | ||
|
|
79208720d1 | ||
|
|
fca04c4125 | ||
|
|
5b5b72cc19 | ||
|
|
217ad97bfd | ||
|
|
3e3cfc5325 | ||
|
|
da86ea98fc | ||
|
|
5f3e422b5c | ||
|
|
1f1f89b062 | ||
|
|
0f79960b85 | ||
|
|
117ce59f27 | ||
|
|
214121480e | ||
|
|
6261536f57 | ||
|
|
a748b7e606 | ||
|
|
92952ee746 | ||
|
|
c22a9aff7d | ||
|
|
dd8a3c8d59 | ||
|
|
4a1abee1df | ||
|
|
92ef3ffbb8 | ||
|
|
899763bc34 | ||
|
|
c69ad3c2d6 | ||
|
|
9a5b932139 | ||
|
|
ba96e457b4 | ||
|
|
bdfe943bd5 | ||
|
|
3870445b7e | ||
|
|
5395a3e8bc | ||
|
|
45b3d8b0df | ||
|
|
f1ee3c003a | ||
|
|
606181406c | ||
|
|
b537400f38 | ||
|
|
0a4fdc155e | ||
|
|
0b8e59974b | ||
|
|
22eebea633 | ||
|
|
5dd414f9aa | ||
|
|
72c72f6530 | ||
|
|
de970f9dbb | ||
|
|
e8d6c5b4dd | ||
|
|
e91a5ae13e | ||
|
|
b08bfb9ad5 | ||
|
|
5353011ee4 | ||
|
|
5faa3af19a | ||
|
|
c8461c9c11 | ||
|
|
3112e2ba56 | ||
|
|
fee03e101c | ||
|
|
c730a20a26 | ||
|
|
f7ed60ac67 | ||
|
|
417716391a | ||
|
|
ee5e3cb3ca | ||
|
|
2298c5d6e3 | ||
|
|
ca9f870ff6 | ||
|
|
e9b2fd8bc4 | ||
|
|
09a4985fd2 | ||
|
|
a9e61b4cd5 | ||
|
|
6ef19c3ccd | ||
|
|
0d29458874 | ||
|
|
1795bae8b5 | ||
|
|
c1152ee09a | ||
|
|
182149aac7 | ||
|
|
d6df440987 | ||
|
|
df16c24d68 | ||
|
|
8a2c259235 | ||
|
|
a7f265de11 | ||
|
|
581529540a | ||
|
|
8ad61d9061 | ||
|
|
3d79861970 | ||
|
|
0a84ccb299 | ||
|
|
3aa37450a0 | ||
|
|
450722153d | ||
|
|
fbba32defb | ||
|
|
d762d64b49 | ||
|
|
a5b1dda62d | ||
|
|
aad904b550 | ||
|
|
a01e895e30 | ||
|
|
52e5d41518 | ||
|
|
77a40b6237 | ||
|
|
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 |
5
.eslintignore
Normal file
5
.eslintignore
Normal file
@@ -0,0 +1,5 @@
|
||||
coverage
|
||||
dist
|
||||
node_modules
|
||||
packages/**/vendor/*
|
||||
packages/examples
|
||||
@@ -25,7 +25,8 @@
|
||||
"document": false,
|
||||
"navigator": false,
|
||||
"window": false,
|
||||
// Flow global types
|
||||
// Flow global types,
|
||||
"$Enum": false,
|
||||
"HTMLInputElement": false,
|
||||
"ReactClass": false,
|
||||
"ReactComponent": false,
|
||||
|
||||
15
.flowconfig
15
.flowconfig
@@ -1,14 +1,17 @@
|
||||
[version]
|
||||
^0.63.0
|
||||
|
||||
[ignore]
|
||||
.*/__tests__/.*
|
||||
.*/benchmarks/.*
|
||||
.*/docs/.*
|
||||
.*/node_modules/animated/*
|
||||
<PROJECT_ROOT>/.*/__tests__/.*
|
||||
<PROJECT_ROOT>/packages/.*/dist/.*
|
||||
<PROJECT_ROOT>/packages/examples/.*
|
||||
<PROJECT_ROOT>/packages/website/.*
|
||||
.*/node_modules/babel-plugin-transform-react-remove-prop-types/*
|
||||
|
||||
[include]
|
||||
|
||||
[libs]
|
||||
types
|
||||
<PROJECT_ROOT>/types
|
||||
|
||||
[options]
|
||||
unsafe.enable_getters_and_setters=true
|
||||
|
||||
|
||||
98
.github/CONTRIBUTING.md
vendored
98
.github/CONTRIBUTING.md
vendored
@@ -4,7 +4,8 @@
|
||||
|
||||
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.
|
||||
issue hasn't already been reported. Please note that your issue may be closed
|
||||
if it doesn't include the information requested in the issue template.
|
||||
|
||||
## Getting started
|
||||
|
||||
@@ -17,7 +18,7 @@ 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):
|
||||
Install dependencies (requires [yarn](https://yarnpkg.com/en/docs/install)):
|
||||
|
||||
```
|
||||
yarn
|
||||
@@ -25,6 +26,12 @@ yarn
|
||||
|
||||
## Automated tests
|
||||
|
||||
To run the linter:
|
||||
|
||||
```
|
||||
yarn lint
|
||||
```
|
||||
|
||||
To run flow:
|
||||
|
||||
```
|
||||
@@ -40,62 +47,57 @@ yarn jest
|
||||
…in watch mode:
|
||||
|
||||
```
|
||||
yarn jest:watch
|
||||
yarn jest --watch
|
||||
```
|
||||
|
||||
To run all automated tests:
|
||||
To run all these 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 benchmarks
|
||||
```
|
||||
|
||||
## Compile and build
|
||||
|
||||
To compile the source code to `dist`:
|
||||
To compile the `react-native-web` source code:
|
||||
|
||||
```
|
||||
yarn compile
|
||||
```
|
||||
|
||||
To create a UMD bundle of the library:
|
||||
…in watch mode:
|
||||
|
||||
```
|
||||
yarn build
|
||||
yarn compile --watch
|
||||
```
|
||||
|
||||
### Pre-commit
|
||||
## Website and visual tests
|
||||
|
||||
To format and lint code before commit:
|
||||
To run the interactive storybook:
|
||||
|
||||
```
|
||||
yarn precommit
|
||||
yarn website
|
||||
```
|
||||
|
||||
To format and lint the entire project:
|
||||
When you're also making changes to the 'react-native-web' source files, run this command in another process:
|
||||
|
||||
```
|
||||
yarn fmt
|
||||
yarn lint
|
||||
yarn compile --watch
|
||||
```
|
||||
|
||||
## Benchmarks
|
||||
|
||||
To run the benchmarks locally:
|
||||
|
||||
```
|
||||
yarn benchmarks
|
||||
open ./packages/benchmarks/dist/index.html
|
||||
```
|
||||
|
||||
To develop against these benchmarks:
|
||||
|
||||
```
|
||||
yarn compile --watch
|
||||
yarn benchmarks --watch
|
||||
```
|
||||
|
||||
### New Features
|
||||
@@ -104,13 +106,16 @@ 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
|
||||
## Pull requests
|
||||
|
||||
* 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.
|
||||
**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`).
|
||||
|
||||
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.
|
||||
@@ -119,3 +124,18 @@ 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!
|
||||
|
||||
## Releases
|
||||
|
||||
To commit, publish, and push a final version:
|
||||
|
||||
```
|
||||
yarn release <version>
|
||||
```
|
||||
|
||||
Release candidates or versions that you'd like to publish to npm, but do not
|
||||
want to produce a commit and push it to GitHub:
|
||||
|
||||
```
|
||||
yarn release <version> --skip-git
|
||||
```
|
||||
|
||||
30
.github/ISSUE_TEMPLATE.md
vendored
30
.github/ISSUE_TEMPLATE.md
vendored
@@ -1,30 +0,0 @@
|
||||
<!--
|
||||
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?**
|
||||
|
||||
Link to minimal test case: (template: [codepen](https://codepen.io/necolas/pen/PZzwBR?editors=0010))
|
||||
|
||||
**What is the expected behaviour?**
|
||||
|
||||
**Steps to reproduce**
|
||||
|
||||
1.
|
||||
2.
|
||||
|
||||
**Environment (include versions)**
|
||||
|
||||
OS:
|
||||
Device:
|
||||
Browser:
|
||||
React Native for Web (version):
|
||||
React (version):
|
||||
52
.github/ISSUE_TEMPLATE/bug.md
vendored
Normal file
52
.github/ISSUE_TEMPLATE/bug.md
vendored
Normal file
@@ -0,0 +1,52 @@
|
||||
---
|
||||
name: "\U0001F41B Bug report"
|
||||
about: "If something isn't working as expected \U0001F914"
|
||||
|
||||
---
|
||||
|
||||
<!--
|
||||
Thank you for reporting an issue. Please note that an issue must include the
|
||||
information that is marked as REQUIRED below, or it may be closed.
|
||||
-->
|
||||
|
||||
**The problem**
|
||||
<!--
|
||||
REQUIRED: A clear and concise description of the bug or problem.
|
||||
-->
|
||||
|
||||
**How to reproduce**
|
||||
<!--
|
||||
REQUIRED: Create a test case by forking this template https://codesandbox.io/s/6lx6ql1w5r
|
||||
|
||||
Failing to include a reduced test case may result in the issue being closed,
|
||||
and will delay any potential fix. Your application or GitHub project is NOT
|
||||
considered a reduced test case. If the issue only affects certain browsers,
|
||||
providing screenshots is also helpful.
|
||||
-->
|
||||
Simplified test case: <!-- add link here -->
|
||||
|
||||
Steps to reproduce:
|
||||
1.
|
||||
2.
|
||||
3.
|
||||
|
||||
**Expected behavior**
|
||||
<!--
|
||||
REQUIRED: A clear and concise description of what you expected to happen.
|
||||
|
||||
Please check that the behaviour is not expected React Native behaviour by
|
||||
running your test case on iOS or Android using https://snack.expo.io.
|
||||
-->
|
||||
|
||||
**Environment (include versions). Did this work in previous versions?**
|
||||
|
||||
* React Native for Web (version): TBC
|
||||
* React (version): TBC
|
||||
* Browser: TBC
|
||||
|
||||
<!--
|
||||
OPTIONAL:
|
||||
|
||||
**Additional context**
|
||||
Add any other context about the problem here.
|
||||
-->
|
||||
17
.github/ISSUE_TEMPLATE/feature.md
vendored
Normal file
17
.github/ISSUE_TEMPLATE/feature.md
vendored
Normal file
@@ -0,0 +1,17 @@
|
||||
---
|
||||
name: "\U0001F680 Feature request"
|
||||
about: If you have a suggestion
|
||||
|
||||
---
|
||||
|
||||
**Is your feature request related to a problem? Please describe.**
|
||||
<!-- A clear and concise description of what the problem is, e.g., I have an issue when [...] -->
|
||||
|
||||
**Describe a solution you'd like**
|
||||
<!-- A clear and concise description of what you want to happen. Add any considered drawbacks. -->
|
||||
|
||||
**Describe alternatives you've considered**
|
||||
<!-- A clear and concise description of any alternative solutions or features you've considered. -->
|
||||
|
||||
**Additional context**
|
||||
<!-- Add any other context or screenshots about the feature request here. -->
|
||||
18
.github/PULL_REQUEST_TEMPLATE.md
vendored
18
.github/PULL_REQUEST_TEMPLATE.md
vendored
@@ -1,18 +0,0 @@
|
||||
<!--
|
||||
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,2 +1,3 @@
|
||||
coverage
|
||||
node_modules
|
||||
dist
|
||||
|
||||
5
.prettierignore
Normal file
5
.prettierignore
Normal file
@@ -0,0 +1,5 @@
|
||||
coverage
|
||||
dist
|
||||
node_modules
|
||||
packages/**/vendor/*
|
||||
packages/examples
|
||||
20
.travis.yml
20
.travis.yml
@@ -1,9 +1,17 @@
|
||||
language: node_js
|
||||
|
||||
node_js:
|
||||
- "6"
|
||||
before_script:
|
||||
- export DISPLAY=:99.0
|
||||
- sh -e /etc/init.d/xvfb start
|
||||
- "8"
|
||||
|
||||
before_install:
|
||||
# Install Yarn
|
||||
- curl -o- -L https://yarnpkg.com/install.sh | bash
|
||||
- export PATH=$HOME/.yarn/bin:$PATH
|
||||
|
||||
cache:
|
||||
yarn: true
|
||||
directories:
|
||||
- node_modules
|
||||
|
||||
script:
|
||||
- npm run lint
|
||||
- npm test
|
||||
- yarn test
|
||||
|
||||
45
LICENSE
45
LICENSE
@@ -1,31 +1,22 @@
|
||||
BSD License
|
||||
MIT License
|
||||
|
||||
For React Native software
|
||||
Copyright (c) 2015-present, Nicolas Gallagher.
|
||||
Copyright (c) 2015-present, Facebook, Inc.
|
||||
|
||||
Copyright (c) 2015-present, Nicolas Gallagher. All rights reserved.
|
||||
Copyright (c) 2015-present, Facebook, Inc. All rights reserved.
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
Redistribution and use in source and binary forms, with or without modification,
|
||||
are permitted provided that the following conditions are met:
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
* Redistributions of source code must retain the above copyright notice, this
|
||||
list of conditions and the following disclaimer.
|
||||
|
||||
* Redistributions in binary form must reproduce the above copyright notice,
|
||||
this list of conditions and the following disclaimer in the documentation
|
||||
and/or other materials provided with the distribution.
|
||||
|
||||
* Neither the name Facebook nor the names of its contributors may be used to
|
||||
endorse or promote products derived from this software without specific
|
||||
prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
|
||||
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
|
||||
ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
|
||||
291
README.md
291
README.md
@@ -1,103 +1,246 @@
|
||||
# React Native for Web
|
||||
|
||||
[![Build Status][travis-image]][travis-url]
|
||||
[![npm version][npm-image]][npm-url]
|
||||
[![npm version][package-badge]][package-url] [![Build Status][ci-badge]][ci-url] [](https://reactjs.org/docs/how-to-contribute.html#your-first-pull-request)
|
||||
|
||||
[React Native][react-native-url] components and APIs for the Web.
|
||||
**Compatibility: React Native 0.55**.
|
||||
|
||||
Browser support: Chrome, Firefox, Safari >= 7, IE 10, Edge.
|
||||
"React Native for Web" makes it possible to run [React
|
||||
Native][react-native-url] components and APIs on the web using React DOM. Check
|
||||
out the live demo of the [React Native examples][examples-url] running on the
|
||||
web.
|
||||
|
||||
[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
|
||||
* **High-quality web interfaces**: makes it easy to
|
||||
create [fast](https://github.com/necolas/react-native-web/blob/master/packages/benchmarks/README.md),
|
||||
adaptive web UIs in JavaScript. It provides native-quality interactions, support
|
||||
for multiple input modes (touch, mouse, keyboard), optimized vendor-prefixed
|
||||
styles, built-in support for RTL layout, built-in accessibility, and integrates
|
||||
with React Dev Tools.
|
||||
|
||||
## Overview
|
||||
* **Write once, render anywhere**: interoperates with existing React DOM
|
||||
components and is compatible with the majority of the React Native API. You can
|
||||
develop new components for native and web without rewriting existing code.
|
||||
React Native for Web can also render to HTML and critical CSS on the server
|
||||
using Node.js.
|
||||
|
||||
"React Native for Web" is a project to bring React Native's building blocks and
|
||||
touch handling to the Web.
|
||||
Who is using React Native in production web apps?
|
||||
[Twitter](https://mobile.twitter.com),
|
||||
[Major League Soccer](https://matchcenter.mlssoccer.com),
|
||||
[Flipkart](https://twitter.com/naqvitalha/status/969577892991549440),
|
||||
[Uber](https://www.youtube.com/watch?v=RV9rxrNIxnY),
|
||||
[The Times](https://github.com/newsuk/times-components), [DataCamp](https://www.datacamp.com/community/tech/porting-practice-to-web-part1).
|
||||
|
||||
Browse the [UI Explorer](https://necolas.github.io/react-native-web/storybook/)
|
||||
to see React Native examples running on Web. Or try it out online with [React
|
||||
Native for Web: Playground](https://www.webpackbin.com/bins/-KgucwxRbn7HRU-V-3Bc).
|
||||
Browser support: Chrome, Firefox, Edge, Safari 7+, IE 10+.
|
||||
|
||||
## Quick start
|
||||
|
||||
To install in your app:
|
||||
The easiest way to get started is to edit this
|
||||
[CodeSandbox](https://codesandbox.io/s/q4qymyp2l6) template (or
|
||||
[Glitch](https://glitch.com/edit/#!/react-native)). You don’t need to install
|
||||
anything to try it out.
|
||||
|
||||
```
|
||||
npm install --save react@15.6 react-dom@15.6 react-native-web
|
||||
```
|
||||
|
||||
NOTE: React Native for Web supports React/ReactDOM 15.4, 15.5, or 15.6.
|
||||
|
||||
Then read the [Getting Started](docs/guides/getting-started.md) guide.
|
||||
For installation and configuration details please read the [getting
|
||||
started](https://github.com/necolas/react-native-web/blob/master/docs/guides/getting-started.md)
|
||||
guide.
|
||||
|
||||
## Documentation
|
||||
|
||||
The [UI Explorer](https://necolas.github.io/react-native-web/storybook/)
|
||||
interactively documents all the APIs and Components.
|
||||
Please refer to the [React Native documentation][react-native-url] for the
|
||||
overall API, design details, and information about the [Gesture Responder
|
||||
system](https://facebook.github.io/react-native/docs/gesture-responder-system.html)
|
||||
and [animations](https://facebook.github.io/react-native/docs/animations.html).
|
||||
|
||||
Guides:
|
||||
Some components and APIs are extended with additional features for the web. And
|
||||
in a few cases, features present for Android or iOS are missing on the web.
|
||||
These differences are documented [on the website][website-url].
|
||||
|
||||
* [Getting started](docs/guides/getting-started.md)
|
||||
* [Style](docs/guides/style.md)
|
||||
* [Accessibility](docs/guides/accessibility.md)
|
||||
* [Direct manipulation](docs/guides/direct-manipulation.md)
|
||||
* [Internationalization](docs/guides/internationalization.md)
|
||||
* [Advanced use](docs/guides/advanced.md)
|
||||
* [Known issues](docs/guides/known-issues.md)
|
||||
### Guides
|
||||
|
||||
## Example code
|
||||
These guides provide a detailed look at using React Native to create accessible
|
||||
web experiences. Certain web-specific patterns are documented in the "web
|
||||
recipes" guide.
|
||||
|
||||
* [Getting started](https://github.com/necolas/react-native-web/blob/master/docs/guides/getting-started.md)
|
||||
* [Client-side rendering](https://github.com/necolas/react-native-web/blob/master/docs/guides/client-side-rendering.md)
|
||||
* [Server-side rendering](https://github.com/necolas/react-native-web/blob/master/docs/guides/server-side-rendering.md)
|
||||
* [Style](https://github.com/necolas/react-native-web/blob/master/docs/guides/style.md)
|
||||
* [Accessibility](https://github.com/necolas/react-native-web/blob/master/docs/guides/accessibility.md)
|
||||
* [Internationalization](https://github.com/necolas/react-native-web/blob/master/docs/guides/internationalization.md)
|
||||
* [Direct manipulation](https://github.com/necolas/react-native-web/blob/master/docs/guides/direct-manipulation.md)
|
||||
* [Web recipes](https://github.com/necolas/react-native-web/blob/master/docs/guides/web-recipes.md)
|
||||
* [Multi-platform apps](https://github.com/necolas/react-native-web/blob/master/docs/guides/multi-platform-apps.md)
|
||||
* [Experimental / unstable use](https://github.com/necolas/react-native-web/blob/master/docs/guides/advanced.md)
|
||||
|
||||
## Integrations
|
||||
|
||||
Examples of using React Native for Web with other web tools:
|
||||
|
||||
* [Docz](https://github.com/pedronauck/docz-plugin-react-native)
|
||||
* [Gatsby](https://github.com/slorber/gatsby-plugin-react-native-web)
|
||||
* [Next.js](https://github.com/zeit/next.js/tree/master/examples/with-react-native-web) (and [example recipes](https://gist.github.com/necolas/f9034091723f1b279be86c7429eb0c96))
|
||||
* [Phenomic](https://github.com/phenomic/phenomic/tree/master/examples/react-native-web-app)
|
||||
* [Razzle](https://github.com/jaredpalmer/razzle/tree/master/examples/with-react-native-web)
|
||||
* [Storybook](https://github.com/necolas/react-native-web/tree/master/packages/website/storybook/.storybook)
|
||||
* [Styleguidist](https://github.com/styleguidist/react-styleguidist/tree/master/examples/react-native)
|
||||
|
||||
## Examples
|
||||
|
||||
Check out all the [React Native examples][examples-url] ([source
|
||||
code](https://github.com/necolas/react-native-web/blob/master/packages/examples)).
|
||||
There are more examples [on the website][website-url] ([source
|
||||
code](https://github.com/necolas/react-native-web/blob/master/packages/website)).
|
||||
And here is a simple example to get you started:
|
||||
|
||||
```js
|
||||
import React from 'react'
|
||||
import { AppRegistry, Image, StyleSheet, Text, View } from 'react-native'
|
||||
import React from 'react';
|
||||
import { AppRegistry, StyleSheet, Text, View } from 'react-native';
|
||||
|
||||
// Components
|
||||
const Card = ({ children }) => <View style={styles.card}>{children}</View>
|
||||
const Title = ({ children }) => <Text style={styles.title}>{children}</Text>
|
||||
const Photo = ({ uri }) => <Image source={{ uri }} style={styles.image} />
|
||||
const App = () => (
|
||||
<Card>
|
||||
<Title>App Card</Title>
|
||||
<Photo uri="/some-photo.jpg" />
|
||||
</Card>
|
||||
)
|
||||
|
||||
// Styles
|
||||
const styles = StyleSheet.create({
|
||||
card: {
|
||||
flexGrow: 1,
|
||||
justifyContent: 'center'
|
||||
},
|
||||
title: {
|
||||
fontSize: '1.25rem',
|
||||
fontWeight: 'bold'
|
||||
},
|
||||
image: {
|
||||
height: 40,
|
||||
marginVertical: 10,
|
||||
width: 40
|
||||
class App extends React.Component {
|
||||
render() {
|
||||
return (
|
||||
<View style={styles.box}>
|
||||
<Text style={styles.text}>Hello, world!</Text>
|
||||
</View>
|
||||
);
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
// App registration and rendering
|
||||
AppRegistry.registerComponent('MyApp', () => App)
|
||||
AppRegistry.runApplication('MyApp', { rootTag: document.getElementById('react-root') })
|
||||
const styles = StyleSheet.create({
|
||||
box: { padding: 10 },
|
||||
text: { fontWeight: 'bold' }
|
||||
});
|
||||
|
||||
AppRegistry.registerComponent('App', () => App);
|
||||
AppRegistry.runApplication('App', { rootTag: document.getElementById('react-root') });
|
||||
```
|
||||
|
||||
## Related projects
|
||||
This example will render the `App` into a container on the page.
|
||||
|
||||
* [react-primitives](https://github.com/lelandrichardson/react-primitives/)
|
||||
* [react-native-web-player](https://github.com/dabbott/react-native-web-player)
|
||||
* [react-native-web-starter](https://github.com/grabcode/react-native-web-starter)
|
||||
* [react-native-web-webpack](https://github.com/ndbroadbent/react-native-web-webpack)
|
||||
* [react-sketchapp](https://github.com/airbnb/react-sketchapp)
|
||||
* [react-web](https://github.com/taobaofed/react-web)
|
||||
* [reactxp](https://github.com/microsoft/reactxp)
|
||||
You'll notice that there is no reference to `react-dom`; the `App` component is
|
||||
defined using the platform-agnostic APIs and Components introduced by React
|
||||
Native. This allows the app to be rendered to web and native platforms.
|
||||
|
||||
## Compatibility with React Native
|
||||
|
||||
React Native v0.55
|
||||
|
||||
### Components
|
||||
|
||||
| Name | Status | Notes |
|
||||
| :----------------------- | :----- | :---- |
|
||||
| ActivityIndicator | ✓ | |
|
||||
| ART | ✓ | |
|
||||
| Button | ✓ | |
|
||||
| CheckBox | ✓ | |
|
||||
| FlatList | ✓ | |
|
||||
| Image | ✓ | Missing multiple sources ([#515](https://github.com/necolas/react-native-web/issues/515)) and HTTP headers ([#1019](https://github.com/necolas/react-native-web/issues/1019)). |
|
||||
| ImageBackground | ✓ | |
|
||||
| KeyboardAvoidingView | (✓) | Mock. No equivalent web APIs. |
|
||||
| ListView | ✓ | |
|
||||
| Modal | ✘ | Not started ([#1020](https://github.com/necolas/react-native-web/issues/1020)). |
|
||||
| Picker | ✓ | |
|
||||
| RefreshControl | ✘ | Not started ([#1027](https://github.com/necolas/react-native-web/issues/1027)). |
|
||||
| SafeAreaView | ✓ | |
|
||||
| ScrollView | ✓ | Missing momentum scroll events ([#1021](https://github.com/necolas/react-native-web/issues/1021)). |
|
||||
| SectionList | ✓ | |
|
||||
| Slider | ✘ | Not started ([#1022](https://github.com/necolas/react-native-web/issues/1022)). |
|
||||
| StatusBar | (✓) | Mock. No equivalent web APIs. |
|
||||
| SwipeableFlatList | ✓ | |
|
||||
| SwipeableListView | ✓ | |
|
||||
| Switch | ✓ | |
|
||||
| Text | ✓ | Missing `onLongPress` ([#1011](https://github.com/necolas/react-native-web/issues/1011)) and `numberOfLines` ([#13](https://github.com/necolas/react-native-web/issues/13)) support. |
|
||||
| TextInput | ✓ | Missing `onContentSizeChange` ([#793](https://github.com/necolas/react-native-web/issues/793)), rich text features ([#1023](https://github.com/necolas/react-native-web/issues/1023)), and auto-expanding behaviour ([#795](https://github.com/necolas/react-native-web/issues/795)). |
|
||||
| Touchable | ✓ | Includes additional support for mouse and keyboard interactions. |
|
||||
| TouchableHighlight | ✓ | |
|
||||
| TouchableNativeFeedback | ✘ | Not started ([#1024](https://github.com/necolas/react-native-web/issues/1024)). |
|
||||
| TouchableOpacity | ✓ | |
|
||||
| TouchableWithoutFeedback | ✓ | |
|
||||
| View | ✓ | |
|
||||
| VirtualizedList | ✓ | |
|
||||
| WebView | ✘ | Not started ([1025](https://github.com/necolas/react-native-web/issues/1025)). |
|
||||
| YellowBox | (✓) | Mock. No YellowBox functionality. |
|
||||
|
||||
### Modules
|
||||
|
||||
| Name | Status | Notes |
|
||||
| :----------------------- | :----- | :---- |
|
||||
| AccessibilityInfo | (✓) | Mock. No equivalent web APIs. |
|
||||
| Alert | ✘ | Not started ([#1026](https://github.com/necolas/react-native-web/issues/1026)). |
|
||||
| Animated | ✓ | Missing `useNativeDriver` support. |
|
||||
| AppRegistry | ✓ | Includes additional support for server rendering with `getApplication`. |
|
||||
| AppState | ✓ | |
|
||||
| AsyncStorage | ✓ | |
|
||||
| BackHandler | (✓) | Mock. No equivalent web APIs. |
|
||||
| CameraRoll | ✘ | No equivalent web APIs. |
|
||||
| Clipboard | ✓ | |
|
||||
| ColorPropType | ✓ | |
|
||||
| DeviceInfo | (✓) | Limited information. |
|
||||
| Dimensions | ✓ | |
|
||||
| Easing | ✓ | |
|
||||
| EdgeInsetsPropType | ✓ | |
|
||||
| Geolocation | ✓ | |
|
||||
| I18nManager | ✓ | Includes additional support for runtime switch to RTL. |
|
||||
| ImageEditor | ✘ | No equivalent web APIs. |
|
||||
| ImageStore | ✘ | No equivalent web APIs. |
|
||||
| InteractionManager | (✓) | |
|
||||
| Keyboard | (✓) | Mock. |
|
||||
| LayoutAnimation | (✓) | Missing translation to web animations. |
|
||||
| Linking | ✓ | |
|
||||
| NativeEventEmitter | ✓ | |
|
||||
| NativeMethodsMixin | ✓ | |
|
||||
| NativeModules | (✓) | Mocked. Missing ability to load native modules. |
|
||||
| NetInfo | ✓ | Missing functionality to detect expensive connections as there are no equivalent web APIs. |
|
||||
| PanResponder | ✓ | |
|
||||
| PixelRatio | ✓ | |
|
||||
| Platform | ✓ | |
|
||||
| PointPropType | ✓ | |
|
||||
| Settings | ✘ | No equivalent web APIs. |
|
||||
| Share | ✓ | Only available over HTTPS. Read about the [Web Share API](https://wicg.github.io/web-share/). |
|
||||
| StyleSheet | ✓ | |
|
||||
| TextPropTypes | ✓ | |
|
||||
| UIManager | ✓ | |
|
||||
| Vibration | ✓ | |
|
||||
| ViewPropTypes | ✓ | |
|
||||
|
||||
## Contributing
|
||||
|
||||
The main purpose of this repository is to help evolve React web and native
|
||||
development towards the platform-agnostic design of React Native, and in the
|
||||
process make it faster and easier to build high-quality experiences for the web
|
||||
with React. Development happens in the open on GitHub, and we are grateful for
|
||||
contributing bugfixes and improvements. Read below to learn how you can take
|
||||
part in improving React Native for Web.
|
||||
|
||||
### Code of conduct
|
||||
|
||||
Facebook has adopted a [Code of Conduct][code-of-conduct] that this project
|
||||
expects all participants to adhere to. Please read the full text so that you
|
||||
can understand what actions will and will not be tolerated.
|
||||
|
||||
### Contributing guide
|
||||
|
||||
Read the [contributing guide][contributing-url] to learn about the
|
||||
development process, how to propose bugfixes and improvements, and how to build
|
||||
and test your changes to React Native for Web.
|
||||
|
||||
### Good first issues
|
||||
|
||||
To help you get you familiar with the contribution process, there is a list of
|
||||
[good first issues][good-first-issue-url] that contain bugs which have a
|
||||
relatively limited scope. This is a great place to get started.
|
||||
|
||||
## License
|
||||
|
||||
React Native for Web is [BSD licensed](LICENSE).
|
||||
React Native for Web is [MIT licensed](./LICENSE). By contributing to React
|
||||
Native for Web, you agree that your contributions will be licensed under its
|
||||
MIT license.
|
||||
|
||||
[package-badge]: https://img.shields.io/npm/v/react-native-web.svg?style=flat
|
||||
[package-url]: https://yarnpkg.com/en/package/react-native-web
|
||||
[ci-badge]: https://travis-ci.org/necolas/react-native-web.svg?branch=master
|
||||
[ci-url]: https://travis-ci.org/necolas/react-native-web
|
||||
[examples-url]: https://necolas.github.io/react-native-web/examples/
|
||||
[website-url]: https://necolas.github.io/react-native-web/storybook/
|
||||
[react-native-url]: https://facebook.github.io/react-native/
|
||||
[contributing-url]: https://github.com/necolas/react-native-web/blob/master/.github/CONTRIBUTING.md
|
||||
[good-first-issue-url]: https://github.com/necolas/react-native-web/labels/good%20first%20issue
|
||||
[code-of-conduct]: https://code.facebook.com/codeofconduct
|
||||
|
||||
@@ -1,47 +0,0 @@
|
||||
# Performance
|
||||
|
||||
To run these benchmarks:
|
||||
|
||||
```
|
||||
npm run build:performance
|
||||
open ./performance/index.html
|
||||
```
|
||||
|
||||
## 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` | `94.96` `±31.01` | `200.43` `±38.90` | |
|
||||
| `react-native-web/stylesheet@0.0.107` | `98.58` `±10.83` | `218.59` `±36.52` | |
|
||||
| `react-native-web@0.0.107` | `117.45` `±18.76` | `288.27` `±33.50` | `15.10` `±5.45ms` |
|
||||
|
||||
Other libraries
|
||||
|
||||
| Implementation | Deep tree (ms) | Wide tree (ms) |
|
||||
| :--- | ---: | ---: |
|
||||
| `styletron@2.5.1` | `90.38` `±15.15` | `197.40` `±29.02` |
|
||||
| `aphrodite@1.2.0` | `88.65` `±19.62` | `187.35` `±24.60` |
|
||||
| `glamor@3.0.0-1` | `145.64` `±21.93` | `283.60` `±23.26` |
|
||||
| `react-jss@5.4.1` | `143.17` `±19.14` | `361.80` `±33.39` |
|
||||
| `reactxp@0.34.3` | `227.18` `±28.75` | `496.08` `±59.96` |
|
||||
| `styled-components@2.1.0` | `262.85` `±46.12` | `578.43` `±35.86` |
|
||||
| `styled-components/primitives@2.1.0` | `261.43` `±44.14` | `569.65` `±22.19` |
|
||||
|
||||
These results indicate that render performance is not a significant
|
||||
differentiating factor between `aphrodite`, `styletron`, and
|
||||
`react-native-web/stylesheet`.
|
||||
|
||||
*MacBook Pro (13-inch, Early 2015); 3.1 GHz Intel Core i7; 16 GB 1867 MHz DDR3. Google Chrome 58 (2x CPU slowdown).
|
||||
@@ -1,97 +0,0 @@
|
||||
import * as marky from 'marky';
|
||||
|
||||
const fmt = time => `${Math.round(time * 100) / 100}ms`;
|
||||
|
||||
const measure = (name, fn) => {
|
||||
marky.mark(name);
|
||||
fn();
|
||||
const performanceMeasure = marky.stop(name);
|
||||
return performanceMeasure.duration;
|
||||
};
|
||||
|
||||
const mean = values => {
|
||||
const sum = values.reduce((sum, value) => sum + value, 0);
|
||||
return sum / values.length;
|
||||
};
|
||||
|
||||
const median = values => {
|
||||
if (!Array.isArray(values)) {
|
||||
return 0;
|
||||
}
|
||||
if (values.length === 1) {
|
||||
return values[0];
|
||||
}
|
||||
|
||||
const numbers = [...values].sort((a, b) => a - b);
|
||||
return (numbers[(numbers.length - 1) >> 1] + numbers[numbers.length >> 1]) / 2;
|
||||
};
|
||||
|
||||
const standardDeviation = values => {
|
||||
const avg = mean(values);
|
||||
|
||||
const squareDiffs = values.map(value => {
|
||||
const diff = value - avg;
|
||||
return diff * diff;
|
||||
});
|
||||
|
||||
const meanSquareDiff = mean(squareDiffs);
|
||||
return Math.sqrt(meanSquareDiff);
|
||||
};
|
||||
|
||||
const benchmark = ({ name, description, setup, teardown, task, runs }) => {
|
||||
return new Promise(resolve => {
|
||||
const durations = [];
|
||||
let i = 0;
|
||||
|
||||
setup();
|
||||
const first = measure('first', task);
|
||||
teardown();
|
||||
|
||||
const done = () => {
|
||||
const stdDev = standardDeviation(durations);
|
||||
const formattedFirst = fmt(first);
|
||||
const formattedMean = fmt(mean(durations));
|
||||
const formattedMedian = fmt(median(durations));
|
||||
const formattedStdDev = fmt(stdDev);
|
||||
|
||||
console.groupCollapsed(`${name}\n${formattedMean} ±${fmt(2 * stdDev)}`);
|
||||
description && console.log(description);
|
||||
console.log(`First: ${formattedFirst}`);
|
||||
console.log(`Median: ${formattedMedian}`);
|
||||
console.log(`Mean: ${formattedMean}`);
|
||||
console.log(`Standard deviation: ${formattedStdDev}`);
|
||||
console.log(durations);
|
||||
console.groupEnd();
|
||||
resolve();
|
||||
};
|
||||
|
||||
const a = () => {
|
||||
setup();
|
||||
window.requestAnimationFrame(b);
|
||||
};
|
||||
|
||||
const b = () => {
|
||||
const duration = measure('mean', task);
|
||||
durations.push(duration);
|
||||
window.requestAnimationFrame(c);
|
||||
};
|
||||
|
||||
const c = () => {
|
||||
teardown();
|
||||
window.requestAnimationFrame(d);
|
||||
};
|
||||
|
||||
const d = () => {
|
||||
i += 1;
|
||||
if (i < runs) {
|
||||
window.requestAnimationFrame(a);
|
||||
} else {
|
||||
window.requestAnimationFrame(done);
|
||||
}
|
||||
};
|
||||
|
||||
window.requestAnimationFrame(a);
|
||||
});
|
||||
};
|
||||
|
||||
export default benchmark;
|
||||
@@ -1,20 +0,0 @@
|
||||
import benchmark from './benchmark';
|
||||
import ReactDOM from 'react-dom';
|
||||
|
||||
const node = document.querySelector('.root');
|
||||
|
||||
const createRenderBenchmark = ({ description, getElement, name, runs }) => () => {
|
||||
const setup = () => {};
|
||||
const teardown = () => ReactDOM.unmountComponentAtNode(node);
|
||||
|
||||
return benchmark({
|
||||
name,
|
||||
description,
|
||||
runs,
|
||||
setup,
|
||||
teardown,
|
||||
task: () => ReactDOM.render(getElement(), node)
|
||||
});
|
||||
};
|
||||
|
||||
export default createRenderBenchmark;
|
||||
@@ -1,11 +0,0 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<title>Performance tests</title>
|
||||
</head>
|
||||
<body>
|
||||
<div class="root"></div>
|
||||
<script src="dist/performance.bundle.js"></script>
|
||||
</body>
|
||||
</html>
|
||||
@@ -1,52 +0,0 @@
|
||||
import aphrodite from './src/aphrodite';
|
||||
import cssModules from './src/css-modules';
|
||||
import glamor from './src/glamor';
|
||||
import jss from './src/jss';
|
||||
import reactNative from './src/react-native';
|
||||
import reactNativeStyleSheet from './src/react-native-stylesheet';
|
||||
import styledComponents from './src/styled-components';
|
||||
import styledComponentsPrimitives from './src/styled-components-primitives';
|
||||
import styletron from './src/styletron';
|
||||
import xp from './src/reactxp';
|
||||
|
||||
import renderDeepTree from './tests/renderDeepTree';
|
||||
import renderTweet from './tests/renderTweet';
|
||||
import renderWideTree from './tests/renderWideTree';
|
||||
|
||||
const testAll = window.location.search === '?all';
|
||||
|
||||
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)
|
||||
];
|
||||
|
||||
/**
|
||||
* Optionally run tests using other libraries
|
||||
*/
|
||||
const extraTests = [
|
||||
() => renderDeepTree('styletron', styletron),
|
||||
() => renderWideTree('styletron', styletron),
|
||||
() => renderDeepTree('aphrodite', aphrodite),
|
||||
() => renderWideTree('aphrodite', aphrodite),
|
||||
() => renderDeepTree('glamor', glamor),
|
||||
() => renderWideTree('glamor', glamor),
|
||||
() => renderDeepTree('react-jss', jss),
|
||||
() => renderWideTree('react-jss', jss),
|
||||
() => renderDeepTree('reactxp', xp),
|
||||
() => renderWideTree('reactxp', xp),
|
||||
() => renderDeepTree('styled-components', styledComponents),
|
||||
() => renderWideTree('styled-components', styledComponents),
|
||||
() => renderDeepTree('styled-components/primitives', styledComponentsPrimitives),
|
||||
() => renderWideTree('styled-components/primitives', styledComponentsPrimitives)
|
||||
];
|
||||
|
||||
const tests = testAll ? coreTests.concat(extraTests) : coreTests;
|
||||
|
||||
// run benchmarks
|
||||
tests.reduce((promise, test) => promise.then(test()), Promise.resolve());
|
||||
@@ -1,21 +0,0 @@
|
||||
{
|
||||
"name": "performance",
|
||||
"private": true,
|
||||
"dependencies": {
|
||||
"aphrodite": "^1.2.1",
|
||||
"classnames": "^2.2.5",
|
||||
"glamor": "2.20.25",
|
||||
"marky": "^1.2.0",
|
||||
"react-jss": "^6.1.1",
|
||||
"react-primitives": "^0.4.2",
|
||||
"reactxp": "^0.34.3",
|
||||
"styled-components": "^2.1.0",
|
||||
"styletron-client": "^2.5.7",
|
||||
"styletron-utils": "^2.5.4"
|
||||
},
|
||||
"devDependencies": {
|
||||
"css-loader": "^0.28.4",
|
||||
"react-addons-perf": "^15.4.2",
|
||||
"style-loader": "^0.18.2"
|
||||
}
|
||||
}
|
||||
@@ -1,7 +0,0 @@
|
||||
import Box from './components/Box/aphrodite';
|
||||
import View from './components/View/aphrodite';
|
||||
|
||||
export default {
|
||||
Box,
|
||||
View
|
||||
};
|
||||
@@ -1,48 +0,0 @@
|
||||
/* eslint-disable react/prop-types */
|
||||
import React from 'react';
|
||||
import StyleSheet from 'react-native/apis/StyleSheet';
|
||||
import View from '../View/react-native-stylesheet';
|
||||
|
||||
const Box = ({ color, fixed = false, layout = 'column', outer = false, ...other }) =>
|
||||
<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
|
||||
}
|
||||
});
|
||||
|
||||
module.exports = Box;
|
||||
@@ -1,30 +0,0 @@
|
||||
import styled from 'styled-components/primitives';
|
||||
|
||||
const getColor = color => {
|
||||
switch (color) {
|
||||
case 0:
|
||||
return '#222';
|
||||
case 1:
|
||||
return '#666';
|
||||
case 2:
|
||||
return '#999';
|
||||
case 3:
|
||||
return 'blue';
|
||||
case 4:
|
||||
return 'orange';
|
||||
case 5:
|
||||
return 'red';
|
||||
default:
|
||||
return 'transparent';
|
||||
}
|
||||
};
|
||||
|
||||
const Box = styled.View`
|
||||
flex-direction: ${props => (props.layout === 'column' ? 'column' : 'row')};
|
||||
padding: ${props => (props.outer ? '4px' : '0')};
|
||||
height: ${props => (props.fixed ? '20px' : 'auto')};
|
||||
width: ${props => (props.fixed ? '20px' : 'auto')};
|
||||
background-color: ${props => getColor(props.color)};
|
||||
`;
|
||||
|
||||
module.exports = Box;
|
||||
@@ -1,36 +0,0 @@
|
||||
.outer {
|
||||
padding: 4px;
|
||||
}
|
||||
|
||||
.row {
|
||||
flex-direction: row;
|
||||
}
|
||||
|
||||
.color0 {
|
||||
background-color: #222;
|
||||
}
|
||||
|
||||
.color1 {
|
||||
background-color: #666;
|
||||
}
|
||||
|
||||
.color2 {
|
||||
background-color: #999;
|
||||
}
|
||||
|
||||
.color3 {
|
||||
background-color: blue;
|
||||
}
|
||||
|
||||
.color4 {
|
||||
background-color: orange;
|
||||
}
|
||||
|
||||
.color5 {
|
||||
background-color: red;
|
||||
}
|
||||
|
||||
.fixed {
|
||||
width: 20px;
|
||||
height: 20px;
|
||||
}
|
||||
@@ -1,48 +0,0 @@
|
||||
/* 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'
|
||||
})
|
||||
};
|
||||
|
||||
module.exports = Box;
|
||||
@@ -1,39 +0,0 @@
|
||||
import React, { Component, PropTypes } 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
|
||||
};
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = DeepTree;
|
||||
@@ -1,35 +0,0 @@
|
||||
/* 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
|
||||
}
|
||||
});
|
||||
|
||||
module.exports = View;
|
||||
@@ -1,33 +0,0 @@
|
||||
/* 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;
|
||||
@@ -1,7 +0,0 @@
|
||||
import Box from './components/Box/css-modules';
|
||||
import View from './components/View/css-modules';
|
||||
|
||||
export default {
|
||||
Box,
|
||||
View
|
||||
};
|
||||
@@ -1,7 +0,0 @@
|
||||
import Box from './components/Box/glamor';
|
||||
import View from './components/View/glamor';
|
||||
|
||||
export default {
|
||||
Box,
|
||||
View
|
||||
};
|
||||
@@ -1,7 +0,0 @@
|
||||
import Box from './components/Box/jss';
|
||||
import View from './components/View/jss';
|
||||
|
||||
export default {
|
||||
Box,
|
||||
View
|
||||
};
|
||||
7
benchmarks/src/react-native-stylesheet.js
vendored
7
benchmarks/src/react-native-stylesheet.js
vendored
@@ -1,7 +0,0 @@
|
||||
import Box from './components/Box/react-native-stylesheet';
|
||||
import View from './components/View/react-native-stylesheet';
|
||||
|
||||
export default {
|
||||
Box,
|
||||
View
|
||||
};
|
||||
9
benchmarks/src/react-native.js
vendored
9
benchmarks/src/react-native.js
vendored
@@ -1,9 +0,0 @@
|
||||
import Box from './components/Box/react-native';
|
||||
import Tweet from './components/Tweet';
|
||||
import { View } from 'react-native';
|
||||
|
||||
export default {
|
||||
Box,
|
||||
Tweet,
|
||||
View
|
||||
};
|
||||
@@ -1,7 +0,0 @@
|
||||
import Box from './components/Box/reactxp';
|
||||
import { View } from 'reactxp';
|
||||
|
||||
export default {
|
||||
Box,
|
||||
View
|
||||
};
|
||||
@@ -1,7 +0,0 @@
|
||||
import Box from './components/Box/styled-components';
|
||||
import styled from 'styled-components/primitives';
|
||||
|
||||
export default {
|
||||
Box,
|
||||
View: styled.View
|
||||
};
|
||||
@@ -1,7 +0,0 @@
|
||||
import Box from './components/Box/styled-components';
|
||||
import View from './components/View/styled-components';
|
||||
|
||||
export default {
|
||||
Box,
|
||||
View
|
||||
};
|
||||
@@ -1,7 +0,0 @@
|
||||
import Box from './components/Box/styletron';
|
||||
import View from './components/View/styletron';
|
||||
|
||||
export default {
|
||||
Box,
|
||||
View
|
||||
};
|
||||
@@ -1,14 +0,0 @@
|
||||
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;
|
||||
@@ -1,113 +0,0 @@
|
||||
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, components) =>
|
||||
createRenderBenchmark({
|
||||
name: `Tweet [${label}]`,
|
||||
runs: 10,
|
||||
getElement() {
|
||||
return (
|
||||
<div style={{ width: 500 }}>
|
||||
<Tweet tweet={tweet1} />
|
||||
<Tweet tweet={tweet2} />
|
||||
</div>
|
||||
);
|
||||
}
|
||||
});
|
||||
|
||||
export default renderTweet;
|
||||
@@ -1,14 +0,0 @@
|
||||
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;
|
||||
@@ -1,55 +0,0 @@
|
||||
const BundleAnalyzerPlugin = require('webpack-bundle-analyzer').BundleAnalyzerPlugin;
|
||||
const path = require('path');
|
||||
const webpack = require('webpack');
|
||||
|
||||
module.exports = {
|
||||
context: __dirname,
|
||||
entry: './index',
|
||||
output: {
|
||||
path: path.resolve(__dirname, 'dist'),
|
||||
filename: 'performance.bundle.js'
|
||||
},
|
||||
module: {
|
||||
rules: [
|
||||
{
|
||||
test: /\.css$/,
|
||||
use: [
|
||||
'style-loader',
|
||||
{
|
||||
loader: 'css-loader',
|
||||
options: { module: true, localIdentName: '[hash:base64:8]' }
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
test: /\.js$/,
|
||||
exclude: /node_modules/,
|
||||
use: {
|
||||
loader: 'babel-loader',
|
||||
options: { cacheDirectory: true }
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
plugins: [
|
||||
new BundleAnalyzerPlugin({
|
||||
analyzerMode: 'static',
|
||||
openAnalyzer: false
|
||||
}),
|
||||
new webpack.DefinePlugin({
|
||||
'process.env.NODE_ENV': JSON.stringify('production')
|
||||
}),
|
||||
new webpack.optimize.UglifyJsPlugin({
|
||||
compress: {
|
||||
dead_code: true,
|
||||
screw_ie8: true,
|
||||
warnings: false
|
||||
}
|
||||
})
|
||||
],
|
||||
resolve: {
|
||||
alias: {
|
||||
'react-native': path.join(__dirname, '../src')
|
||||
}
|
||||
}
|
||||
};
|
||||
1303
benchmarks/yarn.lock
1303
benchmarks/yarn.lock
File diff suppressed because it is too large
Load Diff
@@ -1,60 +0,0 @@
|
||||
# AppRegistry
|
||||
|
||||
`AppRegistry` is the control point for registering, running, prerendering, and
|
||||
unmounting all apps. App root components should register themselves with
|
||||
`AppRegistry.registerComponent`. Apps can be run by invoking
|
||||
`AppRegistry.runApplication` (see the [getting started guide](../guides/getting-started.md) for more details).
|
||||
|
||||
To "stop" an application when a view should be destroyed, call
|
||||
`AppRegistry.unmountApplicationComponentAtRootTag` with the tag that was passed
|
||||
into `runApplication`. These should always be used as a pair.
|
||||
|
||||
## Methods
|
||||
|
||||
(web) static **getApplication**(appKey:string, appParameters: object)
|
||||
|
||||
Returns the given application element. Use this for server-side rendering.
|
||||
Return object is of type `{ element: ReactElement; stylesheets: [ ReactElement ] }`.
|
||||
|
||||
static **registerConfig**(config: Array<AppConfig>)
|
||||
|
||||
Registry multiple applications. `AppConfig` is of type `{ appKey: string;
|
||||
component: ComponentProvider; run?: Function }`.
|
||||
|
||||
static **registerComponent**(appKey: string, getComponentFunc: ComponentProvider)
|
||||
|
||||
Register a component provider under the given `appKey`.
|
||||
|
||||
static **registerRunnable**(appKey: string, run: Function)
|
||||
|
||||
Register a custom render function for an application. The function will receive
|
||||
the `appParameters` passed to `runApplication`.
|
||||
|
||||
static **getAppKeys**()
|
||||
|
||||
Returns all registered app keys.
|
||||
|
||||
static **runApplication**(appKey: string, appParameters?: object)
|
||||
|
||||
Runs the application that was registered under `appKey`. The `appParameters`
|
||||
must include the `rootTag` into which the application is rendered, and
|
||||
optionally any `initialProps`.
|
||||
|
||||
On web, if the `rootTag` is a sub-section of your application it should be
|
||||
styled as `position:relative` and given an explicit height.
|
||||
|
||||
static **unmountApplicationComponentAtRootTag**(rootTag: HTMLElement)
|
||||
|
||||
To "stop" an application when a view should be destroyed, call
|
||||
`AppRegistry.unmountApplicationComponentAtRootTag` with the tag that was passed
|
||||
into `runApplication`
|
||||
|
||||
## Example
|
||||
|
||||
```js
|
||||
AppRegistry.registerComponent('MyApp', () => AppComponent)
|
||||
AppRegistry.runApplication('MyApp', {
|
||||
initialProps: {},
|
||||
rootTag: document.getElementById('react-root')
|
||||
})
|
||||
```
|
||||
@@ -1,60 +0,0 @@
|
||||
## AppState
|
||||
|
||||
`AppState` can tell you if the app is in the foreground or background, and
|
||||
notify you when the state changes.
|
||||
|
||||
States
|
||||
|
||||
* `active` - The app is running in the foreground
|
||||
* `background` - The app is running in the background (i.e., the user has not focused the app's tab).
|
||||
|
||||
## Properties
|
||||
|
||||
static **currentState**
|
||||
|
||||
Returns the current state of the app: `active` or `background`.
|
||||
|
||||
## Methods
|
||||
|
||||
static **addEventListener**(type: string, handler: Function)
|
||||
|
||||
Add a handler to `AppState` changes by listening to the `change` event type and
|
||||
providing the `handler`. The handler is called with the app state value.
|
||||
|
||||
static **removeEventListener**(type: string, handler: Function)
|
||||
|
||||
Remove a handler by passing the change event `type` and the `handler`.
|
||||
|
||||
## Examples
|
||||
|
||||
To see the current state, you can check `AppState.currentState`, which will be
|
||||
kept up-to-date. This example will only ever appear to say "Current state is:
|
||||
active" because the app is only visible to the user when in the `active` state,
|
||||
and the null state will happen only momentarily.
|
||||
|
||||
```js
|
||||
class Example extends React.Component {
|
||||
constructor(props) {
|
||||
super(props)
|
||||
this.state = { currentAppState: AppState.currentState }
|
||||
}
|
||||
|
||||
componentDidMount() {
|
||||
AppState.addEventListener('change', this._handleAppStateChange);
|
||||
}
|
||||
|
||||
componentWillUnmount() {
|
||||
AppState.removeEventListener('change', this._handleAppStateChange);
|
||||
}
|
||||
|
||||
_handleAppStateChange = (currentAppState) => {
|
||||
this.setState({ currentAppState });
|
||||
}
|
||||
|
||||
render() {
|
||||
return (
|
||||
<Text>Current state is: {this.state.currentAppState}</Text>
|
||||
)
|
||||
}
|
||||
}
|
||||
```
|
||||
@@ -1,71 +0,0 @@
|
||||
# AsyncStorage
|
||||
|
||||
`AsyncStorage` is a simple, asynchronous, persistent, key-value storage system
|
||||
that is global to the domain. It's a facade over, and should be used instead of
|
||||
`window.localStorage` to provide an asynchronous API and multi functions. Each
|
||||
method returns a `Promise` object.
|
||||
|
||||
It is recommended that you use an abstraction on top of `AsyncStorage` instead
|
||||
of `AsyncStorage` directly for anything more than light usage since it operates
|
||||
globally.
|
||||
|
||||
The batched functions are useful for executing a lot of operations at once,
|
||||
allowing for optimizations to provide the convenience of a single promise after
|
||||
all operations are complete.
|
||||
|
||||
## Methods
|
||||
|
||||
static **clear**()
|
||||
|
||||
Erases all AsyncStorage. You probably don't want to call this - use
|
||||
`removeItem` or `multiRemove` to clear only your own keys instead. Returns a
|
||||
Promise object.
|
||||
|
||||
static **getAllKeys**()
|
||||
|
||||
Gets all known keys. Returns a Promise object.
|
||||
|
||||
static **getItem**(key: string)
|
||||
|
||||
Fetches the value of the given key. Returns a Promise object.
|
||||
|
||||
static **mergeItem**(key: string, value: string)
|
||||
|
||||
Merges existing value with input value, assuming they are stringified JSON.
|
||||
Returns a Promise object.
|
||||
|
||||
static **multiGet**(keys: Array<string>)
|
||||
|
||||
`multiGet` results in an array of key-value pair arrays that matches the input
|
||||
format of `multiSet`. Returns a Promise object.
|
||||
|
||||
```js
|
||||
multiGet(['k1', 'k2']) -> [['k1', 'val1'], ['k2', 'val2']]
|
||||
```
|
||||
|
||||
static **multiMerge**(keyValuePairs: Array<Array<string>>)
|
||||
|
||||
multiMerge takes an array of key-value array pairs that match the output of
|
||||
`multiGet`. It merges existing values with input values, assuming they are
|
||||
stringified JSON. Returns a Promise object.
|
||||
|
||||
static **multiRemove**(keys: Array<string>)
|
||||
|
||||
Delete all the keys in the keys array. Returns a Promise object.
|
||||
|
||||
static **multiSet**(keyValuePairs: Array<Array<string>>)
|
||||
|
||||
`multiSet` takes an array of key-value array pairs that match the output of
|
||||
`multiGet`. Returns a Promise object.
|
||||
|
||||
```js
|
||||
multiSet([['k1', 'val1'], ['k2', 'val2']]);
|
||||
```
|
||||
|
||||
static **removeItem**(key: string)
|
||||
|
||||
Removes the value of the given key. Returns a Promise object.
|
||||
|
||||
static **setItem**(key: string, value: string)
|
||||
|
||||
Sets the value of the given key. Returns a Promise object.
|
||||
@@ -1,16 +0,0 @@
|
||||
# Clipboard
|
||||
|
||||
Clipboard gives you an interface for setting to the clipboard. (Getting
|
||||
clipboard content is not supported on web.)
|
||||
|
||||
## Methods
|
||||
|
||||
static **getString**()
|
||||
|
||||
Returns a `Promise` of an empty string.
|
||||
|
||||
static **setString**(content: string): boolean
|
||||
|
||||
Copies a string to the clipboard. On web, some browsers may not support copying
|
||||
to the clipboard, therefore, this function returns a boolean to indicate if the
|
||||
copy was successful.
|
||||
@@ -1,13 +0,0 @@
|
||||
# Dimensions
|
||||
|
||||
Note: dimensions may change (e.g due to device rotation) so any rendering logic
|
||||
or styles that depend on these constants should try to call this function on
|
||||
every render, rather than caching the value.
|
||||
|
||||
## Methods
|
||||
|
||||
static **get**(dimension: string)
|
||||
|
||||
Get a dimension (e.g., `"window"` or `"screen"`).
|
||||
|
||||
Example: `const { height, width } = Dimensions.get('window')`
|
||||
@@ -1,25 +0,0 @@
|
||||
# I18nManager
|
||||
|
||||
Control and set the layout and writing direction of the application.
|
||||
|
||||
## Properties
|
||||
|
||||
**isRTL**: bool = false
|
||||
|
||||
Whether the application is currently in RTL mode.
|
||||
|
||||
## Methods
|
||||
|
||||
static **allowRTL**(allowRTL: bool)
|
||||
|
||||
Allow the application to display in RTL mode.
|
||||
|
||||
static **forceRTL**(forceRTL: bool)
|
||||
|
||||
Force the application to display in RTL mode.
|
||||
|
||||
static **setPreferredLanguageRTL**(isRTL: bool)
|
||||
|
||||
Set the application's preferred writing direction to RTL. You will need to
|
||||
determine the user's preferred locale server-side (from HTTP headers) and
|
||||
decide whether it's an RTL language.
|
||||
@@ -1,77 +0,0 @@
|
||||
# NetInfo
|
||||
|
||||
`NetInfo` asynchronously determines the online/offline status of the
|
||||
application.
|
||||
|
||||
Connection types:
|
||||
|
||||
* `bluetooth` - The user agent is using a Bluetooth connection.
|
||||
* `cellular` - The user agent is using a cellular connection (e.g., EDGE, HSPA, LTE, etc.).
|
||||
* `ethernet` - The user agent is using an Ethernet connection.
|
||||
* `mixed` - The user agent is using multiple connection types.
|
||||
* `none` - The user agent will not contact the network (offline).
|
||||
* `other` - The user agent is using a connection type that is not one of enumerated connection types.
|
||||
* `unknown` - The user agent has established a network connection, but is unable to determine what is the underlying connection technology.
|
||||
* `wifi` - The user agent is using a Wi-Fi connection.
|
||||
* `wimax` - The user agent is using a WiMAX connection.
|
||||
|
||||
## Methods
|
||||
|
||||
Note that support for retrieving the connection type depends upon browswer
|
||||
support (and is limited to mobile browsers). It will default to `unknown` when
|
||||
support is missing.
|
||||
|
||||
static **addEventListener**(eventName: ChangeEventName, handler: Function)
|
||||
|
||||
static **fetch**(): Promise
|
||||
|
||||
static **removeEventListener**(eventName: ChangeEventName, handler: Function)
|
||||
|
||||
## Properties
|
||||
|
||||
**isConnected**: bool = true
|
||||
|
||||
Available on all user agents. Asynchronously fetch a boolean to determine
|
||||
internet connectivity. Use this if you are only interested with whether the device has internet connectivity.
|
||||
|
||||
**isConnected.addEventListener**(eventName: ChangeEventName, handler: Function)
|
||||
|
||||
**isConnected.fetch**(): Promise
|
||||
|
||||
**isConnected.removeEventListener**(eventName: ChangeEventName, handler: Function)
|
||||
|
||||
## Examples
|
||||
|
||||
Fetching the connection type:
|
||||
|
||||
```js
|
||||
NetInfo.fetch().then((connectionType) => {
|
||||
console.log('Connection type:', connectionType);
|
||||
});
|
||||
```
|
||||
|
||||
Subscribing to changes in the connection type:
|
||||
|
||||
```js
|
||||
const handleConnectivityTypeChange = (connectionType) => {
|
||||
console.log('Current connection type:', connectionType);
|
||||
}
|
||||
NetInfo.addEventListener('change', handleConnectivityTypeChange);
|
||||
```
|
||||
|
||||
Fetching the connection status:
|
||||
|
||||
```js
|
||||
NetInfo.isConnected.fetch().then((isConnected) => {
|
||||
console.log('Connection status:', (isConnected ? 'online' : 'offline'));
|
||||
});
|
||||
```
|
||||
|
||||
Subscribing to changes in the connection status:
|
||||
|
||||
```js
|
||||
const handleConnectivityStatusChange = (isConnected) => {
|
||||
console.log('Current connection status:', (isConnected ? 'online' : 'offline'));
|
||||
}
|
||||
NetInfo.isConnected.addEventListener('change', handleConnectivityStatusChange);
|
||||
```
|
||||
@@ -1,51 +0,0 @@
|
||||
# PixelRatio
|
||||
|
||||
`PixelRatio` gives access to the device pixel density.
|
||||
|
||||
## Methods
|
||||
|
||||
static **get**()
|
||||
|
||||
Returns the device pixel density. Some examples:
|
||||
|
||||
* PixelRatio.get() === 1
|
||||
* mdpi Android devices (160 dpi)
|
||||
* PixelRatio.get() === 1.5
|
||||
* hdpi Android devices (240 dpi)
|
||||
* PixelRatio.get() === 2
|
||||
* iPhone 4, 4S
|
||||
* iPhone 5, 5c, 5s
|
||||
* iPhone 6
|
||||
* xhdpi Android devices (320 dpi)
|
||||
* PixelRatio.get() === 3
|
||||
* iPhone 6 plus
|
||||
* xxhdpi Android devices (480 dpi)
|
||||
* PixelRatio.get() === 3.5
|
||||
* Nexus 6
|
||||
|
||||
static **getPixelSizeForLayoutSize**(layoutSize: number)
|
||||
|
||||
Converts a layout size (dp) to pixel size (px). Guaranteed to return an integer
|
||||
number.
|
||||
|
||||
static **roundToNearestPixel**(layoutSize: number)
|
||||
|
||||
Rounds a layout size (dp) to the nearest layout size that corresponds to an
|
||||
integer number of pixels. For example, on a device with a PixelRatio of 3,
|
||||
`PixelRatio.roundToNearestPixel(8.4)` = `8.33`, which corresponds to exactly
|
||||
`(8.33 * 3)` = `25` pixels.
|
||||
|
||||
## Examples
|
||||
|
||||
Fetching a correctly sized image. You should get a higher resolution image if
|
||||
you are on a high pixel density device. A good rule of thumb is to multiply the
|
||||
size of the image you display by the pixel ratio.
|
||||
|
||||
```js
|
||||
const image = getImage({
|
||||
width: PixelRatio.getPixelSizeForLayoutSize(200),
|
||||
height: PixelRatio.getPixelSizeForLayoutSize(100),
|
||||
});
|
||||
|
||||
<Image source={image} style={{ width: 200, height: 100 }} />
|
||||
```
|
||||
@@ -1,45 +0,0 @@
|
||||
# Platform
|
||||
|
||||
Detect what is the platform in which the app is running. This piece of
|
||||
functionality can be useful when only small parts of a component are platform
|
||||
specific.
|
||||
|
||||
## Properties
|
||||
|
||||
**OS**: string
|
||||
|
||||
`Platform.OS` will be `web` when running in a Web browser.
|
||||
|
||||
```js
|
||||
import { Platform } from 'react-native';
|
||||
|
||||
const styles = StyleSheet.create({
|
||||
height: (Platform.OS === 'web') ? 200 : 100,
|
||||
});
|
||||
```
|
||||
|
||||
## Methods
|
||||
|
||||
**select**(object): any
|
||||
|
||||
`Platform.select` takes an object containing `Platform.OS` as keys and returns
|
||||
the value for the platform you are currently running on.
|
||||
|
||||
```js
|
||||
import { Platform } from 'react-native';
|
||||
|
||||
const containerStyles = {
|
||||
flex: 1,
|
||||
...Platform.select({
|
||||
android: {
|
||||
backgroundColor: 'blue'
|
||||
},
|
||||
ios: {
|
||||
backgroundColor: 'red'
|
||||
},
|
||||
web: {
|
||||
backgroundColor: 'green'
|
||||
}
|
||||
})
|
||||
});
|
||||
```
|
||||
@@ -1,80 +0,0 @@
|
||||
# StyleSheet
|
||||
|
||||
The `StyleSheet` abstraction converts predefined styles to (vendor-prefixed)
|
||||
CSS without requiring a compile-time step. Styles that cannot be resolved
|
||||
outside of the render loop (e.g., dynamic positioning) are usually applied as
|
||||
inline styles. Read more about [how to style your
|
||||
application](../guides/style.md).
|
||||
|
||||
## Methods
|
||||
|
||||
**create**(obj: {[key: string]: any})
|
||||
|
||||
Each key of the object passed to `create` must define a style object.
|
||||
|
||||
**flatten**: function
|
||||
|
||||
Flattens an array of styles into a single style object.
|
||||
|
||||
(web) **getStyleSheets**: function
|
||||
|
||||
Returns an array of stylesheets (`{ id, textContent }`). Useful for
|
||||
compile-time or server-side rendering.
|
||||
|
||||
## Properties
|
||||
|
||||
**absoluteFill**: number
|
||||
|
||||
A very common pattern is to create overlays with position absolute and zero positioning,
|
||||
so `absoluteFill` can be used for convenience and to reduce duplication of these repeated
|
||||
styles.
|
||||
|
||||
```js
|
||||
<View style={StyleSheet.absoluteFill} />
|
||||
```
|
||||
|
||||
**absoluteFillObject**: object
|
||||
|
||||
Sometimes you may want `absoluteFill` but with a couple tweaks - `absoluteFillObject` can be
|
||||
used to create a customized entry in a `StyleSheet`, e.g.:
|
||||
|
||||
```js
|
||||
const styles = StyleSheet.create({
|
||||
wrapper: {
|
||||
...StyleSheet.absoluteFillObject,
|
||||
backgroundColor: 'transparent',
|
||||
top: 10
|
||||
}
|
||||
})
|
||||
```
|
||||
|
||||
**hairlineWidth**: number
|
||||
|
||||
## Example
|
||||
|
||||
```js
|
||||
<View style={styles.container}>
|
||||
<Text
|
||||
children={'Title text'}
|
||||
style={[
|
||||
styles.title,
|
||||
this.props.isActive && styles.activeTitle
|
||||
]}
|
||||
/>
|
||||
</View>
|
||||
|
||||
const styles = StyleSheet.create({
|
||||
container: {
|
||||
borderRadius: 4,
|
||||
borderWidth: 0.5,
|
||||
borderColor: '#d6d7da',
|
||||
},
|
||||
title: {
|
||||
fontSize: 19,
|
||||
fontWeight: 'bold',
|
||||
},
|
||||
activeTitle: {
|
||||
color: 'red',
|
||||
}
|
||||
})
|
||||
```
|
||||
@@ -1,35 +0,0 @@
|
||||
# Vibration
|
||||
|
||||
Vibration is described as a pattern of on-off pulses, which may be of varying
|
||||
lengths. The pattern may consist of either a single integer, describing the
|
||||
number of milliseconds to vibrate, or an array of integers describing a pattern
|
||||
of vibrations and pauses. Vibration is controlled with a single method:
|
||||
`Vibration.vibrate()`.
|
||||
|
||||
The vibration is asynchronous so this method will return immediately. There
|
||||
will be no effect on devices that do not support vibration.
|
||||
|
||||
## Methods
|
||||
|
||||
static **cancel**()
|
||||
|
||||
Stop the vibration.
|
||||
|
||||
static **vibrate**(pattern)
|
||||
|
||||
Start the vibration pattern.
|
||||
|
||||
## Examples
|
||||
|
||||
Vibrate once for 200ms:
|
||||
|
||||
```js
|
||||
Vibration.vibrate(200);
|
||||
Vibration.vibrate([200]);
|
||||
```
|
||||
|
||||
Vibrate for 200ms, pause for 100ms, vibrate for 200ms:
|
||||
|
||||
```js
|
||||
Vibration.vibrate([200, 100, 200]);
|
||||
```
|
||||
@@ -1,70 +0,0 @@
|
||||
# ActivityIndicator
|
||||
|
||||
## Props
|
||||
|
||||
[...View props](./View.md)
|
||||
|
||||
**animating**: boolean = true
|
||||
|
||||
Whether to show the indicator or hide it.
|
||||
|
||||
**color**: ?color = '#1976D2'
|
||||
|
||||
The foreground color of the spinner.
|
||||
|
||||
**hidesWhenStopped**: ?boolean = true
|
||||
|
||||
Whether the indicator should hide when not animating.
|
||||
|
||||
**size**: ?enum('small, 'large') | number = 'small'
|
||||
|
||||
Size of the indicator. Small has a height of `20`, large has a height of `36`.
|
||||
|
||||
## Examples
|
||||
|
||||
```js
|
||||
import React, { Component } from 'react'
|
||||
import { ActivityIndicator, StyleSheet, View } from 'react-native'
|
||||
|
||||
class ToggleAnimatingActivityIndicator extends Component {
|
||||
constructor(props) {
|
||||
super(props)
|
||||
this.state = { animating: true }
|
||||
}
|
||||
|
||||
componentDidMount: function() {
|
||||
this.setToggleTimeout();
|
||||
}
|
||||
|
||||
render() {
|
||||
return (
|
||||
<ActivityIndicator
|
||||
animating={this.state.animating}
|
||||
size="large"
|
||||
style={[styles.centering, { height: 80 }]}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
_setToggleTimeout() {
|
||||
setTimeout(() => {
|
||||
this.setState({ animating: !this.state.animating })
|
||||
this._setToggleTimeout()
|
||||
}, 1200)
|
||||
}
|
||||
})
|
||||
|
||||
const styles = StyleSheet.create({
|
||||
centering: {
|
||||
alignItems: 'center',
|
||||
justifyContent: 'center'
|
||||
},
|
||||
gray: {
|
||||
backgroundColor: '#cccccc'
|
||||
},
|
||||
horizontal: {
|
||||
flexDirection: 'row',
|
||||
justifyContent: 'space-around'
|
||||
}
|
||||
})
|
||||
```
|
||||
@@ -1,43 +0,0 @@
|
||||
# Button
|
||||
|
||||
A basic button component. Supports a minimal level of customization. You can
|
||||
build your own custom button using `TouchableOpacity` or
|
||||
`TouchableNativeFeedback`.
|
||||
|
||||
## Props
|
||||
|
||||
**accessibilityLabel**: ?string
|
||||
|
||||
Overrides the text that's read by a screen reader when the user interacts
|
||||
with the element.
|
||||
|
||||
**color**: ?string
|
||||
|
||||
Background color of the button.
|
||||
|
||||
**disabled**: ?boolean
|
||||
|
||||
If `true`, disable all interactions for this element.
|
||||
|
||||
**onPress**: function
|
||||
|
||||
This function is called on press.
|
||||
|
||||
**testID**: ?string
|
||||
|
||||
Used to locate this view in end-to-end tests.
|
||||
|
||||
**title**: string
|
||||
|
||||
Text to display inside the button.
|
||||
|
||||
## Examples
|
||||
|
||||
```js
|
||||
<Button
|
||||
accessibilityLabel="Learn more about this purple button"
|
||||
color="#841584"
|
||||
onPress={onPressLearnMore}
|
||||
title="Learn More"
|
||||
/>
|
||||
```
|
||||
@@ -1,167 +0,0 @@
|
||||
# Image
|
||||
|
||||
An accessibile image component with support for image resizing, default image,
|
||||
and child content.
|
||||
|
||||
Unsupported React Native props:
|
||||
`capInsets` (ios),
|
||||
`onProgress` (ios)
|
||||
|
||||
## Props
|
||||
|
||||
**accessibilityLabel**: ?string
|
||||
|
||||
The text that's read by a screenreader when someone interacts with the image.
|
||||
|
||||
**accessible**: ?boolean
|
||||
|
||||
When `true`, indicates the image is an accessibility element.
|
||||
|
||||
**children**: ?any
|
||||
|
||||
Content to display over the image.
|
||||
|
||||
**defaultSource**: ?object
|
||||
|
||||
An image to display as a placeholder while downloading the final image off the
|
||||
network. `{ uri: string, width, height }`
|
||||
|
||||
**onError**: ?function
|
||||
|
||||
Invoked on load error with `{nativeEvent: {error}}`.
|
||||
|
||||
**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.
|
||||
|
||||
**onLoad**: ?function
|
||||
|
||||
Invoked when load completes successfully.
|
||||
|
||||
**onLoadEnd**: ?function
|
||||
|
||||
Invoked when load either succeeds or fails,
|
||||
|
||||
**onLoadStart**: ?function
|
||||
|
||||
Invoked on load start.
|
||||
|
||||
**resizeMode**: ?enum('center', 'contain', 'cover', 'none', 'repeat', 'stretch') = 'cover'
|
||||
|
||||
Determines how to resize the image when the frame doesn't match the raw image
|
||||
dimensions.
|
||||
|
||||
**source**: ?object
|
||||
|
||||
`uri` is a string representing the resource identifier for the image, which
|
||||
could be an http address or a base64 encoded image. `{ uri: string, width, height }`
|
||||
|
||||
**style**: ?style
|
||||
|
||||
+ ...[View#style](./View.md)
|
||||
+ `resizeMode`
|
||||
|
||||
**testID**: ?string
|
||||
|
||||
Used to locate a view in end-to-end tests.
|
||||
|
||||
## Properties
|
||||
|
||||
static **resizeMode**: object
|
||||
|
||||
Example usage:
|
||||
|
||||
```
|
||||
<Image resizeMode={Image.resizeMode.contain} />
|
||||
```
|
||||
|
||||
## Methods
|
||||
|
||||
static **getSize**(uri: string, success: (width, height) => {}, failure: function)
|
||||
|
||||
Retrieve the width and height (in pixels) of an image prior to displaying it.
|
||||
This method can fail if the image cannot be found, or fails to download.
|
||||
|
||||
(In order to retrieve the image dimensions, the image may first need to be
|
||||
loaded or downloaded, after which it will be cached. This means that in
|
||||
principle you could use this method to preload images, however it is not
|
||||
optimized for that purpose, and may in future be implemented in a way that does
|
||||
not fully load/download the image data.)
|
||||
|
||||
static **prefetch**(url: string): Promise
|
||||
|
||||
Prefetches a remote image for later use by downloading it.
|
||||
|
||||
## Examples
|
||||
|
||||
```js
|
||||
import placeholderAvatar from './placeholderAvatar.png'
|
||||
import React, { Component } from 'react'
|
||||
import { Image, PropTypes, StyleSheet } from 'react-native'
|
||||
|
||||
export default class ImageExample extends Component {
|
||||
constructor(props, context) {
|
||||
super(props, context)
|
||||
this.state = { loading: true }
|
||||
}
|
||||
|
||||
static propTypes = {
|
||||
size: PropTypes.oneOf(['small', 'normal', 'large']),
|
||||
testID: Image.propTypes.testID,
|
||||
user: PropTypes.object
|
||||
}
|
||||
|
||||
static defaultProps = {
|
||||
size: 'normal'
|
||||
}
|
||||
|
||||
_onLoad(e) {
|
||||
console.log('Avatar.onLoad', e)
|
||||
this.setState({ loading: false })
|
||||
}
|
||||
|
||||
render() {
|
||||
const { size, testID, user } = this.props
|
||||
const loadingStyle = this.state.loading ? { styles.loading } : { }
|
||||
|
||||
return (
|
||||
<Image
|
||||
accessibilityLabel={`${user.name}'s profile picture`}
|
||||
defaultSource={{ uri: placeholderAvatar }}
|
||||
onLoad={this._onLoad.bind(this)}
|
||||
resizeMode='cover'
|
||||
source={{ uri: user.avatarUrl }}
|
||||
style={[
|
||||
styles.base,
|
||||
styles[size],
|
||||
loadingStyle
|
||||
]}
|
||||
/>
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
const styles = StyleSheet.create({
|
||||
base: {
|
||||
borderColor: 'white',
|
||||
borderRadius: 5,
|
||||
borderWidth: 5
|
||||
},
|
||||
loading: {
|
||||
opacity: 0.5
|
||||
},
|
||||
small: {
|
||||
height: 32,
|
||||
width: 32
|
||||
},
|
||||
normal: {
|
||||
height: 48,
|
||||
width: 48
|
||||
},
|
||||
large: {
|
||||
height: 64,
|
||||
width: 64
|
||||
}
|
||||
})
|
||||
```
|
||||
@@ -1,27 +0,0 @@
|
||||
# ProgressBar
|
||||
|
||||
Display an activity progress bar.
|
||||
|
||||
## Props
|
||||
|
||||
[...View props](./View.md)
|
||||
|
||||
**color**: ?string = '#1976D2'
|
||||
|
||||
Color of the progress bar.
|
||||
|
||||
**indeterminate**: ?boolean = true
|
||||
|
||||
Whether the progress bar will show indeterminate progress.
|
||||
|
||||
**progress**: ?number
|
||||
|
||||
The progress value (between 0 and 1).
|
||||
|
||||
**testID**: ?string
|
||||
|
||||
Used to locate this view in end-to-end tests.
|
||||
|
||||
(web) **trackColor**: ?string = 'transparent'
|
||||
|
||||
Color of the track bar.
|
||||
@@ -1,134 +0,0 @@
|
||||
# ScrollView
|
||||
|
||||
A scrollable `View` that provides itegration with the touch-locking "responder"
|
||||
system. `ScrollView`'s must have a bounded height: either set the height of the
|
||||
view directly (discouraged) or make sure all parent views have bounded height
|
||||
(e.g., transfer `{ flex: 1}` down the view stack).
|
||||
|
||||
## Props
|
||||
|
||||
[...View props](./View.md)
|
||||
|
||||
**contentContainerStyle**: ?style
|
||||
|
||||
These styles will be applied to the scroll view content container which wraps
|
||||
all of the child views.
|
||||
|
||||
**horizontal**: ?boolean = false
|
||||
|
||||
When `true`, the scroll view's children are arranged horizontally in a row
|
||||
instead of vertically in a column.
|
||||
|
||||
**keyboardDismissMode**: ?enum('none', 'on-drag') = 'none'
|
||||
|
||||
Determines whether the keyboard gets dismissed in response to a scroll drag.
|
||||
|
||||
* `none` (the default), drags do not dismiss the keyboard.
|
||||
* `on-drag`, the keyboard is dismissed when a drag begins.
|
||||
* `interactive` (not supported on web; same as `none`)
|
||||
|
||||
**onContentSizeChange**: ?function
|
||||
|
||||
Called when scrollable content view of the `ScrollView` changes. It's
|
||||
implemented using the `onLayout` handler attached to the content container
|
||||
which this `ScrollView` renders.
|
||||
|
||||
**onScroll**: ?function
|
||||
|
||||
Fires at most once per frame during scrolling. The frequency of the events can
|
||||
be contolled using the `scrollEventThrottle` prop.
|
||||
|
||||
Invoked on scroll with the following event:
|
||||
|
||||
```js
|
||||
{
|
||||
nativeEvent: {
|
||||
contentOffset: { x, y },
|
||||
contentSize: { height, width },
|
||||
layoutMeasurement: { height, width }
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
**refreshControl**: ?element
|
||||
|
||||
TODO
|
||||
|
||||
A [RefreshControl](../RefreshControl) component, used to provide
|
||||
pull-to-refresh functionality for the `ScrollView`.
|
||||
|
||||
**scrollEnabled**: ?boolean = true
|
||||
|
||||
When false, the content does not scroll.
|
||||
|
||||
**scrollEventThrottle**: ?number = 0
|
||||
|
||||
This controls how often the scroll event will be fired while scrolling (as a
|
||||
time interval in ms). A lower number yields better accuracy for code that is
|
||||
tracking the scroll position, but can lead to scroll performance problems. The
|
||||
default value is `0`, which means the scroll event will be sent only once each
|
||||
time the view is scrolled.
|
||||
|
||||
## Instance methods
|
||||
|
||||
**getInnerViewNode()**: any
|
||||
|
||||
Returns a reference to the underlying content container DOM node within the `ScrollView`.
|
||||
|
||||
**getScrollableNode()**: any
|
||||
|
||||
Returns a reference to the underlying scrollable DOM node.
|
||||
|
||||
**getScrollResponder()**: Component
|
||||
|
||||
Returns a reference to the underlying scroll responder, which supports
|
||||
operations like `scrollTo`. All `ScrollView`-like components should implement
|
||||
this method so that they can be composed while providing access to the
|
||||
underlying scroll responder's methods.
|
||||
|
||||
**scrollTo(options: { x: number = 0; y: number = 0; animated: boolean = true })**
|
||||
|
||||
Scrolls to a given `x`, `y` offset (animation is not currently supported).
|
||||
|
||||
## Examples
|
||||
|
||||
```js
|
||||
import React, { Component } from 'react'
|
||||
import { ScrollView, StyleSheet } from 'react-native'
|
||||
import Item from './Item'
|
||||
|
||||
export default class ScrollViewExample extends Component {
|
||||
constructor(props, context) {
|
||||
super(props, context)
|
||||
this.state = {
|
||||
items: Array.from(new Array(20)).map((_, i) => ({ id: i }))
|
||||
}
|
||||
}
|
||||
|
||||
onScroll(e) {
|
||||
console.log(e)
|
||||
}
|
||||
|
||||
render() {
|
||||
return (
|
||||
<ScrollView
|
||||
children={this.state.items.map((item) => <Item {...item} />)}
|
||||
contentContainerStyle={styles.container}
|
||||
horizontal
|
||||
onScroll={(e) => this.onScroll(e)}
|
||||
scrollEventThrottle={100}
|
||||
style={styles.root}
|
||||
/>
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
const styles = StyleSheet.create({
|
||||
root: {
|
||||
borderWidth: 1
|
||||
},
|
||||
container: {
|
||||
padding: 10
|
||||
}
|
||||
})
|
||||
```
|
||||
@@ -1,76 +0,0 @@
|
||||
# Switch
|
||||
|
||||
This is a controlled component that requires an `onValueChange` callback that
|
||||
updates the value prop in order for the component to reflect user actions. If
|
||||
the `value` prop is not updated, the component will continue to render the
|
||||
supplied `value` prop instead of the expected result of any user actions.
|
||||
|
||||
## Props
|
||||
|
||||
[...View props](./View.md)
|
||||
|
||||
**disabled**: ?boolean = false
|
||||
|
||||
If `true` the user won't be able to interact with the switch.
|
||||
|
||||
**onValueChange**: ?function
|
||||
|
||||
Invoked with the new value when the value changes.
|
||||
|
||||
**value**: ?boolean = false
|
||||
|
||||
The value of the switch. If `true` the switch will be turned on.
|
||||
|
||||
(web) **activeThumbColor**: ?color = #009688
|
||||
|
||||
The color of the thumb grip when the switch is turned on.
|
||||
|
||||
(web) **activeTrackColor**: ?color = #A3D3CF
|
||||
|
||||
The color of the track when the switch is turned on.
|
||||
|
||||
(web) **thumbColor**: ?color = #FAFAFA
|
||||
|
||||
The color of the thumb grip when the switch is turned off.
|
||||
|
||||
(web) **trackColor**: ?color = #939393
|
||||
|
||||
The color of the track when the switch is turned off.
|
||||
|
||||
## Examples
|
||||
|
||||
```js
|
||||
import React, { Component } from 'react'
|
||||
import { Switch, View } from 'react-native'
|
||||
|
||||
class ColorSwitchExample extends Component {
|
||||
constructor(props) {
|
||||
super(props)
|
||||
this.state = {
|
||||
colorTrueSwitchIsOn: true,
|
||||
colorFalseSwitchIsOn: false
|
||||
}
|
||||
}
|
||||
|
||||
render() {
|
||||
return (
|
||||
<View>
|
||||
<Switch
|
||||
activeThumbColor='#428BCA'
|
||||
activeTrackColor='#A0C4E3'
|
||||
onValueChange={(value) => this.setState({ colorFalseSwitchIsOn: value })}
|
||||
value={this.state.colorFalseSwitchIsOn}
|
||||
/>
|
||||
<Switch
|
||||
activeThumbColor='#5CB85C'
|
||||
activeTrackColor='#ADDAAD'
|
||||
onValueChange={(value) => this.setState({ colorTrueSwitchIsOn: value })}
|
||||
thumbColor='#EBA9A7'
|
||||
trackColor='#D9534F'
|
||||
value={this.state.colorTrueSwitchIsOn}
|
||||
/>
|
||||
</View>
|
||||
)
|
||||
}
|
||||
}
|
||||
```
|
||||
@@ -1,161 +0,0 @@
|
||||
# Text
|
||||
|
||||
`Text` is component for displaying text. It supports style, basic touch
|
||||
handling, and inherits typographic styles from ancestor elements.
|
||||
|
||||
The `Text` is unique relative to layout: child elements use text layout
|
||||
(`inline`) rather than flexbox layout. This means that elements inside of a
|
||||
`Text` are not rectangles, as they wrap when reaching the edge of their
|
||||
container.
|
||||
|
||||
Unsupported React Native props:
|
||||
`allowFontScaling` (ios),
|
||||
`suppressHighlighting` (ios)
|
||||
|
||||
## Props
|
||||
|
||||
NOTE: `Text` will transfer all other props to the rendered HTML element.
|
||||
|
||||
(web) **accessibilityLabel**: ?string
|
||||
|
||||
Overrides the text that's read by a screen reader when the user interacts
|
||||
with the element. (This is implemented using `aria-label`.)
|
||||
|
||||
See the [Accessibility guide](../guides/accessibility) for more information.
|
||||
|
||||
(web) **accessibilityRole**: ?oneOf(roles)
|
||||
|
||||
Allows assistive technologies to present and support interaction with the view
|
||||
in a manner that is consistent with user expectations for similar views of that
|
||||
type. For example, marking a touchable view with an `accessibilityRole` of
|
||||
`button`. (This is implemented using [ARIA roles](http://www.w3.org/TR/wai-aria/roles#role_definitions)).
|
||||
|
||||
See the [Accessibility guide](../guides/accessibility) for more information.
|
||||
|
||||
**accessible**: ?boolean
|
||||
|
||||
When `true`, indicates that the view is an accessibility element (i.e.,
|
||||
focusable) and groups its child content. By default, all the touchable elements
|
||||
and elements with `accessibilityRole` of `button` and `link` are accessible.
|
||||
(This is implemented using `tabindex`.)
|
||||
|
||||
See the [Accessibility guide](../guides/accessibility) for more information.
|
||||
|
||||
**children**: ?any
|
||||
|
||||
Child content.
|
||||
|
||||
**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`.
|
||||
|
||||
**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.
|
||||
|
||||
**onPress**: ?function
|
||||
|
||||
This function is called on press.
|
||||
|
||||
**selectable**: ?boolean
|
||||
|
||||
When `false`, the text is not selectable.
|
||||
|
||||
**style**: ?style
|
||||
|
||||
+ ...[View#style](View.md)
|
||||
+ `color`
|
||||
+ `fontFamily`
|
||||
+ `fontFeatureSettings` ‡
|
||||
+ `fontSize`
|
||||
+ `fontStyle`
|
||||
+ `fontWeight`
|
||||
+ `letterSpacing`
|
||||
+ `lineHeight`
|
||||
+ `textAlign`
|
||||
+ `textAlignVertical`
|
||||
+ `textDecorationLine`
|
||||
+ `textIndent` ‡
|
||||
+ `textOverflow` ‡
|
||||
+ `textRendering` ‡
|
||||
+ `textShadowColor`
|
||||
+ `textShadowOffset`
|
||||
+ `textShadowRadius`
|
||||
+ `textTransform` ‡
|
||||
+ `unicodeBidi` ‡
|
||||
+ `whiteSpace`
|
||||
+ `wordWrap` ‡
|
||||
+ `writingDirection`
|
||||
|
||||
‡ web only.
|
||||
|
||||
**testID**: ?string
|
||||
|
||||
Used to locate this view in end-to-end tests.
|
||||
|
||||
## Examples
|
||||
|
||||
```js
|
||||
import React, { Component, PropTypes } from 'react'
|
||||
import { StyleSheet, Text } from 'react-native'
|
||||
|
||||
export default class PrettyText extends Component {
|
||||
static propTypes = {
|
||||
...Text.propTypes,
|
||||
color: PropTypes.oneOf(['white', 'gray', 'red']),
|
||||
size: PropTypes.oneOf(['small', 'normal', 'large']),
|
||||
weight: PropTypes.oneOf(['light', 'normal', 'bold'])
|
||||
};
|
||||
|
||||
static defaultProps = {
|
||||
...Text.defaultProps,
|
||||
color: 'gray',
|
||||
size: 'normal',
|
||||
weight: 'normal'
|
||||
};
|
||||
|
||||
render() {
|
||||
const { color, size, style, weight, ...other } = this.props;
|
||||
|
||||
return (
|
||||
<Text
|
||||
...other
|
||||
style={[
|
||||
style,
|
||||
colorStyles[color],
|
||||
sizeStyles[size],
|
||||
weightStyles[weight]
|
||||
]}
|
||||
/>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
const colorStyles = StyleSheet.create({
|
||||
white: { color: 'white' },
|
||||
gray: { color: 'gray' },
|
||||
red: { color: 'red' }
|
||||
})
|
||||
|
||||
const sizeStyles = StyleSheet.create({
|
||||
small: { fontSize: '0.85rem', padding: '0.5rem' },
|
||||
normal: { fontSize: '1rem', padding: '0.75rem' },
|
||||
large: { fontSize: '1.5rem', padding: '1rem' }
|
||||
})
|
||||
|
||||
const weightStyles = StyleSheet.create({
|
||||
light: { fontWeight: '300' },
|
||||
normal: { fontWeight: '400' },
|
||||
bold: { fontWeight: '700' }
|
||||
})
|
||||
```
|
||||
@@ -1,226 +0,0 @@
|
||||
# TextInput
|
||||
|
||||
Accessible single- and multi-line text input via a keyboard. Supports features
|
||||
such as auto-complete, auto-focus, placeholder text, and event callbacks.
|
||||
|
||||
Note: some props are exclusive to or excluded from `multiline`.
|
||||
|
||||
Unsupported React Native props:
|
||||
`onEndEditing`,
|
||||
`clearButtonMode` (ios),
|
||||
`enablesReturnKeyAutomatically` (ios),
|
||||
`placeholderTextColor`,
|
||||
`returnKeyType` (ios),
|
||||
`selectionState` (ios),
|
||||
`underlineColorAndroid` (android)
|
||||
|
||||
## Props
|
||||
|
||||
[...View props](./View.md)
|
||||
|
||||
**autoCapitalize**: ?enum('characters', 'none', 'sentences', 'words') = 'sentences'
|
||||
|
||||
Automatically capitalize certain characters (only available in Chrome and iOS Safari).
|
||||
|
||||
* `characters`: Automatically capitalize all characters.
|
||||
* `none`: Completely disables automatic capitalization
|
||||
* `sentences`: Automatically capitalize the first letter of sentences.
|
||||
* `words`: Automatically capitalize the first letter of words.
|
||||
|
||||
(web) **autoComplete**: ?string
|
||||
|
||||
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).
|
||||
|
||||
**autoCorrect**: ?boolean = true
|
||||
|
||||
Automatically correct spelling mistakes (only available in iOS Safari).
|
||||
|
||||
**autoFocus**: ?boolean = false
|
||||
|
||||
If `true`, focuses the input on `componentDidMount`. Only the first form element
|
||||
in a document with `autofocus` is focused.
|
||||
|
||||
**blurOnSubmit**: ?boolean
|
||||
|
||||
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
|
||||
fields setting `blurOnSubmit` to `true` means that pressing return will blur
|
||||
the field and trigger the `onSubmitEditing` event instead of inserting a
|
||||
newline into the field.
|
||||
|
||||
**clearTextOnFocus**: ?boolean = false
|
||||
|
||||
If `true`, clears the text field automatically when focused.
|
||||
|
||||
**defaultValue**: ?string
|
||||
|
||||
Provides an initial value that will change when the user starts typing. Useful
|
||||
for simple use-cases where you don't want to deal with listening to events and
|
||||
updating the `value` prop to keep the controlled state in sync.
|
||||
|
||||
**editable**: ?boolean = true
|
||||
|
||||
If `false`, text is not editable (i.e., read-only).
|
||||
|
||||
**keyboardType**: enum('default', 'email-address', 'numeric', 'phone-pad', 'search', 'url', 'web-search') = 'default'
|
||||
|
||||
Determines which keyboard to open. (NOTE: Safari iOS requires an ancestral
|
||||
`<form action>` element to display the `search` keyboard).
|
||||
|
||||
(Not available when `multiline` is `true`.)
|
||||
|
||||
**maxLength**: ?number
|
||||
|
||||
Limits the maximum number of characters that can be entered.
|
||||
|
||||
**multiline**: ?boolean = false
|
||||
|
||||
If true, the text input can be multiple lines.
|
||||
|
||||
**numberOfLines**: ?number = 2
|
||||
|
||||
Sets the number of lines for a multiline `TextInput`.
|
||||
|
||||
(Requires `multiline` to be `true`.)
|
||||
|
||||
**onBlur**: ?function
|
||||
|
||||
Callback that is called when the text input is blurred.
|
||||
|
||||
**onChange**: ?function
|
||||
|
||||
Callback that is called when the text input's text changes.
|
||||
|
||||
**onChangeText**: ?function
|
||||
|
||||
Callback that is called when the text input's text changes. The text is passed
|
||||
as an argument to the callback handler.
|
||||
|
||||
**onFocus**: ?function
|
||||
|
||||
Callback that is called when the text input is focused.
|
||||
|
||||
**onKeyPress**: ?function
|
||||
|
||||
Callback that is called when a key is pressed. This will be called with `{
|
||||
nativeEvent: { key: keyValue } }` where keyValue is 'Enter` or 'Backspace' for
|
||||
respective keys and the typed-in character otherwise including ' ' for space.
|
||||
Modifier keys are also included in the nativeEvent. Fires before onChange
|
||||
callbacks.
|
||||
|
||||
**onSelectionChange**: ?function
|
||||
|
||||
Callback that is called when the text input's selection changes. This will be called with
|
||||
`{ nativeEvent: { selection: { start, end } } }`.
|
||||
|
||||
**onSubmitEditing**: ?function
|
||||
|
||||
Callback that is called when the keyboard's submit button is pressed.
|
||||
|
||||
**placeholder**: ?string
|
||||
|
||||
The string that will be rendered in an empty `TextInput` before text has been
|
||||
entered.
|
||||
|
||||
**secureTextEntry**: ?boolean = false
|
||||
|
||||
If true, the text input obscures the text entered so that sensitive text like
|
||||
passwords stay secure.
|
||||
|
||||
(Not available when `multiline` is `true`.)
|
||||
|
||||
**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.
|
||||
|
||||
**selectTextOnFocus**: ?boolean = false
|
||||
|
||||
If `true`, all text will automatically be selected on focus.
|
||||
|
||||
**style**: ?style
|
||||
|
||||
+ ...[Text#style](./Text.md)
|
||||
+ `resize` ‡
|
||||
|
||||
‡ web only.
|
||||
|
||||
**testID**: ?string
|
||||
|
||||
Used to locate this view in end-to-end tests.
|
||||
|
||||
**value**: ?string
|
||||
|
||||
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.
|
||||
Read about how [React form
|
||||
components](https://facebook.github.io/react/docs/forms.html) work. To prevent
|
||||
user edits to the value set `editable={false}`.
|
||||
|
||||
## Instance methods
|
||||
|
||||
**blur()**
|
||||
|
||||
Blur the underlying DOM input.
|
||||
|
||||
**clear()**
|
||||
|
||||
Clear the text from the underlying DOM input.
|
||||
|
||||
**focus()**
|
||||
|
||||
Focus the underlying DOM input.
|
||||
|
||||
**isFocused()**
|
||||
|
||||
Returns `true` if the input is currently focused; `false` otherwise.
|
||||
|
||||
## Examples
|
||||
|
||||
```js
|
||||
import React, { Component } from 'react'
|
||||
import { StyleSheet, TextInput } from 'react-native'
|
||||
|
||||
export default class TextInputExample extends Component {
|
||||
constructor(props, context) {
|
||||
super(props, context)
|
||||
this.state = { isFocused: false }
|
||||
}
|
||||
|
||||
_onBlur(e) {
|
||||
this.setState({ isFocused: false })
|
||||
}
|
||||
|
||||
_onFocus(e) {
|
||||
this.setState({ isFocused: true })
|
||||
}
|
||||
|
||||
render() {
|
||||
return (
|
||||
<TextInput
|
||||
accessibilityLabel='Write a status update'
|
||||
maxNumberOfLines={5}
|
||||
multiline
|
||||
numberOfLines={2}
|
||||
onBlur={this._onBlur.bind(this)}
|
||||
onFocus={this._onFocus.bind(this)}
|
||||
placeholder={`What's happening?`}
|
||||
style={[
|
||||
styles.default
|
||||
this.state.isFocused && styles.focused
|
||||
]}
|
||||
/>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
const styles = StyleSheet.create({
|
||||
default: {
|
||||
borderColor: 'gray',
|
||||
borderBottomWidth: 2
|
||||
},
|
||||
focused: {
|
||||
borderColor: 'blue'
|
||||
}
|
||||
})
|
||||
```
|
||||
@@ -1,46 +0,0 @@
|
||||
# TouchableWithoutFeedback
|
||||
|
||||
Do not use unless you have a very good reason. All the elements that respond to
|
||||
press should have a visual feedback when touched. This is one of the primary
|
||||
reason a "web" app doesn't feel "native".
|
||||
|
||||
**NOTE: `TouchableWithoutFeedback` supports only one child**. If you wish to have
|
||||
several child components, wrap them in a View.
|
||||
|
||||
## Props
|
||||
|
||||
[...View props](./View.md)
|
||||
|
||||
**delayLongPress**: ?number
|
||||
|
||||
Delay in ms, from `onPressIn`, before `onLongPress` is called.
|
||||
|
||||
**delayPressIn**: ?number
|
||||
|
||||
Delay in ms, from the start of the touch, before `onPressIn` is called.
|
||||
|
||||
**delayPressOut**: ?number
|
||||
|
||||
Delay in ms, from the release of the touch, before `onPressOut` is called.
|
||||
|
||||
**disabled**: ?boolean
|
||||
|
||||
If `true`, disable all interactions for this component.
|
||||
|
||||
**onLongPress**: ?function
|
||||
|
||||
**onPress**: ?function
|
||||
|
||||
Called when the touch is released, but not if cancelled (e.g. by a scroll that steals the responder lock).
|
||||
|
||||
**onPressIn**: ?function
|
||||
|
||||
**onPressOut**: ?function
|
||||
|
||||
**pressRetentionOffset**: ?`{top: number, left: number, bottom: number, right: number}`
|
||||
|
||||
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
|
||||
back and you'll see that the button is once again reactivated! Move it back and
|
||||
forth several times while the scroll view is disabled. Ensure you pass in a
|
||||
constant to reduce memory allocations.
|
||||
@@ -1,317 +0,0 @@
|
||||
# View
|
||||
|
||||
`View` is the fundamental UI building block. It is a component that supports
|
||||
style, layout with flexbox, and accessibility controls. It can be nested
|
||||
inside another `View` and has 0-to-many children of any type.
|
||||
|
||||
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).
|
||||
|
||||
Unsupported React Native props: `collapsable`, `onAccessibilityTap`, `onMagicTap`.
|
||||
|
||||
## Props
|
||||
|
||||
NOTE: `View` will transfer all other props to the rendered HTML element.
|
||||
|
||||
**accessibilityLabel**: ?string
|
||||
|
||||
Overrides the text that's read by a screen reader when the user interacts
|
||||
with the element. (This is implemented using `aria-label`.)
|
||||
|
||||
See the [Accessibility guide](../guides/accessibility.md) for more information.
|
||||
|
||||
**accessibilityLiveRegion**: ?enum('assertive', 'none', 'polite')
|
||||
|
||||
Indicates to assistive technologies whether to notify the user when the view
|
||||
changes. The values of this attribute are expressed in degrees of importance.
|
||||
When regions are specified as `polite` (recommended), updates take low
|
||||
priority. When regions are specified as `assertive`, assistive technologies
|
||||
will interrupt and immediately notify the user. (This is implemented using
|
||||
[`aria-live`](http://www.w3.org/TR/wai-aria/states_and_properties#aria-live).)
|
||||
|
||||
See the [Accessibility guide](../guides/accessibility.md) for more information.
|
||||
|
||||
(web) **accessibilityRole**: ?enum(roles)
|
||||
|
||||
Allows assistive technologies to present and support interaction with the view
|
||||
in a manner that is consistent with user expectations for similar views of that
|
||||
type. For example, marking a touchable view with an `accessibilityRole` of
|
||||
`button`. (This is implemented using [ARIA roles](http://www.w3.org/TR/wai-aria/roles#role_definitions)).
|
||||
|
||||
See the [Accessibility guide](../guides/accessibility.md) for more information.
|
||||
|
||||
**accessible**: ?boolean
|
||||
|
||||
When `true`, indicates that the view is an accessibility element (i.e.,
|
||||
focusable) and groups its child content. By default, all the touchable elements
|
||||
and elements with `accessibilityRole` of `button` and `link` are accessible.
|
||||
(This is implemented using `tabindex`.)
|
||||
|
||||
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,
|
||||
height } } }`, where `x` and `y` are the offsets from the parent node.
|
||||
|
||||
**onMoveShouldSetResponder**: ?function => boolean
|
||||
|
||||
Does this view want to "claim" touch responsiveness? This is called for every
|
||||
touch move on the `View` when it is not the responder.
|
||||
|
||||
**onMoveShouldSetResponderCapture**: ?function => boolean
|
||||
|
||||
If a parent `View` wants to prevent a child `View` from becoming responder on a
|
||||
move, it should have this handler return `true`.
|
||||
|
||||
**onResponderGrant**: ?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`.
|
||||
|
||||
**onResponderMove**: ?function
|
||||
|
||||
The user is moving their finger.
|
||||
|
||||
**onResponderReject**: ?function
|
||||
|
||||
Another responder is already active and will not release it to the `View`
|
||||
asking to be the responder.
|
||||
|
||||
**onResponderRelease**: ?function
|
||||
|
||||
Fired at the end of the touch.
|
||||
|
||||
**onResponderTerminate**: ?function
|
||||
|
||||
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:
|
||||
|
||||
```css
|
||||
.box-none { pointer-events: none !important; }
|
||||
.box-none > * { pointer-events: auto; }
|
||||
```
|
||||
|
||||
`box-only` is the equivalent of:
|
||||
|
||||
```css
|
||||
.box-only { pointer-events: auto !important; }
|
||||
.box-only > * { pointer-events: none; }
|
||||
```
|
||||
|
||||
**style**: ?style
|
||||
|
||||
+ `alignContent`
|
||||
+ `alignItems`
|
||||
+ `alignSelf`
|
||||
+ `animationDelay` ‡
|
||||
+ `animationDirection` ‡
|
||||
+ `animationDuration` ‡
|
||||
+ `animationFillMode` ‡
|
||||
+ `animationIterationCount` ‡
|
||||
+ `animationName` ‡
|
||||
+ `animationPlayState` ‡
|
||||
+ `animationTimingFunction` ‡
|
||||
+ `backfaceVisibility`
|
||||
+ `backgroundAttachment` ‡
|
||||
+ `backgroundBlendMode` ‡
|
||||
+ `backgroundClip` ‡
|
||||
+ `backgroundColor`
|
||||
+ `backgroundImage` ‡
|
||||
+ `backgroundOrigin` ‡
|
||||
+ `backgroundPosition` ‡
|
||||
+ `backgroundRepeat` ‡
|
||||
+ `backgroundSize` ‡
|
||||
+ `borderColor` (single value)
|
||||
+ `borderTopColor`
|
||||
+ `borderBottomColor`
|
||||
+ `borderRightColor`
|
||||
+ `borderLeftColor`
|
||||
+ `borderRadius` (single value)
|
||||
+ `borderTopLeftRadius`
|
||||
+ `borderTopRightRadius`
|
||||
+ `borderBottomLeftRadius`
|
||||
+ `borderBottomRightRadius`
|
||||
+ `borderStyle` (single value)
|
||||
+ `borderTopStyle`
|
||||
+ `borderRightStyle`
|
||||
+ `borderBottomStyle`
|
||||
+ `borderLeftStyle`
|
||||
+ `borderWidth` (single value)
|
||||
+ `borderBottomWidth`
|
||||
+ `borderLeftWidth`
|
||||
+ `borderRightWidth`
|
||||
+ `borderTopWidth`
|
||||
+ `bottom`
|
||||
+ `boxShadow` ‡
|
||||
+ `boxSizing`
|
||||
+ `clip` ‡
|
||||
+ `cursor` ‡
|
||||
+ `display`
|
||||
+ `filter` ‡
|
||||
+ `flex` (number)
|
||||
+ `flexBasis`
|
||||
+ `flexDirection`
|
||||
+ `flexGrow`
|
||||
+ `flexShrink`
|
||||
+ `flexWrap`
|
||||
+ `gridAutoColumns` ‡
|
||||
+ `gridAutoFlow` ‡
|
||||
+ `gridAutoRows` ‡
|
||||
+ `gridColumnEnd` ‡
|
||||
+ `gridColumnGap` ‡
|
||||
+ `gridColumnStart` ‡
|
||||
+ `gridRowEnd` ‡
|
||||
+ `gridRowGap` ‡
|
||||
+ `gridRowStart` ‡
|
||||
+ `gridTemplateColumns` ‡
|
||||
+ `gridTemplateRows` ‡
|
||||
+ `gridTemplateAreas` ‡
|
||||
+ `height`
|
||||
+ `justifyContent`
|
||||
+ `left`
|
||||
+ `margin` (single value)
|
||||
+ `marginBottom`
|
||||
+ `marginHorizontal`
|
||||
+ `marginLeft`
|
||||
+ `marginRight`
|
||||
+ `marginTop`
|
||||
+ `marginVertical`
|
||||
+ `maxHeight`
|
||||
+ `maxWidth`
|
||||
+ `minHeight`
|
||||
+ `minWidth`
|
||||
+ `opacity`
|
||||
+ `order`
|
||||
+ `outline` ‡
|
||||
+ `outlineColor` ‡
|
||||
+ `overflow`
|
||||
+ `overflowX` ‡
|
||||
+ `overflowY` ‡
|
||||
+ `padding` (single value)
|
||||
+ `paddingBottom`
|
||||
+ `paddingHorizontal`
|
||||
+ `paddingLeft`
|
||||
+ `paddingRight`
|
||||
+ `paddingTop`
|
||||
+ `paddingVertical`
|
||||
+ `perspective` ‡
|
||||
+ `perspectiveOrigin` ‡
|
||||
+ `position`
|
||||
+ `right`
|
||||
+ `shadowColor`
|
||||
+ `shadowOffset`
|
||||
+ `shadowOpacity`
|
||||
+ `shadowRadius`
|
||||
+ `top`
|
||||
+ `transform`
|
||||
+ `transformOrigin` ‡
|
||||
+ `transitionDelay` ‡
|
||||
+ `transitionDuration` ‡
|
||||
+ `transitionProperty` ‡
|
||||
+ `transitionTimingFunction` ‡
|
||||
+ `userSelect` ‡
|
||||
+ `visibility` ‡
|
||||
+ `width`
|
||||
+ `willChange` ‡
|
||||
+ `zIndex`
|
||||
|
||||
‡ web only.
|
||||
|
||||
Default:
|
||||
|
||||
```js
|
||||
{
|
||||
alignItems: 'stretch',
|
||||
borderWidth: 0,
|
||||
borderStyle: 'solid',
|
||||
boxSizing: 'border-box',
|
||||
display: 'flex',
|
||||
flexBasis: 'auto',
|
||||
flexDirection: 'column',
|
||||
flexShrink: 0,
|
||||
margin: 0,
|
||||
padding: 0,
|
||||
position: 'relative'
|
||||
};
|
||||
```
|
||||
|
||||
(See [facebook/yoga](https://github.com/facebook/yoga)).
|
||||
|
||||
**testID**: ?string
|
||||
|
||||
Used to locate this view in end-to-end tests.
|
||||
|
||||
## Examples
|
||||
|
||||
```js
|
||||
import React, { Component, PropTypes } from 'react'
|
||||
import { StyleSheet, View } from 'react-native'
|
||||
|
||||
export default class ViewExample extends Component {
|
||||
render() {
|
||||
return (
|
||||
<View style={styles.row}>
|
||||
{
|
||||
['1', '2', '3', '4', '5'].map((value, i) => {
|
||||
return <View children={value} key={i} style={styles.cell} />
|
||||
})
|
||||
}
|
||||
</View>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
const styles = StyleSheet.create({
|
||||
row: {
|
||||
flexDirection: 'row'
|
||||
},
|
||||
cell: {
|
||||
flexGrow: 1
|
||||
}
|
||||
})
|
||||
```
|
||||
@@ -39,34 +39,46 @@ using `aria-label`.
|
||||
|
||||
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 provides a compatibility mapping of equivalent
|
||||
readers on the web, you should use 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] to use in addition to the resulting ARIA `role`, where
|
||||
possible. While this may contradict some ARIA recommendations, it also helps
|
||||
avoid certain HTML5 conformance errors and accessibility anti-patterns (e.g.,
|
||||
giving a `heading` role to a `button` element).
|
||||
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 browser bugs, HTML5 conformance
|
||||
errors, and accessibility anti-patterns (e.g., giving a `heading` role to a
|
||||
`button` element).
|
||||
|
||||
For example:
|
||||
Straight-forward examples:
|
||||
|
||||
* `<View accessibilityRole='article' />` => `<article role='article' />`.
|
||||
* `<View accessibilityRole='banner' />` => `<header role='banner' />`.
|
||||
* `<View accessibilityRole='button' />` => `<button type='button' role='button' />`.
|
||||
* `<Text accessibilityRole='link' href='/' />` => `<a role='link' href='/' />`.
|
||||
* `<View accessibilityRole='main' />` => `<main role='main' />`.
|
||||
* `<View accessibilityRole="article" />` => `<article role="article" />`.
|
||||
* `<View accessibilityRole="banner" />` => `<header role="banner" />`.
|
||||
* `<Text accessibilityRole="label" />` => `<label />`.
|
||||
* `<Text accessibilityRole="link" />` => `<a role="link" />`.
|
||||
* `<View accessibilityRole="main" />` => `<main role="main" />`.
|
||||
|
||||
In the example below, the `TouchableWithoutFeedback` is announced by screen
|
||||
readers as a native Button.
|
||||
The `heading` role can be combined with `aria-level`:
|
||||
|
||||
```
|
||||
<TouchableWithoutFeedback accessibilityRole="button" onPress={this._onPress}>
|
||||
* `<Text accessibilityRole="heading" />` => `<h1 />`.
|
||||
* `<Text accessibilityRole="heading" aria-level="3" />` => `<h3 />`.
|
||||
|
||||
The `button` role renders an accessible button but is not implemented using the
|
||||
native `button` element due to some browsers limiting the use of flexbox layout on
|
||||
its children.
|
||||
|
||||
* `<View accessibilityRole="button" />` => `<div role="button" tabIndex="0" />`.
|
||||
|
||||
In the example below, the `TouchableHighlight` is announced by screen readers
|
||||
as a button and it responds to touch, mouse, and keyboard interactions.
|
||||
|
||||
```js
|
||||
<TouchableHighlight accessibilityRole="button" onPress={this._handlePress}>
|
||||
<View style={styles.button}>
|
||||
<Text style={styles.buttonText}>Press me!</Text>
|
||||
</View>
|
||||
</TouchableWithoutFeedback>
|
||||
</TouchableHighlight>
|
||||
```
|
||||
|
||||
Note: Avoid changing `accessibilityRole` values over time or after user
|
||||
@@ -75,7 +87,7 @@ assistive technologies of a `role` value change.
|
||||
|
||||
### accessibilityLiveRegion
|
||||
|
||||
When components dynamically change we may need to inform the user. The
|
||||
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`.
|
||||
@@ -109,6 +121,18 @@ 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`).
|
||||
|
||||
### Spatial navigation
|
||||
|
||||
Focus-based web UIs, e.g., for TVs and Game Consoles can implement [TV remote
|
||||
control navigation](https://developer.mozilla.org/en-US/docs/Mozilla/Firefox_OS_for_TV/TV_remote_control_navigation)
|
||||
outside of React using existing directional-focus libraries. Every DOM element
|
||||
that React Native considers focusable can be matched by the attribute
|
||||
`data-focusable="true"`.
|
||||
|
||||
```js
|
||||
const focusableElements = document.querySelectorAll('[data-focusable="true"]');
|
||||
```
|
||||
|
||||
### Other
|
||||
|
||||
Other ARIA properties can be set via [direct
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
# Advanced use
|
||||
# Experimental / unstable uses
|
||||
|
||||
## Use with existing React DOM components
|
||||
|
||||
React Native for Web exports a web-specific module called `createDOMElement`,
|
||||
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.
|
||||
|
||||
@@ -11,9 +11,8 @@ In the example below, `Video` will now accept common React Native props such as
|
||||
props.
|
||||
|
||||
```js
|
||||
import { createDOMElement } from 'react-native';
|
||||
|
||||
const Video = (props) => createDOMElement('video', props);
|
||||
import { createElement } from 'react-native-web';
|
||||
const Video = (props) => createElement('video', props);
|
||||
```
|
||||
|
||||
This also works with composite components defined in your existing component
|
||||
@@ -21,9 +20,10 @@ gallery or dependencies ([live example](https://www.webpackbin.com/bins/-KiTSGFw
|
||||
|
||||
```js
|
||||
import RaisedButton from 'material-ui/RaisedButton';
|
||||
import { createDOMElement, StyleSheet } from 'react-native';
|
||||
import { createElement } from 'react-native-web';
|
||||
import { StyleSheet } from 'react-native';
|
||||
|
||||
const CustomButton = (props) => createDOMElement(RaisedButton, {
|
||||
const CustomButton = (props) => createElement(RaisedButton, {
|
||||
...props,
|
||||
style: [ styles.button, props.style ]
|
||||
});
|
||||
@@ -35,6 +35,14 @@ const styles = StyleSheet.create({
|
||||
});
|
||||
```
|
||||
|
||||
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.
|
||||
@@ -47,7 +55,8 @@ an API inspired by styled-components ([live
|
||||
example](https://www.webpackbin.com/bins/-KjT9ziwv4O7FDZdvsnX)).
|
||||
|
||||
```js
|
||||
const { createDOMElement, StyleSheet } = ReactNative;
|
||||
import { createElement } from 'react-native-web';
|
||||
import { StyleSheet } from 'react-native';
|
||||
|
||||
/**
|
||||
* styled API
|
||||
@@ -69,7 +78,7 @@ const styled = (Component, styler) => {
|
||||
|
||||
return (
|
||||
isDOMComponent
|
||||
? createDOMElement(Component, nextProps)
|
||||
? createElement(Component, nextProps)
|
||||
: <Component {...nextProps} />
|
||||
);
|
||||
}
|
||||
@@ -92,9 +101,9 @@ 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`.
|
||||
alias `react-native` to `react-sketchapp`. This will allow you to render simple
|
||||
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)
|
||||
|
||||
42
docs/guides/client-side-rendering.md
Normal file
42
docs/guides/client-side-rendering.md
Normal file
@@ -0,0 +1,42 @@
|
||||
# Client-side rendering
|
||||
|
||||
Render apps using `AppRegistry`:
|
||||
|
||||
```js
|
||||
// index.web.js
|
||||
|
||||
import App from './src/App';
|
||||
import React from 'react';
|
||||
import { AppRegistry } from 'react-native';
|
||||
|
||||
// register the app
|
||||
AppRegistry.registerComponent('App', () => App);
|
||||
|
||||
AppRegistry.runApplication('App', {
|
||||
initialProps: {},
|
||||
rootTag: document.getElementById('react-app')
|
||||
});
|
||||
```
|
||||
|
||||
Or render individual components:
|
||||
|
||||
```js
|
||||
import AppHeader from './src/AppHeader';
|
||||
import React from 'react';
|
||||
import { render } from 'react-native';
|
||||
|
||||
render(<AppHeader />, document.getElementById('react-app-header'))
|
||||
```
|
||||
|
||||
(Components will also be rendered within a tree produced by calling
|
||||
`ReactDOM.render` (i.e., an existing web app), but
|
||||
otherwise it is not recommended.)
|
||||
|
||||
You might need to adjust the styles of the HTML document's root elements for
|
||||
your app to fill the viewport.
|
||||
|
||||
```html
|
||||
<html style="height:100%">
|
||||
<body style="height:100%">
|
||||
<div id="react-root" style="display:flex;height:100%"></div>
|
||||
```
|
||||
@@ -1,13 +1,13 @@
|
||||
# Direct manipulation
|
||||
|
||||
React Native for Web provides several methods to directly access the underlying
|
||||
DOM node. This can be useful when you need to make changes directly to a
|
||||
component without using state/props to trigger a re-render of the entire
|
||||
subtree, or when you want to focus a view or measure its on-screen dimensions.
|
||||
React Native provides several methods to directly access the underlying host
|
||||
node. This can be useful when you need to make changes directly to a component
|
||||
without using state/props to trigger a re-render of the entire subtree, or when
|
||||
you want to focus a view or measure its on-screen dimensions.
|
||||
|
||||
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.
|
||||
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
|
||||
|
||||
@@ -35,11 +35,17 @@ 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.
|
||||
|
||||
As always, to obtain a native node handle for a component, you can use
|
||||
`findNodeHandle(component)`.
|
||||
|
||||
**measureInWindow**(callback: (x, y, width, height) => void)
|
||||
|
||||
Determines the location of the given view in the window and returns the values
|
||||
via an async callback.
|
||||
|
||||
**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.
|
||||
This function sends props straight to the underlying DOM node.
|
||||
|
||||
## About `setNativeProps`
|
||||
|
||||
|
||||
@@ -1,204 +1,109 @@
|
||||
# Getting started
|
||||
|
||||
This guide will help you to correctly configure build and test tools to work
|
||||
with React Native for Web.
|
||||
This guide will help you render components and applications with React Native
|
||||
for Web.
|
||||
|
||||
Your application may need to polyfill `Promise`, `Object.assign`, `Array.from`,
|
||||
and [`ResizeObserver`](https://github.com/que-etc/resize-observer-polyfill) as
|
||||
necessary for your desired browser support.
|
||||
|
||||
If you're not familiar with setting up a new React web project, please follow
|
||||
the recommendations in the [React documentation](https://reactjs.org/).
|
||||
|
||||
## Install
|
||||
|
||||
```
|
||||
yarn add react react-dom react-native-web
|
||||
```
|
||||
|
||||
And if you need to use `ART`:
|
||||
|
||||
```
|
||||
yarn add react-art
|
||||
```
|
||||
|
||||
## Starter kits
|
||||
|
||||
Alternatively, you can quickly setup a local project using
|
||||
[create-react-app](https://github.com/facebookincubator/create-react-app)
|
||||
(which supports `react-native-web` out-of-the-box once installed),
|
||||
[react-native-web-starter](https://github.com/grabcode/react-native-web-starter),
|
||||
or [react-native-web-webpack](https://github.com/ndbroadbent/react-native-web-webpack).
|
||||
includes built-in support for aliasing `react-native-web` to `react-native`.
|
||||
|
||||
It is recommended that your application provide a `Promise` and `Array.from`
|
||||
polyfill.
|
||||
```
|
||||
create-react-app my-app
|
||||
```
|
||||
|
||||
## Webpack and Babel
|
||||
## Configuring a module bundler
|
||||
|
||||
[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.
|
||||
If you have a custom setup, you may choose to configure your module bundler to
|
||||
alias the package to `react-native`.
|
||||
|
||||
For example, modify your [webpack](https://github.com/webpack/webpack)
|
||||
configuration as follows:
|
||||
|
||||
```js
|
||||
// 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,
|
||||
// The 'react-native' preset is recommended
|
||||
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.
|
||||
new webpack.DefinePlugin({
|
||||
'process.env.NODE_ENV': JSON.stringify('production')
|
||||
})
|
||||
],
|
||||
|
||||
resolve: {
|
||||
// Maps the 'react-native' import to 'react-native-web'.
|
||||
alias: {
|
||||
'react-native': 'react-native-web'
|
||||
},
|
||||
// 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' ]
|
||||
'react-native$': 'react-native-web'
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Please refer to the Webpack documentation for more information.
|
||||
Now you can create your components and applications with the React Native API.
|
||||
|
||||
## Jest
|
||||
## Configuring Babel
|
||||
|
||||
[Jest](https://facebook.github.io/jest/) also needs to map `react-native` to `react-native-web`.
|
||||
If you need to do the aliasing with Babel you can use
|
||||
[babel-plugin-module-resolver](https://www.npmjs.com/package/babel-plugin-module-resolver)
|
||||
|
||||
```
|
||||
"jest": {
|
||||
"moduleNameMapper": {
|
||||
"react-native": "<rootDir>/node_modules/react-native-web"
|
||||
}
|
||||
{
|
||||
"plugins": [
|
||||
["module-resolver", {
|
||||
"alias": {
|
||||
"^react-native$": "react-native-web"
|
||||
}
|
||||
}]
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
## Configuring Jest
|
||||
|
||||
[Jest](https://facebook.github.io/jest/) can be configured using the provided
|
||||
preset. This will map `react-native` to `react-native-web` and provide
|
||||
appropriate mocks:
|
||||
|
||||
```
|
||||
{
|
||||
"preset": "react-native-web"
|
||||
}
|
||||
```
|
||||
|
||||
Please refer to the Jest documentation for more information.
|
||||
|
||||
## Web-specific code
|
||||
## Configuring Flow
|
||||
|
||||
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 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:
|
||||
[Flow](https://flow.org) can be configured to understand the aliased module:
|
||||
|
||||
```
|
||||
MyComponent.android.js
|
||||
MyComponent.ios.js
|
||||
MyComponent.web.js
|
||||
[options]
|
||||
module.name_mapper='^react-native$' -> 'react-native-web'
|
||||
```
|
||||
|
||||
And the following import:
|
||||
You may also need to include a custom libdef
|
||||
([example](https://gist.github.com/paularmstrong/f60b40d16fc83e1e8e532d483336f9bb))
|
||||
in your config.
|
||||
|
||||
```js
|
||||
import MyComponent from './MyComponent';
|
||||
```
|
||||
## Other notes
|
||||
|
||||
React Native will automatically import the correct variant for each specific
|
||||
target platform.
|
||||
### Safari flexbox performance
|
||||
|
||||
## Client-side rendering
|
||||
|
||||
Rendering using `ReactNative`:
|
||||
|
||||
```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 `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')
|
||||
})
|
||||
```
|
||||
|
||||
Rendering within `ReactDOM.render` also works when introducing
|
||||
`react-native-web` to an existing web app, but otherwise it is not recommended.
|
||||
|
||||
## Server-side rendering
|
||||
|
||||
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, 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}
|
||||
`
|
||||
```
|
||||
Safari prior to version 10.1 can suffer from extremely [poor flexbox
|
||||
performance](https://bugs.webkit.org/show_bug.cgi?id=150445). The recommended
|
||||
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.
|
||||
|
||||
@@ -1,31 +0,0 @@
|
||||
# Known issues
|
||||
|
||||
## Safari flexbox performance
|
||||
|
||||
Safari version prior to 10.1 can suffer from extremely [poor flexbox
|
||||
performance](https://bugs.webkit.org/show_bug.cgi?id=150445). The recommended
|
||||
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
|
||||
cases it will be necessary to use a Web counterpart or to guard the use of a
|
||||
module with `Platform.OS` (e.g. `NativeModules`)
|
||||
|
||||
## Missing component props
|
||||
|
||||
There are properties that do not work across all platforms. All web-specific
|
||||
props are annotated with `(web)` in the documentation.
|
||||
|
||||
## Platform parity
|
||||
|
||||
There are some known issues in React Native where APIs could be made more
|
||||
consistent between platforms. For example, React Native for Web includes
|
||||
`ActivityIndicator` and a horizontal `ProgressBar` for Web use, in anticipation
|
||||
of the convergence between the iOS and Android components in React Native.
|
||||
154
docs/guides/multi-platform-apps.md
Normal file
154
docs/guides/multi-platform-apps.md
Normal file
@@ -0,0 +1,154 @@
|
||||
# Multi-platform applications
|
||||
|
||||
## 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 below 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.
|
||||
|
||||
## Web packaging for existing React Native apps
|
||||
|
||||
What follows is merely an _example_ of one basic way to package a web app using
|
||||
[Webpack](https://webpack.js.org) and [Babel](https://babeljs.io/). (You can
|
||||
also use the React Native bundler, [Metro](https://github.com/facebook/metro), to
|
||||
build web apps.)
|
||||
|
||||
Packaging web apps is subtly different to packaging React Native apps and is
|
||||
complicated by the need to tree-shake and code-split non-trivial apps.
|
||||
|
||||
Install webpack-related dependencies, for example:
|
||||
|
||||
```
|
||||
yarn add --dev babel-loader url-loader webpack webpack-cli webpack-dev-server
|
||||
```
|
||||
|
||||
React Native's Babel preset rewrites ES modules to CommonJS modules, preventing
|
||||
bundlers from automatically performing "tree-shaking" to remove unused modules
|
||||
from your web app build. To help with this, you can install the following Babel
|
||||
plugin:
|
||||
|
||||
```
|
||||
yarn add --dev babel-plugin-react-native-web
|
||||
```
|
||||
|
||||
Create a `web/webpack.config.js` file:
|
||||
|
||||
```js
|
||||
// web/webpack.config.js
|
||||
|
||||
const path = require('path');
|
||||
const webpack = require('webpack');
|
||||
|
||||
const appDirectory = path.resolve(__dirname, '../');
|
||||
|
||||
// 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(appDirectory, 'index.web.js'),
|
||||
path.resolve(appDirectory, 'src'),
|
||||
path.resolve(appDirectory, 'node_modules/react-native-uncompiled')
|
||||
],
|
||||
use: {
|
||||
loader: 'babel-loader',
|
||||
options: {
|
||||
cacheDirectory: true,
|
||||
// The 'react-native' preset is recommended to match React Native's packager
|
||||
presets: ['react-native'],
|
||||
// Re-write paths to import only the modules needed by the app
|
||||
plugins: ['react-native-web']
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
// 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 = {
|
||||
entry: [
|
||||
// load any web API polyfills
|
||||
// path.resolve(appDirectory, 'polyfills-web.js'),
|
||||
// your web-specific entry file
|
||||
path.resolve(appDirectory, 'index.web.js')
|
||||
],
|
||||
|
||||
// configures where the build ends up
|
||||
output: {
|
||||
filename: 'bundle.web.js',
|
||||
path: path.resolve(appDirectory, 'dist')
|
||||
},
|
||||
|
||||
// ...the rest of your config
|
||||
|
||||
module: {
|
||||
rules: [
|
||||
babelLoaderConfiguration,
|
||||
imageLoaderConfiguration
|
||||
]
|
||||
},
|
||||
|
||||
resolve: {
|
||||
// This will only alias the exact import "react-native"
|
||||
alias: {
|
||||
'react-native$': 'react-native-web'
|
||||
},
|
||||
// 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 from the root of your application:
|
||||
|
||||
```
|
||||
./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.
|
||||
33
docs/guides/server-side-rendering.md
Normal file
33
docs/guides/server-side-rendering.md
Normal file
@@ -0,0 +1,33 @@
|
||||
# Server-side rendering
|
||||
|
||||
Server-side rendering to HTML is supported using `AppRegistry`:
|
||||
|
||||
```js
|
||||
import App from './src/App';
|
||||
import ReactDOMServer from 'react-dom/server';
|
||||
import { AppRegistry } from 'react-native-web';
|
||||
|
||||
// register the app
|
||||
AppRegistry.registerComponent('App', () => App);
|
||||
|
||||
// prerender the app
|
||||
const { element, getStyleElement } = AppRegistry.getApplication('App', { initialProps });
|
||||
// first the element
|
||||
const html = ReactDOMServer.renderToString(element);
|
||||
// then the styles (optionally include a nonce if your CSP policy requires it)
|
||||
const css = ReactDOMServer.renderToStaticMarkup(getStyleElement({ nonce }));
|
||||
|
||||
// example HTML document string
|
||||
const document = `
|
||||
<!DOCTYPE html>
|
||||
<html style="height:100%">
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
${css}
|
||||
<body style="height:100%; overflow-y:hidden">
|
||||
<div id="root" style="display:flex; height: 100%">
|
||||
${html}
|
||||
</div>
|
||||
<script nonce="${nonce}" src="${bundlePath}"></script>
|
||||
`
|
||||
```
|
||||
@@ -5,22 +5,22 @@ application. React Native for Web implements the React Native style API in a
|
||||
way that avoids *all* the [problems with CSS at
|
||||
scale](https://speakerdeck.com/vjeux/react-css-in-js):
|
||||
|
||||
1. No local variables
|
||||
2. Implicit dependencies
|
||||
3. No dead code elimination
|
||||
4. No code minification
|
||||
5. No sharing of constants
|
||||
6. Non-deterministic resolution
|
||||
7. No isolation
|
||||
1. No local variables.
|
||||
2. Implicit dependencies.
|
||||
3. No dead code elimination.
|
||||
4. No code minification.
|
||||
5. No sharing of constants.
|
||||
6. Non-deterministic resolution.
|
||||
7. No isolation.
|
||||
|
||||
At the same time, it has several benefits:
|
||||
|
||||
1. Simple API and expressive subset of CSS
|
||||
2. Generates CSS; the minimum required
|
||||
3. Good runtime performance
|
||||
4. Support for static and dynamic styles
|
||||
5. Support for RTL layouts
|
||||
6. Easy pre-rendering of critical CSS
|
||||
1. Simple API and expressive subset of CSS.
|
||||
2. Generates CSS; the minimum required.
|
||||
3. Good runtime performance.
|
||||
4. Support for static and dynamic styles.
|
||||
5. Support for RTL layouts.
|
||||
6. Easy pre-rendering of critical CSS.
|
||||
|
||||
## Defining styles
|
||||
|
||||
@@ -43,6 +43,8 @@ const styles = StyleSheet.create({
|
||||
|
||||
See the `style` documentation of individual components for supported properties.
|
||||
|
||||
NOTE: React Native does not yet support `rem` or `em` units.
|
||||
|
||||
## Using styles
|
||||
|
||||
All the React Native components accept a `style` property. The value can be a
|
||||
@@ -126,7 +128,7 @@ the CSS and takes precedence over the previous rules, resulting in a margin of
|
||||
<div class="marginTop marginBottom margin"></div>
|
||||
```
|
||||
|
||||
But in React Native the most *specific* style property takes precedence,
|
||||
But in React Native the most *precise* style property takes precedence,
|
||||
resulting in margins of `10, 0, 20, 0`.
|
||||
|
||||
```js
|
||||
@@ -192,7 +194,7 @@ inline styles.
|
||||
|
||||
All this allows React Native for Web to support the rich functionality of React
|
||||
Native styles (including RTL layouts and `setNativeProps`) while providing one
|
||||
of the [fastest](https://github.com/necolas/react-native-web/blob/master/benchmarks/README.md),
|
||||
of the [fastest](https://github.com/necolas/react-native-web/blob/master/packages/benchmarks/README.md),
|
||||
safest, and most efficient styles-in-JavaScript solutions.
|
||||
|
||||
## FAQs
|
||||
@@ -204,14 +206,11 @@ it does not concern itself with _where_ or _when_ those styles are applied to
|
||||
elements.
|
||||
|
||||
Media Queries may not be most appropriate for component-based designs. React
|
||||
Native provides the `Dimensions` API and `onLayout` props. If you do need Media
|
||||
Queries, using the `matchMedia` DOM API has the benefit of allowing you to swap
|
||||
out entire components, not just styles. There are also many React libraries
|
||||
wrapping JavaScript Media Query API's, e.g.,
|
||||
[react-media](https://github.com/reacttraining/react-media),
|
||||
[react-media-queries](https://github.com/bloodyowl/react-media-queries),
|
||||
[media-query-fascade](https://github.com/tanem/media-query-facade), or
|
||||
[react-responsive](https://github.com/contra/react-responsive).
|
||||
Native provides the `Dimensions` API and the component-scoped `onLayout` prop.
|
||||
|
||||
If you do choose to use Media Queries, using them in JavaScript via the
|
||||
`matchMedia` DOM API has the benefit of allowing you to swap out entire
|
||||
components, not just styles.
|
||||
|
||||
### What about pseudo-classes and pseudo-elements?
|
||||
|
||||
|
||||
51
docs/guides/web-recipes.md
Normal file
51
docs/guides/web-recipes.md
Normal file
@@ -0,0 +1,51 @@
|
||||
# Web recipes
|
||||
|
||||
Examples of how to implement web patterns with React Native.
|
||||
|
||||
#### `html` and `body` styles
|
||||
|
||||
The `html` and `body` elements require certain styles to support full-screen
|
||||
React Native apps, and disable "features" like pull-to-refresh in mobile
|
||||
browsers. Using the `body` as the root scroll view is [not reliably
|
||||
supported](https://github.com/necolas/react-native-web/issues/829).
|
||||
|
||||
[Example code](https://codesandbox.io/s/52x1871vjl).
|
||||
|
||||
#### Hover styles
|
||||
|
||||
Relying on the web's native hover styles can result in several unwanted UX
|
||||
consequences. Hover styles might be displayed during touch interactions and can
|
||||
remain visually "stuck". Furthermore, there's no way to delay or persist hover
|
||||
for accessibility purposes. This recipe shows how to apply hover styles that
|
||||
integrate with the Responder event system (e.g., the `Touchable*` press styles)
|
||||
and display styles *only* when the mouse is active. It can also be used as the
|
||||
basis for programmatic hover delays and rendering of components (e.g., hover
|
||||
cards).
|
||||
|
||||
[Example code](https://codesandbox.io/s/o9q8vy70l5)
|
||||
|
||||
#### Link styles
|
||||
|
||||
Cross-platform link components are straight-forward to create and can be
|
||||
combined with the hover recipe.
|
||||
|
||||
[Example code](https://codesandbox.io/s/53r88k5opx)
|
||||
|
||||
<!--
|
||||
#### Typography
|
||||
|
||||
Rather than relying on inhereted global typography styles, React Native allows
|
||||
you to define components that encapsulate a typographic system. This has the
|
||||
added benefit of enabling content-specific typography adjustments, e.g.,
|
||||
different font sizes or weights for different languages.
|
||||
|
||||
[Example code]()
|
||||
|
||||
#### Responsive font size
|
||||
|
||||
[Example code]()
|
||||
|
||||
#### SVG icons
|
||||
|
||||
[Example code]()
|
||||
-->
|
||||
@@ -1 +0,0 @@
|
||||
import '@kadira/storybook-addon-options/register';
|
||||
@@ -1,33 +0,0 @@
|
||||
const path = require('path');
|
||||
const webpack = require('webpack');
|
||||
|
||||
const DEV = process.env.NODE_ENV !== 'production';
|
||||
|
||||
module.exports = {
|
||||
module: {
|
||||
loaders: [
|
||||
{
|
||||
test: /\.js$/,
|
||||
exclude: /node_modules/,
|
||||
loader: 'babel-loader',
|
||||
query: { cacheDirectory: true }
|
||||
},
|
||||
{
|
||||
test: /\.(gif|jpe?g|png|svg)$/,
|
||||
loader: 'url-loader',
|
||||
query: { name: '[name].[ext]' }
|
||||
}
|
||||
]
|
||||
},
|
||||
plugins: [
|
||||
new webpack.DefinePlugin({
|
||||
'process.env.NODE_ENV': JSON.stringify(process.env.NODE_ENV || 'development'),
|
||||
'process.env.__REACT_NATIVE_DEBUG_ENABLED__': DEV
|
||||
})
|
||||
],
|
||||
resolve: {
|
||||
alias: {
|
||||
'react-native': path.join(__dirname, '../../../src/module')
|
||||
}
|
||||
}
|
||||
};
|
||||
@@ -1,107 +0,0 @@
|
||||
/**
|
||||
* @flow
|
||||
*/
|
||||
|
||||
import React from 'react';
|
||||
import { storiesOf } from '@kadira/storybook';
|
||||
import UIExplorer, { AppText, Code, DocItem } from '../../ui-explorer';
|
||||
|
||||
const sections = [
|
||||
{
|
||||
title: 'Methods',
|
||||
entries: [
|
||||
<DocItem
|
||||
description="Returns the given application's element and stylesheets. Use this for server-side rendering."
|
||||
label="web"
|
||||
name="static getApplication"
|
||||
typeInfo="(appKey: string, appParameters: ?object) => { element: ReactElement; stylesheets: Array<ReactElement> }"
|
||||
/>,
|
||||
|
||||
<DocItem
|
||||
description={
|
||||
<AppText>
|
||||
Register multiple applications. <Code>AppConfig</Code> is of type
|
||||
<Code>{'{ appKey: string; component: ComponentProvider; run?: Function }'}</Code>.
|
||||
</AppText>
|
||||
}
|
||||
name="static registerConfig"
|
||||
typeInfo="(config: Array<AppConfig>) => avoid"
|
||||
/>,
|
||||
|
||||
<DocItem
|
||||
description={
|
||||
<AppText>Register a component provider under the given <Code>appKey</Code>.</AppText>
|
||||
}
|
||||
example={{
|
||||
code: 'AppRegistry.registerComponent("MyApp", () => AppComponent)'
|
||||
}}
|
||||
name="static registerComponent"
|
||||
typeInfo="(appKey: string, getComponentFunc: ComponentProvider) => void"
|
||||
/>,
|
||||
|
||||
<DocItem
|
||||
description={
|
||||
<AppText>
|
||||
Register a custom render function for an application. The
|
||||
function will receive the <Code>appParameters</Code> passed
|
||||
to <Code>runApplication</Code>.
|
||||
</AppText>
|
||||
}
|
||||
name="static registerRunnable"
|
||||
typeInfo="(appKey: string, run: Function) => void"
|
||||
/>,
|
||||
|
||||
<DocItem
|
||||
description="Returns all registered app keys"
|
||||
name="static getAppKeys"
|
||||
typeInfo="() => Array<string>"
|
||||
/>,
|
||||
|
||||
<DocItem
|
||||
description={
|
||||
<AppText>
|
||||
Runs the application that was registered under <Code>appKey</Code>. The
|
||||
<Code>appParameters</Code> must include the <Code>rootTag</Code> into which the
|
||||
application is rendered, and optionally any <Code>initialProps</Code>.
|
||||
</AppText>
|
||||
}
|
||||
example={{
|
||||
code: `AppRegistry.runApplication('MyApp', {
|
||||
initialProps: {},
|
||||
rootTag: document.getElementById('react-root')
|
||||
})`
|
||||
}}
|
||||
name="static runApplication"
|
||||
typeInfo="(appKey: string, appParameters?: object) => void"
|
||||
/>,
|
||||
|
||||
<DocItem
|
||||
description={
|
||||
<AppText>
|
||||
To "stop" an application when a view should be destroyed, call{' '}
|
||||
<Code>AppRegistry.unmountApplicationComponentAtRootTag</Code> with the tag that was
|
||||
passed into <Code>runApplication</Code>.
|
||||
</AppText>
|
||||
}
|
||||
name="static unmountApplicationComponentAtRootTag"
|
||||
typeInfo="(rootTag: HTMLElement) => void"
|
||||
/>
|
||||
]
|
||||
}
|
||||
];
|
||||
|
||||
storiesOf('APIs', module).add('AppRegistry', () =>
|
||||
<UIExplorer
|
||||
description={
|
||||
<AppText>
|
||||
AppRegistry is the control point for registering, running,
|
||||
prerendering, and unmounting all apps. App root components should
|
||||
register themselves with <Code>AppRegistry.registerComponent</Code>. Apps can be
|
||||
run by invoking <Code>AppRegistry.runApplication</Code>
|
||||
</AppText>
|
||||
}
|
||||
sections={sections}
|
||||
title="AppRegistry"
|
||||
url="apis/AppRegistry"
|
||||
/>
|
||||
);
|
||||
@@ -1,33 +0,0 @@
|
||||
/* eslint-disable react/jsx-sort-props */
|
||||
|
||||
/**
|
||||
* @flow
|
||||
*/
|
||||
|
||||
import { storiesOf } from '@kadira/storybook';
|
||||
import UIExplorer, { DocItem } from '../../ui-explorer';
|
||||
import React from 'react';
|
||||
|
||||
const sections = [
|
||||
{
|
||||
title: 'Methods',
|
||||
entries: [
|
||||
<DocItem
|
||||
name="static get"
|
||||
typeInfo="(dimension: string) => Object"
|
||||
description="Get a dimension (e.g., `window` or `screen`)."
|
||||
example={{
|
||||
code: "const { height, width } = Dimensions.get('window')"
|
||||
}}
|
||||
/>
|
||||
]
|
||||
}
|
||||
];
|
||||
|
||||
storiesOf('APIs', module).add('Dimensions', () =>
|
||||
<UIExplorer
|
||||
description="Note: dimensions may change (e.g., due to device rotation) so any rendering logic or styles that depend on these constants should try to call this function on every render, rather than caching the value."
|
||||
sections={sections}
|
||||
title="Dimensions"
|
||||
/>
|
||||
);
|
||||
@@ -1,66 +0,0 @@
|
||||
/* eslint-disable react/jsx-sort-props */
|
||||
|
||||
/**
|
||||
* @flow
|
||||
*/
|
||||
|
||||
import RTLToggleExample from './examples/RTLToggle';
|
||||
import React from 'react';
|
||||
import { storiesOf } from '@kadira/storybook';
|
||||
import UIExplorer, { DocItem } from '../../ui-explorer';
|
||||
|
||||
const sections = [
|
||||
{
|
||||
title: 'Properties',
|
||||
entries: [
|
||||
<DocItem
|
||||
name="isRTL"
|
||||
typeInfo="boolean = false"
|
||||
description="Whether the application is currently in RTL mode."
|
||||
/>
|
||||
]
|
||||
},
|
||||
{
|
||||
title: 'Methods',
|
||||
entries: [
|
||||
<DocItem
|
||||
name="static allowRTL"
|
||||
typeInfo="(allowRTL: boolean) => void"
|
||||
description="Allow the application to display in RTL mode."
|
||||
/>,
|
||||
|
||||
<DocItem
|
||||
name="static forceRTL"
|
||||
typeInfo="(forceRTL: boolean) => void"
|
||||
description="Force the application to display in RTL mode."
|
||||
/>,
|
||||
|
||||
<DocItem
|
||||
label="web"
|
||||
name="static setPreferredLanguageRTL"
|
||||
typeInfo="(isRTL: boolean) => void"
|
||||
description="Set the application's preferred writing direction to RTL. You will need to determine the user's preferred locale server-side (from HTTP headers) and decide whether it's an RTL language."
|
||||
/>
|
||||
]
|
||||
},
|
||||
{
|
||||
title: 'Examples',
|
||||
entries: [
|
||||
<DocItem
|
||||
description="Toggling LTR/RTL layout at runtime"
|
||||
example={{
|
||||
render: () => <RTLToggleExample />
|
||||
}}
|
||||
/>
|
||||
]
|
||||
}
|
||||
];
|
||||
|
||||
storiesOf('APIs', module).add('I18nManager', () =>
|
||||
<UIExplorer
|
||||
description="Control and set the layout and writing direction of the application."
|
||||
sections={sections}
|
||||
title="I18nManager"
|
||||
url="apis/I18nManager"
|
||||
/>
|
||||
);
|
||||
@@ -1,75 +0,0 @@
|
||||
/**
|
||||
* @flow
|
||||
*/
|
||||
|
||||
import React from 'react';
|
||||
import { storiesOf } from '@kadira/storybook';
|
||||
import UIExplorer, { AppText, Code, DocItem } from '../../ui-explorer';
|
||||
|
||||
const sections = [
|
||||
{
|
||||
title: 'Methods',
|
||||
entries: [
|
||||
<DocItem
|
||||
description={
|
||||
'Invokes the listener whenever network status changes. The listener receives one of the following connectivity types (from the DOM connection API): bluetooth, cellular, ethernet, mixed, none, other, unknown, wifi, wimax'
|
||||
}
|
||||
example={{
|
||||
code: "NetInfo.addEventListener('change', (connectionType) => {})"
|
||||
}}
|
||||
name="static addEventListener"
|
||||
typeInfo="(eventName, handler) => void"
|
||||
/>,
|
||||
|
||||
<DocItem
|
||||
description="Returns a promise that resolves with one of the connectivity types listed above."
|
||||
example={{
|
||||
code: `NetInfo.fetch().then((connectionType) => {
|
||||
console.log('Connection type:', connectionType);
|
||||
});`
|
||||
}}
|
||||
name="static fetch"
|
||||
typeInfo="() => Promise<string>"
|
||||
/>,
|
||||
|
||||
<DocItem
|
||||
description="Removes the listener for network status changes."
|
||||
name="static removeEventListener"
|
||||
typeInfo="(eventName, handler) => void"
|
||||
/>
|
||||
]
|
||||
},
|
||||
{
|
||||
title: 'Properties',
|
||||
entries: [
|
||||
<DocItem
|
||||
description="An object with the same methods as above but the listener receives a boolean which represents the internet connectivity. Use this if you are only interested with whether the device has internet connectivity."
|
||||
example={{
|
||||
code: `NetInfo.isConnected.fetch().then((isConnected) => {
|
||||
console.log('Connection status:', (isConnected ? 'online' : 'offline'));
|
||||
});`
|
||||
}}
|
||||
name="isConnected"
|
||||
typeInfo="ObjectExpression"
|
||||
/>
|
||||
]
|
||||
}
|
||||
];
|
||||
|
||||
storiesOf('APIs', module).add('NetInfo', () =>
|
||||
<UIExplorer
|
||||
description={[
|
||||
<AppText>
|
||||
NetInfo asynchronously determines the online/offline status of the application.
|
||||
</AppText>,
|
||||
<AppText>
|
||||
Note that support for retrieving the connection type depends upon browswer support (and is
|
||||
limited to mobile browsers).
|
||||
It will default to <Code>unknown</Code> when support is missing.
|
||||
</AppText>
|
||||
]}
|
||||
sections={sections}
|
||||
title="NetInfo"
|
||||
url="apis/NetInfo"
|
||||
/>
|
||||
);
|
||||
@@ -1,44 +0,0 @@
|
||||
/**
|
||||
* @flow
|
||||
*/
|
||||
|
||||
import DraggableCircleExample from './examples/DraggableCircle';
|
||||
import { storiesOf } from '@kadira/storybook';
|
||||
import React from 'react';
|
||||
import UIExplorer, { AppText, DocItem } from '../../ui-explorer';
|
||||
|
||||
const sections = [
|
||||
{
|
||||
title: 'Examples',
|
||||
entries: [
|
||||
<DocItem
|
||||
example={{
|
||||
render: () => <DraggableCircleExample />
|
||||
}}
|
||||
/>
|
||||
]
|
||||
}
|
||||
];
|
||||
|
||||
storiesOf('APIs', module).add('PanResponder', () =>
|
||||
<UIExplorer
|
||||
description={
|
||||
<AppText>
|
||||
PanResponder reconciles several touches into a single gesture. It makes single-touch
|
||||
gestures resilient to extra touches, and can be used to recognize simple multi-touch
|
||||
gestures. For more information, please refer to the React Native{' '}
|
||||
<AppText
|
||||
accessibilityTraits="link"
|
||||
href="https://facebook.github.io/react-native/docs/panresponder.html"
|
||||
style={{ color: '#1B95E0' }}
|
||||
target="_blank"
|
||||
>
|
||||
PanResponder documentation
|
||||
</AppText>
|
||||
</AppText>
|
||||
}
|
||||
sections={sections}
|
||||
title="PanResponder"
|
||||
url="apis/PanResponder"
|
||||
/>
|
||||
);
|
||||
@@ -1,30 +0,0 @@
|
||||
/**
|
||||
* @flow
|
||||
*/
|
||||
|
||||
import sources from '../sources';
|
||||
import React from 'react';
|
||||
import { Image, StyleSheet, Text } from 'react-native';
|
||||
|
||||
const ImageChildrenExample = () =>
|
||||
<Image source={sources.large} style={styles.image}>
|
||||
<Text style={styles.text}>
|
||||
React
|
||||
</Text>
|
||||
</Image>;
|
||||
|
||||
const styles = StyleSheet.create({
|
||||
image: {
|
||||
width: 60,
|
||||
height: 60,
|
||||
backgroundColor: 'transparent',
|
||||
justifyContent: 'center',
|
||||
alignItems: 'center'
|
||||
},
|
||||
text: {
|
||||
backgroundColor: 'transparent',
|
||||
color: 'white'
|
||||
}
|
||||
});
|
||||
|
||||
export default ImageChildrenExample;
|
||||
@@ -1,47 +0,0 @@
|
||||
/**
|
||||
* @flow
|
||||
*/
|
||||
|
||||
import sources from '../sources';
|
||||
import React from 'react';
|
||||
import { Image, StyleSheet, Text, View } from 'react-native';
|
||||
|
||||
const ImageSourceExample = () =>
|
||||
<View style={styles.row}>
|
||||
<View style={styles.column}>
|
||||
<Text style={styles.text}>Static image</Text>
|
||||
<Image source={sources.static} style={styles.image} />
|
||||
</View>
|
||||
<View style={styles.column}>
|
||||
<Text style={styles.text}>Animated GIF</Text>
|
||||
<Image source={sources.animatedGif} style={styles.image} />
|
||||
</View>
|
||||
<View style={styles.column}>
|
||||
<Text style={styles.text}>Data PNG</Text>
|
||||
<Image source={sources.dataPng} style={styles.image} />
|
||||
</View>
|
||||
<View style={styles.column}>
|
||||
<Text style={styles.text}>Data SVG</Text>
|
||||
<Image source={sources.dataSvg} style={styles.image} />
|
||||
</View>
|
||||
</View>;
|
||||
|
||||
const styles = StyleSheet.create({
|
||||
row: {
|
||||
flexDirection: 'row',
|
||||
flexWrap: 'wrap'
|
||||
},
|
||||
column: {
|
||||
marginRight: '1rem'
|
||||
},
|
||||
text: {
|
||||
marginBottom: '0.5rem'
|
||||
},
|
||||
image: {
|
||||
flex: 1,
|
||||
height: 50,
|
||||
resizeMode: 'contain'
|
||||
}
|
||||
});
|
||||
|
||||
export default ImageSourceExample;
|
||||
@@ -1,28 +0,0 @@
|
||||
import placeholder from './bunny.png';
|
||||
import staticImage from './uie_thumb_normal@2x.png';
|
||||
|
||||
const dataPng =
|
||||
'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAEsAAABLCAQAAACSR7JhAAADtUlEQVR4Ac3YA2Bj6QLH0XPT1Fzbtm29tW3btm3bfLZtv7e2ObZnms7d8Uw098tuetPzrxv8wiISrtVudrG2JXQZ4VOv+qUfmqCGGl1mqLhoA52oZlb0mrjsnhKpgeUNEs91Z0pd1kvihA3ULGVHiQO2narKSHKkEMulm9VgUyE60s1aWoMQUbpZOWE+kaqs4eLEjdIlZTcFZB0ndc1+lhB1lZrIuk5P2aib1NBpZaL+JaOGIt0ls47SKzLC7CqrlGF6RZ09HGoNy1lYl2aRSWL5GuzqWU1KafRdoRp0iOQEiDzgZPnG6DbldcomadViflnl/cL93tOoVbsOLVM2jylvdWjXolWX1hmfZbGR/wjypDjFLSZIRov09BgYmtUqPQPlQrPapecLgTIy0jMgPKtTeob2zWtrGH3xvjUkPCtNg/tm1rjwrMa+mdUkPd3hWbH0jArPGiU9ufCsNNWFZ40wpwn+62/66R2RUtoso1OB34tnLOcy7YB1fUdc9e0q3yru8PGM773vXsuZ5YIZX+5xmHwHGVvlrGPN6ZSiP1smOsMMde40wKv2VmwPPVXNut4sVpUreZiLBHi0qln/VQeI/LTMYXpsJtFiclUN+5HVZazim+Ky+7sAvxWnvjXrJFneVtLWLyPJu9K3cXLWeOlbMTlrIelbMDlrLenrjEQOtIF+fuI9xRp9ZBFp6+b6WT8RrxEpdK64BuvHgDk+vUy+b5hYk6zfyfs051gRoNO1usU12WWRWL73/MMEy9pMi9qIrR4ZpV16Rrvduxazmy1FSvuFXRkqTnE7m2kdb5U8xGjLw/spRr1uTov4uOgQE+0N/DvFrG/Jt7i/FzwxbA9kDanhf2w+t4V97G8lrT7wc08aA2QNUkuTfW/KimT01wdlfK4yEw030VfT0RtZbzjeMprNq8m8tnSTASrTLti64oBNdpmMQm0eEwvfPwRbUBywG5TzjPCsdwk3IeAXjQblLCoXnDVeoAz6SfJNk5TTzytCNZk/POtTSV40NwOFWzw86wNJRpubpXsn60NJFlHeqlYRbslqZm2jnEZ3qcSKgm0kTli3zZVS7y/iivZTweYXJ26Y+RTbV1zh3hYkgyFGSTKPfRVbRqWWVReaxYeSLarYv1Qqsmh1s95S7G+eEWK0f3jYKTbV6bOwepjfhtafsvUsqrQvrGC8YhmnO9cSCk3yuY984F1vesdHYhWJ5FvASlacshUsajFt2mUM9pqzvKGcyNJW0arTKN1GGGzQlH0tXwLDgQTurS8eIQAAAABJRU5ErkJggg==';
|
||||
const dataSvg =
|
||||
'data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 841.9 595.3"><g fill="#61DAFB"><path d="M666.3 296.5c0-32.5-40.7-63.3-103.1-82.4 14.4-63.6 8-114.2-20.2-130.4-6.5-3.8-14.1-5.6-22.4-5.6v22.3c4.6 0 8.3.9 11.4 2.6 13.6 7.8 19.5 37.5 14.9 75.7-1.1 9.4-2.9 19.3-5.1 29.4-19.6-4.8-41-8.5-63.5-10.9-13.5-18.5-27.5-35.3-41.6-50 32.6-30.3 63.2-46.9 84-46.9V78c-27.5 0-63.5 19.6-99.9 53.6-36.4-33.8-72.4-53.2-99.9-53.2v22.3c20.7 0 51.4 16.5 84 46.6-14 14.7-28 31.4-41.3 49.9-22.6 2.4-44 6.1-63.6 11-2.3-10-4-19.7-5.2-29-4.7-38.2 1.1-67.9 14.6-75.8 3-1.8 6.9-2.6 11.5-2.6V78.5c-8.4 0-16 1.8-22.6 5.6-28.1 16.2-34.4 66.7-19.9 130.1-62.2 19.2-102.7 49.9-102.7 82.3 0 32.5 40.7 63.3 103.1 82.4-14.4 63.6-8 114.2 20.2 130.4 6.5 3.8 14.1 5.6 22.5 5.6 27.5 0 63.5-19.6 99.9-53.6 36.4 33.8 72.4 53.2 99.9 53.2 8.4 0 16-1.8 22.6-5.6 28.1-16.2 34.4-66.7 19.9-130.1 62-19.1 102.5-49.9 102.5-82.3zm-130.2-66.7c-3.7 12.9-8.3 26.2-13.5 39.5-4.1-8-8.4-16-13.1-24-4.6-8-9.5-15.8-14.4-23.4 14.2 2.1 27.9 4.7 41 7.9zm-45.8 106.5c-7.8 13.5-15.8 26.3-24.1 38.2-14.9 1.3-30 2-45.2 2-15.1 0-30.2-.7-45-1.9-8.3-11.9-16.4-24.6-24.2-38-7.6-13.1-14.5-26.4-20.8-39.8 6.2-13.4 13.2-26.8 20.7-39.9 7.8-13.5 15.8-26.3 24.1-38.2 14.9-1.3 30-2 45.2-2 15.1 0 30.2.7 45 1.9 8.3 11.9 16.4 24.6 24.2 38 7.6 13.1 14.5 26.4 20.8 39.8-6.3 13.4-13.2 26.8-20.7 39.9zm32.3-13c5.4 13.4 10 26.8 13.8 39.8-13.1 3.2-26.9 5.9-41.2 8 4.9-7.7 9.8-15.6 14.4-23.7 4.6-8 8.9-16.1 13-24.1zM421.2 430c-9.3-9.6-18.6-20.3-27.8-32 9 .4 18.2.7 27.5.7 9.4 0 18.7-.2 27.8-.7-9 11.7-18.3 22.4-27.5 32zm-74.4-58.9c-14.2-2.1-27.9-4.7-41-7.9 3.7-12.9 8.3-26.2 13.5-39.5 4.1 8 8.4 16 13.1 24 4.7 8 9.5 15.8 14.4 23.4zM420.7 163c9.3 9.6 18.6 20.3 27.8 32-9-.4-18.2-.7-27.5-.7-9.4 0-18.7.2-27.8.7 9-11.7 18.3-22.4 27.5-32zm-74 58.9c-4.9 7.7-9.8 15.6-14.4 23.7-4.6 8-8.9 16-13 24-5.4-13.4-10-26.8-13.8-39.8 13.1-3.1 26.9-5.8 41.2-7.9zm-90.5 125.2c-35.4-15.1-58.3-34.9-58.3-50.6 0-15.7 22.9-35.6 58.3-50.6 8.6-3.7 18-7 27.7-10.1 5.7 19.6 13.2 40 22.5 60.9-9.2 20.8-16.6 41.1-22.2 60.6-9.9-3.1-19.3-6.5-28-10.2zM310 490c-13.6-7.8-19.5-37.5-14.9-75.7 1.1-9.4 2.9-19.3 5.1-29.4 19.6 4.8 41 8.5 63.5 10.9 13.5 18.5 27.5 35.3 41.6 50-32.6 30.3-63.2 46.9-84 46.9-4.5-.1-8.3-1-11.3-2.7zm237.2-76.2c4.7 38.2-1.1 67.9-14.6 75.8-3 1.8-6.9 2.6-11.5 2.6-20.7 0-51.4-16.5-84-46.6 14-14.7 28-31.4 41.3-49.9 22.6-2.4 44-6.1 63.6-11 2.3 10.1 4.1 19.8 5.2 29.1zm38.5-66.7c-8.6 3.7-18 7-27.7 10.1-5.7-19.6-13.2-40-22.5-60.9 9.2-20.8 16.6-41.1 22.2-60.6 9.9 3.1 19.3 6.5 28.1 10.2 35.4 15.1 58.3 34.9 58.3 50.6-.1 15.7-23 35.6-58.4 50.6zM320.8 78.4z"/><circle cx="420.9" cy="296.5" r="45.7"/><path d="M520.5 78.1z"/></g></svg>';
|
||||
|
||||
const sources = {
|
||||
animatedGif: {
|
||||
uri:
|
||||
'http://38.media.tumblr.com/9e9bd08c6e2d10561dd1fb4197df4c4e/tumblr_mfqekpMktw1rn90umo1_500.gif'
|
||||
},
|
||||
broken: { uri: 'http://TYPO_ERROR.github.io/image.png' },
|
||||
small: { uri: 'http://facebook.github.io/react/img/logo_small_2x.png' },
|
||||
large: { uri: 'http://facebook.github.io/react/img/logo_og.png' },
|
||||
largeAlt: { uri: 'http://facebook.github.io/origami/public/images/birds.jpg' },
|
||||
placeholder,
|
||||
prefetchable: { uri: 'http://origami.design/public/images/bird-logo.png' },
|
||||
static: staticImage,
|
||||
huge: {
|
||||
uri: 'https://upload.wikimedia.org/wikipedia/commons/d/d7/Chestnut-mandibled_Toucan.jpg'
|
||||
},
|
||||
dataPng,
|
||||
dataSvg
|
||||
};
|
||||
|
||||
export default sources;
|
||||
@@ -1,89 +0,0 @@
|
||||
/* eslint-disable react/jsx-sort-props */
|
||||
|
||||
/**
|
||||
* @flow
|
||||
*/
|
||||
|
||||
import CustomStyleOverrides from './examples/CustomStyleOverrides';
|
||||
import React from 'react';
|
||||
import { storiesOf } from '@kadira/storybook';
|
||||
import { TouchableHighlightDisabled } from './examples/PropDisabled';
|
||||
import UIExplorer, { AppText, DocItem } from '../../ui-explorer';
|
||||
|
||||
const sections = [
|
||||
{
|
||||
title: 'Props',
|
||||
entries: [
|
||||
<DocItem name="...TouchableWithoutFeedback props" />,
|
||||
|
||||
<DocItem
|
||||
name="activeOpacity"
|
||||
typeInfo="?number = 0.85"
|
||||
description="Determines what the opacity of the wrapped view should be when touch is active."
|
||||
/>,
|
||||
|
||||
<DocItem
|
||||
name="onHideUnderlay"
|
||||
typeInfo="?function"
|
||||
description="Called immediately after the underlay is hidden."
|
||||
/>,
|
||||
|
||||
<DocItem
|
||||
name="onShowUnderlay"
|
||||
typeInfo="?function"
|
||||
description="Called immediately after the underlay is shown"
|
||||
/>,
|
||||
|
||||
<DocItem
|
||||
name="underlayColor"
|
||||
typeInfo="?color = black"
|
||||
description="The color of the underlay that will show through when the touch is active."
|
||||
/>
|
||||
]
|
||||
},
|
||||
{
|
||||
title: 'More examples',
|
||||
entries: [
|
||||
<DocItem
|
||||
description="Disabled TouchableHighlight"
|
||||
example={{
|
||||
code: '',
|
||||
render: () => <TouchableHighlightDisabled />
|
||||
}}
|
||||
/>,
|
||||
|
||||
<DocItem
|
||||
description="Custom style overrides"
|
||||
example={{
|
||||
code: '',
|
||||
render: () => <CustomStyleOverrides />
|
||||
}}
|
||||
/>
|
||||
]
|
||||
}
|
||||
];
|
||||
|
||||
storiesOf('Components', module).add('TouchableHighlight', () =>
|
||||
<UIExplorer
|
||||
description={[
|
||||
<AppText>
|
||||
A wrapper for making views respond properly to touches. On press down, the
|
||||
opacity of the wrapped view is decreased, which allows the underlay color to
|
||||
show through, darkening or tinting the view.
|
||||
</AppText>,
|
||||
<AppText>
|
||||
The underlay comes from wrapping the child in a new View, which can affect
|
||||
layout, and sometimes cause unwanted visual artifacts if not used correctly,
|
||||
for example if the backgroundColor of the wrapped view isn't explicitly set to
|
||||
an opaque color.
|
||||
</AppText>,
|
||||
<AppText>
|
||||
TouchableHighlight must have one child (not zero or more than one). If you wish
|
||||
to have several child components, wrap them in a View.
|
||||
</AppText>
|
||||
]}
|
||||
sections={sections}
|
||||
title="TouchableHighlight"
|
||||
url="components/Touchable"
|
||||
/>
|
||||
);
|
||||
@@ -1,246 +0,0 @@
|
||||
/**
|
||||
* @flow
|
||||
*/
|
||||
|
||||
/*
|
||||
import React from 'react';
|
||||
import UIExplorer, { PropText } from '../../ui-explorer';
|
||||
import { action, storiesOf } from '@kadira/storybook';
|
||||
import {
|
||||
Image,
|
||||
StyleSheet,
|
||||
Text,
|
||||
TouchableHighlight,
|
||||
TouchableOpacity,
|
||||
Platform,
|
||||
TouchableNativeFeedback,
|
||||
View
|
||||
} from 'react-native';
|
||||
|
||||
class TouchableFeedbackEvents extends React.Component {
|
||||
constructor(props) {
|
||||
super(props);
|
||||
this.state = { eventLog: [] };
|
||||
}
|
||||
|
||||
render() {
|
||||
return (
|
||||
<View testID="touchable_feedback_events">
|
||||
<View style={[styles.row, { justifyContent: 'center' }]}>
|
||||
<TouchableOpacity
|
||||
accessibilityComponentType="button"
|
||||
accessibilityLabel="touchable feedback events"
|
||||
accessibilityTraits="button"
|
||||
onLongPress={this._createPressHandler('longPress')}
|
||||
onPress={this._createPressHandler('press')}
|
||||
onPressIn={this._createPressHandler('pressIn')}
|
||||
onPressOut={this._createPressHandler('pressOut')}
|
||||
style={styles.wrapper}
|
||||
testID="touchable_feedback_events_button"
|
||||
>
|
||||
<Text style={styles.button}>
|
||||
Press Me
|
||||
</Text>
|
||||
</TouchableOpacity>
|
||||
</View>
|
||||
<View style={styles.eventLogBox} testID="touchable_feedback_events_console">
|
||||
{this.state.eventLog.map((e, ii) => <Text key={ii}>{e}</Text>)}
|
||||
</View>
|
||||
</View>
|
||||
);
|
||||
}
|
||||
|
||||
_createPressHandler = eventName => {
|
||||
return () => {
|
||||
const limit = 6;
|
||||
const eventLog = this.state.eventLog.slice(0, limit - 1);
|
||||
eventLog.unshift(eventName);
|
||||
this.setState({ eventLog });
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
class TouchableDelayEvents extends React.Component {
|
||||
constructor(props) {
|
||||
super(props);
|
||||
this.state = { eventLog: [] };
|
||||
}
|
||||
|
||||
render() {
|
||||
return (
|
||||
<View testID="touchable_delay_events">
|
||||
<View style={[styles.row, { justifyContent: 'center' }]}>
|
||||
<TouchableOpacity
|
||||
delayLongPress={800}
|
||||
delayPressIn={400}
|
||||
delayPressOut={1000}
|
||||
onLongPress={this._createPressHandler('longPress - 800ms delay')}
|
||||
onPress={this._createPressHandler('press')}
|
||||
onPressIn={this._createPressHandler('pressIn - 400ms delay')}
|
||||
onPressOut={this._createPressHandler('pressOut - 1000ms delay')}
|
||||
style={styles.wrapper}
|
||||
testID="touchable_delay_events_button"
|
||||
>
|
||||
<Text style={styles.button}>
|
||||
Press Me
|
||||
</Text>
|
||||
</TouchableOpacity>
|
||||
</View>
|
||||
<View style={styles.eventLogBox} testID="touchable_delay_events_console">
|
||||
{this.state.eventLog.map((e, ii) => <Text key={ii}>{e}</Text>)}
|
||||
</View>
|
||||
</View>
|
||||
);
|
||||
}
|
||||
|
||||
_createPressHandler = eventName => {
|
||||
return () => {
|
||||
const limit = 6;
|
||||
const eventLog = this.state.eventLog.slice(0, limit - 1);
|
||||
eventLog.unshift(eventName);
|
||||
this.setState({ eventLog });
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
const heartImage = { uri: 'https://pbs.twimg.com/media/BlXBfT3CQAA6cVZ.png:small' };
|
||||
|
||||
const styles = StyleSheet.create({
|
||||
row: {
|
||||
justifyContent: 'center',
|
||||
flexDirection: 'row'
|
||||
},
|
||||
icon: {
|
||||
width: 24,
|
||||
height: 24
|
||||
},
|
||||
image: {
|
||||
width: 50,
|
||||
height: 50
|
||||
},
|
||||
text: {
|
||||
fontSize: 16
|
||||
},
|
||||
block: {
|
||||
padding: 10
|
||||
},
|
||||
button: {
|
||||
color: '#007AFF'
|
||||
},
|
||||
disabledButton: {
|
||||
color: '#007AFF',
|
||||
opacity: 0.5
|
||||
},
|
||||
nativeFeedbackButton: {
|
||||
textAlign: 'center',
|
||||
margin: 10
|
||||
},
|
||||
hitSlopButton: {
|
||||
color: 'white'
|
||||
},
|
||||
wrapper: {
|
||||
borderRadius: 8
|
||||
},
|
||||
wrapperCustom: {
|
||||
borderRadius: 8,
|
||||
padding: 6
|
||||
},
|
||||
hitSlopWrapper: {
|
||||
backgroundColor: 'red',
|
||||
marginVertical: 30
|
||||
},
|
||||
logBox: {
|
||||
padding: 20,
|
||||
margin: 10,
|
||||
borderWidth: StyleSheet.hairlineWidth,
|
||||
borderColor: '#f0f0f0',
|
||||
backgroundColor: '#f9f9f9'
|
||||
},
|
||||
eventLogBox: {
|
||||
padding: 10,
|
||||
margin: 10,
|
||||
height: 120,
|
||||
borderWidth: StyleSheet.hairlineWidth,
|
||||
borderColor: '#f0f0f0',
|
||||
backgroundColor: '#f9f9f9'
|
||||
},
|
||||
forceTouchBox: {
|
||||
padding: 10,
|
||||
margin: 10,
|
||||
borderWidth: StyleSheet.hairlineWidth,
|
||||
borderColor: '#f0f0f0',
|
||||
backgroundColor: '#f9f9f9',
|
||||
alignItems: 'center'
|
||||
},
|
||||
textBlock: {
|
||||
fontWeight: '500',
|
||||
color: 'blue'
|
||||
}
|
||||
});
|
||||
|
||||
const examples = [
|
||||
{
|
||||
title: '<TouchableHighlight>',
|
||||
description:
|
||||
'TouchableHighlight works by adding an extra view with a ' +
|
||||
'black background under the single child view. This works best when the ' +
|
||||
'child view is fully opaque, although it can be made to work as a simple ' +
|
||||
'background color change as well with the activeOpacity and ' +
|
||||
'underlayColor props.',
|
||||
render() {
|
||||
return (
|
||||
<View>
|
||||
<View style={styles.row}>
|
||||
<TouchableHighlight
|
||||
onPress={() => console.log('stock THW image - highlight')}
|
||||
style={styles.wrapper}
|
||||
>
|
||||
<Image source={heartImage} style={styles.image} />
|
||||
</TouchableHighlight>
|
||||
<TouchableHighlight
|
||||
activeOpacity={1}
|
||||
onPress={() => console.log('custom THW text - highlight')}
|
||||
style={styles.wrapper}
|
||||
underlayColor="rgb(210, 230, 255)"
|
||||
>
|
||||
<View style={styles.wrapperCustom}>
|
||||
<Text style={styles.text}>
|
||||
Tap Here For Custom Highlight!
|
||||
</Text>
|
||||
</View>
|
||||
</TouchableHighlight>
|
||||
</View>
|
||||
</View>
|
||||
);
|
||||
}
|
||||
},
|
||||
{
|
||||
title: 'Touchable feedback events',
|
||||
description:
|
||||
'<Touchable*> components accept onPress, onPressIn, ' +
|
||||
'onPressOut, and onLongPress as props.',
|
||||
render() {
|
||||
return <TouchableFeedbackEvents />;
|
||||
}
|
||||
},
|
||||
{
|
||||
title: 'Touchable delay for events',
|
||||
description:
|
||||
'<Touchable*> components also accept delayPressIn, ' +
|
||||
'delayPressOut, and delayLongPress as props. These props impact the ' +
|
||||
'timing of feedback events.',
|
||||
render() {
|
||||
return <TouchableDelayEvents />;
|
||||
}
|
||||
},
|
||||
{
|
||||
title: 'Disabled Touchable*',
|
||||
description:
|
||||
'<Touchable*> components accept disabled prop which prevents ' +
|
||||
'any interaction with component',
|
||||
render() {
|
||||
return <TouchableDisabled />;
|
||||
}
|
||||
}
|
||||
];
|
||||
*/
|
||||
@@ -1,25 +0,0 @@
|
||||
/**
|
||||
* @flow
|
||||
*/
|
||||
|
||||
import { logger } from '../helpers';
|
||||
import React from 'react';
|
||||
import { Text, TouchableHighlight, View } from 'react-native';
|
||||
|
||||
const ViewStyleExample = () =>
|
||||
<View pointerEvents="box-none">
|
||||
<View pointerEvents="box-none">
|
||||
<View pointerEvents="none"><Text onPress={logger}>none</Text></View>
|
||||
<TouchableHighlight onPress={logger} pointerEvents="auto">
|
||||
<Text>auto</Text>
|
||||
</TouchableHighlight>
|
||||
<TouchableHighlight onPress={logger} pointerEvents="box-only">
|
||||
<Text>box-only</Text>
|
||||
</TouchableHighlight>
|
||||
<TouchableHighlight onPress={logger} pointerEvents="box-none">
|
||||
<Text>box-none</Text>
|
||||
</TouchableHighlight>
|
||||
</View>
|
||||
</View>;
|
||||
|
||||
export default ViewStyleExample;
|
||||
@@ -1,5 +0,0 @@
|
||||
import React from 'react';
|
||||
import { storiesOf } from '@kadira/storybook';
|
||||
import Game2048 from './Game2048';
|
||||
|
||||
storiesOf('Example apps', module).add('Game2048', () => <Game2048 />);
|
||||
@@ -1,5 +0,0 @@
|
||||
import React from 'react';
|
||||
import { storiesOf } from '@kadira/storybook';
|
||||
import TicTacToe from './TicTacToe';
|
||||
|
||||
storiesOf('Example apps', module).add('TicTacToe', () => <TicTacToe />);
|
||||
@@ -1,31 +0,0 @@
|
||||
/* eslint-disable react/prop-types */
|
||||
|
||||
/**
|
||||
* @flow
|
||||
*/
|
||||
|
||||
import React from 'react';
|
||||
import { StyleSheet, Text } from 'react-native';
|
||||
|
||||
const AppText = ({ style, ...rest }) =>
|
||||
<Text
|
||||
{...rest}
|
||||
accessibilityRole={rest.href ? 'link' : null}
|
||||
style={[styles.baseText, style, rest.href && styles.link]}
|
||||
/>;
|
||||
|
||||
export default AppText;
|
||||
|
||||
const styles = StyleSheet.create({
|
||||
baseText: {
|
||||
fontFamily:
|
||||
'-apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Ubuntu, "Helvetica Neue", sans-serif, ' +
|
||||
'"Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol"', // emoji fonts
|
||||
lineHeight: '1.3125em'
|
||||
},
|
||||
link: {
|
||||
color: '#1B95E0',
|
||||
marginTop: 'calc(0.5 * 1.3125rem)',
|
||||
textDecorationLine: 'underline'
|
||||
}
|
||||
});
|
||||
@@ -1,16 +0,0 @@
|
||||
/**
|
||||
* @flow
|
||||
*/
|
||||
|
||||
import { createDOMElement, StyleSheet } from 'react-native';
|
||||
|
||||
const Code = props => createDOMElement('code', { ...props, style: [styles.code, props.style] });
|
||||
|
||||
export default Code;
|
||||
|
||||
const styles = StyleSheet.create({
|
||||
code: {
|
||||
fontFamily: 'monospace, monospace',
|
||||
lineHeight: '1.3125em'
|
||||
}
|
||||
});
|
||||
@@ -1,82 +0,0 @@
|
||||
/* eslint-disable react/prop-types */
|
||||
|
||||
/**
|
||||
* @flow
|
||||
*/
|
||||
|
||||
import AppText from './AppText';
|
||||
import React from 'react';
|
||||
import { StyleSheet, View } from 'react-native';
|
||||
|
||||
const Title = ({ children }) => <AppText style={styles.title}>{children}</AppText>;
|
||||
const Description = ({ children }) => <AppText style={styles.description}>{children}</AppText>;
|
||||
const SectionTitle = ({ children }) => <AppText style={styles.sectionTitle}>{children}</AppText>;
|
||||
|
||||
const insertBetween = (item, array) =>
|
||||
array.reduce((acc, curr, i, { length }) => {
|
||||
if (i && i < length) {
|
||||
return [...acc, item, curr];
|
||||
}
|
||||
return [...acc, curr];
|
||||
}, []);
|
||||
|
||||
const Divider = () => <View style={styles.divider} />;
|
||||
|
||||
const SourceLink = ({ uri }) =>
|
||||
<AppText
|
||||
accessibilityRole="link"
|
||||
href={`https://github.com/necolas/react-native-web/tree/master/docs/storybook/${uri}`}
|
||||
style={styles.link}
|
||||
target="_blank"
|
||||
>
|
||||
View source code on GitHub
|
||||
</AppText>;
|
||||
|
||||
const UIExplorer = ({ description, sections, title, url }) =>
|
||||
<View style={styles.root}>
|
||||
<Title>{title}</Title>
|
||||
{description &&
|
||||
<Description>
|
||||
{Array.isArray(description) ? insertBetween(<Divider />, description) : description}
|
||||
</Description>}
|
||||
{sections.map(({ entries, title }, i) =>
|
||||
<View key={i}>
|
||||
<SectionTitle>{title}</SectionTitle>
|
||||
{entries}
|
||||
</View>
|
||||
)}
|
||||
{url && <SourceLink uri={url} />}
|
||||
</View>;
|
||||
|
||||
const styles = StyleSheet.create({
|
||||
root: {
|
||||
padding: '1rem',
|
||||
flex: 1
|
||||
},
|
||||
divider: {
|
||||
height: '1.3125rem'
|
||||
},
|
||||
title: {
|
||||
fontSize: '2rem'
|
||||
},
|
||||
sectionTitle: {
|
||||
fontSize: '1.3125rem',
|
||||
marginBottom: '1.3125rem',
|
||||
fontWeight: 'bold'
|
||||
},
|
||||
description: {
|
||||
color: '#666',
|
||||
display: 'flex',
|
||||
flexDirection: 'column',
|
||||
fontSize: '1.25rem',
|
||||
marginTop: 'calc(0.5 * 1.3125rem)',
|
||||
marginBottom: 'calc(1.5 * 1.3125rem)'
|
||||
},
|
||||
link: {
|
||||
color: '#1B95E0',
|
||||
marginTop: 'calc(0.5 * 1.3125rem)',
|
||||
textDecorationLine: 'underline'
|
||||
}
|
||||
});
|
||||
|
||||
export default UIExplorer;
|
||||
@@ -1,13 +0,0 @@
|
||||
/**
|
||||
* @flow
|
||||
*/
|
||||
|
||||
import AppText from './AppText';
|
||||
import Code from './Code';
|
||||
import DocItem from './DocItem';
|
||||
import StyleList from './StyleList';
|
||||
import TextList from './TextList';
|
||||
import UIExplorer from './UIExplorer';
|
||||
|
||||
export default UIExplorer;
|
||||
export { AppText, Code, DocItem, StyleList, TextList };
|
||||
181
package.json
181
package.json
@@ -1,117 +1,84 @@
|
||||
{
|
||||
"name": "react-native-web",
|
||||
"version": "0.0.108",
|
||||
"description": "React Native for Web",
|
||||
"main": "dist/index.js",
|
||||
"files": [
|
||||
"dist",
|
||||
"src",
|
||||
"!**/__tests__"
|
||||
],
|
||||
"private": true,
|
||||
"version": "0.9.13",
|
||||
"name": "react-native-web-monorepo",
|
||||
"scripts": {
|
||||
"benchmarks": "cd benchmarks && yarn && webpack && open index.html",
|
||||
"build": "webpack --config webpack.config.js --sort-assets-by --progress",
|
||||
"compile": "del ./dist && mkdir dist && babel src -d dist --ignore **/__tests__",
|
||||
"docs:build": "build-storybook -o ./docs/dist -c ./docs/storybook/.storybook",
|
||||
"docs:start": "start-storybook -p 9001 -c ./docs/storybook/.storybook --dont-track",
|
||||
"docs:publish": "yarn docs:build && git checkout gh-pages && rm -rf ./storybook && mv docs/dist storybook && git add -A && git commit -m \"Storybook deploy\" && git push origin gh-pages && git checkout -",
|
||||
"clean": "del ./packages/*/dist",
|
||||
"compile": "npm-run-all clean -p \"compile:* -- {@}\" --",
|
||||
"compile:commonjs": "cd packages/react-native-web && BABEL_ENV=commonjs babel src --out-dir dist/cjs --ignore \"**/__tests__\"",
|
||||
"compile:es": "cd packages/react-native-web && babel src --out-dir dist --ignore \"**/__tests__\"",
|
||||
"benchmarks": "cd packages/benchmarks && yarn build",
|
||||
"benchmarks:release": "cd packages/benchmarks && yarn release",
|
||||
"examples": "cd packages/examples && yarn build",
|
||||
"examples:release": "cd packages/examples && yarn release",
|
||||
"website": "cd packages/website && yarn start",
|
||||
"website:release": "cd packages/website && yarn release",
|
||||
"flow": "flow",
|
||||
"fmt": "find benchmarks docs src -name '*.js' | grep -v -E '(node_modules|dist)' | xargs yarn fmt:cmd",
|
||||
"fmt:cmd": "prettier --print-width=100 --single-quote --write",
|
||||
"jest": "jest",
|
||||
"jest:watch": "yarn test -- --watch",
|
||||
"lint": "yarn lint:cmd -- benchmarks docs src",
|
||||
"lint:cmd": "eslint --fix --ignore-path .gitignore",
|
||||
"fmt": "prettier --write \"**/*.js\"",
|
||||
"jest": "BABEL_ENV=commonjs jest --config ./scripts/jest/config.js",
|
||||
"lint": "yarn lint:check --fix",
|
||||
"lint:check": "eslint packages scripts",
|
||||
"precommit": "lint-staged",
|
||||
"release": "yarn lint && yarn test && yarn compile && yarn build && npm publish",
|
||||
"test": "flow && jest"
|
||||
},
|
||||
"babel": {
|
||||
"presets": [
|
||||
"react-native"
|
||||
],
|
||||
"plugins": [
|
||||
[
|
||||
"transform-react-remove-prop-types",
|
||||
{
|
||||
"mode": "wrap"
|
||||
}
|
||||
]
|
||||
]
|
||||
},
|
||||
"jest": {
|
||||
"testEnvironment": "jsdom",
|
||||
"timers": "fake",
|
||||
"snapshotSerializers": [
|
||||
"<rootDir>/node_modules/enzyme-to-json/serializer"
|
||||
]
|
||||
},
|
||||
"lint-staged": {
|
||||
"**/*.js": [
|
||||
"fmt:cmd",
|
||||
"git update-index --again",
|
||||
"lint:cmd"
|
||||
]
|
||||
},
|
||||
"dependencies": {
|
||||
"animated": "^0.2.0",
|
||||
"array-find-index": "^1.0.2",
|
||||
"babel-runtime": "^6.23.0",
|
||||
"create-react-class": "^15.6.0",
|
||||
"debounce": "1.0.2",
|
||||
"deep-assign": "^2.0.0",
|
||||
"fbjs": "^0.8.12",
|
||||
"hyphenate-style-name": "^1.0.2",
|
||||
"inline-style-prefixer": "^3.0.6",
|
||||
"normalize-css-color": "^1.0.2",
|
||||
"prop-types": "^15.5.10",
|
||||
"react-timer-mixin": "^0.13.3"
|
||||
"prerelease": "yarn test && yarn compile && yarn compile:commonjs",
|
||||
"release": "node ./scripts/release/publish.js",
|
||||
"postrelease": "yarn benchmarks:release && yarn examples:release && yarn website:release",
|
||||
"test": "yarn flow && yarn lint:check && yarn jest --runInBand"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@kadira/storybook": "^2.35.3",
|
||||
"@kadira/storybook-addon-options": "^1.0.2",
|
||||
"babel-cli": "^6.24.1",
|
||||
"babel-core": "^6.25.0",
|
||||
"babel-eslint": "^7.2.3",
|
||||
"babel-loader": "^7.1.0",
|
||||
"babel-plugin-transform-react-remove-prop-types": "^0.4.6",
|
||||
"babel-preset-react-native": "^2.0.0",
|
||||
"del-cli": "^1.0.0",
|
||||
"enzyme": "^2.8.2",
|
||||
"enzyme-to-json": "^1.5.1",
|
||||
"eslint": "^4.0.0",
|
||||
"eslint-config-prettier": "^2.2.0",
|
||||
"eslint-plugin-promise": "^3.5.0",
|
||||
"eslint-plugin-react": "^7.1.0",
|
||||
"file-loader": "^0.11.2",
|
||||
"flow-bin": "^0.48.0",
|
||||
"jest": "^20.0.4",
|
||||
"lint-staged": "^4.0.0",
|
||||
"prettier": "^1.4.4",
|
||||
"react": "^15.6.1",
|
||||
"react-dom": "^15.6.1",
|
||||
"react-test-renderer": "^15.6.1",
|
||||
"url-loader": "^0.5.9",
|
||||
"webpack": "^3.0.0",
|
||||
"webpack-bundle-analyzer": "^2.8.2"
|
||||
"babel-cli": "^6.26.0",
|
||||
"babel-core": "^6.26.0",
|
||||
"babel-eslint": "^8.2.3",
|
||||
"babel-loader": "^7.1.2",
|
||||
"babel-plugin-add-module-exports": "^0.2.1",
|
||||
"babel-plugin-transform-class-properties": "^6.24.1",
|
||||
"babel-plugin-transform-object-rest-spread": "^6.26.0",
|
||||
"babel-plugin-transform-react-remove-prop-types": "^0.4.10",
|
||||
"babel-preset-env": "^1.6.1",
|
||||
"babel-preset-flow": "^6.23.0",
|
||||
"babel-preset-react": "^6.24.1",
|
||||
"babel-preset-react-native": "^4.0.0",
|
||||
"caniuse-api": "^2.0.0",
|
||||
"del-cli": "^1.1.0",
|
||||
"enzyme": "^3.6.0",
|
||||
"enzyme-adapter-react-16": "^1.5.0",
|
||||
"enzyme-to-json": "^3.3.3",
|
||||
"eslint": "^4.19.1",
|
||||
"eslint-config-prettier": "^2.9.0",
|
||||
"eslint-plugin-promise": "^3.7.0",
|
||||
"eslint-plugin-react": "^7.7.0",
|
||||
"flow-bin": "^0.63.1",
|
||||
"glob": "^7.1.2",
|
||||
"husky": "^0.14.3",
|
||||
"inline-style-prefixer": "^5.0.3",
|
||||
"jest": "^22.4.3",
|
||||
"jest-canvas-mock": "^1.0.2",
|
||||
"lint-staged": "^7.1.0",
|
||||
"npm-run-all": "^4.1.3",
|
||||
"prettier": "^1.12.1",
|
||||
"react": "^16.7.0",
|
||||
"react-art": "^16.7.0",
|
||||
"react-dom": "^16.7.0",
|
||||
"react-test-renderer": "^16.7.0"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"react": "15.4.x || 15.5.x || 15.6.x",
|
||||
"react-dom": "15.4.x || 15.5.x || 15.6.x"
|
||||
"workspaces": [
|
||||
"packages/*"
|
||||
],
|
||||
"lint-staged": {
|
||||
"packages/react-native-web/src/index.js": [
|
||||
"node ./scripts/babel/createModuleMap.js",
|
||||
"prettier --write ./packages/babel-plugin-react-native-web/src/moduleMap.js",
|
||||
"git add ./packages/babel-plugin-react-native-web/src/moduleMap.js"
|
||||
],
|
||||
"**/*.js": [
|
||||
"prettier --write",
|
||||
"git update-index --again",
|
||||
"eslint"
|
||||
]
|
||||
},
|
||||
"prettier": {
|
||||
"printWidth": 100,
|
||||
"singleQuote": true
|
||||
},
|
||||
"author": "Nicolas Gallagher",
|
||||
"license": "BSD-3-Clause",
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "git://github.com/necolas/react-native-web.git"
|
||||
},
|
||||
"tags": [
|
||||
"react"
|
||||
],
|
||||
"keywords": [
|
||||
"react",
|
||||
"react-component",
|
||||
"react-native",
|
||||
"web"
|
||||
]
|
||||
"license": "MIT"
|
||||
}
|
||||
|
||||
52
packages/babel-plugin-react-native-web/README.md
Normal file
52
packages/babel-plugin-react-native-web/README.md
Normal file
@@ -0,0 +1,52 @@
|
||||
# babel-plugin-react-native-web
|
||||
|
||||
[![npm version][package-badge]][package-url] [](https://reactjs.org/docs/how-to-contribute.html#your-first-pull-request)
|
||||
|
||||
A Babel plugin that will alias `react-native` to `react-native-web` and exclude
|
||||
any modules not required by your app (keeping bundle size down).
|
||||
|
||||
## Installation
|
||||
|
||||
```
|
||||
yarn add --dev babel-plugin-react-native-web
|
||||
```
|
||||
|
||||
## Usage
|
||||
|
||||
**.babelrc**
|
||||
|
||||
```
|
||||
{
|
||||
"plugins": [
|
||||
["react-native-web", { commonjs: true }]
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
You should configure the plugin to match the module format used by your
|
||||
bundler. Most modern bundlers will use a package's ES modules by default (i.e.,
|
||||
if `package.json` has a `module` field). But if you need the plugin to rewrite
|
||||
import paths to point to CommonJS modules, you must set the `commonjs` option
|
||||
to `true`.
|
||||
|
||||
## Example
|
||||
|
||||
NOTE: `react-native-web` internal paths are _not stable_ and you must not rely
|
||||
on them. Always use the Babel plugin to optimize your build. What follows is an
|
||||
example of the rewrite performed by the plugin.
|
||||
|
||||
**Before**
|
||||
|
||||
```js
|
||||
import { StyleSheet, View } from 'react-native';
|
||||
```
|
||||
|
||||
**After**
|
||||
|
||||
```js
|
||||
import StyleSheet from 'react-native-web/dist/exports/StyleSheet';
|
||||
import View from 'react-native-web/dist/exports/View';
|
||||
```
|
||||
|
||||
[package-badge]: https://img.shields.io/npm/v/babel-plugin-react-native-web.svg?style=flat
|
||||
[package-url]: https://yarnpkg.com/en/package/babel-plugin-react-native-web
|
||||
1
packages/babel-plugin-react-native-web/index.js
Normal file
1
packages/babel-plugin-react-native-web/index.js
Normal file
@@ -0,0 +1 @@
|
||||
module.exports = require('./src');
|
||||
15
packages/babel-plugin-react-native-web/package.json
Normal file
15
packages/babel-plugin-react-native-web/package.json
Normal file
@@ -0,0 +1,15 @@
|
||||
{
|
||||
"name": "babel-plugin-react-native-web",
|
||||
"version": "0.9.13",
|
||||
"description": "Babel plugin for React Native for Web",
|
||||
"main": "index.js",
|
||||
"devDependencies": {
|
||||
"babel-plugin-tester": "^5.0.0"
|
||||
},
|
||||
"author": "Nicolas Gallagher",
|
||||
"license": "MIT",
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "git://github.com/necolas/react-native-web.git"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,145 @@
|
||||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||
|
||||
exports[`Rewrite react-native to react-native-web export from "react-native": export from "react-native" 1`] = `
|
||||
"
|
||||
export { View } from 'react-native';
|
||||
export { ColorPropType, StyleSheet, Text, createElement } from 'react-native';
|
||||
|
||||
↓ ↓ ↓ ↓ ↓ ↓
|
||||
|
||||
export { default as View } from 'react-native-web/dist/exports/View';
|
||||
export { default as ColorPropType } from 'react-native-web/dist/exports/ColorPropType';
|
||||
export { default as StyleSheet } from 'react-native-web/dist/exports/StyleSheet';
|
||||
export { default as Text } from 'react-native-web/dist/exports/Text';
|
||||
export { default as createElement } from 'react-native-web/dist/exports/createElement';
|
||||
"
|
||||
`;
|
||||
|
||||
exports[`Rewrite react-native to react-native-web export from "react-native-web": export from "react-native-web" 1`] = `
|
||||
"
|
||||
export { View } from 'react-native-web';
|
||||
export { ColorPropType, StyleSheet, Text, createElement } from 'react-native-web';
|
||||
|
||||
↓ ↓ ↓ ↓ ↓ ↓
|
||||
|
||||
export { default as View } from 'react-native-web/dist/exports/View';
|
||||
export { default as ColorPropType } from 'react-native-web/dist/exports/ColorPropType';
|
||||
export { default as StyleSheet } from 'react-native-web/dist/exports/StyleSheet';
|
||||
export { default as Text } from 'react-native-web/dist/exports/Text';
|
||||
export { default as createElement } from 'react-native-web/dist/exports/createElement';
|
||||
"
|
||||
`;
|
||||
|
||||
exports[`Rewrite react-native to react-native-web import from "native-native": import from "native-native" 1`] = `
|
||||
"
|
||||
import ReactNative from 'react-native';
|
||||
import { View } from 'react-native';
|
||||
import { Invalid, View as MyView, ViewPropTypes } from 'react-native';
|
||||
import * as ReactNativeModules from 'react-native';
|
||||
|
||||
↓ ↓ ↓ ↓ ↓ ↓
|
||||
|
||||
import ReactNative from 'react-native-web/dist/index';
|
||||
import View from 'react-native-web/dist/exports/View';
|
||||
import { Invalid } from 'react-native-web/dist/index';
|
||||
import MyView from 'react-native-web/dist/exports/View';
|
||||
import ViewPropTypes from 'react-native-web/dist/exports/ViewPropTypes';
|
||||
import * as ReactNativeModules from 'react-native-web/dist/index';
|
||||
"
|
||||
`;
|
||||
|
||||
exports[`Rewrite react-native to react-native-web import from "native-native": import from "native-native" 2`] = `
|
||||
"
|
||||
import ReactNative from 'react-native';
|
||||
import { View } from 'react-native';
|
||||
import { Invalid, View as MyView, ViewPropTypes } from 'react-native';
|
||||
import * as ReactNativeModules from 'react-native';
|
||||
|
||||
↓ ↓ ↓ ↓ ↓ ↓
|
||||
|
||||
import ReactNative from 'react-native-web/dist/cjs/index';
|
||||
import View from 'react-native-web/dist/cjs/exports/View';
|
||||
import { Invalid } from 'react-native-web/dist/cjs/index';
|
||||
import MyView from 'react-native-web/dist/cjs/exports/View';
|
||||
import ViewPropTypes from 'react-native-web/dist/cjs/exports/ViewPropTypes';
|
||||
import * as ReactNativeModules from 'react-native-web/dist/cjs/index';
|
||||
"
|
||||
`;
|
||||
|
||||
exports[`Rewrite react-native to react-native-web import from "react-native-web": import from "react-native-web" 1`] = `
|
||||
"
|
||||
import { createElement } from 'react-native-web';
|
||||
import { ColorPropType, StyleSheet, View, TouchableOpacity, processColor } from 'react-native-web';
|
||||
import * as ReactNativeModules from 'react-native-web';
|
||||
|
||||
↓ ↓ ↓ ↓ ↓ ↓
|
||||
|
||||
import createElement from 'react-native-web/dist/exports/createElement';
|
||||
import ColorPropType from 'react-native-web/dist/exports/ColorPropType';
|
||||
import StyleSheet from 'react-native-web/dist/exports/StyleSheet';
|
||||
import View from 'react-native-web/dist/exports/View';
|
||||
import TouchableOpacity from 'react-native-web/dist/exports/TouchableOpacity';
|
||||
import processColor from 'react-native-web/dist/exports/processColor';
|
||||
import * as ReactNativeModules from 'react-native-web/dist/index';
|
||||
"
|
||||
`;
|
||||
|
||||
exports[`Rewrite react-native to react-native-web require "react-native": require "react-native" 1`] = `
|
||||
"
|
||||
const ReactNative = require('react-native');
|
||||
const { View } = require('react-native');
|
||||
const { StyleSheet, TouchableOpacity } = require('react-native');
|
||||
|
||||
↓ ↓ ↓ ↓ ↓ ↓
|
||||
|
||||
const ReactNative = require('react-native-web/dist/index').default;
|
||||
|
||||
const View = require('react-native-web/dist/exports/View').default;
|
||||
|
||||
const StyleSheet = require('react-native-web/dist/exports/StyleSheet').default;
|
||||
|
||||
const TouchableOpacity = require('react-native-web/dist/exports/TouchableOpacity').default;
|
||||
"
|
||||
`;
|
||||
|
||||
exports[`Rewrite react-native to react-native-web require "react-native": require "react-native" 2`] = `
|
||||
"
|
||||
const ReactNative = require('react-native');
|
||||
const { View } = require('react-native');
|
||||
const { StyleSheet, TouchableOpacity } = require('react-native');
|
||||
|
||||
↓ ↓ ↓ ↓ ↓ ↓
|
||||
|
||||
const ReactNative = require('react-native-web/dist/cjs/index').default;
|
||||
|
||||
const View = require('react-native-web/dist/cjs/exports/View').default;
|
||||
|
||||
const StyleSheet = require('react-native-web/dist/cjs/exports/StyleSheet').default;
|
||||
|
||||
const TouchableOpacity = require('react-native-web/dist/cjs/exports/TouchableOpacity').default;
|
||||
"
|
||||
`;
|
||||
|
||||
exports[`Rewrite react-native to react-native-web require "react-native-web": require "react-native-web" 1`] = `
|
||||
"
|
||||
const ReactNative = require('react-native-web');
|
||||
const { createElement } = require('react-native-web');
|
||||
const { ColorPropType, StyleSheet, View, TouchableOpacity, processColor } = require('react-native-web');
|
||||
|
||||
↓ ↓ ↓ ↓ ↓ ↓
|
||||
|
||||
const ReactNative = require('react-native-web/dist/index').default;
|
||||
|
||||
const createElement = require('react-native-web/dist/exports/createElement').default;
|
||||
|
||||
const ColorPropType = require('react-native-web/dist/exports/ColorPropType').default;
|
||||
|
||||
const StyleSheet = require('react-native-web/dist/exports/StyleSheet').default;
|
||||
|
||||
const View = require('react-native-web/dist/exports/View').default;
|
||||
|
||||
const TouchableOpacity = require('react-native-web/dist/exports/TouchableOpacity').default;
|
||||
|
||||
const processColor = require('react-native-web/dist/exports/processColor').default;
|
||||
"
|
||||
`;
|
||||
@@ -0,0 +1,69 @@
|
||||
const plugin = require('..');
|
||||
const pluginTester = require('babel-plugin-tester');
|
||||
|
||||
const tests = [
|
||||
// import react-native
|
||||
{
|
||||
title: 'import from "native-native"',
|
||||
code: `import ReactNative from 'react-native';
|
||||
import { View } from 'react-native';
|
||||
import { Invalid, View as MyView, ViewPropTypes } from 'react-native';
|
||||
import * as ReactNativeModules from 'react-native';`,
|
||||
snapshot: true
|
||||
},
|
||||
{
|
||||
title: 'import from "native-native"',
|
||||
code: `import ReactNative from 'react-native';
|
||||
import { View } from 'react-native';
|
||||
import { Invalid, View as MyView, ViewPropTypes } from 'react-native';
|
||||
import * as ReactNativeModules from 'react-native';`,
|
||||
snapshot: true,
|
||||
pluginOptions: { commonjs: true }
|
||||
},
|
||||
{
|
||||
title: 'import from "react-native-web"',
|
||||
code: `import { createElement } from 'react-native-web';
|
||||
import { ColorPropType, StyleSheet, View, TouchableOpacity, processColor } from 'react-native-web';
|
||||
import * as ReactNativeModules from 'react-native-web';`,
|
||||
snapshot: true
|
||||
},
|
||||
{
|
||||
title: 'export from "react-native"',
|
||||
code: `export { View } from 'react-native';
|
||||
export { ColorPropType, StyleSheet, Text, createElement } from 'react-native';`,
|
||||
snapshot: true
|
||||
},
|
||||
{
|
||||
title: 'export from "react-native-web"',
|
||||
code: `export { View } from 'react-native-web';
|
||||
export { ColorPropType, StyleSheet, Text, createElement } from 'react-native-web';`,
|
||||
snapshot: true
|
||||
},
|
||||
{
|
||||
title: 'require "react-native"',
|
||||
code: `const ReactNative = require('react-native');
|
||||
const { View } = require('react-native');
|
||||
const { StyleSheet, TouchableOpacity } = require('react-native');`,
|
||||
snapshot: true
|
||||
},
|
||||
{
|
||||
title: 'require "react-native"',
|
||||
code: `const ReactNative = require('react-native');
|
||||
const { View } = require('react-native');
|
||||
const { StyleSheet, TouchableOpacity } = require('react-native');`,
|
||||
snapshot: true,
|
||||
pluginOptions: { commonjs: true }
|
||||
},
|
||||
{
|
||||
title: 'require "react-native-web"',
|
||||
code: `const ReactNative = require('react-native-web');
|
||||
const { createElement } = require('react-native-web');
|
||||
const { ColorPropType, StyleSheet, View, TouchableOpacity, processColor } = require('react-native-web');`,
|
||||
snapshot: true
|
||||
}
|
||||
];
|
||||
|
||||
pluginTester({
|
||||
plugin,
|
||||
tests
|
||||
});
|
||||
136
packages/babel-plugin-react-native-web/src/index.js
Normal file
136
packages/babel-plugin-react-native-web/src/index.js
Normal file
@@ -0,0 +1,136 @@
|
||||
const moduleMap = require('./moduleMap');
|
||||
|
||||
const isCommonJS = opts => opts.commonjs === true;
|
||||
|
||||
const getDistLocation = (importName, opts) => {
|
||||
const format = isCommonJS(opts) ? 'cjs/' : '';
|
||||
if (importName === 'index') {
|
||||
return `react-native-web/dist/${format}index`;
|
||||
} else if (importName && moduleMap[importName]) {
|
||||
return `react-native-web/dist/${format}exports/${importName}`;
|
||||
}
|
||||
};
|
||||
|
||||
const isReactNativeRequire = (t, node) => {
|
||||
const { declarations } = node;
|
||||
if (declarations.length > 1) {
|
||||
return false;
|
||||
}
|
||||
const { id, init } = declarations[0];
|
||||
return (
|
||||
(t.isObjectPattern(id) || t.isIdentifier(id)) &&
|
||||
t.isCallExpression(init) &&
|
||||
t.isIdentifier(init.callee) &&
|
||||
init.callee.name === 'require' &&
|
||||
init.arguments.length === 1 &&
|
||||
(init.arguments[0].value === 'react-native' || init.arguments[0].value === 'react-native-web')
|
||||
);
|
||||
};
|
||||
|
||||
const isReactNativeModule = ({ source, specifiers }) =>
|
||||
source &&
|
||||
(source.value === 'react-native' || source.value === 'react-native-web') &&
|
||||
specifiers.length;
|
||||
|
||||
module.exports = function({ types: t }) {
|
||||
return {
|
||||
name: 'Rewrite react-native to react-native-web',
|
||||
visitor: {
|
||||
ImportDeclaration(path, state) {
|
||||
const { specifiers } = path.node;
|
||||
if (isReactNativeModule(path.node)) {
|
||||
const imports = specifiers
|
||||
.map(specifier => {
|
||||
if (t.isImportSpecifier(specifier)) {
|
||||
const importName = specifier.imported.name;
|
||||
const distLocation = getDistLocation(importName, state.opts);
|
||||
|
||||
if (distLocation) {
|
||||
return t.importDeclaration(
|
||||
[t.importDefaultSpecifier(t.identifier(specifier.local.name))],
|
||||
t.stringLiteral(distLocation)
|
||||
);
|
||||
}
|
||||
}
|
||||
return t.importDeclaration(
|
||||
[specifier],
|
||||
t.stringLiteral(getDistLocation('index', state.opts))
|
||||
);
|
||||
})
|
||||
.filter(Boolean);
|
||||
|
||||
path.replaceWithMultiple(imports);
|
||||
}
|
||||
},
|
||||
ExportNamedDeclaration(path, state) {
|
||||
const { specifiers } = path.node;
|
||||
if (isReactNativeModule(path.node)) {
|
||||
const exports = specifiers
|
||||
.map(specifier => {
|
||||
if (t.isExportSpecifier(specifier)) {
|
||||
const exportName = specifier.exported.name;
|
||||
const localName = specifier.local.name;
|
||||
const distLocation = getDistLocation(localName, state.opts);
|
||||
|
||||
if (distLocation) {
|
||||
return t.exportNamedDeclaration(
|
||||
null,
|
||||
[t.exportSpecifier(t.identifier('default'), t.identifier(exportName))],
|
||||
t.stringLiteral(distLocation)
|
||||
);
|
||||
}
|
||||
}
|
||||
return t.exportNamedDeclaration(
|
||||
null,
|
||||
[specifier],
|
||||
t.stringLiteral(getDistLocation('index', state.opts))
|
||||
);
|
||||
})
|
||||
.filter(Boolean);
|
||||
|
||||
path.replaceWithMultiple(exports);
|
||||
}
|
||||
},
|
||||
VariableDeclaration(path, state) {
|
||||
if (isReactNativeRequire(t, path.node)) {
|
||||
const { id } = path.node.declarations[0];
|
||||
if (t.isObjectPattern(id)) {
|
||||
const imports = id.properties
|
||||
.map(identifier => {
|
||||
const distLocation = getDistLocation(identifier.key.name, state.opts);
|
||||
if (distLocation) {
|
||||
return t.variableDeclaration(path.node.kind, [
|
||||
t.variableDeclarator(
|
||||
t.identifier(identifier.value.name),
|
||||
t.memberExpression(
|
||||
t.callExpression(t.identifier('require'), [t.stringLiteral(distLocation)]),
|
||||
t.identifier('default')
|
||||
)
|
||||
)
|
||||
]);
|
||||
}
|
||||
})
|
||||
.filter(Boolean);
|
||||
|
||||
path.replaceWithMultiple(imports);
|
||||
} else if (t.isIdentifier(id)) {
|
||||
const name = id.name;
|
||||
const importIndex = t.variableDeclaration(path.node.kind, [
|
||||
t.variableDeclarator(
|
||||
t.identifier(name),
|
||||
t.memberExpression(
|
||||
t.callExpression(t.identifier('require'), [
|
||||
t.stringLiteral(getDistLocation('index', state.opts))
|
||||
]),
|
||||
t.identifier('default')
|
||||
)
|
||||
)
|
||||
]);
|
||||
|
||||
path.replaceWith(importIndex);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
};
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user