Skip to content

Commit 52eab5c

Browse files
committed
chore: create adapter for both navigation, adjust types
1 parent dd68f60 commit 52eab5c

File tree

7 files changed

+145
-48
lines changed

7 files changed

+145
-48
lines changed

package.json

+2-2
Original file line numberDiff line numberDiff line change
@@ -59,7 +59,7 @@
5959
"@callstack/eslint-config": "^13.0.2",
6060
"@commitlint/config-conventional": "^8.3.4",
6161
"@expo/vector-icons": "^14.0.2",
62-
"@react-navigation/native": "^6.1.2",
62+
"@react-navigation/native": "^7.1.6",
6363
"@release-it/conventional-changelog": "^1.1.0",
6464
"@testing-library/jest-native": "^5.4.1",
6565
"@testing-library/react-native": "11.5.0",
@@ -132,7 +132,7 @@
132132
"__fixtures__\\/[^/]+\\/(output|error)\\.js"
133133
],
134134
"transformIgnorePatterns": [
135-
"node_modules/(?!(@react-native|react-native(-.*)?)/)"
135+
"node_modules/(?!(@react-navigation|@react-native|react-native(-.*)?)/)"
136136
]
137137
},
138138
"greenkeeper": {
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
// @ts-ignore
2+
import { useLinkTools, useLinkBuilder } from '@react-navigation/native';
3+
import { renderHook } from '@testing-library/react-native';
4+
5+
import { useNavigationLink } from '../adapter';
6+
7+
jest.mock('@react-navigation/native', () => ({
8+
useLinkBuilder: jest.fn().mockReturnValue(jest.fn()),
9+
}));
10+
11+
describe('React Navigation adapter', () => {
12+
describe('when v6 is used', () => {
13+
it('should use useLinkBuilder() to create link', () => {
14+
let builder;
15+
16+
renderHook(() => {
17+
builder = useNavigationLink();
18+
builder('routeKey');
19+
});
20+
21+
expect(useLinkTools).toBeUndefined();
22+
expect(useLinkBuilder).toHaveBeenCalled();
23+
expect(builder).toHaveBeenCalledWith('routeKey');
24+
});
25+
});
26+
});
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
// @ts-ignore
2+
import { useLinkTools, useLinkBuilder } from '@react-navigation/native';
3+
import { renderHook } from '@testing-library/react-native';
4+
5+
import { useNavigationLink } from '../adapter';
6+
7+
jest.mock('@react-navigation/native', () => ({
8+
useLinkTools: jest.fn().mockReturnValue({ buildHref: jest.fn() }),
9+
}));
10+
11+
describe('React Navigation adapter', () => {
12+
describe('when v7 is used', () => {
13+
it('should use useLinkTools() to create link', () => {
14+
let builder;
15+
16+
renderHook(() => {
17+
builder = useNavigationLink();
18+
builder('routeKey');
19+
});
20+
21+
expect(useLinkTools).toHaveBeenCalled();
22+
expect(useLinkBuilder).toBeUndefined();
23+
expect(builder).toHaveBeenCalledWith('routeKey');
24+
});
25+
});
26+
});

src/react-navigation/adapter.ts

+24
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
import {
2+
// @ts-ignore: this hook is not available in React Navigation v7
3+
useLinkBuilder,
4+
// @ts-ignore: this hook is not available in React Navigation v6
5+
useLinkTools,
6+
} from '@react-navigation/native';
7+
8+
function useV7LinkBuilder() {
9+
const tools = useLinkTools();
10+
return tools.buildHref;
11+
}
12+
13+
type NavigationLink = () => (
14+
name: string,
15+
params?: object
16+
) => string | undefined;
17+
18+
/**
19+
* In React Navigation 7 `useLinkBuilder` was superseded by `useLinkTools`
20+
* https://reactnavigation.org/docs/7.x/upgrading-from-6.x/#the-uselinkto-and-uselinkbuilder-hooks-are-merged-into-uselinktools
21+
**/
22+
23+
export const useNavigationLink: NavigationLink =
24+
typeof useLinkTools !== 'undefined' ? useV7LinkBuilder : useLinkBuilder;

src/react-navigation/navigators/createMaterialBottomTabNavigator.tsx

+26-7
Original file line numberDiff line numberDiff line change
@@ -3,11 +3,14 @@ import * as React from 'react';
33
import {
44
createNavigatorFactory,
55
DefaultNavigatorOptions,
6+
NavigatorTypeBagBase,
67
ParamListBase,
8+
StaticConfig,
79
TabActionHelpers,
810
TabNavigationState,
911
TabRouter,
1012
TabRouterOptions,
13+
TypedNavigator,
1114
useNavigationBuilder,
1215
} from '@react-navigation/native';
1316

@@ -18,11 +21,14 @@ import type {
1821
} from '../types';
1922
import MaterialBottomTabView from '../views/MaterialBottomTabView';
2023

24+
// Based on: https://github.com/react-navigation/react-navigation/blob/main/packages/bottom-tabs/src/types.tsx#L445-L454
2125
export type MaterialBottomTabNavigatorProps = DefaultNavigatorOptions<
2226
ParamListBase,
27+
undefined,
2328
TabNavigationState<ParamListBase>,
2429
MaterialBottomTabNavigationOptions,
25-
MaterialBottomTabNavigationEventMap
30+
MaterialBottomTabNavigationEventMap,
31+
typeof MaterialBottomTabView
2632
> &
2733
TabRouterOptions &
2834
MaterialBottomTabNavigationConfig;
@@ -64,9 +70,22 @@ function MaterialBottomTabNavigator({
6470
);
6571
}
6672

67-
export default createNavigatorFactory<
68-
TabNavigationState<ParamListBase>,
69-
MaterialBottomTabNavigationOptions,
70-
MaterialBottomTabNavigationEventMap,
71-
typeof MaterialBottomTabNavigator
72-
>(MaterialBottomTabNavigator);
73+
// Based on: https://github.com/react-navigation/react-navigation/blob/main/packages/material-top-tabs/src/navigators/createMaterialTopTabNavigator.tsx#L65-L86
74+
export default function <
75+
const ParamList extends ParamListBase,
76+
const NavigatorID extends string | undefined,
77+
const TypeBag extends NavigatorTypeBagBase = {
78+
ParamList: ParamList;
79+
NavigatorID: NavigatorID;
80+
State: TabNavigationState<ParamList>;
81+
ScreenOptions: MaterialBottomTabNavigationOptions;
82+
EventMap: MaterialBottomTabNavigationEventMap;
83+
NavigationList: {
84+
[RouteName in keyof ParamList]: MaterialBottomTabNavigatorProps;
85+
};
86+
Navigator: typeof MaterialBottomTabNavigator;
87+
},
88+
const Config extends StaticConfig<TypeBag> = StaticConfig<TypeBag>
89+
>(config?: Config): TypedNavigator<TypeBag, Config> {
90+
return createNavigatorFactory(MaterialBottomTabNavigator)(config);
91+
}

src/react-navigation/views/MaterialBottomTabView.tsx

+2-2
Original file line numberDiff line numberDiff line change
@@ -7,11 +7,11 @@ import {
77
ParamListBase,
88
Route,
99
TabNavigationState,
10-
useLinkBuilder,
1110
} from '@react-navigation/native';
1211

1312
import BottomNavigation from '../../components/BottomNavigation/BottomNavigation';
1413
import MaterialCommunityIcon from '../../components/MaterialCommunityIcon';
14+
import { useNavigationLink } from '../adapter';
1515
import type {
1616
MaterialBottomTabDescriptorMap,
1717
MaterialBottomTabNavigationConfig,
@@ -29,7 +29,7 @@ export default function MaterialBottomTabView({
2929
descriptors,
3030
...rest
3131
}: Props) {
32-
const buildLink = useLinkBuilder();
32+
const buildLink = useNavigationLink();
3333

3434
return (
3535
<BottomNavigation

yarn.lock

+39-37
Original file line numberDiff line numberDiff line change
@@ -3741,43 +3741,45 @@ __metadata:
37413741
languageName: node
37423742
linkType: hard
37433743

3744-
"@react-navigation/core@npm:^6.4.9":
3745-
version: 6.4.9
3746-
resolution: "@react-navigation/core@npm:6.4.9"
3744+
"@react-navigation/core@npm:^7.8.5":
3745+
version: 7.8.5
3746+
resolution: "@react-navigation/core@npm:7.8.5"
37473747
dependencies:
3748-
"@react-navigation/routers": "npm:^6.1.9"
3748+
"@react-navigation/routers": "npm:^7.3.5"
37493749
escape-string-regexp: "npm:^4.0.0"
3750-
nanoid: "npm:^3.1.23"
3750+
nanoid: "npm:3.3.8"
37513751
query-string: "npm:^7.1.3"
3752-
react-is: "npm:^16.13.0"
3753-
use-latest-callback: "npm:^0.1.5"
3752+
react-is: "npm:^18.2.0"
3753+
use-latest-callback: "npm:^0.2.1"
3754+
use-sync-external-store: "npm:^1.2.2"
37543755
peerDependencies:
3755-
react: "*"
3756-
checksum: 10c0/31b77d026a6064712ef275e66c891c6eaf82c6494b96391ba839dad99c40dd2635921ebab8af0a4df71042f889d7165695124f751804ce16012182573139c255
3756+
react: ">= 18.2.0"
3757+
checksum: 10c0/3c26d39cd1186a8a78805b6a19e9fcea9747b6c0fdeb470b5aced0dc56cd209040880a874df71731cb4b426b31aa6e4efb0e9d3ced0b52009afc5676352f7bb7
37573758
languageName: node
37583759
linkType: hard
37593760

3760-
"@react-navigation/native@npm:^6.1.2":
3761-
version: 6.1.7
3762-
resolution: "@react-navigation/native@npm:6.1.7"
3761+
"@react-navigation/native@npm:^7.1.6":
3762+
version: 7.1.6
3763+
resolution: "@react-navigation/native@npm:7.1.6"
37633764
dependencies:
3764-
"@react-navigation/core": "npm:^6.4.9"
3765+
"@react-navigation/core": "npm:^7.8.5"
37653766
escape-string-regexp: "npm:^4.0.0"
37663767
fast-deep-equal: "npm:^3.1.3"
3767-
nanoid: "npm:^3.1.23"
3768+
nanoid: "npm:3.3.8"
3769+
use-latest-callback: "npm:^0.2.1"
37683770
peerDependencies:
3769-
react: "*"
3771+
react: ">= 18.2.0"
37703772
react-native: "*"
3771-
checksum: 10c0/d1f6bc00782c8c40bc8a471fde7240cab41e627f7e4bba060aff118abc0496df006f2354a6d3a896cfc8048bbacb71eb682677ff9a3b5649e22efbe4b04e6bfe
3773+
checksum: 10c0/f0f78885662bb20d48e31a9f7ffae24c90de43b1b902aee87ffe2e9e510e69d0417202e20f97077d41ab42170665eb4c2815a271758134701175ffe39374e166
37723774
languageName: node
37733775
linkType: hard
37743776

3775-
"@react-navigation/routers@npm:^6.1.9":
3776-
version: 6.1.9
3777-
resolution: "@react-navigation/routers@npm:6.1.9"
3777+
"@react-navigation/routers@npm:^7.3.5":
3778+
version: 7.3.5
3779+
resolution: "@react-navigation/routers@npm:7.3.5"
37783780
dependencies:
3779-
nanoid: "npm:^3.1.23"
3780-
checksum: 10c0/5b58014cf29bb71c7dc01201e271d55f0ecfe6d38d064179eeff0fc0b5cb739d4d9906eb133f100d25fc674c72c24aa65d5f6bfc3d036d79f7c5d1936391c605
3781+
nanoid: "npm:3.3.8"
3782+
checksum: 10c0/f94f70391b5429707932a5c49014371815da20d715f15911c556bf606a8519d0f43382e0983c6c96cf2a40ddd8c2f8ecf38e33dcb9a65eb8cb02bdf377fccdd9
37813783
languageName: node
37823784
linkType: hard
37833785

@@ -11685,12 +11687,12 @@ __metadata:
1168511687
languageName: node
1168611688
linkType: hard
1168711689

11688-
"nanoid@npm:^3.1.23":
11689-
version: 3.3.6
11690-
resolution: "nanoid@npm:3.3.6"
11690+
"nanoid@npm:3.3.8":
11691+
version: 3.3.8
11692+
resolution: "nanoid@npm:3.3.8"
1169111693
bin:
1169211694
nanoid: bin/nanoid.cjs
11693-
checksum: 10c0/606b355960d0fcbe3d27924c4c52ef7d47d3b57208808ece73279420d91469b01ec1dce10fae512b6d4a8c5a5432b352b228336a8b2202a6ea68e67fa348e2ee
11695+
checksum: 10c0/4b1bb29f6cfebf3be3bc4ad1f1296fb0a10a3043a79f34fbffe75d1621b4318319211cd420549459018ea3592f0d2f159247a6f874911d6d26eaaadda2478120
1169411696
languageName: node
1169511697
linkType: hard
1169611698

@@ -12880,14 +12882,14 @@ __metadata:
1288012882
languageName: node
1288112883
linkType: hard
1288212884

12883-
"react-is@npm:^16.13.0, react-is@npm:^16.13.1, react-is@npm:^16.7.0, react-is@npm:^16.8.4":
12885+
"react-is@npm:^16.13.1, react-is@npm:^16.7.0, react-is@npm:^16.8.4":
1288412886
version: 16.13.1
1288512887
resolution: "react-is@npm:16.13.1"
1288612888
checksum: 10c0/33977da7a5f1a287936a0c85639fec6ca74f4f15ef1e59a6bc20338fc73dc69555381e211f7a3529b8150a1f71e4225525b41b60b52965bda53ce7d47377ada1
1288712889
languageName: node
1288812890
linkType: hard
1288912891

12890-
"react-is@npm:^18.3.1":
12892+
"react-is@npm:^18.2.0, react-is@npm:^18.3.1":
1289112893
version: 18.3.1
1289212894
resolution: "react-is@npm:18.3.1"
1289312895
checksum: 10c0/f2f1e60010c683479e74c63f96b09fb41603527cd131a9959e2aee1e5a8b0caf270b365e5ca77d4a6b18aae659b60a86150bb3979073528877029b35aecd2072
@@ -12938,7 +12940,7 @@ __metadata:
1293812940
"@callstack/react-theme-provider": "npm:^3.0.9"
1293912941
"@commitlint/config-conventional": "npm:^8.3.4"
1294012942
"@expo/vector-icons": "npm:^14.0.2"
12941-
"@react-navigation/native": "npm:^6.1.2"
12943+
"@react-navigation/native": "npm:^7.1.6"
1294212944
"@release-it/conventional-changelog": "npm:^1.1.0"
1294312945
"@testing-library/jest-native": "npm:^5.4.1"
1294412946
"@testing-library/react-native": "npm:11.5.0"
@@ -15295,21 +15297,21 @@ __metadata:
1529515297
languageName: node
1529615298
linkType: hard
1529715299

15298-
"use-latest-callback@npm:^0.1.5":
15299-
version: 0.1.6
15300-
resolution: "use-latest-callback@npm:0.1.6"
15300+
"use-latest-callback@npm:^0.2.1, use-latest-callback@npm:^0.2.3":
15301+
version: 0.2.3
15302+
resolution: "use-latest-callback@npm:0.2.3"
1530115303
peerDependencies:
1530215304
react: ">=16.8"
15303-
checksum: 10c0/514604ad33cb2f040ad3ece8ee787cc549ec92135ee12ebc6857bb309eeacf5d66426b3b94089842e8215a252d5ca6f04b059387f681688fb70ac37b238209f9
15305+
checksum: 10c0/dc87503f6279ce2980f78e1019231ba20d7509e9d17adac05285babe4d6ba6f68c52f4ef7b5ad777cbc2af9fbaaa09d7adb664ca556da0aebab9f020022880be
1530415306
languageName: node
1530515307
linkType: hard
1530615308

15307-
"use-latest-callback@npm:^0.2.3":
15308-
version: 0.2.3
15309-
resolution: "use-latest-callback@npm:0.2.3"
15309+
"use-sync-external-store@npm:^1.2.2":
15310+
version: 1.5.0
15311+
resolution: "use-sync-external-store@npm:1.5.0"
1531015312
peerDependencies:
15311-
react: ">=16.8"
15312-
checksum: 10c0/dc87503f6279ce2980f78e1019231ba20d7509e9d17adac05285babe4d6ba6f68c52f4ef7b5ad777cbc2af9fbaaa09d7adb664ca556da0aebab9f020022880be
15313+
react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0
15314+
checksum: 10c0/1b8663515c0be34fa653feb724fdcce3984037c78dd4a18f68b2c8be55cc1a1084c578d5b75f158d41b5ddffc2bf5600766d1af3c19c8e329bb20af2ec6f52f4
1531315315
languageName: node
1531415316
linkType: hard
1531515317

0 commit comments

Comments
 (0)