Files
supabase/packages/ui/package.json
T
Alaister YoungandAlaister Young ec1029dff0 chore: migrate from clsx + tailwind-merge to shadcn-ui/cn (#49938)
Migrates the repo off `clsx` + `tailwind-merge` to
[shadcn-ui/cn](https://github.com/shadcn-ui/cn). Every app and package
already gets `cn` from `packages/ui`, so the swap happens in that one
helper and flows through to Studio, docs, www, and the rest.

**Changed:**
- `packages/ui` `cn` helper now uses `createCn` from `cn/config`,
keeping the custom `card`/`content` spacing scale so `p-card` still
overrides `p-4`. It has an explicit signature and re-exports
`ClassValue`.
- The four www Launch Week files that imported the `ClassValue` type
from `clsx` now import it from `ui`.
- `blocks/vue` local `lib/utils.ts` re-exports `cn` from the package.
- Comments/README that referenced tailwind-merge.

**Removed:**
- Direct `clsx` and `tailwind-merge` deps from `ui`, `ui-patterns`,
`www`, and `blocks/vue`. `ui-patterns` and `www` declared them without
importing.

**Added:**
- `packages/ui/src/lib/utils/cn.test.ts` covering clsx-style joining,
conflict resolution, the custom spacing scale, and variant handling.

Not migrated: the standalone apps under `examples/`. They're outside the
workspace and mostly on Tailwind v3, which `cn` doesn't support.

Lockfile note: after merging master, the lockfile diff is only the
intended swap (`clsx` and `tailwind-merge` out, `cn@0.2.5` in).
`tailwind-merge` stays in the lockfile as a transitive dep of a
third-party package.

Release-age note: this sat in draft with a temporary
`minimumReleaseAgeExclude` entry for `cn` while `cn` was inside the
workspace's 3-day `minimumReleaseAge` window. That window has closed, so
the exclusion is gone and nothing bypasses the release-age gate.

## To test

- `pnpm install --frozen-lockfile` succeeds with no
`minimumReleaseAgeExclude` entry for `cn`.
- `pnpm --filter ui test` – new `cn.test.ts` passes, including
`cn('p-4', 'p-card')` → `p-card`.
- Typecheck passes for studio, ui, ui-patterns, vue-blocks. www
typecheck panics under tsgo on master already (pre-existing, unrelated);
it passes with the JS `tsc` binary.
- Spot-check Studio locally: class overrides still win in the usual
places (e.g. `CodeEditor` height, `Button` variants with a custom
`className`).

https://claude.ai/code/session_01MkAt16tsPRDTm9oB5Jr8Ub


<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->

## Summary by CodeRabbit

* **Improvements**
* Standardized Tailwind class merging across shared UI utilities while
preserving conditional classes, custom spacing classes, and variant
behavior.
* Updated related components and examples to use the standardized
class-merging utility.

* **Tests**
* Added coverage for conditional class handling, conflicting utility
resolution, custom spacing classes, and variant separation.

* **Documentation**
* Updated usage guidance to reflect the standardized Tailwind
class-merging approach.

<!-- end of auto-generated comment: release notes by coderabbit.ai -->

---------

Co-authored-by: Alaister Young <10985857+alaister@users.noreply.github.com>
2026-09-07 21:35:06 +08:00

64 lines
1.9 KiB
JSON

{
"name": "ui",
"version": "0.0.0",
"main": "./index.tsx",
"types": "./index.tsx",
"license": "MIT",
"sideEffects": false,
"scripts": {
"preinstall": "npx only-allow pnpm",
"typecheck": "tsc --noEmit",
"generate-tailwind-classes": "tsx ./scripts/generate-tailwind-classes.ts",
"clean": "rimraf .turbo tsconfig.tsbuildinfo",
"test": "vitest",
"test:ci": "vitest --run --coverage",
"test:report": "open coverage/lcov-report/index.html"
},
"dependencies": {
"@tailwindcss/forms": "^0.5.11",
"@tailwindcss/typography": "^0.5.19",
"class-variance-authority": "^0.7.1",
"cn": "^0.2.4",
"cmdk": "^1.1.1",
"color": "^4.2.3",
"date-fns": "^2.30.0",
"framer-motion": "^11.18.2",
"input-otp": "^1.4.2",
"lodash": "catalog:",
"lucide-react": "^0.436.0",
"prop-types": "^15.7.2",
"radix-ui": "catalog:",
"react": "catalog:",
"react-accessible-treeview": "^2.11.2",
"react-copy-to-clipboard": "^5.1.0",
"react-day-picker": "^9.11.1",
"react-dom": "catalog:",
"react-hook-form": "^7.71.2",
"react-intersection-observer": "^9.8.2",
"react-resizable-panels": "^4.6.5",
"recharts": "catalog:",
"sonner": "^1.5.0",
"tailwindcss": "catalog:",
"vaul": "^1.1.2"
},
"devDependencies": {
"@hookform/resolvers": "^3.1.1",
"@testing-library/jest-dom": "^6.6.0",
"@testing-library/react": "^16.0.0",
"@testing-library/user-event": "^14.0.0",
"@types/lodash": "4.17.5",
"@types/node": "catalog:",
"@types/react": "catalog:",
"@types/react-copy-to-clipboard": "^5.0.4",
"@types/react-dom": "catalog:",
"@typescript/native": "catalog:",
"@vitest/coverage-v8": "catalog:",
"config": "workspace:*",
"tsconfig": "workspace:*",
"tsx": "catalog:",
"typescript": "catalog:",
"vite": "catalog:",
"vitest": "catalog:"
}
}