feat: add BannerAlert React Native and shared types#966
Conversation
📖 Storybook Preview |
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: React constants hardcode severity type, diverging from shared
- Updated React constants to import BannerAlertSeverity from the shared package, derive the severity union type from it, and set the default via BannerAlertSeverity.Info, ensuring Record maps are compile-time validated against shared severities.
Or push these changes by commenting:
@cursor push 1e100bdb90
Preview (1e100bdb90)
diff --git a/packages/design-system-react/src/components/BannerAlert/BannerAlert.constants.ts b/packages/design-system-react/src/components/BannerAlert/BannerAlert.constants.ts
--- a/packages/design-system-react/src/components/BannerAlert/BannerAlert.constants.ts
+++ b/packages/design-system-react/src/components/BannerAlert/BannerAlert.constants.ts
@@ -1,8 +1,10 @@
+import { BannerAlertSeverity } from '@metamask/design-system-shared';
import { BoxBackgroundColor, IconColor, IconName, IconSize } from '../../types';
-type BannerAlertSeverityType = 'info' | 'success' | 'warning' | 'danger';
+type BannerAlertSeverityType =
+ (typeof BannerAlertSeverity)[keyof typeof BannerAlertSeverity];
-export const DEFAULT_BANNER_ALERT_SEVERITY: BannerAlertSeverityType = 'info';
+export const DEFAULT_BANNER_ALERT_SEVERITY = BannerAlertSeverity.Info;
export const MAP_BANNER_ALERT_SEVERITY_ICON_NAME: Record<
BannerAlertSeverityType,096fd41 to
bcce9cd
Compare
📖 Storybook Preview |
📖 Storybook Preview |
18b39e7 to
eedeee6
Compare
📖 Storybook Preview |
📖 Storybook Preview |
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: Spread order lets users override severity-driven props
- Moved the props spread before explicit severity-driven props in both web and React Native BannerAlert components so consumer values cannot override computed startAccessory, backgroundColor, or paddingLeft.
Or push these changes by commenting:
@cursor push 394e624fb0
Preview (394e624fb0)
diff --git a/packages/design-system-react-native/src/components/BannerAlert/BannerAlert.tsx b/packages/design-system-react-native/src/components/BannerAlert/BannerAlert.tsx
--- a/packages/design-system-react-native/src/components/BannerAlert/BannerAlert.tsx
+++ b/packages/design-system-react-native/src/components/BannerAlert/BannerAlert.tsx
@@ -38,6 +38,7 @@
return (
<BannerBase
+ {...props}
startAccessory={
<Icon
testID={BANNER_ALERT_ICON_TEST_ID}
@@ -49,7 +50,6 @@
backgroundColor={backgroundColor}
paddingLeft={2}
twClassName={mergedTwClassName}
- {...props}
/>
);
};
diff --git a/packages/design-system-react/src/components/BannerAlert/BannerAlert.tsx b/packages/design-system-react/src/components/BannerAlert/BannerAlert.tsx
--- a/packages/design-system-react/src/components/BannerAlert/BannerAlert.tsx
+++ b/packages/design-system-react/src/components/BannerAlert/BannerAlert.tsx
@@ -35,6 +35,7 @@
return (
<BannerBase
ref={ref}
+ {...props}
startAccessory={
<Icon
data-testid={BANNER_ALERT_ICON_TEST_ID}
@@ -46,7 +47,6 @@
backgroundColor={backgroundColor}
paddingLeft={2}
className={mergedClassName}
- {...props}
/>
);
},
📖 Storybook Preview |
📖 Storybook Preview |
📖 Storybook Preview |
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: Unnecessary variable alias adds dead indirection
- Removed the redundant resolvedSeverity alias and used severity directly in all map lookups.
Or push these changes by commenting:
@cursor push 8d09acce91
Preview (8d09acce91)
diff --git a/packages/design-system-react-native/src/components/BannerAlert/BannerAlert.tsx b/packages/design-system-react-native/src/components/BannerAlert/BannerAlert.tsx
--- a/packages/design-system-react-native/src/components/BannerAlert/BannerAlert.tsx
+++ b/packages/design-system-react-native/src/components/BannerAlert/BannerAlert.tsx
@@ -19,13 +19,12 @@
twClassName,
...props
}) => {
- const resolvedSeverity = severity;
- const iconName = MAP_BANNER_ALERT_SEVERITY_ICON_NAME[resolvedSeverity];
- const iconColor = MAP_BANNER_ALERT_SEVERITY_ICON_COLOR[resolvedSeverity];
+ const iconName = MAP_BANNER_ALERT_SEVERITY_ICON_NAME[severity];
+ const iconColor = MAP_BANNER_ALERT_SEVERITY_ICON_COLOR[severity];
const backgroundColor =
- MAP_BANNER_ALERT_SEVERITY_BACKGROUND_COLOR[resolvedSeverity];
+ MAP_BANNER_ALERT_SEVERITY_BACKGROUND_COLOR[severity];
const borderColorClass =
- MAP_BANNER_ALERT_SEVERITY_BORDER_COLOR[resolvedSeverity] ??
+ MAP_BANNER_ALERT_SEVERITY_BORDER_COLOR[severity] ??
BoxBorderColor.BorderDefault;
const mergedTwClassName = `border-l-4 ${borderColorClass}${
twClassName ? ` ${twClassName}` : ''
📖 Storybook Preview |
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: Inconsistent iconProps spread order across platforms
- Updated React BannerAlert to spread iconProps before severity-driven props to match React Native and ensure consistent runtime behavior.
Or push these changes by commenting:
@cursor push a4794ee24b
Preview (a4794ee24b)
diff --git a/packages/design-system-react/src/components/BannerAlert/BannerAlert.tsx b/packages/design-system-react/src/components/BannerAlert/BannerAlert.tsx
--- a/packages/design-system-react/src/components/BannerAlert/BannerAlert.tsx
+++ b/packages/design-system-react/src/components/BannerAlert/BannerAlert.tsx
@@ -33,10 +33,10 @@
ref={ref}
startAccessory={
<Icon
+ {...iconProps}
name={iconName}
color={iconColor}
size={IconSize.Lg}
- {...iconProps}
/>
}
backgroundColor={backgroundColor}
📖 Storybook Preview |
📖 Storybook Preview |
📖 Storybook Preview |
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: Test asserts non-existent
data-nameattribute on Icon- Updated the web BannerAlert test to mock the Icon component so it renders a data-name attribute, allowing the assertions to correctly verify the rendered icon without changing production code.
Or push these changes by commenting:
@cursor push df4c553835
Preview (df4c553835)
diff --git a/packages/design-system-react/src/components/BannerAlert/BannerAlert.test.tsx b/packages/design-system-react/src/components/BannerAlert/BannerAlert.test.tsx
--- a/packages/design-system-react/src/components/BannerAlert/BannerAlert.test.tsx
+++ b/packages/design-system-react/src/components/BannerAlert/BannerAlert.test.tsx
@@ -7,6 +7,18 @@
import { BannerAlertSeverity } from '.';
+jest.mock('../Icon', () => {
+ const React = require('react');
+ return {
+ Icon: ({ name, color, ...rest }: any) =>
+ React.createElement('svg', {
+ 'data-name': name,
+ 'data-testid': (rest as any)['data-testid'],
+ className: color,
+ }),
+ };
+});
+
const ICON_TEST_ID = 'banner-alert-icon';
describe('BannerAlert', () => {383c5e1 to
4f1e768
Compare
ffad99e to
9676cfe
Compare
📖 Storybook Preview |
|
Updated PR to focus on React Native + shared types implementation only. ✅ React Native implementation (design-system-react-native) The React implementation has been moved to PR #975 for separate, focused review of each platform. Key patterns demonstrated:
|
📖 Storybook Preview |
| } | ||
| backgroundColor={backgroundColor} | ||
| paddingLeft={2} | ||
| style={[tw.style(`border-l-4 ${borderColorClass}`), style]} |
There was a problem hiding this comment.
Array pattern for tw.style() + style prop merging. This should be the new recommended React Native pattern from the styling guidelines. Created PR for rule update here #974
| | `BannerAlertSeverity.Info` (`'Info'`) | `BannerAlertSeverity.Info` (`'info'`) | casing changed | | ||
| | `BannerAlertSeverity.Success` (`'Success'`) | `BannerAlertSeverity.Success` (`'success'`) | casing changed | | ||
| | `BannerAlertSeverity.Warning` (`'Warning'`) | `BannerAlertSeverity.Warning` (`'warning'`) | casing changed | | ||
| | `BannerAlertSeverity.Error` (`'Error'`) | `BannerAlertSeverity.Danger` (`'danger'`) | renamed | |
There was a problem hiding this comment.
Breaking change: Error → Danger rename. Mobile's BannerAlertSeverity.Error is renamed to BannerAlertSeverity.Danger for consistency with the cross-platform design system. The migration guide documents this rename explicitly with before/after examples. Additionally, all severity values changed from PascalCase string values ('Info', 'Success') to lowercase ('info', 'success') for consistency with web platform and design tokens.
|
|
||
| describe('BannerAlert', () => { | ||
| const mockBannerBase = BannerBase as jest.Mock; | ||
| const mockTwStyle = jest.fn((...args) => args.filter(Boolean)); |
There was a problem hiding this comment.
React Native test pattern for tw.style mocking. The mockTwStyle function returns filtered args to simulate tw.style behavior without actual Tailwind processing. This allows tests to verify the correct classes are passed to tw.style (line 93-95) and that the array pattern is used correctly (line 98-100). The mock filters out falsy values with .filter(Boolean), matching real tw.style behavior for conditional classes.
| IconName, | ||
| } from '../../types'; | ||
|
|
||
| export const MAP_BANNER_ALERT_SEVERITY_ICON_NAME: Record< |
There was a problem hiding this comment.
Cross-platform constants consistency. These MAP constants are identical across React and React Native implementations (same key names, same enum values). We could consider moving these consts into shared if it makes sense in a subsequent PR
| */ | ||
| export type BannerAlertProps = BannerAlertPropsShared & | ||
| BannerBaseProps & { | ||
| iconProps?: Omit<IconProps, 'name' | 'size' | 'color'>; |
There was a problem hiding this comment.
Platform-specific customization for icon. The component internally controls icon name, size, and color based on severity mappings, but consumers may need to attach test IDs or platform-specific styling. Omitting the controlled props (name, size, color) prevents accidental overrides that would break severity semantics while allowing testID, accessibilityLabel, and other React Native-specific Icon props.
| @@ -0,0 +1,3 @@ | |||
| export { BannerAlertSeverity } from '@metamask/design-system-shared'; | |||
There was a problem hiding this comment.
Direct export from shared package. Component index.ts files export const objects directly from @metamask/design-system-shared (not through src/types/index.ts). This prevents duplicate exports that cause uncovered code paths in Jest coverage reports. The pattern ensures const objects have a single export location, matching the BadgeStatus proof-of-concept for ADR-0003/0004.
| expect(props.startAccessory.props.testID).toBe(ICON_TEST_ID); | ||
| }); | ||
|
|
||
| it.each([ |
There was a problem hiding this comment.
Table-driven test validates all severity mappings. Each severity (Info, Success, Warning, Danger) gets exhaustive assertions for icon name, icon color, and background color. This ensures the constants file mappings correctly wire through to the rendered component. The test catches any mismatch between MAP constants and actual component behavior, and validates cross-platform consistency (same severity values and mappings as React Web).
| * BannerAlert severity variants. | ||
| * Uses const object with derived union type (ADR-0003). | ||
| */ | ||
| export const BannerAlertSeverity = { |
There was a problem hiding this comment.
Const object with derived union type (ADR-0003). This replaces TypeScript enums with runtime const objects that have derived union types. Benefits include better tree-shaking, simpler cross-package imports without enum re-export issues, and consistency with the shared package architecture. The lowercase values (info, success, warning, danger) align with React Web and design token naming conventions.
| * BannerAlert shared props (ADR-0004). | ||
| * Platform-independent properties shared across React and React Native. | ||
| */ | ||
| export type BannerAlertPropsShared = BannerBasePropsShared & { |
There was a problem hiding this comment.
Extends BannerBasePropsShared (ADR-0004 centralized types). Shared props inherit from BannerBase to get all banner functionality (title, description, action buttons, close button) while adding only the severity prop. This creates a clear component hierarchy where BannerBase provides structure and BannerAlert adds semantic severity styling. The pattern ensures consistent props across React and React Native platforms.
|
|
||
| // BannerAlert types (ADR-0003 + ADR-0004) | ||
| export { | ||
| BannerAlertSeverity, |
There was a problem hiding this comment.
Inline type keyword prevents duplicate identifier errors. When exporting both a const object and a type with the same name (BannerAlertSeverity), the inline type keyword is required for the type export. Without it, TypeScript sees duplicate identifiers and compilation fails. This pattern is used consistently across all ADR-0003/0004 component exports in the shared package.
## **Description** Adds React implementation and shared types for `BannerAlert` component, broken out from the complete cross-platform implementation in #966. This PR introduces: - **Shared types** in `@metamask/design-system-shared` (ADR-0003/0004 aligned) - `BannerAlertSeverity` const object with derived union type - `BannerAlertPropsShared` interface for cross-platform props - **React implementation** in `@metamask/design-system-react` - Severity-driven icon, background, and left-border styling - Built on `BannerBase` with design token mappings - Full Storybook stories, unit tests, and component documentation - **Migration documentation** updated in `packages/design-system-react/MIGRATION.md` The React Native implementation will follow in a separate PR, allowing for focused review of each platform. ## **Related issues** Related to: - https://consensyssoftware.atlassian.net/browse/DSYS-512 (React implementation) - #966 (Original complete cross-platform PR) ## **Manual testing steps** 1. Run `yarn build` from repo root and verify all workspaces build. 2. Run `yarn lint` from repo root and verify lint/format/dependency checks pass. 3. Run `yarn test` from repo root and verify package tests pass. 4. Run React coverage check: - `NODE_OPTIONS=--experimental-vm-modules ./node_modules/.bin/jest -c packages/design-system-react/jest.config.js --runInBand --watchman=false` 5. Run `yarn storybook` and verify `BannerAlert` renders all severities (Info, Success, Warning, Danger) and supports action/close props. ## **Screenshots/Recordings** ### **Before** N/A ### **After** Default stories and args (React Web) https://github.com/user-attachments/assets/573bf78c-f2a8-48d0-93be-965854b26b22 Other stories (React Web) https://github.com/user-attachments/assets/a23bd123-b315-4ae9-8cbe-27773351a0d6 Docs (React Web) https://github.com/user-attachments/assets/b3e20382-e28e-4feb-abcf-6670d5f32f42 ## **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 - [ ] 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** > Primarily additive UI/component work with isolated exports and coverage via stories/tests; low likelihood of impacting existing behavior aside from any downstream import/export expectations. > > **Overview** > Adds a new `BannerAlert` React component (built on `BannerBase`) that applies severity-driven icon, background, and left-border styling via shared `BannerAlertSeverity` and token mapping constants. > > Introduces shared cross-platform `BannerAlertSeverity` and `BannerAlertPropsShared` exports in `@metamask/design-system-shared`, wires `BannerAlert`/types into the React package public exports, and adds Storybook stories, unit tests, component docs (`README.mdx`), plus migration guide updates covering severity import/source changes. > > <sup>Written by [Cursor Bugbot](https://cursor.com/dashboard?tab=bugbot) for commit 990b04d. This will update automatically on new commits. Configure [here](https://cursor.com/dashboard?tab=bugbot).</sup> <!-- /CURSOR_SUMMARY -->
📖 Storybook Preview |
## **Description** Extracts and documents the React Native `tw.style()` array pattern from the BannerAlert migration (PR #966) into the styling cursor rule. This pattern is essential for components that need to apply Tailwind classes while accepting a custom `style` prop. **What is the reason for the change?** - The BannerAlert component migration introduced an important pattern for merging `tw.style()` with style props using arrays - This pattern ensures type safety and proper merge order (tw classes → twClassName → style prop) - The pattern needs to be documented in the styling rule so it's available as a reference for all future components **What is the improvement/solution?** - Adds comprehensive documentation of the array pattern to `.cursor/rules/styling.md` - Includes correct ✅ and incorrect ❌ examples - Explains why the array pattern is preferred (type safety, merge order, consistency with Box) - Provides real-world example from BannerAlert component - Ensures AI agents and developers follow this pattern consistently This documentation was originally added as part of PR #966 but is being extracted into a standalone documentation update for better visibility and reusability. ## **Related issues** Related to: - #966 (BannerAlert migration) ## **Manual testing steps** 1. Review the updated `.cursor/rules/styling.md` file 2. Verify the array pattern documentation is clear and comprehensive 3. Confirm examples match the BannerAlert implementation ## **Screenshots/Recordings** N/A - Documentation only change ### **Before** No documentation for merging `tw.style()` with style props ### **After** Comprehensive documentation including: - ❌ Wrong pattern (passing style directly to tw.style) - ✅ Correct pattern (array with tw.style and style) - Why array pattern explanation - Real-world BannerAlert example ## **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 (N/A - documentation only) - [x] I've documented my code using [JSDoc](https://jsdoc.app/) format if applicable (N/A) - [ ] 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 because this PR only updates documentation and adds no runtime code changes. > > **Overview** > Documents a React Native **array-based merge pattern** for combining component `tw.style()` classes with a passed-in `style` prop, while keeping `twClassName` forwarded separately. > > Adds do/don’t examples, rationale (type-safety and consistent merge behavior), and a `BannerAlert` snippet illustrating the recommended approach. > > <sup>Written by [Cursor Bugbot](https://cursor.com/dashboard?tab=bugbot) for commit de51983. This will update automatically on new commits. Configure [here](https://cursor.com/dashboard?tab=bugbot).</sup> <!-- /CURSOR_SUMMARY -->
## Release 26.0.0 This release adds new BannerAlert components, introduces `KeyValueRow` for React Native, includes breaking simplifications to React Native `TextButton` and `TextField`, and continues ADR-0003/0004 shared type migrations. ### 📦 Package Versions - `@metamask/design-system-shared`: **0.5.0** - `@metamask/design-system-react`: **0.12.0** - `@metamask/design-system-react-native`: **0.12.0** ### 🔄 Shared Type Updates (0.5.0) #### Component Type Additions (#975, #997) **What Changed:** - Added `BannerAlertSeverity` const object + `BannerAlertPropsShared` - Added `AvatarNetworkPropsShared` type (ADR-0004) **Impact:** - Enables consistent cross-platform `BannerAlert` severity/types - Continues ADR-0003/ADR-0004 const-object + string-union + shared types adoption ### 🌐 React Web Updates (0.12.0) #### Added - Added `BannerAlert` component (#975) #### Changed - Updated `TextButton` hover/pressed styles to be text-only (no background fill) (#1001) - Updated `Candlestick` icon asset with smaller size variant (#998) ### 📱 React Native Updates (0.12.0) #### Added - Added `BannerAlert` component (#966) - Added `KeyValueRow` component (#959) #### Changed - **BREAKING:** Simplified `TextButton` to a text-only control and removed `size`/`TextButtonSize`, inverse/disabled props, and icon/accessory props (#1001) - Migration: `./packages/design-system-react-native/MIGRATION.md#from-version-0110-to-0120` - **BREAKING:** Removed `TextFieldSize` and the `size` prop; `TextField` is now a single fixed-height (48px) row (#1000) - Migration: `./packages/design-system-react-native/MIGRATION.md#from-version-0110-to-0120` - Updated `Candlestick` icon asset with smaller size variant (#998) #### Fixed - Improved `Input` single-line typography alignment (including iOS placeholder behavior) (#1000) ###⚠️ Breaking Changes #### TextButton API (React Native) **What Changed:** - Removed `size`/`TextButtonSize`, `isDisabled`, `isInverse`, and start/end icon & accessory props - `TextButton` now aligns with `Text` typography and press handlers (`variant`, `fontWeight`, `onPress`, etc.) **Migration:** See `./packages/design-system-react-native/MIGRATION.md#from-version-0110-to-0120`. **Impact:** - Affects all React Native `TextButton` usages relying on the removed props #### TextField Size API (React Native) **What Changed:** - Removed `TextFieldSize` and the `size` prop - `TextField` is now a single fixed-height (48px) row **Migration:** See `./packages/design-system-react-native/MIGRATION.md#from-version-0110-to-0120`. **Impact:** - Affects all React Native `TextField` usages passing `size` / importing `TextFieldSize` ### ✅ Checklist - [x] Changelogs updated with human-readable descriptions - [x] Changelog validation passed (`yarn changelog:validate`) - [x] Version bumps follow semantic versioning - [x] design-system-shared: minor (0.4.0 → 0.5.0) - new shared types - [x] design-system-react: minor (0.11.0 → 0.12.0) - new component + non-breaking changes - [x] design-system-react-native: minor (0.11.0 → 0.12.0) - new components + breaking API changes (pre-1.0) - [x] Breaking changes documented with migration guidance - [x] Migration guides updated with before/after examples (if breaking changes) - [x] PR references included in changelog entries ## **Pre-merge author checklist** - [ ] I've followed [MetaMask Contributor Docs](https://github.com/MetaMask/contributor-docs) - [x] I've reviewed the [Release Workflow](./.cursor/rules/release-workflow.md) cursor rule - [x] All tests pass (`yarn build && yarn test && yarn lint`) - [x] Changelog validation passes (`yarn changelog:validate`) ## **Pre-merge reviewer checklist** - [ ] I've reviewed the [Reviewing Release PRs](./docs/reviewing-release-prs.md) guide - [ ] Package versions follow semantic versioning - [ ] Changelog entries are consumer-facing (not commit message regurgitation) - [ ] Breaking changes are documented in MIGRATION.md with examples - [ ] All unreleased changes are accounted for in changelogs <!-- CURSOR_SUMMARY --> --- > [!NOTE] > **Medium Risk** > Mostly a version/changelog release PR, but includes documented **breaking** React Native API removals for `TextButton` and `TextField` that can break downstream consumers on upgrade. > > **Overview** > Bumps the monorepo version to `26.0.0` and releases `@metamask/design-system-react`/`@metamask/design-system-react-native` to `0.12.0` and `@metamask/design-system-shared` to `0.5.0`. > > Updates changelogs and the React Native migration guide to reflect new `BannerAlert` (web + RN) and `KeyValueRow` (RN), shared type additions (`BannerAlertSeverity`/`BannerAlertPropsShared`, `AvatarNetworkPropsShared`), and **breaking** RN API changes removing `TextButton` sizing/icons/disabled/inverse props and removing `TextField` sizing (`TextFieldSize`/`size`) in favor of a fixed-height row. > > <sup>Written by [Cursor Bugbot](https://cursor.com/dashboard?tab=bugbot) for commit 5ead00c. This will update automatically on new commits. Configure [here](https://cursor.com/dashboard?tab=bugbot).</sup> <!-- /CURSOR_SUMMARY -->
## **Description** Extracts and documents the React Native `tw.style()` array pattern from the BannerAlert migration (PR #966) into the styling cursor rule. This pattern is essential for components that need to apply Tailwind classes while accepting a custom `style` prop. **What is the reason for the change?** - The BannerAlert component migration introduced an important pattern for merging `tw.style()` with style props using arrays - This pattern ensures type safety and proper merge order (tw classes → twClassName → style prop) - The pattern needs to be documented in the styling rule so it's available as a reference for all future components **What is the improvement/solution?** - Adds comprehensive documentation of the array pattern to `.cursor/rules/styling.md` - Includes correct ✅ and incorrect ❌ examples - Explains why the array pattern is preferred (type safety, merge order, consistency with Box) - Provides real-world example from BannerAlert component - Ensures AI agents and developers follow this pattern consistently This documentation was originally added as part of PR #966 but is being extracted into a standalone documentation update for better visibility and reusability. ## **Related issues** Related to: - #966 (BannerAlert migration) ## **Manual testing steps** 1. Review the updated `.cursor/rules/styling.md` file 2. Verify the array pattern documentation is clear and comprehensive 3. Confirm examples match the BannerAlert implementation ## **Screenshots/Recordings** N/A - Documentation only change ### **Before** No documentation for merging `tw.style()` with style props ### **After** Comprehensive documentation including: - ❌ Wrong pattern (passing style directly to tw.style) - ✅ Correct pattern (array with tw.style and style) - Why array pattern explanation - Real-world BannerAlert example ## **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 (N/A - documentation only) - [x] I've documented my code using [JSDoc](https://jsdoc.app/) format if applicable (N/A) - [ ] 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 because this PR only updates documentation and adds no runtime code changes. > > **Overview** > Documents a React Native **array-based merge pattern** for combining component `tw.style()` classes with a passed-in `style` prop, while keeping `twClassName` forwarded separately. > > Adds do/don’t examples, rationale (type-safety and consistent merge behavior), and a `BannerAlert` snippet illustrating the recommended approach. > > <sup>Written by [Cursor Bugbot](https://cursor.com/dashboard?tab=bugbot) for commit de51983. This will update automatically on new commits. Configure [here](https://cursor.com/dashboard?tab=bugbot).</sup> <!-- /CURSOR_SUMMARY -->
## Release 26.0.0 This release adds new BannerAlert components, introduces `KeyValueRow` for React Native, includes breaking simplifications to React Native `TextButton` and `TextField`, and continues ADR-0003/0004 shared type migrations. ### 📦 Package Versions - `@metamask/design-system-shared`: **0.5.0** - `@metamask/design-system-react`: **0.12.0** - `@metamask/design-system-react-native`: **0.12.0** ### 🔄 Shared Type Updates (0.5.0) #### Component Type Additions (#975, #997) **What Changed:** - Added `BannerAlertSeverity` const object + `BannerAlertPropsShared` - Added `AvatarNetworkPropsShared` type (ADR-0004) **Impact:** - Enables consistent cross-platform `BannerAlert` severity/types - Continues ADR-0003/ADR-0004 const-object + string-union + shared types adoption ### 🌐 React Web Updates (0.12.0) #### Added - Added `BannerAlert` component (#975) #### Changed - Updated `TextButton` hover/pressed styles to be text-only (no background fill) (#1001) - Updated `Candlestick` icon asset with smaller size variant (#998) ### 📱 React Native Updates (0.12.0) #### Added - Added `BannerAlert` component (#966) - Added `KeyValueRow` component (#959) #### Changed - **BREAKING:** Simplified `TextButton` to a text-only control and removed `size`/`TextButtonSize`, inverse/disabled props, and icon/accessory props (#1001) - Migration: `./packages/design-system-react-native/MIGRATION.md#from-version-0110-to-0120` - **BREAKING:** Removed `TextFieldSize` and the `size` prop; `TextField` is now a single fixed-height (48px) row (#1000) - Migration: `./packages/design-system-react-native/MIGRATION.md#from-version-0110-to-0120` - Updated `Candlestick` icon asset with smaller size variant (#998) #### Fixed - Improved `Input` single-line typography alignment (including iOS placeholder behavior) (#1000) ###⚠️ Breaking Changes #### TextButton API (React Native) **What Changed:** - Removed `size`/`TextButtonSize`, `isDisabled`, `isInverse`, and start/end icon & accessory props - `TextButton` now aligns with `Text` typography and press handlers (`variant`, `fontWeight`, `onPress`, etc.) **Migration:** See `./packages/design-system-react-native/MIGRATION.md#from-version-0110-to-0120`. **Impact:** - Affects all React Native `TextButton` usages relying on the removed props #### TextField Size API (React Native) **What Changed:** - Removed `TextFieldSize` and the `size` prop - `TextField` is now a single fixed-height (48px) row **Migration:** See `./packages/design-system-react-native/MIGRATION.md#from-version-0110-to-0120`. **Impact:** - Affects all React Native `TextField` usages passing `size` / importing `TextFieldSize` ### ✅ Checklist - [x] Changelogs updated with human-readable descriptions - [x] Changelog validation passed (`yarn changelog:validate`) - [x] Version bumps follow semantic versioning - [x] design-system-shared: minor (0.4.0 → 0.5.0) - new shared types - [x] design-system-react: minor (0.11.0 → 0.12.0) - new component + non-breaking changes - [x] design-system-react-native: minor (0.11.0 → 0.12.0) - new components + breaking API changes (pre-1.0) - [x] Breaking changes documented with migration guidance - [x] Migration guides updated with before/after examples (if breaking changes) - [x] PR references included in changelog entries ## **Pre-merge author checklist** - [ ] I've followed [MetaMask Contributor Docs](https://github.com/MetaMask/contributor-docs) - [x] I've reviewed the [Release Workflow](./.cursor/rules/release-workflow.md) cursor rule - [x] All tests pass (`yarn build && yarn test && yarn lint`) - [x] Changelog validation passes (`yarn changelog:validate`) ## **Pre-merge reviewer checklist** - [ ] I've reviewed the [Reviewing Release PRs](./docs/reviewing-release-prs.md) guide - [ ] Package versions follow semantic versioning - [ ] Changelog entries are consumer-facing (not commit message regurgitation) - [ ] Breaking changes are documented in MIGRATION.md with examples - [ ] All unreleased changes are accounted for in changelogs <!-- CURSOR_SUMMARY --> --- > [!NOTE] > **Medium Risk** > Mostly a version/changelog release PR, but includes documented **breaking** React Native API removals for `TextButton` and `TextField` that can break downstream consumers on upgrade. > > **Overview** > Bumps the monorepo version to `26.0.0` and releases `@metamask/design-system-react`/`@metamask/design-system-react-native` to `0.12.0` and `@metamask/design-system-shared` to `0.5.0`. > > Updates changelogs and the React Native migration guide to reflect new `BannerAlert` (web + RN) and `KeyValueRow` (RN), shared type additions (`BannerAlertSeverity`/`BannerAlertPropsShared`, `AvatarNetworkPropsShared`), and **breaking** RN API changes removing `TextButton` sizing/icons/disabled/inverse props and removing `TextField` sizing (`TextFieldSize`/`size`) in favor of a fixed-height row. > > <sup>Written by [Cursor Bugbot](https://cursor.com/dashboard?tab=bugbot) for commit 5ead00c. This will update automatically on new commits. Configure [here](https://cursor.com/dashboard?tab=bugbot).</sup> <!-- /CURSOR_SUMMARY -->

Description
Adds React Native implementation and shared types for
BannerAlertcomponent, broken out from the complete cross-platform implementation. This PR introduces:@metamask/design-system-shared(ADR-0003/0004 aligned)BannerAlertSeverityconst object with derived union typeBannerAlertPropsSharedinterface for cross-platform props@metamask/design-system-react-nativeBannerBasewith design token mappingspackages/design-system-react-native/MIGRATION.mdThe React implementation was separated into PR #975 for focused platform-specific review.
Related issues
Related to:
Manual testing steps
yarn buildfrom repo root and verify all workspaces build.yarn lintfrom repo root and verify lint/format/dependency checks pass.yarn testfrom repo root and verify package tests pass.NODE_OPTIONS=--experimental-vm-modules ./node_modules/.bin/jest -c packages/design-system-react-native/jest.config.js --runInBand --watchman=falseyarn storybook:iosoryarn storybook:androidand verifyBannerAlertrenders all severities (Info, Success, Warning, Danger) and supports action/close props.Screenshots/Recordings
Before
N/A
After
N/A
Default stories and args (React Native)
banneralert.defautstory.mov
Other stories (React Native)
banner.alert.stories.mov
Docs (React Native)
banneralert.docs.mov
Pre-merge author checklist
Pre-merge reviewer checklist
Note
Low Risk
Mostly additive UI component work (new component, exports, docs, stories, and tests) with minimal impact on existing runtime behavior beyond new public API surface.
Overview
Adds a new
BannerAlertcomponent to@metamask/design-system-react-native, built onBannerBaseand driven by sharedBannerAlertSeverityto map severity to icon, colors, and a left-border style.Includes Storybook stories and unit tests for severity/default behavior and style merging, updates
MIGRATION.mdwith BannerAlert-specific breaking changes/mapping, and exports the new component/types from the package (and registers the story in RN Storybook’s auto-generatedstorybook.requires.js).Written by Cursor Bugbot for commit c883769. This will update automatically on new commits. Configure here.