Skip to content

docs: add TextButton migration (extension)#1098

Merged
kirillzyusko merged 3 commits into
mainfrom
docs/text-button-extension
Apr 28, 2026
Merged

docs: add TextButton migration (extension)#1098
kirillzyusko merged 3 commits into
mainfrom
docs/text-button-extension

Conversation

@kirillzyusko

@kirillzyusko kirillzyusko commented Apr 21, 2026

Copy link
Copy Markdown
Collaborator

Description

Added migration for TextButton (extension part).

Related issues

Fixes: https://consensyssoftware.atlassian.net/browse/DSYS-637

Manual testing steps

  1. Open MIGRATION.MD file
  2. Check that TextButton migration is in place

Screenshots/Recordings

Before

N/A

After

image

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

Low Risk
Documentation-only changes that add migration guidance; no runtime code paths are modified.

Overview
Adds a new TextButton migration section to MIGRATION.md, documenting how to replace extension ButtonLink and Button variant={ButtonVariant.Link} with design-system TextButton (and when to use Button variant={ButtonVariant.Tertiary} for isDanger/isLoading/button-like behaviors).

Includes detailed prop/enum mappings (notably TextButtonSize as typography), removed/renamed prop guidance (disabledisDisabled, blockisFullWidth, as/hrefasChild), and before/after code examples; also links this guide from the TextButton docs (README.mdx).

Reviewed by Cursor Bugbot for commit 4e66515. Bugbot is set up for automated code reviews on this repo. Configure here.

@kirillzyusko kirillzyusko self-assigned this Apr 21, 2026
@kirillzyusko kirillzyusko added the documentation Improvements or additions to documentation label Apr 21, 2026
@github-actions

Copy link
Copy Markdown
Contributor

📖 Storybook Preview

@kirillzyusko kirillzyusko marked this pull request as ready for review April 21, 2026 14:42
@kirillzyusko kirillzyusko requested a review from a team as a code owner April 21, 2026 14:42

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

Compared the new TextButton migration docs against extension button-link / Button variant={ButtonVariant.Link} and the current MMDS TextButton implementation. I left a couple of inline comments where the migration guide overstates or misstates the supported API.

| --------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------ |
| `ellipsis` | Removed — use `className="truncate"` or `textProps` with truncation classes |
| `textDirection` | Removed — set the standard HTML `dir` attribute directly |
| `block` (inherited from `ButtonBase`) | Removed — `TextButton` is inline-styled; wrap with `asChild` and a block element if needed |

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.

suggestion: I don't think block is removed here. TextButton still inherits isFullWidth from ButtonBaseProps because TextButtonProps only omits className, disabled/loading props, style, and size before reintroducing its own fields: TextButton.types.ts#L4-L14. The component then forwards the remaining props to ButtonBase: TextButton.tsx#L46-L56. I think the migration should map extension block to isFullWidth rather than calling it unsupported.


`TextButton` adds props not available in the extension `ButtonLink`:

- `isInverse` — inverse coloring for use on dark or colored backgrounds

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.

non-blocking: This "new props" list looks broader than the actual delta. On the extension side, ButtonLink already inherited textProps from ButtonBaseStyleUtilityProps: button-link.types.ts#L19-L20, button-base.types.ts#L83-L86. It also already inherited DOM/ARIA props through PolymorphicComponentPropWithRef: button-link.types.ts#L42-L43, box.types.ts#L218-L231. className was also already part of the extension surface: button-link.tsx#L30-L31. The genuinely new pieces here seem more like isInverse and asChild.

@github-actions

Copy link
Copy Markdown
Contributor

📖 Storybook Preview

@github-actions

Copy link
Copy Markdown
Contributor

📖 Storybook Preview

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

non-blocking: In the ellipsis migration row, could we call out textProps={{ ellipsis: true }} explicitly for string children? TextButton forwards textProps through ButtonBase to the inner Text, so that reads closer to the legacy ButtonLink behavior than only mentioning truncation classes. For non-string children, a custom truncating wrapper or classes still makes sense.

@github-actions

Copy link
Copy Markdown
Contributor

📖 Storybook Preview

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

I re-checked the current extension ButtonLink migration text against the React Native guidance. I only found one docs consistency point worth calling out.

The legacy `ButtonLink` (and `Button` with `variant={ButtonVariant.Link}`) is replaced by **two** design system components depending on the use case:

- **`TextButton`** — for inline text-styled links within content flows (the primary replacement)
- **`Button` with `variant={ButtonVariant.Tertiary}`** — for standalone link-styled buttons that still need `isDanger`, `isLoading`, or full button affordances

@georgewrmarshall georgewrmarshall Apr 28, 2026

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.

non-blocking: The Button tertiary fallback guidance could be framed more consistently with the React Native migration docs. The important migration rule across both packages is that TextButton is the inline-link replacement, while Button with variant={ButtonVariant.Tertiary} is the path when the legacy link needed more button-like affordances such as isFullWidth or danger/loading/custom visual treatment. The current docs already say this in places, but tightening that framing here would make the migration story more consistent across packages.

@github-actions

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.

Fix All in Cursor

❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, have a team admin enable autofix in the Cursor dashboard.

Reviewed by Cursor Bugbot for commit 3a530b2. Configure here.


| Extension Prop | Design System Migration |
| --------------------------------------------------------------------------------------------------- | --------------------------------------------------------------------------- |
| `ellipsis` | Removed — use `className="truncate"` or `textProps` with truncation classes |

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.

Migration recommends CSS over component API for ellipsis

Low Severity

The ellipsis migration guidance suggests className="truncate" as the primary approach, but the Text component exposes a dedicated ellipsis boolean prop, and textProps accepts Partial<TextProps>. The recommended migration path is textProps={{ ellipsis: true }}, which uses the component's own API rather than a generic Tailwind class. This violates the rule requiring migration guides to prefer the component API over generic CSS when the component supports it.

Fix in Cursor Fix in Web

Triggered by learned rule: Migration guides must only reference public API

Reviewed by Cursor Bugbot for commit 3a530b2. Configure here.

@kirillzyusko kirillzyusko enabled auto-merge (squash) April 28, 2026 20:25
@github-actions

Copy link
Copy Markdown
Contributor

📖 Storybook Preview

@kirillzyusko kirillzyusko merged commit c8e873b into main Apr 28, 2026
44 checks passed
@kirillzyusko kirillzyusko deleted the docs/text-button-extension branch April 28, 2026 20:28
@georgewrmarshall georgewrmarshall mentioned this pull request Apr 30, 2026
18 tasks
georgewrmarshall added a commit that referenced this pull request Apr 30, 2026
## Release 37.0.0

This release focuses on consumer-facing changelog cleanup for the
packages being published, plus migration-guide coverage for the React
Native `TextField` API changes included in this release.

### 📦 Package Versions

- `@metamask/design-system-shared`: **0.15.0**
- `@metamask/design-system-react`: **0.20.0**
- `@metamask/design-system-react-native`: **0.22.0**

### 🔄 Shared Type Updates (0.15.0)

