Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
43 commits
Select commit Hold shift + click to select a range
0b11558
chore: initial commit
georgewrmarshall Oct 16, 2025
a4c620c
chore: update
georgewrmarshall Oct 16, 2025
912cb27
chore: update
georgewrmarshall Oct 17, 2025
ecb1b9e
chore: updates to tests
georgewrmarshall Oct 17, 2025
043e4ad
chore: update
georgewrmarshall Oct 20, 2025
c85c887
fix: migrate to eslint-plugin-better-tailwindcss for Tailwind v4 comp…
georgewrmarshall Oct 20, 2025
c04da02
chore: reverting tailwind package
georgewrmarshall Mar 6, 2026
d472684
Add tailwind parity check and align new theme.css utilities
georgewrmarshall Mar 6, 2026
37d8455
Fix Storybook Tailwind v4 theme import path
georgewrmarshall Mar 6, 2026
268e77b
chore: configure tailwind v4 entrypoints for lint and vscode
georgewrmarshall Mar 6, 2026
6bca0ab
chore: resolve lint failures for tailwind v4 migration
georgewrmarshall Mar 6, 2026
dd743df
chore: configure Tailwind v3/v4 dual support across packages
georgewrmarshall Mar 10, 2026
1006d14
fix: add @types/react dependencies for TypeScript compilation
georgewrmarshall Mar 10, 2026
eadf0e8
fix: resolve test dependency and platform mock issues
georgewrmarshall Mar 16, 2026
93ba165
revert: undo out-of-scope component and infrastructure changes
georgewrmarshall Mar 16, 2026
690caa0
fix: address PR review feedback for Tailwind v4 migration
georgewrmarshall Mar 16, 2026
a3c5290
feat: signal dual Tailwind v3/v4 support in package manifests
georgewrmarshall Mar 16, 2026
60a85cd
fix: use @theme instead of @theme inline to enable dark mode CSS vari…
georgewrmarshall Mar 16, 2026
4db57dd
fix: preserve Tailwind v4 directives in build and enable ESLint corre…
georgewrmarshall Mar 16, 2026
24165cd
fix: resolve RN ESLint plugin loading to use tailwindcss v3 context
georgewrmarshall Mar 16, 2026
87402b2
fix: build twrnc-preset before lint in CI for RN class name resolution
georgewrmarshall Mar 16, 2026
3fdf2c0
fix: disable default Tailwind font sizes/weights and add .light theme…
georgewrmarshall Mar 16, 2026
5eb7940
fix: build design-tokens before twrnc-preset in CI lint setup
georgewrmarshall Mar 16, 2026
83a127d
fix: add missing font-medium and font-bold @utility directives in the…
georgewrmarshall Mar 16, 2026
f85fce0
feat: upgrade tailwind-merge to v3 and adopt Tailwind v4 outline syntax
georgewrmarshall Mar 16, 2026
9133359
fix: promote no-conflicting-classes ESLint rule to error
georgewrmarshall Mar 17, 2026
712ca02
chore: remove v3 tailwind-preset peer dep from design-system-react
georgewrmarshall Mar 17, 2026
7d94c3e
docs: add Tailwind v3 to v4 migration guides
georgewrmarshall Mar 17, 2026
fe569fb
fix: copy CSS imports to dist so theme.css resolves from npm
georgewrmarshall Mar 17, 2026
f7508d1
fix: bundle theme.css imports at build time into a single file
georgewrmarshall Mar 17, 2026
3a3fdc0
fix: replace import.meta.dirname with fileURLToPath for Node 18 compat
georgewrmarshall Mar 17, 2026
3788306
fix: handle shorthand hex colors in getContrastYIQ
georgewrmarshall Mar 17, 2026
4cef415
fix: align Tailwind v4 shadows with native shadow system
georgewrmarshall Mar 18, 2026
660e50a
fix: override --font-sans in Tailwind v4 theme to use Geist globally
georgewrmarshall Mar 18, 2026
a786e1c
chore: update chomatic config
georgewrmarshall Mar 19, 2026
768d674
fix(dsr): restore button focus outline classes for Chromatic baseline
georgewrmarshall Mar 20, 2026
2d187d0
chore(dsr): align button focus eslint hints and class order
georgewrmarshall Mar 20, 2026
d2d1dc8
chore(design-tokens): align parity check with v4 shadow utilities
georgewrmarshall Mar 20, 2026
bd2bceb
fix(design-tokens): use composable shadow classes in Shadows stories
georgewrmarshall Mar 20, 2026
4ac09f1
fix lint issues after tailwind v4 rebase
georgewrmarshall Apr 27, 2026
5408028
docs: add tailwind v4 PR split plan
georgewrmarshall Apr 27, 2026
6a2da3d
fix: clean up post-rebase conflict markers
georgewrmarshall May 5, 2026
4b50dc2
fix: resolve post-rebase tailwind lint issues
georgewrmarshall May 5, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .depcheckrc.yml
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ ignores:
- 'eslint-interactive'
- 'rimraf'
- 'simple-git-hooks'
- 'tailwindcss'
- 'tsx'
# Ignore plugins for tools
- '@typescript-eslint/*'
Expand Down
3 changes: 2 additions & 1 deletion .github/workflows/lint-build-test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,8 @@ jobs:
is-high-risk-environment: false
- name: Setup
# The Tailwind Prettier plugin requires the Tailwind preset to be built, as the plugin depends on the configuration provided by the preset for linting to function correctly.
run: yarn workspace @metamask/design-system-tailwind-preset build
# The twrnc preset must also be built so the RN ESLint tailwind-intellisense config can resolve custom class names.
run: yarn workspace @metamask/design-tokens build && yarn workspace @metamask/design-system-tailwind-preset build && yarn workspace @metamask/design-system-twrnc-preset build
- run: yarn lint
Comment thread
georgewrmarshall marked this conversation as resolved.
- name: Require clean working directory
shell: bash
Expand Down
2 changes: 1 addition & 1 deletion .vscode/settings.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"tailwindCSS.experimental.configFile": {
"apps/storybook-react/tailwind.config.js": [
"apps/storybook-react/tailwind.css": [
"apps/storybook-react/**",
"packages/design-system-react/src/**",
"packages/design-tokens/stories/**"
Expand Down
3 changes: 3 additions & 0 deletions apps/storybook-react-native/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -39,11 +39,14 @@
"@storybook/react-native": "^10",
"@types/react": "^18.2.0",
"@types/react-dom": "^18.2.0",
"@types/react-native-get-random-values": "^1",
"eslint-plugin-tailwindcss": "^3.18.2",
"react-dom": "18.3.1",
"react-native-safe-area-context": "^5.4.0",
"react-native-svg": "~15.11.2",
"react-native-svg-transformer": "^1.5.0",
"storybook": "^10.3.1",
"tailwindcss": "^3.4.0",
"typescript": "~5.2.2"
},
"engines": {
Expand Down
1 change: 0 additions & 1 deletion apps/storybook-react/.storybook/preview.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
import React from 'react';
import '../../../packages/design-tokens/dist/styles.css';
import '../tailwind.css';

import { Preview } from '@storybook/react-vite';
Expand Down
6 changes: 6 additions & 0 deletions apps/storybook-react/chromatic.config.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
{
"onlyChanged": true,
"projectId": "Project:687fcaddf8b7897929097b3a",
"storybookBaseDir": "apps/storybook-react",
"zip": true
}
9 changes: 5 additions & 4 deletions apps/storybook-react/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -7,13 +7,13 @@
"scripts": {
"build-storybook": "storybook build",
"chromatic": "chromatic --exit-zero-on-changes",
"check:tailwind-theme-parity": "yarn workspace @metamask/design-tokens check:tailwind-theme-parity",
"storybook": "storybook dev -p 6006",
"test-storybook": "vitest --run"
},
"devDependencies": {
"@chromatic-com/storybook": "^5.0.0",
"@metamask/design-system-react": "workspace:^",
"@metamask/design-system-tailwind-preset": "workspace:^",
"@metamask/design-tokens": "workspace:^",
"@metamask/utils": "^11.11.0",
"@playwright/test": "^1.52.0",
Expand All @@ -22,14 +22,13 @@
"@storybook/addon-mcp": "^0.4.1",
"@storybook/addon-vitest": "^10.3.1",
"@storybook/react-vite": "^10.3.1",
"@testing-library/dom": "^9.0.0",
"@testing-library/dom": "^10.0.0",
"@testing-library/react": "^16.0.1",
"@types/prop-types": "^15",
"@types/react": "^18.2.0",
"@types/react-dom": "^18.2.0",
"@vitejs/plugin-react": "^4.5.0",
"@vitest/coverage-v8": "^3.2.4",
"autoprefixer": "^10.0.0",
"axe-playwright": "^2.1.0",
"chromatic": "^15.2.0",
"playwright": "^1.52.0",
Expand All @@ -38,7 +37,7 @@
"react": "18.3.1",
"react-dom": "18.3.1",
"storybook": "^10.3.1",
"tailwindcss": "^3.0.0",
"tailwindcss": "^4.0.0",
"typescript": "~5.2.2",
"vite": "^6.3.6",
"vitest": "^3.2.0"
Expand All @@ -53,6 +52,8 @@
}
},
"dependencies": {
"@tailwindcss/postcss": "^4.0.0",
"@tailwindcss/vite": "^4.0.0",
"@vitest/browser": "^3.2.0"
}
}
3 changes: 1 addition & 2 deletions apps/storybook-react/postcss.config.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
module.exports = {
plugins: {
tailwindcss: {},
autoprefixer: {},

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.

Dual Tailwind v4 plugins cause double-processing conflict

Medium Severity

Both @tailwindcss/vite (in vite.config.ts) and @tailwindcss/postcss (in postcss.config.js) are active simultaneously. Tailwind v4 documentation explicitly states these should not be used together — pick one based on your build tool. Using both causes Tailwind CSS to be processed twice, which can lead to duplicated styles, unexpected specificity, or subtle rendering issues.

Additional Locations (1)
Fix in Cursor Fix in Web

Reviewed by Cursor Bugbot for commit aa8bbd5. Configure here.

'@tailwindcss/postcss': {},
},
};
8 changes: 4 additions & 4 deletions apps/storybook-react/stories/WalletHome.stories.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -150,15 +150,15 @@ const WalletHome: React.FC = () => {
<Text
asChild
fontWeight={FontWeight.Medium}
className="flex-1 border-b-2 border-icon-default pb-2 pt-1"
className="flex-1 border-b-2 border-icon-default pt-1 pb-2"
>
<button>Tokens</button>
</Text>
<Text
asChild
fontWeight={FontWeight.Medium}
color={TextColor.TextAlternative}
className="flex flex-1 items-center justify-center gap-1 pb-2 pt-1 hover:text-default"
className="flex flex-1 items-center justify-center gap-1 pt-1 pb-2 hover:text-default"
>
<button>
<span className="pl-4">DeFi</span>
Expand All @@ -169,15 +169,15 @@ const WalletHome: React.FC = () => {
asChild
fontWeight={FontWeight.Medium}
color={TextColor.TextAlternative}
className="flex-1 pb-2 pt-1 hover:text-default"
className="flex-1 pt-1 pb-2 hover:text-default"
>
<button>NFTs</button>
</Text>
<Text
asChild
fontWeight={FontWeight.Medium}
color={TextColor.TextAlternative}
className="flex-1 pb-2 pt-1 hover:text-default"
className="flex-1 pt-1 pb-2 hover:text-default"
>
<button>Activity</button>
</Text>
Expand Down
9 changes: 6 additions & 3 deletions apps/storybook-react/tailwind.css
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
@tailwind base;
@tailwind components;
@tailwind utilities;
@import 'tailwindcss';
@import '../../packages/design-tokens/src/tailwind/theme.css';

/* Scan the other packages with stories for tailwind class names */
@source "../../packages/design-system-react";
@source "../../packages/design-tokens";

/* Geist */
@font-face {
Expand Down
6 changes: 5 additions & 1 deletion apps/storybook-react/vite.config.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,13 @@
import react from '@vitejs/plugin-react';
import { defineConfig } from 'vite';
import tailwindcss from '@tailwindcss/vite';
import path from 'path';

export default defineConfig({
plugins: [react()],
plugins: [
react(),
tailwindcss()
],
Comment thread
cursor[bot] marked this conversation as resolved.
resolve: {
alias: {
'@metamask/design-tokens': path.resolve(
Expand Down
199 changes: 199 additions & 0 deletions docs/tailwind-v4-pr-split-plan.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,199 @@
# Tailwind v4 PR Split Plan

This document is the source of truth for breaking the Tailwind v4 migration into smaller, reviewable PRs.

It exists because the current migration branch mixes foundation work, tooling changes, package contract changes, and component adoption. That makes review difficult and increases the chance that behavior changes, tooling changes, and migration mechanics get conflated.

This file should stay in the source-of-truth PR while we split the work into follow-up PRs. Once the migration has been fully broken out and merged, this file can be removed or the source-of-truth PR can be closed.

## Goals

- Reduce review surface area
- Separate platform changes from consumer adoption
- Keep each PR focused on one primary risk area
- Preserve a shippable, incremental migration path
- Make it clear which PRs are compatibility steps versus cutover steps

## Review Principles

Each PR should answer one primary question:

- Are the new Tailwind v4 design-token artifacts correct?
- Can the repo tooling safely support Tailwind v3 and v4 during migration?
- Can a real web consumer adopt `theme.css` successfully?
- Does a given component family preserve behavior while moving to Tailwind v4?
- Are cleanup and contract-removal steps safe after adoption is complete?

Each PR should avoid mixing:

- token generation with component churn
- lint/tooling enablement with behavioral component changes
- web Tailwind v4 adoption with unrelated React Native changes
- migration mechanics with unrelated cleanup

## Recommended Phases

### Phase 1: `design-tokens` Tailwind v4 Foundation

Goal: introduce the Tailwind v4 token surface as a stable foundation for downstream adoption.

Scope:

- add and build `packages/design-tokens/src/tailwind/theme.css`
- export the built `tailwind/theme.css` artifact
- add or refine parity validation against the v3 preset
- document consumer migration for token usage

Should prove:

- Tailwind v4 token output exists
- token output is sufficiently compatible with the v3 preset
- known deltas are explicitly documented

Should not include:

- `design-system-react` component migrations
- Storybook wiring
- broad repo-wide lint or package contract changes

### Phase 2: Tooling and Dual-Support Infrastructure

Goal: make the repo capable of understanding and validating Tailwind v4 without forcing immediate cutover everywhere.

Scope:

- ESLint support for web Tailwind v4 class validation
- any required dual-support configuration across packages
- build or config changes needed so v3 and v4 can coexist during migration

Should prove:

- the repo can lint and build Tailwind v4 consumers safely
- migration work can land incrementally without breaking unrelated packages

Should not include:

- broad component family migrations
- unrelated refactors

### Phase 3: Canary Consumer Adoption

Goal: wire one real web consumer to Tailwind v4 as proof that the foundation is usable end to end.

Recommended first consumer:

- `apps/storybook-react`

Scope:

- Tailwind v4 CSS entrypoint wiring
- PostCSS or Vite integration updates as needed
- `@source` scanning updates for Storybook and package consumption

Should prove:

- a real consumer can use `@metamask/design-tokens/tailwind/theme.css`
- the migration path works outside of isolated parity tests

Should not include:

- broad React component migration
- peer dependency removal unless strictly required

### Phase 4: `design-system-react` Package Contract

Goal: update the consumer-facing contract for web package adoption.

Scope:

- remove the v3 preset peer dependency from `@metamask/design-system-react`
- update package metadata and migration docs
- clarify the expected Tailwind v4 consumer setup

Should prove:

- consumers have a clear, documented adoption contract
- the package no longer signals the old preset as the expected integration path

Should not include:

- large component churn
- unrelated styling rewrites

### Phase 5: Component Migration by Family

Goal: migrate component implementations in small, reviewable groups.

Recommended grouping:

- typography primitives: `Text`, `Input`, typography mappings
- buttons: `Button`, `ButtonIcon`, `TextButton`
- form controls: `Checkbox`, `Radio`, related controls
- utility/config follow-ups where required

Rules:

- keep each PR focused on one component family
- preserve runtime behavior where possible
- isolate intentional behavior changes and call them out explicitly
- keep tests close to the migrated surface

Should prove:

- the migrated family behaves the same under Tailwind v4
- reviewers can reason about behavior without reading unrelated migration noise

### Phase 6: Cleanup and Compatibility Removal

Goal: remove temporary compatibility paths once adoption is complete.

Scope:

- remove transitional docs or config
- remove temporary dual-support behavior no longer needed
- tighten remaining lint or package expectations

Should prove:

- the repo has completed the cutover
- no migration-only scaffolding remains

## Compatibility vs. Cutover

This migration should distinguish clearly between compatibility work and cutover work.

Compatibility work:

- introduces `theme.css`
- allows v3 and v4 to coexist
- validates parity
- proves early adoption in a low-risk consumer

Cutover work:

- removes the old preset from the expected package contract
- migrates component families
- removes temporary compatibility scaffolding

This distinction matters because compatibility steps should leave the repo flexible, while cutover steps intentionally narrow the supported path.

## Suggested PR Sequence

1. `design-tokens`: Tailwind v4 foundation
2. Tooling: dual-support lint/build/config support
3. Storybook React: canary consumer adoption
4. `design-system-react`: package contract and migration docs
5. Component family PRs
6. Cleanup and removal of temporary compatibility paths

## Open Questions

- Should `design-system-react` package contract changes land before or after Storybook adoption?
- Which component family is the best first migration candidate after the canary consumer is stable?
- Are any React Native-adjacent changes truly required for the web Tailwind v4 rollout, or should they be split completely?
- Which known parity exceptions are acceptable and permanent versus temporary?

## Working Notes

- Initial leaning: start with `design-tokens` foundation, including the stylesheet, parity check, and migration docs.
- Strong preference: do not mix `twMerge` behavior changes, component-family migration, and tooling churn in the same PR unless one change is mechanically required by another.
Loading