feat: Skeleton migration (extension)#1146
Conversation
📖 Storybook Preview |
There was a problem hiding this comment.
Cursor Bugbot has reviewed your changes and found 2 potential issues.
❌ 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 e787fff. Configure here.
| // directly without any skeleton overlay or animation. | ||
| if (!hideChildren && hasChildren) { | ||
| return <>{children}</>; | ||
| } |
There was a problem hiding this comment.
Pass-through mode silently drops forwarded ref and props
Medium Severity
When !hideChildren && hasChildren, the component returns <>{children}</>, silently discarding the ref, className, style, and all rest ...props (including data-testid, id, aria-*). The forwardRef<HTMLDivElement> signature creates a contract that ref will point to a DOM element, but in pass-through mode ref.current stays null. Consumers dynamically toggling hideChildren (as shown in the ToggleHideChildren story) will see the ref oscillate between a valid node and null, risking null-reference crashes. The React Native Skeleton does the same pass-through but is a plain React.FC without ref forwarding, so this contract issue is unique to the web version.
Reviewed by Cursor Bugbot for commit e787fff. Configure here.
e787fff to
21f98c6
Compare
📖 Storybook Preview |
📖 Storybook Preview |
georgewrmarshall
left a comment
There was a problem hiding this comment.
The migration is close, but I think there are still a few API/contract issues to resolve before merge. The main ones are removing autoPlay from the web/shared direction, fixing the current pass-through branch so forwarded refs and root props do not disappear on web, and softening the React Native parity language in the docs. I am not blocking on Code Connect here because we do not have the corresponding Figma component/tag yet; once that exists, we should add it in follow-up.
| // Pass-through case (matches RN `BottomSheet` Skeleton): when children | ||
| // are provided and we're not asked to hide them, render the children | ||
| // directly without any skeleton overlay or animation. | ||
| if (!hideChildren && hasChildren) { |
There was a problem hiding this comment.
suggestion: This pass-through branch still drops the forwarded ref and all root props (className, style, data-*, aria-*, etc.) when !hideChildren && hasChildren. Can we make the web contract consistent here instead of changing behavior based on runtime state?
There was a problem hiding this comment.
But current web implementation also is doing this?
if (!isLoading) {
return <>{children}</>;
}And mobile also uses this approach. Do we want to wrap that children always in additional div and pass these props there?..
There was a problem hiding this comment.
Hmm good point. OK I think we can merge as is
|
|
||
| ### Skeleton Component | ||
|
|
||
| The extension `skeleton` component maps to `Skeleton` in the design system. The visual contract — a pulsing placeholder with `bg-icon-alternative` opacity-cycling at 1400ms — is preserved, but the public API is realigned with the React Native `Skeleton` (`@metamask/design-system-react-native`): |
There was a problem hiding this comment.
non-blocking: I am fine treating the ADR/shared-types alignment as follow-up rather than blocking this migration PR on it. Tracking ticket: DSYS-717 https://consensyssoftware.atlassian.net/browse/DSYS-717
📖 Storybook Preview |
| // Skeleton loading-placeholder pulse: opacity oscillates 0.2 → 0.1 → 0.2. | ||
| // Used by `Skeleton` to animate the loading bar. | ||
| 'skeleton-pulse': { | ||
| '0%, 100%': { opacity: '0.2' }, | ||
| '50%': { opacity: '0.1' }, | ||
| }, |
There was a problem hiding this comment.
non-blocking: will have to make sure these are brought across in the Tailwind v3 => v4 upgrade.
📖 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 `Skeleton` to DSR. ## **Related issues** Fixes: https://consensyssoftware.atlassian.net/browse/DSYS-310 ## **Manual testing steps** 1. Open Storybook 2. Check `Skeleton` 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/ebf4ae48-5193-404e-a8a0-d04e47490a8e ### **After** https://github.com/user-attachments/assets/9632967d-718a-4a23-8d9a-fb94a437b23e ## **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** > Medium risk because it introduces a new public component/export and a new Tailwind animation utility that could affect consumers’ loading-state behavior and styling expectations (notably the inverted `isLoading`→`hideChildren` migration semantics). Changes are otherwise isolated and covered by new unit tests and Storybook docs. > > **Overview** > Adds a new `Skeleton` component to `@metamask/design-system-react` (exported from the package barrel) that renders an animated loading placeholder with optional invisible-children layout preservation via `hideChildren`. > > Extends `@metamask/design-system-tailwind-preset` with the `skeleton-pulse` keyframes/animation used by the component, and adds Storybook docs/stories plus unit tests. > > Updates `MIGRATION.md` with a dedicated Skeleton migration guide, highlighting the **breaking** prop rename and inverted default semantics (`isLoading` → `hideChildren`) and the move from SCSS hooks to Tailwind utilities. > > <sup>Reviewed by [Cursor Bugbot](https://cursor.com/bugbot) for commit 56f7874. 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
Skeletonto DSR.Related issues
Fixes: https://consensyssoftware.atlassian.net/browse/DSYS-310
Manual testing steps
SkeletoncomponentScreenshots/Recordings
Before
Screen.Recording.2026-05-01.at.17.59.51.mov
After
Screen.Recording.2026-05-01.at.17.58.34.mov
Pre-merge author checklist
Pre-merge reviewer checklist
Note
Medium Risk
Adds a new
Skeletoncomponent with an inverted loading-toggle API (hideChildrenvs extensionisLoading) and updates Tailwind preset animations; consumers migrating from the extension can easily regress loading behavior if the default/prop rename is missed.Overview
Adds a new
Skeletoncomponent to@metamask/design-system-react(exported from the component barrel) with Storybook docs/stories and a test suite.The component implements a Tailwind-driven pulse overlay (
motion-safe:animate-skeleton-pulse), renders children directly by default, and only shows the skeleton whenhideChildrenis set (children are then rendered invisibly for layout).Updates the migration guide with explicit extension→DS mapping notes (including the inverted
isLoading→hideChildrenbehavior) and extends@metamask/design-system-tailwind-presetwithskeleton-pulsekeyframes/animation used by the new component.Reviewed by Cursor Bugbot for commit f7b6237. Bugbot is set up for automated code reviews on this repo. Configure here.