chore: upgrade React Native v76.9 and Storybook v10 and align deps with MetaMask Mobile#844
chore: upgrade React Native v76.9 and Storybook v10 and align deps with MetaMask Mobile#844georgewrmarshall wants to merge 10 commits intomainfrom
Conversation
|
All alerts resolved. Learn more about Socket for GitHub. This PR previously contained dependency changes with security issues that have been resolved, removed, or ignored. Ignoring alerts on:
|
📖 Storybook Preview |
af6beb2 to
25f832a
Compare
📖 Storybook Preview |
📖 Storybook Preview |
|
@SocketSecurity ignore-all |
6857f5e to
9ca35a5
Compare
📖 Storybook Preview |
There was a problem hiding this comment.
Cursor Bugbot has reviewed your changes and found 2 potential issues.
There are 4 total unresolved issues (including 2 from previous reviews).
Autofix Details
Bugbot Autofix prepared fixes for both issues found in the latest run.
- ✅ Fixed: Duplicate JSX transform from conflicting Babel presets
- Removed '@babel/preset-react' and set '@react-native/babel-preset' jsxRuntime: 'automatic' to prevent duplicate JSX transforms.
- ✅ Fixed: Missing reanimated
setUpTests()call after removing mock- Added require('react-native-reanimated').setUpTests() in jest.setup.js to initialize Reanimated for Jest.
Or push these changes by commenting:
@cursor push 884076eb43
Preview (884076eb43)
diff --git a/packages/design-system-react-native/babel.config.js b/packages/design-system-react-native/babel.config.js
--- a/packages/design-system-react-native/babel.config.js
+++ b/packages/design-system-react-native/babel.config.js
@@ -2,11 +2,10 @@
env: {
test: {
presets: [
- '@react-native/babel-preset',
[
- '@babel/preset-react',
+ '@react-native/babel-preset',
{
- runtime: 'automatic',
+ jsxRuntime: 'automatic',
},
],
[
diff --git a/packages/design-system-react-native/jest.setup.js b/packages/design-system-react-native/jest.setup.js
--- a/packages/design-system-react-native/jest.setup.js
+++ b/packages/design-system-react-native/jest.setup.js
@@ -1,3 +1,5 @@
+require('react-native-reanimated').setUpTests();
+
jest.mock('react-native-svg', () => {
const React = require('react');
const { View } = require('react-native');ad39389 to
52a9edb
Compare
📖 Storybook Preview |
There was a problem hiding this comment.
Cursor Bugbot has reviewed your changes and found 1 potential issue.
There are 5 total unresolved issues (including 4 from previous reviews).
Autofix Details
Bugbot Autofix prepared a fix for the issue found in the latest run.
- ✅ Fixed: Published package peer dependency pinned to exact React version
- Changed @metamask/design-system-twrnc-preset peerDependencies.react from "18.3.1" to the range ">=18.2.0" to match other packages and avoid strict pinning.
Or push these changes by commenting:
@cursor push 4e1d02e2a7
Preview (4e1d02e2a7)
diff --git a/packages/design-system-twrnc-preset/package.json b/packages/design-system-twrnc-preset/package.json
--- a/packages/design-system-twrnc-preset/package.json
+++ b/packages/design-system-twrnc-preset/package.json
@@ -81,7 +81,7 @@
},
"peerDependencies": {
"@metamask/design-tokens": "^8.0.0",
- "react": "18.3.1"
+ "react": ">=18.2.0"
},
"engines": {
"node": "^18.18 || >=20"You can send follow-ups to the cloud agent here.
📖 Storybook Preview |
There was a problem hiding this comment.
Cursor Bugbot has reviewed your changes and found 2 potential issues.
There are 7 total unresolved issues (including 5 from previous reviews).
Autofix Details
Bugbot Autofix prepared fixes for both issues found in the latest run.
- ✅ Fixed: Script finds zero stories due to glob path bug
- Adjusted base directory extraction to strip '**' from glob patterns so 'find' searches real directories and discovers stories.
- ✅ Fixed: GestureHandlerRootView wrapper removed from Storybook decorator
- Restored GestureHandlerRootView wrapper in preview decorator to enable gesture handling.
Or push these changes by commenting:
@cursor push b360e425fd
Preview (b360e425fd)
diff --git a/apps/storybook-react-native/.rnstorybook/preview.js b/apps/storybook-react-native/.rnstorybook/preview.js
--- a/apps/storybook-react-native/.rnstorybook/preview.js
+++ b/apps/storybook-react-native/.rnstorybook/preview.js
@@ -1,5 +1,6 @@
import React from 'react';
import { useColorScheme } from 'react-native';
+import { GestureHandlerRootView } from 'react-native-gesture-handler';
import { ThemeProvider, Theme } from '@metamask/design-system-twrnc-preset';
const ThemeDecorator = ({ children }) => {
@@ -7,9 +8,11 @@
const theme = colorScheme === 'dark' ? Theme.Dark : Theme.Light;
return (
- <ThemeProvider theme={theme}>
- {children}
- </ThemeProvider>
+ <GestureHandlerRootView style={{ flex: 1 }}>
+ <ThemeProvider theme={theme}>
+ {children}
+ </ThemeProvider>
+ </GestureHandlerRootView>
);
};
diff --git a/apps/storybook-react-native/scripts/generate-storybook-requires.js b/apps/storybook-react-native/scripts/generate-storybook-requires.js
--- a/apps/storybook-react-native/scripts/generate-storybook-requires.js
+++ b/apps/storybook-react-native/scripts/generate-storybook-requires.js
@@ -28,7 +28,19 @@
* @returns {string[]} Matching file paths relative to rnstorybookDir.
*/
function findStoryFiles(pattern, cwd) {
- const resolvedBase = path.resolve(cwd, path.dirname(pattern));
+ // Derive a real base directory from the glob pattern.
+ // path.dirname on a pattern with "**" yields a non-existent "src/**" folder.
+ // Strip "**" and everything after it to get the actual base directory.
+ let baseFromPattern = pattern;
+ const recursiveIdx = baseFromPattern.indexOf('**');
+ if (recursiveIdx !== -1) {
+ baseFromPattern = baseFromPattern.slice(0, recursiveIdx);
+ } else {
+ baseFromPattern = path.dirname(baseFromPattern);
+ }
+ // Remove any trailing path separators left after slicing
+ baseFromPattern = baseFromPattern.replace(/[\\/]+$/u, '') || '.';
+ const resolvedBase = path.resolve(cwd, baseFromPattern);
// Extract extensions from @(js|jsx|ts|tsx) pattern
const extMatch = pattern.match(/@\(([^)]+)\)/u);You can send follow-ups to the cloud agent here.
📖 Storybook Preview |
There was a problem hiding this comment.
Cursor Bugbot has reviewed your changes and found 1 potential issue.
There are 4 total unresolved issues (including 3 from previous reviews).
Autofix Details
Bugbot Autofix prepared a fix for the issue found in the latest run.
- ✅ Fixed: Pinned
reactversion mismatchesreact-domrange- Pinned react-dom to 18.3.1 in both Storybook apps to match the pinned react version.
Or push these changes by commenting:
@cursor push 556c18b76a
Preview (556c18b76a)
diff --git a/apps/storybook-react-native/package.json b/apps/storybook-react-native/package.json
--- a/apps/storybook-react-native/package.json
+++ b/apps/storybook-react-native/package.json
@@ -39,7 +39,7 @@
"@storybook/react-native": "^10",
"@types/react": "^18.2.0",
"@types/react-dom": "^18.2.0",
- "react-dom": "^18.2.0",
+ "react-dom": "18.3.1",
"react-native-safe-area-context": "^5.4.0",
"react-native-svg": "^15.11.1",
"react-native-svg-transformer": "^1.5.0",
diff --git a/apps/storybook-react/package.json b/apps/storybook-react/package.json
--- a/apps/storybook-react/package.json
+++ b/apps/storybook-react/package.json
@@ -36,7 +36,7 @@
"postcss": "^8.4.47",
"prop-types": "^15.8.1",
"react": "18.3.1",
- "react-dom": "^18.2.0",
+ "react-dom": "18.3.1",
"storybook": "^10.3.1",
"tailwindcss": "^3.0.0",
"typescript": "~5.2.2",You can send follow-ups to the cloud agent here.
📖 Storybook Preview |
There was a problem hiding this comment.
Cursor Bugbot has reviewed your changes and found 1 potential issue.
There are 4 total unresolved issues (including 3 from previous reviews).
Autofix Details
Bugbot Autofix prepared a fix for the issue found in the latest run.
- ✅ Fixed: Mismatched
useJssetting between Metro and prestorybook script- Set useJs: true in apps/storybook-react-native/metro.config.js to align with prestorybook’s --use-js generation and avoid TS/JS mismatch.
Or push these changes by commenting:
@cursor push cc6e2767ea
Preview (cc6e2767ea)
diff --git a/apps/storybook-react-native/metro.config.js b/apps/storybook-react-native/metro.config.js
--- a/apps/storybook-react-native/metro.config.js
+++ b/apps/storybook-react-native/metro.config.js
@@ -24,4 +24,5 @@
module.exports = withStorybook(defaultConfig, {
enabled: true,
+ useJs: true,
});You can send follow-ups to the cloud agent here.
📖 Storybook Preview |
📖 Storybook Preview |
|
@metamaskbot publish-preview |
## **Description** Cherry-picks the React Native `Icon` type fix out of [#844](#844) into a focused PR. This updates `IconProps` to align with `react-native-svg` (`Omit<SvgProps, 'color' | 'name'>` instead of `ViewProps`) and keeps `hitSlop` forwarding type-safe in `Icon.tsx`. Also adds migration guidance in `packages/design-system-react-native/MIGRATION.md` for consumers that were passing `View`-specific props to `Icon`. ## **Related issues** Fixes: ## **Manual testing steps** 1. Pull this branch. 2. Open `packages/design-system-react-native/src/components/Icon/Icon.types.ts` and confirm `IconProps` extends `Omit<SvgProps, 'color' | 'name'>`. 3. Open `packages/design-system-react-native/src/components/Icon/Icon.tsx` and confirm `hitSlop` is forwarded as `hitSlop ?? undefined`. 4. Open `packages/design-system-react-native/MIGRATION.md` and confirm the new Icon migration note under `From version 0.18.0 to 0.19.0`. ## **Screenshots/Recordings** N/A (type-only + docs update) ### **Before** N/A ### **After** N/A ## **Pre-merge author checklist** - [x] I've followed [MetaMask Contributor Docs](https://github.com/MetaMask/contributor-docs) - [x] I've completed the PR template to the best of my ability - [ ] I’ve included tests if applicable - [ ] I’ve documented my code using [JSDoc](https://jsdoc.app/) format if applicable - [ ] I’ve applied the right labels on the PR (see [labeling guidelines](https://github.com/MetaMask/metamask-extension/blob/develop/.github/guidelines/LABELING_GUIDELINES.md)). Not required for external contributors. ## **Pre-merge reviewer checklist** - [ ] I've manually tested the PR (e.g. pull and build branch, run the app, test code being changed). - [ ] 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] > **Medium Risk** > Mostly a type-surface change, but it can break TypeScript builds for consumers passing `ViewProps` (e.g., `onLayout`, `testID`) directly to `Icon` and may require small refactors. > > **Overview** > Aligns the React Native `Icon` API surface with `react-native-svg` by changing `IconProps` to extend `Omit<SvgProps, 'color' | 'name'>` (instead of `ViewProps`), which removes `View`-specific props from the `Icon` type. > > Updates `Icon` to destructure and forward `hitSlop` as `hitSlop ?? undefined` for stricter SVG typing, and documents the type-breaking migration path in `MIGRATION.md` (wrap `Icon` in a `View` for layout/view props). > > <sup>Reviewed by [Cursor Bugbot](https://cursor.com/bugbot) for commit 14817d4. Bugbot is set up for automated code reviews on this repo. Configure [here](https://www.cursor.com/dashboard/bugbot).</sup> <!-- /CURSOR_SUMMARY -->
|
Preview builds have been published. See these instructions for more information about preview builds. Expand for full list of packages and versions. |
… upgrading storybook v10
ba86146 to
568da7f
Compare
📖 Storybook Preview |
| }, | ||
| }; | ||
| })(); | ||
| const defaultConfig = getDefaultConfig(__dirname); |
There was a problem hiding this comment.
This starts from Expo default Metro config rather than rebuilding resolver settings by hand, which keeps the app aligned with Expo monorepo-aware defaults for watch folders and workspace module resolution. That matches the Storybook guidance to wrap an existing Metro config instead of replacing it: https://storybookjs.github.io/react-native/docs/intro/configuration/metro-configuration/
📖 Storybook Preview |
| "expo-system-ui": "~2.4.0", | ||
| "react-native-reanimated": "~3.3.0", | ||
| "uuid": "^3.0.0" | ||
| "expo": "~52.0.49", |
There was a problem hiding this comment.
This dependency block is intentionally split so the app owns the native runtime pieces it actually boots with: Expo, React Native, React, gesture-handler, and reanimated stay aligned with Mobile, while Storybook v10 and its on-device addons live in devDependencies as tooling. That keeps Yarn constraints happy, avoids relying on root-hoisted native modules, and makes this app a realistic client for validating @metamask/design-system-react-native behavior.
|
|
||
| module.exports = { | ||
| assets: [path.resolve(__dirname, '../assets/fonts')], | ||
| assets: [path.resolve(__dirname, 'fonts')], |
There was a problem hiding this comment.
Looks like this was always wrong?
| "expo-system-ui": "~2.4.0", | ||
| "react-native-reanimated": "~3.3.0", | ||
| "uuid": "^3.0.0" | ||
| "expo": "~52.0.49", |
There was a problem hiding this comment.
These runtime dependencies now describe the actual native environment the app boots with instead of depending on root hoists or stale Expo 49-era transitive installs. Keeping Expo, React, React Native, gesture-handler, and reanimated aligned here makes this app a realistic client for validating design-system-react-native against the same compatibility floor Mobile is targeting.
| "@storybook/addon-ondevice-actions": "6.5", | ||
| "@storybook/addon-ondevice-controls": "6.5", | ||
| "@storybook/react-native": "6.5", | ||
| "@babel/core": "^7.25.2", |
There was a problem hiding this comment.
The devDependency block is now clearly the Storybook/tooling layer: Storybook v10 packages, SVG transform support, and test/build helpers live here while the app runtime stays in dependencies. That split matters because this workspace is an app, not a published library, so reviewers can read this file as runtime surface versus local development surface.
| "peerDependencies": { | ||
| "react": "^18.2.0", | ||
| "react-native": "0.72.15", | ||
| "react-native-gesture-handler": "~2.12.0", |
There was a problem hiding this comment.
Dropping peerDependencies makes this manifest read like a private app again instead of a consumable package. The compatibility contract belongs on @metamask/design-system-react-native; this app should pin the concrete versions it runs and test against, not ask an external consumer to provide them.
| "dependenciesMeta": { | ||
| "uuid": {} | ||
| }, | ||
| "peerDependencies": { |
There was a problem hiding this comment.
Removing dependenciesMeta for uuid is part of the same cleanup: uuid is no longer part of the Storybook runtime path, so the app no longer needs package-manager hints to special-case it. That keeps the manifest focused on the modules this native client actually uses after the Storybook v10 migration.
| @@ -35,8 +35,8 @@ | |||
| "playwright": "^1.52.0", | |||
There was a problem hiding this comment.
Aligns deps and passes yarn constraints
| PanGestureHandler, | ||
| PanGestureHandlerGestureEvent, | ||
| } from 'react-native-gesture-handler'; | ||
| // eslint-disable-next-line import-x/default |
There was a problem hiding this comment.
Removing unused eslint disable comment
| } from 'react'; | ||
| import { Dimensions, View } from 'react-native'; | ||
| import type { LayoutChangeEvent, StyleProp, ViewStyle } from 'react-native'; | ||
| // eslint-disable-next-line import-x/default |
There was a problem hiding this comment.
Removing unused eslint disable comment
📖 Storybook Preview |
📖 Storybook Preview |
📖 Storybook Preview |
| "deepmerge": "^4.2.2", | ||
| "jest": "^29.7.0", | ||
| "react": "^18.2.0", | ||
| "react": "18.3.1", |
There was a problem hiding this comment.
Aligns deps and passes yarn constraints
| "jest": "^29.7.0", | ||
| "postcss": "^8.4.47", | ||
| "react": "^18.2.0", | ||
| "react": "18.3.1", |
There was a problem hiding this comment.
Aligns deps and passes yarn constraints
| }, | ||
| transformIgnorePatterns: [ | ||
| 'node_modules/(?!react-native|@react-native|react-native-reanimated|@react-navigation)', | ||
| 'node_modules/(?!(react-native|@react-native|react-native-reanimated|@react-navigation|react-native-jazzicon|react-native-gesture-handler|react-native-safe-area-context)/)', |
There was a problem hiding this comment.
react-native-safe-area-context is included in transformIgnorePatterns because its official Jest mock is distributed from the package and needs Babel/Jest to transpile it in node_modules. This follows the safe-area testing guidance here: https://appandflow.github.io/react-native-safe-area-context/testing/
| '\\.(css|less|scss)$': 'identity-obj-proxy', | ||
| '\\.svg$': '<rootDir>/__mocks__/svgMock.js', | ||
| }, | ||
| setupFiles: ['react-native-gesture-handler/jestSetup'], |
There was a problem hiding this comment.
react-native-gesture-handler/jestSetup keeps the Jest environment aligned with Gesture Handler's supported test setup instead of relying on ad hoc mocks in component tests. Upstream guidance is here: https://docs.swmansion.com/react-native-gesture-handler/docs/guides/testing/
| @@ -1,5 +1,4 @@ | |||
| // Import built-in Jest matchers from React Native Testing Library | |||
| import '@testing-library/react-native/extend-expect'; | |||
| require('react-native-reanimated').setUpTests(); | |||
There was a problem hiding this comment.
Reanimated now uses setUpTests() from the library itself, which is the supported way to initialize its Jest environment after the RN upgrade. That keeps animation-related assumptions centralized in upstream setup instead of maintaining a custom global mock here: https://docs.swmansion.com/react-native-reanimated/docs/guides/testing/
| // Silence warnings related to the Animated API | ||
| jest.mock('react-native/Libraries/Animated/NativeAnimatedHelper'); | ||
|
|
||
| jest.mock( |
There was a problem hiding this comment.
The suite now uses react-native-safe-area-context's official Jest mock and then reapplies zero insets/frame defaults before each test because some specs override the module state at runtime. That keeps the baseline deterministic while still following the library's documented mock entrypoint: https://appandflow.github.io/react-native-safe-area-context/testing/
| @@ -117,13 +117,10 @@ | |||
| "lodash": "^4.17.21", | |||
There was a problem hiding this comment.
react, react-native, and twrnc are removed from the root devDependencies because Storybook React Native now declares and resolves its own runtime stack inside the app workspace instead of relying on hoisted fallbacks. That keeps the monorepo aligned with Yarn constraints and avoids masking missing app-level dependencies behind the root package.json.
| 'apps/storybook-react/tailwind.config.js', | ||
| // storybook react native | ||
| 'apps/storybook-react-native/.storybook/**/*.js', | ||
| 'apps/storybook-react-native/.rnstorybook/**', |
There was a problem hiding this comment.
The React Native app now generates and owns its config under .rnstorybook, so the old .storybook ignore was replaced instead of expanded. That also leaves .storybook available for a future web Storybook setup, which matches the Storybook template split between .rnstorybook and .storybook: https://github.com/dannyhw/expo-template-storybook

Description
Upgrades the React Native Storybook app from Storybook 6.5 → v10 and aligns native dependencies with MetaMask Mobile (RN 0.76.9, React 18.3.1). This is a major infrastructure upgrade that modernizes the mobile component development environment.
Key changes
Storybook v10 Migration:
.storybook/to.rnstorybook/(SB10 default config path)view.getStorybookUI()with AsyncStorage persistence^10)scripts/generate-storybook-requires.jsreplacessb-rn-get-storiesto avoid Metrorequire.contextcrashes in Expo 52Dependency Alignment with MetaMask Mobile:
expo~52.0.47~52.0.49expo-font~13.0.4~13.0.4react18.3.118.3.1react-native0.76.90.76.9react-native-reanimated^3.17.2~3.17.2react-native-gesture-handler^2.25.0^2.25.0react-native-safe-area-context^5.4.0^5.4.0react-native-svg^15.11.1^15.10.1@react-native-async-storage/async-storage^1.23.1^1.23.1@react-native-community/datetimepicker^8.5.18.4.4Build & Config Changes:
hoistingLimits: "workspaces"— was causing dual-React copies in the monorepo, breaking hookstransform-inline-environment-variablesbabel plugin — conflicts withbabel-preset-expometro.config.jswithwithStorybookwrapper for SB10 Metro integrationmetro-react-native-babel-presetwith@react-native/babel-preset(RN 0.76 standard)assets/fonts/directory, added SemiBold variantsios/from git tracking (generated byexpo prebuild, already in.gitignore).rnstorybook/**to ESLint ignores (Metro-processed files)Known Issues (documented in
UPGRADE-STATUS.md)@gorhom/bottom-sheethas a "property is not writable" Metro compatibility issue affecting 2 stories. Other stories load fine.Related issues
Fixes: #843
Manual testing steps
First-time setup after pulling
Day-to-day development
Verification steps
Examples/WalletHomestory — should render the full wallet mockupyarn testto verify no test regressionsyarn lintto verify no lint errorsScreenshots/Recordings
After
Storybook v10 — full component showcase with on-device controls in android and ios
Screen.Recording.2026-04-16.at.1.02.23.PM.mov
Preview packages working in mobile in both Android and iOS
react.native.upgrade720.mov
Pre-merge author checklist
Pre-merge reviewer checklist
Note
High Risk
High risk due to major upgrades of the React Native Storybook app (Storybook v10, Expo 52, RN 0.76.9, React 18.3.1) plus related Metro/Jest/Babel config changes that can break builds, bundling, or tests across the monorepo.
Overview
Upgrades the React Native Storybook app to Storybook v10 and migrates configuration/entrypoints from
.storybook/to.rnstorybook/, including a newview.getStorybookUI()bootstrap with AsyncStorage persistence and an updated decorator-based preview setup.Aligns the Storybook RN runtime and several workspace packages to MetaMask Mobile versions (Expo 52, RN
0.76.9, React18.3.1) and updates Metro integration (wraps config withwithStorybook, keeps SVG transformer support). Also refreshes native app config (app.jsonidentifiers,expo-fontplugin, new architecture) and updates ignores for generated requires +ios//android/prebuild outputs.Modernizes RN package test/build tooling by switching DSRN test Babel preset to
@react-native/babel-preset, updating Jest transforms/ignored modules, and adjusting reanimated/gesture-handler test setup; includes minor cleanup of lint suppressions in reanimated imports.Reviewed by Cursor Bugbot for commit 78128fe. Bugbot is set up for automated code reviews on this repo. Configure here.