feat: migrate BannerBase to MMDS react#961
Conversation
📖 Storybook Preview |
| > | ||
| {startAccessory} | ||
|
|
||
| <Box className="min-w-0 flex-1"> |
There was a problem hiding this comment.
Can probably improve some nesting here in the polish stages
There was a problem hiding this comment.
Cursor Bugbot has reviewed your changes and found 1 potential issue.
Autofix Details
Bugbot Autofix prepared a fix for the issue found in the latest run.
- ✅ Fixed: Shared package imports
reactwithout declaring dependency- Added react as a peerDependency in @metamask/design-system-shared/package.json to satisfy ReactNode type references.
Or push these changes by commenting:
@cursor push 71fe057fff
Preview (71fe057fff)
diff --git a/packages/design-system-shared/package.json b/packages/design-system-shared/package.json
--- a/packages/design-system-shared/package.json
+++ b/packages/design-system-shared/package.json
@@ -57,6 +57,9 @@
"ts-jest": "^29.2.5",
"typescript": "~5.2.2"
},
+ "peerDependencies": {
+ "react": "^17.0.0 || ^18.0.0"
+ },
"engines": {
"node": "^18.18 || >=20"
},
diff --git a/yarn.lock b/yarn.lock
--- a/yarn.lock
+++ b/yarn.lock
@@ -3473,6 +3473,8 @@
jest: "npm:^29.7.0"
ts-jest: "npm:^29.2.5"
typescript: "npm:~5.2.2"
+ peerDependencies:
+ react: ^17.0.0 || ^18.0.0
languageName: unknown
linkType: soft| } = closeButtonProps ?? {}; | ||
|
|
||
| const shouldShowCloseButton = Boolean(onClose || closeButtonProps); | ||
| const shouldShowActionButton = Boolean(actionButtonOnClick); |
There was a problem hiding this comment.
Action rendering is intentionally keyed off the handler rather than label presence so a label-only prop does not create an inert button. This keeps runtime behavior aligned with the conditional requirement documented in the API.
| ))} | ||
|
|
||
| {hasContent(description) && ( | ||
| <Box className={hasContent(title) ? 'mt-1' : undefined}> |
There was a problem hiding this comment.
Using hasContent for both rendering and spacing avoids the numeric zero edge case where title exists but is falsy. This keeps text wrapping and vertical rhythm consistent for number-based content.
| /** | ||
| * Optional test id for the close button element. | ||
| */ | ||
| 'data-testid'?: string; |
There was a problem hiding this comment.
The close-button test selector is explicit on closeButtonProps so consumers can opt in to testing hooks without BannerBase baking in a fixed id. This keeps the base component less opinionated while still supporting stable tests.
| closeButtonProps?: BannerBaseCloseButtonProps; | ||
| }; | ||
|
|
||
| type BannerBaseActionPropsWithHandler = { |
There was a problem hiding this comment.
This discriminated union encodes the runtime rule that a label is required when the click handler exists, so misuse is surfaced at compile time instead of silently producing incomplete UI.
📖 Storybook Preview |
| expect(screen.getByText('Body copy')).toBeInTheDocument(); | ||
| }); | ||
|
|
||
| it('renders numeric title, description, and children', () => { |
There was a problem hiding this comment.
These numeric content assertions protect the non-obvious edge case where 0 can bypass truthy checks and skip Text wrapping. Keeping this in tests prevents regressions that are easy to miss in visual review.
| onClick={onClose ?? closeButtonPropsOnClick} | ||
| {...resolvedCloseButtonProps} | ||
| /> | ||
| )} |
There was a problem hiding this comment.
Close button spread can override explicit size prop
Low Severity
The {...resolvedCloseButtonProps} spread on ButtonIcon comes after the explicit size={ButtonIconSize.Sm} prop. Since BannerBaseCloseButtonProps only omits iconName and onClick from ButtonIconProps, properties like size, variant, and isDisabled remain in resolvedCloseButtonProps and silently override the component's hardcoded defaults. The same pattern applies to the action Button where {...resolvedActionButtonProps} follows size={ButtonSize.Md} and onClick={actionButtonOnClick} — while onClick is type-omitted, size is not and can override the default.
## 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 -->



Description
BannerBaseinto MMDS for@metamask/design-system-react.@metamask/design-system-sharedviaBannerBasePropsShared(ADR-0004 layering).Box,Text,Button,ButtonIcon) with default primary action button behavior.Scope note:
Related issues
Fixes:
Manual testing steps
yarn buildfrom repo root.yarn testfrom repo root.yarn lintfrom repo root.BannerBasestories:Default,Title,Description,Children,ActionButtonOnClick,OnClose,StartAccessory.DefaultandActionButtonOnClickrender an action button.Screenshots/Recordings
Before
BannerBase in extension
bannerbase.ext720.mov
BannerBase in mobile
bannerbasemobile.720.mov
After
@metamask/design-system-react.@metamask/design-system-shared.Stories
storybook720.mov
READMES
docs720.mov
Pre-merge author checklist
Pre-merge reviewer checklist
Note
Low Risk
Additive change that introduces a new exported component plus stories/tests/docs; low risk beyond potential minor API/export or styling regressions in consumers that adopt it.
Overview
Introduces a new
BannerBasecomponent built from MMDS primitives (Box,Text,Button,ButtonIcon), including optional title/description/body content, a start accessory slot, an optional close affordance, and a conditional action button that only renders whenactionButtonOnClickis provided.Adds
BannerBaseProps(layered on sharedBannerBasePropsShared), Storybook stories + MDX README docs, and a unit test suite covering rendering variants and click handling. ExportsBannerBasefrom the component barrel (components/index.ts).Written by Cursor Bugbot for commit e7fb088. This will update automatically on new commits. Configure here.