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
📖 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.
…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
1d7f7e0 to
e907234
Compare



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
Mostly additive, but introduces new shared/public exports (
Textarea,TextareaResize,TextareaPropsShared) and new focus/disabled/error styling behavior that could affect consumers once adopted.Overview
Adds a new cross-platform
Textareato the design system for React web and React Native, including public exports from each package.Web implementation wraps
<textarea>with Tailwind styling,TextareaResize(mapped toresize-*classes), typography viatextVariant, and accessibility viaaria-invalidon error. Native implementation adds a controlled-only multilineTextInputwith theme-based placeholder color, typography metrics tuned for multiline (nolineHeight), and optional state styling for focus/disabled/error.Introduces
TextareaPropsSharedin@metamask/design-system-shared, plus Storybook stories, tests, and Figma Code Connect wiring for both platforms.Reviewed by Cursor Bugbot for commit e907234. Bugbot is set up for automated code reviews on this repo. Configure here.