Skip to content

feat: Skeleton migration (extension)#1146

Merged
kirillzyusko merged 5 commits into
mainfrom
feat/skeleton-migration
May 7, 2026
Merged

feat: Skeleton migration (extension)#1146
kirillzyusko merged 5 commits into
mainfrom
feat/skeleton-migration

Conversation

@kirillzyusko

@kirillzyusko kirillzyusko commented May 1, 2026

Copy link
Copy Markdown
Collaborator

Description

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

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

  • 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
Adds a new Skeleton component with an inverted loading-toggle API (hideChildren vs extension isLoading) 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 Skeleton component 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 when hideChildren is set (children are then rendered invisibly for layout).

Updates the migration guide with explicit extension→DS mapping notes (including the inverted isLoadinghideChildren behavior) and extends @metamask/design-system-tailwind-preset with skeleton-pulse keyframes/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.

@kirillzyusko kirillzyusko self-assigned this May 1, 2026
@github-actions

github-actions Bot commented May 1, 2026

Copy link
Copy Markdown
Contributor

📖 Storybook Preview

@kirillzyusko kirillzyusko marked this pull request as ready for review May 1, 2026 16:01
@kirillzyusko kirillzyusko requested a review from a team as a code owner May 1, 2026 16:01

@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 e787fff. Configure here.

// directly without any skeleton overlay or animation.
if (!hideChildren && hasChildren) {
return <>{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.

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.

Fix in Cursor Fix in Web

Reviewed by Cursor Bugbot for commit e787fff. Configure here.

Comment thread packages/design-system-react/src/components/Skeleton/Skeleton.stories.tsx Outdated
@kirillzyusko kirillzyusko force-pushed the feat/skeleton-migration branch from e787fff to 21f98c6 Compare May 4, 2026 13:47
@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

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

Comment thread packages/design-system-react/src/components/Skeleton/Skeleton.types.ts Outdated
// 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) {

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.

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?

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

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

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.

Hmm good point. OK I think we can merge as is

Comment thread packages/design-system-react/src/components/Skeleton/README.mdx Outdated

### 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`):

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

Comment thread packages/design-system-react/src/components/Skeleton/Skeleton.stories.tsx Outdated
@github-actions

github-actions Bot commented May 6, 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.

LGTM!

Comment on lines +34 to +39
// 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' },
},

@georgewrmarshall georgewrmarshall May 7, 2026

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: will have to make sure these are brought across in the Tailwind v3 => v4 upgrade.

@kirillzyusko kirillzyusko enabled auto-merge (squash) May 7, 2026 18:30
@github-actions

github-actions Bot commented May 7, 2026

Copy link
Copy Markdown
Contributor

📖 Storybook Preview

@kirillzyusko kirillzyusko merged commit 34b82c2 into main May 7, 2026
44 checks passed
@kirillzyusko kirillzyusko deleted the feat/skeleton-migration branch May 7, 2026 18:34
georgewrmarshall pushed a commit that referenced this pull request May 7, 2026
<!--
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 -->
@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 -->
@brianacnguyen brianacnguyen mentioned this pull request May 15, 2026
17 tasks
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