Compare commits
476 Commits
v1.0.0-bet
...
2.5.3
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
4f93200c91 | ||
|
|
665736d754 | ||
|
|
5598c3e28f | ||
|
|
cde6e845cd | ||
|
|
fb8c712ad8 | ||
|
|
350b7e0aed | ||
|
|
de112565d3 | ||
|
|
acdd515c13 | ||
|
|
452a6d2004 | ||
|
|
08c8031a71 | ||
|
|
608365266a | ||
|
|
247fba56e6 | ||
|
|
060f5dcecf | ||
|
|
fdec05c87a | ||
|
|
76da804574 | ||
|
|
dde091848a | ||
|
|
824fa32416 | ||
|
|
c518e7f36c | ||
|
|
1cfe01dbdb | ||
|
|
e62a9050fd | ||
|
|
310b909ba8 | ||
|
|
aebe8a5c23 | ||
|
|
e1df2c6c4a | ||
|
|
fa86718a24 | ||
|
|
c8e5673183 | ||
|
|
b312a5e307 | ||
|
|
ee6a6c53b1 | ||
|
|
8edec88341 | ||
|
|
b8d6d4253d | ||
|
|
0adb1ba9f1 | ||
|
|
d3ef3d1271 | ||
|
|
89a24bdc12 | ||
|
|
128a95b496 | ||
|
|
470eaf3b08 | ||
|
|
c91e8206a5 | ||
|
|
da283915f8 | ||
|
|
3031e7bd80 | ||
|
|
98a4f26f26 | ||
|
|
b7f5435c93 | ||
|
|
21ef4fcb82 | ||
|
|
5f64a2a9cb | ||
|
|
992d0fb267 | ||
|
|
6f41379ed1 | ||
|
|
267af01e72 | ||
|
|
b68c3a755d | ||
|
|
7345634493 | ||
|
|
6517169119 | ||
|
|
ea5d14a720 | ||
|
|
313d0726a8 | ||
|
|
b52f153747 | ||
|
|
44621005ff | ||
|
|
bf58364c3d | ||
|
|
b55053cde6 | ||
|
|
9abb2644a9 | ||
|
|
6a946d6ab7 | ||
|
|
395abe5200 | ||
|
|
ba62509ff4 | ||
|
|
45391db7d9 | ||
|
|
7f86362e86 | ||
|
|
99605737e9 | ||
|
|
842f5eb7b2 | ||
|
|
183ea82416 | ||
|
|
108a6504a7 | ||
|
|
f92d671746 | ||
|
|
e0c4a8f7d3 | ||
|
|
bc881c8aa1 | ||
|
|
118c19dcce | ||
|
|
01b43974e6 | ||
|
|
2f90899620 | ||
|
|
6cc86f66e1 | ||
|
|
4be99b6645 | ||
|
|
80016b7218 | ||
|
|
f555a9ec9a | ||
|
|
05cbd85d5c | ||
|
|
51965eac38 | ||
|
|
a3956bf3ce | ||
|
|
ce24c66b5a | ||
|
|
5467f0e22d | ||
|
|
1e7d8d55c3 | ||
|
|
1d2ce862c2 | ||
|
|
d778479e4a | ||
|
|
352dae50e1 | ||
|
|
61385cae59 | ||
|
|
aa3c13891e | ||
|
|
9696d7220d | ||
|
|
2b83b44816 | ||
|
|
ec749023ed | ||
|
|
adc9389eb3 | ||
|
|
54d143fee2 | ||
|
|
d50e74d0c7 | ||
|
|
22926c5230 | ||
|
|
f6c47a6c66 | ||
|
|
046a9f8930 | ||
|
|
72f17538c2 | ||
|
|
550001b053 | ||
|
|
d168ab26f9 | ||
|
|
99916328a1 | ||
|
|
08e1b53f2e | ||
|
|
2243528e97 | ||
|
|
931271198b | ||
|
|
1876706bad | ||
|
|
e97d6b26a8 | ||
|
|
ec1694f909 | ||
|
|
93db7d0c95 | ||
|
|
589b80b2fa | ||
|
|
364144d639 | ||
|
|
2fd7284fe2 | ||
|
|
6499f02157 | ||
|
|
39d5714ac0 | ||
|
|
1ceda5f04d | ||
|
|
4533883ba7 | ||
|
|
8ec2466fef | ||
|
|
1bd6593ede | ||
|
|
4e8d8ce12f | ||
|
|
9f95a7f10b | ||
|
|
f6bd3e4306 | ||
|
|
c1a94895f5 | ||
|
|
ad7cde9eb9 | ||
|
|
2643f690a9 | ||
|
|
8e52995ef3 | ||
|
|
8ed3817c90 | ||
|
|
eda9bfd567 | ||
|
|
723c5f2149 | ||
|
|
ab5481a290 | ||
|
|
df281cfed0 | ||
|
|
e0df3cf74a | ||
|
|
2440af66e4 | ||
|
|
47fe858d4e | ||
|
|
c641bee11b | ||
|
|
4b39e2db3c | ||
|
|
f7533a790f | ||
|
|
c56122466f | ||
|
|
7fc992dc58 | ||
|
|
32922cdd7d | ||
|
|
eda51b3b79 | ||
|
|
921ee09587 | ||
|
|
7ae4c60eb8 | ||
|
|
5fff7ef5c6 | ||
|
|
42bb1cc317 | ||
|
|
337fd89ad5 | ||
|
|
acf9b92ff7 | ||
|
|
5072130d6f | ||
|
|
20bbbd62ff | ||
|
|
0890896824 | ||
|
|
0cf14f8e1e | ||
|
|
e5e434c9e2 | ||
|
|
e5d8d2c216 | ||
|
|
abd5200739 | ||
|
|
202609d9cf | ||
|
|
7b4dd98255 | ||
|
|
70c644f522 | ||
|
|
5274d16e3b | ||
|
|
e5e2cbb86d | ||
|
|
a8caa0d93c | ||
|
|
f70a25a6a8 | ||
|
|
6cde6e2558 | ||
|
|
0794c0faaa | ||
|
|
ea28e84e5a | ||
|
|
419ee5318d | ||
|
|
fbbf00875b | ||
|
|
22e09f7186 | ||
|
|
ece6297e8e | ||
|
|
ad52caf57b | ||
|
|
11f5e6e8e5 | ||
|
|
1764b21f34 | ||
|
|
bbacabeba3 | ||
|
|
b140b70555 | ||
|
|
356646cbfa | ||
|
|
6234b5661e | ||
|
|
270c3f0754 | ||
|
|
6f04bdffa6 | ||
|
|
8415378784 | ||
|
|
9e47092d56 | ||
|
|
029d6ac4d2 | ||
|
|
d57d118fda | ||
|
|
2232e394bb | ||
|
|
670d48366b | ||
|
|
99ac5b6c08 | ||
|
|
68a2a106f3 | ||
|
|
b7c6d072a5 | ||
|
|
ecd9fd71e9 | ||
|
|
cfc9690326 | ||
|
|
828e7f2d43 | ||
|
|
9c3fffa47f | ||
|
|
be524e4224 | ||
|
|
095814230b | ||
|
|
9cf557bba0 | ||
|
|
5e4512f3eb | ||
|
|
ee1b5972ce | ||
|
|
2233d0e1d8 | ||
|
|
577d99c165 | ||
|
|
aa362ea776 | ||
|
|
864908a49c | ||
|
|
5cab55b8c9 | ||
|
|
9b9db86bde | ||
|
|
4def39c0f7 | ||
|
|
e6559f5878 | ||
|
|
a9d8f2e03e | ||
|
|
84a070b9d5 | ||
|
|
ee984943c7 | ||
|
|
9fdfec18f6 | ||
|
|
aee16b91a4 | ||
|
|
191439f79a | ||
|
|
b1ac152fec | ||
|
|
c588ab9f9d | ||
|
|
ae8cd41396 | ||
|
|
5038ee2360 | ||
|
|
5bf071e3ee | ||
|
|
fcbf78e658 | ||
|
|
fd75e9c14c | ||
|
|
7d36a3b137 | ||
|
|
175387b22f | ||
|
|
0dd7daecc0 | ||
|
|
42230634fd | ||
|
|
a9943e9b2e | ||
|
|
6475e32dba | ||
|
|
f67872d8f1 | ||
|
|
2c7187b22a | ||
|
|
160d44f58e | ||
|
|
d017ed01b3 | ||
|
|
c2e197f8d3 | ||
|
|
6b3968b601 | ||
|
|
b575200879 | ||
|
|
cd5bd8882e | ||
|
|
3f837c895e | ||
|
|
bc5d35aba3 | ||
|
|
9a6e0bbd98 | ||
|
|
052d22804c | ||
|
|
7a978b1087 | ||
|
|
b06fb7e432 | ||
|
|
a92ed83302 | ||
|
|
0c31bc44ea | ||
|
|
8e5ee4d312 | ||
|
|
4bb8987ab7 | ||
|
|
81a86fa091 | ||
|
|
47f357f332 | ||
|
|
bdda6fa5be | ||
|
|
b097136f74 | ||
|
|
c9b0219cec | ||
|
|
ac83cf804c | ||
|
|
cf63521516 | ||
|
|
7c488c8d49 | ||
|
|
9005494e64 | ||
|
|
0daab8c55b | ||
|
|
ae98089337 | ||
|
|
57e37a8783 | ||
|
|
b7994d28db | ||
|
|
f1bfdeee46 | ||
|
|
c6301abaed | ||
|
|
4569ad49f9 | ||
|
|
214eeb13fb | ||
|
|
416fe58cab | ||
|
|
2e47cbb3cb | ||
|
|
cd99dc8054 | ||
|
|
e27ad22c57 | ||
|
|
6785729fb5 | ||
|
|
d3b6e70d16 | ||
|
|
5f32a48c16 | ||
|
|
d5a0b5912b | ||
|
|
13fd8acb20 | ||
|
|
8fc8f3b8f7 | ||
|
|
a37473c5e4 | ||
|
|
23eb0839cb | ||
|
|
e84473db78 | ||
|
|
c8531d0f38 | ||
|
|
276fb8f7b3 | ||
|
|
ab758bcaaa | ||
|
|
2bb91a6740 | ||
|
|
ffa3a92534 | ||
|
|
6dda8c30a9 | ||
|
|
065fdf61d8 | ||
|
|
371a714b57 | ||
|
|
1d33b95c5f | ||
|
|
593bc8a648 | ||
|
|
174a6e4175 | ||
|
|
af991e5512 | ||
|
|
0b0e9e9df5 | ||
|
|
42b0ccca79 | ||
|
|
da6a960bb1 | ||
|
|
3ca47ec778 | ||
|
|
14ee56a20d | ||
|
|
9d36daf48e | ||
|
|
055fdb2ffc | ||
|
|
b3bf80634d | ||
|
|
fafd0e8702 | ||
|
|
d94045817c | ||
|
|
f0acaddf05 | ||
|
|
9beb32ecac | ||
|
|
29a29936bf | ||
|
|
8961fef00b | ||
|
|
021c7e54be | ||
|
|
27538cad94 | ||
|
|
9a8a50ef1d | ||
|
|
2c6dc35723 | ||
|
|
3600ecbd9b | ||
|
|
c74f001b1c | ||
|
|
7f4706e4cc | ||
|
|
d0ef33b12f | ||
|
|
3c3668c952 | ||
|
|
5febb81a1c | ||
|
|
50dcb37cd7 | ||
|
|
69bca191a7 | ||
|
|
4df9198979 | ||
|
|
0fc7f87173 | ||
|
|
5b4d11ab5d | ||
|
|
4d1cc285b9 | ||
|
|
41725afa8a | ||
|
|
58b77d44ae | ||
|
|
1d49b6e3fe | ||
|
|
58b8a08af6 | ||
|
|
b11ea8a1d5 | ||
|
|
3c2b977eca | ||
|
|
95565487ec | ||
|
|
a26d2acfca | ||
|
|
a1b3d2213d | ||
|
|
eb39df507e | ||
|
|
cca06bb530 | ||
|
|
2187d8fe66 | ||
|
|
67f98b69eb | ||
|
|
c0c5c86f63 | ||
|
|
4388b6403c | ||
|
|
2cb740fbf6 | ||
|
|
ac741a703b | ||
|
|
5641b42975 | ||
|
|
ea19ceaa6a | ||
|
|
57ae6e4736 | ||
|
|
858a0d7a53 | ||
|
|
cf36f22e68 | ||
|
|
7385c244b7 | ||
|
|
8bd25cf372 | ||
|
|
20af8c688e | ||
|
|
b0dccd7e88 | ||
|
|
c69a22f10e | ||
|
|
43a1c5ddbd | ||
|
|
e97d41cccf | ||
|
|
3e4ddc685a | ||
|
|
f62c728593 | ||
|
|
616f9a56f2 | ||
|
|
3b93faa0fc | ||
|
|
333b2e4b68 | ||
|
|
7f50173cf1 | ||
|
|
8432f67529 | ||
|
|
c72b44ce10 | ||
|
|
149f5f5c66 | ||
|
|
85f77fe903 | ||
|
|
d4b759606d | ||
|
|
4d2609f4a8 | ||
|
|
0766ec963e | ||
|
|
0759e8cc8f | ||
|
|
fae1f71fb3 | ||
|
|
03fbd98ce4 | ||
|
|
63a6565afa | ||
|
|
154aa85f70 | ||
|
|
a14002084f | ||
|
|
98cfd7a531 | ||
|
|
282e5abac2 | ||
|
|
d6d1dd279d | ||
|
|
b0b7b556a3 | ||
|
|
56d233be8b | ||
|
|
cfda9b290b | ||
|
|
bce5fde5cb | ||
|
|
33c6ac9ae7 | ||
|
|
189e7ee539 | ||
|
|
dc06c50966 | ||
|
|
b013cc98be | ||
|
|
37c3a357fc | ||
|
|
836a164693 | ||
|
|
a9582c5dd3 | ||
|
|
fe4079c495 | ||
|
|
ed0306587c | ||
|
|
c88ec60fe3 | ||
|
|
d0da40fa32 | ||
|
|
7141f66efd | ||
|
|
ffcf179883 | ||
|
|
441b9ffe10 | ||
|
|
0d3d83bd90 | ||
|
|
d1d81d7033 | ||
|
|
a1fc566679 | ||
|
|
088e9e82ad | ||
|
|
dca37627a2 | ||
|
|
50a3f8de93 | ||
|
|
e0de8b4dce | ||
|
|
a62ad18b31 | ||
|
|
77b5402404 | ||
|
|
6c1ab47719 | ||
|
|
24bfab93b4 | ||
|
|
f8426bef7e | ||
|
|
afcce1a0c0 | ||
|
|
6f430b2f1e | ||
|
|
427e89480f | ||
|
|
4ae2a42a4d | ||
|
|
9e026ec2c8 | ||
|
|
82572e73f3 | ||
|
|
d84c320bd7 | ||
|
|
339732e956 | ||
|
|
8e0fdc67b8 | ||
|
|
122f6cfcee | ||
|
|
0157a4c9e9 | ||
|
|
cbd1fee8a4 | ||
|
|
ebfbbe2c09 | ||
|
|
ecfa38bfd2 | ||
|
|
276249c4c7 | ||
|
|
1715513519 | ||
|
|
2f4bacf6e2 | ||
|
|
05d342dac5 | ||
|
|
a57f129cc0 | ||
|
|
c0d76755e7 | ||
|
|
b221afc80b | ||
|
|
f895564605 | ||
|
|
36775007b0 | ||
|
|
99c4d448b2 | ||
|
|
8cf2953115 | ||
|
|
abbd88601f | ||
|
|
ff6d6f4e5e | ||
|
|
7fa0ef3aee | ||
|
|
6ac3bb90ed | ||
|
|
627c487936 | ||
|
|
f46bdff703 | ||
|
|
bc75a5b7b9 | ||
|
|
50d5c8bc0a | ||
|
|
c7b73cd8b4 | ||
|
|
e2e540c32d | ||
|
|
7a57c4e779 | ||
|
|
4373544257 | ||
|
|
8329e269b6 | ||
|
|
450a1e3ba5 | ||
|
|
a83220b511 | ||
|
|
6af770d644 | ||
|
|
ef63b230b2 | ||
|
|
41b587ca65 | ||
|
|
faed4731bc | ||
|
|
7fe76fb7c6 | ||
|
|
89a6668595 | ||
|
|
9cf9e25661 | ||
|
|
363f93fc4d | ||
|
|
928f632c89 | ||
|
|
950d0c6877 | ||
|
|
5a26506595 | ||
|
|
5cb42bdf5d | ||
|
|
d5618ebd41 | ||
|
|
368bc615c1 | ||
|
|
f332b6bdf7 | ||
|
|
b5700b9277 | ||
|
|
ad59d161db | ||
|
|
cc355dcee9 | ||
|
|
04c075c1bb | ||
|
|
7ae6908428 | ||
|
|
93dd28749d | ||
|
|
7f1fb8cdd8 | ||
|
|
0a662c9835 | ||
|
|
3cff180224 | ||
|
|
88dfd84cf5 | ||
|
|
4e48d43f0f | ||
|
|
e0704e48a1 | ||
|
|
caf83794e0 | ||
|
|
65f44ae003 | ||
|
|
24a3a79996 | ||
|
|
e25bdd2ed2 | ||
|
|
346264e132 | ||
|
|
f2f4e5ce44 | ||
|
|
931677781e | ||
|
|
dec79f6a99 | ||
|
|
44616dd45a | ||
|
|
fafe68b8cb | ||
|
|
87a1b77525 | ||
|
|
f0e9f70320 | ||
|
|
e396795753 | ||
|
|
53472b72f9 | ||
|
|
6e4afe2153 | ||
|
|
838b7c369a | ||
|
|
6a6207ce7b | ||
|
|
79317e83ae | ||
|
|
ffb95fdb73 | ||
|
|
d93acdd918 | ||
|
|
b9d1d0d021 | ||
|
|
7adad618d1 |
34
.babelrc
@@ -1,35 +1,3 @@
|
||||
{
|
||||
"env": {
|
||||
// For RN example development
|
||||
"development": {
|
||||
"presets": ["react-native"],
|
||||
"plugins": [
|
||||
"transform-flow-strip-types"
|
||||
]
|
||||
},
|
||||
// For Jest
|
||||
"test": {
|
||||
"presets": ["react-native"],
|
||||
"plugins": [
|
||||
"transform-flow-strip-types"
|
||||
]
|
||||
},
|
||||
// For publishing to NPM for RN
|
||||
"publish-rn": {
|
||||
"presets": ["react-native-syntax"],
|
||||
"plugins": [
|
||||
"transform-flow-strip-types"
|
||||
]
|
||||
},
|
||||
// For publishing to NPM for web
|
||||
"publish-web": {
|
||||
"presets": ["es2015", "stage-1", "react"],
|
||||
"plugins": [
|
||||
"transform-flow-strip-types",
|
||||
["transform-define", {
|
||||
"__DEV__": false
|
||||
}]
|
||||
]
|
||||
}
|
||||
}
|
||||
"presets": ["react-native"]
|
||||
}
|
||||
|
||||
@@ -24,20 +24,17 @@ jobs:
|
||||
tar -xz -C /tmp -f /tmp/docker-$VER.tgz
|
||||
mv /tmp/docker/* /usr/bin
|
||||
|
||||
if [ "${CIRCLE_BRANCH}" == "master" ]; then
|
||||
# deploy website
|
||||
cd website && yarn && cd ../
|
||||
yarn run build-docs
|
||||
./scripts/deploy-website.sh
|
||||
|
||||
# deploy expo playground demo
|
||||
# exp login -u "$EXPO_USERNAME" -p "$EXPO_PASSWORD"
|
||||
# cd examples/NavigationPlayground && exp publish
|
||||
fi
|
||||
yarn global add exp
|
||||
set +x
|
||||
exp login -u "$EXPO_USERNAME" -p "$EXPO_PASSWORD"
|
||||
set -x
|
||||
cd examples/NavigationPlayground && yarn && exp publish --release-channel "${CIRCLE_SHA1}"
|
||||
- save_cache:
|
||||
key: v3-react-navigation-{{ .Branch }}-{{ checksum "package.json" }}
|
||||
paths:
|
||||
- ~/.cache/yarn
|
||||
- ~/react-navigation/website/node_modules
|
||||
- ~/react-navigation/examples/NavigationPlayground/node_modules
|
||||
- ~/react-navigation/examples/ReduxExample/node_modules
|
||||
notify:
|
||||
webhooks:
|
||||
- url: https://react-navigation-ci.now.sh
|
||||
@@ -1,5 +1,4 @@
|
||||
coverage
|
||||
flow-typed
|
||||
flow
|
||||
node_modules
|
||||
lib*
|
||||
|
||||
49
.eslintrc
@@ -1,27 +1,24 @@
|
||||
{
|
||||
"extends": [
|
||||
"plugin:flowtype/recommended",
|
||||
"plugin:react/recommended",
|
||||
"plugin:import/errors",
|
||||
"plugin:import/warnings",
|
||||
"prettier",
|
||||
"prettier/flowtype",
|
||||
"prettier/react"
|
||||
],
|
||||
"parser": "babel-eslint",
|
||||
"plugins": [
|
||||
"react",
|
||||
"flowtype",
|
||||
"prettier"
|
||||
],
|
||||
"plugins": ["react", "prettier"],
|
||||
"env": {
|
||||
"jasmine": true
|
||||
},
|
||||
"rules": {
|
||||
"prettier/prettier": ["error", {
|
||||
"trailingComma": "es5",
|
||||
"singleQuote": true
|
||||
}],
|
||||
"prettier/prettier": [
|
||||
"error",
|
||||
{
|
||||
"trailingComma": "es5",
|
||||
"singleQuote": true
|
||||
}
|
||||
],
|
||||
|
||||
"no-underscore-dangle": "off",
|
||||
"no-use-before-define": "off",
|
||||
@@ -30,44 +27,20 @@
|
||||
"no-plusplus": "off",
|
||||
"no-class-assign": "off",
|
||||
"no-duplicate-imports": "off",
|
||||
|
||||
"import/extensions": "off",
|
||||
"import/no-extraneous-dependencies": "off",
|
||||
"import/no-unresolved": "off",
|
||||
|
||||
"react/jsx-filename-extension": [
|
||||
"off", { "extensions": [".js", ".jsx"] }
|
||||
],
|
||||
"react/jsx-filename-extension": ["off", { "extensions": [".js", ".jsx"] }],
|
||||
|
||||
"react/sort-comp": "off",
|
||||
"react/prefer-stateless-function": "off",
|
||||
"react/no-deprecated": "off",
|
||||
|
||||
"react/forbid-prop-types": "warn",
|
||||
"react/prop-types": "off",
|
||||
"react/require-default-props": "off",
|
||||
"react/no-unused-prop-types": "off",
|
||||
|
||||
"flowtype/boolean-style": [
|
||||
"error",
|
||||
"boolean"
|
||||
],
|
||||
"flowtype/no-weak-types": "off",
|
||||
"flowtype/require-parameter-type": "error",
|
||||
"flowtype/require-return-type": [
|
||||
"off",
|
||||
"always",
|
||||
{
|
||||
"annotateUndefined": "never"
|
||||
}
|
||||
],
|
||||
"flowtype/require-valid-file-annotation": "error",
|
||||
"flowtype/use-flow-type": "warn",
|
||||
"flowtype/valid-syntax": "warn"
|
||||
},
|
||||
"settings": {
|
||||
"flowtype": {
|
||||
"onlyFilesWithFlowAnnotation": true
|
||||
}
|
||||
"react/no-unused-prop-types": "off"
|
||||
},
|
||||
"parserOptions": {
|
||||
"ecmaVersion": 6,
|
||||
|
||||
63
.flowconfig
@@ -1,63 +0,0 @@
|
||||
[ignore]
|
||||
; We fork some components by platform
|
||||
.*/*[.]android.js
|
||||
|
||||
; Ignore "BUCK" generated dirs
|
||||
.*/node_modules/react-native/\.buckd/
|
||||
|
||||
; Ignore unexpected extra "@providesModule"
|
||||
.*/node_modules/.*/node_modules/fbjs/.*
|
||||
|
||||
; Ignore duplicate module providers
|
||||
; For RN Apps installed via npm, "Libraries" folder is inside
|
||||
; "node_modules/react-native" but in the source repo it is in the root
|
||||
.*/Libraries/react-native/React.js
|
||||
|
||||
; Ignore polyfills
|
||||
.*/Libraries/polyfills/.*
|
||||
|
||||
; Ignore website node_modules react and react-native
|
||||
<PROJECT_ROOT>/website/node_modules/react/.*
|
||||
<PROJECT_ROOT>/website/node_modules/react-native/.*
|
||||
<PROJECT_ROOT>/website/node_modules/fbjs/.*
|
||||
|
||||
; Ignore transpiled folders and examples folder
|
||||
<PROJECT_ROOT>/lib
|
||||
<PROJECT_ROOT>/lib-rn
|
||||
<PROJECT_ROOT>/examples
|
||||
|
||||
[include]
|
||||
|
||||
[libs]
|
||||
node_modules/react-native/Libraries/react-native/react-native-interface.js
|
||||
node_modules/react-native/flow/
|
||||
|
||||
[options]
|
||||
module.system=haste
|
||||
|
||||
emoji=true
|
||||
|
||||
munge_underscores=true
|
||||
|
||||
module.name_mapper='^[./a-zA-Z0-9$_-]+\.\(bmp\|gif\|jpg\|jpeg\|png\|psd\|svg\|webp\|m4v\|mov\|mp4\|mpeg\|mpg\|webm\|aac\|aiff\|caf\|m4a\|mp3\|wav\|html\|pdf\)$' -> 'RelativeImageStub'
|
||||
|
||||
module.file_ext=.js
|
||||
module.file_ext=.jsx
|
||||
module.file_ext=.json
|
||||
module.file_ext=.native.js
|
||||
|
||||
suppress_type=$FlowIssue
|
||||
suppress_type=$FlowFixMe
|
||||
suppress_type=$FlowFixMeProps
|
||||
suppress_type=$FlowFixMeState
|
||||
suppress_type=$FixMe
|
||||
|
||||
suppress_comment=\\(.\\|\n\\)*\\$FlowFixMe\\($\\|[^(]\\|(\\(>=0\\.\\(5[0-3]\\|[1-4][0-9]\\|[0-9]\\).[0-9]\\)? *\\(site=[a-z,_]*react_native[a-z,_]*\\)?)\\)
|
||||
suppress_comment=\\(.\\|\n\\)*\\$FlowIssue\\((\\(>=0\\.\\(5[0-3]\\|[1-4][0-9]\\|[0-9]\\).[0-9]\\)? *\\(site=[a-z,_]*react_native[a-z,_]*\\)?)\\)?:? #[0-9]+
|
||||
suppress_comment=\\(.\\|\n\\)*\\$FlowFixedInNextDeploy
|
||||
suppress_comment=\\(.\\|\n\\)*\\$FlowExpectedError
|
||||
|
||||
unsafe.enable_getters_and_setters=true
|
||||
|
||||
[version]
|
||||
0.53.0
|
||||
30
.github/ISSUE_TEMPLATE.md
vendored
@@ -1,21 +1,33 @@
|
||||
## The issue list is reserved for bugs and feature requests, not for questions.
|
||||
## The issue tracker is reserved for bug reports only.
|
||||
|
||||
For usage questions, try to:
|
||||
If you have a question, feature request, or an idea for improving the library or its related tools, please try one of the following resources:
|
||||
|
||||
- [Read the docs](https://reactnavigation.org/)
|
||||
- [Ask on the Reactiflux (#react-navigation)](https://discord.gg/reactiflux)
|
||||
- [Look for / ask questions on StackOverflow](https://stackoverflow.com/questions/tagged/react-navigation)
|
||||
- [Read the documentation](https://reactnavigation.org/)
|
||||
- [Post an issue to the website repository if you'd like to see a documentation change](http://github.com/react-navigation/website)
|
||||
- [Post a feature request to Canny](https://react-navigation.canny.io/feature-requests)
|
||||
- [Write a RFC if you have ideas for how to implement a feature request](https://github.com/react-navigation/rfcs)
|
||||
- [Get help on Discord chat (#react-navigation on Reactiflux)](https://discord.gg/4xEK3nD) or [on StackOverflow](https://stackoverflow.com/questions/tagged/react-navigation)
|
||||
- Search for your issue - it may have already been answered or even fixed in the development branch. However, if you find that an old, closed issue still persists in the latest version, you should open a new issue.
|
||||
|
||||
Bugs with react-navigation must be reproducible *without any external libraries that operate on it*. This means that if you are attempting to use Redux or MobX with it and you think you have found a bug, you must be able to reproduce it without Redux or MobX in this report. Redux related issues belong in [react-navigation-redux-helpers](https://github.com/react-navigation/react-navigation-redux-helpers), and we do not have any first-class integration with MobX at the moment.
|
||||
|
||||
---
|
||||
|
||||
### Current Behavior
|
||||
- _If describing a bug, tell us what happens. Please provide a repository with code and steps to reproduce the bug. **Not providing code that other people can run makes is significantly harder to fix your bug.** Provide a screenshot when possible_
|
||||
- _If suggesting a change/improvement, explain the difference from current behavior_
|
||||
|
||||
- What code are you running and what is happening?
|
||||
- Include a screenshot if it makes sense.
|
||||
|
||||
### Expected Behavior
|
||||
- _If you're describing a bug, tell us what should happen_
|
||||
- _If you're suggesting a change/improvement, tell us how it should work_
|
||||
|
||||
- What do you expect should be happening?
|
||||
- Include a screenshot if it makes sense.
|
||||
|
||||
### How to reproduce
|
||||
|
||||
- You must provide a way to reproduce the problem. If you are having an issue with your machine or build tools, the issue belongs on another repoistory as that is outside of the scope of Rect Navigation.
|
||||
- Either re-create the bug on [Snack](https://snack.expo.io) or link to a GitHub repository with code that reproduces the bug.
|
||||
- Explain how to run the example app and any steps that we need to take to reproduce the issue from the example app.
|
||||
|
||||
### Your Environment
|
||||
|
||||
|
||||
18
.github/PULL_REQUEST_TEMPLATE.md
vendored
@@ -1,17 +1,21 @@
|
||||
Please provide enough information so that others can review your pull request:
|
||||
|
||||
## Motivation
|
||||
|
||||
Explain the **motivation** for making this change. What existing problem does the pull request solve?
|
||||
|
||||
Prefer **small pull requests**. These are much easier to review and more likely to get merged. Make sure the PR does only one thing, otherwise split it.
|
||||
## Test plan
|
||||
|
||||
**Test plan (required)**
|
||||
|
||||
Demonstrate the code is solid. Example: The exact commands you ran and their output, screenshots / videos if the pull request changes UI.
|
||||
Demonstrate the code is solid. Example: the exact commands you ran and their output, screenshots / videos if the pull request changes UI.
|
||||
|
||||
Make sure you test on both platforms if your change affects both platforms.
|
||||
|
||||
The code must pass tests and shouldn't add more Flow errors.
|
||||
The code must pass tests.
|
||||
|
||||
**Code formatting**
|
||||
## Code formatting
|
||||
|
||||
Look around. Match the style of the rest of the codebase.
|
||||
Look around. Match the style of the rest of the codebase. Run `yarn format` before committing.
|
||||
|
||||
## Changelog
|
||||
|
||||
Add an entry under the "Unreleased" heading in [CHANGELOG.md](https://github.com/react-navigation/react-navigation/blob/master/CHANGELOG.md#unreleased) which explains your change.
|
||||
|
||||
4
.gitignore
vendored
@@ -8,8 +8,6 @@ jsconfig.json
|
||||
# NodeJS
|
||||
npm-debug.log
|
||||
node_modules
|
||||
lib-rn
|
||||
lib
|
||||
yarn-error.log
|
||||
|
||||
# OS X
|
||||
@@ -19,4 +17,4 @@ yarn-error.log
|
||||
.exponent
|
||||
|
||||
# Jest
|
||||
coverage
|
||||
coverage
|
||||
|
||||
39
CHANGELOG.md
Normal file
@@ -0,0 +1,39 @@
|
||||
# Changelog
|
||||
|
||||
All notable changes to this project will be documented in this file.
|
||||
|
||||
The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/)
|
||||
and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.html).
|
||||
|
||||
## [Unreleased]
|
||||
|
||||
## [2.5.3] - [2018-06-23](https://github.com/react-navigation/react-navigation/releases/tag/2.5.3)
|
||||
### Fixed
|
||||
- `setParams` applies to the navigation object it is called on even if that is the navigation object for a navigation view (more details in https://github.com/react-navigation/react-navigation/issues/4497)
|
||||
|
||||
## [2.5.2] - [2018-06-23](https://github.com/react-navigation/react-navigation/releases/tag/2.5.2)
|
||||
### Fixed
|
||||
- Update react-navigation-drawer to fix regression in toggleDrawer
|
||||
|
||||
## [2.5.1] - [2018-06-22](https://github.com/react-navigation/react-navigation/releases/tag/2.5.1)
|
||||
### Fixed
|
||||
- `transitionConfig` in stack navigator no longer passes incorrect `fromTransitionProps` when navigating back
|
||||
|
||||
## [2.5.0] - [2018-06-22](https://github.com/react-navigation/react-navigation/releases/tag/2.5.0)
|
||||
### Changed
|
||||
- Refactor internals to make it play more nicely with web
|
||||
|
||||
### Fixed
|
||||
- `const defaultGetStateForAction = SwitchBasedNavigator.router.getStateForAction` no longer throws error.
|
||||
- Updated react-navigation-drawer to 0.4.1 which should fix issues related to automatically closing drawer when changing routes.
|
||||
|
||||
## [2.4.1] - [2018-06-21](https://github.com/react-navigation/react-navigation/releases/tag/2.4.1)
|
||||
### Changed
|
||||
- Improved examples
|
||||
|
||||
[Unreleased]: https://github.com/react-navigation/react-navigation/compare/2.5.3...HEAD
|
||||
[2.5.3]: https://github.com/react-navigation/react-navigation/compare/2.5.2...2.5.3
|
||||
[2.5.2]: https://github.com/react-navigation/react-navigation/compare/2.5.1...2.5.2
|
||||
[2.5.1]: https://github.com/react-navigation/react-navigation/compare/2.5.0...2.5.1
|
||||
[2.5.0]: https://github.com/react-navigation/react-navigation/compare/2.4.1...2.5.0
|
||||
[2.4.1]: https://github.com/react-navigation/react-navigation/compare/2.4.0...2.4.1
|
||||
43
COMMUNITY_RESOURCES.md
Normal file
@@ -0,0 +1,43 @@
|
||||
## Community resources
|
||||
|
||||
A lot of developers poured their knowledge in blog posts, and other repos - we will try to keep here a list of resources to help someone who wants to learn about React Navigation and techniques to handle navigation effectively.
|
||||
|
||||
#### Introduction to the library
|
||||
|
||||
* [Getting Started with React Navigation](https://hackernoon.com/getting-started-with-react-navigation-the-navigation-solution-for-react-native-ea3f4bd786a4)
|
||||
|
||||
#### Basic Tutorials
|
||||
|
||||
* [Basic ReactNavigation Example App and Tutorial](http://docs.nativebase.io/docs/examples/navigation/StackNavigationExample.html)
|
||||
* [Understanding Navigation in React Native](https://www.codementor.io/blessingoraz/understanding-navigation-in-react-native-a3wlcxmzu?published=1#.WXfDlvk_ooE.twitter)
|
||||
* [Comprehensive routing and navigation in React Native made easy](https://medium.com/@kevinle/comprehensive-routing-and-navigation-in-react-native-made-easy-6383e6cdc293)
|
||||
* [Replace a Screen Using React Navigation](https://medium.com/handlebar-labs/replace-a-screen-using-react-navigation-a503eab207eb)
|
||||
|
||||
#### Intermediate Concepts
|
||||
|
||||
* [Integrating React-Navigation and Redux with authentication flow](https://medium.com/@shubhnik/a-comprehensive-guide-for-integrating-react-navigation-with-redux-including-authentication-flow-cb7b90611adf)
|
||||
* [Using React Navigation and Redux in your React Native Application](https://medium.com/modus-create-front-end-development/using-react-navigation-and-redux-in-your-react-native-application-efac33265138)
|
||||
* [React-Navigation, complete Redux state management, tab-bar, and multiple navigators](https://medium.com/@parkerdan/react-navigation-with-complete-redux-state-management-tab-bar-and-multiple-navigators-ed30a69d9a4d)
|
||||
* [Custom Drawer with React-Navigation in React-Native](http://www.skywardsoftwares.co.in/react-native/custom-drawer-with-react-navigation-in-react-native/)
|
||||
* [React Navigation Drawer - a tutorial series](https://shift.infinite.red/react-navigation-drawer-tutorial-a802fc3ee6dc)
|
||||
|
||||
#### Advanced Topics
|
||||
|
||||
* [Full Stack React Native Development using GraphCool and Apollo Subscriptions + React Navigation](https://medium.com/react-native-training/full-stack-react-native-development-using-graphcool-and-apollo-subscriptions-react-navigation-cdb3e1374c05)
|
||||
|
||||
#### Comparisons and Discussion
|
||||
|
||||
* [Migrate from ExNavigation to React Navigation](https://hackernoon.com/migrate-from-exnavigation-to-react-navigation-1af661ec5082)
|
||||
* [Playing with React Navigation and Airbnb's Native Navigation](https://medium.com/@ericvicenti/playing-with-react-navigation-and-airbnbs-native-navigation-4e49fc765489)
|
||||
* [How we restructured our app with React Navigation](https://m.oursky.com/how-we-restructured-our-app-with-react-navigation-98a89e219c26)
|
||||
* [What’s Happening with Navigation in React Native?](https://blog.revisify.com/whats-happening-with-navigation-in-react-native-c193535888c3)
|
||||
|
||||
#### Example Projects
|
||||
|
||||
* [Yaba-Social](https://github.com/allpwrfulroot/yaba-social)
|
||||
* [React Native Boilerplate with React Navigation and Redux integration](https://github.com/verybluebot/react-native-boilerplate)
|
||||
|
||||
#### Libraries
|
||||
|
||||
* [react-navigation-addons](https://github.com/satya164/react-navigation-addons)
|
||||
* [react-navigation-props-mapper](https://github.com/vonovak/react-navigation-props-mapper)
|
||||
13
CONTRIBUTING.md
Normal file
@@ -0,0 +1,13 @@
|
||||
# Contributing to React Navigation
|
||||
|
||||
This library is a community effort: it can only be great if we all help out in one way or another! If you feel like you aren't experienced enough using React Navigation to contribute, you can still make an impact by:
|
||||
|
||||
* Responding to one of the open [issues](https://github.com/react-community/react-navigation/issues). Even if you can't resolve or fully answer a question, asking for more information or clarity on an issue is extremely beneficial for someone to come after you to resolve the issue.
|
||||
* Creating public example repositories or [Snacks](https://snack.expo.io/) of navigation problems you have solved and sharing the links in [Community Resources](https://github.com/react-navigation/react-navigation/blob/master/COMMUNITY_RESOURCES.md).
|
||||
* Answering questions on [Stack Overflow](https://stackoverflow.com/search?q=react-navigation).
|
||||
* Answering questions in our [Reactiflux](https://www.reactiflux.com/) channel.
|
||||
* Providing feedback on the open [PRs](https://github.com/react-navigation/react-navigation/pulls).
|
||||
* Providing feedback on the open [RFCs](https://github.com/react-navigation/rfcs).
|
||||
* Improving the [website](https://github.com/react-navigation/react-navigation.github.io).
|
||||
|
||||
If you would like to submit a pull request, please follow the [Contributors guide](https://reactnavigation.org/docs/contributing.html) to find out how. If you don't know where to start, check the ones with the label [`good first issue`](https://github.com/react-community/react-navigation/labels/good%20first%20issue) - even [fixing a typo in the documentation](https://github.com/react-community/react-navigation/pull/2727) is a worthy contribution!
|
||||
142
README.md
@@ -1,149 +1,53 @@
|
||||
# React Navigation [](https://circleci.com/gh/react-community/react-navigation/tree/master) [](https://badge.fury.io/js/react-navigation) [](https://codecov.io/gh/react-community/react-navigation) [](https://reactnavigation.org/docs/guides/contributors)
|
||||
# React Navigation
|
||||
|
||||
*Learn once, navigate anywhere.*
|
||||
[](https://badge.fury.io/js/react-navigation) [](https://codecov.io/gh/react-navigation/react-navigation) [](https://circleci.com/gh/react-navigation/react-navigation/tree/master) [](https://reactnavigation.org/docs/contributing.html)
|
||||
|
||||
React Navigation is born from the React Native community's need for an extensible yet easy-to-use navigation solution based on Javascript.
|
||||
|
||||
React Navigation is the result of a collaboration between developers from Facebook, Expo and the React community at large: it replaces and improves upon several navigation libraries in the ecosystem, including Ex-Navigation, React Native's Navigator and NavigationExperimental components.
|
||||
|
||||
* [Installation](#installation)
|
||||
* [Community contributions](#community-contributions)
|
||||
* [Introduction to the library](#introduction-to-the-library)
|
||||
* [Basic Tutorials](#basic-tutorials)
|
||||
* [Intermediate Concepts](#intermediate-concepts)
|
||||
* [Advanced Topics](#advanced-topics)
|
||||
* [Comparisons and Discussion](##comparisons-and-discussion)
|
||||
* [Example Projects](#example-projects)
|
||||
* [Libraries](#libraries)
|
||||
* [FAQs](#faqs)
|
||||
* [When is version 1.0.0 going to be released?](#when-is-version-100-going-to-be-released)
|
||||
* [I'm having troubles using the library, what can I do?](#im-having-troubles-using-the-library-what-can-i-do)
|
||||
* [My app is really slow!](#my-app-is-really-slow)
|
||||
* [How can I help?](#how-can-i-help)
|
||||
* [Is this the only library available for navigation?](#is-this-the-only-library-available-for-navigation)
|
||||
* [Can I use this library for web?](#can-i-use-this-library-for-web)
|
||||
* [Code of conduct](#code-of-conduct)
|
||||
* [License](#license)
|
||||
|
||||
## Installation
|
||||
|
||||
Since the library is a JS-based solution, to install the latest version of react-navigation you only need to run:
|
||||
|
||||
```bash
|
||||
yarn add react-navigation
|
||||
```
|
||||
```bash
|
||||
yarn add react-navigation
|
||||
```
|
||||
|
||||
or
|
||||
or
|
||||
|
||||
```bash
|
||||
npm install --save react-navigation
|
||||
```
|
||||
```bash
|
||||
npm install --save react-navigation
|
||||
```
|
||||
|
||||
## Get Started
|
||||
## Documentation
|
||||
|
||||
To learn how the library work, head to the [introduction](https://reactnavigation.org/docs/intro/) on the website for a quick tutorial that will cover all the basics - or try it out [our expo demo](https://exp.host/@react-navigation/NavigationPlayground).
|
||||
* The best way to learn is to follow the [Getting started guide](https://reactnavigation.org/docs/getting-started.html). It guides you through the fundamentals of React Navigation.
|
||||
* The documentation includes solutions for common use cases in the "How do I do ...?" section, such as [tab navigation](https://reactnavigation.org/docs/tab-based-navigation.html) and [Redux integration](https://reactnavigation.org/docs/redux-integration.html).
|
||||
* If you need to build your own navigator, [there's a section for that](https://reactnavigation.org/docs/custom-navigator-overview.html) too.
|
||||
* The [API reference](https://reactnavigation.org/docs/api-reference.html) lists all public APIs.
|
||||
* The [Community Resources](https://github.com/react-navigation/react-navigation/blob/master/COMMUNITY_RESOURCES.md) document lists some other resources submitted to us by people who use React Navigation. Feel free to open a pull request to add your resource to the list.
|
||||
* You can contribute improvements to the documentation [in the website repository](https://github.com/react-navigation/react-navigation.github.io).
|
||||
|
||||
#### Advanced guides
|
||||
## Try it out
|
||||
|
||||
* [Redux integration](https://reactnavigation.org/docs/guides/redux)
|
||||
* [Deep linking](https://reactnavigation.org/docs/guides/linking)
|
||||
|
||||
#### React Navigation API
|
||||
|
||||
* [Navigators](https://reactnavigation.org/docs/navigators/)
|
||||
* [Routers](https://reactnavigation.org/docs/routers/)
|
||||
* [Views](https://reactnavigation.org/docs/views/)
|
||||
|
||||
## Community contributions
|
||||
|
||||
A lot of developers poured their knowledge in blog posts, and other repos - we will try to keep here a list of tutorials and resources to help someone who wants to learn about React Navigation and techniques to handle navigation effectively.
|
||||
|
||||
#### Introduction to the library
|
||||
|
||||
* [Getting Started with React Navigation](https://hackernoon.com/getting-started-with-react-navigation-the-navigation-solution-for-react-native-ea3f4bd786a4)
|
||||
|
||||
#### Basic Tutorials
|
||||
|
||||
* [Basic ReactNavigation Example App and Tutorial](http://docs.nativebase.io/docs/examples/navigation/StackNavigationExample.html)
|
||||
* [Understanding Navigation in React Native](https://www.codementor.io/blessingoraz/understanding-navigation-in-react-native-a3wlcxmzu?published=1#.WXfDlvk_ooE.twitter)
|
||||
* [Comprehensive routing and navigation in React Native made easy](https://medium.com/@kevinle/comprehensive-routing-and-navigation-in-react-native-made-easy-6383e6cdc293)
|
||||
* [Replace a Screen Using React Navigation](https://medium.com/handlebar-labs/replace-a-screen-using-react-navigation-a503eab207eb)
|
||||
|
||||
#### Intermediate Concepts
|
||||
|
||||
* [Using React Navigation and Redux in your React Native Application](https://medium.com/modus-create-front-end-development/using-react-navigation-and-redux-in-your-react-native-application-efac33265138)
|
||||
* [React-Navigation, complete Redux state management, tab-bar, and multiple navigators](https://medium.com/@parkerdan/react-navigation-with-complete-redux-state-management-tab-bar-and-multiple-navigators-ed30a69d9a4d)
|
||||
* [Custom Drawer with React-Navigation in React-Native](http://www.skywardsoftwares.co.in/react-native/custom-drawer-with-react-navigation-in-react-native/)
|
||||
* [React Navigation Drawer - a tutorial series](https://shift.infinite.red/react-navigation-drawer-tutorial-a802fc3ee6dc)
|
||||
|
||||
#### Advanced Topics
|
||||
|
||||
* [Full Stack React Native Development using GraphCool and Apollo Subscriptions + React Navigation](https://medium.com/react-native-training/full-stack-react-native-development-using-graphcool-and-apollo-subscriptions-react-navigation-cdb3e1374c05)
|
||||
|
||||
#### Comparisons and Discussion
|
||||
|
||||
* [Migrate from ExNavigation to React Navigation](https://hackernoon.com/migrate-from-exnavigation-to-react-navigation-1af661ec5082)
|
||||
* [Playing with React Navigation and Airbnb's Native Navigation](https://medium.com/@ericvicenti/playing-with-react-navigation-and-airbnbs-native-navigation-4e49fc765489)
|
||||
* [How we restructured our app with React Navigation](https://m.oursky.com/how-we-restructured-our-app-with-react-navigation-98a89e219c26)
|
||||
* [What’s Happening with Navigation in React Native?](https://blog.revisify.com/whats-happening-with-navigation-in-react-native-c193535888c3)
|
||||
|
||||
#### Example Projects
|
||||
|
||||
* [Yaba-Social](https://github.com/allpwrfulroot/yaba-social)
|
||||
* [React Native Boilerplate with React Navigation and Redux integration](https://github.com/verybluebot/react-native-boilerplate)
|
||||
|
||||
#### Libraries
|
||||
|
||||
* [react-navigation-addons](https://github.com/satya164/react-navigation-addons)
|
||||
* [react-navigation-props-mapper](https://github.com/vonovak/react-navigation-props-mapper)
|
||||
You can also try out the [Navigation Playground app](https://exp.host/@react-navigation/NavigationPlayground) to get a sense for some of the tools built in to React Navigation. The "Fundamentals" in the documentation also include examples you can play with.
|
||||
|
||||
## FAQs
|
||||
|
||||
#### When is version 1.0.0 going to be released?
|
||||
|
||||
As soon as all the tasks [here](https://github.com/react-community/react-navigation/issues/2585) have been completed. You can read more about it in the [blog](https://reactnavigation.org/blog/2017/9/Renewed-v1).
|
||||
|
||||
(in the meantime, you can find the changelog for every release [here](https://github.com/react-community/react-navigation/releases))
|
||||
|
||||
#### I'm having troubles using the library, what can I do?
|
||||
|
||||
Head to the [issues](https://github.com/react-community/react-navigation/issues) and do a quick search: if you think you are experiencing a bug chances are somebody already opened an issue for it. If instead you are having more general problems, use [Stack Overflow](https://stackoverflow.com/search?q=react-navigation) - which is better suited and helps keeping the Issues section of the repo clean. Alternatively you could join the [Reactiflux](https://www.reactiflux.com/) community on Discord where there are React Native and React Navigation channels with helpful people who might be able to answer you.
|
||||
|
||||
You should **only** open a new issue if you believe that you are experiencing a bug or have a feature request, and please **follow** the dedicated template - it will help everyone helping you (and may get closed if it doesn't).
|
||||
|
||||
#### My app is really slow!
|
||||
|
||||
We are aware that the performances can be improved - we will work on this (keep an eye on the roadmap linked above). In the meantime, please refer to these few issues for specific information regarding:
|
||||
|
||||
* [Tab Navigators](https://github.com/react-community/react-navigation/issues/739)
|
||||
|
||||
* [Stack Navigators](https://github.com/react-community/react-navigation/issues/608)
|
||||
|
||||
In particular, refer to [this comment](https://github.com/react-community/react-navigation/issues/608#issuecomment-328635042) (and the [one after](https://github.com/react-community/react-navigation/issues/608#issuecomment-333386346) that) to learn more about how you can try improving the performance of your code.
|
||||
See [the help page](https://reactnavigation.org/en/help.html).
|
||||
|
||||
#### How can I help?
|
||||
|
||||
Glad you ask! This library is a community effort: it can only be great if we all help out in one way or another 😄 . If you feel like you aren't experienced enough using react navigation to contribute, you can still make an impact by:
|
||||
|
||||
1. Responding to one of the open [issues](https://github.com/react-community/react-navigation/issues). Even if you can't resolve or fully answer a question, asking for more information or clarity on an issue is extremely beneficial for someone to come after you to resolve the issue.
|
||||
|
||||
1. Creating public example repos of navigation problems you have solved.
|
||||
|
||||
1. Answering questions on [Stack Overflow](https://stackoverflow.com/search?q=react-navigation). Alternatively, asking questions on Stack Overflow instead of opening an issue.
|
||||
|
||||
1. Answering questions in our [Reactiflux](https://www.reactiflux.com/) channel.
|
||||
|
||||
1. Providing feedback on the open [PRs](https://github.com/react-community/react-navigation/pulls).
|
||||
|
||||
If you feel brave enough you can submit a PR: follow the [Contributors guide](https://reactnavigation.org/docs/guides/contributors) to find out how. If you don't know where to start, check the ones with the label [`Type: Good First Task`](https://github.com/react-community/react-navigation/labels/Type%3A%20Good%20First%20Task) - even [fixing a typo in the documentation](https://github.com/react-community/react-navigation/pull/2727) is a worthy contribution!
|
||||
See our [Contributing Guide](CONTRIBUTING.md)!
|
||||
|
||||
#### Is this the only library available for navigation?
|
||||
|
||||
No: there are some other libraries - which, depending on your project, can be better or worse suited for your project. They differ in the approach and implementation from `react-navigation`, but share the common goal of helping you create a good React Native application; you can find a general round up in the [React Native docs](http://facebook.github.io/react-native/docs/navigation.html).
|
||||
Certainly not! There other libraries - which, depending on your needs, can be better or worse suited for your project. Read more in the [alternative libraries](https://reactnavigation.org/docs/alternatives.html) documentation, and read React Navigation's [pitch & anti-pitch](https://reactnavigation.org/docs/pitch.html) to understand the tradeoffs.
|
||||
|
||||
#### Can I use this library for web?
|
||||
|
||||
This library originally planned to support web too - but at the moment [it is not a priority](https://github.com/react-community/react-navigation/issues/2585#issuecomment-330338793) for v1.0; a lot of work is necessary to reach it as-is and we had to freeze this support (consider it ["experimental"](https://reactnavigation.org/docs/guides/web)).
|
||||
Web support was [not a priority for the 1.0 release](https://github.com/react-community/react-navigation/issues/2585#issuecomment-330338793), but the architecture of this library allows for it (and it has worked in the past). If you would like to lead this charge, please reach out with your ideas for how to move forward on the [RFCs repository](https://github.com/react-navigation/rfcs) and we would be happy to discuss.
|
||||
|
||||
## Code of conduct
|
||||
|
||||
@@ -151,4 +55,4 @@ This library has adopted a Code of Conduct that we expect project participants t
|
||||
|
||||
## License
|
||||
|
||||
React-navigation is licensed under the [BSD 2-clause "Simplified" License](https://github.com/react-community/react-navigation/blob/master/LICENSE).
|
||||
React Navigation is licensed under the [BSD 2-clause "Simplified" License](https://github.com/react-community/react-navigation/blob/master/LICENSE).
|
||||
|
||||
12
assetsTransformer.js
Normal file
@@ -0,0 +1,12 @@
|
||||
/**
|
||||
* This file is needed to hijack asset imports so that test files don't attempt
|
||||
* to import them as JavaScript modules.
|
||||
* See https://github.com/facebook/jest/issues/2663#issuecomment-317109798
|
||||
*/
|
||||
const path = require('path');
|
||||
|
||||
module.exports = {
|
||||
process(src, filename, config, options) {
|
||||
return 'module.exports = ' + JSON.stringify(path.basename(filename)) + ';';
|
||||
},
|
||||
};
|
||||
@@ -1,205 +0,0 @@
|
||||
# DrawerNavigator
|
||||
|
||||
Used to easily set up a screen with a drawer navigation. For a live example please see [our expo demo](https://exp.host/@react-navigation/NavigationPlayground).
|
||||
|
||||
```js
|
||||
class MyHomeScreen extends React.Component {
|
||||
static navigationOptions = {
|
||||
drawerLabel: 'Home',
|
||||
drawerIcon: ({ tintColor }) => (
|
||||
<Image
|
||||
source={require('./chats-icon.png')}
|
||||
style={[styles.icon, {tintColor: tintColor}]}
|
||||
/>
|
||||
),
|
||||
};
|
||||
|
||||
render() {
|
||||
return (
|
||||
<Button
|
||||
onPress={() => this.props.navigation.navigate('Notifications')}
|
||||
title="Go to notifications"
|
||||
/>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class MyNotificationsScreen extends React.Component {
|
||||
static navigationOptions = {
|
||||
drawerLabel: 'Notifications',
|
||||
drawerIcon: ({ tintColor }) => (
|
||||
<Image
|
||||
source={require('./notif-icon.png')}
|
||||
style={[styles.icon, {tintColor: tintColor}]}
|
||||
/>
|
||||
),
|
||||
};
|
||||
|
||||
render() {
|
||||
return (
|
||||
<Button
|
||||
onPress={() => this.props.navigation.goBack()}
|
||||
title="Go back home"
|
||||
/>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
const styles = StyleSheet.create({
|
||||
icon: {
|
||||
width: 24,
|
||||
height: 24,
|
||||
},
|
||||
});
|
||||
|
||||
const MyApp = DrawerNavigator({
|
||||
Home: {
|
||||
screen: MyHomeScreen,
|
||||
},
|
||||
Notifications: {
|
||||
screen: MyNotificationsScreen,
|
||||
},
|
||||
});
|
||||
```
|
||||
|
||||
To open and close drawer, navigate to `'DrawerOpen'` and `'DrawerClose'` respectively.
|
||||
|
||||
```js
|
||||
this.props.navigation.navigate('DrawerOpen'); // open drawer
|
||||
this.props.navigation.navigate('DrawerClose'); // close drawer
|
||||
```
|
||||
If you would like to toggle the drawer you can navigate to `'DrawerToggle'`, and this will choose which navigation is appropriate for you given the drawers current state.
|
||||
|
||||
```js
|
||||
// fires 'DrawerOpen'/'DrawerClose' accordingly
|
||||
this.props.navigation.navigate('DrawerToggle');
|
||||
```
|
||||
|
||||
## API Definition
|
||||
|
||||
```js
|
||||
DrawerNavigator(RouteConfigs, DrawerNavigatorConfig)
|
||||
```
|
||||
|
||||
### RouteConfigs
|
||||
|
||||
The route configs object is a mapping from route name to a route config, which tells the navigator what to present for that route, see [example](/docs/api/navigators/StackNavigator.md#routeconfigs) from `StackNavigator`.
|
||||
|
||||
|
||||
### DrawerNavigatorConfig
|
||||
- `drawerWidth` - Width of the drawer.
|
||||
- `drawerPosition` - Options are `left` or `right`. Default is `left` position.
|
||||
- `contentComponent` - Component used to render the content of the drawer, for example, navigation items. Receives the `navigation` prop for the drawer. Defaults to `DrawerItems`. For more information, see below.
|
||||
- `contentOptions` - Configure the drawer content, see below.
|
||||
- `useNativeAnimations` - Enable native animations. Default is `true`.
|
||||
- `drawerBackgroundColor` - Use the Drawer background for some color. The Default is `white`.
|
||||
|
||||
#### Example:
|
||||
|
||||
Default the `DrawerView` isn't scrollable.
|
||||
To achieve a scrollable `View`, you have to use the `contentComponent` to customize the container,
|
||||
as you can see in the example below.
|
||||
|
||||
```js
|
||||
{
|
||||
drawerWidth: 200,
|
||||
drawerPosition: 'right',
|
||||
contentComponent: props => <ScrollView><DrawerItems {...props} /></ScrollView>,
|
||||
drawerBackgroundColor: 'transparent'
|
||||
}
|
||||
```
|
||||
|
||||
Several options get passed to the underlying router to modify navigation logic:
|
||||
|
||||
- `initialRouteName` - The routeName for the initial route.
|
||||
- `order` - Array of routeNames which defines the order of the drawer items.
|
||||
- `paths` - Provide a mapping of routeName to path config, which overrides the paths set in the routeConfigs.
|
||||
- `backBehavior` - Should the back button cause switch to the initial route? If yes, set to `initialRoute`, otherwise `none`. Defaults to `initialRoute` behavior.
|
||||
|
||||
### Providing a custom `contentComponent`
|
||||
|
||||
You can easily override the default component used by `react-navigation`:
|
||||
|
||||
```js
|
||||
import { DrawerItems } from 'react-navigation';
|
||||
|
||||
const CustomDrawerContentComponent = (props) => (
|
||||
<View style={styles.container}>
|
||||
<DrawerItems {...props} />
|
||||
</View>
|
||||
);
|
||||
|
||||
const styles = StyleSheet.create({
|
||||
container: {
|
||||
flex: 1,
|
||||
},
|
||||
});
|
||||
```
|
||||
|
||||
### `contentOptions` for `DrawerItems`
|
||||
|
||||
- `items` - the array of routes, can be modified or overridden
|
||||
- `activeItemKey` - key identifying the active route
|
||||
- `activeTintColor` - label and icon color of the active label
|
||||
- `activeBackgroundColor` - background color of the active label
|
||||
- `inactiveTintColor` - label and icon color of the inactive label
|
||||
- `inactiveBackgroundColor` - background color of the inactive label
|
||||
- `onItemPress(route)` - function to be invoked when an item is pressed
|
||||
- `itemsContainerForceInset` - override default forceInset on the SafeAreaView that wraps the items container component
|
||||
- `itemsContainerStyle` - style object for the content section
|
||||
- `itemStyle` - style object for the single item, which can contain an Icon and/or a Label
|
||||
- `labelStyle` - style object to overwrite `Text` style inside content section, when your label is a string
|
||||
- `iconContainerStyle` - style object to overwrite `View` icon container styles.
|
||||
|
||||
#### Example:
|
||||
|
||||
```js
|
||||
contentOptions: {
|
||||
activeTintColor: '#e91e63',
|
||||
itemsContainerStyle: {
|
||||
marginVertical: 0,
|
||||
},
|
||||
iconContainerStyle: {
|
||||
opacity: 1
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Screen Navigation Options
|
||||
|
||||
#### `title`
|
||||
|
||||
Generic title that can be used as a fallback for `headerTitle` and `drawerLabel`
|
||||
|
||||
#### `drawerLabel`
|
||||
|
||||
String, React Element or a function that given `{ focused: boolean, tintColor: string }` returns a React.Node, to display in drawer sidebar. When undefined, scene `title` is used
|
||||
|
||||
#### `drawerIcon`
|
||||
|
||||
React Element or a function, that given `{ focused: boolean, tintColor: string }` returns a React.Node, to display in drawer sidebar
|
||||
|
||||
#### `drawerLockMode`
|
||||
|
||||
Specifies the [lock mode](https://facebook.github.io/react-native/docs/drawerlayoutandroid.html#drawerlockmode) of the drawer. This can also update dynamically by using screenProps.drawerLockMode on your top level router.
|
||||
|
||||
### Navigator Props
|
||||
|
||||
The navigator component created by `DrawerNavigator(...)` takes the following props:
|
||||
|
||||
- `screenProps` - Pass down extra options to child screens, for example:
|
||||
|
||||
|
||||
```jsx
|
||||
const DrawerNav = DrawerNavigator({
|
||||
// config
|
||||
});
|
||||
|
||||
<DrawerNav
|
||||
screenProps={/* this prop will get passed to the screen components and nav options as props.screenProps */}
|
||||
/>
|
||||
```
|
||||
|
||||
### Nesting `DrawerNavigation`
|
||||
|
||||
Please bear in mind that if you nest the DrawerNavigation, the drawer will show below the parent navigation.
|
||||
@@ -1,63 +0,0 @@
|
||||
# Navigators
|
||||
|
||||
Navigators allow you to define your application's navigation structure. Navigators also render common elements such as headers and tab bars which you can configure.
|
||||
|
||||
Under the hood, navigators are plain React components.
|
||||
|
||||
## Built-in Navigators
|
||||
|
||||
`react-navigation` includes the following functions to help you create navigators:
|
||||
|
||||
- [StackNavigator](/docs/navigators/stack) - Renders one screen at a time and provides transitions between screens. When a new screen is opened it is placed on top of the stack.
|
||||
- [TabNavigator](/docs/navigators/tab) - Renders a tab bar that lets the user switch between several screens
|
||||
- [DrawerNavigator](/docs/navigators/drawer) - Provides a drawer that slides in from the left of the screen
|
||||
|
||||
## Rendering screens with Navigators
|
||||
|
||||
The navigators render application screens which are just React components.
|
||||
|
||||
To learn how to create screens, read about:
|
||||
- [Screen `navigation` prop](/docs/navigators/navigation-prop) to allow the screen to dispatch navigation actions, such as opening another screen
|
||||
- [Screen `navigationOptions`](/docs/navigators/navigation-options) to customize how the screen gets presented by the navigator (e.g. header title, tab label)
|
||||
|
||||
### Calling Navigate on Top Level Component
|
||||
|
||||
In case you want to use Navigator from the same level you declare it you can use react's [`ref`](https://facebook.github.io/react/docs/refs-and-the-dom.html#the-ref-callback-attribute) option:
|
||||
```js
|
||||
import { NavigationActions } from 'react-navigation';
|
||||
|
||||
const AppNavigator = StackNavigator(SomeAppRouteConfigs);
|
||||
|
||||
class App extends React.Component {
|
||||
someEvent() {
|
||||
// call navigate for AppNavigator here:
|
||||
this.navigator && this.navigator.dispatch(
|
||||
NavigationActions.navigate({ routeName: someRouteName })
|
||||
);
|
||||
}
|
||||
render() {
|
||||
return (
|
||||
<AppNavigator ref={nav => { this.navigator = nav; }} />
|
||||
);
|
||||
}
|
||||
}
|
||||
```
|
||||
Please notice that this solution should only be used on the top level navigator.
|
||||
|
||||
## Navigation Containers
|
||||
|
||||
The built in navigators can automatically behave like top-level navigators when the navigation prop is missing. This functionality provides a transparent navigation container, which is where the top-level navigation prop comes from.
|
||||
|
||||
When rendering one of the included navigators, the navigation prop is optional. When it is missing, the container steps in and manages its own navigation state. It also handles URLs, external linking, and Android back button integration.
|
||||
|
||||
For the purpose of convenience, the built-in navigators have this ability because behind the scenes they use `createNavigationContainer`. Usually, navigators require a navigation prop in order to function.
|
||||
|
||||
Top-level navigators accept the following props:
|
||||
|
||||
### `onNavigationStateChange(prevState, newState, action)`
|
||||
|
||||
Function that gets called every time navigation state managed by the navigator changes. It receives the previous state, the new state of the navigation and the action that issued state change. By default it prints state changes to the console.
|
||||
|
||||
### `uriPrefix`
|
||||
|
||||
The prefix of the URIs that the app might handle. This will be used when handling a [deep link](/docs/guides/linking) to extract the path passed to the router.
|
||||
@@ -1,224 +0,0 @@
|
||||
# StackNavigator
|
||||
|
||||
Provides a way for your app to transition between screens where each new screen is placed on top of a stack.
|
||||
|
||||
By default the StackNavigator is configured to have the familiar iOS and Android look & feel: new screens slide in from the right on iOS, fade in from the bottom on Android. On iOS the StackNavigator can also be configured to a modal style where screens slide in from the bottom.
|
||||
|
||||
```jsx
|
||||
|
||||
class MyHomeScreen extends React.Component {
|
||||
static navigationOptions = {
|
||||
title: 'Home',
|
||||
}
|
||||
|
||||
render() {
|
||||
return (
|
||||
<Button
|
||||
onPress={() => this.props.navigation.navigate('Profile', {name: 'Lucy'})}
|
||||
title="Go to Lucy's profile"
|
||||
/>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
const ModalStack = StackNavigator({
|
||||
Home: {
|
||||
screen: MyHomeScreen,
|
||||
},
|
||||
Profile: {
|
||||
path: 'people/:name',
|
||||
screen: MyProfileScreen,
|
||||
},
|
||||
});
|
||||
```
|
||||
|
||||
## API Definition
|
||||
|
||||
```js
|
||||
StackNavigator(RouteConfigs, StackNavigatorConfig)
|
||||
```
|
||||
|
||||
### RouteConfigs
|
||||
|
||||
The route configs object is a mapping from route name to a route config, which tells the navigator what to present for that route.
|
||||
|
||||
```js
|
||||
StackNavigator({
|
||||
|
||||
// For each screen that you can navigate to, create a new entry like this:
|
||||
Profile: {
|
||||
|
||||
// `ProfileScreen` is a React component that will be the main content of the screen.
|
||||
screen: ProfileScreen,
|
||||
// When `ProfileScreen` is loaded by the StackNavigator, it will be given a `navigation` prop.
|
||||
|
||||
// Optional: When deep linking or using react-navigation in a web app, this path is used:
|
||||
path: 'people/:name',
|
||||
// The action and route params are extracted from the path.
|
||||
|
||||
// Optional: Override the `navigationOptions` for the screen
|
||||
navigationOptions: ({navigation}) => ({
|
||||
title: `${navigation.state.params.name}'s Profile'`,
|
||||
}),
|
||||
},
|
||||
|
||||
...MyOtherRoutes,
|
||||
});
|
||||
```
|
||||
|
||||
### StackNavigatorConfig
|
||||
|
||||
Options for the router:
|
||||
|
||||
- `initialRouteName` - Sets the default screen of the stack. Must match one of the keys in route configs.
|
||||
- `initialRouteParams` - The params for the initial route
|
||||
- `navigationOptions` - Default navigation options to use for screens
|
||||
- `paths` - A mapping of overrides for the paths set in the route configs
|
||||
|
||||
Visual options:
|
||||
|
||||
- `mode` - Defines the style for rendering and transitions:
|
||||
- `card` - Use the standard iOS and Android screen transitions. This is the default.
|
||||
- `modal` - Make the screens slide in from the bottom which is a common iOS pattern. Only works on iOS, has no effect on Android.
|
||||
- `headerMode` - Specifies how the header should be rendered:
|
||||
- `float` - Render a single header that stays at the top and animates as screens are changed. This is a common pattern on iOS.
|
||||
- `screen` - Each screen has a header attached to it and the header fades in and out together with the screen. This is a common pattern on Android.
|
||||
- `none` - No header will be rendered.
|
||||
- `cardStyle` - Use this prop to override or extend the default style for an individual card in stack.
|
||||
- `transitionConfig` - Function to return an object that is merged with the default screen transitions (take a look at TransitionConfig in [type definitions](https://github.com/react-community/react-navigation/blob/master/src/TypeDefinition.js)). Provided function will be passed the following arguments:
|
||||
- `transitionProps` - Transition props for the new screen.
|
||||
- `prevTransitionProps` - Transitions props for the old screen.
|
||||
- `isModal` - Boolean specifying if screen is modal.
|
||||
- `onTransitionStart` - Function to be invoked when the card transition animation is about to start.
|
||||
- `onTransitionEnd` - Function to be invoked once the card transition animation completes.
|
||||
|
||||
|
||||
### Screen Navigation Options
|
||||
|
||||
#### `title`
|
||||
|
||||
String that can be used as a fallback for `headerTitle`. Additionally, will be used as a fallback for `tabBarLabel` (if nested in a TabNavigator) or `drawerLabel` (if nested in a DrawerNavigator).
|
||||
|
||||
#### `header`
|
||||
|
||||
React Element or a function that given `HeaderProps` returns a React Element, to display as a header. Setting to `null` hides header.
|
||||
|
||||
#### `headerTitle`
|
||||
|
||||
String or React Element used by the header. Defaults to scene `title`
|
||||
|
||||
#### `headerTitleAllowFontScaling`
|
||||
|
||||
Whether header title font should scale to respect Text Size accessibility settings. Defaults to true
|
||||
|
||||
#### `headerBackTitle`
|
||||
|
||||
Title string used by the back button on iOS, or `null` to disable label. Defaults to the previous scene's `headerTitle`
|
||||
|
||||
#### `headerTruncatedBackTitle`
|
||||
|
||||
Title string used by the back button when `headerBackTitle` doesn't fit on the screen. `"Back"` by default.
|
||||
|
||||
#### `headerRight`
|
||||
|
||||
React Element to display on the right side of the header
|
||||
|
||||
#### `headerLeft`
|
||||
|
||||
React Element to display on the left side of the header
|
||||
|
||||
#### `headerStyle`
|
||||
|
||||
Style object for the header
|
||||
|
||||
#### `headerTitleStyle`
|
||||
|
||||
Style object for the title component
|
||||
|
||||
#### `headerBackTitleStyle`
|
||||
|
||||
Style object for the back title
|
||||
|
||||
#### `headerTintColor`
|
||||
|
||||
Tint color for the header
|
||||
|
||||
#### `headerPressColorAndroid`
|
||||
|
||||
Color for material ripple (Android >= 5.0 only)
|
||||
|
||||
#### `gesturesEnabled`
|
||||
|
||||
Whether you can use gestures to dismiss this screen. Defaults to true on iOS, false on Android.
|
||||
|
||||
#### `gestureResponseDistance`
|
||||
|
||||
Object to override the distance of touch start from the edge of the screen to recognize gestures. It takes the following properties:
|
||||
|
||||
- `horizontal` - *number* - Distance for horizontal direction. Defaults to 25.
|
||||
- `vertical` - *number* - Distance for vertical direction. Defaults to 135.
|
||||
|
||||
### Navigator Props
|
||||
|
||||
The navigator component created by `StackNavigator(...)` takes the following props:
|
||||
|
||||
- `screenProps` - Pass down extra options to child screens, for example:
|
||||
|
||||
|
||||
```jsx
|
||||
const SomeStack = StackNavigator({
|
||||
// config
|
||||
});
|
||||
|
||||
<SomeStack
|
||||
screenProps={/* this prop will get passed to the screen components as this.props.screenProps */}
|
||||
/>
|
||||
```
|
||||
|
||||
### Examples
|
||||
|
||||
See the examples [SimpleStack.js](https://github.com/react-community/react-navigation/tree/master/examples/NavigationPlayground/js/SimpleStack.js) and [ModalStack.js](https://github.com/react-community/react-navigation/tree/master/examples/NavigationPlayground/js/ModalStack.js) which you can run locally as part of the [NavigationPlayground](https://github.com/react-community/react-navigation/tree/master/examples/NavigationPlayground) app.
|
||||
|
||||
You can view these examples directly on your phone by visiting [our expo demo](https://exp.host/@react-navigation/NavigationPlayground).
|
||||
|
||||
#### Modal StackNavigator with Custom Screen Transitions
|
||||
|
||||
```js
|
||||
const ModalNavigator = StackNavigator(
|
||||
{
|
||||
Main: { screen: Main },
|
||||
Login: { screen: Login },
|
||||
},
|
||||
{
|
||||
headerMode: 'none',
|
||||
mode: 'modal',
|
||||
navigationOptions: {
|
||||
gesturesEnabled: false,
|
||||
},
|
||||
transitionConfig: () => ({
|
||||
transitionSpec: {
|
||||
duration: 300,
|
||||
easing: Easing.out(Easing.poly(4)),
|
||||
timing: Animated.timing,
|
||||
},
|
||||
screenInterpolator: sceneProps => {
|
||||
const { layout, position, scene } = sceneProps;
|
||||
const { index } = scene;
|
||||
|
||||
const height = layout.initHeight;
|
||||
const translateY = position.interpolate({
|
||||
inputRange: [index - 1, index, index + 1],
|
||||
outputRange: [height, 0, 0],
|
||||
});
|
||||
|
||||
const opacity = position.interpolate({
|
||||
inputRange: [index - 1, index - 0.99, index],
|
||||
outputRange: [0, 1, 1],
|
||||
});
|
||||
|
||||
return { opacity, transform: [{ translateY }] };
|
||||
},
|
||||
}),
|
||||
}
|
||||
);
|
||||
```
|
||||
@@ -1,197 +0,0 @@
|
||||
# TabNavigator
|
||||
|
||||
Used to easily set up a screen with several tabs with a TabRouter. For a live example please see [our expo demo](https://exp.host/@react-navigation/NavigationPlayground).
|
||||
|
||||
```js
|
||||
class MyHomeScreen extends React.Component {
|
||||
static navigationOptions = {
|
||||
tabBarLabel: 'Home',
|
||||
// Note: By default the icon is only shown on iOS. Search the showIcon option below.
|
||||
tabBarIcon: ({ tintColor }) => (
|
||||
<Image
|
||||
source={require('./chats-icon.png')}
|
||||
style={[styles.icon, {tintColor: tintColor}]}
|
||||
/>
|
||||
),
|
||||
};
|
||||
|
||||
render() {
|
||||
return (
|
||||
<Button
|
||||
onPress={() => this.props.navigation.navigate('Notifications')}
|
||||
title="Go to notifications"
|
||||
/>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class MyNotificationsScreen extends React.Component {
|
||||
static navigationOptions = {
|
||||
tabBarLabel: 'Notifications',
|
||||
tabBarIcon: ({ tintColor }) => (
|
||||
<Image
|
||||
source={require('./notif-icon.png')}
|
||||
style={[styles.icon, {tintColor: tintColor}]}
|
||||
/>
|
||||
),
|
||||
};
|
||||
|
||||
render() {
|
||||
return (
|
||||
<Button
|
||||
onPress={() => this.props.navigation.goBack()}
|
||||
title="Go back home"
|
||||
/>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
const styles = StyleSheet.create({
|
||||
icon: {
|
||||
width: 26,
|
||||
height: 26,
|
||||
},
|
||||
});
|
||||
|
||||
const MyApp = TabNavigator({
|
||||
Home: {
|
||||
screen: MyHomeScreen,
|
||||
},
|
||||
Notifications: {
|
||||
screen: MyNotificationsScreen,
|
||||
},
|
||||
}, {
|
||||
tabBarPosition: 'top',
|
||||
animationEnabled: true,
|
||||
tabBarOptions: {
|
||||
activeTintColor: '#e91e63',
|
||||
},
|
||||
});
|
||||
```
|
||||
|
||||
## API Definition
|
||||
|
||||
```js
|
||||
TabNavigator(RouteConfigs, TabNavigatorConfig)
|
||||
```
|
||||
|
||||
### RouteConfigs
|
||||
|
||||
The route configs object is a mapping from route name to a route config, which tells the navigator what to present for that route, see [example](/docs/api/navigators/StackNavigator.md#routeconfigs) from `StackNavigator`.
|
||||
|
||||
### TabNavigatorConfig
|
||||
|
||||
- `tabBarComponent` - Component to use as the tab bar, e.g. `TabBarBottom`
|
||||
(this is the default on iOS), `TabBarTop`
|
||||
(this is the default on Android).
|
||||
- `tabBarPosition` - Position of the tab bar, can be `'top'` or `'bottom'`.
|
||||
- `swipeEnabled` - Whether to allow swiping between tabs.
|
||||
- `animationEnabled` - Whether to animate when changing tabs.
|
||||
- `lazy` - Whether to lazily render tabs as needed as opposed to rendering them upfront.
|
||||
- `initialLayout` - Optional object containing the initial `height` and `width`, can be passed to prevent the one frame delay in [react-native-tab-view](https://github.com/react-native-community/react-native-tab-view#avoid-one-frame-delay) rendering.
|
||||
- `tabBarOptions` - Configure the tab bar, see below.
|
||||
|
||||
Several options get passed to the underlying router to modify navigation logic:
|
||||
|
||||
- `initialRouteName` - The routeName for the initial tab route when first loading.
|
||||
- `order` - Array of routeNames which defines the order of the tabs.
|
||||
- `paths` - Provide a mapping of routeName to path config, which overrides the paths set in the routeConfigs.
|
||||
- `backBehavior` - Should the back button cause a tab switch to the initial tab? If yes, set to `initialRoute`, otherwise `none`. Defaults to `initialRoute` behavior.
|
||||
|
||||
### `tabBarOptions` for `TabBarBottom` (default tab bar on iOS)
|
||||
|
||||
- `activeTintColor` - Label and icon color of the active tab.
|
||||
- `activeBackgroundColor` - Background color of the active tab.
|
||||
- `inactiveTintColor` - Label and icon color of the inactive tab.
|
||||
- `inactiveBackgroundColor` - Background color of the inactive tab.
|
||||
- `showLabel` - Whether to show label for tab, default is true.
|
||||
- `style` - Style object for the tab bar.
|
||||
- `labelStyle` - Style object for the tab label.
|
||||
- `tabStyle` - Style object for the tab.
|
||||
- `allowFontScaling` - Whether label font should scale to respect Text Size accessibility settings, default is true.
|
||||
|
||||
Example:
|
||||
|
||||
```js
|
||||
tabBarOptions: {
|
||||
activeTintColor: '#e91e63',
|
||||
labelStyle: {
|
||||
fontSize: 12,
|
||||
},
|
||||
style: {
|
||||
backgroundColor: 'blue',
|
||||
},
|
||||
}
|
||||
```
|
||||
|
||||
### `tabBarOptions` for `TabBarTop` (default tab bar on Android)
|
||||
|
||||
- `activeTintColor` - Label and icon color of the active tab.
|
||||
- `inactiveTintColor` - Label and icon color of the inactive tab.
|
||||
- `showIcon` - Whether to show icon for tab, default is false.
|
||||
- `showLabel` - Whether to show label for tab, default is true.
|
||||
- `upperCaseLabel` - Whether to make label uppercase, default is true.
|
||||
- `pressColor` - Color for material ripple (Android >= 5.0 only).
|
||||
- `pressOpacity` - Opacity for pressed tab (iOS and Android < 5.0 only).
|
||||
- `scrollEnabled` - Whether to enable scrollable tabs.
|
||||
- `tabStyle` - Style object for the tab.
|
||||
- `indicatorStyle` - Style object for the tab indicator (line at the bottom of the tab).
|
||||
- `labelStyle` - Style object for the tab label.
|
||||
- `iconStyle` - Style object for the tab icon.
|
||||
- `style` - Style object for the tab bar.
|
||||
- `allowFontScaling` - Whether label font should scale to respect Text Size accessibility settings, default is true.
|
||||
|
||||
Example:
|
||||
|
||||
```js
|
||||
tabBarOptions: {
|
||||
labelStyle: {
|
||||
fontSize: 12,
|
||||
},
|
||||
tabStyle: {
|
||||
width: 100,
|
||||
},
|
||||
style: {
|
||||
backgroundColor: 'blue',
|
||||
},
|
||||
}
|
||||
```
|
||||
|
||||
### Screen Navigation Options
|
||||
|
||||
#### `title`
|
||||
|
||||
Generic title that can be used as a fallback for `headerTitle` and `tabBarLabel`.
|
||||
|
||||
#### `tabBarVisible`
|
||||
|
||||
True or false to show or hide the tab bar, if not set then defaults to true.
|
||||
|
||||
#### `tabBarIcon`
|
||||
|
||||
React Element or a function that given `{ focused: boolean, tintColor: string }` returns a React.Node, to display in tab bar.
|
||||
|
||||
#### `tabBarLabel`
|
||||
|
||||
Title string of a tab displayed in the tab bar or React Element or a function that given `{ focused: boolean, tintColor: string }` returns a React.Node, to display in tab bar. When undefined, scene `title` is used. To hide, see `tabBarOptions.showLabel` in the previous section.
|
||||
|
||||
#### `tabBarOnPress`
|
||||
|
||||
Callback to handle tap events; arguments are the `scene: { route, index }` that was tapped and a `jumpToIndex` method that can perform the navigation for you.
|
||||
|
||||
### Navigator Props
|
||||
|
||||
The navigator component created by `TabNavigator(...)` takes the following props:
|
||||
|
||||
- `screenProps` - Pass down extra options to child screens and navigation options, for example:
|
||||
|
||||
|
||||
```jsx
|
||||
const TabNav = TabNavigator({
|
||||
// config
|
||||
});
|
||||
|
||||
<TabNav
|
||||
screenProps={/* this prop will get passed to the screen components as this.props.screenProps */}
|
||||
/>
|
||||
```
|
||||
@@ -1,131 +0,0 @@
|
||||
# Routers
|
||||
|
||||
Routers define a component's navigation state, and they allow the developer to define paths and actions that can be handled.
|
||||
|
||||
|
||||
## Built-In Routers
|
||||
|
||||
`react-navigation` ships with a few standard routers:
|
||||
|
||||
- [StackRouter](/docs/routers/stack)
|
||||
- [TabRouter](/docs/routers/tab)
|
||||
|
||||
|
||||
## Using Routers
|
||||
|
||||
To make a navigator manually, put a static `router` on a component. (To quickly make a navigator with a built-in component, it may be easier to use a [Navigator Factory](/docs/navigators) instead)
|
||||
|
||||
```js
|
||||
class MyNavigator extends React.Component {
|
||||
static router = StackRouter(routes, config);
|
||||
...
|
||||
}
|
||||
```
|
||||
|
||||
Now you can use this component as a `screen` in another navigator, and the navigation logic for `MyNavigator` will be defined by this `StackRouter`.
|
||||
|
||||
|
||||
## Customizing Routers
|
||||
|
||||
See the [Custom Router API spec](/docs/routers/api) to learn about the API of `StackRouter` and `TabRouter`. You can override the router functions as you see fit:
|
||||
|
||||
### Custom Navigation Actions
|
||||
|
||||
To override navigation behavior, you can override the navigation state logic in `getStateForAction`, and manually manipulate the `routes` and `index`.
|
||||
|
||||
```js
|
||||
const MyApp = StackNavigator({
|
||||
Home: { screen: HomeScreen },
|
||||
Profile: { screen: ProfileScreen },
|
||||
}, {
|
||||
initialRouteName: 'Home',
|
||||
})
|
||||
|
||||
const defaultGetStateForAction = MyApp.router.getStateForAction;
|
||||
|
||||
MyApp.router.getStateForAction = (action, state) => {
|
||||
if (state && action.type === 'PushTwoProfiles') {
|
||||
const routes = [
|
||||
...state.routes,
|
||||
{key: 'A', routeName: 'Profile', params: { name: action.name1 }},
|
||||
{key: 'B', routeName: 'Profile', params: { name: action.name2 }},
|
||||
];
|
||||
return {
|
||||
...state,
|
||||
routes,
|
||||
index: routes.length - 1,
|
||||
};
|
||||
}
|
||||
return defaultGetStateForAction(action, state);
|
||||
};
|
||||
```
|
||||
|
||||
### Blocking Navigation Actions
|
||||
|
||||
Sometimes you may want to prevent some navigation activity, depending on your route.
|
||||
|
||||
```js
|
||||
import { NavigationActions } from 'react-navigation'
|
||||
|
||||
const MyStackRouter = StackRouter({
|
||||
Home: { screen: HomeScreen },
|
||||
Profile: { screen: ProfileScreen },
|
||||
}, {
|
||||
initialRouteName: 'Home',
|
||||
})
|
||||
|
||||
const defaultGetStateForAction = MyStackRouter.router.getStateForAction;
|
||||
|
||||
MyStackRouter.router.getStateForAction = (action, state) => {
|
||||
if (
|
||||
state &&
|
||||
action.type === NavigationActions.BACK &&
|
||||
state.routes[state.index].params.isEditing
|
||||
) {
|
||||
// Returning null from getStateForAction means that the action
|
||||
// has been handled/blocked, but there is not a new state
|
||||
return null;
|
||||
}
|
||||
|
||||
return defaultGetStateForAction(action, state);
|
||||
};
|
||||
```
|
||||
|
||||
|
||||
### Handling Custom URIs
|
||||
|
||||
Perhaps your app has a unique URI which the built-in routers cannot handle. You can always extend the router `getActionForPathAndParams`.
|
||||
|
||||
```js
|
||||
|
||||
import { NavigationActions } from 'react-navigation'
|
||||
|
||||
const MyApp = StackNavigator({
|
||||
Home: { screen: HomeScreen },
|
||||
Profile: { screen: ProfileScreen },
|
||||
}, {
|
||||
initialRouteName: 'Home',
|
||||
})
|
||||
const previousGetActionForPathAndParams = MyApp.router.getActionForPathAndParams;
|
||||
|
||||
Object.assign(MyApp.router, {
|
||||
getActionForPathAndParams(path, params) {
|
||||
if (
|
||||
path === 'my/custom/path' &&
|
||||
params.magic === 'yes'
|
||||
) {
|
||||
// returns a profile navigate action for /my/custom/path?magic=yes
|
||||
return NavigationActions.navigate({
|
||||
routeName: 'Profile',
|
||||
action: NavigationActions.navigate({
|
||||
// This child action will get passed to the child router
|
||||
// ProfileScreen.router.getStateForAction to get the child
|
||||
// navigation state.
|
||||
routeName: 'Friends',
|
||||
}),
|
||||
});
|
||||
}
|
||||
return previousGetActionForPathAndParams(path, params);
|
||||
},
|
||||
});
|
||||
```
|
||||
@@ -1,103 +0,0 @@
|
||||
## Custom Router API
|
||||
|
||||
You can make your own router by building an object with the following functions:
|
||||
|
||||
```js
|
||||
const MyRouter = {
|
||||
getStateForAction: (action, state) => ({}),
|
||||
getActionForPathAndParams: (path, params) => null,
|
||||
getPathAndParamsForState: (state) => null,
|
||||
getComponentForState: (state) => MyScreen,
|
||||
getComponentForRouteName: (routeName) => MyScreen,
|
||||
};
|
||||
|
||||
// Now, you can make a navigator by putting the router on it:
|
||||
class MyNavigator extends React.Component {
|
||||
static router = MyRouter;
|
||||
render() {
|
||||
...
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||

|
||||
|
||||
|
||||
### `getStateForAction(action, state)`
|
||||
|
||||
Defines the navigation state in response to a given action. This function will be run when an action gets passed into `props.navigation.dispatch(`, or when any of the helper functions are called, like `navigation.navigate(`.
|
||||
|
||||
Typically this should return a navigation state, with the following form:
|
||||
|
||||
```
|
||||
{
|
||||
index: 1, // identifies which route in the routes array is active
|
||||
routes: [
|
||||
{
|
||||
// Each route needs a name to identify the type.
|
||||
routeName: 'MyRouteName',
|
||||
|
||||
// A unique identifier for this route in the routes array:
|
||||
key: 'myroute-123',
|
||||
// (used to specify the re-ordering of routes)
|
||||
|
||||
// Routes can have any data, as long as key and routeName are correct
|
||||
...randomRouteData,
|
||||
},
|
||||
...moreRoutes,
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
If the router has handled the action externally, or wants to swallow it without changing the navigation state, this function will return `null`.
|
||||
|
||||
### `getComponentForRouteName(routeName)`
|
||||
|
||||
Returns the child component or navigator for the given route name.
|
||||
|
||||
Say a router `getStateForAction` outputs a state like this:
|
||||
```js
|
||||
{
|
||||
index: 1,
|
||||
routes: [
|
||||
{ key: 'A', routeName: 'Foo' },
|
||||
{ key: 'B', routeName: 'Bar' },
|
||||
],
|
||||
}
|
||||
```
|
||||
|
||||
Based on the routeNames in the state, the router is responsible for returning valid components when calling `router.getComponentForRouteName('Foo')` or `router.getComponentForRouteName('Bar')`.
|
||||
|
||||
### `getComponentForState(state)`
|
||||
|
||||
Returns the active component for a deep navigation state.
|
||||
|
||||
### `getActionForPathAndParams(path, params)`
|
||||
|
||||
Returns an optional navigation action that should be used when the user navigates to this path and provides optional query parameters.
|
||||
|
||||
### `getPathAndParamsForState(state)`
|
||||
|
||||
Returns the path and params that can be put into the URL to link the user back to the same spot in the app.
|
||||
|
||||
The path/params that are output from this should form an action when passed back into the router's `getActionForPathAndParams`. That action should take you to a similar state once passed through `getStateForAction`.
|
||||
|
||||
### `getScreenOptions(navigation, screenProps)`
|
||||
|
||||
Used to retrieve the navigation options for a screen. Must provide the screen's current navigation prop and optionally, other props that your navigation options may need to consume.
|
||||
|
||||
- `navigation` - This is the navigation prop that the screen will use, where the state refers to the screen's route/state. Dispatch will trigger actions in the context of that screen.
|
||||
- `screenProps` - Other props that your navigation options may need to consume
|
||||
- `navigationOptions` - The previous set of options that are default or provided by the previous configurer
|
||||
|
||||
Inside an example view, perhaps you need to fetch the configured title:
|
||||
```js
|
||||
// First, prepare a navigation prop for your child, or re-use one if already available.
|
||||
const screenNavigation = addNavigationHelpers({
|
||||
// In this case we use navigation.state.index because we want the title for the active route.
|
||||
state: navigation.state.routes[navigation.state.index],
|
||||
dispatch: navigation.dispatch,
|
||||
});
|
||||
const options = this.props.router.getScreenOptions(screenNavigation, {});
|
||||
const title = options.title;
|
||||
```
|
||||
@@ -1,64 +0,0 @@
|
||||
# StackRouter
|
||||
|
||||
Manage the logical navigation stack, including pushing, popping, and handling path parsing to create a deep stack.
|
||||
|
||||
Let's take a look at a simple stack router:
|
||||
|
||||
```js
|
||||
const MyApp = StackRouter({
|
||||
Home: { screen: HomeScreen },
|
||||
Profile: { screen: ProfileScreen },
|
||||
}, {
|
||||
initialRouteName: 'Home',
|
||||
})
|
||||
```
|
||||
|
||||
|
||||
### RouteConfig
|
||||
|
||||
A basic stack router expects a route config object. Here is an example configuration:
|
||||
|
||||
```js
|
||||
const MyApp = StackRouter({ // This is the RouteConfig:
|
||||
Home: {
|
||||
screen: HomeScreen,
|
||||
path: '',
|
||||
},
|
||||
Profile: {
|
||||
screen: ProfileScreen,
|
||||
path: 'profile/:name',
|
||||
},
|
||||
Settings: {
|
||||
// This can be handy to lazily require a screen:
|
||||
getScreen: () => require('Settings').default,
|
||||
// Note: Child navigators cannot be configured using getScreen because
|
||||
// the router will not be accessible. Navigators must be configured
|
||||
// using `screen: MyNavigator`
|
||||
path: 'settings',
|
||||
},
|
||||
});
|
||||
```
|
||||
|
||||
Each item in the config may have the following:
|
||||
|
||||
- `path` - Specify the path and params to be parsed for item in the stack
|
||||
- `screen` - Specify the screen component or child navigator
|
||||
- `getScreen` - Set a lazy getter for a screen component (but not navigators)
|
||||
|
||||
|
||||
### StackConfig
|
||||
|
||||
Config options that are also passed to the stack router.
|
||||
|
||||
- `initialRouteName` - The routeName for the default route when the stack first loads
|
||||
- `initialRouteParams` - Default params of the initial route
|
||||
- `paths` - Provide a mapping of routeName to path config, which overrides the paths set in the routeConfigs.
|
||||
|
||||
### Supported Actions
|
||||
|
||||
The stack router may respond to the following navigation actions. The router will generally delegate the action handling to a child router, if possible.
|
||||
|
||||
- Navigate - Will push a new route on the stack if the routeName matches one of the router's routeConfigs
|
||||
- Back - Goes back (pops)
|
||||
- Reset - Clears the stack and provides new actions to create a fully new navigation state
|
||||
- SetParams - An action that a screen dispatches to change the params of the current route.
|
||||
@@ -1,60 +0,0 @@
|
||||
# TabRouter
|
||||
|
||||
Manage a set of tabs in the application, handle jumping to tabs, and handle the back button press to jump to the initial tab.
|
||||
|
||||
Let's take a look at a simple tabs router:
|
||||
|
||||
```js
|
||||
const MyApp = TabRouter({
|
||||
Home: { screen: HomeScreen },
|
||||
Settings: { screen: SettingsScreen },
|
||||
}, {
|
||||
initialRouteName: 'Home',
|
||||
})
|
||||
```
|
||||
|
||||
|
||||
### RouteConfig
|
||||
|
||||
A tabs router has a routeConfig for each possible tab:
|
||||
|
||||
```js
|
||||
const MyApp = TabRouter({ // This is the RouteConfig:
|
||||
Home: {
|
||||
screen: HomeScreen,
|
||||
path: 'main',
|
||||
},
|
||||
Settings: {
|
||||
// This can be handy to lazily require a tab:
|
||||
getScreen: () => require('./SettingsScreen').default,
|
||||
// Note: Child navigators cannot be configured using getScreen because
|
||||
// the router will not be accessible. Navigators must be configured
|
||||
// using `screen: MyNavigator`
|
||||
path: 'settings',
|
||||
},
|
||||
});
|
||||
```
|
||||
|
||||
Each item in the config may have the following:
|
||||
|
||||
- `path` - Specify the path for each tab
|
||||
- `screen` - Specify the screen component or child navigator
|
||||
- `getScreen` - Set a lazy getter for a screen component (but not navigators)
|
||||
|
||||
|
||||
### Tab Router Config
|
||||
|
||||
Config options that are also passed to the router.
|
||||
|
||||
- `initialRouteName` - The routeName for the initial tab route when first loading
|
||||
- `order` - Array of routeNames which defines the order of the tabs
|
||||
- `paths` - Provide a mapping of routeName to path config, which overrides the paths set in the routeConfigs.
|
||||
- `backBehavior` - Should the back button cause a tab switch to the initial tab? If yes, set to `initialRoute`, otherwise `none`. Defaults to `initialRoute` behavior.
|
||||
|
||||
### Supported Actions
|
||||
|
||||
The tabs router may respond to the following navigation actions. The router will generally delegate the action handling to a child router, if possible.
|
||||
|
||||
- Navigate - Will jump to the routeName if it matches a tab
|
||||
- Back - Goes to the first tab, if not already selected
|
||||
- SetParams - An action that a screen dispatches to change the params of the current route.
|
||||
@@ -1,191 +0,0 @@
|
||||
# Transitioner
|
||||
|
||||
`Transitioner` is a React component that helps manage transitions for complex animated components. It manages the timing of animations and keeps track of various screens as they enter and leave, but it doesn't know what anything looks like, because rendering is entirely deferred to the developer.
|
||||
|
||||
Under the covers, `Transitioner` is used to implement `CardStack`, and hence the `StackNavigator`.
|
||||
|
||||
The most useful thing `Transitioner` does is to take in a prop of the current navigation state. When routes are removed from that navigation state, `Transitioner` will coordinate the transition away from those routes, keeping them on screen even though they are gone from the navigation state.
|
||||
|
||||
|
||||
## Example
|
||||
|
||||
```jsx
|
||||
class MyNavView extends Component {
|
||||
...
|
||||
render() {
|
||||
return (
|
||||
<Transitioner
|
||||
configureTransition={this._configureTransition}
|
||||
navigation={this.props.navigation}
|
||||
render={this._render}
|
||||
onTransitionStart={this.onTransitionStart}
|
||||
onTransitionEnd={this.onTransitionEnd}
|
||||
/>
|
||||
);
|
||||
}
|
||||
```
|
||||
|
||||
## Props
|
||||
|
||||
### `configureTransition` function
|
||||
|
||||
Invoked on `Transitioner.componentWillReceiveProps`, this function allows customization of animation parameters such as `duration`. The value returned from this function will be fed into a timing function, by default `Animated.timing()`, as its config.
|
||||
|
||||
#### Examples
|
||||
|
||||
```js
|
||||
_configureTransition(transitionProps, prevTransitionProps) {
|
||||
return {
|
||||
// duration in milliseconds, default: 250
|
||||
duration: 500,
|
||||
// An easing function from `Easing`, default: Easing.inOut(Easing.ease)
|
||||
easing: Easing.bounce,
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Note: `duration` and `easing` are only applicable when the timing function is `Animated.timing`. We can also use a different timing function and its corresponding config parameters, like so:
|
||||
|
||||
```js
|
||||
_configureTransition(transitionProps, prevTransitionProps) {
|
||||
return {
|
||||
// A timing function, default: Animated.timing.
|
||||
timing: Animated.spring,
|
||||
// Some parameters relevant to Animated.spring
|
||||
friction: 1,
|
||||
tension: 0.5,
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
#### Flow definition
|
||||
|
||||
```js
|
||||
configureTransition: (
|
||||
transitionProps: NavigationTransitionProps,
|
||||
prevTransitionProps: ?NavigationTransitionProps,
|
||||
) => NavigationTransitionSpec,
|
||||
```
|
||||
|
||||
#### Parameters
|
||||
- `transitionProps`: the current [NavigationTransitionProps](https://github.com/react-community/react-navigation/blob/master/src/TypeDefinition.js#L273) created from the current navigation state and props
|
||||
- `prevTransitionProps`: the previous [NavigationTransitionProps](https://github.com/react-community/react-navigation/blob/master/src/TypeDefinition.js#L273) created from the previous navigation state and props
|
||||
|
||||
#### Returns
|
||||
- An object of type [NavigationTransitionSpec](https://github.com/react-community/react-navigation/blob/master/src/TypeDefinition.js#L316) that will be fed into an Animated timing function as its config
|
||||
|
||||
|
||||
### `navigation` prop
|
||||
An object with `state` that represents the navigation state, with `routes` and an active route `index`. Also includes `dispatch` and other methods for requesting actions.
|
||||
|
||||
#### Example value
|
||||
|
||||
```js
|
||||
{
|
||||
// Index refers to the active child route in the routes array.
|
||||
index: 1,
|
||||
routes: [
|
||||
{ key: 'DF2FGWGAS-12', routeName: 'ContactHome' },
|
||||
{ key: 'DF2FGWGAS-13', routeName: 'ContactDetail', params: { personId: 123 } }
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
#### Flow definition
|
||||
```js
|
||||
export type NavigationState = {
|
||||
index: number,
|
||||
routes: Array<NavigationRoute>,
|
||||
};
|
||||
```
|
||||
|
||||
For more information about the `NavigationRoute` type, check out its [flow definition](https://github.com/react-community/react-navigation/blob/master/src/TypeDefinition.js#L32).
|
||||
|
||||
### `render` function
|
||||
Invoked from `Transitioner.render()`. This function performs the actual rendering delegated from `Transitioner`. In this function, we can use the information included in the `transitionProps` and `prevTransitionProps` parameters to render scenes, create animations and handle gestures.
|
||||
|
||||
There are a few important properties of the `transitionProps` and `prevTransitionProps` parameters that are useful for the tasks mentioned above:
|
||||
|
||||
- `scenes: Array<NavigationScene>` - a list of all available scenes
|
||||
- `position: NavigationAnimatedValue` - the progressive index of the transitioner's navigation state
|
||||
- `progress: NavigationAnimatedValue` - the value that represents the progress of the transition when navigation state changes from one to another. Its numeric value will range from 0 to 1.
|
||||
|
||||
For the complete list of properties of `NavigationTransitionProps`, check out its [flow definition](https://github.com/react-community/react-navigation/blob/master/src/TypeDefinition.js#L273).
|
||||
|
||||
#### Examples
|
||||
|
||||
`transitionProps.scenes` is the list of all available scenes. It is up to the implementor to determine how to lay them out on the screen. For example, we can render the scenes as a stack of cards like so:
|
||||
|
||||
```jsx
|
||||
_render(transitionProps, prevTransitionProps) {
|
||||
const scenes = transitionProps.scenes.map(scene => this._renderScene(transitionProps, scene));
|
||||
return (
|
||||
<View style={styles.stack}>
|
||||
{scenes}
|
||||
</View>
|
||||
);
|
||||
}
|
||||
```
|
||||
|
||||
We can then use an `Animated.View` to animate the transition. To create necessary animated style properties, such as `opacity`, we can interpolate on `position` and `progress` values that come with `transitionProps`:
|
||||
|
||||
```jsx
|
||||
_renderScene(transitionProps, scene) {
|
||||
const { position } = transitionProps;
|
||||
const { index } = scene;
|
||||
const opacity = position.interpolate({
|
||||
inputRange: [index-1, index, index+1],
|
||||
outputRange: [0, 1, 0],
|
||||
});
|
||||
// The prop `router` is populated when we call `createNavigator`.
|
||||
const Scene = this.props.router.getComponent(scene.route.routeName);
|
||||
return (
|
||||
<Animated.View style={{ opacity }}>
|
||||
{ Scene }
|
||||
</Animated.View>
|
||||
)
|
||||
}
|
||||
```
|
||||
|
||||
The above code creates a cross fade animation during transition.
|
||||
|
||||
For a comprehensive tutorial on how to create custom transitions, see this [blog post](http://www.reactnativediary.com/2016/12/20/navigation-experimental-custom-transition-1.html).
|
||||
|
||||
#### Flow definition
|
||||
```js
|
||||
render: (transitionProps: NavigationTransitionProps, prevTransitionProps: ?NavigationTransitionProps) => React.Node,
|
||||
```
|
||||
|
||||
#### Parameters
|
||||
- `transitionProps`: the current [NavigationTransitionProps](https://github.com/react-community/react-navigation/blob/master/src/TypeDefinition.js#L273) created from the current state and props
|
||||
- `prevTransitionProps`: the previous [NavigationTransitionProps](https://github.com/react-community/react-navigation/blob/master/src/TypeDefinition.js#L273) created from the previous state and props
|
||||
|
||||
#### Returns
|
||||
- A ReactElement, which will be used to render the Transitioner component
|
||||
|
||||
### `onTransitionStart` function
|
||||
Invoked when the transition animation is about to start.
|
||||
|
||||
#### Flow definition
|
||||
```js
|
||||
onTransitionStart: (transitionProps: NavigationTransitionProps, prevTransitionProps: ?NavigationTransitionProps) => void,
|
||||
```
|
||||
#### Parameters
|
||||
- `transitionProps`: the current [NavigationTransitionProps](https://github.com/react-community/react-navigation/blob/master/src/TypeDefinition.js#L273) created from the current state and props
|
||||
- `prevTransitionProps`: the previous [NavigationTransitionProps](https://github.com/react-community/react-navigation/blob/master/src/TypeDefinition.js#L273) created from the previous state and props
|
||||
|
||||
#### Returns
|
||||
- none.
|
||||
|
||||
### `onTransitionEnd` function
|
||||
Invoked once the transition animation completes.
|
||||
|
||||
#### Flow definition
|
||||
```js
|
||||
onTransitionEnd: () => void
|
||||
```
|
||||
#### Parameters
|
||||
- none.
|
||||
|
||||
#### Returns
|
||||
- none.
|
||||
@@ -1,18 +0,0 @@
|
||||
# Views
|
||||
|
||||
Navigation views are presentation components that take a [`router`](/docs/api/routers) and a [`navigation`](/docs/navigators/navigation-prop) prop, and can display several screens, as specified by the `navigation.state`.
|
||||
|
||||
Navigation views are controlled React components that can present the current navigation state. They manage switching of screens, animations and gestures. They also present persistent navigation views such as tab bars and headers.
|
||||
|
||||
## Built in Views
|
||||
|
||||
- [CardStack](https://github.com/react-community/react-navigation/blob/master/src/views/CardStack/CardStack.js) - Present a stack that looks suitable on any platform
|
||||
+ [Card](https://github.com/react-community/react-navigation/blob/master/src/views/CardStack/Card.js) - Present one card from the card stack, with gestures
|
||||
+ [Header](https://github.com/react-community/react-navigation/blob/master/src/views/Header/Header.js) - The header view for the card stack
|
||||
- [Tabs](https://github.com/react-community/react-navigation/blob/master/src/views/TabView/TabView.js) - A configurable tab switcher / pager
|
||||
- [Drawer](https://github.com/react-community/react-navigation/blob/master/src/views/Drawer/DrawerView.js) - A view with a drawer that slides from the left
|
||||
|
||||
|
||||
## [Transitioner](/docs/views/transitioner)
|
||||
|
||||
`Transitioner` manages the animations during the transition and can be used to build fully custom navigation views. It is used inside the `CardStack` view. [Learn more about Transitioner here.](/docs/views/transitioner)
|
||||
@@ -1,17 +0,0 @@
|
||||
|
||||
# withNavigation
|
||||
|
||||
[`withNavigation`](/src/views/withNavigation.js) is a Higher Order Component which passes the `navigation` prop into a wrapped Component. It's useful when you cannot pass the `navigation` prop into the component directly, or don't want to pass it in case of a deeply nested child.
|
||||
|
||||
## Example
|
||||
|
||||
```js
|
||||
import { Button } 'react-native';
|
||||
import { withNavigation } from 'react-navigation';
|
||||
|
||||
const MyComponent = ({ to, navigation }) => (
|
||||
<Button title={`navigate to ${to}`} onPress={() => navigation.navigate(to)} />
|
||||
);
|
||||
|
||||
const MyComponentWithNavigation = withNavigation(MyComponent);
|
||||
```
|
||||
@@ -1,62 +0,0 @@
|
||||
# Introducing React Navigation for React Native
|
||||
_January 26, 2017_
|
||||
|
||||
Today we're excited to introduce React Navigation, a flexible navigation library for React Native and web, including customizable views for React Native, routers for any platform, and navigators that make it super easy to get started. We aim to provide a simple and extensible solution which enables developers to share one navigation paradigm for all of their React apps.
|
||||
|
||||
|
||||
## Start Quick with pre-built Navigators
|
||||
|
||||
A navigator is a React component with a static `.router` declared on it. To make it super easy to get started, React Navigation ships with a few navigator factories, pairing common views with routers.
|
||||
|
||||
For example, the provided `StackNavigator` makes it easy to use a `CardStack` view and a `StackRouter` together:
|
||||
|
||||
```js
|
||||
const MyApp = StackNavigator({
|
||||
Home: {screen: HomeScreen},
|
||||
Profile: {screen: ProfileScreen},
|
||||
});
|
||||
```
|
||||
|
||||
Each of these screens are just React components, and they can easily set their own title:
|
||||
|
||||
```js
|
||||
class HomeScreen extends React.Component {
|
||||
static navigationOptions = {
|
||||
title: 'Home',
|
||||
};
|
||||
render() {
|
||||
const { navigate } = this.props.navigation;
|
||||
return (
|
||||
<Button
|
||||
onPress={() => navigate('Profile', { name: 'A' })}
|
||||
title="Go to A's profile"
|
||||
/>
|
||||
);
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
To learn more, [continue with the getting started guide](/docs/intro).
|
||||
|
||||
|
||||
## Performant Views on React Native
|
||||
|
||||
Animations and gestures are critical for smooth navigation in a mobile app. React Navigation utilizes React Native's Animated library to provide 60fps animations that are driven from the native thread.
|
||||
|
||||
The views are designed to be highly extensible. For your app, you may want to build a custom modal, fork the stack header, or even utilize the underlying `<Transitioner>` component to build an entirely custom navigation presentation.
|
||||
|
||||
|
||||
## Routers for Every Platform
|
||||
|
||||
In React Navigation, routers manage the [relationship between actions, state, and URIs](/docs/routers/api). The routers are cross-platform, and there is example code for iOS, Android, and web. Several routers are included, including [`TabRouter`](/docs/routers/tab) and [`StackRouter`](/docs/routers/stack), and it is encouraged to [override their behavior as needed](/docs/routers).
|
||||
|
||||
The routers are composable and can be useful for structuring your app. A common navigation structure in iOS is to have an independent navigation stack for each tab, where all tabs can be covered by a modal. This is three layers of router: a card stack, within tabs, all within a modal stack. So unlike our experience on web apps, the navigation state of mobile apps is too complex to encode into a single URI. Routers in `react-navigation` map from URIs to navigation actions, which are then used to compute navigation state.
|
||||
|
||||
|
||||
## Future
|
||||
|
||||
React Navigation is born from the React Native community's need for an extensible yet easy-to-use navigation solution. It replaces and improves upon several navigation libraries in the ecosystem, including Ex-Navigation and React Native's Navigator and NavigationExperimental components.
|
||||
|
||||
Until the community lands on one navigation solution that works well on the web and React Native, we will forever be destined to re-invent navigation. We are extremely sensitive about the burden of change that accompanies a new navigation library, so we aim to provide a solution that will work long into the future. We are excited to support React Navigation for any platform, including cutting-edge frontiers like hybrid native apps, web server rendering, and ReactVR.
|
||||
|
||||
The first beta of React Navigation is available today on npm and GitHub, and you can [get started here](/docs/intro). We're excited to hear feedback from the React community, and together we still have a long way to go before our dream is realized. We'd love to see the community flourish with beautiful navigation views, custom router integrations, and more easy-to-use navigators. All of these individual contributions can work together seamlessly. If you have improvements for the built-in components, please [follow the contributors guide](/docs/guides/contributors) and dive right in!
|
||||
@@ -1,13 +0,0 @@
|
||||
# On the path to React Navigation v1
|
||||
|
||||
*April 26, 2017*
|
||||
|
||||
When we announced React Navigation earlier this year, the core team was blown away at the community's overwhelming excitement and support for the new project. Since the launch in late January, hundreds of contributors have sprung up, reported detailed issues, and committed important fixes to the library.
|
||||
|
||||
With several community members preparing to put apps in production, the highest priority for the core team is to refine the final v1 API, and stabilize it to make sure your apps feel rock-soild.
|
||||
|
||||
Today we're excited to announce the release of [beta 9](https://github.com/react-community/react-navigation/releases/tag/v1.0.0-beta.9), which iterates upon the initial API. Although you will need to modify your screen navigation options for this upgrade, we are very confident in the new API. Our goal for future v1 releases is to avoid making any breaking API changes - we are now focused on filling in essential missing features, and stabilization.
|
||||
|
||||
The community has experienced some thrash by a few of our earlier beta releases. So, starting with [this release](https://github.com/react-community/react-navigation/releases/tag/v1.0.0-beta.9), we will include detailed [release notes](https://github.com/react-community/react-navigation/releases) about any API changes, new features, and bug fixes.
|
||||
|
||||
After the stabilization and release of v1, we're excited to explore new ways of customizing transitions, and overriding navigation components. There are some [exciting proposals](https://github.com/react-community/react-navigation/issues/1263) about these new APIs, and we look forward to the community's feedback and involvement.
|
||||
@@ -1,71 +0,0 @@
|
||||
# A (Renewed) Path to React Navigation V1
|
||||
|
||||
*September 12, 2017*
|
||||
|
||||
It’s been awhile since the last post on this blog and I wanted to take a moment to bring everyone up to speed on what’s been going on with React Navigation.
|
||||
|
||||
This project got big really fast: as the officially recommended navigation library for React Native, thousands of developers are using the project every day to build apps.
|
||||
|
||||
Having such a broad usage, the repository has a lot of new questions, feature requests, and (as with any library) bugs. It’s gotten a bit out of hand (thus hard to manage) so I wanted to give you an overview of how we’re trying to get things moving forward again resulting in a stable V1 release.
|
||||
|
||||
## Issues
|
||||
|
||||
If you've looked at the project over the last few months you've probably seen that there are a lot of open issues. If you've looked closely over the last few weeks you may have noticed that it's a few hundred less - [progress](https://github.com/react-community/react-navigation/pulse/monthly)!
|
||||
|
||||
I wanted to tell you about how we’re addressing the GitHub issues: in an effort to reduce the cognitive load associated with so many open issues we've set out to accomplish a few things:
|
||||
|
||||
1. Label all issues
|
||||
2. Close any "question" type issues. The idea here is to keep GitHub issues focused on bugs & feature requests. [StackOverflow](https://stackoverflow.com/questions/tagged/react-navigation) and [Reactiflux](https://www.reactiflux.com/) are better places for questions.
|
||||
3. Eliminate duplicate issues
|
||||
4. Of the remaining issues determine bugs & features necessary for V1
|
||||
|
||||
Don't hesitate to open new issues but **please do follow** the issue template! 😄
|
||||
|
||||
## Pull Requests
|
||||
|
||||
We greatly appreciate all the time put into each and every one of them but, as with issues, there's a bit of a backlog to work through.
|
||||
|
||||
We encourage PRs but we want you to know that we’re prioritizing bug fixes and feature requests that align with the new 1.0 roadmap (see next section). We want to focus on the highest impact features for the community as a whole.
|
||||
|
||||
## A New Roadmap
|
||||
|
||||
We’re happy to say we’ve put together a new roadmap to version 1.0 of this package! You can see what will be included by checking out [this issue](https://github.com/react-community/react-navigation/issues/2585).
|
||||
|
||||
How do we decide on what to include in the revised V1.0?
|
||||
|
||||
We had conversations with people using React Navigation in production, looked at issues with the most reactions, reviewed high quality pull requests, and talked with the community to see what was needed.
|
||||
|
||||
Will V1.0 cover everyone’s uses? No. But it should cover most use cases and we hope to improve documentation enough that you’re comfortable and able to customize React Navigation to your needs.
|
||||
|
||||
## Roles & Responsibilities
|
||||
|
||||
Just like any other organization - no one person can do everything. It’s helpful to have defined roles & responsibilities so that others know who to ask and we can avoid becoming overwhelmed.
|
||||
|
||||
This is something I want to adopt for the management of React Navigation. I hope it reduces the likelihood of burnout for those that have chosen to dedicate time to the project. With that in mind here are the roles a few primary contributors have chosen to take on:
|
||||
|
||||
- [davepack](https://github.com/davepack) - Pull request review, development
|
||||
- [GantMan](https://github.com/GantMan) - Issue management, testing
|
||||
- [kelset](https://github.com/kelset) - Issue management, pull request review
|
||||
- [matthamil](https://github.com/matthamil) - Pull request review, issue management
|
||||
- [skevy](https://github.com/skevy) - Pull request review, release management
|
||||
- [spencercarli](https://github.com/spencercarli) - Documentation, issue management
|
||||
|
||||
[Expo](https://expo.io/) has expressed that React Navigation V1.0 is a priority for them and has committed one of their engineers (Dave) to aid in that.
|
||||
|
||||
## The Community Navigation Library
|
||||
|
||||
React Navigation is the React Native community’s navigation library with that being said - you too can contribute!
|
||||
|
||||
If you see someone's question - try to answer it!
|
||||
If you have thoughts on a potential API for a requested feature - share it!
|
||||
If you think you know the cause for a bug - explain it!
|
||||
|
||||
Regardless of what you do though, be nice & remember that on the other side of the screen there is another developer, just like you…
|
||||
|
||||
Personally, I [enjoy some shade](https://media.giphy.com/media/l4FGlDsvuUd2RkBYQ/giphy.gif) thrown my way, but I might be in the minority 😉.
|
||||
|
||||
Thanks for reading and I look forward to working with you on React Navigation!
|
||||
|
||||
Spencer Carli
|
||||
|
||||
*Thanks to Matt Hamill & Lorenzo Sciandra for reviewing.*
|
||||
@@ -1,229 +0,0 @@
|
||||
# Common Navigation Spec
|
||||
|
||||
### Introduction
|
||||
|
||||
It is useful to have “one standard way” to handle navigation in a React app. Unfortunately, we've learned that a single navigation library cannot be the right fit for every application. There is often a tradeoff between several useful features:
|
||||
|
||||
* Simplicity
|
||||
* Supporting complex animations
|
||||
* Navigating between natively-implemented screens and JavaScript screens
|
||||
* Precise fidelity to the native UI controls
|
||||
* Default support for deep linking and the Android back button
|
||||
|
||||
Although the React Native community will need more than one navigation library, we can make them work nicely together. The goal of this document is to specify a common API for navigation libraries. Consistency will make several things easier for React Native developers:
|
||||
|
||||
* Combining multiple navigation libraries in one application
|
||||
* Switching out navigation libraries when requirements change
|
||||
* Learning navigation once, and applying that knowledge in different applications
|
||||
|
||||
Navigation libraries don't have to implement all of this API - it's just a recommendation.
|
||||
|
||||
(TODO: When we actually publish this spec, we should mention here what libraries are supporting it, what libraries will support it, and (link to?) how to migrate from other now-discouraged navigation libraries.)
|
||||
|
||||
|
||||
## Key Concepts
|
||||
|
||||
#### Navigation Container
|
||||
|
||||
The parent component which hosts a navigation-aware component. It must provide the `navigation` prop, and usually uses the child component's static `router` to determine navigation state.
|
||||
|
||||
#### Navigation-Aware Component
|
||||
|
||||
A React component which can observe and initiate navigation in an app. It uses the navigation prop to see navigation state and request actions. It may expose a router to define navigation state and URI handling.
|
||||
|
||||
The card stack of your application may be a navigation-aware component. Also, one screen of your app that handles the Android back button is a navigation-aware component.
|
||||
|
||||
#### Navigation State
|
||||
|
||||
The object that defines the navigation state of your component, passed in as a prop. A router can define the state, which optionally specifies the title and URI of the component.
|
||||
|
||||
#### Action
|
||||
|
||||
A JSON object used to request changes in the app's navigation state.
|
||||
|
||||
#### Router
|
||||
|
||||
Defines the navigation behavior of a component by defining navigation state as a function of actions, and allows URIs to be optionally converted into an action that can be handled.
|
||||
|
||||
#### Navigator
|
||||
|
||||
A navigation-aware component that hosts other navigation-aware components. Most navigators are expected to delegate all router logic, manage child navigation state, and pass up actions as they are dispatched.
|
||||
|
||||
## Specification
|
||||
|
||||
### The `navigation` prop
|
||||
|
||||
The navigation prop should be provided to components who need access to navigation. If provided, it must follow this interface:
|
||||
|
||||
```javascript
|
||||
type BackAction = {type: 'Navigation/BACK'};
|
||||
type URIAction = {type: 'Navigation/URI', uri: string};
|
||||
|
||||
interface Navigation<S, A> {
|
||||
dispatch(action: (A | BackAction | URIAction)): boolean;
|
||||
state: S;
|
||||
}
|
||||
```
|
||||
|
||||
#### navigation.state
|
||||
|
||||
The controlled navigation state prop, as requested by the parent.
|
||||
|
||||
```javascript
|
||||
const MyView = ({ navigation }) => {
|
||||
switch (navigation.state.myRequestedView) {
|
||||
case 'ViewA': return <ViewA />;
|
||||
case 'ViewB': return <ViewB />;
|
||||
default: return <OtherView />;
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
#### navigation.dispatch(action)
|
||||
|
||||
The channel that a component can call to request navigation from its parent. When calling `dispatch`, you must provide an action object with a `type`. There are two special action types: 'Navigation/BACK' and 'Navigation/URI'.
|
||||
|
||||
```javascript
|
||||
const MyLink = ({ navigation }) => (
|
||||
<Button onPress={() => {
|
||||
navigation.dispatch({
|
||||
type: 'MyNavigationRequest',
|
||||
myParam: 42,
|
||||
});
|
||||
}>
|
||||
Press me to navigate
|
||||
</Button>
|
||||
);
|
||||
```
|
||||
|
||||
|
||||
### The static `router`
|
||||
|
||||
A router object may be statically defined on your component. If defined, it must follow this interface:
|
||||
|
||||
```javascript
|
||||
type BackAction = {type: 'Navigation/BACK'};
|
||||
type URIAction = {type: 'Navigation/URI', uri: string};
|
||||
|
||||
interface Router<S, A> {
|
||||
getStateForAction(action: (A | BackAction | URIAction), lastState: ?S): ?S;
|
||||
getActionForURI(uri: string): ?A;
|
||||
}
|
||||
```
|
||||
|
||||
The state and action types of the static router must match the state and action types associated with the navigation prop passed into the component.
|
||||
|
||||
#### router.getStateForAction(action, lastState)
|
||||
|
||||
This function is defined on the static router and is used to define the expected navigation state.
|
||||
|
||||
```javascript
|
||||
class ScreenWithEditMode extends React.Component {
|
||||
static router = {
|
||||
getStateForAction: (action, prevState) => {
|
||||
return { isEditing: true };
|
||||
},
|
||||
};
|
||||
render() {
|
||||
// this.props.navigation.state.isEditing === true
|
||||
...
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
`getStateForAction` must **always** return a navigation state that can be rendered by the component when passed in as the `navigation.state` prop.
|
||||
|
||||
If null is returned, we are signaling that the previous navigation state has not changed, but the action is handled. This is usually used in cases where the action is being swallowed.
|
||||
|
||||
|
||||
#### router.getActionForURI(uri)
|
||||
|
||||
Return an action if a URI can be handled, otherwise return `null`
|
||||
|
||||
|
||||
|
||||
### Special Actions
|
||||
|
||||
There are two special actions that can be fired into `navigation.dispatch` and can be handled by your `router.getStateForAction`.
|
||||
|
||||
#### Back Action
|
||||
|
||||
This action means the same thing as an Android back button press.
|
||||
|
||||
```
|
||||
type BackAction = { type: 'Navigation/BACK' };
|
||||
```
|
||||
|
||||
#### URI Open Action
|
||||
|
||||
Used to request the enclosing app or OS to open a link at a particular URI. If it is a web URI like `http` or `https`, the app may open a WebView to present the page. Or the app may open the URI in a web browser. In some cases, an app may choose to block a URI action or handle it differently.
|
||||
|
||||
```
|
||||
type URIAction = { type: 'Navigation/URI', uri: string };
|
||||
```
|
||||
|
||||
|
||||
### Special Navigation State
|
||||
|
||||
The state defined by `router.getStateForAction` can contain special navigation properties that may be relevant to your app. The title and current URI of a component may change over time, and the parent often needs to observe the behavior.
|
||||
|
||||
#### `state.title`
|
||||
|
||||
If the navigation state contains 'title', it will be used as the title for the given component. This is relevant for top-level components on the web to update the browser title, and is relevant in mobile apps where a title is shown in the header.
|
||||
|
||||
#### `state.uri`
|
||||
|
||||
A URI can also be put in `state.uri`, which will signal to the parent how it may be possible to deep link into a similar navigation state. In web apps, this will be used to keep the URI bar in sync with the current navigation state of the app.
|
||||
|
||||
|
||||
## Use Cases
|
||||
|
||||
### "Block the Android back button on one screen of my app"
|
||||
|
||||
To block the Android back button:
|
||||
|
||||
```
|
||||
class Foo extends React.Component {
|
||||
static router = {
|
||||
getStateForAction(action, prevState = {}) {
|
||||
if (action.type === 'Navigation/BACK') return null;
|
||||
else return prevState;
|
||||
},
|
||||
};
|
||||
render() {
|
||||
...
|
||||
```
|
||||
|
||||
Because we return null, we signal to our container that the action has been handled but the state does not change. The parent should not handle the back behavior at this point, and nothing should be re-rendered.
|
||||
|
||||
### "Link deeply into one screen of my app"
|
||||
|
||||
```
|
||||
class Foo extends React.Component {
|
||||
static router = {
|
||||
getStateForAction(action, prevState = {deep: false}) {
|
||||
if (action.type === 'GoDeep') return { deep: true };
|
||||
else return prevState;
|
||||
},
|
||||
getActionForURI(uri) {
|
||||
if (uri === 'myapp://foo')
|
||||
return {type: 'Go'};
|
||||
else if (uri === 'myapp://foo_deep')
|
||||
return {type: 'GoDeep'};
|
||||
return null;
|
||||
},
|
||||
};
|
||||
render() {
|
||||
// this.props.navigation.state.deep may be true or false
|
||||
...
|
||||
```
|
||||
|
||||
Based on the state URI we may decide to return an action. If an action is returned, `getStateForAction` is expected to output the correct state for a deep link.
|
||||
|
||||
## Reference Implementations
|
||||
|
||||
A library to that helps easily produce navigation-aware components: https://github.com/react-community/react-navigation . (Also uses a HOC to provide navigation containers when needed.)
|
||||
|
||||
A simple navigation container: https://gist.github.com/ericvicenti/77d190e2ec408012255937400e34bdb1
|
||||
|
||||
A web implementation of a navigation container: https://gist.github.com/ericvicenti/55bef95fcd8558029a3bae8483baea6c
|
||||
@@ -1,99 +0,0 @@
|
||||
# Contributors Guide
|
||||
|
||||
## Environment
|
||||
|
||||
React Navigation was initially developed on macOS v10.12, with node v7+, and react-native v0.39+.
|
||||
It's also been verified to work using Boron LTS (node v6.11.1 with npm v3.10.10), and using node v8.1.4 with npm v4.6.1.
|
||||
Please open issues if you uncover problems in different environments.
|
||||
|
||||
In all of the below commands, you can use `npm` instead of `yarn` if you prefer.
|
||||
[Yarn](https://yarnpkg.com/en/) is generally much faster, but some people still prefer `npm`.
|
||||
They should work the same here.
|
||||
|
||||
## Development
|
||||
|
||||
### Fork the repo
|
||||
|
||||
- Fork [`react-navigation`](https://github.com/react-community/react-navigation) on GitHub
|
||||
- Run these commands in the terminal to download locally and install it:
|
||||
|
||||
```bash
|
||||
git clone https://github.com/<USERNAME>/react-navigation.git
|
||||
cd react-navigation
|
||||
git remote add upstream https://github.com/react-community/react-navigation.git
|
||||
yarn install
|
||||
```
|
||||
|
||||
### Run the example app
|
||||
|
||||
```bash
|
||||
yarn install
|
||||
cd examples/NavigationPlayground
|
||||
yarn install
|
||||
yarn start
|
||||
```
|
||||
|
||||
You will be given a URL to open in your Expo app. You can get Expo [here](https://docs.expo.io/versions/v18.0.0/introduction/installation.html) if you don't have it yet.
|
||||
|
||||
If you run into any issues, please try the following to start fresh:
|
||||
|
||||
```bash
|
||||
watchman watch-del-all
|
||||
yarn start -- --reset-cache
|
||||
```
|
||||
|
||||
### Run the website
|
||||
|
||||
For development mode and live-reloading:
|
||||
|
||||
```bash
|
||||
cd website
|
||||
yarn install
|
||||
yarn start
|
||||
```
|
||||
|
||||
To run the website in production mode with server rendering:
|
||||
|
||||
```bash
|
||||
yarn run prod
|
||||
```
|
||||
|
||||
### Run tests and type-checking
|
||||
|
||||
```bash
|
||||
jest
|
||||
flow
|
||||
```
|
||||
|
||||
Tests must pass for your changes to be accepted and merged.
|
||||
|
||||
Flow is not yet passing, but your code should be flow checked and we expect that your changes do not introduce any flow errors.
|
||||
|
||||
### Developing Docs
|
||||
|
||||
The docs are indexed in [App.js](https://github.com/react-community/react-navigation/blob/master/website/src/App.js), where all the pages are declared alongside the titles. To test the docs, follow the above instructions for running the website. Changing existing markdown files should not require any testing.
|
||||
|
||||
The markdown from the `docs` folder gets generated and dumped into a json file as a part of the build step. To see updated docs appear in the website, re-run the build step by running `npm run build-docs` from the `react-navigation` root folder.
|
||||
|
||||
## Submitting Contributions
|
||||
|
||||
### New views or unique features
|
||||
|
||||
Often navigation needs are specific to certain apps. If your changes are unique to your app, you may want to fork the view or router that has changed. You can keep the source code in your app, or publish it on npm as a `react-navigation` compatible view or router.
|
||||
|
||||
This library is intended to include highly standard and generic navigation patterns.
|
||||
|
||||
### Major Changes
|
||||
|
||||
Before embarking on any major changes, please file an issue describing the suggested change and motivation. We may already have thought about it and we want to make sure we all are on the same page before starting on any big changes.
|
||||
|
||||
### Minor Bugfixes
|
||||
|
||||
Simple bug fixes are welcomed in pull requests! Please check for duplicate PRs before posting.
|
||||
|
||||
#### Make sure to sync up with the state of upstream before submitting a PR:
|
||||
|
||||
```bash
|
||||
git fetch upstream
|
||||
git rebase upstream/master
|
||||
```
|
||||
@@ -1,94 +0,0 @@
|
||||
# Custom Navigators
|
||||
|
||||
A navigator is any React component that has a [router](/docs/routers/) on it. Here is a basic one, which uses the [router's API](/docs/routers/api) to get the active component to render:
|
||||
|
||||
```js
|
||||
class MyNavigator extends React.Component {
|
||||
static router = MyRouter;
|
||||
render() {
|
||||
const { state, dispatch } = this.props.navigation;
|
||||
const { routes, index } = state;
|
||||
|
||||
// Figure out what to render based on the navigation state and the router:
|
||||
const Component = MyRouter.getComponentForState(state);
|
||||
|
||||
// The state of the active child screen can be found at routes[index]
|
||||
let childNavigation = { dispatch, state: routes[index] };
|
||||
// If we want, we can also tinker with the dispatch function here, to limit
|
||||
// or augment our children's actions
|
||||
|
||||
// Assuming our children want the convenience of calling .navigate() and so on,
|
||||
// we should call addNavigationHelpers to augment our navigation prop:
|
||||
childNavigation = addNavigationHelpers(childNavigation);
|
||||
|
||||
return <Component navigation={childNavigation} />;
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## Navigation Prop
|
||||
|
||||
The navigation prop passed down to a navigator only includes `state` and `dispatch`. This is the current state of the navigator, and an event channel to send action requests.
|
||||
|
||||
All navigators are controlled components: they always display what is coming in through `props.navigation.state`, and their only way to change the state is to send actions into `props.navigation.dispatch`.
|
||||
|
||||
Navigators can specify custom behavior to parent navigators by [customizing their router](/docs/routers/). For example, a navigator is able to specify when actions should be blocked by returning null from `router.getStateForAction`. Or a navigator can specify custom URI handling by overriding `router.getActionForPathAndParams` to output a relevant navigation action, and handling that action in `router.getStateForAction`.
|
||||
|
||||
### Navigation State
|
||||
|
||||
The navigation state that is passed into a navigator's `props.navigation.state` has the following structure:
|
||||
|
||||
```
|
||||
{
|
||||
index: 1, // identifies which route in the routes array is active
|
||||
routes: [
|
||||
{
|
||||
// Each route needs a name, which routers will use to associate each route
|
||||
// with a react component
|
||||
routeName: 'MyRouteName',
|
||||
|
||||
// A unique id for this route, used to keep order in the routes array:
|
||||
key: 'myroute-123',
|
||||
|
||||
// Routes can have any additional data. The included routers have `params`
|
||||
...customRouteData,
|
||||
},
|
||||
...moreRoutes,
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
### Navigation Dispatchers
|
||||
|
||||
A navigator can dispatch navigation actions, such as 'Go to a URI', 'Go back'.
|
||||
|
||||
The dispatcher will return `true` if the action was successfully handled, otherwise `false`.
|
||||
|
||||
## API for building custom navigators
|
||||
|
||||
To help developers implement custom navigators, the following utilities are provided with React Navigation:
|
||||
|
||||
### `createNavigator`
|
||||
|
||||
This utility combines a [router](/docs/routers/) and a [navigation view](/docs/views/) together in a standard way:
|
||||
|
||||
```js
|
||||
const MyApp = createNavigator(MyRouter)(MyView);
|
||||
```
|
||||
|
||||
All this does behind the scenes is:
|
||||
|
||||
```js
|
||||
const MyApp = ({ navigation }) => (
|
||||
<MyView router={MyRouter} navigation={navigation} />
|
||||
);
|
||||
MyApp.router = MyRouter;
|
||||
```
|
||||
|
||||
### `addNavigationHelpers`
|
||||
|
||||
Takes in a bare navigator navigation prop with `state` and `dispatch`, and augments it with all the various functions in a screen navigation prop, such as `navigation.navigate()` and `navigation.goBack()`. These functions are simply helpers to create the actions and send them into `dispatch`.
|
||||
|
||||
### `createNavigationContainer`
|
||||
|
||||
If you want your navigator to be usable as a top-level component, (without a navigation prop being passed in), you can use `createNavigationContainer`. This utility will make your navigator act like a top-level navigator when the navigation prop is missing. It will manage the app state, and integrate with app-level nav features, like handling incoming and outgoing links, and Android back button behavior.
|
||||
@@ -1,53 +0,0 @@
|
||||
## Customizing Navigation Views
|
||||
|
||||
Modify the presentation of navigation, including styles, animations and gestures.
|
||||
|
||||
## Customizing Routers
|
||||
|
||||
Building a custom router allows you to change the navigation logic of your component, manage navigation state, and define behavior for URIs.
|
||||
|
||||
|
||||
A router can be defined like this:
|
||||
|
||||
```js
|
||||
class MyNavigationAwareComponent extends React.Component {
|
||||
|
||||
static router = {
|
||||
|
||||
// Defines the navigation state for a component:
|
||||
getStateForAction: (action: {type: string}, lastState?: any) => {
|
||||
const state = lastState = { myMode: 'default' };
|
||||
if (action.type === 'MyAction') {
|
||||
return { myMode: 'action' };
|
||||
} else if (action.type === NavigationActions.BACK) {
|
||||
return { myMode: 'blockBackButton' };
|
||||
} else {
|
||||
return state;
|
||||
}
|
||||
},
|
||||
|
||||
// Defines if a component can handle a particular URI.
|
||||
// If it does, return an action to be passed to `getStateForAction`
|
||||
|
||||
getActionForURI: (uri: string) => {
|
||||
if (uri === 'myapp://myAction') {
|
||||
return { type: 'MyAction' };
|
||||
}
|
||||
return null;
|
||||
},
|
||||
|
||||
};
|
||||
|
||||
render() {
|
||||
// render something based on this.props.navigation.state
|
||||
...
|
||||
}
|
||||
|
||||
onButtonPress = () => {
|
||||
this.props.navigation.dispatch({ type: 'MyAction' });
|
||||
};
|
||||
|
||||
...
|
||||
|
||||
}
|
||||
```
|
||||
@@ -1,111 +0,0 @@
|
||||
# Deep Linking
|
||||
|
||||
In this guide we will set up our app to handle external URIs. Let's start with the SimpleApp that [we created in the getting started guide](/docs/intro).
|
||||
|
||||
In this example, we want a URI like `mychat://chat/Taylor` to open our app and link straight into Taylor's chat page.
|
||||
|
||||
## Configuration
|
||||
|
||||
Previously, we had defined a navigator like this:
|
||||
|
||||
```js
|
||||
const SimpleApp = StackNavigator({
|
||||
Home: { screen: HomeScreen },
|
||||
Chat: { screen: ChatScreen },
|
||||
});
|
||||
```
|
||||
|
||||
We want paths like `chat/Taylor` to link to a "Chat" screen with the `user` passed as a param. Let's re-configure our chat screen with a `path` that tells the router what relative path to match against, and what params to extract. This path spec would be `chat/:user`.
|
||||
|
||||
```js
|
||||
const SimpleApp = StackNavigator({
|
||||
Home: { screen: HomeScreen },
|
||||
Chat: {
|
||||
screen: ChatScreen,
|
||||
path: 'chat/:user',
|
||||
},
|
||||
});
|
||||
```
|
||||
|
||||
|
||||
### URI Prefix
|
||||
|
||||
Next, let's configure our navigation container to extract the path from the app's incoming URI.
|
||||
|
||||
```js
|
||||
const SimpleApp = StackNavigator({...});
|
||||
|
||||
// on Android, the URI prefix typically contains a host in addition to scheme
|
||||
const prefix = Platform.OS == 'android' ? 'mychat://mychat/' : 'mychat://';
|
||||
|
||||
const MainApp = () => <SimpleApp uriPrefix={prefix} />;
|
||||
```
|
||||
|
||||
## iOS
|
||||
|
||||
Let's configure the native iOS app to open based on the `mychat://` URI scheme.
|
||||
|
||||
In `SimpleApp/ios/SimpleApp/AppDelegate.m`:
|
||||
|
||||
```
|
||||
// Add the header at the top of the file:
|
||||
#import <React/RCTLinkingManager.h>
|
||||
|
||||
// Add this above the `@end`:
|
||||
- (BOOL)application:(UIApplication *)application openURL:(NSURL *)url
|
||||
sourceApplication:(NSString *)sourceApplication annotation:(id)annotation
|
||||
{
|
||||
return [RCTLinkingManager application:application openURL:url
|
||||
sourceApplication:sourceApplication annotation:annotation];
|
||||
}
|
||||
```
|
||||
|
||||
In Xcode, open the project at `SimpleApp/ios/SimpleApp.xcodeproj`. Select the project in sidebar and navigate to the info tab. Scroll down to "URL Types" and add one. In the new URL type, set the identifier and the url scheme to your desired url scheme.
|
||||
|
||||

|
||||
|
||||
Now you can press play in Xcode, or re-build on the command line:
|
||||
|
||||
```sh
|
||||
react-native run-ios
|
||||
```
|
||||
|
||||
To test the URI on the simulator, run the following:
|
||||
|
||||
```
|
||||
xcrun simctl openurl booted mychat://chat/Taylor
|
||||
```
|
||||
|
||||
To test the URI on a real device, open Safari and type `mychat://chat/Taylor`.
|
||||
|
||||
## Android
|
||||
|
||||
To configure the external linking in Android, you can create a new intent in the manifest.
|
||||
|
||||
In `SimpleApp/android/app/src/main/AndroidManifest.xml`, add the new `VIEW` type `intent-filter` inside the `MainActivity` entry:
|
||||
|
||||
```
|
||||
<intent-filter>
|
||||
<action android:name="android.intent.action.VIEW" />
|
||||
<category android:name="android.intent.category.DEFAULT" />
|
||||
<category android:name="android.intent.category.BROWSABLE" />
|
||||
<data android:scheme="mychat"
|
||||
android:host="mychat" />
|
||||
</intent-filter>
|
||||
```
|
||||
|
||||
Now, re-install the app:
|
||||
|
||||
```sh
|
||||
react-native run-android
|
||||
```
|
||||
|
||||
To test the intent handling in Android, run the following:
|
||||
|
||||
```
|
||||
adb shell am start -W -a android.intent.action.VIEW -d "mychat://mychat/chat/Taylor" com.simpleapp
|
||||
```
|
||||
|
||||
```phone-example
|
||||
linking
|
||||
```
|
||||
@@ -1,235 +0,0 @@
|
||||
# Hello Mobile Navigation
|
||||
|
||||
Let's use React Navigation to build a simple chat-like application for Android and iOS.
|
||||
|
||||
## Setup and Installation
|
||||
|
||||
First, make sure you're [all set up to use React Native](http://facebook.github.io/react-native/docs/getting-started.html). Next, create a new project and add `react-navigation`:
|
||||
|
||||
```sh
|
||||
# Create a new React Native App
|
||||
react-native init SimpleApp
|
||||
cd SimpleApp
|
||||
|
||||
# Install the latest version of react-navigation from npm
|
||||
npm install --save react-navigation
|
||||
|
||||
# Run the new app
|
||||
react-native run-android
|
||||
# or:
|
||||
react-native run-ios
|
||||
```
|
||||
|
||||
If you are using `create-react-native-app` instead of `react-native init`, then:
|
||||
|
||||
```sh
|
||||
# Create a new React Native App
|
||||
create-react-native-app SimpleApp
|
||||
cd SimpleApp
|
||||
|
||||
# Install the latest version of react-navigation from npm
|
||||
npm install --save react-navigation
|
||||
|
||||
# Run the new app
|
||||
npm start
|
||||
|
||||
# This will start a development server for you and print a QR code in your terminal.
|
||||
```
|
||||
|
||||
Verify that you can successfully see the bare sample app run on iOS and/or Android:
|
||||
|
||||
```phone-example
|
||||
bare-project
|
||||
```
|
||||
|
||||
We want to share code on iOS and Android, so let's delete the contents of `index.js` (or `index.ios.js` and `index.android.js` if using a React Native version before 0.49) and replace it with `import './App';` - after which, we need to create the new file for our app implementation, `App.js` (if you used `create-react-native-app` this has been already done)
|
||||
|
||||
## Introducing Stack Navigator
|
||||
|
||||
For our app, we want to use the `StackNavigator` because conceptually we want to obtain a 'card stack' effect of movement, where each new screen is put on the top of the stack and going back removes a screen from the top of the stack. Let's start with just one screen:
|
||||
|
||||
```js
|
||||
import React from 'react';
|
||||
import {
|
||||
AppRegistry,
|
||||
Text,
|
||||
} from 'react-native';
|
||||
import { StackNavigator } from 'react-navigation';
|
||||
|
||||
class HomeScreen extends React.Component {
|
||||
static navigationOptions = {
|
||||
title: 'Welcome',
|
||||
};
|
||||
render() {
|
||||
return <Text>Hello, Navigation!</Text>;
|
||||
}
|
||||
}
|
||||
|
||||
export const SimpleApp = StackNavigator({
|
||||
Home: { screen: HomeScreen },
|
||||
});
|
||||
|
||||
AppRegistry.registerComponent('SimpleApp', () => SimpleApp);
|
||||
```
|
||||
|
||||
If you used `create-react-native-app` the already existing `App.js` will be modified to
|
||||
|
||||
```js
|
||||
import React from 'react';
|
||||
import { StyleSheet, Text, View } from 'react-native';
|
||||
import { StackNavigator } from 'react-navigation';
|
||||
|
||||
class HomeScreen extends React.Component {
|
||||
static navigationOptions = {
|
||||
title: 'Welcome'
|
||||
};
|
||||
render() {
|
||||
return <Text>Hello, Navigation!</Text>;
|
||||
}
|
||||
}
|
||||
|
||||
const SimpleApp = StackNavigator({
|
||||
Home: { screen: HomeScreen }
|
||||
});
|
||||
|
||||
export default class App extends React.Component {
|
||||
render() {
|
||||
return <SimpleApp />;
|
||||
}
|
||||
}
|
||||
|
||||
const styles = StyleSheet.create({
|
||||
container: {
|
||||
flex: 1,
|
||||
backgroundColor: '#fff',
|
||||
alignItems: 'center',
|
||||
justifyContent: 'center'
|
||||
}
|
||||
});
|
||||
|
||||
```
|
||||
|
||||
The `title` of the screen is configurable on the [static `navigationOptions`](/docs/navigators/navigation-options), where many options can be set to configure the presentation of the screen in the navigator.
|
||||
|
||||
Now the same screen should appear on both iPhone and Android apps:
|
||||
|
||||
```phone-example
|
||||
first-screen
|
||||
```
|
||||
|
||||
## Adding a New Screen
|
||||
|
||||
In our `App.js` file, let's add a new screen called `ChatScreen`, defining it under `HomeScreen`:
|
||||
|
||||
```js
|
||||
// ...
|
||||
|
||||
class HomeScreen extends React.Component {
|
||||
//...
|
||||
}
|
||||
|
||||
class ChatScreen extends React.Component {
|
||||
static navigationOptions = {
|
||||
title: 'Chat with Lucy',
|
||||
};
|
||||
render() {
|
||||
return (
|
||||
<View>
|
||||
<Text>Chat with Lucy</Text>
|
||||
</View>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
We can then add a button to our `HomeScreen` component that links to `ChatScreen`: we need to use the provided method `navigate` (from the [screen navigation prop](/docs/navigators/navigation-prop)) by giving it the `routeName` of the screen we want to reach, in this case `Chat`.
|
||||
|
||||
```js
|
||||
class HomeScreen extends React.Component {
|
||||
static navigationOptions = {
|
||||
title: 'Welcome',
|
||||
};
|
||||
render() {
|
||||
const { navigate } = this.props.navigation;
|
||||
return (
|
||||
<View>
|
||||
<Text>Hello, Chat App!</Text>
|
||||
<Button
|
||||
onPress={() => navigate('Chat')}
|
||||
title="Chat with Lucy"
|
||||
/>
|
||||
</View>
|
||||
);
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
(*don't forget to import View and Button from react-native:* `import { AppRegistry, Text, View, Button } from 'react-native';`)
|
||||
|
||||
But that won't work until we say to our `StackNavigator` of the existence of the `Chat` screen, like so:
|
||||
|
||||
```js
|
||||
export const SimpleApp = StackNavigator({
|
||||
Home: { screen: HomeScreen },
|
||||
Chat: { screen: ChatScreen },
|
||||
});
|
||||
```
|
||||
|
||||
Now you can navigate to your new screen, and go back:
|
||||
|
||||
```phone-example
|
||||
first-navigation
|
||||
```
|
||||
|
||||
## Passing params
|
||||
|
||||
Hardcoding a name into the `ChatScreen` isn't ideal. It'd be more useful if we could pass a name to be rendered instead, so let's do that.
|
||||
|
||||
In addition to specifying the target `routeName` in the navigate function, we can pass params that will be put into the new route. First, we'll edit our `HomeScreen` component to pass a `user` param into the route.
|
||||
|
||||
```js
|
||||
class HomeScreen extends React.Component {
|
||||
static navigationOptions = {
|
||||
title: 'Welcome',
|
||||
};
|
||||
render() {
|
||||
const { navigate } = this.props.navigation;
|
||||
return (
|
||||
<View>
|
||||
<Text>Hello, Chat App!</Text>
|
||||
<Button
|
||||
onPress={() => navigate('Chat', { user: 'Lucy' })}
|
||||
title="Chat with Lucy"
|
||||
/>
|
||||
</View>
|
||||
);
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
We can then edit our `ChatScreen` component to display the `user` param that was passed in through the route:
|
||||
|
||||
```js
|
||||
class ChatScreen extends React.Component {
|
||||
// Nav options can be defined as a function of the screen's props:
|
||||
static navigationOptions = ({ navigation }) => ({
|
||||
title: `Chat with ${navigation.state.params.user}`,
|
||||
});
|
||||
render() {
|
||||
// The screen's current route is passed in to `props.navigation.state`:
|
||||
const { params } = this.props.navigation.state;
|
||||
return (
|
||||
<View>
|
||||
<Text>Chat with {params.user}</Text>
|
||||
</View>
|
||||
);
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Now you can see the name when you navigate to the Chat screen. Try changing the `user` param in `HomeScreen` and see what happens!
|
||||
|
||||
```phone-example
|
||||
first-navigation
|
||||
```
|
||||
@@ -1,138 +0,0 @@
|
||||
# Configuring the Header
|
||||
|
||||
Header is only available for StackNavigator.
|
||||
|
||||
In the previous example, we created a StackNavigator to display several screens in our app.
|
||||
|
||||
|
||||
When navigating to a chat screen, we can specify params for the new route by providing them to the navigate function. In this case, we want to provide the name of the person on the chat screen:
|
||||
|
||||
```js
|
||||
this.props.navigation.navigate('Chat', { user: 'Lucy' });
|
||||
```
|
||||
|
||||
The `user` param can be accessed from the chat screen:
|
||||
|
||||
```js
|
||||
class ChatScreen extends React.Component {
|
||||
render() {
|
||||
const { params } = this.props.navigation.state;
|
||||
return <Text>Chat with {params.user}</Text>;
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Setting the Header Title
|
||||
|
||||
Next, the header title can be configured to use the screen param:
|
||||
|
||||
```js
|
||||
class ChatScreen extends React.Component {
|
||||
static navigationOptions = ({ navigation }) => ({
|
||||
title: `Chat with ${navigation.state.params.user}`,
|
||||
});
|
||||
...
|
||||
}
|
||||
```
|
||||
|
||||
```phone-example
|
||||
basic-header
|
||||
```
|
||||
|
||||
|
||||
### Adding a Right Button
|
||||
|
||||
Then we can add a [`header` navigation option](/docs/navigators/navigation-options#Stack-Navigation-Options) that allows us to add a custom right button:
|
||||
|
||||
```js
|
||||
static navigationOptions = {
|
||||
headerRight: <Button title="Info" />,
|
||||
...
|
||||
```
|
||||
|
||||
```phone-example
|
||||
header-button
|
||||
```
|
||||
|
||||
The navigation options can be defined with a [navigation prop](/docs/navigators/navigation-prop). Let's render a different button based on the route params, and set up the button to call `navigation.setParams` when pressed.
|
||||
|
||||
```js
|
||||
static navigationOptions = ({ navigation }) => {
|
||||
const { state, setParams } = navigation;
|
||||
const isInfo = state.params.mode === 'info';
|
||||
const { user } = state.params;
|
||||
return {
|
||||
title: isInfo ? `${user}'s Contact Info` : `Chat with ${state.params.user}`,
|
||||
headerRight: (
|
||||
<Button
|
||||
title={isInfo ? 'Done' : `${user}'s info`}
|
||||
onPress={() => setParams({ mode: isInfo ? 'none' : 'info' })}
|
||||
/>
|
||||
),
|
||||
};
|
||||
};
|
||||
```
|
||||
|
||||
Now, the header can interact with the screen route/state:
|
||||
|
||||
```phone-example
|
||||
header-interaction
|
||||
```
|
||||
|
||||
### Header interaction with screen component
|
||||
|
||||
Sometimes it is necessary for the header to access properties of the screen component such as functions or state.
|
||||
|
||||
Let's say we want to create an 'edit contact info' screen with a save button in the header. We want the save button to be replaced by an `ActivityIndicator` while saving.
|
||||
|
||||
```js
|
||||
class EditInfoScreen extends React.Component {
|
||||
static navigationOptions = ({ navigation }) => {
|
||||
const { params = {} } = navigation.state;
|
||||
let headerRight = (
|
||||
<Button
|
||||
title="Save"
|
||||
onPress={params.handleSave ? params.handleSave : () => null}
|
||||
/>
|
||||
);
|
||||
if (params.isSaving) {
|
||||
headerRight = <ActivityIndicator />;
|
||||
}
|
||||
return { headerRight };
|
||||
};
|
||||
|
||||
state = {
|
||||
nickname: 'Lucy jacuzzi'
|
||||
}
|
||||
|
||||
_handleSave = () => {
|
||||
// Update state, show ActivityIndicator
|
||||
this.props.navigation.setParams({ isSaving: true });
|
||||
|
||||
// Fictional function to save information in a store somewhere
|
||||
saveInfo().then(() => {
|
||||
this.props.navigation.setParams({ isSaving: false});
|
||||
})
|
||||
}
|
||||
|
||||
componentDidMount() {
|
||||
// We can only set the function after the component has been initialized
|
||||
this.props.navigation.setParams({ handleSave: this._handleSave });
|
||||
}
|
||||
|
||||
render() {
|
||||
return (
|
||||
<TextInput
|
||||
onChangeText={(nickname) => this.setState({ nickname })}
|
||||
placeholder={'Nickname'}
|
||||
value={this.state.nickname}
|
||||
/>
|
||||
);
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
**Note**: Since the `handleSave`-param is only set on component mount it is not immidiately available in the `navigationOptions`-function. Before `handleSave` is set we pass down an empty function to the `Button`-component in order to make it render immidiately and avoid flickering.
|
||||
|
||||
|
||||
To see the rest of the header options, see the [navigation options document](/docs/navigators/navigation-options#Stack-Navigation-Options).
|
||||
@@ -1,23 +0,0 @@
|
||||
# Introduction
|
||||
|
||||
_Learn once, navigate anywhere._
|
||||
|
||||
React Navigation is born from the React Native community's need for an extensible yet easy-to-use navigation solution based on Javascript.
|
||||
|
||||
React Navigation is the result of a collaboration between developers from Facebook, Expo and the React community at large: it replaces and improves upon several navigation libraries in the ecosystem, including Ex-Navigation, React Native's Navigator and NavigationExperimental components.
|
||||
|
||||
## Getting Started
|
||||
|
||||
If you're already familiar with React Native then you'll be able to get moving with React Navigation in minimal time.
|
||||
|
||||
1. [Quick Start](/docs/intro/quick-start)
|
||||
Quickly get a grasp on the React Navigation API with demonstrations of the StackNavigator, TabNavigator, and DrawerNavigator.
|
||||
|
||||
2. [Simple App](/docs/intro/basic-app)
|
||||
Dive into the basics of React Navigation by creating a new React Native project, installing React Navigation, creating your first navigator, and learning how to interact with it.
|
||||
|
||||
3. [Navigation Playground](https://github.com/react-community/react-navigation/tree/master/examples/NavigationPlayground)
|
||||
Curious of the various capabilities of React Navigation? Browse the official example app, which will demonstrates various patterns with React Navigation.
|
||||
|
||||
4. [Community Contributions](https://github.com/react-community/react-navigation#community-contributions)
|
||||
With the flexibility of React Navigation we won't be able to cover every possible situation, but another developer may have! Browse our list of community contributions to find topics that may answer your questions.
|
||||
@@ -1,122 +0,0 @@
|
||||
# Nesting Navigators
|
||||
|
||||
It is common in mobile apps to compose various forms of navigation. The routers and navigators in React Navigation are composable, which allows you to define a complicated navigation structure for your app.
|
||||
|
||||
For our chat app, we want to put several tabs on the first screen, to view recent chat threads or all contacts.
|
||||
|
||||
## Introducing Tab Navigator
|
||||
|
||||
Lets create a new `TabNavigator` in our `App.js`:
|
||||
|
||||
```js
|
||||
import { TabNavigator } from "react-navigation";
|
||||
|
||||
class RecentChatsScreen extends React.Component {
|
||||
render() {
|
||||
return <Text>List of recent chats</Text>
|
||||
}
|
||||
}
|
||||
|
||||
class AllContactsScreen extends React.Component {
|
||||
render() {
|
||||
return <Text>List of all contacts</Text>
|
||||
}
|
||||
}
|
||||
|
||||
const MainScreenNavigator = TabNavigator({
|
||||
Recent: { screen: RecentChatsScreen },
|
||||
All: { screen: AllContactsScreen },
|
||||
});
|
||||
```
|
||||
|
||||
If the `MainScreenNavigator` was rendered as the top-level navigator component, it would look like this:
|
||||
|
||||
```phone-example
|
||||
simple-tabs
|
||||
```
|
||||
|
||||
|
||||
|
||||
## Nesting a Navigator in a screen
|
||||
|
||||
We want these tabs to be visible in the first screen of the app, but new screens in the stack should cover the tabs.
|
||||
|
||||
Lets add our tabs navigator as a screen in our top-level `StackNavigator` that we set up in the [previous step](/docs/intro/).
|
||||
|
||||
```js
|
||||
const SimpleApp = StackNavigator({
|
||||
Home: { screen: MainScreenNavigator },
|
||||
Chat: { screen: ChatScreen },
|
||||
});
|
||||
```
|
||||
|
||||
Because `MainScreenNavigator` is being used as a screen, we can give it `navigationOptions`:
|
||||
|
||||
```js
|
||||
const SimpleApp = StackNavigator({
|
||||
Home: {
|
||||
screen: MainScreenNavigator,
|
||||
navigationOptions: {
|
||||
title: 'My Chats',
|
||||
},
|
||||
},
|
||||
Chat: { screen: ChatScreen },
|
||||
})
|
||||
```
|
||||
|
||||
Lets also add a button to each tab that links to a chat:
|
||||
|
||||
```js
|
||||
<Button
|
||||
onPress={() => this.props.navigation.navigate('Chat', { user: 'Lucy' })}
|
||||
title="Chat with Lucy"
|
||||
/>
|
||||
```
|
||||
|
||||
Now we have put one navigator inside another, and we can `navigate` between navigators:
|
||||
|
||||
```phone-example
|
||||
nested
|
||||
```
|
||||
|
||||
## Nesting a Navigator in a Component
|
||||
Sometimes it is desirable to nest a navigator that is wrapped in a component. This is useful in cases where the navigator only takes up part of the screen. For the child navigator to be wired into the navigation tree, it needs the `navigation` property from the parent navigator.
|
||||
|
||||
```js
|
||||
const SimpleApp = StackNavigator({
|
||||
Home: { screen: NavigatorWrappingScreen },
|
||||
Chat: { screen: ChatScreen },
|
||||
});
|
||||
```
|
||||
In this case, the NavigatorWrappingScreen is not a navigator, but it renders a navigator as part of its output.
|
||||
|
||||
If this navigator renders blank then change `<View>` to `<View style={{flex: 1}}>`.
|
||||
|
||||
```js
|
||||
class NavigatorWrappingScreen extends React.Component {
|
||||
render() {
|
||||
return (
|
||||
<View>
|
||||
<SomeComponent/>
|
||||
<MainScreenNavigator/>
|
||||
</View>
|
||||
);
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
To wire `MainScreenNavigator` into the navigation tree, we assign its `router` to the wrapping component. This makes `NavigatorWrappingScreen` "navigation aware", which tells the parent navigator to pass the navigation object down. Since the `NavigatorWrappingScreen`'s `router` is overridden with the child navigator's `router`, the child navigator will receive the needed `navigation`.
|
||||
|
||||
```js
|
||||
class NavigatorWrappingScreen extends React.Component {
|
||||
render() {
|
||||
return (
|
||||
<View>
|
||||
<SomeComponent/>
|
||||
<MainScreenNavigator navigation={this.props.navigation}/>
|
||||
</View>
|
||||
);
|
||||
}
|
||||
}
|
||||
NavigatorWrappingScreen.router = MainScreenNavigator.router;
|
||||
```
|
||||
@@ -1,316 +0,0 @@
|
||||
# Quick Start Guide
|
||||
|
||||
To get started with React Navigation, all you have to do is install the `react-navigation` npm package.
|
||||
|
||||
### Install with NPM
|
||||
|
||||
```
|
||||
npm install --save react-navigation
|
||||
```
|
||||
|
||||
### Install with Yarn
|
||||
|
||||
```
|
||||
yarn add react-navigation
|
||||
```
|
||||
|
||||
To start using React Navigation you'll have to create a navigator. React Navigation comes with three default navigators.
|
||||
|
||||
- `StackNavigator` - Provides a way for your app to transition between screens where each new screen is placed on top of a stack.
|
||||
- `TabNavigator` - Used to set up a screen with several tabs.
|
||||
- `DrawerNavigator` - Used to set up a screen with drawer navigation.
|
||||
|
||||
## Creating a StackNavigator
|
||||
|
||||
StackNavigator's are the most common form of navigator so we'll use it as a basic demonstration. To get started, create a `StackNavigator`.
|
||||
|
||||
```javascript
|
||||
import { StackNavigator } from 'react-navigation';
|
||||
|
||||
const RootNavigator = StackNavigator({
|
||||
|
||||
});
|
||||
|
||||
export default RootNavigator;
|
||||
```
|
||||
|
||||
We can then add screens to this `StackNavigator`. Each key represents a screen.
|
||||
|
||||
```javascript
|
||||
import React from 'react';
|
||||
import { View, Text } from 'react-native';
|
||||
import { StackNavigator } from 'react-navigation';
|
||||
|
||||
const HomeScreen = () => (
|
||||
<View style={{ flex: 1, alignItems: 'center', justifyContent: 'center' }}>
|
||||
<Text>Home Screen</Text>
|
||||
</View>
|
||||
);
|
||||
|
||||
const DetailsScreen = () => (
|
||||
<View style={{ flex: 1, alignItems: 'center', justifyContent: 'center' }}>
|
||||
<Text>Details Screen</Text>
|
||||
</View>
|
||||
);
|
||||
|
||||
const RootNavigator = StackNavigator({
|
||||
Home: {
|
||||
screen: HomeScreen,
|
||||
},
|
||||
Details: {
|
||||
screen: DetailsScreen,
|
||||
},
|
||||
});
|
||||
|
||||
export default RootNavigator;
|
||||
```
|
||||
|
||||
Now let's add a title to the navigation bar.
|
||||
|
||||
```javascript
|
||||
...
|
||||
|
||||
const RootNavigator = StackNavigator({
|
||||
Home: {
|
||||
screen: HomeScreen,
|
||||
navigationOptions: {
|
||||
headerTitle: 'Home',
|
||||
},
|
||||
},
|
||||
Details: {
|
||||
screen: DetailsScreen,
|
||||
navigationOptions: {
|
||||
headerTitle: 'Details',
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
export default RootNavigator;
|
||||
```
|
||||
|
||||
Finally, we should be able to navigate from the home screen to the details screen. When you register a component with a navigator that component will then have a `navigation` prop added to it. This `navigation` prop drives how we use move between different screens.
|
||||
|
||||
To move from the home screen to the details screen we'll want to use `navigation.navigate`, like so:
|
||||
|
||||
```javascript
|
||||
...
|
||||
import { View, Text, Button } from 'react-native';
|
||||
|
||||
const HomeScreen = ({ navigation }) => (
|
||||
<View style={{ flex: 1, alignItems: 'center', justifyContent: 'center' }}>
|
||||
<Text>Home Screen</Text>
|
||||
<Button
|
||||
onPress={() => navigation.navigate('Details')}
|
||||
title="Go to details"
|
||||
/>
|
||||
</View>
|
||||
);
|
||||
|
||||
...
|
||||
```
|
||||
|
||||
And there you have it! That's the basics of using the [StackNavigator](/docs/navigators/stack), and React Navigation as a whole. Here's the full code from this example:
|
||||
|
||||
<div class="snack" data-snack-id="HJlnU0XTb" data-snack-platform="ios" data-snack-preview="true" data-snack-theme="light" style="overflow:hidden;background:#fafafa;border:1px solid rgba(0,0,0,.16);border-radius:4px;height:505px;width:100%"></div>
|
||||
|
||||
## Creating a TabNavigator
|
||||
|
||||
To get started with `TabNavigator` first import and create a new `RootTabs` component.
|
||||
|
||||
```javascript
|
||||
import { TabNavigator } from 'react-navigation';
|
||||
|
||||
const RootTabs = TabNavigator({
|
||||
|
||||
});
|
||||
|
||||
export default RootTabs;
|
||||
```
|
||||
|
||||
We then need to create some screens and add them to our `TabNavigator`.
|
||||
|
||||
```javascript
|
||||
import React from 'react';
|
||||
import { View, Text } from 'react-native';
|
||||
import { TabNavigator } from 'react-navigation';
|
||||
|
||||
const HomeScreen = () => (
|
||||
<View style={{ flex: 1, alignItems: 'center', justifyContent: 'center' }}>
|
||||
<Text>Home Screen</Text>
|
||||
</View>
|
||||
);
|
||||
|
||||
const ProfileScreen = () => (
|
||||
<View style={{ flex: 1, alignItems: 'center', justifyContent: 'center' }}>
|
||||
<Text>Profile Screen</Text>
|
||||
</View>
|
||||
);
|
||||
|
||||
const RootTabs = TabNavigator({
|
||||
Home: {
|
||||
screen: HomeScreen,
|
||||
},
|
||||
Profile: {
|
||||
screen: ProfileScreen,
|
||||
},
|
||||
});
|
||||
|
||||
export default RootTabs;
|
||||
```
|
||||
|
||||
Getting there! Now let's explicity set a label and icon for the tab bar.
|
||||
|
||||
> We'll be using [`react-native-vector-icons`](https://github.com/oblador/react-native-vector-icons) in the example. If you don't have it installed in your project already please do so.
|
||||
|
||||
```javascript
|
||||
...
|
||||
import Ionicons from 'react-native-vector-icons/Ionicons';
|
||||
|
||||
...
|
||||
|
||||
const RootTabs = TabNavigator({
|
||||
Home: {
|
||||
screen: HomeScreen,
|
||||
navigationOptions: {
|
||||
tabBarLabel: 'Home',
|
||||
tabBarIcon: ({ tintColor, focused }) => (
|
||||
<Ionicons
|
||||
name={focused ? 'ios-home' : 'ios-home-outline'}
|
||||
size={26}
|
||||
style={{ color: tintColor }}
|
||||
/>
|
||||
),
|
||||
},
|
||||
},
|
||||
Profile: {
|
||||
screen: ProfileScreen,
|
||||
navigationOptions: {
|
||||
tabBarLabel: 'Profile',
|
||||
tabBarIcon: ({ tintColor, focused }) => (
|
||||
<Ionicons
|
||||
name={focused ? 'ios-person' : 'ios-person-outline'}
|
||||
size={26}
|
||||
style={{ color: tintColor }}
|
||||
/>
|
||||
),
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
export default RootTabs;
|
||||
```
|
||||
|
||||
This will ensure the `tabBarLabel` is consistent (important when using nested navigators) and it will set a `tabBarIcon`. This icon will only be visible on iOS by default given the tab bar component used, which aligns with standard design patterns on Android.
|
||||
|
||||
You can view the complete finished code below:
|
||||
|
||||
<div class="snack" data-snack-id="BJZ2GVVpb" data-snack-platform="ios" data-snack-preview="true" data-snack-theme="light" style="overflow:hidden;background:#fafafa;border:1px solid rgba(0,0,0,.16);border-radius:4px;height:505px;width:100%"></div>
|
||||
|
||||
## Creating a DrawerNavigator
|
||||
|
||||
To get started with `DrawerNavigator` first import and create a new `RootDrawer` component.
|
||||
|
||||
```javascript
|
||||
import { DrawerNavigator } from 'react-navigation';
|
||||
|
||||
const RootDrawer = DrawerNavigator({
|
||||
|
||||
});
|
||||
|
||||
export default RootDrawer;
|
||||
```
|
||||
|
||||
We then need to create some screens and add them to our `DrawerNavigator`.
|
||||
|
||||
```javascript
|
||||
import React from 'react';
|
||||
import { View, Text } from 'react-native';
|
||||
import { DrawerNavigator } from 'react-navigation';
|
||||
|
||||
const HomeScreen = () => (
|
||||
<View style={{ flex: 1, alignItems: 'center', justifyContent: 'center' }}>
|
||||
<Text>Home Screen</Text>
|
||||
</View>
|
||||
);
|
||||
|
||||
const ProfileScreen = () => (
|
||||
<View style={{ flex: 1, alignItems: 'center', justifyContent: 'center' }}>
|
||||
<Text>Profile Screen</Text>
|
||||
</View>
|
||||
);
|
||||
|
||||
const RootDrawer = DrawerNavigator({
|
||||
Home: {
|
||||
screen: HomeScreen,
|
||||
},
|
||||
Profile: {
|
||||
screen: ProfileScreen,
|
||||
},
|
||||
});
|
||||
|
||||
export default RootDrawer;
|
||||
```
|
||||
|
||||
Getting there! Now let's explicity set a label and icon for the drawer items.
|
||||
|
||||
> We'll be using `react-native-vector-icons` in the example. If you don't have it installed in your project already please do so.
|
||||
|
||||
```javascript
|
||||
...
|
||||
import Ionicons from 'react-native-vector-icons/Ionicons';
|
||||
|
||||
...
|
||||
|
||||
const RootDrawer = DrawerNavigator({
|
||||
Home: {
|
||||
screen: HomeScreen,
|
||||
navigationOptions: {
|
||||
drawerLabel: 'Home',
|
||||
drawerIcon: ({ tintColor, focused }) => (
|
||||
<Ionicons
|
||||
name={focused ? 'ios-home' : 'ios-home-outline'}
|
||||
size={20}
|
||||
style={{ color: tintColor }}
|
||||
/>
|
||||
),
|
||||
},
|
||||
},
|
||||
Profile: {
|
||||
screen: ProfileScreen,
|
||||
navigationOptions: {
|
||||
drawerLabel: 'Profile',
|
||||
drawerIcon: ({ tintColor, focused }) => (
|
||||
<Ionicons
|
||||
name={focused ? 'ios-person' : 'ios-person-outline'}
|
||||
size={20}
|
||||
style={{ color: tintColor }}
|
||||
/>
|
||||
),
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
export default RootDrawer;
|
||||
```
|
||||
|
||||
To open the drawer you can swipe from the left edge of the screen to the right. You've also got the option to open the drawer view `navigation.navigate('DrawerToggle')`, which we'll add to the Home component now. Make sure you import the `Button` component from `react-native`.
|
||||
|
||||
```javascript
|
||||
...
|
||||
|
||||
const HomeScreen = ({ navigation }) => (
|
||||
<View style={{ flex: 1, alignItems: 'center', justifyContent: 'center' }}>
|
||||
<Text>Home Screen</Text>
|
||||
<Button
|
||||
onPress={() => navigation.navigate('DrawerToggle')}
|
||||
title="Open Drawer"
|
||||
/>
|
||||
</View>
|
||||
);
|
||||
|
||||
...
|
||||
```
|
||||
|
||||
You can view the finished code below.
|
||||
|
||||
<div class="snack" data-snack-id="rk90N44a-" data-snack-platform="ios" data-snack-preview="true" data-snack-theme="light" style="overflow:hidden;background:#fafafa;border:1px solid rgba(0,0,0,.16);border-radius:4px;height:505px;width:100%"></div>
|
||||
@@ -1,174 +0,0 @@
|
||||
## Common React Navigation API - Hybrid Integration
|
||||
|
||||
This is a purely speculative API that demonstrates how it may be possible to integrate the [JS navigation API](./Common-Navigation-Spec.md) in a hybrid app.
|
||||
|
||||
## Setting up a screen
|
||||
|
||||
It should be possible to register new screens from JS into native. In your main bundle:
|
||||
|
||||
```
|
||||
const HybridNavigationModule = require('NativeModules').HybridNavigation;
|
||||
|
||||
HybridNavigationModule.registerScreens([
|
||||
{
|
||||
type: 'Marketplace',
|
||||
screen: MarketplaceScreen,
|
||||
},
|
||||
{
|
||||
type: 'Product',
|
||||
screen: ProductScreen,
|
||||
},
|
||||
]);
|
||||
```
|
||||
|
||||
## Linking to JS
|
||||
|
||||
Now, your native code can open a react screen by type name:
|
||||
|
||||
```
|
||||
// please pretend this is Obj-C or Java syntax:
|
||||
CoreHybridNavigation.openReactScreen('Profile', {id: 123});
|
||||
```
|
||||
|
||||
## Linking to Native
|
||||
|
||||
If JS product code wants to request navigation to a screen that may *or may not* be in native, it can do this:
|
||||
|
||||
```
|
||||
const MarketplaceScreen = ({ navigation }) => (
|
||||
<View>
|
||||
<Button onPress={() => navigation.dispatch({
|
||||
type: 'Product',
|
||||
id: 42,
|
||||
})}>
|
||||
See product 42
|
||||
</Button>
|
||||
</View>
|
||||
);
|
||||
```
|
||||
|
||||
Inside the infra:
|
||||
|
||||
```
|
||||
class InfraScreen extends React.Component {
|
||||
constructor() {
|
||||
const {initURI, type} = this.props;
|
||||
const ScreenView = ScreenRegistry[type].screen;
|
||||
const router = ScreenView.router;
|
||||
const deepLinkAction = router.getActionForURI(initURI);
|
||||
const initAction = deepLinkAction || {type: 'init'}
|
||||
const nav = router.getStateForAction(initAction);
|
||||
this.state = {
|
||||
nav,
|
||||
};
|
||||
HybridNavigationModule.setNavOptions(this.state.nav);
|
||||
}
|
||||
componentWillUpdate() {
|
||||
HybridNavigationModule.setNavOptions(this.state.nav);
|
||||
}
|
||||
dispatch = (action) => {
|
||||
const {type} = this.props;
|
||||
const ScreenView = ScreenRegistry[type].screen;
|
||||
const {getStateForAction} = ScreenView.router;
|
||||
const newNavState = getStateForAction(action, this.state.nav);
|
||||
if (newNavState !== this.state.nav) {
|
||||
this.setState({ nav: newNavState });
|
||||
return true;
|
||||
}
|
||||
if (action.type === 'URI') {
|
||||
HybridNavigationModule.openURI(action.uri);
|
||||
return true;
|
||||
}
|
||||
if (action.type === NavigationActions.BACK) {
|
||||
HybridNavigationModule.goBack();
|
||||
return true;
|
||||
}
|
||||
HybridNavigationModule.openAction(action);
|
||||
return true;
|
||||
}
|
||||
render() {
|
||||
const {type} = this.props;
|
||||
const ScreenView = ScreenRegistry[type].screen;
|
||||
const navigation = {
|
||||
dispatch: this.dispatch,
|
||||
state: this.state.nav,
|
||||
};
|
||||
return <ScreenView navigation={navigation} />;
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## Setting title
|
||||
|
||||
```
|
||||
MarketplaceScreen.router = {
|
||||
getStateForAction(action, lastState) {
|
||||
return lastState || {title: 'Marketplace Home'};
|
||||
},
|
||||
};
|
||||
```
|
||||
A HOC could be used to make this feel more elegant.
|
||||
|
||||
|
||||
## Disabling/Enabling the right button
|
||||
|
||||
```
|
||||
const TestScreen = ({ navigation }) => (
|
||||
<View>
|
||||
<Button onPress={() => navigation.dispatch({
|
||||
type: 'ToggleMyButtonPressability',
|
||||
})}>
|
||||
{navigation.state.rightButtonEnabled ? 'Disable' : 'Enable'} right button
|
||||
</Button>
|
||||
<Text>Pressed {navigation.state} times</Text>
|
||||
</View>
|
||||
);
|
||||
TestScreen.router = {
|
||||
getStateForAction(action, lastState = {}) {
|
||||
let state = lastState || {
|
||||
rightButtonEnabled: true,
|
||||
rightButtonTitle: 'Tap Me',
|
||||
pressCount: 0,
|
||||
};
|
||||
if (action.type === 'ToggleMyButtonPressability') {
|
||||
state = {
|
||||
...state,
|
||||
rightButtonEnabled: !state.rightButtonEnabled,
|
||||
};
|
||||
} else if (action.type === 'RightButtonPress') {
|
||||
state = {
|
||||
...state,
|
||||
pressCount: state.pressCount + 1,
|
||||
};
|
||||
}
|
||||
return state;
|
||||
},
|
||||
};
|
||||
```
|
||||
|
||||
|
||||
## Before JS starts
|
||||
|
||||
A JSON file could be defined for native to consume before JS spins up:
|
||||
|
||||
```
|
||||
{
|
||||
"screens": [
|
||||
{
|
||||
"type": "Profile",
|
||||
"path": "/users/:id?name=:name",
|
||||
"params": {
|
||||
"name": "string",
|
||||
"id": "number"
|
||||
},
|
||||
"title": "%name%' s Profile",
|
||||
"rightButtonTitle": "Message %name%"
|
||||
},
|
||||
{
|
||||
...
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
This seems like a pain to set up, so we can statically analyze our JS and autogenerate this JSON! If the JS in an app changes, there could be a way for JS to report the new routing configuration to native for use on the next cold start.
|
||||
@@ -1,109 +0,0 @@
|
||||
# Navigation Actions
|
||||
|
||||
All Navigation Actions return an object that can be sent to the router using `navigation.dispatch()` method.
|
||||
|
||||
Note that if you want to dispatch react-navigation actions you should use the action creators provided in this library.
|
||||
|
||||
The following actions are supported:
|
||||
* [Navigate](#Navigate) - Navigate to another route
|
||||
* [Reset](#Reset) - Replace current state with a new state
|
||||
* [Back](#Back) - Go back to previous state
|
||||
* [Set Params](#SetParams) - Set Params for given route
|
||||
* [Init](#Init) - Used to initialize first state if state is undefined
|
||||
|
||||
### Navigate
|
||||
The `Navigate` action will update the current state with the result of a `Navigate` action.
|
||||
|
||||
- `routeName` - *String* - Required - A destination routeName that has been registered somewhere in the app's router
|
||||
- `params` - *Object* - Optional - Params to merge into the destination route
|
||||
- `action` - *Object* - Optional - (advanced) The sub-action to run in the child router, if the screen is a navigator. Any one of the actions described in this doc can be set as a sub-action.
|
||||
|
||||
```js
|
||||
import { NavigationActions } from 'react-navigation'
|
||||
|
||||
const navigateAction = NavigationActions.navigate({
|
||||
|
||||
routeName: 'Profile',
|
||||
|
||||
params: {},
|
||||
|
||||
action: NavigationActions.navigate({ routeName: 'SubProfileRoute'})
|
||||
})
|
||||
|
||||
this.props.navigation.dispatch(navigateAction)
|
||||
|
||||
```
|
||||
|
||||
|
||||
### Reset
|
||||
|
||||
The `Reset` action wipes the whole navigation state and replaces it with the result of several actions.
|
||||
|
||||
- `index` - *number* - required - Index of the active route on `routes` array in navigation `state`.
|
||||
- `actions` - *array* - required - Array of Navigation Actions that will replace the navigation state.
|
||||
- `key` - *string or null* - optional - If set, the navigator with the given key will reset. If null, the root navigator will reset.
|
||||
|
||||
```js
|
||||
import { NavigationActions } from 'react-navigation'
|
||||
|
||||
const resetAction = NavigationActions.reset({
|
||||
index: 0,
|
||||
actions: [
|
||||
NavigationActions.navigate({ routeName: 'Profile'})
|
||||
]
|
||||
})
|
||||
this.props.navigation.dispatch(resetAction)
|
||||
|
||||
```
|
||||
#### How to use the `index` parameter
|
||||
The `index` param is used to specify the current active route.
|
||||
|
||||
eg: given a basic stack navigation with two routes `Profile` and `Settings`.
|
||||
To reset the state to a point where the active screen was `Settings` but have it stacked on top of a `Profile` screen, you would do the following:
|
||||
|
||||
```js
|
||||
import { NavigationActions } from 'react-navigation'
|
||||
|
||||
const resetAction = NavigationActions.reset({
|
||||
index: 1,
|
||||
actions: [
|
||||
NavigationActions.navigate({ routeName: 'Profile'}),
|
||||
NavigationActions.navigate({ routeName: 'Settings'})
|
||||
]
|
||||
})
|
||||
this.props.navigation.dispatch(resetAction)
|
||||
|
||||
```
|
||||
|
||||
### Back
|
||||
|
||||
Go back to previous screen and close current screen. `back` action creator takes in one optional parameter:
|
||||
- `key` - *string or null* - optional - If set, navigation will go back from the given key. If null, navigation will go back anywhere.
|
||||
|
||||
```js
|
||||
import { NavigationActions } from 'react-navigation'
|
||||
|
||||
const backAction = NavigationActions.back({
|
||||
key: 'Profile'
|
||||
})
|
||||
this.props.navigation.dispatch(backAction)
|
||||
|
||||
```
|
||||
|
||||
### SetParams
|
||||
|
||||
When dispatching `SetParams`, the router will produce a new state that has changed the params of a particular route, as identified by the key
|
||||
|
||||
- `params` - *object* - required - New params to be merged into existing route params
|
||||
- `key` - *string* - required - Route key that should get the new params
|
||||
|
||||
```js
|
||||
import { NavigationActions } from 'react-navigation'
|
||||
|
||||
const setParamsAction = NavigationActions.setParams({
|
||||
params: { title: 'Hello' },
|
||||
key: 'screen-123',
|
||||
})
|
||||
this.props.navigation.dispatch(setParamsAction)
|
||||
|
||||
```
|
||||
@@ -1,131 +0,0 @@
|
||||
# Redux Integration
|
||||
|
||||
To handle your app's navigation state in redux, you can pass your own `navigation` prop to a navigator. Your navigation prop must provide the current state, as well as access to a dispatcher to handle navigation options.
|
||||
|
||||
With redux, your app's state is defined by a reducer. Each navigation router effectively has a reducer, called `getStateForAction`. The following is a minimal example of how you might use navigators within a redux application:
|
||||
|
||||
```es6
|
||||
import { addNavigationHelpers } from 'react-navigation';
|
||||
|
||||
const AppNavigator = StackNavigator(AppRouteConfigs);
|
||||
|
||||
const initialState = AppNavigator.router.getStateForAction(AppNavigator.router.getActionForPathAndParams('Login'));
|
||||
|
||||
const navReducer = (state = initialState, action) => {
|
||||
const nextState = AppNavigator.router.getStateForAction(action, state);
|
||||
|
||||
// Simply return the original `state` if `nextState` is null or undefined.
|
||||
return nextState || state;
|
||||
};
|
||||
|
||||
const appReducer = combineReducers({
|
||||
nav: navReducer,
|
||||
...
|
||||
});
|
||||
|
||||
class App extends React.Component {
|
||||
render() {
|
||||
return (
|
||||
<AppNavigator navigation={addNavigationHelpers({
|
||||
dispatch: this.props.dispatch,
|
||||
state: this.props.nav,
|
||||
})} />
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
const mapStateToProps = (state) => ({
|
||||
nav: state.nav
|
||||
});
|
||||
|
||||
const AppWithNavigationState = connect(mapStateToProps)(App);
|
||||
|
||||
const store = createStore(appReducer);
|
||||
|
||||
class Root extends React.Component {
|
||||
render() {
|
||||
return (
|
||||
<Provider store={store}>
|
||||
<AppWithNavigationState />
|
||||
</Provider>
|
||||
);
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Once you do this, your navigation state is stored within your redux store, at which point you can fire navigation actions using your redux dispatch function.
|
||||
|
||||
Keep in mind that when a navigator is given a `navigation` prop, it relinquishes control of its internal state. That means you are now responsible for persisting its state, handling any deep linking, [Handling the Hardware Back Button in Android](#handling-the-hardware-back-button-in-android), etc.
|
||||
|
||||
Navigation state is automatically passed down from one navigator to another when you nest them. Note that in order for a child navigator to receive the state from a parent navigator, it should be defined as a `screen`.
|
||||
|
||||
Applying this to the example above, you could instead define `AppNavigator` to contain a nested `TabNavigator` as follows:
|
||||
|
||||
```es6
|
||||
const AppNavigator = StackNavigator({
|
||||
Home: { screen: MyTabNavigator },
|
||||
});
|
||||
```
|
||||
|
||||
In this case, once you `connect` `AppNavigator` to Redux as is done in `AppWithNavigationState`, `MyTabNavigator` will automatically have access to navigation state as a `navigation` prop.
|
||||
|
||||
## Full example
|
||||
|
||||
There's a working example app with redux [here](https://github.com/react-community/react-navigation/tree/master/examples/ReduxExample) if you want to try it out yourself.
|
||||
|
||||
## Mocking tests
|
||||
|
||||
To make jest tests work with your react-navigation app, you need to change the jest preset in the `package.json`, see [here](https://facebook.github.io/jest/docs/tutorial-react-native.html#transformignorepatterns-customization):
|
||||
|
||||
|
||||
```json
|
||||
"jest": {
|
||||
"preset": "react-native",
|
||||
"transformIgnorePatterns": [
|
||||
"node_modules/(?!(jest-)?react-native|react-navigation)"
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
## Handling the Hardware Back Button in Android
|
||||
|
||||
By using the following snippet, your nav component will be aware of the back button press actions and will correctly interact with your stack. This is really useful on Android.
|
||||
|
||||
```es6
|
||||
import React from "react";
|
||||
import { BackHandler } from "react-native";
|
||||
import { addNavigationHelpers, NavigationActions } from "react-navigation";
|
||||
|
||||
const AppNavigation = TabNavigator(
|
||||
{
|
||||
Home: { screen: HomeScreen },
|
||||
Settings: { screen: SettingScreen }
|
||||
}
|
||||
);
|
||||
|
||||
class ReduxNavigation extends React.Component {
|
||||
componentDidMount() {
|
||||
BackHandler.addEventListener("hardwareBackPress", this.onBackPress);
|
||||
}
|
||||
componentWillUnmount() {
|
||||
BackHandler.removeEventListener("hardwareBackPress", this.onBackPress);
|
||||
}
|
||||
onBackPress = () => {
|
||||
const { dispatch, nav } = this.props;
|
||||
if (nav.index === 0) {
|
||||
return false;
|
||||
}
|
||||
dispatch(NavigationActions.back());
|
||||
return true;
|
||||
};
|
||||
|
||||
render() {
|
||||
const { dispatch, nav } = this.props;
|
||||
const navigation = addNavigationHelpers({
|
||||
dispatch,
|
||||
state: nav
|
||||
});
|
||||
|
||||
return <AppNavigation navigation={navigation} />;
|
||||
}
|
||||
}
|
||||
@@ -1,104 +0,0 @@
|
||||
|
||||
# Screen Navigation Options
|
||||
|
||||
Each screen can configure several aspects about how it gets presented in parent navigators.
|
||||
|
||||
#### Two Ways to specify each option
|
||||
|
||||
**Static configuration:** Each navigation option can either be directly assigned:
|
||||
|
||||
```js
|
||||
class MyScreen extends React.Component {
|
||||
static navigationOptions = {
|
||||
title: 'Great',
|
||||
};
|
||||
...
|
||||
```
|
||||
|
||||
**Dynamic Configuration**
|
||||
|
||||
Or, the options can be a function that takes the following arguments, and returns an object of navigation options that will override the route-defined and navigator-defined navigationOptions.
|
||||
|
||||
- `props` - The same props that are available to the screen component
|
||||
- `navigation` - The [navigation prop](/docs/navigators/navigation-prop) for the screen, with the screen's route at `navigation.state`
|
||||
- `screenProps` - The props passing from above the navigator component
|
||||
- `navigationOptions` - The default or previous options that would be used if new values are not provided
|
||||
|
||||
```js
|
||||
class ProfileScreen extends React.Component {
|
||||
static navigationOptions = ({ navigation, screenProps }) => ({
|
||||
title: navigation.state.params.name + "'s Profile!",
|
||||
headerRight: <Button color={screenProps.tintColor} {...} />,
|
||||
});
|
||||
...
|
||||
```
|
||||
|
||||
The screenProps are passed in at render-time. If this screen was hosted in a SimpleApp navigator:
|
||||
|
||||
```js
|
||||
<SimpleApp
|
||||
screenProps={{tintColor: 'blue'}}
|
||||
// navigation={{state, dispatch}} // optionally control the app
|
||||
/>
|
||||
```
|
||||
|
||||
#### Generic Navigation Options
|
||||
|
||||
The `title` navigation option is generic between every navigator. It is used to set the title string for a given screen.
|
||||
|
||||
```js
|
||||
class MyScreen extends React.Component {
|
||||
static navigationOptions = {
|
||||
title: 'Great',
|
||||
};
|
||||
...
|
||||
```
|
||||
|
||||
Unlike the other nav options which are only utilized by the navigator view, the title option can be used by the environment to update the title in the browser window or app switcher.
|
||||
|
||||
#### Default Navigation Options
|
||||
|
||||
It's very common to define `navigationOptions` on a screen, but sometimes it is useful to define `navigationOptions` on a navigator too.
|
||||
|
||||
Imagine the following scenario:
|
||||
Your `TabNavigator` represents one of the screens in the app, and is nested within a top-level `StackNavigator`:
|
||||
|
||||
```
|
||||
StackNavigator({
|
||||
route1: { screen: RouteOne },
|
||||
route2: { screen: MyTabNavigator },
|
||||
});
|
||||
```
|
||||
|
||||
Now, when `route2` is active, you would like to change the tint color of a header. It's easy to do it for `route1`, and it should also be easy to do it for `route2`. This is what Default Navigation Options are for - they are simply `navigationOptions` set on a navigator:
|
||||
|
||||
```js
|
||||
const MyTabNavigator = TabNavigator({
|
||||
profile: ProfileScreen,
|
||||
...
|
||||
}, {
|
||||
navigationOptions: {
|
||||
headerTintColor: 'blue',
|
||||
},
|
||||
});
|
||||
```
|
||||
|
||||
Note that you can still decide to **also** specify the `navigationOptions` on the screens at the leaf level - e.g. the `ProfileScreen` above. The `navigationOptions` from the screen will be merged key-by-key with the default options coming from the navigator. Whenever both the navigator and screen define the same option (e.g. `headerTintColor`), the screen wins. Therefore, you could change the tint color when `ProfileScreen` is active by doing the following:
|
||||
|
||||
```js
|
||||
class ProfileScreen extends React.Component {
|
||||
static navigationOptions = {
|
||||
headerTintColor: 'black',
|
||||
};
|
||||
...
|
||||
}
|
||||
```
|
||||
|
||||
## Navigation Option Reference
|
||||
|
||||
List of available navigation options depends on the `navigator` the screen is added to.
|
||||
|
||||
Check available options for:
|
||||
- [`drawer navigator`](/docs/navigators/drawer#Screen-Navigation-Options)
|
||||
- [`stack navigator`](/docs/navigators/stack#Screen-Navigation-Options)
|
||||
- [`tab navigator`](/docs/navigators/tab#Screen-Navigation-Options)
|
||||
@@ -1,159 +0,0 @@
|
||||
|
||||
# Screen Navigation Prop
|
||||
|
||||
Each *screen* in your app will receive a navigation prop which contain the following:
|
||||
* `navigate` - (helper) link to other screens
|
||||
* `state` - screen's current state/routes
|
||||
* `setParams` - (helper) make changes to route's params
|
||||
* `goBack` - (helper) close active screen and move back
|
||||
* `dispatch` - send an action to router
|
||||
|
||||
*NOTE:* The `navigation` prop is passed down to every navigation-aware component including navigators. The big exception is that a navigator's `navigation` prop may not have the helper functions (`navigate`, `goBack`, etc); it may only have `state` and `dispatch`. In order to `navigate` using the navigator's `navigation` prop, you will have to `dispatch` using an [action creator](navigation-actions).
|
||||
|
||||
*Notes regarding hooking things up with Redux*
|
||||
|
||||
> People don't always hook things up to redux correctly, because they mis-understand the navigator's top-level API, where the navigation prop is optional. The navigator will maintain its own state if it doesn't get a navigation prop, but this is not a feature you generally want to use when hooking your app up with redux. For navigators that are nested inside of your main navigator, you always want to pass the screen's navigation prop down. This allows your top-level navigator to communicate and provide state for all the children navigators. Only your top-level router needs to be integrated with redux, because all the other routers are inside it.
|
||||
|
||||
## `navigate` - Link to other screens
|
||||
|
||||
Call this to link to another screen in your app. Takes the following arguments:
|
||||
|
||||
`navigate(routeName, params, action)`
|
||||
|
||||
- `routeName` - A destination routeName that has been registered somewhere in the app's router
|
||||
- `params` - Params to merge into the destination route
|
||||
- `action` - (advanced) The sub-action to run in the child router, if the screen is a navigator. See [Actions Doc](navigation-actions) for a full list of supported actions.
|
||||
|
||||
```js
|
||||
class HomeScreen extends React.Component {
|
||||
render() {
|
||||
const {navigate} = this.props.navigation;
|
||||
|
||||
return (
|
||||
<View>
|
||||
<Text>This is the home screen of the app</Text>
|
||||
<Button
|
||||
onPress={() => navigate('Profile', {name: 'Brent'})}
|
||||
title="Go to Brent's profile"
|
||||
/>
|
||||
</View>
|
||||
)
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## `state` - The screen's current state/route
|
||||
|
||||
A screen has access to its route via `this.props.navigation.state`. Each will return an object with the following:
|
||||
|
||||
```js
|
||||
{
|
||||
// the name of the route config in the router
|
||||
routeName: 'profile',
|
||||
//a unique identifier used to sort routes
|
||||
key: 'main0',
|
||||
//an optional object of string options for this screen
|
||||
params: { hello: 'world' }
|
||||
}
|
||||
```
|
||||
|
||||
```js
|
||||
class ProfileScreen extends React.Component {
|
||||
render() {
|
||||
const {state} = this.props.navigation;
|
||||
// state.routeName === 'Profile'
|
||||
return (
|
||||
<Text>Name: {state.params.name}</Text>
|
||||
);
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
## `setParams` - Make changes to route params
|
||||
|
||||
Firing the `setParams` action allows a screen to change the params in the route, which is useful for updating the header buttons and title.
|
||||
|
||||
```js
|
||||
class ProfileScreen extends React.Component {
|
||||
render() {
|
||||
const {setParams} = this.props.navigation;
|
||||
return (
|
||||
<Button
|
||||
onPress={() => setParams({name: 'Lucy'})}
|
||||
title="Set title name to 'Lucy'"
|
||||
/>
|
||||
)
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## `goBack` - Close the active screen and move back
|
||||
|
||||
Optionally provide a key, which specifies the route to go back from. By default, goBack will close the route that it is called from. If the goal is to go back *anywhere*, without specifying what is getting closed, call `.goBack(null);`
|
||||
|
||||
```js
|
||||
class HomeScreen extends React.Component {
|
||||
render() {
|
||||
const {goBack} = this.props.navigation;
|
||||
return (
|
||||
<View>
|
||||
<Button
|
||||
onPress={() => goBack()}
|
||||
title="Go back from this HomeScreen"
|
||||
/>
|
||||
<Button
|
||||
onPress={() => goBack(null)}
|
||||
title="Go back anywhere"
|
||||
/>
|
||||
<Button
|
||||
onPress={() => goBack('screen-123')}
|
||||
title="Go back from screen-123"
|
||||
/>
|
||||
</View>
|
||||
)
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
*Going back from a specific screen*
|
||||
|
||||
Consider the following navigation stack history:
|
||||
```...
|
||||
navigation.navigate(SCREEN_KEY_A);
|
||||
...
|
||||
navigation.navigate(SCREEN_KEY_B);
|
||||
...
|
||||
navigation.navigate(SCREEN_KEY_C);
|
||||
...
|
||||
navigation.navigate(SCREEN_KEY_D);
|
||||
```
|
||||
|
||||
Now you are on *screen D* and want to go back to *screen A* (popping D, C, and B).
|
||||
Then you need to supply a key to goBack *FROM*:
|
||||
|
||||
```
|
||||
navigation.goBack(SCREEN_KEY_B) // will go to screen A FROM screen B
|
||||
```
|
||||
|
||||
## `dispatch` - Send an action to the router
|
||||
|
||||
Use dispatch to send any navigation action to the router. The other navigation functions use dispatch behind the scenes.
|
||||
|
||||
Note that if you want to dispatch react-navigation actions you should use the action creators provided in this library.
|
||||
|
||||
See [Navigation Actions Docs](navigation-actions) for a full list of available actions.
|
||||
|
||||
```js
|
||||
import { NavigationActions } from 'react-navigation'
|
||||
|
||||
const navigateAction = NavigationActions.navigate({
|
||||
routeName: 'Profile',
|
||||
params: {},
|
||||
|
||||
// navigate can have a nested navigate action that will be run inside the child router
|
||||
action: NavigationActions.navigate({ routeName: 'SubProfileRoute'})
|
||||
})
|
||||
this.props.navigation.dispatch(navigateAction)
|
||||
|
||||
```
|
||||
@@ -1,93 +0,0 @@
|
||||
## Screen tracking and analytics
|
||||
|
||||
This example shows how to do screen tracking and send to Google Analytics. The approach can be adapted to any other mobile analytics SDK.
|
||||
|
||||
### Screen tracking
|
||||
|
||||
When using built-in navigation container, we can use `onNavigationStateChange` to track the screen.
|
||||
|
||||
```js
|
||||
import { GoogleAnalyticsTracker } from 'react-native-google-analytics-bridge';
|
||||
|
||||
const tracker = new GoogleAnalyticsTracker(GA_TRACKING_ID);
|
||||
|
||||
// gets the current screen from navigation state
|
||||
function getCurrentRouteName(navigationState) {
|
||||
if (!navigationState) {
|
||||
return null;
|
||||
}
|
||||
const route = navigationState.routes[navigationState.index];
|
||||
// dive into nested navigators
|
||||
if (route.routes) {
|
||||
return getCurrentRouteName(route);
|
||||
}
|
||||
return route.routeName;
|
||||
}
|
||||
|
||||
const AppNavigator = StackNavigator(AppRouteConfigs);
|
||||
|
||||
export default () => (
|
||||
<AppNavigator
|
||||
onNavigationStateChange={(prevState, currentState) => {
|
||||
const currentScreen = getCurrentRouteName(currentState);
|
||||
const prevScreen = getCurrentRouteName(prevState);
|
||||
|
||||
if (prevScreen !== currentScreen) {
|
||||
// the line below uses the Google Analytics tracker
|
||||
// change the tracker here to use other Mobile analytics SDK.
|
||||
tracker.trackScreenView(currentScreen);
|
||||
}
|
||||
}}
|
||||
/>
|
||||
);
|
||||
```
|
||||
|
||||
### Screen tracking with Redux
|
||||
|
||||
When using Redux, we can write a Redux middleware to track the screen. For this purpose,
|
||||
we will reuse `getCurrentRouteName` from the previous section.
|
||||
|
||||
```js
|
||||
import { NavigationActions } from 'react-navigation';
|
||||
import { GoogleAnalyticsTracker } from 'react-native-google-analytics-bridge';
|
||||
|
||||
const tracker = new GoogleAnalyticsTracker(GA_TRACKING_ID);
|
||||
|
||||
const screenTracking = ({ getState }) => next => (action) => {
|
||||
if (
|
||||
action.type !== NavigationActions.NAVIGATE
|
||||
&& action.type !== NavigationActions.BACK
|
||||
) {
|
||||
return next(action);
|
||||
}
|
||||
|
||||
const currentScreen = getCurrentRouteName(getState().navigation);
|
||||
const result = next(action);
|
||||
const nextScreen = getCurrentRouteName(getState().navigation);
|
||||
if (nextScreen !== currentScreen) {
|
||||
// the line below uses the Google Analytics tracker
|
||||
// change the tracker here to use other Mobile analytics SDK.
|
||||
tracker.trackScreenView(nextScreen);
|
||||
}
|
||||
return result;
|
||||
};
|
||||
|
||||
export default screenTracking;
|
||||
```
|
||||
|
||||
### Create Redux store and apply the above middleware
|
||||
|
||||
The `screenTracking` middleware can be applied to the store during its creation. See [Redux Integration](Redux-Integration.md) for details.
|
||||
|
||||
```js
|
||||
const store = createStore(
|
||||
combineReducers({
|
||||
navigation: navigationReducer,
|
||||
...
|
||||
}),
|
||||
applyMiddleware(
|
||||
screenTracking,
|
||||
...
|
||||
),
|
||||
);
|
||||
```
|
||||
@@ -1,16 +0,0 @@
|
||||
# Web Integration
|
||||
|
||||
React Navigation routers work on web and allow you to share navigation logic with native apps. The views currently bundled in `react-navigation` currently only work on React Native, but that may change with future-facing projects like [react-primitives](https://github.com/lelandrichardson/react-primitives).
|
||||
|
||||
## Example App
|
||||
|
||||
[This website](https://reactnavigation.org/) is [built with](https://github.com/react-community/react-navigation/blob/master/website/) React Navigation, specifically using `createNavigator` and `TabRouter`.
|
||||
|
||||
See the source code of the site here: [App.js](https://github.com/react-community/react-navigation/blob/master/website/src/App.js).
|
||||
|
||||
To see how the app gets rendered on the server, see [Server.js](https://github.com/react-community/react-navigation/blob/master/website/src/Server.js). On the browser, the App wakes up and gets rendered with [BrowserAppContainer.js](https://github.com/react-community/react-navigation/blob/master/website/src/BrowserAppContainer.js).
|
||||
|
||||
|
||||
## More Coming Soon
|
||||
|
||||
Soon this guide will be replaced with a more thorough walkthrough of react-navigation usage on the web.
|
||||
@@ -1,16 +1,17 @@
|
||||
{
|
||||
"presets": ["babel-preset-expo"],
|
||||
"plugins": [
|
||||
["module-resolver", {
|
||||
"alias": {
|
||||
"react-native": "./node_modules/react-native",
|
||||
"react": "./node_modules/react"
|
||||
}
|
||||
}]
|
||||
"presets": [
|
||||
"babel-preset-expo"
|
||||
],
|
||||
"env": {
|
||||
"development": {
|
||||
"plugins": ["transform-react-jsx-source"]
|
||||
"plugins": [
|
||||
"transform-react-jsx-source"
|
||||
],
|
||||
},
|
||||
"production": {
|
||||
"plugins": [
|
||||
"transform-remove-console"
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -34,28 +34,27 @@
|
||||
; Ignore react-native-fbads dependency of the expo sdk
|
||||
.*/node_modules/react-native-fbads/*
|
||||
|
||||
.*/react-navigation/lib-rn/.*
|
||||
.*/react-navigation/lib/.*
|
||||
|
||||
.*/react-navigation/examples/ReduxExample/.*
|
||||
.*/react-navigation/website/.*
|
||||
|
||||
; This package is required by Expo and causes Flow errors
|
||||
.*/node_modules/react-native-gesture-handler/.*
|
||||
|
||||
.*/node_modules/metro/.*
|
||||
|
||||
[include]
|
||||
|
||||
[libs]
|
||||
node_modules/react-native/Libraries/react-native/react-native-interface.js
|
||||
node_modules/react-native/flow/
|
||||
node_modules/react-native/flow-github/
|
||||
../../flow/
|
||||
|
||||
[options]
|
||||
module.system=haste
|
||||
|
||||
emoji=true
|
||||
|
||||
experimental.strict_type_args=true
|
||||
|
||||
munge_underscores=true
|
||||
|
||||
module.name_mapper='^[./a-zA-Z0-9$_-]+\.\(bmp\|gif\|jpg\|jpeg\|png\|psd\|svg\|webp\|m4v\|mov\|mp4\|mpeg\|mpg\|webm\|aac\|aiff\|caf\|m4a\|mp3\|wav\|html\|pdf\)$' -> 'RelativeImageStub'
|
||||
@@ -64,18 +63,17 @@ module.file_ext=.jsx
|
||||
module.file_ext=.json
|
||||
module.file_ext=.native.js
|
||||
|
||||
suppress_type=$FlowIgnore
|
||||
suppress_type=$FlowIssue
|
||||
suppress_type=$FlowFixMe
|
||||
suppress_type=$FlowFixMeProps
|
||||
suppress_type=$FlowFixMeState
|
||||
suppress_type=$FixMe
|
||||
|
||||
suppress_comment=\\(.\\|\n\\)*\\$FlowFixMe\\($\\|[^(]\\|(\\(>=0\\.\\(5[0-3]\\|[1-4][0-9]\\|[0-9]\\).[0-9]\\)? *\\(site=[a-z,_]*react_native[a-z,_]*\\)?)\\)
|
||||
suppress_comment=\\(.\\|\n\\)*\\$FlowIssue\\((\\(>=0\\.\\(5[0-3]\\|[1-4][0-9]\\|[0-9]\\).[0-9]\\)? *\\(site=[a-z,_]*react_native[a-z,_]*\\)?)\\)?:? #[0-9]+
|
||||
suppress_comment=\\(.\\|\n\\)*\\$FlowIgnore\\($\\|[^(]\\|(\\(<VERSION>\\)? *\\(site=[a-z,_]*react_native[a-z,_]*\\)?)\\)
|
||||
suppress_comment=\\(.\\|\n\\)*\\$FlowFixMe\\($\\|[^(]\\|(\\(<VERSION>\\)? *\\(site=[a-z,_]*react_native[a-z,_]*\\)?)\\)
|
||||
suppress_comment=\\(.\\|\n\\)*\\$FlowIssue\\((\\(<VERSION>\\)? *\\(site=[a-z,_]*react_native[a-z,_]*\\)?)\\)?:? #[0-9]+
|
||||
suppress_comment=\\(.\\|\n\\)*\\$FlowFixedInNextDeploy
|
||||
suppress_comment=\\(.\\|\n\\)*\\$FlowExpectedError
|
||||
|
||||
unsafe.enable_getters_and_setters=true
|
||||
|
||||
[version]
|
||||
0.53.0
|
||||
^0.67.0
|
||||
|
||||
@@ -5,5 +5,6 @@ import renderer from 'react-test-renderer';
|
||||
|
||||
it('renders without crashing', () => {
|
||||
const rendered = renderer.create(<App />).toJSON();
|
||||
expect(rendered).toBeTruthy();
|
||||
// Will be null because the playground uses state persistence which happens asyncronously
|
||||
expect(rendered).toEqual(null);
|
||||
});
|
||||
|
||||
@@ -4,6 +4,6 @@ A playground for experimenting with react-navigation in a pure-JS React Native a
|
||||
|
||||
## Usage
|
||||
|
||||
Please see the [Contributors Guide](https://github.com/react-community/react-navigation/blob/master/docs/guides/Contributors.md#development) for instructions on running these example apps.
|
||||
Please see the [Contributors Guide](https://reactnavigation.org/docs/contributing.html#run-the-example-app) for instructions on running these example apps.
|
||||
|
||||
You can view this example application directly on your phone by visiting [our expo demo](https://exp.host/@react-navigation/NavigationPlayground).
|
||||
|
||||
@@ -7,21 +7,21 @@
|
||||
"privacy": "public",
|
||||
"orientation": "portrait",
|
||||
"primaryColor": "#cccccc",
|
||||
"icon": "./assets/icons/react-navigation.png",
|
||||
"loading": {
|
||||
"icon": "./assets/icons/react-navigation.png",
|
||||
"hideExponentText": false
|
||||
"icon": "./assets/icons/icon.png",
|
||||
"splash": {
|
||||
"image": "./assets/icons/splash.png"
|
||||
},
|
||||
"sdkVersion": "22.0.0",
|
||||
"sdkVersion": "27.0.0",
|
||||
"entryPoint": "./node_modules/react-native-scripts/build/bin/crna-entry.js",
|
||||
"packagerOpts": {
|
||||
"assetExts": [
|
||||
"ttf",
|
||||
"mp4"
|
||||
]
|
||||
},
|
||||
"assetBundlePatterns": [
|
||||
"**/*"
|
||||
],
|
||||
"ios": {
|
||||
"bundleIdentifier": "com.reactnavigation.example",
|
||||
"supportsTablet": true
|
||||
},
|
||||
"android": {
|
||||
"package": "com.reactnavigation.example"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
BIN
examples/NavigationPlayground/assets/icons/icon.png
Normal file
|
After Width: | Height: | Size: 36 KiB |
|
Before Width: | Height: | Size: 13 KiB |
BIN
examples/NavigationPlayground/assets/icons/splash.png
Normal file
|
After Width: | Height: | Size: 145 KiB |
@@ -1,5 +1,5 @@
|
||||
// flow-typed signature: 5964a245d3129ecd50da1f74a2f86454
|
||||
// flow-typed version: <<STUB>>/babel-jest_v^21.0.0/flow_v0.53.0
|
||||
// flow-typed signature: ee7b4028012cfdcd83cc6541a39b2282
|
||||
// flow-typed version: <<STUB>>/babel-jest_v^21.0.0/flow_v0.61.0
|
||||
|
||||
/**
|
||||
* This is an autogenerated libdef stub for:
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
// flow-typed signature: 4fb1f6897647ab1ad25d819aa06d2d6c
|
||||
// flow-typed version: <<STUB>>/expo_v^22.0.0/flow_v0.53.0
|
||||
// flow-typed signature: c1ecfe71fbb86c3602b7da3d7c141df1
|
||||
// flow-typed version: <<STUB>>/expo_v^24.0.2/flow_v0.61.0
|
||||
|
||||
/**
|
||||
* This is an autogenerated libdef stub for:
|
||||
@@ -26,6 +26,18 @@ declare module 'expo/AppEntry' {
|
||||
declare module.exports: any;
|
||||
}
|
||||
|
||||
declare module 'expo/flow/metro-bundler' {
|
||||
declare module.exports: any;
|
||||
}
|
||||
|
||||
declare module 'expo/flow/react-native-gesture-handler' {
|
||||
declare module.exports: any;
|
||||
}
|
||||
|
||||
declare module 'expo/src/__mocks__/Constants-development' {
|
||||
declare module.exports: any;
|
||||
}
|
||||
|
||||
declare module 'expo/src/__tests__/Amplitude-test' {
|
||||
declare module.exports: any;
|
||||
}
|
||||
@@ -50,6 +62,10 @@ declare module 'expo/src/__tests__/Facebook-test' {
|
||||
declare module.exports: any;
|
||||
}
|
||||
|
||||
declare module 'expo/src/__tests__/Font-test' {
|
||||
declare module.exports: any;
|
||||
}
|
||||
|
||||
declare module 'expo/src/__tests__/Location-test' {
|
||||
declare module.exports: any;
|
||||
}
|
||||
@@ -70,6 +86,22 @@ declare module 'expo/src/__tests__/WebBrowser-test' {
|
||||
declare module.exports: any;
|
||||
}
|
||||
|
||||
declare module 'expo/src/admob/RNAdMobBanner' {
|
||||
declare module.exports: any;
|
||||
}
|
||||
|
||||
declare module 'expo/src/admob/RNAdMobInterstitial' {
|
||||
declare module.exports: any;
|
||||
}
|
||||
|
||||
declare module 'expo/src/admob/RNAdMobRewarded' {
|
||||
declare module.exports: any;
|
||||
}
|
||||
|
||||
declare module 'expo/src/admob/RNPublisherBanner' {
|
||||
declare module.exports: any;
|
||||
}
|
||||
|
||||
declare module 'expo/src/Amplitude' {
|
||||
declare module.exports: any;
|
||||
}
|
||||
@@ -78,43 +110,39 @@ declare module 'expo/src/apisAreAvailable' {
|
||||
declare module.exports: any;
|
||||
}
|
||||
|
||||
declare module 'expo/src/AppLoading' {
|
||||
declare module.exports: any;
|
||||
}
|
||||
|
||||
declare module 'expo/src/AppLoadingNativeWrapper.android' {
|
||||
declare module.exports: any;
|
||||
}
|
||||
|
||||
declare module 'expo/src/AppLoadingNativeWrapper.ios' {
|
||||
declare module.exports: any;
|
||||
}
|
||||
|
||||
declare module 'expo/src/Asset' {
|
||||
declare module.exports: any;
|
||||
}
|
||||
|
||||
declare module 'expo/src/Audio' {
|
||||
declare module.exports: any;
|
||||
}
|
||||
|
||||
declare module 'expo/src/AuthSession' {
|
||||
declare module.exports: any;
|
||||
}
|
||||
|
||||
declare module 'expo/src/AV' {
|
||||
declare module 'expo/src/av/Audio' {
|
||||
declare module.exports: any;
|
||||
}
|
||||
|
||||
declare module 'expo/src/BarCodeScanner' {
|
||||
declare module 'expo/src/av/Audio/Recording' {
|
||||
declare module.exports: any;
|
||||
}
|
||||
|
||||
declare module 'expo/src/BlurView.android' {
|
||||
declare module 'expo/src/av/Audio/Sound' {
|
||||
declare module.exports: any;
|
||||
}
|
||||
|
||||
declare module 'expo/src/BlurView.ios' {
|
||||
declare module 'expo/src/av/AV' {
|
||||
declare module.exports: any;
|
||||
}
|
||||
|
||||
declare module 'expo/src/av/Video' {
|
||||
declare module.exports: any;
|
||||
}
|
||||
|
||||
declare module 'expo/src/BarCodeScanner.android' {
|
||||
declare module.exports: any;
|
||||
}
|
||||
|
||||
declare module 'expo/src/BarCodeScanner.ios' {
|
||||
declare module.exports: any;
|
||||
}
|
||||
|
||||
@@ -126,6 +154,10 @@ declare module 'expo/src/Camera' {
|
||||
declare module.exports: any;
|
||||
}
|
||||
|
||||
declare module 'expo/src/CameraBasedBarCodeScanner' {
|
||||
declare module.exports: any;
|
||||
}
|
||||
|
||||
declare module 'expo/src/Constants' {
|
||||
declare module.exports: any;
|
||||
}
|
||||
@@ -142,6 +174,34 @@ declare module 'expo/src/DocumentPicker' {
|
||||
declare module.exports: any;
|
||||
}
|
||||
|
||||
declare module 'expo/src/effects/BlurView.android' {
|
||||
declare module.exports: any;
|
||||
}
|
||||
|
||||
declare module 'expo/src/effects/BlurView.ios' {
|
||||
declare module.exports: any;
|
||||
}
|
||||
|
||||
declare module 'expo/src/effects/LinearGradient.android' {
|
||||
declare module.exports: any;
|
||||
}
|
||||
|
||||
declare module 'expo/src/effects/LinearGradient.ios' {
|
||||
declare module.exports: any;
|
||||
}
|
||||
|
||||
declare module 'expo/src/environment/__tests__/validate-test' {
|
||||
declare module.exports: any;
|
||||
}
|
||||
|
||||
declare module 'expo/src/environment/logging' {
|
||||
declare module.exports: any;
|
||||
}
|
||||
|
||||
declare module 'expo/src/environment/validate' {
|
||||
declare module.exports: any;
|
||||
}
|
||||
|
||||
declare module 'expo/src/ErrorRecovery' {
|
||||
declare module.exports: any;
|
||||
}
|
||||
@@ -150,31 +210,35 @@ declare module 'expo/src/Expo' {
|
||||
declare module.exports: any;
|
||||
}
|
||||
|
||||
declare module 'expo/src/facebook-ads/AdSettings' {
|
||||
declare module.exports: any;
|
||||
}
|
||||
|
||||
declare module 'expo/src/facebook-ads/BannerViewManager' {
|
||||
declare module.exports: any;
|
||||
}
|
||||
|
||||
declare module 'expo/src/facebook-ads/index' {
|
||||
declare module.exports: any;
|
||||
}
|
||||
|
||||
declare module 'expo/src/facebook-ads/InterstitialAdManager' {
|
||||
declare module.exports: any;
|
||||
}
|
||||
|
||||
declare module 'expo/src/facebook-ads/NativeAdsManager' {
|
||||
declare module.exports: any;
|
||||
}
|
||||
|
||||
declare module 'expo/src/facebook-ads/withNativeAd' {
|
||||
declare module.exports: any;
|
||||
}
|
||||
|
||||
declare module 'expo/src/Facebook' {
|
||||
declare module.exports: any;
|
||||
}
|
||||
|
||||
declare module 'expo/src/FacebookAds/AdSettings' {
|
||||
declare module.exports: any;
|
||||
}
|
||||
|
||||
declare module 'expo/src/FacebookAds/BannerViewManager' {
|
||||
declare module.exports: any;
|
||||
}
|
||||
|
||||
declare module 'expo/src/FacebookAds/index' {
|
||||
declare module.exports: any;
|
||||
}
|
||||
|
||||
declare module 'expo/src/FacebookAds/InterstitialAdManager' {
|
||||
declare module.exports: any;
|
||||
}
|
||||
|
||||
declare module 'expo/src/FacebookAds/NativeAdsManager' {
|
||||
declare module.exports: any;
|
||||
}
|
||||
|
||||
declare module 'expo/src/FacebookAds/withNativeAd' {
|
||||
declare module 'expo/src/FaceDetector' {
|
||||
declare module.exports: any;
|
||||
}
|
||||
|
||||
@@ -202,6 +266,10 @@ declare module 'expo/src/Icon' {
|
||||
declare module.exports: any;
|
||||
}
|
||||
|
||||
declare module 'expo/src/ImageManipulator' {
|
||||
declare module.exports: any;
|
||||
}
|
||||
|
||||
declare module 'expo/src/ImagePicker' {
|
||||
declare module.exports: any;
|
||||
}
|
||||
@@ -214,11 +282,23 @@ declare module 'expo/src/KeepAwake' {
|
||||
declare module.exports: any;
|
||||
}
|
||||
|
||||
declare module 'expo/src/LegacyAsyncStorage.android' {
|
||||
declare module 'expo/src/launch/AppLoading' {
|
||||
declare module.exports: any;
|
||||
}
|
||||
|
||||
declare module 'expo/src/LegacyAsyncStorage.ios' {
|
||||
declare module 'expo/src/launch/AppLoadingNativeWrapper.android' {
|
||||
declare module.exports: any;
|
||||
}
|
||||
|
||||
declare module 'expo/src/launch/AppLoadingNativeWrapper.ios' {
|
||||
declare module.exports: any;
|
||||
}
|
||||
|
||||
declare module 'expo/src/launch/registerRootComponent' {
|
||||
declare module.exports: any;
|
||||
}
|
||||
|
||||
declare module 'expo/src/launch/RootErrorBoundary' {
|
||||
declare module.exports: any;
|
||||
}
|
||||
|
||||
@@ -226,35 +306,59 @@ declare module 'expo/src/lib/Queue' {
|
||||
declare module.exports: any;
|
||||
}
|
||||
|
||||
declare module 'expo/src/LinearGradient.android' {
|
||||
declare module.exports: any;
|
||||
}
|
||||
|
||||
declare module 'expo/src/LinearGradient.ios' {
|
||||
declare module.exports: any;
|
||||
}
|
||||
|
||||
declare module 'expo/src/Location' {
|
||||
declare module.exports: any;
|
||||
}
|
||||
|
||||
declare module 'expo/src/Logs' {
|
||||
declare module 'expo/src/logs/__tests__/Logs-test' {
|
||||
declare module.exports: any;
|
||||
}
|
||||
|
||||
declare module 'expo/src/Modal/Modal' {
|
||||
declare module 'expo/src/logs/__tests__/LogSerialization-test' {
|
||||
declare module.exports: any;
|
||||
}
|
||||
|
||||
declare module 'expo/src/Modal/ModalHost' {
|
||||
declare module 'expo/src/logs/__tests__/RemoteConsole-test' {
|
||||
declare module.exports: any;
|
||||
}
|
||||
|
||||
declare module 'expo/src/Modal/ModalImplementation' {
|
||||
declare module 'expo/src/logs/__tests__/RemoteLogging-test' {
|
||||
declare module.exports: any;
|
||||
}
|
||||
|
||||
declare module 'expo/src/Modal/PureContainer' {
|
||||
declare module 'expo/src/logs/__tests__/RemoteLogs-test' {
|
||||
declare module.exports: any;
|
||||
}
|
||||
|
||||
declare module 'expo/src/logs/Logs' {
|
||||
declare module.exports: any;
|
||||
}
|
||||
|
||||
declare module 'expo/src/logs/LogSerialization' {
|
||||
declare module.exports: any;
|
||||
}
|
||||
|
||||
declare module 'expo/src/logs/RemoteConsole' {
|
||||
declare module.exports: any;
|
||||
}
|
||||
|
||||
declare module 'expo/src/logs/RemoteLogging' {
|
||||
declare module.exports: any;
|
||||
}
|
||||
|
||||
declare module 'expo/src/modal/Modal' {
|
||||
declare module.exports: any;
|
||||
}
|
||||
|
||||
declare module 'expo/src/modal/ModalHost' {
|
||||
declare module.exports: any;
|
||||
}
|
||||
|
||||
declare module 'expo/src/modal/ModalImplementation' {
|
||||
declare module.exports: any;
|
||||
}
|
||||
|
||||
declare module 'expo/src/modal/PureContainer' {
|
||||
declare module.exports: any;
|
||||
}
|
||||
|
||||
@@ -262,6 +366,10 @@ declare module 'expo/src/Notifications' {
|
||||
declare module.exports: any;
|
||||
}
|
||||
|
||||
declare module 'expo/src/OldBarCodeScanner' {
|
||||
declare module.exports: any;
|
||||
}
|
||||
|
||||
declare module 'expo/src/Payments' {
|
||||
declare module.exports: any;
|
||||
}
|
||||
@@ -274,30 +382,6 @@ declare module 'expo/src/Permissions' {
|
||||
declare module.exports: any;
|
||||
}
|
||||
|
||||
declare module 'expo/src/registerRootComponent' {
|
||||
declare module.exports: any;
|
||||
}
|
||||
|
||||
declare module 'expo/src/RNAdMobBanner' {
|
||||
declare module.exports: any;
|
||||
}
|
||||
|
||||
declare module 'expo/src/RNAdMobInterstitial' {
|
||||
declare module.exports: any;
|
||||
}
|
||||
|
||||
declare module 'expo/src/RNAdMobRewarded' {
|
||||
declare module.exports: any;
|
||||
}
|
||||
|
||||
declare module 'expo/src/RNPublisherBanner' {
|
||||
declare module.exports: any;
|
||||
}
|
||||
|
||||
declare module 'expo/src/RootErrorBoundary' {
|
||||
declare module.exports: any;
|
||||
}
|
||||
|
||||
declare module 'expo/src/ScreenOrientation' {
|
||||
declare module.exports: any;
|
||||
}
|
||||
@@ -374,11 +458,11 @@ declare module 'expo/src/takeSnapshotAsync' {
|
||||
declare module.exports: any;
|
||||
}
|
||||
|
||||
declare module 'expo/src/Util' {
|
||||
declare module 'expo/src/timer/polyfillNextTick' {
|
||||
declare module.exports: any;
|
||||
}
|
||||
|
||||
declare module 'expo/src/Video' {
|
||||
declare module 'expo/src/Util' {
|
||||
declare module.exports: any;
|
||||
}
|
||||
|
||||
@@ -398,6 +482,15 @@ declare module 'expo/tools/LogReporter' {
|
||||
declare module 'expo/AppEntry.js' {
|
||||
declare module.exports: $Exports<'expo/AppEntry'>;
|
||||
}
|
||||
declare module 'expo/flow/metro-bundler.js' {
|
||||
declare module.exports: $Exports<'expo/flow/metro-bundler'>;
|
||||
}
|
||||
declare module 'expo/flow/react-native-gesture-handler.js' {
|
||||
declare module.exports: $Exports<'expo/flow/react-native-gesture-handler'>;
|
||||
}
|
||||
declare module 'expo/src/__mocks__/Constants-development.js' {
|
||||
declare module.exports: $Exports<'expo/src/__mocks__/Constants-development'>;
|
||||
}
|
||||
declare module 'expo/src/__tests__/Amplitude-test.js' {
|
||||
declare module.exports: $Exports<'expo/src/__tests__/Amplitude-test'>;
|
||||
}
|
||||
@@ -416,6 +509,9 @@ declare module 'expo/src/__tests__/Expo-test.js' {
|
||||
declare module 'expo/src/__tests__/Facebook-test.js' {
|
||||
declare module.exports: $Exports<'expo/src/__tests__/Facebook-test'>;
|
||||
}
|
||||
declare module 'expo/src/__tests__/Font-test.js' {
|
||||
declare module.exports: $Exports<'expo/src/__tests__/Font-test'>;
|
||||
}
|
||||
declare module 'expo/src/__tests__/Location-test.js' {
|
||||
declare module.exports: $Exports<'expo/src/__tests__/Location-test'>;
|
||||
}
|
||||
@@ -431,41 +527,50 @@ declare module 'expo/src/__tests__/Segment-test.js' {
|
||||
declare module 'expo/src/__tests__/WebBrowser-test.js' {
|
||||
declare module.exports: $Exports<'expo/src/__tests__/WebBrowser-test'>;
|
||||
}
|
||||
declare module 'expo/src/admob/RNAdMobBanner.js' {
|
||||
declare module.exports: $Exports<'expo/src/admob/RNAdMobBanner'>;
|
||||
}
|
||||
declare module 'expo/src/admob/RNAdMobInterstitial.js' {
|
||||
declare module.exports: $Exports<'expo/src/admob/RNAdMobInterstitial'>;
|
||||
}
|
||||
declare module 'expo/src/admob/RNAdMobRewarded.js' {
|
||||
declare module.exports: $Exports<'expo/src/admob/RNAdMobRewarded'>;
|
||||
}
|
||||
declare module 'expo/src/admob/RNPublisherBanner.js' {
|
||||
declare module.exports: $Exports<'expo/src/admob/RNPublisherBanner'>;
|
||||
}
|
||||
declare module 'expo/src/Amplitude.js' {
|
||||
declare module.exports: $Exports<'expo/src/Amplitude'>;
|
||||
}
|
||||
declare module 'expo/src/apisAreAvailable.js' {
|
||||
declare module.exports: $Exports<'expo/src/apisAreAvailable'>;
|
||||
}
|
||||
declare module 'expo/src/AppLoading.js' {
|
||||
declare module.exports: $Exports<'expo/src/AppLoading'>;
|
||||
}
|
||||
declare module 'expo/src/AppLoadingNativeWrapper.android.js' {
|
||||
declare module.exports: $Exports<'expo/src/AppLoadingNativeWrapper.android'>;
|
||||
}
|
||||
declare module 'expo/src/AppLoadingNativeWrapper.ios.js' {
|
||||
declare module.exports: $Exports<'expo/src/AppLoadingNativeWrapper.ios'>;
|
||||
}
|
||||
declare module 'expo/src/Asset.js' {
|
||||
declare module.exports: $Exports<'expo/src/Asset'>;
|
||||
}
|
||||
declare module 'expo/src/Audio.js' {
|
||||
declare module.exports: $Exports<'expo/src/Audio'>;
|
||||
}
|
||||
declare module 'expo/src/AuthSession.js' {
|
||||
declare module.exports: $Exports<'expo/src/AuthSession'>;
|
||||
}
|
||||
declare module 'expo/src/AV.js' {
|
||||
declare module.exports: $Exports<'expo/src/AV'>;
|
||||
declare module 'expo/src/av/Audio.js' {
|
||||
declare module.exports: $Exports<'expo/src/av/Audio'>;
|
||||
}
|
||||
declare module 'expo/src/BarCodeScanner.js' {
|
||||
declare module.exports: $Exports<'expo/src/BarCodeScanner'>;
|
||||
declare module 'expo/src/av/Audio/Recording.js' {
|
||||
declare module.exports: $Exports<'expo/src/av/Audio/Recording'>;
|
||||
}
|
||||
declare module 'expo/src/BlurView.android.js' {
|
||||
declare module.exports: $Exports<'expo/src/BlurView.android'>;
|
||||
declare module 'expo/src/av/Audio/Sound.js' {
|
||||
declare module.exports: $Exports<'expo/src/av/Audio/Sound'>;
|
||||
}
|
||||
declare module 'expo/src/BlurView.ios.js' {
|
||||
declare module.exports: $Exports<'expo/src/BlurView.ios'>;
|
||||
declare module 'expo/src/av/AV.js' {
|
||||
declare module.exports: $Exports<'expo/src/av/AV'>;
|
||||
}
|
||||
declare module 'expo/src/av/Video.js' {
|
||||
declare module.exports: $Exports<'expo/src/av/Video'>;
|
||||
}
|
||||
declare module 'expo/src/BarCodeScanner.android.js' {
|
||||
declare module.exports: $Exports<'expo/src/BarCodeScanner.android'>;
|
||||
}
|
||||
declare module 'expo/src/BarCodeScanner.ios.js' {
|
||||
declare module.exports: $Exports<'expo/src/BarCodeScanner.ios'>;
|
||||
}
|
||||
declare module 'expo/src/Brightness.js' {
|
||||
declare module.exports: $Exports<'expo/src/Brightness'>;
|
||||
@@ -473,6 +578,9 @@ declare module 'expo/src/Brightness.js' {
|
||||
declare module 'expo/src/Camera.js' {
|
||||
declare module.exports: $Exports<'expo/src/Camera'>;
|
||||
}
|
||||
declare module 'expo/src/CameraBasedBarCodeScanner.js' {
|
||||
declare module.exports: $Exports<'expo/src/CameraBasedBarCodeScanner'>;
|
||||
}
|
||||
declare module 'expo/src/Constants.js' {
|
||||
declare module.exports: $Exports<'expo/src/Constants'>;
|
||||
}
|
||||
@@ -485,32 +593,56 @@ declare module 'expo/src/DangerZone.js' {
|
||||
declare module 'expo/src/DocumentPicker.js' {
|
||||
declare module.exports: $Exports<'expo/src/DocumentPicker'>;
|
||||
}
|
||||
declare module 'expo/src/effects/BlurView.android.js' {
|
||||
declare module.exports: $Exports<'expo/src/effects/BlurView.android'>;
|
||||
}
|
||||
declare module 'expo/src/effects/BlurView.ios.js' {
|
||||
declare module.exports: $Exports<'expo/src/effects/BlurView.ios'>;
|
||||
}
|
||||
declare module 'expo/src/effects/LinearGradient.android.js' {
|
||||
declare module.exports: $Exports<'expo/src/effects/LinearGradient.android'>;
|
||||
}
|
||||
declare module 'expo/src/effects/LinearGradient.ios.js' {
|
||||
declare module.exports: $Exports<'expo/src/effects/LinearGradient.ios'>;
|
||||
}
|
||||
declare module 'expo/src/environment/__tests__/validate-test.js' {
|
||||
declare module.exports: $Exports<'expo/src/environment/__tests__/validate-test'>;
|
||||
}
|
||||
declare module 'expo/src/environment/logging.js' {
|
||||
declare module.exports: $Exports<'expo/src/environment/logging'>;
|
||||
}
|
||||
declare module 'expo/src/environment/validate.js' {
|
||||
declare module.exports: $Exports<'expo/src/environment/validate'>;
|
||||
}
|
||||
declare module 'expo/src/ErrorRecovery.js' {
|
||||
declare module.exports: $Exports<'expo/src/ErrorRecovery'>;
|
||||
}
|
||||
declare module 'expo/src/Expo.js' {
|
||||
declare module.exports: $Exports<'expo/src/Expo'>;
|
||||
}
|
||||
declare module 'expo/src/facebook-ads/AdSettings.js' {
|
||||
declare module.exports: $Exports<'expo/src/facebook-ads/AdSettings'>;
|
||||
}
|
||||
declare module 'expo/src/facebook-ads/BannerViewManager.js' {
|
||||
declare module.exports: $Exports<'expo/src/facebook-ads/BannerViewManager'>;
|
||||
}
|
||||
declare module 'expo/src/facebook-ads/index.js' {
|
||||
declare module.exports: $Exports<'expo/src/facebook-ads/index'>;
|
||||
}
|
||||
declare module 'expo/src/facebook-ads/InterstitialAdManager.js' {
|
||||
declare module.exports: $Exports<'expo/src/facebook-ads/InterstitialAdManager'>;
|
||||
}
|
||||
declare module 'expo/src/facebook-ads/NativeAdsManager.js' {
|
||||
declare module.exports: $Exports<'expo/src/facebook-ads/NativeAdsManager'>;
|
||||
}
|
||||
declare module 'expo/src/facebook-ads/withNativeAd.js' {
|
||||
declare module.exports: $Exports<'expo/src/facebook-ads/withNativeAd'>;
|
||||
}
|
||||
declare module 'expo/src/Facebook.js' {
|
||||
declare module.exports: $Exports<'expo/src/Facebook'>;
|
||||
}
|
||||
declare module 'expo/src/FacebookAds/AdSettings.js' {
|
||||
declare module.exports: $Exports<'expo/src/FacebookAds/AdSettings'>;
|
||||
}
|
||||
declare module 'expo/src/FacebookAds/BannerViewManager.js' {
|
||||
declare module.exports: $Exports<'expo/src/FacebookAds/BannerViewManager'>;
|
||||
}
|
||||
declare module 'expo/src/FacebookAds/index.js' {
|
||||
declare module.exports: $Exports<'expo/src/FacebookAds/index'>;
|
||||
}
|
||||
declare module 'expo/src/FacebookAds/InterstitialAdManager.js' {
|
||||
declare module.exports: $Exports<'expo/src/FacebookAds/InterstitialAdManager'>;
|
||||
}
|
||||
declare module 'expo/src/FacebookAds/NativeAdsManager.js' {
|
||||
declare module.exports: $Exports<'expo/src/FacebookAds/NativeAdsManager'>;
|
||||
}
|
||||
declare module 'expo/src/FacebookAds/withNativeAd.js' {
|
||||
declare module.exports: $Exports<'expo/src/FacebookAds/withNativeAd'>;
|
||||
declare module 'expo/src/FaceDetector.js' {
|
||||
declare module.exports: $Exports<'expo/src/FaceDetector'>;
|
||||
}
|
||||
declare module 'expo/src/FileSystem.js' {
|
||||
declare module.exports: $Exports<'expo/src/FileSystem'>;
|
||||
@@ -530,6 +662,9 @@ declare module 'expo/src/Google.js' {
|
||||
declare module 'expo/src/Icon.js' {
|
||||
declare module.exports: $Exports<'expo/src/Icon'>;
|
||||
}
|
||||
declare module 'expo/src/ImageManipulator.js' {
|
||||
declare module.exports: $Exports<'expo/src/ImageManipulator'>;
|
||||
}
|
||||
declare module 'expo/src/ImagePicker.js' {
|
||||
declare module.exports: $Exports<'expo/src/ImagePicker'>;
|
||||
}
|
||||
@@ -539,42 +674,72 @@ declare module 'expo/src/IntentLauncherAndroid.js' {
|
||||
declare module 'expo/src/KeepAwake.js' {
|
||||
declare module.exports: $Exports<'expo/src/KeepAwake'>;
|
||||
}
|
||||
declare module 'expo/src/LegacyAsyncStorage.android.js' {
|
||||
declare module.exports: $Exports<'expo/src/LegacyAsyncStorage.android'>;
|
||||
declare module 'expo/src/launch/AppLoading.js' {
|
||||
declare module.exports: $Exports<'expo/src/launch/AppLoading'>;
|
||||
}
|
||||
declare module 'expo/src/LegacyAsyncStorage.ios.js' {
|
||||
declare module.exports: $Exports<'expo/src/LegacyAsyncStorage.ios'>;
|
||||
declare module 'expo/src/launch/AppLoadingNativeWrapper.android.js' {
|
||||
declare module.exports: $Exports<'expo/src/launch/AppLoadingNativeWrapper.android'>;
|
||||
}
|
||||
declare module 'expo/src/launch/AppLoadingNativeWrapper.ios.js' {
|
||||
declare module.exports: $Exports<'expo/src/launch/AppLoadingNativeWrapper.ios'>;
|
||||
}
|
||||
declare module 'expo/src/launch/registerRootComponent.js' {
|
||||
declare module.exports: $Exports<'expo/src/launch/registerRootComponent'>;
|
||||
}
|
||||
declare module 'expo/src/launch/RootErrorBoundary.js' {
|
||||
declare module.exports: $Exports<'expo/src/launch/RootErrorBoundary'>;
|
||||
}
|
||||
declare module 'expo/src/lib/Queue.js' {
|
||||
declare module.exports: $Exports<'expo/src/lib/Queue'>;
|
||||
}
|
||||
declare module 'expo/src/LinearGradient.android.js' {
|
||||
declare module.exports: $Exports<'expo/src/LinearGradient.android'>;
|
||||
}
|
||||
declare module 'expo/src/LinearGradient.ios.js' {
|
||||
declare module.exports: $Exports<'expo/src/LinearGradient.ios'>;
|
||||
}
|
||||
declare module 'expo/src/Location.js' {
|
||||
declare module.exports: $Exports<'expo/src/Location'>;
|
||||
}
|
||||
declare module 'expo/src/Logs.js' {
|
||||
declare module.exports: $Exports<'expo/src/Logs'>;
|
||||
declare module 'expo/src/logs/__tests__/Logs-test.js' {
|
||||
declare module.exports: $Exports<'expo/src/logs/__tests__/Logs-test'>;
|
||||
}
|
||||
declare module 'expo/src/Modal/Modal.js' {
|
||||
declare module.exports: $Exports<'expo/src/Modal/Modal'>;
|
||||
declare module 'expo/src/logs/__tests__/LogSerialization-test.js' {
|
||||
declare module.exports: $Exports<'expo/src/logs/__tests__/LogSerialization-test'>;
|
||||
}
|
||||
declare module 'expo/src/Modal/ModalHost.js' {
|
||||
declare module.exports: $Exports<'expo/src/Modal/ModalHost'>;
|
||||
declare module 'expo/src/logs/__tests__/RemoteConsole-test.js' {
|
||||
declare module.exports: $Exports<'expo/src/logs/__tests__/RemoteConsole-test'>;
|
||||
}
|
||||
declare module 'expo/src/Modal/ModalImplementation.js' {
|
||||
declare module.exports: $Exports<'expo/src/Modal/ModalImplementation'>;
|
||||
declare module 'expo/src/logs/__tests__/RemoteLogging-test.js' {
|
||||
declare module.exports: $Exports<'expo/src/logs/__tests__/RemoteLogging-test'>;
|
||||
}
|
||||
declare module 'expo/src/Modal/PureContainer.js' {
|
||||
declare module.exports: $Exports<'expo/src/Modal/PureContainer'>;
|
||||
declare module 'expo/src/logs/__tests__/RemoteLogs-test.js' {
|
||||
declare module.exports: $Exports<'expo/src/logs/__tests__/RemoteLogs-test'>;
|
||||
}
|
||||
declare module 'expo/src/logs/Logs.js' {
|
||||
declare module.exports: $Exports<'expo/src/logs/Logs'>;
|
||||
}
|
||||
declare module 'expo/src/logs/LogSerialization.js' {
|
||||
declare module.exports: $Exports<'expo/src/logs/LogSerialization'>;
|
||||
}
|
||||
declare module 'expo/src/logs/RemoteConsole.js' {
|
||||
declare module.exports: $Exports<'expo/src/logs/RemoteConsole'>;
|
||||
}
|
||||
declare module 'expo/src/logs/RemoteLogging.js' {
|
||||
declare module.exports: $Exports<'expo/src/logs/RemoteLogging'>;
|
||||
}
|
||||
declare module 'expo/src/modal/Modal.js' {
|
||||
declare module.exports: $Exports<'expo/src/modal/Modal'>;
|
||||
}
|
||||
declare module 'expo/src/modal/ModalHost.js' {
|
||||
declare module.exports: $Exports<'expo/src/modal/ModalHost'>;
|
||||
}
|
||||
declare module 'expo/src/modal/ModalImplementation.js' {
|
||||
declare module.exports: $Exports<'expo/src/modal/ModalImplementation'>;
|
||||
}
|
||||
declare module 'expo/src/modal/PureContainer.js' {
|
||||
declare module.exports: $Exports<'expo/src/modal/PureContainer'>;
|
||||
}
|
||||
declare module 'expo/src/Notifications.js' {
|
||||
declare module.exports: $Exports<'expo/src/Notifications'>;
|
||||
}
|
||||
declare module 'expo/src/OldBarCodeScanner.js' {
|
||||
declare module.exports: $Exports<'expo/src/OldBarCodeScanner'>;
|
||||
}
|
||||
declare module 'expo/src/Payments.js' {
|
||||
declare module.exports: $Exports<'expo/src/Payments'>;
|
||||
}
|
||||
@@ -584,24 +749,6 @@ declare module 'expo/src/Pedometer.js' {
|
||||
declare module 'expo/src/Permissions.js' {
|
||||
declare module.exports: $Exports<'expo/src/Permissions'>;
|
||||
}
|
||||
declare module 'expo/src/registerRootComponent.js' {
|
||||
declare module.exports: $Exports<'expo/src/registerRootComponent'>;
|
||||
}
|
||||
declare module 'expo/src/RNAdMobBanner.js' {
|
||||
declare module.exports: $Exports<'expo/src/RNAdMobBanner'>;
|
||||
}
|
||||
declare module 'expo/src/RNAdMobInterstitial.js' {
|
||||
declare module.exports: $Exports<'expo/src/RNAdMobInterstitial'>;
|
||||
}
|
||||
declare module 'expo/src/RNAdMobRewarded.js' {
|
||||
declare module.exports: $Exports<'expo/src/RNAdMobRewarded'>;
|
||||
}
|
||||
declare module 'expo/src/RNPublisherBanner.js' {
|
||||
declare module.exports: $Exports<'expo/src/RNPublisherBanner'>;
|
||||
}
|
||||
declare module 'expo/src/RootErrorBoundary.js' {
|
||||
declare module.exports: $Exports<'expo/src/RootErrorBoundary'>;
|
||||
}
|
||||
declare module 'expo/src/ScreenOrientation.js' {
|
||||
declare module.exports: $Exports<'expo/src/ScreenOrientation'>;
|
||||
}
|
||||
@@ -659,12 +806,12 @@ declare module 'expo/src/Svg.js' {
|
||||
declare module 'expo/src/takeSnapshotAsync.js' {
|
||||
declare module.exports: $Exports<'expo/src/takeSnapshotAsync'>;
|
||||
}
|
||||
declare module 'expo/src/timer/polyfillNextTick.js' {
|
||||
declare module.exports: $Exports<'expo/src/timer/polyfillNextTick'>;
|
||||
}
|
||||
declare module 'expo/src/Util.js' {
|
||||
declare module.exports: $Exports<'expo/src/Util'>;
|
||||
}
|
||||
declare module 'expo/src/Video.js' {
|
||||
declare module.exports: $Exports<'expo/src/Video'>;
|
||||
}
|
||||
declare module 'expo/src/WebBrowser.js' {
|
||||
declare module.exports: $Exports<'expo/src/WebBrowser'>;
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
// flow-typed signature: 72ab5b9c7dcb88b82de627702a0db27a
|
||||
// flow-typed version: <<STUB>>/jest-expo_v^22.0.0/flow_v0.53.0
|
||||
// flow-typed signature: b1e3826a494aecf4ff482336321b54bd
|
||||
// flow-typed version: <<STUB>>/jest-expo_v^24.0.0/flow_v0.61.0
|
||||
|
||||
/**
|
||||
* This is an autogenerated libdef stub for:
|
||||
|
||||
@@ -1,528 +0,0 @@
|
||||
// flow-typed signature: a0369c11661f437ec4ccdd805579ddcf
|
||||
// flow-typed version: c4b9fea7c9/jest_v20.x.x/flow_>=v0.33.x
|
||||
|
||||
type JestMockFn = {
|
||||
(...args: Array<any>): any,
|
||||
/**
|
||||
* An object for introspecting mock calls
|
||||
*/
|
||||
mock: {
|
||||
/**
|
||||
* An array that represents all calls that have been made into this mock
|
||||
* function. Each call is represented by an array of arguments that were
|
||||
* passed during the call.
|
||||
*/
|
||||
calls: Array<Array<any>>,
|
||||
/**
|
||||
* An array that contains all the object instances that have been
|
||||
* instantiated from this mock function.
|
||||
*/
|
||||
instances: mixed
|
||||
},
|
||||
/**
|
||||
* Resets all information stored in the mockFn.mock.calls and
|
||||
* mockFn.mock.instances arrays. Often this is useful when you want to clean
|
||||
* up a mock's usage data between two assertions.
|
||||
*/
|
||||
mockClear(): Function,
|
||||
/**
|
||||
* Resets all information stored in the mock. This is useful when you want to
|
||||
* completely restore a mock back to its initial state.
|
||||
*/
|
||||
mockReset(): Function,
|
||||
/**
|
||||
* Removes the mock and restores the initial implementation. This is useful
|
||||
* when you want to mock functions in certain test cases and restore the
|
||||
* original implementation in others. Beware that mockFn.mockRestore only
|
||||
* works when mock was created with jest.spyOn. Thus you have to take care of
|
||||
* restoration yourself when manually assigning jest.fn().
|
||||
*/
|
||||
mockRestore(): Function,
|
||||
/**
|
||||
* Accepts a function that should be used as the implementation of the mock.
|
||||
* The mock itself will still record all calls that go into and instances
|
||||
* that come from itself -- the only difference is that the implementation
|
||||
* will also be executed when the mock is called.
|
||||
*/
|
||||
mockImplementation(fn: Function): JestMockFn,
|
||||
/**
|
||||
* Accepts a function that will be used as an implementation of the mock for
|
||||
* one call to the mocked function. Can be chained so that multiple function
|
||||
* calls produce different results.
|
||||
*/
|
||||
mockImplementationOnce(fn: Function): JestMockFn,
|
||||
/**
|
||||
* Just a simple sugar function for returning `this`
|
||||
*/
|
||||
mockReturnThis(): void,
|
||||
/**
|
||||
* Deprecated: use jest.fn(() => value) instead
|
||||
*/
|
||||
mockReturnValue(value: any): JestMockFn,
|
||||
/**
|
||||
* Sugar for only returning a value once inside your mock
|
||||
*/
|
||||
mockReturnValueOnce(value: any): JestMockFn
|
||||
};
|
||||
|
||||
type JestAsymmetricEqualityType = {
|
||||
/**
|
||||
* A custom Jasmine equality tester
|
||||
*/
|
||||
asymmetricMatch(value: mixed): boolean
|
||||
};
|
||||
|
||||
type JestCallsType = {
|
||||
allArgs(): mixed,
|
||||
all(): mixed,
|
||||
any(): boolean,
|
||||
count(): number,
|
||||
first(): mixed,
|
||||
mostRecent(): mixed,
|
||||
reset(): void
|
||||
};
|
||||
|
||||
type JestClockType = {
|
||||
install(): void,
|
||||
mockDate(date: Date): void,
|
||||
tick(milliseconds?: number): void,
|
||||
uninstall(): void
|
||||
};
|
||||
|
||||
type JestMatcherResult = {
|
||||
message?: string | (() => string),
|
||||
pass: boolean
|
||||
};
|
||||
|
||||
type JestMatcher = (actual: any, expected: any) => JestMatcherResult;
|
||||
|
||||
type JestPromiseType = {
|
||||
/**
|
||||
* Use rejects to unwrap the reason of a rejected promise so any other
|
||||
* matcher can be chained. If the promise is fulfilled the assertion fails.
|
||||
*/
|
||||
rejects: JestExpectType,
|
||||
/**
|
||||
* Use resolves to unwrap the value of a fulfilled promise so any other
|
||||
* matcher can be chained. If the promise is rejected the assertion fails.
|
||||
*/
|
||||
resolves: JestExpectType
|
||||
};
|
||||
|
||||
/**
|
||||
* Plugin: jest-enzyme
|
||||
*/
|
||||
type EnzymeMatchersType = {
|
||||
toBeChecked(): void,
|
||||
toBeDisabled(): void,
|
||||
toBeEmpty(): void,
|
||||
toBePresent(): void,
|
||||
toContainReact(element: React$Element<any>): void,
|
||||
toHaveClassName(className: string): void,
|
||||
toHaveHTML(html: string): void,
|
||||
toHaveProp(propKey: string, propValue?: any): void,
|
||||
toHaveRef(refName: string): void,
|
||||
toHaveState(stateKey: string, stateValue?: any): void,
|
||||
toHaveStyle(styleKey: string, styleValue?: any): void,
|
||||
toHaveTagName(tagName: string): void,
|
||||
toHaveText(text: string): void,
|
||||
toIncludeText(text: string): void,
|
||||
toHaveValue(value: any): void,
|
||||
toMatchElement(element: React$Element<any>): void,
|
||||
toMatchSelector(selector: string): void,
|
||||
};
|
||||
|
||||
type JestExpectType = {
|
||||
not: JestExpectType & EnzymeMatchersType,
|
||||
/**
|
||||
* If you have a mock function, you can use .lastCalledWith to test what
|
||||
* arguments it was last called with.
|
||||
*/
|
||||
lastCalledWith(...args: Array<any>): void,
|
||||
/**
|
||||
* toBe just checks that a value is what you expect. It uses === to check
|
||||
* strict equality.
|
||||
*/
|
||||
toBe(value: any): void,
|
||||
/**
|
||||
* Use .toHaveBeenCalled to ensure that a mock function got called.
|
||||
*/
|
||||
toBeCalled(): void,
|
||||
/**
|
||||
* Use .toBeCalledWith to ensure that a mock function was called with
|
||||
* specific arguments.
|
||||
*/
|
||||
toBeCalledWith(...args: Array<any>): void,
|
||||
/**
|
||||
* Using exact equality with floating point numbers is a bad idea. Rounding
|
||||
* means that intuitive things fail.
|
||||
*/
|
||||
toBeCloseTo(num: number, delta: any): void,
|
||||
/**
|
||||
* Use .toBeDefined to check that a variable is not undefined.
|
||||
*/
|
||||
toBeDefined(): void,
|
||||
/**
|
||||
* Use .toBeFalsy when you don't care what a value is, you just want to
|
||||
* ensure a value is false in a boolean context.
|
||||
*/
|
||||
toBeFalsy(): void,
|
||||
/**
|
||||
* To compare floating point numbers, you can use toBeGreaterThan.
|
||||
*/
|
||||
toBeGreaterThan(number: number): void,
|
||||
/**
|
||||
* To compare floating point numbers, you can use toBeGreaterThanOrEqual.
|
||||
*/
|
||||
toBeGreaterThanOrEqual(number: number): void,
|
||||
/**
|
||||
* To compare floating point numbers, you can use toBeLessThan.
|
||||
*/
|
||||
toBeLessThan(number: number): void,
|
||||
/**
|
||||
* To compare floating point numbers, you can use toBeLessThanOrEqual.
|
||||
*/
|
||||
toBeLessThanOrEqual(number: number): void,
|
||||
/**
|
||||
* Use .toBeInstanceOf(Class) to check that an object is an instance of a
|
||||
* class.
|
||||
*/
|
||||
toBeInstanceOf(cls: Class<*>): void,
|
||||
/**
|
||||
* .toBeNull() is the same as .toBe(null) but the error messages are a bit
|
||||
* nicer.
|
||||
*/
|
||||
toBeNull(): void,
|
||||
/**
|
||||
* Use .toBeTruthy when you don't care what a value is, you just want to
|
||||
* ensure a value is true in a boolean context.
|
||||
*/
|
||||
toBeTruthy(): void,
|
||||
/**
|
||||
* Use .toBeUndefined to check that a variable is undefined.
|
||||
*/
|
||||
toBeUndefined(): void,
|
||||
/**
|
||||
* Use .toContain when you want to check that an item is in a list. For
|
||||
* testing the items in the list, this uses ===, a strict equality check.
|
||||
*/
|
||||
toContain(item: any): void,
|
||||
/**
|
||||
* Use .toContainEqual when you want to check that an item is in a list. For
|
||||
* testing the items in the list, this matcher recursively checks the
|
||||
* equality of all fields, rather than checking for object identity.
|
||||
*/
|
||||
toContainEqual(item: any): void,
|
||||
/**
|
||||
* Use .toEqual when you want to check that two objects have the same value.
|
||||
* This matcher recursively checks the equality of all fields, rather than
|
||||
* checking for object identity.
|
||||
*/
|
||||
toEqual(value: any): void,
|
||||
/**
|
||||
* Use .toHaveBeenCalled to ensure that a mock function got called.
|
||||
*/
|
||||
toHaveBeenCalled(): void,
|
||||
/**
|
||||
* Use .toHaveBeenCalledTimes to ensure that a mock function got called exact
|
||||
* number of times.
|
||||
*/
|
||||
toHaveBeenCalledTimes(number: number): void,
|
||||
/**
|
||||
* Use .toHaveBeenCalledWith to ensure that a mock function was called with
|
||||
* specific arguments.
|
||||
*/
|
||||
toHaveBeenCalledWith(...args: Array<any>): void,
|
||||
/**
|
||||
* Use .toHaveBeenLastCalledWith to ensure that a mock function was last called
|
||||
* with specific arguments.
|
||||
*/
|
||||
toHaveBeenLastCalledWith(...args: Array<any>): void,
|
||||
/**
|
||||
* Check that an object has a .length property and it is set to a certain
|
||||
* numeric value.
|
||||
*/
|
||||
toHaveLength(number: number): void,
|
||||
/**
|
||||
*
|
||||
*/
|
||||
toHaveProperty(propPath: string, value?: any): void,
|
||||
/**
|
||||
* Use .toMatch to check that a string matches a regular expression or string.
|
||||
*/
|
||||
toMatch(regexpOrString: RegExp | string): void,
|
||||
/**
|
||||
* Use .toMatchObject to check that a javascript object matches a subset of the properties of an object.
|
||||
*/
|
||||
toMatchObject(object: Object): void,
|
||||
/**
|
||||
* This ensures that a React component matches the most recent snapshot.
|
||||
*/
|
||||
toMatchSnapshot(name?: string): void,
|
||||
/**
|
||||
* Use .toThrow to test that a function throws when it is called.
|
||||
* If you want to test that a specific error gets thrown, you can provide an
|
||||
* argument to toThrow. The argument can be a string for the error message,
|
||||
* a class for the error, or a regex that should match the error.
|
||||
*
|
||||
* Alias: .toThrowError
|
||||
*/
|
||||
toThrow(message?: string | Error | RegExp): void,
|
||||
toThrowError(message?: string | Error | RegExp): void,
|
||||
/**
|
||||
* Use .toThrowErrorMatchingSnapshot to test that a function throws a error
|
||||
* matching the most recent snapshot when it is called.
|
||||
*/
|
||||
toThrowErrorMatchingSnapshot(): void
|
||||
};
|
||||
|
||||
type JestObjectType = {
|
||||
/**
|
||||
* Disables automatic mocking in the module loader.
|
||||
*
|
||||
* After this method is called, all `require()`s will return the real
|
||||
* versions of each module (rather than a mocked version).
|
||||
*/
|
||||
disableAutomock(): JestObjectType,
|
||||
/**
|
||||
* An un-hoisted version of disableAutomock
|
||||
*/
|
||||
autoMockOff(): JestObjectType,
|
||||
/**
|
||||
* Enables automatic mocking in the module loader.
|
||||
*/
|
||||
enableAutomock(): JestObjectType,
|
||||
/**
|
||||
* An un-hoisted version of enableAutomock
|
||||
*/
|
||||
autoMockOn(): JestObjectType,
|
||||
/**
|
||||
* Clears the mock.calls and mock.instances properties of all mocks.
|
||||
* Equivalent to calling .mockClear() on every mocked function.
|
||||
*/
|
||||
clearAllMocks(): JestObjectType,
|
||||
/**
|
||||
* Resets the state of all mocks. Equivalent to calling .mockReset() on every
|
||||
* mocked function.
|
||||
*/
|
||||
resetAllMocks(): JestObjectType,
|
||||
/**
|
||||
* Removes any pending timers from the timer system.
|
||||
*/
|
||||
clearAllTimers(): void,
|
||||
/**
|
||||
* The same as `mock` but not moved to the top of the expectation by
|
||||
* babel-jest.
|
||||
*/
|
||||
doMock(moduleName: string, moduleFactory?: any): JestObjectType,
|
||||
/**
|
||||
* The same as `unmock` but not moved to the top of the expectation by
|
||||
* babel-jest.
|
||||
*/
|
||||
dontMock(moduleName: string): JestObjectType,
|
||||
/**
|
||||
* Returns a new, unused mock function. Optionally takes a mock
|
||||
* implementation.
|
||||
*/
|
||||
fn(implementation?: Function): JestMockFn,
|
||||
/**
|
||||
* Determines if the given function is a mocked function.
|
||||
*/
|
||||
isMockFunction(fn: Function): boolean,
|
||||
/**
|
||||
* Given the name of a module, use the automatic mocking system to generate a
|
||||
* mocked version of the module for you.
|
||||
*/
|
||||
genMockFromModule(moduleName: string): any,
|
||||
/**
|
||||
* Mocks a module with an auto-mocked version when it is being required.
|
||||
*
|
||||
* The second argument can be used to specify an explicit module factory that
|
||||
* is being run instead of using Jest's automocking feature.
|
||||
*
|
||||
* The third argument can be used to create virtual mocks -- mocks of modules
|
||||
* that don't exist anywhere in the system.
|
||||
*/
|
||||
mock(
|
||||
moduleName: string,
|
||||
moduleFactory?: any,
|
||||
options?: Object
|
||||
): JestObjectType,
|
||||
/**
|
||||
* Resets the module registry - the cache of all required modules. This is
|
||||
* useful to isolate modules where local state might conflict between tests.
|
||||
*/
|
||||
resetModules(): JestObjectType,
|
||||
/**
|
||||
* Exhausts the micro-task queue (usually interfaced in node via
|
||||
* process.nextTick).
|
||||
*/
|
||||
runAllTicks(): void,
|
||||
/**
|
||||
* Exhausts the macro-task queue (i.e., all tasks queued by setTimeout(),
|
||||
* setInterval(), and setImmediate()).
|
||||
*/
|
||||
runAllTimers(): void,
|
||||
/**
|
||||
* Exhausts all tasks queued by setImmediate().
|
||||
*/
|
||||
runAllImmediates(): void,
|
||||
/**
|
||||
* Executes only the macro task queue (i.e. all tasks queued by setTimeout()
|
||||
* or setInterval() and setImmediate()).
|
||||
*/
|
||||
runTimersToTime(msToRun: number): void,
|
||||
/**
|
||||
* Executes only the macro-tasks that are currently pending (i.e., only the
|
||||
* tasks that have been queued by setTimeout() or setInterval() up to this
|
||||
* point)
|
||||
*/
|
||||
runOnlyPendingTimers(): void,
|
||||
/**
|
||||
* Explicitly supplies the mock object that the module system should return
|
||||
* for the specified module. Note: It is recommended to use jest.mock()
|
||||
* instead.
|
||||
*/
|
||||
setMock(moduleName: string, moduleExports: any): JestObjectType,
|
||||
/**
|
||||
* Indicates that the module system should never return a mocked version of
|
||||
* the specified module from require() (e.g. that it should always return the
|
||||
* real module).
|
||||
*/
|
||||
unmock(moduleName: string): JestObjectType,
|
||||
/**
|
||||
* Instructs Jest to use fake versions of the standard timer functions
|
||||
* (setTimeout, setInterval, clearTimeout, clearInterval, nextTick,
|
||||
* setImmediate and clearImmediate).
|
||||
*/
|
||||
useFakeTimers(): JestObjectType,
|
||||
/**
|
||||
* Instructs Jest to use the real versions of the standard timer functions.
|
||||
*/
|
||||
useRealTimers(): JestObjectType,
|
||||
/**
|
||||
* Creates a mock function similar to jest.fn but also tracks calls to
|
||||
* object[methodName].
|
||||
*/
|
||||
spyOn(object: Object, methodName: string): JestMockFn
|
||||
};
|
||||
|
||||
type JestSpyType = {
|
||||
calls: JestCallsType
|
||||
};
|
||||
|
||||
/** Runs this function after every test inside this context */
|
||||
declare function afterEach(fn: Function): void;
|
||||
/** Runs this function before every test inside this context */
|
||||
declare function beforeEach(fn: Function): void;
|
||||
/** Runs this function after all tests have finished inside this context */
|
||||
declare function afterAll(fn: Function): void;
|
||||
/** Runs this function before any tests have started inside this context */
|
||||
declare function beforeAll(fn: Function): void;
|
||||
|
||||
/** A context for grouping tests together */
|
||||
declare var describe: {
|
||||
/**
|
||||
* Creates a block that groups together several related tests in one "test suite"
|
||||
*/
|
||||
(name: string, fn: Function): void,
|
||||
|
||||
/**
|
||||
* Only run this describe block
|
||||
*/
|
||||
only(name: string, fn: Function): void,
|
||||
|
||||
/**
|
||||
* Skip running this describe block
|
||||
*/
|
||||
skip(name: string, fn: Function): void,
|
||||
};
|
||||
|
||||
|
||||
/** An individual test unit */
|
||||
declare var it: {
|
||||
/**
|
||||
* An individual test unit
|
||||
*
|
||||
* @param {string} Name of Test
|
||||
* @param {Function} Test
|
||||
*/
|
||||
(name: string, fn?: Function): ?Promise<void>,
|
||||
/**
|
||||
* Only run this test
|
||||
*
|
||||
* @param {string} Name of Test
|
||||
* @param {Function} Test
|
||||
*/
|
||||
only(name: string, fn?: Function): ?Promise<void>,
|
||||
/**
|
||||
* Skip running this test
|
||||
*
|
||||
* @param {string} Name of Test
|
||||
* @param {Function} Test
|
||||
*/
|
||||
skip(name: string, fn?: Function): ?Promise<void>,
|
||||
/**
|
||||
* Run the test concurrently
|
||||
*
|
||||
* @param {string} Name of Test
|
||||
* @param {Function} Test
|
||||
*/
|
||||
concurrent(name: string, fn?: Function): ?Promise<void>
|
||||
};
|
||||
declare function fit(name: string, fn: Function): ?Promise<void>;
|
||||
/** An individual test unit */
|
||||
declare var test: typeof it;
|
||||
/** A disabled group of tests */
|
||||
declare var xdescribe: typeof describe;
|
||||
/** A focused group of tests */
|
||||
declare var fdescribe: typeof describe;
|
||||
/** A disabled individual test */
|
||||
declare var xit: typeof it;
|
||||
/** A disabled individual test */
|
||||
declare var xtest: typeof it;
|
||||
|
||||
/** The expect function is used every time you want to test a value */
|
||||
declare var expect: {
|
||||
/** The object that you want to make assertions against */
|
||||
(value: any): JestExpectType & JestPromiseType & EnzymeMatchersType,
|
||||
/** Add additional Jasmine matchers to Jest's roster */
|
||||
extend(matchers: { [name: string]: JestMatcher }): void,
|
||||
/** Add a module that formats application-specific data structures. */
|
||||
addSnapshotSerializer(serializer: (input: Object) => string): void,
|
||||
assertions(expectedAssertions: number): void,
|
||||
hasAssertions(): void,
|
||||
any(value: mixed): JestAsymmetricEqualityType,
|
||||
anything(): void,
|
||||
arrayContaining(value: Array<mixed>): void,
|
||||
objectContaining(value: Object): void,
|
||||
/** Matches any received string that contains the exact expected string. */
|
||||
stringContaining(value: string): void,
|
||||
stringMatching(value: string | RegExp): void
|
||||
};
|
||||
|
||||
// TODO handle return type
|
||||
// http://jasmine.github.io/2.4/introduction.html#section-Spies
|
||||
declare function spyOn(value: mixed, method: string): Object;
|
||||
|
||||
/** Holds all functions related to manipulating test runner */
|
||||
declare var jest: JestObjectType;
|
||||
|
||||
/**
|
||||
* The global Jamine object, this is generally not exposed as the public API,
|
||||
* using features inside here could break in later versions of Jest.
|
||||
*/
|
||||
declare var jasmine: {
|
||||
DEFAULT_TIMEOUT_INTERVAL: number,
|
||||
any(value: mixed): JestAsymmetricEqualityType,
|
||||
anything(): void,
|
||||
arrayContaining(value: Array<mixed>): void,
|
||||
clock(): JestClockType,
|
||||
createSpy(name: string): JestSpyType,
|
||||
createSpyObj(
|
||||
baseName: string,
|
||||
methodNames: Array<string>
|
||||
): { [methodName: string]: JestSpyType },
|
||||
objectContaining(value: Object): void,
|
||||
stringMatching(value: string): void
|
||||
};
|
||||
@@ -1,5 +1,5 @@
|
||||
// flow-typed signature: 5960ed076fe29ecf92f57584d68acf98
|
||||
// flow-typed version: b2a49dc910/jest_v20.x.x/flow_>=v0.39.x
|
||||
// flow-typed signature: 107cf7068b8835594e97f938e8848244
|
||||
// flow-typed version: 8b4dd96654/jest_v21.x.x/flow_>=v0.39.x
|
||||
|
||||
type JestMockFn<TArguments: $ReadOnlyArray<*>, TReturn> = {
|
||||
(...args: TArguments): TReturn,
|
||||
@@ -45,7 +45,7 @@ type JestMockFn<TArguments: $ReadOnlyArray<*>, TReturn> = {
|
||||
* will also be executed when the mock is called.
|
||||
*/
|
||||
mockImplementation(
|
||||
fn: (...args: TArguments) => TReturn,
|
||||
fn: (...args: TArguments) => TReturn
|
||||
): JestMockFn<TArguments, TReturn>,
|
||||
/**
|
||||
* Accepts a function that will be used as an implementation of the mock for
|
||||
@@ -53,7 +53,7 @@ type JestMockFn<TArguments: $ReadOnlyArray<*>, TReturn> = {
|
||||
* calls produce different results.
|
||||
*/
|
||||
mockImplementationOnce(
|
||||
fn: (...args: TArguments) => TReturn,
|
||||
fn: (...args: TArguments) => TReturn
|
||||
): JestMockFn<TArguments, TReturn>,
|
||||
/**
|
||||
* Just a simple sugar function for returning `this`
|
||||
@@ -133,7 +133,7 @@ type EnzymeMatchersType = {
|
||||
toIncludeText(text: string): void,
|
||||
toHaveValue(value: any): void,
|
||||
toMatchElement(element: React$Element<any>): void,
|
||||
toMatchSelector(selector: string): void,
|
||||
toMatchSelector(selector: string): void
|
||||
};
|
||||
|
||||
type JestExpectType = {
|
||||
@@ -258,7 +258,7 @@ type JestExpectType = {
|
||||
/**
|
||||
* Use .toMatchObject to check that a javascript object matches a subset of the properties of an object.
|
||||
*/
|
||||
toMatchObject(object: Object): void,
|
||||
toMatchObject(object: Object | Array<Object>): void,
|
||||
/**
|
||||
* This ensures that a React component matches the most recent snapshot.
|
||||
*/
|
||||
@@ -271,8 +271,8 @@ type JestExpectType = {
|
||||
*
|
||||
* Alias: .toThrowError
|
||||
*/
|
||||
toThrow(message?: string | Error | RegExp): void,
|
||||
toThrowError(message?: string | Error | RegExp): void,
|
||||
toThrow(message?: string | Error | Class<Error> | RegExp): void,
|
||||
toThrowError(message?: string | Error | Class<Error> | RegExp): void,
|
||||
/**
|
||||
* Use .toThrowErrorMatchingSnapshot to test that a function throws a error
|
||||
* matching the most recent snapshot when it is called.
|
||||
@@ -329,7 +329,7 @@ type JestObjectType = {
|
||||
* implementation.
|
||||
*/
|
||||
fn<TArguments: $ReadOnlyArray<*>, TReturn>(
|
||||
implementation?: (...args: TArguments) => TReturn,
|
||||
implementation?: (...args: TArguments) => TReturn
|
||||
): JestMockFn<TArguments, TReturn>,
|
||||
/**
|
||||
* Determines if the given function is a mocked function.
|
||||
@@ -354,6 +354,16 @@ type JestObjectType = {
|
||||
moduleFactory?: any,
|
||||
options?: Object
|
||||
): JestObjectType,
|
||||
/**
|
||||
* Returns the actual module instead of a mock, bypassing all checks on
|
||||
* whether the module should receive a mock implementation or not.
|
||||
*/
|
||||
requireActual(moduleName: string): any,
|
||||
/**
|
||||
* Returns a mock module instead of the actual module, bypassing all checks
|
||||
* on whether the module should be required normally or not.
|
||||
*/
|
||||
requireMock(moduleName: string): any,
|
||||
/**
|
||||
* Resets the module registry - the cache of all required modules. This is
|
||||
* useful to isolate modules where local state might conflict between tests.
|
||||
@@ -410,7 +420,12 @@ type JestObjectType = {
|
||||
* Creates a mock function similar to jest.fn but also tracks calls to
|
||||
* object[methodName].
|
||||
*/
|
||||
spyOn(object: Object, methodName: string): JestMockFn<any, any>
|
||||
spyOn(object: Object, methodName: string): JestMockFn<any, any>,
|
||||
/**
|
||||
* Set the default timeout interval for tests and before/after hooks in milliseconds.
|
||||
* Note: The default timeout interval is 5 seconds if this method is not called.
|
||||
*/
|
||||
setTimeout(timeout: number): JestObjectType
|
||||
};
|
||||
|
||||
type JestSpyType = {
|
||||
@@ -418,13 +433,25 @@ type JestSpyType = {
|
||||
};
|
||||
|
||||
/** Runs this function after every test inside this context */
|
||||
declare function afterEach(fn: (done: () => void) => ?Promise<mixed>, timeout?: number): void;
|
||||
declare function afterEach(
|
||||
fn: (done: () => void) => ?Promise<mixed>,
|
||||
timeout?: number
|
||||
): void;
|
||||
/** Runs this function before every test inside this context */
|
||||
declare function beforeEach(fn: (done: () => void) => ?Promise<mixed>, timeout?: number): void;
|
||||
declare function beforeEach(
|
||||
fn: (done: () => void) => ?Promise<mixed>,
|
||||
timeout?: number
|
||||
): void;
|
||||
/** Runs this function after all tests have finished inside this context */
|
||||
declare function afterAll(fn: (done: () => void) => ?Promise<mixed>, timeout?: number): void;
|
||||
declare function afterAll(
|
||||
fn: (done: () => void) => ?Promise<mixed>,
|
||||
timeout?: number
|
||||
): void;
|
||||
/** Runs this function before any tests have started inside this context */
|
||||
declare function beforeAll(fn: (done: () => void) => ?Promise<mixed>, timeout?: number): void;
|
||||
declare function beforeAll(
|
||||
fn: (done: () => void) => ?Promise<mixed>,
|
||||
timeout?: number
|
||||
): void;
|
||||
|
||||
/** A context for grouping tests together */
|
||||
declare var describe: {
|
||||
@@ -441,10 +468,9 @@ declare var describe: {
|
||||
/**
|
||||
* Skip running this describe block
|
||||
*/
|
||||
skip(name: string, fn: () => void): void,
|
||||
skip(name: string, fn: () => void): void
|
||||
};
|
||||
|
||||
|
||||
/** An individual test unit */
|
||||
declare var it: {
|
||||
/**
|
||||
@@ -454,7 +480,11 @@ declare var it: {
|
||||
* @param {Function} Test
|
||||
* @param {number} Timeout for the test, in milliseconds.
|
||||
*/
|
||||
(name: string, fn?: (done: () => void) => ?Promise<mixed>, timeout?: number): void,
|
||||
(
|
||||
name: string,
|
||||
fn?: (done: () => void) => ?Promise<mixed>,
|
||||
timeout?: number
|
||||
): void,
|
||||
/**
|
||||
* Only run this test
|
||||
*
|
||||
@@ -462,7 +492,11 @@ declare var it: {
|
||||
* @param {Function} Test
|
||||
* @param {number} Timeout for the test, in milliseconds.
|
||||
*/
|
||||
only(name: string, fn?: (done: () => void) => ?Promise<mixed>, timeout?: number): void,
|
||||
only(
|
||||
name: string,
|
||||
fn?: (done: () => void) => ?Promise<mixed>,
|
||||
timeout?: number
|
||||
): void,
|
||||
/**
|
||||
* Skip running this test
|
||||
*
|
||||
@@ -470,7 +504,11 @@ declare var it: {
|
||||
* @param {Function} Test
|
||||
* @param {number} Timeout for the test, in milliseconds.
|
||||
*/
|
||||
skip(name: string, fn?: (done: () => void) => ?Promise<mixed>, timeout?: number): void,
|
||||
skip(
|
||||
name: string,
|
||||
fn?: (done: () => void) => ?Promise<mixed>,
|
||||
timeout?: number
|
||||
): void,
|
||||
/**
|
||||
* Run the test concurrently
|
||||
*
|
||||
@@ -478,12 +516,16 @@ declare var it: {
|
||||
* @param {Function} Test
|
||||
* @param {number} Timeout for the test, in milliseconds.
|
||||
*/
|
||||
concurrent(name: string, fn?: (done: () => void) => ?Promise<mixed>, timeout?: number): void,
|
||||
concurrent(
|
||||
name: string,
|
||||
fn?: (done: () => void) => ?Promise<mixed>,
|
||||
timeout?: number
|
||||
): void
|
||||
};
|
||||
declare function fit(
|
||||
name: string,
|
||||
fn: (done: () => void) => ?Promise<mixed>,
|
||||
timeout?: number,
|
||||
timeout?: number
|
||||
): void;
|
||||
/** An individual test unit */
|
||||
declare var test: typeof it;
|
||||
@@ -523,7 +565,7 @@ declare function spyOn(value: mixed, method: string): Object;
|
||||
declare var jest: JestObjectType;
|
||||
|
||||
/**
|
||||
* The global Jamine object, this is generally not exposed as the public API,
|
||||
* The global Jasmine object, this is generally not exposed as the public API,
|
||||
* using features inside here could break in later versions of Jest.
|
||||
*/
|
||||
declare var jasmine: {
|
||||
@@ -1,5 +1,5 @@
|
||||
// flow-typed signature: bd52927dcfdd08c54751906ebaf7cfa1
|
||||
// flow-typed version: <<STUB>>/react-native-scripts_v^1.3.1/flow_v0.53.0
|
||||
// flow-typed signature: 42d8cd2e84e894c09d28f891fef9f01d
|
||||
// flow-typed version: <<STUB>>/react-native-scripts_v^1.5.0/flow_v0.61.0
|
||||
|
||||
/**
|
||||
* This is an autogenerated libdef stub for:
|
||||
|
||||
62
examples/NavigationPlayground/flow-typed/npm/react-test-renderer_v16.x.x.js
vendored
Normal file
@@ -0,0 +1,62 @@
|
||||
// flow-typed signature: 2d946f2ec4aba5210b19d053c411a59d
|
||||
// flow-typed version: 95b3e05165/react-test-renderer_v16.x.x/flow_>=v0.47.x
|
||||
|
||||
// Type definitions for react-test-renderer 16.x.x
|
||||
// Ported from: https://github.com/DefinitelyTyped/DefinitelyTyped/blob/master/types/react-test-renderer
|
||||
|
||||
type ReactTestRendererJSON = {
|
||||
type: string,
|
||||
props: { [propName: string]: any },
|
||||
children: null | ReactTestRendererJSON[]
|
||||
};
|
||||
|
||||
type ReactTestRendererTree = ReactTestRendererJSON & {
|
||||
nodeType: "component" | "host",
|
||||
instance: any,
|
||||
rendered: null | ReactTestRendererTree
|
||||
};
|
||||
|
||||
type ReactTestInstance = {
|
||||
instance: any,
|
||||
type: string,
|
||||
props: { [propName: string]: any },
|
||||
parent: null | ReactTestInstance,
|
||||
children: Array<ReactTestInstance | string>,
|
||||
|
||||
find(predicate: (node: ReactTestInstance) => boolean): ReactTestInstance,
|
||||
findByType(type: React$ElementType): ReactTestInstance,
|
||||
findByProps(props: { [propName: string]: any }): ReactTestInstance,
|
||||
|
||||
findAll(
|
||||
predicate: (node: ReactTestInstance) => boolean,
|
||||
options?: { deep: boolean }
|
||||
): ReactTestInstance[],
|
||||
findAllByType(
|
||||
type: React$ElementType,
|
||||
options?: { deep: boolean }
|
||||
): ReactTestInstance[],
|
||||
findAllByProps(
|
||||
props: { [propName: string]: any },
|
||||
options?: { deep: boolean }
|
||||
): ReactTestInstance[]
|
||||
};
|
||||
|
||||
type ReactTestRenderer = {
|
||||
toJSON(): null | ReactTestRendererJSON,
|
||||
toTree(): null | ReactTestRendererTree,
|
||||
unmount(nextElement?: React$Element<any>): void,
|
||||
update(nextElement: React$Element<any>): void,
|
||||
getInstance(): null | ReactTestInstance,
|
||||
root: ReactTestInstance
|
||||
};
|
||||
|
||||
type TestRendererOptions = {
|
||||
createNodeMock(element: React$Element<any>): any
|
||||
};
|
||||
|
||||
declare module "react-test-renderer" {
|
||||
declare function create(
|
||||
nextElement: React$Element<any>,
|
||||
options?: TestRendererOptions
|
||||
): ReactTestRenderer;
|
||||
}
|
||||
@@ -1,61 +1,92 @@
|
||||
/* @flow */
|
||||
|
||||
import React from 'react';
|
||||
import { ScreenOrientation } from 'expo';
|
||||
import { Asset, Constants, ScreenOrientation } from 'expo';
|
||||
|
||||
ScreenOrientation.allow(ScreenOrientation.Orientation.ALL);
|
||||
|
||||
import {
|
||||
Animated,
|
||||
Image,
|
||||
Platform,
|
||||
ScrollView,
|
||||
StyleSheet,
|
||||
TouchableOpacity,
|
||||
Text,
|
||||
StatusBar,
|
||||
View,
|
||||
} from 'react-native';
|
||||
import { SafeAreaView, StackNavigator } from 'react-navigation';
|
||||
import { SafeAreaView, createStackNavigator } from 'react-navigation';
|
||||
|
||||
import Banner from './Banner';
|
||||
import CustomTabs from './CustomTabs';
|
||||
import CustomTransitioner from './CustomTransitioner';
|
||||
import Drawer from './Drawer';
|
||||
import MultipleDrawer from './MultipleDrawer';
|
||||
import TabsInDrawer from './TabsInDrawer';
|
||||
import ModalStack from './ModalStack';
|
||||
import StacksInTabs from './StacksInTabs';
|
||||
import StacksOverTabs from './StacksOverTabs';
|
||||
import StacksOverTopTabs from './StacksOverTopTabs';
|
||||
import StacksWithKeys from './StacksWithKeys';
|
||||
import InactiveStack from './InactiveStack';
|
||||
import StackWithCustomHeaderBackImage from './StackWithCustomHeaderBackImage';
|
||||
import SimpleStack from './SimpleStack';
|
||||
import StackWithHeaderPreset from './StackWithHeaderPreset';
|
||||
import StackWithTranslucentHeader from './StackWithTranslucentHeader';
|
||||
import SimpleTabs from './SimpleTabs';
|
||||
import SwitchWithStacks from './SwitchWithStacks';
|
||||
import TabsWithNavigationFocus from './TabsWithNavigationFocus';
|
||||
import KeyboardHandlingExample from './KeyboardHandlingExample';
|
||||
|
||||
const ExampleRoutes = {
|
||||
const ExampleInfo = {
|
||||
SimpleStack: {
|
||||
name: 'Stack Example',
|
||||
description: 'A card stack',
|
||||
screen: SimpleStack,
|
||||
},
|
||||
SwitchWithStacks: {
|
||||
name: 'Switch between routes',
|
||||
description: 'Jump between routes',
|
||||
},
|
||||
InactiveStack: {
|
||||
name: 'Navigate idempotently to stacks in inactive routes',
|
||||
description:
|
||||
'An inactive route in a stack should be given the opportunity to handle actions',
|
||||
},
|
||||
StackWithCustomHeaderBackImage: {
|
||||
name: 'Custom header back image',
|
||||
description: 'Stack with custom header back image',
|
||||
},
|
||||
SimpleTabs: {
|
||||
name: 'Tabs Example',
|
||||
description: 'Tabs following platform conventions',
|
||||
screen: SimpleTabs,
|
||||
},
|
||||
Drawer: {
|
||||
name: 'Drawer Example',
|
||||
description: 'Android-style drawer navigation',
|
||||
screen: Drawer,
|
||||
},
|
||||
StackWithHeaderPreset: {
|
||||
name: 'UIKit-style Header Transitions',
|
||||
description: 'Masked back button and sliding header items. iOS only.',
|
||||
},
|
||||
StackWithTranslucentHeader: {
|
||||
name: 'Translucent Header',
|
||||
description: 'Render arbitrary translucent content in header background.',
|
||||
},
|
||||
// MultipleDrawer: {
|
||||
// name: 'Multiple Drawer Example',
|
||||
// description: 'Add any drawer you need',
|
||||
// },
|
||||
TabsInDrawer: {
|
||||
name: 'Drawer + Tabs Example',
|
||||
description: 'A drawer combined with tabs',
|
||||
screen: TabsInDrawer,
|
||||
},
|
||||
CustomTabs: {
|
||||
name: 'Custom Tabs',
|
||||
description: 'Custom tabs with tab router',
|
||||
screen: CustomTabs,
|
||||
},
|
||||
CustomTransitioner: {
|
||||
name: 'Custom Transitioner',
|
||||
description: 'Custom transitioner with stack router',
|
||||
screen: CustomTransitioner,
|
||||
},
|
||||
ModalStack: {
|
||||
name:
|
||||
@@ -66,62 +97,224 @@ const ExampleRoutes = {
|
||||
Platform.OS === 'ios'
|
||||
? 'Stack navigation with modals'
|
||||
: 'Dynamically showing and hiding the header',
|
||||
screen: ModalStack,
|
||||
},
|
||||
StacksInTabs: {
|
||||
name: 'Stacks in Tabs',
|
||||
description: 'Nested stack navigation in tabs',
|
||||
screen: StacksInTabs,
|
||||
},
|
||||
StacksOverTabs: {
|
||||
name: 'Stacks over Tabs',
|
||||
description: 'Nested stack navigation that pushes on top of tabs',
|
||||
screen: StacksOverTabs,
|
||||
},
|
||||
StacksOverTopTabs: {
|
||||
name: 'Stacks with non-standard header height',
|
||||
description: 'Tab navigator in stack with custom header heights',
|
||||
},
|
||||
StacksWithKeys: {
|
||||
name: 'Link in Stack with keys',
|
||||
description: 'Use keys to link between screens',
|
||||
},
|
||||
LinkStack: {
|
||||
name: 'Link in Stack',
|
||||
description: 'Deep linking into a route in stack',
|
||||
screen: SimpleStack,
|
||||
path: 'people/Jordan',
|
||||
},
|
||||
LinkTabs: {
|
||||
name: 'Link to Settings Tab',
|
||||
description: 'Deep linking into a route in tab',
|
||||
screen: SimpleTabs,
|
||||
path: 'settings',
|
||||
},
|
||||
TabsWithNavigationFocus: {
|
||||
name: 'withNavigationFocus',
|
||||
description: 'Receive the focus prop to know when a screen is focused',
|
||||
},
|
||||
KeyboardHandlingExample: {
|
||||
name: 'Keyboard Handling Example',
|
||||
description:
|
||||
'Demo automatic handling of keyboard showing/hiding inside StackNavigator',
|
||||
},
|
||||
};
|
||||
|
||||
const MainScreen = ({ navigation }) => (
|
||||
<ScrollView style={{ flex: 1 }} contentInsetAdjustmentBehavior="automatic">
|
||||
<Banner />
|
||||
{Object.keys(ExampleRoutes).map((routeName: string) => (
|
||||
<TouchableOpacity
|
||||
key={routeName}
|
||||
onPress={() => {
|
||||
const { path, params, screen } = ExampleRoutes[routeName];
|
||||
const { router } = screen;
|
||||
const action = path && router.getActionForPathAndParams(path, params);
|
||||
navigation.navigate(routeName, {}, action);
|
||||
}}
|
||||
>
|
||||
<SafeAreaView
|
||||
style={styles.itemContainer}
|
||||
forceInset={{ vertical: 'never' }}
|
||||
>
|
||||
<View style={styles.item}>
|
||||
<Text style={styles.title}>{ExampleRoutes[routeName].name}</Text>
|
||||
<Text style={styles.description}>
|
||||
{ExampleRoutes[routeName].description}
|
||||
</Text>
|
||||
</View>
|
||||
</SafeAreaView>
|
||||
</TouchableOpacity>
|
||||
))}
|
||||
</ScrollView>
|
||||
);
|
||||
const ExampleRoutes = {
|
||||
SimpleStack,
|
||||
SwitchWithStacks,
|
||||
SimpleTabs: SimpleTabs,
|
||||
Drawer: Drawer,
|
||||
// MultipleDrawer: {
|
||||
// screen: MultipleDrawer,
|
||||
// },
|
||||
StackWithCustomHeaderBackImage: StackWithCustomHeaderBackImage,
|
||||
...Platform.select({
|
||||
ios: {
|
||||
StackWithHeaderPreset: StackWithHeaderPreset,
|
||||
},
|
||||
android: {},
|
||||
}),
|
||||
StackWithTranslucentHeader: StackWithTranslucentHeader,
|
||||
TabsInDrawer: TabsInDrawer,
|
||||
CustomTabs: CustomTabs,
|
||||
CustomTransitioner: CustomTransitioner,
|
||||
ModalStack: ModalStack,
|
||||
StacksWithKeys: StacksWithKeys,
|
||||
StacksInTabs: StacksInTabs,
|
||||
StacksOverTabs: StacksOverTabs,
|
||||
StacksOverTopTabs: StacksOverTopTabs,
|
||||
LinkStack: {
|
||||
screen: SimpleStack,
|
||||
path: 'people/Jordan',
|
||||
},
|
||||
LinkTabs: {
|
||||
screen: SimpleTabs,
|
||||
path: 'settings',
|
||||
},
|
||||
TabsWithNavigationFocus,
|
||||
KeyboardHandlingExample,
|
||||
// This is commented out because it's rarely useful
|
||||
// InactiveStack,
|
||||
};
|
||||
|
||||
const AppNavigator = StackNavigator(
|
||||
type State = {
|
||||
scrollY: Animated.Value,
|
||||
};
|
||||
class MainScreen extends React.Component<any, State> {
|
||||
state = {
|
||||
scrollY: new Animated.Value(0),
|
||||
};
|
||||
|
||||
componentDidMount() {
|
||||
Asset.fromModule(
|
||||
require('react-navigation/src/views/assets/back-icon-mask.png')
|
||||
).downloadAsync();
|
||||
Asset.fromModule(
|
||||
require('react-navigation/src/views/assets/back-icon.png')
|
||||
).downloadAsync();
|
||||
}
|
||||
|
||||
render() {
|
||||
const { navigation } = this.props;
|
||||
|
||||
const scale = this.state.scrollY.interpolate({
|
||||
inputRange: [-450, 0, 100],
|
||||
outputRange: [2, 1, 0.8],
|
||||
extrapolate: 'clamp',
|
||||
});
|
||||
|
||||
const translateY = this.state.scrollY.interpolate({
|
||||
inputRange: [-450, 0, 100],
|
||||
outputRange: [-150, 0, 40],
|
||||
});
|
||||
|
||||
const opacity = this.state.scrollY.interpolate({
|
||||
inputRange: [0, 50],
|
||||
outputRange: [1, 0],
|
||||
extrapolate: 'clamp',
|
||||
});
|
||||
|
||||
const underlayOpacity = this.state.scrollY.interpolate({
|
||||
inputRange: [0, 50],
|
||||
outputRange: [0, 1],
|
||||
extrapolate: 'clamp',
|
||||
});
|
||||
|
||||
const backgroundScale = this.state.scrollY.interpolate({
|
||||
inputRange: [-450, 0],
|
||||
outputRange: [3, 1],
|
||||
extrapolate: 'clamp',
|
||||
});
|
||||
|
||||
const backgroundTranslateY = this.state.scrollY.interpolate({
|
||||
inputRange: [-450, 0],
|
||||
outputRange: [0, 0],
|
||||
});
|
||||
|
||||
return (
|
||||
<View style={{ flex: 1 }}>
|
||||
<Animated.ScrollView
|
||||
style={{ flex: 1 }}
|
||||
scrollEventThrottle={1}
|
||||
onScroll={Animated.event(
|
||||
[
|
||||
{
|
||||
nativeEvent: { contentOffset: { y: this.state.scrollY } },
|
||||
},
|
||||
],
|
||||
{ useNativeDriver: true }
|
||||
)}
|
||||
>
|
||||
<Animated.View
|
||||
style={[
|
||||
styles.backgroundUnderlay,
|
||||
{
|
||||
transform: [
|
||||
{ scale: backgroundScale },
|
||||
{ translateY: backgroundTranslateY },
|
||||
],
|
||||
},
|
||||
]}
|
||||
/>
|
||||
<Animated.View
|
||||
style={{ opacity, transform: [{ scale }, { translateY }] }}
|
||||
>
|
||||
<SafeAreaView
|
||||
style={styles.bannerContainer}
|
||||
forceInset={{ top: 'always', bottom: 'never' }}
|
||||
>
|
||||
<View style={styles.banner}>
|
||||
<Image
|
||||
source={require('./assets/NavLogo.png')}
|
||||
style={styles.bannerImage}
|
||||
/>
|
||||
<Text style={styles.bannerTitle}>
|
||||
React Navigation Examples
|
||||
</Text>
|
||||
</View>
|
||||
</SafeAreaView>
|
||||
</Animated.View>
|
||||
|
||||
<SafeAreaView forceInset={{ bottom: 'always', horizontal: 'never' }}>
|
||||
<View style={{ backgroundColor: '#fff' }}>
|
||||
{Object.keys(ExampleRoutes).map((routeName: string) => (
|
||||
<TouchableOpacity
|
||||
key={routeName}
|
||||
onPress={() => {
|
||||
let route = ExampleRoutes[routeName];
|
||||
if (route.screen || route.path || route.params) {
|
||||
const { path, params, screen } = route;
|
||||
const { router } = screen;
|
||||
const action =
|
||||
path && router.getActionForPathAndParams(path, params);
|
||||
navigation.navigate(routeName, {}, action);
|
||||
} else {
|
||||
navigation.navigate(routeName);
|
||||
}
|
||||
}}
|
||||
>
|
||||
<SafeAreaView
|
||||
style={styles.itemContainer}
|
||||
forceInset={{ veritcal: 'never', bottom: 'never' }}
|
||||
>
|
||||
<View style={styles.item}>
|
||||
<Text style={styles.title}>
|
||||
{ExampleInfo[routeName].name}
|
||||
</Text>
|
||||
<Text style={styles.description}>
|
||||
{ExampleInfo[routeName].description}
|
||||
</Text>
|
||||
</View>
|
||||
</SafeAreaView>
|
||||
</TouchableOpacity>
|
||||
))}
|
||||
</View>
|
||||
</SafeAreaView>
|
||||
</Animated.ScrollView>
|
||||
<StatusBar barStyle="light-content" />
|
||||
<Animated.View
|
||||
style={[styles.statusBarUnderlay, { opacity: underlayOpacity }]}
|
||||
/>
|
||||
</View>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
const AppNavigator = createStackNavigator(
|
||||
{
|
||||
...ExampleRoutes,
|
||||
Index: {
|
||||
@@ -140,7 +333,7 @@ const AppNavigator = StackNavigator(
|
||||
}
|
||||
);
|
||||
|
||||
export default () => <AppNavigator />;
|
||||
export default AppNavigator;
|
||||
|
||||
const styles = StyleSheet.create({
|
||||
item: {
|
||||
@@ -159,6 +352,14 @@ const styles = StyleSheet.create({
|
||||
marginBottom: 20,
|
||||
resizeMode: 'contain',
|
||||
},
|
||||
statusBarUnderlay: {
|
||||
backgroundColor: '#673ab7',
|
||||
position: 'absolute',
|
||||
top: 0,
|
||||
left: 0,
|
||||
right: 0,
|
||||
height: Constants.statusBarHeight,
|
||||
},
|
||||
title: {
|
||||
fontSize: 16,
|
||||
fontWeight: 'bold',
|
||||
@@ -168,4 +369,35 @@ const styles = StyleSheet.create({
|
||||
fontSize: 13,
|
||||
color: '#999',
|
||||
},
|
||||
backgroundUnderlay: {
|
||||
backgroundColor: '#673ab7',
|
||||
position: 'absolute',
|
||||
top: -100,
|
||||
height: 300,
|
||||
left: 0,
|
||||
right: 0,
|
||||
},
|
||||
bannerContainer: {
|
||||
// backgroundColor: '#673ab7',
|
||||
alignItems: 'center',
|
||||
},
|
||||
banner: {
|
||||
flexDirection: 'row',
|
||||
alignItems: 'center',
|
||||
padding: 16,
|
||||
},
|
||||
bannerImage: {
|
||||
width: 36,
|
||||
height: 36,
|
||||
resizeMode: 'contain',
|
||||
tintColor: '#fff',
|
||||
margin: 8,
|
||||
},
|
||||
bannerTitle: {
|
||||
fontSize: 18,
|
||||
fontWeight: '200',
|
||||
color: '#fff',
|
||||
marginVertical: 8,
|
||||
marginRight: 5,
|
||||
},
|
||||
});
|
||||
|
||||
@@ -8,7 +8,7 @@ import { SafeAreaView } from 'react-navigation';
|
||||
const Banner = () => (
|
||||
<SafeAreaView
|
||||
style={styles.bannerContainer}
|
||||
forceInset={{ vertical: 'never' }}
|
||||
forceInset={{ top: 'always' }}
|
||||
>
|
||||
<View style={styles.banner}>
|
||||
<Image source={require('./assets/NavLogo.png')} style={styles.image} />
|
||||
@@ -22,6 +22,7 @@ export default Banner;
|
||||
const styles = StyleSheet.create({
|
||||
bannerContainer: {
|
||||
backgroundColor: '#673ab7',
|
||||
paddingTop: 20,
|
||||
},
|
||||
banner: {
|
||||
flexDirection: 'row',
|
||||
|
||||
@@ -4,10 +4,10 @@
|
||||
|
||||
import React from 'react';
|
||||
import {
|
||||
Button,
|
||||
Platform,
|
||||
ScrollView,
|
||||
StyleSheet,
|
||||
StatusBar,
|
||||
Text,
|
||||
TouchableOpacity,
|
||||
View,
|
||||
@@ -17,9 +17,9 @@ import {
|
||||
createNavigationContainer,
|
||||
SafeAreaView,
|
||||
TabRouter,
|
||||
addNavigationHelpers,
|
||||
} from 'react-navigation';
|
||||
import SampleText from './SampleText';
|
||||
import { Button } from './commonComponents/ButtonWithMargin';
|
||||
|
||||
const MyNavScreen = ({ navigation, banner }) => (
|
||||
<ScrollView>
|
||||
@@ -32,6 +32,7 @@ const MyNavScreen = ({ navigation, banner }) => (
|
||||
title="Go back"
|
||||
/>
|
||||
</SafeAreaView>
|
||||
<StatusBar barStyle="default" />
|
||||
</ScrollView>
|
||||
);
|
||||
|
||||
@@ -64,18 +65,14 @@ const CustomTabBar = ({ navigation }) => {
|
||||
);
|
||||
};
|
||||
|
||||
const CustomTabView = ({ router, navigation }) => {
|
||||
const CustomTabView = ({ descriptors, navigation }) => {
|
||||
const { routes, index } = navigation.state;
|
||||
const ActiveScreen = router.getComponentForRouteName(routes[index].routeName);
|
||||
const descriptor = descriptors[routes[index].key];
|
||||
const ActiveScreen = descriptor.getComponent();
|
||||
return (
|
||||
<SafeAreaView forceInset={{ top: 'always' }}>
|
||||
<CustomTabBar navigation={navigation} />
|
||||
<ActiveScreen
|
||||
navigation={addNavigationHelpers({
|
||||
dispatch: navigation.dispatch,
|
||||
state: routes[index],
|
||||
})}
|
||||
/>
|
||||
<ActiveScreen navigation={descriptor.navigation} />
|
||||
</SafeAreaView>
|
||||
);
|
||||
};
|
||||
@@ -102,7 +99,7 @@ const CustomTabRouter = TabRouter(
|
||||
);
|
||||
|
||||
const CustomTabs = createNavigationContainer(
|
||||
createNavigator(CustomTabRouter)(CustomTabView)
|
||||
createNavigator(CustomTabView, CustomTabRouter, {})
|
||||
);
|
||||
|
||||
const styles = StyleSheet.create({
|
||||
|
||||
@@ -1,22 +1,22 @@
|
||||
import React, { Component, PropTypes } from 'react';
|
||||
import {
|
||||
StyleSheet,
|
||||
Platform,
|
||||
Easing,
|
||||
View,
|
||||
Animated,
|
||||
Easing,
|
||||
Image,
|
||||
Button,
|
||||
Platform,
|
||||
StatusBar,
|
||||
StyleSheet,
|
||||
View,
|
||||
} from 'react-native';
|
||||
import {
|
||||
Transitioner,
|
||||
SafeAreaView,
|
||||
StackRouter,
|
||||
createNavigationContainer,
|
||||
addNavigationHelpers,
|
||||
createNavigator,
|
||||
} from 'react-navigation';
|
||||
import SampleText from './SampleText';
|
||||
import { Button } from './commonComponents/ButtonWithMargin';
|
||||
|
||||
const MyNavScreen = ({ navigation, banner }) => (
|
||||
<SafeAreaView forceInset={{ top: 'always' }}>
|
||||
@@ -30,6 +30,7 @@ const MyNavScreen = ({ navigation, banner }) => (
|
||||
)}
|
||||
|
||||
<Button onPress={() => navigation.goBack(null)} title="Go back" />
|
||||
<StatusBar barStyle="default" />
|
||||
</SafeAreaView>
|
||||
);
|
||||
|
||||
@@ -43,11 +44,12 @@ const MySettingsScreen = ({ navigation }) => (
|
||||
|
||||
class CustomNavigationView extends Component {
|
||||
render() {
|
||||
const { navigation, router } = this.props;
|
||||
const { navigation, router, descriptors } = this.props;
|
||||
|
||||
return (
|
||||
<Transitioner
|
||||
configureTransition={this._configureTransition}
|
||||
descriptors={descriptors}
|
||||
navigation={navigation}
|
||||
render={this._render}
|
||||
/>
|
||||
@@ -84,16 +86,10 @@ class CustomNavigationView extends Component {
|
||||
transform: [{ scale: animatedValue }],
|
||||
};
|
||||
|
||||
// The prop `router` is populated when we call `createNavigator`.
|
||||
const Scene = router.getComponentForRouteName(scene.route.routeName);
|
||||
const Scene = scene.descriptor.getComponent();
|
||||
return (
|
||||
<Animated.View key={index} style={[styles.view, animation]}>
|
||||
<Scene
|
||||
navigation={addNavigationHelpers({
|
||||
...navigation,
|
||||
state: routes[index],
|
||||
})}
|
||||
/>
|
||||
<Scene navigation={scene.descriptor.navigation} />
|
||||
</Animated.View>
|
||||
);
|
||||
};
|
||||
@@ -105,7 +101,7 @@ const CustomRouter = StackRouter({
|
||||
});
|
||||
|
||||
const CustomTransitioner = createNavigationContainer(
|
||||
createNavigator(CustomRouter)(CustomNavigationView)
|
||||
createNavigator(CustomNavigationView, CustomRouter, {})
|
||||
);
|
||||
|
||||
export default CustomTransitioner;
|
||||
|
||||
@@ -3,21 +3,28 @@
|
||||
*/
|
||||
|
||||
import React from 'react';
|
||||
import { Button, Platform, ScrollView } from 'react-native';
|
||||
import { DrawerNavigator, SafeAreaView } from 'react-navigation';
|
||||
import { Platform, ScrollView, StatusBar } from 'react-native';
|
||||
import {
|
||||
createStackNavigator,
|
||||
createDrawerNavigator,
|
||||
SafeAreaView,
|
||||
} from 'react-navigation';
|
||||
import MaterialIcons from 'react-native-vector-icons/MaterialIcons';
|
||||
import SampleText from './SampleText';
|
||||
import { Button } from './commonComponents/ButtonWithMargin';
|
||||
|
||||
const MyNavScreen = ({ navigation, banner }) => (
|
||||
<ScrollView>
|
||||
<SafeAreaView forceInset={{ top: 'always' }}>
|
||||
<SampleText>{banner}</SampleText>
|
||||
<Button onPress={() => navigation.openDrawer()} title="Open drawer" />
|
||||
<Button
|
||||
onPress={() => navigation.navigate('DrawerOpen')}
|
||||
title="Open drawer"
|
||||
onPress={() => navigation.navigate('Email')}
|
||||
title="Open other screen"
|
||||
/>
|
||||
<Button onPress={() => navigation.goBack(null)} title="Go back" />
|
||||
</SafeAreaView>
|
||||
<StatusBar barStyle="default" />
|
||||
</ScrollView>
|
||||
);
|
||||
|
||||
@@ -25,6 +32,26 @@ const InboxScreen = ({ navigation }) => (
|
||||
<MyNavScreen banner={'Inbox Screen'} navigation={navigation} />
|
||||
);
|
||||
InboxScreen.navigationOptions = {
|
||||
headerTitle: 'Inbox',
|
||||
};
|
||||
|
||||
const EmailScreen = ({ navigation }) => (
|
||||
<MyNavScreen banner={'Email Screen'} navigation={navigation} />
|
||||
);
|
||||
|
||||
const DraftsScreen = ({ navigation }) => (
|
||||
<MyNavScreen banner={'Drafts Screen'} navigation={navigation} />
|
||||
);
|
||||
DraftsScreen.navigationOptions = {
|
||||
headerTitle: 'Drafts',
|
||||
};
|
||||
|
||||
const InboxStack = createStackNavigator({
|
||||
Inbox: { screen: InboxScreen },
|
||||
Email: { screen: EmailScreen },
|
||||
});
|
||||
|
||||
InboxStack.navigationOptions = {
|
||||
drawerLabel: 'Inbox',
|
||||
drawerIcon: ({ tintColor }) => (
|
||||
<MaterialIcons
|
||||
@@ -35,25 +62,27 @@ InboxScreen.navigationOptions = {
|
||||
),
|
||||
};
|
||||
|
||||
const DraftsScreen = ({ navigation }) => (
|
||||
<MyNavScreen banner={'Drafts Screen'} navigation={navigation} />
|
||||
);
|
||||
DraftsScreen.navigationOptions = {
|
||||
const DraftsStack = createStackNavigator({
|
||||
Drafts: { screen: DraftsScreen },
|
||||
Email: { screen: EmailScreen },
|
||||
});
|
||||
|
||||
DraftsStack.navigationOptions = {
|
||||
drawerLabel: 'Drafts',
|
||||
drawerIcon: ({ tintColor }) => (
|
||||
<MaterialIcons name="drafts" size={24} style={{ color: tintColor }} />
|
||||
),
|
||||
};
|
||||
|
||||
const DrawerExample = DrawerNavigator(
|
||||
const DrawerExample = createDrawerNavigator(
|
||||
{
|
||||
Inbox: {
|
||||
path: '/',
|
||||
screen: InboxScreen,
|
||||
screen: InboxStack,
|
||||
},
|
||||
Drafts: {
|
||||
path: '/sent',
|
||||
screen: DraftsScreen,
|
||||
screen: DraftsStack,
|
||||
},
|
||||
},
|
||||
{
|
||||
|
||||
96
examples/NavigationPlayground/js/InactiveStack.js
Normal file
@@ -0,0 +1,96 @@
|
||||
import React from 'react';
|
||||
import { Button, Text, StatusBar, View, StyleSheet } from 'react-native';
|
||||
import {
|
||||
SafeAreaView,
|
||||
createStackNavigator,
|
||||
createSwitchNavigator,
|
||||
NavigationActions,
|
||||
} from 'react-navigation';
|
||||
|
||||
const runSubRoutes = navigation => {
|
||||
navigation.dispatch(NavigationActions.navigate({ routeName: 'First2' }));
|
||||
navigation.dispatch(NavigationActions.navigate({ routeName: 'Second2' }));
|
||||
navigation.dispatch(NavigationActions.navigate({ routeName: 'First2' }));
|
||||
};
|
||||
|
||||
const runSubRoutesWithIntermediate = navigation => {
|
||||
navigation.dispatch(toFirst1);
|
||||
navigation.dispatch(toSecond2);
|
||||
navigation.dispatch(toFirst);
|
||||
navigation.dispatch(toFirst2);
|
||||
};
|
||||
|
||||
const runSubAction = navigation => {
|
||||
navigation.dispatch(toFirst2);
|
||||
navigation.dispatch(toSecond2);
|
||||
navigation.dispatch(toFirstChild1);
|
||||
};
|
||||
|
||||
const DummyScreen = ({ routeName, navigation, style }) => {
|
||||
return (
|
||||
<SafeAreaView
|
||||
style={[
|
||||
StyleSheet.absoluteFill,
|
||||
{
|
||||
alignItems: 'center',
|
||||
justifyContent: 'center',
|
||||
backgroundColor: 'white',
|
||||
},
|
||||
style,
|
||||
]}
|
||||
>
|
||||
<Text style={{ fontWeight: '800' }}>
|
||||
{routeName}({navigation.state.key})
|
||||
</Text>
|
||||
<View>
|
||||
<Button title="back" onPress={() => navigation.goBack()} />
|
||||
<Button title="dismiss" onPress={() => navigation.dismiss()} />
|
||||
<Button
|
||||
title="between sub-routes"
|
||||
onPress={() => runSubRoutes(navigation)}
|
||||
/>
|
||||
<Button
|
||||
title="between sub-routes (with intermediate)"
|
||||
onPress={() => runSubRoutesWithIntermediate(navigation)}
|
||||
/>
|
||||
|
||||
<Button
|
||||
title="with sub-action"
|
||||
onPress={() => runSubAction(navigation)}
|
||||
/>
|
||||
</View>
|
||||
<StatusBar barStyle="default" />
|
||||
</SafeAreaView>
|
||||
);
|
||||
};
|
||||
|
||||
const createDummyScreen = routeName => {
|
||||
const BoundDummyScreen = props => DummyScreen({ ...props, routeName });
|
||||
return BoundDummyScreen;
|
||||
};
|
||||
|
||||
const toFirst = NavigationActions.navigate({ routeName: 'First' });
|
||||
const toFirst1 = NavigationActions.navigate({ routeName: 'First1' });
|
||||
const toFirst2 = NavigationActions.navigate({ routeName: 'First2' });
|
||||
const toSecond2 = NavigationActions.navigate({ routeName: 'Second2' });
|
||||
const toFirstChild1 = NavigationActions.navigate({
|
||||
routeName: 'First',
|
||||
action: NavigationActions.navigate({ routeName: 'First1' }),
|
||||
});
|
||||
|
||||
export default createStackNavigator(
|
||||
{
|
||||
Other: createDummyScreen('Leaf'),
|
||||
First: createStackNavigator({
|
||||
First1: createDummyScreen('First1'),
|
||||
First2: createDummyScreen('First2'),
|
||||
}),
|
||||
Second: createStackNavigator({
|
||||
Second1: createDummyScreen('Second1'),
|
||||
Second2: createDummyScreen('Second2'),
|
||||
}),
|
||||
},
|
||||
{
|
||||
headerMode: 'none',
|
||||
}
|
||||
);
|
||||
63
examples/NavigationPlayground/js/KeyboardHandlingExample.js
Normal file
@@ -0,0 +1,63 @@
|
||||
import React from 'react';
|
||||
import { StatusBar, View, TextInput, InteractionManager } from 'react-native';
|
||||
import { createStackNavigator, withNavigationFocus } from 'react-navigation';
|
||||
import { Button } from './commonComponents/ButtonWithMargin';
|
||||
|
||||
class ScreenOne extends React.Component {
|
||||
static navigationOptions = {
|
||||
title: 'Home',
|
||||
};
|
||||
|
||||
render() {
|
||||
const { navigation } = this.props;
|
||||
return (
|
||||
<View style={{ paddingTop: 30 }}>
|
||||
<Button
|
||||
onPress={() => navigation.push('ScreenTwo')}
|
||||
title="Push screen with focused text input"
|
||||
/>
|
||||
<Button onPress={() => navigation.goBack(null)} title="Go Home" />
|
||||
<StatusBar barStyle="default" />
|
||||
</View>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class ScreenTwo extends React.Component {
|
||||
static navigationOptions = ({ navigation }) => ({
|
||||
title: navigation.getParam('inputValue', 'Screen w/ Input'),
|
||||
});
|
||||
|
||||
componentDidMount() {
|
||||
InteractionManager.runAfterInteractions(() => {
|
||||
this._textInput.focus();
|
||||
});
|
||||
}
|
||||
|
||||
render() {
|
||||
const { navigation } = this.props;
|
||||
return (
|
||||
<View style={{ paddingTop: 30 }}>
|
||||
<View style={{ alignSelf: 'center', paddingVertical: 20 }}>
|
||||
<TextInput
|
||||
ref={c => (this._textInput = c)}
|
||||
onChangeText={inputValue => navigation.setParams({ inputValue })}
|
||||
style={{
|
||||
backgroundColor: 'white',
|
||||
height: 24,
|
||||
width: 150,
|
||||
borderColor: '#555',
|
||||
borderWidth: 1,
|
||||
}}
|
||||
/>
|
||||
</View>
|
||||
<Button onPress={() => navigation.pop()} title="Pop" />
|
||||
</View>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export default createStackNavigator({
|
||||
ScreenOne,
|
||||
ScreenTwo: withNavigationFocus(ScreenTwo),
|
||||
});
|
||||
@@ -3,12 +3,13 @@
|
||||
*/
|
||||
|
||||
import React from 'react';
|
||||
import { Button, ScrollView, Text } from 'react-native';
|
||||
import { SafeAreaView, StackNavigator } from 'react-navigation';
|
||||
import { ScrollView, StatusBar, Text } from 'react-native';
|
||||
import { SafeAreaView, createStackNavigator } from 'react-navigation';
|
||||
import SampleText from './SampleText';
|
||||
import { Button } from './commonComponents/ButtonWithMargin';
|
||||
|
||||
const MyNavScreen = ({ navigation, banner }) => (
|
||||
<ScrollView contentInsetAdjustmentBehavior="automatic">
|
||||
<ScrollView>
|
||||
<SafeAreaView
|
||||
forceInset={{
|
||||
top: navigation.state.routeName === 'HeaderTest' ? 'always' : 'never',
|
||||
@@ -31,11 +32,13 @@ const MyNavScreen = ({ navigation, banner }) => (
|
||||
headerVisible:
|
||||
!navigation.state.params ||
|
||||
!navigation.state.params.headerVisible,
|
||||
})}
|
||||
})
|
||||
}
|
||||
/>
|
||||
)}
|
||||
<Button onPress={() => navigation.goBack(null)} title="Go back" />
|
||||
</SafeAreaView>
|
||||
<StatusBar barStyle="default" />
|
||||
</ScrollView>
|
||||
);
|
||||
|
||||
@@ -56,7 +59,7 @@ MyProfileScreen.navigationOptions = ({ navigation }) => ({
|
||||
title: `${navigation.state.params.name}'s Profile!`,
|
||||
});
|
||||
|
||||
const ProfileNavigator = StackNavigator(
|
||||
const ProfileNavigator = createStackNavigator(
|
||||
{
|
||||
Home: {
|
||||
screen: MyHomeScreen,
|
||||
@@ -68,8 +71,9 @@ const ProfileNavigator = StackNavigator(
|
||||
},
|
||||
{
|
||||
navigationOptions: {
|
||||
header: null,
|
||||
headerLeft: null,
|
||||
},
|
||||
mode: 'modal',
|
||||
}
|
||||
);
|
||||
|
||||
@@ -85,17 +89,17 @@ MyHeaderTestScreen.navigationOptions = ({ navigation }) => {
|
||||
};
|
||||
};
|
||||
|
||||
const ModalStack = StackNavigator(
|
||||
const ModalStack = createStackNavigator(
|
||||
{
|
||||
Home: {
|
||||
screen: MyHomeScreen,
|
||||
},
|
||||
ProfileNavigator: {
|
||||
screen: ProfileNavigator,
|
||||
},
|
||||
HeaderTest: { screen: MyHeaderTestScreen },
|
||||
},
|
||||
{
|
||||
navigationOptions: {
|
||||
header: null,
|
||||
},
|
||||
mode: 'modal',
|
||||
}
|
||||
);
|
||||
|
||||
75
examples/NavigationPlayground/js/MultipleDrawer.js
Normal file
@@ -0,0 +1,75 @@
|
||||
/**
|
||||
* @flow
|
||||
*/
|
||||
|
||||
import React from 'react';
|
||||
import { Platform, ScrollView, StyleSheet } from 'react-native';
|
||||
import { createDrawerNavigator } from 'react-navigation';
|
||||
import MaterialIcons from 'react-native-vector-icons/MaterialIcons';
|
||||
import SampleText from './SampleText';
|
||||
import { Button } from './commonComponents/ButtonWithMargin';
|
||||
|
||||
const MyNavScreen = ({ navigation, banner }) => (
|
||||
<ScrollView style={styles.container}>
|
||||
<SampleText>{banner}</SampleText>
|
||||
<Button onPress={() => navigation.openDrawer()} title="Open drawer" />
|
||||
<Button onPress={() => navigation.goBack(null)} title="Go back" />
|
||||
</ScrollView>
|
||||
);
|
||||
|
||||
const InboxScreen = ({ navigation }) => (
|
||||
<MyNavScreen banner={'Inbox Screen'} navigation={navigation} />
|
||||
);
|
||||
InboxScreen.navigationOptions = {
|
||||
drawerLabel: 'Inbox',
|
||||
drawerIcon: ({ tintColor }) => (
|
||||
<MaterialIcons
|
||||
name="move-to-inbox"
|
||||
size={24}
|
||||
style={{ color: tintColor }}
|
||||
/>
|
||||
),
|
||||
};
|
||||
|
||||
const DraftsScreen = ({ navigation }) => (
|
||||
<MyNavScreen banner={'Drafts Screen'} navigation={navigation} />
|
||||
);
|
||||
DraftsScreen.navigationOptions = {
|
||||
drawerLabel: 'Drafts',
|
||||
drawerIcon: ({ tintColor }) => (
|
||||
<MaterialIcons name="drafts" size={24} style={{ color: tintColor }} />
|
||||
),
|
||||
};
|
||||
|
||||
const DrawerExample = createDrawerNavigator(
|
||||
{
|
||||
Inbox: {
|
||||
path: '/',
|
||||
screen: InboxScreen,
|
||||
},
|
||||
Drafts: {
|
||||
path: '/sent',
|
||||
screen: DraftsScreen,
|
||||
},
|
||||
},
|
||||
{
|
||||
initialRouteName: 'Drafts',
|
||||
contentOptions: {
|
||||
activeTintColor: '#e91e63',
|
||||
},
|
||||
}
|
||||
);
|
||||
|
||||
const MainDrawerExample = createDrawerNavigator({
|
||||
Drafts: {
|
||||
screen: DrawerExample,
|
||||
},
|
||||
});
|
||||
|
||||
const styles = StyleSheet.create({
|
||||
container: {
|
||||
marginTop: Platform.OS === 'ios' ? 20 : 0,
|
||||
},
|
||||
});
|
||||
|
||||
export default MainDrawerExample;
|
||||
@@ -2,48 +2,209 @@
|
||||
* @flow
|
||||
*/
|
||||
|
||||
import React from 'react';
|
||||
import { Button, ScrollView } from 'react-native';
|
||||
import { StackNavigator, SafeAreaView } from 'react-navigation';
|
||||
import type {
|
||||
NavigationScreenProp,
|
||||
NavigationState,
|
||||
NavigationStateRoute,
|
||||
NavigationEventSubscription,
|
||||
} from 'react-navigation';
|
||||
|
||||
import * as React from 'react';
|
||||
import { ScrollView, StatusBar } from 'react-native';
|
||||
import {
|
||||
createStackNavigator,
|
||||
SafeAreaView,
|
||||
withNavigation,
|
||||
NavigationActions,
|
||||
StackActions,
|
||||
} from 'react-navigation';
|
||||
import invariant from 'invariant';
|
||||
|
||||
import SampleText from './SampleText';
|
||||
import { Button } from './commonComponents/ButtonWithMargin';
|
||||
import { HeaderButtons } from './commonComponents/HeaderButtons';
|
||||
|
||||
const MyNavScreen = ({ navigation, banner }) => (
|
||||
<SafeAreaView>
|
||||
<SampleText>{banner}</SampleText>
|
||||
<Button
|
||||
onPress={() => navigation.navigate('Profile', { name: 'Jane' })}
|
||||
title="Go to a profile screen"
|
||||
/>
|
||||
<Button
|
||||
onPress={() => navigation.navigate('Photos', { name: 'Jane' })}
|
||||
title="Go to a photos screen"
|
||||
/>
|
||||
<Button onPress={() => navigation.goBack(null)} title="Go back" />
|
||||
</SafeAreaView>
|
||||
);
|
||||
|
||||
const MyHomeScreen = ({ navigation }) => (
|
||||
<MyNavScreen banner="Home Screen" navigation={navigation} />
|
||||
);
|
||||
MyHomeScreen.navigationOptions = {
|
||||
title: 'Welcome',
|
||||
type MyNavScreenProps = {
|
||||
navigation: NavigationScreenProp<NavigationState>,
|
||||
banner: React.Node,
|
||||
};
|
||||
|
||||
const MyPhotosScreen = ({ navigation }) => (
|
||||
<MyNavScreen
|
||||
banner={`${navigation.state.params.name}'s Photos`}
|
||||
navigation={navigation}
|
||||
/>
|
||||
);
|
||||
MyPhotosScreen.navigationOptions = {
|
||||
title: 'Photos',
|
||||
type BackButtonProps = {
|
||||
navigation: NavigationScreenProp<NavigationStateRoute>,
|
||||
};
|
||||
|
||||
class MyBackButton extends React.Component<BackButtonProps, any> {
|
||||
render() {
|
||||
return (
|
||||
<HeaderButtons>
|
||||
<HeaderButtons.Item title="Back" onPress={this._navigateBack} />
|
||||
</HeaderButtons>
|
||||
);
|
||||
}
|
||||
|
||||
_navigateBack = () => {
|
||||
this.props.navigation.goBack(null);
|
||||
};
|
||||
}
|
||||
|
||||
const MyBackButtonWithNavigation = withNavigation(MyBackButton);
|
||||
|
||||
class MyNavScreen extends React.Component<MyNavScreenProps> {
|
||||
render() {
|
||||
const { navigation, banner } = this.props;
|
||||
const { push, replace, popToTop, pop, dismiss } = navigation;
|
||||
invariant(
|
||||
push && replace && popToTop && pop && dismiss,
|
||||
'missing action creators for StackNavigator'
|
||||
);
|
||||
return (
|
||||
<SafeAreaView>
|
||||
<SampleText>{banner}</SampleText>
|
||||
<Button
|
||||
onPress={() => push('Profile', { name: 'Jane' })}
|
||||
title="Push a profile screen"
|
||||
/>
|
||||
<Button
|
||||
onPress={() =>
|
||||
navigation.dispatch(
|
||||
StackActions.reset({
|
||||
index: 0,
|
||||
actions: [
|
||||
NavigationActions.navigate({
|
||||
routeName: 'Photos',
|
||||
params: { name: 'Jane' },
|
||||
}),
|
||||
],
|
||||
})
|
||||
)
|
||||
}
|
||||
title="Reset photos"
|
||||
/>
|
||||
<Button
|
||||
onPress={() => navigation.navigate('Photos', { name: 'Jane' })}
|
||||
title="Navigate to a photos screen"
|
||||
/>
|
||||
<Button
|
||||
onPress={() => replace('Profile', { name: 'Lucy' })}
|
||||
title="Replace with profile"
|
||||
/>
|
||||
<Button onPress={() => popToTop()} title="Pop to top" />
|
||||
<Button onPress={() => pop()} title="Pop" />
|
||||
<Button
|
||||
onPress={() => {
|
||||
if (navigation.goBack()) {
|
||||
console.log('goBack handled');
|
||||
} else {
|
||||
console.log('goBack unhandled');
|
||||
}
|
||||
}}
|
||||
title="Go back"
|
||||
/>
|
||||
<Button onPress={() => dismiss()} title="Dismiss" />
|
||||
<StatusBar barStyle="default" />
|
||||
</SafeAreaView>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
type MyHomeScreenProps = {
|
||||
navigation: NavigationScreenProp<NavigationState>,
|
||||
};
|
||||
|
||||
class MyHomeScreen extends React.Component<MyHomeScreenProps> {
|
||||
static navigationOptions = {
|
||||
title: 'Welcome',
|
||||
};
|
||||
_s0: NavigationEventSubscription;
|
||||
_s1: NavigationEventSubscription;
|
||||
_s2: NavigationEventSubscription;
|
||||
_s3: NavigationEventSubscription;
|
||||
|
||||
componentDidMount() {
|
||||
this._s0 = this.props.navigation.addListener('willFocus', this._onWF);
|
||||
this._s1 = this.props.navigation.addListener('didFocus', this._onDF);
|
||||
this._s2 = this.props.navigation.addListener('willBlur', this._onWB);
|
||||
this._s3 = this.props.navigation.addListener('didBlur', this._onDB);
|
||||
}
|
||||
componentWillUnmount() {
|
||||
this._s0.remove();
|
||||
this._s1.remove();
|
||||
this._s2.remove();
|
||||
this._s3.remove();
|
||||
}
|
||||
_onWF = a => {
|
||||
console.log('_willFocus HomeScreen', a);
|
||||
};
|
||||
_onDF = a => {
|
||||
console.log('_didFocus HomeScreen', a);
|
||||
};
|
||||
_onWB = a => {
|
||||
console.log('_willBlur HomeScreen', a);
|
||||
};
|
||||
_onDB = a => {
|
||||
console.log('_didBlur HomeScreen', a);
|
||||
};
|
||||
|
||||
render() {
|
||||
const { navigation } = this.props;
|
||||
return <MyNavScreen banner="Home Screen" navigation={navigation} />;
|
||||
}
|
||||
}
|
||||
|
||||
type MyPhotosScreenProps = {
|
||||
navigation: NavigationScreenProp<NavigationState>,
|
||||
};
|
||||
class MyPhotosScreen extends React.Component<MyPhotosScreenProps> {
|
||||
static navigationOptions = {
|
||||
title: 'Photos',
|
||||
headerLeft: <MyBackButtonWithNavigation />,
|
||||
};
|
||||
_s0: NavigationEventSubscription;
|
||||
_s1: NavigationEventSubscription;
|
||||
_s2: NavigationEventSubscription;
|
||||
_s3: NavigationEventSubscription;
|
||||
|
||||
componentDidMount() {
|
||||
this._s0 = this.props.navigation.addListener('willFocus', this._onWF);
|
||||
this._s1 = this.props.navigation.addListener('didFocus', this._onDF);
|
||||
this._s2 = this.props.navigation.addListener('willBlur', this._onWB);
|
||||
this._s3 = this.props.navigation.addListener('didBlur', this._onDB);
|
||||
}
|
||||
componentWillUnmount() {
|
||||
this._s0.remove();
|
||||
this._s1.remove();
|
||||
this._s2.remove();
|
||||
this._s3.remove();
|
||||
}
|
||||
_onWF = a => {
|
||||
console.log('_willFocus PhotosScreen', a);
|
||||
};
|
||||
_onDF = a => {
|
||||
console.log('_didFocus PhotosScreen', a);
|
||||
};
|
||||
_onWB = a => {
|
||||
console.log('_willBlur PhotosScreen', a);
|
||||
};
|
||||
_onDB = a => {
|
||||
console.log('_didBlur PhotosScreen', a);
|
||||
};
|
||||
|
||||
render() {
|
||||
const { navigation } = this.props;
|
||||
return (
|
||||
<MyNavScreen
|
||||
banner={`${navigation.getParam('name')}'s Photos`}
|
||||
navigation={navigation}
|
||||
/>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
const MyProfileScreen = ({ navigation }) => (
|
||||
<MyNavScreen
|
||||
banner={`${navigation.state.params.mode === 'edit'
|
||||
? 'Now Editing '
|
||||
: ''}${navigation.state.params.name}'s Profile`}
|
||||
banner={`${
|
||||
navigation.getParam('mode') === 'edit' ? 'Now Editing ' : ''
|
||||
}${navigation.getParam('name')}'s Profile`}
|
||||
navigation={navigation}
|
||||
/>
|
||||
);
|
||||
@@ -53,20 +214,24 @@ MyProfileScreen.navigationOptions = props => {
|
||||
const { state, setParams } = navigation;
|
||||
const { params } = state;
|
||||
return {
|
||||
headerBackImage: params.headerBackImage,
|
||||
headerTitle: `${params.name}'s Profile!`,
|
||||
// Render a button on the right side of the header.
|
||||
// When pressed switches the screen to edit mode.
|
||||
headerRight: (
|
||||
<Button
|
||||
title={params.mode === 'edit' ? 'Done' : 'Edit'}
|
||||
onPress={() =>
|
||||
setParams({ mode: params.mode === 'edit' ? '' : 'edit' })}
|
||||
/>
|
||||
<HeaderButtons>
|
||||
<HeaderButtons.Item
|
||||
title={params.mode === 'edit' ? 'Done' : 'Edit'}
|
||||
onPress={() =>
|
||||
setParams({ mode: params.mode === 'edit' ? '' : 'edit' })
|
||||
}
|
||||
/>
|
||||
</HeaderButtons>
|
||||
),
|
||||
};
|
||||
};
|
||||
|
||||
const SimpleStack = StackNavigator({
|
||||
const SimpleStack = createStackNavigator({
|
||||
Home: {
|
||||
screen: MyHomeScreen,
|
||||
},
|
||||
|
||||
@@ -2,11 +2,17 @@
|
||||
* @flow
|
||||
*/
|
||||
|
||||
import type {
|
||||
NavigationScreenProp,
|
||||
NavigationEventSubscription,
|
||||
} from 'react-navigation';
|
||||
|
||||
import React from 'react';
|
||||
import { Button, Platform, ScrollView, View } from 'react-native';
|
||||
import { SafeAreaView, TabNavigator } from 'react-navigation';
|
||||
import { Platform, ScrollView, StatusBar, View } from 'react-native';
|
||||
import { SafeAreaView, createBottomTabNavigator } from 'react-navigation';
|
||||
import Ionicons from 'react-native-vector-icons/Ionicons';
|
||||
import SampleText from './SampleText';
|
||||
import { Button } from './commonComponents/ButtonWithMargin';
|
||||
|
||||
const MyNavScreen = ({ navigation, banner }) => (
|
||||
<SafeAreaView forceInset={{ horizontal: 'always', top: 'always' }}>
|
||||
@@ -20,6 +26,7 @@ const MyNavScreen = ({ navigation, banner }) => (
|
||||
title="Go to settings tab"
|
||||
/>
|
||||
<Button onPress={() => navigation.goBack(null)} title="Go back" />
|
||||
<StatusBar barStyle="default" />
|
||||
</SafeAreaView>
|
||||
);
|
||||
|
||||
@@ -42,35 +49,85 @@ MyHomeScreen.navigationOptions = {
|
||||
),
|
||||
};
|
||||
|
||||
const MyPeopleScreen = ({ navigation }) => (
|
||||
<MyNavScreen banner="People Tab" navigation={navigation} />
|
||||
);
|
||||
|
||||
MyPeopleScreen.navigationOptions = {
|
||||
tabBarLabel: 'People',
|
||||
tabBarIcon: ({ tintColor, focused }) => (
|
||||
<Ionicons
|
||||
name={focused ? 'ios-people' : 'ios-people-outline'}
|
||||
size={26}
|
||||
style={{ color: tintColor }}
|
||||
/>
|
||||
),
|
||||
type MyPeopleScreenProps = {
|
||||
navigation: NavigationScreenProp<*>,
|
||||
};
|
||||
class MyPeopleScreen extends React.Component<MyPeopleScreenProps> {
|
||||
_s0: NavigationEventSubscription;
|
||||
_s1: NavigationEventSubscription;
|
||||
_s2: NavigationEventSubscription;
|
||||
_s3: NavigationEventSubscription;
|
||||
|
||||
const MyChatScreen = ({ navigation }) => (
|
||||
<MyNavScreen banner="Chat Tab" navigation={navigation} />
|
||||
);
|
||||
static navigationOptions = {
|
||||
tabBarLabel: 'People',
|
||||
tabBarIcon: ({ tintColor, focused }) => (
|
||||
<Ionicons
|
||||
name={focused ? 'ios-people' : 'ios-people-outline'}
|
||||
size={26}
|
||||
style={{ color: tintColor }}
|
||||
/>
|
||||
),
|
||||
};
|
||||
componentDidMount() {
|
||||
this._s0 = this.props.navigation.addListener('willFocus', this._onEvent);
|
||||
this._s1 = this.props.navigation.addListener('didFocus', this._onEvent);
|
||||
this._s2 = this.props.navigation.addListener('willBlur', this._onEvent);
|
||||
this._s3 = this.props.navigation.addListener('didBlur', this._onEvent);
|
||||
}
|
||||
componentWillUnmount() {
|
||||
this._s0.remove();
|
||||
this._s1.remove();
|
||||
this._s2.remove();
|
||||
this._s3.remove();
|
||||
}
|
||||
_onEvent = a => {
|
||||
console.log('EVENT ON PEOPLE TAB', a.type, a);
|
||||
};
|
||||
render() {
|
||||
const { navigation } = this.props;
|
||||
return <MyNavScreen banner="People Tab" navigation={navigation} />;
|
||||
}
|
||||
}
|
||||
|
||||
MyChatScreen.navigationOptions = {
|
||||
tabBarLabel: 'Chat',
|
||||
tabBarIcon: ({ tintColor, focused }) => (
|
||||
<Ionicons
|
||||
name={focused ? 'ios-chatboxes' : 'ios-chatboxes-outline'}
|
||||
size={26}
|
||||
style={{ color: tintColor }}
|
||||
/>
|
||||
),
|
||||
type MyChatScreenProps = {
|
||||
navigation: NavigationScreenProp<*>,
|
||||
};
|
||||
class MyChatScreen extends React.Component<MyChatScreenProps> {
|
||||
_s0: NavigationEventSubscription;
|
||||
_s1: NavigationEventSubscription;
|
||||
_s2: NavigationEventSubscription;
|
||||
_s3: NavigationEventSubscription;
|
||||
|
||||
static navigationOptions = {
|
||||
tabBarLabel: 'Chat',
|
||||
tabBarIcon: ({ tintColor, focused }) => (
|
||||
<Ionicons
|
||||
name={focused ? 'ios-chatboxes' : 'ios-chatboxes-outline'}
|
||||
size={26}
|
||||
style={{ color: tintColor }}
|
||||
/>
|
||||
),
|
||||
};
|
||||
componentDidMount() {
|
||||
this._s0 = this.props.navigation.addListener('willFocus', this._onEvent);
|
||||
this._s1 = this.props.navigation.addListener('didFocus', this._onEvent);
|
||||
this._s2 = this.props.navigation.addListener('willBlur', this._onEvent);
|
||||
this._s3 = this.props.navigation.addListener('didBlur', this._onEvent);
|
||||
}
|
||||
componentWillUnmount() {
|
||||
this._s0.remove();
|
||||
this._s1.remove();
|
||||
this._s2.remove();
|
||||
this._s3.remove();
|
||||
}
|
||||
_onEvent = a => {
|
||||
console.log('EVENT ON CHAT TAB', a.type, a);
|
||||
};
|
||||
render() {
|
||||
const { navigation } = this.props;
|
||||
return <MyNavScreen banner="Chat Tab" navigation={navigation} />;
|
||||
}
|
||||
}
|
||||
|
||||
const MySettingsScreen = ({ navigation }) => (
|
||||
<MyNavScreen banner="Settings Tab" navigation={navigation} />
|
||||
@@ -87,7 +144,7 @@ MySettingsScreen.navigationOptions = {
|
||||
),
|
||||
};
|
||||
|
||||
const SimpleTabs = TabNavigator(
|
||||
const SimpleTabs = createBottomTabNavigator(
|
||||
{
|
||||
Home: {
|
||||
screen: MyHomeScreen,
|
||||
@@ -108,9 +165,40 @@ const SimpleTabs = TabNavigator(
|
||||
},
|
||||
{
|
||||
tabBarOptions: {
|
||||
activeTintColor: Platform.OS === 'ios' ? '#e91e63' : '#fff',
|
||||
activeTintColor: '#e91e63',
|
||||
},
|
||||
}
|
||||
);
|
||||
|
||||
export default SimpleTabs;
|
||||
type SimpleTabsContainerProps = {
|
||||
navigation: NavigationScreenProp<*>,
|
||||
};
|
||||
|
||||
class SimpleTabsContainer extends React.Component<SimpleTabsContainerProps> {
|
||||
static router = SimpleTabs.router;
|
||||
_s0: NavigationEventSubscription;
|
||||
_s1: NavigationEventSubscription;
|
||||
_s2: NavigationEventSubscription;
|
||||
_s3: NavigationEventSubscription;
|
||||
|
||||
componentDidMount() {
|
||||
this._s0 = this.props.navigation.addListener('willFocus', this._onAction);
|
||||
this._s1 = this.props.navigation.addListener('didFocus', this._onAction);
|
||||
this._s2 = this.props.navigation.addListener('willBlur', this._onAction);
|
||||
this._s3 = this.props.navigation.addListener('didBlur', this._onAction);
|
||||
}
|
||||
componentWillUnmount() {
|
||||
this._s0.remove();
|
||||
this._s1.remove();
|
||||
this._s2.remove();
|
||||
this._s3.remove();
|
||||
}
|
||||
_onAction = a => {
|
||||
console.log('TABS EVENT', a.type, a);
|
||||
};
|
||||
render() {
|
||||
return <SimpleTabs navigation={this.props.navigation} />;
|
||||
}
|
||||
}
|
||||
|
||||
export default SimpleTabsContainer;
|
||||
|
||||
@@ -0,0 +1,145 @@
|
||||
/**
|
||||
* @flow
|
||||
*/
|
||||
|
||||
import type { NavigationScreenProp } from 'react-navigation';
|
||||
|
||||
import * as React from 'react';
|
||||
import { Image, Button, StatusBar, StyleSheet } from 'react-native';
|
||||
import { createStackNavigator, SafeAreaView } from 'react-navigation';
|
||||
import SampleText from './SampleText';
|
||||
|
||||
type MyNavScreenProps = {
|
||||
navigation: NavigationScreenProp<*>,
|
||||
banner: React.Node,
|
||||
};
|
||||
|
||||
class MyCustomHeaderBackImage extends React.Component<any, any> {
|
||||
render() {
|
||||
const source = require('./assets/back.png');
|
||||
return (
|
||||
<Image
|
||||
source={source}
|
||||
style={[styles.myCustomHeaderBackImage, this.props.style]}
|
||||
/>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class MyNavScreen extends React.Component<MyNavScreenProps> {
|
||||
render() {
|
||||
const { navigation, banner } = this.props;
|
||||
return (
|
||||
<SafeAreaView>
|
||||
<SampleText>{banner}</SampleText>
|
||||
<Button
|
||||
onPress={() => navigation.navigate('Photos', { name: 'Jane' })}
|
||||
title="Navigate to a photos screen"
|
||||
/>
|
||||
<Button onPress={() => navigation.goBack(null)} title="Go back" />
|
||||
<StatusBar barStyle="default" />
|
||||
</SafeAreaView>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
type MyHomeScreenProps = {
|
||||
navigation: NavigationScreenProp<*>,
|
||||
};
|
||||
|
||||
class MyHomeScreen extends React.Component<MyHomeScreenProps> {
|
||||
static navigationOptions = {
|
||||
title: 'Welcome',
|
||||
headerBackTitle: null,
|
||||
};
|
||||
|
||||
render() {
|
||||
const { navigation } = this.props;
|
||||
return <MyNavScreen banner="Home Screen" navigation={navigation} />;
|
||||
}
|
||||
}
|
||||
|
||||
type MyPhotosScreenProps = {
|
||||
navigation: NavigationScreenProp<*>,
|
||||
};
|
||||
class MyPhotosScreen extends React.Component<MyPhotosScreenProps> {
|
||||
static navigationOptions = ({ navigation }) => ({
|
||||
title: `${navigation.state.params.name}'s photos`,
|
||||
headerBackTitle: null,
|
||||
});
|
||||
|
||||
render() {
|
||||
const { navigation } = this.props;
|
||||
return (
|
||||
<SafeAreaView>
|
||||
<SampleText>{`${navigation.state.params.name}'s Photos`}</SampleText>
|
||||
<Button
|
||||
onPress={() => navigation.navigate('Profile', { name: 'Jane' })}
|
||||
title="Navigate to a profile screen"
|
||||
/>
|
||||
<Button onPress={() => navigation.goBack(null)} title="Go back" />
|
||||
<StatusBar barStyle="default" />
|
||||
</SafeAreaView>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
type MyProfileScreenProps = {
|
||||
navigation: NavigationScreenProp<*>,
|
||||
};
|
||||
class MyProfileScreen extends React.Component<MyProfileScreenProps> {
|
||||
static navigationOptions = ({ navigation }) => ({
|
||||
title: 'Profile',
|
||||
headerBackImage: (
|
||||
<MyCustomHeaderBackImage style={styles.myCustomHeaderBackImageAlt} />
|
||||
),
|
||||
});
|
||||
|
||||
render() {
|
||||
const { navigation } = this.props;
|
||||
return (
|
||||
<SafeAreaView>
|
||||
<SampleText>{`${navigation.state.params.name}'s Profile`}</SampleText>
|
||||
<Button onPress={() => navigation.goBack(null)} title="Go back" />
|
||||
<StatusBar barStyle="default" />
|
||||
</SafeAreaView>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
const StackWithCustomHeaderBackImage = createStackNavigator(
|
||||
{
|
||||
Home: {
|
||||
screen: MyHomeScreen,
|
||||
},
|
||||
Photos: {
|
||||
path: 'photos/:name',
|
||||
screen: MyPhotosScreen,
|
||||
},
|
||||
Profile: {
|
||||
path: 'profile/:name',
|
||||
screen: MyProfileScreen,
|
||||
},
|
||||
},
|
||||
{
|
||||
navigationOptions: {
|
||||
headerBackImage: MyCustomHeaderBackImage,
|
||||
},
|
||||
}
|
||||
);
|
||||
|
||||
export default StackWithCustomHeaderBackImage;
|
||||
|
||||
const styles = StyleSheet.create({
|
||||
myCustomHeaderBackImage: {
|
||||
height: 14.5,
|
||||
width: 24,
|
||||
marginLeft: 9,
|
||||
marginRight: 12,
|
||||
marginVertical: 12,
|
||||
resizeMode: 'contain',
|
||||
},
|
||||
myCustomHeaderBackImageAlt: {
|
||||
tintColor: '#f00',
|
||||
},
|
||||
});
|
||||
123
examples/NavigationPlayground/js/StackWithHeaderPreset.js
Normal file
@@ -0,0 +1,123 @@
|
||||
/**
|
||||
* @flow
|
||||
*/
|
||||
import type { NavigationScreenProp } from 'react-navigation';
|
||||
|
||||
import * as React from 'react';
|
||||
import { ScrollView, StatusBar } from 'react-native';
|
||||
import { createStackNavigator, SafeAreaView } from 'react-navigation';
|
||||
import invariant from 'invariant';
|
||||
|
||||
import { Button } from './commonComponents/ButtonWithMargin';
|
||||
|
||||
type NavScreenProps = {
|
||||
navigation: NavigationScreenProp<*>,
|
||||
};
|
||||
|
||||
class HomeScreen extends React.Component<NavScreenProps> {
|
||||
static navigationOptions = {
|
||||
title: 'Welcome',
|
||||
};
|
||||
|
||||
render() {
|
||||
const { navigation } = this.props;
|
||||
const { push } = navigation;
|
||||
invariant(push, 'missing `push` action creator for StackNavigator');
|
||||
|
||||
return (
|
||||
<SafeAreaView style={{ paddingTop: 30 }}>
|
||||
<Button onPress={() => push('Other')} title="Push another screen" />
|
||||
<Button
|
||||
onPress={() => push('ScreenWithNoHeader')}
|
||||
title="Push screen with no header"
|
||||
/>
|
||||
<Button onPress={() => navigation.goBack(null)} title="Go Home" />
|
||||
<StatusBar barStyle="default" />
|
||||
</SafeAreaView>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class OtherScreen extends React.Component<NavScreenProps> {
|
||||
static navigationOptions = {
|
||||
title: 'Your title here',
|
||||
};
|
||||
|
||||
render() {
|
||||
const { navigation } = this.props;
|
||||
const { push, pop } = navigation;
|
||||
invariant(push && pop, 'missing action creators for StackNavigator');
|
||||
|
||||
return (
|
||||
<SafeAreaView style={{ paddingTop: 30 }}>
|
||||
<Button
|
||||
onPress={() => push('ScreenWithLongTitle')}
|
||||
title="Push another screen"
|
||||
/>
|
||||
<Button
|
||||
onPress={() => push('ScreenWithNoHeader')}
|
||||
title="Push screen with no header"
|
||||
/>
|
||||
<Button onPress={() => pop()} title="Pop" />
|
||||
<Button onPress={() => navigation.goBack(null)} title="Go back" />
|
||||
<StatusBar barStyle="default" />
|
||||
</SafeAreaView>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class ScreenWithLongTitle extends React.Component<NavScreenProps> {
|
||||
static navigationOptions = {
|
||||
title: "Another title that's kind of long",
|
||||
};
|
||||
|
||||
render() {
|
||||
const { navigation } = this.props;
|
||||
const { pop } = navigation;
|
||||
invariant(pop, 'missing `pop` action creator for StackNavigator');
|
||||
|
||||
return (
|
||||
<SafeAreaView style={{ paddingTop: 30 }}>
|
||||
<Button onPress={() => pop()} title="Pop" />
|
||||
<Button onPress={() => navigation.goBack(null)} title="Go back" />
|
||||
<StatusBar barStyle="default" />
|
||||
</SafeAreaView>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class ScreenWithNoHeader extends React.Component<NavScreenProps> {
|
||||
static navigationOptions = {
|
||||
header: null,
|
||||
title: 'No Header',
|
||||
};
|
||||
|
||||
render() {
|
||||
const { navigation } = this.props;
|
||||
const { push, pop } = navigation;
|
||||
invariant(push && pop, 'missing action creators for StackNavigator');
|
||||
|
||||
return (
|
||||
<SafeAreaView style={{ paddingTop: 30 }}>
|
||||
<Button onPress={() => push('Other')} title="Push another screen" />
|
||||
<Button onPress={() => pop()} title="Pop" />
|
||||
<Button onPress={() => navigation.goBack(null)} title="Go back" />
|
||||
<StatusBar barStyle="default" />
|
||||
</SafeAreaView>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
const StackWithHeaderPreset = createStackNavigator(
|
||||
{
|
||||
Home: HomeScreen,
|
||||
Other: OtherScreen,
|
||||
ScreenWithNoHeader: ScreenWithNoHeader,
|
||||
ScreenWithLongTitle: ScreenWithLongTitle,
|
||||
},
|
||||
{
|
||||
headerTransitionPreset: 'uikit',
|
||||
}
|
||||
);
|
||||
|
||||
export default StackWithHeaderPreset;
|
||||
244
examples/NavigationPlayground/js/StackWithTranslucentHeader.js
Normal file
@@ -0,0 +1,244 @@
|
||||
/**
|
||||
* @flow
|
||||
*/
|
||||
|
||||
import type {
|
||||
NavigationScreenProp,
|
||||
NavigationEventSubscription,
|
||||
} from 'react-navigation';
|
||||
|
||||
import { isIphoneX } from 'react-native-iphone-x-helper';
|
||||
|
||||
import * as React from 'react';
|
||||
import { BlurView, Constants } from 'expo';
|
||||
import {
|
||||
Dimensions,
|
||||
Platform,
|
||||
ScrollView,
|
||||
StatusBar,
|
||||
View,
|
||||
} from 'react-native';
|
||||
import { Header, createStackNavigator } from 'react-navigation';
|
||||
import invariant from 'invariant';
|
||||
|
||||
import SampleText from './SampleText';
|
||||
import { Button } from './commonComponents/ButtonWithMargin';
|
||||
import { HeaderButtons } from './commonComponents/HeaderButtons';
|
||||
|
||||
type MyNavScreenProps = {
|
||||
navigation: NavigationScreenProp<*>,
|
||||
banner: React.Node,
|
||||
};
|
||||
|
||||
class MyNavScreen extends React.Component<MyNavScreenProps> {
|
||||
render() {
|
||||
const { navigation, banner } = this.props;
|
||||
const { push, replace, popToTop, pop } = navigation;
|
||||
invariant(
|
||||
push && replace && popToTop && pop,
|
||||
'missing action creators for StackNavigator'
|
||||
);
|
||||
return (
|
||||
<ScrollView style={{ flex: 1 }} {...this.getHeaderInset()}>
|
||||
<SampleText>{banner}</SampleText>
|
||||
<Button
|
||||
onPress={() => push('Profile', { name: 'Jane' })}
|
||||
title="Push a profile screen"
|
||||
/>
|
||||
<Button
|
||||
onPress={() => navigation.navigate('Photos', { name: 'Jane' })}
|
||||
title="Navigate to a photos screen"
|
||||
/>
|
||||
<Button
|
||||
onPress={() => replace('Profile', { name: 'Lucy' })}
|
||||
title="Replace with profile"
|
||||
/>
|
||||
<Button onPress={() => popToTop()} title="Pop to top" />
|
||||
<Button onPress={() => pop()} title="Pop" />
|
||||
<Button onPress={() => navigation.goBack(null)} title="Go back" />
|
||||
<StatusBar barStyle="default" />
|
||||
</ScrollView>
|
||||
);
|
||||
}
|
||||
|
||||
// Inset to compensate for navigation bar being transparent.
|
||||
// And improved abstraction for this will be built in to react-navigation
|
||||
// at some point.
|
||||
|
||||
getHeaderInset() {
|
||||
const NOTCH_HEIGHT = isIphoneX() ? 25 : 0;
|
||||
|
||||
// $FlowIgnore: we will remove the HEIGHT static soon enough
|
||||
const BASE_HEADER_HEIGHT = Header.HEIGHT;
|
||||
|
||||
const HEADER_HEIGHT =
|
||||
Platform.OS === 'ios'
|
||||
? BASE_HEADER_HEIGHT + NOTCH_HEIGHT
|
||||
: BASE_HEADER_HEIGHT + Constants.statusBarHeight;
|
||||
|
||||
return Platform.select({
|
||||
ios: {
|
||||
contentInset: { top: HEADER_HEIGHT },
|
||||
contentOffset: { y: -HEADER_HEIGHT },
|
||||
},
|
||||
android: {
|
||||
contentContainerStyle: {
|
||||
paddingTop: HEADER_HEIGHT,
|
||||
},
|
||||
},
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
type MyHomeScreenProps = {
|
||||
navigation: NavigationScreenProp<*>,
|
||||
};
|
||||
|
||||
class MyHomeScreen extends React.Component<MyHomeScreenProps> {
|
||||
static navigationOptions = {
|
||||
title: 'Welcome',
|
||||
};
|
||||
_s0: NavigationEventSubscription;
|
||||
_s1: NavigationEventSubscription;
|
||||
_s2: NavigationEventSubscription;
|
||||
_s3: NavigationEventSubscription;
|
||||
|
||||
componentDidMount() {
|
||||
this._s0 = this.props.navigation.addListener('willFocus', this._onWF);
|
||||
this._s1 = this.props.navigation.addListener('didFocus', this._onDF);
|
||||
this._s2 = this.props.navigation.addListener('willBlur', this._onWB);
|
||||
this._s3 = this.props.navigation.addListener('didBlur', this._onDB);
|
||||
}
|
||||
componentWillUnmount() {
|
||||
this._s0.remove();
|
||||
this._s1.remove();
|
||||
this._s2.remove();
|
||||
this._s3.remove();
|
||||
}
|
||||
_onWF = a => {
|
||||
console.log('_willFocus HomeScreen', a);
|
||||
};
|
||||
_onDF = a => {
|
||||
console.log('_didFocus HomeScreen', a);
|
||||
};
|
||||
_onWB = a => {
|
||||
console.log('_willBlur HomeScreen', a);
|
||||
};
|
||||
_onDB = a => {
|
||||
console.log('_didBlur HomeScreen', a);
|
||||
};
|
||||
|
||||
render() {
|
||||
const { navigation } = this.props;
|
||||
return <MyNavScreen banner="Home Screen" navigation={navigation} />;
|
||||
}
|
||||
}
|
||||
|
||||
type MyPhotosScreenProps = {
|
||||
navigation: NavigationScreenProp<*>,
|
||||
};
|
||||
class MyPhotosScreen extends React.Component<MyPhotosScreenProps> {
|
||||
static navigationOptions = {
|
||||
title: 'Photos',
|
||||
};
|
||||
_s0: NavigationEventSubscription;
|
||||
_s1: NavigationEventSubscription;
|
||||
_s2: NavigationEventSubscription;
|
||||
_s3: NavigationEventSubscription;
|
||||
|
||||
componentDidMount() {
|
||||
this._s0 = this.props.navigation.addListener('willFocus', this._onWF);
|
||||
this._s1 = this.props.navigation.addListener('didFocus', this._onDF);
|
||||
this._s2 = this.props.navigation.addListener('willBlur', this._onWB);
|
||||
this._s3 = this.props.navigation.addListener('didBlur', this._onDB);
|
||||
}
|
||||
componentWillUnmount() {
|
||||
this._s0.remove();
|
||||
this._s1.remove();
|
||||
this._s2.remove();
|
||||
this._s3.remove();
|
||||
}
|
||||
_onWF = a => {
|
||||
console.log('_willFocus PhotosScreen', a);
|
||||
};
|
||||
_onDF = a => {
|
||||
console.log('_didFocus PhotosScreen', a);
|
||||
};
|
||||
_onWB = a => {
|
||||
console.log('_willBlur PhotosScreen', a);
|
||||
};
|
||||
_onDB = a => {
|
||||
console.log('_didBlur PhotosScreen', a);
|
||||
};
|
||||
|
||||
render() {
|
||||
const { navigation } = this.props;
|
||||
return (
|
||||
<MyNavScreen
|
||||
banner={`${navigation.state.params.name}'s Photos`}
|
||||
navigation={navigation}
|
||||
/>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
const MyProfileScreen = ({ navigation }) => (
|
||||
<MyNavScreen
|
||||
banner={`${navigation.state.params.mode === 'edit' ? 'Now Editing ' : ''}${
|
||||
navigation.state.params.name
|
||||
}'s Profile`}
|
||||
navigation={navigation}
|
||||
/>
|
||||
);
|
||||
|
||||
MyProfileScreen.navigationOptions = props => {
|
||||
const { navigation } = props;
|
||||
const { state, setParams } = navigation;
|
||||
const { params } = state;
|
||||
return {
|
||||
headerBackImage: params.headerBackImage,
|
||||
headerTitle: `${params.name}'s Profile!`,
|
||||
// Render a button on the right side of the header.
|
||||
// When pressed switches the screen to edit mode.
|
||||
headerRight: (
|
||||
<HeaderButtons>
|
||||
<HeaderButtons.Item
|
||||
title={params.mode === 'edit' ? 'Done' : 'Edit'}
|
||||
onPress={() =>
|
||||
setParams({ mode: params.mode === 'edit' ? '' : 'edit' })
|
||||
}
|
||||
/>
|
||||
</HeaderButtons>
|
||||
),
|
||||
};
|
||||
};
|
||||
|
||||
const StackWithTranslucentHeader = createStackNavigator(
|
||||
{
|
||||
Home: {
|
||||
screen: MyHomeScreen,
|
||||
},
|
||||
Profile: {
|
||||
path: 'people/:name',
|
||||
screen: MyProfileScreen,
|
||||
},
|
||||
Photos: {
|
||||
path: 'photos/:name',
|
||||
screen: MyPhotosScreen,
|
||||
},
|
||||
},
|
||||
{
|
||||
headerTransitionPreset: 'uikit',
|
||||
navigationOptions: {
|
||||
headerTransparent: true,
|
||||
headerBackground: Platform.select({
|
||||
ios: <BlurView style={{ flex: 1 }} intensity={98} />,
|
||||
android: (
|
||||
<View style={{ flex: 1, backgroundColor: 'rgba(255,255,255,0.7)' }} />
|
||||
),
|
||||
}),
|
||||
},
|
||||
}
|
||||
);
|
||||
|
||||
export default StackWithTranslucentHeader;
|
||||
@@ -3,11 +3,16 @@
|
||||
*/
|
||||
|
||||
import React from 'react';
|
||||
import { Button, ScrollView } from 'react-native';
|
||||
import { SafeAreaView, StackNavigator, TabNavigator } from 'react-navigation';
|
||||
import { ScrollView, StatusBar } from 'react-native';
|
||||
import {
|
||||
SafeAreaView,
|
||||
createStackNavigator,
|
||||
createBottomTabNavigator,
|
||||
} from 'react-navigation';
|
||||
|
||||
import Ionicons from 'react-native-vector-icons/Ionicons';
|
||||
import SampleText from './SampleText';
|
||||
import { Button } from './commonComponents/ButtonWithMargin';
|
||||
|
||||
const MyNavScreen = ({ navigation, banner }) => (
|
||||
<ScrollView>
|
||||
@@ -27,6 +32,8 @@ const MyNavScreen = ({ navigation, banner }) => (
|
||||
/>
|
||||
<Button onPress={() => navigation.goBack(null)} title="Go back" />
|
||||
</SafeAreaView>
|
||||
|
||||
<StatusBar barStyle="default" />
|
||||
</ScrollView>
|
||||
);
|
||||
|
||||
@@ -49,7 +56,7 @@ const MySettingsScreen = ({ navigation }) => (
|
||||
<MyNavScreen banner="Settings Screen" navigation={navigation} />
|
||||
);
|
||||
|
||||
const MainTab = StackNavigator({
|
||||
const MainTab = createStackNavigator({
|
||||
Home: {
|
||||
screen: MyHomeScreen,
|
||||
path: '/',
|
||||
@@ -66,7 +73,7 @@ const MainTab = StackNavigator({
|
||||
},
|
||||
});
|
||||
|
||||
const SettingsTab = StackNavigator({
|
||||
const SettingsTab = createStackNavigator({
|
||||
Settings: {
|
||||
screen: MySettingsScreen,
|
||||
path: '/',
|
||||
@@ -82,7 +89,7 @@ const SettingsTab = StackNavigator({
|
||||
},
|
||||
});
|
||||
|
||||
const StacksInTabs = TabNavigator(
|
||||
const StacksInTabs = createBottomTabNavigator(
|
||||
{
|
||||
MainTab: {
|
||||
screen: MainTab,
|
||||
@@ -114,9 +121,9 @@ const StacksInTabs = TabNavigator(
|
||||
},
|
||||
},
|
||||
{
|
||||
tabBarPosition: 'bottom',
|
||||
animationEnabled: false,
|
||||
swipeEnabled: false,
|
||||
tabBarOptions: {
|
||||
showLabel: false,
|
||||
},
|
||||
}
|
||||
);
|
||||
|
||||
|
||||
@@ -3,11 +3,16 @@
|
||||
*/
|
||||
|
||||
import React from 'react';
|
||||
import { Button, ScrollView } from 'react-native';
|
||||
import { SafeAreaView, StackNavigator, TabNavigator } from 'react-navigation';
|
||||
import { ScrollView, StatusBar } from 'react-native';
|
||||
import {
|
||||
SafeAreaView,
|
||||
createStackNavigator,
|
||||
createBottomTabNavigator,
|
||||
} from 'react-navigation';
|
||||
|
||||
import Ionicons from 'react-native-vector-icons/Ionicons';
|
||||
import SampleText from './SampleText';
|
||||
import { Button } from './commonComponents/ButtonWithMargin';
|
||||
|
||||
const MyNavScreen = ({ navigation, banner }) => (
|
||||
<ScrollView>
|
||||
@@ -27,6 +32,7 @@ const MyNavScreen = ({ navigation, banner }) => (
|
||||
/>
|
||||
<Button onPress={() => navigation.goBack(null)} title="Go back" />
|
||||
</SafeAreaView>
|
||||
<StatusBar barStyle="default" />
|
||||
</ScrollView>
|
||||
);
|
||||
|
||||
@@ -49,7 +55,7 @@ const MySettingsScreen = ({ navigation }) => (
|
||||
<MyNavScreen banner="Settings Screen" navigation={navigation} />
|
||||
);
|
||||
|
||||
const TabNav = TabNavigator(
|
||||
const TabNav = createBottomTabNavigator(
|
||||
{
|
||||
MainTab: {
|
||||
screen: MyHomeScreen,
|
||||
@@ -88,7 +94,20 @@ const TabNav = TabNavigator(
|
||||
}
|
||||
);
|
||||
|
||||
const StacksOverTabs = StackNavigator({
|
||||
TabNav.navigationOptions = ({ navigation }) => {
|
||||
let { routeName } = navigation.state.routes[navigation.state.index];
|
||||
let title;
|
||||
if (routeName === 'SettingsTab') {
|
||||
title = 'Settings';
|
||||
} else if (routeName === 'MainTab') {
|
||||
title = 'Home';
|
||||
}
|
||||
return {
|
||||
title,
|
||||
};
|
||||
};
|
||||
|
||||
const StacksOverTabs = createStackNavigator({
|
||||
Root: {
|
||||
screen: TabNav,
|
||||
},
|
||||
@@ -101,9 +120,9 @@ const StacksOverTabs = StackNavigator({
|
||||
Profile: {
|
||||
screen: MyProfileScreen,
|
||||
path: '/people/:name',
|
||||
navigationOptions: ({ navigation }) => {
|
||||
title: `${navigation.state.params.name}'s Profile!`;
|
||||
},
|
||||
navigationOptions: ({ navigation }) => ({
|
||||
title: `${navigation.state.params.name}'s Profile!`,
|
||||
}),
|
||||
},
|
||||
});
|
||||
|
||||
|
||||
142
examples/NavigationPlayground/js/StacksOverTopTabs.js
Normal file
@@ -0,0 +1,142 @@
|
||||
/**
|
||||
* @flow
|
||||
*/
|
||||
|
||||
import React from 'react';
|
||||
import { View, ScrollView, StatusBar, StyleSheet } from 'react-native';
|
||||
import {
|
||||
SafeAreaView,
|
||||
createStackNavigator,
|
||||
createMaterialTopTabNavigator,
|
||||
} from 'react-navigation';
|
||||
import { Constants } from 'expo';
|
||||
import { MaterialTopTabBar } from 'react-navigation-tabs';
|
||||
|
||||
import SampleText from './SampleText';
|
||||
import { Button } from './commonComponents/ButtonWithMargin';
|
||||
|
||||
const HEADER_HEIGHT = 64;
|
||||
|
||||
const MyNavScreen = ({ navigation, banner, statusBarStyle }) => (
|
||||
<ScrollView>
|
||||
<SafeAreaView forceInset={{ horizontal: 'always' }}>
|
||||
<SampleText>{banner}</SampleText>
|
||||
<Button
|
||||
onPress={() => navigation.navigate('Profile', { name: 'Jordan' })}
|
||||
title="Open profile screen"
|
||||
/>
|
||||
<Button
|
||||
onPress={() => navigation.navigate('NotifSettings')}
|
||||
title="Open notifications screen"
|
||||
/>
|
||||
<Button
|
||||
onPress={() => navigation.navigate('SettingsTab')}
|
||||
title="Go to settings tab"
|
||||
/>
|
||||
<Button onPress={() => navigation.goBack(null)} title="Go back" />
|
||||
</SafeAreaView>
|
||||
<StatusBar barStyle={statusBarStyle || 'default'} />
|
||||
</ScrollView>
|
||||
);
|
||||
|
||||
const MyHomeScreen = ({ navigation }) => (
|
||||
<MyNavScreen
|
||||
banner="Home Screen"
|
||||
navigation={navigation}
|
||||
statusBarStyle="light-content"
|
||||
/>
|
||||
);
|
||||
|
||||
const MyProfileScreen = ({ navigation }) => (
|
||||
<MyNavScreen
|
||||
banner={`${navigation.state.params.name}s Profile`}
|
||||
navigation={navigation}
|
||||
/>
|
||||
);
|
||||
|
||||
const MyNotificationsSettingsScreen = ({ navigation }) => (
|
||||
<MyNavScreen banner="Notifications Screen" navigation={navigation} />
|
||||
);
|
||||
|
||||
const MySettingsScreen = ({ navigation }) => (
|
||||
<MyNavScreen
|
||||
banner="Settings Screen"
|
||||
navigation={navigation}
|
||||
statusBarStyle="light-content"
|
||||
/>
|
||||
);
|
||||
|
||||
const styles = StyleSheet.create({
|
||||
stackHeader: {
|
||||
height: HEADER_HEIGHT,
|
||||
},
|
||||
tab: {
|
||||
height: HEADER_HEIGHT,
|
||||
},
|
||||
});
|
||||
|
||||
function MaterialTopTabBarWithStatusBar(props) {
|
||||
return (
|
||||
<View
|
||||
style={{
|
||||
paddingTop: Constants.statusBarHeight,
|
||||
backgroundColor: '#2196f3',
|
||||
}}
|
||||
>
|
||||
<MaterialTopTabBar {...props} jumpToIndex={() => {}} />
|
||||
</View>
|
||||
);
|
||||
}
|
||||
|
||||
const TabNavigator = createMaterialTopTabNavigator(
|
||||
{
|
||||
MainTab: {
|
||||
screen: MyHomeScreen,
|
||||
navigationOptions: {
|
||||
title: 'Welcome',
|
||||
},
|
||||
},
|
||||
SettingsTab: {
|
||||
screen: MySettingsScreen,
|
||||
navigationOptions: {
|
||||
title: 'Settings',
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
tabBarComponent: MaterialTopTabBarWithStatusBar,
|
||||
tabBarOptions: {
|
||||
tabStyle: styles.tab,
|
||||
},
|
||||
}
|
||||
);
|
||||
|
||||
const StackNavigator = createStackNavigator(
|
||||
{
|
||||
Root: {
|
||||
screen: TabNavigator,
|
||||
navigationOptions: {
|
||||
header: null,
|
||||
},
|
||||
},
|
||||
NotifSettings: {
|
||||
screen: MyNotificationsSettingsScreen,
|
||||
navigationOptions: {
|
||||
title: 'Notifications',
|
||||
},
|
||||
},
|
||||
Profile: {
|
||||
screen: MyProfileScreen,
|
||||
navigationOptions: ({ navigation }) => ({
|
||||
title: `${navigation.state.params.name}'s Profile!`,
|
||||
}),
|
||||
},
|
||||
},
|
||||
{
|
||||
navigationOptions: {
|
||||
headerStyle: styles.stackHeader,
|
||||
},
|
||||
}
|
||||
);
|
||||
|
||||
export default StackNavigator;
|
||||
102
examples/NavigationPlayground/js/StacksWithKeys.js
Normal file
@@ -0,0 +1,102 @@
|
||||
import React from 'react';
|
||||
import { StatusBar, Text, View } from 'react-native';
|
||||
import { createStackNavigator } from 'react-navigation';
|
||||
import { Button } from './commonComponents/ButtonWithMargin';
|
||||
|
||||
class HomeScreen extends React.Component<any, any> {
|
||||
render() {
|
||||
return (
|
||||
<View style={{ flex: 1, alignItems: 'center', justifyContent: 'center' }}>
|
||||
<Text>Home</Text>
|
||||
<Button
|
||||
title="Navigate to 'Profile' with key 'A'"
|
||||
onPress={() =>
|
||||
this.props.navigation.navigate({
|
||||
routeName: 'Profile',
|
||||
key: 'A',
|
||||
params: { homeKey: this.props.navigation.state.key },
|
||||
})
|
||||
}
|
||||
/>
|
||||
<Button
|
||||
title="Go back to other examples"
|
||||
onPress={() => this.props.navigation.goBack(null)}
|
||||
/>
|
||||
<StatusBar barStyle="default" />
|
||||
</View>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class ProfileScreen extends React.Component<any, any> {
|
||||
render() {
|
||||
const { homeKey } = this.props.navigation.state.params;
|
||||
return (
|
||||
<View style={{ flex: 1, alignItems: 'center', justifyContent: 'center' }}>
|
||||
<Text>Profile</Text>
|
||||
<Button
|
||||
title="Navigate to 'Settings' with key 'B'"
|
||||
onPress={() =>
|
||||
this.props.navigation.navigate({
|
||||
routeName: 'Settings',
|
||||
key: 'B',
|
||||
params: { homeKey },
|
||||
})
|
||||
}
|
||||
/>
|
||||
<Button
|
||||
title={`Navigate back to 'Home' with key ${homeKey}`}
|
||||
onPress={() =>
|
||||
this.props.navigation.navigate({ routeName: 'Home', key: homeKey })
|
||||
}
|
||||
/>
|
||||
</View>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class SettingsScreen extends React.Component<any, any> {
|
||||
render() {
|
||||
const { homeKey } = this.props.navigation.state.params;
|
||||
|
||||
return (
|
||||
<View style={{ flex: 1, alignItems: 'center', justifyContent: 'center' }}>
|
||||
<Text>Settings</Text>
|
||||
<Button
|
||||
title={`Navigate back to 'Home' with key ${homeKey}`}
|
||||
onPress={() =>
|
||||
this.props.navigation.navigate({ routeName: 'Home', key: homeKey })
|
||||
}
|
||||
/>
|
||||
<Button
|
||||
title="Navigate back to 'Profile' with key 'A'"
|
||||
onPress={() =>
|
||||
this.props.navigation.navigate({
|
||||
routeName: 'Profile',
|
||||
key: 'A',
|
||||
})
|
||||
}
|
||||
/>
|
||||
</View>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
const Stack = createStackNavigator(
|
||||
{
|
||||
Home: {
|
||||
screen: HomeScreen,
|
||||
},
|
||||
Profile: {
|
||||
screen: ProfileScreen,
|
||||
},
|
||||
Settings: {
|
||||
screen: SettingsScreen,
|
||||
},
|
||||
},
|
||||
{
|
||||
headerMode: 'none',
|
||||
}
|
||||
);
|
||||
|
||||
export default Stack;
|
||||
121
examples/NavigationPlayground/js/SwitchWithStacks.js
Normal file
@@ -0,0 +1,121 @@
|
||||
/**
|
||||
* @flow
|
||||
*/
|
||||
|
||||
import React from 'react';
|
||||
import {
|
||||
ActivityIndicator,
|
||||
AsyncStorage,
|
||||
StatusBar,
|
||||
StyleSheet,
|
||||
View,
|
||||
} from 'react-native';
|
||||
import { createStackNavigator, createSwitchNavigator } from 'react-navigation';
|
||||
import { Button } from './commonComponents/ButtonWithMargin';
|
||||
|
||||
class SignInScreen extends React.Component<any, any> {
|
||||
static navigationOptions = {
|
||||
title: 'Please sign in',
|
||||
};
|
||||
|
||||
render() {
|
||||
return (
|
||||
<View style={styles.container}>
|
||||
<Button title="Sign in!" onPress={this._signInAsync} />
|
||||
<Button
|
||||
title="Go back to other examples"
|
||||
onPress={() => this.props.navigation.goBack(null)}
|
||||
/>
|
||||
<StatusBar barStyle="default" />
|
||||
</View>
|
||||
);
|
||||
}
|
||||
|
||||
_signInAsync = async () => {
|
||||
await AsyncStorage.setItem('userToken', 'abc');
|
||||
this.props.navigation.navigate('Home');
|
||||
};
|
||||
}
|
||||
|
||||
class HomeScreen extends React.Component<any, any> {
|
||||
static navigationOptions = {
|
||||
title: 'Welcome to the app!',
|
||||
};
|
||||
|
||||
render() {
|
||||
return (
|
||||
<View style={styles.container}>
|
||||
<Button title="Show me more of the app" onPress={this._showMoreApp} />
|
||||
<Button title="Actually, sign me out :)" onPress={this._signOutAsync} />
|
||||
<StatusBar barStyle="default" />
|
||||
</View>
|
||||
);
|
||||
}
|
||||
|
||||
_showMoreApp = () => {
|
||||
this.props.navigation.navigate('Other');
|
||||
};
|
||||
|
||||
_signOutAsync = async () => {
|
||||
await AsyncStorage.clear();
|
||||
this.props.navigation.navigate('Auth');
|
||||
};
|
||||
}
|
||||
|
||||
class OtherScreen extends React.Component<any, any> {
|
||||
static navigationOptions = {
|
||||
title: 'Lots of features here',
|
||||
};
|
||||
|
||||
render() {
|
||||
return (
|
||||
<View style={styles.container}>
|
||||
<Button title="I'm done, sign me out" onPress={this._signOutAsync} />
|
||||
<StatusBar barStyle="default" />
|
||||
</View>
|
||||
);
|
||||
}
|
||||
|
||||
_signOutAsync = async () => {
|
||||
await AsyncStorage.clear();
|
||||
this.props.navigation.navigate('Auth');
|
||||
};
|
||||
}
|
||||
|
||||
class LoadingScreen extends React.Component<any, any> {
|
||||
componentDidMount() {
|
||||
this._bootstrapAsync();
|
||||
}
|
||||
|
||||
_bootstrapAsync = async () => {
|
||||
const userToken = await AsyncStorage.getItem('userToken');
|
||||
let initialRouteName = userToken ? 'App' : 'Auth';
|
||||
this.props.navigation.navigate(initialRouteName);
|
||||
};
|
||||
|
||||
render() {
|
||||
return (
|
||||
<View style={styles.container}>
|
||||
<ActivityIndicator />
|
||||
<StatusBar barStyle="default" />
|
||||
</View>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
const styles = StyleSheet.create({
|
||||
container: {
|
||||
flex: 1,
|
||||
alignItems: 'center',
|
||||
justifyContent: 'center',
|
||||
},
|
||||
});
|
||||
|
||||
const AppStack = createStackNavigator({ Home: HomeScreen, Other: OtherScreen });
|
||||
const AuthStack = createStackNavigator({ SignIn: SignInScreen });
|
||||
|
||||
export default createSwitchNavigator({
|
||||
Loading: LoadingScreen,
|
||||
App: AppStack,
|
||||
Auth: AuthStack,
|
||||
});
|
||||
@@ -3,13 +3,13 @@
|
||||
*/
|
||||
|
||||
import React from 'react';
|
||||
import { Button, Platform, ScrollView } from 'react-native';
|
||||
import { TabNavigator, DrawerNavigator } from 'react-navigation';
|
||||
import { Platform, ScrollView } from 'react-native';
|
||||
import { createDrawerNavigator } from 'react-navigation';
|
||||
import MaterialIcons from 'react-native-vector-icons/MaterialIcons';
|
||||
import SimpleTabs from './SimpleTabs';
|
||||
import StacksOverTabs from './StacksOverTabs';
|
||||
|
||||
const TabsInDrawer = DrawerNavigator({
|
||||
const TabsInDrawer = createDrawerNavigator({
|
||||
SimpleTabs: {
|
||||
screen: SimpleTabs,
|
||||
navigationOptions: {
|
||||
|
||||
103
examples/NavigationPlayground/js/TabsWithNavigationFocus.js
Normal file
@@ -0,0 +1,103 @@
|
||||
/**
|
||||
* @flow
|
||||
*/
|
||||
|
||||
import React from 'react';
|
||||
import { SafeAreaView, StatusBar, Text, View } from 'react-native';
|
||||
import { withNavigationFocus } from 'react-navigation';
|
||||
import { createMaterialBottomTabNavigator } from 'react-navigation-material-bottom-tabs';
|
||||
import MaterialCommunityIcons from 'react-native-vector-icons/MaterialCommunityIcons';
|
||||
import { Button } from './commonComponents/ButtonWithMargin';
|
||||
|
||||
import SampleText from './SampleText';
|
||||
|
||||
class Child extends React.Component<any, any> {
|
||||
render() {
|
||||
return (
|
||||
<Text style={{ color: this.props.isFocused ? 'green' : 'maroon' }}>
|
||||
{this.props.isFocused
|
||||
? 'I know that my parent is focused!'
|
||||
: 'My parent is not focused! :O'}
|
||||
</Text>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
const ChildWithNavigationFocus = withNavigationFocus(Child);
|
||||
|
||||
const createTabScreen = (name, icon, focusedIcon, tintColor = '#673ab7') => {
|
||||
class TabScreen extends React.Component<any, any> {
|
||||
static navigationOptions = {
|
||||
tabBarLabel: name,
|
||||
tabBarIcon: ({ tintColor, focused }) => (
|
||||
<MaterialCommunityIcons
|
||||
name={focused ? focusedIcon : icon}
|
||||
size={26}
|
||||
style={{ color: focused ? tintColor : '#ccc' }}
|
||||
/>
|
||||
),
|
||||
};
|
||||
|
||||
state = { showChild: false };
|
||||
|
||||
render() {
|
||||
const { isFocused } = this.props;
|
||||
|
||||
return (
|
||||
<SafeAreaView
|
||||
forceInset={{ horizontal: 'always', top: 'always' }}
|
||||
style={{
|
||||
flex: 1,
|
||||
alignItems: 'center',
|
||||
justifyContent: 'center',
|
||||
}}
|
||||
>
|
||||
<Text style={{ fontWeight: '700', fontSize: 16, marginBottom: 5 }}>
|
||||
{'Tab ' + name.toLowerCase()}
|
||||
</Text>
|
||||
<Text style={{ marginBottom: 20 }}>
|
||||
{'props.isFocused: ' + (isFocused ? ' true' : 'false')}
|
||||
</Text>
|
||||
{this.state.showChild ? (
|
||||
<ChildWithNavigationFocus />
|
||||
) : (
|
||||
<Button
|
||||
title="Press me"
|
||||
onPress={() => this.setState({ showChild: true })}
|
||||
/>
|
||||
)}
|
||||
<Button
|
||||
onPress={() => this.props.navigation.pop()}
|
||||
title="Back to other examples"
|
||||
/>
|
||||
<StatusBar barStyle="default" />
|
||||
</SafeAreaView>
|
||||
);
|
||||
}
|
||||
}
|
||||
return withNavigationFocus(TabScreen);
|
||||
};
|
||||
|
||||
const TabsWithNavigationFocus = createMaterialBottomTabNavigator(
|
||||
{
|
||||
One: {
|
||||
screen: createTabScreen('One', 'numeric-1-box-outline', 'numeric-1-box'),
|
||||
},
|
||||
Two: {
|
||||
screen: createTabScreen('Two', 'numeric-2-box-outline', 'numeric-2-box'),
|
||||
},
|
||||
Three: {
|
||||
screen: createTabScreen(
|
||||
'Three',
|
||||
'numeric-3-box-outline',
|
||||
'numeric-3-box'
|
||||
),
|
||||
},
|
||||
},
|
||||
{
|
||||
shifting: false,
|
||||
activeTintColor: '#F44336',
|
||||
}
|
||||
);
|
||||
|
||||
export default TabsWithNavigationFocus;
|
||||
BIN
examples/NavigationPlayground/js/assets/back.png
Normal file
|
After Width: | Height: | Size: 2.3 KiB |
BIN
examples/NavigationPlayground/js/assets/dog-back.png
Normal file
|
After Width: | Height: | Size: 7.5 KiB |
@@ -0,0 +1,18 @@
|
||||
import { Button as RNButton, StyleSheet, View, Platform } from 'react-native';
|
||||
import React from 'react';
|
||||
|
||||
export const Button = props => (
|
||||
<View style={styles.margin}>
|
||||
<RNButton {...props} />
|
||||
</View>
|
||||
);
|
||||
|
||||
const styles = StyleSheet.create({
|
||||
margin: {
|
||||
...Platform.select({
|
||||
android: {
|
||||
margin: 10,
|
||||
},
|
||||
}),
|
||||
},
|
||||
});
|
||||
@@ -0,0 +1,16 @@
|
||||
import DefaultHeaderButtons from 'react-navigation-header-buttons';
|
||||
import * as React from 'react';
|
||||
import { Platform } from 'react-native';
|
||||
|
||||
export class HeaderButtons extends React.PureComponent {
|
||||
static Item = DefaultHeaderButtons.Item;
|
||||
|
||||
render() {
|
||||
return (
|
||||
<DefaultHeaderButtons
|
||||
color={Platform.OS === 'ios' ? '#037aff' : 'black'}
|
||||
{...this.props}
|
||||
/>
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -4,27 +4,31 @@
|
||||
"private": true,
|
||||
"main": "./node_modules/react-native-scripts/build/bin/crna-entry.js",
|
||||
"scripts": {
|
||||
"postinstall": "rm -rf node_modules/react-navigation/{node_modules,examples}",
|
||||
"start": "react-native-scripts start",
|
||||
"eject": "react-native-scripts eject",
|
||||
"android": "react-native-scripts android",
|
||||
"ios": "react-native-scripts ios",
|
||||
"test": "node node_modules/jest/bin/jest.js"
|
||||
"test": "flow"
|
||||
},
|
||||
"dependencies": {
|
||||
"expo": "^22.0.0",
|
||||
"react": "16.0.0-beta.5",
|
||||
"react-native": "^0.49.3",
|
||||
"react-navigation": "file:../.."
|
||||
"expo": "^27.0.0",
|
||||
"invariant": "^2.2.4",
|
||||
"react": "16.3.1",
|
||||
"react-native": "^0.55.0",
|
||||
"react-native-iphone-x-helper": "^1.0.2",
|
||||
"react-navigation": "link:../..",
|
||||
"react-navigation-header-buttons": "^0.0.4",
|
||||
"react-navigation-material-bottom-tabs": "0.1.3",
|
||||
"react-navigation-tabs": "^0.5.1"
|
||||
},
|
||||
"devDependencies": {
|
||||
"babel-jest": "^21.0.0",
|
||||
"flow-bin": "0.53.0",
|
||||
"jest": "^21.0.1",
|
||||
"jest-expo": "^22.0.0",
|
||||
"react-addons-test-utils": "16.0.0-alpha.3",
|
||||
"babel-jest": "^22.4.1",
|
||||
"babel-plugin-transform-remove-console": "^6.9.0",
|
||||
"flow-bin": "^0.67.0",
|
||||
"jest": "^22.1.3",
|
||||
"jest-expo": "^26.0.0",
|
||||
"react-native-scripts": "^1.5.0",
|
||||
"react-test-renderer": "16.0.0-alpha.12"
|
||||
"react-test-renderer": "16.3.0-alpha.1"
|
||||
},
|
||||
"jest": {
|
||||
"preset": "jest-expo",
|
||||
|
||||
54
examples/NavigationPlayground/rn-cli.config.js
Normal file
@@ -0,0 +1,54 @@
|
||||
/**
|
||||
* @noflow
|
||||
*/
|
||||
|
||||
const fs = require('fs');
|
||||
const path = require('path');
|
||||
const blacklist = require('metro/src/blacklist');
|
||||
|
||||
module.exports = {
|
||||
getBlacklistRE() {
|
||||
return blacklist([
|
||||
/react\-navigation\/examples\/(?!NavigationPlayground).*/,
|
||||
/react\-navigation\/node_modules\/react-native\/(.*)/,
|
||||
/react\-navigation\/node_modules\/react\/(.*)/,
|
||||
/react\-navigation\/node_modules\/react-native-paper\/(.*)/,
|
||||
/react\-navigation\/node_modules\/@expo\/vector-icons\/(.*)/,
|
||||
]);
|
||||
},
|
||||
extraNodeModules: getNodeModulesForDirectory(path.resolve('.')),
|
||||
};
|
||||
|
||||
function getNodeModulesForDirectory(rootPath) {
|
||||
const nodeModulePath = path.join(rootPath, 'node_modules');
|
||||
const folders = fs.readdirSync(nodeModulePath);
|
||||
return folders.reduce((modules, folderName) => {
|
||||
const folderPath = path.join(nodeModulePath, folderName);
|
||||
if (folderName.startsWith('@')) {
|
||||
const scopedModuleFolders = fs.readdirSync(folderPath);
|
||||
const scopedModules = scopedModuleFolders.reduce(
|
||||
(scopedModules, scopedFolderName) => {
|
||||
scopedModules[
|
||||
`${folderName}/${scopedFolderName}`
|
||||
] = maybeResolveSymlink(path.join(folderPath, scopedFolderName));
|
||||
return scopedModules;
|
||||
},
|
||||
{}
|
||||
);
|
||||
return Object.assign({}, modules, scopedModules);
|
||||
}
|
||||
modules[folderName] = maybeResolveSymlink(folderPath);
|
||||
return modules;
|
||||
}, {});
|
||||
}
|
||||
|
||||
function maybeResolveSymlink(maybeSymlinkPath) {
|
||||
if (fs.lstatSync(maybeSymlinkPath).isSymbolicLink()) {
|
||||
const resolved = path.resolve(
|
||||
path.dirname(maybeSymlinkPath),
|
||||
fs.readlinkSync(maybeSymlinkPath)
|
||||
);
|
||||
return resolved;
|
||||
}
|
||||
return maybeSymlinkPath;
|
||||
}
|
||||
@@ -2,4 +2,4 @@
|
||||
|
||||
## Usage
|
||||
|
||||
Please see the [Contributors Guide](https://github.com/react-community/react-navigation/blob/master/docs/guides/Contributors.md#development) for instructions on running these example apps.
|
||||
Please see the [Contributors Guide](https://reactnavigation.org/docs/contributing.html#run-the-example-app) for instructions on running these example apps.
|
||||
|
||||
@@ -1,22 +1,18 @@
|
||||
/**
|
||||
* @flow
|
||||
*/
|
||||
|
||||
import React from 'react';
|
||||
import { AppRegistry } from 'react-native';
|
||||
import { Provider } from 'react-redux';
|
||||
import { createStore } from 'redux';
|
||||
import { createStore, applyMiddleware } from 'redux';
|
||||
|
||||
import AppReducer from './src/reducers';
|
||||
import AppWithNavigationState from './src/navigators/AppNavigator';
|
||||
import { AppNavigator, middleware } from './src/navigators/AppNavigator';
|
||||
|
||||
const store = createStore(AppReducer, applyMiddleware(middleware));
|
||||
|
||||
class ReduxExampleApp extends React.Component {
|
||||
store = createStore(AppReducer);
|
||||
|
||||
render() {
|
||||
return (
|
||||
<Provider store={this.store}>
|
||||
<AppWithNavigationState />
|
||||
<Provider store={store}>
|
||||
<AppNavigator />
|
||||
</Provider>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -2,4 +2,4 @@
|
||||
|
||||
## Usage
|
||||
|
||||
Please see the [Contributors Guide](https://github.com/react-community/react-navigation/blob/master/docs/guides/Contributors.md#development) for instructions on running these example apps.
|
||||
Please see the [Contributors Guide](https://reactnavigation.org/docs/contributing.html#run-the-example-app) for instructions on running these example apps.
|
||||
|
||||
@@ -12,13 +12,10 @@
|
||||
"icon": "./assets/icons/react-navigation.png",
|
||||
"hideExponentText": false
|
||||
},
|
||||
"sdkVersion": "22.0.0",
|
||||
"sdkVersion": "27.0.0",
|
||||
"entryPoint": "./node_modules/react-native-scripts/build/bin/crna-entry.js",
|
||||
"packagerOpts": {
|
||||
"assetExts": [
|
||||
"ttf",
|
||||
"mp4"
|
||||
]
|
||||
"assetExts": ["ttf", "mp4"]
|
||||
},
|
||||
"ios": {
|
||||
"supportsTablet": true
|
||||
|
||||
|
Before Width: | Height: | Size: 13 KiB After Width: | Height: | Size: 20 KiB |
@@ -4,7 +4,6 @@
|
||||
"private": true,
|
||||
"main": "./node_modules/react-native-scripts/build/bin/crna-entry.js",
|
||||
"scripts": {
|
||||
"postinstall": "rm -rf node_modules/react-navigation/{node_modules,examples}",
|
||||
"start": "react-native-scripts start",
|
||||
"eject": "react-native-scripts eject",
|
||||
"android": "react-native-scripts android",
|
||||
@@ -22,19 +21,21 @@
|
||||
]
|
||||
},
|
||||
"dependencies": {
|
||||
"expo": "^22.0.0",
|
||||
"expo": "^27.0.0",
|
||||
"prop-types": "^15.5.10",
|
||||
"react": "16.0.0-beta.5",
|
||||
"react-native": "^0.49.3",
|
||||
"react": "16.3.1",
|
||||
"react-native": "^0.55.0",
|
||||
"react-navigation": "link:../..",
|
||||
"react-navigation-redux-helpers": "^2.0.0-beta.1",
|
||||
"react-redux": "^5.0.6",
|
||||
"redux": "^3.7.2"
|
||||
},
|
||||
"devDependencies": {
|
||||
"babel-jest": "^21.0.0",
|
||||
"jest": "^21.0.1",
|
||||
"jest-expo": "^22.0.0",
|
||||
"babel-jest": "^22.4.1",
|
||||
"flow-bin": "^0.74.0",
|
||||
"jest": "^22.1.3",
|
||||
"jest-expo": "^25.1.0",
|
||||
"react-native-scripts": "^1.3.1",
|
||||
"react-navigation": "file:../..",
|
||||
"react-test-renderer": "16.0.0-alpha.12"
|
||||
"react-test-renderer": "16.0.0"
|
||||
}
|
||||
}
|
||||
|
||||
52
examples/ReduxExample/rn-cli.config.js
Normal file
@@ -0,0 +1,52 @@
|
||||
/**
|
||||
* @noflow
|
||||
*/
|
||||
|
||||
const fs = require('fs');
|
||||
const path = require('path');
|
||||
const blacklist = require('metro/src/blacklist');
|
||||
|
||||
module.exports = {
|
||||
getBlacklistRE() {
|
||||
return blacklist([
|
||||
/react\-navigation\/examples\/(?!ReduxExample).*/,
|
||||
/react\-navigation\/node_modules\/react-native\/(.*)/,
|
||||
/react\-navigation\/node_modules\/react\/(.*)/
|
||||
]);
|
||||
},
|
||||
extraNodeModules: getNodeModulesForDirectory(path.resolve('.')),
|
||||
};
|
||||
|
||||
function getNodeModulesForDirectory(rootPath) {
|
||||
const nodeModulePath = path.join(rootPath, 'node_modules');
|
||||
const folders = fs.readdirSync(nodeModulePath);
|
||||
return folders.reduce((modules, folderName) => {
|
||||
const folderPath = path.join(nodeModulePath, folderName);
|
||||
if (folderName.startsWith('@')) {
|
||||
const scopedModuleFolders = fs.readdirSync(folderPath);
|
||||
const scopedModules = scopedModuleFolders.reduce(
|
||||
(scopedModules, scopedFolderName) => {
|
||||
scopedModules[
|
||||
`${folderName}/${scopedFolderName}`
|
||||
] = maybeResolveSymlink(path.join(folderPath, scopedFolderName));
|
||||
return scopedModules;
|
||||
},
|
||||
{}
|
||||
);
|
||||
return Object.assign({}, modules, scopedModules);
|
||||
}
|
||||
modules[folderName] = maybeResolveSymlink(folderPath);
|
||||
return modules;
|
||||
}, {});
|
||||
}
|
||||
|
||||
function maybeResolveSymlink(maybeSymlinkPath) {
|
||||
if (fs.lstatSync(maybeSymlinkPath).isSymbolicLink()) {
|
||||
const resolved = path.resolve(
|
||||
path.dirname(maybeSymlinkPath),
|
||||
fs.readlinkSync(maybeSymlinkPath)
|
||||
);
|
||||
return resolved;
|
||||
}
|
||||
return maybeSymlinkPath;
|
||||
}
|
||||
@@ -1,29 +1,33 @@
|
||||
import React from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import { connect } from 'react-redux';
|
||||
import { addNavigationHelpers, StackNavigator } from 'react-navigation';
|
||||
import { createStackNavigator } from 'react-navigation';
|
||||
import {
|
||||
reduxifyNavigator,
|
||||
createReactNavigationReduxMiddleware,
|
||||
} from 'react-navigation-redux-helpers';
|
||||
|
||||
import LoginScreen from '../components/LoginScreen';
|
||||
import MainScreen from '../components/MainScreen';
|
||||
import ProfileScreen from '../components/ProfileScreen';
|
||||
|
||||
export const AppNavigator = StackNavigator({
|
||||
const middleware = createReactNavigationReduxMiddleware(
|
||||
'root',
|
||||
state => state.nav
|
||||
);
|
||||
|
||||
const RootNavigator = createStackNavigator({
|
||||
Login: { screen: LoginScreen },
|
||||
Main: { screen: MainScreen },
|
||||
Profile: { screen: ProfileScreen },
|
||||
});
|
||||
|
||||
const AppWithNavigationState = ({ dispatch, nav }) => (
|
||||
<AppNavigator navigation={addNavigationHelpers({ dispatch, state: nav })} />
|
||||
);
|
||||
|
||||
AppWithNavigationState.propTypes = {
|
||||
dispatch: PropTypes.func.isRequired,
|
||||
nav: PropTypes.object.isRequired,
|
||||
};
|
||||
const AppWithNavigationState = reduxifyNavigator(RootNavigator, 'root');
|
||||
|
||||
const mapStateToProps = state => ({
|
||||
nav: state.nav,
|
||||
state: state.nav,
|
||||
});
|
||||
|
||||
export default connect(mapStateToProps)(AppWithNavigationState);
|
||||
const AppNavigator = connect(mapStateToProps)(AppWithNavigationState);
|
||||
|
||||
export { RootNavigator, AppNavigator, middleware };
|
||||
|
||||
@@ -1,13 +1,13 @@
|
||||
import { combineReducers } from 'redux';
|
||||
import { NavigationActions } from 'react-navigation';
|
||||
|
||||
import { AppNavigator } from '../navigators/AppNavigator';
|
||||
import { RootNavigator } from '../navigators/AppNavigator';
|
||||
|
||||
// Start with two routes: The Main screen, with the Login screen on top.
|
||||
const firstAction = AppNavigator.router.getActionForPathAndParams('Main');
|
||||
const tempNavState = AppNavigator.router.getStateForAction(firstAction);
|
||||
const secondAction = AppNavigator.router.getActionForPathAndParams('Login');
|
||||
const initialNavState = AppNavigator.router.getStateForAction(
|
||||
const firstAction = RootNavigator.router.getActionForPathAndParams('Main');
|
||||
const tempNavState = RootNavigator.router.getStateForAction(firstAction);
|
||||
const secondAction = RootNavigator.router.getActionForPathAndParams('Login');
|
||||
const initialNavState = RootNavigator.router.getStateForAction(
|
||||
secondAction,
|
||||
tempNavState
|
||||
);
|
||||
@@ -16,19 +16,19 @@ function nav(state = initialNavState, action) {
|
||||
let nextState;
|
||||
switch (action.type) {
|
||||
case 'Login':
|
||||
nextState = AppNavigator.router.getStateForAction(
|
||||
nextState = RootNavigator.router.getStateForAction(
|
||||
NavigationActions.back(),
|
||||
state
|
||||
);
|
||||
break;
|
||||
case 'Logout':
|
||||
nextState = AppNavigator.router.getStateForAction(
|
||||
nextState = RootNavigator.router.getStateForAction(
|
||||
NavigationActions.navigate({ routeName: 'Login' }),
|
||||
state
|
||||
);
|
||||
break;
|
||||
default:
|
||||
nextState = AppNavigator.router.getStateForAction(action, state);
|
||||
nextState = RootNavigator.router.getStateForAction(action, state);
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
"description": "An empty new project",
|
||||
"slug": "SafeAreaExample",
|
||||
"privacy": "public",
|
||||
"sdkVersion": "22.0.0",
|
||||
"sdkVersion": "25.0.0",
|
||||
"version": "1.0.0",
|
||||
"primaryColor": "#cccccc",
|
||||
"icon": "./assets/icon.png",
|
||||
|
||||
@@ -2,11 +2,11 @@
|
||||
"main": "node_modules/expo/AppEntry.js",
|
||||
"private": true,
|
||||
"dependencies": {
|
||||
"expo": "^22.0.1",
|
||||
"react": "16.0.0-beta.5",
|
||||
"react-native": "https://github.com/expo/react-native/archive/sdk-22.0.1.tar.gz",
|
||||
"expo": "^25.0.0",
|
||||
"react": "16.2.0",
|
||||
"react-native": "^0.52.0",
|
||||
"react-native-platform-touchable": "^1.1.1",
|
||||
"react-navigation": "^1.0.0-beta.16"
|
||||
"react-navigation": "link:../.."
|
||||
},
|
||||
"name": "SafeAreaExample",
|
||||
"version": "0.0.0",
|
||||
|
||||