feat: [DSRN] Add TitleSubpage#1059
Conversation
📖 Storybook Preview |
📖 Storybook Preview |
📖 Storybook Preview |
There was a problem hiding this comment.
Two architectural patterns run throughout the implementation that need to be addressed before merge.
1. Conditional rendering logic React already handles
The component pre-computes renderTitleRow, renderSubtitleRow, renderAmountRow, renderBottomLabelRow, and renderBottomAccessory before the return, and separately normalises all four *EndAccessory props to undefined when isReactNodeRenderable returns false. None of this is necessary — null, undefined, and false are valid ReactNode values that React renders as nothing. This is exactly the pattern we identified and removed from HeaderRoot in #1076 (where isReactNodeRenderable is also being deleted from design-system-shared, making this a build-time blocker once that lands).
2. Indirection that makes the layout harder to read and easier to miss bugs in
titleAvatarSlot, titleRow, subtitleRow, identityRow, amountRow, and bottomLabelRow are all extracted into variables and then referenced exactly once with no conditional branching. JSX is readable top-to-bottom — pulling single-use fragments into named variables forces readers to jump between definition sites and the return, obscuring the actual layout and making redundant conditionals harder to spot.
Left some other more minor comments
…gn-system into dsrn/titlesubpage
📖 Storybook Preview |
georgewrmarshall
left a comment
There was a problem hiding this comment.
Follow-up review — component structure, tests, and the same recurring patterns from TitleStandard/TitleHub.
📖 Storybook Preview |
📖 Storybook Preview |
…o dsrn/titlesubpage
📖 Storybook Preview |
| startAccessory={ | ||
| <Box | ||
| testID="title-subpage-title-avatar-slot" | ||
| alignItems={BoxAlignItems.Center} | ||
| justifyContent={BoxJustifyContent.Center} | ||
| twClassName="size-10 overflow-hidden" | ||
| > | ||
| {titleAvatar} | ||
| </Box> | ||
| } |
There was a problem hiding this comment.
Still curious if this Box wrapper is necessary?
There was a problem hiding this comment.
@georgewrmarshall this is to make sure the avatar is contained within a 40px x 40px box. what do you think?
There was a problem hiding this comment.
I think the component would be more flexible without the wrapper? We should ensure AvatarToken is size large but what if we need to add a badge or change something that goes outside of the Box it will be cut off or confined to the 40px size?
…o dsrn/titlesubpage
📖 Storybook Preview |
📖 Storybook Preview |
There was a problem hiding this comment.
Cursor Bugbot has reviewed your changes and found 1 potential issue.
❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, have a team admin enable autofix in the Cursor dashboard.
Reviewed by Cursor Bugbot for commit 1ec1d52. Configure here.
| titleEndAccessory?: ReactNode; | ||
| /** | ||
| * Optional subtitle row below the title and above the amount (via platform `textProps` when a string). | ||
| * The subtitle row renders when `subtitle` is renderable. |
There was a problem hiding this comment.
Shared types JSDoc says "renderable" instead of "truthy"
Low Severity
The subtitle JSDoc says "The subtitle row renders when subtitle is renderable" but the implementation uses a truthy check ({subtitle && (...)}). Other props in the same file consistently use "truthy" — amount (line 12) says "renders when amount is truthy" and bottomLabel (line 48) says "When bottomLabel is truthy". The README also correctly says "truthy" for subtitle. This wording mismatch means the JSDoc doesn't accurately reflect implementation behavior, which is inconsistent within the file itself.
Triggered by learned rule: JSDoc and README must match implementation behavior
Reviewed by Cursor Bugbot for commit 1ec1d52. Configure here.
There was a problem hiding this comment.
false positive we always provide content in a string
📖 Storybook Preview |
georgewrmarshall
left a comment
There was a problem hiding this comment.
The component looks in a good place after the review rounds. I just have one remaining suggestion around keeping the titleAvatar slot more flexible for composed avatar use cases.
…o dsrn/titlesubpage
…gn-system into dsrn/titlesubpage
…o dsrn/titlesubpage
📖 Storybook Preview |
📖 Storybook Preview |
There was a problem hiding this comment.
Approving. The component looks in a good place after the recent changes.
I just have one non-blocking docs follow-up. I’ll also adjust the Cursor documentation rule in an effort to keep docs consumer-focused and avoid process history, implementation-detail narration, or extra fluff in these README additions.
| @@ -0,0 +1,512 @@ | |||
| # TitleSubpage | |||
|
|
|||
| TitleSubpage lays out a required identity block (leading `titleAvatar` beside a title stack), an optional subtitle, an optional amount row, optional bottom rows, and optional inline accessories per row. On React Native, `titleAvatar` is passed straight through as the identity `BoxRow` `startAccessory` (no fixed-size or `overflow: hidden` wrapper), so network badges and other overlays can extend past the token without being clipped. For the default layout, use `AvatarToken` at `AvatarTokenSize.Lg` (40×40) so the token aligns with the row; the component stays agnostic—you own composition when you need badges or other chrome. | |||
There was a problem hiding this comment.
non-blocking: I’d simplify this opening description to keep it consumer-focused. Something like: TitleSubpage lays out a required identity block with a leading titleAvatar beside a title stack, plus an optional subtitle, optional amount row, optional bottom rows, and optional inline accessories per row. For avatars passed to titleAvatar, use a large size, for example AvatarToken at AvatarTokenSize.Lg (40×40).
## Release 35.0.0 This release adds new React Native title primitives, continues the enum-to-const-object/string-union migration for public type exports, and updates the release documentation so breaking changes are consumer-focused and migration-oriented. ### Package Versions - `@metamask/design-system-shared`: **0.13.0** - `@metamask/design-system-react`: **0.18.0** - `@metamask/design-system-react-native`: **0.20.0** - `@metamask/design-system-tailwind-preset`: **0.6.2** ### Shared Type Updates (0.13.0) #### Added (#1051, #1053, #1059) **What Changed:** - Added `TitleStandardPropsShared` and `TitleSubpagePropsShared` - Added `TagSeverity` and `TagPropsShared` **Impact:** - Supports the new React Native `TitleStandard`, `TitleSubpage`, and `Tag` APIs #### Changed (#1026, #1042) **What Changed:** - **BREAKING:** Updated shared `Box` and `Icon` exports from enums to const objects with derived string-union types - Removed stale Box `WarningAlternative`, `SuccessAlternative`, and `InfoAlternative` color entries that no longer map to design tokens **Impact:** - Affects consumers of `@metamask/design-system-shared` directly - Platform package consumers should continue importing from `@metamask/design-system-react` or `@metamask/design-system-react-native` ### React Web Updates (0.18.0) #### Changed - **BREAKING:** Updated `IconName`, `IconColor`, and `IconSize` exports to use const-object + string-union types instead of enums (#1042, #1101) - **BREAKING:** Updated `Box` type exports to use const-object + string-union types and removed stale Box color entries (#1026) - Updated `ButtonTertiary` to use the default text color for more consistent contrast across states (#1099) ### React Native Updates (0.20.0) #### Added - Added `TitleStandard` for mobile title layouts with optional top and bottom accessory rows (#1051) - Added `TitleSubpage` for subpage headers with avatar, title, subtitle, amount, and bottom-label layouts (#1059) - Added `Tag` for compact severity-based metadata labels with optional icons or custom accessories (#1053) #### Changed - **BREAKING:** Updated `IconName`, `IconColor`, and `IconSize` exports to use const-object + string-union types instead of enums (#1042) - **BREAKING:** Updated `Box` type exports to use const-object + string-union types and removed stale Box color entries (#1026) - `Box` now forwards refs to the underlying `View` (#1102) - Updated `ButtonTertiary` to use the default text color for more consistent contrast across states (#1099) ### Tailwind Preset Updates (0.6.2) #### Changed - No consumer-facing API or behavior changes in this release; this patch republishes the existing preset without requiring changes in consuming apps ### Breaking Changes #### Icon and Box enum exports migrated to const objects plus string unions (Both Platforms) **What Changed:** - `IconName`, `IconColor`, and `IconSize` now use const objects with derived string-union types instead of enums - `BoxFlexDirection`, `BoxFlexWrap`, `BoxAlignItems`, `BoxJustifyContent`, `BoxBackgroundColor`, `BoxBorderColor`, `BoxSpacing`, and `BoxBorderWidth` now use const objects with derived string-union types instead of enums - Removed stale Box color entries with no backing design token: - `BoxBackgroundColor.WarningAlternative` - `BoxBackgroundColor.SuccessAlternative` - `BoxBorderColor.WarningAlternative` - `BoxBorderColor.SuccessAlternative` - `BoxBorderColor.InfoAlternative` **Migration:** ```tsx // Before import { BoxBackgroundColor, IconColor, IconName, } from '@metamask/design-system-react-native'; <Box backgroundColor={BoxBackgroundColor.WarningAlternative} /> <Icon name={IconName.Add} color={IconColor.IconDefault} /> // After import { BoxBackgroundColor, IconColor, IconName, } from '@metamask/design-system-react-native'; <Box backgroundColor={BoxBackgroundColor.WarningDefault} /> <Icon name={IconName.Add} color={IconColor.IconDefault} /> ``` **Impact:** - Affects consumers relying on enum-specific TypeScript behavior for `Icon*` and `Box*` exports - Import paths stay the same for platform-package consumers - Any use of the removed Box `*Alternative` color entries will need to switch to the corresponding `*Default` or `*Muted` token See migration guides for complete instructions: - [React Migration Guide](./packages/design-system-react/MIGRATION.md#from-version-0170-to-0180) - [React Native Migration Guide](./packages/design-system-react-native/MIGRATION.md#from-version-0190-to-0200) ### Validation - `yarn changelog:validate` <!-- CURSOR_SUMMARY --> --- > [!NOTE] > **Medium Risk** > Medium risk because it publishes new versions with **breaking TypeScript surface changes** (Box/Icon enums → const-object/string-union and removal of stale Box color members), which can break downstream builds despite minimal runtime behavior changes. > > **Overview** > Bumps the monorepo release to `35.0.0` and publishes new package versions for `@metamask/design-system-react` (`0.18.0`), `@metamask/design-system-react-native` (`0.20.0`), and `@metamask/design-system-shared` (`0.13.0`). > > Updates changelogs/migration guides to reflect the release: adds React Native primitives (`TitleStandard`, `TitleSubpage`, `Tag`) and shared prop contracts, and documents **breaking** shifts of `Box*` and `Icon*` exports from enums to const-object + string-union types (plus removal of stale `*Alternative` Box color entries) with consumer-facing migration steps. > > <sup>Reviewed by [Cursor Bugbot](https://cursor.com/bugbot) for commit addbae5. Bugbot is set up for automated code reviews on this repo. Configure [here](https://www.cursor.com/dashboard/bugbot).</sup> <!-- /CURSOR_SUMMARY -->
## **Description** Adds **`TitleSubpage`** to `@metamask/design-system-react-native`: a layout for subpage headers with a required **identity row** (leading `titleAvatar` in a 40×40 centered slot + title stack), optional **subtitle**, **amount** (display typography when a string), optional **bottom label** or **bottom accessory**, and **end accessories** on title, subtitle, amount, and bottom label rows. --- ## **Related issues** Fixes: https://consensyssoftware.atlassian.net/browse/DSYS-583 --- ## **Manual testing steps** 1. From the repo root, run React Native Storybook (e.g. `yarn storybook:ios` or `yarn storybook:android`). 2. Open **Components → TitleSubpage** and review **Default**, **Amount**, accessory variants, **BottomLabel** / **BottomAccessory**, and controls for text fields where enabled. 3. Confirm layout: avatar slot, title/subtitle/amount stacking, and bottom row behavior matches expectations. --- ## **Screenshots/Recordings** _If applicable, add screenshots and/or recordings to visualize the before and after of your change._ ### **Before** _N/A — new component (or attach Storybook before/after if replacing something in-app)._ ### **After** https://github.com/user-attachments/assets/3ac61e0e-86b9-48d4-a167-bb1e5ed86547 --- ## **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 - [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-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] > **Low Risk** > Low risk: changes are additive (new component, shared types, stories, and tests) with no modifications to existing runtime behavior beyond new exports. > > **Overview** > Adds a new React Native `TitleSubpage` component for subpage header layouts, supporting a required identity row (`titleAvatar` + title stack) plus optional `subtitle`, `amount`, and either a `bottomLabel` row or a custom `bottomAccessory`, each with optional end-accessories. > > Exports the component from `design-system-react-native`, introduces the corresponding shared props type (`TitleSubpagePropsShared`) in `design-system-shared`, and includes Storybook stories, unit tests, and a detailed README documenting composition and prop behavior (notably passing `titleAvatar` directly as the identity `BoxRow` `startAccessory`). > > <sup>Reviewed by [Cursor Bugbot](https://cursor.com/bugbot) for commit 2c5a102. Bugbot is set up for automated code reviews on this repo. Configure [here](https://www.cursor.com/dashboard/bugbot).</sup> <!-- /CURSOR_SUMMARY -->
## Release 35.0.0 This release adds new React Native title primitives, continues the enum-to-const-object/string-union migration for public type exports, and updates the release documentation so breaking changes are consumer-focused and migration-oriented. ### Package Versions - `@metamask/design-system-shared`: **0.13.0** - `@metamask/design-system-react`: **0.18.0** - `@metamask/design-system-react-native`: **0.20.0** - `@metamask/design-system-tailwind-preset`: **0.6.2** ### Shared Type Updates (0.13.0) #### Added (#1051, #1053, #1059) **What Changed:** - Added `TitleStandardPropsShared` and `TitleSubpagePropsShared` - Added `TagSeverity` and `TagPropsShared` **Impact:** - Supports the new React Native `TitleStandard`, `TitleSubpage`, and `Tag` APIs #### Changed (#1026, #1042) **What Changed:** - **BREAKING:** Updated shared `Box` and `Icon` exports from enums to const objects with derived string-union types - Removed stale Box `WarningAlternative`, `SuccessAlternative`, and `InfoAlternative` color entries that no longer map to design tokens **Impact:** - Affects consumers of `@metamask/design-system-shared` directly - Platform package consumers should continue importing from `@metamask/design-system-react` or `@metamask/design-system-react-native` ### React Web Updates (0.18.0) #### Changed - **BREAKING:** Updated `IconName`, `IconColor`, and `IconSize` exports to use const-object + string-union types instead of enums (#1042, #1101) - **BREAKING:** Updated `Box` type exports to use const-object + string-union types and removed stale Box color entries (#1026) - Updated `ButtonTertiary` to use the default text color for more consistent contrast across states (#1099) ### React Native Updates (0.20.0) #### Added - Added `TitleStandard` for mobile title layouts with optional top and bottom accessory rows (#1051) - Added `TitleSubpage` for subpage headers with avatar, title, subtitle, amount, and bottom-label layouts (#1059) - Added `Tag` for compact severity-based metadata labels with optional icons or custom accessories (#1053) #### Changed - **BREAKING:** Updated `IconName`, `IconColor`, and `IconSize` exports to use const-object + string-union types instead of enums (#1042) - **BREAKING:** Updated `Box` type exports to use const-object + string-union types and removed stale Box color entries (#1026) - `Box` now forwards refs to the underlying `View` (#1102) - Updated `ButtonTertiary` to use the default text color for more consistent contrast across states (#1099) ### Tailwind Preset Updates (0.6.2) #### Changed - No consumer-facing API or behavior changes in this release; this patch republishes the existing preset without requiring changes in consuming apps ### Breaking Changes #### Icon and Box enum exports migrated to const objects plus string unions (Both Platforms) **What Changed:** - `IconName`, `IconColor`, and `IconSize` now use const objects with derived string-union types instead of enums - `BoxFlexDirection`, `BoxFlexWrap`, `BoxAlignItems`, `BoxJustifyContent`, `BoxBackgroundColor`, `BoxBorderColor`, `BoxSpacing`, and `BoxBorderWidth` now use const objects with derived string-union types instead of enums - Removed stale Box color entries with no backing design token: - `BoxBackgroundColor.WarningAlternative` - `BoxBackgroundColor.SuccessAlternative` - `BoxBorderColor.WarningAlternative` - `BoxBorderColor.SuccessAlternative` - `BoxBorderColor.InfoAlternative` **Migration:** ```tsx // Before import { BoxBackgroundColor, IconColor, IconName, } from '@metamask/design-system-react-native'; <Box backgroundColor={BoxBackgroundColor.WarningAlternative} /> <Icon name={IconName.Add} color={IconColor.IconDefault} /> // After import { BoxBackgroundColor, IconColor, IconName, } from '@metamask/design-system-react-native'; <Box backgroundColor={BoxBackgroundColor.WarningDefault} /> <Icon name={IconName.Add} color={IconColor.IconDefault} /> ``` **Impact:** - Affects consumers relying on enum-specific TypeScript behavior for `Icon*` and `Box*` exports - Import paths stay the same for platform-package consumers - Any use of the removed Box `*Alternative` color entries will need to switch to the corresponding `*Default` or `*Muted` token See migration guides for complete instructions: - [React Migration Guide](./packages/design-system-react/MIGRATION.md#from-version-0170-to-0180) - [React Native Migration Guide](./packages/design-system-react-native/MIGRATION.md#from-version-0190-to-0200) ### Validation - `yarn changelog:validate` <!-- CURSOR_SUMMARY --> --- > [!NOTE] > **Medium Risk** > Medium risk because it publishes new versions with **breaking TypeScript surface changes** (Box/Icon enums → const-object/string-union and removal of stale Box color members), which can break downstream builds despite minimal runtime behavior changes. > > **Overview** > Bumps the monorepo release to `35.0.0` and publishes new package versions for `@metamask/design-system-react` (`0.18.0`), `@metamask/design-system-react-native` (`0.20.0`), and `@metamask/design-system-shared` (`0.13.0`). > > Updates changelogs/migration guides to reflect the release: adds React Native primitives (`TitleStandard`, `TitleSubpage`, `Tag`) and shared prop contracts, and documents **breaking** shifts of `Box*` and `Icon*` exports from enums to const-object + string-union types (plus removal of stale `*Alternative` Box color entries) with consumer-facing migration steps. > > <sup>Reviewed by [Cursor Bugbot](https://cursor.com/bugbot) for commit addbae5. Bugbot is set up for automated code reviews on this repo. Configure [here](https://www.cursor.com/dashboard/bugbot).</sup> <!-- /CURSOR_SUMMARY -->
## Release 35.0.0 This release adds new React Native title primitives, continues the enum-to-const-object/string-union migration for public type exports, and updates the release documentation so breaking changes are consumer-focused and migration-oriented. ### Package Versions - `@metamask/design-system-shared`: **0.13.0** - `@metamask/design-system-react`: **0.18.0** - `@metamask/design-system-react-native`: **0.20.0** - `@metamask/design-system-tailwind-preset`: **0.6.2** ### Shared Type Updates (0.13.0) #### Added (#1051, #1053, #1059) **What Changed:** - Added `TitleStandardPropsShared` and `TitleSubpagePropsShared` - Added `TagSeverity` and `TagPropsShared` **Impact:** - Supports the new React Native `TitleStandard`, `TitleSubpage`, and `Tag` APIs #### Changed (#1026, #1042) **What Changed:** - **BREAKING:** Updated shared `Box` and `Icon` exports from enums to const objects with derived string-union types - Removed stale Box `WarningAlternative`, `SuccessAlternative`, and `InfoAlternative` color entries that no longer map to design tokens **Impact:** - Affects consumers of `@metamask/design-system-shared` directly - Platform package consumers should continue importing from `@metamask/design-system-react` or `@metamask/design-system-react-native` ### React Web Updates (0.18.0) #### Changed - **BREAKING:** Updated `IconName`, `IconColor`, and `IconSize` exports to use const-object + string-union types instead of enums (#1042, #1101) - **BREAKING:** Updated `Box` type exports to use const-object + string-union types and removed stale Box color entries (#1026) - Updated `ButtonTertiary` to use the default text color for more consistent contrast across states (#1099) ### React Native Updates (0.20.0) #### Added - Added `TitleStandard` for mobile title layouts with optional top and bottom accessory rows (#1051) - Added `TitleSubpage` for subpage headers with avatar, title, subtitle, amount, and bottom-label layouts (#1059) - Added `Tag` for compact severity-based metadata labels with optional icons or custom accessories (#1053) #### Changed - **BREAKING:** Updated `IconName`, `IconColor`, and `IconSize` exports to use const-object + string-union types instead of enums (#1042) - **BREAKING:** Updated `Box` type exports to use const-object + string-union types and removed stale Box color entries (#1026) - `Box` now forwards refs to the underlying `View` (#1102) - Updated `ButtonTertiary` to use the default text color for more consistent contrast across states (#1099) ### Tailwind Preset Updates (0.6.2) #### Changed - No consumer-facing API or behavior changes in this release; this patch republishes the existing preset without requiring changes in consuming apps ### Breaking Changes #### Icon and Box enum exports migrated to const objects plus string unions (Both Platforms) **What Changed:** - `IconName`, `IconColor`, and `IconSize` now use const objects with derived string-union types instead of enums - `BoxFlexDirection`, `BoxFlexWrap`, `BoxAlignItems`, `BoxJustifyContent`, `BoxBackgroundColor`, `BoxBorderColor`, `BoxSpacing`, and `BoxBorderWidth` now use const objects with derived string-union types instead of enums - Removed stale Box color entries with no backing design token: - `BoxBackgroundColor.WarningAlternative` - `BoxBackgroundColor.SuccessAlternative` - `BoxBorderColor.WarningAlternative` - `BoxBorderColor.SuccessAlternative` - `BoxBorderColor.InfoAlternative` **Migration:** ```tsx // Before import { BoxBackgroundColor, IconColor, IconName, } from '@metamask/design-system-react-native'; <Box backgroundColor={BoxBackgroundColor.WarningAlternative} /> <Icon name={IconName.Add} color={IconColor.IconDefault} /> // After import { BoxBackgroundColor, IconColor, IconName, } from '@metamask/design-system-react-native'; <Box backgroundColor={BoxBackgroundColor.WarningDefault} /> <Icon name={IconName.Add} color={IconColor.IconDefault} /> ``` **Impact:** - Affects consumers relying on enum-specific TypeScript behavior for `Icon*` and `Box*` exports - Import paths stay the same for platform-package consumers - Any use of the removed Box `*Alternative` color entries will need to switch to the corresponding `*Default` or `*Muted` token See migration guides for complete instructions: - [React Migration Guide](./packages/design-system-react/MIGRATION.md#from-version-0170-to-0180) - [React Native Migration Guide](./packages/design-system-react-native/MIGRATION.md#from-version-0190-to-0200) ### Validation - `yarn changelog:validate` <!-- CURSOR_SUMMARY --> --- > [!NOTE] > **Medium Risk** > Medium risk because it publishes new versions with **breaking TypeScript surface changes** (Box/Icon enums → const-object/string-union and removal of stale Box color members), which can break downstream builds despite minimal runtime behavior changes. > > **Overview** > Bumps the monorepo release to `35.0.0` and publishes new package versions for `@metamask/design-system-react` (`0.18.0`), `@metamask/design-system-react-native` (`0.20.0`), and `@metamask/design-system-shared` (`0.13.0`). > > Updates changelogs/migration guides to reflect the release: adds React Native primitives (`TitleStandard`, `TitleSubpage`, `Tag`) and shared prop contracts, and documents **breaking** shifts of `Box*` and `Icon*` exports from enums to const-object + string-union types (plus removal of stale `*Alternative` Box color entries) with consumer-facing migration steps. > > <sup>Reviewed by [Cursor Bugbot](https://cursor.com/bugbot) for commit addbae5. Bugbot is set up for automated code reviews on this repo. Configure [here](https://www.cursor.com/dashboard/bugbot).</sup> <!-- /CURSOR_SUMMARY -->
## **Description** Adds **`TitleSubpage`** to `@metamask/design-system-react-native`: a layout for subpage headers with a required **identity row** (leading `titleAvatar` in a 40×40 centered slot + title stack), optional **subtitle**, **amount** (display typography when a string), optional **bottom label** or **bottom accessory**, and **end accessories** on title, subtitle, amount, and bottom label rows. --- ## **Related issues** Fixes: https://consensyssoftware.atlassian.net/browse/DSYS-583 --- ## **Manual testing steps** 1. From the repo root, run React Native Storybook (e.g. `yarn storybook:ios` or `yarn storybook:android`). 2. Open **Components → TitleSubpage** and review **Default**, **Amount**, accessory variants, **BottomLabel** / **BottomAccessory**, and controls for text fields where enabled. 3. Confirm layout: avatar slot, title/subtitle/amount stacking, and bottom row behavior matches expectations. --- ## **Screenshots/Recordings** _If applicable, add screenshots and/or recordings to visualize the before and after of your change._ ### **Before** _N/A — new component (or attach Storybook before/after if replacing something in-app)._ ### **After** https://github.com/user-attachments/assets/3ac61e0e-86b9-48d4-a167-bb1e5ed86547 --- ## **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 - [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-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] > **Low Risk** > Low risk: changes are additive (new component, shared types, stories, and tests) with no modifications to existing runtime behavior beyond new exports. > > **Overview** > Adds a new React Native `TitleSubpage` component for subpage header layouts, supporting a required identity row (`titleAvatar` + title stack) plus optional `subtitle`, `amount`, and either a `bottomLabel` row or a custom `bottomAccessory`, each with optional end-accessories. > > Exports the component from `design-system-react-native`, introduces the corresponding shared props type (`TitleSubpagePropsShared`) in `design-system-shared`, and includes Storybook stories, unit tests, and a detailed README documenting composition and prop behavior (notably passing `titleAvatar` directly as the identity `BoxRow` `startAccessory`). > > <sup>Reviewed by [Cursor Bugbot](https://cursor.com/bugbot) for commit 2c5a102. Bugbot is set up for automated code reviews on this repo. Configure [here](https://www.cursor.com/dashboard/bugbot).</sup> <!-- /CURSOR_SUMMARY -->
## Release 35.0.0 This release adds new React Native title primitives, continues the enum-to-const-object/string-union migration for public type exports, and updates the release documentation so breaking changes are consumer-focused and migration-oriented. ### Package Versions - `@metamask/design-system-shared`: **0.13.0** - `@metamask/design-system-react`: **0.18.0** - `@metamask/design-system-react-native`: **0.20.0** - `@metamask/design-system-tailwind-preset`: **0.6.2** ### Shared Type Updates (0.13.0) #### Added (#1051, #1053, #1059) **What Changed:** - Added `TitleStandardPropsShared` and `TitleSubpagePropsShared` - Added `TagSeverity` and `TagPropsShared` **Impact:** - Supports the new React Native `TitleStandard`, `TitleSubpage`, and `Tag` APIs #### Changed (#1026, #1042) **What Changed:** - **BREAKING:** Updated shared `Box` and `Icon` exports from enums to const objects with derived string-union types - Removed stale Box `WarningAlternative`, `SuccessAlternative`, and `InfoAlternative` color entries that no longer map to design tokens **Impact:** - Affects consumers of `@metamask/design-system-shared` directly - Platform package consumers should continue importing from `@metamask/design-system-react` or `@metamask/design-system-react-native` ### React Web Updates (0.18.0) #### Changed - **BREAKING:** Updated `IconName`, `IconColor`, and `IconSize` exports to use const-object + string-union types instead of enums (#1042, #1101) - **BREAKING:** Updated `Box` type exports to use const-object + string-union types and removed stale Box color entries (#1026) - Updated `ButtonTertiary` to use the default text color for more consistent contrast across states (#1099) ### React Native Updates (0.20.0) #### Added - Added `TitleStandard` for mobile title layouts with optional top and bottom accessory rows (#1051) - Added `TitleSubpage` for subpage headers with avatar, title, subtitle, amount, and bottom-label layouts (#1059) - Added `Tag` for compact severity-based metadata labels with optional icons or custom accessories (#1053) #### Changed - **BREAKING:** Updated `IconName`, `IconColor`, and `IconSize` exports to use const-object + string-union types instead of enums (#1042) - **BREAKING:** Updated `Box` type exports to use const-object + string-union types and removed stale Box color entries (#1026) - `Box` now forwards refs to the underlying `View` (#1102) - Updated `ButtonTertiary` to use the default text color for more consistent contrast across states (#1099) ### Tailwind Preset Updates (0.6.2) #### Changed - No consumer-facing API or behavior changes in this release; this patch republishes the existing preset without requiring changes in consuming apps ### Breaking Changes #### Icon and Box enum exports migrated to const objects plus string unions (Both Platforms) **What Changed:** - `IconName`, `IconColor`, and `IconSize` now use const objects with derived string-union types instead of enums - `BoxFlexDirection`, `BoxFlexWrap`, `BoxAlignItems`, `BoxJustifyContent`, `BoxBackgroundColor`, `BoxBorderColor`, `BoxSpacing`, and `BoxBorderWidth` now use const objects with derived string-union types instead of enums - Removed stale Box color entries with no backing design token: - `BoxBackgroundColor.WarningAlternative` - `BoxBackgroundColor.SuccessAlternative` - `BoxBorderColor.WarningAlternative` - `BoxBorderColor.SuccessAlternative` - `BoxBorderColor.InfoAlternative` **Migration:** ```tsx // Before import { BoxBackgroundColor, IconColor, IconName, } from '@metamask/design-system-react-native'; <Box backgroundColor={BoxBackgroundColor.WarningAlternative} /> <Icon name={IconName.Add} color={IconColor.IconDefault} /> // After import { BoxBackgroundColor, IconColor, IconName, } from '@metamask/design-system-react-native'; <Box backgroundColor={BoxBackgroundColor.WarningDefault} /> <Icon name={IconName.Add} color={IconColor.IconDefault} /> ``` **Impact:** - Affects consumers relying on enum-specific TypeScript behavior for `Icon*` and `Box*` exports - Import paths stay the same for platform-package consumers - Any use of the removed Box `*Alternative` color entries will need to switch to the corresponding `*Default` or `*Muted` token See migration guides for complete instructions: - [React Migration Guide](./packages/design-system-react/MIGRATION.md#from-version-0170-to-0180) - [React Native Migration Guide](./packages/design-system-react-native/MIGRATION.md#from-version-0190-to-0200) ### Validation - `yarn changelog:validate` <!-- CURSOR_SUMMARY --> --- > [!NOTE] > **Medium Risk** > Medium risk because it publishes new versions with **breaking TypeScript surface changes** (Box/Icon enums → const-object/string-union and removal of stale Box color members), which can break downstream builds despite minimal runtime behavior changes. > > **Overview** > Bumps the monorepo release to `35.0.0` and publishes new package versions for `@metamask/design-system-react` (`0.18.0`), `@metamask/design-system-react-native` (`0.20.0`), and `@metamask/design-system-shared` (`0.13.0`). > > Updates changelogs/migration guides to reflect the release: adds React Native primitives (`TitleStandard`, `TitleSubpage`, `Tag`) and shared prop contracts, and documents **breaking** shifts of `Box*` and `Icon*` exports from enums to const-object + string-union types (plus removal of stale `*Alternative` Box color entries) with consumer-facing migration steps. > > <sup>Reviewed by [Cursor Bugbot](https://cursor.com/bugbot) for commit addbae5. Bugbot is set up for automated code reviews on this repo. Configure [here](https://www.cursor.com/dashboard/bugbot).</sup> <!-- /CURSOR_SUMMARY -->


Description
Adds
TitleSubpageto@metamask/design-system-react-native: a layout for subpage headers with a required identity row (leadingtitleAvatarin a 40×40 centered slot + title stack), optional subtitle, amount (display typography when a string), optional bottom label or bottom accessory, and end accessories on title, subtitle, amount, and bottom label rows.Related issues
Fixes: https://consensyssoftware.atlassian.net/browse/DSYS-583
Manual testing steps
yarn storybook:iosoryarn storybook:android).Screenshots/Recordings
If applicable, add screenshots and/or recordings to visualize the before and after of your change.
Before
N/A — new component (or attach Storybook before/after if replacing something in-app).
After
Simulator.Screen.Recording.-.iPhone.15.Pro.Max.-.2026-04-08.at.21.41.11.mov
Pre-merge author checklist
Pre-merge reviewer checklist
Note
Low Risk
Low risk: changes are additive (new component, shared types, stories, and tests) with no modifications to existing runtime behavior beyond new exports.
Overview
Adds a new React Native
TitleSubpagecomponent for subpage header layouts, supporting a required identity row (titleAvatar+ title stack) plus optionalsubtitle,amount, and either abottomLabelrow or a custombottomAccessory, each with optional end-accessories.Exports the component from
design-system-react-native, introduces the corresponding shared props type (TitleSubpagePropsShared) indesign-system-shared, and includes Storybook stories, unit tests, and a detailed README documenting composition and prop behavior (notably passingtitleAvatardirectly as the identityBoxRowstartAccessory).Reviewed by Cursor Bugbot for commit 2c5a102. Bugbot is set up for automated code reviews on this repo. Configure here.