Skip to content

fix(rn): web rendering compatibility for BottomSheet, BottomSheetOverlay, Icon, and animated components#1187

Merged
georgewrmarshall merged 6 commits into
mainfrom
fix/rn-web-storybook-component-fixes-2
May 27, 2026
Merged

fix(rn): web rendering compatibility for BottomSheet, BottomSheetOverlay, Icon, and animated components#1187
georgewrmarshall merged 6 commits into
mainfrom
fix/rn-web-storybook-component-fixes-2

Conversation

@georgewrmarshall

@georgewrmarshall georgewrmarshall commented May 25, 2026

Copy link
Copy Markdown
Contributor

Description

Several @metamask/design-system-react-native components and stories required small compatibility fixes to render correctly in the web Storybook environment introduced in #1134. All changes are safe no-ops or functional equivalents on iOS and Android.

Component fixes:

  • BottomSheet — Guard the BackHandler useEffect behind Platform.OS === 'android'. The BackHandler API is unavailable in react-native-web; without the guard the effect throws during initialization. iOS is unaffected (no hardware back button); Android BackHandler behaviour is unchanged.

  • BottomSheetDialog — Pass explicit [] deps to useAnimatedStyle. In Reanimated the deps array controls when the worklet function is re-created in JS, not when it updates on the UI thread — shared values are tracked automatically regardless. The [] prevents unnecessary worklet re-creation on every parent render and is the correct pattern.

  • BottomSheetOverlay — Replace useAnimatedValue(0) with useRef(new Animated.Value(0)).current. The two are functionally identical; the useRef form works across all RN versions and environments. Uses react-native's Animated, not Reanimated.

  • Icon — Flatten the style array via StyleSheet.flatten before passing to the SVG component. react-native-svg does not accept style arrays in all environments. StyleSheet.flatten produces identical visual output on iOS and Android.

  • ButtonAnimated, Spinner — Same [] deps fix for useAnimatedStyle as BottomSheetDialog.

Story import fixes:

  • HeaderSearch, Blockies, Jazzicon, Maskicon stories — Import TextVariant, TextColor, FontWeight from the owning Text component index instead of the legacy ../types barrel, following the architecture rule to import shared consts from their owning module.

Related issues

Part of: #1134

Manual testing steps

  1. Checkout this branch
  2. Run yarn storybook:ios — verify BottomSheet, Icon, Spinner, and ButtonAnimated stories render identically to main
  3. Run yarn storybook:android — verify same
  4. Run yarn workspace @metamask/design-system-react-native test — all tests pass

Screenshots/Recordings

No visual change expected — added screenshots to show in comments

Pre-merge author checklist

  • I've followed MetaMask Contributor Docs
  • 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 format if applicable
  • I've applied the right labels on the PR (see labeling guidelines). 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.

Note

Low Risk
Changes are platform guards and equivalent animation/style patterns for web; Android back handling and native visuals are intended to stay the same, with tests updated for flattened Icon styles.

Overview
Makes React Native design-system components and Storybook setups safe to run in web / react-native-web without changing intended behavior on iOS and Android.

Bottom sheet stack: BottomSheet only registers BackHandler when Platform.OS === 'android' (avoids web init crashes). BottomSheetOverlay uses useRef(new Animated.Value(0)) instead of useAnimatedValue. BottomSheetDialog, ButtonAnimated, and Spinner pass an empty dependency list to useAnimatedStyle so worklets are not recreated every render.

Icons: Icon flattens tailwind + custom styles with StyleSheet.flatten before passing them to SVGs; related unit tests now assert a single style object.

Storybook / tooling: RN Storybook Metro config is reformatted only. ESLint ignores for apps/storybook-react-native are tightened from broad globs to named Storybook and Tailwind config files. Several stories import TextVariant / TextColor / FontWeight from the Text component instead of the legacy types barrel.

Reviewed by Cursor Bugbot for commit 17c4678. Bugbot is set up for automated code reviews on this repo. Configure here.

…lay, Icon, and animated components

- BottomSheet: guard BackHandler useEffect behind Platform.OS === 'android' to
  avoid crashes in environments where BackHandler is unavailable
- BottomSheetDialog: pass explicit [] deps to useAnimatedStyle so the worklet
  is not re-created on every render (shared value tracking is unaffected)
