Skip to content

[3/N] feat: Modal migration (extension)#1136

Merged
kirillzyusko merged 3 commits into
mainfrom
feat/modal-migration
May 5, 2026
Merged

[3/N] feat: Modal migration (extension)#1136
kirillzyusko merged 3 commits into
mainfrom
feat/modal-migration

Conversation

@kirillzyusko

@kirillzyusko kirillzyusko commented Apr 30, 2026

Copy link
Copy Markdown
Collaborator

Description

Added Modal component to DSR.

Related issues

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

Manual testing steps

  1. Open Storybook
  2. Check Modal component

Screenshots/Recordings

Before

Screen.Recording.2026-05-04.at.19.16.08.mov

After

Screen.Recording.2026-05-04.at.19.17.21.mov

Important

The animation is added in ModalContent and it's handled in #1139

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
Introduces a new portal-based Modal root component and new public exports (Modal, useModalContext, ModalProps), which can affect consumers via bundle API surface and runtime portal/context behavior. Risk is mitigated by added unit tests and Storybook coverage, but modal/focus behavior regressions are still possible in consuming apps.

Overview
Adds new Modal root component that conditionally portals its subtree into document.body when isOpen and provides modal behavior configuration to descendants via ModalContext/useModalContext.

Exports Modal, useModalContext, and related types (ModalProps, ModalContextType) from the component barrel, and adds Storybook (README.mdx + stories) plus unit tests covering portal mount/unmount, ref/attribute forwarding, context defaults, and the outside-provider error case.

Updates MIGRATION.md with a Modal migration section documenting import-path swaps, prop/context shape notes, and the updated useModalContext error message (plus removal of the legacy mm-modal class hook).

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

@kirillzyusko kirillzyusko self-assigned this Apr 30, 2026
@github-actions

Copy link
Copy Markdown
Contributor

📖 Storybook Preview

@github-actions

Copy link
Copy Markdown
Contributor

📖 Storybook Preview

@kirillzyusko kirillzyusko changed the title feat: Modal migration (extension) [1/N] feat: Modal migration (extension) Apr 30, 2026
@kirillzyusko kirillzyusko changed the title [1/N] feat: Modal migration (extension) [5/N] feat: Modal migration (extension) Apr 30, 2026
@kirillzyusko kirillzyusko force-pushed the feat/modal-migration branch from ddf5756 to 71ee7c4 Compare May 4, 2026 14:15
@github-actions

github-actions Bot commented May 4, 2026

Copy link
Copy Markdown
Contributor

📖 Storybook Preview

@kirillzyusko kirillzyusko changed the title [5/N] feat: Modal migration (extension) [3/N] feat: Modal migration (extension) May 4, 2026
@kirillzyusko kirillzyusko force-pushed the feat/modal-migration branch from 71ee7c4 to ea0dbaa Compare May 4, 2026 16:35
@github-actions

github-actions Bot commented May 4, 2026

Copy link
Copy Markdown
Contributor

📖 Storybook Preview

@github-actions

github-actions Bot commented May 4, 2026

Copy link
Copy Markdown
Contributor

📖 Storybook Preview

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

@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 2 potential issues.

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 d237976. Configure here.

autoFocus = true,
initialFocusRef,
finalFocusRef,
restoreFocus,

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.

Missing restoreFocus default value unlike sibling props

Low Severity

restoreFocus is destructured without a default value, unlike its sibling boolean props (isClosedOnOutsideClick = true, isClosedOnEscapeKey = true, autoFocus = true). This means ctx.restoreFocus is undefined instead of false when unset, despite the JSDoc documenting @default false. Both the test and story work around this by wrapping in Boolean() (String(Boolean(ctx.restoreFocus))) while the other three props use plain String() — confirming the value is unexpectedly undefined. A consumer checking ctx.restoreFocus === false would get the wrong result.

Additional Locations (2)
Fix in Cursor Fix in Web

Reviewed by Cursor Bugbot for commit d237976. Configure here.

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 we address these comments? I think it makes sense to add the default here


import type { ModalProps } from './Modal.types';

export type ModalContextType = Omit<ModalProps, 'children'>;

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.

Context type leaks all HTML div attributes

Low Severity

ModalContextType is defined as Omit<ModalProps, 'children'>, but ModalProps extends ComponentProps<'div'>. This means the exported public context type includes every HTML div attribute (onClick, style, id, role, className, etc.), even though the context value only ever populates the eight modal-specific fields. Consumers typing against ModalContextType see ~150 properties that are always undefined. A narrower dedicated type listing only the behavior-config fields would accurately reflect what the context actually provides.

Additional Locations (1)
Fix in Cursor Fix in Web

Reviewed by Cursor Bugbot for commit d237976. Configure here.

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.

This makes sense

@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 root API and behavior look aligned with the extension version, and the current test coverage gives reasonable confidence in the portal/context contract. I have one follow-up note on Storybook/docs parity: the story set is still thinner than the extension source today, but that seems appropriate to expand once the rest of the modal subcomponents are available so the examples can demonstrate the intended composed usage more realistically.

Could we also address the Cursor comments #1136 (review)

);

const Backdrop = ({ onClick }: { onClick?: () => void }) => (
<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.

non-blocking: The current story set is enough for the root primitive, but it is still much thinner than the extension source stories for major modal behaviors. Once ModalContent, ModalHeader, and the rest of the modal family are merged, can we expand this with richer stories for the main behavior props so Storybook/docs better reflect the intended composed usage?

@georgewrmarshall georgewrmarshall enabled auto-merge (squash) May 5, 2026 20:27
@georgewrmarshall georgewrmarshall disabled auto-merge May 5, 2026 20:27
@github-actions

github-actions Bot commented May 5, 2026

Copy link
Copy Markdown
Contributor

📖 Storybook Preview

@kirillzyusko kirillzyusko merged commit b2e887f into main May 5, 2026
44 checks passed
@kirillzyusko kirillzyusko deleted the feat/modal-migration branch May 5, 2026 21:08
@brianacnguyen brianacnguyen mentioned this pull request May 8, 2026
20 tasks
georgewrmarshall pushed a commit that referenced this pull request May 8, 2026
## Release 39.0.0

This release adds Tailwind CSS v4 integration via
`@metamask/design-tokens/tailwind/theme.css`, ships extension migration
UI on React web (`Modal`, `ModalContent`, `Skeleton`, `HeaderBase`),
adds Tailwind preset animations (`animate-slide-up`,
`animate-skeleton-pulse`), and refreshes the shared icon set
(`ListArrow`, `Musd`, `MusdFilled`, `Group`, `PieChart`, `Predictions`,
refreshed `Candlestick`, `Musd` SVG fix) across
`@metamask/design-system-shared`, React, and React Native. **React
Native** also ships a **breaking** Toast follow-up
([#1143](#1143)):
root **`Toaster`**, imperative **`toast`** / **`toast.dismiss()`**, and
flat **`ToastSeverity`** options. The TWRNC preset widens its React peer
range for newer React Native / React stacks.

### 📦 Package Versions

- `@metamask/design-tokens`: **8.4.0**
- `@metamask/design-system-shared`: **0.17.0**
- `@metamask/design-system-react`: **0.22.0**
- `@metamask/design-system-react-native`: **0.24.0**
- `@metamask/design-system-tailwind-preset`: **0.8.0**
- `@metamask/design-system-twrnc-preset`: **0.4.2**

### 🎨 Design Tokens (8.4.0)

#### Added (#1117)

**What changed**

- Added `@metamask/design-tokens/tailwind/theme.css` for Tailwind CSS v4
so consumers can import MetaMask token variables, theme values,
typography, font, and shadow utilities in one place.

**Impact**

- Web apps on Tailwind v4 can adopt the token theme without hand-rolling
CSS variables; see [Tailwind CSS v3 to
v4](./packages/design-tokens/MIGRATION.md#tailwind-css-v3-to-v4).

### 🪶 `@metamask/design-system-tailwind-preset` (0.8.0)

#### Added

- **`animate-slide-up`** (and `slide-up` keyframes) for the same dialog
entrance motion as `ModalContent`
([#1139](#1139))
- **`animate-skeleton-pulse`** (and `skeleton-pulse` keyframes) for
loading placeholders used with `Skeleton`
([#1146](#1146))

### 📲 `@metamask/design-system-twrnc-preset` (0.4.2)

#### Changed (#844)

- Expanded the `react` peer dependency range to `>=18.2.0` so the preset
installs cleanly alongside React Native 0.76 and React 19 app stacks.

### 🔄 Shared Type Updates (0.17.0)

#### Shared icon set (#1157, #1161, #1162, #1163)

**What changed**

- Extended the shared icon set with `ListArrow`, `Musd`, `MusdFilled`,
`Group`, `PieChart`, and `Predictions`, refreshed the `Candlestick`
icon, and corrected the `Musd` asset to use a single SVG path.

**Impact**

- Keeps `IconName` and assets aligned for
`@metamask/design-system-react` and
`@metamask/design-system-react-native`.

### 🌐 React Web Updates (0.22.0)

#### Added

- Added `Modal` and `ModalContent` for dialogs, `Skeleton` for loading
placeholders, and `HeaderBase` for header layouts—supporting the
MetaMask extension migration into the design system
([#1136](#1136),
[#1139](#1139),
[#1146](#1146),
[#1142](#1142))
- Added icons `ListArrow`, `Musd`, `MusdFilled`, `Group`, `PieChart`,
and `Predictions`, and updated the `Candlestick` icon
([#1157](#1157),
[#1161](#1161),
[#1162](#1162))

#### Fixed

- Corrected the `Musd` icon asset so it renders from a single SVG path
([#1163](#1163))

### 📱 React Native Updates (0.24.0)

#### Added

- Added icons `ListArrow`, `Musd`, `MusdFilled`, `Group`, `PieChart`,
and `Predictions`, and updated the `Candlestick` icon
([#1157](#1157),
[#1161](#1161),
[#1162](#1162))

#### Changed

- **BREAKING:** Toast API follow-up
([#1143](#1143)):
mount **`<Toaster />`** once at the root; use **`toast(...)`** /
**`toast.dismiss()`** instead of **`Toast.show(...)`** /
**`Toast.hide()`**; content-first options with **`ToastSeverity`** and
**`iconAlertProps`** (renamed from **`iconProps`**). See [Migration
Guide](./packages/design-system-react-native/MIGRATION.md#from-version-0230-to-0240).

#### Fixed

- Corrected the `Musd` icon asset so it renders from a single SVG path
([#1163](#1163))

### ⚠️ Breaking Changes

#### React Native — Toast (#1143)

**What changed**

- Imperative API moves from **`Toast.show`** / **`Toast.hide`** on
**0.23.x** to **`toast`** / **`toast.dismiss()`** with a root
**`<Toaster />`**.
- Options flatten to **`title`**, **`description`**, **`severity`**
(**`ToastSeverity`**), accessories, and **`iconAlertProps`**; map
**`ToastVariant`**-style payloads from **0.23.0** using the migration
guide.

**Migration**

- See [From version 0.23.0 to
0.24.0](./packages/design-system-react-native/MIGRATION.md#from-version-0230-to-0240)
(and [Toast
Component](./packages/design-system-react-native/MIGRATION.md#toast-component)
for component-library migration context).

### ✅ Checklist

- [x] Changelogs updated with human-readable descriptions
- [x] Changelog validation passed (`yarn changelog:validate`)
- [x] Version bumps follow semantic versioning
- [x] design-tokens: minor (8.3.0 → 8.4.0) — Tailwind v4 `theme.css`
entry point
- [x] design-system-shared: minor (0.16.0 → 0.17.0) — shared icon set
additions and asset fixes
- [x] design-system-react: minor (0.21.0 → 0.22.0) — extension migration
components and icons
- [x] design-system-react-native: minor (0.23.0 → 0.24.0) — **breaking
Toast follow-up (#1143)**, icons, `Musd` fix
- [x] design-system-tailwind-preset: minor (0.7.0 → 0.8.0) —
`animate-slide-up` and `animate-skeleton-pulse` for ModalContent /
Skeleton
- [x] design-system-twrnc-preset: patch (0.4.1 → 0.4.2) — wider `react`
peer range
- [x] Breaking changes documented with migration guidance (React Native
Toast — see MIGRATION.md link above)
- [x] Migration guides updated with before/after examples (Toast **0.23
→ 0.24**; Tailwind v4 consumers — design-tokens migration link above)
- [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
- [x] 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
(**React Native Toast** — [0.23.0 →
0.24.0](./packages/design-system-react-native/MIGRATION.md#from-version-0230-to-0240))
- [ ] All unreleased changes are accounted for in changelogs


<!-- CURSOR_SUMMARY -->
---

> [!NOTE]
> **Medium Risk**
> Primarily a release/version bump, but it changes published package
versions and updates peer dependency requirements, which can affect
downstream installs. React Native release notes include a breaking
`Toast` API change that consumers must account for when upgrading.
> 
> **Overview**
> Bumps the monorepo release to `39.0.0` and increments package versions
for `@metamask/design-system-react` (`0.22.0`),
`@metamask/design-system-react-native` (`0.24.0`),
`@metamask/design-system-shared` (`0.17.0`), and
`@metamask/design-system-tailwind-preset` (`0.8.0`), updating
corresponding changelogs and compare links.
> 
> Updates `@metamask/design-system-react` to require
`@metamask/design-system-tailwind-preset@^0.8.0` (and aligns
`yarn.lock`). Changelogs capture the release contents, including new
modal/skeleton/header additions on web, icon set updates across
packages, and a **breaking** React Native `Toast` API tightening for
`Toaster`/`toast(...)` usage.
> 
> <sup>Reviewed by [Cursor Bugbot](https://cursor.com/bugbot) for commit
4e3ea63. 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