feat(rn): add SelectButtonSize and align SelectButton with Figma#1177
Conversation
Adds SelectButtonSize (Sm/Md/Lg) as a first-class const object in design-system-shared following ADR-0003/ADR-0004, moves size into SelectButtonPropsShared, and changes the default from ButtonBaseSize.Sm to SelectButtonSize.Md to match the Figma component's "Md (default)" label. Figma branch 8KPwHulIorYFJiTWK8MapC was updated in parallel: - Added variant property (Primary/Secondary/Tertiary) - Renamed sizes Large/Md(default)/Small → Lg/Md/Sm - Reorganised layout to 3×3 grid - Secondary/Tertiary: transparent fills; Tertiary: text/alternative token Relates to DSYS-742
📖 Storybook Preview |
…electButtonSize to ButtonBaseSize
📖 Storybook Preview |
| * SelectButton size — alias of ButtonBaseSize. | ||
| * Sm (32px) | Md (40px, default) | Lg (48px). | ||
| */ | ||
| export const SelectButtonSize = ButtonBaseSize; |
There was a problem hiding this comment.
The alias approach mirrors the existing pattern used by ButtonSize and ButtonHeroSize in the same file — both are direct assignments from ButtonBaseSize. Since SelectButton maps 1:1 to ButtonBase sizes with no additional values, aliasing avoids duplicating string literals and guarantees the two types stay in sync automatically.
| Omit< | ||
| ButtonBaseProps, | ||
| 'children' | 'endIconName' | 'endIconProps' | 'disabled' | ||
| 'children' | 'endIconName' | 'endIconProps' | 'disabled' | 'size' |
There was a problem hiding this comment.
'size' is explicitly omitted from the ButtonBaseProps passthrough here because it is now declared in SelectButtonPropsShared. Without this omission, TypeScript sees two definitions of 'size' in the intersection — one typed as SelectButtonSize and one as ButtonBaseSize — which can cause subtle type widening. The omit keeps the prop owned by exactly one layer.
| title: 'Components/SelectButton', | ||
| component: SelectButton, | ||
| argTypes: { | ||
| size: { |
There was a problem hiding this comment.
Object.keys gives the human-readable label (Sm/Md/Lg) shown in the controls panel, while mapping resolves each label back to the string value ('sm'/'md'/'lg') passed to the component. Using Object.values alone would show raw strings in the panel dropdown, which is less readable on a small device screen.
📖 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: SelectButtonSize duplicates literals instead of aliasing ButtonBaseSize
- Replaced the duplicated SelectButtonSize object with an alias to ButtonBaseSize and added the proper import to keep them in sync.
Or push these changes by commenting:
@cursor push 75021c769b
Preview (75021c769b)
diff --git a/packages/design-system-shared/src/types/SelectButton/SelectButton.types.ts b/packages/design-system-shared/src/types/SelectButton/SelectButton.types.ts
--- a/packages/design-system-shared/src/types/SelectButton/SelectButton.types.ts
+++ b/packages/design-system-shared/src/types/SelectButton/SelectButton.types.ts
@@ -1,16 +1,12 @@
import type { ReactNode } from 'react';
+import { ButtonBaseSize } from '../ButtonBase';
/**
* SelectButton size options (ADR-0003).
* Sm (32px) | Md (40px, default) | Lg (48px).
*/
-export const SelectButtonSize = {
- Sm: 'sm',
- Md: 'md',
- Lg: 'lg',
-} as const;
-export type SelectButtonSize =
- (typeof SelectButtonSize)[keyof typeof SelectButtonSize];
+export const SelectButtonSize = ButtonBaseSize;
+export type SelectButtonSize = ButtonBaseSize;
/**
* SelectButton — trailing arrow direction (maps to platform arrow icons).You can send follow-ups to the cloud agent here.
📖 Storybook Preview |
There was a problem hiding this comment.
Cursor Bugbot has reviewed your changes and found 1 potential issue.
There are 2 total unresolved issues (including 1 from previous review).
Autofix Details
Bugbot Autofix prepared a fix for the issue found in the latest run.
- ✅ Fixed: Default size remains Sm instead of intended Md
- Updated default size to SelectButtonSize.Md in component, and aligned README and JSDoc defaults to Md.
Or push these changes by commenting:
@cursor push 80c81b1b3c
Preview (80c81b1b3c)
diff --git a/packages/design-system-react-native/src/components/SelectButton/README.md b/packages/design-system-react-native/src/components/SelectButton/README.md
--- a/packages/design-system-react-native/src/components/SelectButton/README.md
+++ b/packages/design-system-react-native/src/components/SelectButton/README.md
@@ -305,7 +305,7 @@
| TYPE | REQUIRED | DEFAULT |
| ------------------ | -------- | --------------------- |
-| `SelectButtonSize` | No | `SelectButtonSize.Sm` |
+| `SelectButtonSize` | No | `SelectButtonSize.Md` |
```tsx
import {
diff --git a/packages/design-system-react-native/src/components/SelectButton/SelectButton.tsx b/packages/design-system-react-native/src/components/SelectButton/SelectButton.tsx
--- a/packages/design-system-react-native/src/components/SelectButton/SelectButton.tsx
+++ b/packages/design-system-react-native/src/components/SelectButton/SelectButton.tsx
@@ -24,7 +24,7 @@
endArrowDirectionIconProps,
variant = SelectButtonVariant.Primary,
isLoading = false,
- size = SelectButtonSize.Sm,
+ size = SelectButtonSize.Md,
twClassName = '',
style,
...buttonBaseRest
diff --git a/packages/design-system-shared/src/types/SelectButton/SelectButton.types.ts b/packages/design-system-shared/src/types/SelectButton/SelectButton.types.ts
--- a/packages/design-system-shared/src/types/SelectButton/SelectButton.types.ts
+++ b/packages/design-system-shared/src/types/SelectButton/SelectButton.types.ts
@@ -48,7 +48,7 @@
/**
* Height size of the button. Maps 1:1 to ButtonBaseSize values.
*
- * @default Sm
+ * @default Md
*/
size?: SelectButtonSize;
/**You can send follow-ups to the cloud agent here.
|
|
||
| export const Size: Story = { | ||
| render: () => ( | ||
| <SelectButtonStoryWrapper style={{ gap: 16 }}> |
There was a problem hiding this comment.
@cursoragent update SelectButtonStoryWrapper to use the Box component and spread props so we can use gap={4} prop here
…o enable gap prop (gap={4})
Co-authored-by: George Marshall <georgewrmarshall@users.noreply.github.com>
📖 Storybook Preview |
…iteral duplication Co-authored-by: George Marshall <georgewrmarshall@users.noreply.github.com>
📖 Storybook Preview |
Co-authored-by: George Marshall <georgewrmarshall@users.noreply.github.com>
📖 Storybook Preview |
There was a problem hiding this comment.
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:
SelectButtonSizemissing from package barrel export- Added
SelectButtonSizetopackages/design-system-react-native/src/components/index.tsso it’s re-exported from the package entry.
- Added
Or push these changes by commenting:
@cursor push a8d891fc82
Preview (a8d891fc82)
diff --git a/packages/design-system-react-native/src/components/index.ts b/packages/design-system-react-native/src/components/index.ts
--- a/packages/design-system-react-native/src/components/index.ts
+++ b/packages/design-system-react-native/src/components/index.ts
@@ -200,6 +200,7 @@
export {
SelectButton,
SelectButtonEndArrow,
+ SelectButtonSize,
SelectButtonVariant,
} from './SelectButton';
export type { SelectButtonProps } from './SelectButton';You can send follow-ups to the cloud agent here.
Reviewed by Cursor Bugbot for commit 2fc8a92. Configure here.
…tch README and package entry Applied via @cursor push command
📖 Storybook Preview |
📖 Storybook Preview |
## Release 42.0.0 This release curates the changelogs for three published packages into consumer-facing Keep a Changelog entries. It adds the `FlashFilled` icon and `SelectButtonSize` across platforms, adds the `TextField` component to React web, and ships two React Native breaking changes: the `panGestureHandlerProps` removal (part of the `react-native-gesture-handler` v2 migration) and the removal of the variant-based title API from `HeaderBase`/`BottomSheetHeader`. ### 📦 Package Versions - `@metamask/design-system-shared`: **0.20.0** (was 0.19.0) - `@metamask/design-system-react`: **0.24.0** (was 0.23.1) - `@metamask/design-system-react-native`: **0.27.0** (was 0.26.0) > `@metamask/design-tokens`, `@metamask/design-system-tailwind-preset`, and `@metamask/design-system-twrnc-preset` are unchanged in this release. ### 🔄 Shared Type Updates (0.20.0) #### Component Type Additions (#1191, #1177, #1170) **What Changed:** - Added `FlashFilled` to the `IconName` const so the filled lightning bolt is available on both platforms. - Added `SelectButtonSize` so `SelectButton` exposes a semantic size type shared across platforms. - Added `TextFieldPropsShared` for the cross-platform text field input contract. **Impact:** - Additive only — no breaking changes to the shared package. - Continues the ADR-0003/0004 const-object + centralized-types pattern. ### 🌐 React Web Updates (0.24.0) #### Added - Added `TextField` for labeled text entry with optional helper and validation text, exposing `TextFieldSize` and `TextFieldType` (#1170) - Added `FlashFilled` icon (filled lightning bolt) to `IconName` (#1191) ### 📱 React Native Updates (0.27.0) #### Added - Added `FlashFilled` icon (filled lightning bolt) to `IconName` (#1191) - Added `SelectButtonSize` so `SelectButton` exposes a semantic size type (#1177) #### Changed - **BREAKING:** Removed `panGestureHandlerProps` from `BottomSheet` and `BottomSheetDialog` following the migration to the `react-native-gesture-handler` v2 `GestureDetector`/`Gesture.Pan()` API (#1165) - Migration: [From version 0.26.0 to 0.27.0](./packages/design-system-react-native/MIGRATION.md#from-version-0260-to-0270) - **BREAKING:** Removed the variant-based title API from `HeaderBase` and `BottomSheetHeader` — `variant`, `HeaderBaseVariant`, `BottomSheetHeaderVariant`, and `HeaderBase`'s `titleTestID` (#1103) - String titles now render with a centered `HeadingSm` treatment; pass custom `children` for bespoke title layouts and use `textProps.testID` in place of `titleTestID` - Migration: [From version 0.26.0 to 0.27.0](./packages/design-system-react-native/MIGRATION.md#from-version-0260-to-0270) - Reduced the default `SegmentGroup` segment spacing from `gap-3` to `gap-1` for tighter grouped segments (#1194) #### Fixed - Fixed a `HeaderStandardAnimated` runtime crash under React Native Reanimated 4 by inlining the scroll-handler worklet (#1185) - Fixed React Native Web rendering for `BottomSheet`, `BottomSheetOverlay`, `Icon`, and the animated `ButtonAnimated` and `Spinner` components (#1187) ###⚠️ Breaking Changes #### Removed `panGestureHandlerProps` from `BottomSheet` / `BottomSheetDialog` (React Native Only) **What Changed:** - Removed the `panGestureHandlerProps` prop. The components migrated from the deprecated RNGH v1 `PanGestureHandler` JSX component to the v2 `GestureDetector` + `Gesture.Pan()` API. - `simultaneousHandlers` (the only real-world use case) was never wired up under the old shim, so no working behavior is lost. **Migration:** ```tsx // Before (0.26.0) <BottomSheet goBack={goBack} panGestureHandlerProps={{ simultaneousHandlers: scrollViewRef }} > {children} </BottomSheet> // After (0.27.0) <BottomSheet goBack={goBack}>{children}</BottomSheet> ``` #### Removed variant-based title API from `HeaderBase` / `BottomSheetHeader` (React Native Only) **What Changed:** - Removed `variant`, `HeaderBaseVariant`, `BottomSheetHeaderVariant`, and `HeaderBase`'s `titleTestID`. - String titles now render with a centered `HeadingSm` treatment; custom layouts use `children`, and `titleTestID` is replaced by `textProps.testID`. **Migration:** ```tsx // Before (0.26.0) import { HeaderBase, HeaderBaseVariant } from '@metamask/design-system-react-native'; <HeaderBase variant={HeaderBaseVariant.Display} titleTestID="title"> Account details </HeaderBase> // After (0.27.0) import { HeaderBase } from '@metamask/design-system-react-native'; <HeaderBase textProps={{ testID: 'title' }}>Account details</HeaderBase> ``` See migration guide for complete instructions: - [React Native Migration Guide — 0.26.0 to 0.27.0](./packages/design-system-react-native/MIGRATION.md#from-version-0260-to-0270) ### 🔗 Consumer note: MetaMask Mobile MetaMask Mobile currently consumes `@metamask/design-system-react-native@0.20.0` and applies a local yarn patch — `.yarn/patches/@metamask-design-system-react-native-npm-0.20.0-2ae4d6f1dd.patch` — to migrate `BottomSheetDialog` from `PanGestureHandler` to `GestureDetector` for its React Native Reanimated 4 upgrade ([MetaMask/metamask-mobile#29470](MetaMask/metamask-mobile#29470)). This release **upstreams that exact migration natively** (#1165). Once mobile bumps to `0.27.0`, it can **drop that yarn patch** — the package now uses the RNGH v2 `GestureDetector`/`Gesture.Pan()` API on its own. Compatibility note: the package keeps `react-native-reanimated` at `peerDependencies: >=3.17.0` (unchanged). It was validated against mobile's current Reanimated 3.19 and is forward-compatible with the incoming Reanimated 4.1.x (the #1185 worklet fix works on both), so no peer-dependency bump is required. ### ✅ 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.19.0 → 0.20.0) - additive type exports - [x] design-system-react: minor (0.23.1 → 0.24.0) - new `TextField` component + icon - [x] design-system-react-native: minor (0.26.0 → 0.27.0) - pre-1.0 minor with breaking changes - [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** - [x] 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 - [ ] 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** > No runtime code in the diff, but the published React Native 0.27.0 changelog documents breaking BottomSheet and Header API changes that require consumer migrations. > > **Overview** > **Release 42.0.0** bumps the monorepo to **42.0.0** and publishes **@metamask/design-system-shared@0.20.0**, **@metamask/design-system-react@0.24.0**, and **@metamask/design-system-react-native@0.27.0** with finalized Keep a Changelog entries and compare links. > > The diff is mostly **release packaging**: version fields in root and package `package.json` files, new changelog sections for those versions, and doc updates. **React Native** docs drop **`panGestureHandlerProps`** from `BottomSheet` / `BottomSheetDialog` READMEs; **`MIGRATION.md`** adds a **0.26.0 → 0.27.0** section (bottom-sheet gesture prop removal, header title API) and moves **BannerBase** guidance under **0.24.0 → 0.25.0**. > > What consumers get in this release (documented in changelogs, not new code in this PR): shared **`FlashFilled`**, **`SelectButtonSize`**, **`TextFieldPropsShared`**; web **`TextField`** and **`FlashFilled`**; native **`FlashFilled`**, **`SelectButtonSize`**, two **breaking** API removals (`panGestureHandlerProps`, header **`variant`** / **`titleTestID`**), tighter **`SegmentGroup`** spacing, Reanimated 4 / RN Web fixes. > > <sup>Reviewed by [Cursor Bugbot](https://cursor.com/bugbot) for commit 6710621. Bugbot is set up for automated code reviews on this repo. Configure [here](https://www.cursor.com/dashboard/bugbot).</sup> <!-- /CURSOR_SUMMARY -->




Description
Adds
SelectButtonSizeas a first-class const object in@metamask/design-system-sharedfollowing ADR-0003/ADR-0004, aligning theSelectButtoncomponent's size API with its Figma counterpart.Previously,
SelectButtonusedButtonBaseSizedirectly and defaulted toButtonBaseSize.Sm. This PR:SelectButtonSize(Sm/Md/Lg) in the shared package so consumers have a semantically correct typesizeintoSelectButtonPropsShared(ADR-0004 centralised types)SmtoMdto match the Figma design's "Md (default)" labelFigma branch: SelectButton — branch 8KPwHulIorYFJiTWK8MapC
Figma changes made on the branch:
variantproperty (Primary / Secondary / Tertiary) to the component setLarge / Md (default) / Small→Lg / Md / Smto match code namingtext/alternativedesign token to label text and arrow iconRelated issues
Fixes: DSYS-742
Manual testing steps
yarn workspace @metamask/design-system-react-native test --testPathPattern="SelectButton"— all 36 tests should passyarn storybook:ios, navigate to Components → SelectButton → Variant and verify three visual variants render correctly (Primary with muted bg, Secondary transparent, Tertiary with alternative text colour)SelectButtonSizeis importable:import { SelectButtonSize } from '@metamask/design-system-react-native'Screenshots/Recordings
After
sizedefaults toSelectButtonSize.Md(40px /rounded-xl)SelectButtonSize.Sm | Md | Lgexported from both@metamask/design-system-sharedand@metamask/design-system-react-nativesize×variant3×3 grid matching code API exactlySimulator.Screen.Recording.-.iPhone.15.Pro.-.2026-05-19.at.15.00.02.mov
Screen.Recording.2026-05-19.at.3.15.34.PM.mov
Pre-merge author checklist
Pre-merge reviewer checklist
Note
Medium Risk
Medium risk due to public API/type changes around
SelectButtonsizing (new exportedSelectButtonSize,sizemoved into shared props, andButtonBasesizeomitted), which may require consumer updates but has limited runtime impact.Overview
Adds a first-class
SelectButtonSizeoption set (aliased toButtonBaseSize) in@metamask/design-system-shared, and re-exports it throughdesign-system-react-nativeso consumers can use a semantically named size type.Updates
SelectButton’s API/types to useSelectButtonSize(including defaultingsizevia this new type) and prevents prop-type collisions by omittingButtonBase’ssizefromSelectButtonProps. Storybook and docs are refreshed to demonstrate and control the newsizeprop, and the stories’ wrapper layout is migrated fromView+Tailwind toBoxprops.Reviewed by Cursor Bugbot for commit 916d358. Bugbot is set up for automated code reviews on this repo. Configure here.