#### Shared type additions
([#1034](#1034),
[#1038](#1038),
[#1081](#1081))

**What Changed:**

- Added shared `ButtonBaseSize`, `ButtonSize`, `ButtonHeroSize`,
`ButtonVariant`, `ButtonBasePropsShared`, and `ButtonPropsShared`
- Added shared `ButtonIconSize`, `ButtonIconVariant`, and
`ButtonIconPropsShared`
- Added shared `TextFieldPropsShared` for the controlled text-field
contract used across platforms

**Impact:**

- Continues ADR-0003 and ADR-0004 migration toward shared const-object
plus string-union exports
- Gives React and React Native one shared source of truth for these
component contracts

### 🌐 React Web Updates (0.20.0)

#### Changed

- **BREAKING:** Updated `Button`, `ButtonBase`, and `ButtonHero` size
and variant exports to use shared const-object + string-union types
rather than platform-local enum-based definitions
([#1034](#1034))
- No migration required for typical usage; continue importing from
`@metamask/design-system-react` as before
- **BREAKING:** Updated `ButtonIconSize` and `ButtonIconVariant` to use
shared const-object + string-union types rather than platform-local
enum-based definitions
([#1038](#1038))
- No migration required for typical usage; continue importing from
`@metamask/design-system-react` as before
- Updated Figma Code Connect to the live `MMDS Components` file and
aligned `ButtonIcon` and `TextButton` mappings with the current
component APIs shown in Dev Mode
([#1109](#1109))
- Expanded the `TextButton` migration guide for extension consumers
replacing `ButtonLink` and `ButtonVariant.Link` with the current
design-system APIs
([#1098](#1098))

### 📱 React Native Updates (0.22.0)

#### Changed

- **BREAKING:** Updated `Button`, `ButtonBase`, and `ButtonHero` size
and variant exports to use shared const-object + string-union types
rather than platform-local enum-based definitions
([#1034](#1034))
- No migration required for typical usage; continue importing from
`@metamask/design-system-react-native` as before
- **BREAKING:** Updated `ButtonIconSize` and `ButtonIconVariant` to use
shared const-object + string-union types rather than platform-local
enum-based definitions
([#1038](#1038))
- No migration required for typical usage; continue importing from
`@metamask/design-system-react-native` as before
- **BREAKING:** `TextField` and `TextFieldSearch` now use a root
`Box`/`View`, require native `TextInput` props under `inputProps`,
rename `isReadonly` to `isReadOnly`, and use `inputRef` for the inner
input ref
([#1081](#1081))
- Updated Figma Code Connect to the live `MMDS Components` file and
aligned `ButtonIcon` and `TextButton` mappings with the current
component APIs shown in Dev Mode
([#1109](#1109))

### ⚠️ Breaking Changes

#### Shared button size and variant exports (Both Platforms)

**What Changed:**

- `ButtonVariant`, `ButtonBaseSize`, `ButtonSize`, `ButtonHeroSize`,
`ButtonIconSize`, and `ButtonIconVariant` now come from shared
ADR-0003/ADR-0004 definitions instead of platform-local enums
- Runtime values and standard imports remain stable for typical usage

**Impact:**

- Affects TypeScript consumers that depended on enum-specific behavior
rather than the exported members themselves

#### React Native TextField prop layering (React Native)

**What Changed:**

- `TextField` and `TextFieldSearch` now treat the root as a `Box`/`View`
- Native `TextInput` props must move under `inputProps`
- `isReadonly` is renamed to `isReadOnly`
- `ref` now targets the outer container and `inputRef` targets the inner
`TextInput`

**Migration:**

```tsx
// Before (0.21.0)
<TextField
  value={query}
  onChangeText={setQuery}
  placeholder="Search"
  keyboardType="default"
  secureTextEntry
  onFocus={handleFocus}
/>

// After (0.22.0)
<TextField
  value={query}
  onChangeText={setQuery}
  placeholder="Search"
  onFocus={handleFocus}
  inputProps={{
    keyboardType: 'default',
    secureTextEntry: true,
  }}
/>
```

**Impact:**

- Affects React Native consumers passing `TextInput` props or
pressable-only props at the top level of `TextField` / `TextFieldSearch`

See migration guides for complete instructions:

- [React Native Migration
Guide](./packages/design-system-react-native/MIGRATION.md#from-version-0210-to-0220)

### ✅ 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.14.0` → `0.15.0`) - shared type
additions
- [x] design-system-react: minor (`0.19.0` → `0.20.0`) - includes
breaking changes under pre-1.0 semver
- [x] design-system-react-native: minor (`0.21.0` → `0.22.0`) - includes
breaking changes under pre-1.0 semver
- [x] Breaking changes documented with migration guidance where needed
- [x] Migration guides updated with before/after examples for the React
Native `TextField` 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 where migration
guidance is required
- [ ] All unreleased changes are accounted for in changelogs

<!-- CURSOR_SUMMARY -->
---

> [!NOTE]
> **Low Risk**
> Release-only change: bumps package versions and updates
changelog/migration documentation without modifying runtime code. Low
risk aside from potential downstream confusion if documented breaking
changes don’t match what was actually published.
> 
> **Overview**
> Bumps the monorepo release to `37.0.0` and increments package versions
for `@metamask/design-system-shared` (`0.15.0`),
`@metamask/design-system-react` (`0.20.0`), and
`@metamask/design-system-react-native` (`0.22.0`).
> 
> Updates consumer-facing release notes: adds new changelog entries
(including documented *breaking* type-export contract changes and RN
`TextField` API migration details), refreshes the RN migration guide
section for `0.21.0` → `0.22.0`, and updates changelog compare links
accordingly.
> 
> <sup>Reviewed by [Cursor Bugbot](https://cursor.com/bugbot) for commit
2140b12. Bugbot is set up for automated
code reviews on this repo. Configure
[here](https://www.cursor.com/dashboard/bugbot).</sup>
<!-- /CURSOR_SUMMARY -->
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

documentation Improvements or additions to documentation

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants