Skip to content

Commit 2dc06a8

Browse files
authored
chore: migrate StackNavigationProp types to native-stack equivalents (#32119)
<!-- Please submit this PR as a draft initially. Do not mark it as "Ready for review" until this PR meets the canonical Definition of Ready For Review in `docs/readme/ready-for-review.md`. In short: the template must be materially complete (not just section titles present), all status checks must be currently passing, and the only expected follow-up commits must be reviewer-driven. --> <!-- mms-check directive vocabulary — read by .github/scripts/shared/pr-template-checks.ts at module load to build the validation plan. Directives are invisible in rendered markdown and must NOT be removed or edited without updating the validator registry. type=text Section must contain non-placeholder prose. type=changelog Section must have a valid CHANGELOG entry: line. type=issue-link Section must have a Fixes:/Closes:/Refs: line with a value. type=manual-testing Section must have real testing steps or an explicit N/A. type=screenshot Section must have evidence (image/URL) or an explicit N/A. type=checklist Section must have all checkboxes consciously checked. required=true|false Whether a missing/invalid section runs the validator at all. blocking=true|false Whether a failure of this check fails the CI workflow. Default: false — failures are shown as warnings in the sticky comment but do not block the PR. Sections without a directive are checked for structural presence only. --> ## **Description** <!-- mms-check: type=text required=true --> Replaces remaining @react-navigation/stack type usage with native-stack-aligned types now that the app runs on createNativeStackNavigator. This PR is type-only for production code — no navigator or screen transition behavior changes. - Migrate StackNavigationProp call sites to AppNavigationProp, NavigationProp, or NativeStackNavigationProp as appropriate - Update AppNavigationProp to extend NativeStackNavigationProp so stack APIs (replace, push, pop) type-check correctly - Update test/storybook render helpers to use createNativeStackNavigator ## **Changelog** <!-- mms-check: type=changelog required=true blocking=true --> <!-- If this PR is not End-User-Facing and should not show up in the CHANGELOG, you can choose to either: 1. Write `CHANGELOG entry: null` 2. Label with `no-changelog` If this PR is End-User-Facing, please write a short User-Facing description in the past tense like: `CHANGELOG entry: Added a new tab for users to see their NFTs` `CHANGELOG entry: Fixed a bug that was causing some NFTs to flicker` (This helps the Release Engineer do their job more quickly and accurately) --> CHANGELOG entry:null ## **Related issues** <!-- mms-check: type=issue-link required=true --> Fixes: https://consensyssoftware.atlassian.net/browse/MCWP-586 ## **Manual testing steps** <!-- mms-check: type=manual-testing required=true --> N/A - the changes are limited to tests and type changes, no functional changes ## **Screenshots/Recordings** <!-- mms-check: type=screenshot required=true --> <!-- If applicable, add screenshots and/or recordings to visualize the before and after of your change. --> n/a ### **Before** <!-- [screenshots/recordings] --> ### **After** <!-- [screenshots/recordings] --> ## **Pre-merge author checklist** <!-- mms-check: type=checklist required=true --> <!-- Every checklist item must be consciously assessed before marking this PR as "Ready for review". A checked box means you deliberately considered that responsibility, not that you literally performed every action listed. Unchecked boxes are ambiguous: they are not an implicit "N/A" and they are not a silent "skip". See `docs/readme/ready-for-review.md` for the full checklist semantics. --> - [x] I've followed [MetaMask Contributor Docs](https://github.com/MetaMask/contributor-docs) and [MetaMask Mobile Coding Standards](https://github.com/MetaMask/metamask-mobile/blob/main/.github/guidelines/CODING_GUIDELINES.md). - [x] I've completed the PR template to the best of my ability - [x] I've included tests if applicable - [x] I've documented my code using [JSDoc](https://jsdoc.app/) format if applicable - [x] I've applied the right labels on the PR (see [labeling guidelines](https://github.com/MetaMask/metamask-mobile/blob/main/.github/guidelines/LABELING_GUIDELINES.md)). Not required for external contributors. #### Performance checks (if applicable) - [x] I've tested on Android - Ideally on a mid-range device; emulator is acceptable - [x] I've tested with a power user scenario - Use these [power-user SRPs](https://consensyssoftware.atlassian.net/wiki/spaces/TL1/pages/edit-v2/401401446401?draftShareId=9d77e1e1-4bdc-4be1-9ebb-ccd916988d93) to import wallets with many accounts and tokens - [x] I've instrumented key operations with Sentry traces for production performance metrics - See [`trace()`](/app/util/trace.ts) for usage and [`addToken`](/app/components/Views/AddAsset/components/AddCustomToken/AddCustomToken.tsx#L274) for an example For performance guidelines and tooling, see the [Performance Guide](https://consensyssoftware.atlassian.net/wiki/spaces/TL1/pages/400085549067/Performance+Guide+for+Engineers). ## **Pre-merge reviewer checklist** <!-- Reviewer checklist items follow the same semantics as the author checklist: an unchecked box is ambiguous, a checked box means the reviewer consciously assessed that responsibility. See `docs/readme/ready-for-review.md`. --> - [x] I've manually tested the PR (e.g. pull and build branch, run the app, test code being changed). - [x] I confirm that this PR addresses all acceptance criteria described in the ticket it closes and includes the necessary testing evidence such as recordings and or screenshots. <!-- CURSOR_SUMMARY --> --- > [!NOTE] > **Low Risk** > Mostly compile-time and test harness changes; the only runtime tweak is deferring Ramp order-history navigation until a sheet closes, which is low risk. > > **Overview** > Finishes the **native-stack migration** for typing and test infrastructure now that the app uses `createNativeStackNavigator`: **`@react-navigation/stack` is removed** from dependencies and call sites. > > Production screens and hooks swap loose `StackNavigationProp` / `ParamListBase` usage for **`AppNavigationProp`**, **`AppStackNavigationProp`**, or **`NavigationProp`** from `NavigationService/types`. **`AppStackNavigationProp`** is added for stack-only APIs (`replace`, `push`, `pop`) with the same safe `getState()` typing as **`AppNavigationProp`**. Legacy **JS stack navigator option presets** in `clearStackNavigatorOptions.ts` are dropped in favor of **`clearNativeStackNavigatorOptions`**. > > Tests, Storybook, and shared **`renderWithProvider` / component-view renderers** use **`createNativeStackNavigator`** and mock **`react-native-screens`** in Jest so native-stack mounts cleanly. **Ramp Settings** defers “View order history” navigation until the bottom sheet **`onCloseBottomSheet` callback** runs. **Earn withdraw** tests press **Done** before asserting the TRON **Unstake** button. > > <sup>Reviewed by [Cursor Bugbot](https://cursor.com/bugbot) for commit eac64c1. Bugbot is set up for automated code reviews on this repo. Configure [here](https://www.cursor.com/dashboard/bugbot).</sup> <!-- /CURSOR_SUMMARY -->
1 parent 2f45c8a commit 2dc06a8

70 files changed

Lines changed: 202 additions & 221 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

.storybook/decorators/withNavigation.tsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
import React from 'react';
2-
import { createStackNavigator } from '@react-navigation/stack';
2+
import { createNativeStackNavigator } from '@react-navigation/native-stack';
33
import { NavigationContainer } from '@react-navigation/native';
44

5-
const StoryBookStack = createStackNavigator();
5+
const StoryBookStack = createNativeStackNavigator();
66

77
const withNavigation = (story: any) => {
88
const StorybookScreen = () => story();

app/components/Nav/Main/MainNavigator.test.tsx

Lines changed: 0 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -10,16 +10,6 @@ jest.mock('react-native-device-info', () => ({
1010
getVersion: jest.fn(() => '7.72.0'),
1111
}));
1212

13-
jest.mock('@react-navigation/stack', () => ({
14-
createStackNavigator: jest.fn().mockReturnValue({
15-
Navigator: 'Navigator',
16-
Screen: 'Screen',
17-
}),
18-
TransitionPresets: {
19-
ModalSlideFromBottomIOS: {},
20-
},
21-
}));
22-
2313
jest.mock('@react-navigation/native-stack', () => ({
2414
createNativeStackNavigator: jest.fn().mockReturnValue({
2515
Navigator: 'Navigator',

app/components/UI/Assets/PriceAlerts/Views/CreatePriceAlertView/CreatePriceAlertView.tsx

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ import {
1919
useRoute,
2020
type RouteProp,
2121
} from '@react-navigation/native';
22-
import type { StackNavigationProp } from '@react-navigation/stack';
22+
import type { AppStackNavigationProp } from '../../../../../../core/NavigationService/types';
2323
import { SafeAreaView } from 'react-native-safe-area-context';
2424
import {
2525
Box,
@@ -107,8 +107,7 @@ const viewStyles = StyleSheet.create({
107107
const CreatePriceAlertView: React.FC = () => {
108108
const tw = useTailwind();
109109
const { colors, brandColors } = useTheme();
110-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
111-
const navigation = useNavigation<StackNavigationProp<any>>();
110+
const navigation = useNavigation<AppStackNavigationProp>();
112111
const route =
113112
useRoute<
114113
RouteProp<

app/components/UI/Assets/PriceAlerts/Views/ManagePriceAlertsView/ManagePriceAlertsView.tsx

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ import {
1919
useRoute,
2020
type RouteProp,
2121
} from '@react-navigation/native';
22-
import type { StackNavigationProp } from '@react-navigation/stack';
22+
import type { AppStackNavigationProp } from '../../../../../../core/NavigationService/types';
2323
import { SafeAreaView } from 'react-native-safe-area-context';
2424
import {
2525
Box,
@@ -66,8 +66,7 @@ const ManagePriceAlertsView: React.FC = () => {
6666
const { colors, brandColors } = useTheme();
6767
const queryClient = useQueryClient();
6868
const { toastRef } = useContext(ToastContext);
69-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
70-
const navigation = useNavigation<StackNavigationProp<any>>();
69+
const navigation = useNavigation<AppStackNavigationProp>();
7170
const route =
7271
useRoute<
7372
RouteProp<

app/components/UI/Bridge/components/BatchSellFinalReviewModal/index.tsx

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import { useNavigation } from '@react-navigation/native';
2-
import { StackNavigationProp } from '@react-navigation/stack';
2+
import type { AppStackNavigationProp } from '../../../../../core/NavigationService/types';
33
import React, { useCallback, useMemo, useRef, useState } from 'react';
44
import { Pressable } from 'react-native';
55
import { useDispatch, useSelector } from 'react-redux';
@@ -290,8 +290,7 @@ function NetworkFeeRow({
290290

291291
export function BatchSellFinalReviewModal() {
292292
const dispatch = useDispatch();
293-
const navigation =
294-
useNavigation<StackNavigationProp<Record<string, object | undefined>>>();
293+
const navigation = useNavigation<AppStackNavigationProp>();
295294
const selectedTokens = useSelector(selectBatchSellSourceTokens);
296295
const isSubmittingTx = useSelector(selectIsSubmittingTx);
297296
const batchSellQuoteData = useBatchSellQuoteData({

app/components/UI/Bridge/components/BatchSellMinimumReceivedInfoModal/index.tsx

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import { useNavigation } from '@react-navigation/native';
2-
import { StackNavigationProp } from '@react-navigation/stack';
2+
import type { AppStackNavigationProp } from '../../../../../core/NavigationService/types';
33
import React from 'react';
44
import {
55
BottomSheet,
@@ -18,8 +18,7 @@ import { BatchSellMinimumReceivedInfoModalParams } from './BatchSellMinimumRecei
1818
import { useElevatedSurface } from '../../../../../util/theme/themeUtils';
1919

2020
export function BatchSellMinimumReceivedInfoModal() {
21-
const navigation =
22-
useNavigation<StackNavigationProp<Record<string, object | undefined>>>();
21+
const navigation = useNavigation<AppStackNavigationProp>();
2322
const { sourceModal } = useParams<BatchSellMinimumReceivedInfoModalParams>();
2423
const handleBack = sourceModal
2524
? () => navigation.replace(sourceModal.screen, sourceModal.params)

app/components/UI/Bridge/components/BatchSellNetworkFeeInfoModal/index.tsx

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import { useNavigation } from '@react-navigation/native';
2-
import { StackNavigationProp } from '@react-navigation/stack';
2+
import type { AppStackNavigationProp } from '../../../../../core/NavigationService/types';
33
import React from 'react';
44
import {
55
BottomSheet,
@@ -18,8 +18,7 @@ import { BatchSellNetworkFeeInfoModalParams } from './BatchSellNetworkFeeInfoMod
1818
import { useElevatedSurface } from '../../../../../util/theme/themeUtils';
1919

2020
export function BatchSellNetworkFeeInfoModal() {
21-
const navigation =
22-
useNavigation<StackNavigationProp<Record<string, object | undefined>>>();
21+
const navigation = useNavigation<AppStackNavigationProp>();
2322
const { sourceModal } = useParams<BatchSellNetworkFeeInfoModalParams>();
2423
const handleBack = sourceModal
2524
? () => navigation.replace(sourceModal.screen, sourceModal.params)

app/components/UI/Bridge/components/BatchSellQuoteDetailsModal/index.tsx

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import { useNavigation } from '@react-navigation/native';
2-
import { StackNavigationProp } from '@react-navigation/stack';
2+
import type { AppStackNavigationProp } from '../../../../../core/NavigationService/types';
33
import React, { useMemo } from 'react';
44
import { useSelector } from 'react-redux';
55
import {
@@ -20,8 +20,7 @@ import { strings } from '../../../../../../locales/i18n';
2020
import { useElevatedSurface } from '../../../../../util/theme/themeUtils';
2121

2222
export function BatchSellQuoteDetailsModal() {
23-
const navigation =
24-
useNavigation<StackNavigationProp<Record<string, object | undefined>>>();
23+
const navigation = useNavigation<AppStackNavigationProp>();
2524
const sourceTokens = useSelector(selectBatchSellSourceTokens);
2625
const surfaceClass = useElevatedSurface();
2726
const batchSellQuoteData = useBatchSellQuoteData({

app/components/UI/Bridge/components/MissingPriceModal/index.tsx

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import React, { useCallback, useRef, useState } from 'react';
22
import { useSelector } from 'react-redux';
33
import { useNavigation } from '@react-navigation/native';
4-
import { StackNavigationProp } from '@react-navigation/stack';
4+
import type { AppNavigationProp } from '../../../../../core/NavigationService/types';
55
import { MetaMetricsSwapsEventSource } from '@metamask/bridge-controller';
66
import { strings } from '../../../../../../locales/i18n';
77
import { useParams } from '../../../../../util/navigation/navUtils';
@@ -32,8 +32,7 @@ export interface MissingPriceModalParams {
3232
}
3333

3434
export const MissingPriceModal = () => {
35-
const navigation =
36-
useNavigation<StackNavigationProp<Record<string, object | undefined>>>();
35+
const navigation = useNavigation<AppNavigationProp>();
3736
const sheetRef = useRef<BottomSheetRef>(null);
3837
const [loading, setLoading] = useState(false);
3938
const { location } = useParams<MissingPriceModalParams>();

app/components/UI/Bridge/components/TokenWarningModal/index.tsx

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ import { useSelector } from 'react-redux';
33
// Must use this to make sure scroll works inside a bottom sheet on Android
44
import { ScrollView } from 'react-native-gesture-handler';
55
import { useNavigation } from '@react-navigation/native';
6-
import { StackNavigationProp } from '@react-navigation/stack';
6+
import type { AppStackNavigationProp } from '../../../../../core/NavigationService/types';
77
import { MetaMetricsSwapsEventSource } from '@metamask/bridge-controller';
88
import BottomSheet, {
99
BottomSheetRef,
@@ -90,8 +90,7 @@ export const getTokenWarningContent = (
9090
};
9191

9292
export const TokenWarningModal = () => {
93-
const navigation =
94-
useNavigation<StackNavigationProp<Record<string, object | undefined>>>();
93+
const navigation = useNavigation<AppStackNavigationProp>();
9594
const sheetRef = useRef<BottomSheetRef>(null);
9695
const [loading, setLoading] = useState(false);
9796

0 commit comments

Comments
 (0)