Skip to content

refactor: Added default padding and added isInteractive to SectionHeader#1210

Merged
brianacnguyen merged 9 commits into
mainfrom
update/section-header
Jun 4, 2026
Merged

refactor: Added default padding and added isInteractive to SectionHeader#1210
brianacnguyen merged 9 commits into
mainfrom
update/section-header

Conversation

@brianacnguyen

@brianacnguyen brianacnguyen commented Jun 3, 2026

Copy link
Copy Markdown
Contributor

Description

This PR updates the React Native SectionHeader component to match design specs and support tappable section headers.

Why: Section headers needed consistent default spacing, and some headers (e.g. "See all") should be pressable with clear visual feedback.

What changed:

  • Default padding — Applies px-4 pt-3 pb-2 to the outer wrapper by default (still overridable via twClassName).
  • isInteractive prop — Discriminated union type:
    • false/omitted: static BoxRow with ViewProps (unchanged behavior).
    • true: wraps the header in Pressable with PressableProps; opacity reduces to 0.7 while pressed.
  • Default end icon — When isInteractive is true, renders IconName.ArrowRight unless endIconName, endIconProps.name, or endAccessory is provided.
  • End icon color — End icons use IconColor.IconAlternative.

Also includes README updates, an Interactive Storybook story, unit tests, and a jest branch coverage override for the untestable pressed-state branch (same pattern as ActionListItem).

Related issues

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

Manual testing steps

  1. Run React Native Storybook: yarn storybook:ios or yarn storybook:android
  2. Open Components/SectionHeader
  3. Default — Confirm default padding (px-4 pt-3 pb-2) on static headers
  4. Interactive — Confirm:
    • Arrow-right end icon appears by default
    • Row is tappable (onPress fires)
    • Opacity reduces to ~0.7 while pressed
  5. Optionally verify overrides: custom endIconName, endAccessory, and twClassName still work when isInteractive is true

Screenshots/Recordings

Before

After

Simulator.Screen.Recording.-.iPhone.15.Pro.Max.-.2026-06-02.at.21.52.29.mov

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

Medium Risk
Default padding and optional Pressable behavior change layout and touch targets for every SectionHeader consumer; removing icon name resolution via iconProps is a subtle breaking API change.

Overview
React Native SectionHeader now applies default outer padding (px-4 pt-3 pb-2) and supports isInteractive: when true, the row is a Pressable with PressableProps, default accessibilityRole of button, opacity-70 while pressed (skipped when disabled), and a default ArrowRight end icon unless endIconName or endAccessory is set. Non-interactive usage stays on a static outer BoxRow with ViewProps.

API / styling tweaks: SectionHeaderProps is a discriminated union on isInteractive; startIconProps / endIconProps no longer accept name (icons come only from startIconName / endIconName). End icons use IconColor.IconAlternative. Layout is refactored so the title sits in an inner row and start/end accessories sit on the outer wrapper (or inside the pressable inner row when interactive).

Docs, Storybook (Interactive story), expanded unit tests, and a Jest branch coverage exception for SectionHeader.tsx (same pressed-state limitation as ActionListItem) are included.

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

@brianacnguyen brianacnguyen self-assigned this Jun 3, 2026
@brianacnguyen brianacnguyen requested a review from a team as a code owner June 3, 2026 04:57
@github-actions

github-actions Bot commented Jun 3, 2026

Copy link
Copy Markdown
Contributor

📖 Storybook Preview

@github-actions

github-actions Bot commented Jun 3, 2026

Copy link
Copy Markdown
Contributor

📖 Storybook Preview

@github-actions

github-actions Bot commented Jun 3, 2026

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 5b42e83. Configure here.

@github-actions

github-actions Bot commented Jun 3, 2026

Copy link
Copy Markdown
Contributor

📖 Storybook Preview

@github-actions

github-actions Bot commented Jun 3, 2026

Copy link
Copy Markdown
Contributor

📖 Storybook Preview

@brianacnguyen brianacnguyen enabled auto-merge (squash) June 3, 2026 20:44
Comment on lines -35 to -41
decorators: [
(Story) => (
<Box twClassName="w-full bg-background-default p-4">
<Story />
</Box>
),
],

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.

Nice. I think we should actually remove all of these types of wrappers from our stories regardless of how they sit within the page...

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

Nice work adding the interactive SectionHeader behavior. The implementation looks good overall, Bugbot's disabled pressed-state concern appears addressed in the latest commits, and the focused SectionHeader test suite passes locally. I left a few non-blocking comments around Storybook controls, accessibility defaults, prop typing, and docs consistency.

@brianacnguyen brianacnguyen left a comment

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Let me update

@github-actions

github-actions Bot commented Jun 3, 2026

Copy link
Copy Markdown
Contributor

📖 Storybook Preview

@github-actions

github-actions Bot commented Jun 3, 2026

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.

Approved. I left non-blocking follow-up comments.

import { SectionHeader } from './SectionHeader';
import type { SectionHeaderProps } from './SectionHeader.types';

const noopPress = () => undefined;

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 would be a good use of actions but we can do a bulk update not critical

jest.clearAllMocks();
});

const flattenStyles = (

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: I think this is okay to approve and merge, but could we avoid leaning further into flattenStyles, findPressableStyleFn, and getPressableStyleFn long term? PR #1184 moved us away from react-test-renderer tree traversal because it is related to RNTL implementation-detail anti-patterns: RNTL cautions against navigating the ReactTestInstance tree because it makes tests fragile, and its type/props queries are explicitly marked UNSAFE for the same reason. I have not found a reliable way to test Pressable pressed-state visual logic through RNTL without reaching into renderer internals, so we may want to remove these helpers and accept/document the reduced branch coverage in the PR that upgrades RNTL. References: https://callstack.github.io/react-native-testing-library/docs/advanced/testing-env#tree-navigation and https://callstack.github.io/react-native-testing-library/docs/api/queries#legacy-unit-testing-helpers

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sure. Should we do a change to remove these tips and add a rule to the testing rules?

@github-actions

github-actions Bot commented Jun 4, 2026

Copy link
Copy Markdown
Contributor

📖 Storybook Preview

@brianacnguyen brianacnguyen merged commit 8e53c31 into main Jun 4, 2026
36 checks passed
@brianacnguyen brianacnguyen deleted the update/section-header branch June 4, 2026 03:15
@georgewrmarshall georgewrmarshall mentioned this pull request Jun 4, 2026
18 tasks
georgewrmarshall added a commit that referenced this pull request Jun 4, 2026
## Release 43.0.0

This release drops Node.js 18 support across the release line, adds
several new components, and includes a small set of breaking API changes
that are documented in the migration guides.

### 📦 Package Versions

- `@metamask/design-system-shared`: **0.21.0**
- `@metamask/design-system-react`: **0.25.0**
- `@metamask/design-system-react-native`: **0.28.0**
- `@metamask/design-tokens`: **8.5.0**
- `@metamask/design-system-tailwind-preset`: **0.9.0**
- `@metamask/design-system-twrnc-preset`: **0.5.0**

### 🔄 Shared Type Updates (0.21.0)

#### Added

- Added `ContentPropsShared` and `ContentVerticalAlignment` for React
Native list-style rows and related layout patterns
([#1192](#1192))

#### Changed

- **BREAKING:** Dropped Node.js 18 support for the release line;
consumers must run Node 20 or newer
([#1206](#1206))
- **BREAKING:** Updated `TextAreaPropsShared` to remove `inputElement`
so React Native `TextArea` can render the root `TextInput` directly
([#1205](#1205))

### 🌐 React Web Updates (0.25.0)

#### Added

- Added `Popover` for anchored overlays such as menus, tooltips, and
dialogs
([#1153](#1153))
- Added `TextArea` for controlled multiline text entry
([#1036](#1036))
- Added `TextFieldSearch` for controlled search-field flows on top of
`TextField`
([#1171](#1171))
- Added `FormTextField` for labeled form controls built from `Label`,
`TextField`, and `HelpText`
([#1197](#1197))

#### Changed

- **BREAKING:** Dropped Node.js 18 support for the release line;
consumers must run Node 20 or newer
([#1206](#1206))
- Updated avatar fallback handling so `AvatarToken`, `AvatarNetwork`,
and `AvatarFavicon` resolve consistently when the requested image is
unavailable
([#1212](#1212))

### 📱 React Native Updates (0.28.0)

#### Added

- Added `Content` for composing scrollable and padded content sections
on React Native screens; it is closely related to the upcoming
`ListItem` work
([#1192](#1192))

#### Changed

- **BREAKING:** Dropped Node.js 18 support for the release line;
consumers must run Node 20 or newer
([#1206](#1206))
- Added default padding and `isInteractive` support to `SectionHeader`
so section rows match the new mobile layout patterns
([#1210](#1210))
- **BREAKING:** Flattened `TextArea` so it renders the root `TextInput`
directly; pass `TextInput` props on `TextArea`, use the component `ref`
for the input, and stop relying on `inputProps` or `inputElement`
([#1205](#1205))
- Updated avatar fallback handling so `AvatarToken`, `AvatarNetwork`,
and `AvatarFavicon` resolve consistently when the requested image is
unavailable
([#1212](#1212))

### ⚠️ Breaking Changes

#### Node.js 18 support removed

**What Changed:**

- The release line now requires Node 20 or newer.
- This applies across the monorepo, including the shared package, web
package, React Native package, tokens, and both preset packages.

**Impact:**

- Consumers still on Node 18 must upgrade their runtime before
installing or developing against this release line.
- Node 18 is end-of-life, so this change aligns the repo with the
supported app runtimes.

#### React Native `TextArea` flattening

**What Changed:**

- `TextArea` now renders the root `TextInput` directly.
- `inputProps` and `inputElement` are removed.
- `inputRef` is replaced by the component `ref`.

**Migration:**

```tsx
// Before (0.27.0)
<TextArea
  inputProps={{ placeholder: 'Message' }}
  inputElement={<CustomInput />}
/>

// After (0.28.0)
<TextArea placeholder="Message" ref={inputRef} />
```

**Impact:**

- Affects React Native consumers using `TextArea`.
- Call sites that depended on the wrapper/input split need to be
updated.

See migration guides for complete instructions:

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

### ✅ 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.20.0 → 0.21.0) - shared type
additions and breaking TextArea/shared runtime baseline
- [x] design-system-react: minor (0.24.0 → 0.25.0) - new components and
release-line update
- [x] design-system-react-native: minor (0.27.0 → 0.28.0) - new
component, SectionHeader update, and breaking TextArea change
- [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**

- [x] I've reviewed the [Reviewing Release
PRs](./docs/reviewing-release-prs.md) guide
- [x] Package versions follow semantic versioning
- [x] Changelog entries are consumer-facing (not commit message
regurgitation)
- [x] Breaking changes are documented in MIGRATION.md with examples
- [x] All unreleased changes are accounted for in changelogs

<!-- CURSOR_SUMMARY -->
---

> [!NOTE]
> **Medium Risk**
> Breaking React Native TextArea and Node 18 removal affect consumer
upgrades; most diff is release metadata with coordinated peer dependency
bumps.
> 
> **Overview**
> **Release 43.0.0** bumps the monorepo root to **43.0.0** and publishes
coordinated semver bumps across design-system packages, with
**yarn.lock** peer ranges updated for
`@metamask/design-system-tailwind-preset` **^0.9.0** and
`@metamask/design-system-twrnc-preset` **^0.5.0**.
> 
> Across the release line, changelogs record **Node.js 18 dropped**
(Node **20+** required). **@metamask/design-system-react** **0.25.0**
documents new **`Popover`**, **`TextArea`**, **`TextFieldSearch`**, and
**`FormTextField`**, plus avatar fallback fixes.
**@metamask/design-system-react-native** **0.28.0** adds **`Content`**,
updates **`SectionHeader`** (default padding, **`isInteractive`**), and
includes a **breaking** **`TextArea`** flattening (`inputProps` /
`inputElement` / `inputRef` removed; props and **`ref`** target the root
**`TextInput`**). **@metamask/design-system-shared** **0.21.0** adds
**`ContentPropsShared`** / **`ContentVerticalAlignment`** and removes
**`inputElement`** from shared **`TextArea`** props.
> 
> Migration guide edits in this diff: React Native **0.27.0 → 0.28.0**
**`TextArea`** guidance; React version heading **0.22.0 → 0.23.0** for
**`BannerBase`** (changelog-driven **0.25.0** items are not new
migration sections here).
> 
> <sup>Reviewed by [Cursor Bugbot](https://cursor.com/bugbot) for commit
23b0cda. 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.

2 participants