Skip to content

feat: TextField migration (extension)#1170

Merged
georgewrmarshall merged 10 commits into
mainfrom
feat/text-field-migration-extension
May 25, 2026
Merged

feat: TextField migration (extension)#1170
georgewrmarshall merged 10 commits into
mainfrom
feat/text-field-migration-extension

Conversation

@kirillzyusko

@kirillzyusko kirillzyusko commented May 11, 2026

Copy link
Copy Markdown
Collaborator

Description

Added TextField component to DSR.

Related issues

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

Manual testing steps

  1. Open Storybook app
  2. Check TextField example

Screenshots/Recordings

Before

image

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
New UI component with tests and documentation only; no changes to auth, data handling, or existing consumer runtime behavior until extensions adopt the new import.

Overview
Adds TextField to @metamask/design-system-react as the web implementation of the extension migration (DSYS-316): a forwardRef root <div> that wraps design-system Input, with Tailwind-based chrome (sizes, focus/error/disabled borders), optional start/end accessories, and inputElement / inputRef / inputProps for customization.

Exports TextField, TextFieldSize, TextFieldType, and TextFieldProps from the package barrel; web-only size/type const objects extend shared TextFieldPropsShared. Includes Storybook docs, stories, and unit tests. MIGRATION.md documents extension → design-system moves (disabled/readOnly/erroris*, InputComponentinputElement, controlled-only, no polymorphic Box).

Shared package: comment tweak on TextFieldPropsShared and export { type ... } on the TextField types index.

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

@kirillzyusko kirillzyusko self-assigned this May 11, 2026
@github-actions

Copy link
Copy Markdown
Contributor

📖 Storybook Preview

@github-actions

Copy link
Copy Markdown
Contributor

📖 Storybook Preview

@kirillzyusko kirillzyusko marked this pull request as ready for review May 11, 2026 16:11
@kirillzyusko kirillzyusko requested a review from a team as a code owner May 11, 2026 16:11

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

Can you address Bugbot comments?

@github-actions

Copy link
Copy Markdown
Contributor

📖 Storybook Preview

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

do you think you can extract TextField types out to shared like the other components we've been migrating?

@kirillzyusko kirillzyusko force-pushed the feat/text-field-migration-extension branch from a4daf39 to 5fda8a6 Compare May 13, 2026 16:05
@github-actions

Copy link
Copy Markdown
Contributor

📖 Storybook Preview

Comment thread packages/design-system-shared/src/types/TextField/TextField.types.ts 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.

The implementation and MIGRATION.md are solid, but the TextFieldPropsShared additions need to be addressed before merging — several props added to the shared type are either HTML-specific or were deliberately removed from the RN platform. See inline comments for the full breakdown.

One additional item not capturable as an inline comment: the focused border color differs between platforms. The React implementation uses border-primary-default (blue) while the RN TextField uses border-default (gray) — worth aligning

Screenshot 2026-05-20 at 12 03 45 PM Screenshot 2026-05-20 at 12 20 03 PM

*
* @default TextFieldSize.Md
*/
size?: TextFieldSize;

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.

These props added to TextFieldPropsShared need to move to the React-only TextFieldProps. Cross-referencing against the RN TextField implementation:

  • size — removed from RN as a breaking change in v0.12.0 (PR refactor: updated Input and TextField to align with mobile fixes #1000); implementation hardcodes h-12
  • type — HTML input attribute with no RN equivalent; RN consumers use inputProps.keyboardType / inputProps.secureTextEntry instead; falls through to Box via ...props
  • truncate — RN hardcodes numberOfLines={1}; prop is not consumed
  • name / id / required — HTML form attributes with no RN equivalent; fall through to Box via ...props
  • maxLength — RN TextInput supports this natively but the RN TextField doesn't destructure or forward it to the inner Input, so it currently falls through to Box instead

The props that correctly belong in shared are: isError, startAccessory, endAccessory, and inputElement. Once the web-only props move to the React layer, TextFieldSize and TextFieldType const objects can also move to the React package since nothing in shared will reference them.

placeholder: 'Sample placeholder',
value: '',
},
render: (args) => <ControlledTextField {...args} />,

@georgewrmarshall georgewrmarshall May 20, 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 Default story renders via <ControlledTextField>, so Storybook's "View Code" panel shows that wrapper name instead of <TextField>. Since that panel is intended to be a copy-pasteable example, consider inlining useState directly in the render function so <TextField> is the visible root element.

Screenshot 2026-05-20 at 12 07 12 PM

@kirillzyusko kirillzyusko force-pushed the feat/text-field-migration-extension branch from 5fda8a6 to 27d5e9f Compare May 22, 2026 14:42
@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 27d5e9f. Configure here.

Comment thread packages/design-system-react/src/components/TextField/TextField.stories.tsx Outdated
@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.

LGTM! The two blocking issues from round 1 are properly resolved: web-only props (TextFieldSize, TextFieldType, size, type, truncate, name, id, required, maxLength) correctly moved out of shared into the React package, and the TextFieldInputProps Omit list now covers all props that would silently collide with top-level ones. The Default story inline state fix and className control removal are also done. Nice work. Approved!

@georgewrmarshall georgewrmarshall enabled auto-merge (squash) May 25, 2026 22:41
@georgewrmarshall georgewrmarshall dismissed brianacnguyen’s stale review May 25, 2026 22:41

OOO and issues have been resolved

@github-actions

Copy link
Copy Markdown
Contributor

📖 Storybook Preview

@georgewrmarshall georgewrmarshall merged commit b172be8 into main May 25, 2026
44 checks passed
@georgewrmarshall georgewrmarshall deleted the feat/text-field-migration-extension branch May 25, 2026 22:45
@georgewrmarshall georgewrmarshall mentioned this pull request May 29, 2026
18 tasks
georgewrmarshall added a commit that referenced this pull request May 29, 2026
## 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 -->
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.

3 participants