feat: [DSR+DSRN] Migrate Textarea component from extension#1036
feat: [DSR+DSRN] Migrate Textarea component from extension#1036georgewrmarshall wants to merge 1 commit intomainfrom
Conversation
…repo Adds Textarea component to both React and React Native packages following ADR-0003/0004 patterns. - Shared types in @metamask/design-system-shared with TextareaPropsShared (isDisabled, isReadOnly, isError) - React: forwardRef textarea with TextareaResize (None/Both/Horizontal/Vertical), textVariant, error/disabled/readonly states, aria-invalid - React Native: multiline TextInput wrapper with numberOfLines, focus/error styling, isStateStylesDisabled - Storybook stories, README, tests (23 tests, 100% coverage), and Figma Code Connect for both platforms
📖 Storybook Preview |
There was a problem hiding this comment.
Cursor Bugbot has reviewed your changes and found 2 potential issues.
Bugbot Autofix prepared fixes for both issues found in the latest run.
- ✅ Fixed: Web Textarea uses visible border instead of transparent
- Replaced the non-error border class with border-transparent to match borderless design and Input behavior.
- ✅ Fixed: Textarea metrics constant duplicates Input's identical constant
- Removed duplicated RN Textarea metrics object and re-exported the Input metrics constant instead.
Or push these changes by commenting:
@cursor push 33e5ca596b
Preview (33e5ca596b)
diff --git a/packages/design-system-react-native/src/components/Textarea/Textarea.constants.ts b/packages/design-system-react-native/src/components/Textarea/Textarea.constants.ts
--- a/packages/design-system-react-native/src/components/Textarea/Textarea.constants.ts
+++ b/packages/design-system-react-native/src/components/Textarea/Textarea.constants.ts
@@ -1,73 +1,11 @@
-import { typography } from '@metamask/design-tokens';
+import { MAP_TEXT_VARIANT_INPUT_METRICS } from '../Input/Input.constants';
-import { TextVariant } from '../../types';
-
/**
* Typographic metrics for Textarea: same tokens as `text-*` utilities but **without** `lineHeight`.
* React Native `TextInput` with multiline aligns text more predictably when line height is not set
* from the design-system paragraph specs.
*/
-export const MAP_TEXT_VARIANT_TEXTAREA_METRICS: Record<
- TextVariant,
- { fontSize: number; letterSpacing: number }
-> = {
- [TextVariant.DisplayLg]: {
- fontSize: typography.sDisplayLG.fontSize,
- letterSpacing: typography.sDisplayLG.letterSpacing,
- },
- [TextVariant.DisplayMd]: {
- fontSize: typography.sDisplayMD.fontSize,
- letterSpacing: typography.sDisplayMD.letterSpacing,
- },
- [TextVariant.HeadingLg]: {
- fontSize: typography.sHeadingLG.fontSize,
- letterSpacing: typography.sHeadingLG.letterSpacing,
- },
- [TextVariant.HeadingMd]: {
- fontSize: typography.sHeadingMD.fontSize,
- letterSpacing: typography.sHeadingMD.letterSpacing,
- },
- [TextVariant.HeadingSm]: {
- fontSize: typography.sHeadingSM.fontSize,
- letterSpacing: typography.sHeadingSM.letterSpacing,
- },
- [TextVariant.BodyLg]: {
- fontSize: typography.sBodyLGMedium.fontSize,
- letterSpacing: typography.sBodyLGMedium.letterSpacing,
- },
- [TextVariant.BodyMd]: {
- fontSize: typography.sBodyMD.fontSize,
- letterSpacing: typography.sBodyMD.letterSpacing,
- },
- [TextVariant.BodySm]: {
- fontSize: typography.sBodySM.fontSize,
- letterSpacing: typography.sBodySM.letterSpacing,
- },
- [TextVariant.BodyXs]: {
- fontSize: typography.sBodyXS.fontSize,
- letterSpacing: typography.sBodyXS.letterSpacing,
- },
- [TextVariant.PageHeading]: {
- fontSize: typography.sPageHeading.fontSize,
- letterSpacing: typography.sPageHeading.letterSpacing,
- },
- [TextVariant.SectionHeading]: {
- fontSize: typography.sSectionHeading.fontSize,
- letterSpacing: typography.sSectionHeading.letterSpacing,
- },
- [TextVariant.ButtonLabelMd]: {
- fontSize: typography.sButtonLabelMd.fontSize,
- letterSpacing: typography.sButtonLabelMd.letterSpacing,
- },
- [TextVariant.ButtonLabelLg]: {
- fontSize: typography.sButtonLabelLg.fontSize,
- letterSpacing: typography.sButtonLabelLg.letterSpacing,
- },
- [TextVariant.AmountDisplayLg]: {
- fontSize: typography.sAmountDisplayLg.fontSize,
- letterSpacing: typography.sAmountDisplayLg.letterSpacing,
- },
-};
+export const MAP_TEXT_VARIANT_TEXTAREA_METRICS = MAP_TEXT_VARIANT_INPUT_METRICS;
/**
* Default number of lines displayed in the Textarea.
diff --git a/packages/design-system-react/src/components/Textarea/Textarea.tsx b/packages/design-system-react/src/components/Textarea/Textarea.tsx
--- a/packages/design-system-react/src/components/Textarea/Textarea.tsx
+++ b/packages/design-system-react/src/components/Textarea/Textarea.tsx
@@ -30,7 +30,7 @@
'placeholder:text-alternative',
isError
? 'border-error-default focus:border-error-default'
- : 'border-default focus:border-primary-default',
+ : 'border-transparent focus:border-primary-default',
CLASSMAP_TEXTAREA_RESIZE[resize],
CLASSMAP_TEXT_VARIANT_FONTSTYLE[textVariant],
CLASSMAP_TEXT_VARIANT_FONTWEIGHT[textVariant],You can send follow-ups to this agent here.
| 'placeholder:text-alternative', | ||
| isError | ||
| ? 'border-error-default focus:border-error-default' | ||
| : 'border-default focus:border-primary-default', |
There was a problem hiding this comment.
Web Textarea uses visible border instead of transparent
Medium Severity
The non-error border class is border-default (a visible design-token color), but the README describes this as a "borderless" component. The web Input component and the React Native Textarea both use border-transparent for the non-error default state. Using border-default here causes the web Textarea to render with a visible border, inconsistent with the stated design intent and the other components it mirrors.
| fontSize: typography.sAmountDisplayLg.fontSize, | ||
| letterSpacing: typography.sAmountDisplayLg.letterSpacing, | ||
| }, | ||
| }; |
There was a problem hiding this comment.
Textarea metrics constant duplicates Input's identical constant
Low Severity
MAP_TEXT_VARIANT_TEXTAREA_METRICS is an exact copy of MAP_TEXT_VARIANT_INPUT_METRICS from Input.constants.ts — same type signature, same values for every TextVariant key. This duplication means any typography-metric fix or new variant addition needs to be applied in both files, risking drift.



Description
Migrates the
Textareacomponent from the MetaMask Extension component-library into the design system monorepo for both React (web) and React Native (mobile) platforms.The Extension has a Textarea component; mobile has no dedicated multiline text input, so the React Native implementation is new and follows the existing
Inputcomponent pattern.Follows ADR-0003 (const objects instead of enums) and ADR-0004 (centralized types in
@metamask/design-system-shared).What's included
@metamask/design-system-sharedTextareaPropsShared— shared cross-platform props:isDisabled,isReadOnly,isError@metamask/design-system-reactTextareacomponent —forwardRefwrapper around<textarea>with Tailwind stylingTextareaResizeconst object —None,Both,Horizontal,Vertical(maps to Tailwindresize-*classes)textVariant,resize,rows,cols,maxLength,isDisabled,isReadOnly,isError,className,stylearia-invalidwhenisErroris true@metamask/design-system-react-nativeTextareacomponent —forwardRefwrapper aroundTextInputwithmultiline={true}andtextAlignVertical="top"textVariant,numberOfLines(default: 4),isDisabled,isReadOnly,isError,isStateStylesDisabled,twClassName,styleBoth platforms include Figma Code Connect files pointing to node
12091:104.Related issues
Fixes:
Manual testing steps
yarn storybookand navigate to React Components/Textarea — verify Default, Variant, Resize, IsDisabled, IsReadOnly, IsError, and Rows stories render correctlyyarn storybook:iosand navigate to Components/Textarea — verify all stories render correctly on iOS simulatorTextareaResizevalue applies the correct CSS classborder-error-defaultstyling andaria-invalid="true"on webopacity-50andcursor-not-allowedon web, andopacity-50+ non-editable on nativeScreenshots/Recordings
Before
No Textarea component in the design system monorepo.
After
Pre-merge author checklist
Pre-merge reviewer checklist
Note
Medium Risk
Introduces new public
Textareaexports in bothdesign-system-reactanddesign-system-react-native, plus shared prop types, which may impact consumers via new API surface and styling/behavior expectations. Risk is mitigated by comprehensive Storybook docs and unit tests, but integration/visual regressions are still possible.Overview
Adds a new cross-platform
Textareacomponent to the design system for both web (design-system-react) and React Native (design-system-react-native), and exports it from each package’s components index.Web
Textareawraps<textarea>with Tailwind classes, supports typography viatextVariant, error/disabled/readonly states (includingaria-invalid), and a newTextareaResizeconst mapping to CSSresize-*behavior. React NativeTextareawrapsTextInputwithmultiline, controlled-onlyvalue, theming-based placeholder color,numberOfLinesdefaulting to4, and optional state styling (focus/disabled/error) that can be disabled viaisStateStylesDisabled.Adds
TextareaPropsSharedtodesign-system-shared, plus Storybook stories, Figma Code Connect mappings, READMEs, and unit tests for both platforms.Written by Cursor Bugbot for commit 1d7f7e0. This will update automatically on new commits. Configure here.