Skip to content

chore: centralize Icon types and assets (ADR-0003/ADR-0004)#1042

Merged
georgewrmarshall merged 4 commits into
mainfrom
cursor/enum-shared-type-migration-9e19
Apr 22, 2026
Merged

chore: centralize Icon types and assets (ADR-0003/ADR-0004)#1042
georgewrmarshall merged 4 commits into
mainfrom
cursor/enum-shared-type-migration-9e19

Conversation

@cursor
Copy link
Copy Markdown
Contributor

@cursor cursor Bot commented Apr 5, 2026

Description

Migrates the Icon component across all packages to follow ADR-0003 (const objects instead of enums) and ADR-0004 (centralized types in @metamask/design-system-shared).

Key changes:

  • Centralized SVG assets — all 280+ SVG icons moved from packages/design-system-react/src/components/Icon/assets/ to packages/design-system-shared/src/assets/icons/ as the single source of truth
  • Unified generation script — new packages/design-system-shared/scripts/generate-icons.ts replaces the separate per-platform scripts. A single yarn generate:icons from the repo root now:
    1. Processes SVGs (blackcurrentColor)
    2. Updates IconName in the shared package (sentinel-guarded auto-generated block)
    3. Copies SVGs + generates Icon.assets.ts for React Native
    4. Generates TSX components + icons/index.ts barrel for React
  • IconName and IconSize — migrated to @metamask/design-system-shared as const objects; both platform packages re-export from shared
  • IconColor — migrated to @metamask/design-system-shared as a const object with the full union of all color values. Pressed state variants removed (icons inherit pressed appearance from their parent interactive element). Both platform packages re-export from shared — the platform-local definition and IconColorBase alias are removed
  • React Native gains PopUp and SidePanel — previously React-only icons, now generated for React Native too since all SVGs live in shared
  • ESLint config — extended nodejs rules to cover packages/*/scripts/**/*.ts, removing per-file eslint-disable comments from existing scripts

Generated files kept in git with README notes indicating their source (packages/design-system-shared/src/assets/icons/).

Related issues

Fixes: DSYS-487

Manual testing steps

  1. Run yarn generate:icons from the repo root — verify it completes with no diff in the working tree
  2. Run yarn build — all packages should build cleanly
  3. Run yarn test — all tests should pass
  4. Run yarn lint — no errors
  5. Import IconName, IconSize, IconColor from @metamask/design-system-react or @metamask/design-system-react-native — verify autocomplete includes all values

Screenshots/Recordings

Before

  • IconName defined separately in each platform package (enum in RN, const in React)
  • IconColor defined as a local const in each platform package with different value sets
  • Two separate generation scripts (generate-icons.ts in RN, generate-icons-index.ts in React)
  • SVG assets lived only in the React package; React Native had a separate copy

yarn generate:icons

icon.generate.script.before.720.mov

After

  • IconName, IconSize, IconColor defined once in @metamask/design-system-shared, re-exported by both platforms
  • Single yarn generate:icons script handles the full generation pipeline
  • All SVG assets in packages/design-system-shared/src/assets/icons/ — one source of truth

yarn workspace @metamask/design-system-react/native generate:icons now runs the single script in shared but results in the same build

icon.generate.script.after.720.mov

No visual changes

icon.after.720.mov

Mobile working with preview package. Some small breaking change updates needed but nothing serious MetaMask/metamask-mobile#28840

mobile.after720.mov

Extension working with preview package. Some small breaking change updates needed but nothing serious MetaMask/metamask-extension#41733

Screenshot 2026-04-14 at 2 23 33 PM

yarn lint:tsc passing in extension with fixes from above PR

Screenshot 2026-04-14 at 2 19 26 PM

CSS rendering icon-color classnames from shared

Screenshot 2026-04-14 at 2 24 21 PM

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
Medium risk because it changes the icon type surface (IconName/IconColor/IconSize) and the icon generation/build pipeline across React + React Native, which could break downstream builds or icon imports if regeneration or publishing order is off.

Overview
Centralizes icon definitions and generation by introducing @metamask/design-system-shared/src/types/Icon (IconColor, IconSize, and a generated IconName const-object + string-union) and exporting these from design-system-shared’s public index.

Unifies the icon build pipeline with a new design-system-shared/scripts/generate-icons.ts (process SVGs, update shared IconName, regenerate React Native Icon.assets.ts + assets, and regenerate React TSX icon components + icons/index.ts). Root package.json adds generate:icons, platform packages remove their per-package icon generation scripts/tests/config, and design-system-shared now runs icon generation during build.

