Compare commits

..

35 Commits

Author SHA1 Message Date
Kyle Fang
073f04b6eb test: rename screen 2021-06-27 09:54:36 +08:00
Kyle Fang
ed37e6aec0 docs: add comments on sort 2021-06-27 07:37:25 +08:00
Kyle Fang
f80ed7790e Merge branch 'main' of github.com:react-navigation/react-navigation into fix/sortOnPaths 2021-06-25 18:25:54 +08:00
Cedric van Putten
4c16083d51 chore: upgrade to expo-github-actions v6 2021-06-23 15:40:22 +02:00
Satyajit Sahoo
e7631ea239 chore: comment on closed issues regarding watching 2021-06-15 03:32:04 +02:00
Kyle Fang
32fe3f17d0 test: add case on :params 2021-06-14 15:39:37 +08:00
Kyle Fang
b7c5305453 fix: move :hello to bottom along with * 2021-06-14 15:38:36 +08:00
Max Schmitt
2ee435be3a chore: add nvmrc for using LTS Node.js version (#9668)
This should fix the Netlify builds too.
See here for reference: https://github.com/nvm-sh/nvm#nvmrc

The integration tests are failing but they are getting fixed in #9667.
2021-06-13 17:39:55 +02:00
Max Schmitt
016e7920df test: upgrade to the new Playwright test-runner (#9667)
Hey!

I made the following changes:

- Replaced Jest by the new Playwright test-runner
- Disabled the Jest linting rules for the Playwright e2e tests
- Rewrote the tests to the new test-runner
- Adjusted `Link.test.ts` which should be less flaky
- The tests run now across all three browsers: Chromium, Firefox, and WebKit

See here for reference about the new test-runner: https://playwright.dev/docs/test-intro

I extracted a fix for Netlify in #9668.

Let me know if you have any questions.
2021-06-13 17:38:46 +02:00
Satyajit Sahoo
26ba019155 chore: publish
- @react-navigation/bottom-tabs@6.0.0-next.19
 - @react-navigation/core@6.0.0-next.14
 - @react-navigation/devtools@6.0.0-next.15
 - @react-navigation/drawer@6.0.0-next.18
 - @react-navigation/elements@1.0.0-next.18
 - flipper-plugin-react-navigation@1.2.0
 - @react-navigation/material-bottom-tabs@6.0.0-next.15
 - @react-navigation/material-top-tabs@6.0.0-next.15
 - @react-navigation/native-stack@6.0.0-next.8
 - @react-navigation/native@6.0.0-next.14
 - @react-navigation/routers@6.0.0-next.5
 - @react-navigation/stack@6.0.0-next.26
2021-06-11 01:15:43 +02:00
Satyajit Sahoo
97772affa3 feat: show stack trace in the flipper plugin 2021-06-11 01:09:02 +02:00
Satyajit Sahoo
67f6950c14 chore: upgrade dependencies 2021-06-05 07:33:26 +02:00
Satyajit Sahoo
fe6d20c10e chore: publish
- @react-navigation/bottom-tabs@6.0.0-next.18
 - @react-navigation/drawer@6.0.0-next.17
 - @react-navigation/elements@1.0.0-next.17
 - @react-navigation/material-bottom-tabs@6.0.0-next.14
 - @react-navigation/native-stack@6.0.0-next.7
 - @react-navigation/stack@6.0.0-next.25
2021-06-01 13:30:34 +02:00
Satyajit Sahoo
7d74bd73a7 fix: tweak android q animation 2021-06-01 04:21:51 +02:00
Satyajit Sahoo
b46c433f1e fix: tweak opacity animation for PlatformPressable 2021-06-01 03:17:16 +02:00
Satyajit Sahoo
7e71ee6c47 chore: revert yarn.lock 2021-06-01 03:14:25 +02:00
Satyajit Sahoo
1287a784e6 chore: fix mapping in server babel config 2021-05-31 20:42:07 +02:00
Satyajit Sahoo
56f7df5384 chore: fix running the example app on web 2021-05-31 20:12:05 +02:00
Satyajit Sahoo
5996bbbce2 chore: bump react-native-paper 2021-05-31 19:31:08 +02:00
Satyajit Sahoo
c3ba72df65 chore: publish
- @react-navigation/bottom-tabs@6.0.0-next.17
 - @react-navigation/core@6.0.0-next.13
 - @react-navigation/devtools@6.0.0-next.14
 - @react-navigation/drawer@6.0.0-next.16
 - @react-navigation/elements@1.0.0-next.16
 - flipper-plugin-react-navigation@1.1.4
 - @react-navigation/material-bottom-tabs@6.0.0-next.13
 - @react-navigation/material-top-tabs@6.0.0-next.14
 - @react-navigation/native-stack@6.0.0-next.6
 - @react-navigation/native@6.0.0-next.13
 - @react-navigation/stack@6.0.0-next.24
2021-05-29 20:35:14 +02:00
Satyajit Sahoo
be40244214 chore: remove unused dep from flipper plugin 2021-05-29 20:32:41 +02:00
Satyajit Sahoo
7388e6d9bc chore: add a LICENSE to flipper plugin 2021-05-29 20:27:59 +02:00
Satyajit Sahoo
00e70da0d4 chore: add repository entry to flipper plugin 2021-05-29 20:22:52 +02:00
Satyajit Sahoo
70f4fe2ffa fix: remove card shadow from default animation
closes #9569
2021-05-29 20:16:41 +02:00
Satyajit Sahoo
e639748b23 refactor: rename headerSearchBar to headerSearchBarOptions 2021-05-29 20:04:30 +02:00
Satyajit Sahoo
324ea7181d fix: validate property names in linking config 2021-05-29 20:03:10 +02:00
Satyajit Sahoo
9d3731c2df chore: add a README to Flipper plugin 2021-05-29 19:28:39 +02:00
Satyajit Sahoo
baf8ff77d5 chore: publish
- @react-navigation/bottom-tabs@6.0.0-next.16
 - @react-navigation/core@6.0.0-next.12
 - @react-navigation/devtools@6.0.0-next.13
 - @react-navigation/drawer@6.0.0-next.15
 - @react-navigation/elements@1.0.0-next.15
 - flipper-plugin-react-navigation@1.1.3
 - @react-navigation/material-bottom-tabs@6.0.0-next.12
 - @react-navigation/material-top-tabs@6.0.0-next.13
 - @react-navigation/native-stack@6.0.0-next.5
 - @react-navigation/native@6.0.0-next.12
 - @react-navigation/stack@6.0.0-next.23
2021-05-29 16:04:32 +02:00
Satyajit Sahoo
b4d7b0ee86 fix: try to fix #9631 2021-05-29 16:02:40 +02:00
Satyajit Sahoo
a184ce24b3 chore: publish
- @react-navigation/bottom-tabs@6.0.0-next.15
 - @react-navigation/core@6.0.0-next.11
 - @react-navigation/devtools@6.0.0-next.12
 - @react-navigation/drawer@6.0.0-next.14
 - @react-navigation/elements@1.0.0-next.14
 - flipper-plugin-react-navigation@1.1.2
 - @react-navigation/material-bottom-tabs@6.0.0-next.11
 - @react-navigation/material-top-tabs@6.0.0-next.12
 - @react-navigation/native-stack@6.0.0-next.4
 - @react-navigation/native@6.0.0-next.11
 - @react-navigation/routers@6.0.0-next.4
 - @react-navigation/stack@6.0.0-next.22
2021-05-27 18:50:18 +02:00
Satyajit Sahoo
80cdc88588 fix: use safe area context in material bottom tabs 2021-05-27 18:48:44 +02:00
Satyajit Sahoo
b91c9b05ff chore: sort imports automatically 2021-05-26 21:29:11 +02:00
Satyajit Sahoo
29cdd886a0 chore: publish
- @react-navigation/bottom-tabs@6.0.0-next.14
 - @react-navigation/core@6.0.0-next.10
 - @react-navigation/devtools@6.0.0-next.11
 - @react-navigation/drawer@6.0.0-next.13
 - @react-navigation/elements@1.0.0-next.13
 - flipper-plugin-react-navigation@1.1.1
 - @react-navigation/material-bottom-tabs@6.0.0-next.10
 - @react-navigation/material-top-tabs@6.0.0-next.11
 - @react-navigation/native-stack@6.0.0-next.3
 - @react-navigation/native@6.0.0-next.10
 - @react-navigation/stack@6.0.0-next.21
2021-05-26 21:12:06 +02:00
Satyajit Sahoo
1d40279db1 feat: expose container ref in useNavigation 2021-05-26 21:06:16 +02:00
Satyajit Sahoo
cde44a5785 feat: add screenListeners prop on navigators similar to screenOptions 2021-05-26 00:41:09 +02:00
272 changed files with 5786 additions and 5049 deletions

View File

@@ -75,9 +75,13 @@ jobs:
- run:
name: Build example for web
command: yarn example expo build:web --no-pwa
# Yarn does not execute the postinstall scripts if the package is in the cache
- run:
name: Install browsers
command: yarn playwright install
- run:
name: Run integration tests
command: yarn example test --maxWorkers=2
command: yarn example test:e2e
build-packages:
executor: default

View File

@@ -1,5 +1,6 @@
{
"extends": "satya164",
"plugins": ["simple-import-sort"],
"settings": {
"react": {
"version": "16"
@@ -23,6 +24,13 @@
"node": true
},
"rules": {
"react/no-unused-prop-types": "off"
}
"simple-import-sort/imports": "error",
"simple-import-sort/exports": "error"
},
"overrides": [{
"files":["example/e2e/tests/*.ts"],
"rules": {
"jest/*": 0
}
}]
}

31
.github/workflows/closed-issue.yml vendored Normal file
View File

@@ -0,0 +1,31 @@
name: Comment on closed issue
on:
issue_comment:
types: [created]
jobs:
closed-issue:
runs-on: ubuntu-latest
if: ${{ github.event.issue.state == 'closed' }}
steps:
- uses: actions/github-script@v3
with:
github-token: ${{ secrets.GITHUB_TOKEN }}
script: |
const body = "Hey! This issue is closed and isn't watched by the core team. You are welcome to discuss the issue with others in this thread, but if you think this issue is still valid and needs to be tracked, please open a new issue with a repro.";
const comments = await github.issues.listComments({
issue_number: context.issue.number,
owner: context.repo.owner,
repo: context.repo.repo,
});
if (comments.data.some(comment => comment.body === body)) {
return;
}
await github.issues.createComment({
issue_number: context.issue.number,
owner: context.repo.owner,
repo: context.repo.repo,
body,
});

View File

@@ -16,10 +16,9 @@ jobs:
node-version: 14.x
- name: Setup Expo
uses: expo/expo-github-action@v5
uses: expo/expo-github-action@v6
with:
expo-token: ${{ secrets.EXPO_TOKEN }}
expo-cache: true
token: ${{ secrets.EXPO_TOKEN }}
- name: Restore yarn cache
id: yarn-cache

View File

@@ -19,10 +19,9 @@ jobs:
node-version: 14.x
- name: Setup Expo
uses: expo/expo-github-action@v5
uses: expo/expo-github-action@v6
with:
expo-token: ${{ secrets.EXPO_TOKEN }}
expo-cache: true
token: ${{ secrets.EXPO_TOKEN }}
- name: Restore yarn cache
id: yarn-cache

1
.nvmrc Normal file
View File

@@ -0,0 +1 @@
lts/*

File diff suppressed because one or more lines are too long

View File

@@ -2,4 +2,4 @@
# yarn lockfile v1
yarn-path ".yarn/releases/yarn-1.18.0.js"
yarn-path ".yarn/releases/yarn-1.22.10.cjs"

View File

@@ -1,7 +1,8 @@
import 'react-native-gesture-handler';
import { Assets } from '@react-navigation/elements';
import { registerRootComponent } from 'expo';
import { Asset } from 'expo-asset';
import { Assets } from '@react-navigation/elements';
import App from './src/index';

View File

@@ -4,7 +4,7 @@
* <p>This source code is licensed under the MIT license found in the LICENSE file in the root
* directory of this source tree.
*/
package com.reactnavigation;
package org.reactnavigation.example;
import android.content.Context;
import com.facebook.flipper.android.AndroidFlipperClient;
@@ -66,4 +66,4 @@ public class ReactNativeFlipper {
}
}
}
}
}

View File

@@ -1,44 +0,0 @@
import { page } from '../config/setup-playwright';
beforeEach(async () => {
await page.click('[data-testid=LinkComponent]');
});
const getPageInfo = async () => ({
url: await page.evaluate(() => location.pathname + location.search),
title: await page.evaluate(() => document.title),
heading: (await page.accessibility.snapshot())?.children?.find(
(it) => it.role === 'heading'
)?.name,
});
it('loads the article page', async () => {
const { url, title, heading } = await getPageInfo();
expect(url).toBe('/link-component/article/gandalf');
expect(title).toBe('Article by Gandalf - React Navigation Example');
expect(heading).toBe('Article by Gandalf');
});
it('goes to the album page and goes back', async () => {
await page.click('[href="/link-component/music"]');
{
const { url, title, heading } = await getPageInfo();
expect(url).toBe('/link-component/music');
expect(title).toBe('Albums - React Navigation Example');
expect(heading).toBe('Albums');
}
await page.click('[aria-label="Article by Gandalf, back"]');
await page.waitForNavigation();
{
const { url, title, heading } = await getPageInfo();
expect(url).toBe('/link-component/article/gandalf');
expect(title).toBe('Article by Gandalf - React Navigation Example');
expect(heading).toBe('Article by Gandalf');
}
});

View File

@@ -1,28 +0,0 @@
/* eslint-env jest */
import { chromium, Browser, BrowserContext, Page } from 'playwright';
let browser: Browser;
let context: BrowserContext;
let page: Page;
beforeAll(async () => {
browser = await chromium.launch();
});
afterAll(async () => {
await browser.close();
});
beforeEach(async () => {
context = await browser.newContext();
page = await context.newPage();
await page.goto('http://localhost:3579');
});
afterEach(async () => {
await context.close();
});
export { browser, context, page };

View File

@@ -0,0 +1,28 @@
import type { PlaywrightTestConfig } from '@playwright/test';
import path from 'path';
const config: PlaywrightTestConfig = {
testDir: path.join(__dirname, 'tests'),
globalSetup: require.resolve('./config/setup-server.ts'),
globalTeardown: require.resolve('./config/teardown-server.ts'),
workers: 1,
reporter: 'list',
projects: [
{
name: 'Chromium',
use: { browserName: 'chromium' },
},
{
name: 'Firefox',
use: { browserName: 'firefox' },
},
{
name: 'WebKit',
use: { browserName: 'webkit' },
},
],
};
export default config;

View File

@@ -0,0 +1,43 @@
import type { Page } from '@playwright/test';
import { expect, it } from './baseFixture';
it.beforeEach(async ({ page }) => {
await page.click('[data-testid=LinkComponent]');
});
const waitAndAssertPageHeading = async (
page: Page,
expectedHeading: string
) => {
await page.waitForSelector(`text=${expectedHeading}`);
const heading = (await page.accessibility.snapshot())?.children?.find(
(it) => it.role === 'heading'
)?.name;
expect(heading).toBe(expectedHeading);
};
it('loads the article page', async ({ page }) => {
await page.waitForURL('**/link-component/article/gandalf');
expect(await page.title()).toBe(
'Article by Gandalf - React Navigation Example'
);
await waitAndAssertPageHeading(page, 'Article by Gandalf');
});
it('goes to the album page and goes back', async ({ page }) => {
await page.click('[href="/link-component/music"]');
await page.waitForURL('**/link-component/music');
expect(await page.title()).toBe('Albums - React Navigation Example');
await waitAndAssertPageHeading(page, 'Albums');
await page.click('[aria-label="Article by Gandalf, back"]');
await page.waitForNavigation();
await page.waitForURL('**/link-component/article/gandalf');
expect(await page.title()).toBe(
'Article by Gandalf - React Navigation Example'
);
await waitAndAssertPageHeading(page, 'Article by Gandalf');
});

View File

@@ -0,0 +1,11 @@
import { test as baseTest } from '@playwright/test';
const test = baseTest.extend({
page: async ({ page }, use) => {
await page.goto('http://localhost:3579');
await use(page);
},
});
export const it = test;
export const expect = test.expect;

View File

@@ -1,6 +1,6 @@
import { page } from '../config/setup-playwright';
import { expect, it } from './baseFixture';
it('loads the example app', async () => {
it('loads the example app', async ({ page }) => {
const snapshot = await page.accessibility.snapshot();
expect(

View File

@@ -1,5 +1,6 @@
import fetch from 'node-fetch';
import { expect, test as it } from '@playwright/test';
import cheerio from 'cheerio';
import fetch from 'node-fetch';
const server = 'http://localhost:3275';

View File

@@ -23,15 +23,15 @@ PODS:
- UMImageLoaderInterface
- EXKeepAwake (9.1.2):
- UMCore
- EXPermissions (12.0.0):
- EXPermissions (12.0.1):
- UMCore
- UMPermissionsInterface
- EXSplashScreen (0.10.0):
- EXSplashScreen (0.10.2):
- React-Core
- UMCore
- EXStructuredHeaders (1.0.1):
- UMCore
- EXUpdates (0.5.4):
- EXUpdates (0.5.5):
- EXStructuredHeaders
- React-Core
- UMCore
@@ -271,9 +271,9 @@ PODS:
- React
- react-native-flipper (0.80.0):
- React-Core
- react-native-safe-area-context (3.2.0):
- react-native-pager-view (5.1.10):
- React-Core
- react-native-viewpager (5.0.12):
- react-native-safe-area-context (3.2.0):
- React-Core
- React-RCTActionSheet (0.63.4):
- React-Core/RCTActionSheetHeaders (= 0.63.4)
@@ -335,13 +335,13 @@ PODS:
- React-Core (= 0.63.4)
- React-cxxreact (= 0.63.4)
- React-jsi (= 0.63.4)
- RNCAsyncStorage (1.15.1):
- RNCAsyncStorage (1.15.5):
- React-Core
- RNCMaskedView (0.2.4):
- React-Core
- RNGestureHandler (1.10.3):
- React-Core
- RNReanimated (2.1.0):
- RNReanimated (2.2.0):
- DoubleConversion
- FBLazyVector
- FBReactNativeSpec
@@ -370,8 +370,9 @@ PODS:
- React-RCTVibration
- ReactCommon/turbomodule/core
- Yoga
- RNScreens (3.0.0):
- RNScreens (3.3.0):
- React-Core
- React-RCTImage
- RNVectorIcons (8.1.0):
- React-Core
- UMAppLoader (2.1.0)
@@ -451,8 +452,8 @@ DEPENDENCIES:
- React-jsinspector (from `../../node_modules/react-native/ReactCommon/jsinspector`)
- react-native-appearance (from `../../node_modules/react-native-appearance`)
- react-native-flipper (from `../../node_modules/react-native-flipper`)
- react-native-pager-view (from `../../node_modules/react-native-pager-view`)
- react-native-safe-area-context (from `../../node_modules/react-native-safe-area-context`)
- react-native-viewpager (from `../node_modules/react-native-pager-view`)
- React-RCTActionSheet (from `../../node_modules/react-native/Libraries/ActionSheetIOS`)
- React-RCTAnimation (from `../../node_modules/react-native/Libraries/NativeAnimation`)
- React-RCTBlob (from `../../node_modules/react-native/Libraries/Blob`)
@@ -464,7 +465,7 @@ DEPENDENCIES:
- React-RCTVibration (from `../../node_modules/react-native/Libraries/Vibration`)
- ReactCommon/turbomodule/core (from `../../node_modules/react-native/ReactCommon`)
- "RNCAsyncStorage (from `../../node_modules/@react-native-async-storage/async-storage`)"
- "RNCMaskedView (from `../node_modules/@react-native-masked-view/masked-view`)"
- "RNCMaskedView (from `../../node_modules/@react-native-masked-view/masked-view`)"
- RNGestureHandler (from `../../node_modules/react-native-gesture-handler`)
- RNReanimated (from `../../node_modules/react-native-reanimated`)
- RNScreens (from `../../node_modules/react-native-screens`)
@@ -558,10 +559,10 @@ EXTERNAL SOURCES:
:path: "../../node_modules/react-native-appearance"
react-native-flipper:
:path: "../../node_modules/react-native-flipper"
react-native-pager-view:
:path: "../../node_modules/react-native-pager-view"
react-native-safe-area-context:
:path: "../../node_modules/react-native-safe-area-context"
react-native-viewpager:
:path: "../node_modules/react-native-pager-view"
React-RCTActionSheet:
:path: "../../node_modules/react-native/Libraries/ActionSheetIOS"
React-RCTAnimation:
@@ -585,7 +586,7 @@ EXTERNAL SOURCES:
RNCAsyncStorage:
:path: "../../node_modules/@react-native-async-storage/async-storage"
RNCMaskedView:
:path: "../node_modules/@react-native-masked-view/masked-view"
:path: "../../node_modules/@react-native-masked-view/masked-view"
RNGestureHandler:
:path: "../../node_modules/react-native-gesture-handler"
RNReanimated:
@@ -635,10 +636,10 @@ SPEC CHECKSUMS:
EXFont: d6fb79f9863120f0d0b26b0c2d1453bc9511e9df
EXImageLoader: da941c9399e01ec28f2d5b270bdd21f2c8ca596c
EXKeepAwake: d4e4a3ed8c1c4fd940dd62fc5a8be2a190371fd4
EXPermissions: 67ff17d3c12ea06066492dde4242f8047658fd62
EXSplashScreen: 9d79ea338b7bb2ee94df51723870bac70b408d44
EXPermissions: 8f8c1c05580c4e02d4ee2c8dd74bfe173ff6a723
EXSplashScreen: a9baaf4fa866003884c90ba049f18760d6a8ce39
EXStructuredHeaders: be834496a4d9fd0069cd12ec1cc57b31c6d3b256
EXUpdates: e191b83e00d3e7ebfd7db3986806ceca09b7b322
EXUpdates: efe0e8c514dcff06a8fd0b63be6019a6365fb9c7
FBLazyVector: 3bb422f41b18121b71783a905c10e58606f7dc3e
FBReactNativeSpec: f2c97f2529dd79c083355182cc158c9f98f4bd6e
Flipper: d3da1aa199aad94455ae725e9f3aa43f3ec17021
@@ -664,8 +665,8 @@ SPEC CHECKSUMS:
React-jsinspector: 58aef7155bc9a9683f5b60b35eccea8722a4f53a
react-native-appearance: 0f0e5fc2fcef70e03d48c8fe6b00b9158c2ba8aa
react-native-flipper: 5a9d5959364fca6a8a9658d941343774cb197857
react-native-pager-view: 967d50ce0f1b72e434a2d9f3b739ddbf7d5bbf83
react-native-safe-area-context: f0906bf8bc9835ac9a9d3f97e8bde2a997d8da79
react-native-viewpager: 98a850d1c7ac6263122d82618a77062a5f427073
React-RCTActionSheet: 89a0ca9f4a06c1f93c26067af074ccdce0f40336
React-RCTAnimation: 1bde3ecc0c104c55df246eda516e0deb03c4e49b
React-RCTBlob: a97d378b527740cc667e03ebfa183a75231ab0f0
@@ -676,11 +677,11 @@ SPEC CHECKSUMS:
React-RCTText: 5c51df3f08cb9dedc6e790161195d12bac06101c
React-RCTVibration: ae4f914cfe8de7d4de95ae1ea6cc8f6315d73d9d
ReactCommon: 73d79c7039f473b76db6ff7c6b159c478acbbb3b
RNCAsyncStorage: 08719e311ab90492c2dafd6d6fb7ffb396493638
RNCAsyncStorage: 56a3355a10b5d660c48c6e37325ac85ebfd09885
RNCMaskedView: fc29d354a40316a990e8fb46391f08aea829c3aa
RNGestureHandler: a479ebd5ed4221a810967000735517df0d2db211
RNReanimated: 70f662b5232dd5d19ccff581e919a54ea73df51c
RNScreens: e8e8dd0588b5da0ab57dcca76ab9b2d8987757e0
RNReanimated: d9da990fc90123f4ffbfdda93d00fc15174863a8
RNScreens: bf59f17fbf001f1025243eeed5f19419d3c11ef2
RNVectorIcons: 31cebfcf94e8cf8686eb5303ae0357da64d7a5a4
UMAppLoader: fe2708bb0ac5cd70052bc207d06aa3b7e72b9e97
UMBarCodeScannerInterface: 79f92bea5f7af39b381a4c82298105ceb537408a

View File

@@ -1,6 +0,0 @@
module.exports = {
testRegex: '/__integration_tests__/.*\\.(test|spec)\\.(js|tsx?)$',
globalSetup: './e2e/config/setup-server.tsx',
globalTeardown: './e2e/config/teardown-server.tsx',
setupFilesAfterEnv: ['./e2e/config/setup-playwright.tsx'],
};

View File

@@ -11,65 +11,63 @@
"ios": "react-native run-ios",
"preios": "pod-install",
"server": "nodemon -e '.js,.ts,.tsx' --exec \"babel-node -i '/node_modules[/\\](?react-native)/' -x '.web.tsx,.web.ts,.web.js,.tsx,.ts,.js' --config-file ./server/babel.config.js server\"",
"test": "jest"
"test:e2e": "playwright test --config=e2e/playwright.config.ts"
},
"dependencies": {
"@expo/vector-icons": "^12.0.0",
"@react-native-async-storage/async-storage": "^1.13.0",
"@expo/vector-icons": "^12.0.5",
"@react-native-async-storage/async-storage": "^1.15.5",
"@react-native-masked-view/masked-view": "~0.2.4",
"color": "^3.1.3",
"expo": "^41.0.1",
"expo-asset": "~8.3.1",
"expo-asset": "~8.3.2",
"expo-blur": "~9.0.3",
"expo-linking": "~2.2.3",
"expo-splash-screen": "~0.10.0",
"expo-splash-screen": "~0.10.2",
"expo-status-bar": "~1.0.4",
"expo-updates": "~0.5.4",
"expo-updates": "~0.5.5",
"koa": "^2.13.0",
"react": "16.13.1",
"react-dom": "16.13.1",
"react-native": "~0.63.4",
"react-native-appearance": "~0.3.3",
"react-native-gesture-handler": "~1.10.2",
"react-native-pager-view": "~5.0.12",
"react-native-paper": "^4.7.2",
"react-native-reanimated": "~2.1.0",
"react-native-pager-view": "~5.1.10",
"react-native-paper": "^4.9.1",
"react-native-reanimated": "~2.2.0",
"react-native-safe-area-context": "~3.2.0",
"react-native-screens": "~3.0.0",
"react-native-screens": "~3.3.0",
"react-native-tab-view": "^3.0.1",
"react-native-unimodules": "~0.13.1",
"react-native-unimodules": "~0.13.3",
"react-native-vector-icons": "^8.1.0",
"react-native-web": "~0.15.0"
"react-native-web": "~0.16.3"
},
"devDependencies": {
"@babel/core": "^7.9.0",
"@babel/node": "^7.13.13",
"@expo/webpack-config": "~0.12.63",
"@types/cheerio": "^0.22.28",
"@babel/core": "^7.14.3",
"@babel/node": "^7.14.2",
"@expo/webpack-config": "~0.12.76",
"@playwright/test": "^1.12.2",
"@types/cheerio": "^0.22.29",
"@types/jest-dev-server": "^4.2.0",
"@types/koa": "^2.13.1",
"@types/koa": "^2.13.3",
"@types/mock-require": "^2.0.0",
"@types/node-fetch": "^2.5.9",
"@types/react": "~16.9.35",
"@types/react-dom": "~16.9.8",
"@types/react-native": "~0.63.2",
"babel-jest": "~25.2.6",
"@types/node-fetch": "^2.5.10",
"@types/react": "~17.0.9",
"@types/react-dom": "~17.0.6",
"@types/react-native": "~0.64.9",
"babel-loader": "^8.2.2",
"babel-plugin-module-resolver": "^4.0.0",
"babel-preset-expo": "8.3.0",
"cheerio": "^1.0.0-rc.3",
"expo-cli": "^4.4.4",
"jest": "^26.6.3",
"jest-dev-server": "^4.4.0",
"cheerio": "^1.0.0-rc.9",
"expo-cli": "^4.5.2",
"jest-dev-server": "^5.0.3",
"mock-require": "^3.0.3",
"mock-require-assets": "^0.0.1",
"node-fetch": "^2.6.1",
"nodemon": "^2.0.6",
"playwright": "^1.11.0",
"pod-install": "^0.1.19",
"pod-install": "^0.1.23",
"react-native-flipper": "~0.80.0",
"react-test-renderer": "~16.13.1",
"serve": "^11.3.0",
"typescript": "~4.2.3"
"typescript": "^4.3.2"
}
}

View File

@@ -7,14 +7,9 @@ const alias = Object.fromEntries(
fs
.readdirSync(packages)
.filter((name) => !name.startsWith('.'))
.map((name) => [
`@react-navigation/${name}`,
path.resolve(
packages,
name,
require(`../../packages/${name}/package.json`).source
),
])
.map((name) => [name, require(`../../packages/${name}/package.json`)])
.filter(([, pak]) => pak.source != null)
.map(([name, pak]) => [pak.name, path.resolve(packages, name, pak.source)])
);
module.exports = {

View File

@@ -1,10 +1,11 @@
import './resolve-hooks';
import { ServerContainer, ServerContainerRef } from '@react-navigation/native';
import Koa from 'koa';
import * as React from 'react';
import ReactDOMServer from 'react-dom/server';
import { AppRegistry } from 'react-native-web';
import { ServerContainer, ServerContainerRef } from '@react-navigation/native';
import App from '../src/index';
AppRegistry.registerComponent('App', () => App);

View File

@@ -1,12 +1,12 @@
import * as React from 'react';
import { View, TextInput, ActivityIndicator, StyleSheet } from 'react-native';
import { Title, Button } from 'react-native-paper';
import { useTheme, ParamListBase } from '@react-navigation/native';
import { HeaderBackButton } from '@react-navigation/elements';
import { ParamListBase, useTheme } from '@react-navigation/native';
import {
createStackNavigator,
StackScreenProps,
} from '@react-navigation/stack';
import { HeaderBackButton } from '@react-navigation/elements';
import * as React from 'react';
import { ActivityIndicator, StyleSheet, TextInput, View } from 'react-native';
import { Button, Title } from 'react-native-paper';
type AuthStackParams = {
Splash: undefined;

View File

@@ -1,30 +1,28 @@
import * as React from 'react';
import { ScrollView, StyleSheet } from 'react-native';
import MaterialCommunityIcons from 'react-native-vector-icons/MaterialCommunityIcons';
import { BlurView } from 'expo-blur';
import {
getFocusedRouteNameFromRoute,
ParamListBase,
NavigatorScreenParams,
} from '@react-navigation/native';
import type { StackScreenProps } from '@react-navigation/stack';
import {
createBottomTabNavigator,
useBottomTabBarHeight,
} from '@react-navigation/bottom-tabs';
import { HeaderBackButton } from '@react-navigation/elements';
import {
getFocusedRouteNameFromRoute,
NavigatorScreenParams,
ParamListBase,
} from '@react-navigation/native';
import type { StackScreenProps } from '@react-navigation/stack';
import { BlurView } from 'expo-blur';
import * as React from 'react';
import { ScrollView, StyleSheet } from 'react-native';
import MaterialCommunityIcons from 'react-native-vector-icons/MaterialCommunityIcons';
import Albums from '../Shared/Albums';
import Contacts from '../Shared/Contacts';
import Chat from '../Shared/Chat';
import Contacts from '../Shared/Contacts';
import SimpleStackScreen, { SimpleStackParams } from './SimpleStack';
const getTabBarIcon = (name: string) => ({
color,
size,
}: {
color: string;
size: number;
}) => <MaterialCommunityIcons name={name} color={color} size={size} />;
const getTabBarIcon =
(name: string) =>
({ color, size }: { color: string; size: number }) =>
<MaterialCommunityIcons name={name} color={color} size={size} />;
type BottomTabParams = {
TabStack: NavigatorScreenParams<SimpleStackParams>;

View File

@@ -1,8 +1,8 @@
import * as React from 'react';
import { View, StyleSheet } from 'react-native';
import { Title, Button } from 'react-native-paper';
import Feather from 'react-native-vector-icons/Feather';
import { createBottomTabNavigator } from '@react-navigation/bottom-tabs';
import * as React from 'react';
import { StyleSheet, View } from 'react-native';
import { Button, Title } from 'react-native-paper';
import Feather from 'react-native-vector-icons/Feather';
type BottomTabParams = {
[key: string]: undefined;

View File

@@ -1,18 +1,19 @@
import * as React from 'react';
import { View, StyleSheet, ScrollView, Platform } from 'react-native';
import { Button } from 'react-native-paper';
import {
Link,
StackActions,
ParamListBase,
StackActions,
useLinkProps,
} from '@react-navigation/native';
import {
createStackNavigator,
StackScreenProps,
} from '@react-navigation/stack';
import Article from '../Shared/Article';
import * as React from 'react';
import { Platform, ScrollView, StyleSheet, View } from 'react-native';
import { Button } from 'react-native-paper';
import Albums from '../Shared/Albums';
import Article from '../Shared/Article';
type SimpleStackParams = {
Article: { author: string };

View File

@@ -1,20 +1,21 @@
import {
createDrawerNavigator,
DrawerContent,
DrawerContentComponentProps,
DrawerScreenProps,
} from '@react-navigation/drawer';
import {
ParamListBase,
useNavigation,
useTheme,
} from '@react-navigation/native';
import type { StackScreenProps } from '@react-navigation/stack';
import * as React from 'react';
import { Dimensions, ScaledSize } from 'react-native';
import { Appbar } from 'react-native-paper';
import {
useTheme,
useNavigation,
ParamListBase,
} from '@react-navigation/native';
import {
createDrawerNavigator,
DrawerScreenProps,
DrawerContent,
DrawerContentComponentProps,
} from '@react-navigation/drawer';
import type { StackScreenProps } from '@react-navigation/stack';
import Article from '../Shared/Article';
import Albums from '../Shared/Albums';
import Article from '../Shared/Article';
import NewsFeed from '../Shared/NewsFeed';
type DrawerParams = {

View File

@@ -1,10 +1,11 @@
import { createMaterialBottomTabNavigator } from '@react-navigation/material-bottom-tabs';
import type { NavigatorScreenParams } from '@react-navigation/native';
import * as React from 'react';
import { StyleSheet } from 'react-native';
import type { NavigatorScreenParams } from '@react-navigation/native';
import { createMaterialBottomTabNavigator } from '@react-navigation/material-bottom-tabs';
import Albums from '../Shared/Albums';
import Contacts from '../Shared/Contacts';
import Chat from '../Shared/Chat';
import Contacts from '../Shared/Contacts';
import SimpleStackScreen, { SimpleStackParams } from './SimpleStack';
type MaterialBottomTabParams = {
@@ -14,7 +15,8 @@ type MaterialBottomTabParams = {
TabChat: undefined;
};
const MaterialBottomTabs = createMaterialBottomTabNavigator<MaterialBottomTabParams>();
const MaterialBottomTabs =
createMaterialBottomTabNavigator<MaterialBottomTabParams>();
export default function MaterialBottomTabsScreen() {
return (

View File

@@ -1,10 +1,11 @@
import * as React from 'react';
import { createMaterialTopTabNavigator } from '@react-navigation/material-top-tabs';
import type { ParamListBase } from '@react-navigation/native';
import type { StackScreenProps } from '@react-navigation/stack';
import { createMaterialTopTabNavigator } from '@react-navigation/material-top-tabs';
import * as React from 'react';
import Albums from '../Shared/Albums';
import Contacts from '../Shared/Contacts';
import Chat from '../Shared/Chat';
import Contacts from '../Shared/Contacts';
type MaterialTopTabParams = {
Albums: undefined;

View File

@@ -1,15 +1,16 @@
import * as React from 'react';
import { View, Platform, StyleSheet, ScrollView } from 'react-native';
import { Button } from 'react-native-paper';
import type { ParamListBase } from '@react-navigation/native';
import {
createStackNavigator,
HeaderStyleInterpolators,
StackScreenProps,
TransitionPresets,
HeaderStyleInterpolators,
} from '@react-navigation/stack';
import Article from '../Shared/Article';
import * as React from 'react';
import { Platform, ScrollView, StyleSheet, View } from 'react-native';
import { Button } from 'react-native-paper';
import Albums from '../Shared/Albums';
import Article from '../Shared/Article';
import NewsFeed from '../Shared/NewsFeed';
export type SimpleStackParams = {

View File

@@ -1,13 +1,14 @@
import * as React from 'react';
import { View, StyleSheet, ScrollView, Platform } from 'react-native';
import { Button } from 'react-native-paper';
import type { ParamListBase } from '@react-navigation/native';
import {
createStackNavigator,
StackScreenProps,
} from '@react-navigation/stack';
import Article from '../Shared/Article';
import * as React from 'react';
import { Platform, ScrollView, StyleSheet, View } from 'react-native';
import { Button } from 'react-native-paper';
import Albums from '../Shared/Albums';
import Article from '../Shared/Article';
type MixedStackParams = {
Article: { author: string };

View File

@@ -1,13 +1,14 @@
import * as React from 'react';
import { View, StyleSheet, ScrollView, Platform } from 'react-native';
import { Button } from 'react-native-paper';
import type { ParamListBase } from '@react-navigation/native';
import {
createStackNavigator,
StackScreenProps,
} from '@react-navigation/stack';
import Article from '../Shared/Article';
import * as React from 'react';
import { Platform, ScrollView, StyleSheet, View } from 'react-native';
import { Button } from 'react-native-paper';
import Albums from '../Shared/Albums';
import Article from '../Shared/Article';
type ModalStackParams = {
Article: { author: string };

View File

@@ -1,14 +1,15 @@
import * as React from 'react';
import { View, Platform, StyleSheet, ScrollView } from 'react-native';
import { Button } from 'react-native-paper';
import { useSafeAreaInsets } from 'react-native-safe-area-context';
import type { ParamListBase } from '@react-navigation/native';
import {
createNativeStackNavigator,
NativeStackScreenProps,
} from '@react-navigation/native-stack';
import Article from '../Shared/Article';
import * as React from 'react';
import { Platform, ScrollView, StyleSheet, View } from 'react-native';
import { Button } from 'react-native-paper';
import { useSafeAreaInsets } from 'react-native-safe-area-context';
import Albums from '../Shared/Albums';
import Article from '../Shared/Article';
import NewsFeed from '../Shared/NewsFeed';
export type NativeStackParams = {

View File

@@ -1,13 +1,14 @@
import * as React from 'react';
import { View, Platform, StyleSheet, ScrollView, Alert } from 'react-native';
import { Appbar, Button } from 'react-native-paper';
import type { ParamListBase } from '@react-navigation/native';
import {
createNativeStackNavigator,
NativeStackScreenProps,
} from '@react-navigation/native-stack';
import Article from '../Shared/Article';
import * as React from 'react';
import { Alert, Platform, ScrollView, StyleSheet, View } from 'react-native';
import { Appbar, Button } from 'react-native-paper';
import Albums from '../Shared/Albums';
import Article from '../Shared/Article';
import NewsFeed from '../Shared/NewsFeed';
export type NativeStackParams = {

View File

@@ -1,7 +1,7 @@
import type { StackScreenProps } from '@react-navigation/stack';
import * as React from 'react';
import { StyleSheet, Text, View } from 'react-native';
import { Button } from 'react-native-paper';
import type { StackScreenProps } from '@react-navigation/stack';
const NotFoundScreen = ({
route,

View File

@@ -1,23 +1,24 @@
import * as React from 'react';
import {
Alert,
View,
TextInput,
ScrollView,
StyleSheet,
Platform,
} from 'react-native';
import { Button } from 'react-native-paper';
import {
useTheme,
CommonActions,
ParamListBase,
NavigationAction,
ParamListBase,
useTheme,
} from '@react-navigation/native';
import {
createStackNavigator,
StackScreenProps,
} from '@react-navigation/stack';
import * as React from 'react';
import {
Alert,
Platform,
ScrollView,
StyleSheet,
TextInput,
View,
} from 'react-native';
import { Button } from 'react-native-paper';
import Article from '../Shared/Article';
type PreventRemoveParams = {

View File

@@ -1,14 +1,15 @@
import * as React from 'react';
import { View, Platform, StyleSheet, ScrollView } from 'react-native';
import { Button } from 'react-native-paper';
import type { ParamListBase } from '@react-navigation/native';
import {
createStackNavigator,
StackNavigationOptions,
StackScreenProps,
} from '@react-navigation/stack';
import Article from '../Shared/Article';
import * as React from 'react';
import { Platform, ScrollView, StyleSheet, View } from 'react-native';
import { Button } from 'react-native-paper';
import Albums from '../Shared/Albums';
import Article from '../Shared/Article';
import NewsFeed from '../Shared/NewsFeed';
export type SimpleStackParams = {

View File

@@ -1,25 +1,26 @@
import * as React from 'react';
import {
Animated,
View,
StyleSheet,
ScrollView,
Alert,
Platform,
} from 'react-native';
import { Button, Appbar } from 'react-native-paper';
import MaterialCommunityIcons from 'react-native-vector-icons/MaterialCommunityIcons';
import { useTheme, ParamListBase } from '@react-navigation/native';
import { HeaderBackground, useHeaderHeight } from '@react-navigation/elements';
import { ParamListBase, useTheme } from '@react-navigation/native';
import {
createStackNavigator,
StackScreenProps,
Header,
StackHeaderProps,
StackScreenProps,
} from '@react-navigation/stack';
import { HeaderBackground, useHeaderHeight } from '@react-navigation/elements';
import BlurView from '../Shared/BlurView';
import Article from '../Shared/Article';
import * as React from 'react';
import {
Alert,
Animated,
Platform,
ScrollView,
StyleSheet,
View,
} from 'react-native';
import { Appbar, Button } from 'react-native-paper';
import MaterialCommunityIcons from 'react-native-vector-icons/MaterialCommunityIcons';
import Albums from '../Shared/Albums';
import Article from '../Shared/Article';
import BlurView from '../Shared/BlurView';
type SimpleStackParams = {
Article: { author: string };

View File

@@ -1,19 +1,20 @@
import * as React from 'react';
import {
View,
StyleSheet,
ScrollView,
Platform,
Pressable,
Animated,
} from 'react-native';
import { Button, Paragraph } from 'react-native-paper';
import { ParamListBase, useTheme } from '@react-navigation/native';
import {
createStackNavigator,
StackScreenProps,
useCardAnimation,
} from '@react-navigation/stack';
import * as React from 'react';
import {
Animated,
Platform,
Pressable,
ScrollView,
StyleSheet,
View,
} from 'react-native';
import { Button, Paragraph } from 'react-native-paper';
import Article from '../Shared/Article';
import NewsFeed from '../Shared/NewsFeed';

View File

@@ -1,17 +1,17 @@
/* eslint-disable import/no-commonjs */
import { useScrollToTop } from '@react-navigation/native';
import * as React from 'react';
import {
View,
Image,
ScrollView,
StyleSheet,
ScrollViewProps,
Dimensions,
Image,
Platform,
ScaledSize,
ScrollView,
ScrollViewProps,
StyleSheet,
View,
} from 'react-native';
import { useScrollToTop } from '@react-navigation/native';
const COVERS = [
require('../../assets/album-art-01.jpg'),

View File

@@ -1,14 +1,14 @@
import { useScrollToTop, useTheme } from '@react-navigation/native';
import * as React from 'react';
import {
View,
Text,
Image,
ScrollView,
StyleSheet,
ScrollViewProps,
StyleSheet,
Text,
TextProps,
View,
} from 'react-native';
import { useScrollToTop, useTheme } from '@react-navigation/native';
type Props = Partial<ScrollViewProps> & {
date?: string;

View File

@@ -1,15 +1,15 @@
import * as React from 'react';
import {
View,
Image,
Text,
TextInput,
ScrollView,
StyleSheet,
ScrollViewProps,
} from 'react-native';
import { useScrollToTop, useTheme } from '@react-navigation/native';
import Color from 'color';
import * as React from 'react';
import {
Image,
ScrollView,
ScrollViewProps,
StyleSheet,
Text,
TextInput,
View,
} from 'react-native';
const MESSAGES = [
'okay',

View File

@@ -1,6 +1,6 @@
import * as React from 'react';
import { View, Text, FlatList, StyleSheet } from 'react-native';
import { useScrollToTop, useTheme } from '@react-navigation/native';
import * as React from 'react';
import { FlatList, StyleSheet, Text, View } from 'react-native';
type Item = { name: string; number: number };

View File

@@ -1,22 +1,22 @@
import { useScrollToTop, useTheme } from '@react-navigation/native';
import Color from 'color';
import * as React from 'react';
import {
View,
TextInput,
Image,
ScrollView,
StyleSheet,
ScrollViewProps,
StyleSheet,
TextInput,
View,
} from 'react-native';
import { useScrollToTop, useTheme } from '@react-navigation/native';
import {
Card,
Text,
Avatar,
Subheading,
IconButton,
Card,
Divider,
IconButton,
Subheading,
Text,
} from 'react-native-paper';
import Color from 'color';
type Props = Partial<ScrollViewProps> & {
date?: number;

View File

@@ -1,65 +1,69 @@
import * as React from 'react';
import {
ScrollView,
Platform,
StatusBar,
I18nManager,
Dimensions,
ScaledSize,
Linking,
LogBox,
} from 'react-native';
import { SafeAreaView } from 'react-native-safe-area-context';
import MaterialIcons from 'react-native-vector-icons/MaterialIcons';
import {
Provider as PaperProvider,
DefaultTheme as PaperLightTheme,
DarkTheme as PaperDarkTheme,
List,
Divider,
Text,
} from 'react-native-paper';
import { createURL } from 'expo-linking';
import AsyncStorage from '@react-native-async-storage/async-storage';
import {
useFlipper,
useReduxDevToolsExtension,
} from '@react-navigation/devtools';
import {
createDrawerNavigator,
DrawerScreenProps,
} from '@react-navigation/drawer';
import {
CompositeScreenProps,
DarkTheme,
DefaultTheme,
InitialState,
NavigationContainer,
DefaultTheme,
DarkTheme,
NavigatorScreenParams,
PathConfigMap,
useNavigationContainerRef,
NavigatorScreenParams,
} from '@react-navigation/native';
import { createDrawerNavigator } from '@react-navigation/drawer';
import {
createStackNavigator,
HeaderStyleInterpolators,
StackNavigationProp,
StackScreenProps,
} from '@react-navigation/stack';
import { createURL } from 'expo-linking';
import * as React from 'react';
import {
useReduxDevToolsExtension,
useFlipper,
} from '@react-navigation/devtools';
Dimensions,
I18nManager,
Linking,
LogBox,
Platform,
ScaledSize,
ScrollView,
StatusBar,
} from 'react-native';
import {
DarkTheme as PaperDarkTheme,
DefaultTheme as PaperLightTheme,
Divider,
List,
Provider as PaperProvider,
Text,
} from 'react-native-paper';
import { SafeAreaView } from 'react-native-safe-area-context';
import MaterialIcons from 'react-native-vector-icons/MaterialIcons';
import { restartApp } from './Restart';
import SettingsItem from './Shared/SettingsItem';
import NativeStack from './Screens/NativeStack';
import SimpleStack from './Screens/SimpleStack';
import ModalStack from './Screens/ModalStack';
import MixedStack from './Screens/MixedStack';
import MixedHeaderMode from './Screens/MixedHeaderMode';
import StackTransparent from './Screens/StackTransparent';
import StackHeaderCustomization from './Screens/StackHeaderCustomization';
import NativeStackHeaderCustomization from './Screens/NativeStackHeaderCustomization';
import BottomTabs from './Screens/BottomTabs';
import MaterialTopTabsScreen from './Screens/MaterialTopTabs';
import MaterialBottomTabs from './Screens/MaterialBottomTabs';
import NotFound from './Screens/NotFound';
import DynamicTabs from './Screens/DynamicTabs';
import MasterDetail from './Screens/MasterDetail';
import AuthFlow from './Screens/AuthFlow';
import PreventRemove from './Screens/PreventRemove';
import BottomTabs from './Screens/BottomTabs';
import DynamicTabs from './Screens/DynamicTabs';
import LinkComponent from './Screens/LinkComponent';
import MasterDetail from './Screens/MasterDetail';
import MaterialBottomTabs from './Screens/MaterialBottomTabs';
import MaterialTopTabsScreen from './Screens/MaterialTopTabs';
import MixedHeaderMode from './Screens/MixedHeaderMode';
import MixedStack from './Screens/MixedStack';
import ModalStack from './Screens/ModalStack';
import NativeStack from './Screens/NativeStack';
import NativeStackHeaderCustomization from './Screens/NativeStackHeaderCustomization';
import NotFound from './Screens/NotFound';
import PreventRemove from './Screens/PreventRemove';
import SimpleStack from './Screens/SimpleStack';
import StackHeaderCustomization from './Screens/StackHeaderCustomization';
import StackTransparent from './Screens/StackTransparent';
import SettingsItem from './Shared/SettingsItem';
if (Platform.OS !== 'web') {
LogBox.ignoreLogs(['Require cycle:']);
@@ -151,9 +155,8 @@ export default function App() {
const [theme, setTheme] = React.useState(DefaultTheme);
const [isReady, setIsReady] = React.useState(Platform.OS === 'web');
const [initialState, setInitialState] = React.useState<
InitialState | undefined
>();
const [initialState, setInitialState] =
React.useState<InitialState | undefined>();
React.useEffect(() => {
const restoreState = async () => {
@@ -333,9 +336,10 @@ export default function App() {
>
{({
navigation,
}: {
navigation: StackNavigationProp<RootStackParamList>;
}) => (
}: CompositeScreenProps<
DrawerScreenProps<RootDrawerParamList, 'Examples'>,
StackScreenProps<RootStackParamList>
>) => (
<ScrollView
style={{ backgroundColor: theme.colors.background }}
>

View File

@@ -8,8 +8,6 @@ const packages = path.resolve(__dirname, '..', 'packages');
module.exports = async function (env, argv) {
const config = await createExpoWebpackConfigAsync(env, argv);
config.context = path.resolve(__dirname, '..');
config.module.rules.push({
test: /\.(js|ts|tsx)$/,
include: /(packages|example)\/.+/,
@@ -27,11 +25,13 @@ module.exports = async function (env, argv) {
fs.readdirSync(packages)
.filter((name) => !name.startsWith('.'))
.forEach((name) => {
config.resolve.alias[`@react-navigation/${name}`] = path.resolve(
packages,
name,
require(`../packages/${name}/package.json`).source
);
const pak = require(`../packages/${name}/package.json`);
if (pak.source == null) {
return;
}
config.resolve.alias[pak.name] = path.resolve(packages, name, pak.source);
});
return config;

View File

@@ -29,20 +29,24 @@
"release": "lerna publish",
"example": "yarn --cwd example"
},
"dependencies": {
"react-native-web": "~0.16.3"
},
"devDependencies": {
"@commitlint/config-conventional": "^12.1.1",
"@types/jest": "^26.0.22",
"@commitlint/config-conventional": "^12.1.4",
"@types/jest": "^26.0.23",
"babel-jest": "^26.6.3",
"codecov": "^3.8.1",
"commitlint": "^12.1.1",
"eslint": "^7.23.0",
"codecov": "^3.8.2",
"commitlint": "^12.1.4",
"eslint": "^7.27.0",
"eslint-config-satya164": "^3.1.10",
"eslint-plugin-simple-import-sort": "^7.0.0",
"husky": "^4.3.6",
"jest": "^26.6.3",
"lerna": "^4.0.0",
"metro-react-native-babel-preset": "^0.65.2",
"prettier": "^2.2.1",
"typescript": "^4.2.3"
"metro-react-native-babel-preset": "^0.66.0",
"prettier": "^2.3.0",
"typescript": "^4.3.2"
},
"resolutions": {
"react": "~16.13.1",
@@ -66,6 +70,7 @@
"preset": "react-native"
},
"prettier": {
"quoteProps": "consistent",
"tabWidth": 2,
"useTabs": false,
"singleQuote": true,

View File

@@ -3,6 +3,57 @@
All notable changes to this project will be documented in this file.
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
# [6.0.0-next.19](https://github.com/react-navigation/react-navigation/compare/@react-navigation/bottom-tabs@6.0.0-next.18...@react-navigation/bottom-tabs@6.0.0-next.19) (2021-06-10)
**Note:** Version bump only for package @react-navigation/bottom-tabs
# [6.0.0-next.18](https://github.com/react-navigation/react-navigation/compare/@react-navigation/bottom-tabs@6.0.0-next.17...@react-navigation/bottom-tabs@6.0.0-next.18) (2021-06-01)
**Note:** Version bump only for package @react-navigation/bottom-tabs
# [6.0.0-next.17](https://github.com/react-navigation/react-navigation/compare/@react-navigation/bottom-tabs@6.0.0-next.16...@react-navigation/bottom-tabs@6.0.0-next.17) (2021-05-29)
**Note:** Version bump only for package @react-navigation/bottom-tabs
# [6.0.0-next.16](https://github.com/react-navigation/react-navigation/compare/@react-navigation/bottom-tabs@6.0.0-next.15...@react-navigation/bottom-tabs@6.0.0-next.16) (2021-05-29)
**Note:** Version bump only for package @react-navigation/bottom-tabs
# [6.0.0-next.15](https://github.com/react-navigation/react-navigation/compare/@react-navigation/bottom-tabs@6.0.0-next.14...@react-navigation/bottom-tabs@6.0.0-next.15) (2021-05-27)
**Note:** Version bump only for package @react-navigation/bottom-tabs
# [6.0.0-next.14](https://github.com/react-navigation/react-navigation/compare/@react-navigation/bottom-tabs@6.0.0-next.13...@react-navigation/bottom-tabs@6.0.0-next.14) (2021-05-26)
### Features
* add screenListeners prop on navigators similar to screenOptions ([cde44a5](https://github.com/react-navigation/react-navigation/commit/cde44a5785444a121aa08f94af9f8fe4fc89910a))
# [6.0.0-next.13](https://github.com/react-navigation/react-navigation/compare/@react-navigation/bottom-tabs@6.0.0-next.12...@react-navigation/bottom-tabs@6.0.0-next.13) (2021-05-25)
**Note:** Version bump only for package @react-navigation/bottom-tabs

View File

@@ -1,7 +1,7 @@
{
"name": "@react-navigation/bottom-tabs",
"description": "Bottom tab navigator following iOS design guidelines",
"version": "6.0.0-next.13",
"version": "6.0.0-next.19",
"keywords": [
"react-native-component",
"react-component",
@@ -36,23 +36,23 @@
"clean": "del lib"
},
"dependencies": {
"@react-navigation/elements": "^1.0.0-next.12",
"@react-navigation/elements": "^1.0.0-next.18",
"color": "^3.1.3",
"warn-once": "^0.1.0"
},
"devDependencies": {
"@react-navigation/native": "^6.0.0-next.9",
"@react-navigation/native": "^6.0.0-next.14",
"@testing-library/react-native": "^7.2.0",
"@types/color": "^3.0.1",
"@types/react": "^16.9.53",
"@types/react-native": "~0.64.4",
"@types/react": "^17.0.9",
"@types/react-native": "~0.64.9",
"del-cli": "^3.0.1",
"react": "~16.13.1",
"react-native": "~0.63.4",
"react-native-builder-bob": "^0.18.1",
"react-native-safe-area-context": "~3.2.0",
"react-native-screens": "~3.0.0",
"typescript": "^4.2.3"
"react-native-screens": "~3.3.0",
"typescript": "^4.3.2"
},
"peerDependencies": {
"@react-navigation/native": "^6.0.0",

View File

@@ -1,8 +1,9 @@
import * as React from 'react';
import { View, Text, Button } from 'react-native';
import { render, fireEvent } from '@testing-library/react-native';
import { NavigationContainer, ParamListBase } from '@react-navigation/native';
import { createBottomTabNavigator, BottomTabScreenProps } from '../index';
import { fireEvent, render } from '@testing-library/react-native';
import * as React from 'react';
import { Button, Text, View } from 'react-native';
import { BottomTabScreenProps, createBottomTabNavigator } from '../index';
it('renders a bottom tab navigator with screens', async () => {
const Test = ({ route, navigation }: BottomTabScreenProps<ParamListBase>) => (

View File

@@ -6,23 +6,22 @@ export { default as createBottomTabNavigator } from './navigators/createBottomTa
/**
* Views
*/
export { default as BottomTabView } from './views/BottomTabView';
export { default as BottomTabBar } from './views/BottomTabBar';
export { default as BottomTabView } from './views/BottomTabView';
/**
* Utilities
*/
export { default as BottomTabBarHeightContext } from './utils/BottomTabBarHeightContext';
export { default as useBottomTabBarHeight } from './utils/useBottomTabBarHeight';
/**
* Types
*/
export type {
BottomTabBarButtonProps,
BottomTabBarProps,
BottomTabNavigationOptions,
BottomTabNavigationProp,
BottomTabScreenProps,
BottomTabBarProps,
BottomTabBarButtonProps,
} from './types';

View File

@@ -1,23 +1,29 @@
import * as React from 'react';
import warnOnce from 'warn-once';
import {
useNavigationBuilder,
createNavigatorFactory,
DefaultNavigatorOptions,
ParamListBase,
TabActionHelpers,
TabNavigationState,
TabRouter,
TabRouterOptions,
TabNavigationState,
TabActionHelpers,
ParamListBase,
useNavigationBuilder,
} from '@react-navigation/native';
import BottomTabView from '../views/BottomTabView';
import * as React from 'react';
import warnOnce from 'warn-once';
import type {
BottomTabNavigationConfig,
BottomTabNavigationOptions,
BottomTabNavigationEventMap,
BottomTabNavigationOptions,
} from '../types';
import BottomTabView from '../views/BottomTabView';
type Props = DefaultNavigatorOptions<BottomTabNavigationOptions> &
type Props = DefaultNavigatorOptions<
ParamListBase,
TabNavigationState<ParamListBase>,
BottomTabNavigationOptions,
BottomTabNavigationEventMap
> &
TabRouterOptions &
BottomTabNavigationConfig;
@@ -25,6 +31,7 @@ function BottomTabNavigator({
initialRouteName,
backBehavior,
children,
screenListeners,
screenOptions,
sceneContainerStyle,
// @ts-expect-error: lazy is deprecated
@@ -70,24 +77,21 @@ function BottomTabNavigator({
);
}
const {
state,
descriptors,
navigation,
NavigationContent,
} = useNavigationBuilder<
TabNavigationState<ParamListBase>,
TabRouterOptions,
TabActionHelpers<ParamListBase>,
BottomTabNavigationOptions,
BottomTabNavigationEventMap
>(TabRouter, {
initialRouteName,
backBehavior,
children,
screenOptions,
defaultScreenOptions,
});
const { state, descriptors, navigation, NavigationContent } =
useNavigationBuilder<
TabNavigationState<ParamListBase>,
TabRouterOptions,
TabActionHelpers<ParamListBase>,
BottomTabNavigationOptions,
BottomTabNavigationEventMap
>(TabRouter, {
initialRouteName,
backBehavior,
children,
screenListeners,
screenOptions,
defaultScreenOptions,
});
return (
<NavigationContent>

View File

@@ -1,23 +1,23 @@
import type * as React from 'react';
import type {
Animated,
TouchableWithoutFeedbackProps,
StyleProp,
TextStyle,
ViewStyle,
GestureResponderEvent,
} from 'react-native';
import type { HeaderOptions } from '@react-navigation/elements';
import type {
Descriptor,
NavigationHelpers,
NavigationProp,
ParamListBase,
Descriptor,
TabNavigationState,
TabActionHelpers,
RouteProp,
TabActionHelpers,
TabNavigationState,
} from '@react-navigation/native';
import type * as React from 'react';
import type {
Animated,
GestureResponderEvent,
StyleProp,
TextStyle,
TouchableWithoutFeedbackProps,
ViewStyle,
} from 'react-native';
import type { EdgeInsets } from 'react-native-safe-area-context';
import type { HeaderOptions } from '@react-navigation/elements';
export type Layout = { width: number; height: number };

View File

@@ -1,4 +1,5 @@
import * as React from 'react';
import BottomTabBarHeightContext from './BottomTabBarHeightContext';
export default function useFloatingBottomTabBarHeight() {

View File

@@ -1,5 +1,5 @@
import * as React from 'react';
import { Keyboard, Platform, EmitterSubscription } from 'react-native';
import { EmitterSubscription, Keyboard, Platform } from 'react-native';
export default function useIsKeyboardShown() {
const [isKeyboardShown, setIsKeyboardShown] = React.useState(false);

View File

@@ -1,7 +1,7 @@
import * as React from 'react';
import { Animated, StyleSheet, StyleProp, TextStyle } from 'react-native';
import color from 'color';
import { useTheme } from '@react-navigation/native';
import color from 'color';
import * as React from 'react';
import { Animated, StyleProp, StyleSheet, TextStyle } from 'react-native';
type Props = {
/**

View File

@@ -1,29 +1,29 @@
import React from 'react';
import {
View,
Animated,
StyleSheet,
Platform,
LayoutChangeEvent,
StyleProp,
ViewStyle,
} from 'react-native';
import { MissingIcon } from '@react-navigation/elements';
import {
CommonActions,
NavigationContext,
NavigationRouteContext,
TabNavigationState,
ParamListBase,
CommonActions,
useTheme,
TabNavigationState,
useLinkBuilder,
useTheme,
} from '@react-navigation/native';
import { MissingIcon } from '@react-navigation/elements';
import React from 'react';
import {
Animated,
LayoutChangeEvent,
Platform,
StyleProp,
StyleSheet,
View,
ViewStyle,
} from 'react-native';
import { EdgeInsets, useSafeAreaFrame } from 'react-native-safe-area-context';
import BottomTabItem from './BottomTabItem';
import type { BottomTabBarProps, BottomTabDescriptorMap } from '../types';
import BottomTabBarHeightCallbackContext from '../utils/BottomTabBarHeightCallbackContext';
import useIsKeyboardShown from '../utils/useIsKeyboardShown';
import type { BottomTabBarProps, BottomTabDescriptorMap } from '../types';
import BottomTabItem from './BottomTabItem';
type Props = BottomTabBarProps & {
style?: Animated.WithAnimatedValue<StyleProp<ViewStyle>>;
@@ -48,9 +48,8 @@ const shouldUseHorizontalLabels = ({
layout,
dimensions,
}: Options) => {
const { tabBarLabelPosition, tabBarAdaptive = true } = descriptors[
state.routes[state.index].key
].options;
const { tabBarLabelPosition, tabBarAdaptive = true } =
descriptors[state.routes[state.index].key].options;
if (tabBarLabelPosition) {
return tabBarLabelPosition === 'beside-icon';

View File

@@ -1,19 +1,19 @@
import React from 'react';
import {
Text,
Pressable,
StyleSheet,
Platform,
StyleProp,
ViewStyle,
TextStyle,
GestureResponderEvent,
} from 'react-native';
import { Link, Route, useTheme } from '@react-navigation/native';
import Color from 'color';
import React from 'react';
import {
GestureResponderEvent,
Platform,
Pressable,
StyleProp,
StyleSheet,
Text,
TextStyle,
ViewStyle,
} from 'react-native';
import TabBarIcon from './TabBarIcon';
import type { BottomTabBarButtonProps, LabelPosition } from '../types';
import TabBarIcon from './TabBarIcon';
type Props = {
/**

View File

@@ -1,28 +1,29 @@
import * as React from 'react';
import { StyleSheet, Platform } from 'react-native';
import { SafeAreaInsetsContext } from 'react-native-safe-area-context';
import {
getHeaderTitle,
Header,
SafeAreaProviderCompat,
Screen,
} from '@react-navigation/elements';
import type {
ParamListBase,
TabNavigationState,
} from '@react-navigation/native';
import {
Header,
Screen,
SafeAreaProviderCompat,
getHeaderTitle,
} from '@react-navigation/elements';
import { MaybeScreenContainer, MaybeScreen } from './ScreenFallback';
import BottomTabBar, { getTabBarHeight } from './BottomTabBar';
import BottomTabBarHeightCallbackContext from '../utils/BottomTabBarHeightCallbackContext';
import BottomTabBarHeightContext from '../utils/BottomTabBarHeightContext';
import * as React from 'react';
import { Platform, StyleSheet } from 'react-native';
import { SafeAreaInsetsContext } from 'react-native-safe-area-context';
import type {
BottomTabNavigationConfig,
BottomTabDescriptorMap,
BottomTabNavigationHelpers,
BottomTabBarProps,
BottomTabDescriptorMap,
BottomTabHeaderProps,
BottomTabNavigationConfig,
BottomTabNavigationHelpers,
BottomTabNavigationProp,
} from '../types';
import BottomTabBarHeightCallbackContext from '../utils/BottomTabBarHeightCallbackContext';
import BottomTabBarHeightContext from '../utils/BottomTabBarHeightContext';
import BottomTabBar, { getTabBarHeight } from './BottomTabBar';
import { MaybeScreen, MaybeScreenContainer } from './ScreenFallback';
type Props = BottomTabNavigationConfig & {
state: TabNavigationState<ParamListBase>;
@@ -136,7 +137,8 @@ export default function BottomTabView(props: Props) {
header={header({
layout: dimensions,
route: descriptor.route,
navigation: descriptor.navigation as BottomTabNavigationProp<ParamListBase>,
navigation:
descriptor.navigation as BottomTabNavigationProp<ParamListBase>,
options: descriptor.options,
})}
style={sceneContainerStyle}

View File

@@ -1,6 +1,6 @@
import { ResourceSavingView } from '@react-navigation/elements';
import * as React from 'react';
import { StyleProp, View, ViewProps, ViewStyle } from 'react-native';
import { ResourceSavingView } from '@react-navigation/elements';
type Props = {
visible: boolean;

View File

@@ -1,12 +1,13 @@
import type { Route } from '@react-navigation/native';
import React from 'react';
import {
View,
StyleSheet,
StyleProp,
StyleSheet,
TextStyle,
View,
ViewStyle,
} from 'react-native';
import type { Route } from '@react-navigation/native';
import Badge from './Badge';
type Props = {
@@ -27,6 +28,7 @@ type Props = {
};
export default function TabBarIcon({
route: _,
horizontal,
badge,
badgeStyle,

View File

@@ -3,6 +3,59 @@
All notable changes to this project will be documented in this file.
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
# [6.0.0-next.14](https://github.com/react-navigation/react-navigation/compare/@react-navigation/core@6.0.0-next.13...@react-navigation/core@6.0.0-next.14) (2021-06-10)
### Features
* show stack trace in the flipper plugin ([97772af](https://github.com/react-navigation/react-navigation/commit/97772affa3c8f26489f0bdbfb6872ef4377b8ed1))
# [6.0.0-next.13](https://github.com/react-navigation/react-navigation/compare/@react-navigation/core@6.0.0-next.12...@react-navigation/core@6.0.0-next.13) (2021-05-29)
### Bug Fixes
* validate property names in linking config ([324ea71](https://github.com/react-navigation/react-navigation/commit/324ea7181db6b743f512854be267cc9d65975b6f))
# [6.0.0-next.12](https://github.com/react-navigation/react-navigation/compare/@react-navigation/core@6.0.0-next.11...@react-navigation/core@6.0.0-next.12) (2021-05-29)
### Bug Fixes
* try to fix [#9631](https://github.com/react-navigation/react-navigation/issues/9631) ([b4d7b0e](https://github.com/react-navigation/react-navigation/commit/b4d7b0ee86c09419a18357867a0a25bb90d960c0))
# [6.0.0-next.11](https://github.com/react-navigation/react-navigation/compare/@react-navigation/core@6.0.0-next.10...@react-navigation/core@6.0.0-next.11) (2021-05-27)
**Note:** Version bump only for package @react-navigation/core
# [6.0.0-next.10](https://github.com/react-navigation/react-navigation/compare/@react-navigation/core@6.0.0-next.9...@react-navigation/core@6.0.0-next.10) (2021-05-26)
### Features
* add screenListeners prop on navigators similar to screenOptions ([cde44a5](https://github.com/react-navigation/react-navigation/commit/cde44a5785444a121aa08f94af9f8fe4fc89910a))
* expose container ref in useNavigation ([1d40279](https://github.com/react-navigation/react-navigation/commit/1d40279db18ab2aed12517ed3ca6af6d509477d2))
# [6.0.0-next.9](https://github.com/react-navigation/react-navigation/compare/@react-navigation/core@6.0.0-next.8...@react-navigation/core@6.0.0-next.9) (2021-05-23)
**Note:** Version bump only for package @react-navigation/core

View File

@@ -1,7 +1,7 @@
{
"name": "@react-navigation/core",
"description": "Core utilities for building navigators",
"version": "6.0.0-next.9",
"version": "6.0.0-next.14",
"keywords": [
"react",
"react-native",
@@ -35,22 +35,22 @@
"clean": "del lib"
},
"dependencies": {
"@react-navigation/routers": "^6.0.0-next.3",
"@react-navigation/routers": "^6.0.0-next.5",
"escape-string-regexp": "^4.0.0",
"nanoid": "^3.1.22",
"nanoid": "^3.1.23",
"query-string": "^7.0.0",
"react-is": "^16.13.0"
},
"devDependencies": {
"@testing-library/react-native": "^7.2.0",
"@types/react": "^16.9.53",
"@types/react-is": "^16.7.1",
"@types/react": "^17.0.9",
"@types/react-is": "^17.0.0",
"del-cli": "^3.0.1",
"immer": "^9.0.1",
"immer": "^9.0.2",
"react": "~16.13.1",
"react-native-builder-bob": "^0.18.1",
"react-test-renderer": "~16.13.1",
"typescript": "^4.2.3"
"typescript": "^4.3.2"
},
"peerDependencies": {
"react": "*"

View File

@@ -1,59 +1,42 @@
import * as React from 'react';
import {
CommonActions,
Route,
NavigationState,
InitialState,
PartialState,
NavigationAction,
NavigationState,
ParamListBase,
PartialState,
Route,
} from '@react-navigation/routers';
import EnsureSingleNavigator from './EnsureSingleNavigator';
import UnhandledActionContext from './UnhandledActionContext';
import NavigationBuilderContext from './NavigationBuilderContext';
import NavigationStateContext from './NavigationStateContext';
import NavigationRouteContext from './NavigationRouteContext';
import NavigationContext from './NavigationContext';
import { ScheduleUpdateContext } from './useScheduleUpdate';
import useChildListeners from './useChildListeners';
import useKeyedChildListeners from './useKeyedChildListeners';
import useOptionsGetters from './useOptionsGetters';
import useEventEmitter from './useEventEmitter';
import useSyncState from './useSyncState';
import checkSerializable from './checkSerializable';
import * as React from 'react';
import checkDuplicateRouteNames from './checkDuplicateRouteNames';
import findFocusedRoute from './findFocusedRoute';
import checkSerializable from './checkSerializable';
import { NOT_INITIALIZED_ERROR } from './createNavigationContainerRef';
import EnsureSingleNavigator from './EnsureSingleNavigator';
import findFocusedRoute from './findFocusedRoute';
import NavigationBuilderContext from './NavigationBuilderContext';
import NavigationContainerRefContext from './NavigationContainerRefContext';
import NavigationContext from './NavigationContext';
import NavigationRouteContext from './NavigationRouteContext';
import NavigationStateContext from './NavigationStateContext';
import type {
NavigationContainerEventMap,
NavigationContainerRef,
NavigationContainerProps,
NavigationContainerRef,
} from './types';
import UnhandledActionContext from './UnhandledActionContext';
import useChildListeners from './useChildListeners';
import useEventEmitter from './useEventEmitter';
import useKeyedChildListeners from './useKeyedChildListeners';
import useOptionsGetters from './useOptionsGetters';
import { ScheduleUpdateContext } from './useScheduleUpdate';
import useSyncState from './useSyncState';
type State = NavigationState | PartialState<NavigationState> | undefined;
const serializableWarnings: string[] = [];
const duplicateNameWarnings: string[] = [];
try {
/**
* Migration instructions for removal of devtools from core
*/
Object.defineProperty(
global,
'REACT_NAVIGATION_REDUX_DEVTOOLS_EXTENSION_INTEGRATION_ENABLED',
{
set(_) {
console.warn(
"Redux devtools extension integration can be enabled with the '@react-navigation/devtools' package. For more details, see https://reactnavigation.org/docs/devtools"
);
},
}
);
} catch (e) {
// Ignore
}
/**
* Remove `key` and `routeNames` from the state objects recursively to get partial state.
*
@@ -112,15 +95,10 @@ const BaseNavigationContainer = React.forwardRef(
);
}
const [
state,
getState,
setState,
scheduleUpdate,
flushUpdates,
] = useSyncState<State>(() =>
getPartialState(initialState == null ? undefined : initialState)
);
const [state, getState, setState, scheduleUpdate, flushUpdates] =
useSyncState<State>(() =>
getPartialState(initialState == null ? undefined : initialState)
);
const isFirstMountRef = React.useRef<boolean>(true);
@@ -136,17 +114,22 @@ const BaseNavigationContainer = React.forwardRef(
const { keyedListeners, addKeyedListener } = useKeyedChildListeners();
const dispatch = (
action: NavigationAction | ((state: NavigationState) => NavigationAction)
) => {
if (listeners.focus[0] == null) {
console.error(NOT_INITIALIZED_ERROR);
} else {
listeners.focus[0]((navigation) => navigation.dispatch(action));
}
};
const dispatch = React.useCallback(
(
action:
| NavigationAction
| ((state: NavigationState) => NavigationAction)
) => {
if (listeners.focus[0] == null) {
console.error(NOT_INITIALIZED_ERROR);
} else {
listeners.focus[0]((navigation) => navigation.dispatch(action));
}
},
[listeners.focus]
);
const canGoBack = () => {
const canGoBack = React.useCallback(() => {
if (listeners.focus[0] == null) {
return false;
}
@@ -160,7 +143,7 @@ const BaseNavigationContainer = React.forwardRef(
} else {
return false;
}
};
}, [listeners.focus]);
const resetRoot = React.useCallback(
(state?: PartialState<NavigationState> | NavigationState) => {
@@ -200,28 +183,45 @@ const BaseNavigationContainer = React.forwardRef(
const { addOptionsGetter, getCurrentOptions } = useOptionsGetters({});
React.useImperativeHandle(ref, () => ({
...Object.keys(CommonActions).reduce<any>((acc, name) => {
acc[name] = (...args: any[]) =>
// @ts-expect-error: this is ok
dispatch(CommonActions[name](...args));
return acc;
}, {}),
...emitter.create('root'),
resetRoot,
dispatch,
canGoBack,
getRootState,
getState: () => state,
getParent: () => undefined,
getCurrentRoute,
getCurrentOptions,
isReady: () => listeners.focus[0] != null,
}));
const navigation: NavigationContainerRef<ParamListBase> = React.useMemo(
() => ({
...Object.keys(CommonActions).reduce<any>((acc, name) => {
acc[name] = (...args: any[]) =>
// @ts-expect-error: this is ok
dispatch(CommonActions[name](...args));
return acc;
}, {}),
...emitter.create('root'),
resetRoot,
dispatch,
canGoBack,
getRootState,
getState: () => stateRef.current,
getParent: () => undefined,
getCurrentRoute,
getCurrentOptions,
isReady: () => listeners.focus[0] != null,
}),
[
canGoBack,
dispatch,
emitter,
getCurrentOptions,
getCurrentRoute,
getRootState,
listeners.focus,
resetRoot,
]
);
React.useImperativeHandle(ref, () => navigation, [navigation]);
const onDispatchAction = React.useCallback(
(action: NavigationAction, noop: boolean) => {
emitter.emit({ type: '__unsafe_action__', data: { action, noop } });
emitter.emit({
type: '__unsafe_action__',
data: { action, noop, stack: stackRef.current },
});
},
[emitter]
);
@@ -244,12 +244,15 @@ const BaseNavigationContainer = React.forwardRef(
[emitter]
);
const stackRef = React.useRef<string | undefined>();
const builderContext = React.useMemo(
() => ({
addListener,
addKeyedListener,
onDispatchAction,
onOptionsChange,
stackRef,
}),
[addListener, addKeyedListener, onDispatchAction, onOptionsChange]
);
@@ -285,10 +288,12 @@ const BaseNavigationContainer = React.forwardRef(
);
const onStateChangeRef = React.useRef(onStateChange);
const stateRef = React.useRef(state);
React.useEffect(() => {
isInitialRef.current = false;
onStateChangeRef.current = onStateChange;
stateRef.current = state;
});
React.useEffect(() => {
@@ -345,9 +350,8 @@ const BaseNavigationContainer = React.forwardRef(
}
}
const duplicateRouteNamesResult = checkDuplicateRouteNames(
hydratedState
);
const duplicateRouteNamesResult =
checkDuplicateRouteNames(hydratedState);
if (duplicateRouteNamesResult.length) {
const message = `Found screens with the same name nested inside one another. Check:\n${duplicateRouteNamesResult.map(
@@ -415,17 +419,19 @@ const BaseNavigationContainer = React.forwardRef(
);
let element = (
<ScheduleUpdateContext.Provider value={scheduleContext}>
<NavigationBuilderContext.Provider value={builderContext}>
<NavigationStateContext.Provider value={context}>
<UnhandledActionContext.Provider
value={onUnhandledAction ?? defaultOnUnhandledAction}
>
<EnsureSingleNavigator>{children}</EnsureSingleNavigator>
</UnhandledActionContext.Provider>
</NavigationStateContext.Provider>
</NavigationBuilderContext.Provider>
</ScheduleUpdateContext.Provider>
<NavigationContainerRefContext.Provider value={navigation}>
<ScheduleUpdateContext.Provider value={scheduleContext}>
<NavigationBuilderContext.Provider value={builderContext}>
<NavigationStateContext.Provider value={context}>
<UnhandledActionContext.Provider
value={onUnhandledAction ?? defaultOnUnhandledAction}
>
<EnsureSingleNavigator>{children}</EnsureSingleNavigator>
</UnhandledActionContext.Provider>
</NavigationStateContext.Provider>
</NavigationBuilderContext.Provider>
</ScheduleUpdateContext.Provider>
</NavigationContainerRefContext.Provider>
);
if (independent) {

View File

@@ -4,8 +4,7 @@ import * as React from 'react';
* Context which holds the values for the current navigation tree.
* Intended for use in SSR. This is not safe to use on the client.
*/
const CurrentRenderContext = React.createContext<
{ options?: object } | undefined
>(undefined);
const CurrentRenderContext =
React.createContext<{ options?: object } | undefined>(undefined);
export default CurrentRenderContext;

View File

@@ -6,13 +6,14 @@ type Props = {
const MULTIPLE_NAVIGATOR_ERROR = `Another navigator is already registered for this container. You likely have multiple navigators under a single "NavigationContainer" or "Screen". Make sure each navigator is under a separate "Screen" container. See https://reactnavigation.org/docs/nesting-navigators for a guide on nesting.`;
export const SingleNavigatorContext = React.createContext<
| {
register(key: string): void;
unregister(key: string): void;
}
| undefined
>(undefined);
export const SingleNavigatorContext =
React.createContext<
| {
register(key: string): void;
unregister(key: string): void;
}
| undefined
>(undefined);
/**
* Component which ensures that there's only one navigator nested under it.

View File

@@ -1,4 +1,5 @@
import type { ParamListBase } from '@react-navigation/routers';
import type { RouteGroupConfig } from './types';
/**

View File

@@ -1,9 +1,10 @@
import * as React from 'react';
import type {
NavigationAction,
NavigationState,
ParamListBase,
} from '@react-navigation/routers';
import * as React from 'react';
import type { NavigationHelpers } from './types';
export type ListenerMap = {
@@ -38,7 +39,10 @@ export type FocusedNavigationCallback<T> = (
export type FocusedNavigationListener = <T>(
callback: FocusedNavigationCallback<T>
) => { handled: boolean; result: T };
) => {
handled: boolean;
result: T;
};
export type GetStateListener = () => NavigationState;
@@ -57,6 +61,7 @@ const NavigationBuilderContext = React.createContext<{
onRouteFocus?: (key: string) => void;
onDispatchAction: (action: NavigationAction, noop: boolean) => void;
onOptionsChange: (options: object) => void;
stackRef?: React.MutableRefObject<string | undefined>;
}>({
onDispatchAction: () => undefined,
onOptionsChange: () => undefined,

View File

@@ -0,0 +1,14 @@
import type { ParamListBase } from '@react-navigation/routers';
import * as React from 'react';
import type { NavigationContainerRef } from './types';
/**
* Context which holds the route prop for a screen.
*/
const NavigationContainerRefContext =
React.createContext<NavigationContainerRef<ParamListBase> | undefined>(
undefined
);
export default NavigationContainerRefContext;

View File

@@ -1,12 +1,12 @@
import * as React from 'react';
import type { ParamListBase } from '@react-navigation/routers';
import * as React from 'react';
import type { NavigationProp } from './types';
/**
* Context which holds the navigation prop for a screen.
*/
const NavigationContext = React.createContext<
NavigationProp<ParamListBase> | undefined
>(undefined);
const NavigationContext =
React.createContext<NavigationProp<ParamListBase> | undefined>(undefined);
export default NavigationContext;

View File

@@ -1,13 +1,13 @@
import * as React from 'react';
import type { ParamListBase } from '@react-navigation/routers';
import * as React from 'react';
import type { NavigationHelpers } from './types';
/**
* Context which holds the navigation helpers of the parent navigator.
* Navigators should use this context in their view component.
*/
const NavigationHelpersContext = React.createContext<
NavigationHelpers<ParamListBase> | undefined
>(undefined);
const NavigationHelpersContext =
React.createContext<NavigationHelpers<ParamListBase> | undefined>(undefined);
export default NavigationHelpersContext;

View File

@@ -1,11 +1,10 @@
import * as React from 'react';
import type { Route } from '@react-navigation/routers';
import * as React from 'react';
/**
* Context which holds the route prop for a screen.
*/
const NavigationContext = React.createContext<Route<string> | undefined>(
undefined
);
const NavigationRouteContext =
React.createContext<Route<string> | undefined>(undefined);
export default NavigationContext;
export default NavigationRouteContext;

View File

@@ -1,5 +1,5 @@
import * as React from 'react';
import type { NavigationState, PartialState } from '@react-navigation/routers';
import * as React from 'react';
const MISSING_CONTEXT_ERROR =
"Couldn't find a navigation context. Have you wrapped your app with 'NavigationContainer'? See https://reactnavigation.org/docs/getting-started for setup instructions.";

View File

@@ -1,15 +1,16 @@
import * as React from 'react';
import type {
Route,
ParamListBase,
NavigationState,
ParamListBase,
PartialState,
Route,
} from '@react-navigation/routers';
import * as React from 'react';
import EnsureSingleNavigator from './EnsureSingleNavigator';
import NavigationStateContext from './NavigationStateContext';
import StaticContainer from './StaticContainer';
import EnsureSingleNavigator from './EnsureSingleNavigator';
import useOptionsGetters from './useOptionsGetters';
import type { NavigationProp, RouteConfigComponent } from './types';
import useOptionsGetters from './useOptionsGetters';
type Props<State extends NavigationState, ScreenOptions extends {}> = {
screen: RouteConfigComponent<ParamListBase, string> & { name: string };

View File

@@ -1,5 +1,6 @@
import type { ParamListBase, NavigationState } from '@react-navigation/routers';
import type { RouteConfig, EventMapBase } from './types';
import type { NavigationState, ParamListBase } from '@react-navigation/routers';
import type { EventMapBase, RouteConfig } from './types';
/**
* Empty component used for specifying route configuration.

View File

@@ -1,8 +1,9 @@
import * as React from 'react';
import type { NavigationAction } from '@react-navigation/routers';
import * as React from 'react';
const UnhandledActionContext = React.createContext<
((action: NavigationAction) => void) | undefined
>(undefined);
const UnhandledActionContext =
React.createContext<((action: NavigationAction) => void) | undefined>(
undefined
);
export default UnhandledActionContext;

View File

@@ -1,5 +1,3 @@
import * as React from 'react';
import { act, render } from '@testing-library/react-native';
import {
DefaultRouterOptions,
NavigationState,
@@ -8,12 +6,15 @@ import {
StackRouter,
TabRouter,
} from '@react-navigation/routers';
import { act, render } from '@testing-library/react-native';
import * as React from 'react';
import BaseNavigationContainer from '../BaseNavigationContainer';
import NavigationStateContext from '../NavigationStateContext';
import createNavigationContainerRef from '../createNavigationContainerRef';
import MockRouter, { MockActions } from './__fixtures__/MockRouter';
import useNavigationBuilder from '../useNavigationBuilder';
import NavigationStateContext from '../NavigationStateContext';
import Screen from '../Screen';
import useNavigationBuilder from '../useNavigationBuilder';
import MockRouter, { MockActions } from './__fixtures__/MockRouter';
it('throws when getState is accessed without a container', () => {
expect.assertions(1);

View File

@@ -1,5 +1,6 @@
import * as React from 'react';
import { render } from '@testing-library/react-native';
import * as React from 'react';
import StaticContainer from '../StaticContainer';
it("doesn't update element if no props changed", () => {

View File

@@ -1,10 +1,10 @@
import {
BaseRouter,
Router,
CommonNavigationAction,
DefaultRouterOptions,
NavigationState,
Route,
DefaultRouterOptions,
Router,
} from '@react-navigation/routers';
export type MockActions = CommonNavigationAction | { type: 'NOOP' | 'UPDATE' };

View File

@@ -1,4 +1,5 @@
import type { NavigationState, PartialState } from '@react-navigation/routers';
import getPathFromState from '../getPathFromState';
import getStateFromPath from '../getStateFromPath';

View File

@@ -1,8 +1,9 @@
import type { InitialState } from '@react-navigation/routers';
import produce from 'immer';
import getStateFromPath from '../getStateFromPath';
import getPathFromState from '../getPathFromState';
import findFocusedRoute from '../findFocusedRoute';
import getPathFromState from '../getPathFromState';
import getStateFromPath from '../getStateFromPath';
const changePath = <T extends InitialState>(state: T, path: string): T =>
produce(state, (draftState) => {
@@ -2195,6 +2196,7 @@ it('tries to match wildcard patterns at the end', () => {
path: '/bar/:id/',
screens: {
404: '*',
UserProfile: ':userSlug',
Test: 'test',
},
},
@@ -2419,3 +2421,57 @@ it('correctly applies initialRouteName for config with similar route names v2',
getStateFromPath<object>(getPathFromState<object>(state, config), config)
).toEqual(state);
});
it('throws when invalid properties are specified in the config', () => {
expect(() =>
getStateFromPath<object>('', {
Foo: 'foo',
Bar: {
path: 'bar',
},
} as any)
).toThrowErrorMatchingInlineSnapshot(`
"Found invalid properties in the configuration:
- Foo
- Bar
Did you forget to specify them under a 'screens' property?
You can only specify the following properties:
- initialRouteName
- screens
See https://reactnavigation.org/docs/configuring-links for more details on how to specify a linking configuration."
`);
expect(() =>
getStateFromPath<object>('', {
screens: {
Foo: 'foo',
Bar: {
path: 'bar',
},
Baz: {
Qux: {
path: 'qux',
},
},
},
} as any)
).toThrowErrorMatchingInlineSnapshot(`
"Found invalid properties in the configuration:
- Qux
Did you forget to specify them under a 'screens' property?
You can only specify the following properties:
- initialRouteName
- screens
- path
- exact
- stringify
- parse
See https://reactnavigation.org/docs/configuring-links for more details on how to specify a linking configuration."
`);
});

View File

@@ -1,12 +1,13 @@
import * as React from 'react';
import { render, act } from '@testing-library/react-native';
import type { NavigationState, ParamListBase } from '@react-navigation/routers';
import { act, render } from '@testing-library/react-native';
import * as React from 'react';
import BaseNavigationContainer from '../BaseNavigationContainer';
import createNavigationContainerRef from '../createNavigationContainerRef';
import Group from '../Group';
import Screen from '../Screen';
import BaseNavigationContainer from '../BaseNavigationContainer';
import useNavigationBuilder from '../useNavigationBuilder';
import createNavigationContainerRef from '../createNavigationContainerRef';
import useNavigation from '../useNavigation';
import useNavigationBuilder from '../useNavigationBuilder';
import MockRouter, { MockRouterKey } from './__fixtures__/MockRouter';
beforeEach(() => (MockRouterKey.current = 0));

View File

@@ -1,13 +1,14 @@
import * as React from 'react';
import { render, act } from '@testing-library/react-native';
import type {
DefaultRouterOptions,
NavigationState,
Router,
} from '@react-navigation/routers';
import useNavigationBuilder from '../useNavigationBuilder';
import { act, render } from '@testing-library/react-native';
import * as React from 'react';
import BaseNavigationContainer from '../BaseNavigationContainer';
import Screen from '../Screen';
import useNavigationBuilder from '../useNavigationBuilder';
import MockRouter, {
MockActions,
MockRouterKey,

View File

@@ -1,9 +1,10 @@
import type { NavigationState, Router } from '@react-navigation/routers';
import { act, render } from '@testing-library/react-native';
import * as React from 'react';
import { render, act } from '@testing-library/react-native';
import type { Router, NavigationState } from '@react-navigation/routers';
import useNavigationBuilder from '../useNavigationBuilder';
import BaseNavigationContainer from '../BaseNavigationContainer';
import Screen from '../Screen';
import useNavigationBuilder from '../useNavigationBuilder';
import MockRouter from './__fixtures__/MockRouter';
it('fires focus and blur events in root navigator', () => {
@@ -30,19 +31,21 @@ it('fires focus and blur events in root navigator', () => {
const fourthFocusCallback = jest.fn();
const fourthBlurCallback = jest.fn();
const createComponent = (focusCallback: any, blurCallback: any) => ({
navigation,
}: any) => {
React.useEffect(() => navigation.addListener('focus', focusCallback), [
navigation,
]);
const createComponent =
(focusCallback: any, blurCallback: any) =>
({ navigation }: any) => {
React.useEffect(
() => navigation.addListener('focus', focusCallback),
[navigation]
);
React.useEffect(() => navigation.addListener('blur', blurCallback), [
navigation,
]);
React.useEffect(
() => navigation.addListener('blur', blurCallback),
[navigation]
);
return null;
};
return null;
};
const navigation = React.createRef<any>();
@@ -184,19 +187,21 @@ it('fires focus and blur events in nested navigator', () => {
const fourthFocusCallback = jest.fn();
const fourthBlurCallback = jest.fn();
const createComponent = (focusCallback: any, blurCallback: any) => ({
navigation,
}: any) => {
React.useEffect(() => navigation.addListener('focus', focusCallback), [
navigation,
]);
const createComponent =
(focusCallback: any, blurCallback: any) =>
({ navigation }: any) => {
React.useEffect(
() => navigation.addListener('focus', focusCallback),
[navigation]
);
React.useEffect(() => navigation.addListener('blur', blurCallback), [
navigation,
]);
React.useEffect(
() => navigation.addListener('blur', blurCallback),
[navigation]
);
return null;
};
return null;
};
const parent = React.createRef<any>();
const child = React.createRef<any>();
@@ -391,9 +396,10 @@ it('fires blur event when a route is removed with a delay', async () => {
const First = () => null;
const Second = ({ navigation }: any) => {
React.useEffect(() => navigation.addListener('blur', blurCallback), [
navigation,
]);
React.useEffect(
() => navigation.addListener('blur', blurCallback),
[navigation]
);
return null;
};
@@ -446,13 +452,16 @@ it('fires custom events added with addListener', () => {
const secondCallback = jest.fn();
const thirdCallback = jest.fn();
const createComponent = (callback: any) => ({ navigation }: any) => {
React.useEffect(() => navigation.addListener(eventName, callback), [
navigation,
]);
const createComponent =
(callback: any) =>
({ navigation }: any) => {
React.useEffect(
() => navigation.addListener(eventName, callback),
[navigation]
);
return null;
};
return null;
};
const ref = React.createRef<any>();
@@ -525,9 +534,10 @@ it("doesn't call same listener multiple times with addListener", () => {
const callback = jest.fn();
const Test = ({ navigation }: any) => {
React.useEffect(() => navigation.addListener(eventName, callback), [
navigation,
]);
React.useEffect(
() => navigation.addListener(eventName, callback),
[navigation]
);
return null;
};
@@ -801,9 +811,10 @@ it('has option to prevent default', () => {
};
const Test = ({ navigation }: any) => {
React.useEffect(() => navigation.addListener(eventName, callback), [
navigation,
]);
React.useEffect(
() => navigation.addListener(eventName, callback),
[navigation]
);
return null;
};

View File

@@ -1,9 +1,10 @@
import { act, render } from '@testing-library/react-native';
import * as React from 'react';
import { render, act } from '@testing-library/react-native';
import useNavigationBuilder from '../useNavigationBuilder';
import useFocusEffect from '../useFocusEffect';
import BaseNavigationContainer from '../BaseNavigationContainer';
import Screen from '../Screen';
import useFocusEffect from '../useFocusEffect';
import useNavigationBuilder from '../useNavigationBuilder';
import MockRouter from './__fixtures__/MockRouter';
it('runs focus effect on focus change', () => {

View File

@@ -1,9 +1,10 @@
import { act, render } from '@testing-library/react-native';
import * as React from 'react';
import { render, act } from '@testing-library/react-native';
import useNavigationBuilder from '../useNavigationBuilder';
import useIsFocused from '../useIsFocused';
import BaseNavigationContainer from '../BaseNavigationContainer';
import Screen from '../Screen';
import useIsFocused from '../useIsFocused';
import useNavigationBuilder from '../useNavigationBuilder';
import MockRouter from './__fixtures__/MockRouter';
it('renders correct focus state', () => {

View File

@@ -1,9 +1,10 @@
import * as React from 'react';
import { render } from '@testing-library/react-native';
import useNavigationBuilder from '../useNavigationBuilder';
import useNavigation from '../useNavigation';
import * as React from 'react';
import BaseNavigationContainer from '../BaseNavigationContainer';
import Screen from '../Screen';
import useNavigation from '../useNavigation';
import useNavigationBuilder from '../useNavigationBuilder';
import MockRouter from './__fixtures__/MockRouter';
it('gets navigation prop from context', () => {
@@ -106,13 +107,40 @@ it("gets navigation's parent's parent from context", () => {
);
});
it('gets navigation from container from context', () => {
expect.assertions(1);
const TestNavigator = (props: any): any => {
const { state, descriptors } = useNavigationBuilder(MockRouter, props);
return state.routes.map((route) => descriptors[route.key].render());
};
const Test = () => {
const navigation = useNavigation();
expect(navigation.navigate).toBeDefined();
return null;
};
render(
<BaseNavigationContainer>
<Test />
<TestNavigator>
<Screen name="foo">{() => null}</Screen>
</TestNavigator>
</BaseNavigationContainer>
);
});
it('throws if called outside a navigation context', () => {
expect.assertions(1);
const Test = () => {
// eslint-disable-next-line react-hooks/rules-of-hooks
expect(() => useNavigation()).toThrow(
"Couldn't find a navigation object. Is your component inside a screen in a navigator?"
"Couldn't find a navigation object. Is your component inside NavigationContainer?"
);
return null;

View File

@@ -1,10 +1,11 @@
import { act, render } from '@testing-library/react-native';
import * as React from 'react';
import { render, act } from '@testing-library/react-native';
import useEventEmitter from '../useEventEmitter';
import useNavigationCache from '../useNavigationCache';
import useNavigationBuilder from '../useNavigationBuilder';
import BaseNavigationContainer from '../BaseNavigationContainer';
import Screen from '../Screen';
import useEventEmitter from '../useEventEmitter';
import useNavigationBuilder from '../useNavigationBuilder';
import useNavigationCache from '../useNavigationCache';
import MockRouter, { MockRouterKey } from './__fixtures__/MockRouter';
beforeEach(() => (MockRouterKey.current = 0));

View File

@@ -1,10 +1,11 @@
import * as React from 'react';
import { render, act } from '@testing-library/react-native';
import type { NavigationState } from '@react-navigation/routers';
import useNavigationBuilder from '../useNavigationBuilder';
import useNavigationState from '../useNavigationState';
import { act, render } from '@testing-library/react-native';
import * as React from 'react';
import BaseNavigationContainer from '../BaseNavigationContainer';
import Screen from '../Screen';
import useNavigationBuilder from '../useNavigationBuilder';
import useNavigationState from '../useNavigationState';
import MockRouter from './__fixtures__/MockRouter';
it('gets the current navigation state', () => {

View File

@@ -1,16 +1,17 @@
import * as React from 'react';
import { act, render } from '@testing-library/react-native';
import {
Router,
DefaultRouterOptions,
NavigationState,
StackRouter,
ParamListBase,
Router,
StackRouter,
} from '@react-navigation/routers';
import useNavigationBuilder from '../useNavigationBuilder';
import { act, render } from '@testing-library/react-native';
import * as React from 'react';
import BaseNavigationContainer from '../BaseNavigationContainer';
import Screen from '../Screen';
import createNavigationContainerRef from '../createNavigationContainerRef';
import Screen from '../Screen';
import useNavigationBuilder from '../useNavigationBuilder';
import MockRouter, {
MockActions,
MockRouterKey,

View File

@@ -1,11 +1,12 @@
import * as React from 'react';
import { render } from '@testing-library/react-native';
import useNavigationBuilder from '../useNavigationBuilder';
import useRoute from '../useRoute';
import * as React from 'react';
import BaseNavigationContainer from '../BaseNavigationContainer';
import Screen from '../Screen';
import MockRouter from './__fixtures__/MockRouter';
import type { RouteProp } from '../types';
import useNavigationBuilder from '../useNavigationBuilder';
import useRoute from '../useRoute';
import MockRouter from './__fixtures__/MockRouter';
it('gets route prop from context', () => {
expect.assertions(1);

View File

@@ -1,4 +1,5 @@
import { CommonActions } from '@react-navigation/routers';
import type { NavigationContainerRefWithCurrent } from './types';
export const NOT_INITIALIZED_ERROR =

View File

@@ -1,8 +1,9 @@
import type { NavigationState, ParamListBase } from '@react-navigation/routers';
import type * as React from 'react';
import type { ParamListBase, NavigationState } from '@react-navigation/routers';
import Group from './Group';
import Screen from './Screen';
import type { TypedNavigator, EventMapBase } from './types';
import type { EventMapBase, TypedNavigator } from './types';
/**
* Higher order component to create a `Navigator` and `Screen` pair.

View File

@@ -1,12 +1,13 @@
import type {
Route,
PartialRoute,
ParamListBase,
NavigationState,
PartialState,
CommonActions,
NavigationState,
ParamListBase,
PartialRoute,
PartialState,
Route,
} from '@react-navigation/routers';
import type { PathConfig, PathConfigMap, NavigatorScreenParams } from './types';
import type { NavigatorScreenParams, PathConfig, PathConfigMap } from './types';
type ConfigItem = {
initialRouteName?: string;

View File

@@ -1,4 +1,5 @@
import type { Route } from '@react-navigation/routers';
import { CHILD_STATE } from './useRouteCache';
export default function getFocusedRouteNameFromRoute(

View File

@@ -1,11 +1,13 @@
import * as queryString from 'query-string';
import type {
NavigationState,
PartialState,
Route,
} from '@react-navigation/routers';
import * as queryString from 'query-string';
import fromEntries from './fromEntries';
import type { PathConfig, PathConfigMap } from './types';
import validatePathConfig from './validatePathConfig';
type Options<ParamList> = {
initialRouteName?: string;
@@ -74,6 +76,10 @@ export default function getPathFromState<ParamList extends {}>(
);
}
if (options) {
validatePathConfig(options);
}
// Create a normalized configs object which will be easier to use
const configs: Record<string, ConfigItem> = options?.screens
? createNormalizedConfigs(options?.screens)

View File

@@ -1,12 +1,14 @@
import escape from 'escape-string-regexp';
import * as queryString from 'query-string';
import type {
InitialState,
NavigationState,
PartialState,
InitialState,
} from '@react-navigation/routers';
import escape from 'escape-string-regexp';
import * as queryString from 'query-string';
import findFocusedRoute from './findFocusedRoute';
import type { PathConfigMap } from './types';
import validatePathConfig from './validatePathConfig';
type Options<ParamList extends {}> = {
initialRouteName?: string;
@@ -64,6 +66,10 @@ export default function getStateFromPath<ParamList extends {}>(
path: string,
options?: Options<ParamList>
): ResultState | undefined {
if (options) {
validatePathConfig(options);
}
let initialRoutes: InitialRouteConfig[] = [];
if (options?.initialRouteName) {
@@ -137,27 +143,31 @@ export default function getStateFromPath<ParamList extends {}>(
const aParts = a.pattern.split('/');
const bParts = b.pattern.split('/');
const aWildcardIndex = aParts.indexOf('*');
const bWildcardIndex = bParts.indexOf('*');
// If only one of the patterns has a wildcard, move it down in the list
if (aWildcardIndex === -1 && bWildcardIndex !== -1) {
return -1;
for (let i = 0; i < Math.max(aParts.length, bParts.length); i++) {
// if b is longer, b get higher priority
if (aParts[i] == null) {
return 1;
}
// if a is longer, a get higher priority
if (bParts[i] == null) {
return -1;
}
const aWildCard = aParts[i] === '*' || aParts[i].startsWith(':');
const bWildCard = bParts[i] === '*' || bParts[i].startsWith(':');
// if both are wildcard we compare next component
if (aWildCard && bWildCard) {
continue;
}
// if only a is wild card, b get higher priority
if (aWildCard) {
return 1;
}
// if only b is wild card, a get higher priority
if (bWildCard) {
return -1;
}
}
if (aWildcardIndex !== -1 && bWildcardIndex === -1) {
return 1;
}
if (aWildcardIndex === bWildcardIndex) {
// If `b` has more `/`, it's more exhaustive
// So we move it up in the list
return bParts.length - aParts.length;
}
// If the wildcard appears later in the pattern (has higher index), it's more specific
// So we move it up in the list
return bWildcardIndex - aWildcardIndex;
return bParts.length - aParts.length;
});
// Check for duplicate patterns in the config

View File

@@ -1,30 +1,23 @@
export * from '@react-navigation/routers';
export { default as BaseNavigationContainer } from './BaseNavigationContainer';
export { default as createNavigatorFactory } from './createNavigatorFactory';
export { default as createNavigationContainerRef } from './createNavigationContainerRef';
export { default as useNavigationContainerRef } from './useNavigationContainerRef';
export { default as NavigationHelpersContext } from './NavigationHelpersContext';
export { default as NavigationContext } from './NavigationContext';
export { default as NavigationRouteContext } from './NavigationRouteContext';
export { default as createNavigatorFactory } from './createNavigatorFactory';
export { default as CurrentRenderContext } from './CurrentRenderContext';
export { default as useNavigationBuilder } from './useNavigationBuilder';
export { default as useNavigation } from './useNavigation';
export { default as useRoute } from './useRoute';
export { default as findFocusedRoute } from './findFocusedRoute';
export { default as getActionFromState } from './getActionFromState';
export { default as getFocusedRouteNameFromRoute } from './getFocusedRouteNameFromRoute';
export { default as getPathFromState } from './getPathFromState';
export { default as getStateFromPath } from './getStateFromPath';
export { default as NavigationContainerRefContext } from './NavigationContainerRefContext';
export { default as NavigationContext } from './NavigationContext';
export { default as NavigationHelpersContext } from './NavigationHelpersContext';
export { default as NavigationRouteContext } from './NavigationRouteContext';
export * from './types';
export { default as useFocusEffect } from './useFocusEffect';
export { default as useIsFocused } from './useIsFocused';
export { default as useNavigation } from './useNavigation';
export { default as useNavigationBuilder } from './useNavigationBuilder';
export { default as useNavigationContainerRef } from './useNavigationContainerRef';
export { default as useNavigationState } from './useNavigationState';
export { default as getStateFromPath } from './getStateFromPath';
export { default as getPathFromState } from './getPathFromState';
export { default as getActionFromState } from './getActionFromState';
export { default as findFocusedRoute } from './findFocusedRoute';
export { default as getFocusedRouteNameFromRoute } from './getFocusedRouteNameFromRoute';
export * from './types';
export { default as useRoute } from './useRoute';
export { default as validatePathConfig } from './validatePathConfig';
export * from '@react-navigation/routers';

Some files were not shown because too many files have changed in this diff Show More