Skip to content

feat: [DSRN] Add TitleSubpage#1059

Merged
georgewrmarshall merged 26 commits into
mainfrom
dsrn/titlesubpage
Apr 23, 2026
Merged

feat: [DSRN] Add TitleSubpage#1059
georgewrmarshall merged 26 commits into
mainfrom
dsrn/titlesubpage

Conversation

@brianacnguyen
Copy link
Copy Markdown
Contributor

@brianacnguyen brianacnguyen commented Apr 9, 2026

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

Simulator.Screen.Recording.-.iPhone.15.Pro.Max.-.2026-04-08.at.21.41.11.mov

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
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).

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

@brianacnguyen brianacnguyen self-assigned this Apr 9, 2026
@brianacnguyen brianacnguyen requested a review from a team as a code owner April 9, 2026 04:55
@brianacnguyen brianacnguyen marked this pull request as draft April 9, 2026 04:55
@github-actions
Copy link
Copy Markdown
Contributor

github-actions Bot commented Apr 9, 2026

📖 Storybook Preview

Comment thread packages/design-system-react-native/src/components/TitleSubpage/TitleSubpage.tsx Outdated
@github-actions
Copy link
Copy Markdown
Contributor

github-actions Bot commented Apr 9, 2026

📖 Storybook Preview

@brianacnguyen brianacnguyen marked this pull request as ready for review April 10, 2026 04:45
@github-actions
Copy link
Copy Markdown
Contributor

📖 Storybook Preview

Comment thread packages/design-system-react-native/src/components/TitleSubpage/TitleSubpage.tsx Outdated
Copy link
Copy Markdown
Contributor

@georgewrmarshall georgewrmarshall left a comment

Choose a reason for hiding this comment

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

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

Comment thread packages/design-system-react-native/src/components/TitleSubpage/TitleSubpage.tsx Outdated
Comment thread packages/design-system-react-native/src/components/TitleSubpage/TitleSubpage.tsx Outdated
Comment thread packages/design-system-react-native/src/components/TitleSubpage/TitleSubpage.tsx Outdated
Comment thread packages/design-system-react-native/src/components/TitleSubpage/TitleSubpage.tsx Outdated
Comment thread packages/design-system-react-native/src/components/TitleSubpage/README.md Outdated
Comment thread packages/design-system-react-native/src/components/TitleSubpage/README.md Outdated
@github-actions
Copy link
Copy Markdown
Contributor

📖 Storybook Preview

Copy link
Copy Markdown
Contributor

@georgewrmarshall georgewrmarshall left a comment

Choose a reason for hiding this comment

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

Good progress on the simplification — the inlined layout and removal of isReactNodeRenderable / render* booleans / align-middle all look great. A few remaining items, mostly the same patterns flagged on TitleStandard (#1051) and TitleHub (#1052).

Comment thread packages/design-system-react-native/src/components/TitleSubpage/TitleSubpage.tsx Outdated
Comment thread packages/design-system-react-native/src/components/TitleSubpage/TitleSubpage.tsx Outdated
Comment thread packages/design-system-shared/src/types/TitleSubpage/TitleSubpage.types.ts Outdated
Comment thread packages/design-system-react-native/src/components/TitleSubpage/README.md Outdated
Comment thread packages/design-system-react-native/src/components/TitleSubpage/README.md Outdated
Comment thread packages/design-system-react-native/src/components/TitleSubpage/README.md Outdated
Copy link
Copy Markdown
Contributor

@georgewrmarshall georgewrmarshall left a comment

Choose a reason for hiding this comment

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

Follow-up review — component structure, tests, and the same recurring patterns from TitleStandard/TitleHub.

Comment thread packages/design-system-react-native/src/components/TitleSubpage/TitleSubpage.tsx Outdated
Comment thread packages/design-system-react-native/src/components/TitleSubpage/TitleSubpage.tsx Outdated
Comment thread packages/design-system-react-native/src/components/TitleSubpage/TitleSubpage.tsx Outdated
Comment thread packages/design-system-shared/src/types/TitleSubpage/TitleSubpage.types.ts Outdated
Comment thread packages/design-system-react-native/src/components/TitleSubpage/README.md Outdated
@github-actions
Copy link
Copy Markdown
Contributor

📖 Storybook Preview

@github-actions
Copy link
Copy Markdown
Contributor

📖 Storybook Preview

@github-actions
Copy link
Copy Markdown
Contributor

📖 Storybook Preview

Comment on lines +70 to +79
startAccessory={
<Box
testID="title-subpage-title-avatar-slot"
alignItems={BoxAlignItems.Center}
justifyContent={BoxJustifyContent.Center}
twClassName="size-10 overflow-hidden"
>
{titleAvatar}
</Box>
}
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.

Still curious if this Box wrapper is necessary?

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.

@georgewrmarshall this is to make sure the avatar is contained within a 40px x 40px box. what do you think?

Copy link
Copy Markdown
Contributor

@georgewrmarshall georgewrmarshall Apr 22, 2026

Choose a reason for hiding this comment

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

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?

@github-actions
Copy link
Copy Markdown
Contributor

📖 Storybook Preview

@github-actions
Copy link
Copy Markdown
Contributor

📖 Storybook Preview

Copy link
Copy Markdown
Contributor

@cursor cursor Bot left a comment

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 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.
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.

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.

Fix in Cursor Fix in Web

Triggered by learned rule: JSDoc and README must match implementation behavior

Reviewed by Cursor Bugbot for commit 1ec1d52. Configure here.

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.

false positive we always provide content in a string

@github-actions
Copy link
Copy Markdown
Contributor

📖 Storybook Preview

Copy link
Copy Markdown
Contributor

@georgewrmarshall georgewrmarshall left a comment

Choose a reason for hiding this comment

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

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.

Comment thread packages/design-system-react-native/src/components/TitleSubpage/TitleSubpage.tsx Outdated
@github-actions
Copy link
Copy Markdown
Contributor

📖 Storybook Preview

@github-actions
Copy link
Copy Markdown
Contributor

📖 Storybook Preview

Copy link
Copy Markdown
Contributor

@georgewrmarshall georgewrmarshall left a comment

Choose a reason for hiding this comment

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

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.
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.

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).

@georgewrmarshall georgewrmarshall merged commit b94b0d5 into main Apr 23, 2026
44 checks passed
@georgewrmarshall georgewrmarshall deleted the dsrn/titlesubpage branch April 23, 2026 21:04
@georgewrmarshall georgewrmarshall mentioned this pull request Apr 23, 2026
georgewrmarshall added a commit that referenced this pull request Apr 23, 2026
## 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 -->
georgewrmarshall pushed a commit that referenced this pull request Apr 27, 2026
## **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 -->
georgewrmarshall added a commit that referenced this pull request Apr 27, 2026
## 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 -->
georgewrmarshall added a commit that referenced this pull request Apr 28, 2026
## 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 -->
cursor Bot pushed a commit that referenced this pull request Apr 28, 2026
## **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 -->
cursor Bot pushed a commit that referenced this pull request Apr 28, 2026
## 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 -->
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants