Skip to content

feat: migrate MainActionButton to design-system-react-native#952

Merged
georgewrmarshall merged 21 commits into
mainfrom
feat/dsys-296-main-action-button-rn
Mar 6, 2026
Merged

feat: migrate MainActionButton to design-system-react-native#952
georgewrmarshall merged 21 commits into
mainfrom
feat/dsys-296-main-action-button-rn

Conversation

@georgewrmarshall

@georgewrmarshall georgewrmarshall commented Mar 3, 2026

Copy link
Copy Markdown
Contributor

Description

  • migrate MainActionButton from MetaMask Mobile component-library temp components into @metamask/design-system-react-native
  • add component source, types, constants, styles, stories, tests, and README under packages/design-system-react-native/src/components/MainActionButton
  • export MainActionButton from RN components barrel

Related issue

Screenshots

Mobile

mobile.main.action.button.mov

MMDS

mainactionbutton.mov

Notes


Note

Low Risk
Low risk: primarily adds a new UI component with isolated exports plus Storybook wiring and tests; minimal impact on existing runtime behavior aside from the new barrel export.

Overview
Adds a new MainActionButton component to design-system-react-native, including its implementation, typed props, README docs, Storybook stories, and a test suite covering disabled/press handling, prop forwarding, and style merging.

Wires the component into the library and RN Storybook by exporting it from the components barrel and registering the new story; also makes a small cleanup to TabEmptyState story’s onAction handler comment.

Written by Cursor Bugbot for commit e67d853. This will update automatically on new commits. Configure here.

@georgewrmarshall georgewrmarshall force-pushed the feat/dsys-296-main-action-button-rn branch from dd39cd1 to d06237a Compare March 4, 2026 04:59
@github-actions

github-actions Bot commented Mar 4, 2026

Copy link
Copy Markdown
Contributor

📖 Storybook Preview

@github-actions

github-actions Bot commented Mar 4, 2026

Copy link
Copy Markdown
Contributor

📖 Storybook Preview

@georgewrmarshall georgewrmarshall force-pushed the feat/dsys-296-main-action-button-rn branch from e91636c to 3ccca16 Compare March 5, 2026 00:16
@github-actions

github-actions Bot commented Mar 5, 2026

Copy link
Copy Markdown
Contributor

📖 Storybook Preview

@georgewrmarshall georgewrmarshall left a comment

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.

Left some comments

Comment on lines +70 to +76
export const ActionButtonOnPress: Story = {
args: {
iconName: IconName.Add,
label: 'Tap me',
isDisabled: false,
},
};

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.

Let's remove this story

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.

Updated

Comment on lines +1 to +8
export const TWCLASS_MAINACTIONBUTTON_BASE =
'items-center justify-center rounded-xl px-1 py-4 min-w-[68px]';

export const TWCLASS_MAINACTIONBUTTON_CONTAINER =
'items-center justify-center w-full';

export const TWCLASS_MAINACTIONBUTTON_LABEL =
'mt-0.5 w-full text-center shrink';

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.

These can all be applied directly in the component file

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.

Updated

@georgewrmarshall georgewrmarshall force-pushed the feat/dsys-296-main-action-button-rn branch from 3ccca16 to 9844bbb Compare March 5, 2026 18:44
@github-actions

github-actions Bot commented Mar 5, 2026

Copy link
Copy Markdown
Contributor

📖 Storybook Preview

@github-actions

github-actions Bot commented Mar 5, 2026

Copy link
Copy Markdown
Contributor

📖 Storybook Preview

@georgewrmarshall georgewrmarshall self-assigned this Mar 5, 2026
onPress: {
action: 'pressed',
description: 'Callback fired when the action button is pressed.',
},

@georgewrmarshall georgewrmarshall Mar 5, 2026

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Intentionally not adding twClassName here as it causes errors in storybook

Image

@github-actions

github-actions Bot commented Mar 5, 2026

Copy link
Copy Markdown
Contributor

📖 Storybook Preview

@github-actions

github-actions Bot commented Mar 5, 2026

Copy link
Copy Markdown
Contributor

📖 Storybook Preview

@cursor cursor Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

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

Autofix Details

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

  • ✅ Fixed: labelProps type allows props silently overridden at runtime
    • Added 'numberOfLines' and 'ellipsizeMode' to the labelProps Omit type to align types with hardcoded Text props.

Create PR

Or push these changes by commenting:

@cursor push 7f0a0c1dfe
Preview (7f0a0c1dfe)
diff --git a/packages/design-system-react-native/src/components/MainActionButton/MainActionButton.types.ts b/packages/design-system-react-native/src/components/MainActionButton/MainActionButton.types.ts
--- a/packages/design-system-react-native/src/components/MainActionButton/MainActionButton.types.ts
+++ b/packages/design-system-react-native/src/components/MainActionButton/MainActionButton.types.ts
@@ -31,7 +31,13 @@
    */
   labelProps?: Omit<
     Partial<TextProps>,
-    'children' | 'variant' | 'fontWeight' | 'color' | 'twClassName'
+    | 'children'
+    | 'variant'
+    | 'fontWeight'
+    | 'color'
+    | 'twClassName'
+    | 'numberOfLines'
+    | 'ellipsizeMode'
   >;
   /**
    * Disables the button interaction and applies disabled styling.

@georgewrmarshall georgewrmarshall marked this pull request as ready for review March 5, 2026 22:07
@georgewrmarshall georgewrmarshall requested a review from a team as a code owner March 5, 2026 22:07
disabled={isDisabled}
accessible
onPress={!isDisabled ? onPress : undefined}
onPressIn={!isDisabled ? onPressIn : undefined}

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.

Disabled state explicitly removes onPressIn and onPressOut alongside onPress so integrations do not run side effects while the button is non-interactive.

) as StyleProp<ViewStyle>;

const additionalStyle =
typeof style === 'function' ? style({ pressed }) : style;

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

The style callback runs for both pressed and idle states and merges after base tokens so consumers can layer interaction overrides without replacing layout defaults.

* Optional props forwarded to the internal Text component.
* Useful for test IDs and accessibility metadata.
*/
labelProps?: Omit<

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.

iconProps and labelProps intentionally omit controlled visual props so size, color, and typography stay consistent while still allowing test IDs and accessibility metadata.

expect(onPress).toHaveBeenCalledTimes(1);
});

it('does not call press handlers when disabled', () => {

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.

This disabled interaction test exercises press, pressIn, and pressOut together because guarding all three handlers prevents downstream side effects in analytics and navigation hooks.

brianacnguyen
brianacnguyen previously approved these changes Mar 5, 2026
@github-actions

github-actions Bot commented Mar 6, 2026

Copy link
Copy Markdown
Contributor

📖 Storybook Preview

@georgewrmarshall georgewrmarshall enabled auto-merge (squash) March 6, 2026 01:09
@georgewrmarshall georgewrmarshall force-pushed the feat/dsys-296-main-action-button-rn branch from a19f71a to bb0880b Compare March 6, 2026 01:09
@github-actions

github-actions Bot commented Mar 6, 2026

Copy link
Copy Markdown
Contributor

📖 Storybook Preview

description="No results found"
actionButtonText="Try Again"
onAction={() => {
// eslint-disable-next-line no-console

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.

Fixes eslint warning for unused eslint disablle comment

@github-actions

github-actions Bot commented Mar 6, 2026

Copy link
Copy Markdown
Contributor

📖 Storybook Preview

@github-actions

github-actions Bot commented Mar 6, 2026

Copy link
Copy Markdown
Contributor

📖 Storybook Preview

@github-actions

github-actions Bot commented Mar 6, 2026

Copy link
Copy Markdown
Contributor

📖 Storybook Preview

@cursor cursor Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

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

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

  • ✅ Fixed: Story export IconName shadows imported enum IconName
    • Renamed the story export from IconName to IconStory and set name: 'IconName' so references in renders now resolve to the imported enum without changing the story's displayed name.

Create PR

Or push these changes by commenting:

@cursor push a0de1bc250
Preview (a0de1bc250)
diff --git a/packages/design-system-react-native/src/components/MainActionButton/MainActionButton.stories.tsx b/packages/design-system-react-native/src/components/MainActionButton/MainActionButton.stories.tsx
--- a/packages/design-system-react-native/src/components/MainActionButton/MainActionButton.stories.tsx
+++ b/packages/design-system-react-native/src/components/MainActionButton/MainActionButton.stories.tsx
@@ -89,7 +89,8 @@
   },
 };
 
-export const IconName: Story = {
+export const IconStory: Story = {
+  name: 'IconName',
   parameters: {
     actions: {
       disable: true,

@github-actions

github-actions Bot commented Mar 6, 2026

Copy link
Copy Markdown
Contributor

📖 Storybook Preview

@georgewrmarshall georgewrmarshall force-pushed the feat/dsys-296-main-action-button-rn branch from a3a299e to e67d853 Compare March 6, 2026 19:53
@github-actions

github-actions Bot commented Mar 6, 2026

Copy link
Copy Markdown
Contributor

📖 Storybook Preview

@georgewrmarshall georgewrmarshall merged commit 4159128 into main Mar 6, 2026
43 checks passed
@georgewrmarshall georgewrmarshall deleted the feat/dsys-296-main-action-button-rn branch March 6, 2026 20:34
@georgewrmarshall georgewrmarshall mentioned this pull request Mar 10, 2026
6 tasks
georgewrmarshall added a commit that referenced this pull request Mar 10, 2026
## Release 25.0.0

This release includes new components migrated from Extension and Mobile,
breaking API improvements to ButtonIcon and Input components, and
continued ADR-0003/0004 type migrations.

### 📦 Package Versions

- `@metamask/design-system-shared`: **0.4.0**
- `@metamask/design-system-react`: **0.11.0**
- `@metamask/design-system-react-native`: **0.11.0**

### 🔄 Shared Type Updates (0.4.0)

#### Component Type Additions (#964, #955)

Added shared types for newly migrated components following ADR-0003 and
ADR-0004 patterns:

**What Changed:**
- Added `ButtonFilter` shared types with `ButtonFilterVariant` const
object and `ButtonFilterPropsShared`
- Added `BannerBase` shared types with `BannerBaseSeverity` const object
and `BannerBasePropsShared`

**Impact:**
- Enables consistent ButtonFilter and BannerBase implementations across
React and React Native
- Continues ADR-0003/0004 const-object + string-union pattern adoption

### 🌐 React Web Updates (0.11.0)

#### Added
- Added `ButtonFilter` component for filter button functionality (#964)
- Added `BannerBase` component for creating custom banner notifications
(#961)

#### Changed
- **BREAKING:** Updated `ButtonIcon` API to use `variant` prop instead
of `isInverse` and `isFloating` boolean props (#948)
- Updated `Ai` icon to filled version for visual consistency (#970)

### 📱 React Native Updates (0.11.0)

#### Added
- Added `ButtonFilter` component (#964)
- Added `BottomSheet` component for modal interactions (#963)
- Added `MainActionButton` component for primary CTAs (#952)
- Added `BannerBase` component for custom banners (#955)
- Added `ListItem` component for standardized list rows (#958)
- Added `TabEmptyState` component for empty states (#949)
- Added `BottomSheetDialog` component for dialogs (#905)

#### Changed
- **BREAKING:** Updated `ButtonIcon` API to use `variant` prop instead
of `isInverse` and `isFloating` boolean props (#948)
- **BREAKING:** `Input` component now requires `value` prop and is
controlled-only (#960)
- Updated `Ai` icon to filled version (#970)

#### Fixed
- Fixed iOS placeholder alignment issue in `Input` component (#960)
- Fixed missing component exports (#967)

### ⚠️ Breaking Changes

#### ButtonIcon Variant Prop (Both Platforms)

**What Changed:**
- Removed `isInverse` and `isFloating` boolean props
- Added `variant` prop with three options:
  - `ButtonIconVariant.Default` (transparent background - default)
- `ButtonIconVariant.Filled` (muted background with rounded corners -
new)
- `ButtonIconVariant.Floating` (colored background with inverse icon -
replaces `isFloating`)

**Migration:**
```tsx
// Before
<ButtonIcon name={IconName.Add} isFloating />

// After
<ButtonIcon name={IconName.Add} variant={ButtonIconVariant.Floating} />
```

See migration guides for complete instructions:
- [React Migration
Guide](./packages/design-system-react/MIGRATION.md#from-version-0100-to-0110)
- [React Native Migration
Guide](./packages/design-system-react-native/MIGRATION.md#from-version-0100-to-0110)

#### Input Controlled-Only (React Native Only)

**What Changed:**
- Removed `defaultValue` prop
- `value` prop is now required
- All Input instances must be controlled with state management

**Migration:**
```tsx
// Before
<Input placeholder="Enter text" defaultValue="Initial" onChange={handleChange} />

// After
const [text, setText] = useState('Initial');
<Input placeholder="Enter text" value={text} onChange={setText} />
```

**Impact:**
- Affects `Input` and `TextField` components
- Provides consistent behavior and fixes iOS placeholder alignment

See [React Native Migration
Guide](./packages/design-system-react-native/MIGRATION.md#from-version-0100-to-0110)
for complete instructions.

### ✅ Checklist

- [x] Changelogs updated with human-readable descriptions
- [x] Changelog validation passed (`yarn changelog:validate`)
- [x] Version bumps follow semantic versioning
  - design-system-shared: minor (0.3.0 → 0.4.0) - new shared types
- design-system-react: minor (0.10.0 → 0.11.0) - new components +
breaking ButtonIcon change
- design-system-react-native: minor (0.10.0 → 0.11.0) - new components +
breaking ButtonIcon and Input changes
- [x] Breaking changes documented with migration guidance
- [x] Migration guides updated with before/after examples
- [x] PR references included in changelog entries

<!-- CURSOR_SUMMARY -->
---

> [!NOTE]
> **Medium Risk**
> Although this PR is mostly versioning/docs, it formalizes breaking
public API changes (`ButtonIcon` and RN `Input`) that will require
downstream updates and could cause consumer build failures if missed.
> 
> **Overview**
> Bumps the monorepo release to `25.0.0` and publishes new package
versions (`@metamask/design-system-react@0.11.0`,
`@metamask/design-system-react-native@0.11.0`,
`@metamask/design-system-shared@0.4.0`) with updated changelogs.
> 
> Documents newly added components/types (`ButtonFilter`, `BannerBase`,
plus several React Native-only additions like `BottomSheet`, `ListItem`,
etc.) and **breaking API changes**: `ButtonIcon` replaces
`isInverse`/`isFloating` with a `variant` prop (React + RN), and React
Native `Input` becomes controlled-only (requires `value`, removes
`defaultValue`). Migration guides are updated with before/after examples
and new compare links.
> 
> <sup>Written by [Cursor
Bugbot](https://cursor.com/dashboard?tab=bugbot) for commit
0148a27. This will update automatically
on new commits. Configure
[here](https://cursor.com/dashboard?tab=bugbot).</sup>
<!-- /CURSOR_SUMMARY -->
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants