refactor(rn): simplify HeaderBase text API#1103
Conversation
3815a4a to
daf9858
Compare
📖 Storybook Preview |
📖 Storybook Preview |
daf9858 to
08349aa
Compare
📖 Storybook Preview |
There was a problem hiding this comment.
Cursor Bugbot has reviewed your changes and found 2 potential issues.
Autofix Details
Bugbot Autofix prepared fixes for both issues found in the latest run.
- ✅ Fixed: ReactNode children lose flex-1 layout wrapper
- Wrapped the title area in a flex-1 items-center View so ReactNode children expand and center correctly.
- ✅ Fixed:
TextVariantimported from sibling instead of shared- Changed import to pull TextVariant from @metamask/design-system-shared as per shared import rules.
Or push these changes by commenting:
@cursor push eb84e43ebf
Preview (eb84e43ebf)
diff --git a/packages/design-system-react-native/src/components/HeaderBase/HeaderBase.tsx b/packages/design-system-react-native/src/components/HeaderBase/HeaderBase.tsx
--- a/packages/design-system-react-native/src/components/HeaderBase/HeaderBase.tsx
+++ b/packages/design-system-react-native/src/components/HeaderBase/HeaderBase.tsx
@@ -8,7 +8,7 @@
// External dependencies.
import { ButtonIcon, ButtonIconSize } from '../ButtonIcon';
import { TextOrChildren } from '../temp-components/TextOrChildren';
-import { TextVariant } from '../Text';
+import { TextVariant } from '@metamask/design-system-shared';
import type { HeaderBaseProps } from './HeaderBase.types';
@@ -146,18 +146,20 @@
})}
{/* Title */}
- <TextOrChildren
- textProps={{
- variant: TextVariant.HeadingSm,
- ...textProps,
- style: [
- tw.style('text-center flex-1 items-center'),
- textProps?.style,
- ],
- }}
- >
- {children}
- </TextOrChildren>
+ <View style={tw.style('flex-1 items-center')}>
+ <TextOrChildren
+ textProps={{
+ variant: TextVariant.HeadingSm,
+ ...textProps,
+ style: [
+ tw.style('text-center flex-1 items-center'),
+ textProps?.style,
+ ],
+ }}
+ >
+ {children}
+ </TextOrChildren>
+ </View>
{/* End accessory */}
{renderAccessoryWrapper({You can send follow-ups to the cloud agent here.
08349aa to
141cf07
Compare
📖 Storybook Preview |
📖 Storybook Preview |
44905bf to
6140f09
Compare
📖 Storybook Preview |
There was a problem hiding this comment.
Cursor Bugbot has reviewed your changes and found 1 potential issue.
Autofix Details
Bugbot Autofix prepared a fix for the issue found in the latest run.
- ✅ Fixed:
BottomSheetHeaderPropsOmit misses button icon props- Updated BottomSheetHeaderProps to also omit startButtonIconProps and endButtonIconProps, preventing unintended buttons from being rendered via forwarded props.
Or push these changes by commenting:
@cursor push 2d9c69fa65
Preview (2d9c69fa65)
diff --git a/packages/design-system-react-native/src/components/BottomSheetHeader/BottomSheetHeader.types.ts b/packages/design-system-react-native/src/components/BottomSheetHeader/BottomSheetHeader.types.ts
--- a/packages/design-system-react-native/src/components/BottomSheetHeader/BottomSheetHeader.types.ts
+++ b/packages/design-system-react-native/src/components/BottomSheetHeader/BottomSheetHeader.types.ts
@@ -32,4 +32,7 @@
* Note: `iconName` and `onPress` are managed internally and excluded.
*/
closeButtonProps?: Partial<Omit<ButtonIconProps, 'iconName' | 'onPress'>>;
-} & Omit<HeaderBaseProps, 'startAccessory' | 'endAccessory'>;
+} & Omit<
+ HeaderBaseProps,
+ 'startAccessory' | 'endAccessory' | 'startButtonIconProps' | 'endButtonIconProps'
+>;You can send follow-ups to the cloud agent here.
📖 Storybook Preview |
f8cef21 to
d9c8398
Compare
📖 Storybook Preview |
📖 Storybook Preview |
da51ae2 to
d9c8398
Compare
📖 Storybook Preview |
📖 Storybook Preview |
e4d983c to
ba04193
Compare
📖 Storybook Preview |
8fec4c5 to
34f858b
Compare
34f858b to
2d9dcf7
Compare
There was a problem hiding this comment.
Cursor Bugbot has reviewed your changes and found 1 potential issue.
Autofix Details
Bugbot Autofix prepared a fix for the issue found in the latest run.
- ✅ Fixed: Story name uses prohibited "With" prefix
- Renamed the
WithTitlestory toChildrento comply with naming conventions.
- Renamed the
Or push these changes by commenting:
@cursor push 31ac9f20e7
Preview (31ac9f20e7)
diff --git a/packages/design-system-react-native/src/components/BottomSheetHeader/BottomSheetHeader.stories.tsx b/packages/design-system-react-native/src/components/BottomSheetHeader/BottomSheetHeader.stories.tsx
--- a/packages/design-system-react-native/src/components/BottomSheetHeader/BottomSheetHeader.stories.tsx
+++ b/packages/design-system-react-native/src/components/BottomSheetHeader/BottomSheetHeader.stories.tsx
@@ -39,7 +39,7 @@
},
};
-export const WithTitle: Story = {
+export const Children: Story = {
render: () => (
<BottomSheetHeader>Centered bottom sheet title</BottomSheetHeader>
),You can send follow-ups to the cloud agent here.
|
|
||
| // `startAccessory` is the primary escape hatch. `startButtonIconProps` | ||
| // remains as a convenience path for the common single-back-button case. | ||
| const resolveStartAccessory = ({ |
There was a problem hiding this comment.
Accessory resolution is extracted into two module-level pure functions rather than inline render functions inside the component. This keeps the component body focused purely on layout and makes the precedence rules (e.g. startAccessory wins over startButtonIconProps) readable in isolation without having to trace through conditional render logic.
| * Props are spread onto TextOrChildren `textProps` and can override default values. | ||
| */ | ||
| titleTestID?: string; | ||
| textProps?: Omit<Partial<TextProps>, 'children'>; |
There was a problem hiding this comment.
textProps is a broader escape hatch than the old titleTestID prop alone. It lets callers pass any TextProps — including testID, accessibilityLabel, or additional style — to the auto-rendered string title, which is the same pattern used by other components in the system that wrap TextOrChildren.
| */ | ||
| variant?: BottomSheetHeaderVariant; | ||
| } & Omit<HeaderBaseProps, 'variant'>; | ||
| } & Omit< |
There was a problem hiding this comment.
The previous Omit<HeaderBaseProps, 'variant'> only blocked the old variant prop. This expanded omit also blocks the four accessory-slot props, making the compile-time contract match the runtime behaviour: BottomSheetHeader callers cannot configure accessories directly and must go through onBack/onClose or compose a custom header instead.
| @@ -1,3 +1,2 @@ | |||
| export { HeaderBase } from './HeaderBase'; | |||
| export { HeaderBaseVariant } from './HeaderBase.types'; | |||
| export type { HeaderBaseProps } from './HeaderBase.types'; | |||
There was a problem hiding this comment.
HeaderBaseVariant and BottomSheetHeaderVariant are removed from the public API because variant-based layout control belongs to the caller, not the base component. The Compact variant (centered HeadingSm) is now the sole string-children treatment; callers that previously relied on Display (left-aligned HeadingLg) should pass a custom ReactNode as children to compose the title layout they need. The MIGRATION.md entry covers this with concrete before/after examples.
aa9425c to
fdaaeda
Compare
📖 Storybook Preview |
There was a problem hiding this comment.
Cursor Bugbot has reviewed your changes and found 1 potential issue.
There are 2 total unresolved issues (including 1 from previous review).
Bugbot Autofix prepared a fix for the issue found in the latest run.
- ✅ Fixed: Omitted props leak through rest spread to HeaderBase
- Added explicit startButtonIconProps and endButtonIconProps overrides to undefined on HeaderBase so they cannot leak via ...props at runtime.
Or push these changes by commenting:
@cursor push c7eb5ca95b
Preview (c7eb5ca95b)
diff --git a/packages/design-system-react-native/src/components/BottomSheetHeader/BottomSheetHeader.tsx b/packages/design-system-react-native/src/components/BottomSheetHeader/BottomSheetHeader.tsx
--- a/packages/design-system-react-native/src/components/BottomSheetHeader/BottomSheetHeader.tsx
+++ b/packages/design-system-react-native/src/components/BottomSheetHeader/BottomSheetHeader.tsx
@@ -41,6 +41,9 @@
return (
<HeaderBase
{...props}
+ // Ensure omitted props never leak through to HeaderBase at runtime
+ startButtonIconProps={undefined}
+ endButtonIconProps={undefined}
style={[tw.style('px-4', twClassName), style]}
startAccessory={startAccessory}
endAccessory={endAccessory}You can send follow-ups to the cloud agent here.
Reviewed by Cursor Bugbot for commit fdaaeda. Configure here.
📖 Storybook Preview |
6a87cd7 to
a30cdb7
Compare
📖 Storybook Preview |
📖 Storybook Preview |
📖 Storybook Preview |
## 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 -->


Description
Simplifies the React Native header primitives by removing the
HeaderBasevariant system and consolidating title text passthrough ontoTextOrChildren'stextPropsAPI.This refactor:
HeaderBaseVariantandBottomSheetHeaderVariantHeaderBase'stitlePropsalias in favor oftextPropsHeaderBasecompact-only with the compact title styling/layoutRelated issues
Fixes:
Manual testing steps
yarn workspace @metamask/design-system-react-native test --runInBand --coverage=false --runTestsByPath src/components/HeaderBase/HeaderBase.test.tsx src/components/BottomSheetHeader/BottomSheetHeader.test.tsxHeaderBaseandBottomSheetHeadersuites pass.HeaderBaseandBottomSheetHeaderto confirm compact title layout and accessory alignment.Screenshots/Recordings
Before
After
HeaderBasein storybook has no behavioural or visual regressionsSimulator.Screen.Recording.-.iPhone.15.Pro.-.2026-05-21.at.15.33.22.mov
HeaderStandard,HeaderStandardAnimated,BottomSheetHeaderin storybook has no behavioural or visual regressionsSimulator.Screen.Recording.-.iPhone.15.Pro.-.2026-05-21.at.15.38.54.mov
Pre-merge author checklist
Pre-merge reviewer checklist
Note
Medium Risk
Breaking public API changes (removed enums/props) require consumer migrations; layout behavior for former Display variant users must move to custom children.
Overview
Removes the Compact/Display variant model from
HeaderBaseandBottomSheetHeader, dropsHeaderBaseVariant/BottomSheetHeaderVariantexports, and standardizes string titles on a single centeredHeadingSmpath viaTextOrChildrenandtextProps(replacingtitleTestID).BottomSheetHeaderno longer forwardsvarianttoHeaderBase; variant mapping constants are deleted.HeaderBaseimplementation is refactored around resolved start/end accessories (custom slots still win overstartButtonIconProps/endButtonIconProps), addschildrenWrapperProps, and tightensBottomSheetHeader’s public type so accessory slots are only viaonBack/onClose.MIGRATION.md, READMEs, stories, tests, and package exports are updated for the breaking changes.Reviewed by Cursor Bugbot for commit d8b3617. Bugbot is set up for automated code reviews on this repo. Configure here.