Compare commits
56 Commits
@react-nav
...
@react-nav
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
3fbfb70699 | ||
|
|
abdf9d12b5 | ||
|
|
ba85db28d4 | ||
|
|
e5063b9339 | ||
|
|
ec35bd5821 | ||
|
|
22e306004a | ||
|
|
8a835b3556 | ||
|
|
d9237e9a0d | ||
|
|
0644ac03aa | ||
|
|
41a5e1a385 | ||
|
|
3d937d1e65 | ||
|
|
343320783f | ||
|
|
5411816188 | ||
|
|
d8bda604ee | ||
|
|
c70635b7d7 | ||
|
|
94d7b28c0b | ||
|
|
b19b3b2725 | ||
|
|
3dcec142f7 | ||
|
|
0c159db4c9 | ||
|
|
2479da98ed | ||
|
|
5197ee2a9c | ||
|
|
0ead2662ec | ||
|
|
5af5c29f07 | ||
|
|
d448cdc11f | ||
|
|
0e8fda3196 | ||
|
|
9198597b7f | ||
|
|
9be904d9c4 | ||
|
|
fa4a959549 | ||
|
|
d0510d0220 | ||
|
|
0b4bf1dcc8 | ||
|
|
5a3f8356b0 | ||
|
|
eeae11033a | ||
|
|
b931ae62df | ||
|
|
ea66b1a3b8 | ||
|
|
4bc0c8f66f | ||
|
|
68016de385 | ||
|
|
e55e866af2 | ||
|
|
50b366e734 | ||
|
|
edf96d839f | ||
|
|
141d397bdf | ||
|
|
0f18b91690 | ||
|
|
6262f7298b | ||
|
|
a6f58677dc | ||
|
|
9bfb295620 | ||
|
|
ecd68afb46 | ||
|
|
5fe140e61b | ||
|
|
944fa35ed4 | ||
|
|
2243b45cc1 | ||
|
|
5e7cfc4ac0 | ||
|
|
5751e7f97a | ||
|
|
179e807a64 | ||
|
|
2f1f0af862 | ||
|
|
9976a888a0 | ||
|
|
16c64e7298 | ||
|
|
f1fe951cf9 | ||
|
|
14250851d1 |
1
.gitattributes
vendored
Normal file
@@ -0,0 +1 @@
|
|||||||
|
* text eol=lf
|
||||||
53
.github/workflows/expo-preview.yml
vendored
Normal file
@@ -0,0 +1,53 @@
|
|||||||
|
name: Expo Preview
|
||||||
|
on: [pull_request]
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
publish:
|
||||||
|
name: Install and publish
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- name: Checkout
|
||||||
|
uses: actions/checkout@v1
|
||||||
|
|
||||||
|
- name: Setup Node.js
|
||||||
|
uses: actions/setup-node@v1
|
||||||
|
with:
|
||||||
|
node-version: 10.x
|
||||||
|
|
||||||
|
- name: Setup Expo
|
||||||
|
uses: expo/expo-github-action@v5
|
||||||
|
with:
|
||||||
|
expo-version: 3.x
|
||||||
|
expo-username: ${{ secrets.EXPO_CLI_USERNAME }}
|
||||||
|
expo-password: ${{ secrets.EXPO_CLI_PASSWORD }}
|
||||||
|
expo-cache: true
|
||||||
|
|
||||||
|
- name: Get yarn cache
|
||||||
|
id: yarn-cache
|
||||||
|
run: echo "::set-output name=dir::$(yarn cache dir)"
|
||||||
|
|
||||||
|
- name: Check yarn cache
|
||||||
|
uses: actions/cache@v1
|
||||||
|
with:
|
||||||
|
path: ${{ steps.yarn-cache.outputs.dir }}
|
||||||
|
key: ${{ runner.os }}-yarn-${{ hashFiles('**/yarn.lock') }}
|
||||||
|
restore-keys: |
|
||||||
|
${{ runner.os }}-yarn-
|
||||||
|
|
||||||
|
- name: Install dependencies
|
||||||
|
run: yarn
|
||||||
|
|
||||||
|
- name: Publish Expo app
|
||||||
|
working-directory: ./example
|
||||||
|
run: expo publish --release-channel=pr-${{ github.event.number }}
|
||||||
|
|
||||||
|
- name: Get expo link
|
||||||
|
id: expo
|
||||||
|
run: echo "::set-output name=path::@react-navigation/react-navigation-example?release-channel=pr-${{ github.event.number }}"
|
||||||
|
|
||||||
|
- name: Comment on PR
|
||||||
|
uses: unsplash/comment-on-pr@master
|
||||||
|
env:
|
||||||
|
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||||
|
with:
|
||||||
|
msg: The Expo app for the example from this branch is ready!<br><br>[expo.io/${{ steps.expo.outputs.path }}](https://expo.io/${{ steps.expo.outputs.path }})<br><br><a href="https://exp.host/${{ steps.expo.outputs.path }}"><img src="https://api.qrserver.com/v1/create-qr-code/?size=400x400&data=exp://exp.host/${{ steps.expo.outputs.path }}" height="200px" width="200px"></a>.
|
||||||
44
.github/workflows/expo.yml
vendored
Normal file
@@ -0,0 +1,44 @@
|
|||||||
|
name: Expo Publish
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
branches:
|
||||||
|
- master
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
publish:
|
||||||
|
name: Install and publish
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- name: Checkout
|
||||||
|
uses: actions/checkout@v1
|
||||||
|
|
||||||
|
- name: Setup Node.js
|
||||||
|
uses: actions/setup-node@v1
|
||||||
|
with:
|
||||||
|
node-version: 10.x
|
||||||
|
|
||||||
|
- name: Setup Expo
|
||||||
|
uses: expo/expo-github-action@v5
|
||||||
|
with:
|
||||||
|
expo-version: 3.x
|
||||||
|
expo-username: ${{ secrets.EXPO_CLI_USERNAME }}
|
||||||
|
expo-password: ${{ secrets.EXPO_CLI_PASSWORD }}
|
||||||
|
expo-cache: true
|
||||||
|
|
||||||
|
- name: Get yarn cache
|
||||||
|
id: yarn-cache
|
||||||
|
run: echo "::set-output name=dir::$(yarn cache dir)"
|
||||||
|
|
||||||
|
- uses: actions/cache@v1
|
||||||
|
with:
|
||||||
|
path: ${{ steps.yarn-cache.outputs.dir }}
|
||||||
|
key: ${{ runner.os }}-yarn-${{ hashFiles('**/yarn.lock') }}
|
||||||
|
restore-keys: |
|
||||||
|
${{ runner.os }}-yarn-
|
||||||
|
|
||||||
|
- name: Install dependencies
|
||||||
|
run: yarn
|
||||||
|
|
||||||
|
- name: Publish Expo app
|
||||||
|
working-directory: ./example
|
||||||
|
run: expo publish
|
||||||
27
.github/workflows/rebase.yml
vendored
Normal file
@@ -0,0 +1,27 @@
|
|||||||
|
name: Automatic Rebase
|
||||||
|
on:
|
||||||
|
issue_comment:
|
||||||
|
types: [created]
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
rebase:
|
||||||
|
name: Rebase
|
||||||
|
if: github.event.issue.pull_request != '' && contains(github.event.comment.body, '/rebase')
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@master
|
||||||
|
with:
|
||||||
|
fetch-depth: 0
|
||||||
|
|
||||||
|
- name: Automatic Rebase
|
||||||
|
uses: cirrus-actions/rebase@1.2
|
||||||
|
env:
|
||||||
|
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||||
|
|
||||||
|
# https://github.community/t5/GitHub-Actions/Workflow-is-failing-if-no-job-can-be-ran-due-to-condition/m-p/38186#M3250
|
||||||
|
always_job:
|
||||||
|
name: Always run job
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- name: Always run
|
||||||
|
run: echo "This job is used to prevent the workflow to fail when all other jobs are skipped."
|
||||||
@@ -16,5 +16,7 @@ module.exports = {
|
|||||||
plugins: [
|
plugins: [
|
||||||
'@babel/plugin-proposal-class-properties',
|
'@babel/plugin-proposal-class-properties',
|
||||||
'@babel/plugin-proposal-optional-chaining',
|
'@babel/plugin-proposal-optional-chaining',
|
||||||
|
'@babel/transform-flow-strip-types',
|
||||||
|
'@babel/plugin-proposal-nullish-coalescing-operator',
|
||||||
],
|
],
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -5,3 +5,5 @@ If you want to run the example from the repo,
|
|||||||
- Clone the repository and run `yarn` in the project root
|
- Clone the repository and run `yarn` in the project root
|
||||||
- Run `yarn example start` to start the packager
|
- Run `yarn example start` to start the packager
|
||||||
- Follow the instructions to open it with the [Expo app](https://expo.io/)
|
- Follow the instructions to open it with the [Expo app](https://expo.io/)
|
||||||
|
|
||||||
|
You can also run the currently published [app on Expo](https://expo.io/@react-navigation/react-navigation-example) on your Android device or iOS simulator or the [web app](https://react-navigation-example.netlify.com/) in your browser.
|
||||||
|
|||||||
@@ -4,8 +4,8 @@
|
|||||||
<facet type="android-gradle" name="Android-Gradle">
|
<facet type="android-gradle" name="Android-Gradle">
|
||||||
<configuration>
|
<configuration>
|
||||||
<option name="GRADLE_PROJECT_PATH" value=":app" />
|
<option name="GRADLE_PROJECT_PATH" value=":app" />
|
||||||
<option name="LAST_SUCCESSFUL_SYNC_AGP_VERSION" value="3.3.0" />
|
<option name="LAST_SUCCESSFUL_SYNC_AGP_VERSION" value="3.4.2" />
|
||||||
<option name="LAST_KNOWN_AGP_VERSION" value="3.3.0" />
|
<option name="LAST_KNOWN_AGP_VERSION" value="3.4.2" />
|
||||||
</configuration>
|
</configuration>
|
||||||
</facet>
|
</facet>
|
||||||
<facet type="android" name="Android">
|
<facet type="android" name="Android">
|
||||||
@@ -19,8 +19,8 @@
|
|||||||
<option name="ALLOW_USER_CONFIGURATION" value="false" />
|
<option name="ALLOW_USER_CONFIGURATION" value="false" />
|
||||||
<option name="MANIFEST_FILE_RELATIVE_PATH" value="/src/main/AndroidManifest.xml" />
|
<option name="MANIFEST_FILE_RELATIVE_PATH" value="/src/main/AndroidManifest.xml" />
|
||||||
<option name="RES_FOLDER_RELATIVE_PATH" value="/src/main/res" />
|
<option name="RES_FOLDER_RELATIVE_PATH" value="/src/main/res" />
|
||||||
<option name="RES_FOLDERS_RELATIVE_PATH" value="file://$MODULE_DIR$/src/main/res;file://$MODULE_DIR$/build/generated/res/rs/debug;file://$MODULE_DIR$/build/generated/res/resValues/debug" />
|
<option name="RES_FOLDERS_RELATIVE_PATH" value="file://$MODULE_DIR$/src/main/res;file://$MODULE_DIR$/build/generated/res/resValues/debug" />
|
||||||
<option name="TEST_RES_FOLDERS_RELATIVE_PATH" value="file://$MODULE_DIR$/build/generated/res/rs/androidTest/debug" />
|
<option name="TEST_RES_FOLDERS_RELATIVE_PATH" value="" />
|
||||||
<option name="ASSETS_FOLDER_RELATIVE_PATH" value="/src/main/assets" />
|
<option name="ASSETS_FOLDER_RELATIVE_PATH" value="/src/main/assets" />
|
||||||
</configuration>
|
</configuration>
|
||||||
</facet>
|
</facet>
|
||||||
@@ -70,6 +70,7 @@
|
|||||||
<sourceFolder url="file://$MODULE_DIR$/src/main/assets" type="java-resource" />
|
<sourceFolder url="file://$MODULE_DIR$/src/main/assets" type="java-resource" />
|
||||||
<sourceFolder url="file://$MODULE_DIR$/src/main/aidl" isTestSource="false" />
|
<sourceFolder url="file://$MODULE_DIR$/src/main/aidl" isTestSource="false" />
|
||||||
<sourceFolder url="file://$MODULE_DIR$/src/main/java" isTestSource="false" />
|
<sourceFolder url="file://$MODULE_DIR$/src/main/java" isTestSource="false" />
|
||||||
|
<sourceFolder url="file://$MODULE_DIR$/build/generated/rncli/src/main/java" isTestSource="false" />
|
||||||
<sourceFolder url="file://$MODULE_DIR$/src/main/rs" isTestSource="false" />
|
<sourceFolder url="file://$MODULE_DIR$/src/main/rs" isTestSource="false" />
|
||||||
<sourceFolder url="file://$MODULE_DIR$/src/main/shaders" isTestSource="false" />
|
<sourceFolder url="file://$MODULE_DIR$/src/main/shaders" isTestSource="false" />
|
||||||
<sourceFolder url="file://$MODULE_DIR$/src/androidTest/res" type="java-test-resource" />
|
<sourceFolder url="file://$MODULE_DIR$/src/androidTest/res" type="java-test-resource" />
|
||||||
@@ -90,91 +91,103 @@
|
|||||||
</content>
|
</content>
|
||||||
<orderEntry type="jdk" jdkName="Android API 28 Platform" jdkType="Android SDK" />
|
<orderEntry type="jdk" jdkName="Android API 28 Platform" jdkType="Android SDK" />
|
||||||
<orderEntry type="sourceFolder" forTests="false" />
|
<orderEntry type="sourceFolder" forTests="false" />
|
||||||
<orderEntry type="library" name="Gradle: com.android.support:collections:28.0.0@jar" level="project" />
|
|
||||||
<orderEntry type="library" name="Gradle: android.arch.lifecycle:common:1.1.1@jar" level="project" />
|
|
||||||
<orderEntry type="library" name="Gradle: android.arch.core:common:1.1.1@jar" level="project" />
|
|
||||||
<orderEntry type="library" name="Gradle: com.android.support:support-annotations:28.0.0@jar" level="project" />
|
|
||||||
<orderEntry type="library" name="Gradle: com.facebook.infer.annotation:infer-annotation:0.11.2@jar" level="project" />
|
<orderEntry type="library" name="Gradle: com.facebook.infer.annotation:infer-annotation:0.11.2@jar" level="project" />
|
||||||
<orderEntry type="library" name="Gradle: javax.inject:javax.inject:1@jar" level="project" />
|
|
||||||
<orderEntry type="library" name="Gradle: com.google.code.findbugs:jsr305:3.0.2@jar" level="project" />
|
<orderEntry type="library" name="Gradle: com.google.code.findbugs:jsr305:3.0.2@jar" level="project" />
|
||||||
|
<orderEntry type="library" name="Gradle: javax.inject:javax.inject:1@jar" level="project" />
|
||||||
|
<orderEntry type="library" name="Gradle: androidx.collection:collection:1.1.0@jar" level="project" />
|
||||||
|
<orderEntry type="library" name="Gradle: androidx.lifecycle:lifecycle-common:2.1.0@jar" level="project" />
|
||||||
|
<orderEntry type="library" name="Gradle: androidx.arch.core:core-common:2.1.0@jar" level="project" />
|
||||||
|
<orderEntry type="library" name="Gradle: androidx.annotation:annotation:1.1.0@jar" level="project" />
|
||||||
<orderEntry type="library" name="Gradle: com.squareup.okhttp3:okhttp-urlconnection:3.12.1@jar" level="project" />
|
<orderEntry type="library" name="Gradle: com.squareup.okhttp3:okhttp-urlconnection:3.12.1@jar" level="project" />
|
||||||
<orderEntry type="library" name="Gradle: com.squareup.okhttp3:okhttp:3.12.1@jar" level="project" />
|
<orderEntry type="library" name="Gradle: com.squareup.okhttp3:okhttp:3.12.1@jar" level="project" />
|
||||||
<orderEntry type="library" name="Gradle: com.squareup.okio:okio:1.15.0@jar" level="project" />
|
<orderEntry type="library" name="Gradle: com.squareup.okio:okio:1.15.0@jar" level="project" />
|
||||||
|
<orderEntry type="library" name="Gradle: com.github.bumptech.glide:disklrucache:4.9.0@jar" level="project" />
|
||||||
|
<orderEntry type="library" name="Gradle: com.github.bumptech.glide:annotations:4.9.0@jar" level="project" />
|
||||||
|
<orderEntry type="library" name="Gradle: org.jetbrains.kotlin:kotlin-stdlib-jdk7:1.3.41@jar" level="project" />
|
||||||
|
<orderEntry type="library" name="Gradle: org.jetbrains.kotlin:kotlin-stdlib:1.3.41@jar" level="project" />
|
||||||
|
<orderEntry type="library" name="Gradle: org.jetbrains.kotlin:kotlin-stdlib-common:1.3.41@jar" level="project" />
|
||||||
|
<orderEntry type="library" name="Gradle: org.jetbrains:annotations:13.0@jar" level="project" />
|
||||||
<orderEntry type="library" name="Gradle: com.facebook.device.yearclass:yearclass:2.1.0@jar" level="project" />
|
<orderEntry type="library" name="Gradle: com.facebook.device.yearclass:yearclass:2.1.0@jar" level="project" />
|
||||||
<orderEntry type="library" name="Gradle: commons-codec:commons-codec:1.10@jar" level="project" />
|
<orderEntry type="library" name="Gradle: commons-codec:commons-codec:1.10@jar" level="project" />
|
||||||
<orderEntry type="library" name="Gradle: commons-io:commons-io:1.4@jar" level="project" />
|
<orderEntry type="library" name="Gradle: commons-io:commons-io:1.4@jar" level="project" />
|
||||||
<orderEntry type="library" name="Gradle: com.github.bumptech.glide:disklrucache:4.9.0@jar" level="project" />
|
|
||||||
<orderEntry type="library" name="Gradle: com.github.bumptech.glide:annotations:4.9.0@jar" level="project" />
|
|
||||||
<orderEntry type="library" name="Gradle: com.parse.bolts:bolts-tasks:1.4.0@jar" level="project" />
|
|
||||||
<orderEntry type="library" name="Gradle: com.facebook.react:react-native:0.61.5@aar" level="project" />
|
<orderEntry type="library" name="Gradle: com.facebook.react:react-native:0.61.5@aar" level="project" />
|
||||||
<orderEntry type="library" name="Gradle: com.android.support:appcompat-v7:28.0.0@aar" level="project" />
|
<orderEntry type="library" name="Gradle: androidx.appcompat:appcompat:1.1.0@aar" level="project" />
|
||||||
|
<orderEntry type="library" name="Gradle: androidx.browser:browser:1.0.0@aar" level="project" />
|
||||||
<orderEntry type="library" name="Gradle: com.github.bumptech.glide:glide:4.9.0@aar" level="project" />
|
<orderEntry type="library" name="Gradle: com.github.bumptech.glide:glide:4.9.0@aar" level="project" />
|
||||||
|
<orderEntry type="library" name="Gradle: com.github.bumptech.glide:gifdecoder:4.9.0@aar" level="project" />
|
||||||
<orderEntry type="library" name="Gradle: com.google.android.gms:play-services-location:16.0.0@aar" level="project" />
|
<orderEntry type="library" name="Gradle: com.google.android.gms:play-services-location:16.0.0@aar" level="project" />
|
||||||
<orderEntry type="library" name="Gradle: com.google.android.gms:play-services-base:16.0.1@aar" level="project" />
|
<orderEntry type="library" name="Gradle: com.google.android.gms:play-services-base:16.0.1@aar" level="project" />
|
||||||
<orderEntry type="library" name="Gradle: com.google.android.gms:play-services-places-placereport:16.0.0@aar" level="project" />
|
<orderEntry type="library" name="Gradle: com.google.android.gms:play-services-places-placereport:16.0.0@aar" level="project" />
|
||||||
<orderEntry type="library" name="Gradle: com.google.android.gms:play-services-tasks:16.0.1@aar" level="project" />
|
<orderEntry type="library" name="Gradle: com.google.android.gms:play-services-tasks:16.0.1@aar" level="project" />
|
||||||
<orderEntry type="library" name="Gradle: com.google.android.gms:play-services-basement:16.0.1@aar" level="project" />
|
<orderEntry type="library" name="Gradle: com.google.android.gms:play-services-basement:16.0.1@aar" level="project" />
|
||||||
<orderEntry type="library" name="Gradle: com.android.support:support-v4:28.0.0@aar" level="project" />
|
<orderEntry type="library" name="Gradle: androidx.legacy:legacy-support-v4:1.0.0@aar" level="project" />
|
||||||
<orderEntry type="library" name="Gradle: com.android.support:support-fragment:28.0.0@aar" level="project" />
|
<orderEntry type="library" name="Gradle: androidx.fragment:fragment:1.1.0@aar" level="project" />
|
||||||
<orderEntry type="library" name="Gradle: com.android.support:animated-vector-drawable:28.0.0@aar" level="project" />
|
<orderEntry type="library" name="Gradle: androidx.media:media:1.0.0@aar" level="project" />
|
||||||
<orderEntry type="library" name="Gradle: com.android.support:customtabs:28.0.0@aar" level="project" />
|
<orderEntry type="library" name="Gradle: androidx.legacy:legacy-support-core-ui:1.0.0@aar" level="project" />
|
||||||
<orderEntry type="library" name="Gradle: com.android.support:support-core-ui:28.0.0@aar" level="project" />
|
<orderEntry type="library" name="Gradle: androidx.legacy:legacy-support-core-utils:1.0.0@aar" level="project" />
|
||||||
<orderEntry type="library" name="Gradle: com.android.support:support-core-utils:28.0.0@aar" level="project" />
|
<orderEntry type="library" name="Gradle: androidx.appcompat:appcompat-resources:1.1.0@aar" level="project" />
|
||||||
<orderEntry type="library" name="Gradle: com.android.support:support-vector-drawable:28.0.0@aar" level="project" />
|
<orderEntry type="library" name="Gradle: androidx.drawerlayout:drawerlayout:1.0.0@aar" level="project" />
|
||||||
<orderEntry type="library" name="Gradle: com.android.support:loader:28.0.0@aar" level="project" />
|
<orderEntry type="library" name="Gradle: androidx.viewpager:viewpager:1.0.0@aar" level="project" />
|
||||||
<orderEntry type="library" name="Gradle: com.android.support:support-media-compat:28.0.0@aar" level="project" />
|
<orderEntry type="library" name="Gradle: androidx.loader:loader:1.0.0@aar" level="project" />
|
||||||
<orderEntry type="library" name="Gradle: com.android.support:viewpager:28.0.0@aar" level="project" />
|
<orderEntry type="library" name="Gradle: androidx.activity:activity:1.0.0@aar" level="project" />
|
||||||
<orderEntry type="library" name="Gradle: com.android.support:coordinatorlayout:28.0.0@aar" level="project" />
|
<orderEntry type="library" name="Gradle: androidx.vectordrawable:vectordrawable-animated:1.1.0@aar" level="project" />
|
||||||
<orderEntry type="library" name="Gradle: com.android.support:drawerlayout:28.0.0@aar" level="project" />
|
<orderEntry type="library" name="Gradle: androidx.vectordrawable:vectordrawable:1.1.0@aar" level="project" />
|
||||||
<orderEntry type="library" name="Gradle: com.android.support:slidingpanelayout:28.0.0@aar" level="project" />
|
<orderEntry type="library" name="Gradle: androidx.coordinatorlayout:coordinatorlayout:1.0.0@aar" level="project" />
|
||||||
<orderEntry type="library" name="Gradle: com.android.support:customview:28.0.0@aar" level="project" />
|
<orderEntry type="library" name="Gradle: androidx.slidingpanelayout:slidingpanelayout:1.0.0@aar" level="project" />
|
||||||
<orderEntry type="library" name="Gradle: com.android.support:swiperefreshlayout:28.0.0@aar" level="project" />
|
<orderEntry type="library" name="Gradle: androidx.customview:customview:1.0.0@aar" level="project" />
|
||||||
<orderEntry type="library" name="Gradle: com.android.support:asynclayoutinflater:28.0.0@aar" level="project" />
|
<orderEntry type="library" name="Gradle: androidx.swiperefreshlayout:swiperefreshlayout:1.0.0@aar" level="project" />
|
||||||
<orderEntry type="library" name="Gradle: com.android.support:support-compat:28.0.0@aar" level="project" />
|
<orderEntry type="library" name="Gradle: androidx.asynclayoutinflater:asynclayoutinflater:1.0.0@aar" level="project" />
|
||||||
<orderEntry type="library" name="Gradle: com.android.support:versionedparcelable:28.0.0@aar" level="project" />
|
<orderEntry type="library" name="Gradle: androidx.core:core:1.1.0@aar" level="project" />
|
||||||
<orderEntry type="library" name="Gradle: com.android.support:cursoradapter:28.0.0@aar" level="project" />
|
<orderEntry type="library" name="Gradle: androidx.cursoradapter:cursoradapter:1.0.0@aar" level="project" />
|
||||||
<orderEntry type="library" name="Gradle: android.arch.lifecycle:runtime:1.1.1@aar" level="project" />
|
<orderEntry type="library" name="Gradle: androidx.versionedparcelable:versionedparcelable:1.1.0@aar" level="project" />
|
||||||
<orderEntry type="library" name="Gradle: com.android.support:documentfile:28.0.0@aar" level="project" />
|
<orderEntry type="library" name="Gradle: androidx.interpolator:interpolator:1.0.0@aar" level="project" />
|
||||||
<orderEntry type="library" name="Gradle: com.android.support:localbroadcastmanager:28.0.0@aar" level="project" />
|
<orderEntry type="library" name="Gradle: androidx.lifecycle:lifecycle-viewmodel:2.1.0@aar" level="project" />
|
||||||
<orderEntry type="library" name="Gradle: com.android.support:print:28.0.0@aar" level="project" />
|
<orderEntry type="library" name="Gradle: androidx.lifecycle:lifecycle-runtime:2.1.0@aar" level="project" />
|
||||||
<orderEntry type="library" name="Gradle: android.arch.lifecycle:viewmodel:1.1.1@aar" level="project" />
|
<orderEntry type="library" name="Gradle: androidx.documentfile:documentfile:1.0.0@aar" level="project" />
|
||||||
<orderEntry type="library" name="Gradle: com.github.bumptech.glide:gifdecoder:4.9.0@aar" level="project" />
|
<orderEntry type="library" name="Gradle: androidx.localbroadcastmanager:localbroadcastmanager:1.0.0@aar" level="project" />
|
||||||
<orderEntry type="library" name="Gradle: com.android.support:interpolator:28.0.0@aar" level="project" />
|
<orderEntry type="library" name="Gradle: androidx.print:print:1.0.0@aar" level="project" />
|
||||||
<orderEntry type="library" name="Gradle: android.arch.lifecycle:livedata:1.1.1@aar" level="project" />
|
<orderEntry type="library" name="Gradle: androidx.savedstate:savedstate:1.0.0@aar" level="project" />
|
||||||
<orderEntry type="library" name="Gradle: android.arch.lifecycle:livedata-core:1.1.1@aar" level="project" />
|
<orderEntry type="library" name="Gradle: androidx.lifecycle:lifecycle-livedata:2.0.0@aar" level="project" />
|
||||||
<orderEntry type="library" name="Gradle: android.arch.core:runtime:1.1.1@aar" level="project" />
|
<orderEntry type="library" name="Gradle: androidx.lifecycle:lifecycle-livedata-core:2.0.0@aar" level="project" />
|
||||||
<orderEntry type="library" name="Gradle: com.facebook.fresco:fresco:1.10.0@aar" level="project" />
|
<orderEntry type="library" name="Gradle: androidx.arch.core:core-runtime:2.0.0@aar" level="project" />
|
||||||
<orderEntry type="library" name="Gradle: com.facebook.fresco:imagepipeline-okhttp3:1.10.0@aar" level="project" />
|
<orderEntry type="library" name="Gradle: com.facebook.fresco:fresco:2.0.0@aar" level="project" />
|
||||||
<orderEntry type="library" name="Gradle: com.facebook.fresco:drawee:1.10.0@aar" level="project" />
|
<orderEntry type="library" name="Gradle: com.facebook.fresco:fbcore:2.0.0@aar" level="project" />
|
||||||
<orderEntry type="library" name="Gradle: com.facebook.fresco:imagepipeline:1.10.0@aar" level="project" />
|
<orderEntry type="library" name="Gradle: com.facebook.fresco:drawee:2.0.0@aar" level="project" />
|
||||||
<orderEntry type="library" name="Gradle: com.facebook.fresco:imagepipeline-base:1.10.0@aar" level="project" />
|
<orderEntry type="library" name="Gradle: com.facebook.fresco:imagepipeline:2.0.0@aar" level="project" />
|
||||||
|
<orderEntry type="library" name="Gradle: com.facebook.fresco:imagepipeline-base:2.0.0@aar" level="project" />
|
||||||
<orderEntry type="library" name="Gradle: com.facebook.soloader:soloader:0.6.0@aar" level="project" />
|
<orderEntry type="library" name="Gradle: com.facebook.soloader:soloader:0.6.0@aar" level="project" />
|
||||||
|
<orderEntry type="library" name="Gradle: com.facebook.fresco:nativeimagefilters:2.0.0@aar" level="project" />
|
||||||
|
<orderEntry type="library" name="Gradle: com.facebook.fresco:nativeimagetranscoder:2.0.0@aar" level="project" />
|
||||||
|
<orderEntry type="library" name="Gradle: com.facebook.fresco:imagepipeline-okhttp3:2.0.0@aar" level="project" />
|
||||||
<orderEntry type="library" name="Gradle: io.nlopez.smartlocation:library:3.2.11@aar" level="project" />
|
<orderEntry type="library" name="Gradle: io.nlopez.smartlocation:library:3.2.11@aar" level="project" />
|
||||||
<orderEntry type="library" name="Gradle: com.facebook.fresco:fbcore:1.10.0@aar" level="project" />
|
<orderEntry type="library" name="Gradle: org.webkit:android-jsc:r245459@aar" level="project" />
|
||||||
|
<orderEntry type="module" module-name="android-expo-permissions" />
|
||||||
|
<orderEntry type="module" module-name="android-expo-constants" />
|
||||||
|
<orderEntry type="module" module-name="android-unimodules-image-loader-interface" />
|
||||||
|
<orderEntry type="module" module-name="android-expo-web-browser" />
|
||||||
|
<orderEntry type="module" module-name="android-unimodules-react-native-adapter" />
|
||||||
|
<orderEntry type="module" module-name="android-expo-file-system" />
|
||||||
|
<orderEntry type="module" module-name="android-expo-location" />
|
||||||
|
<orderEntry type="module" module-name="android-expo-error-recovery" />
|
||||||
|
<orderEntry type="module" module-name="android-unimodules-permissions-interface" />
|
||||||
|
<orderEntry type="module" module-name="android-unimodules-core" />
|
||||||
|
<orderEntry type="module" module-name="android-expo-app-loader-provider" />
|
||||||
|
<orderEntry type="module" module-name="android-expo-font" />
|
||||||
|
<orderEntry type="module" module-name="android-expo-keep-awake" />
|
||||||
|
<orderEntry type="module" module-name="android-expo-linear-gradient" />
|
||||||
|
<orderEntry type="module" module-name="android-expo-sqlite" />
|
||||||
|
<orderEntry type="module" module-name="android-unimodules-barcode-scanner-interface" />
|
||||||
|
<orderEntry type="module" module-name="android-unimodules-camera-interface" />
|
||||||
|
<orderEntry type="module" module-name="android-unimodules-constants-interface" />
|
||||||
|
<orderEntry type="module" module-name="android-unimodules-face-detector-interface" />
|
||||||
|
<orderEntry type="module" module-name="android-unimodules-file-system-interface" />
|
||||||
|
<orderEntry type="module" module-name="android-unimodules-font-interface" />
|
||||||
|
<orderEntry type="module" module-name="android-unimodules-sensors-interface" />
|
||||||
|
<orderEntry type="module" module-name="android-unimodules-task-manager-interface" />
|
||||||
|
<orderEntry type="module" module-name="android-@react-native-community_masked-view" />
|
||||||
|
<orderEntry type="module" module-name="android-react-native-gesture-handler" />
|
||||||
|
<orderEntry type="module" module-name="android-react-native-reanimated" />
|
||||||
|
<orderEntry type="module" module-name="react-native-safe-area-context" />
|
||||||
<orderEntry type="module" module-name="react-native-screens" />
|
<orderEntry type="module" module-name="react-native-screens" />
|
||||||
<orderEntry type="module" module-name="react-native-reanimated" />
|
|
||||||
<orderEntry type="module" module-name="react-native-gesture-handler" />
|
|
||||||
<orderEntry type="module" module-name="expo-permissions" />
|
|
||||||
<orderEntry type="module" module-name="unimodules-core" />
|
|
||||||
<orderEntry type="module" module-name="unimodules-react-native-adapter" />
|
|
||||||
<orderEntry type="module" module-name="expo-app-loader-provider" />
|
|
||||||
<orderEntry type="module" module-name="expo-constants" />
|
|
||||||
<orderEntry type="module" module-name="expo-file-system" />
|
|
||||||
<orderEntry type="module" module-name="expo-font" />
|
|
||||||
<orderEntry type="module" module-name="expo-keep-awake" />
|
|
||||||
<orderEntry type="module" module-name="expo-linear-gradient" />
|
|
||||||
<orderEntry type="module" module-name="expo-location" />
|
|
||||||
<orderEntry type="module" module-name="expo-sqlite" />
|
|
||||||
<orderEntry type="module" module-name="expo-web-browser" />
|
|
||||||
<orderEntry type="module" module-name="unimodules-barcode-scanner-interface" />
|
|
||||||
<orderEntry type="module" module-name="unimodules-camera-interface" />
|
|
||||||
<orderEntry type="module" module-name="unimodules-constants-interface" />
|
|
||||||
<orderEntry type="module" module-name="unimodules-face-detector-interface" />
|
|
||||||
<orderEntry type="module" module-name="unimodules-file-system-interface" />
|
|
||||||
<orderEntry type="module" module-name="unimodules-font-interface" />
|
|
||||||
<orderEntry type="module" module-name="unimodules-image-loader-interface" />
|
|
||||||
<orderEntry type="module" module-name="unimodules-permissions-interface" />
|
|
||||||
<orderEntry type="module" module-name="unimodules-sensors-interface" />
|
|
||||||
<orderEntry type="module" module-name="unimodules-task-manager-interface" />
|
|
||||||
</component>
|
</component>
|
||||||
</module>
|
</module>
|
||||||
@@ -36,12 +36,19 @@
|
|||||||
<activity
|
<activity
|
||||||
android:name=".MainActivity"
|
android:name=".MainActivity"
|
||||||
android:label="@string/app_name"
|
android:label="@string/app_name"
|
||||||
|
android:launchMode="singleTask"
|
||||||
android:configChanges="keyboard|keyboardHidden|orientation|screenSize"
|
android:configChanges="keyboard|keyboardHidden|orientation|screenSize"
|
||||||
android:windowSoftInputMode="adjustResize">
|
android:windowSoftInputMode="adjustResize">
|
||||||
<intent-filter>
|
<intent-filter>
|
||||||
<action android:name="android.intent.action.MAIN" />
|
<action android:name="android.intent.action.MAIN" />
|
||||||
<category android:name="android.intent.category.LAUNCHER" />
|
<category android:name="android.intent.category.LAUNCHER" />
|
||||||
</intent-filter>
|
</intent-filter>
|
||||||
|
<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="rne" />
|
||||||
|
</intent-filter>
|
||||||
</activity>
|
</activity>
|
||||||
<activity android:name="com.facebook.react.devsupport.DevSettingsActivity" />
|
<activity android:name="com.facebook.react.devsupport.DevSettingsActivity" />
|
||||||
</application>
|
</application>
|
||||||
|
|||||||
@@ -3,6 +3,7 @@
|
|||||||
"displayName": "React Navigation Example",
|
"displayName": "React Navigation Example",
|
||||||
"expo": {
|
"expo": {
|
||||||
"name": "@react-navigation/example",
|
"name": "@react-navigation/example",
|
||||||
|
"owner": "react-navigation",
|
||||||
"slug": "react-navigation-example",
|
"slug": "react-navigation-example",
|
||||||
"description": "Demo app to showcase various functionality of React Navigation",
|
"description": "Demo app to showcase various functionality of React Navigation",
|
||||||
"privacy": "public",
|
"privacy": "public",
|
||||||
|
|||||||
|
Before Width: | Height: | Size: 28 KiB After Width: | Height: | Size: 27 KiB |
|
Before Width: | Height: | Size: 20 KiB After Width: | Height: | Size: 20 KiB |
|
Before Width: | Height: | Size: 27 KiB After Width: | Height: | Size: 27 KiB |
BIN
example/assets/album-art-04.jpg
Normal file
|
After Width: | Height: | Size: 33 KiB |
BIN
example/assets/album-art-05.jpg
Normal file
|
After Width: | Height: | Size: 11 KiB |
BIN
example/assets/album-art-06.jpg
Normal file
|
After Width: | Height: | Size: 21 KiB |
BIN
example/assets/album-art-07.jpg
Normal file
|
After Width: | Height: | Size: 9.7 KiB |
BIN
example/assets/album-art-08.jpg
Normal file
|
After Width: | Height: | Size: 20 KiB |
BIN
example/assets/album-art-09.jpg
Normal file
|
After Width: | Height: | Size: 110 KiB |
BIN
example/assets/album-art-10.jpg
Normal file
|
After Width: | Height: | Size: 229 KiB |
BIN
example/assets/album-art-11.jpg
Normal file
|
After Width: | Height: | Size: 50 KiB |
BIN
example/assets/album-art-12.jpg
Normal file
|
After Width: | Height: | Size: 18 KiB |
BIN
example/assets/album-art-13.jpg
Normal file
|
After Width: | Height: | Size: 81 KiB |
BIN
example/assets/album-art-14.jpg
Normal file
|
After Width: | Height: | Size: 75 KiB |
BIN
example/assets/album-art-15.jpg
Normal file
|
After Width: | Height: | Size: 84 KiB |
BIN
example/assets/album-art-16.jpg
Normal file
|
After Width: | Height: | Size: 116 KiB |
BIN
example/assets/album-art-17.jpg
Normal file
|
After Width: | Height: | Size: 87 KiB |
BIN
example/assets/album-art-18.jpg
Normal file
|
After Width: | Height: | Size: 136 KiB |
BIN
example/assets/album-art-19.jpg
Normal file
|
After Width: | Height: | Size: 93 KiB |
BIN
example/assets/album-art-20.jpg
Normal file
|
After Width: | Height: | Size: 116 KiB |
BIN
example/assets/album-art-21.jpg
Normal file
|
After Width: | Height: | Size: 186 KiB |
BIN
example/assets/album-art-22.jpg
Normal file
|
After Width: | Height: | Size: 78 KiB |
BIN
example/assets/album-art-23.jpg
Normal file
|
After Width: | Height: | Size: 55 KiB |
BIN
example/assets/album-art-24.jpg
Normal file
|
After Width: | Height: | Size: 125 KiB |
|
Before Width: | Height: | Size: 33 KiB |
|
Before Width: | Height: | Size: 11 KiB |
|
Before Width: | Height: | Size: 22 KiB |
|
Before Width: | Height: | Size: 10 KiB |
|
Before Width: | Height: | Size: 21 KiB |
|
Before Width: | Height: | Size: 94 KiB After Width: | Height: | Size: 93 KiB |
|
Before Width: | Height: | Size: 900 B After Width: | Height: | Size: 683 B |
@@ -2,6 +2,8 @@ PODS:
|
|||||||
- boost-for-react-native (1.63.0)
|
- boost-for-react-native (1.63.0)
|
||||||
- DoubleConversion (1.1.6)
|
- DoubleConversion (1.1.6)
|
||||||
- EXAppLoaderProvider (8.0.0)
|
- EXAppLoaderProvider (8.0.0)
|
||||||
|
- EXBlur (8.0.0):
|
||||||
|
- UMCore
|
||||||
- EXConstants (8.0.0):
|
- EXConstants (8.0.0):
|
||||||
- UMConstantsInterface
|
- UMConstantsInterface
|
||||||
- UMCore
|
- UMCore
|
||||||
@@ -48,6 +50,8 @@ PODS:
|
|||||||
- glog
|
- glog
|
||||||
- glog (0.3.5)
|
- glog (0.3.5)
|
||||||
- RCTRequired (0.61.5)
|
- RCTRequired (0.61.5)
|
||||||
|
- RCTRestart (0.0.13):
|
||||||
|
- React
|
||||||
- RCTTypeSafety (0.61.5):
|
- RCTTypeSafety (0.61.5):
|
||||||
- FBLazyVector (= 0.61.5)
|
- FBLazyVector (= 0.61.5)
|
||||||
- Folly (= 2018.10.22.00)
|
- Folly (= 2018.10.22.00)
|
||||||
@@ -249,11 +253,11 @@ PODS:
|
|||||||
- ReactCommon/jscallinvoker (= 0.61.5)
|
- ReactCommon/jscallinvoker (= 0.61.5)
|
||||||
- RNCMaskedView (0.1.5):
|
- RNCMaskedView (0.1.5):
|
||||||
- React
|
- React
|
||||||
- RNGestureHandler (1.5.3):
|
- RNGestureHandler (1.5.5):
|
||||||
- React
|
- React
|
||||||
- RNReanimated (1.4.0):
|
- RNReanimated (1.4.0):
|
||||||
- React
|
- React
|
||||||
- RNScreens (2.0.0-alpha.22):
|
- RNScreens (2.0.0-alpha.33):
|
||||||
- React
|
- React
|
||||||
- UMBarCodeScannerInterface (5.0.0)
|
- UMBarCodeScannerInterface (5.0.0)
|
||||||
- UMCameraInterface (5.0.0)
|
- UMCameraInterface (5.0.0)
|
||||||
@@ -275,6 +279,7 @@ PODS:
|
|||||||
DEPENDENCIES:
|
DEPENDENCIES:
|
||||||
- DoubleConversion (from `../../node_modules/react-native/third-party-podspecs/DoubleConversion.podspec`)
|
- DoubleConversion (from `../../node_modules/react-native/third-party-podspecs/DoubleConversion.podspec`)
|
||||||
- EXAppLoaderProvider (from `../../node_modules/expo-app-loader-provider/ios`)
|
- EXAppLoaderProvider (from `../../node_modules/expo-app-loader-provider/ios`)
|
||||||
|
- EXBlur (from `../../node_modules/expo-blur/ios`)
|
||||||
- EXConstants (from `../../node_modules/expo-constants/ios`)
|
- EXConstants (from `../../node_modules/expo-constants/ios`)
|
||||||
- EXErrorRecovery (from `../../node_modules/expo-error-recovery/ios`)
|
- EXErrorRecovery (from `../../node_modules/expo-error-recovery/ios`)
|
||||||
- EXFileSystem (from `../../node_modules/expo-file-system/ios`)
|
- EXFileSystem (from `../../node_modules/expo-file-system/ios`)
|
||||||
@@ -290,6 +295,7 @@ DEPENDENCIES:
|
|||||||
- Folly (from `../../node_modules/react-native/third-party-podspecs/Folly.podspec`)
|
- Folly (from `../../node_modules/react-native/third-party-podspecs/Folly.podspec`)
|
||||||
- glog (from `../../node_modules/react-native/third-party-podspecs/glog.podspec`)
|
- glog (from `../../node_modules/react-native/third-party-podspecs/glog.podspec`)
|
||||||
- RCTRequired (from `../../node_modules/react-native/Libraries/RCTRequired`)
|
- RCTRequired (from `../../node_modules/react-native/Libraries/RCTRequired`)
|
||||||
|
- RCTRestart (from `../../node_modules/react-native-restart/ios`)
|
||||||
- RCTTypeSafety (from `../../node_modules/react-native/Libraries/TypeSafety`)
|
- RCTTypeSafety (from `../../node_modules/react-native/Libraries/TypeSafety`)
|
||||||
- React (from `../../node_modules/react-native/`)
|
- React (from `../../node_modules/react-native/`)
|
||||||
- React-Core (from `../../node_modules/react-native/`)
|
- React-Core (from `../../node_modules/react-native/`)
|
||||||
@@ -340,6 +346,9 @@ EXTERNAL SOURCES:
|
|||||||
EXAppLoaderProvider:
|
EXAppLoaderProvider:
|
||||||
:path: !ruby/object:Pathname
|
:path: !ruby/object:Pathname
|
||||||
path: "../../node_modules/expo-app-loader-provider/ios"
|
path: "../../node_modules/expo-app-loader-provider/ios"
|
||||||
|
EXBlur:
|
||||||
|
:path: !ruby/object:Pathname
|
||||||
|
path: "../../node_modules/expo-blur/ios"
|
||||||
EXConstants:
|
EXConstants:
|
||||||
:path: !ruby/object:Pathname
|
:path: !ruby/object:Pathname
|
||||||
path: "../../node_modules/expo-constants/ios"
|
path: "../../node_modules/expo-constants/ios"
|
||||||
@@ -380,6 +389,8 @@ EXTERNAL SOURCES:
|
|||||||
:podspec: "../../node_modules/react-native/third-party-podspecs/glog.podspec"
|
:podspec: "../../node_modules/react-native/third-party-podspecs/glog.podspec"
|
||||||
RCTRequired:
|
RCTRequired:
|
||||||
:path: "../../node_modules/react-native/Libraries/RCTRequired"
|
:path: "../../node_modules/react-native/Libraries/RCTRequired"
|
||||||
|
RCTRestart:
|
||||||
|
:path: "../../node_modules/react-native-restart/ios"
|
||||||
RCTTypeSafety:
|
RCTTypeSafety:
|
||||||
:path: "../../node_modules/react-native/Libraries/TypeSafety"
|
:path: "../../node_modules/react-native/Libraries/TypeSafety"
|
||||||
React:
|
React:
|
||||||
@@ -469,6 +480,7 @@ SPEC CHECKSUMS:
|
|||||||
boost-for-react-native: 39c7adb57c4e60d6c5479dd8623128eb5b3f0f2c
|
boost-for-react-native: 39c7adb57c4e60d6c5479dd8623128eb5b3f0f2c
|
||||||
DoubleConversion: 5805e889d232975c086db112ece9ed034df7a0b2
|
DoubleConversion: 5805e889d232975c086db112ece9ed034df7a0b2
|
||||||
EXAppLoaderProvider: ebdb6bc2632c1ccadbe49f5e4104d8d690969c49
|
EXAppLoaderProvider: ebdb6bc2632c1ccadbe49f5e4104d8d690969c49
|
||||||
|
EXBlur: d1604f66f89a9414f5ee65dfb23874437c1bb147
|
||||||
EXConstants: 4051b16c17ef3defa03c541d42811dc92b249146
|
EXConstants: 4051b16c17ef3defa03c541d42811dc92b249146
|
||||||
EXErrorRecovery: d36db99ec6a3808f313f01b0890eb443796dd1c2
|
EXErrorRecovery: d36db99ec6a3808f313f01b0890eb443796dd1c2
|
||||||
EXFileSystem: 6e0d9bb6cc4ea404dbb8f583c1a8a2dcdf4b83b6
|
EXFileSystem: 6e0d9bb6cc4ea404dbb8f583c1a8a2dcdf4b83b6
|
||||||
@@ -484,6 +496,7 @@ SPEC CHECKSUMS:
|
|||||||
Folly: 30e7936e1c45c08d884aa59369ed951a8e68cf51
|
Folly: 30e7936e1c45c08d884aa59369ed951a8e68cf51
|
||||||
glog: 1f3da668190260b06b429bb211bfbee5cd790c28
|
glog: 1f3da668190260b06b429bb211bfbee5cd790c28
|
||||||
RCTRequired: b153add4da6e7dbc44aebf93f3cf4fcae392ddf1
|
RCTRequired: b153add4da6e7dbc44aebf93f3cf4fcae392ddf1
|
||||||
|
RCTRestart: dd19aab87fc1118e05b6b5b91b959105647f56b4
|
||||||
RCTTypeSafety: 9aa1b91d7f9310fc6eadc3cf95126ffe818af320
|
RCTTypeSafety: 9aa1b91d7f9310fc6eadc3cf95126ffe818af320
|
||||||
React: b6a59ef847b2b40bb6e0180a97d0ca716969ac78
|
React: b6a59ef847b2b40bb6e0180a97d0ca716969ac78
|
||||||
React-Core: 688b451f7d616cc1134ac95295b593d1b5158a04
|
React-Core: 688b451f7d616cc1134ac95295b593d1b5158a04
|
||||||
@@ -504,9 +517,9 @@ SPEC CHECKSUMS:
|
|||||||
React-RCTVibration: a49a1f42bf8f5acf1c3e297097517c6b3af377ad
|
React-RCTVibration: a49a1f42bf8f5acf1c3e297097517c6b3af377ad
|
||||||
ReactCommon: 198c7c8d3591f975e5431bec1b0b3b581aa1c5dd
|
ReactCommon: 198c7c8d3591f975e5431bec1b0b3b581aa1c5dd
|
||||||
RNCMaskedView: dd13f9f7b146a9ad82f9b7eb6c9b5548fcf6e990
|
RNCMaskedView: dd13f9f7b146a9ad82f9b7eb6c9b5548fcf6e990
|
||||||
RNGestureHandler: 02905abe54e1f6e59c081a10b4bd689721e17aa6
|
RNGestureHandler: d2270608171c868581b840cfc692f2962c05cd17
|
||||||
RNReanimated: b2ab0b693dddd2339bd2f300e770f6302d2e960c
|
RNReanimated: b2ab0b693dddd2339bd2f300e770f6302d2e960c
|
||||||
RNScreens: 6adf01eb4080f44af6cca551207c6b0505066857
|
RNScreens: 1c7fd499b915c77c21e8e6c327890c5af9b4cf7e
|
||||||
UMBarCodeScannerInterface: 3802c8574ef119c150701d679ab386e2266d6a54
|
UMBarCodeScannerInterface: 3802c8574ef119c150701d679ab386e2266d6a54
|
||||||
UMCameraInterface: 985d301f688ed392f815728f0dd906ca34b7ccb1
|
UMCameraInterface: 985d301f688ed392f815728f0dd906ca34b7ccb1
|
||||||
UMConstantsInterface: bda5f8bd3403ad99e663eb3c4da685d063c5653c
|
UMConstantsInterface: bda5f8bd3403ad99e663eb3c4da685d063c5653c
|
||||||
|
|||||||
@@ -13,6 +13,7 @@
|
|||||||
#import <UMCore/UMModuleRegistry.h>
|
#import <UMCore/UMModuleRegistry.h>
|
||||||
#import <UMReactNativeAdapter/UMNativeModulesProxy.h>
|
#import <UMReactNativeAdapter/UMNativeModulesProxy.h>
|
||||||
#import <UMReactNativeAdapter/UMModuleRegistryAdapter.h>
|
#import <UMReactNativeAdapter/UMModuleRegistryAdapter.h>
|
||||||
|
#import <React/RCTLinkingManager.h>
|
||||||
|
|
||||||
@implementation AppDelegate
|
@implementation AppDelegate
|
||||||
|
|
||||||
@@ -52,4 +53,10 @@
|
|||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
- (BOOL)application:(UIApplication *)app openURL:(NSURL *)url
|
||||||
|
options:(NSDictionary<UIApplicationOpenURLOptionsKey,id> *)options
|
||||||
|
{
|
||||||
|
return [RCTLinkingManager application:app openURL:url options:options];
|
||||||
|
}
|
||||||
|
|
||||||
@end
|
@end
|
||||||
|
|||||||
@@ -20,33 +20,27 @@
|
|||||||
<string>1.0</string>
|
<string>1.0</string>
|
||||||
<key>CFBundleSignature</key>
|
<key>CFBundleSignature</key>
|
||||||
<string>????</string>
|
<string>????</string>
|
||||||
|
<key>CFBundleURLTypes</key>
|
||||||
|
<array>
|
||||||
|
<dict>
|
||||||
|
<key>CFBundleTypeRole</key>
|
||||||
|
<string>Editor</string>
|
||||||
|
<key>CFBundleURLName</key>
|
||||||
|
<string>React Navigation Example</string>
|
||||||
|
<key>CFBundleURLSchemes</key>
|
||||||
|
<array>
|
||||||
|
<string>rne</string>
|
||||||
|
</array>
|
||||||
|
</dict>
|
||||||
|
</array>
|
||||||
<key>CFBundleVersion</key>
|
<key>CFBundleVersion</key>
|
||||||
<string>1</string>
|
<string>1</string>
|
||||||
<key>LSRequiresIPhoneOS</key>
|
<key>LSRequiresIPhoneOS</key>
|
||||||
<true/>
|
<true/>
|
||||||
<key>NSLocationWhenInUseUsageDescription</key>
|
|
||||||
<string></string>
|
|
||||||
<key>UILaunchStoryboardName</key>
|
|
||||||
<string>LaunchScreen</string>
|
|
||||||
<key>UIRequiredDeviceCapabilities</key>
|
|
||||||
<array>
|
|
||||||
<string>armv7</string>
|
|
||||||
</array>
|
|
||||||
<key>UISupportedInterfaceOrientations</key>
|
|
||||||
<array>
|
|
||||||
<string>UIInterfaceOrientationPortrait</string>
|
|
||||||
<string>UIInterfaceOrientationLandscapeLeft</string>
|
|
||||||
<string>UIInterfaceOrientationLandscapeRight</string>
|
|
||||||
</array>
|
|
||||||
<key>UIViewControllerBasedStatusBarAppearance</key>
|
|
||||||
<false/>
|
|
||||||
<key>NSLocationWhenInUseUsageDescription</key>
|
|
||||||
<string></string>
|
|
||||||
<key>NSAppTransportSecurity</key>
|
<key>NSAppTransportSecurity</key>
|
||||||
<!--See http://ste.vn/2015/06/10/configuring-app-transport-security-ios-9-osx-10-11/ -->
|
|
||||||
<dict>
|
<dict>
|
||||||
<key>NSAllowsArbitraryLoads</key>
|
<key>NSAllowsArbitraryLoads</key>
|
||||||
<true/>
|
<true/>
|
||||||
<key>NSExceptionDomains</key>
|
<key>NSExceptionDomains</key>
|
||||||
<dict>
|
<dict>
|
||||||
<key>localhost</key>
|
<key>localhost</key>
|
||||||
@@ -78,5 +72,19 @@
|
|||||||
<string>Give React Navigation Example periences permission to access your photos</string>
|
<string>Give React Navigation Example periences permission to access your photos</string>
|
||||||
<key>NSRemindersUsageDescription</key>
|
<key>NSRemindersUsageDescription</key>
|
||||||
<string>Allow React Navigation Example to access your reminders</string>
|
<string>Allow React Navigation Example to access your reminders</string>
|
||||||
|
<key>UILaunchStoryboardName</key>
|
||||||
|
<string>LaunchScreen</string>
|
||||||
|
<key>UIRequiredDeviceCapabilities</key>
|
||||||
|
<array>
|
||||||
|
<string>armv7</string>
|
||||||
|
</array>
|
||||||
|
<key>UISupportedInterfaceOrientations</key>
|
||||||
|
<array>
|
||||||
|
<string>UIInterfaceOrientationPortrait</string>
|
||||||
|
<string>UIInterfaceOrientationLandscapeLeft</string>
|
||||||
|
<string>UIInterfaceOrientationLandscapeRight</string>
|
||||||
|
</array>
|
||||||
|
<key>UIViewControllerBasedStatusBarAppearance</key>
|
||||||
|
<false/>
|
||||||
</dict>
|
</dict>
|
||||||
</plist>
|
</plist>
|
||||||
|
|||||||
@@ -6,7 +6,7 @@ const escape = require('escape-string-regexp');
|
|||||||
const blacklist = require('metro-config/src/defaults/blacklist');
|
const blacklist = require('metro-config/src/defaults/blacklist');
|
||||||
|
|
||||||
const root = path.resolve(__dirname, '..');
|
const root = path.resolve(__dirname, '..');
|
||||||
const packages = path.resolve(__dirname, '..', 'packages');
|
const packages = path.resolve(root, 'packages');
|
||||||
|
|
||||||
// Get the list of dependencies for all packages in the monorepo
|
// Get the list of dependencies for all packages in the monorepo
|
||||||
const modules = ['@expo/vector-icons']
|
const modules = ['@expo/vector-icons']
|
||||||
@@ -22,7 +22,7 @@ const modules = ['@expo/vector-icons']
|
|||||||
);
|
);
|
||||||
|
|
||||||
// We need to collect list of deps that this package imports
|
// We need to collect list of deps that this package imports
|
||||||
// Collecting both dependencies are peerDependencies sould do it
|
// Collecting both dependencies are peerDependencies should do it
|
||||||
return Object.keys({
|
return Object.keys({
|
||||||
...pak.dependencies,
|
...pak.dependencies,
|
||||||
...pak.peerDependencies,
|
...pak.peerDependencies,
|
||||||
@@ -59,7 +59,7 @@ module.exports = {
|
|||||||
// When we import a package from the monorepo, metro won't be able to find their deps
|
// When we import a package from the monorepo, metro won't be able to find their deps
|
||||||
// We need to specify them in `extraNodeModules` to tell metro where to find them
|
// We need to specify them in `extraNodeModules` to tell metro where to find them
|
||||||
extraNodeModules: modules.reduce((acc, name) => {
|
extraNodeModules: modules.reduce((acc, name) => {
|
||||||
acc[name] = path.join(__dirname, '..', 'node_modules', name);
|
acc[name] = path.join(root, 'node_modules', name);
|
||||||
return acc;
|
return acc;
|
||||||
}, {}),
|
}, {}),
|
||||||
},
|
},
|
||||||
@@ -67,11 +67,11 @@ module.exports = {
|
|||||||
server: {
|
server: {
|
||||||
enhanceMiddleware: middleware => {
|
enhanceMiddleware: middleware => {
|
||||||
return (req, res, next) => {
|
return (req, res, next) => {
|
||||||
|
// When an asset is imported outside the project root, it has wrong path on Android
|
||||||
|
// This happens for the back button in stack, so we fix the path to correct one
|
||||||
const assets = '/packages/stack/src/views/assets';
|
const assets = '/packages/stack/src/views/assets';
|
||||||
|
|
||||||
if (req.url.startsWith(assets)) {
|
if (req.url.startsWith(assets)) {
|
||||||
// When an asset is imported outside the project root, it has wrong path on Android
|
|
||||||
// This happens for the back button in stack, so we fix the path to correct one
|
|
||||||
req.url = req.url.replace(
|
req.url = req.url.replace(
|
||||||
assets,
|
assets,
|
||||||
'/assets/../packages/stack/src/views/assets'
|
'/assets/../packages/stack/src/views/assets'
|
||||||
|
|||||||
@@ -5,7 +5,7 @@
|
|||||||
"private": true,
|
"private": true,
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"start": "expo start",
|
"start": "expo start",
|
||||||
"web": "expo start --web",
|
"web": "expo start:web",
|
||||||
"native": "react-native start",
|
"native": "react-native start",
|
||||||
"android": "react-native run-android",
|
"android": "react-native run-android",
|
||||||
"ios": "react-native run-ios"
|
"ios": "react-native run-ios"
|
||||||
@@ -13,6 +13,7 @@
|
|||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@expo/vector-icons": "^10.0.0",
|
"@expo/vector-icons": "^10.0.0",
|
||||||
"@react-native-community/masked-view": "0.1.5",
|
"@react-native-community/masked-view": "0.1.5",
|
||||||
|
"@types/react-native-restart": "^0.0.0",
|
||||||
"color": "^3.1.2",
|
"color": "^3.1.2",
|
||||||
"expo": "^36.0.2",
|
"expo": "^36.0.2",
|
||||||
"expo-asset": "~8.0.0",
|
"expo-asset": "~8.0.0",
|
||||||
@@ -20,12 +21,13 @@
|
|||||||
"react": "~16.9.0",
|
"react": "~16.9.0",
|
||||||
"react-dom": "~16.9.0",
|
"react-dom": "~16.9.0",
|
||||||
"react-native": "~0.61.5",
|
"react-native": "~0.61.5",
|
||||||
"react-native-gesture-handler": "~1.5.3",
|
"react-native-gesture-handler": "^1.5.5",
|
||||||
"react-native-paper": "^3.5.0",
|
"react-native-paper": "^3.5.0",
|
||||||
"react-native-reanimated": "^1.4.0",
|
"react-native-reanimated": "^1.4.0",
|
||||||
|
"react-native-restart": "^0.0.13",
|
||||||
"react-native-safe-area-context": "^0.6.2",
|
"react-native-safe-area-context": "^0.6.2",
|
||||||
"react-native-screens": "^2.0.0-alpha.25",
|
"react-native-screens": "^2.0.0-alpha.33",
|
||||||
"react-native-tab-view": "2.11.0",
|
"react-native-tab-view": "2.13.0",
|
||||||
"react-native-unimodules": "^0.7.0",
|
"react-native-unimodules": "^0.7.0",
|
||||||
"react-native-web": "^0.11.7"
|
"react-native-web": "^0.11.7"
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -1 +1 @@
|
|||||||
export default [];
|
export default ['rne://127.0.0.1:19000/--/'];
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
import * as React from 'react';
|
import * as React from 'react';
|
||||||
import { View, TextInput, ActivityIndicator, StyleSheet } from 'react-native';
|
import { View, TextInput, ActivityIndicator, StyleSheet } from 'react-native';
|
||||||
import { Title, Button } from 'react-native-paper';
|
import { Title, Button } from 'react-native-paper';
|
||||||
import { ParamListBase } from '@react-navigation/native';
|
import { useTheme, ParamListBase } from '@react-navigation/native';
|
||||||
import {
|
import {
|
||||||
createStackNavigator,
|
createStackNavigator,
|
||||||
HeaderBackButton,
|
HeaderBackButton,
|
||||||
@@ -40,11 +40,25 @@ const SplashScreen = () => {
|
|||||||
|
|
||||||
const SignInScreen = () => {
|
const SignInScreen = () => {
|
||||||
const { signIn } = React.useContext(AuthContext);
|
const { signIn } = React.useContext(AuthContext);
|
||||||
|
const { colors } = useTheme();
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<View style={styles.content}>
|
<View style={styles.content}>
|
||||||
<TextInput placeholder="Username" style={styles.input} />
|
<TextInput
|
||||||
<TextInput placeholder="Password" secureTextEntry style={styles.input} />
|
placeholder="Username"
|
||||||
|
style={[
|
||||||
|
styles.input,
|
||||||
|
{ backgroundColor: colors.card, color: colors.text },
|
||||||
|
]}
|
||||||
|
/>
|
||||||
|
<TextInput
|
||||||
|
placeholder="Password"
|
||||||
|
secureTextEntry
|
||||||
|
style={[
|
||||||
|
styles.input,
|
||||||
|
{ backgroundColor: colors.card, color: colors.text },
|
||||||
|
]}
|
||||||
|
/>
|
||||||
<Button mode="contained" onPress={signIn} style={styles.button}>
|
<Button mode="contained" onPress={signIn} style={styles.button}>
|
||||||
Sign in
|
Sign in
|
||||||
</Button>
|
</Button>
|
||||||
@@ -73,6 +87,7 @@ type Props = {
|
|||||||
|
|
||||||
type State = {
|
type State = {
|
||||||
isLoading: boolean;
|
isLoading: boolean;
|
||||||
|
isSignout: boolean;
|
||||||
userToken: undefined | string;
|
userToken: undefined | string;
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -94,17 +109,20 @@ export default function SimpleStackScreen({ navigation }: Props) {
|
|||||||
case 'SIGN_IN':
|
case 'SIGN_IN':
|
||||||
return {
|
return {
|
||||||
...prevState,
|
...prevState,
|
||||||
|
isSignout: false,
|
||||||
userToken: action.token,
|
userToken: action.token,
|
||||||
};
|
};
|
||||||
case 'SIGN_OUT':
|
case 'SIGN_OUT':
|
||||||
return {
|
return {
|
||||||
...prevState,
|
...prevState,
|
||||||
|
isSignout: true,
|
||||||
userToken: undefined,
|
userToken: undefined,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
isLoading: true,
|
isLoading: true,
|
||||||
|
isSignout: false,
|
||||||
userToken: undefined,
|
userToken: undefined,
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
@@ -147,7 +165,10 @@ export default function SimpleStackScreen({ navigation }: Props) {
|
|||||||
) : state.userToken === undefined ? (
|
) : state.userToken === undefined ? (
|
||||||
<SimpleStack.Screen
|
<SimpleStack.Screen
|
||||||
name="SignIn"
|
name="SignIn"
|
||||||
options={{ title: 'Sign in' }}
|
options={{
|
||||||
|
title: 'Sign in',
|
||||||
|
animationTypeForReplace: state.isSignout ? 'pop' : 'push',
|
||||||
|
}}
|
||||||
component={SignInScreen}
|
component={SignInScreen}
|
||||||
/>
|
/>
|
||||||
) : (
|
) : (
|
||||||
@@ -171,7 +192,6 @@ const styles = StyleSheet.create({
|
|||||||
input: {
|
input: {
|
||||||
margin: 8,
|
margin: 8,
|
||||||
padding: 10,
|
padding: 10,
|
||||||
backgroundColor: 'white',
|
|
||||||
borderRadius: 3,
|
borderRadius: 3,
|
||||||
borderWidth: StyleSheet.hairlineWidth,
|
borderWidth: StyleSheet.hairlineWidth,
|
||||||
borderColor: 'rgba(0, 0, 0, 0.08)',
|
borderColor: 'rgba(0, 0, 0, 0.08)',
|
||||||
|
|||||||
154
example/src/Screens/StackTransparent.tsx
Normal file
@@ -0,0 +1,154 @@
|
|||||||
|
import * as React from 'react';
|
||||||
|
import { View, StyleSheet, ScrollView } from 'react-native';
|
||||||
|
import { Button, Paragraph } from 'react-native-paper';
|
||||||
|
import { RouteProp, ParamListBase, useTheme } from '@react-navigation/native';
|
||||||
|
import {
|
||||||
|
createStackNavigator,
|
||||||
|
StackNavigationProp,
|
||||||
|
} from '@react-navigation/stack';
|
||||||
|
import Article from '../Shared/Article';
|
||||||
|
|
||||||
|
type SimpleStackParams = {
|
||||||
|
Article: { author: string };
|
||||||
|
Dialog: undefined;
|
||||||
|
};
|
||||||
|
|
||||||
|
type SimpleStackNavigation = StackNavigationProp<SimpleStackParams>;
|
||||||
|
|
||||||
|
const ArticleScreen = ({
|
||||||
|
navigation,
|
||||||
|
route,
|
||||||
|
}: {
|
||||||
|
navigation: SimpleStackNavigation;
|
||||||
|
route: RouteProp<SimpleStackParams, 'Article'>;
|
||||||
|
}) => {
|
||||||
|
return (
|
||||||
|
<ScrollView>
|
||||||
|
<View style={styles.buttons}>
|
||||||
|
<Button
|
||||||
|
mode="contained"
|
||||||
|
onPress={() => navigation.push('Dialog')}
|
||||||
|
style={styles.button}
|
||||||
|
>
|
||||||
|
Show Dialog
|
||||||
|
</Button>
|
||||||
|
<Button
|
||||||
|
mode="outlined"
|
||||||
|
onPress={() => navigation.goBack()}
|
||||||
|
style={styles.button}
|
||||||
|
>
|
||||||
|
Go back
|
||||||
|
</Button>
|
||||||
|
</View>
|
||||||
|
<Article author={{ name: route.params.author }} scrollEnabled={false} />
|
||||||
|
</ScrollView>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
const DialogScreen = ({
|
||||||
|
navigation,
|
||||||
|
}: {
|
||||||
|
navigation: SimpleStackNavigation;
|
||||||
|
}) => {
|
||||||
|
const { colors } = useTheme();
|
||||||
|
|
||||||
|
return (
|
||||||
|
<View style={styles.container}>
|
||||||
|
<View style={[styles.dialog, { backgroundColor: colors.card }]}>
|
||||||
|
<Paragraph>
|
||||||
|
Mise en place is a French term that literally means “put in place.” It
|
||||||
|
also refers to a way cooks in professional kitchens and restaurants
|
||||||
|
set up their work stations—first by gathering all ingredients for a
|
||||||
|
recipes, partially preparing them (like measuring out and chopping),
|
||||||
|
and setting them all near each other. Setting up mise en place before
|
||||||
|
cooking is another top tip for home cooks, as it seriously helps with
|
||||||
|
organization. It’ll pretty much guarantee you never forget to add an
|
||||||
|
ingredient and save you time from running back and forth from the
|
||||||
|
pantry ten times.
|
||||||
|
</Paragraph>
|
||||||
|
<Button style={styles.close} compact onPress={navigation.goBack}>
|
||||||
|
Okay
|
||||||
|
</Button>
|
||||||
|
</View>
|
||||||
|
</View>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
const SimpleStack = createStackNavigator<SimpleStackParams>();
|
||||||
|
|
||||||
|
type Props = Partial<React.ComponentProps<typeof SimpleStack.Navigator>> & {
|
||||||
|
navigation: StackNavigationProp<ParamListBase>;
|
||||||
|
};
|
||||||
|
|
||||||
|
export default function SimpleStackScreen({ navigation, ...rest }: Props) {
|
||||||
|
navigation.setOptions({
|
||||||
|
headerShown: false,
|
||||||
|
});
|
||||||
|
|
||||||
|
return (
|
||||||
|
<SimpleStack.Navigator mode="modal" {...rest}>
|
||||||
|
<SimpleStack.Screen
|
||||||
|
name="Article"
|
||||||
|
component={ArticleScreen}
|
||||||
|
initialParams={{ author: 'Gandalf' }}
|
||||||
|
/>
|
||||||
|
<SimpleStack.Screen
|
||||||
|
name="Dialog"
|
||||||
|
component={DialogScreen}
|
||||||
|
options={{
|
||||||
|
headerShown: false,
|
||||||
|
cardStyle: { backgroundColor: 'transparent' },
|
||||||
|
cardOverlayEnabled: true,
|
||||||
|
cardStyleInterpolator: ({ current: { progress } }) => ({
|
||||||
|
cardStyle: {
|
||||||
|
opacity: progress.interpolate({
|
||||||
|
inputRange: [0, 0.5, 0.9, 1],
|
||||||
|
outputRange: [0, 0.25, 0.7, 1],
|
||||||
|
}),
|
||||||
|
transform: [
|
||||||
|
{
|
||||||
|
scale: progress.interpolate({
|
||||||
|
inputRange: [0, 1],
|
||||||
|
outputRange: [0.9, 1],
|
||||||
|
extrapolate: 'clamp',
|
||||||
|
}),
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
overlayStyle: {
|
||||||
|
opacity: progress.interpolate({
|
||||||
|
inputRange: [0, 1],
|
||||||
|
outputRange: [0, 0.5],
|
||||||
|
extrapolate: 'clamp',
|
||||||
|
}),
|
||||||
|
},
|
||||||
|
}),
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
</SimpleStack.Navigator>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
const styles = StyleSheet.create({
|
||||||
|
buttons: {
|
||||||
|
flexDirection: 'row',
|
||||||
|
padding: 8,
|
||||||
|
},
|
||||||
|
button: {
|
||||||
|
margin: 8,
|
||||||
|
},
|
||||||
|
container: {
|
||||||
|
flex: 1,
|
||||||
|
alignItems: 'center',
|
||||||
|
justifyContent: 'center',
|
||||||
|
},
|
||||||
|
dialog: {
|
||||||
|
padding: 16,
|
||||||
|
width: '90%',
|
||||||
|
maxWidth: 400,
|
||||||
|
borderRadius: 3,
|
||||||
|
},
|
||||||
|
close: {
|
||||||
|
alignSelf: 'flex-end',
|
||||||
|
},
|
||||||
|
});
|
||||||
@@ -2,23 +2,41 @@
|
|||||||
|
|
||||||
import * as React from 'react';
|
import * as React from 'react';
|
||||||
import {
|
import {
|
||||||
|
View,
|
||||||
Image,
|
Image,
|
||||||
Dimensions,
|
|
||||||
ScrollView,
|
ScrollView,
|
||||||
StyleSheet,
|
StyleSheet,
|
||||||
ScrollViewProps,
|
ScrollViewProps,
|
||||||
|
Dimensions,
|
||||||
|
Platform,
|
||||||
} from 'react-native';
|
} from 'react-native';
|
||||||
import { useScrollToTop } from '@react-navigation/native';
|
import { useScrollToTop } from '@react-navigation/native';
|
||||||
|
|
||||||
const COVERS = [
|
const COVERS = [
|
||||||
require('../../assets/album-art-1.jpg'),
|
require('../../assets/album-art-01.jpg'),
|
||||||
require('../../assets/album-art-2.jpg'),
|
require('../../assets/album-art-02.jpg'),
|
||||||
require('../../assets/album-art-3.jpg'),
|
require('../../assets/album-art-03.jpg'),
|
||||||
require('../../assets/album-art-4.jpg'),
|
require('../../assets/album-art-04.jpg'),
|
||||||
require('../../assets/album-art-5.jpg'),
|
require('../../assets/album-art-05.jpg'),
|
||||||
require('../../assets/album-art-6.jpg'),
|
require('../../assets/album-art-06.jpg'),
|
||||||
require('../../assets/album-art-7.jpg'),
|
require('../../assets/album-art-07.jpg'),
|
||||||
require('../../assets/album-art-8.jpg'),
|
require('../../assets/album-art-08.jpg'),
|
||||||
|
require('../../assets/album-art-09.jpg'),
|
||||||
|
require('../../assets/album-art-10.jpg'),
|
||||||
|
require('../../assets/album-art-11.jpg'),
|
||||||
|
require('../../assets/album-art-12.jpg'),
|
||||||
|
require('../../assets/album-art-13.jpg'),
|
||||||
|
require('../../assets/album-art-14.jpg'),
|
||||||
|
require('../../assets/album-art-15.jpg'),
|
||||||
|
require('../../assets/album-art-16.jpg'),
|
||||||
|
require('../../assets/album-art-17.jpg'),
|
||||||
|
require('../../assets/album-art-18.jpg'),
|
||||||
|
require('../../assets/album-art-19.jpg'),
|
||||||
|
require('../../assets/album-art-20.jpg'),
|
||||||
|
require('../../assets/album-art-21.jpg'),
|
||||||
|
require('../../assets/album-art-22.jpg'),
|
||||||
|
require('../../assets/album-art-23.jpg'),
|
||||||
|
require('../../assets/album-art-24.jpg'),
|
||||||
];
|
];
|
||||||
|
|
||||||
export default function Albums(props: Partial<ScrollViewProps>) {
|
export default function Albums(props: Partial<ScrollViewProps>) {
|
||||||
@@ -27,34 +45,46 @@ export default function Albums(props: Partial<ScrollViewProps>) {
|
|||||||
useScrollToTop(ref);
|
useScrollToTop(ref);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<ScrollView
|
<ScrollView ref={ref} contentContainerStyle={styles.content} {...props}>
|
||||||
ref={ref}
|
|
||||||
style={styles.container}
|
|
||||||
contentContainerStyle={styles.content}
|
|
||||||
{...props}
|
|
||||||
>
|
|
||||||
{COVERS.map((source, i) => (
|
{COVERS.map((source, i) => (
|
||||||
// eslint-disable-next-line react/no-array-index-key
|
// eslint-disable-next-line react/no-array-index-key
|
||||||
<Image key={i} source={source} style={styles.cover} />
|
<View key={i} style={styles.item}>
|
||||||
))}
|
<Image source={source} style={styles.photo} />
|
||||||
{COVERS.map((source, i) => (
|
</View>
|
||||||
// eslint-disable-next-line react/no-array-index-key
|
|
||||||
<Image key={i + 'F'} source={source} style={styles.cover} />
|
|
||||||
))}
|
))}
|
||||||
</ScrollView>
|
</ScrollView>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
const styles = StyleSheet.create({
|
const styles = StyleSheet.create({
|
||||||
container: {
|
|
||||||
backgroundColor: '#000',
|
|
||||||
},
|
|
||||||
content: {
|
content: {
|
||||||
flexDirection: 'row',
|
flexDirection: 'row',
|
||||||
flexWrap: 'wrap',
|
flexWrap: 'wrap',
|
||||||
},
|
},
|
||||||
cover: {
|
...Platform.select({
|
||||||
width: '50%',
|
web: {
|
||||||
height: Dimensions.get('window').width / 2,
|
content: {
|
||||||
|
display: 'grid' as 'none',
|
||||||
|
gridTemplateColumns: 'repeat(auto-fill, minmax(150px, 1fr))',
|
||||||
|
},
|
||||||
|
item: {
|
||||||
|
width: '100%',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
default: {
|
||||||
|
content: {
|
||||||
|
flexDirection: 'row',
|
||||||
|
flexWrap: 'wrap',
|
||||||
|
},
|
||||||
|
item: {
|
||||||
|
height: Dimensions.get('window').width / 2,
|
||||||
|
width: '50%',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}),
|
||||||
|
photo: {
|
||||||
|
flex: 1,
|
||||||
|
resizeMode: 'cover',
|
||||||
|
paddingTop: '100%',
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -7,6 +7,7 @@ import {
|
|||||||
StatusBar,
|
StatusBar,
|
||||||
I18nManager,
|
I18nManager,
|
||||||
} from 'react-native';
|
} from 'react-native';
|
||||||
|
import RNRestart from 'react-native-restart';
|
||||||
import { MaterialIcons } from '@expo/vector-icons';
|
import { MaterialIcons } from '@expo/vector-icons';
|
||||||
import {
|
import {
|
||||||
Provider as PaperProvider,
|
Provider as PaperProvider,
|
||||||
@@ -40,6 +41,7 @@ import LinkingPrefixes from './LinkingPrefixes';
|
|||||||
import SimpleStack from './Screens/SimpleStack';
|
import SimpleStack from './Screens/SimpleStack';
|
||||||
import NativeStack from './Screens/NativeStack';
|
import NativeStack from './Screens/NativeStack';
|
||||||
import ModalPresentationStack from './Screens/ModalPresentationStack';
|
import ModalPresentationStack from './Screens/ModalPresentationStack';
|
||||||
|
import StackTransparent from './Screens/StackTransparent';
|
||||||
import StackHeaderCustomization from './Screens/StackHeaderCustomization';
|
import StackHeaderCustomization from './Screens/StackHeaderCustomization';
|
||||||
import BottomTabs from './Screens/BottomTabs';
|
import BottomTabs from './Screens/BottomTabs';
|
||||||
import MaterialTopTabsScreen from './Screens/MaterialTopTabs';
|
import MaterialTopTabsScreen from './Screens/MaterialTopTabs';
|
||||||
@@ -70,6 +72,10 @@ const SCREENS = {
|
|||||||
title: 'Modal Presentation Stack',
|
title: 'Modal Presentation Stack',
|
||||||
component: ModalPresentationStack,
|
component: ModalPresentationStack,
|
||||||
},
|
},
|
||||||
|
StackTransparent: {
|
||||||
|
title: 'Transparent Stack',
|
||||||
|
component: StackTransparent,
|
||||||
|
},
|
||||||
StackHeaderCustomization: {
|
StackHeaderCustomization: {
|
||||||
title: 'Header Customization in Stack',
|
title: 'Header Customization in Stack',
|
||||||
component: StackHeaderCustomization,
|
component: StackHeaderCustomization,
|
||||||
@@ -111,22 +117,27 @@ export default function App() {
|
|||||||
// To test deep linking on, run the following in the Terminal:
|
// To test deep linking on, run the following in the Terminal:
|
||||||
// Android: adb shell am start -a android.intent.action.VIEW -d "exp://127.0.0.1:19000/--/simple-stack"
|
// Android: adb shell am start -a android.intent.action.VIEW -d "exp://127.0.0.1:19000/--/simple-stack"
|
||||||
// iOS: xcrun simctl openurl booted exp://127.0.0.1:19000/--/simple-stack
|
// iOS: xcrun simctl openurl booted exp://127.0.0.1:19000/--/simple-stack
|
||||||
|
// Android (bare): adb shell am start -a android.intent.action.VIEW -d "rne://127.0.0.1:19000/--/simple-stack"
|
||||||
|
// iOS (bare): xcrun simctl openurl booted rne://127.0.0.1:19000/--/simple-stack
|
||||||
// The first segment of the link is the the scheme + host (returned by `Linking.makeUrl`)
|
// The first segment of the link is the the scheme + host (returned by `Linking.makeUrl`)
|
||||||
const { getInitialState } = useLinking(containerRef, {
|
const { getInitialState } = useLinking(containerRef, {
|
||||||
prefixes: LinkingPrefixes,
|
prefixes: LinkingPrefixes,
|
||||||
config: {
|
config: {
|
||||||
Root: Object.keys(SCREENS).reduce<{ [key: string]: string }>(
|
Root: {
|
||||||
(acc, name) => {
|
path: 'root',
|
||||||
// Convert screen names such as SimpleStack to kebab case (simple-stack)
|
screens: Object.keys(SCREENS).reduce<{ [key: string]: string }>(
|
||||||
acc[name] = name
|
(acc, name) => {
|
||||||
.replace(/([A-Z]+)/g, '-$1')
|
// Convert screen names such as SimpleStack to kebab case (simple-stack)
|
||||||
.replace(/^-/, '')
|
acc[name] = name
|
||||||
.toLowerCase();
|
.replace(/([A-Z]+)/g, '-$1')
|
||||||
|
.replace(/^-/, '')
|
||||||
|
.toLowerCase();
|
||||||
|
|
||||||
return acc;
|
return acc;
|
||||||
},
|
},
|
||||||
{}
|
{}
|
||||||
),
|
),
|
||||||
|
},
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -142,7 +153,7 @@ export default function App() {
|
|||||||
try {
|
try {
|
||||||
let state = await getInitialState();
|
let state = await getInitialState();
|
||||||
|
|
||||||
if (state === undefined) {
|
if (Platform.OS !== 'web' && state === undefined) {
|
||||||
const savedState = await AsyncStorage.getItem(
|
const savedState = await AsyncStorage.getItem(
|
||||||
NAVIGATION_PERSISTENCE_KEY
|
NAVIGATION_PERSISTENCE_KEY
|
||||||
);
|
);
|
||||||
@@ -248,7 +259,12 @@ export default function App() {
|
|||||||
value={I18nManager.isRTL}
|
value={I18nManager.isRTL}
|
||||||
onValueChange={() => {
|
onValueChange={() => {
|
||||||
I18nManager.forceRTL(!I18nManager.isRTL);
|
I18nManager.forceRTL(!I18nManager.isRTL);
|
||||||
Updates.reloadFromCache();
|
// @ts-ignore
|
||||||
|
if (global.Expo) {
|
||||||
|
Updates.reloadFromCache();
|
||||||
|
} else {
|
||||||
|
RNRestart.Restart();
|
||||||
|
}
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
<Divider />
|
<Divider />
|
||||||
@@ -270,7 +286,7 @@ export default function App() {
|
|||||||
<List.Item
|
<List.Item
|
||||||
key={name}
|
key={name}
|
||||||
title={SCREENS[name].title}
|
title={SCREENS[name].title}
|
||||||
onPress={() => navigation.push(name)}
|
onPress={() => navigation.navigate(name)}
|
||||||
/>
|
/>
|
||||||
)
|
)
|
||||||
)}
|
)}
|
||||||
|
|||||||
@@ -10,6 +10,8 @@ const packages = path.resolve(__dirname, '..', 'packages');
|
|||||||
module.exports = async function(env, argv) {
|
module.exports = async function(env, argv) {
|
||||||
const config = await createExpoWebpackConfigAsync(env, argv);
|
const config = await createExpoWebpackConfigAsync(env, argv);
|
||||||
|
|
||||||
|
config.context = path.resolve(__dirname, '..');
|
||||||
|
|
||||||
config.module.rules.push({
|
config.module.rules.push({
|
||||||
test: /\.(js|ts|tsx)$/,
|
test: /\.(js|ts|tsx)$/,
|
||||||
include: /(packages|example)\/.+/,
|
include: /(packages|example)\/.+/,
|
||||||
|
|||||||
@@ -64,7 +64,8 @@
|
|||||||
],
|
],
|
||||||
"moduleNameMapper": {
|
"moduleNameMapper": {
|
||||||
"@react-navigation/([^/]+)": "<rootDir>/packages/$1/src"
|
"@react-navigation/([^/]+)": "<rootDir>/packages/$1/src"
|
||||||
}
|
},
|
||||||
|
"preset": "react-native"
|
||||||
},
|
},
|
||||||
"prettier": {
|
"prettier": {
|
||||||
"tabWidth": 2,
|
"tabWidth": 2,
|
||||||
|
|||||||
@@ -3,6 +3,47 @@
|
|||||||
All notable changes to this project will be documented in this file.
|
All notable changes to this project will be documented in this file.
|
||||||
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
||||||
|
|
||||||
|
# [5.0.0-alpha.43](https://github.com/react-navigation/navigation-ex/tree/master/packages/bottom-tabs/compare/@react-navigation/bottom-tabs@5.0.0-alpha.42...@react-navigation/bottom-tabs@5.0.0-alpha.43) (2020-02-03)
|
||||||
|
|
||||||
|
**Note:** Version bump only for package @react-navigation/bottom-tabs
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
# [5.0.0-alpha.42](https://github.com/react-navigation/navigation-ex/tree/master/packages/bottom-tabs/compare/@react-navigation/bottom-tabs@5.0.0-alpha.39...@react-navigation/bottom-tabs@5.0.0-alpha.42) (2020-02-02)
|
||||||
|
|
||||||
|
|
||||||
|
### Bug Fixes
|
||||||
|
|
||||||
|
* add licenses ([0c159db](https://github.com/react-navigation/navigation-ex/tree/master/packages/bottom-tabs/commit/0c159db4c9bc85e83b5cfe6819ab2562669a4d8f))
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
# [5.0.0-alpha.40](https://github.com/react-navigation/navigation-ex/tree/master/packages/bottom-tabs/compare/@react-navigation/bottom-tabs@5.0.0-alpha.39...@react-navigation/bottom-tabs@5.0.0-alpha.40) (2020-02-02)
|
||||||
|
|
||||||
|
|
||||||
|
### Bug Fixes
|
||||||
|
|
||||||
|
* add licenses ([0c159db](https://github.com/react-navigation/navigation-ex/tree/master/packages/bottom-tabs/commit/0c159db4c9bc85e83b5cfe6819ab2562669a4d8f))
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
# [5.0.0-alpha.39](https://github.com/react-navigation/navigation-ex/tree/master/packages/bottom-tabs/compare/@react-navigation/bottom-tabs@5.0.0-alpha.38...@react-navigation/bottom-tabs@5.0.0-alpha.39) (2020-01-24)
|
||||||
|
|
||||||
|
|
||||||
|
### Bug Fixes
|
||||||
|
|
||||||
|
* use layout instead of dimensions for determining tab bar layout ([f1fe951](https://github.com/react-navigation/navigation-ex/tree/master/packages/bottom-tabs/commit/f1fe951cf9d602e1b6d4932e3c6c77bbeaaec5c0))
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
# [5.0.0-alpha.38](https://github.com/react-navigation/navigation-ex/tree/master/packages/bottom-tabs/compare/@react-navigation/bottom-tabs@5.0.0-alpha.37...@react-navigation/bottom-tabs@5.0.0-alpha.38) (2020-01-23)
|
# [5.0.0-alpha.38](https://github.com/react-navigation/navigation-ex/tree/master/packages/bottom-tabs/compare/@react-navigation/bottom-tabs@5.0.0-alpha.37...@react-navigation/bottom-tabs@5.0.0-alpha.38) (2020-01-23)
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
21
packages/bottom-tabs/LICENSE
Normal file
@@ -0,0 +1,21 @@
|
|||||||
|
MIT License
|
||||||
|
|
||||||
|
Copyright (c) 2017 React Navigation Contributors
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
of this software and associated documentation files (the "Software"), to deal
|
||||||
|
in the Software without restriction, including without limitation the rights
|
||||||
|
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
copies of the Software, and to permit persons to whom the Software is
|
||||||
|
furnished to do so, subject to the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be included in all
|
||||||
|
copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
SOFTWARE.
|
||||||
@@ -10,7 +10,7 @@
|
|||||||
"android",
|
"android",
|
||||||
"tab"
|
"tab"
|
||||||
],
|
],
|
||||||
"version": "5.0.0-alpha.38",
|
"version": "5.0.0-alpha.43",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"repository": "https://github.com/react-navigation/navigation-ex/tree/master/packages/bottom-tabs",
|
"repository": "https://github.com/react-navigation/navigation-ex/tree/master/packages/bottom-tabs",
|
||||||
"main": "lib/commonjs/index.js",
|
"main": "lib/commonjs/index.js",
|
||||||
@@ -30,7 +30,7 @@
|
|||||||
"clean": "del lib"
|
"clean": "del lib"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@react-navigation/routers": "^5.0.0-alpha.26",
|
"@react-navigation/routers": "^5.0.0-alpha.31",
|
||||||
"color": "^3.1.2",
|
"color": "^3.1.2",
|
||||||
"react-native-iphone-x-helper": "^1.2.1"
|
"react-native-iphone-x-helper": "^1.2.1"
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -99,6 +99,12 @@ export type BottomTabNavigationOptions = {
|
|||||||
* Renders `TouchableWithoutFeedback` by default.
|
* Renders `TouchableWithoutFeedback` by default.
|
||||||
*/
|
*/
|
||||||
tabBarButton?: (props: BottomTabBarButtonProps) => React.ReactNode;
|
tabBarButton?: (props: BottomTabBarButtonProps) => React.ReactNode;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Whether this screen should be unmounted when navigating away from it.
|
||||||
|
* Defaults to `false`.
|
||||||
|
*/
|
||||||
|
unmountOnBlur?: boolean;
|
||||||
};
|
};
|
||||||
|
|
||||||
export type BottomTabDescriptor = Descriptor<
|
export type BottomTabDescriptor = Descriptor<
|
||||||
@@ -118,11 +124,6 @@ export type BottomTabNavigationConfig = {
|
|||||||
* Set it to `false` if you want to render all screens on initial render.
|
* Set it to `false` if you want to render all screens on initial render.
|
||||||
*/
|
*/
|
||||||
lazy?: boolean;
|
lazy?: boolean;
|
||||||
/**
|
|
||||||
* Whether a screen should be unmounted when navigating away from it.
|
|
||||||
* Defaults to `false`.
|
|
||||||
*/
|
|
||||||
unmountInactiveScreens?: boolean;
|
|
||||||
/**
|
/**
|
||||||
* Function that returns a React element to display as the tab bar.
|
* Function that returns a React element to display as the tab bar.
|
||||||
*/
|
*/
|
||||||
@@ -176,14 +177,9 @@ export type BottomTabBarOptions = {
|
|||||||
tabStyle?: StyleProp<ViewStyle>;
|
tabStyle?: StyleProp<ViewStyle>;
|
||||||
/**
|
/**
|
||||||
* Whether the label is renderd below the icon or beside the icon.
|
* Whether the label is renderd below the icon or beside the icon.
|
||||||
* When a function is passed, it receives the device dimensions to render the label differently.
|
|
||||||
* By default, in `vertical` orinetation, label is rendered below and in `horizontal` orientation, it's renderd beside.
|
* By default, in `vertical` orinetation, label is rendered below and in `horizontal` orientation, it's renderd beside.
|
||||||
*/
|
*/
|
||||||
labelPosition?:
|
labelPosition?: LabelPosition;
|
||||||
| LabelPosition
|
|
||||||
| ((options: {
|
|
||||||
dimensions: { height: number; width: number };
|
|
||||||
}) => LabelPosition);
|
|
||||||
/**
|
/**
|
||||||
* Whether the label position should adapt to the orientation.
|
* Whether the label position should adapt to the orientation.
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -50,7 +50,10 @@ export default function BottomTabBar({
|
|||||||
const { colors } = useTheme();
|
const { colors } = useTheme();
|
||||||
|
|
||||||
const [dimensions, setDimensions] = React.useState(Dimensions.get('window'));
|
const [dimensions, setDimensions] = React.useState(Dimensions.get('window'));
|
||||||
const [layout, setLayout] = React.useState({ height: 0, width: 0 });
|
const [layout, setLayout] = React.useState({
|
||||||
|
height: 0,
|
||||||
|
width: dimensions.width,
|
||||||
|
});
|
||||||
const [keyboardShown, setKeyboardShown] = React.useState(false);
|
const [keyboardShown, setKeyboardShown] = React.useState(false);
|
||||||
|
|
||||||
const [visible] = React.useState(() => new Animated.Value(0));
|
const [visible] = React.useState(() => new Animated.Value(0));
|
||||||
@@ -124,27 +127,15 @@ export default function BottomTabBar({
|
|||||||
};
|
};
|
||||||
|
|
||||||
const shouldUseHorizontalLabels = () => {
|
const shouldUseHorizontalLabels = () => {
|
||||||
const isLandscape = dimensions.width > dimensions.height;
|
|
||||||
|
|
||||||
if (labelPosition) {
|
if (labelPosition) {
|
||||||
let position;
|
return labelPosition === 'beside-icon';
|
||||||
|
|
||||||
if (typeof labelPosition === 'string') {
|
|
||||||
position = labelPosition;
|
|
||||||
} else {
|
|
||||||
position = labelPosition({ dimensions });
|
|
||||||
}
|
|
||||||
|
|
||||||
if (position) {
|
|
||||||
return position === 'beside-icon';
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!adaptive) {
|
if (!adaptive) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (dimensions.width >= 768) {
|
if (layout.width >= 768) {
|
||||||
// Screen size matches a tablet
|
// Screen size matches a tablet
|
||||||
let maxTabItemWidth = DEFAULT_MAX_TAB_ITEM_WIDTH;
|
let maxTabItemWidth = DEFAULT_MAX_TAB_ITEM_WIDTH;
|
||||||
|
|
||||||
@@ -158,8 +149,10 @@ export default function BottomTabBar({
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return routes.length * maxTabItemWidth <= dimensions.width;
|
return routes.length * maxTabItemWidth <= layout.width;
|
||||||
} else {
|
} else {
|
||||||
|
const isLandscape = dimensions.width > dimensions.height;
|
||||||
|
|
||||||
return isLandscape;
|
return isLandscape;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -92,7 +92,7 @@ export default class BottomTabView extends React.Component<Props, State> {
|
|||||||
};
|
};
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
const { state, descriptors, lazy, unmountInactiveScreens } = this.props;
|
const { state, descriptors, lazy } = this.props;
|
||||||
const { routes } = state;
|
const { routes } = state;
|
||||||
const { loaded } = this.state;
|
const { loaded } = this.state;
|
||||||
|
|
||||||
@@ -101,17 +101,19 @@ export default class BottomTabView extends React.Component<Props, State> {
|
|||||||
<View style={styles.container}>
|
<View style={styles.container}>
|
||||||
<ScreenContainer style={styles.pages}>
|
<ScreenContainer style={styles.pages}>
|
||||||
{routes.map((route, index) => {
|
{routes.map((route, index) => {
|
||||||
if (unmountInactiveScreens && index !== state.index) {
|
const descriptor = descriptors[route.key];
|
||||||
|
const { unmountOnBlur } = descriptor.options;
|
||||||
|
const isFocused = state.index === index;
|
||||||
|
|
||||||
|
if (unmountOnBlur && !isFocused) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (lazy && !loaded.includes(index)) {
|
if (lazy && !loaded.includes(index) && !isFocused) {
|
||||||
// Don't render a screen if we've never navigated to it
|
// Don't render a screen if we've never navigated to it
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
const isFocused = state.index === index;
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<ResourceSavingScene
|
<ResourceSavingScene
|
||||||
key={route.key}
|
key={route.key}
|
||||||
@@ -119,7 +121,7 @@ export default class BottomTabView extends React.Component<Props, State> {
|
|||||||
isVisible={isFocused}
|
isVisible={isFocused}
|
||||||
>
|
>
|
||||||
<SceneContent isFocused={isFocused}>
|
<SceneContent isFocused={isFocused}>
|
||||||
{descriptors[route.key].render()}
|
{descriptor.render()}
|
||||||
</SceneContent>
|
</SceneContent>
|
||||||
</ResourceSavingScene>
|
</ResourceSavingScene>
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -3,6 +3,46 @@
|
|||||||
All notable changes to this project will be documented in this file.
|
All notable changes to this project will be documented in this file.
|
||||||
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
||||||
|
|
||||||
|
# [5.0.0-alpha.32](https://github.com/react-navigation/navigation-ex/tree/master/packages/compat/compare/@react-navigation/compat@5.0.0-alpha.31...@react-navigation/compat@5.0.0-alpha.32) (2020-02-03)
|
||||||
|
|
||||||
|
**Note:** Version bump only for package @react-navigation/compat
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
# [5.0.0-alpha.31](https://github.com/react-navigation/navigation-ex/tree/master/packages/compat/compare/@react-navigation/compat@5.0.0-alpha.28...@react-navigation/compat@5.0.0-alpha.31) (2020-02-02)
|
||||||
|
|
||||||
|
|
||||||
|
### Bug Fixes
|
||||||
|
|
||||||
|
* add licenses ([0c159db](https://github.com/react-navigation/navigation-ex/tree/master/packages/compat/commit/0c159db4c9bc85e83b5cfe6819ab2562669a4d8f))
|
||||||
|
* throw when assigning or accessing the router property in compat ([944fa35](https://github.com/react-navigation/navigation-ex/tree/master/packages/compat/commit/944fa35ed4778ebc7fa7cd50092719cbd5bf3caf))
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
# [5.0.0-alpha.29](https://github.com/react-navigation/navigation-ex/tree/master/packages/compat/compare/@react-navigation/compat@5.0.0-alpha.28...@react-navigation/compat@5.0.0-alpha.29) (2020-02-02)
|
||||||
|
|
||||||
|
|
||||||
|
### Bug Fixes
|
||||||
|
|
||||||
|
* add licenses ([0c159db](https://github.com/react-navigation/navigation-ex/tree/master/packages/compat/commit/0c159db4c9bc85e83b5cfe6819ab2562669a4d8f))
|
||||||
|
* throw when assigning or accessing the router property in compat ([944fa35](https://github.com/react-navigation/navigation-ex/tree/master/packages/compat/commit/944fa35ed4778ebc7fa7cd50092719cbd5bf3caf))
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
# [5.0.0-alpha.28](https://github.com/react-navigation/navigation-ex/tree/master/packages/compat/compare/@react-navigation/compat@5.0.0-alpha.27...@react-navigation/compat@5.0.0-alpha.28) (2020-01-24)
|
||||||
|
|
||||||
|
**Note:** Version bump only for package @react-navigation/compat
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
# [5.0.0-alpha.27](https://github.com/react-navigation/navigation-ex/tree/master/packages/compat/compare/@react-navigation/compat@5.0.0-alpha.26...@react-navigation/compat@5.0.0-alpha.27) (2020-01-23)
|
# [5.0.0-alpha.27](https://github.com/react-navigation/navigation-ex/tree/master/packages/compat/compare/@react-navigation/compat@5.0.0-alpha.26...@react-navigation/compat@5.0.0-alpha.27) (2020-01-23)
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
21
packages/compat/LICENSE
Normal file
@@ -0,0 +1,21 @@
|
|||||||
|
MIT License
|
||||||
|
|
||||||
|
Copyright (c) 2017 React Navigation Contributors
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
of this software and associated documentation files (the "Software"), to deal
|
||||||
|
in the Software without restriction, including without limitation the rights
|
||||||
|
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
copies of the Software, and to permit persons to whom the Software is
|
||||||
|
furnished to do so, subject to the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be included in all
|
||||||
|
copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
SOFTWARE.
|
||||||
@@ -1,7 +1,7 @@
|
|||||||
{
|
{
|
||||||
"name": "@react-navigation/compat",
|
"name": "@react-navigation/compat",
|
||||||
"description": "Compatibility layer to write navigator definitions in static configuration format",
|
"description": "Compatibility layer to write navigator definitions in static configuration format",
|
||||||
"version": "5.0.0-alpha.27",
|
"version": "5.0.0-alpha.32",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"repository": "https://github.com/react-navigation/navigation-ex/tree/master/packages/compat",
|
"repository": "https://github.com/react-navigation/navigation-ex/tree/master/packages/compat",
|
||||||
"main": "lib/commonjs/index.js",
|
"main": "lib/commonjs/index.js",
|
||||||
@@ -21,7 +21,7 @@
|
|||||||
"clean": "del lib"
|
"clean": "del lib"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@react-navigation/routers": "^5.0.0-alpha.26"
|
"@react-navigation/routers": "^5.0.0-alpha.31"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@types/react": "^16.9.17",
|
"@types/react": "^16.9.17",
|
||||||
|
|||||||
@@ -19,7 +19,7 @@ export function replace({
|
|||||||
key?: string;
|
key?: string;
|
||||||
newKey?: string;
|
newKey?: string;
|
||||||
action?: never;
|
action?: never;
|
||||||
}): CommonActions.Action {
|
}): StackActionType {
|
||||||
if (action !== undefined) {
|
if (action !== undefined) {
|
||||||
throw new Error(
|
throw new Error(
|
||||||
'Sub-actions are not supported for `replace`. Remove the `action` key from the options.'
|
'Sub-actions are not supported for `replace`. Remove the `action` key from the options.'
|
||||||
|
|||||||
@@ -165,7 +165,25 @@ export default function createCompatNavigatorFactory<
|
|||||||
return Navigator;
|
return Navigator;
|
||||||
};
|
};
|
||||||
|
|
||||||
createCompatNavigator.isCompat = true;
|
Object.defineProperties(createCompatNavigator, {
|
||||||
|
isCompat: {
|
||||||
|
get() {
|
||||||
|
return true;
|
||||||
|
},
|
||||||
|
},
|
||||||
|
router: {
|
||||||
|
get() {
|
||||||
|
throw new Error(
|
||||||
|
"It's no longer possible to access the router with the 'router' property."
|
||||||
|
);
|
||||||
|
},
|
||||||
|
set() {
|
||||||
|
throw new Error(
|
||||||
|
"It's no longer possible to override the router by assigning the 'router' property."
|
||||||
|
);
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
return createCompatNavigator;
|
return createCompatNavigator;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,6 +3,70 @@
|
|||||||
All notable changes to this project will be documented in this file.
|
All notable changes to this project will be documented in this file.
|
||||||
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
||||||
|
|
||||||
|
# [5.0.0-alpha.41](https://github.com/react-navigation/navigation-ex/tree/master/packages/core/compare/@react-navigation/core@5.0.0-alpha.40...@react-navigation/core@5.0.0-alpha.41) (2020-02-03)
|
||||||
|
|
||||||
|
|
||||||
|
### Bug Fixes
|
||||||
|
|
||||||
|
* ignore circular references when checking serializable ([e5063b9](https://github.com/react-navigation/navigation-ex/tree/master/packages/core/commit/e5063b93398350511f3fd2ef48425559f871781f))
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
# [5.0.0-alpha.40](https://github.com/react-navigation/navigation-ex/tree/master/packages/core/compare/@react-navigation/core@5.0.0-alpha.37...@react-navigation/core@5.0.0-alpha.40) (2020-02-02)
|
||||||
|
|
||||||
|
|
||||||
|
### Bug Fixes
|
||||||
|
|
||||||
|
* add licenses ([0c159db](https://github.com/react-navigation/navigation-ex/tree/master/packages/core/commit/0c159db4c9bc85e83b5cfe6819ab2562669a4d8f))
|
||||||
|
* add warning when passing inline function to component prop ([fa4a959](https://github.com/react-navigation/navigation-ex/tree/master/packages/core/commit/fa4a959549ccd9dc2f9bd2ea495e99abdedc9f94))
|
||||||
|
* tweak error messages for validation ([2243b45](https://github.com/react-navigation/navigation-ex/tree/master/packages/core/commit/2243b45cc1addf83727166d82736d214f181b1fb))
|
||||||
|
|
||||||
|
|
||||||
|
### Features
|
||||||
|
|
||||||
|
* add `screens` prop for nested configs ([#308](https://github.com/react-navigation/navigation-ex/tree/master/packages/core/issues/308)) ([b931ae6](https://github.com/react-navigation/navigation-ex/tree/master/packages/core/commit/b931ae62dfb2c5253c94ea5ace73e9070ec17c4a))
|
||||||
|
* add useIsDrawerOpen hook ([#299](https://github.com/react-navigation/navigation-ex/tree/master/packages/core/issues/299)) ([ecd68af](https://github.com/react-navigation/navigation-ex/tree/master/packages/core/commit/ecd68afb46a4c56200748da5e5fb284fa5a839db))
|
||||||
|
* integrate with history API on web ([5a3f835](https://github.com/react-navigation/navigation-ex/tree/master/packages/core/commit/5a3f8356b05bff7ed20893a5db6804612da3e568))
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
# [5.0.0-alpha.38](https://github.com/react-navigation/navigation-ex/tree/master/packages/core/compare/@react-navigation/core@5.0.0-alpha.37...@react-navigation/core@5.0.0-alpha.38) (2020-02-02)
|
||||||
|
|
||||||
|
|
||||||
|
### Bug Fixes
|
||||||
|
|
||||||
|
* add licenses ([0c159db](https://github.com/react-navigation/navigation-ex/tree/master/packages/core/commit/0c159db4c9bc85e83b5cfe6819ab2562669a4d8f))
|
||||||
|
* add warning when passing inline function to component prop ([fa4a959](https://github.com/react-navigation/navigation-ex/tree/master/packages/core/commit/fa4a959549ccd9dc2f9bd2ea495e99abdedc9f94))
|
||||||
|
* tweak error messages for validation ([2243b45](https://github.com/react-navigation/navigation-ex/tree/master/packages/core/commit/2243b45cc1addf83727166d82736d214f181b1fb))
|
||||||
|
|
||||||
|
|
||||||
|
### Features
|
||||||
|
|
||||||
|
* add `screens` prop for nested configs ([#308](https://github.com/react-navigation/navigation-ex/tree/master/packages/core/issues/308)) ([b931ae6](https://github.com/react-navigation/navigation-ex/tree/master/packages/core/commit/b931ae62dfb2c5253c94ea5ace73e9070ec17c4a))
|
||||||
|
* add useIsDrawerOpen hook ([#299](https://github.com/react-navigation/navigation-ex/tree/master/packages/core/issues/299)) ([ecd68af](https://github.com/react-navigation/navigation-ex/tree/master/packages/core/commit/ecd68afb46a4c56200748da5e5fb284fa5a839db))
|
||||||
|
* integrate with history API on web ([5a3f835](https://github.com/react-navigation/navigation-ex/tree/master/packages/core/commit/5a3f8356b05bff7ed20893a5db6804612da3e568))
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
# [5.0.0-alpha.37](https://github.com/react-navigation/navigation-ex/tree/master/packages/core/compare/@react-navigation/core@5.0.0-alpha.36...@react-navigation/core@5.0.0-alpha.37) (2020-01-24)
|
||||||
|
|
||||||
|
|
||||||
|
### Bug Fixes
|
||||||
|
|
||||||
|
* add error message when trying to use v4 API with v5 ([179e807](https://github.com/react-navigation/navigation-ex/tree/master/packages/core/commit/179e807a64a7d031d671c2c4b12edaee3c3440c5))
|
||||||
|
* validate screen configs ([2f1f0af](https://github.com/react-navigation/navigation-ex/tree/master/packages/core/commit/2f1f0af862ef8625da4c2aaf463d45fe17a4ac88))
|
||||||
|
* warn if non-serializable values found in state ([5751e7f](https://github.com/react-navigation/navigation-ex/tree/master/packages/core/commit/5751e7f97a1731a5c71862174dfd931b6ffe13e2))
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
# [5.0.0-alpha.36](https://github.com/react-navigation/navigation-ex/tree/master/packages/core/compare/@react-navigation/core@5.0.0-alpha.35...@react-navigation/core@5.0.0-alpha.36) (2020-01-23)
|
# [5.0.0-alpha.36](https://github.com/react-navigation/navigation-ex/tree/master/packages/core/compare/@react-navigation/core@5.0.0-alpha.35...@react-navigation/core@5.0.0-alpha.36) (2020-01-23)
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
21
packages/core/LICENSE
Normal file
@@ -0,0 +1,21 @@
|
|||||||
|
MIT License
|
||||||
|
|
||||||
|
Copyright (c) 2017 React Navigation Contributors
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
of this software and associated documentation files (the "Software"), to deal
|
||||||
|
in the Software without restriction, including without limitation the rights
|
||||||
|
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
copies of the Software, and to permit persons to whom the Software is
|
||||||
|
furnished to do so, subject to the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be included in all
|
||||||
|
copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
SOFTWARE.
|
||||||
@@ -6,7 +6,7 @@
|
|||||||
"react-native",
|
"react-native",
|
||||||
"react-navigation"
|
"react-navigation"
|
||||||
],
|
],
|
||||||
"version": "5.0.0-alpha.36",
|
"version": "5.0.0-alpha.41",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"repository": "https://github.com/react-navigation/navigation-ex/tree/master/packages/core",
|
"repository": "https://github.com/react-navigation/navigation-ex/tree/master/packages/core",
|
||||||
"main": "lib/commonjs/index.js",
|
"main": "lib/commonjs/index.js",
|
||||||
@@ -27,6 +27,7 @@
|
|||||||
"dependencies": {
|
"dependencies": {
|
||||||
"escape-string-regexp": "^2.0.0",
|
"escape-string-regexp": "^2.0.0",
|
||||||
"query-string": "^6.9.0",
|
"query-string": "^6.9.0",
|
||||||
|
"react-is": "^16.12.0",
|
||||||
"shortid": "^2.2.15",
|
"shortid": "^2.2.15",
|
||||||
"use-subscription": "^1.3.0"
|
"use-subscription": "^1.3.0"
|
||||||
},
|
},
|
||||||
@@ -34,6 +35,7 @@
|
|||||||
"@babel/core": "^7.7.7",
|
"@babel/core": "^7.7.7",
|
||||||
"@react-native-community/bob": "^0.8.0",
|
"@react-native-community/bob": "^0.8.0",
|
||||||
"@types/react": "^16.9.17",
|
"@types/react": "^16.9.17",
|
||||||
|
"@types/react-is": "^16.7.1",
|
||||||
"@types/shortid": "^0.0.29",
|
"@types/shortid": "^0.0.29",
|
||||||
"@types/use-subscription": "^1.0.0",
|
"@types/use-subscription": "^1.0.0",
|
||||||
"del-cli": "^3.0.0",
|
"del-cli": "^3.0.0",
|
||||||
|
|||||||
@@ -1,4 +1,3 @@
|
|||||||
import shortid from 'shortid';
|
|
||||||
import { CommonAction, NavigationState, PartialState } from './types';
|
import { CommonAction, NavigationState, PartialState } from './types';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -11,35 +10,6 @@ const BaseRouter = {
|
|||||||
action: CommonAction
|
action: CommonAction
|
||||||
): State | PartialState<State> | null {
|
): State | PartialState<State> | null {
|
||||||
switch (action.type) {
|
switch (action.type) {
|
||||||
case 'REPLACE': {
|
|
||||||
const index = action.source
|
|
||||||
? state.routes.findIndex(r => r.key === action.source)
|
|
||||||
: state.index;
|
|
||||||
|
|
||||||
if (index === -1) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
const { name, key, params } = action.payload;
|
|
||||||
|
|
||||||
if (!state.routeNames.includes(name)) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
return {
|
|
||||||
...state,
|
|
||||||
routes: state.routes.map((route, i) =>
|
|
||||||
i === index
|
|
||||||
? {
|
|
||||||
key: key !== undefined ? key : `${name}-${shortid()}`,
|
|
||||||
name,
|
|
||||||
params,
|
|
||||||
}
|
|
||||||
: route
|
|
||||||
),
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
case 'SET_PARAMS': {
|
case 'SET_PARAMS': {
|
||||||
const index = action.source
|
const index = action.source
|
||||||
? state.routes.findIndex(r => r.key === action.source)
|
? state.routes.findIndex(r => r.key === action.source)
|
||||||
|
|||||||
@@ -14,12 +14,6 @@ export type Action =
|
|||||||
source?: string;
|
source?: string;
|
||||||
target?: string;
|
target?: string;
|
||||||
}
|
}
|
||||||
| {
|
|
||||||
type: 'REPLACE';
|
|
||||||
payload: { name: string; key?: string; params?: object };
|
|
||||||
source?: string;
|
|
||||||
target?: string;
|
|
||||||
}
|
|
||||||
| {
|
| {
|
||||||
type: 'RESET';
|
type: 'RESET';
|
||||||
payload: PartialState<NavigationState>;
|
payload: PartialState<NavigationState>;
|
||||||
@@ -59,10 +53,6 @@ export function navigate(...args: any): Action {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export function replace(name: string, params?: object): Action {
|
|
||||||
return { type: 'REPLACE', payload: { name, params } };
|
|
||||||
}
|
|
||||||
|
|
||||||
export function reset(state: PartialState<NavigationState>): Action {
|
export function reset(state: PartialState<NavigationState>): Action {
|
||||||
return { type: 'RESET', payload: state };
|
return { type: 'RESET', payload: state };
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,10 +2,10 @@ import * as React from 'react';
|
|||||||
import * as CommonActions from './CommonActions';
|
import * as CommonActions from './CommonActions';
|
||||||
import EnsureSingleNavigator from './EnsureSingleNavigator';
|
import EnsureSingleNavigator from './EnsureSingleNavigator';
|
||||||
import NavigationBuilderContext from './NavigationBuilderContext';
|
import NavigationBuilderContext from './NavigationBuilderContext';
|
||||||
import ResetRootContext from './ResetRootContext';
|
|
||||||
import useFocusedListeners from './useFocusedListeners';
|
import useFocusedListeners from './useFocusedListeners';
|
||||||
import useDevTools from './useDevTools';
|
import useDevTools from './useDevTools';
|
||||||
import useStateGetters from './useStateGetters';
|
import useStateGetters from './useStateGetters';
|
||||||
|
import isSerializable from './isSerializable';
|
||||||
|
|
||||||
import {
|
import {
|
||||||
Route,
|
Route,
|
||||||
@@ -16,6 +16,7 @@ import {
|
|||||||
NavigationContainerRef,
|
NavigationContainerRef,
|
||||||
NavigationContainerProps,
|
NavigationContainerProps,
|
||||||
} from './types';
|
} from './types';
|
||||||
|
import useEventEmitter from './useEventEmitter';
|
||||||
|
|
||||||
type State = NavigationState | PartialState<NavigationState> | undefined;
|
type State = NavigationState | PartialState<NavigationState> | undefined;
|
||||||
|
|
||||||
@@ -45,6 +46,8 @@ export const NavigationStateContext = React.createContext<{
|
|||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
|
let hasWarnedForSerialization = false;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Remove `key` and `routeNames` from the state objects recursively to get partial state.
|
* Remove `key` and `routeNames` from the state objects recursively to get partial state.
|
||||||
*
|
*
|
||||||
@@ -203,6 +206,8 @@ const Container = React.forwardRef(function NavigationContainer(
|
|||||||
return getStateForRoute('root');
|
return getStateForRoute('root');
|
||||||
}, [getStateForRoute]);
|
}, [getStateForRoute]);
|
||||||
|
|
||||||
|
const emitter = useEventEmitter();
|
||||||
|
|
||||||
React.useImperativeHandle(ref, () => ({
|
React.useImperativeHandle(ref, () => ({
|
||||||
...(Object.keys(CommonActions) as (keyof typeof CommonActions)[]).reduce<
|
...(Object.keys(CommonActions) as (keyof typeof CommonActions)[]).reduce<
|
||||||
any
|
any
|
||||||
@@ -216,6 +221,7 @@ const Container = React.forwardRef(function NavigationContainer(
|
|||||||
);
|
);
|
||||||
return acc;
|
return acc;
|
||||||
}, {}),
|
}, {}),
|
||||||
|
...emitter.create('root'),
|
||||||
resetRoot,
|
resetRoot,
|
||||||
dispatch,
|
dispatch,
|
||||||
canGoBack,
|
canGoBack,
|
||||||
@@ -242,6 +248,25 @@ const Container = React.forwardRef(function NavigationContainer(
|
|||||||
);
|
);
|
||||||
|
|
||||||
React.useEffect(() => {
|
React.useEffect(() => {
|
||||||
|
if (process.env.NODE_ENV !== 'production') {
|
||||||
|
if (
|
||||||
|
state !== undefined &&
|
||||||
|
!isSerializable(state) &&
|
||||||
|
!hasWarnedForSerialization
|
||||||
|
) {
|
||||||
|
hasWarnedForSerialization = true;
|
||||||
|
|
||||||
|
console.warn(
|
||||||
|
"We found non-serializable values in the navigation state, which can break usage such as persisting and restoring state. This might happen if you passed non-serializable values such as function, class instances etc. in params. If you need to use functions in your options, you can use 'navigation.setOptions' instead."
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
emitter.emit({
|
||||||
|
type: 'state',
|
||||||
|
data: { state },
|
||||||
|
});
|
||||||
|
|
||||||
if (skipTrackingRef.current) {
|
if (skipTrackingRef.current) {
|
||||||
skipTrackingRef.current = false;
|
skipTrackingRef.current = false;
|
||||||
} else {
|
} else {
|
||||||
@@ -256,14 +281,12 @@ const Container = React.forwardRef(function NavigationContainer(
|
|||||||
}
|
}
|
||||||
|
|
||||||
isFirstMountRef.current = false;
|
isFirstMountRef.current = false;
|
||||||
}, [state, onStateChange, trackState, getRootState]);
|
}, [state, onStateChange, trackState, getRootState, emitter]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<NavigationBuilderContext.Provider value={builderContext}>
|
<NavigationBuilderContext.Provider value={builderContext}>
|
||||||
<NavigationStateContext.Provider value={context}>
|
<NavigationStateContext.Provider value={context}>
|
||||||
<ResetRootContext.Provider value={resetRoot}>
|
<EnsureSingleNavigator>{children}</EnsureSingleNavigator>
|
||||||
<EnsureSingleNavigator>{children}</EnsureSingleNavigator>
|
|
||||||
</ResetRootContext.Provider>
|
|
||||||
</NavigationStateContext.Provider>
|
</NavigationStateContext.Provider>
|
||||||
</NavigationBuilderContext.Provider>
|
</NavigationBuilderContext.Provider>
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -1,15 +0,0 @@
|
|||||||
import * as React from 'react';
|
|
||||||
import { NavigationState, PartialState } from './types';
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Context which holds the method to reset root navigator state.
|
|
||||||
*/
|
|
||||||
const ResetRootContext = React.createContext<
|
|
||||||
(state: PartialState<NavigationState> | NavigationState) => void
|
|
||||||
>(() => {
|
|
||||||
throw new Error(
|
|
||||||
"We couldn't find a way to reset root state. Have you wrapped your app with 'NavigationContainer'?"
|
|
||||||
);
|
|
||||||
});
|
|
||||||
|
|
||||||
export default ResetRootContext;
|
|
||||||
@@ -16,64 +16,6 @@ const STATE = {
|
|||||||
routeNames: ['foo', 'bar', 'baz', 'qux'],
|
routeNames: ['foo', 'bar', 'baz', 'qux'],
|
||||||
};
|
};
|
||||||
|
|
||||||
it('replaces focused screen with REPLACE', () => {
|
|
||||||
const result = BaseRouter.getStateForAction(
|
|
||||||
STATE,
|
|
||||||
CommonActions.replace('qux', { answer: 42 })
|
|
||||||
);
|
|
||||||
|
|
||||||
expect(result).toEqual({
|
|
||||||
stale: false,
|
|
||||||
type: 'test',
|
|
||||||
key: 'root',
|
|
||||||
index: 1,
|
|
||||||
routes: [
|
|
||||||
{ key: 'foo', name: 'foo' },
|
|
||||||
{ key: 'qux-test', name: 'qux', params: { answer: 42 } },
|
|
||||||
{ key: 'baz', name: 'baz' },
|
|
||||||
],
|
|
||||||
routeNames: ['foo', 'bar', 'baz', 'qux'],
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
it('replaces source screen with REPLACE', () => {
|
|
||||||
const result = BaseRouter.getStateForAction(STATE, {
|
|
||||||
...CommonActions.replace('qux', { answer: 42 }),
|
|
||||||
source: 'baz',
|
|
||||||
});
|
|
||||||
|
|
||||||
expect(result).toEqual({
|
|
||||||
stale: false,
|
|
||||||
type: 'test',
|
|
||||||
key: 'root',
|
|
||||||
index: 1,
|
|
||||||
routes: [
|
|
||||||
{ key: 'foo', name: 'foo' },
|
|
||||||
{ key: 'bar', name: 'bar', params: { fruit: 'orange' } },
|
|
||||||
{ key: 'qux-test', name: 'qux', params: { answer: 42 } },
|
|
||||||
],
|
|
||||||
routeNames: ['foo', 'bar', 'baz', 'qux'],
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
it("doesn't handle REPLACE if source key isn't present", () => {
|
|
||||||
const result = BaseRouter.getStateForAction(STATE, {
|
|
||||||
...CommonActions.replace('qux', { answer: 42 }),
|
|
||||||
source: 'magic',
|
|
||||||
});
|
|
||||||
|
|
||||||
expect(result).toBe(null);
|
|
||||||
});
|
|
||||||
|
|
||||||
it("doesn't handle REPLACE if screen to replace with isn't present", () => {
|
|
||||||
const result = BaseRouter.getStateForAction(
|
|
||||||
STATE,
|
|
||||||
CommonActions.replace('nonexistent', { answer: 42 })
|
|
||||||
);
|
|
||||||
|
|
||||||
expect(result).toBe(null);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('sets params for the focused screen with SET_PARAMS', () => {
|
it('sets params for the focused screen with SET_PARAMS', () => {
|
||||||
const result = BaseRouter.getStateForAction(
|
const result = BaseRouter.getStateForAction(
|
||||||
STATE,
|
STATE,
|
||||||
|
|||||||
@@ -233,8 +233,8 @@ it('handle dispatching with ref', () => {
|
|||||||
<Screen name="foo2">
|
<Screen name="foo2">
|
||||||
{() => (
|
{() => (
|
||||||
<ChildNavigator>
|
<ChildNavigator>
|
||||||
<Screen name="qux" component={() => null} />
|
<Screen name="qux">{() => null}</Screen>
|
||||||
<Screen name="lex" component={() => null} />
|
<Screen name="lex">{() => null}</Screen>
|
||||||
</ChildNavigator>
|
</ChildNavigator>
|
||||||
)}
|
)}
|
||||||
</Screen>
|
</Screen>
|
||||||
@@ -242,8 +242,8 @@ it('handle dispatching with ref', () => {
|
|||||||
<Screen name="baz">
|
<Screen name="baz">
|
||||||
{() => (
|
{() => (
|
||||||
<ChildNavigator>
|
<ChildNavigator>
|
||||||
<Screen name="qux" component={() => null} />
|
<Screen name="qux">{() => null}</Screen>
|
||||||
<Screen name="lex" component={() => null} />
|
<Screen name="lex">{() => null}</Screen>
|
||||||
</ChildNavigator>
|
</ChildNavigator>
|
||||||
)}
|
)}
|
||||||
</Screen>
|
</Screen>
|
||||||
@@ -254,9 +254,7 @@ it('handle dispatching with ref', () => {
|
|||||||
render(element).update(element);
|
render(element).update(element);
|
||||||
|
|
||||||
act(() => {
|
act(() => {
|
||||||
if (ref.current != null) {
|
ref.current?.dispatch({ type: 'REVERSE' });
|
||||||
ref.current.dispatch({ type: 'REVERSE' });
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
|
|
||||||
expect(onStateChange).toBeCalledTimes(1);
|
expect(onStateChange).toBeCalledTimes(1);
|
||||||
@@ -309,8 +307,8 @@ it('handle resetting state with ref', () => {
|
|||||||
<Screen name="foo2">
|
<Screen name="foo2">
|
||||||
{() => (
|
{() => (
|
||||||
<TestNavigator>
|
<TestNavigator>
|
||||||
<Screen name="qux" component={() => null} />
|
<Screen name="qux">{() => null}</Screen>
|
||||||
<Screen name="lex" component={() => null} />
|
<Screen name="lex">{() => null}</Screen>
|
||||||
</TestNavigator>
|
</TestNavigator>
|
||||||
)}
|
)}
|
||||||
</Screen>
|
</Screen>
|
||||||
@@ -318,8 +316,8 @@ it('handle resetting state with ref', () => {
|
|||||||
<Screen name="baz">
|
<Screen name="baz">
|
||||||
{() => (
|
{() => (
|
||||||
<TestNavigator>
|
<TestNavigator>
|
||||||
<Screen name="qux" component={() => null} />
|
<Screen name="qux">{() => null}</Screen>
|
||||||
<Screen name="lex" component={() => null} />
|
<Screen name="lex">{() => null}</Screen>
|
||||||
</TestNavigator>
|
</TestNavigator>
|
||||||
)}
|
)}
|
||||||
</Screen>
|
</Screen>
|
||||||
@@ -350,9 +348,7 @@ it('handle resetting state with ref', () => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
act(() => {
|
act(() => {
|
||||||
if (ref.current != null) {
|
ref.current?.resetRoot(state);
|
||||||
ref.current.resetRoot(state);
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
|
|
||||||
expect(onStateChange).toBeCalledTimes(1);
|
expect(onStateChange).toBeCalledTimes(1);
|
||||||
@@ -383,7 +379,7 @@ it('handle resetting state with ref', () => {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
it('handle getRootState', () => {
|
it('handles getRootState', () => {
|
||||||
const TestNavigator = (props: any) => {
|
const TestNavigator = (props: any) => {
|
||||||
const { state, descriptors } = useNavigationBuilder(MockRouter, props);
|
const { state, descriptors } = useNavigationBuilder(MockRouter, props);
|
||||||
|
|
||||||
@@ -398,12 +394,12 @@ it('handle getRootState', () => {
|
|||||||
<Screen name="foo">
|
<Screen name="foo">
|
||||||
{() => (
|
{() => (
|
||||||
<TestNavigator>
|
<TestNavigator>
|
||||||
<Screen name="qux" component={() => null} />
|
<Screen name="qux">{() => null}</Screen>
|
||||||
<Screen name="lex" component={() => null} />
|
<Screen name="lex">{() => null}</Screen>
|
||||||
</TestNavigator>
|
</TestNavigator>
|
||||||
)}
|
)}
|
||||||
</Screen>
|
</Screen>
|
||||||
<Screen name="bar" component={() => null} />
|
<Screen name="bar">{() => null}</Screen>
|
||||||
</TestNavigator>
|
</TestNavigator>
|
||||||
</NavigationContainer>
|
</NavigationContainer>
|
||||||
);
|
);
|
||||||
@@ -440,3 +436,68 @@ it('handle getRootState', () => {
|
|||||||
type: 'test',
|
type: 'test',
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
it('emits state events when the state changes', () => {
|
||||||
|
const TestNavigator = (props: any) => {
|
||||||
|
const { state, descriptors } = useNavigationBuilder(MockRouter, props);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<React.Fragment>
|
||||||
|
{state.routes.map(route => descriptors[route.key].render())}
|
||||||
|
</React.Fragment>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
const ref = React.createRef<NavigationContainerRef>();
|
||||||
|
|
||||||
|
const element = (
|
||||||
|
<NavigationContainer ref={ref}>
|
||||||
|
<TestNavigator>
|
||||||
|
<Screen name="foo">{() => null}</Screen>
|
||||||
|
<Screen name="bar">{() => null}</Screen>
|
||||||
|
<Screen name="baz">{() => null}</Screen>
|
||||||
|
</TestNavigator>
|
||||||
|
</NavigationContainer>
|
||||||
|
);
|
||||||
|
|
||||||
|
render(element).update(element);
|
||||||
|
|
||||||
|
const listener = jest.fn();
|
||||||
|
|
||||||
|
ref.current?.addListener('state', listener);
|
||||||
|
|
||||||
|
expect(listener).not.toHaveBeenCalled();
|
||||||
|
|
||||||
|
act(() => {
|
||||||
|
ref.current?.navigate('bar');
|
||||||
|
});
|
||||||
|
|
||||||
|
expect(listener.mock.calls[0][0].data.state).toEqual({
|
||||||
|
type: 'test',
|
||||||
|
stale: false,
|
||||||
|
index: 1,
|
||||||
|
key: '9',
|
||||||
|
routeNames: ['foo', 'bar', 'baz'],
|
||||||
|
routes: [
|
||||||
|
{ key: 'foo', name: 'foo' },
|
||||||
|
{ key: 'bar', name: 'bar' },
|
||||||
|
{ key: 'baz', name: 'baz' },
|
||||||
|
],
|
||||||
|
});
|
||||||
|
|
||||||
|
act(() => {
|
||||||
|
ref.current?.navigate('baz', { answer: 42 });
|
||||||
|
});
|
||||||
|
|
||||||
|
expect(listener.mock.calls[1][0].data.state).toEqual({
|
||||||
|
type: 'test',
|
||||||
|
stale: false,
|
||||||
|
index: 2,
|
||||||
|
key: '9',
|
||||||
|
routeNames: ['foo', 'bar', 'baz'],
|
||||||
|
routes: [
|
||||||
|
{ key: 'foo', name: 'foo' },
|
||||||
|
{ key: 'bar', name: 'bar' },
|
||||||
|
{ key: 'baz', name: 'baz', params: { answer: 42 } },
|
||||||
|
],
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|||||||
12
packages/core/src/__tests__/createNavigatorFactory.test.tsx
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
import createNavigatorFactory from '../createNavigatorFactory';
|
||||||
|
|
||||||
|
it('throws descriptive error if an argument is passed', () => {
|
||||||
|
const createDummyNavigator = createNavigatorFactory(() => null);
|
||||||
|
|
||||||
|
expect(() => createDummyNavigator()).not.toThrowError();
|
||||||
|
|
||||||
|
// @ts-ignore
|
||||||
|
expect(() => createDummyNavigator({})).toThrowError(
|
||||||
|
"Creating a navigator doesn't take an argument."
|
||||||
|
);
|
||||||
|
});
|
||||||
@@ -116,10 +116,13 @@ it("doesn't add query param for empty params", () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
it('handles state with config with nested screens', () => {
|
it('handles state with config with nested screens', () => {
|
||||||
const path = '/few/bar/sweet/apple/baz/jane?answer=42&count=10&valid=true';
|
const path = '/foe/bar/sweet/apple/baz/jane?answer=42&count=10&valid=true';
|
||||||
const config = {
|
const config = {
|
||||||
Foo: {
|
Foo: {
|
||||||
Foe: 'few',
|
path: 'foo',
|
||||||
|
screens: {
|
||||||
|
Foe: 'foe',
|
||||||
|
},
|
||||||
},
|
},
|
||||||
Bar: 'bar/:type/:fruit',
|
Bar: 'bar/:type/:fruit',
|
||||||
Baz: {
|
Baz: {
|
||||||
@@ -178,10 +181,13 @@ it('handles state with config with nested screens', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
it('handles state with config with nested screens and unused configs', () => {
|
it('handles state with config with nested screens and unused configs', () => {
|
||||||
const path = '/few/baz/jane?answer=42&count=10&valid=true';
|
const path = '/foe/baz/jane?answer=42&count=10&valid=true';
|
||||||
const config = {
|
const config = {
|
||||||
Foo: {
|
Foo: {
|
||||||
Foe: 'few',
|
path: 'foo',
|
||||||
|
screens: {
|
||||||
|
Foe: 'foe',
|
||||||
|
},
|
||||||
},
|
},
|
||||||
Baz: {
|
Baz: {
|
||||||
path: 'baz/:author',
|
path: 'baz/:author',
|
||||||
@@ -230,19 +236,31 @@ it('handles state with config with nested screens and unused configs', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
it('handles nested object with stringify in it', () => {
|
it('handles nested object with stringify in it', () => {
|
||||||
const path = '/bar/sweet/apple/few/bis/jane?answer=42&count=10&valid=true';
|
const path = '/bar/sweet/apple/foe/bis/jane?answer=42&count=10&valid=true';
|
||||||
const config = {
|
const config = {
|
||||||
Foo: {
|
Foo: {
|
||||||
Foe: 'few',
|
path: 'foo',
|
||||||
|
screens: {
|
||||||
|
Foe: 'foe',
|
||||||
|
},
|
||||||
},
|
},
|
||||||
Bar: 'bar/:type/:fruit',
|
Bar: 'bar/:type/:fruit',
|
||||||
Baz: {
|
Baz: {
|
||||||
Bos: 'bos',
|
path: 'baz',
|
||||||
Bis: {
|
screens: {
|
||||||
path: 'bis/:author',
|
Bos: 'bos',
|
||||||
stringify: {
|
Bis: {
|
||||||
author: (author: string) =>
|
path: 'bis/:author',
|
||||||
author.replace(/^\w/, c => c.toLowerCase()),
|
stringify: {
|
||||||
|
author: (author: string) =>
|
||||||
|
author.replace(/^\w/, c => c.toLowerCase()),
|
||||||
|
},
|
||||||
|
parse: {
|
||||||
|
author: (author: string) =>
|
||||||
|
author.replace(/^\w/, c => c.toUpperCase()),
|
||||||
|
count: Number,
|
||||||
|
valid: Boolean,
|
||||||
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@@ -292,7 +310,7 @@ it('handles nested object with stringify in it', () => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
expect(getPathFromState(state, config)).toBe(path);
|
expect(getPathFromState(state, config)).toBe(path);
|
||||||
expect(getPathFromState(getStateFromPath(path))).toBe(path);
|
expect(getPathFromState(getStateFromPath(path, config), config)).toBe(path);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('handles nested object for second route depth', () => {
|
it('handles nested object for second route depth', () => {
|
||||||
@@ -300,9 +318,14 @@ it('handles nested object for second route depth', () => {
|
|||||||
const config = {
|
const config = {
|
||||||
Foo: {
|
Foo: {
|
||||||
path: 'foo',
|
path: 'foo',
|
||||||
Foe: 'foe',
|
screens: {
|
||||||
Bar: {
|
Foe: 'foe',
|
||||||
Baz: 'baz',
|
Bar: {
|
||||||
|
path: 'bar',
|
||||||
|
screens: {
|
||||||
|
Baz: 'baz',
|
||||||
|
},
|
||||||
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
@@ -326,7 +349,7 @@ it('handles nested object for second route depth', () => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
expect(getPathFromState(state, config)).toBe(path);
|
expect(getPathFromState(state, config)).toBe(path);
|
||||||
expect(getPathFromState(getStateFromPath(path))).toBe(path);
|
expect(getPathFromState(getStateFromPath(path, config), config)).toBe(path);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('handles nested object for second route depth and and path and stringify in roots', () => {
|
it('handles nested object for second route depth and and path and stringify in roots', () => {
|
||||||
@@ -337,16 +360,20 @@ it('handles nested object for second route depth and and path and stringify in r
|
|||||||
stringify: {
|
stringify: {
|
||||||
id: (id: number) => `id=${id}`,
|
id: (id: number) => `id=${id}`,
|
||||||
},
|
},
|
||||||
Foe: 'foe',
|
screens: {
|
||||||
Bar: {
|
Foe: 'foe',
|
||||||
path: 'bar/:id',
|
Bar: {
|
||||||
stringify: {
|
path: 'bar/:id',
|
||||||
id: (id: number) => `id=${id}`,
|
stringify: {
|
||||||
|
id: (id: number) => `id=${id}`,
|
||||||
|
},
|
||||||
|
parse: {
|
||||||
|
id: Number,
|
||||||
|
},
|
||||||
|
screens: {
|
||||||
|
Baz: 'baz',
|
||||||
|
},
|
||||||
},
|
},
|
||||||
parse: {
|
|
||||||
id: Number,
|
|
||||||
},
|
|
||||||
Baz: 'baz',
|
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
@@ -370,5 +397,5 @@ it('handles nested object for second route depth and and path and stringify in r
|
|||||||
};
|
};
|
||||||
|
|
||||||
expect(getPathFromState(state, config)).toBe(path);
|
expect(getPathFromState(state, config)).toBe(path);
|
||||||
expect(getPathFromState(getStateFromPath(path))).toBe(path);
|
expect(getPathFromState(getStateFromPath(path, config), config)).toBe(path);
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -35,9 +35,9 @@ it('converts path string to initial state', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
it('converts path string to initial state with config', () => {
|
it('converts path string to initial state with config', () => {
|
||||||
const path = '/few/bar/sweet/apple/baz/jane?count=10&answer=42&valid=true';
|
const path = '/foo/bar/sweet/apple/baz/jane?count=10&answer=42&valid=true';
|
||||||
const config = {
|
const config = {
|
||||||
Foo: 'few',
|
Foo: 'foo',
|
||||||
Bar: 'bar/:type/:fruit',
|
Bar: 'bar/:type/:fruit',
|
||||||
Baz: {
|
Baz: {
|
||||||
path: 'baz/:author',
|
path: 'baz/:author',
|
||||||
@@ -141,10 +141,13 @@ it('handles route without param', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
it('converts path string to initial state with config with nested screens', () => {
|
it('converts path string to initial state with config with nested screens', () => {
|
||||||
const path = '/few/bar/sweet/apple/baz/jane?count=10&answer=42&valid=true';
|
const path = '/foe/bar/sweet/apple/baz/jane?count=10&answer=42&valid=true';
|
||||||
const config = {
|
const config = {
|
||||||
Foo: {
|
Foo: {
|
||||||
Foe: 'few',
|
path: 'foo',
|
||||||
|
screens: {
|
||||||
|
Foe: 'foe',
|
||||||
|
},
|
||||||
},
|
},
|
||||||
Bar: 'bar/:type/:fruit',
|
Bar: 'bar/:type/:fruit',
|
||||||
Baz: {
|
Baz: {
|
||||||
@@ -203,10 +206,13 @@ it('converts path string to initial state with config with nested screens', () =
|
|||||||
});
|
});
|
||||||
|
|
||||||
it('converts path string to initial state with config with nested screens and unused parse functions', () => {
|
it('converts path string to initial state with config with nested screens and unused parse functions', () => {
|
||||||
const path = '/few/baz/jane?count=10&answer=42&valid=true';
|
const path = '/foe/baz/jane?count=10&answer=42&valid=true';
|
||||||
const config = {
|
const config = {
|
||||||
Foo: {
|
Foo: {
|
||||||
Foe: 'few',
|
path: 'foo',
|
||||||
|
screens: {
|
||||||
|
Foe: 'foe',
|
||||||
|
},
|
||||||
},
|
},
|
||||||
Baz: {
|
Baz: {
|
||||||
path: 'baz/:author',
|
path: 'baz/:author',
|
||||||
@@ -254,21 +260,31 @@ it('converts path string to initial state with config with nested screens and un
|
|||||||
});
|
});
|
||||||
|
|
||||||
it('handles nested object with unused configs and with parse in it', () => {
|
it('handles nested object with unused configs and with parse in it', () => {
|
||||||
const path = '/bar/sweet/apple/few/bis/jane?count=10&answer=42&valid=true';
|
const path = '/bar/sweet/apple/foe/bis/jane?count=10&answer=42&valid=true';
|
||||||
const config = {
|
const config = {
|
||||||
Foo: {
|
Foo: {
|
||||||
Foe: 'few',
|
path: 'foo',
|
||||||
|
screens: {
|
||||||
|
Foe: 'foe',
|
||||||
|
},
|
||||||
},
|
},
|
||||||
Bar: 'bar/:type/:fruit',
|
Bar: 'bar/:type/:fruit',
|
||||||
Baz: {
|
Baz: {
|
||||||
Bos: 'bos',
|
path: 'baz',
|
||||||
Bis: {
|
screens: {
|
||||||
path: 'bis/:author',
|
Bos: 'bos',
|
||||||
parse: {
|
Bis: {
|
||||||
author: (author: string) =>
|
path: 'bis/:author',
|
||||||
author.replace(/^\w/, c => c.toUpperCase()),
|
stringify: {
|
||||||
count: Number,
|
author: (author: string) =>
|
||||||
valid: Boolean,
|
author.replace(/^\w/, c => c.toLowerCase()),
|
||||||
|
},
|
||||||
|
parse: {
|
||||||
|
author: (author: string) =>
|
||||||
|
author.replace(/^\w/, c => c.toUpperCase()),
|
||||||
|
count: Number,
|
||||||
|
valid: Boolean,
|
||||||
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@@ -328,9 +344,14 @@ it('handles parse in nested object for second route depth', () => {
|
|||||||
const config = {
|
const config = {
|
||||||
Foo: {
|
Foo: {
|
||||||
path: 'foo',
|
path: 'foo',
|
||||||
Foe: 'foe',
|
screens: {
|
||||||
Bar: {
|
Foe: 'foe',
|
||||||
Baz: 'baz',
|
Bar: {
|
||||||
|
path: 'bar',
|
||||||
|
screens: {
|
||||||
|
Baz: 'baz',
|
||||||
|
},
|
||||||
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
@@ -370,16 +391,20 @@ it('handles parse in nested object for second route depth and and path and parse
|
|||||||
stringify: {
|
stringify: {
|
||||||
id: (id: number) => `id=${id}`,
|
id: (id: number) => `id=${id}`,
|
||||||
},
|
},
|
||||||
Foe: 'foe',
|
screens: {
|
||||||
Bar: {
|
Foe: 'foe',
|
||||||
path: 'bar/:id',
|
Bar: {
|
||||||
parse: {
|
path: 'bar/:id',
|
||||||
id: Number,
|
parse: {
|
||||||
|
id: Number,
|
||||||
|
},
|
||||||
|
stringify: {
|
||||||
|
id: (id: number) => `id=${id}`,
|
||||||
|
},
|
||||||
|
screens: {
|
||||||
|
Baz: 'baz',
|
||||||
|
},
|
||||||
},
|
},
|
||||||
stringify: {
|
|
||||||
id: (id: number) => `id=${id}`,
|
|
||||||
},
|
|
||||||
Baz: 'baz',
|
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
@@ -407,3 +432,34 @@ it('handles parse in nested object for second route depth and and path and parse
|
|||||||
state
|
state
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('returns undefined if path is empty', () => {
|
||||||
|
const config = {
|
||||||
|
Foo: {
|
||||||
|
path: 'foo/:id',
|
||||||
|
starting: true,
|
||||||
|
stringify: {
|
||||||
|
id: (id: number) => `id=${id}`,
|
||||||
|
},
|
||||||
|
screens: {
|
||||||
|
Foe: 'foe',
|
||||||
|
Bar: {
|
||||||
|
path: 'bar/:id',
|
||||||
|
parse: {
|
||||||
|
id: Number,
|
||||||
|
},
|
||||||
|
stringify: {
|
||||||
|
id: (id: number) => `id=${id}`,
|
||||||
|
},
|
||||||
|
screens: {
|
||||||
|
Baz: 'baz',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
const path = '';
|
||||||
|
|
||||||
|
expect(getStateFromPath(path, config)).toEqual(undefined);
|
||||||
|
});
|
||||||
|
|||||||
@@ -936,3 +936,138 @@ it('switches rendered navigators', () => {
|
|||||||
'Another navigator is already registered for this container.'
|
'Another navigator is already registered for this container.'
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('throws if no name is passed to Screen', () => {
|
||||||
|
const TestNavigator = (props: any) => {
|
||||||
|
useNavigationBuilder(MockRouter, props);
|
||||||
|
return null;
|
||||||
|
};
|
||||||
|
|
||||||
|
const element = (
|
||||||
|
<NavigationContainer>
|
||||||
|
<TestNavigator>
|
||||||
|
<Screen name={undefined as any} component={jest.fn()} />
|
||||||
|
</TestNavigator>
|
||||||
|
</NavigationContainer>
|
||||||
|
);
|
||||||
|
|
||||||
|
expect(() => render(element).update(element)).toThrowError(
|
||||||
|
'Got an invalid name (undefined) for the screen. It must be a non-empty string.'
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('throws if invalid name is passed to Screen', () => {
|
||||||
|
const TestNavigator = (props: any) => {
|
||||||
|
useNavigationBuilder(MockRouter, props);
|
||||||
|
return null;
|
||||||
|
};
|
||||||
|
|
||||||
|
const element = (
|
||||||
|
<NavigationContainer>
|
||||||
|
<TestNavigator>
|
||||||
|
<Screen name={[] as any} component={jest.fn()} />
|
||||||
|
</TestNavigator>
|
||||||
|
</NavigationContainer>
|
||||||
|
);
|
||||||
|
|
||||||
|
expect(() => render(element).update(element)).toThrowError(
|
||||||
|
'Got an invalid name ([]) for the screen. It must be a non-empty string.'
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('throws if both children and component are passed', () => {
|
||||||
|
const TestNavigator = (props: any) => {
|
||||||
|
useNavigationBuilder(MockRouter, props);
|
||||||
|
return null;
|
||||||
|
};
|
||||||
|
|
||||||
|
const element = (
|
||||||
|
<NavigationContainer>
|
||||||
|
<TestNavigator>
|
||||||
|
<Screen name="foo" component={jest.fn()}>
|
||||||
|
{jest.fn()}
|
||||||
|
</Screen>
|
||||||
|
</TestNavigator>
|
||||||
|
</NavigationContainer>
|
||||||
|
);
|
||||||
|
|
||||||
|
expect(() => render(element).update(element)).toThrowError(
|
||||||
|
"Got both 'component' and 'children' props for the screen 'foo'. You must pass only one of them."
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('throws descriptive error for undefined screen component', () => {
|
||||||
|
const TestNavigator = (props: any) => {
|
||||||
|
useNavigationBuilder(MockRouter, props);
|
||||||
|
return null;
|
||||||
|
};
|
||||||
|
|
||||||
|
const element = (
|
||||||
|
<NavigationContainer>
|
||||||
|
<TestNavigator>
|
||||||
|
<Screen name="foo" component={undefined as any} />
|
||||||
|
</TestNavigator>
|
||||||
|
</NavigationContainer>
|
||||||
|
);
|
||||||
|
|
||||||
|
expect(() => render(element).update(element)).toThrowError(
|
||||||
|
"Couldn't find a 'component' or 'children' prop for the screen 'foo'"
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('throws descriptive error for invalid screen component', () => {
|
||||||
|
const TestNavigator = (props: any) => {
|
||||||
|
useNavigationBuilder(MockRouter, props);
|
||||||
|
return null;
|
||||||
|
};
|
||||||
|
|
||||||
|
const element = (
|
||||||
|
<NavigationContainer>
|
||||||
|
<TestNavigator>
|
||||||
|
<Screen name="foo" component={{} as any} />
|
||||||
|
</TestNavigator>
|
||||||
|
</NavigationContainer>
|
||||||
|
);
|
||||||
|
|
||||||
|
expect(() => render(element).update(element)).toThrowError(
|
||||||
|
"Got an invalid value for 'component' prop for the screen 'foo'. It must be a a valid React Component."
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('throws descriptive error for invalid children', () => {
|
||||||
|
const TestNavigator = (props: any) => {
|
||||||
|
useNavigationBuilder(MockRouter, props);
|
||||||
|
return null;
|
||||||
|
};
|
||||||
|
|
||||||
|
const element = (
|
||||||
|
<NavigationContainer>
|
||||||
|
<TestNavigator>
|
||||||
|
<Screen name="foo">{[] as any}</Screen>
|
||||||
|
</TestNavigator>
|
||||||
|
</NavigationContainer>
|
||||||
|
);
|
||||||
|
|
||||||
|
expect(() => render(element).update(element)).toThrowError(
|
||||||
|
"Got an invalid value for 'children' prop for the screen 'foo'. It must be a function returning a React Element."
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("doesn't throw if children is null", () => {
|
||||||
|
const TestNavigator = (props: any) => {
|
||||||
|
useNavigationBuilder(MockRouter, props);
|
||||||
|
return null;
|
||||||
|
};
|
||||||
|
|
||||||
|
const element = (
|
||||||
|
<NavigationContainer>
|
||||||
|
<TestNavigator>
|
||||||
|
<Screen name="foo" component={jest.fn()}>
|
||||||
|
{null as any}
|
||||||
|
</Screen>
|
||||||
|
</TestNavigator>
|
||||||
|
</NavigationContainer>
|
||||||
|
);
|
||||||
|
|
||||||
|
expect(() => render(element).update(element)).not.toThrowError();
|
||||||
|
});
|
||||||
|
|||||||
70
packages/core/src/__tests__/isSerializable.test.tsx
Normal file
@@ -0,0 +1,70 @@
|
|||||||
|
import isSerializable from '../isSerializable';
|
||||||
|
|
||||||
|
it('returns true for serializable object', () => {
|
||||||
|
expect(
|
||||||
|
isSerializable({
|
||||||
|
index: 0,
|
||||||
|
key: '7',
|
||||||
|
routeNames: ['foo', 'bar'],
|
||||||
|
routes: [
|
||||||
|
{
|
||||||
|
key: 'foo',
|
||||||
|
name: 'foo',
|
||||||
|
state: {
|
||||||
|
index: 0,
|
||||||
|
key: '8',
|
||||||
|
routeNames: ['qux', 'lex'],
|
||||||
|
routes: [
|
||||||
|
{ key: 'qux', name: 'qux' },
|
||||||
|
{ key: 'lex', name: 'lex' },
|
||||||
|
],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
})
|
||||||
|
).toBe(true);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('returns false for non-serializable object', () => {
|
||||||
|
expect(
|
||||||
|
isSerializable({
|
||||||
|
index: 0,
|
||||||
|
key: '7',
|
||||||
|
routeNames: ['foo', 'bar'],
|
||||||
|
routes: [
|
||||||
|
{
|
||||||
|
key: 'foo',
|
||||||
|
name: 'foo',
|
||||||
|
state: {
|
||||||
|
index: 0,
|
||||||
|
key: '8',
|
||||||
|
routeNames: ['qux', 'lex'],
|
||||||
|
routes: [
|
||||||
|
{ key: 'qux', name: 'qux', params: () => 42 },
|
||||||
|
{ key: 'lex', name: 'lex' },
|
||||||
|
],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
})
|
||||||
|
).toBe(false);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('returns false for circular references', () => {
|
||||||
|
const o = {
|
||||||
|
index: 0,
|
||||||
|
key: '7',
|
||||||
|
routeNames: ['foo', 'bar'],
|
||||||
|
routes: [
|
||||||
|
{
|
||||||
|
key: 'foo',
|
||||||
|
name: 'foo',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
};
|
||||||
|
|
||||||
|
// @ts-ignore
|
||||||
|
o.routes[0].state = o;
|
||||||
|
|
||||||
|
expect(isSerializable(o)).toBe(false);
|
||||||
|
});
|
||||||
@@ -592,7 +592,7 @@ it('returns true for canGoBack when parent router handles GO_BACK', () => {
|
|||||||
<Screen name="qux">
|
<Screen name="qux">
|
||||||
{() => (
|
{() => (
|
||||||
<OverrodeNavigator>
|
<OverrodeNavigator>
|
||||||
<Screen name="qux" component={() => null} />
|
<Screen name="qux">{() => null}</Screen>
|
||||||
</OverrodeNavigator>
|
</OverrodeNavigator>
|
||||||
)}
|
)}
|
||||||
</Screen>
|
</Screen>
|
||||||
|
|||||||
@@ -181,8 +181,8 @@ it("lets children handle the action if parent didn't", () => {
|
|||||||
<Screen name="baz">
|
<Screen name="baz">
|
||||||
{() => (
|
{() => (
|
||||||
<ChildNavigator>
|
<ChildNavigator>
|
||||||
<Screen name="qux" component={() => null} />
|
<Screen name="qux">{() => null}</Screen>
|
||||||
<Screen name="lex" component={() => null} />
|
<Screen name="lex">{() => null}</Screen>
|
||||||
</ChildNavigator>
|
</ChildNavigator>
|
||||||
)}
|
)}
|
||||||
</Screen>
|
</Screen>
|
||||||
@@ -291,8 +291,8 @@ it("action doesn't bubble if target is specified", () => {
|
|||||||
<Screen name="baz">
|
<Screen name="baz">
|
||||||
{() => (
|
{() => (
|
||||||
<ChildNavigator>
|
<ChildNavigator>
|
||||||
<Screen name="qux" component={() => null} />
|
<Screen name="qux">{() => null}</Screen>
|
||||||
<Screen name="lex" component={() => null} />
|
<Screen name="lex">{() => null}</Screen>
|
||||||
</ChildNavigator>
|
</ChildNavigator>
|
||||||
)}
|
)}
|
||||||
</Screen>
|
</Screen>
|
||||||
@@ -356,8 +356,8 @@ it('logs error if no navigator handled the action', () => {
|
|||||||
<Screen name="baz">
|
<Screen name="baz">
|
||||||
{() => (
|
{() => (
|
||||||
<TestNavigator>
|
<TestNavigator>
|
||||||
<Screen name="qux" component={() => null} />
|
<Screen name="qux">{() => null}</Screen>
|
||||||
<Screen name="lex" component={() => null} />
|
<Screen name="lex">{() => null}</Screen>
|
||||||
</TestNavigator>
|
</TestNavigator>
|
||||||
)}
|
)}
|
||||||
</Screen>
|
</Screen>
|
||||||
|
|||||||
@@ -13,11 +13,17 @@ export default function createNavigatorFactory<
|
|||||||
ScreenOptions extends object,
|
ScreenOptions extends object,
|
||||||
NavigatorComponent extends React.ComponentType<any>
|
NavigatorComponent extends React.ComponentType<any>
|
||||||
>(Navigator: NavigatorComponent) {
|
>(Navigator: NavigatorComponent) {
|
||||||
return <ParamList extends ParamListBase>(): TypedNavigator<
|
return function<ParamList extends ParamListBase>(): TypedNavigator<
|
||||||
ParamList,
|
ParamList,
|
||||||
ScreenOptions,
|
ScreenOptions,
|
||||||
typeof Navigator
|
typeof Navigator
|
||||||
> => {
|
> {
|
||||||
|
if (arguments[0] !== undefined) {
|
||||||
|
throw new Error(
|
||||||
|
"Creating a navigator doesn't take an argument. Maybe you are trying to use React Navigation 4 API with React Navigation 5?"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
return {
|
return {
|
||||||
Navigator,
|
Navigator,
|
||||||
Screen,
|
Screen,
|
||||||
|
|||||||
@@ -8,8 +8,11 @@ type StringifyConfig = Record<string, (value: any) => string>;
|
|||||||
type Options = {
|
type Options = {
|
||||||
[routeName: string]:
|
[routeName: string]:
|
||||||
| string
|
| string
|
||||||
| { path: string; stringify?: StringifyConfig }
|
| {
|
||||||
| Options;
|
path: string;
|
||||||
|
stringify?: StringifyConfig;
|
||||||
|
screens?: Options;
|
||||||
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -43,6 +46,9 @@ export default function getPathFromState(
|
|||||||
state?: State,
|
state?: State,
|
||||||
options: Options = {}
|
options: Options = {}
|
||||||
): string {
|
): string {
|
||||||
|
if (state === undefined) {
|
||||||
|
throw Error('NavigationState not passed');
|
||||||
|
}
|
||||||
let path = '/';
|
let path = '/';
|
||||||
|
|
||||||
let current: State | undefined = state;
|
let current: State | undefined = state;
|
||||||
@@ -50,7 +56,7 @@ export default function getPathFromState(
|
|||||||
while (current) {
|
while (current) {
|
||||||
let index = typeof current.index === 'number' ? current.index : 0;
|
let index = typeof current.index === 'number' ? current.index : 0;
|
||||||
let route = current.routes[index] as Route<string> & {
|
let route = current.routes[index] as Route<string> & {
|
||||||
state?: State | undefined;
|
state?: State;
|
||||||
};
|
};
|
||||||
let currentOptions = options;
|
let currentOptions = options;
|
||||||
let pattern = route.name;
|
let pattern = route.name;
|
||||||
@@ -64,10 +70,14 @@ export default function getPathFromState(
|
|||||||
pattern = (currentOptions[route.name] as { path: string }).path;
|
pattern = (currentOptions[route.name] as { path: string }).path;
|
||||||
break;
|
break;
|
||||||
} else {
|
} else {
|
||||||
currentOptions = currentOptions[route.name] as Options;
|
if (!(currentOptions[route.name] as { screens?: Options }).screens) {
|
||||||
|
throw Error('Wrong Options object passed');
|
||||||
|
}
|
||||||
|
currentOptions = (currentOptions[route.name] as { screens: Options })
|
||||||
|
.screens;
|
||||||
index = typeof route.state.index === 'number' ? route.state.index : 0;
|
index = typeof route.state.index === 'number' ? route.state.index : 0;
|
||||||
route = route.state.routes[index] as Route<string> & {
|
route = route.state.routes[index] as Route<string> & {
|
||||||
state?: State | undefined;
|
state?: State;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,7 +5,13 @@ import { NavigationState, PartialState, InitialState } from './types';
|
|||||||
type ParseConfig = Record<string, (value: string) => any>;
|
type ParseConfig = Record<string, (value: string) => any>;
|
||||||
|
|
||||||
type Options = {
|
type Options = {
|
||||||
[routeName: string]: string | { path: string; parse?: ParseConfig } | Options;
|
[routeName: string]:
|
||||||
|
| string
|
||||||
|
| {
|
||||||
|
path: string;
|
||||||
|
parse?: ParseConfig;
|
||||||
|
screens?: Options;
|
||||||
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
type RouteConfig = {
|
type RouteConfig = {
|
||||||
@@ -42,6 +48,9 @@ export default function getStateFromPath(
|
|||||||
path: string,
|
path: string,
|
||||||
options: Options = {}
|
options: Options = {}
|
||||||
): ResultState | undefined {
|
): ResultState | undefined {
|
||||||
|
if (path === '') {
|
||||||
|
return undefined;
|
||||||
|
}
|
||||||
// Create a normalized configs array which will be easier to use
|
// Create a normalized configs array which will be easier to use
|
||||||
const configs = ([] as RouteConfig[]).concat(
|
const configs = ([] as RouteConfig[]).concat(
|
||||||
...Object.keys(options).map(key => createNormalizedConfigs(key, options))
|
...Object.keys(options).map(key => createNormalizedConfigs(key, options))
|
||||||
@@ -65,7 +74,7 @@ export default function getStateFromPath(
|
|||||||
|
|
||||||
// If our regex matches, we need to extract params from the path
|
// If our regex matches, we need to extract params from the path
|
||||||
if (match) {
|
if (match) {
|
||||||
routeNames = config.routeNames;
|
routeNames = [...config.routeNames];
|
||||||
|
|
||||||
const paramPatterns = config.pattern
|
const paramPatterns = config.pattern
|
||||||
.split('/')
|
.split('/')
|
||||||
@@ -164,7 +173,7 @@ export default function getStateFromPath(
|
|||||||
const route = current.routes[0];
|
const route = current.routes[0];
|
||||||
|
|
||||||
const params = queryString.parse(query);
|
const params = queryString.parse(query);
|
||||||
const parseFunction = findParseConfigForRoute(route.name, options);
|
const parseFunction = findParseConfigForRoute(route.name, configs);
|
||||||
|
|
||||||
if (parseFunction) {
|
if (parseFunction) {
|
||||||
Object.keys(params).forEach(name => {
|
Object.keys(params).forEach(name => {
|
||||||
@@ -185,7 +194,7 @@ function createNormalizedConfigs(
|
|||||||
routeConfig: Options,
|
routeConfig: Options,
|
||||||
routeNames: string[] = []
|
routeNames: string[] = []
|
||||||
): RouteConfig[] {
|
): RouteConfig[] {
|
||||||
const configs = [];
|
const configs: RouteConfig[] = [];
|
||||||
|
|
||||||
routeNames.push(key);
|
routeNames.push(key);
|
||||||
|
|
||||||
@@ -196,30 +205,19 @@ function createNormalizedConfigs(
|
|||||||
configs.push(createConfigItem(routeNames, value));
|
configs.push(createConfigItem(routeNames, value));
|
||||||
} else if (typeof value === 'object') {
|
} else if (typeof value === 'object') {
|
||||||
// if an object is specified as the value (e.g. Foo: { ... }),
|
// if an object is specified as the value (e.g. Foo: { ... }),
|
||||||
// it could have config object and optionally nested config
|
// it has `path` property and
|
||||||
Object.keys(value).forEach(nestedKey => {
|
// it could have `screens` prop which has nested configs
|
||||||
if (nestedKey === 'path') {
|
configs.push(createConfigItem(routeNames, value.path, value.parse));
|
||||||
configs.push(
|
if (value.screens) {
|
||||||
createConfigItem(
|
Object.keys(value.screens).forEach(nestedConfig => {
|
||||||
routeNames,
|
|
||||||
value[nestedKey] as string,
|
|
||||||
value.parse ? (value.parse as ParseConfig) : undefined
|
|
||||||
)
|
|
||||||
);
|
|
||||||
} else if (nestedKey === 'parse') {
|
|
||||||
// We handle custom parse function when a `path` is specified (in nestedKey === path)
|
|
||||||
} else {
|
|
||||||
// If the name of the key is not `path` or `parse`, it's a nested config for route
|
|
||||||
// So we need to traverse into it and collect the configs
|
|
||||||
const result = createNormalizedConfigs(
|
const result = createNormalizedConfigs(
|
||||||
nestedKey,
|
nestedConfig,
|
||||||
routeConfig[key] as Options,
|
value.screens as Options,
|
||||||
routeNames
|
routeNames
|
||||||
);
|
);
|
||||||
|
|
||||||
configs.push(...result);
|
configs.push(...result);
|
||||||
}
|
});
|
||||||
});
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
routeNames.pop();
|
routeNames.pop();
|
||||||
@@ -247,21 +245,12 @@ function createConfigItem(
|
|||||||
|
|
||||||
function findParseConfigForRoute(
|
function findParseConfigForRoute(
|
||||||
routeName: string,
|
routeName: string,
|
||||||
config: Options
|
flatConfig: RouteConfig[]
|
||||||
): ParseConfig | undefined {
|
): ParseConfig | undefined {
|
||||||
if (config[routeName]) {
|
for (const config of flatConfig) {
|
||||||
return (config[routeName] as { parse?: ParseConfig }).parse;
|
if (routeName === config.routeNames[config.routeNames.length - 1]) {
|
||||||
}
|
return config.parse;
|
||||||
|
|
||||||
for (const name in config) {
|
|
||||||
if (typeof config[name] === 'object') {
|
|
||||||
const parse = findParseConfigForRoute(routeName, config[name] as Options);
|
|
||||||
|
|
||||||
if (parse) {
|
|
||||||
return parse;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return undefined;
|
return undefined;
|
||||||
}
|
}
|
||||||
|
|||||||
47
packages/core/src/isSerializable.tsx
Normal file
@@ -0,0 +1,47 @@
|
|||||||
|
const isSerializableWithoutCircularReference = (
|
||||||
|
o: { [key: string]: any },
|
||||||
|
seen = new Set<any>()
|
||||||
|
): boolean => {
|
||||||
|
if (
|
||||||
|
o === undefined ||
|
||||||
|
o === null ||
|
||||||
|
typeof o === 'boolean' ||
|
||||||
|
typeof o === 'number' ||
|
||||||
|
typeof o === 'string'
|
||||||
|
) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (
|
||||||
|
Object.prototype.toString.call(o) !== '[object Object]' &&
|
||||||
|
!Array.isArray(o)
|
||||||
|
) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (seen.has(o)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
seen.add(o);
|
||||||
|
|
||||||
|
if (Array.isArray(o)) {
|
||||||
|
for (const it of o) {
|
||||||
|
if (!isSerializableWithoutCircularReference(it, seen)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
for (const key in o) {
|
||||||
|
if (!isSerializableWithoutCircularReference(o[key], seen)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
};
|
||||||
|
|
||||||
|
export default function isSerializable(o: { [key: string]: any }) {
|
||||||
|
return isSerializableWithoutCircularReference(o);
|
||||||
|
}
|
||||||
@@ -16,6 +16,10 @@ export type NavigationState = {
|
|||||||
* List of valid route names as defined in the screen components.
|
* List of valid route names as defined in the screen components.
|
||||||
*/
|
*/
|
||||||
routeNames: string[];
|
routeNames: string[];
|
||||||
|
/**
|
||||||
|
* Alternative entries for history.
|
||||||
|
*/
|
||||||
|
history?: unknown[];
|
||||||
/**
|
/**
|
||||||
* List of rendered routes.
|
* List of rendered routes.
|
||||||
*/
|
*/
|
||||||
@@ -212,10 +216,10 @@ export type EventMapBase = Record<
|
|||||||
{ data?: any; canPreventDefault?: boolean }
|
{ data?: any; canPreventDefault?: boolean }
|
||||||
>;
|
>;
|
||||||
|
|
||||||
export type EventMapCore = {
|
export type EventMapCore<State extends NavigationState> = {
|
||||||
focus: { data: undefined };
|
focus: { data: undefined };
|
||||||
blur: { data: undefined };
|
blur: { data: undefined };
|
||||||
state: { data: { state: NavigationState } };
|
state: { data: { state: State } };
|
||||||
};
|
};
|
||||||
|
|
||||||
export type EventArg<
|
export type EventArg<
|
||||||
@@ -365,13 +369,6 @@ type NavigationHelpersCommon<
|
|||||||
*/
|
*/
|
||||||
reset(state: PartialState<State> | State): void;
|
reset(state: PartialState<State> | State): void;
|
||||||
|
|
||||||
/**
|
|
||||||
* Reset the navigation state of the root navigator to the provided state.
|
|
||||||
*
|
|
||||||
* @param state Navigation state object.
|
|
||||||
*/
|
|
||||||
resetRoot(state?: PartialState<NavigationState> | NavigationState): void;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Go back to the previous route in history.
|
* Go back to the previous route in history.
|
||||||
*/
|
*/
|
||||||
@@ -465,7 +462,7 @@ export type NavigationProp<
|
|||||||
* Note that this method doesn't re-render screen when the result changes. So don't use it in `render`.
|
* Note that this method doesn't re-render screen when the result changes. So don't use it in `render`.
|
||||||
*/
|
*/
|
||||||
dangerouslyGetState(): State;
|
dangerouslyGetState(): State;
|
||||||
} & EventConsumer<EventMap & EventMapCore> &
|
} & EventConsumer<EventMap & EventMapCore<State>> &
|
||||||
PrivateValueStore<ParamList, RouteName, EventMap>;
|
PrivateValueStore<ParamList, RouteName, EventMap>;
|
||||||
|
|
||||||
export type RouteProp<
|
export type RouteProp<
|
||||||
@@ -586,15 +583,21 @@ export type RouteConfig<
|
|||||||
);
|
);
|
||||||
|
|
||||||
export type NavigationContainerRef =
|
export type NavigationContainerRef =
|
||||||
| (NavigationHelpers<ParamListBase> & {
|
| (NavigationHelpers<ParamListBase> &
|
||||||
/**
|
EventConsumer<{ state: { data: { state: NavigationState } } }> & {
|
||||||
* Reset the navigation state of the root navigator to the provided state.
|
/**
|
||||||
*
|
* Reset the navigation state of the root navigator to the provided state.
|
||||||
* @param state Navigation state object.
|
*
|
||||||
*/
|
* @param state Navigation state object.
|
||||||
resetRoot(state?: PartialState<NavigationState> | NavigationState): void;
|
*/
|
||||||
getRootState(): NavigationState;
|
resetRoot(
|
||||||
})
|
state?: PartialState<NavigationState> | NavigationState
|
||||||
|
): void;
|
||||||
|
/**
|
||||||
|
* Get the rehydrated navigation state of the navigation tree.
|
||||||
|
*/
|
||||||
|
getRootState(): NavigationState;
|
||||||
|
})
|
||||||
| undefined
|
| undefined
|
||||||
| null;
|
| null;
|
||||||
|
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
import * as React from 'react';
|
import * as React from 'react';
|
||||||
|
import { isValidElementType } from 'react-is';
|
||||||
import { NavigationStateContext } from './NavigationContainer';
|
import { NavigationStateContext } from './NavigationContainer';
|
||||||
import NavigationRouteContext from './NavigationRouteContext';
|
import NavigationRouteContext from './NavigationRouteContext';
|
||||||
import Screen from './Screen';
|
import Screen from './Screen';
|
||||||
@@ -53,8 +54,8 @@ const isArrayEqual = (a: any[], b: any[]) =>
|
|||||||
*/
|
*/
|
||||||
const getRouteConfigsFromChildren = <ScreenOptions extends object>(
|
const getRouteConfigsFromChildren = <ScreenOptions extends object>(
|
||||||
children: React.ReactNode
|
children: React.ReactNode
|
||||||
) =>
|
) => {
|
||||||
React.Children.toArray(children).reduce<
|
const configs = React.Children.toArray(children).reduce<
|
||||||
RouteConfig<ParamListBase, string, ScreenOptions>[]
|
RouteConfig<ParamListBase, string, ScreenOptions>[]
|
||||||
>((acc, child) => {
|
>((acc, child) => {
|
||||||
if (React.isValidElement(child)) {
|
if (React.isValidElement(child)) {
|
||||||
@@ -85,6 +86,56 @@ const getRouteConfigsFromChildren = <ScreenOptions extends object>(
|
|||||||
);
|
);
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
|
if (process.env.NODE_ENV !== 'production') {
|
||||||
|
configs.forEach(config => {
|
||||||
|
const { name, children, component } = config as any;
|
||||||
|
|
||||||
|
if (typeof name !== 'string' || !name) {
|
||||||
|
throw new Error(
|
||||||
|
`Got an invalid name (${JSON.stringify(
|
||||||
|
name
|
||||||
|
)}) for the screen. It must be a non-empty string.`
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (children != null || component !== undefined) {
|
||||||
|
if (children != null && component !== undefined) {
|
||||||
|
throw new Error(
|
||||||
|
`Got both 'component' and 'children' props for the screen '${name}'. You must pass only one of them.`
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (children != null && typeof children !== 'function') {
|
||||||
|
throw new Error(
|
||||||
|
`Got an invalid value for 'children' prop for the screen '${name}'. It must be a function returning a React Element.`
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (component !== undefined && !isValidElementType(component)) {
|
||||||
|
throw new Error(
|
||||||
|
`Got an invalid value for 'component' prop for the screen '${name}'. It must be a a valid React Component.`
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (typeof component === 'function' && component.name === 'component') {
|
||||||
|
// Inline anonymous functions passed in the `component` prop will have the name of the prop
|
||||||
|
// It's relatively safe to assume that it's not a component since it should also have PascalCase name
|
||||||
|
// We won't catch all scenarios here, but this should catch a good chunk of incorrect use.
|
||||||
|
console.warn(
|
||||||
|
`Looks like you're passing an inline function for 'component' prop for the screen '${name}' (e.g. component={() => <SomeComponent />}). Passing an inline function will cause the component state to be lost on re-render and cause perf issues since it's re-created every render. You can pass the function as children to 'Screen' instead to achieve the desired behaviour.`
|
||||||
|
);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
throw new Error(
|
||||||
|
`Couldn't find a 'component' or 'children' prop for the screen '${name}'. This can happen if you passed 'undefined'. You likely forgot to export your component from the file it's defined in, or mixed up default import and named import when importing.`
|
||||||
|
);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
return configs;
|
||||||
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Hook for building navigators.
|
* Hook for building navigators.
|
||||||
*
|
*
|
||||||
|
|||||||
@@ -1,7 +1,6 @@
|
|||||||
import * as React from 'react';
|
import * as React from 'react';
|
||||||
import * as CommonActions from './CommonActions';
|
import * as CommonActions from './CommonActions';
|
||||||
import NavigationContext from './NavigationContext';
|
import NavigationContext from './NavigationContext';
|
||||||
import ResetRootContext from './ResetRootContext';
|
|
||||||
import { NavigationStateContext } from './NavigationContainer';
|
import { NavigationStateContext } from './NavigationContainer';
|
||||||
import { NavigationEventEmitter } from './useEventEmitter';
|
import { NavigationEventEmitter } from './useEventEmitter';
|
||||||
import {
|
import {
|
||||||
@@ -37,7 +36,6 @@ export default function useNavigationHelpers<
|
|||||||
Action extends NavigationAction,
|
Action extends NavigationAction,
|
||||||
EventMap extends Record<string, any>
|
EventMap extends Record<string, any>
|
||||||
>({ onAction, getState, emitter, router }: Options<State, Action>) {
|
>({ onAction, getState, emitter, router }: Options<State, Action>) {
|
||||||
const resetRoot = React.useContext(ResetRootContext);
|
|
||||||
const parentNavigationHelpers = React.useContext(NavigationContext);
|
const parentNavigationHelpers = React.useContext(NavigationContext);
|
||||||
const { performTransaction } = React.useContext(NavigationStateContext);
|
const { performTransaction } = React.useContext(NavigationStateContext);
|
||||||
|
|
||||||
@@ -76,7 +74,6 @@ export default function useNavigationHelpers<
|
|||||||
return {
|
return {
|
||||||
...parentNavigationHelpers,
|
...parentNavigationHelpers,
|
||||||
...helpers,
|
...helpers,
|
||||||
resetRoot,
|
|
||||||
dispatch,
|
dispatch,
|
||||||
emit: emitter.emit,
|
emit: emitter.emit,
|
||||||
isFocused: parentNavigationHelpers
|
isFocused: parentNavigationHelpers
|
||||||
@@ -100,7 +97,6 @@ export default function useNavigationHelpers<
|
|||||||
router,
|
router,
|
||||||
getState,
|
getState,
|
||||||
parentNavigationHelpers,
|
parentNavigationHelpers,
|
||||||
resetRoot,
|
|
||||||
emitter.emit,
|
emitter.emit,
|
||||||
performTransaction,
|
performTransaction,
|
||||||
onAction,
|
onAction,
|
||||||
|
|||||||
@@ -3,6 +3,65 @@
|
|||||||
All notable changes to this project will be documented in this file.
|
All notable changes to this project will be documented in this file.
|
||||||
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
||||||
|
|
||||||
|
# [5.0.0-alpha.45](https://github.com/react-navigation/navigation-ex/tree/master/packages/drawer/compare/@react-navigation/drawer@5.0.0-alpha.44...@react-navigation/drawer@5.0.0-alpha.45) (2020-02-03)
|
||||||
|
|
||||||
|
**Note:** Version bump only for package @react-navigation/drawer
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
# [5.0.0-alpha.44](https://github.com/react-navigation/navigation-ex/tree/master/packages/drawer/compare/@react-navigation/drawer@5.0.0-alpha.41...@react-navigation/drawer@5.0.0-alpha.44) (2020-02-02)
|
||||||
|
|
||||||
|
|
||||||
|
### Bug Fixes
|
||||||
|
|
||||||
|
* add licenses ([0c159db](https://github.com/react-navigation/navigation-ex/tree/master/packages/drawer/commit/0c159db4c9bc85e83b5cfe6819ab2562669a4d8f))
|
||||||
|
* fix drawerType=back when drawer is on right ([9198597](https://github.com/react-navigation/navigation-ex/tree/master/packages/drawer/commit/9198597b7f0a34fbe3844ec86a8b82171036f8ed)), closes [#316](https://github.com/react-navigation/navigation-ex/tree/master/packages/drawer/issues/316)
|
||||||
|
* handle back button in drawer itself ([0e8fda3](https://github.com/react-navigation/navigation-ex/tree/master/packages/drawer/commit/0e8fda319685a34090cfe82da08084c156eb5783))
|
||||||
|
* screens integration on Android ([#294](https://github.com/react-navigation/navigation-ex/tree/master/packages/drawer/issues/294)) ([9bfb295](https://github.com/react-navigation/navigation-ex/tree/master/packages/drawer/commit/9bfb29562020c61b4d5c9bee278bcb1c7bdb8b67))
|
||||||
|
* update screens for native stack ([5411816](https://github.com/react-navigation/navigation-ex/tree/master/packages/drawer/commit/54118161885738a6d20b062c7e6679f3bace8424))
|
||||||
|
* wrap navigators in gesture handler root ([41a5e1a](https://github.com/react-navigation/navigation-ex/tree/master/packages/drawer/commit/41a5e1a385aa5180abc3992a4c67077c37b998b9))
|
||||||
|
|
||||||
|
|
||||||
|
### Features
|
||||||
|
|
||||||
|
* add useIsDrawerOpen hook ([#299](https://github.com/react-navigation/navigation-ex/tree/master/packages/drawer/issues/299)) ([ecd68af](https://github.com/react-navigation/navigation-ex/tree/master/packages/drawer/commit/ecd68afb46a4c56200748da5e5fb284fa5a839db))
|
||||||
|
* integrate with history API on web ([5a3f835](https://github.com/react-navigation/navigation-ex/tree/master/packages/drawer/commit/5a3f8356b05bff7ed20893a5db6804612da3e568))
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
# [5.0.0-alpha.42](https://github.com/react-navigation/navigation-ex/tree/master/packages/drawer/compare/@react-navigation/drawer@5.0.0-alpha.41...@react-navigation/drawer@5.0.0-alpha.42) (2020-02-02)
|
||||||
|
|
||||||
|
|
||||||
|
### Bug Fixes
|
||||||
|
|
||||||
|
* add licenses ([0c159db](https://github.com/react-navigation/navigation-ex/tree/master/packages/drawer/commit/0c159db4c9bc85e83b5cfe6819ab2562669a4d8f))
|
||||||
|
* fix drawerType=back when drawer is on right ([9198597](https://github.com/react-navigation/navigation-ex/tree/master/packages/drawer/commit/9198597b7f0a34fbe3844ec86a8b82171036f8ed)), closes [#316](https://github.com/react-navigation/navigation-ex/tree/master/packages/drawer/issues/316)
|
||||||
|
* handle back button in drawer itself ([0e8fda3](https://github.com/react-navigation/navigation-ex/tree/master/packages/drawer/commit/0e8fda319685a34090cfe82da08084c156eb5783))
|
||||||
|
* screens integration on Android ([#294](https://github.com/react-navigation/navigation-ex/tree/master/packages/drawer/issues/294)) ([9bfb295](https://github.com/react-navigation/navigation-ex/tree/master/packages/drawer/commit/9bfb29562020c61b4d5c9bee278bcb1c7bdb8b67))
|
||||||
|
* update screens for native stack ([5411816](https://github.com/react-navigation/navigation-ex/tree/master/packages/drawer/commit/54118161885738a6d20b062c7e6679f3bace8424))
|
||||||
|
|
||||||
|
|
||||||
|
### Features
|
||||||
|
|
||||||
|
* add useIsDrawerOpen hook ([#299](https://github.com/react-navigation/navigation-ex/tree/master/packages/drawer/issues/299)) ([ecd68af](https://github.com/react-navigation/navigation-ex/tree/master/packages/drawer/commit/ecd68afb46a4c56200748da5e5fb284fa5a839db))
|
||||||
|
* integrate with history API on web ([5a3f835](https://github.com/react-navigation/navigation-ex/tree/master/packages/drawer/commit/5a3f8356b05bff7ed20893a5db6804612da3e568))
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
# [5.0.0-alpha.41](https://github.com/react-navigation/navigation-ex/tree/master/packages/drawer/compare/@react-navigation/drawer@5.0.0-alpha.40...@react-navigation/drawer@5.0.0-alpha.41) (2020-01-24)
|
||||||
|
|
||||||
|
**Note:** Version bump only for package @react-navigation/drawer
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
# [5.0.0-alpha.40](https://github.com/react-navigation/navigation-ex/tree/master/packages/drawer/compare/@react-navigation/drawer@5.0.0-alpha.39...@react-navigation/drawer@5.0.0-alpha.40) (2020-01-23)
|
# [5.0.0-alpha.40](https://github.com/react-navigation/navigation-ex/tree/master/packages/drawer/compare/@react-navigation/drawer@5.0.0-alpha.39...@react-navigation/drawer@5.0.0-alpha.40) (2020-01-23)
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
21
packages/drawer/LICENSE
Normal file
@@ -0,0 +1,21 @@
|
|||||||
|
MIT License
|
||||||
|
|
||||||
|
Copyright (c) 2017 React Navigation Contributors
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
of this software and associated documentation files (the "Software"), to deal
|
||||||
|
in the Software without restriction, including without limitation the rights
|
||||||
|
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
copies of the Software, and to permit persons to whom the Software is
|
||||||
|
furnished to do so, subject to the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be included in all
|
||||||
|
copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
SOFTWARE.
|
||||||
@@ -11,7 +11,7 @@
|
|||||||
"material",
|
"material",
|
||||||
"drawer"
|
"drawer"
|
||||||
],
|
],
|
||||||
"version": "5.0.0-alpha.40",
|
"version": "5.0.0-alpha.45",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"repository": "https://github.com/react-navigation/navigation-ex/tree/master/packages/drawer",
|
"repository": "https://github.com/react-navigation/navigation-ex/tree/master/packages/drawer",
|
||||||
"main": "lib/commonjs/index.js",
|
"main": "lib/commonjs/index.js",
|
||||||
@@ -31,7 +31,7 @@
|
|||||||
"clean": "del lib"
|
"clean": "del lib"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@react-navigation/routers": "^5.0.0-alpha.26",
|
"@react-navigation/routers": "^5.0.0-alpha.31",
|
||||||
"color": "^3.1.2",
|
"color": "^3.1.2",
|
||||||
"react-native-iphone-x-helper": "^1.2.1"
|
"react-native-iphone-x-helper": "^1.2.1"
|
||||||
},
|
},
|
||||||
@@ -42,10 +42,10 @@
|
|||||||
"del-cli": "^3.0.0",
|
"del-cli": "^3.0.0",
|
||||||
"react": "~16.9.0",
|
"react": "~16.9.0",
|
||||||
"react-native": "~0.61.5",
|
"react-native": "~0.61.5",
|
||||||
"react-native-gesture-handler": "^1.5.3",
|
"react-native-gesture-handler": "^1.5.5",
|
||||||
"react-native-reanimated": "^1.4.0",
|
"react-native-reanimated": "^1.4.0",
|
||||||
"react-native-safe-area-context": "^0.6.2",
|
"react-native-safe-area-context": "^0.6.2",
|
||||||
"react-native-screens": "^2.0.0-alpha.25",
|
"react-native-screens": "^2.0.0-alpha.33",
|
||||||
"typescript": "^3.7.4"
|
"typescript": "^3.7.4"
|
||||||
},
|
},
|
||||||
"peerDependencies": {
|
"peerDependencies": {
|
||||||
@@ -55,7 +55,7 @@
|
|||||||
"react-native-gesture-handler": "^1.0.0",
|
"react-native-gesture-handler": "^1.0.0",
|
||||||
"react-native-reanimated": "^1.0.0",
|
"react-native-reanimated": "^1.0.0",
|
||||||
"react-native-safe-area-context": "^0.6.0",
|
"react-native-safe-area-context": "^0.6.0",
|
||||||
"react-native-screens": "^1.0.0-alpha.0 || ^2.0.0-alpha.0"
|
"react-native-screens": "^2.0.0-alpha.33"
|
||||||
},
|
},
|
||||||
"@react-native-community/bob": {
|
"@react-native-community/bob": {
|
||||||
"source": "src",
|
"source": "src",
|
||||||
|
|||||||
@@ -17,6 +17,8 @@ export { default as DrawerContentScrollView } from './views/DrawerContentScrollV
|
|||||||
*/
|
*/
|
||||||
export { default as DrawerGestureContext } from './utils/DrawerGestureContext';
|
export { default as DrawerGestureContext } from './utils/DrawerGestureContext';
|
||||||
|
|
||||||
|
export { default as useIsDrawerOpen } from './utils/useIsDrawerOpen';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Types
|
* Types
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -63,11 +63,6 @@ export type DrawerNavigationConfig<T = DrawerContentOptions> = {
|
|||||||
* Set it to `false` if you want to render all screens on initial render.
|
* Set it to `false` if you want to render all screens on initial render.
|
||||||
*/
|
*/
|
||||||
lazy?: boolean;
|
lazy?: boolean;
|
||||||
/**
|
|
||||||
* Whether a screen should be unmounted when navigating away from it.
|
|
||||||
* Defaults to `false`.
|
|
||||||
*/
|
|
||||||
unmountInactiveScreens?: boolean;
|
|
||||||
/**
|
/**
|
||||||
* Function that returns React element to render as the content of the drawer, for example, navigation items.
|
* Function that returns React element to render as the content of the drawer, for example, navigation items.
|
||||||
* Defaults to `DrawerContent`.
|
* Defaults to `DrawerContent`.
|
||||||
@@ -117,6 +112,11 @@ export type DrawerNavigationOptions = {
|
|||||||
* Defaults to `true`
|
* Defaults to `true`
|
||||||
*/
|
*/
|
||||||
gestureEnabled?: boolean;
|
gestureEnabled?: boolean;
|
||||||
|
/**
|
||||||
|
* Whether this screen should be unmounted when navigating away from it.
|
||||||
|
* Defaults to `false`.
|
||||||
|
*/
|
||||||
|
unmountOnBlur?: boolean;
|
||||||
};
|
};
|
||||||
|
|
||||||
export type DrawerContentComponentProps<T = DrawerContentOptions> = T & {
|
export type DrawerContentComponentProps<T = DrawerContentOptions> = T & {
|
||||||
@@ -128,10 +128,6 @@ export type DrawerContentComponentProps<T = DrawerContentOptions> = T & {
|
|||||||
* `0` is closed, `1` is open.
|
* `0` is closed, `1` is open.
|
||||||
*/
|
*/
|
||||||
progress: Animated.Node<number>;
|
progress: Animated.Node<number>;
|
||||||
/**
|
|
||||||
* Position of the drawer on the screen.
|
|
||||||
*/
|
|
||||||
drawerPosition: 'left' | 'right';
|
|
||||||
};
|
};
|
||||||
|
|
||||||
export type DrawerContentOptions = {
|
export type DrawerContentOptions = {
|
||||||
|
|||||||
3
packages/drawer/src/utils/DrawerPositionContext.tsx
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
import * as React from 'react';
|
||||||
|
|
||||||
|
export default React.createContext<'left' | 'right' | undefined>(undefined);
|
||||||
38
packages/drawer/src/utils/useIsDrawerOpen.tsx
Normal file
@@ -0,0 +1,38 @@
|
|||||||
|
import * as React from 'react';
|
||||||
|
import { useNavigation, ParamListBase } from '@react-navigation/native';
|
||||||
|
import { DrawerNavigationProp } from '../types';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Hook to detect if the drawer is open in a parent navigator.
|
||||||
|
*/
|
||||||
|
export default function useIsDrawerOpen() {
|
||||||
|
const navigation = useNavigation();
|
||||||
|
|
||||||
|
let drawer = navigation as DrawerNavigationProp<ParamListBase>;
|
||||||
|
|
||||||
|
// The screen might be inside another navigator such as stack nested in drawer
|
||||||
|
// We need to find the closest drawer navigator and add the listener there
|
||||||
|
while (drawer && drawer.dangerouslyGetState().type !== 'drawer') {
|
||||||
|
drawer = drawer.dangerouslyGetParent();
|
||||||
|
}
|
||||||
|
|
||||||
|
const [isDrawerOpen, setIsDrawerOpen] = React.useState(() =>
|
||||||
|
drawer
|
||||||
|
? Boolean(
|
||||||
|
drawer.dangerouslyGetState().history.find(it => it.type === 'drawer')
|
||||||
|
)
|
||||||
|
: false
|
||||||
|
);
|
||||||
|
|
||||||
|
React.useEffect(() => {
|
||||||
|
const unsubscribe = drawer.addListener('state', e => {
|
||||||
|
setIsDrawerOpen(
|
||||||
|
Boolean(e.data.state.history.find(it => it.type === 'drawer'))
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
return unsubscribe;
|
||||||
|
}, [drawer, isDrawerOpen]);
|
||||||
|
|
||||||
|
return isDrawerOpen;
|
||||||
|
}
|
||||||
@@ -17,6 +17,7 @@ import {
|
|||||||
State,
|
State,
|
||||||
} from 'react-native-gesture-handler';
|
} from 'react-native-gesture-handler';
|
||||||
import Animated from 'react-native-reanimated';
|
import Animated from 'react-native-reanimated';
|
||||||
|
import Overlay from './Overlay';
|
||||||
|
|
||||||
const {
|
const {
|
||||||
Clock,
|
Clock,
|
||||||
@@ -25,7 +26,6 @@ const {
|
|||||||
clockRunning,
|
clockRunning,
|
||||||
startClock,
|
startClock,
|
||||||
stopClock,
|
stopClock,
|
||||||
interpolate,
|
|
||||||
spring,
|
spring,
|
||||||
abs,
|
abs,
|
||||||
add,
|
add,
|
||||||
@@ -52,8 +52,6 @@ const FALSE = 0;
|
|||||||
const NOOP = 0;
|
const NOOP = 0;
|
||||||
const UNSET = -1;
|
const UNSET = -1;
|
||||||
|
|
||||||
const PROGRESS_EPSILON = 0.05;
|
|
||||||
|
|
||||||
const DIRECTION_LEFT = 1;
|
const DIRECTION_LEFT = 1;
|
||||||
const DIRECTION_RIGHT = -1;
|
const DIRECTION_RIGHT = -1;
|
||||||
|
|
||||||
@@ -525,21 +523,29 @@ export default class DrawerView extends React.PureComponent<Props> {
|
|||||||
gestureHandlerProps,
|
gestureHandlerProps,
|
||||||
} = this.props;
|
} = this.props;
|
||||||
|
|
||||||
const right = drawerPosition === 'right';
|
const isRight = drawerPosition === 'right';
|
||||||
|
|
||||||
const contentTranslateX = drawerType === 'front' ? 0 : this.translateX;
|
const contentTranslateX = drawerType === 'front' ? 0 : this.translateX;
|
||||||
const drawerTranslateX =
|
const drawerTranslateX =
|
||||||
drawerType === 'back'
|
drawerType === 'back'
|
||||||
? I18nManager.isRTL
|
? I18nManager.isRTL
|
||||||
? multiply(this.drawerWidth, DIRECTION_RIGHT)
|
? multiply(
|
||||||
: this.drawerWidth
|
sub(this.containerWidth, this.drawerWidth),
|
||||||
|
isRight ? 1 : -1
|
||||||
|
)
|
||||||
|
: 0
|
||||||
: this.translateX;
|
: this.translateX;
|
||||||
|
|
||||||
const offset = I18nManager.isRTL ? '100%' : multiply(this.drawerWidth, -1);
|
const offset =
|
||||||
|
drawerType === 'back'
|
||||||
|
? 0
|
||||||
|
: I18nManager.isRTL
|
||||||
|
? '100%'
|
||||||
|
: multiply(this.drawerWidth, -1);
|
||||||
|
|
||||||
// FIXME: Currently hitSlop is broken when on Android when drawer is on right
|
// FIXME: Currently hitSlop is broken when on Android when drawer is on right
|
||||||
// https://github.com/kmagiera/react-native-gesture-handler/issues/569
|
// https://github.com/kmagiera/react-native-gesture-handler/issues/569
|
||||||
const hitSlop = right
|
const hitSlop = isRight
|
||||||
? // Extend hitSlop to the side of the screen when drawer is closed
|
? // Extend hitSlop to the side of the screen when drawer is closed
|
||||||
// This lets the user drag the drawer from the side of the screen
|
// This lets the user drag the drawer from the side of the screen
|
||||||
{ right: 0, width: open ? undefined : swipeEdgeWidth }
|
{ right: 0, width: open ? undefined : swipeEdgeWidth }
|
||||||
@@ -577,26 +583,7 @@ export default class DrawerView extends React.PureComponent<Props> {
|
|||||||
{renderSceneContent({ progress: this.progress })}
|
{renderSceneContent({ progress: this.progress })}
|
||||||
</View>
|
</View>
|
||||||
<TapGestureHandler onHandlerStateChange={this.handleTapStateChange}>
|
<TapGestureHandler onHandlerStateChange={this.handleTapStateChange}>
|
||||||
<Animated.View
|
<Overlay progress={this.progress} style={overlayStyle} />
|
||||||
style={[
|
|
||||||
styles.overlay,
|
|
||||||
{
|
|
||||||
opacity: interpolate(this.progress, {
|
|
||||||
inputRange: [PROGRESS_EPSILON, 1],
|
|
||||||
outputRange: [0, 1],
|
|
||||||
}),
|
|
||||||
// We don't want the user to be able to press through the overlay when drawer is open
|
|
||||||
// One approach is to adjust the pointerEvents based on the progress
|
|
||||||
// But we can also send the overlay behind the screen, which works, and is much less code
|
|
||||||
zIndex: cond(
|
|
||||||
greaterThan(this.progress, PROGRESS_EPSILON),
|
|
||||||
0,
|
|
||||||
-1
|
|
||||||
),
|
|
||||||
},
|
|
||||||
overlayStyle,
|
|
||||||
]}
|
|
||||||
/>
|
|
||||||
</TapGestureHandler>
|
</TapGestureHandler>
|
||||||
</Animated.View>
|
</Animated.View>
|
||||||
<Animated.Code
|
<Animated.Code
|
||||||
@@ -615,7 +602,7 @@ export default class DrawerView extends React.PureComponent<Props> {
|
|||||||
onLayout={this.handleDrawerLayout}
|
onLayout={this.handleDrawerLayout}
|
||||||
style={[
|
style={[
|
||||||
styles.container,
|
styles.container,
|
||||||
right ? { right: offset } : { left: offset },
|
isRight ? { right: offset } : { left: offset },
|
||||||
{
|
{
|
||||||
transform: [{ translateX: drawerTranslateX }],
|
transform: [{ translateX: drawerTranslateX }],
|
||||||
opacity: this.drawerOpacity,
|
opacity: this.drawerOpacity,
|
||||||
@@ -641,10 +628,6 @@ const styles = StyleSheet.create({
|
|||||||
width: '80%',
|
width: '80%',
|
||||||
maxWidth: '100%',
|
maxWidth: '100%',
|
||||||
},
|
},
|
||||||
overlay: {
|
|
||||||
...StyleSheet.absoluteFillObject,
|
|
||||||
backgroundColor: 'rgba(0, 0, 0, 0.5)',
|
|
||||||
},
|
|
||||||
content: {
|
content: {
|
||||||
flex: 1,
|
flex: 1,
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -1,19 +1,19 @@
|
|||||||
import * as React from 'react';
|
import * as React from 'react';
|
||||||
import { ScrollView, StyleSheet, ScrollViewProps } from 'react-native';
|
import { ScrollView, StyleSheet, ScrollViewProps } from 'react-native';
|
||||||
import { useSafeArea } from 'react-native-safe-area-context';
|
import { useSafeArea } from 'react-native-safe-area-context';
|
||||||
|
import DrawerPositionContext from '../utils/DrawerPositionContext';
|
||||||
|
|
||||||
type Props = ScrollViewProps & {
|
type Props = ScrollViewProps & {
|
||||||
drawerPosition: 'left' | 'right';
|
|
||||||
children: React.ReactNode;
|
children: React.ReactNode;
|
||||||
};
|
};
|
||||||
|
|
||||||
export default function DrawerContentScrollView({
|
export default function DrawerContentScrollView({
|
||||||
contentContainerStyle,
|
contentContainerStyle,
|
||||||
style,
|
style,
|
||||||
drawerPosition,
|
|
||||||
children,
|
children,
|
||||||
...rest
|
...rest
|
||||||
}: Props) {
|
}: Props) {
|
||||||
|
const drawerPosition = React.useContext(DrawerPositionContext);
|
||||||
const insets = useSafeArea();
|
const insets = useSafeArea();
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
|||||||
@@ -1,14 +1,20 @@
|
|||||||
import * as React from 'react';
|
import * as React from 'react';
|
||||||
import {
|
import {
|
||||||
|
View,
|
||||||
Dimensions,
|
Dimensions,
|
||||||
StyleSheet,
|
StyleSheet,
|
||||||
I18nManager,
|
I18nManager,
|
||||||
Platform,
|
Platform,
|
||||||
ScaledSize,
|
ScaledSize,
|
||||||
|
BackHandler,
|
||||||
|
NativeEventSubscription,
|
||||||
} from 'react-native';
|
} from 'react-native';
|
||||||
// eslint-disable-next-line import/no-unresolved
|
// eslint-disable-next-line import/no-unresolved
|
||||||
import { ScreenContainer } from 'react-native-screens';
|
import { ScreenContainer } from 'react-native-screens';
|
||||||
import { PanGestureHandler } from 'react-native-gesture-handler';
|
import {
|
||||||
|
PanGestureHandler,
|
||||||
|
GestureHandlerRootView,
|
||||||
|
} from 'react-native-gesture-handler';
|
||||||
import {
|
import {
|
||||||
DrawerNavigationState,
|
DrawerNavigationState,
|
||||||
DrawerActions,
|
DrawerActions,
|
||||||
@@ -26,6 +32,7 @@ import {
|
|||||||
DrawerNavigationHelpers,
|
DrawerNavigationHelpers,
|
||||||
DrawerContentComponentProps,
|
DrawerContentComponentProps,
|
||||||
} from '../types';
|
} from '../types';
|
||||||
|
import DrawerPositionContext from '../utils/DrawerPositionContext';
|
||||||
|
|
||||||
type Props = DrawerNavigationConfig & {
|
type Props = DrawerNavigationConfig & {
|
||||||
state: DrawerNavigationState;
|
state: DrawerNavigationState;
|
||||||
@@ -54,6 +61,8 @@ const getDefaultDrawerWidth = ({
|
|||||||
return Math.min(smallerAxisSize - appBarHeight, maxWidth);
|
return Math.min(smallerAxisSize - appBarHeight, maxWidth);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const GestureHandlerWrapper = GestureHandlerRootView ?? View;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Component that renders the drawer.
|
* Component that renders the drawer.
|
||||||
*/
|
*/
|
||||||
@@ -77,7 +86,6 @@ export default function DrawerView({
|
|||||||
gestureHandlerProps,
|
gestureHandlerProps,
|
||||||
minSwipeDistance,
|
minSwipeDistance,
|
||||||
sceneContainerStyle,
|
sceneContainerStyle,
|
||||||
unmountInactiveScreens,
|
|
||||||
}: Props) {
|
}: Props) {
|
||||||
const [loaded, setLoaded] = React.useState([state.index]);
|
const [loaded, setLoaded] = React.useState([state.index]);
|
||||||
const [drawerWidth, setDrawerWidth] = React.useState(() =>
|
const [drawerWidth, setDrawerWidth] = React.useState(() =>
|
||||||
@@ -88,6 +96,47 @@ export default function DrawerView({
|
|||||||
|
|
||||||
const { colors } = useTheme();
|
const { colors } = useTheme();
|
||||||
|
|
||||||
|
const isDrawerOpen = Boolean(state.history.find(it => it.type === 'drawer'));
|
||||||
|
|
||||||
|
const handleDrawerOpen = React.useCallback(() => {
|
||||||
|
navigation.dispatch({
|
||||||
|
...DrawerActions.openDrawer(),
|
||||||
|
target: state.key,
|
||||||
|
});
|
||||||
|
}, [navigation, state.key]);
|
||||||
|
|
||||||
|
const handleDrawerClose = React.useCallback(() => {
|
||||||
|
navigation.dispatch({
|
||||||
|
...DrawerActions.closeDrawer(),
|
||||||
|
target: state.key,
|
||||||
|
});
|
||||||
|
}, [navigation, state.key]);
|
||||||
|
|
||||||
|
React.useEffect(() => {
|
||||||
|
if (isDrawerOpen) {
|
||||||
|
navigation.emit({ type: 'drawerOpen' });
|
||||||
|
} else {
|
||||||
|
navigation.emit({ type: 'drawerClose' });
|
||||||
|
}
|
||||||
|
}, [isDrawerOpen, navigation]);
|
||||||
|
|
||||||
|
React.useEffect(() => {
|
||||||
|
let subscription: NativeEventSubscription | undefined;
|
||||||
|
|
||||||
|
if (isDrawerOpen) {
|
||||||
|
// We only add the subscription when drawer opens
|
||||||
|
// This way we can make sure that the subscription is added as late as possible
|
||||||
|
// This will make sure that our handler will run first when back button is pressed
|
||||||
|
subscription = BackHandler.addEventListener('hardwareBackPress', () => {
|
||||||
|
handleDrawerClose();
|
||||||
|
|
||||||
|
return true;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
return () => subscription?.remove();
|
||||||
|
}, [handleDrawerClose, isDrawerOpen, navigation, state.key]);
|
||||||
|
|
||||||
React.useEffect(() => {
|
React.useEffect(() => {
|
||||||
const updateWidth = ({ window }: { window: ScaledSize }) => {
|
const updateWidth = ({ window }: { window: ScaledSize }) => {
|
||||||
setDrawerWidth(getDefaultDrawerWidth(window));
|
setDrawerWidth(getDefaultDrawerWidth(window));
|
||||||
@@ -102,51 +151,37 @@ export default function DrawerView({
|
|||||||
setLoaded([...loaded, state.index]);
|
setLoaded([...loaded, state.index]);
|
||||||
}
|
}
|
||||||
|
|
||||||
const handleDrawerOpen = () => {
|
|
||||||
navigation.dispatch({
|
|
||||||
...DrawerActions.openDrawer(),
|
|
||||||
target: state.key,
|
|
||||||
});
|
|
||||||
|
|
||||||
navigation.emit({ type: 'drawerOpen' });
|
|
||||||
};
|
|
||||||
|
|
||||||
const handleDrawerClose = () => {
|
|
||||||
navigation.dispatch({
|
|
||||||
...DrawerActions.closeDrawer(),
|
|
||||||
target: state.key,
|
|
||||||
});
|
|
||||||
|
|
||||||
navigation.emit({ type: 'drawerClose' });
|
|
||||||
};
|
|
||||||
|
|
||||||
const renderNavigationView = ({ progress }: any) => {
|
const renderNavigationView = ({ progress }: any) => {
|
||||||
return drawerContent({
|
return (
|
||||||
...drawerContentOptions,
|
<DrawerPositionContext.Provider value={drawerPosition}>
|
||||||
progress: progress,
|
{drawerContent({
|
||||||
state: state,
|
...drawerContentOptions,
|
||||||
navigation: navigation,
|
progress: progress,
|
||||||
descriptors: descriptors,
|
state: state,
|
||||||
drawerPosition: drawerPosition,
|
navigation: navigation,
|
||||||
});
|
descriptors: descriptors,
|
||||||
|
})}
|
||||||
|
</DrawerPositionContext.Provider>
|
||||||
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
const renderContent = () => {
|
const renderContent = () => {
|
||||||
return (
|
return (
|
||||||
<ScreenContainer style={styles.content}>
|
<ScreenContainer style={styles.content}>
|
||||||
{state.routes.map((route, index) => {
|
{state.routes.map((route, index) => {
|
||||||
if (unmountInactiveScreens && index !== state.index) {
|
const descriptor = descriptors[route.key];
|
||||||
|
const { unmountOnBlur } = descriptor.options;
|
||||||
|
const isFocused = state.index === index;
|
||||||
|
|
||||||
|
if (unmountOnBlur && !isFocused) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (lazy && !loaded.includes(index) && index !== state.index) {
|
if (lazy && !loaded.includes(index) && !isFocused) {
|
||||||
// Don't render a screen if we've never navigated to it
|
// Don't render a screen if we've never navigated to it
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
const isFocused = state.index === index;
|
|
||||||
const descriptor = descriptors[route.key];
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<ResourceSavingScene
|
<ResourceSavingScene
|
||||||
key={route.key}
|
key={route.key}
|
||||||
@@ -165,40 +200,42 @@ export default function DrawerView({
|
|||||||
const { gestureEnabled } = descriptors[activeKey].options;
|
const { gestureEnabled } = descriptors[activeKey].options;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<SafeAreaProviderCompat>
|
<GestureHandlerWrapper style={styles.content}>
|
||||||
<DrawerGestureContext.Provider value={drawerGestureRef}>
|
<SafeAreaProviderCompat>
|
||||||
<Drawer
|
<DrawerGestureContext.Provider value={drawerGestureRef}>
|
||||||
open={state.isDrawerOpen}
|
<Drawer
|
||||||
gestureEnabled={gestureEnabled !== false}
|
open={isDrawerOpen}
|
||||||
onOpen={handleDrawerOpen}
|
gestureEnabled={gestureEnabled !== false}
|
||||||
onClose={handleDrawerClose}
|
onOpen={handleDrawerOpen}
|
||||||
onGestureRef={ref => {
|
onClose={handleDrawerClose}
|
||||||
// @ts-ignore
|
onGestureRef={ref => {
|
||||||
drawerGestureRef.current = ref;
|
// @ts-ignore
|
||||||
}}
|
drawerGestureRef.current = ref;
|
||||||
gestureHandlerProps={gestureHandlerProps}
|
}}
|
||||||
drawerType={drawerType}
|
gestureHandlerProps={gestureHandlerProps}
|
||||||
drawerPosition={drawerPosition}
|
drawerType={drawerType}
|
||||||
sceneContainerStyle={[
|
drawerPosition={drawerPosition}
|
||||||
{ backgroundColor: colors.background },
|
sceneContainerStyle={[
|
||||||
sceneContainerStyle,
|
{ backgroundColor: colors.background },
|
||||||
]}
|
sceneContainerStyle,
|
||||||
drawerStyle={[
|
]}
|
||||||
{ width: drawerWidth, backgroundColor: colors.card },
|
drawerStyle={[
|
||||||
drawerStyle,
|
{ width: drawerWidth, backgroundColor: colors.card },
|
||||||
]}
|
drawerStyle,
|
||||||
overlayStyle={{ backgroundColor: overlayColor }}
|
]}
|
||||||
swipeEdgeWidth={edgeWidth}
|
overlayStyle={{ backgroundColor: overlayColor }}
|
||||||
swipeDistanceThreshold={minSwipeDistance}
|
swipeEdgeWidth={edgeWidth}
|
||||||
hideStatusBar={hideStatusBar}
|
swipeDistanceThreshold={minSwipeDistance}
|
||||||
statusBarAnimation={statusBarAnimation}
|
hideStatusBar={hideStatusBar}
|
||||||
renderDrawerContent={renderNavigationView}
|
statusBarAnimation={statusBarAnimation}
|
||||||
renderSceneContent={renderContent}
|
renderDrawerContent={renderNavigationView}
|
||||||
keyboardDismissMode={keyboardDismissMode}
|
renderSceneContent={renderContent}
|
||||||
drawerPostion={drawerPosition}
|
keyboardDismissMode={keyboardDismissMode}
|
||||||
/>
|
drawerPostion={drawerPosition}
|
||||||
</DrawerGestureContext.Provider>
|
/>
|
||||||
</SafeAreaProviderCompat>
|
</DrawerGestureContext.Provider>
|
||||||
|
</SafeAreaProviderCompat>
|
||||||
|
</GestureHandlerWrapper>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
51
packages/drawer/src/views/Overlay.tsx
Normal file
@@ -0,0 +1,51 @@
|
|||||||
|
import * as React from 'react';
|
||||||
|
import { Platform, StyleSheet } from 'react-native';
|
||||||
|
import Animated from 'react-native-reanimated';
|
||||||
|
|
||||||
|
const { interpolate, cond, greaterThan } = Animated;
|
||||||
|
|
||||||
|
const PROGRESS_EPSILON = 0.05;
|
||||||
|
|
||||||
|
type Props = React.ComponentProps<typeof Animated.View> & {
|
||||||
|
progress: Animated.Node<number>;
|
||||||
|
};
|
||||||
|
|
||||||
|
const Overlay = React.forwardRef(function Overlay(
|
||||||
|
{ progress, style, ...props }: Props,
|
||||||
|
ref: React.Ref<Animated.View>
|
||||||
|
) {
|
||||||
|
const animatedStyle = {
|
||||||
|
opacity: interpolate(progress, {
|
||||||
|
inputRange: [PROGRESS_EPSILON, 1],
|
||||||
|
outputRange: [0, 1],
|
||||||
|
}),
|
||||||
|
// We don't want the user to be able to press through the overlay when drawer is open
|
||||||
|
// One approach is to adjust the pointerEvents based on the progress
|
||||||
|
// But we can also send the overlay behind the screen, which works, and is much less code
|
||||||
|
zIndex: cond(greaterThan(progress, PROGRESS_EPSILON), 0, -1),
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Animated.View
|
||||||
|
{...props}
|
||||||
|
ref={ref}
|
||||||
|
style={[styles.overlay, animatedStyle, style]}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
const styles = StyleSheet.create({
|
||||||
|
overlay: {
|
||||||
|
...StyleSheet.absoluteFillObject,
|
||||||
|
backgroundColor: 'rgba(0, 0, 0, 0.5)',
|
||||||
|
...Platform.select({
|
||||||
|
web: {
|
||||||
|
// Disable touch highlight on mobile Safari.
|
||||||
|
WebkitTapHighlightColor: 'transparent',
|
||||||
|
},
|
||||||
|
default: {},
|
||||||
|
}),
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
export default Overlay;
|
||||||
@@ -3,6 +3,44 @@
|
|||||||
All notable changes to this project will be documented in this file.
|
All notable changes to this project will be documented in this file.
|
||||||
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
||||||
|
|
||||||
|
# [5.0.0-alpha.40](https://github.com/react-navigation/navigation-ex/tree/master/packages/material-bottom-tabs/compare/@react-navigation/material-bottom-tabs@5.0.0-alpha.39...@react-navigation/material-bottom-tabs@5.0.0-alpha.40) (2020-02-03)
|
||||||
|
|
||||||
|
**Note:** Version bump only for package @react-navigation/material-bottom-tabs
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
# [5.0.0-alpha.39](https://github.com/react-navigation/navigation-ex/tree/master/packages/material-bottom-tabs/compare/@react-navigation/material-bottom-tabs@5.0.0-alpha.36...@react-navigation/material-bottom-tabs@5.0.0-alpha.39) (2020-02-02)
|
||||||
|
|
||||||
|
|
||||||
|
### Bug Fixes
|
||||||
|
|
||||||
|
* add licenses ([0c159db](https://github.com/react-navigation/navigation-ex/tree/master/packages/material-bottom-tabs/commit/0c159db4c9bc85e83b5cfe6819ab2562669a4d8f))
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
# [5.0.0-alpha.37](https://github.com/react-navigation/navigation-ex/tree/master/packages/material-bottom-tabs/compare/@react-navigation/material-bottom-tabs@5.0.0-alpha.36...@react-navigation/material-bottom-tabs@5.0.0-alpha.37) (2020-02-02)
|
||||||
|
|
||||||
|
|
||||||
|
### Bug Fixes
|
||||||
|
|
||||||
|
* add licenses ([0c159db](https://github.com/react-navigation/navigation-ex/tree/master/packages/material-bottom-tabs/commit/0c159db4c9bc85e83b5cfe6819ab2562669a4d8f))
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
# [5.0.0-alpha.36](https://github.com/react-navigation/navigation-ex/tree/master/packages/material-bottom-tabs/compare/@react-navigation/material-bottom-tabs@5.0.0-alpha.35...@react-navigation/material-bottom-tabs@5.0.0-alpha.36) (2020-01-24)
|
||||||
|
|
||||||
|
**Note:** Version bump only for package @react-navigation/material-bottom-tabs
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
# [5.0.0-alpha.35](https://github.com/react-navigation/navigation-ex/tree/master/packages/material-bottom-tabs/compare/@react-navigation/material-bottom-tabs@5.0.0-alpha.34...@react-navigation/material-bottom-tabs@5.0.0-alpha.35) (2020-01-23)
|
# [5.0.0-alpha.35](https://github.com/react-navigation/navigation-ex/tree/master/packages/material-bottom-tabs/compare/@react-navigation/material-bottom-tabs@5.0.0-alpha.34...@react-navigation/material-bottom-tabs@5.0.0-alpha.35) (2020-01-23)
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
21
packages/material-bottom-tabs/LICENSE
Normal file
@@ -0,0 +1,21 @@
|
|||||||
|
MIT License
|
||||||
|
|
||||||
|
Copyright (c) 2017 React Navigation Contributors
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
of this software and associated documentation files (the "Software"), to deal
|
||||||
|
in the Software without restriction, including without limitation the rights
|
||||||
|
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
copies of the Software, and to permit persons to whom the Software is
|
||||||
|
furnished to do so, subject to the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be included in all
|
||||||
|
copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
SOFTWARE.
|
||||||
@@ -11,7 +11,7 @@
|
|||||||
"material",
|
"material",
|
||||||
"tab"
|
"tab"
|
||||||
],
|
],
|
||||||
"version": "5.0.0-alpha.35",
|
"version": "5.0.0-alpha.40",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"repository": "https://github.com/react-navigation/navigation-ex/tree/master/packages/material-bottom-tabs",
|
"repository": "https://github.com/react-navigation/navigation-ex/tree/master/packages/material-bottom-tabs",
|
||||||
"main": "lib/commonjs/index.js",
|
"main": "lib/commonjs/index.js",
|
||||||
@@ -31,7 +31,7 @@
|
|||||||
"clean": "del lib"
|
"clean": "del lib"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@react-navigation/routers": "^5.0.0-alpha.26"
|
"@react-navigation/routers": "^5.0.0-alpha.31"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@react-native-community/bob": "^0.8.0",
|
"@react-native-community/bob": "^0.8.0",
|
||||||
|
|||||||