Updates consumers to shared types/outputs: React and React Native Icon.types now extend IconPropsShared; platform src/types/index.ts stops defining icon enums and re-exports IconColor/IconName/IconSize from shared; generated RN assetByIconName no longer references IconName computed keys. ESLint node rules are expanded to include packages/*/scripts/**/*.ts, and lockfile updates reflect new generator deps (@svgr/*, tsx/esbuild bumps).

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

@github-actions
Copy link
Copy Markdown
Contributor

github-actions Bot commented Apr 5, 2026

📖 Storybook Preview

@georgewrmarshall georgewrmarshall force-pushed the cursor/enum-shared-type-migration-9e19 branch from 20c4e45 to 1aafb68 Compare April 8, 2026 22:31
Comment thread packages/design-system-react-native/src/types/index.ts Outdated
@georgewrmarshall georgewrmarshall force-pushed the cursor/enum-shared-type-migration-9e19 branch from 1aafb68 to 8563b8c Compare April 8, 2026 22:35
@socket-security
Copy link
Copy Markdown

socket-security Bot commented Apr 8, 2026

Review the following changes in direct dependencies. Learn more about Socket for GitHub.

Diff Package Supply Chain
Security
Vulnerability Quality Maintenance License
Updatedtsx@​4.20.6 ⏵ 4.21.01001008185100

View full report

@socket-security
Copy link
Copy Markdown

socket-security Bot commented Apr 8, 2026

Warning

MetaMask internal reviewing guidelines:

  • Do not ignore-all
  • Each alert has instructions on how to review if you don't know what it means. If lost, ask your Security Liaison or the supply-chain group
  • Copy-paste ignore lines for specific packages or a group of one kind with a note on what research you did to deem it safe.
    @SocketSecurity ignore npm/PACKAGE@VERSION
Action Severity Alert  (click "▶" to expand/collapse)
Warn Low
Potential code anomaly (AI signal): npm esbuild is 100.0% likely to have a medium risk anomaly

Notes: The code represents a thorough and sophisticated installer for esbuild with multiple fallback mechanisms to acquire platform-appropriate binaries. While largely legitimate, its use of direct tarball downloads, manual extraction without explicit integrity validation, and the override/wrapper mechanism create nontrivial supply-chain and abuse risks. Recommend enabling strict binary integrity checks (checksums/signatures), minimizing or auditing the override/wrapper feature, and implementing tighter error visibility and logging to reduce operational risk and potential misuse.

Confidence: 1.00

Severity: 0.60

From: ?npm/storybook@10.3.1npm/tsx@4.21.0npm/esbuild@0.27.7

ℹ Read more on: This package | This alert | What is an AI-detected potential code anomaly?

Next steps: Take a moment to review the security alert above. Review the linked package source code to understand the potential risk. Ensure the package is not malicious before proceeding. If you're unsure how to proceed, reach out to your security team or ask the Socket team for help at support@socket.dev.

Suggestion: An AI system found a low-risk anomaly in this package. It may still be fine to use, but you should check that it is safe before proceeding.

Mark the package as acceptable risk. To ignore this alert only in this pull request, reply with the comment @SocketSecurity ignore npm/esbuild@0.27.7. You can also ignore all packages with @SocketSecurity ignore-all. To ignore an alert for all future pull requests, use Socket's Dashboard to change the triage state of this alert.

Warn Low
Potential code anomaly (AI signal): npm tsx is 100.0% likely to have a medium risk anomaly

Notes: The module installs hidden signal handlers for SIGINT and SIGTERM, hides them from other code by monkey-patching process.listenerCount and process.listeners, forwards signals to an external client callback, and may force exit. That stealthy interception of process signals is suspicious from a supply-chain/security perspective because it can be used to intercept or suppress normal shutdown behavior and to forward events to another module which may perform network I/O or exfiltration. There is no direct evidence in this file of data exfiltration, reverse shell, or explicit malicious payload, but the hiding behavior and delegation to an external client warrant caution and further inspection of the imported client and cjs modules. Recommend auditing the client callback and cjs/index.cjs for network operations or data-leaking behavior before trusting this package.

Confidence: 1.00

Severity: 0.60

From: package.jsonnpm/tsx@4.21.0

ℹ Read more on: This package | This alert | What is an AI-detected potential code anomaly?

Next steps: Take a moment to review the security alert above. Review the linked package source code to understand the potential risk. Ensure the package is not malicious before proceeding. If you're unsure how to proceed, reach out to your security team or ask the Socket team for help at support@socket.dev.

Suggestion: An AI system found a low-risk anomaly in this package. It may still be fine to use, but you should check that it is safe before proceeding.

Mark the package as acceptable risk. To ignore this alert only in this pull request, reply with the comment @SocketSecurity ignore npm/tsx@4.21.0. You can also ignore all packages with @SocketSecurity ignore-all. To ignore an alert for all future pull requests, use Socket's Dashboard to change the triage state of this alert.

Warn Low
Potential code anomaly (AI signal): npm tsx is 100.0% likely to have a medium risk anomaly

Notes: This module installs signal handlers and actively hides them from inspection by monkeypatching listener inspection APIs. In the main thread it can forward SIGINT/SIGTERM events to a remote client (via client.connectingToServer) and may exit the process after forwarding. The concealment is a noteworthy red flag: it makes detection and auditing harder and may be used to implement covert telemetry or control. The file alone is not conclusively malicious, but the combination of hiding handlers and forwarding signals to an external component warrants careful review of the client module (client-D6NvIMSC.cjs) and any network destinations it uses before trusting this package in sensitive environments.

Confidence: 1.00

Severity: 0.60

From: package.jsonnpm/tsx@4.21.0

ℹ Read more on: This package | This alert | What is an AI-detected potential code anomaly?

Next steps: Take a moment to review the security alert above. Review the linked package source code to understand the potential risk. Ensure the package is not malicious before proceeding. If you're unsure how to proceed, reach out to your security team or ask the Socket team for help at support@socket.dev.

Suggestion: An AI system found a low-risk anomaly in this package. It may still be fine to use, but you should check that it is safe before proceeding.

Mark the package as acceptable risk. To ignore this alert only in this pull request, reply with the comment @SocketSecurity ignore npm/tsx@4.21.0. You can also ignore all packages with @SocketSecurity ignore-all. To ignore an alert for all future pull requests, use Socket's Dashboard to change the triage state of this alert.

Warn Low
Potential code anomaly (AI signal): npm tsx is 100.0% likely to have a medium risk anomaly

Notes: No clear indicators of classic malware (no reverse shell, no network connections, no child_process usage, no hard-coded credentials). The primary risk is information leakage: the loader posts module load events and dependency paths to external consumers via p.port and O.send. In contexts where those channels are controlled by an untrusted or remote party, this could leak local file paths or project structure. The module otherwise performs expected loader duties (file reads, tsconfig handling, transforming CJS to ESM, returning data: URLs). Review runtime consumers of O and any provided p.port to ensure they are trusted before using this loader in a sensitive environment.

Confidence: 1.00

Severity: 0.60

From: package.jsonnpm/tsx@4.21.0

ℹ Read more on: This package | This alert | What is an AI-detected potential code anomaly?

Next steps: Take a moment to review the security alert above. Review the linked package source code to understand the potential risk. Ensure the package is not malicious before proceeding. If you're unsure how to proceed, reach out to your security team or ask the Socket team for help at support@socket.dev.

Suggestion: An AI system found a low-risk anomaly in this package. It may still be fine to use, but you should check that it is safe before proceeding.

Mark the package as acceptable risk. To ignore this alert only in this pull request, reply with the comment @SocketSecurity ignore npm/tsx@4.21.0. You can also ignore all packages with @SocketSecurity ignore-all. To ignore an alert for all future pull requests, use Socket's Dashboard to change the triage state of this alert.

Warn Low
Potential code anomaly (AI signal): npm tsx is 100.0% likely to have a medium risk anomaly

Notes: This fragment appears to be a bundler-generated bootstrap/initialization piece that imports many modules and executes an initialization function (r). No explicit malicious activity is evident within this fragment itself, but the risk stems from side effects of the imported modules on load. A careful review of the implementations of the imported modules (especially those exporting r and those performing initialization, build-time, or network/file operations) is recommended to rule out hidden telemetry, backdoors, or undesired side effects.

Confidence: 1.00

Severity: 0.60

From: package.jsonnpm/tsx@4.21.0

ℹ Read more on: This package | This alert | What is an AI-detected potential code anomaly?

Next steps: Take a moment to review the security alert above. Review the linked package source code to understand the potential risk. Ensure the package is not malicious before proceeding. If you're unsure how to proceed, reach out to your security team or ask the Socket team for help at support@socket.dev.

Suggestion: An AI system found a low-risk anomaly in this package. It may still be fine to use, but you should check that it is safe before proceeding.

Mark the package as acceptable risk. To ignore this alert only in this pull request, reply with the comment @SocketSecurity ignore npm/tsx@4.21.0. You can also ignore all packages with @SocketSecurity ignore-all. To ignore an alert for all future pull requests, use Socket's Dashboard to change the triage state of this alert.

View full report

@github-actions
Copy link
Copy Markdown
Contributor

github-actions Bot commented Apr 8, 2026

📖 Storybook Preview

@github-actions
Copy link
Copy Markdown
Contributor

github-actions Bot commented Apr 8, 2026

📖 Storybook Preview

@github-actions
Copy link
Copy Markdown
Contributor

github-actions Bot commented Apr 8, 2026

📖 Storybook Preview

@github-actions
Copy link
Copy Markdown
Contributor

github-actions Bot commented Apr 8, 2026

📖 Storybook Preview

Comment thread packages/design-system-react-native/src/types/index.ts Outdated
@georgewrmarshall georgewrmarshall force-pushed the cursor/enum-shared-type-migration-9e19 branch from d88018c to 84b7542 Compare April 9, 2026 01:31
@github-actions
Copy link
Copy Markdown
Contributor

github-actions Bot commented Apr 9, 2026

📖 Storybook Preview

@georgewrmarshall georgewrmarshall self-assigned this Apr 9, 2026
@georgewrmarshall
Copy link
Copy Markdown
Contributor

@metamaskbot publish-preview

@georgewrmarshall georgewrmarshall changed the title chore: migrate Icon to ADR-0003 and ADR-0004 (DSYS-487) chore: centralize Icon types and assets (ADR-0003/ADR-0004) Apr 9, 2026
@github-actions
Copy link
Copy Markdown
Contributor

github-actions Bot commented Apr 9, 2026

📖 Storybook Preview

@georgewrmarshall
Copy link
Copy Markdown
Contributor

@metamaskbot publish-preview

@github-actions
Copy link
Copy Markdown
Contributor

github-actions Bot commented Apr 9, 2026

📖 Storybook Preview

@github-actions
Copy link
Copy Markdown
Contributor

github-actions Bot commented Apr 9, 2026

Preview builds have been published. See these instructions for more information about preview builds.

Expand for full list of packages and versions.
{
  "@metamask-previews/design-system-react": "0.16.0-preview.d854123",
  "@metamask-previews/design-system-react-native": "0.16.0-preview.d854123",
  "@metamask-previews/design-system-shared": "0.9.0-preview.d854123",
  "@metamask-previews/design-system-tailwind-preset": "0.6.1-preview.d854123",
  "@metamask-previews/design-system-twrnc-preset": "0.4.1-preview.d854123",
  "@metamask-previews/design-tokens": "8.3.0-preview.d854123"
}

Comment thread packages/design-system-react/src/components/Icon/Icon.types.ts
@github-actions
Copy link
Copy Markdown
Contributor

github-actions Bot commented Apr 9, 2026

📖 Storybook Preview

Comment thread packages/design-system-shared/scripts/generate-icons.ts
@georgewrmarshall georgewrmarshall force-pushed the cursor/enum-shared-type-migration-9e19 branch from 22b1a4f to ae6f7c9 Compare April 9, 2026 22:26
@github-actions
Copy link
Copy Markdown
Contributor

github-actions Bot commented Apr 9, 2026

📖 Storybook Preview

@georgewrmarshall georgewrmarshall force-pushed the cursor/enum-shared-type-migration-9e19 branch from ae6f7c9 to eb365f9 Compare April 9, 2026 22:43
@github-actions
Copy link
Copy Markdown
Contributor

github-actions Bot commented Apr 9, 2026

📖 Storybook Preview

@georgewrmarshall georgewrmarshall force-pushed the cursor/enum-shared-type-migration-9e19 branch from eb365f9 to 2e46311 Compare April 14, 2026 18:45
Comment thread packages/design-system-react-native/src/types/index.ts
@georgewrmarshall georgewrmarshall force-pushed the cursor/enum-shared-type-migration-9e19 branch from 2e46311 to 5c29117 Compare April 14, 2026 19:33
Copy link
Copy Markdown
Contributor

@georgewrmarshall georgewrmarshall Apr 22, 2026

Choose a reason for hiding this comment

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

Must have been some subtle difference between these 2 svgs. I can't see anything that stands out in the svg code.

@github-actions
Copy link
Copy Markdown
Contributor

📖 Storybook Preview

@georgewrmarshall georgewrmarshall marked this pull request as ready for review April 22, 2026 21:58
@github-actions
Copy link
Copy Markdown
Contributor

📖 Storybook Preview

@georgewrmarshall georgewrmarshall force-pushed the cursor/enum-shared-type-migration-9e19 branch from 2f20830 to f254bdc Compare April 22, 2026 22:01
Comment on lines +5 to +8
/**
* TODO: Remove the following exports and update imports in components to import directly from `@metamask/design-system-shared` once all components have been migrated to React Native.
*/
export { IconColor, IconName, IconSize } from '@metamask/design-system-shared';
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.

Will do this as part of phase 3

/**
* TODO: Remove the following exports and update imports in components to import directly from `@metamask/design-system-shared` once all components have been migrated to React Native.
*/
export { IconColor, IconName, IconSize } from '@metamask/design-system-shared';
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.

Will do this as part of phase 3

@github-actions
Copy link
Copy Markdown
Contributor

📖 Storybook Preview

@georgewrmarshall georgewrmarshall enabled auto-merge (squash) April 22, 2026 22:05
@georgewrmarshall georgewrmarshall merged commit c46d45b into main Apr 22, 2026
44 checks passed
@georgewrmarshall georgewrmarshall deleted the cursor/enum-shared-type-migration-9e19 branch April 22, 2026 22:57
This was referenced Apr 23, 2026
georgewrmarshall added a commit that referenced this pull request Apr 23, 2026
## Release 35.0.0

This release adds new React Native title primitives, continues the
enum-to-const-object/string-union migration for public type exports, and
updates the release documentation so breaking changes are
consumer-focused and migration-oriented.

### Package Versions

- `@metamask/design-system-shared`: **0.13.0**
- `@metamask/design-system-react`: **0.18.0**
- `@metamask/design-system-react-native`: **0.20.0**
- `@metamask/design-system-tailwind-preset`: **0.6.2**

### Shared Type Updates (0.13.0)

#### Added (#1051, #1053, #1059)

**What Changed:**

- Added `TitleStandardPropsShared` and `TitleSubpagePropsShared`
- Added `TagSeverity` and `TagPropsShared`

**Impact:**

- Supports the new React Native `TitleStandard`, `TitleSubpage`, and
`Tag` APIs

#### Changed (#1026, #1042)

**What Changed:**

- **BREAKING:** Updated shared `Box` and `Icon` exports from enums to
const objects with derived string-union types
- Removed stale Box `WarningAlternative`, `SuccessAlternative`, and
`InfoAlternative` color entries that no longer map to design tokens

**Impact:**

- Affects consumers of `@metamask/design-system-shared` directly
- Platform package consumers should continue importing from
`@metamask/design-system-react` or
`@metamask/design-system-react-native`

### React Web Updates (0.18.0)

#### Changed

- **BREAKING:** Updated `IconName`, `IconColor`, and `IconSize` exports
to use const-object + string-union types instead of enums (#1042, #1101)
- **BREAKING:** Updated `Box` type exports to use const-object +
string-union types and removed stale Box color entries (#1026)
- Updated `ButtonTertiary` to use the default text color for more
consistent contrast across states (#1099)

### React Native Updates (0.20.0)

#### Added

- Added `TitleStandard` for mobile title layouts with optional top and
bottom accessory rows (#1051)
- Added `TitleSubpage` for subpage headers with avatar, title, subtitle,
amount, and bottom-label layouts (#1059)
- Added `Tag` for compact severity-based metadata labels with optional
icons or custom accessories (#1053)

#### Changed

- **BREAKING:** Updated `IconName`, `IconColor`, and `IconSize` exports
to use const-object + string-union types instead of enums (#1042)
- **BREAKING:** Updated `Box` type exports to use const-object +
string-union types and removed stale Box color entries (#1026)
- `Box` now forwards refs to the underlying `View` (#1102)
- Updated `ButtonTertiary` to use the default text color for more
consistent contrast across states (#1099)

### Tailwind Preset Updates (0.6.2)

#### Changed

- No consumer-facing API or behavior changes in this release; this patch
republishes the existing preset without requiring changes in consuming
apps

### Breaking Changes

#### Icon and Box enum exports migrated to const objects plus string
unions (Both Platforms)

**What Changed:**

- `IconName`, `IconColor`, and `IconSize` now use const objects with
derived string-union types instead of enums
- `BoxFlexDirection`, `BoxFlexWrap`, `BoxAlignItems`,
`BoxJustifyContent`, `BoxBackgroundColor`, `BoxBorderColor`,
`BoxSpacing`, and `BoxBorderWidth` now use const objects with derived
string-union types instead of enums
- Removed stale Box color entries with no backing design token:
  - `BoxBackgroundColor.WarningAlternative`
  - `BoxBackgroundColor.SuccessAlternative`
  - `BoxBorderColor.WarningAlternative`
  - `BoxBorderColor.SuccessAlternative`
  - `BoxBorderColor.InfoAlternative`

**Migration:**

```tsx
// Before
import {
  BoxBackgroundColor,
  IconColor,
  IconName,
} from '@metamask/design-system-react-native';

<Box backgroundColor={BoxBackgroundColor.WarningAlternative} />
<Icon name={IconName.Add} color={IconColor.IconDefault} />

// After
import {
  BoxBackgroundColor,
  IconColor,
  IconName,
} from '@metamask/design-system-react-native';

<Box backgroundColor={BoxBackgroundColor.WarningDefault} />
<Icon name={IconName.Add} color={IconColor.IconDefault} />
```

**Impact:**

- Affects consumers relying on enum-specific TypeScript behavior for
`Icon*` and `Box*` exports
- Import paths stay the same for platform-package consumers
- Any use of the removed Box `*Alternative` color entries will need to
switch to the corresponding `*Default` or `*Muted` token

See migration guides for complete instructions:

- [React Migration
Guide](./packages/design-system-react/MIGRATION.md#from-version-0170-to-0180)
- [React Native Migration
Guide](./packages/design-system-react-native/MIGRATION.md#from-version-0190-to-0200)

### Validation

- `yarn changelog:validate`

<!-- CURSOR_SUMMARY -->
---

> [!NOTE]
> **Medium Risk**
> Medium risk because it publishes new versions with **breaking
TypeScript surface changes** (Box/Icon enums → const-object/string-union
and removal of stale Box color members), which can break downstream
builds despite minimal runtime behavior changes.
> 
> **Overview**
> Bumps the monorepo release to `35.0.0` and publishes new package
versions for `@metamask/design-system-react` (`0.18.0`),
`@metamask/design-system-react-native` (`0.20.0`), and
`@metamask/design-system-shared` (`0.13.0`).
> 
> Updates changelogs/migration guides to reflect the release: adds React
Native primitives (`TitleStandard`, `TitleSubpage`, `Tag`) and shared
prop contracts, and documents **breaking** shifts of `Box*` and `Icon*`
exports from enums to const-object + string-union types (plus removal of
stale `*Alternative` Box color entries) with consumer-facing migration
steps.
> 
> <sup>Reviewed by [Cursor Bugbot](https://cursor.com/bugbot) for commit
addbae5. Bugbot is set up for automated
code reviews on this repo. Configure
[here](https://www.cursor.com/dashboard/bugbot).</sup>
<!-- /CURSOR_SUMMARY -->
georgewrmarshall added a commit that referenced this pull request Apr 27, 2026
…1084)

## **Description**

Moves the single source of truth for all icon SVG assets into
`packages/design-system-shared/src/assets/icons/`.

Previously each platform package maintained its own copy of the ~279 SVG
files. This is the first of four phases working toward fully
centralizing Icon types and assets per ADR-0003/ADR-0004 (tracked in
#1042).

**What changed:**
- Added `packages/design-system-shared/src/assets/icons/` with 279 SVGs
copied from the React Native package
- Updated `design-system-react-native/scripts/generate-icons.ts` to read
SVGs from the shared source, apply `black→currentColor` processing, then
copy to the local RN `assets/` folder (output is unchanged)
- Updated `design-system-react/package.json` `generate-icons` script to
point `svgr` at the shared assets folder instead of its own local
`assets/` folder

No public API changes. Both platform packages continue to ship the same
generated files as before.

## **Related issues**

Fixes:

Part of #1042 (phase 1 of 4)

## **Manual testing steps**

1. Check out branch and run `yarn install` from repo root
2. Run `yarn workspace @metamask/design-system-react-native run
generate-icons` — confirm `Icon.assets.ts` and `assets/*.svg` in the RN
package are unchanged
3. Run `yarn workspace @metamask/design-system-react run generate-icons`
— confirm the `icons/*.tsx` components and `icons/index.ts` in the React
package are unchanged
4. Run `yarn build` — confirm all packages build without errors
5. Run `yarn test` — confirm all tests pass

## **Screenshots/Recordings**

### **Before**

SVGs duplicated in two locations:
- `packages/design-system-react-native/src/components/Icon/assets/`
(source)
- `packages/design-system-react/src/components/Icon/assets/` (source)

### **After**

Single source of truth:
- `packages/design-system-shared/src/assets/icons/` (source)
- Platform `assets/` folders remain as generated output

## **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
- [ ] I've included tests if applicable
- [ ] 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**
> Changes icon generation inputs for both React and React Native to pull
from a new shared SVG directory; risk is mainly build-time/regeneration
mismatches or missing assets affecting downstream icon bundles.
> 
> **Overview**
> Moves the *source of truth* for icon SVGs into `design-system-shared`
by adding a shared `src/assets/icons` directory and updating platform
builds to consume it.
> 
> React Native’s `generate-icons.ts` now reads SVGs from the shared
directory, normalizes `black` to `currentColor`, and writes the
processed files into the local RN `Icon/assets` folder before
regenerating `Icon.assets.ts`/`IconName`. React’s `generate-icons`
script is updated to point `svgr` at the shared icons path.
> 
> Also adds new `PopUp` and `SidePanel` icons, wiring them into RN
`Icon.assets.ts` and `IconName`.
> 
> <sup>Reviewed by [Cursor Bugbot](https://cursor.com/bugbot) for commit
c95b4ef. Bugbot is set up for automated
code reviews on this repo. Configure
[here](https://www.cursor.com/dashboard/bugbot).</sup>
<!-- /CURSOR_SUMMARY -->
georgewrmarshall added a commit that referenced this pull request Apr 27, 2026
## **Description**

Removes the redundant SVG icon assets that were left behind in
`packages/design-system-react/src/components/Icon/assets/` after the
icon asset source-of-truth was centralized in #1084.

This follow-up keeps `design-system-react` aligned with the phase 1 icon
asset migration by deleting the unused duplicate files that are no
longer referenced by the React package.

## **Related issues**

Fixes:

Follow-up to #1084
Part of #1042

## **Manual testing steps**

1. Check out this branch and run `git diff main...HEAD --
packages/design-system-react/src/components/Icon/assets`.
2. Confirm the diff only deletes redundant SVG files from
`packages/design-system-react/src/components/Icon/assets/`.
3. Optionally run `yarn workspace @metamask/design-system-react run
generate-icons` and confirm icon generation still uses the shared assets
source introduced in #1084.

## **Screenshots/Recordings**

### **Before**

`packages/design-system-react/src/components/Icon/assets/` still
contained duplicate SVG source files after #1084.

### **After**

The redundant `design-system-react` icon asset copies are removed,
leaving the shared asset source introduced in #1084 as the source of
truth.

## **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
- [ ] I’ve included tests if applicable
- [ ] I’ve documented my code using [JSDoc](https://jsdoc.app/) format
if applicable
- [ ] 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.

Validation run locally:
- `git push -u origin remove-redundant-icon-assets` completed
successfully and ran the repo formatting/dedup hooks.
- I did not run package tests or builds locally for this follow-up
cleanup.

<!-- CURSOR_SUMMARY -->
---

> [!NOTE]
> <sup>[Cursor Bugbot](https://cursor.com/bugbot) is generating a
summary for commit 390c3c4. Configure
[here](https://www.cursor.com/dashboard/bugbot).</sup>
<!-- /CURSOR_SUMMARY -->
georgewrmarshall added a commit that referenced this pull request Apr 27, 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**

Migrates the `Icon` component across all packages to follow
[ADR-0003](https://github.com/MetaMask/decisions/blob/main/decisions/design-system/0003-enum-to-string-union-migration.md)
(const objects instead of enums) and
[ADR-0004](https://github.com/MetaMask/decisions/blob/main/decisions/design-system/0004-centralized-types-architecture.md)
(centralized types in `@metamask/design-system-shared`).

**Key changes:**

- **Centralized SVG assets** — all 280+ SVG icons moved from
`packages/design-system-react/src/components/Icon/assets/` to
`packages/design-system-shared/src/assets/icons/` as the single source
of truth
- **Unified generation script** — new
`packages/design-system-shared/scripts/generate-icons.ts` replaces the
separate per-platform scripts. A single `yarn generate:icons` from the
repo root now:
  1. Processes SVGs (`black` → `currentColor`)
2. Updates `IconName` in the shared package (sentinel-guarded
auto-generated block)
  3. Copies SVGs + generates `Icon.assets.ts` for React Native
  4. Generates TSX components + `icons/index.ts` barrel for React
- **`IconName` and `IconSize`** — migrated to
`@metamask/design-system-shared` as const objects; both platform
packages re-export from shared
- **`IconColor`** — migrated to `@metamask/design-system-shared` as a
const object with the full union of all color values. Pressed state
variants removed (icons inherit pressed appearance from their parent
interactive element). Both platform packages re-export from shared — the
platform-local definition and `IconColorBase` alias are removed
- **React Native gains `PopUp` and `SidePanel`** — previously React-only
icons, now generated for React Native too since all SVGs live in shared
- **ESLint config** — extended `nodejs` rules to cover
`packages/*/scripts/**/*.ts`, removing per-file `eslint-disable`
comments from existing scripts

**Generated files kept in git** with README notes indicating their
source (`packages/design-system-shared/src/assets/icons/`).

## **Related issues**

Fixes: DSYS-487

## **Manual testing steps**

1. Run `yarn generate:icons` from the repo root — verify it completes
with no diff in the working tree
2. Run `yarn build` — all packages should build cleanly
3. Run `yarn test` — all tests should pass
4. Run `yarn lint` — no errors
5. Import `IconName`, `IconSize`, `IconColor` from
`@metamask/design-system-react` or
`@metamask/design-system-react-native` — verify autocomplete includes
all values

## **Screenshots/Recordings**

<!-- If applicable, add screenshots and/or recordings to visualize the
before and after of your change. -->

### **Before**

- `IconName` defined separately in each platform package (enum in RN,
const in React)
- `IconColor` defined as a local const in each platform package with
different value sets
- Two separate generation scripts (`generate-icons.ts` in RN,
`generate-icons-index.ts` in React)
- SVG assets lived only in the React package; React Native had a
separate copy

`yarn generate:icons`


https://github.com/user-attachments/assets/062562e0-5677-4fc2-b806-28ced6a00787

### **After**

- `IconName`, `IconSize`, `IconColor` defined once in
`@metamask/design-system-shared`, re-exported by both platforms
- Single `yarn generate:icons` script handles the full generation
pipeline
- All SVG assets in `packages/design-system-shared/src/assets/icons/` —
one source of truth

`yarn workspace @metamask/design-system-react/native generate:icons` now
runs the single script in shared but results in the same build


https://github.com/user-attachments/assets/d8c4e071-cb9b-435d-ad08-39cd935cf015

No visual changes


https://github.com/user-attachments/assets/90f3687c-73ab-4950-9859-52dcc6415bea

Mobile working with preview package. Some small breaking change updates
needed but nothing serious
MetaMask/metamask-mobile#28840


https://github.com/user-attachments/assets/92fd522a-c9dd-4739-9de2-50cf4a343c32

Extension working with preview package. Some small breaking change
updates needed but nothing serious
MetaMask/metamask-extension#41733

<img width="1468" height="869" alt="Screenshot 2026-04-14 at 2 23 33 PM"
src="https://github.com/user-attachments/assets/9234b56b-31c9-451d-882d-55d1272ce732"
/>

`yarn lint:tsc` passing in extension with fixes from above PR

<img width="590" height="509" alt="Screenshot 2026-04-14 at 2 19 26 PM"
src="https://github.com/user-attachments/assets/22d6dfdc-7fbf-47d8-bfd4-a9a6c1ad1570"
/>

CSS rendering icon-color classnames from shared 

<img width="827" height="437" alt="Screenshot 2026-04-14 at 2 24 21 PM"
src="https://github.com/user-attachments/assets/c7bef966-748c-4dce-8d3f-74ca9c5700f0"
/>

## **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
- [ ] 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 changes the icon type surface
(`IconName`/`IconColor`/`IconSize`) and the icon generation/build
pipeline across React + React Native, which could break downstream
builds or icon imports if regeneration or publishing order is off.
> 
> **Overview**
> **Centralizes icon definitions and generation** by introducing
`@metamask/design-system-shared/src/types/Icon` (`IconColor`,
`IconSize`, and a generated `IconName` const-object + string-union) and
exporting these from `design-system-shared`’s public index.
> 
> **Unifies the icon build pipeline** with a new
`design-system-shared/scripts/generate-icons.ts` (process SVGs, update
shared `IconName`, regenerate React Native `Icon.assets.ts` + assets,
and regenerate React TSX icon components + `icons/index.ts`). Root
`package.json` adds `generate:icons`, platform packages remove their
per-package icon generation scripts/tests/config, and
`design-system-shared` now runs icon generation during `build`.
> 
> **Updates consumers to shared types/outputs**: React and React Native
`Icon.types` now extend `IconPropsShared`; platform `src/types/index.ts`
stops defining icon enums and re-exports
`IconColor`/`IconName`/`IconSize` from shared; generated RN
`assetByIconName` no longer references `IconName` computed keys. ESLint
node rules are expanded to include `packages/*/scripts/**/*.ts`, and
lockfile updates reflect new generator deps (`@svgr/*`, `tsx`/`esbuild`
bumps).
> 
> <sup>Reviewed by [Cursor Bugbot](https://cursor.com/bugbot) for commit
f254bdc. 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: georgewrmarshall <george.marshall@consensys.net>
georgewrmarshall added a commit that referenced this pull request Apr 27, 2026
## Release 35.0.0

This release adds new React Native title primitives, continues the
enum-to-const-object/string-union migration for public type exports, and
updates the release documentation so breaking changes are
consumer-focused and migration-oriented.

### Package Versions

- `@metamask/design-system-shared`: **0.13.0**
- `@metamask/design-system-react`: **0.18.0**
- `@metamask/design-system-react-native`: **0.20.0**
- `@metamask/design-system-tailwind-preset`: **0.6.2**

### Shared Type Updates (0.13.0)

#### Added (#1051, #1053, #1059)

**What Changed:**

- Added `TitleStandardPropsShared` and `TitleSubpagePropsShared`
- Added `TagSeverity` and `TagPropsShared`

**Impact:**

- Supports the new React Native `TitleStandard`, `TitleSubpage`, and
`Tag` APIs

#### Changed (#1026, #1042)

**What Changed:**

- **BREAKING:** Updated shared `Box` and `Icon` exports from enums to
const objects with derived string-union types
- Removed stale Box `WarningAlternative`, `SuccessAlternative`, and
`InfoAlternative` color entries that no longer map to design tokens

**Impact:**

- Affects consumers of `@metamask/design-system-shared` directly
- Platform package consumers should continue importing from
`@metamask/design-system-react` or
`@metamask/design-system-react-native`

### React Web Updates (0.18.0)

#### Changed

- **BREAKING:** Updated `IconName`, `IconColor`, and `IconSize` exports
to use const-object + string-union types instead of enums (#1042, #1101)
- **BREAKING:** Updated `Box` type exports to use const-object +
string-union types and removed stale Box color entries (#1026)
- Updated `ButtonTertiary` to use the default text color for more
consistent contrast across states (#1099)

### React Native Updates (0.20.0)

#### Added

- Added `TitleStandard` for mobile title layouts with optional top and
bottom accessory rows (#1051)
- Added `TitleSubpage` for subpage headers with avatar, title, subtitle,
amount, and bottom-label layouts (#1059)
- Added `Tag` for compact severity-based metadata labels with optional
icons or custom accessories (#1053)

#### Changed

- **BREAKING:** Updated `IconName`, `IconColor`, and `IconSize` exports
to use const-object + string-union types instead of enums (#1042)
- **BREAKING:** Updated `Box` type exports to use const-object +
string-union types and removed stale Box color entries (#1026)
- `Box` now forwards refs to the underlying `View` (#1102)
- Updated `ButtonTertiary` to use the default text color for more
consistent contrast across states (#1099)

### Tailwind Preset Updates (0.6.2)

#### Changed

- No consumer-facing API or behavior changes in this release; this patch
republishes the existing preset without requiring changes in consuming
apps

### Breaking Changes

#### Icon and Box enum exports migrated to const objects plus string
unions (Both Platforms)

**What Changed:**

- `IconName`, `IconColor`, and `IconSize` now use const objects with
derived string-union types instead of enums
- `BoxFlexDirection`, `BoxFlexWrap`, `BoxAlignItems`,
`BoxJustifyContent`, `BoxBackgroundColor`, `BoxBorderColor`,
`BoxSpacing`, and `BoxBorderWidth` now use const objects with derived
string-union types instead of enums
- Removed stale Box color entries with no backing design token:
  - `BoxBackgroundColor.WarningAlternative`
  - `BoxBackgroundColor.SuccessAlternative`
  - `BoxBorderColor.WarningAlternative`
  - `BoxBorderColor.SuccessAlternative`
  - `BoxBorderColor.InfoAlternative`

**Migration:**

```tsx
// Before
import {
  BoxBackgroundColor,
  IconColor,
  IconName,
} from '@metamask/design-system-react-native';

<Box backgroundColor={BoxBackgroundColor.WarningAlternative} />
<Icon name={IconName.Add} color={IconColor.IconDefault} />

// After
import {
  BoxBackgroundColor,
  IconColor,
  IconName,
} from '@metamask/design-system-react-native';

<Box backgroundColor={BoxBackgroundColor.WarningDefault} />
<Icon name={IconName.Add} color={IconColor.IconDefault} />
```

**Impact:**

- Affects consumers relying on enum-specific TypeScript behavior for
`Icon*` and `Box*` exports
- Import paths stay the same for platform-package consumers
- Any use of the removed Box `*Alternative` color entries will need to
switch to the corresponding `*Default` or `*Muted` token

See migration guides for complete instructions:

- [React Migration
Guide](./packages/design-system-react/MIGRATION.md#from-version-0170-to-0180)
- [React Native Migration
Guide](./packages/design-system-react-native/MIGRATION.md#from-version-0190-to-0200)

### Validation

- `yarn changelog:validate`

<!-- CURSOR_SUMMARY -->
---

> [!NOTE]
> **Medium Risk**
> Medium risk because it publishes new versions with **breaking
TypeScript surface changes** (Box/Icon enums → const-object/string-union
and removal of stale Box color members), which can break downstream
builds despite minimal runtime behavior changes.
> 
> **Overview**
> Bumps the monorepo release to `35.0.0` and publishes new package
versions for `@metamask/design-system-react` (`0.18.0`),
`@metamask/design-system-react-native` (`0.20.0`), and
`@metamask/design-system-shared` (`0.13.0`).
> 
> Updates changelogs/migration guides to reflect the release: adds React
Native primitives (`TitleStandard`, `TitleSubpage`, `Tag`) and shared
prop contracts, and documents **breaking** shifts of `Box*` and `Icon*`
exports from enums to const-object + string-union types (plus removal of
stale `*Alternative` Box color entries) with consumer-facing migration
steps.
> 
> <sup>Reviewed by [Cursor Bugbot](https://cursor.com/bugbot) for commit
addbae5. Bugbot is set up for automated
code reviews on this repo. Configure
[here](https://www.cursor.com/dashboard/bugbot).</sup>
<!-- /CURSOR_SUMMARY -->
georgewrmarshall added a commit that referenced this pull request Apr 28, 2026
## Release 35.0.0

This release adds new React Native title primitives, continues the
enum-to-const-object/string-union migration for public type exports, and
updates the release documentation so breaking changes are
consumer-focused and migration-oriented.

### Package Versions

- `@metamask/design-system-shared`: **0.13.0**
- `@metamask/design-system-react`: **0.18.0**
- `@metamask/design-system-react-native`: **0.20.0**
- `@metamask/design-system-tailwind-preset`: **0.6.2**

### Shared Type Updates (0.13.0)

#### Added (#1051, #1053, #1059)

**What Changed:**

- Added `TitleStandardPropsShared` and `TitleSubpagePropsShared`
- Added `TagSeverity` and `TagPropsShared`

**Impact:**

- Supports the new React Native `TitleStandard`, `TitleSubpage`, and
`Tag` APIs

#### Changed (#1026, #1042)

**What Changed:**

- **BREAKING:** Updated shared `Box` and `Icon` exports from enums to
const objects with derived string-union types
- Removed stale Box `WarningAlternative`, `SuccessAlternative`, and
`InfoAlternative` color entries that no longer map to design tokens

**Impact:**

- Affects consumers of `@metamask/design-system-shared` directly
- Platform package consumers should continue importing from
`@metamask/design-system-react` or
`@metamask/design-system-react-native`

### React Web Updates (0.18.0)

#### Changed

- **BREAKING:** Updated `IconName`, `IconColor`, and `IconSize` exports
to use const-object + string-union types instead of enums (#1042, #1101)
- **BREAKING:** Updated `Box` type exports to use const-object +
string-union types and removed stale Box color entries (#1026)
- Updated `ButtonTertiary` to use the default text color for more
consistent contrast across states (#1099)

### React Native Updates (0.20.0)

#### Added

- Added `TitleStandard` for mobile title layouts with optional top and
bottom accessory rows (#1051)
- Added `TitleSubpage` for subpage headers with avatar, title, subtitle,
amount, and bottom-label layouts (#1059)
- Added `Tag` for compact severity-based metadata labels with optional
icons or custom accessories (#1053)

#### Changed

- **BREAKING:** Updated `IconName`, `IconColor`, and `IconSize` exports
to use const-object + string-union types instead of enums (#1042)
- **BREAKING:** Updated `Box` type exports to use const-object +
string-union types and removed stale Box color entries (#1026)
- `Box` now forwards refs to the underlying `View` (#1102)
- Updated `ButtonTertiary` to use the default text color for more
consistent contrast across states (#1099)

### Tailwind Preset Updates (0.6.2)

#### Changed

- No consumer-facing API or behavior changes in this release; this patch
republishes the existing preset without requiring changes in consuming
apps

### Breaking Changes

#### Icon and Box enum exports migrated to const objects plus string
unions (Both Platforms)

**What Changed:**

- `IconName`, `IconColor`, and `IconSize` now use const objects with
derived string-union types instead of enums
- `BoxFlexDirection`, `BoxFlexWrap`, `BoxAlignItems`,
`BoxJustifyContent`, `BoxBackgroundColor`, `BoxBorderColor`,
`BoxSpacing`, and `BoxBorderWidth` now use const objects with derived
string-union types instead of enums
- Removed stale Box color entries with no backing design token:
  - `BoxBackgroundColor.WarningAlternative`
  - `BoxBackgroundColor.SuccessAlternative`
  - `BoxBorderColor.WarningAlternative`
  - `BoxBorderColor.SuccessAlternative`
  - `BoxBorderColor.InfoAlternative`

**Migration:**

```tsx
// Before
import {
  BoxBackgroundColor,
  IconColor,
  IconName,
} from '@metamask/design-system-react-native';

<Box backgroundColor={BoxBackgroundColor.WarningAlternative} />
<Icon name={IconName.Add} color={IconColor.IconDefault} />

// After
import {
  BoxBackgroundColor,
  IconColor,
  IconName,
} from '@metamask/design-system-react-native';

<Box backgroundColor={BoxBackgroundColor.WarningDefault} />
<Icon name={IconName.Add} color={IconColor.IconDefault} />
```

**Impact:**

- Affects consumers relying on enum-specific TypeScript behavior for
`Icon*` and `Box*` exports
- Import paths stay the same for platform-package consumers
- Any use of the removed Box `*Alternative` color entries will need to
switch to the corresponding `*Default` or `*Muted` token

See migration guides for complete instructions:

- [React Migration
Guide](./packages/design-system-react/MIGRATION.md#from-version-0170-to-0180)
- [React Native Migration
Guide](./packages/design-system-react-native/MIGRATION.md#from-version-0190-to-0200)

### Validation

- `yarn changelog:validate`

<!-- CURSOR_SUMMARY -->
---

> [!NOTE]
> **Medium Risk**
> Medium risk because it publishes new versions with **breaking
TypeScript surface changes** (Box/Icon enums → const-object/string-union
and removal of stale Box color members), which can break downstream
builds despite minimal runtime behavior changes.
> 
> **Overview**
> Bumps the monorepo release to `35.0.0` and publishes new package
versions for `@metamask/design-system-react` (`0.18.0`),
`@metamask/design-system-react-native` (`0.20.0`), and
`@metamask/design-system-shared` (`0.13.0`).
> 
> Updates changelogs/migration guides to reflect the release: adds React
Native primitives (`TitleStandard`, `TitleSubpage`, `Tag`) and shared
prop contracts, and documents **breaking** shifts of `Box*` and `Icon*`
exports from enums to const-object + string-union types (plus removal of
stale `*Alternative` Box color entries) with consumer-facing migration
steps.
> 
> <sup>Reviewed by [Cursor Bugbot](https://cursor.com/bugbot) for commit
addbae5. Bugbot is set up for automated
code reviews on this repo. Configure
[here](https://www.cursor.com/dashboard/bugbot).</sup>
<!-- /CURSOR_SUMMARY -->
cursor Bot pushed a commit that referenced this pull request Apr 28, 2026
…1084)

## **Description**

Moves the single source of truth for all icon SVG assets into
`packages/design-system-shared/src/assets/icons/`.

Previously each platform package maintained its own copy of the ~279 SVG
files. This is the first of four phases working toward fully
centralizing Icon types and assets per ADR-0003/ADR-0004 (tracked in
#1042).

**What changed:**
- Added `packages/design-system-shared/src/assets/icons/` with 279 SVGs
copied from the React Native package
- Updated `design-system-react-native/scripts/generate-icons.ts` to read
SVGs from the shared source, apply `black→currentColor` processing, then
copy to the local RN `assets/` folder (output is unchanged)
- Updated `design-system-react/package.json` `generate-icons` script to
point `svgr` at the shared assets folder instead of its own local
`assets/` folder

No public API changes. Both platform packages continue to ship the same
generated files as before.

## **Related issues**

Fixes:

Part of #1042 (phase 1 of 4)

## **Manual testing steps**

1. Check out branch and run `yarn install` from repo root
2. Run `yarn workspace @metamask/design-system-react-native run
generate-icons` — confirm `Icon.assets.ts` and `assets/*.svg` in the RN
package are unchanged
3. Run `yarn workspace @metamask/design-system-react run generate-icons`
— confirm the `icons/*.tsx` components and `icons/index.ts` in the React
package are unchanged
4. Run `yarn build` — confirm all packages build without errors
5. Run `yarn test` — confirm all tests pass

## **Screenshots/Recordings**

### **Before**

SVGs duplicated in two locations:
- `packages/design-system-react-native/src/components/Icon/assets/`
(source)
- `packages/design-system-react/src/components/Icon/assets/` (source)

### **After**

Single source of truth:
- `packages/design-system-shared/src/assets/icons/` (source)
- Platform `assets/` folders remain as generated output

## **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
- [ ] I've included tests if applicable
- [ ] 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**
> Changes icon generation inputs for both React and React Native to pull
from a new shared SVG directory; risk is mainly build-time/regeneration
mismatches or missing assets affecting downstream icon bundles.
> 
> **Overview**
> Moves the *source of truth* for icon SVGs into `design-system-shared`
by adding a shared `src/assets/icons` directory and updating platform
builds to consume it.
> 
> React Native’s `generate-icons.ts` now reads SVGs from the shared
directory, normalizes `black` to `currentColor`, and writes the
processed files into the local RN `Icon/assets` folder before
regenerating `Icon.assets.ts`/`IconName`. React’s `generate-icons`
script is updated to point `svgr` at the shared icons path.
> 
> Also adds new `PopUp` and `SidePanel` icons, wiring them into RN
`Icon.assets.ts` and `IconName`.
> 
> <sup>Reviewed by [Cursor Bugbot](https://cursor.com/bugbot) for commit
c95b4ef. Bugbot is set up for automated
code reviews on this repo. Configure
[here](https://www.cursor.com/dashboard/bugbot).</sup>
<!-- /CURSOR_SUMMARY -->
cursor Bot pushed a commit that referenced this pull request Apr 28, 2026
## **Description**

Removes the redundant SVG icon assets that were left behind in
`packages/design-system-react/src/components/Icon/assets/` after the
icon asset source-of-truth was centralized in #1084.

This follow-up keeps `design-system-react` aligned with the phase 1 icon
asset migration by deleting the unused duplicate files that are no
longer referenced by the React package.

## **Related issues**

Fixes:

Follow-up to #1084
Part of #1042

## **Manual testing steps**

1. Check out this branch and run `git diff main...HEAD --
packages/design-system-react/src/components/Icon/assets`.
2. Confirm the diff only deletes redundant SVG files from
`packages/design-system-react/src/components/Icon/assets/`.
3. Optionally run `yarn workspace @metamask/design-system-react run
generate-icons` and confirm icon generation still uses the shared assets
source introduced in #1084.

## **Screenshots/Recordings**

### **Before**

`packages/design-system-react/src/components/Icon/assets/` still
contained duplicate SVG source files after #1084.

### **After**

The redundant `design-system-react` icon asset copies are removed,
leaving the shared asset source introduced in #1084 as the source of
truth.

## **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
- [ ] I’ve included tests if applicable
- [ ] I’ve documented my code using [JSDoc](https://jsdoc.app/) format
if applicable
- [ ] 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.

Validation run locally:
- `git push -u origin remove-redundant-icon-assets` completed
successfully and ran the repo formatting/dedup hooks.
- I did not run package tests or builds locally for this follow-up
cleanup.

<!-- CURSOR_SUMMARY -->
---

> [!NOTE]
> <sup>[Cursor Bugbot](https://cursor.com/bugbot) is generating a
summary for commit 390c3c4. Configure
[here](https://www.cursor.com/dashboard/bugbot).</sup>
<!-- /CURSOR_SUMMARY -->
cursor Bot added a commit that referenced this pull request Apr 28, 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.
-->

Migrates the `Icon` component across all packages to follow
[ADR-0003](https://github.com/MetaMask/decisions/blob/main/decisions/design-system/0003-enum-to-string-union-migration.md)
(const objects instead of enums) and
[ADR-0004](https://github.com/MetaMask/decisions/blob/main/decisions/design-system/0004-centralized-types-architecture.md)
(centralized types in `@metamask/design-system-shared`).

**Key changes:**

- **Centralized SVG assets** — all 280+ SVG icons moved from
`packages/design-system-react/src/components/Icon/assets/` to
`packages/design-system-shared/src/assets/icons/` as the single source
of truth
- **Unified generation script** — new
`packages/design-system-shared/scripts/generate-icons.ts` replaces the
separate per-platform scripts. A single `yarn generate:icons` from the
repo root now:
  1. Processes SVGs (`black` → `currentColor`)
2. Updates `IconName` in the shared package (sentinel-guarded
auto-generated block)
  3. Copies SVGs + generates `Icon.assets.ts` for React Native
  4. Generates TSX components + `icons/index.ts` barrel for React
- **`IconName` and `IconSize`** — migrated to
`@metamask/design-system-shared` as const objects; both platform
packages re-export from shared
- **`IconColor`** — migrated to `@metamask/design-system-shared` as a
const object with the full union of all color values. Pressed state
variants removed (icons inherit pressed appearance from their parent
interactive element). Both platform packages re-export from shared — the
platform-local definition and `IconColorBase` alias are removed
- **React Native gains `PopUp` and `SidePanel`** — previously React-only
icons, now generated for React Native too since all SVGs live in shared
- **ESLint config** — extended `nodejs` rules to cover
`packages/*/scripts/**/*.ts`, removing per-file `eslint-disable`
comments from existing scripts

**Generated files kept in git** with README notes indicating their
source (`packages/design-system-shared/src/assets/icons/`).

Fixes: DSYS-487

1. Run `yarn generate:icons` from the repo root — verify it completes
with no diff in the working tree
2. Run `yarn build` — all packages should build cleanly
3. Run `yarn test` — all tests should pass
4. Run `yarn lint` — no errors
5. Import `IconName`, `IconSize`, `IconColor` from
`@metamask/design-system-react` or
`@metamask/design-system-react-native` — verify autocomplete includes
all values

<!-- If applicable, add screenshots and/or recordings to visualize the
before and after of your change. -->

- `IconName` defined separately in each platform package (enum in RN,
const in React)
- `IconColor` defined as a local const in each platform package with
different value sets
- Two separate generation scripts (`generate-icons.ts` in RN,
`generate-icons-index.ts` in React)
- SVG assets lived only in the React package; React Native had a
separate copy

`yarn generate:icons`

https://github.com/user-attachments/assets/062562e0-5677-4fc2-b806-28ced6a00787

- `IconName`, `IconSize`, `IconColor` defined once in
`@metamask/design-system-shared`, re-exported by both platforms
- Single `yarn generate:icons` script handles the full generation
pipeline
- All SVG assets in `packages/design-system-shared/src/assets/icons/` —
one source of truth

`yarn workspace @metamask/design-system-react/native generate:icons` now
runs the single script in shared but results in the same build

https://github.com/user-attachments/assets/d8c4e071-cb9b-435d-ad08-39cd935cf015

No visual changes

https://github.com/user-attachments/assets/90f3687c-73ab-4950-9859-52dcc6415bea

Mobile working with preview package. Some small breaking change updates
needed but nothing serious
MetaMask/metamask-mobile#28840

https://github.com/user-attachments/assets/92fd522a-c9dd-4739-9de2-50cf4a343c32

Extension working with preview package. Some small breaking change
updates needed but nothing serious
MetaMask/metamask-extension#41733

<img width="1468" height="869" alt="Screenshot 2026-04-14 at 2 23 33 PM"
src="https://github.com/user-attachments/assets/9234b56b-31c9-451d-882d-55d1272ce732"
/>

`yarn lint:tsc` passing in extension with fixes from above PR

<img width="590" height="509" alt="Screenshot 2026-04-14 at 2 19 26 PM"
src="https://github.com/user-attachments/assets/22d6dfdc-7fbf-47d8-bfd4-a9a6c1ad1570"
/>

CSS rendering icon-color classnames from shared

<img width="827" height="437" alt="Screenshot 2026-04-14 at 2 24 21 PM"
src="https://github.com/user-attachments/assets/c7bef966-748c-4dce-8d3f-74ca9c5700f0"
/>

- [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
- [ ] 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.

- [ ] 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 changes the icon type surface
(`IconName`/`IconColor`/`IconSize`) and the icon generation/build
pipeline across React + React Native, which could break downstream
builds or icon imports if regeneration or publishing order is off.
>
> **Overview**
> **Centralizes icon definitions and generation** by introducing
`@metamask/design-system-shared/src/types/Icon` (`IconColor`,
`IconSize`, and a generated `IconName` const-object + string-union) and
exporting these from `design-system-shared`’s public index.
>
> **Unifies the icon build pipeline** with a new
`design-system-shared/scripts/generate-icons.ts` (process SVGs, update
shared `IconName`, regenerate React Native `Icon.assets.ts` + assets,
and regenerate React TSX icon components + `icons/index.ts`). Root
`package.json` adds `generate:icons`, platform packages remove their
per-package icon generation scripts/tests/config, and
`design-system-shared` now runs icon generation during `build`.
>
> **Updates consumers to shared types/outputs**: React and React Native
`Icon.types` now extend `IconPropsShared`; platform `src/types/index.ts`
stops defining icon enums and re-exports
`IconColor`/`IconName`/`IconSize` from shared; generated RN
`assetByIconName` no longer references `IconName` computed keys. ESLint
node rules are expanded to include `packages/*/scripts/**/*.ts`, and
lockfile updates reflect new generator deps (`@svgr/*`, `tsx`/`esbuild`
bumps).
>
> <sup>Reviewed by [Cursor Bugbot](https://cursor.com/bugbot) for commit
f254bdc. 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: georgewrmarshall <george.marshall@consensys.net>
cursor Bot pushed a commit that referenced this pull request Apr 28, 2026
## Release 35.0.0

This release adds new React Native title primitives, continues the
enum-to-const-object/string-union migration for public type exports, and
updates the release documentation so breaking changes are
consumer-focused and migration-oriented.

### Package Versions

- `@metamask/design-system-shared`: **0.13.0**
- `@metamask/design-system-react`: **0.18.0**
- `@metamask/design-system-react-native`: **0.20.0**
- `@metamask/design-system-tailwind-preset`: **0.6.2**

### Shared Type Updates (0.13.0)

#### Added (#1051, #1053, #1059)

**What Changed:**

- Added `TitleStandardPropsShared` and `TitleSubpagePropsShared`
- Added `TagSeverity` and `TagPropsShared`

**Impact:**

- Supports the new React Native `TitleStandard`, `TitleSubpage`, and
`Tag` APIs

#### Changed (#1026, #1042)

**What Changed:**

- **BREAKING:** Updated shared `Box` and `Icon` exports from enums to
const objects with derived string-union types
- Removed stale Box `WarningAlternative`, `SuccessAlternative`, and
`InfoAlternative` color entries that no longer map to design tokens

**Impact:**

- Affects consumers of `@metamask/design-system-shared` directly
- Platform package consumers should continue importing from
`@metamask/design-system-react` or
`@metamask/design-system-react-native`

### React Web Updates (0.18.0)

#### Changed

- **BREAKING:** Updated `IconName`, `IconColor`, and `IconSize` exports
to use const-object + string-union types instead of enums (#1042, #1101)
- **BREAKING:** Updated `Box` type exports to use const-object +
string-union types and removed stale Box color entries (#1026)
- Updated `ButtonTertiary` to use the default text color for more
consistent contrast across states (#1099)

### React Native Updates (0.20.0)

#### Added

- Added `TitleStandard` for mobile title layouts with optional top and
bottom accessory rows (#1051)
- Added `TitleSubpage` for subpage headers with avatar, title, subtitle,
amount, and bottom-label layouts (#1059)
- Added `Tag` for compact severity-based metadata labels with optional
icons or custom accessories (#1053)

#### Changed

- **BREAKING:** Updated `IconName`, `IconColor`, and `IconSize` exports
to use const-object + string-union types instead of enums (#1042)
- **BREAKING:** Updated `Box` type exports to use const-object +
string-union types and removed stale Box color entries (#1026)
- `Box` now forwards refs to the underlying `View` (#1102)
- Updated `ButtonTertiary` to use the default text color for more
consistent contrast across states (#1099)

### Tailwind Preset Updates (0.6.2)

#### Changed

- No consumer-facing API or behavior changes in this release; this patch
republishes the existing preset without requiring changes in consuming
apps

### Breaking Changes

#### Icon and Box enum exports migrated to const objects plus string
unions (Both Platforms)

**What Changed:**

- `IconName`, `IconColor`, and `IconSize` now use const objects with
derived string-union types instead of enums
- `BoxFlexDirection`, `BoxFlexWrap`, `BoxAlignItems`,
`BoxJustifyContent`, `BoxBackgroundColor`, `BoxBorderColor`,
`BoxSpacing`, and `BoxBorderWidth` now use const objects with derived
string-union types instead of enums
- Removed stale Box color entries with no backing design token:
  - `BoxBackgroundColor.WarningAlternative`
  - `BoxBackgroundColor.SuccessAlternative`
  - `BoxBorderColor.WarningAlternative`
  - `BoxBorderColor.SuccessAlternative`
  - `BoxBorderColor.InfoAlternative`

**Migration:**

```tsx
// Before
import {
  BoxBackgroundColor,
  IconColor,
  IconName,
} from '@metamask/design-system-react-native';

<Box backgroundColor={BoxBackgroundColor.WarningAlternative} />
<Icon name={IconName.Add} color={IconColor.IconDefault} />

// After
import {
  BoxBackgroundColor,
  IconColor,
  IconName,
} from '@metamask/design-system-react-native';

<Box backgroundColor={BoxBackgroundColor.WarningDefault} />
<Icon name={IconName.Add} color={IconColor.IconDefault} />
```

**Impact:**

- Affects consumers relying on enum-specific TypeScript behavior for
`Icon*` and `Box*` exports
- Import paths stay the same for platform-package consumers
- Any use of the removed Box `*Alternative` color entries will need to
switch to the corresponding `*Default` or `*Muted` token

See migration guides for complete instructions:

- [React Migration
Guide](./packages/design-system-react/MIGRATION.md#from-version-0170-to-0180)
- [React Native Migration
Guide](./packages/design-system-react-native/MIGRATION.md#from-version-0190-to-0200)

### Validation

- `yarn changelog:validate`

<!-- CURSOR_SUMMARY -->
---

> [!NOTE]
> **Medium Risk**
> Medium risk because it publishes new versions with **breaking
TypeScript surface changes** (Box/Icon enums → const-object/string-union
and removal of stale Box color members), which can break downstream
builds despite minimal runtime behavior changes.
> 
> **Overview**
> Bumps the monorepo release to `35.0.0` and publishes new package
versions for `@metamask/design-system-react` (`0.18.0`),
`@metamask/design-system-react-native` (`0.20.0`), and
`@metamask/design-system-shared` (`0.13.0`).
> 
> Updates changelogs/migration guides to reflect the release: adds React
Native primitives (`TitleStandard`, `TitleSubpage`, `Tag`) and shared
prop contracts, and documents **breaking** shifts of `Box*` and `Icon*`
exports from enums to const-object + string-union types (plus removal of
stale `*Alternative` Box color entries) with consumer-facing migration
steps.
> 
> <sup>Reviewed by [Cursor Bugbot](https://cursor.com/bugbot) for commit
addbae5. 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