- BottomSheetOverlay: replace useAnimatedValue with useRef(new Animated.Value())
  for broader compatibility; the two are functionally equivalent
- Icon: flatten style array via StyleSheet.flatten before passing to SVG to
  support environments that do not accept style arrays on SVG elements
- ButtonAnimated, Spinner: pass explicit [] deps to useAnimatedStyle (same
  reason as BottomSheetDialog)
- HeaderSearch, Blockies, Jazzicon, Maskicon stories: import TextVariant,
  TextColor, FontWeight from their owning Text component index instead of the
  legacy types barrel
@github-actions

Copy link
Copy Markdown
Contributor

📖 Storybook Preview


// Dismiss the sheet when Android back button is pressed.
useEffect(() => {
if (Platform.OS !== 'android') {

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The BackHandler API is not implemented by react-native-web, so without this guard the useEffect throws during initialization in the web Storybook environment. The early return is safe on iOS (no hardware back button exists) and leaves Android behaviour completely unchanged — the rest of the effect still runs on Android and the BackHandler listener is registered and removed as before.

);

const sheetStyle = useMemo(
() => [

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The explicit [] deps array tells Reanimated when to re-create the worklet function in JS — it does not affect when the animation itself updates. Reanimated tracks currentYOffset as a shared value on the UI thread regardless of the deps array, so slide animations continue to work correctly. Without the deps argument the worklet is re-created on every parent render, which is unnecessary. The [] is also required for the web Storybook mock, which calls the updater once and returns the result directly.

}) => {
const tw = useTailwind();
const opacityVal = useAnimatedValue(0);
const opacityVal = useRef(new Animated.Value(0)).current;

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

useAnimatedValue was added in React Native 0.73 as a hook wrapper around exactly this pattern. The useRef form is functionally identical and works across all RN versions and environments, including react-native-web. This uses the core react-native Animated API — not Reanimated — so the Reanimated mock in the web Storybook does not affect this component at all.

TWCLASSMAP_ICON_SIZE_DIMENSION[size],
twClassName,
);
const svgStyle = StyleSheet.flatten([twStyle, style]);

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

react-native-svg does not accept a style array on SVG elements in all environments — passing one directly causes a crash in react-native-web. StyleSheet.flatten merges the array into a single plain object, which is accepted everywhere. On iOS and Android the visual output is identical; StyleSheet.flatten is a zero-cost utility that handles undefined entries and nested arrays correctly.

transform: [{ scale: animation.value }],
};
});
}, []);

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same reasoning as BottomSheetDialog: the [] deps prevent the worklet from being re-created on every render. The scale animation still responds to animation shared value changes on the UI thread — deps only gate worklet re-creation in JS.

const animatedStyle = useAnimatedStyle(() => ({
transform: [{ rotate: `${rotation.value % 360}deg` }],
}));
}), []);

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same [] deps fix as BottomSheetDialog and ButtonAnimated. The rotation animation is driven by the rotation shared value on the UI thread and is unaffected by deps; the [] only prevents the worklet function from being re-created unnecessarily on each render.

import { TextVariant } from '../../types';
import { Box } from '../Box';
import { Text } from '../Text';
import { Text, TextVariant } from '../Text';

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The four story files (HeaderSearch, Blockies, Jazzicon, Maskicon) were importing TextVariant, TextColor, and FontWeight from the legacy ../types barrel rather than from the Text component that owns and re-exports them. Importing from the owning module is the correct pattern per the architecture rules and avoids false coupling to an internal barrel that may be cleaned up in a future migration.

…o.config.js formatting

Replace broad glob ignores for storybook-react-native with specific file
paths. The .rnstorybook/ TS files are ignored because they are outside
tsconfig.packages.json, and tailwind-intellisense.config.js is ignored
because its @metamask/design-system-twrnc-preset/tailwind.config import
is unresolvable at lint time. metro.config.js is now linted and its
prettier/import-order violations are fixed.
@github-actions

Copy link
Copy Markdown
Contributor

📖 Storybook Preview

