Skip to content

refactor: updated ButtonIcon to have variant prop#948

Merged
brianacnguyen merged 4 commits into
mainfrom
update/button-icon-variants
Mar 5, 2026
Merged

refactor: updated ButtonIcon to have variant prop#948
brianacnguyen merged 4 commits into
mainfrom
update/button-icon-variants

Conversation

@brianacnguyen

@brianacnguyen brianacnguyen commented Feb 27, 2026

Copy link
Copy Markdown
Contributor

Description

This PR updates the ButtonIcon API in both @metamask/design-system-react and @metamask/design-system-react-native to use a single variant prop instead of isInverse and isFloating, and adds a Filled variant.

Reason for change

  • Simplify the API by replacing two boolean props with one variant prop.
  • Align with the existing variant pattern (e.g. ButtonVariant).
  • Support a third style (muted, rounded-full) without adding more booleans.

Changes

  1. Removed props

    • isInverse (removed from both packages).
    • isFloating (replaced by variant).
  2. New variant prop and ButtonIconVariant

    • ButtonIconVariant.Default (default): Transparent background, text-icon-default, rounded-lg; hover/pressed use bg-hover / bg-pressed (React: hover + active; RN: pressed).
    • ButtonIconVariant.Filled: Muted background (bg-muted), text-icon-default, rounded-full; hover/pressed use muted tokens (hover:bg-muted-hover, active:bg-muted-pressed / bg-muted-pressed).
    • ButtonIconVariant.Floating: Same as previous “floating” style: rounded-full, bg-icon-default, inverse icon color (text-primary-inverse / text-background-default).
  3. Types

    • ButtonIconVariant enum added in both packages’ types (e.g. packages/design-system-react-native/src/types/index.ts and React equivalent).
    • ButtonIcon props use variant?: ButtonIconVariant with default ButtonIconVariant.Default.
  4. Toast (React Native only)

    • Toast’s close-button type previously used a local ButtonIconVariant (value Icon). That enum is renamed to ToastCloseButtonVariant to avoid clashing with the new ButtonIcon style variant.
    • ToastCloseButtonIconOptions is now Omit<ButtonIconProps, 'variant'> & { variant: ToastCloseButtonVariant } so the close button stays correctly typed.
    • Close button rendering narrows with 'iconName' in closeButtonOptions and passes only ButtonIcon-relevant props (no ToastCloseButtonVariant passed as variant to ButtonIcon).
  5. Docs and tooling

    • README/MDX, Storybook stories, Figma Code Connect, and tests are updated for the new variant API and the three variants in both packages.

Breaking changes

  • ButtonIcon: isInverse and isFloating are removed. Use variant instead:
    • No prop or variant={ButtonIconVariant.Default} for the previous default look.
    • variant={ButtonIconVariant.Floating} for the previous isFloating look.
    • variant={ButtonIconVariant.Filled} for the new filled style.
  • Toast: The close-button icon option still uses variant: ToastCloseButtonVariant.Icon; the export name changes from ButtonIconVariant to ToastCloseButtonVariant for that discriminant.

Related issues

Fixes: DSYS-492


Manual testing steps

  1. React Native (Storybook)

    • Run yarn storybook:ios or yarn storybook:android.
    • Open Components → Button Icon.
    • Confirm Default, Filled, and Floating stories and the variant control behave as above (default transparent, filled muted + rounded-full, floating with inverse icon).
  2. React (Storybook)

    • Run yarn storybook.
    • Open React Components → ButtonIcon.
    • Confirm Default, Filled, and Floating (and variant control) match the same behavior, including hover/active for Default and Filled.
  3. Toast (React Native)

    • In Storybook, open a Toast story that uses an icon close button (closeButtonOptions with iconName and variant: ToastCloseButtonVariant.Icon).
    • Confirm the close button still renders and closes the toast.
  4. Consumers

    • Replace any isFloating / isInverse usage with variant={ButtonIconVariant.Default | Filled | Floating} and re-check screens that use ButtonIcon.

Screenshots/Recordings

Before

After

DSRN

Simulator.Screen.Recording.-.iPhone.15.Pro.Max.-.2026-02-26.at.22.16.45.mov

DSR

Screen.Recording.2026-02-26.at.10.17.42.PM.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

Medium Risk
Medium risk due to a breaking prop API change (isInverse/isFloating removed) that requires consumer updates and could cause subtle style/interaction regressions across platforms.

Overview
Unifies ButtonIcon styling under a new variant prop in both design-system-react and design-system-react-native, removing isInverse/isFloating and introducing ButtonIconVariant (Default, Floating, new Filled) with updated pressed/hover behavior.

Updates Storybook stories, Figma Code Connect mappings, docs, exports, and tests to reflect the new API and validate the new Filled styling.

In React Native Toast, renames the close-button discriminant enum to ToastCloseButtonVariant and refactors close-button option typing/rendering so icon close buttons no longer collide with the new ButtonIconVariant.

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

@brianacnguyen brianacnguyen requested a review from a team as a code owner February 27, 2026 06:24
@github-actions

Copy link
Copy Markdown
Contributor

📖 Storybook Preview

@github-actions

github-actions Bot commented Mar 2, 2026

Copy link
Copy Markdown
Contributor

📖 Storybook Preview

@github-actions

github-actions Bot commented Mar 2, 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 is OFF. To automatically fix reported issues with cloud agents, have a team admin enable autofix in the Cursor dashboard.

Comment thread apps/storybook-react-native/.storybook/storybook.requires.js Outdated

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

LGMT! But blocking until we merge MMDS v24 release #954. I think this change can go into it's own release

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

LGTM!

@brianacnguyen brianacnguyen enabled auto-merge (squash) March 5, 2026 06:54
@github-actions

github-actions Bot commented Mar 5, 2026

Copy link
Copy Markdown
Contributor

📖 Storybook Preview

@brianacnguyen brianacnguyen merged commit 056d85d into main Mar 5, 2026
43 checks passed
@brianacnguyen brianacnguyen deleted the update/button-icon-variants branch March 5, 2026 06:58
@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