[4/N] feat: ModalContent migration (extension)#1139
Conversation
📖 Storybook Preview |
ModalContent migration (extension)ModalContent migration (extension)
ModalContent migration (extension)ModalContent migration (extension)
6e92c37 to
15a62ce
Compare
ddf5756 to
71ee7c4
Compare
15a62ce to
3bd21d5
Compare
ModalContent migration (extension)ModalContent migration (extension)
📖 Storybook Preview |
71ee7c4 to
ea0dbaa
Compare
<!-- Please submit this PR as a draft initially. Do not mark it as "Ready for review" until the template has been completely filled out, and PR status checks have passed at least once. --> ## **Description** <!-- Write a short description of the changes included in this pull request, also include relevant motivation and context. Have in mind the following questions: 1. What is the reason for the change? 2. What is the improvement/solution? --> 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** <!-- If applicable, add screenshots and/or recordings to visualize the before and after of your change. --> ### **Before** https://github.com/user-attachments/assets/a42f3b88-ee65-4714-b34c-8e9190f5dc74 ### **After** https://github.com/user-attachments/assets/704d2f49-ed60-45a2-a306-660f041574dc > [!IMPORTANT] > The animation is added in `ModalContent` and it's handled in #1139 ## **Pre-merge author checklist** - [x] I've followed [MetaMask Contributor Docs](https://github.com/MetaMask/contributor-docs) - [x] I've completed the PR template to the best of my ability - [x] I’ve included tests if applicable - [x] I’ve documented my code using [JSDoc](https://jsdoc.app/) format if applicable - [x] I’ve applied the right labels on the PR (see [labeling guidelines](https://github.com/MetaMask/metamask-extension/blob/develop/.github/guidelines/LABELING_GUIDELINES.md)). 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. <!-- CURSOR_SUMMARY --> --- > [!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). > > <sup>Reviewed by [Cursor Bugbot](https://cursor.com/bugbot) for commit 9b0f7a9. Bugbot is set up for automated code reviews on this repo. Configure [here](https://www.cursor.com/dashboard/bugbot).</sup> <!-- /CURSOR_SUMMARY --> --------- Co-authored-by: George Marshall <georgewrmarshall@gmail.com>
b7d63d9 to
4681654
Compare
📖 Storybook Preview |
georgewrmarshall
left a comment
There was a problem hiding this comment.
ModalContent still has one blocking issue before I think this is ready: the unresolved modalDialogProps.asChild override can remove the dialog semantics when consumers pass asChild: false. I’m not duplicating the existing Bugbot inline thread for that, but I would keep this in request-changes until it’s fixed. I also left two non-blocking follow-ups for the Storybook wiring and migration guide duplication.
| ); | ||
| }; | ||
|
|
||
| export const Default: Story = { |
There was a problem hiding this comment.
suggestion: wire the Default story through args and pass them into ModalContent. Right now the size/className controls in argTypes are inert, so the primary Canvas is not exercising the API the docs expose.
| - `Modal` always renders a `<div>` and forwards arbitrary HTML attributes (`id`, `role`, `data-*`, `aria-*`, `ref`) to it. The `mm-modal` class hook is gone — use `className` to apply Tailwind utilities. | ||
| - `useModalContext` is now exported from the package barrel (`@metamask/design-system-react`). `ModalContextType` is also exported as a type for consumers building custom subtree integrations. | ||
|
|
||
| ### Modal Component |
There was a problem hiding this comment.
non-blocking: this file now has two identical ### Modal Component sections back-to-back. Dropping the duplicate keeps the migration guide navigable and avoids duplicate heading anchors.
There was a problem hiding this comment.
Thank you, fixed it!
📖 Storybook Preview |
📖 Storybook Preview |
8efebf2 to
8e13417
Compare
📖 Storybook Preview |
There was a problem hiding this comment.
Cursor Bugbot has reviewed your changes and found 1 potential issue.
❌ 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 8e13417. Configure here.
📖 Storybook Preview |
<!-- Please submit this PR as a draft initially. Do not mark it as "Ready for review" until the template has been completely filled out, and PR status checks have passed at least once. --> ## **Description** <!-- Write a short description of the changes included in this pull request, also include relevant motivation and context. Have in mind the following questions: 1. What is the reason for the change? 2. What is the improvement/solution? --> Added `ModalContent` component to DSR. ## **Related issues** Fixes: https://consensyssoftware.atlassian.net/browse/DSYS-304 ## **Manual testing steps** 1. Open Storybook 2. Check `ModalContent` example ## **Screenshots/Recordings** <!-- If applicable, add screenshots and/or recordings to visualize the before and after of your change. --> ### **Before** https://github.com/user-attachments/assets/a38f1d99-b1bb-47b0-8591-0d8f02469cd1 ### **After** https://github.com/user-attachments/assets/106d987a-ec10-41f3-bc98-4e725454bda3 ## **Pre-merge author checklist** - [x] I've followed [MetaMask Contributor Docs](https://github.com/MetaMask/contributor-docs) - [x] I've completed the PR template to the best of my ability - [x] I’ve included tests if applicable - [x] I’ve documented my code using [JSDoc](https://jsdoc.app/) format if applicable - [x] I’ve applied the right labels on the PR (see [labeling guidelines](https://github.com/MetaMask/metamask-extension/blob/develop/.github/guidelines/LABELING_GUIDELINES.md)). 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. <!-- CURSOR_SUMMARY --> --- > [!NOTE] > **Medium Risk** > Introduces new modal interaction logic (document-level event listeners, focus handling, and outside-click heuristics) that can affect close behavior and accessibility across consumers. > > **Overview** > Adds a new `ModalContent` component to `@metamask/design-system-react` and exports it (plus `ModalContentSize` and `MODAL_CONTENT_IGNORE_OUTSIDE_CLICK_ATTR`) from the package barrel. > > `ModalContent` owns the modal shell behavior (centered dialog sizing, slide-up entrance animation, close-on-Escape and close-on-outside-click) and introduces a **data-attribute opt-out** (`data-mm-modal-ignore-outside-click`) for portal-rendered floating UI siblings. > > Updates Storybook to demonstrate the new modal composition (`ModalOverlay` + `ModalContent` + `ModalBody`), adds dedicated `ModalContent` stories/docs/tests, extends the Tailwind preset with a `slide-up` keyframe/animation, and documents the migration guidance in `MIGRATION.md`. > > <sup>Reviewed by [Cursor Bugbot](https://cursor.com/bugbot) for commit 8efebf2. Bugbot is set up for automated code reviews on this repo. Configure [here](https://www.cursor.com/dashboard/bugbot).</sup> <!-- /CURSOR_SUMMARY -->
## 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 -->

Description
Added
ModalContentcomponent to DSR.Related issues
Fixes: https://consensyssoftware.atlassian.net/browse/DSYS-304
Manual testing steps
ModalContentexampleScreenshots/Recordings
Before
Screen.Recording.2026-05-04.at.18.23.08.mov
After
Screen.Recording.2026-05-04.at.18.06.14.mov
Pre-merge author checklist
Pre-merge reviewer checklist
Note
Medium Risk
Adds new modal interaction logic (Escape/outside-click handling and focus behavior) and a new Tailwind animation, which could affect close behavior and portal-based popovers if the opt-out attribute is not applied consistently.
Overview
Adds a new
ModalContentcomponent to@metamask/design-system-react, including sizing tokens, focus integration, and document-level Escape/outside-click close handling that is configurable viaModalcontext.Introduces a generic outside-click opt-out mechanism via
MODAL_CONTENT_IGNORE_OUTSIDE_CLICK_ATTR(replacing the legacy hard-coded.mm-popoverexception) and adds a newslide-upanimation to the Tailwind preset used by the dialog.Updates Storybook to use the new modal composition (
ModalOverlay+ModalContent+ModalBody), adds dedicatedModalContentstories/tests/docs, and extendsMIGRATION.mdwith a newModalContentmigration section and follow-up guidance for Popover-in-Modal behavior.Reviewed by Cursor Bugbot for commit 0056f8f. Bugbot is set up for automated code reviews on this repo. Configure here.