Comment thread eslint.config.mjs
'apps/storybook-react-native/.rnstorybook/main.ts',
'apps/storybook-react-native/.rnstorybook/preview.tsx',
'apps/storybook-react-native/.rnstorybook/storybook.requires.ts',
'apps/storybook-react-native/tailwind-intellisense.config.js',

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The previous globs 'apps/storybook-react-native/.rnstorybook/**' and 'apps/storybook-react-native/*.js' were overly broad — they silently opted out config files like metro.config.js that can and should be linted. These specific paths are ignored because @typescript-eslint/parser requires files to be listed in tsconfig.packages.json for type-aware linting, which these Storybook harness files never will be. tailwind-intellisense.config.js is excluded separately because its @metamask/design-system-twrnc-preset/tailwind.config import path is not resolvable at lint time.

@@ -1,13 +1,22 @@
const {
withStorybook,
} = require('@storybook/react-native/metro/withStorybook');

@georgewrmarshall georgewrmarshall May 25, 2026

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

lint fix: The import order fix (withStorybook before getDefaultConfig) is required by the import-x/order rule — external/builtin imports must come before sibling/parent ones. This file was previously silently ignored by the broad *.js glob, so the violation was never caught.

Icon tests now assert on the flattened style object directly instead of
style[0], reflecting the StyleSheet.flatten change that produces a plain
object for web-compatible SVG rendering.

BottomSheet Android back button tests now set Platform.OS = 'android' in
beforeEach so the new platform guard does not short-circuit before the
BackHandler listener is registered.
@github-actions

Copy link
Copy Markdown
Contributor

📖 Storybook Preview


expect(expectedStyles).toBeDefined();
expect(iconElement.props.style[0]).toStrictEqual(expectedStyles);
expect(iconElement.props.style).toStrictEqual(expectedStyles);

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Previously the tests asserted on style[0] because the SVG component received a style array ([twStyle, style]). Now that Icon uses StyleSheet.flatten to merge the array into a plain object before passing it to the SVG renderer, style is a flat object and indexing into it with [0] always returns undefined. Asserting on style directly matches what the component now produces.


expect(expectedStyles).toBeDefined();
expect(textElement.props.style[0]).toStrictEqual(expectedStyles);
expect(textElement.props.style).toStrictEqual(expectedStyles);

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The same style[0]style change applies to all size and color variant assertions in this file. The pattern is consistent: every test that checked textElement.props.style[0] was implicitly depending on the SVG receiving a style array. StyleSheet.flatten removes that array, so all assertions align to the flat object the component now produces.


describe('Android back button', () => {
let backHandlerCallback: (() => boolean) | null = null;
let originalOS: typeof Platform.OS;

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Platform.OS is saved and restored here rather than using jest.spyOn because Platform.OS is a plain string property, not a method. Storing the original value and resetting in afterEach is the standard React Native testing pattern for platform-branching code and keeps each test in this block isolated from the Jest default ('ios' in this environment).

let originalOS: typeof Platform.OS;

beforeEach(() => {
originalOS = Platform.OS;

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Setting Platform.OS = 'android' here is what allows BackHandler.addEventListener to be reached. Without it, the new if (Platform.OS !== 'android') { return undefined; } guard in BottomSheet.tsx exits the effect early, so the addEventListener spy never fires and backHandlerCallback stays null — causing every subsequent assertion in the block to fail silently.

@georgewrmarshall georgewrmarshall self-assigned this May 25, 2026
@@ -42,7 +42,7 @@ describe('AvatarIcon', () => {
expect(container.props.style[1][0]).toStrictEqual(expectedIconBgStyle);

const icon = getByTestId('icon');

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

AvatarIcon renders Icon internally and accesses its resolved style via icon.props.style. These assertions previously indexed into the style array with [0] because Icon passed [twStyle, style] directly to the SVG. Now that Icon calls StyleSheet.flatten before passing the style, the prop is a plain object — so .color, .width, and .height are read directly from style rather than style[0].

@github-actions

Copy link
Copy Markdown
Contributor

📖 Storybook Preview

@georgewrmarshall

Copy link
Copy Markdown
Contributor Author

@metamaskbot publish-preview

@github-actions

Copy link
Copy Markdown
Contributor

Preview builds have been published. See these instructions for more information about preview builds.

Expand for full list of packages and versions.
{
  "@metamask-previews/design-system-react": "0.23.1-preview.620b9f3",
  "@metamask-previews/design-system-react-native": "0.26.0-preview.620b9f3",
  "@metamask-previews/design-system-shared": "0.19.0-preview.620b9f3",
  "@metamask-previews/design-system-tailwind-preset": "0.8.0-preview.620b9f3",
  "@metamask-previews/design-system-twrnc-preset": "0.4.2-preview.620b9f3",
  "@metamask-previews/design-tokens": "8.4.0-preview.620b9f3"
}

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

BottomSheet/Default — iOS Simulator (iPhone 15 Pro)

BottomSheet/Default

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

BottomSheetDialog/Default — iOS Simulator (iPhone 15 Pro)

BottomSheetDialog/Default

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

BottomSheetOverlay/Default — iOS Simulator (iPhone 15 Pro)

BottomSheetOverlay/Default

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Icon/Default — iOS Simulator (iPhone 15 Pro)

Icon/Default

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ButtonAnimated/Default — iOS Simulator (iPhone 15 Pro)

ButtonAnimated/Default

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Spinner/Default — iOS Simulator (iPhone 15 Pro)

Spinner/Default

@georgewrmarshall georgewrmarshall marked this pull request as ready for review May 27, 2026 15:50
@georgewrmarshall georgewrmarshall requested a review from a team as a code owner May 27, 2026 15:50
@georgewrmarshall georgewrmarshall enabled auto-merge (squash) May 27, 2026 15:53
brianacnguyen
brianacnguyen previously approved these changes May 27, 2026
@github-actions

Copy link
Copy Markdown
Contributor

📖 Storybook Preview

@github-actions

Copy link
Copy Markdown
Contributor

📖 Storybook Preview

@cursor cursor Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Cursor Bugbot has reviewed your changes and found 1 potential issue.

Fix All in Cursor

Bugbot Autofix prepared a fix for the issue found in the latest run.

  • ✅ Fixed: ESLint ignore pattern has wrong file extension
    • Updated ESLint ignore entry to use apps/storybook-react-native/.rnstorybook/index.tsx so the file is ignored again.

Create PR

Or push these changes by commenting:

@cursor push b79c82d690
Preview (b79c82d690)
diff --git a/eslint.config.mjs b/eslint.config.mjs
--- a/eslint.config.mjs
+++ b/eslint.config.mjs
@@ -42,7 +42,7 @@
       'apps/storybook-react/postcss.config.js',
       'apps/storybook-react/tailwind.config.js',
       // storybook react native
-      'apps/storybook-react-native/.rnstorybook/index.ts',
+      'apps/storybook-react-native/.rnstorybook/index.tsx',
       'apps/storybook-react-native/.rnstorybook/main.ts',
       'apps/storybook-react-native/.rnstorybook/preview.tsx',
       'apps/storybook-react-native/.rnstorybook/storybook.requires.ts',

You can send follow-ups to the cloud agent here.

Reviewed by Cursor Bugbot for commit 49ea665. Configure here.

Comment thread eslint.config.mjs Outdated
@georgewrmarshall

Copy link
Copy Markdown
Contributor Author

@cursor push b79c82d

@github-actions

Copy link
Copy Markdown
Contributor

📖 Storybook Preview

@georgewrmarshall georgewrmarshall merged commit cfc2207 into main May 27, 2026
44 checks passed
@georgewrmarshall georgewrmarshall deleted the fix/rn-web-storybook-component-fixes-2 branch May 27, 2026 22:05
@georgewrmarshall georgewrmarshall mentioned this pull request May 29, 2026
18 tasks
georgewrmarshall added a commit that referenced this pull request May 29, 2026
## Release 42.0.0

This release curates the changelogs for three published packages into
consumer-facing Keep a Changelog entries. It adds the `FlashFilled` icon
and `SelectButtonSize` across platforms, adds the `TextField` component
to React web, and ships two React Native breaking changes: the
`panGestureHandlerProps` removal (part of the
`react-native-gesture-handler` v2 migration) and the removal of the
variant-based title API from `HeaderBase`/`BottomSheetHeader`.

### 📦 Package Versions

- `@metamask/design-system-shared`: **0.20.0** (was 0.19.0)
- `@metamask/design-system-react`: **0.24.0** (was 0.23.1)
- `@metamask/design-system-react-native`: **0.27.0** (was 0.26.0)

> `@metamask/design-tokens`, `@metamask/design-system-tailwind-preset`,
and `@metamask/design-system-twrnc-preset` are unchanged in this
release.

### 🔄 Shared Type Updates (0.20.0)

#### Component Type Additions (#1191, #1177, #1170)

**What Changed:**

- Added `FlashFilled` to the `IconName` const so the filled lightning
bolt is available on both platforms.
- Added `SelectButtonSize` so `SelectButton` exposes a semantic size
type shared across platforms.
- Added `TextFieldPropsShared` for the cross-platform text field input
contract.

**Impact:**

- Additive only — no breaking changes to the shared package.
- Continues the ADR-0003/0004 const-object + centralized-types pattern.

### 🌐 React Web Updates (0.24.0)

#### Added

- Added `TextField` for labeled text entry with optional helper and
validation text, exposing `TextFieldSize` and `TextFieldType` (#1170)
- Added `FlashFilled` icon (filled lightning bolt) to `IconName` (#1191)

### 📱 React Native Updates (0.27.0)

#### Added

- Added `FlashFilled` icon (filled lightning bolt) to `IconName` (#1191)
- Added `SelectButtonSize` so `SelectButton` exposes a semantic size
type (#1177)

#### Changed

- **BREAKING:** Removed `panGestureHandlerProps` from `BottomSheet` and
`BottomSheetDialog` following the migration to the
`react-native-gesture-handler` v2 `GestureDetector`/`Gesture.Pan()` API
(#1165)
- Migration: [From version 0.26.0 to
0.27.0](./packages/design-system-react-native/MIGRATION.md#from-version-0260-to-0270)
- **BREAKING:** Removed the variant-based title API from `HeaderBase`
and `BottomSheetHeader` — `variant`, `HeaderBaseVariant`,
`BottomSheetHeaderVariant`, and `HeaderBase`'s `titleTestID` (#1103)
- String titles now render with a centered `HeadingSm` treatment; pass
custom `children` for bespoke title layouts and use `textProps.testID`
in place of `titleTestID`
- Migration: [From version 0.26.0 to
0.27.0](./packages/design-system-react-native/MIGRATION.md#from-version-0260-to-0270)
- Reduced the default `SegmentGroup` segment spacing from `gap-3` to
`gap-1` for tighter grouped segments (#1194)

#### Fixed

- Fixed a `HeaderStandardAnimated` runtime crash under React Native
Reanimated 4 by inlining the scroll-handler worklet (#1185)
- Fixed React Native Web rendering for `BottomSheet`,
`BottomSheetOverlay`, `Icon`, and the animated `ButtonAnimated` and
`Spinner` components (#1187)

### ⚠️ Breaking Changes

#### Removed `panGestureHandlerProps` from `BottomSheet` /
`BottomSheetDialog` (React Native Only)

**What Changed:**

- Removed the `panGestureHandlerProps` prop. The components migrated
from the deprecated RNGH v1 `PanGestureHandler` JSX component to the v2
`GestureDetector` + `Gesture.Pan()` API.
- `simultaneousHandlers` (the only real-world use case) was never wired
up under the old shim, so no working behavior is lost.

**Migration:**

```tsx
// Before (0.26.0)
<BottomSheet
  goBack={goBack}
  panGestureHandlerProps={{ simultaneousHandlers: scrollViewRef }}
>
  {children}
</BottomSheet>

// After (0.27.0)
<BottomSheet goBack={goBack}>{children}</BottomSheet>
```

#### Removed variant-based title API from `HeaderBase` /
`BottomSheetHeader` (React Native Only)

**What Changed:**

- Removed `variant`, `HeaderBaseVariant`, `BottomSheetHeaderVariant`,
and `HeaderBase`'s `titleTestID`.
- String titles now render with a centered `HeadingSm` treatment; custom
layouts use `children`, and `titleTestID` is replaced by
`textProps.testID`.

**Migration:**

```tsx
// Before (0.26.0)
import { HeaderBase, HeaderBaseVariant } from '@metamask/design-system-react-native';
<HeaderBase variant={HeaderBaseVariant.Display} titleTestID="title">
  Account details
</HeaderBase>

// After (0.27.0)
import { HeaderBase } from '@metamask/design-system-react-native';
<HeaderBase textProps={{ testID: 'title' }}>Account details</HeaderBase>
```

See migration guide for complete instructions:

- [React Native Migration Guide — 0.26.0 to
0.27.0](./packages/design-system-react-native/MIGRATION.md#from-version-0260-to-0270)

### 🔗 Consumer note: MetaMask Mobile

MetaMask Mobile currently consumes
`@metamask/design-system-react-native@0.20.0` and applies a local yarn
patch —
`.yarn/patches/@metamask-design-system-react-native-npm-0.20.0-2ae4d6f1dd.patch`
— to migrate `BottomSheetDialog` from `PanGestureHandler` to
`GestureDetector` for its React Native Reanimated 4 upgrade
([MetaMask/metamask-mobile#29470](MetaMask/metamask-mobile#29470)).

This release **upstreams that exact migration natively** (#1165). Once
mobile bumps to `0.27.0`, it can **drop that yarn patch** — the package
now uses the RNGH v2 `GestureDetector`/`Gesture.Pan()` API on its own.

Compatibility note: the package keeps `react-native-reanimated` at
`peerDependencies: >=3.17.0` (unchanged). It was validated against
mobile's current Reanimated 3.19 and is forward-compatible with the
incoming Reanimated 4.1.x (the #1185 worklet fix works on both), so no
peer-dependency bump is required.

### ✅ Checklist

- [x] Changelogs updated with human-readable descriptions
- [x] Changelog validation passed (`yarn changelog:validate`)
- [x] Version bumps follow semantic versioning
- [x] design-system-shared: minor (0.19.0 → 0.20.0) - additive type
exports
- [x] design-system-react: minor (0.23.1 → 0.24.0) - new `TextField`
component + icon
- [x] design-system-react-native: minor (0.26.0 → 0.27.0) - pre-1.0
minor with breaking changes
- [x] Breaking changes documented with migration guidance
- [x] Migration guides updated with before/after examples (if breaking
changes)
- [x] PR references included in changelog entries

## **Pre-merge author checklist**

- [x] I've followed [MetaMask Contributor
Docs](https://github.com/MetaMask/contributor-docs)
- [x] I've reviewed the [Release
Workflow](./.cursor/rules/release-workflow.md) cursor rule
- [ ] All tests pass (`yarn build && yarn test && yarn lint`)
- [x] Changelog validation passes (`yarn changelog:validate`)

## **Pre-merge reviewer checklist**

- [ ] I've reviewed the [Reviewing Release
PRs](./docs/reviewing-release-prs.md) guide
- [ ] Package versions follow semantic versioning
- [ ] Changelog entries are consumer-facing (not commit message
regurgitation)
- [ ] Breaking changes are documented in MIGRATION.md with examples
- [ ] All unreleased changes are accounted for in changelogs

<!-- CURSOR_SUMMARY -->
---

> [!NOTE]
> **Medium Risk**
> No runtime code in the diff, but the published React Native 0.27.0
changelog documents breaking BottomSheet and Header API changes that
require consumer migrations.
> 
> **Overview**
> **Release 42.0.0** bumps the monorepo to **42.0.0** and publishes
**@metamask/design-system-shared@0.20.0**,
**@metamask/design-system-react@0.24.0**, and
**@metamask/design-system-react-native@0.27.0** with finalized Keep a
Changelog entries and compare links.
> 
> The diff is mostly **release packaging**: version fields in root and
package `package.json` files, new changelog sections for those versions,
and doc updates. **React Native** docs drop **`panGestureHandlerProps`**
from `BottomSheet` / `BottomSheetDialog` READMEs; **`MIGRATION.md`**
adds a **0.26.0 → 0.27.0** section (bottom-sheet gesture prop removal,
header title API) and moves **BannerBase** guidance under **0.24.0 →
0.25.0**.
> 
> What consumers get in this release (documented in changelogs, not new
code in this PR): shared **`FlashFilled`**, **`SelectButtonSize`**,
**`TextFieldPropsShared`**; web **`TextField`** and **`FlashFilled`**;
native **`FlashFilled`**, **`SelectButtonSize`**, two **breaking** API
removals (`panGestureHandlerProps`, header **`variant`** /
**`titleTestID`**), tighter **`SegmentGroup`** spacing, Reanimated 4 /
RN Web fixes.
> 
> <sup>Reviewed by [Cursor Bugbot](https://cursor.com/bugbot) for commit
6710621. Bugbot is set up for automated
code reviews on this repo. Configure
[here](https://www.cursor.com/dashboard/bugbot).</sup>
<!-- /CURSOR_SUMMARY -->
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants