diff --git a/.changeset/brave-cheetahs-smile.md b/.changeset/brave-cheetahs-smile.md
deleted file mode 100644
index ad4775459d..0000000000
--- a/.changeset/brave-cheetahs-smile.md
+++ /dev/null
@@ -1,5 +0,0 @@
----
-"shadcn": minor
----
-
-add support for TanStack Start
diff --git a/.changeset/cold-impalas-call.md b/.changeset/cold-impalas-call.md
deleted file mode 100644
index 5de218772a..0000000000
--- a/.changeset/cold-impalas-call.md
+++ /dev/null
@@ -1,5 +0,0 @@
----
-"shadcn": patch
----
-
-support for version detection in monorepo
diff --git a/.changeset/cool-mails-bake.md b/.changeset/cool-mails-bake.md
deleted file mode 100644
index 085f768e35..0000000000
--- a/.changeset/cool-mails-bake.md
+++ /dev/null
@@ -1,5 +0,0 @@
----
-"shadcn": patch
----
-
-upgrade @antfu/ni
diff --git a/.changeset/curly-impalas-give.md b/.changeset/curly-impalas-give.md
deleted file mode 100644
index 6667f901d3..0000000000
--- a/.changeset/curly-impalas-give.md
+++ /dev/null
@@ -1,5 +0,0 @@
----
-"shadcn": patch
----
-
-allow silent mode with npm
diff --git a/.changeset/curvy-taxis-help.md b/.changeset/curvy-taxis-help.md
deleted file mode 100644
index c17b6d1b5a..0000000000
--- a/.changeset/curvy-taxis-help.md
+++ /dev/null
@@ -1,5 +0,0 @@
----
-"shadcn": patch
----
-
-do not add ring for v3
diff --git a/.changeset/few-houses-impress.md b/.changeset/few-houses-impress.md
deleted file mode 100644
index 8feeafd979..0000000000
--- a/.changeset/few-houses-impress.md
+++ /dev/null
@@ -1,5 +0,0 @@
----
-"shadcn": minor
----
-
-add theme vars support
diff --git a/.changeset/five-hounds-tell.md b/.changeset/five-hounds-tell.md
deleted file mode 100644
index 849f1c114b..0000000000
--- a/.changeset/five-hounds-tell.md
+++ /dev/null
@@ -1,5 +0,0 @@
----
-"shadcn": minor
----
-
-add tailwind version detection
diff --git a/.changeset/fluffy-years-knock.md b/.changeset/fluffy-years-knock.md
deleted file mode 100644
index fc167c719e..0000000000
--- a/.changeset/fluffy-years-knock.md
+++ /dev/null
@@ -1,5 +0,0 @@
----
-"shadcn": minor
----
-
-add --base-color flag
diff --git a/.changeset/fresh-cherries-brush.md b/.changeset/fresh-cherries-brush.md
deleted file mode 100644
index f57423cce4..0000000000
--- a/.changeset/fresh-cherries-brush.md
+++ /dev/null
@@ -1,5 +0,0 @@
----
-"shadcn": minor
----
-
-add support for tailwind v4
diff --git a/.changeset/great-olives-flow.md b/.changeset/great-olives-flow.md
deleted file mode 100644
index d58ad002ad..0000000000
--- a/.changeset/great-olives-flow.md
+++ /dev/null
@@ -1,5 +0,0 @@
----
-"shadcn": minor
----
-
-default to css vars. add --no-css-variables
diff --git a/.changeset/green-eels-shout.md b/.changeset/green-eels-shout.md
deleted file mode 100644
index a7013814ca..0000000000
--- a/.changeset/green-eels-shout.md
+++ /dev/null
@@ -1,5 +0,0 @@
----
-"shadcn": patch
----
-
-cache registry calls
diff --git a/.changeset/honest-humans-invite.md b/.changeset/honest-humans-invite.md
new file mode 100644
index 0000000000..9d208718a9
--- /dev/null
+++ b/.changeset/honest-humans-invite.md
@@ -0,0 +1,5 @@
+---
+"shadcn": patch
+---
+
+resolved prefixing issue for Tailwind CSS v4 compatibility
diff --git a/.changeset/large-timers-kneel.md b/.changeset/large-timers-kneel.md
deleted file mode 100644
index b49b194acf..0000000000
--- a/.changeset/large-timers-kneel.md
+++ /dev/null
@@ -1,5 +0,0 @@
----
-"shadcn": minor
----
-
-replace tailwindcss-animate with tw-animate-css
diff --git a/.changeset/metal-queens-hang.md b/.changeset/metal-queens-hang.md
deleted file mode 100644
index 8b2d3ef60d..0000000000
--- a/.changeset/metal-queens-hang.md
+++ /dev/null
@@ -1,5 +0,0 @@
----
-"shadcn": patch
----
-
-add --template flag
diff --git a/.changeset/new-cheetahs-dance.md b/.changeset/new-cheetahs-dance.md
deleted file mode 100644
index 31bf21a2e3..0000000000
--- a/.changeset/new-cheetahs-dance.md
+++ /dev/null
@@ -1,5 +0,0 @@
----
-"shadcn": minor
----
-
-default for new-york for v4
diff --git a/.changeset/nine-llamas-sell.md b/.changeset/nine-llamas-sell.md
deleted file mode 100644
index 14f7e942a2..0000000000
--- a/.changeset/nine-llamas-sell.md
+++ /dev/null
@@ -1,5 +0,0 @@
----
-"shadcn": minor
----
-
-fix handling of sidebar colors
diff --git a/.changeset/ninety-needles-brake.md b/.changeset/ninety-needles-brake.md
deleted file mode 100644
index d138c882cc..0000000000
--- a/.changeset/ninety-needles-brake.md
+++ /dev/null
@@ -1,5 +0,0 @@
----
-"shadcn": patch
----
-
-do not overwrite user defined vars
diff --git a/.changeset/orange-papayas-relax.md b/.changeset/orange-papayas-relax.md
deleted file mode 100644
index 56389409db..0000000000
--- a/.changeset/orange-papayas-relax.md
+++ /dev/null
@@ -1,5 +0,0 @@
----
-"shadcn": patch
----
-
-fix cn import bug in monorepo
diff --git a/.changeset/proud-snails-switch.md b/.changeset/proud-snails-switch.md
deleted file mode 100644
index 9aa3af62f7..0000000000
--- a/.changeset/proud-snails-switch.md
+++ /dev/null
@@ -1,5 +0,0 @@
----
-"shadcn": patch
----
-
-filter out deprecated from --all
diff --git a/.changeset/quiet-grapes-poke.md b/.changeset/quiet-grapes-poke.md
deleted file mode 100644
index c2edf88139..0000000000
--- a/.changeset/quiet-grapes-poke.md
+++ /dev/null
@@ -1,5 +0,0 @@
----
-"shadcn": minor
----
-
-add oklch base color
diff --git a/.changeset/serious-geese-reply.md b/.changeset/serious-geese-reply.md
deleted file mode 100644
index 0da0143c06..0000000000
--- a/.changeset/serious-geese-reply.md
+++ /dev/null
@@ -1,5 +0,0 @@
----
-"shadcn": minor
----
-
-hotswap style for v4
diff --git a/.changeset/shaggy-months-tease.md b/.changeset/shaggy-months-tease.md
deleted file mode 100644
index eb292424f7..0000000000
--- a/.changeset/shaggy-months-tease.md
+++ /dev/null
@@ -1,5 +0,0 @@
----
-"shadcn": patch
----
-
-check for empty css vars
diff --git a/.changeset/six-queens-argue.md b/.changeset/six-queens-argue.md
deleted file mode 100644
index a33549d53d..0000000000
--- a/.changeset/six-queens-argue.md
+++ /dev/null
@@ -1,5 +0,0 @@
----
-"shadcn": patch
----
-
-only show deprecated for new projects
diff --git a/.changeset/slow-tools-relax.md b/.changeset/slow-tools-relax.md
deleted file mode 100644
index 68f1588ab8..0000000000
--- a/.changeset/slow-tools-relax.md
+++ /dev/null
@@ -1,5 +0,0 @@
----
-"shadcn": minor
----
-
-add warning for deprecated components
diff --git a/.changeset/spotty-plants-juggle.md b/.changeset/spotty-plants-juggle.md
deleted file mode 100644
index 0474dc152d..0000000000
--- a/.changeset/spotty-plants-juggle.md
+++ /dev/null
@@ -1,5 +0,0 @@
----
-"shadcn": patch
----
-
-fix tanstack check
diff --git a/.changeset/tasty-walls-drum.md b/.changeset/tasty-walls-drum.md
deleted file mode 100644
index ea8d908288..0000000000
--- a/.changeset/tasty-walls-drum.md
+++ /dev/null
@@ -1,5 +0,0 @@
----
-"shadcn": minor
----
-
-add support for route install for react-router and laravel
diff --git a/.changeset/warm-fans-protect.md b/.changeset/warm-fans-protect.md
deleted file mode 100644
index 61465c5b05..0000000000
--- a/.changeset/warm-fans-protect.md
+++ /dev/null
@@ -1,5 +0,0 @@
----
-"shadcn": minor
----
-
-add theme prop to registry-item schema
diff --git a/apps/v4/package.json b/apps/v4/package.json
index 3d5019fb03..9cefbae84a 100644
--- a/apps/v4/package.json
+++ b/apps/v4/package.json
@@ -73,7 +73,7 @@
"react-resizable-panels": "^2.1.7",
"recharts": "2.15.1",
"rimraf": "^6.0.1",
- "shadcn": "2.3.0",
+ "shadcn": "2.5.0",
"sonner": "^2.0.0",
"tailwind-merge": "^3.0.1",
"tailwindcss": "^4.0.7",
diff --git a/apps/v4/registry.json b/apps/v4/registry.json
index b18af6c66d..473efd3f9e 100644
--- a/apps/v4/registry.json
+++ b/apps/v4/registry.json
@@ -6,10 +6,12 @@
"name": "index",
"type": "registry:style",
"dependencies": [
- "tw-animate-css",
"class-variance-authority",
"lucide-react"
],
+ "devDependencies": [
+ "tw-animate-css"
+ ],
"registryDependencies": [
"utils"
],
@@ -27,37 +29,7 @@
"path": "registry/new-york-v4/ui/accordion.tsx",
"type": "registry:ui"
}
- ],
- "tailwind": {
- "config": {
- "theme": {
- "extend": {
- "keyframes": {
- "accordion-down": {
- "from": {
- "height": "0"
- },
- "to": {
- "height": "var(--radix-accordion-content-height)"
- }
- },
- "accordion-up": {
- "from": {
- "height": "var(--radix-accordion-content-height)"
- },
- "to": {
- "height": "0"
- }
- }
- },
- "animation": {
- "accordion-down": "accordion-down 0.2s ease-out",
- "accordion-up": "accordion-up 0.2s ease-out"
- }
- }
- }
- }
- }
+ ]
},
{
"name": "alert",
diff --git a/apps/v4/scripts/build-registry.mts b/apps/v4/scripts/build-registry.mts
index e583049d62..29efbea274 100644
--- a/apps/v4/scripts/build-registry.mts
+++ b/apps/v4/scripts/build-registry.mts
@@ -20,11 +20,8 @@ const registry = {
{
name: "index",
type: "registry:style",
- dependencies: [
- "tw-animate-css",
- "class-variance-authority",
- "lucide-react",
- ],
+ dependencies: ["class-variance-authority", "lucide-react"],
+ devDependencies: ["tw-animate-css"],
registryDependencies: ["utils"],
cssVars: {},
files: [],
@@ -78,6 +75,11 @@ const registry = {
if (item.name === "dashboard-01") {
item.dependencies?.push("@tabler/icons-react")
}
+
+ if (item.name === "accordion" && "tailwind" in item) {
+ delete item.tailwind
+ }
+
return item
})
),
diff --git a/apps/www/app/(app)/themes/layout.tsx b/apps/www/app/(app)/themes/layout.tsx
index cbb27a03dd..e2763d3385 100644
--- a/apps/www/app/(app)/themes/layout.tsx
+++ b/apps/www/app/(app)/themes/layout.tsx
@@ -7,7 +7,8 @@ import {
PageHeaderDescription,
PageHeaderHeading,
} from "@/components/page-header"
-import { ThemeCustomizer } from "@/components/theme-customizer"
+import { Customizer } from "@/components/theme-customizer"
+import { Button } from "@/registry/new-york/ui/button"
const title = "Add colors. Make it yours."
const description =
@@ -48,10 +49,17 @@ export default function ThemesLayout({
{title}
{description}
-
-
-
+
+ New Theme Editor coming soon
+
+
diff --git a/apps/www/components/theme-customizer.tsx b/apps/www/components/theme-customizer.tsx
index a66a03d756..a454fb81b4 100644
--- a/apps/www/components/theme-customizer.tsx
+++ b/apps/www/components/theme-customizer.tsx
@@ -2,7 +2,7 @@
import * as React from "react"
import template from "lodash/template"
-import { Check, Copy, Moon, Repeat, Sun } from "lucide-react"
+import { Check, ClipboardIcon, Copy } from "lucide-react"
import { useTheme } from "next-themes"
import { cn } from "@/lib/utils"
@@ -21,6 +21,9 @@ import {
import {
Drawer,
DrawerContent,
+ DrawerDescription,
+ DrawerHeader,
+ DrawerTitle,
DrawerTrigger,
} from "@/registry/new-york/ui/drawer"
import { Label } from "@/registry/new-york/ui/label"
@@ -29,15 +32,28 @@ import {
PopoverContent,
PopoverTrigger,
} from "@/registry/new-york/ui/popover"
+import { Separator } from "@/registry/new-york/ui/separator"
import { Skeleton } from "@/registry/new-york/ui/skeleton"
import {
- Tooltip,
- TooltipContent,
- TooltipTrigger,
-} from "@/registry/new-york/ui/tooltip"
-import { BaseColor, baseColors } from "@/registry/registry-base-colors"
+ BaseColor,
+ baseColors,
+ baseColorsOKLCH,
+} from "@/registry/registry-base-colors"
import "@/styles/mdx.css"
+import { toast } from "sonner"
+
+import {
+ Tabs,
+ TabsContent,
+ TabsList,
+ TabsTrigger,
+} from "@/registry/new-york/ui/tabs"
+
+interface BaseColorOKLCH {
+ light: Record
+ dark: Record
+}
export function ThemeCustomizer() {
const [config, setConfig] = useConfig()
@@ -78,9 +94,9 @@ export function ThemeCustomizer() {
)
}
-function Customizer() {
+export function Customizer() {
const [mounted, setMounted] = React.useState(false)
- const { setTheme: setMode, resolvedTheme: mode } = useTheme()
+ const { resolvedTheme: mode } = useTheme()
const [config, setConfig] = useConfig()
React.useEffect(() => {
@@ -88,39 +104,11 @@ function Customizer() {
}, [])
return (
-
-
-
-
- Theme Customizer
-
-
- Customize your components colors.
-
-
-
-
-
-
-
-
+
+
+
+
+
{baseColors
.filter(
(theme) =>
@@ -131,7 +119,7 @@ function Customizer() {
return mounted ? (
) : (
-
+
)
})}
-
-
-
+
+
+
+
{["0", "0.3", "0.5", "0.75", "1.0"].map((value) => {
return (
-
-
-
- {mounted ? (
- <>
-
-
- >
- ) : (
- <>
-
-
- >
- )}
-
+
+
)
}
-function CopyCodeButton({
+export function CopyCodeButton({
className,
...props
}: React.ComponentProps
) {
- const [config] = useConfig()
- const activeTheme = baseColors.find((theme) => theme.name === config.theme)
- const [hasCopied, setHasCopied] = React.useState(false)
-
- React.useEffect(() => {
- setTimeout(() => {
- setHasCopied(false)
- }, 2000)
- }, [hasCopied])
-
return (
<>
- {activeTheme && (
-
- )}
+
+
+
+
+
+
+ Theme
+
+ Copy and paste the following code into your CSS file.
+
+
+
+
+
+
+
@@ -311,168 +253,269 @@ function CopyCodeButton({
function CustomizerCode() {
const [config] = useConfig()
- const activeTheme = baseColors.find((theme) => theme.name === config.theme)
+ const [hasCopied, setHasCopied] = React.useState(false)
+ const [themeVersion, setThemeVersion] = React.useState("v4")
+ const activeTheme = React.useMemo(
+ () => baseColors.find((theme) => theme.name === config.theme),
+ [config.theme]
+ )
+ const activeThemeOKLCH = React.useMemo(
+ () => baseColorsOKLCH[config.theme as keyof typeof baseColorsOKLCH],
+ [config.theme]
+ )
+
+ React.useEffect(() => {
+ if (hasCopied) {
+ setTimeout(() => {
+ setHasCopied(false)
+ }, 2000)
+ }
+ }, [hasCopied])
return (
-
-
-
- @layer base {
- :root {
-
- --background:{" "}
- {activeTheme?.cssVars.light["background"]};
-
-
- --foreground:{" "}
- {activeTheme?.cssVars.light["foreground"]};
-
- {[
- "card",
- "popover",
- "primary",
- "secondary",
- "muted",
- "accent",
- "destructive",
- ].map((prefix) => (
- <>
-
- --{prefix}:{" "}
- {
- activeTheme?.cssVars.light[
- prefix as keyof typeof activeTheme.cssVars.light
- ]
- }
- ;
-
-
- --{prefix}-foreground:{" "}
- {
- activeTheme?.cssVars.light[
- `${prefix}-foreground` as keyof typeof activeTheme.cssVars.light
- ]
- }
- ;
-
- >
- ))}
-
- --border:{" "}
- {activeTheme?.cssVars.light["border"]};
-
-
- --input:{" "}
- {activeTheme?.cssVars.light["input"]};
-
-
- --ring:{" "}
- {activeTheme?.cssVars.light["ring"]};
-
-
- --radius: {config.radius}rem;
-
- {["chart-1", "chart-2", "chart-3", "chart-4", "chart-5"].map(
- (prefix) => (
- <>
-
- --{prefix}:{" "}
- {
- activeTheme?.cssVars.light[
- prefix as keyof typeof activeTheme.cssVars.light
- ]
- }
- ;
-
- >
+
+
+
+ Tailwind v4
+ v3
+
+ {
+ copyToClipboardWithMeta(
+ themeVersion === "v3"
+ ? getThemeCode(activeTheme, config.radius)
+ : getThemeCodeOKLCH(activeThemeOKLCH, config.radius),
+ {
+ name: "copy_theme_code",
+ properties: {
+ theme: config.theme,
+ radius: config.radius,
+ },
+ }
)
- )}
- }
-
- .dark {
-
- --background:{" "}
- {activeTheme?.cssVars.dark["background"]};
-
-
- --foreground:{" "}
- {activeTheme?.cssVars.dark["foreground"]};
-
- {[
- "card",
- "popover",
- "primary",
- "secondary",
- "muted",
- "accent",
- "destructive",
- ].map((prefix) => (
- <>
+ setHasCopied(true)
+ }}
+ className="absolute right-0 top-0 shadow-none"
+ >
+ {hasCopied ? : }
+ Copy
+
+
+
+
+
+
+ :root {
- --{prefix}:{" "}
- {
- activeTheme?.cssVars.dark[
- prefix as keyof typeof activeTheme.cssVars.dark
- ]
- }
- ;
+ --radius: {config.radius}rem;
-
- --{prefix}-foreground:{" "}
- {
- activeTheme?.cssVars.dark[
- `${prefix}-foreground` as keyof typeof activeTheme.cssVars.dark
- ]
- }
- ;
-
- >
- ))}
-
- --border:{" "}
- {activeTheme?.cssVars.dark["border"]};
-
-
- --input:{" "}
- {activeTheme?.cssVars.dark["input"]};
-
-
- --ring:{" "}
- {activeTheme?.cssVars.dark["ring"]};
-
- {["chart-1", "chart-2", "chart-3", "chart-4", "chart-5"].map(
- (prefix) => (
- <>
-
- --{prefix}:{" "}
- {
- activeTheme?.cssVars.dark[
- prefix as keyof typeof activeTheme.cssVars.dark
- ]
- }
- ;
+ {Object.entries(activeThemeOKLCH?.light).map(([key, value]) => (
+
+ --{key}: {value};
- >
- )
- )}
- }
- }
-
-
-
+ ))}
+ }
+
+ .dark {
+ {Object.entries(activeThemeOKLCH?.dark).map(([key, value]) => (
+
+ --{key}: {value};
+
+ ))}
+ }
+
+
+
+
+
+
+
+
+ @layer base {
+
+ :root {
+
+
+ --background:{" "}
+ {activeTheme?.cssVars.light["background"]};
+
+
+ --foreground:{" "}
+ {activeTheme?.cssVars.light["foreground"]};
+
+ {[
+ "card",
+ "popover",
+ "primary",
+ "secondary",
+ "muted",
+ "accent",
+ "destructive",
+ ].map((prefix) => (
+ <>
+
+ --{prefix}:{" "}
+ {
+ activeTheme?.cssVars.light[
+ prefix as keyof typeof activeTheme.cssVars.light
+ ]
+ }
+ ;
+
+
+ --{prefix}-foreground:{" "}
+ {
+ activeTheme?.cssVars.light[
+ `${prefix}-foreground` as keyof typeof activeTheme.cssVars.light
+ ]
+ }
+ ;
+
+ >
+ ))}
+
+ --border:{" "}
+ {activeTheme?.cssVars.light["border"]};
+
+
+ --input:{" "}
+ {activeTheme?.cssVars.light["input"]};
+
+
+ --ring:{" "}
+ {activeTheme?.cssVars.light["ring"]};
+
+
+ --radius: {config.radius}rem;
+
+ {["chart-1", "chart-2", "chart-3", "chart-4", "chart-5"].map(
+ (prefix) => (
+ <>
+
+ --{prefix}:{" "}
+ {
+ activeTheme?.cssVars.light[
+ prefix as keyof typeof activeTheme.cssVars.light
+ ]
+ }
+ ;
+
+ >
+ )
+ )}
+ }
+
+
+ .dark {
+
+
+ --background:{" "}
+ {activeTheme?.cssVars.dark["background"]};
+
+
+ --foreground:{" "}
+ {activeTheme?.cssVars.dark["foreground"]};
+
+ {[
+ "card",
+ "popover",
+ "primary",
+ "secondary",
+ "muted",
+ "accent",
+ "destructive",
+ ].map((prefix) => (
+ <>
+
+ --{prefix}:{" "}
+ {
+ activeTheme?.cssVars.dark[
+ prefix as keyof typeof activeTheme.cssVars.dark
+ ]
+ }
+ ;
+
+
+ --{prefix}-foreground:{" "}
+ {
+ activeTheme?.cssVars.dark[
+ `${prefix}-foreground` as keyof typeof activeTheme.cssVars.dark
+ ]
+ }
+ ;
+
+ >
+ ))}
+
+ --border:{" "}
+ {activeTheme?.cssVars.dark["border"]};
+
+
+ --input:{" "}
+ {activeTheme?.cssVars.dark["input"]};
+
+
+ --ring:{" "}
+ {activeTheme?.cssVars.dark["ring"]};
+
+ {["chart-1", "chart-2", "chart-3", "chart-4", "chart-5"].map(
+ (prefix) => (
+ <>
+
+ --{prefix}:{" "}
+ {
+ activeTheme?.cssVars.dark[
+ prefix as keyof typeof activeTheme.cssVars.dark
+ ]
+ }
+ ;
+
+ >
+ )
+ )}
+ }
+ }
+
+
+
+
+
)
}
-function getThemeCode(theme: BaseColor, radius: number) {
+function getThemeCodeOKLCH(theme: BaseColorOKLCH | undefined, radius: number) {
+ if (!theme) {
+ return ""
+ }
+
+ const rootSection =
+ ":root {\n --radius: " +
+ radius +
+ "rem;\n" +
+ Object.entries(theme.light)
+ .map((entry) => " --" + entry[0] + ": " + entry[1] + ";")
+ .join("\n") +
+ "\n}\n\n.dark {\n" +
+ Object.entries(theme.dark)
+ .map((entry) => " --" + entry[0] + ": " + entry[1] + ";")
+ .join("\n") +
+ "\n}\n"
+
+ return rootSection
+}
+
+function getThemeCode(theme: BaseColor | undefined, radius: number) {
if (!theme) {
return ""
}
return template(BASE_STYLES_WITH_VARIABLES)({
colors: theme.cssVars,
- radius,
+ radius: radius.toString(),
})
}
diff --git a/apps/www/config/docs.ts b/apps/www/config/docs.ts
index e1352ed2b8..83e65611e8 100644
--- a/apps/www/config/docs.ts
+++ b/apps/www/config/docs.ts
@@ -433,6 +433,11 @@ export const docsConfig: DocsConfig = {
href: "/docs/registry/getting-started",
items: [],
},
+ {
+ title: "Examples",
+ href: "/docs/registry/examples",
+ items: [],
+ },
{
title: "Open in v0",
href: "/docs/registry/open-in-v0",
diff --git a/apps/www/content/docs/changelog.mdx b/apps/www/content/docs/changelog.mdx
index 1a30b1c151..622be8300f 100644
--- a/apps/www/content/docs/changelog.mdx
+++ b/apps/www/content/docs/changelog.mdx
@@ -321,7 +321,7 @@ I've been working on a new CLI for the past few weeks. It's a complete rewrite.
### `init`
```bash
-npx shadcn-ui@latest init
+npx shadcn@latest init
```
When you run the `init` command, you will be asked a few questions to configure `components.json`:
@@ -363,7 +363,7 @@ This means you can now use the CLI with any directory structure including `src`
### `add`
```bash
-npx shadcn-ui@latest add
+npx shadcn@latest add
```
The `add` command is now much more capable. You can now add UI components but also import more complex components (coming soon).
@@ -373,7 +373,7 @@ The CLI will automatically resolve all components and dependencies, format them
### `diff` (experimental)
```bash
-npx shadcn-ui diff
+npx shadcn diff
```
We're also introducing a new `diff` command to help you keep track of upstream updates.
@@ -383,7 +383,7 @@ You can use this command to see what has changed in the upstream repository and
Run the `diff` command to get a list of components that have updates available:
```bash
-npx shadcn-ui diff
+npx shadcn diff
```
```txt
@@ -398,7 +398,7 @@ The following components have updates available:
Then run `diff [component]` to see the changes:
```bash
-npx shadcn-ui diff alert
+npx shadcn diff alert
```
```diff /pl-12/
diff --git a/apps/www/content/docs/installation/gatsby.mdx b/apps/www/content/docs/installation/gatsby.mdx
index 030deb1e22..9b6dbf9ff2 100644
--- a/apps/www/content/docs/installation/gatsby.mdx
+++ b/apps/www/content/docs/installation/gatsby.mdx
@@ -79,7 +79,7 @@ export const onCreateWebpackConfig = ({ actions }) => {
### Run the CLI
-Run the `shadcn-ui` init command to setup your project:
+Run the `shadcn` init command to setup your project:
```bash
npx shadcn@latest init
diff --git a/apps/www/content/docs/installation/react-router.mdx b/apps/www/content/docs/installation/react-router.mdx
index 684a88432d..5493289d7d 100644
--- a/apps/www/content/docs/installation/react-router.mdx
+++ b/apps/www/content/docs/installation/react-router.mdx
@@ -13,7 +13,7 @@ npx create-react-router@latest my-app
### Run the CLI
-Run the `shadcn-ui` init command to setup your project:
+Run the `shadcn` init command to setup your project:
```bash
npx shadcn@latest init
diff --git a/apps/www/content/docs/installation/remix.mdx b/apps/www/content/docs/installation/remix.mdx
index 9b62feae47..dc60d2581a 100644
--- a/apps/www/content/docs/installation/remix.mdx
+++ b/apps/www/content/docs/installation/remix.mdx
@@ -26,7 +26,7 @@ npx create-remix@latest my-app
### Run the CLI
-Run the `shadcn-ui` init command to setup your project:
+Run the `shadcn` init command to setup your project:
```bash
npx shadcn@latest init
diff --git a/apps/www/content/docs/registry/examples.mdx b/apps/www/content/docs/registry/examples.mdx
new file mode 100644
index 0000000000..248fb55530
--- /dev/null
+++ b/apps/www/content/docs/registry/examples.mdx
@@ -0,0 +1,356 @@
+---
+title: Examples
+description: "Examples of registry items: styles, components, css vars, etc."
+---
+
+## registry:style
+
+### Custom style that extends shadcn/ui
+
+The following registry item is a custom style that extends shadcn/ui. On `npx shadcn init`, it will:
+
+- Install `@tabler/icons-react` as a dependency.
+- Add the `login-01` block and `calendar` component to the project.
+- Add the `editor` from a remote registry.
+- Set the `font-sans` variable to `Inter, sans-serif`.
+- Install a `brand` color in light and dark mode.
+
+```json title="example-style.json" showLineNumbers
+{
+ "$schema": "https://ui.shadcn.com/schema/registry-item.json",
+ "name": "example-style",
+ "type": "registry:style",
+ "dependencies": ["@tabler/icons-react"],
+ "registryDependencies": [
+ "login-01",
+ "calendar",
+ "https://example.com/r/editor.json"
+ ],
+ "cssVars": {
+ "theme": {
+ "font-sans": "Inter, sans-serif"
+ },
+ "light": {
+ "brand": "20 14.3% 4.1%"
+ },
+ "dark": {
+ "brand": "20 14.3% 4.1%"
+ }
+ }
+}
+```
+
+### Custom style from scratch
+
+The following registry item is a custom style that doesn't extend shadcn/ui. See the `extends: none` field.
+
+It can be used to create a new style from scratch i.e custom components, css vars, dependencies, etc.
+
+On `npx shadcn add`, the following will:
+
+- Install `tailwind-merge` and `clsx` as dependencies.
+- Add the `utils` registry item from the shadcn/ui registry.
+- Add the `button`, `input`, `label`, and `select` components from a remote registry.
+- Install new css vars: `main`, `bg`, `border`, `text`, `ring`.
+
+```json title="example-style.json" showLineNumbers
+{
+ "$schema": "https://ui.shadcn.com/schema/registry-item.json",
+ "extends": "none",
+ "name": "new-style",
+ "type": "registry:style",
+ "dependencies": ["tailwind-merge", "clsx"],
+ "registryDependencies": [
+ "utils",
+ "https://example.com/r/button.json",
+ "https://example.com/r/input.json",
+ "https://example.com/r/label.json",
+ "https://example.com/r/select.json"
+ ],
+ "cssVars": {
+ "theme": {
+ "font-sans": "Inter, sans-serif",
+ }
+ "light": {
+ "main": "#88aaee",
+ "bg": "#dfe5f2",
+ "border": "#000",
+ "text": "#000",
+ "ring": "#000",
+ },
+ "dark": {
+ "main": "#88aaee",
+ "bg": "#272933",
+ "border": "#000",
+ "text": "#e6e6e6",
+ "ring": "#fff",
+ }
+ }
+}
+```
+
+## registry:theme
+
+### Custom theme
+
+```json title="example-theme.json" showLineNumbers
+{
+ "$schema": "https://ui.shadcn.com/schema/registry-item.json",
+ "name": "custom-theme",
+ "type": "registry:theme",
+ "cssVars": {
+ "light": {
+ "background": "oklch(1 0 0)",
+ "foreground": "oklch(0.141 0.005 285.823)",
+ "primary": "oklch(0.546 0.245 262.881)",
+ "primary-foreground": "oklch(0.97 0.014 254.604)",
+ "ring": "oklch(0.746 0.16 232.661)",
+ "sidebar-primary": "oklch(0.546 0.245 262.881)",
+ "sidebar-primary-foreground": "oklch(0.97 0.014 254.604)",
+ "sidebar-ring": "oklch(0.746 0.16 232.661)"
+ },
+ "dark": {
+ "background": "oklch(1 0 0)",
+ "foreground": "oklch(0.141 0.005 285.823)",
+ "primary": "oklch(0.707 0.165 254.624)",
+ "primary-foreground": "oklch(0.97 0.014 254.604)",
+ "ring": "oklch(0.707 0.165 254.624)",
+ "sidebar-primary": "oklch(0.707 0.165 254.624)",
+ "sidebar-primary-foreground": "oklch(0.97 0.014 254.604)",
+ "sidebar-ring": "oklch(0.707 0.165 254.624)"
+ }
+ }
+}
+```
+
+### Custom colors
+
+The following style will init using shadcn/ui defaults and then add a custom `brand` color.
+
+```json title="example-style.json" showLineNumbers
+{
+ "$schema": "https://ui.shadcn.com/schema/registry-item.json",
+ "name": "custom-style",
+ "type": "registry:style",
+ "cssVars": {
+ "light": {
+ "brand": "oklch(0.99 0.00 0)"
+ },
+ "dark": {
+ "brand": "oklch(0.14 0.00 286)"
+ }
+ }
+}
+```
+
+## registry:block
+
+### Custom block
+
+This blocks installs the `login-01` block from the shadcn/ui registry.
+
+```json title="login-01.json" showLineNumbers
+{
+ "$schema": "https://ui.shadcn.com/schema/registry-item.json",
+ "name": "login-01",
+ "type": "registry:block",
+ "description": "A simple login form.",
+ "registryDependencies": ["button", "card", "input", "label"],
+ "files": [
+ {
+ "path": "blocks/login-01/page.tsx",
+ "content": "import { LoginForm } ...",
+ "type": "registry:page",
+ "target": "app/login/page.tsx"
+ },
+ {
+ "path": "blocks/login-01/components/login-form.tsx",
+ "content": "...",
+ "type": "registry:component"
+ }
+ ]
+}
+```
+
+### Install a block and override primitives
+
+You can install a block fromt the shadcn/ui registry and override the primitives using your custom ones.
+
+On `npx shadcn add`, the following will:
+
+- Add the `login-01` block from the shadcn/ui registry.
+- Override the `button`, `input`, and `label` primitives with the ones from the remote registry.
+
+```json title="example-style.json" showLineNumbers
+{
+ "$schema": "https://ui.shadcn.com/schema/registry-item.json",
+ "name": "custom-login",
+ "type": "registry:block",
+ "registryDependencies": [
+ "login-01",
+ "https://example.com/r/button.json",
+ "https://example.com/r/input.json",
+ "https://example.com/r/label.json"
+ ]
+}
+```
+
+## CSS Variables
+
+### Custom Theme Variables
+
+Add custom theme variables to the `theme` object.
+
+```json title="example-theme.json" showLineNumbers
+{
+ "$schema": "https://ui.shadcn.com/schema/registry-item.json",
+ "name": "custom-theme",
+ "type": "registry:theme",
+ "cssVars": {
+ "theme": {
+ "font-heading": "Inter, sans-serif",
+ "shadow-card": "0 0 0 1px rgba(0, 0, 0, 0.1)"
+ }
+ }
+}
+```
+
+### Override Tailwind CSS variables
+
+```json title="example-theme.json" showLineNumbers
+{
+ "$schema": "https://ui.shadcn.com/schema/registry-item.json",
+ "name": "custom-theme",
+ "type": "registry:theme",
+ "cssVars": {
+ "theme": {
+ "spacing": "0.2rem",
+ "breakpoint-sm": "640px",
+ "breakpoint-md": "768px",
+ "breakpoint-lg": "1024px",
+ "breakpoint-xl": "1280px",
+ "breakpoint-2xl": "1536px"
+ }
+ }
+}
+```
+
+## Add custom CSS
+
+### Base styles
+
+```json title="example-base.json" showLineNumbers
+{
+ "$schema": "https://ui.shadcn.com/schema/registry-item.json",
+ "name": "custom-style",
+ "type": "registry:style",
+ "css": {
+ "@layer base": {
+ "h1": {
+ "font-size": "var(--text-2xl)"
+ },
+ "h2": {
+ "font-size": "var(--text-xl)"
+ }
+ }
+ }
+}
+```
+
+### Components
+
+```json title="example-card.json" showLineNumbers
+{
+ "$schema": "https://ui.shadcn.com/schema/registry-item.json",
+ "name": "custom-card",
+ "type": "registry:component",
+ "css": {
+ "@layer components": {
+ "card": {
+ "background-color": "var(--color-white)",
+ "border-radius": "var(--rounded-lg)",
+ "padding": "var(--spacing-6)",
+ "box-shadow": "var(--shadow-xl)"
+ }
+ }
+ }
+}
+```
+
+## Add custom utilities
+
+### Simple utility
+
+```json title="example-component.json" showLineNumbers
+{
+ "$schema": "https://ui.shadcn.com/schema/registry-item.json",
+ "name": "custom-component",
+ "type": "registry:component",
+ "css": {
+ "@utility content-auto": {
+ "content-visibility": "auto"
+ }
+ }
+}
+```
+
+### Complex utility
+
+```json title="example-utility.json" showLineNumbers
+{
+ "$schema": "https://ui.shadcn.com/schema/registry-item.json",
+ "name": "custom-component",
+ "type": "registry:component",
+ "css": {
+ "@utility scrollbar-hidden": {
+ "scrollbar-hidden": {
+ "&::-webkit-scrollbar": {
+ "display": "none"
+ }
+ }
+ }
+ }
+}
+```
+
+### Functional utilities
+
+```json title="example-functional.json" showLineNumbers
+{
+ "$schema": "https://ui.shadcn.com/schema/registry-item.json",
+ "name": "custom-component",
+ "type": "registry:component",
+ "css": {
+ "@utility tab-*": {
+ "tab-size": "var(--tab-size-*)"
+ }
+ }
+}
+```
+
+## Add custom animations
+
+Note: you need to define both `@keyframes` in css and `theme` in cssVars to use animations.
+
+```json title="example-component.json" showLineNumbers
+{
+ "$schema": "https://ui.shadcn.com/schema/registry-item.json",
+ "name": "custom-component",
+ "type": "registry:component",
+ "cssVars": {
+ "theme": {
+ "--animate-wiggle": "wiggle 1s ease-in-out infinite"
+ }
+ },
+ "css": {
+ "@keyframes wiggle": {
+ "0%, 100%": {
+ "transform": "rotate(-3deg)"
+ },
+ "50%": {
+ "transform": "rotate(3deg)"
+ }
+ }
+ }
+}
+```
diff --git a/apps/www/content/docs/registry/registry-item-json.mdx b/apps/www/content/docs/registry/registry-item-json.mdx
index f736bc7d75..b8bf5acdec 100644
--- a/apps/www/content/docs/registry/registry-item-json.mdx
+++ b/apps/www/content/docs/registry/registry-item-json.mdx
@@ -36,6 +36,10 @@ The `registry-item.json` schema is used to define your custom registry items.
}
```
+
+ See more examples
+
+
## Definitions
You can see the JSON Schema for `registry-item.json` [here](https://ui.shadcn.com/schema/registry-item.json).
@@ -254,6 +258,41 @@ Use to define CSS variables for your registry item.
}
```
+### css
+
+Use `css` to add new rules to the project's CSS file eg. `@layer base`, `@layer components`, `@utility`, `@keyframes`, etc.
+
+```json title="registry-item.json" showLineNumbers
+{
+ "css": {
+ "@layer base": {
+ "body": {
+ "font-size": "var(--text-base)",
+ "line-height": "1.5"
+ }
+ },
+ "@layer components": {
+ "button": {
+ "background-color": "var(--color-primary)",
+ "color": "var(--color-white)"
+ }
+ },
+ "@utility text-magic": {
+ "font-size": "var(--text-base)",
+ "line-height": "1.5"
+ },
+ "@keyframes wiggle": {
+ "0%, 100%": {
+ "transform": "rotate(-3deg)"
+ },
+ "50%": {
+ "transform": "rotate(3deg)"
+ }
+ }
+ }
+}
+```
+
### docs
Use `docs` to show custom documentation or message when installing your registry item via the CLI.
diff --git a/apps/www/contentlayer.config.js b/apps/www/contentlayer.config.js
index 3394d28b28..147105797c 100644
--- a/apps/www/contentlayer.config.js
+++ b/apps/www/contentlayer.config.js
@@ -113,7 +113,7 @@ export default makeSource({
[
rehypePrettyCode,
{
- theme: "github-dark",
+ theme: "github-dark-default",
getHighlighter,
onVisitLine(node) {
// Prevent lines from collapsing in `display: grid` mode, and allow empty
diff --git a/apps/www/package.json b/apps/www/package.json
index 5863f8300e..1c7aa843bd 100644
--- a/apps/www/package.json
+++ b/apps/www/package.json
@@ -86,7 +86,7 @@
"react-resizable-panels": "^2.0.22",
"react-wrap-balancer": "^0.4.1",
"recharts": "2.12.7",
- "shadcn": "2.3.0",
+ "shadcn": "2.5.0",
"sharp": "^0.32.6",
"sonner": "^1.2.3",
"swr": "2.2.6-beta.3",
diff --git a/apps/www/public/r/styles/new-york-v4/accordion.json b/apps/www/public/r/styles/new-york-v4/accordion.json
index d5dae3ddba..2a03bbc62a 100644
--- a/apps/www/public/r/styles/new-york-v4/accordion.json
+++ b/apps/www/public/r/styles/new-york-v4/accordion.json
@@ -11,35 +11,5 @@
"content": "\"use client\"\n\nimport * as React from \"react\"\nimport * as AccordionPrimitive from \"@radix-ui/react-accordion\"\nimport { ChevronDownIcon } from \"lucide-react\"\n\nimport { cn } from \"@/lib/utils\"\n\nfunction Accordion({\n ...props\n}: React.ComponentProps) {\n return \n}\n\nfunction AccordionItem({\n className,\n ...props\n}: React.ComponentProps) {\n return (\n \n )\n}\n\nfunction AccordionTrigger({\n className,\n children,\n ...props\n}: React.ComponentProps) {\n return (\n \n svg]:rotate-180\",\n className\n )}\n {...props}\n >\n {children}\n \n \n \n )\n}\n\nfunction AccordionContent({\n className,\n children,\n ...props\n}: React.ComponentProps) {\n return (\n \n {children}
\n \n )\n}\n\nexport { Accordion, AccordionItem, AccordionTrigger, AccordionContent }\n",
"type": "registry:ui"
}
- ],
- "tailwind": {
- "config": {
- "theme": {
- "extend": {
- "keyframes": {
- "accordion-down": {
- "from": {
- "height": "0"
- },
- "to": {
- "height": "var(--radix-accordion-content-height)"
- }
- },
- "accordion-up": {
- "from": {
- "height": "var(--radix-accordion-content-height)"
- },
- "to": {
- "height": "0"
- }
- }
- },
- "animation": {
- "accordion-down": "accordion-down 0.2s ease-out",
- "accordion-up": "accordion-up 0.2s ease-out"
- }
- }
- }
- }
- }
+ ]
}
\ No newline at end of file
diff --git a/apps/www/public/r/styles/new-york-v4/index.json b/apps/www/public/r/styles/new-york-v4/index.json
index 8e85cbd881..3a8ab07687 100644
--- a/apps/www/public/r/styles/new-york-v4/index.json
+++ b/apps/www/public/r/styles/new-york-v4/index.json
@@ -3,10 +3,12 @@
"name": "index",
"type": "registry:style",
"dependencies": [
- "tw-animate-css",
"class-variance-authority",
"lucide-react"
],
+ "devDependencies": [
+ "tw-animate-css"
+ ],
"registryDependencies": [
"utils"
],
diff --git a/apps/www/public/schema/registry-item.json b/apps/www/public/schema/registry-item.json
index 16bb183b73..18e03d59bf 100644
--- a/apps/www/public/schema/registry-item.json
+++ b/apps/www/public/schema/registry-item.json
@@ -78,7 +78,8 @@
"registry:hook",
"registry:theme",
"registry:page",
- "registry:file"
+ "registry:file",
+ "registry:style"
],
"description": "The type of the file. This is used to determine the type of the file when resolved for a project."
},
@@ -156,6 +157,38 @@
}
}
},
+ "css": {
+ "type": "object",
+ "description": "CSS definitions to be added to the project's CSS file. Supports at-rules, selectors, nested rules, utilities, layers, and more.",
+ "additionalProperties": {
+ "oneOf": [
+ {
+ "type": "string",
+ "description": "Direct CSS string (e.g., 'font-family: sans-serif; line-height: 1.5;')"
+ },
+ {
+ "type": "object",
+ "description": "CSS properties or nested selectors",
+ "additionalProperties": {
+ "oneOf": [
+ {
+ "type": "string",
+ "description": "CSS property value (e.g., 'blue', 'var(--color-primary)')"
+ },
+ {
+ "type": "object",
+ "description": "Nested selector or rule with properties",
+ "additionalProperties": {
+ "type": "string",
+ "description": "CSS property value for nested rule"
+ }
+ }
+ ]
+ }
+ }
+ ]
+ }
+ },
"meta": {
"type": "object",
"description": "Additional metadata for the registry item. This is an object with any key value pairs.",
diff --git a/apps/www/registry/registry-base-colors.ts b/apps/www/registry/registry-base-colors.ts
index b3db7804ae..badbf61fa0 100644
--- a/apps/www/registry/registry-base-colors.ts
+++ b/apps/www/registry/registry-base-colors.ts
@@ -1102,3 +1102,550 @@ export const baseColorsV4 = {
},
},
} as const
+
+export const baseColorsOKLCH = {
+ zinc: {
+ light: {
+ background: "oklch(1 0 0)", // --color-zinc-50
+ foreground: "oklch(0.141 0.005 285.823)", // --color-zinc-950
+ card: "oklch(1 0 0)", // --color-zinc-50
+ "card-foreground": "oklch(0.141 0.005 285.823)", // --color-zinc-950
+ popover: "oklch(1 0 0)", // --color-zinc-50
+ "popover-foreground": "oklch(0.141 0.005 285.823)", // --color-zinc-950
+ primary: "oklch(0.21 0.006 285.885)", // --color-zinc-900
+ "primary-foreground": "oklch(0.985 0 0)", // --color-zinc-50
+ secondary: "oklch(0.967 0.001 286.375)", // --color-zinc-100
+ "secondary-foreground": "oklch(0.21 0.006 285.885)", // --color-zinc-900
+ muted: "oklch(0.967 0.001 286.375)", // --color-zinc-100
+ "muted-foreground": "oklch(0.552 0.016 285.938)", // --color-zinc-500
+ accent: "oklch(0.967 0.001 286.375)", // --color-zinc-100
+ "accent-foreground": "oklch(0.21 0.006 285.885)", // --color-zinc-900
+ destructive: "oklch(0.577 0.245 27.325)", // --color-red-600
+ border: "oklch(0.92 0.004 286.32)", // --color-zinc-200
+ input: "oklch(0.92 0.004 286.32)", // --color-zinc-200
+ ring: "oklch(0.705 0.015 286.067)", // --color-zinc-400
+ "chart-1": "oklch(0.646 0.222 41.116)", // --color-orange-600
+ "chart-2": "oklch(0.6 0.118 184.704)", // --color-teal-600
+ "chart-3": "oklch(0.398 0.07 227.392)", // --color-cyan-900
+ "chart-4": "oklch(0.828 0.189 84.429)", // --color-amber-400
+ "chart-5": "oklch(0.769 0.188 70.08)", // --color-amber-500
+ sidebar: "oklch(0.985 0 0)", // --color-zinc-50
+ "sidebar-foreground": "oklch(0.141 0.005 285.823)", // --color-zinc-950
+ "sidebar-primary": "oklch(0.21 0.006 285.885)", // --color-zinc-900
+ "sidebar-primary-foreground": "oklch(0.985 0 0)", // --color-zinc-50
+ "sidebar-accent": "oklch(0.967 0.001 286.375)", // --color-zinc-100
+ "sidebar-accent-foreground": "oklch(0.21 0.006 285.885)", // --color-zinc-900
+ "sidebar-border": "oklch(0.92 0.004 286.32)", // --color-zinc-200
+ "sidebar-ring": "oklch(0.705 0.015 286.067)", // --color-zinc-400
+ },
+ dark: {
+ background: "oklch(0.141 0.005 285.823)", // --color-zinc-950
+ foreground: "oklch(0.985 0 0)", // --color-zinc-50
+ card: "oklch(0.21 0.006 285.885)", // --color-zinc-900
+ "card-foreground": "oklch(0.985 0 0)", // --color-zinc-50
+ popover: "oklch(0.21 0.006 285.885)", // --color-zinc-900
+ "popover-foreground": "oklch(0.985 0 0)", // --color-zinc-50
+ primary: "oklch(0.92 0.004 286.32)", // --color-zinc-200
+ "primary-foreground": "oklch(0.21 0.006 285.885)", // --color-zinc-900
+ secondary: "oklch(0.274 0.006 286.033)", // --color-zinc-800
+ "secondary-foreground": "oklch(0.985 0 0)", // --color-zinc-50
+ muted: "oklch(0.274 0.006 286.033)", // --color-zinc-800
+ "muted-foreground": "oklch(0.705 0.015 286.067)", // --color-zinc-400
+ accent: "oklch(0.274 0.006 286.033)", // --color-zinc-800
+ "accent-foreground": "oklch(0.985 0 0)", // --color-zinc-50
+ destructive: "oklch(0.704 0.191 22.216)", // --color-red-400
+ border: "oklch(1 0 0 / 10%)", // --color-white
+ input: "oklch(1 0 0 / 15%)", // --color-white
+ ring: "oklch(0.552 0.016 285.938)", // --color-zinc-500
+ "chart-1": "oklch(0.488 0.243 264.376)", // --color-blue-700
+ "chart-2": "oklch(0.696 0.17 162.48)", // --color-emerald-500
+ "chart-3": "oklch(0.769 0.188 70.08)", // --color-amber-500
+ "chart-4": "oklch(0.627 0.265 303.9)", // --color-purple-500
+ "chart-5": "oklch(0.645 0.246 16.439)", // --color-rose-500
+ sidebar: "oklch(0.21 0.006 285.885)", // --color-zinc-900
+ "sidebar-foreground": "oklch(0.985 0 0)", // --color-zinc-50
+ "sidebar-primary": "oklch(0.488 0.243 264.376)", // --color-blue-700
+ "sidebar-primary-foreground": "oklch(0.985 0 0)", // --color-zinc-50
+ "sidebar-accent": "oklch(0.274 0.006 286.033)", // --color-zinc-800
+ "sidebar-accent-foreground": "oklch(0.985 0 0)", // --color-zinc-50
+ "sidebar-border": "oklch(1 0 0 / 10%)", // --color-white
+ "sidebar-ring": "oklch(0.552 0.016 285.938)", // --color-zinc-500
+ },
+ },
+ red: {
+ light: {
+ background: "oklch(1 0 0)", // --color-zinc-50 (from zinc)
+ foreground: "oklch(0.141 0.005 285.823)", // --color-zinc-950 (from zinc)
+ card: "oklch(1 0 0)", // --color-zinc-50 (from zinc)
+ "card-foreground": "oklch(0.141 0.005 285.823)", // --color-zinc-950 (from zinc)
+ popover: "oklch(1 0 0)", // --color-zinc-50 (from zinc)
+ "popover-foreground": "oklch(0.141 0.005 285.823)", // --color-zinc-950 (from zinc)
+ primary: "oklch(0.637 0.237 25.331)", // --color-red-500 (approx HSL 0 72.2% 50.6%)
+ "primary-foreground": "oklch(0.971 0.013 17.38)", // --color-red-50 (approx HSL 0 85.7% 97.3%)
+ secondary: "oklch(0.967 0.001 286.375)", // --color-zinc-100 (from zinc)
+ "secondary-foreground": "oklch(0.21 0.006 285.885)", // --color-zinc-900 (from zinc)
+ muted: "oklch(0.967 0.001 286.375)", // --color-zinc-100 (from zinc)
+ "muted-foreground": "oklch(0.552 0.016 285.938)", // --color-zinc-500 (from zinc)
+ accent: "oklch(0.967 0.001 286.375)", // --color-zinc-100 (from zinc)
+ "accent-foreground": "oklch(0.21 0.006 285.885)", // --color-zinc-900 (from zinc)
+ destructive: "oklch(0.577 0.245 27.325)", // --color-red-600 (from zinc)
+ border: "oklch(0.92 0.004 286.32)", // --color-zinc-200 (from zinc)
+ input: "oklch(0.92 0.004 286.32)", // --color-zinc-200 (from zinc)
+ ring: "oklch(0.637 0.237 25.331)", // --color-red-500 (approx HSL 0 72.2% 50.6%)
+ "chart-1": "oklch(0.646 0.222 41.116)", // --color-orange-600 (from zinc)
+ "chart-2": "oklch(0.6 0.118 184.704)", // --color-teal-600 (from zinc)
+ "chart-3": "oklch(0.398 0.07 227.392)", // --color-cyan-900 (from zinc)
+ "chart-4": "oklch(0.828 0.189 84.429)", // --color-amber-400 (from zinc)
+ "chart-5": "oklch(0.769 0.188 70.08)", // --color-amber-500 (from zinc)
+ sidebar: "oklch(0.985 0 0)", // --color-zinc-50 (from zinc)
+ "sidebar-foreground": "oklch(0.141 0.005 285.823)", // --color-zinc-950 (from zinc)
+ "sidebar-primary": "oklch(0.637 0.237 25.331)", // --color-red-500 (approx HSL 0 72.2% 50.6%)
+ "sidebar-primary-foreground": "oklch(0.971 0.013 17.38)", // --color-red-50 (approx HSL 0 85.7% 97.3%)
+ "sidebar-accent": "oklch(0.967 0.001 286.375)", // --color-zinc-100 (from zinc)
+ "sidebar-accent-foreground": "oklch(0.21 0.006 285.885)", // --color-zinc-900 (from zinc)
+ "sidebar-border": "oklch(0.92 0.004 286.32)", // --color-zinc-200 (from zinc)
+ "sidebar-ring": "oklch(0.637 0.237 25.331)", // --color-red-500 (approx HSL 0 72.2% 50.6%)
+ },
+ dark: {
+ background: "oklch(0.141 0.005 285.823)", // --color-zinc-950 (from zinc)
+ foreground: "oklch(0.985 0 0)", // --color-zinc-50 (from zinc)
+ card: "oklch(0.21 0.006 285.885)", // --color-zinc-900 (from zinc)
+ "card-foreground": "oklch(0.985 0 0)", // --color-zinc-50 (from zinc)
+ popover: "oklch(0.21 0.006 285.885)", // --color-zinc-900 (from zinc)
+ "popover-foreground": "oklch(0.985 0 0)", // --color-zinc-50 (from zinc)
+ primary: "oklch(0.637 0.237 25.331)", // --color-red-500 (approx HSL 0 72.2% 50.6%)
+ "primary-foreground": "oklch(0.971 0.013 17.38)", // --color-red-50 (approx HSL 0 85.7% 97.3%)
+ secondary: "oklch(0.274 0.006 286.033)", // --color-zinc-800 (from zinc)
+ "secondary-foreground": "oklch(0.985 0 0)", // --color-zinc-50 (from zinc)
+ muted: "oklch(0.274 0.006 286.033)", // --color-zinc-800 (from zinc)
+ "muted-foreground": "oklch(0.705 0.015 286.067)", // --color-zinc-400 (from zinc)
+ accent: "oklch(0.274 0.006 286.033)", // --color-zinc-800 (from zinc)
+ "accent-foreground": "oklch(0.985 0 0)", // --color-zinc-50 (from zinc)
+ destructive: "oklch(0.704 0.191 22.216)", // --color-red-400 (from zinc)
+ border: "oklch(1 0 0 / 10%)", // --color-white (from zinc)
+ input: "oklch(1 0 0 / 15%)", // --color-white (from zinc)
+ ring: "oklch(0.637 0.237 25.331)", // --color-red-500 (approx HSL 0 72.2% 50.6%)
+ "chart-1": "oklch(0.488 0.243 264.376)", // --color-blue-700 (from zinc)
+ "chart-2": "oklch(0.696 0.17 162.48)", // --color-emerald-500 (from zinc)
+ "chart-3": "oklch(0.769 0.188 70.08)", // --color-amber-500 (from zinc)
+ "chart-4": "oklch(0.627 0.265 303.9)", // --color-purple-500 (from zinc)
+ "chart-5": "oklch(0.645 0.246 16.439)", // --color-rose-500 (from zinc)
+ sidebar: "oklch(0.21 0.006 285.885)", // --color-zinc-900 (from zinc)
+ "sidebar-foreground": "oklch(0.985 0 0)", // --color-zinc-50 (from zinc)
+ "sidebar-primary": "oklch(0.637 0.237 25.331)", // --color-red-500 (approx HSL 0 72.2% 50.6%)
+ "sidebar-primary-foreground": "oklch(0.971 0.013 17.38)", // --color-red-50 (approx HSL 0 85.7% 97.3%)
+ "sidebar-accent": "oklch(0.274 0.006 286.033)", // --color-zinc-800 (from zinc)
+ "sidebar-accent-foreground": "oklch(0.985 0 0)", // --color-zinc-50 (from zinc)
+ "sidebar-border": "oklch(1 0 0 / 10%)", // --color-white (from zinc)
+ "sidebar-ring": "oklch(0.637 0.237 25.331)", // --color-red-500 (approx HSL 0 72.2% 50.6%)
+ },
+ },
+ rose: {
+ light: {
+ background: "oklch(1 0 0)", // --color-zinc-50 (from zinc)
+ foreground: "oklch(0.141 0.005 285.823)", // --color-zinc-950 (from zinc)
+ card: "oklch(1 0 0)", // --color-zinc-50 (from zinc)
+ "card-foreground": "oklch(0.141 0.005 285.823)", // --color-zinc-950 (from zinc)
+ popover: "oklch(1 0 0)", // --color-zinc-50 (from zinc)
+ "popover-foreground": "oklch(0.141 0.005 285.823)", // --color-zinc-950 (from zinc)
+ primary: "oklch(0.645 0.246 16.439)", // --color-rose-500 (approx HSL 346.8 77.2% 49.8%)
+ "primary-foreground": "oklch(0.969 0.015 12.422)", // --color-rose-50 (approx HSL 355.7 100% 97.3%)
+ secondary: "oklch(0.967 0.001 286.375)", // --color-zinc-100 (from zinc)
+ "secondary-foreground": "oklch(0.21 0.006 285.885)", // --color-zinc-900 (from zinc)
+ muted: "oklch(0.967 0.001 286.375)", // --color-zinc-100 (from zinc)
+ "muted-foreground": "oklch(0.552 0.016 285.938)", // --color-zinc-500 (from zinc)
+ accent: "oklch(0.967 0.001 286.375)", // --color-zinc-100 (from zinc)
+ "accent-foreground": "oklch(0.21 0.006 285.885)", // --color-zinc-900 (from zinc)
+ destructive: "oklch(0.577 0.245 27.325)", // --color-red-600 (from zinc)
+ border: "oklch(0.92 0.004 286.32)", // --color-zinc-200 (from zinc)
+ input: "oklch(0.92 0.004 286.32)", // --color-zinc-200 (from zinc)
+ ring: "oklch(0.645 0.246 16.439)", // --color-rose-500 (approx HSL 346.8 77.2% 49.8%)
+ "chart-1": "oklch(0.646 0.222 41.116)", // --color-orange-600 (from zinc)
+ "chart-2": "oklch(0.6 0.118 184.704)", // --color-teal-600 (from zinc)
+ "chart-3": "oklch(0.398 0.07 227.392)", // --color-cyan-900 (from zinc)
+ "chart-4": "oklch(0.828 0.189 84.429)", // --color-amber-400 (from zinc)
+ "chart-5": "oklch(0.769 0.188 70.08)", // --color-amber-500 (from zinc)
+ sidebar: "oklch(0.985 0 0)", // --color-zinc-50 (from zinc)
+ "sidebar-foreground": "oklch(0.141 0.005 285.823)", // --color-zinc-950 (from zinc)
+ "sidebar-primary": "oklch(0.645 0.246 16.439)", // --color-rose-500 (approx HSL 346.8 77.2% 49.8%)
+ "sidebar-primary-foreground": "oklch(0.969 0.015 12.422)", // --color-rose-50 (approx HSL 355.7 100% 97.3%)
+ "sidebar-accent": "oklch(0.967 0.001 286.375)", // --color-zinc-100 (from zinc)
+ "sidebar-accent-foreground": "oklch(0.21 0.006 285.885)", // --color-zinc-900 (from zinc)
+ "sidebar-border": "oklch(0.92 0.004 286.32)", // --color-zinc-200 (from zinc)
+ "sidebar-ring": "oklch(0.645 0.246 16.439)", // --color-rose-500 (approx HSL 346.8 77.2% 49.8%)
+ },
+ dark: {
+ background: "oklch(0.141 0.005 285.823)", // --color-zinc-950 (from zinc)
+ foreground: "oklch(0.985 0 0)", // --color-zinc-50 (from zinc)
+ card: "oklch(0.21 0.006 285.885)", // --color-zinc-900 (from zinc)
+ "card-foreground": "oklch(0.985 0 0)", // --color-zinc-50 (from zinc)
+ popover: "oklch(0.21 0.006 285.885)", // --color-zinc-900 (from zinc)
+ "popover-foreground": "oklch(0.985 0 0)", // --color-zinc-50 (from zinc)
+ primary: "oklch(0.645 0.246 16.439)", // --color-rose-500 (approx HSL 346.8 77.2% 49.8%)
+ "primary-foreground": "oklch(0.969 0.015 12.422)", // --color-rose-50 (approx HSL 355.7 100% 97.3%)
+ secondary: "oklch(0.274 0.006 286.033)", // --color-zinc-800 (from zinc)
+ "secondary-foreground": "oklch(0.985 0 0)", // --color-zinc-50 (from zinc)
+ muted: "oklch(0.274 0.006 286.033)", // --color-zinc-800 (from zinc)
+ "muted-foreground": "oklch(0.705 0.015 286.067)", // --color-zinc-400 (from zinc)
+ accent: "oklch(0.274 0.006 286.033)", // --color-zinc-800 (from zinc)
+ "accent-foreground": "oklch(0.985 0 0)", // --color-zinc-50 (from zinc)
+ destructive: "oklch(0.704 0.191 22.216)", // --color-red-400 (from zinc)
+ border: "oklch(1 0 0 / 10%)", // --color-white (from zinc)
+ input: "oklch(1 0 0 / 15%)", // --color-white (from zinc)
+ ring: "oklch(0.645 0.246 16.439)", // --color-rose-500 (approx HSL 346.8 77.2% 49.8%)
+ "chart-1": "oklch(0.488 0.243 264.376)", // --color-blue-700 (from zinc)
+ "chart-2": "oklch(0.696 0.17 162.48)", // --color-emerald-500 (from zinc)
+ "chart-3": "oklch(0.769 0.188 70.08)", // --color-amber-500 (from zinc)
+ "chart-4": "oklch(0.627 0.265 303.9)", // --color-purple-500 (from zinc)
+ "chart-5": "oklch(0.645 0.246 16.439)", // --color-rose-500 (from zinc)
+ sidebar: "oklch(0.21 0.006 285.885)", // --color-zinc-900 (from zinc)
+ "sidebar-foreground": "oklch(0.985 0 0)", // --color-zinc-50 (from zinc)
+ "sidebar-primary": "oklch(0.645 0.246 16.439)", // --color-rose-500 (approx HSL 346.8 77.2% 49.8%)
+ "sidebar-primary-foreground": "oklch(0.969 0.015 12.422)", // --color-rose-50 (approx HSL 355.7 100% 97.3%)
+ "sidebar-accent": "oklch(0.274 0.006 286.033)", // --color-zinc-800 (from zinc)
+ "sidebar-accent-foreground": "oklch(0.985 0 0)", // --color-zinc-50 (from zinc)
+ "sidebar-border": "oklch(1 0 0 / 10%)", // --color-white (from zinc)
+ "sidebar-ring": "oklch(0.645 0.246 16.439)", // --color-rose-500 (approx HSL 346.8 77.2% 49.8%)
+ },
+ },
+ orange: {
+ light: {
+ background: "oklch(1 0 0)", // --color-zinc-50 (from zinc)
+ foreground: "oklch(0.141 0.005 285.823)", // --color-zinc-950 (from zinc)
+ card: "oklch(1 0 0)", // --color-zinc-50 (from zinc)
+ "card-foreground": "oklch(0.141 0.005 285.823)", // --color-zinc-950 (from zinc)
+ popover: "oklch(1 0 0)", // --color-zinc-50 (from zinc)
+ "popover-foreground": "oklch(0.141 0.005 285.823)", // --color-zinc-950 (from zinc)
+ primary: "oklch(0.705 0.213 47.604)", // --color-orange-500 (approx HSL 24.6 95% 53.1%)
+ "primary-foreground": "oklch(0.98 0.016 73.684)", // --color-orange-50 (approx HSL 60 9.1% 97.8%)
+ secondary: "oklch(0.967 0.001 286.375)", // --color-zinc-100 (from zinc)
+ "secondary-foreground": "oklch(0.21 0.006 285.885)", // --color-zinc-900 (from zinc)
+ muted: "oklch(0.967 0.001 286.375)", // --color-zinc-100 (from zinc)
+ "muted-foreground": "oklch(0.552 0.016 285.938)", // --color-zinc-500 (from zinc)
+ accent: "oklch(0.967 0.001 286.375)", // --color-zinc-100 (from zinc)
+ "accent-foreground": "oklch(0.21 0.006 285.885)", // --color-zinc-900 (from zinc)
+ destructive: "oklch(0.577 0.245 27.325)", // --color-red-600 (from zinc)
+ border: "oklch(0.92 0.004 286.32)", // --color-zinc-200 (from zinc)
+ input: "oklch(0.92 0.004 286.32)", // --color-zinc-200 (from zinc)
+ ring: "oklch(0.705 0.213 47.604)", // --color-orange-500 (approx HSL 24.6 95% 53.1%)
+ "chart-1": "oklch(0.646 0.222 41.116)", // --color-orange-600 (from zinc)
+ "chart-2": "oklch(0.6 0.118 184.704)", // --color-teal-600 (from zinc)
+ "chart-3": "oklch(0.398 0.07 227.392)", // --color-cyan-900 (from zinc)
+ "chart-4": "oklch(0.828 0.189 84.429)", // --color-amber-400 (from zinc)
+ "chart-5": "oklch(0.769 0.188 70.08)", // --color-amber-500 (from zinc)
+ sidebar: "oklch(0.985 0 0)", // --color-zinc-50 (from zinc)
+ "sidebar-foreground": "oklch(0.141 0.005 285.823)", // --color-zinc-950 (from zinc)
+ "sidebar-primary": "oklch(0.705 0.213 47.604)", // --color-orange-500 (approx HSL 24.6 95% 53.1%)
+ "sidebar-primary-foreground": "oklch(0.98 0.016 73.684)", // --color-orange-50 (approx HSL 60 9.1% 97.8%)
+ "sidebar-accent": "oklch(0.967 0.001 286.375)", // --color-zinc-100 (from zinc)
+ "sidebar-accent-foreground": "oklch(0.21 0.006 285.885)", // --color-zinc-900 (from zinc)
+ "sidebar-border": "oklch(0.92 0.004 286.32)", // --color-zinc-200 (from zinc)
+ "sidebar-ring": "oklch(0.705 0.213 47.604)", // --color-orange-500 (approx HSL 24.6 95% 53.1%)
+ },
+ dark: {
+ background: "oklch(0.141 0.005 285.823)", // --color-zinc-950 (from zinc)
+ foreground: "oklch(0.985 0 0)", // --color-zinc-50 (from zinc)
+ card: "oklch(0.21 0.006 285.885)", // --color-zinc-900 (from zinc)
+ "card-foreground": "oklch(0.985 0 0)", // --color-zinc-50 (from zinc)
+ popover: "oklch(0.21 0.006 285.885)", // --color-zinc-900 (from zinc)
+ "popover-foreground": "oklch(0.985 0 0)", // --color-zinc-50 (from zinc)
+ primary: "oklch(0.646 0.222 41.116)", // --color-orange-600 (approx HSL 20.5 90.2% 48.2%)
+ "primary-foreground": "oklch(0.98 0.016 73.684)", // --color-orange-50 (approx HSL 60 9.1% 97.8%)
+ secondary: "oklch(0.274 0.006 286.033)", // --color-zinc-800 (from zinc)
+ "secondary-foreground": "oklch(0.985 0 0)", // --color-zinc-50 (from zinc)
+ muted: "oklch(0.274 0.006 286.033)", // --color-zinc-800 (from zinc)
+ "muted-foreground": "oklch(0.705 0.015 286.067)", // --color-zinc-400 (from zinc)
+ accent: "oklch(0.274 0.006 286.033)", // --color-zinc-800 (from zinc)
+ "accent-foreground": "oklch(0.985 0 0)", // --color-zinc-50 (from zinc)
+ destructive: "oklch(0.704 0.191 22.216)", // --color-red-400 (from zinc)
+ border: "oklch(1 0 0 / 10%)", // --color-white (from zinc)
+ input: "oklch(1 0 0 / 15%)", // --color-white (from zinc)
+ ring: "oklch(0.646 0.222 41.116)", // --color-orange-600 (approx HSL 20.5 90.2% 48.2%)
+ "chart-1": "oklch(0.488 0.243 264.376)", // --color-blue-700 (from zinc)
+ "chart-2": "oklch(0.696 0.17 162.48)", // --color-emerald-500 (from zinc)
+ "chart-3": "oklch(0.769 0.188 70.08)", // --color-amber-500 (from zinc)
+ "chart-4": "oklch(0.627 0.265 303.9)", // --color-purple-500 (from zinc)
+ "chart-5": "oklch(0.645 0.246 16.439)", // --color-rose-500 (from zinc)
+ sidebar: "oklch(0.21 0.006 285.885)", // --color-zinc-900 (from zinc)
+ "sidebar-foreground": "oklch(0.985 0 0)", // --color-zinc-50 (from zinc)
+ "sidebar-primary": "oklch(0.646 0.222 41.116)", // --color-orange-600 (approx HSL 20.5 90.2% 48.2%)
+ "sidebar-primary-foreground": "oklch(0.98 0.016 73.684)", // --color-orange-50 (approx HSL 60 9.1% 97.8%)
+ "sidebar-accent": "oklch(0.274 0.006 286.033)", // --color-zinc-800 (from zinc)
+ "sidebar-accent-foreground": "oklch(0.985 0 0)", // --color-zinc-50 (from zinc)
+ "sidebar-border": "oklch(1 0 0 / 10%)", // --color-white (from zinc)
+ "sidebar-ring": "oklch(0.646 0.222 41.116)", // --color-orange-600 (approx HSL 20.5 90.2% 48.2%)
+ },
+ },
+ green: {
+ light: {
+ background: "oklch(1 0 0)", // --color-zinc-50 (from zinc)
+ foreground: "oklch(0.141 0.005 285.823)", // --color-zinc-950 (from zinc)
+ card: "oklch(1 0 0)", // --color-zinc-50 (from zinc)
+ "card-foreground": "oklch(0.141 0.005 285.823)", // --color-zinc-950 (from zinc)
+ popover: "oklch(1 0 0)", // --color-zinc-50 (from zinc)
+ "popover-foreground": "oklch(0.141 0.005 285.823)", // --color-zinc-950 (from zinc)
+ primary: "oklch(0.723 0.219 149.579)", // --color-green-500 (approx HSL 142.1 76.2% 36.3%)
+ "primary-foreground": "oklch(0.982 0.018 155.826)", // --color-green-50 (approx HSL 355.7 100% 97.3%)
+ secondary: "oklch(0.967 0.001 286.375)", // --color-zinc-100 (from zinc)
+ "secondary-foreground": "oklch(0.21 0.006 285.885)", // --color-zinc-900 (from zinc)
+ muted: "oklch(0.967 0.001 286.375)", // --color-zinc-100 (from zinc)
+ "muted-foreground": "oklch(0.552 0.016 285.938)", // --color-zinc-500 (from zinc)
+ accent: "oklch(0.967 0.001 286.375)", // --color-zinc-100 (from zinc)
+ "accent-foreground": "oklch(0.21 0.006 285.885)", // --color-zinc-900 (from zinc)
+ destructive: "oklch(0.577 0.245 27.325)", // --color-red-600 (from zinc)
+ border: "oklch(0.92 0.004 286.32)", // --color-zinc-200 (from zinc)
+ input: "oklch(0.92 0.004 286.32)", // --color-zinc-200 (from zinc)
+ ring: "oklch(0.723 0.219 149.579)", // --color-green-500 (approx HSL 142.1 76.2% 36.3%)
+ "chart-1": "oklch(0.646 0.222 41.116)", // --color-orange-600 (from zinc)
+ "chart-2": "oklch(0.6 0.118 184.704)", // --color-teal-600 (from zinc)
+ "chart-3": "oklch(0.398 0.07 227.392)", // --color-cyan-900 (from zinc)
+ "chart-4": "oklch(0.828 0.189 84.429)", // --color-amber-400 (from zinc)
+ "chart-5": "oklch(0.769 0.188 70.08)", // --color-amber-500 (from zinc)
+ sidebar: "oklch(0.985 0 0)", // --color-zinc-50 (from zinc)
+ "sidebar-foreground": "oklch(0.141 0.005 285.823)", // --color-zinc-950 (from zinc)
+ "sidebar-primary": "oklch(0.723 0.219 149.579)", // --color-green-500 (approx HSL 142.1 76.2% 36.3%)
+ "sidebar-primary-foreground": "oklch(0.982 0.018 155.826)", // --color-green-50 (approx HSL 355.7 100% 97.3%)
+ "sidebar-accent": "oklch(0.967 0.001 286.375)", // --color-zinc-100 (from zinc)
+ "sidebar-accent-foreground": "oklch(0.21 0.006 285.885)", // --color-zinc-900 (from zinc)
+ "sidebar-border": "oklch(0.92 0.004 286.32)", // --color-zinc-200 (from zinc)
+ "sidebar-ring": "oklch(0.723 0.219 149.579)", // --color-green-500 (approx HSL 142.1 76.2% 36.3%)
+ },
+ dark: {
+ background: "oklch(0.141 0.005 285.823)", // --color-zinc-950 (from zinc)
+ foreground: "oklch(0.985 0 0)", // --color-zinc-50 (from zinc)
+ card: "oklch(0.21 0.006 285.885)", // --color-zinc-900 (from zinc)
+ "card-foreground": "oklch(0.985 0 0)", // --color-zinc-50 (from zinc)
+ popover: "oklch(0.21 0.006 285.885)", // --color-zinc-900 (from zinc)
+ "popover-foreground": "oklch(0.985 0 0)", // --color-zinc-50 (from zinc)
+ primary: "oklch(0.696 0.17 162.48)", // --color-emerald-500 (approx HSL 142.1 70.6% 45.3%)
+ "primary-foreground": "oklch(0.393 0.095 152.535)", // --color-green-900 (approx HSL 144.9 80.4% 10%)
+ secondary: "oklch(0.274 0.006 286.033)", // --color-zinc-800 (from zinc)
+ "secondary-foreground": "oklch(0.985 0 0)", // --color-zinc-50 (from zinc)
+ muted: "oklch(0.274 0.006 286.033)", // --color-zinc-800 (from zinc)
+ "muted-foreground": "oklch(0.705 0.015 286.067)", // --color-zinc-400 (from zinc)
+ accent: "oklch(0.274 0.006 286.033)", // --color-zinc-800 (from zinc)
+ "accent-foreground": "oklch(0.985 0 0)", // --color-zinc-50 (from zinc)
+ destructive: "oklch(0.704 0.191 22.216)", // --color-red-400 (from zinc)
+ border: "oklch(1 0 0 / 10%)", // --color-white (from zinc)
+ input: "oklch(1 0 0 / 15%)", // --color-white (from zinc)
+ ring: "oklch(0.527 0.154 150.069)", // --color-green-700 (approx HSL 142.4 71.8% 29.2%)
+ "chart-1": "oklch(0.488 0.243 264.376)", // --color-blue-700 (from zinc)
+ "chart-2": "oklch(0.696 0.17 162.48)", // --color-emerald-500 (from zinc)
+ "chart-3": "oklch(0.769 0.188 70.08)", // --color-amber-500 (from zinc)
+ "chart-4": "oklch(0.627 0.265 303.9)", // --color-purple-500 (from zinc)
+ "chart-5": "oklch(0.645 0.246 16.439)", // --color-rose-500 (from zinc)
+ sidebar: "oklch(0.21 0.006 285.885)", // --color-zinc-900 (from zinc)
+ "sidebar-foreground": "oklch(0.985 0 0)", // --color-zinc-50 (from zinc)
+ "sidebar-primary": "oklch(0.696 0.17 162.48)", // --color-emerald-500 (approx HSL 142.1 70.6% 45.3%)
+ "sidebar-primary-foreground": "oklch(0.393 0.095 152.535)", // --color-green-900 (approx HSL 144.9 80.4% 10%)
+ "sidebar-accent": "oklch(0.274 0.006 286.033)", // --color-zinc-800 (from zinc)
+ "sidebar-accent-foreground": "oklch(0.985 0 0)", // --color-zinc-50 (from zinc)
+ "sidebar-border": "oklch(1 0 0 / 10%)", // --color-white (from zinc)
+ "sidebar-ring": "oklch(0.527 0.154 150.069)", // --color-green-700 (approx HSL 142.4 71.8% 29.2%)
+ },
+ },
+ blue: {
+ light: {
+ background: "oklch(1 0 0)", // --color-zinc-50 (from zinc)
+ foreground: "oklch(0.141 0.005 285.823)", // --color-zinc-950 (from zinc)
+ card: "oklch(1 0 0)", // --color-zinc-50 (from zinc)
+ "card-foreground": "oklch(0.141 0.005 285.823)", // --color-zinc-950 (from zinc)
+ popover: "oklch(1 0 0)", // --color-zinc-50 (from zinc)
+ "popover-foreground": "oklch(0.141 0.005 285.823)", // --color-zinc-950 (from zinc)
+ primary: "oklch(0.623 0.214 259.815)", // --color-blue-500 (approx HSL 221.2 83.2% 53.3%)
+ "primary-foreground": "oklch(0.97 0.014 254.604)", // --color-blue-50 (approx HSL 210 40% 98%)
+ secondary: "oklch(0.967 0.001 286.375)", // --color-zinc-100 (from zinc)
+ "secondary-foreground": "oklch(0.21 0.006 285.885)", // --color-zinc-900 (from zinc)
+ muted: "oklch(0.967 0.001 286.375)", // --color-zinc-100 (from zinc)
+ "muted-foreground": "oklch(0.552 0.016 285.938)", // --color-zinc-500 (from zinc)
+ accent: "oklch(0.967 0.001 286.375)", // --color-zinc-100 (from zinc)
+ "accent-foreground": "oklch(0.21 0.006 285.885)", // --color-zinc-900 (from zinc)
+ destructive: "oklch(0.577 0.245 27.325)", // --color-red-600 (from zinc)
+ border: "oklch(0.92 0.004 286.32)", // --color-zinc-200 (from zinc)
+ input: "oklch(0.92 0.004 286.32)", // --color-zinc-200 (from zinc)
+ ring: "oklch(0.623 0.214 259.815)", // --color-blue-500 (approx HSL 221.2 83.2% 53.3%)
+ "chart-1": "oklch(0.646 0.222 41.116)", // --color-orange-600 (from zinc)
+ "chart-2": "oklch(0.6 0.118 184.704)", // --color-teal-600 (from zinc)
+ "chart-3": "oklch(0.398 0.07 227.392)", // --color-cyan-900 (from zinc)
+ "chart-4": "oklch(0.828 0.189 84.429)", // --color-amber-400 (from zinc)
+ "chart-5": "oklch(0.769 0.188 70.08)", // --color-amber-500 (from zinc)
+ sidebar: "oklch(0.985 0 0)", // --color-zinc-50 (from zinc)
+ "sidebar-foreground": "oklch(0.141 0.005 285.823)", // --color-zinc-950 (from zinc)
+ "sidebar-primary": "oklch(0.623 0.214 259.815)", // --color-blue-500 (approx HSL 221.2 83.2% 53.3%)
+ "sidebar-primary-foreground": "oklch(0.97 0.014 254.604)", // --color-blue-50 (approx HSL 210 40% 98%)
+ "sidebar-accent": "oklch(0.967 0.001 286.375)", // --color-zinc-100 (from zinc)
+ "sidebar-accent-foreground": "oklch(0.21 0.006 285.885)", // --color-zinc-900 (from zinc)
+ "sidebar-border": "oklch(0.92 0.004 286.32)", // --color-zinc-200 (from zinc)
+ "sidebar-ring": "oklch(0.623 0.214 259.815)", // --color-blue-500 (approx HSL 221.2 83.2% 53.3%)
+ },
+ dark: {
+ background: "oklch(0.141 0.005 285.823)", // --color-zinc-950 (from zinc)
+ foreground: "oklch(0.985 0 0)", // --color-zinc-50 (from zinc)
+ card: "oklch(0.21 0.006 285.885)", // --color-zinc-900 (from zinc)
+ "card-foreground": "oklch(0.985 0 0)", // --color-zinc-50 (from zinc)
+ popover: "oklch(0.21 0.006 285.885)", // --color-zinc-900 (from zinc)
+ "popover-foreground": "oklch(0.985 0 0)", // --color-zinc-50 (from zinc)
+ primary: "oklch(0.546 0.245 262.881)", // --color-blue-600 (approx HSL 217.2 91.2% 59.8%)
+ "primary-foreground": "oklch(0.379 0.146 265.522)", // --color-blue-900 (approx HSL 222.2 47.4% 11.2%)
+ secondary: "oklch(0.274 0.006 286.033)", // --color-zinc-800 (from zinc)
+ "secondary-foreground": "oklch(0.985 0 0)", // --color-zinc-50 (from zinc)
+ muted: "oklch(0.274 0.006 286.033)", // --color-zinc-800 (from zinc)
+ "muted-foreground": "oklch(0.705 0.015 286.067)", // --color-zinc-400 (from zinc)
+ accent: "oklch(0.274 0.006 286.033)", // --color-zinc-800 (from zinc)
+ "accent-foreground": "oklch(0.985 0 0)", // --color-zinc-50 (from zinc)
+ destructive: "oklch(0.704 0.191 22.216)", // --color-red-400 (from zinc)
+ border: "oklch(1 0 0 / 10%)", // --color-white (from zinc)
+ input: "oklch(1 0 0 / 15%)", // --color-white (from zinc)
+ ring: "oklch(0.488 0.243 264.376)", // --color-blue-700 (approx HSL 224.3 76.3% 48%)
+ "chart-1": "oklch(0.488 0.243 264.376)", // --color-blue-700 (from zinc)
+ "chart-2": "oklch(0.696 0.17 162.48)", // --color-emerald-500 (from zinc)
+ "chart-3": "oklch(0.769 0.188 70.08)", // --color-amber-500 (from zinc)
+ "chart-4": "oklch(0.627 0.265 303.9)", // --color-purple-500 (from zinc)
+ "chart-5": "oklch(0.645 0.246 16.439)", // --color-rose-500 (from zinc)
+ sidebar: "oklch(0.21 0.006 285.885)", // --color-zinc-900 (from zinc)
+ "sidebar-foreground": "oklch(0.985 0 0)", // --color-zinc-50 (from zinc)
+ "sidebar-primary": "oklch(0.546 0.245 262.881)", // --color-blue-600 (approx HSL 217.2 91.2% 59.8%)
+ "sidebar-primary-foreground": "oklch(0.379 0.146 265.522)", // --color-blue-900 (approx HSL 222.2 47.4% 11.2%)
+ "sidebar-accent": "oklch(0.274 0.006 286.033)", // --color-zinc-800 (from zinc)
+ "sidebar-accent-foreground": "oklch(0.985 0 0)", // --color-zinc-50 (from zinc)
+ "sidebar-border": "oklch(1 0 0 / 10%)", // --color-white (from zinc)
+ "sidebar-ring": "oklch(0.488 0.243 264.376)", // --color-blue-700 (approx HSL 224.3 76.3% 48%)
+ },
+ },
+ yellow: {
+ light: {
+ background: "oklch(1 0 0)", // --color-zinc-50 (from zinc)
+ foreground: "oklch(0.141 0.005 285.823)", // --color-zinc-950 (from zinc)
+ card: "oklch(1 0 0)", // --color-zinc-50 (from zinc)
+ "card-foreground": "oklch(0.141 0.005 285.823)", // --color-zinc-950 (from zinc)
+ popover: "oklch(1 0 0)", // --color-zinc-50 (from zinc)
+ "popover-foreground": "oklch(0.141 0.005 285.823)", // --color-zinc-950 (from zinc)
+ primary: "oklch(0.795 0.184 86.047)", // --color-yellow-500 (approx HSL 47.9 95.8% 53.1%)
+ "primary-foreground": "oklch(0.421 0.095 57.708)", // --color-yellow-900 (approx HSL 26 83.3% 14.1%)
+ secondary: "oklch(0.967 0.001 286.375)", // --color-zinc-100 (from zinc)
+ "secondary-foreground": "oklch(0.21 0.006 285.885)", // --color-zinc-900 (from zinc)
+ muted: "oklch(0.967 0.001 286.375)", // --color-zinc-100 (from zinc)
+ "muted-foreground": "oklch(0.552 0.016 285.938)", // --color-zinc-500 (from zinc)
+ accent: "oklch(0.967 0.001 286.375)", // --color-zinc-100 (from zinc)
+ "accent-foreground": "oklch(0.21 0.006 285.885)", // --color-zinc-900 (from zinc)
+ destructive: "oklch(0.577 0.245 27.325)", // --color-red-600 (from zinc)
+ border: "oklch(0.92 0.004 286.32)", // --color-zinc-200 (from zinc)
+ input: "oklch(0.92 0.004 286.32)", // --color-zinc-200 (from zinc)
+ ring: "oklch(0.795 0.184 86.047)", // --color-yellow-500 (approx HSL 47.9 95.8% 53.1%)
+ "chart-1": "oklch(0.646 0.222 41.116)", // --color-orange-600 (from zinc)
+ "chart-2": "oklch(0.6 0.118 184.704)", // --color-teal-600 (from zinc)
+ "chart-3": "oklch(0.398 0.07 227.392)", // --color-cyan-900 (from zinc)
+ "chart-4": "oklch(0.828 0.189 84.429)", // --color-amber-400 (from zinc)
+ "chart-5": "oklch(0.769 0.188 70.08)", // --color-amber-500 (from zinc)
+ sidebar: "oklch(0.985 0 0)", // --color-zinc-50 (from zinc)
+ "sidebar-foreground": "oklch(0.141 0.005 285.823)", // --color-zinc-950 (from zinc)
+ "sidebar-primary": "oklch(0.795 0.184 86.047)", // --color-yellow-500 (approx HSL 47.9 95.8% 53.1%)
+ "sidebar-primary-foreground": "oklch(0.421 0.095 57.708)", // --color-yellow-900 (approx HSL 26 83.3% 14.1%)
+ "sidebar-accent": "oklch(0.967 0.001 286.375)", // --color-zinc-100 (from zinc)
+ "sidebar-accent-foreground": "oklch(0.21 0.006 285.885)", // --color-zinc-900 (from zinc)
+ "sidebar-border": "oklch(0.92 0.004 286.32)", // --color-zinc-200 (from zinc)
+ "sidebar-ring": "oklch(0.795 0.184 86.047)", // --color-yellow-500 (approx HSL 47.9 95.8% 53.1%)
+ },
+ dark: {
+ background: "oklch(0.141 0.005 285.823)", // --color-zinc-950 (from zinc)
+ foreground: "oklch(0.985 0 0)", // --color-zinc-50 (from zinc)
+ card: "oklch(0.21 0.006 285.885)", // --color-zinc-900 (from zinc)
+ "card-foreground": "oklch(0.985 0 0)", // --color-zinc-50 (from zinc)
+ popover: "oklch(0.21 0.006 285.885)", // --color-zinc-900 (from zinc)
+ "popover-foreground": "oklch(0.985 0 0)", // --color-zinc-50 (from zinc)
+ primary: "oklch(0.795 0.184 86.047)", // --color-yellow-500 (approx HSL 47.9 95.8% 53.1%)
+ "primary-foreground": "oklch(0.421 0.095 57.708)", // --color-yellow-900 (approx HSL 26 83.3% 14.1%)
+ secondary: "oklch(0.274 0.006 286.033)", // --color-zinc-800 (from zinc)
+ "secondary-foreground": "oklch(0.985 0 0)", // --color-zinc-50 (from zinc)
+ muted: "oklch(0.274 0.006 286.033)", // --color-zinc-800 (from zinc)
+ "muted-foreground": "oklch(0.705 0.015 286.067)", // --color-zinc-400 (from zinc)
+ accent: "oklch(0.274 0.006 286.033)", // --color-zinc-800 (from zinc)
+ "accent-foreground": "oklch(0.985 0 0)", // --color-zinc-50 (from zinc)
+ destructive: "oklch(0.704 0.191 22.216)", // --color-red-400 (from zinc)
+ border: "oklch(1 0 0 / 10%)", // --color-white (from zinc)
+ input: "oklch(1 0 0 / 15%)", // --color-white (from zinc)
+ ring: "oklch(0.554 0.135 66.442)", // --color-yellow-700 (approx HSL 35.5 91.7% 32.9%)
+ "chart-1": "oklch(0.488 0.243 264.376)", // --color-blue-700 (from zinc)
+ "chart-2": "oklch(0.696 0.17 162.48)", // --color-emerald-500 (from zinc)
+ "chart-3": "oklch(0.769 0.188 70.08)", // --color-amber-500 (from zinc)
+ "chart-4": "oklch(0.627 0.265 303.9)", // --color-purple-500 (from zinc)
+ "chart-5": "oklch(0.645 0.246 16.439)", // --color-rose-500 (from zinc)
+ sidebar: "oklch(0.21 0.006 285.885)", // --color-zinc-900 (from zinc)
+ "sidebar-foreground": "oklch(0.985 0 0)", // --color-zinc-50 (from zinc)
+ "sidebar-primary": "oklch(0.795 0.184 86.047)", // --color-yellow-500 (approx HSL 47.9 95.8% 53.1%)
+ "sidebar-primary-foreground": "oklch(0.421 0.095 57.708)", // --color-yellow-900 (approx HSL 26 83.3% 14.1%)
+ "sidebar-accent": "oklch(0.274 0.006 286.033)", // --color-zinc-800 (from zinc)
+ "sidebar-accent-foreground": "oklch(0.985 0 0)", // --color-zinc-50 (from zinc)
+ "sidebar-border": "oklch(1 0 0 / 10%)", // --color-white (from zinc)
+ "sidebar-ring": "oklch(0.554 0.135 66.442)", // --color-yellow-700 (approx HSL 35.5 91.7% 32.9%)
+ },
+ },
+ violet: {
+ light: {
+ background: "oklch(1 0 0)", // --color-zinc-50 (from zinc)
+ foreground: "oklch(0.141 0.005 285.823)", // --color-zinc-950 (from zinc)
+ card: "oklch(1 0 0)", // --color-zinc-50 (from zinc)
+ "card-foreground": "oklch(0.141 0.005 285.823)", // --color-zinc-950 (from zinc)
+ popover: "oklch(1 0 0)", // --color-zinc-50 (from zinc)
+ "popover-foreground": "oklch(0.141 0.005 285.823)", // --color-zinc-950 (from zinc)
+ primary: "oklch(0.606 0.25 292.717)", // --color-violet-500 (approx HSL 262.1 83.3% 57.8%)
+ "primary-foreground": "oklch(0.969 0.016 293.756)", // --color-violet-50 (approx HSL 210 20% 98%)
+ secondary: "oklch(0.967 0.001 286.375)", // --color-zinc-100 (from zinc)
+ "secondary-foreground": "oklch(0.21 0.006 285.885)", // --color-zinc-900 (from zinc)
+ muted: "oklch(0.967 0.001 286.375)", // --color-zinc-100 (from zinc)
+ "muted-foreground": "oklch(0.552 0.016 285.938)", // --color-zinc-500 (from zinc)
+ accent: "oklch(0.967 0.001 286.375)", // --color-zinc-100 (from zinc)
+ "accent-foreground": "oklch(0.21 0.006 285.885)", // --color-zinc-900 (from zinc)
+ destructive: "oklch(0.577 0.245 27.325)", // --color-red-600 (from zinc)
+ border: "oklch(0.92 0.004 286.32)", // --color-zinc-200 (from zinc)
+ input: "oklch(0.92 0.004 286.32)", // --color-zinc-200 (from zinc)
+ ring: "oklch(0.606 0.25 292.717)", // --color-violet-500 (approx HSL 262.1 83.3% 57.8%)
+ "chart-1": "oklch(0.646 0.222 41.116)", // --color-orange-600 (from zinc)
+ "chart-2": "oklch(0.6 0.118 184.704)", // --color-teal-600 (from zinc)
+ "chart-3": "oklch(0.398 0.07 227.392)", // --color-cyan-900 (from zinc)
+ "chart-4": "oklch(0.828 0.189 84.429)", // --color-amber-400 (from zinc)
+ "chart-5": "oklch(0.769 0.188 70.08)", // --color-amber-500 (from zinc)
+ sidebar: "oklch(0.985 0 0)", // --color-zinc-50 (from zinc)
+ "sidebar-foreground": "oklch(0.141 0.005 285.823)", // --color-zinc-950 (from zinc)
+ "sidebar-primary": "oklch(0.606 0.25 292.717)", // --color-violet-500 (approx HSL 262.1 83.3% 57.8%)
+ "sidebar-primary-foreground": "oklch(0.969 0.016 293.756)", // --color-violet-50 (approx HSL 210 20% 98%)
+ "sidebar-accent": "oklch(0.967 0.001 286.375)", // --color-zinc-100 (from zinc)
+ "sidebar-accent-foreground": "oklch(0.21 0.006 285.885)", // --color-zinc-900 (from zinc)
+ "sidebar-border": "oklch(0.92 0.004 286.32)", // --color-zinc-200 (from zinc)
+ "sidebar-ring": "oklch(0.606 0.25 292.717)", // --color-violet-500 (approx HSL 262.1 83.3% 57.8%)
+ },
+ dark: {
+ background: "oklch(0.141 0.005 285.823)", // --color-zinc-950 (from zinc)
+ foreground: "oklch(0.985 0 0)", // --color-zinc-50 (from zinc)
+ card: "oklch(0.21 0.006 285.885)", // --color-zinc-900 (from zinc)
+ "card-foreground": "oklch(0.985 0 0)", // --color-zinc-50 (from zinc)
+ popover: "oklch(0.21 0.006 285.885)", // --color-zinc-900 (from zinc)
+ "popover-foreground": "oklch(0.985 0 0)", // --color-zinc-50 (from zinc)
+ primary: "oklch(0.541 0.281 293.009)", // --color-violet-600 (approx HSL 263.4 70% 50.4%)
+ "primary-foreground": "oklch(0.969 0.016 293.756)", // --color-violet-50 (approx HSL 210 20% 98%)
+ secondary: "oklch(0.274 0.006 286.033)", // --color-zinc-800 (from zinc)
+ "secondary-foreground": "oklch(0.985 0 0)", // --color-zinc-50 (from zinc)
+ muted: "oklch(0.274 0.006 286.033)", // --color-zinc-800 (from zinc)
+ "muted-foreground": "oklch(0.705 0.015 286.067)", // --color-zinc-400 (from zinc)
+ accent: "oklch(0.274 0.006 286.033)", // --color-zinc-800 (from zinc)
+ "accent-foreground": "oklch(0.985 0 0)", // --color-zinc-50 (from zinc)
+ destructive: "oklch(0.704 0.191 22.216)", // --color-red-400 (from zinc)
+ border: "oklch(1 0 0 / 10%)", // --color-white (from zinc)
+ input: "oklch(1 0 0 / 15%)", // --color-white (from zinc)
+ ring: "oklch(0.541 0.281 293.009)", // --color-violet-600 (approx HSL 263.4 70% 50.4%)
+ "chart-1": "oklch(0.488 0.243 264.376)", // --color-blue-700 (from zinc)
+ "chart-2": "oklch(0.696 0.17 162.48)", // --color-emerald-500 (from zinc)
+ "chart-3": "oklch(0.769 0.188 70.08)", // --color-amber-500 (from zinc)
+ "chart-4": "oklch(0.627 0.265 303.9)", // --color-purple-500 (from zinc)
+ "chart-5": "oklch(0.645 0.246 16.439)", // --color-rose-500 (from zinc)
+ sidebar: "oklch(0.21 0.006 285.885)", // --color-zinc-900 (from zinc)
+ "sidebar-foreground": "oklch(0.985 0 0)", // --color-zinc-50 (from zinc)
+ "sidebar-primary": "oklch(0.541 0.281 293.009)", // --color-violet-600 (approx HSL 263.4 70% 50.4%)
+ "sidebar-primary-foreground": "oklch(0.969 0.016 293.756)", // --color-violet-50 (approx HSL 210 20% 98%)
+ "sidebar-accent": "oklch(0.274 0.006 286.033)", // --color-zinc-800 (from zinc)
+ "sidebar-accent-foreground": "oklch(0.985 0 0)", // --color-zinc-50 (from zinc)
+ "sidebar-border": "oklch(1 0 0 / 10%)", // --color-white (from zinc)
+ "sidebar-ring": "oklch(0.541 0.281 293.009)", // --color-violet-600 (approx HSL 263.4 70% 50.4%)
+ },
+ },
+}
diff --git a/packages/shadcn/CHANGELOG.md b/packages/shadcn/CHANGELOG.md
index c34ed1ad65..d72d1e80ab 100644
--- a/packages/shadcn/CHANGELOG.md
+++ b/packages/shadcn/CHANGELOG.md
@@ -1,5 +1,81 @@
# @shadcn/ui
+## 2.5.0
+
+### Minor Changes
+
+- [#7220](https://github.com/shadcn-ui/ui/pull/7220) [`d0306774fe0ecc1eae9ef1e918bf7862e866a9e8`](https://github.com/shadcn-ui/ui/commit/d0306774fe0ecc1eae9ef1e918bf7862e866a9e8) Thanks [@shadcn](https://github.com/shadcn)! - resolve imports from anywhere
+
+### Patch Changes
+
+- [#6985](https://github.com/shadcn-ui/ui/pull/6985) [`f1e5cc4666ced2166a859660d769ccee16cde46e`](https://github.com/shadcn-ui/ui/commit/f1e5cc4666ced2166a859660d769ccee16cde46e) Thanks [@nrjdalal](https://github.com/nrjdalal)! - move tw-animate-css to devDependencies
+
+- [#6899](https://github.com/shadcn-ui/ui/pull/6899) [`6f702f5fbf2b82a388e7da6ea08bcc84c2ec19c6`](https://github.com/shadcn-ui/ui/commit/6f702f5fbf2b82a388e7da6ea08bcc84c2ec19c6) Thanks [@justjavac](https://github.com/justjavac)! - add deno support
+
+## 2.4.1
+
+### Patch Changes
+
+- [#7196](https://github.com/shadcn-ui/ui/pull/7196) [`617483fe9c26d607665fcaf79ee26e35d9825d7c`](https://github.com/shadcn-ui/ui/commit/617483fe9c26d607665fcaf79ee26e35d9825d7c) Thanks [@shadcn](https://github.com/shadcn)! - do not throw if empty dir
+
+## 2.4.0
+
+### Minor Changes
+
+- [#6507](https://github.com/shadcn-ui/ui/pull/6507) [`5234c46722750f964d69c92ccbef2c4d260c211d`](https://github.com/shadcn-ui/ui/commit/5234c46722750f964d69c92ccbef2c4d260c211d) Thanks [@shadcn](https://github.com/shadcn)! - add support for TanStack Start
+
+- [#6487](https://github.com/shadcn-ui/ui/pull/6487) [`5ef2bc5f455dfc394116267788c0514b696e13b0`](https://github.com/shadcn-ui/ui/commit/5ef2bc5f455dfc394116267788c0514b696e13b0) Thanks [@shadcn](https://github.com/shadcn)! - add theme vars support
+
+- [#6478](https://github.com/shadcn-ui/ui/pull/6478) [`8f6a64f176defdb1f9c493598d952fb4e9844cd0`](https://github.com/shadcn-ui/ui/commit/8f6a64f176defdb1f9c493598d952fb4e9844cd0) Thanks [@shadcn](https://github.com/shadcn)! - add tailwind version detection
+
+- [#6864](https://github.com/shadcn-ui/ui/pull/6864) [`19665adeeddc4ddb34e91fca219753d15bd46480`](https://github.com/shadcn-ui/ui/commit/19665adeeddc4ddb34e91fca219753d15bd46480) Thanks [@shadcn](https://github.com/shadcn)! - add --base-color flag
+
+- [#6490](https://github.com/shadcn-ui/ui/pull/6490) [`9a14c1d0925d3df2c8f57a3381d212cc3e54f4a6`](https://github.com/shadcn-ui/ui/commit/9a14c1d0925d3df2c8f57a3381d212cc3e54f4a6) Thanks [@shadcn](https://github.com/shadcn)! - add support for tailwind v4
+
+- [#6707](https://github.com/shadcn-ui/ui/pull/6707) [`3db8a07b3f132d396d7fb2e50da96156efcb4138`](https://github.com/shadcn-ui/ui/commit/3db8a07b3f132d396d7fb2e50da96156efcb4138) Thanks [@shadcn](https://github.com/shadcn)! - default to css vars. add --no-css-variables
+
+- [#6968](https://github.com/shadcn-ui/ui/pull/6968) [`205bfc637e093717908ebd2c591b215672950558`](https://github.com/shadcn-ui/ui/commit/205bfc637e093717908ebd2c591b215672950558) Thanks [@shadcn](https://github.com/shadcn)! - replace tailwindcss-animate with tw-animate-css
+
+- [#6574](https://github.com/shadcn-ui/ui/pull/6574) [`1e357cb20d6024b2bc9766fb15f61cb989eb7024`](https://github.com/shadcn-ui/ui/commit/1e357cb20d6024b2bc9766fb15f61cb989eb7024) Thanks [@shadcn](https://github.com/shadcn)! - default for new-york for v4
+
+- [#6515](https://github.com/shadcn-ui/ui/pull/6515) [`d1eb24e23a973646d78cf101fa1e0a22861ac9fd`](https://github.com/shadcn-ui/ui/commit/d1eb24e23a973646d78cf101fa1e0a22861ac9fd) Thanks [@shadcn](https://github.com/shadcn)! - fix handling of sidebar colors
+
+- [#6693](https://github.com/shadcn-ui/ui/pull/6693) [`3740373f99e39943514a45f5808ecb5f17faf700`](https://github.com/shadcn-ui/ui/commit/3740373f99e39943514a45f5808ecb5f17faf700) Thanks [@shadcn](https://github.com/shadcn)! - add oklch base color
+
+- [#6571](https://github.com/shadcn-ui/ui/pull/6571) [`c74a094f14a6e338124709547932dbb20c8d1324`](https://github.com/shadcn-ui/ui/commit/c74a094f14a6e338124709547932dbb20c8d1324) Thanks [@shadcn](https://github.com/shadcn)! - hotswap style for v4
+
+- [#6576](https://github.com/shadcn-ui/ui/pull/6576) [`9f4d65fc8fe72f632706fafd4036f63fd9317780`](https://github.com/shadcn-ui/ui/commit/9f4d65fc8fe72f632706fafd4036f63fd9317780) Thanks [@shadcn](https://github.com/shadcn)! - add warning for deprecated components
+
+- [#6811](https://github.com/shadcn-ui/ui/pull/6811) [`bc7df68620f242ce6aa640839c80ddc8afc7e091`](https://github.com/shadcn-ui/ui/commit/bc7df68620f242ce6aa640839c80ddc8afc7e091) Thanks [@shadcn](https://github.com/shadcn)! - add support for route install for react-router and laravel
+
+- [#7016](https://github.com/shadcn-ui/ui/pull/7016) [`b3b2fe2755e0ec1271c41a2a61b1a6933af42bc6`](https://github.com/shadcn-ui/ui/commit/b3b2fe2755e0ec1271c41a2a61b1a6933af42bc6) Thanks [@shadcn](https://github.com/shadcn)! - add theme prop to registry-item schema
+
+### Patch Changes
+
+- [#6724](https://github.com/shadcn-ui/ui/pull/6724) [`a3fe5074c1375cbd92e1ccdaab38d6808bfec696`](https://github.com/shadcn-ui/ui/commit/a3fe5074c1375cbd92e1ccdaab38d6808bfec696) Thanks [@Kaikaikaifang](https://github.com/Kaikaikaifang)! - support for version detection in monorepo
+
+- [#6414](https://github.com/shadcn-ui/ui/pull/6414) [`202131cd7bf8829b962ae4027545afbdfe79e688`](https://github.com/shadcn-ui/ui/commit/202131cd7bf8829b962ae4027545afbdfe79e688) Thanks [@palmithor](https://github.com/palmithor)! - upgrade @antfu/ni
+
+- [#6965](https://github.com/shadcn-ui/ui/pull/6965) [`69fc8e23cc0631aac6b708ba0481509f1125d3d7`](https://github.com/shadcn-ui/ui/commit/69fc8e23cc0631aac6b708ba0481509f1125d3d7) Thanks [@jherr](https://github.com/jherr)! - allow silent mode with npm
+
+- [#6814](https://github.com/shadcn-ui/ui/pull/6814) [`8539dd6eec948e7a6218c7ca3372d2b1f349d7c0`](https://github.com/shadcn-ui/ui/commit/8539dd6eec948e7a6218c7ca3372d2b1f349d7c0) Thanks [@shadcn](https://github.com/shadcn)! - do not add ring for v3
+
+- [#6732](https://github.com/shadcn-ui/ui/pull/6732) [`839afa714f61e2c0f83e9417354ea6ba8246c177`](https://github.com/shadcn-ui/ui/commit/839afa714f61e2c0f83e9417354ea6ba8246c177) Thanks [@shadcn](https://github.com/shadcn)! - cache registry calls
+
+- [#6863](https://github.com/shadcn-ui/ui/pull/6863) [`c16c58d0f9e672edddd554269fdd0eb0d412cb9d`](https://github.com/shadcn-ui/ui/commit/c16c58d0f9e672edddd554269fdd0eb0d412cb9d) Thanks [@shadcn](https://github.com/shadcn)! - add --template flag
+
+- [#6721](https://github.com/shadcn-ui/ui/pull/6721) [`a5122f9029c91963f493e7348ef7681dad4834e5`](https://github.com/shadcn-ui/ui/commit/a5122f9029c91963f493e7348ef7681dad4834e5) Thanks [@shadcn](https://github.com/shadcn)! - do not overwrite user defined vars
+
+- [#6530](https://github.com/shadcn-ui/ui/pull/6530) [`d6159023ed0817adf14b4398874b1f5f05a73b02`](https://github.com/shadcn-ui/ui/commit/d6159023ed0817adf14b4398874b1f5f05a73b02) Thanks [@zwarunek](https://github.com/zwarunek)! - fix cn import bug in monorepo
+
+- [#6617](https://github.com/shadcn-ui/ui/pull/6617) [`bd8533bd265de7765831d398f4db687483a0e53a`](https://github.com/shadcn-ui/ui/commit/bd8533bd265de7765831d398f4db687483a0e53a) Thanks [@shadcn](https://github.com/shadcn)! - filter out deprecated from --all
+
+- [#6733](https://github.com/shadcn-ui/ui/pull/6733) [`779517a1d46f567c8e3fa8fcdea4c75c65ad4eb4`](https://github.com/shadcn-ui/ui/commit/779517a1d46f567c8e3fa8fcdea4c75c65ad4eb4) Thanks [@shadcn](https://github.com/shadcn)! - check for empty css vars
+
+- [#6967](https://github.com/shadcn-ui/ui/pull/6967) [`9eae13639c10f0219872b5fd28f523a4c25f40df`](https://github.com/shadcn-ui/ui/commit/9eae13639c10f0219872b5fd28f523a4c25f40df) Thanks [@shadcn](https://github.com/shadcn)! - only show deprecated for new projects
+
+- [#6590](https://github.com/shadcn-ui/ui/pull/6590) [`16d4d38f564c75d4187977275f04d5999ee9e2f4`](https://github.com/shadcn-ui/ui/commit/16d4d38f564c75d4187977275f04d5999ee9e2f4) Thanks [@prateekkumarweb](https://github.com/prateekkumarweb)! - fix tanstack check
+
## 2.2.0
### Minor Changes
diff --git a/packages/shadcn/package.json b/packages/shadcn/package.json
index d76fef74aa..e2e0f9a9a9 100644
--- a/packages/shadcn/package.json
+++ b/packages/shadcn/package.json
@@ -1,6 +1,6 @@
{
"name": "shadcn",
- "version": "2.3.0",
+ "version": "2.5.0",
"description": "Add components to your apps.",
"publishConfig": {
"access": "public"
diff --git a/packages/shadcn/src/commands/add.ts b/packages/shadcn/src/commands/add.ts
index 049bb34c12..c9917da09c 100644
--- a/packages/shadcn/src/commands/add.ts
+++ b/packages/shadcn/src/commands/add.ts
@@ -1,7 +1,8 @@
import path from "path"
import { runInit } from "@/src/commands/init"
import { preFlightAdd } from "@/src/preflights/preflight-add"
-import { getRegistryIndex } from "@/src/registry/api"
+import { getRegistryIndex, getRegistryItem, isUrl } from "@/src/registry/api"
+import { registryItemTypeSchema } from "@/src/registry/schema"
import { addComponents } from "@/src/utils/add-components"
import { createProject } from "@/src/utils/create-project"
import * as ERRORS from "@/src/utils/errors"
@@ -78,23 +79,31 @@ export const add = new Command()
...opts,
})
- // Confirm if user is installing themes.
- // For now, we assume a theme is prefixed with "theme-".
- const isTheme = options.components?.some((component) =>
- component.includes("theme-")
- )
- if (!options.yes && isTheme) {
+ let itemType: z.infer | undefined
+
+ if (components.length > 0 && isUrl(components[0])) {
+ const item = await getRegistryItem(components[0], "")
+ itemType = item?.type
+ }
+
+ if (
+ !options.yes &&
+ (itemType === "registry:style" || itemType === "registry:theme")
+ ) {
logger.break()
const { confirm } = await prompts({
type: "confirm",
name: "confirm",
message: highlighter.warn(
- "You are about to install a new theme. \nExisting CSS variables will be overwritten. Continue?"
+ `You are about to install a new ${itemType.replace(
+ "registry:",
+ ""
+ )}. \nExisting CSS variables and components will be overwritten. Continue?`
),
})
if (!confirm) {
logger.break()
- logger.log("Theme installation cancelled.")
+ logger.log(`Installation cancelled.`)
logger.break()
process.exit(1)
}
diff --git a/packages/shadcn/src/commands/init.ts b/packages/shadcn/src/commands/init.ts
index 0171708c4e..068b8f94b7 100644
--- a/packages/shadcn/src/commands/init.ts
+++ b/packages/shadcn/src/commands/init.ts
@@ -6,6 +6,7 @@ import {
getRegistryBaseColors,
getRegistryItem,
getRegistryStyles,
+ isUrl,
} from "@/src/registry/api"
import { addComponents } from "@/src/utils/add-components"
import { TEMPLATES, createProject } from "@/src/utils/create-project"
@@ -127,13 +128,15 @@ export const init = new Command()
// We need to check if we're initializing with a new style.
// We fetch the payload of the first item.
// This is okay since the request is cached and deduped.
- const item = await getRegistryItem(components[0], "")
+ if (components.length > 0 && isUrl(components[0])) {
+ const item = await getRegistryItem(components[0], "")
- // Skip base color if style.
- // We set a default and let the style override it.
- if (item?.type === "registry:style") {
- options.baseColor = "neutral"
- options.style = item.extends ?? "index"
+ // Skip base color if style.
+ // We set a default and let the style override it.
+ if (item?.type === "registry:style") {
+ options.baseColor = "neutral"
+ options.style = item.extends ?? "index"
+ }
}
await runInit(options)
diff --git a/packages/shadcn/src/migrations/migrate-icons.ts b/packages/shadcn/src/migrations/migrate-icons.ts
index 91142c8446..343678ed49 100644
--- a/packages/shadcn/src/migrations/migrate-icons.ts
+++ b/packages/shadcn/src/migrations/migrate-icons.ts
@@ -98,7 +98,7 @@ export async function migrateIcons(config: Config) {
}
if (targetLibrary.package) {
- await updateDependencies([targetLibrary.package], config, {
+ await updateDependencies([targetLibrary.package], [], config, {
silent: false,
})
}
diff --git a/packages/shadcn/src/registry/api.ts b/packages/shadcn/src/registry/api.ts
index 3ead257724..c251599196 100644
--- a/packages/shadcn/src/registry/api.ts
+++ b/packages/shadcn/src/registry/api.ts
@@ -307,6 +307,11 @@ export async function registryResolveItemsTree(
cssVars = deepmerge(cssVars, item.cssVars ?? {})
})
+ let css = {}
+ payload.forEach((item) => {
+ css = deepmerge(css, item.css ?? {})
+ })
+
let docs = ""
payload.forEach((item) => {
if (item.docs) {
@@ -324,6 +329,7 @@ export async function registryResolveItemsTree(
files: deepmerge.all(payload.map((item) => item.files ?? [])),
tailwind,
cssVars,
+ css,
docs,
})
} catch (error) {
@@ -467,7 +473,7 @@ function getRegistryUrl(path: string) {
return `${REGISTRY_URL}/${path}`
}
-function isUrl(path: string) {
+export function isUrl(path: string) {
try {
new URL(path)
return true
diff --git a/packages/shadcn/src/registry/schema.ts b/packages/shadcn/src/registry/schema.ts
index 3d7c6c36e7..6b1af728a0 100644
--- a/packages/shadcn/src/registry/schema.ts
+++ b/packages/shadcn/src/registry/schema.ts
@@ -51,6 +51,19 @@ export const registryItemCssVarsSchema = z.object({
dark: z.record(z.string(), z.string()).optional(),
})
+export const registryItemCssSchema = z.record(
+ z.string(),
+ z.lazy(() =>
+ z.union([
+ z.string(),
+ z.record(
+ z.string(),
+ z.union([z.string(), z.record(z.string(), z.string())])
+ ),
+ ])
+ )
+)
+
export const registryItemSchema = z.object({
$schema: z.string().optional(),
extends: z.string().optional(),
@@ -65,6 +78,7 @@ export const registryItemSchema = z.object({
files: z.array(registryItemFileSchema).optional(),
tailwind: registryItemTailwindSchema.optional(),
cssVars: registryItemCssVarsSchema.optional(),
+ css: registryItemCssSchema.optional(),
meta: z.record(z.string(), z.any()).optional(),
docs: z.string().optional(),
categories: z.array(z.string()).optional(),
@@ -111,5 +125,6 @@ export const registryResolvedItemsTreeSchema = registryItemSchema.pick({
files: true,
tailwind: true,
cssVars: true,
+ css: true,
docs: true,
})
diff --git a/packages/shadcn/src/utils/add-components.ts b/packages/shadcn/src/utils/add-components.ts
index 033d5fe485..444776358b 100644
--- a/packages/shadcn/src/utils/add-components.ts
+++ b/packages/shadcn/src/utils/add-components.ts
@@ -19,6 +19,7 @@ import { getProjectTailwindVersionFromConfig } from "@/src/utils/get-project-inf
import { handleError } from "@/src/utils/handle-error"
import { logger } from "@/src/utils/logger"
import { spinner } from "@/src/utils/spinner"
+import { updateCss } from "@/src/utils/updaters/update-css"
import { updateCssVars } from "@/src/utils/updaters/update-css-vars"
import { updateDependencies } from "@/src/utils/updaters/update-dependencies"
import { updateFiles } from "@/src/utils/updaters/update-files"
@@ -97,7 +98,12 @@ async function addProjectComponents(
initIndex: options.style ? options.style === "index" : false,
})
- await updateDependencies(tree.dependencies, config, {
+ // Add CSS updater
+ await updateCss(tree.css, config, {
+ silent: options.silent,
+ })
+
+ await updateDependencies(tree.dependencies, tree.devDependencies, config, {
silent: options.silent,
})
await updateFiles(tree.files, config, {
@@ -196,12 +202,27 @@ async function addWorkspaceComponents(
)
}
- // 3. Update dependencies.
- await updateDependencies(component.dependencies, targetConfig, {
- silent: true,
- })
+ // 3. Update CSS
+ if (component.css) {
+ await updateCss(component.css, targetConfig, {
+ silent: true,
+ })
+ filesUpdated.push(
+ path.relative(workspaceRoot, targetConfig.resolvedPaths.tailwindCss)
+ )
+ }
- // 4. Update files.
+ // 4. Update dependencies.
+ await updateDependencies(
+ component.dependencies,
+ component.devDependencies,
+ targetConfig,
+ {
+ silent: true,
+ }
+ )
+
+ // 5. Update files.
const files = await updateFiles(component.files, targetConfig, {
overwrite: options.overwrite,
silent: true,
diff --git a/packages/shadcn/src/utils/get-project-info.ts b/packages/shadcn/src/utils/get-project-info.ts
index 6236b5138c..05f04df821 100644
--- a/packages/shadcn/src/utils/get-project-info.ts
+++ b/packages/shadcn/src/utils/get-project-info.ts
@@ -154,7 +154,7 @@ export async function getTailwindVersion(
cwd: string
): Promise {
const [packageInfo, config] = await Promise.all([
- getPackageInfo(cwd),
+ getPackageInfo(cwd, false),
getConfig(cwd),
])
diff --git a/packages/shadcn/src/utils/transformers/transform-tw-prefix.ts b/packages/shadcn/src/utils/transformers/transform-tw-prefix.ts
index 22559abf2b..a5178e8c5f 100644
--- a/packages/shadcn/src/utils/transformers/transform-tw-prefix.ts
+++ b/packages/shadcn/src/utils/transformers/transform-tw-prefix.ts
@@ -1,6 +1,10 @@
import { Transformer } from "@/src/utils/transformers"
import { SyntaxKind } from "ts-morph"
+import {
+ TailwindVersion,
+ getProjectTailwindVersionFromConfig,
+} from "../get-project-info"
import { splitClassName } from "./transform-css-vars"
export const transformTwPrefixes: Transformer = async ({
@@ -10,6 +14,7 @@ export const transformTwPrefixes: Transformer = async ({
if (!config.tailwind?.prefix) {
return sourceFile
}
+ const tailwindVersion = await getProjectTailwindVersionFromConfig(config)
// Find the cva function calls.
sourceFile
@@ -23,7 +28,8 @@ export const transformTwPrefixes: Transformer = async ({
defaultClassNames.replaceWithText(
`"${applyPrefix(
defaultClassNames.getText()?.replace(/"|'/g, ""),
- config.tailwind.prefix
+ config.tailwind.prefix,
+ tailwindVersion
)}"`
)
}
@@ -47,7 +53,8 @@ export const transformTwPrefixes: Transformer = async ({
classNames?.replaceWithText(
`"${applyPrefix(
classNames.getText()?.replace(/"|'/g, ""),
- config.tailwind.prefix
+ config.tailwind.prefix,
+ tailwindVersion
)}"`
)
}
@@ -66,7 +73,8 @@ export const transformTwPrefixes: Transformer = async ({
value.replaceWithText(
`"${applyPrefix(
value.getText()?.replace(/"|'/g, ""),
- config.tailwind.prefix
+ config.tailwind.prefix,
+ tailwindVersion
)}"`
)
}
@@ -92,7 +100,8 @@ export const transformTwPrefixes: Transformer = async ({
node.replaceWithText(
`"${applyPrefix(
node.getText()?.replace(/"|'/g, ""),
- config.tailwind.prefix
+ config.tailwind.prefix,
+ tailwindVersion
)}"`
)
})
@@ -102,7 +111,8 @@ export const transformTwPrefixes: Transformer = async ({
node.replaceWithText(
`"${applyPrefix(
node.getText()?.replace(/"|'/g, ""),
- config.tailwind.prefix
+ config.tailwind.prefix,
+ tailwindVersion
)}"`
)
}
@@ -131,7 +141,8 @@ export const transformTwPrefixes: Transformer = async ({
node.replaceWithText(
`"${applyPrefix(
node.getText()?.replace(/"|'/g, ""),
- config.tailwind.prefix
+ config.tailwind.prefix,
+ tailwindVersion
)}"`
)
})
@@ -141,7 +152,8 @@ export const transformTwPrefixes: Transformer = async ({
arg.replaceWithText(
`"${applyPrefix(
arg.getText()?.replace(/"|'/g, ""),
- config.tailwind.prefix
+ config.tailwind.prefix,
+ tailwindVersion
)}"`
)
}
@@ -156,7 +168,8 @@ export const transformTwPrefixes: Transformer = async ({
classNames.replaceWithText(
`"${applyPrefix(
classNames.getText()?.replace(/"|'/g, ""),
- config.tailwind.prefix
+ config.tailwind.prefix,
+ tailwindVersion
)}"`
)
}
@@ -170,30 +183,49 @@ export const transformTwPrefixes: Transformer = async ({
return sourceFile
}
-export function applyPrefix(input: string, prefix: string = "") {
- const classNames = input.split(" ")
- const prefixed: string[] = []
- for (let className of classNames) {
- const [variant, value, modifier] = splitClassName(className)
- if (variant) {
- modifier
- ? prefixed.push(`${variant}:${prefix}${value}/${modifier}`)
- : prefixed.push(`${variant}:${prefix}${value}`)
- } else {
- modifier
- ? prefixed.push(`${prefix}${value}/${modifier}`)
- : prefixed.push(`${prefix}${value}`)
- }
+export function applyPrefix(
+ input: string,
+ prefix: string = "",
+ tailwindVersion: TailwindVersion
+) {
+ if (tailwindVersion === "v3") {
+ return input
+ .split(" ")
+ .map((className) => {
+ const [variant, value, modifier] = splitClassName(className)
+ if (variant) {
+ return modifier
+ ? `${variant}:${prefix}${value}/${modifier}`
+ : `${variant}:${prefix}${value}`
+ } else {
+ return modifier
+ ? `${prefix}${value}/${modifier}`
+ : `${prefix}${value}`
+ }
+ })
+ .join(" ")
}
- return prefixed.join(" ")
+
+ return input
+ .split(" ")
+ .map((className) =>
+ className.indexOf(`${prefix}:`) === 0
+ ? className
+ : `${prefix}:${className.trim()}`
+ )
+ .join(" ")
}
-export function applyPrefixesCss(css: string, prefix: string) {
+export function applyPrefixesCss(
+ css: string,
+ prefix: string,
+ tailwindVersion: TailwindVersion
+) {
const lines = css.split("\n")
for (let line of lines) {
if (line.includes("@apply")) {
const originalTWCls = line.replace("@apply", "").trim()
- const prefixedTwCls = applyPrefix(originalTWCls, prefix)
+ const prefixedTwCls = applyPrefix(originalTWCls, prefix, tailwindVersion)
css = css.replace(originalTWCls, prefixedTwCls)
}
}
diff --git a/packages/shadcn/src/utils/updaters/update-css-vars.ts b/packages/shadcn/src/utils/updaters/update-css-vars.ts
index 81c588febe..00ca1a6ee1 100644
--- a/packages/shadcn/src/utils/updaters/update-css-vars.ts
+++ b/packages/shadcn/src/utils/updaters/update-css-vars.ts
@@ -45,7 +45,7 @@ export async function updateCssVars(
cssFilepath
)
const cssVarsSpinner = spinner(
- `Updating ${highlighter.info(cssFilepathRelative)}`,
+ `Updating CSS variables in ${highlighter.info(cssFilepathRelative)}`,
{
silent: options.silent,
}
diff --git a/packages/shadcn/src/utils/updaters/update-css.ts b/packages/shadcn/src/utils/updaters/update-css.ts
new file mode 100644
index 0000000000..7c64b7e68e
--- /dev/null
+++ b/packages/shadcn/src/utils/updaters/update-css.ts
@@ -0,0 +1,324 @@
+import { promises as fs } from "fs"
+import path from "path"
+import { registryItemCssSchema } from "@/src/registry/schema"
+import { Config } from "@/src/utils/get-config"
+import { highlighter } from "@/src/utils/highlighter"
+import { spinner } from "@/src/utils/spinner"
+import postcss from "postcss"
+import AtRule from "postcss/lib/at-rule"
+import Declaration from "postcss/lib/declaration"
+import Root from "postcss/lib/root"
+import Rule from "postcss/lib/rule"
+import { z } from "zod"
+
+export async function updateCss(
+ css: z.infer | undefined,
+ config: Config,
+ options: {
+ silent?: boolean
+ }
+) {
+ if (
+ !config.resolvedPaths.tailwindCss ||
+ !css ||
+ Object.keys(css).length === 0
+ ) {
+ return
+ }
+
+ options = {
+ silent: false,
+ ...options,
+ }
+
+ const cssFilepath = config.resolvedPaths.tailwindCss
+ const cssFilepathRelative = path.relative(
+ config.resolvedPaths.cwd,
+ cssFilepath
+ )
+ const cssSpinner = spinner(
+ `Updating ${highlighter.info(cssFilepathRelative)}`,
+ {
+ silent: options.silent,
+ }
+ ).start()
+
+ const raw = await fs.readFile(cssFilepath, "utf8")
+ let output = await transformCss(raw, css)
+ await fs.writeFile(cssFilepath, output, "utf8")
+ cssSpinner.succeed()
+}
+
+export async function transformCss(
+ input: string,
+ css: z.infer
+) {
+ const plugins = [updateCssPlugin(css)]
+
+ const result = await postcss(plugins).process(input, {
+ from: undefined,
+ })
+
+ let output = result.css
+ output = output.replace(/\/\* ---break--- \*\//g, "")
+ output = output.replace(/(\n\s*\n)+/g, "\n\n")
+ output = output.trimEnd()
+
+ return output
+}
+
+function updateCssPlugin(css: z.infer) {
+ return {
+ postcssPlugin: "update-css",
+ Once(root: Root) {
+ for (const [selector, properties] of Object.entries(css)) {
+ if (selector.startsWith("@")) {
+ // Handle at-rules (@layer, @utility, etc.)
+ const atRuleMatch = selector.match(/@([a-zA-Z-]+)\s*(.*)/)
+ if (!atRuleMatch) continue
+
+ const [, name, params] = atRuleMatch
+
+ // Special handling for keyframes - place them under @theme inline
+ if (name === "keyframes") {
+ let themeInline = root.nodes?.find(
+ (node): node is AtRule =>
+ node.type === "atrule" &&
+ node.name === "theme" &&
+ node.params === "inline"
+ ) as AtRule | undefined
+
+ if (!themeInline) {
+ themeInline = postcss.atRule({
+ name: "theme",
+ params: "inline",
+ raws: { semicolon: true, between: " ", before: "\n" },
+ })
+ root.append(themeInline)
+ root.insertBefore(
+ themeInline,
+ postcss.comment({ text: "---break---" })
+ )
+ }
+
+ const keyframesRule = postcss.atRule({
+ name: "keyframes",
+ params,
+ raws: { semicolon: true, between: " ", before: "\n " },
+ })
+
+ themeInline.append(keyframesRule)
+
+ if (typeof properties === "object") {
+ for (const [step, stepProps] of Object.entries(properties)) {
+ processRule(keyframesRule, step, stepProps)
+ }
+ }
+ }
+ // Special handling for utility classes to preserve property values
+ else if (name === "utility") {
+ const utilityAtRule = root.nodes?.find(
+ (node): node is AtRule =>
+ node.type === "atrule" &&
+ node.name === name &&
+ node.params === params
+ ) as AtRule | undefined
+
+ if (!utilityAtRule) {
+ const atRule = postcss.atRule({
+ name,
+ params,
+ raws: { semicolon: true, between: " ", before: "\n" },
+ })
+
+ root.append(atRule)
+ root.insertBefore(
+ atRule,
+ postcss.comment({ text: "---break---" })
+ )
+
+ // Add declarations with their values preserved
+ if (typeof properties === "object") {
+ for (const [prop, value] of Object.entries(properties)) {
+ if (typeof value === "string") {
+ const decl = postcss.decl({
+ prop,
+ value: value,
+ raws: { semicolon: true, before: "\n " },
+ })
+ atRule.append(decl)
+ } else if (typeof value === "object") {
+ processRule(atRule, prop, value)
+ }
+ }
+ }
+ } else {
+ // Update existing utility class
+ if (typeof properties === "object") {
+ for (const [prop, value] of Object.entries(properties)) {
+ if (typeof value === "string") {
+ const existingDecl = utilityAtRule.nodes?.find(
+ (node): node is Declaration =>
+ node.type === "decl" && node.prop === prop
+ )
+
+ const decl = postcss.decl({
+ prop,
+ value: value,
+ raws: { semicolon: true, before: "\n " },
+ })
+
+ existingDecl
+ ? existingDecl.replaceWith(decl)
+ : utilityAtRule.append(decl)
+ } else if (typeof value === "object") {
+ processRule(utilityAtRule, prop, value)
+ }
+ }
+ }
+ }
+ } else {
+ // Handle other at-rules normally
+ processAtRule(root, name, params, properties)
+ }
+ } else {
+ // Handle regular CSS rules
+ processRule(root, selector, properties)
+ }
+ }
+ },
+ }
+}
+
+function processAtRule(
+ root: Root | AtRule,
+ name: string,
+ params: string,
+ properties: any
+) {
+ // Find or create the at-rule
+ let atRule = root.nodes?.find(
+ (node): node is AtRule =>
+ node.type === "atrule" && node.name === name && node.params === params
+ ) as AtRule | undefined
+
+ if (!atRule) {
+ atRule = postcss.atRule({
+ name,
+ params,
+ raws: { semicolon: true, between: " ", before: "\n" },
+ })
+ root.append(atRule)
+ root.insertBefore(atRule, postcss.comment({ text: "---break---" }))
+ }
+
+ // Process children of this at-rule
+ if (typeof properties === "object") {
+ for (const [childSelector, childProps] of Object.entries(properties)) {
+ if (childSelector.startsWith("@")) {
+ // Nested at-rule
+ const nestedMatch = childSelector.match(/@([a-zA-Z-]+)\s*(.*)/)
+ if (nestedMatch) {
+ const [, nestedName, nestedParams] = nestedMatch
+ processAtRule(atRule, nestedName, nestedParams, childProps)
+ }
+ } else {
+ // CSS rule within at-rule
+ processRule(atRule, childSelector, childProps)
+ }
+ }
+ } else if (typeof properties === "string") {
+ // Direct string content for the at-rule
+ try {
+ // Parse the CSS string with PostCSS
+ const parsed = postcss.parse(`.temp{${properties}}`)
+ const tempRule = parsed.first as Rule
+
+ if (tempRule && tempRule.nodes) {
+ // Create a rule for the at-rule if needed
+ const rule = postcss.rule({
+ selector: "temp",
+ raws: { semicolon: true, between: " ", before: "\n " },
+ })
+
+ // Copy all declarations from the temp rule to our actual rule
+ tempRule.nodes.forEach((node) => {
+ if (node.type === "decl") {
+ const clone = node.clone()
+ clone.raws.before = "\n "
+ rule.append(clone)
+ }
+ })
+
+ // Only add the rule if it has declarations
+ if (rule.nodes?.length) {
+ atRule.append(rule)
+ }
+ }
+ } catch (error) {
+ console.error("Error parsing at-rule content:", properties, error)
+ throw error
+ }
+ }
+}
+
+function processRule(parent: Root | AtRule, selector: string, properties: any) {
+ let rule = parent.nodes?.find(
+ (node): node is Rule => node.type === "rule" && node.selector === selector
+ ) as Rule | undefined
+
+ if (!rule) {
+ rule = postcss.rule({
+ selector,
+ raws: { semicolon: true, between: " ", before: "\n " },
+ })
+ parent.append(rule)
+ }
+
+ if (typeof properties === "object") {
+ for (const [prop, value] of Object.entries(properties)) {
+ if (typeof value === "string") {
+ const decl = postcss.decl({
+ prop,
+ value: value,
+ raws: { semicolon: true, before: "\n " },
+ })
+
+ // Replace existing property or add new one
+ const existingDecl = rule.nodes?.find(
+ (node): node is Declaration =>
+ node.type === "decl" && node.prop === prop
+ )
+
+ existingDecl ? existingDecl.replaceWith(decl) : rule.append(decl)
+ } else if (typeof value === "object") {
+ // Nested selector (including & selectors)
+ const nestedSelector = prop.startsWith("&")
+ ? selector.replace(/^([^:]+)/, `$1${prop.substring(1)}`)
+ : prop // Use the original selector for other nested elements
+ processRule(parent, nestedSelector, value)
+ }
+ }
+ } else if (typeof properties === "string") {
+ // Direct string content for the rule
+ try {
+ // Parse the CSS string with PostCSS
+ const parsed = postcss.parse(`.temp{${properties}}`)
+ const tempRule = parsed.first as Rule
+
+ if (tempRule && tempRule.nodes) {
+ // Copy all declarations from the temp rule to our actual rule
+ tempRule.nodes.forEach((node) => {
+ if (node.type === "decl") {
+ const clone = node.clone()
+ clone.raws.before = "\n "
+ rule?.append(clone)
+ }
+ })
+ }
+ } catch (error) {
+ console.error("Error parsing rule content:", selector, properties, error)
+ throw error
+ }
+ }
+}
diff --git a/packages/shadcn/src/utils/updaters/update-dependencies.ts b/packages/shadcn/src/utils/updaters/update-dependencies.ts
index e4f0570f98..a12f9799be 100644
--- a/packages/shadcn/src/utils/updaters/update-dependencies.ts
+++ b/packages/shadcn/src/utils/updaters/update-dependencies.ts
@@ -9,13 +9,16 @@ import prompts from "prompts"
export async function updateDependencies(
dependencies: RegistryItem["dependencies"],
+ devDependencies: RegistryItem["devDependencies"],
config: Config,
options: {
silent?: boolean
}
) {
dependencies = Array.from(new Set(dependencies))
- if (!dependencies?.length) {
+ devDependencies = Array.from(new Set(devDependencies))
+
+ if (!dependencies?.length && !devDependencies?.length) {
return
}
@@ -59,23 +62,44 @@ export async function updateDependencies(
dependenciesSpinner?.start()
- await execa(
- packageManager,
- [
- packageManager === "npm" ? "install" : "add",
- ...(packageManager === "npm" && flag ? [`--${flag}`] : []),
- ...dependencies,
- ],
- {
- cwd: config.resolvedPaths.cwd,
- }
- )
+ if (dependencies?.length) {
+ await execa(
+ packageManager,
+ [
+ packageManager === "npm" ? "install" : "add",
+ ...(packageManager === "npm" && flag ? [`--${flag}`] : []),
+ ...(packageManager === "deno"
+ ? dependencies.map((dep) => `npm:${dep}`)
+ : dependencies),
+ ],
+ {
+ cwd: config.resolvedPaths.cwd,
+ }
+ )
+ }
+
+ if (devDependencies?.length) {
+ await execa(
+ packageManager,
+ [
+ packageManager === "npm" ? "install" : "add",
+ ...(packageManager === "npm" && flag ? [`--${flag}`] : []),
+ "-D",
+ ...(packageManager === "deno"
+ ? devDependencies.map((dep) => `npm:${dep}`)
+ : devDependencies),
+ ],
+ {
+ cwd: config.resolvedPaths.cwd,
+ }
+ )
+ }
dependenciesSpinner?.succeed()
}
function isUsingReact19(config: Config) {
- const packageInfo = getPackageInfo(config.resolvedPaths.cwd)
+ const packageInfo = getPackageInfo(config.resolvedPaths.cwd, false)
if (!packageInfo?.dependencies?.react) {
return false
diff --git a/packages/shadcn/src/utils/updaters/update-files.ts b/packages/shadcn/src/utils/updaters/update-files.ts
index 5ad751cbab..5aab4efde2 100644
--- a/packages/shadcn/src/utils/updaters/update-files.ts
+++ b/packages/shadcn/src/utils/updaters/update-files.ts
@@ -1,4 +1,5 @@
import { existsSync, promises as fs } from "fs"
+import { tmpdir } from "os"
import path, { basename } from "path"
import { getRegistryBaseColor } from "@/src/registry/api"
import { RegistryItem, registryItemFileSchema } from "@/src/registry/schema"
@@ -6,6 +7,7 @@ import { Config } from "@/src/utils/get-config"
import { ProjectInfo, getProjectInfo } from "@/src/utils/get-project-info"
import { highlighter } from "@/src/utils/highlighter"
import { logger } from "@/src/utils/logger"
+import { resolveImport } from "@/src/utils/resolve-import"
import { spinner } from "@/src/utils/spinner"
import { transform } from "@/src/utils/transformers"
import { transformCssVars } from "@/src/utils/transformers/transform-css-vars"
@@ -14,6 +16,8 @@ import { transformImport } from "@/src/utils/transformers/transform-import"
import { transformRsc } from "@/src/utils/transformers/transform-rsc"
import { transformTwPrefixes } from "@/src/utils/transformers/transform-tw-prefix"
import prompts from "prompts"
+import { Project, ScriptKind } from "ts-morph"
+import { loadConfig } from "tsconfig-paths"
import { z } from "zod"
export async function updateFiles(
@@ -50,9 +54,9 @@ export async function updateFiles(
getRegistryBaseColor(config.tailwind.baseColor),
])
- const filesCreated = []
- const filesUpdated = []
- const filesSkipped = []
+ let filesCreated: string[] = []
+ let filesUpdated: string[] = []
+ let filesSkipped: string[] = []
for (const file of files) {
if (!file.content) {
@@ -153,11 +157,25 @@ export async function updateFiles(
: filesCreated.push(path.relative(config.resolvedPaths.cwd, filePath))
}
+ const allFiles = [...filesCreated, ...filesUpdated, ...filesSkipped]
+ const updatedFiles = await resolveImports(allFiles, config)
+
+ // Let's update filesUpdated with the updated files.
+ filesUpdated.push(...updatedFiles)
+
+ // If a file is in filesCreated and filesUpdated, we should remove it from filesUpdated.
+ filesUpdated = filesUpdated.filter((file) => !filesCreated.includes(file))
+
const hasUpdatedFiles = filesCreated.length || filesUpdated.length
if (!hasUpdatedFiles && !filesSkipped.length) {
filesCreatedSpinner?.info("No files updated.")
}
+ // Remove duplicates.
+ filesCreated = Array.from(new Set(filesCreated))
+ filesUpdated = Array.from(new Set(filesUpdated))
+ filesSkipped = Array.from(new Set(filesSkipped))
+
if (filesCreated.length) {
filesCreatedSpinner?.succeed(
`Created ${filesCreated.length} ${
@@ -371,3 +389,227 @@ export function resolvePageTarget(
return ""
}
+
+async function resolveImports(filePaths: string[], config: Config) {
+ const project = new Project({
+ compilerOptions: {},
+ })
+ const projectInfo = await getProjectInfo(config.resolvedPaths.cwd)
+ const tsConfig = await loadConfig(config.resolvedPaths.cwd)
+ const updatedFiles = []
+
+ if (!projectInfo || tsConfig.resultType === "failed") {
+ return []
+ }
+
+ for (const filepath of filePaths) {
+ const resolvedPath = path.resolve(config.resolvedPaths.cwd, filepath)
+
+ // Check if the file exists.
+ if (!existsSync(resolvedPath)) {
+ continue
+ }
+
+ const content = await fs.readFile(resolvedPath, "utf-8")
+
+ const dir = await fs.mkdtemp(path.join(tmpdir(), "shadcn-"))
+ const sourceFile = project.createSourceFile(
+ path.join(dir, basename(resolvedPath)),
+ content,
+ {
+ scriptKind: ScriptKind.TSX,
+ }
+ )
+
+ const importDeclarations = sourceFile.getImportDeclarations()
+ for (const importDeclaration of importDeclarations) {
+ const moduleSpecifier = importDeclaration.getModuleSpecifierValue()
+
+ // Filter out non-local imports.
+ if (
+ projectInfo?.aliasPrefix &&
+ !moduleSpecifier.startsWith(`${projectInfo.aliasPrefix}/`)
+ ) {
+ continue
+ }
+
+ // Find the probable import file path.
+ // This is where we expect to find the file on disk.
+ const probableImportFilePath = await resolveImport(
+ moduleSpecifier,
+ tsConfig
+ )
+
+ if (!probableImportFilePath) {
+ continue
+ }
+
+ // Find the actual import file path.
+ // This is the path where the file has been installed.
+ const resolvedImportFilePath = resolveModuleByProbablePath(
+ probableImportFilePath,
+ filePaths,
+ config
+ )
+
+ if (!resolvedImportFilePath) {
+ continue
+ }
+
+ // Convert the resolved import file path to an aliased import.
+ const newImport = toAliasedImport(
+ resolvedImportFilePath,
+ config,
+ projectInfo
+ )
+
+ if (!newImport || newImport === moduleSpecifier) {
+ continue
+ }
+
+ importDeclaration.setModuleSpecifier(newImport)
+
+ // Write the updated content to the file.
+ await fs.writeFile(resolvedPath, sourceFile.getFullText(), "utf-8")
+
+ // Track the updated file.
+ updatedFiles.push(filepath)
+ }
+ }
+
+ return updatedFiles
+}
+
+/**
+ * Given an absolute "probable" import path (no ext),
+ * plus an array of absolute file paths you already know about,
+ * return 0–N matches (best match first), and also check disk for any missing ones.
+ */
+export function resolveModuleByProbablePath(
+ probableImportFilePath: string,
+ files: string[],
+ config: Config,
+ extensions: string[] = [".tsx", ".ts", ".js", ".jsx", ".css"]
+) {
+ const cwd = path.normalize(config.resolvedPaths.cwd)
+
+ // 1) Build a set of POSIX-normalized, project-relative files
+ const relativeFiles = files.map((f) => f.split(path.sep).join(path.posix.sep))
+ const fileSet = new Set(relativeFiles)
+
+ // 2) Strip any existing extension off the absolute base path
+ const extInPath = path.extname(probableImportFilePath)
+ const hasExt = extInPath !== ""
+ const absBase = hasExt
+ ? probableImportFilePath.slice(0, -extInPath.length)
+ : probableImportFilePath
+
+ // 3) Compute the project-relative "base" directory for strong matching
+ const relBaseRaw = path.relative(cwd, absBase)
+ const relBase = relBaseRaw.split(path.sep).join(path.posix.sep)
+
+ // 4) Decide which extensions to try
+ const tryExts = hasExt ? [extInPath] : extensions
+
+ // 5) Collect candidates
+ const candidates = new Set()
+
+ // 5a) Fast‑path: [base + ext] and [base/index + ext]
+ for (const e of tryExts) {
+ const absCand = absBase + e
+ const relCand = path.posix.normalize(path.relative(cwd, absCand))
+ if (fileSet.has(relCand) || existsSync(absCand)) {
+ candidates.add(relCand)
+ }
+
+ const absIdx = path.join(absBase, `index${e}`)
+ const relIdx = path.posix.normalize(path.relative(cwd, absIdx))
+ if (fileSet.has(relIdx) || existsSync(absIdx)) {
+ candidates.add(relIdx)
+ }
+ }
+
+ // 5b) Fallback: scan known files by basename
+ const name = path.basename(absBase)
+ for (const f of relativeFiles) {
+ if (tryExts.some((e) => f.endsWith(`/${name}${e}`))) {
+ candidates.add(f)
+ }
+ }
+
+ // 6) If no matches, bail
+ if (candidates.size === 0) return null
+
+ // 7) Sort by (1) extension priority, then (2) "strong" base match
+ const sorted = Array.from(candidates).sort((a, b) => {
+ // a) extension order
+ const aExt = path.posix.extname(a)
+ const bExt = path.posix.extname(b)
+ const ord = tryExts.indexOf(aExt) - tryExts.indexOf(bExt)
+ if (ord !== 0) return ord
+ // b) strong match if path starts with relBase
+ const aStrong = relBase && a.startsWith(relBase) ? -1 : 1
+ const bStrong = relBase && b.startsWith(relBase) ? -1 : 1
+ return aStrong - bStrong
+ })
+
+ // 8) Return the first (best) candidate
+ return sorted[0]
+}
+
+export function toAliasedImport(
+ filePath: string,
+ config: Config,
+ projectInfo: ProjectInfo
+): string | null {
+ const abs = path.normalize(path.join(config.resolvedPaths.cwd, filePath))
+
+ // 1️⃣ Find the longest matching alias root in resolvedPaths
+ // e.g. key="ui", root="/…/components/ui" beats key="components"
+ const matches = Object.entries(config.resolvedPaths)
+ .filter(
+ ([, root]) => root && abs.startsWith(path.normalize(root + path.sep))
+ )
+ .sort((a, b) => b[1].length - a[1].length)
+
+ if (matches.length === 0) {
+ return null
+ }
+ const [aliasKey, rootDir] = matches[0]
+
+ // 2️⃣ Compute the path UNDER that root
+ let rel = path.relative(rootDir, abs)
+ // force POSIX-style separators
+ rel = rel.split(path.sep).join("/") // e.g. "button/index.tsx"
+
+ // 3️⃣ Strip code-file extensions, keep others (css, json, etc.)
+ const ext = path.posix.extname(rel)
+ const codeExts = [".ts", ".tsx", ".js", ".jsx"]
+ const keepExt = codeExts.includes(ext) ? "" : ext
+ let noExt = rel.slice(0, rel.length - ext.length)
+
+ // 4️⃣ Collapse "/index" to its directory
+ if (noExt.endsWith("/index")) {
+ noExt = noExt.slice(0, -"/index".length)
+ }
+
+ // 5️⃣ Build the aliased path
+ // config.aliases[aliasKey] is e.g. "@/components/ui"
+ const aliasBase =
+ aliasKey === "cwd"
+ ? projectInfo.aliasPrefix
+ : config.aliases[aliasKey as keyof typeof config.aliases]
+ if (!aliasBase) {
+ return null
+ }
+ // if noExt is empty (i.e. file was exactly at the root), we import the root
+ let suffix = noExt === "" ? "" : `/${noExt}`
+
+ // Rremove /src from suffix.
+ // Alias will handle this.
+ suffix = suffix.replace("/src", "")
+
+ // 6️⃣ Prepend the prefix from projectInfo (e.g. "@") if needed
+ // but usually config.aliases already include it.
+ return `${aliasBase}${suffix}${keepExt}`
+}
diff --git a/packages/shadcn/test/fixtures/project-deno/deno.json b/packages/shadcn/test/fixtures/project-deno/deno.json
new file mode 100644
index 0000000000..9e26dfeeb6
--- /dev/null
+++ b/packages/shadcn/test/fixtures/project-deno/deno.json
@@ -0,0 +1 @@
+{}
\ No newline at end of file
diff --git a/packages/shadcn/test/fixtures/project-deno/deno.lock b/packages/shadcn/test/fixtures/project-deno/deno.lock
new file mode 100644
index 0000000000..e69de29bb2
diff --git a/packages/shadcn/test/fixtures/project-npm-react19/package-lock.json b/packages/shadcn/test/fixtures/project-npm-react19/package-lock.json
new file mode 100644
index 0000000000..9b6d3cd8de
--- /dev/null
+++ b/packages/shadcn/test/fixtures/project-npm-react19/package-lock.json
@@ -0,0 +1,13 @@
+{
+ "name": "test-cli-npm-project",
+ "version": "1.0.0",
+ "lockfileVersion": 2,
+ "requires": true,
+ "packages": {
+ "": {
+ "name": "npm-project",
+ "version": "1.0.0",
+ "license": "MIT"
+ }
+ }
+}
diff --git a/packages/shadcn/test/fixtures/project-npm-react19/package.json b/packages/shadcn/test/fixtures/project-npm-react19/package.json
new file mode 100644
index 0000000000..61ef91b3c7
--- /dev/null
+++ b/packages/shadcn/test/fixtures/project-npm-react19/package.json
@@ -0,0 +1,10 @@
+{
+ "name": "test-cli-project-npm",
+ "version": "1.0.0",
+ "main": "index.js",
+ "author": "shadcn",
+ "license": "MIT",
+ "dependencies": {
+ "react": "19.0.0"
+ }
+}
diff --git a/packages/shadcn/test/utils/__snapshots__/transform-tw-prefix.test.ts.snap b/packages/shadcn/test/utils/__snapshots__/transform-tw-prefix.test.ts.snap
index 5019ddb6d7..6f5dcdf5e4 100644
--- a/packages/shadcn/test/utils/__snapshots__/transform-tw-prefix.test.ts.snap
+++ b/packages/shadcn/test/utils/__snapshots__/transform-tw-prefix.test.ts.snap
@@ -3,7 +3,7 @@
exports[`transform tailwind prefix 1`] = `
"import * as React from "react"
export function Foo() {
- return foo
+ return foo
}
"
`;
@@ -11,7 +11,7 @@ exports[`transform tailwind prefix 1`] = `
exports[`transform tailwind prefix 2`] = `
"import * as React from "react"
export function Foo() {
- return foo
+ return foo
}
"
`;
@@ -19,7 +19,7 @@ export function Foo() {
exports[`transform tailwind prefix 3`] = `
"import * as React from "react"
export function Foo() {
- return foo
+ return foo
}
"
`;
@@ -27,7 +27,7 @@ export function Foo() {
exports[`transform tailwind prefix 4`] = `
"import * as React from "react"
export function Foo() {
- return foo
+ return foo
}
"
`;
@@ -105,10 +105,10 @@ exports[`transform tailwind prefix 5`] = `
@layer base {
* {
- @apply tw-border-border;
+ @apply tw::border-border;
}
body {
- @apply tw-bg-background tw-text-foreground;
+ @apply tw::bg-background tw::text-foreground;
}
}"
`;
diff --git a/packages/shadcn/test/utils/apply-prefix.test.ts b/packages/shadcn/test/utils/apply-prefix.test.ts
index 9afed4c4ed..9ae669e72b 100644
--- a/packages/shadcn/test/utils/apply-prefix.test.ts
+++ b/packages/shadcn/test/utils/apply-prefix.test.ts
@@ -2,7 +2,7 @@ import { describe, expect, test } from "vitest"
import { applyPrefix } from "../../src/utils/transformers/transform-tw-prefix"
-describe("apply tailwind prefix", () => {
+describe("apply tailwind prefix v3", () => {
test.each([
{
input: "bg-slate-800 text-gray-500",
@@ -37,6 +37,45 @@ describe("apply tailwind prefix", () => {
"tw-absolute tw-right-4 tw-top-4 tw-bg-primary tw-rounded-sm tw-opacity-70 tw-ring-offset-background tw-transition-opacity hover:tw-opacity-100 focus:tw-outline-none focus:tw-ring-2 focus:tw-ring-ring focus:tw-ring-offset-2 disabled:tw-pointer-events-none data-[state=open]:tw-bg-secondary",
},
])(`applyTwPrefix($input) -> $output`, ({ input, output }) => {
- expect(applyPrefix(input, "tw-")).toBe(output)
+ expect(applyPrefix(input, "tw-", "v3")).toBe(output)
+ })
+})
+
+describe("apply tailwind prefix v4", () => {
+ test.each([
+ {
+ input: "bg-slate-800 text-gray-500",
+ output: "tw:bg-slate-800 tw:text-gray-500",
+ },
+ {
+ input: "hover:dark:bg-background dark:text-foreground",
+ output: "tw:hover:dark:bg-background tw:dark:text-foreground",
+ },
+ {
+ input:
+ "rounded-lg border border-slate-200 bg-white text-slate-950 shadow-sm dark:border-slate-800 dark:bg-slate-950 dark:text-slate-50",
+ output:
+ "tw:rounded-lg tw:border tw:border-slate-200 tw:bg-white tw:text-slate-950 tw:shadow-sm tw:dark:border-slate-800 tw:dark:bg-slate-950 tw:dark:text-slate-50",
+ },
+ {
+ input:
+ "text-red-500 border-red-500/50 dark:border-red-500 [&>svg]:text-red-500 text-red-500 dark:text-red-900 dark:border-red-900/50 dark:dark:border-red-900 dark:[&>svg]:text-red-900 dark:text-red-900",
+ output:
+ "tw:text-red-500 tw:border-red-500/50 tw:dark:border-red-500 tw:[&>svg]:text-red-500 tw:text-red-500 tw:dark:text-red-900 tw:dark:border-red-900/50 tw:dark:dark:border-red-900 tw:dark:[&>svg]:text-red-900 tw:dark:text-red-900",
+ },
+ {
+ input:
+ "flex h-full w-full items-center justify-center rounded-full bg-muted",
+ output:
+ "tw:flex tw:h-full tw:w-full tw:items-center tw:justify-center tw:rounded-full tw:bg-muted",
+ },
+ {
+ input:
+ "absolute right-4 top-4 bg-primary rounded-sm opacity-70 ring-offset-background transition-opacity hover:opacity-100 focus:outline-none focus:ring-2 focus:ring-ring focus:ring-offset-2 disabled:pointer-events-none data-[state=open]:bg-secondary",
+ output:
+ "tw:absolute tw:right-4 tw:top-4 tw:bg-primary tw:rounded-sm tw:opacity-70 tw:ring-offset-background tw:transition-opacity tw:hover:opacity-100 tw:focus:outline-none tw:focus:ring-2 tw:focus:ring-ring tw:focus:ring-offset-2 tw:disabled:pointer-events-none tw:data-[state=open]:bg-secondary",
+ },
+ ])(`applyTwPrefix($input) -> $output`, ({ input, output }) => {
+ expect(applyPrefix(input, "tw", "v4")).toBe(output)
})
})
diff --git a/packages/shadcn/test/utils/schema/__snapshots__/registry-resolve-items-tree.test.ts.snap b/packages/shadcn/test/utils/schema/__snapshots__/registry-resolve-items-tree.test.ts.snap
index 80a4ab2cc0..91e0fe90d7 100644
--- a/packages/shadcn/test/utils/schema/__snapshots__/registry-resolve-items-tree.test.ts.snap
+++ b/packages/shadcn/test/utils/schema/__snapshots__/registry-resolve-items-tree.test.ts.snap
@@ -2,6 +2,7 @@
exports[`registryResolveItemTree > should resolve index 1`] = `
{
+ "css": {},
"cssVars": {
"dark": {},
"light": {
@@ -87,6 +88,7 @@ export { Label }
exports[`registryResolveItemTree > should resolve items tree 1`] = `
{
+ "css": {},
"cssVars": {},
"dependencies": [
"@radix-ui/react-slot",
@@ -164,6 +166,7 @@ export { Button, buttonVariants }
exports[`registryResolveItemTree > should resolve multiple items tree 1`] = `
{
+ "css": {},
"cssVars": {},
"dependencies": [
"@radix-ui/react-slot",
diff --git a/packages/shadcn/test/utils/transform-tw-prefix.test.ts b/packages/shadcn/test/utils/transform-tw-prefix.test.ts
index 21529f3cbf..31fc37c8e0 100644
--- a/packages/shadcn/test/utils/transform-tw-prefix.test.ts
+++ b/packages/shadcn/test/utils/transform-tw-prefix.test.ts
@@ -16,7 +16,7 @@ test("transform tailwind prefix", async () => {
config: {
tailwind: {
baseColor: "stone",
- prefix: "tw-",
+ prefix: "tw:",
},
aliases: {
components: "@/components",
@@ -39,7 +39,7 @@ export function Foo() {
tailwind: {
baseColor: "stone",
cssVariables: false,
- prefix: "tw-",
+ prefix: "tw:",
},
aliases: {
components: "@/components",
@@ -62,7 +62,7 @@ export function Foo() {
tailwind: {
baseColor: "stone",
cssVariables: false,
- prefix: "tw-",
+ prefix: "tw:",
},
aliases: {
components: "@/components",
@@ -85,7 +85,7 @@ export function Foo() {
tailwind: {
baseColor: "stone",
cssVariables: false,
- prefix: "tw-",
+ prefix: "tw:",
},
aliases: {
components: "@/components",
@@ -99,7 +99,8 @@ export function Foo() {
expect(
applyPrefixesCss(
"@tailwind base;\n@tailwind components;\n@tailwind utilities;\n \n@layer base {\n :root {\n --background: 0 0% 100%;\n --foreground: 224 71.4% 4.1%;\n \n --muted: 220 14.3% 95.9%;\n --muted-foreground: 220 8.9% 46.1%;\n \n --popover: 0 0% 100%;\n --popover-foreground: 224 71.4% 4.1%;\n \n --card: 0 0% 100%;\n --card-foreground: 224 71.4% 4.1%;\n \n --border: 220 13% 91%;\n --input: 220 13% 91%;\n \n --primary: 220.9 39.3% 11%;\n --primary-foreground: 210 20% 98%;\n \n --secondary: 220 14.3% 95.9%;\n --secondary-foreground: 220.9 39.3% 11%;\n \n --accent: 220 14.3% 95.9%;\n --accent-foreground: 220.9 39.3% 11%;\n \n --destructive: 0 84.2% 60.2%;\n --destructive-foreground: 210 20% 98%;\n \n --ring: 217.9 10.6% 64.9%;\n \n --radius: 0.5rem;\n }\n \n .dark {\n --background: 224 71.4% 4.1%;\n --foreground: 210 20% 98%;\n \n --muted: 215 27.9% 16.9%;\n --muted-foreground: 217.9 10.6% 64.9%;\n \n --popover: 224 71.4% 4.1%;\n --popover-foreground: 210 20% 98%;\n \n --card: 224 71.4% 4.1%;\n --card-foreground: 210 20% 98%;\n \n --border: 215 27.9% 16.9%;\n --input: 215 27.9% 16.9%;\n \n --primary: 210 20% 98%;\n --primary-foreground: 220.9 39.3% 11%;\n \n --secondary: 215 27.9% 16.9%;\n --secondary-foreground: 210 20% 98%;\n \n --accent: 215 27.9% 16.9%;\n --accent-foreground: 210 20% 98%;\n \n --destructive: 0 62.8% 30.6%;\n --destructive-foreground: 0 85.7% 97.3%;\n \n --ring: 215 27.9% 16.9%;\n }\n}\n \n@layer base {\n * {\n @apply border-border;\n }\n body {\n @apply bg-background text-foreground;\n }\n}",
- "tw-"
+ "tw:",
+ "v4"
)
).toMatchSnapshot()
})
diff --git a/packages/shadcn/test/utils/updaters/update-css.test.ts b/packages/shadcn/test/utils/updaters/update-css.test.ts
new file mode 100644
index 0000000000..08cb618c4b
--- /dev/null
+++ b/packages/shadcn/test/utils/updaters/update-css.test.ts
@@ -0,0 +1,331 @@
+import { describe, expect, test } from "vitest"
+
+import { transformCss } from "../../../src/utils/updaters/update-css"
+
+describe("transformCss", () => {
+ test("should add utility classes", async () => {
+ const input = `@import "tailwindcss";`
+
+ const result = await transformCss(input, {
+ "@utility content-auto": {
+ "content-visibility": "auto",
+ },
+ })
+
+ expect(result).toMatchInlineSnapshot(`
+ "@import "tailwindcss";
+
+ @utility content-auto {
+ content-visibility: auto;
+ }"
+ `)
+ })
+
+ test("should add utility classes with pseudo-selectors", async () => {
+ const input = `@import "tailwindcss";`
+
+ const result = await transformCss(input, {
+ "@utility scrollbar-hidden": {
+ "&::-webkit-scrollbar": {
+ display: "none",
+ },
+ },
+ })
+
+ expect(result).toMatchInlineSnapshot(`
+ "@import "tailwindcss";
+
+ @utility scrollbar-hidden {
+ &::-webkit-scrollbar {
+ display: none;
+ }
+ }"
+ `)
+ })
+
+ test("should add parameterized utility classes", async () => {
+ const input = `@import "tailwindcss";`
+
+ const result = await transformCss(input, {
+ "@utility tab-*": {
+ "tab-size": "--value([integer])",
+ },
+ })
+
+ expect(result).toMatchInlineSnapshot(`
+ "@import "tailwindcss";
+
+ @utility tab-* {
+ tab-size: --value([integer]);
+ }"
+ `)
+ })
+
+ test("should add component styles", async () => {
+ const input = `@tailwind base;
+@tailwind components;
+@tailwind utilities;`
+
+ const result = await transformCss(input, {
+ "@layer components": {
+ ".card": {
+ "background-color": "var(--color-white)",
+ "border-radius": "var(--rounded-lg)",
+ padding: "var(--spacing-6)",
+ "box-shadow": "var(--shadow-xl)",
+ },
+ },
+ })
+
+ expect(result).toMatchInlineSnapshot(`
+ "@tailwind base;
+ @tailwind components;
+ @tailwind utilities;
+
+ @layer components {
+ .card {
+ background-color: var(--color-white);
+ border-radius: var(--rounded-lg);
+ padding: var(--spacing-6);
+ box-shadow: var(--shadow-xl);
+ }
+ }"
+ `)
+ })
+
+ test("should add base styles", async () => {
+ const input = `@tailwind base;
+@tailwind components;
+@tailwind utilities;`
+
+ const result = await transformCss(input, {
+ "@layer base": {
+ h1: {
+ "font-size": "var(--text-2xl)",
+ },
+ h2: {
+ "font-size": "var(--text-xl)",
+ },
+ },
+ })
+
+ expect(result).toMatchInlineSnapshot(`
+ "@tailwind base;
+ @tailwind components;
+ @tailwind utilities;
+
+ @layer base {
+ h1 {
+ font-size: var(--text-2xl);
+ }
+ h2 {
+ font-size: var(--text-xl);
+ }
+ }"
+ `)
+ })
+
+ test("should update existing rules", async () => {
+ const input = `@import "tailwindcss";
+
+@layer components {
+ .card {
+ background-color: white;
+ padding: 1rem;
+ }
+}`
+
+ const result = await transformCss(input, {
+ "@layer components": {
+ ".card": {
+ "background-color": "var(--color-white)",
+ "border-radius": "var(--rounded-lg)",
+ "box-shadow": "var(--shadow-xl)",
+ },
+ },
+ })
+
+ expect(result).toMatchInlineSnapshot(`
+ "@import "tailwindcss";
+
+ @layer components {
+ .card {
+ background-color: var(--color-white);
+ padding: 1rem;
+ border-radius: var(--rounded-lg);
+ box-shadow: var(--shadow-xl);
+ }
+ }"
+ `)
+ })
+
+ test("should add multiple rules and types", async () => {
+ const input = `@tailwind base;
+@tailwind components;
+@tailwind utilities;`
+
+ const result = await transformCss(input, {
+ "@utility content-auto": {
+ "content-visibility": "auto",
+ },
+ "@layer components": {
+ ".card": {
+ "background-color": "var(--color-white)",
+ "border-radius": "var(--rounded-lg)",
+ },
+ },
+ "@layer base": {
+ h1: {
+ "font-size": "var(--text-2xl)",
+ },
+ },
+ })
+
+ expect(result).toMatchInlineSnapshot(`
+ "@tailwind base;
+ @tailwind components;
+ @tailwind utilities;
+
+ @utility content-auto {
+ content-visibility: auto;
+ }
+
+ @layer components {
+ .card {
+ background-color: var(--color-white);
+ border-radius: var(--rounded-lg);
+ }
+ }
+
+ @layer base {
+ h1 {
+ font-size: var(--text-2xl);
+ }
+ }"
+ `)
+ })
+
+ test("should handle nested selectors with &", async () => {
+ const input = `@tailwind base;
+@tailwind components;
+@tailwind utilities;`
+
+ const result = await transformCss(input, {
+ "@layer components": {
+ ".button": {
+ "background-color": "var(--color-primary)",
+ "&:hover": {
+ "background-color": "var(--color-primary-dark)",
+ },
+ "&:active": {
+ "background-color": "var(--color-primary-darker)",
+ },
+ },
+ },
+ })
+
+ expect(result).toMatchInlineSnapshot(`
+ "@tailwind base;
+ @tailwind components;
+ @tailwind utilities;
+
+ @layer components {
+ .button {
+ background-color: var(--color-primary);
+ }
+ .button:hover {
+ background-color: var(--color-primary-dark);
+ }
+ .button:active {
+ background-color: var(--color-primary-darker);
+ }
+ }"
+ `)
+ })
+
+ test("should handle direct string content", async () => {
+ const input = `@tailwind base;
+@tailwind components;
+@tailwind utilities;`
+
+ const result = await transformCss(input, {
+ "@layer base": {
+ body: "font-family: var(--font-sans); line-height: 1.5;",
+ },
+ })
+
+ expect(result).toMatchInlineSnapshot(`
+ "@tailwind base;
+ @tailwind components;
+ @tailwind utilities;
+
+ @layer base {
+ body {
+ font-family: var(--font-sans);
+ line-height: 1.5;
+ }
+ }"
+ `)
+ })
+
+ test("should handle nested at-rules", async () => {
+ const input = `@tailwind base;
+@tailwind components;
+@tailwind utilities;`
+
+ const result = await transformCss(input, {
+ "@layer components": {
+ "@media (min-width: 768px)": {
+ ".card": {
+ padding: "2rem",
+ },
+ },
+ },
+ })
+
+ expect(result).toMatchInlineSnapshot(`
+ "@tailwind base;
+ @tailwind components;
+ @tailwind utilities;
+
+ @layer components {
+
+ @media (min-width: 768px) {
+ .card {
+ padding: 2rem;
+ }
+ }
+ }"
+ `)
+ })
+
+ test("should place keyframes under @theme inline directive", async () => {
+ const input = `@import "tailwindcss";`
+
+ const result = await transformCss(input, {
+ "@keyframes spin": {
+ "0%": {
+ transform: "rotate(0deg)",
+ },
+ "100%": {
+ transform: "rotate(360deg)",
+ },
+ },
+ })
+
+ expect(result).toMatchInlineSnapshot(`
+ "@import "tailwindcss";
+
+ @theme inline {
+ @keyframes spin {
+ 0% {
+ transform: rotate(0deg);
+ }
+ 100% {
+ transform: rotate(360deg);
+ }
+ }
+ }"
+ `)
+ })
+})
diff --git a/packages/shadcn/test/utils/updaters/update-dependencies.test.ts b/packages/shadcn/test/utils/updaters/update-dependencies.test.ts
new file mode 100644
index 0000000000..7e0c36e682
--- /dev/null
+++ b/packages/shadcn/test/utils/updaters/update-dependencies.test.ts
@@ -0,0 +1,139 @@
+import { vi, describe, afterEach, test, expect } from "vitest"
+import { execa } from "execa"
+import prompts from "prompts"
+import { updateDependencies } from "../../../src/utils/updaters/update-dependencies"
+import path from "path"
+
+vi.mock("execa")
+vi.mock("prompts")
+
+describe("updateDependencies", () => {
+ afterEach(() => {
+ vi.restoreAllMocks()
+ })
+
+ test.each([
+ {
+ description: "npm without react 19 includes no additional flags",
+ options: { silent: true },
+ dependencies: ["first", "second", "third"],
+ devDependencies: ["fourth"],
+ config: {
+ resolvedPaths: {
+ cwd: path.resolve(__dirname, "../../fixtures/project-npm")
+ }
+ },
+ expectedPackageManager: "npm",
+ expectedArgs: ["install", "first", "second", "third"],
+ expectedDevArgs: ["install", "-D", "fourth"]
+ },
+ {
+ description: "npm with react 19 applies force prompt when silent",
+ options: { silent: true },
+ dependencies: ["first", "second", "third"],
+ devDependencies: ["fourth"],
+ config: {
+ resolvedPaths: {
+ cwd: path.resolve(__dirname, "../../fixtures/project-npm-react19")
+ }
+ },
+ expectedPackageManager: "npm",
+ expectedArgs: ["install", "--force", "first", "second", "third"],
+ expectedDevArgs: ["install", "--force", "-D", "fourth"]
+ },
+ {
+ description: "npm with react 19 prompts for flag when not silent",
+ flagPrompt: "legacy-peer-deps",
+ dependencies: ["first", "second", "third"],
+ devDependencies: ["fourth"],
+ config: {
+ resolvedPaths: {
+ cwd: path.resolve(__dirname, "../../fixtures/project-npm-react19")
+ }
+ },
+ expectedPackageManager: "npm",
+ expectedArgs: ["install", "--legacy-peer-deps", "first", "second", "third"],
+ expectedDevArgs: ["install", "--legacy-peer-deps", "-D", "fourth"]
+ },
+ {
+ description: "deno uses npm: package prefix",
+ dependencies: ["first", "second", "third"],
+ devDependencies: ["fourth"],
+ config: {
+ resolvedPaths: {
+ cwd: path.resolve(__dirname, "../../fixtures/project-deno")
+ }
+ },
+ expectedPackageManager: "deno",
+ expectedArgs: ["add", "npm:first", "npm:second", "npm:third"],
+ expectedDevArgs: ["add", "-D", "npm:fourth"]
+ },
+ {
+ description: "bun uses bun",
+ dependencies: ["first", "second", "third"],
+ devDependencies: ["fourth"],
+ config: {
+ resolvedPaths: {
+ cwd: path.resolve(__dirname, "../../fixtures/project-bun")
+ }
+ },
+ expectedPackageManager: "bun",
+ expectedArgs: ["add", "first", "second", "third"],
+ expectedDevArgs: ["add", "-D", "fourth"]
+ },
+ {
+ description: "pnpm uses pnpm",
+ dependencies: ["first", "second", "third"],
+ devDependencies: ["fourth"],
+ config: {
+ resolvedPaths: {
+ cwd: path.resolve(__dirname, "../../fixtures/project-pnpm")
+ }
+ },
+ expectedPackageManager: "pnpm",
+ expectedArgs: ["add", "first", "second", "third"],
+ expectedDevArgs: ["add", "-D", "fourth"]
+ },
+ {
+ description: "deduplicates input dependencies",
+ options: { silent: true },
+ dependencies: ["first", "first"],
+ devDependencies: ["second", "second"],
+ config: {
+ resolvedPaths: {
+ cwd: path.resolve(__dirname, "../../fixtures/project-npm")
+ }
+ },
+ expectedPackageManager: "npm",
+ expectedArgs: ["install", "first"],
+ expectedDevArgs: ["install", "-D", "second"]
+ }
+ ])("$description", async ({ options, flagPrompt, config, dependencies, devDependencies, expectedPackageManager, expectedArgs, expectedDevArgs }) => {
+
+ vi.mocked(prompts).mockResolvedValue({ flag: flagPrompt })
+
+ await updateDependencies(
+ dependencies,
+ devDependencies,
+ config,
+ options ?? {}
+ )
+
+ if (flagPrompt) {
+ expect(prompts).toHaveBeenCalled()
+ }
+
+
+ expect(execa).toHaveBeenCalledWith(
+ expectedPackageManager,
+ expectedArgs,
+ { cwd: config?.resolvedPaths.cwd }
+ )
+
+ expect(execa).toHaveBeenCalledWith(
+ expectedPackageManager,
+ expectedDevArgs,
+ { cwd: config?.resolvedPaths.cwd }
+ )
+ })
+})
\ No newline at end of file
diff --git a/packages/shadcn/test/utils/updaters/update-files.test.ts b/packages/shadcn/test/utils/updaters/update-files.test.ts
index 3dfbcf554c..e0b65a7c2c 100644
--- a/packages/shadcn/test/utils/updaters/update-files.test.ts
+++ b/packages/shadcn/test/utils/updaters/update-files.test.ts
@@ -1,3 +1,4 @@
+import { existsSync } from "fs"
import path from "path"
import { afterAll, afterEach, describe, expect, test, vi } from "vitest"
@@ -5,7 +6,9 @@ import { getConfig } from "../../../src/utils/get-config"
import {
findCommonRoot,
resolveFilePath,
+ resolveModuleByProbablePath,
resolveNestedFilePath,
+ toAliasedImport,
updateFiles,
} from "../../../src/utils/updaters/update-files"
@@ -809,3 +812,340 @@ return Hello World
`)
})
})
+
+describe("resolveModuleByProbablePath", () => {
+ test("should resolve exact file match in provided files list", () => {
+ const files = [
+ "components/button.tsx",
+ "components/card.tsx",
+ "lib/utils.ts",
+ ]
+ const config = {
+ resolvedPaths: {
+ cwd: "/foo/bar",
+ },
+ }
+ expect(
+ resolveModuleByProbablePath("/foo/bar/components/button", files, config)
+ ).toBe("components/button.tsx")
+ })
+
+ test("should resolve index file", () => {
+ const files = ["components/button/index.tsx", "components/card.tsx"]
+ const config = {
+ resolvedPaths: {
+ cwd: "/foo/bar",
+ },
+ }
+ expect(
+ resolveModuleByProbablePath("/foo/bar/components/button", files, config)
+ ).toBe("components/button/index.tsx")
+ })
+
+ test("should try different extensions", () => {
+ const files = ["components/button.jsx", "components/card.tsx"]
+ const config = {
+ resolvedPaths: {
+ cwd: "/foo/bar",
+ },
+ }
+ expect(
+ resolveModuleByProbablePath("/foo/bar/components/button", files, config)
+ ).toBe("components/button.jsx")
+ })
+
+ test("should fallback to basename matching", () => {
+ const files = ["components/ui/button.tsx", "components/card.tsx"]
+ const config = {
+ resolvedPaths: {
+ cwd: "/foo/bar",
+ },
+ }
+ expect(
+ resolveModuleByProbablePath("/foo/bar/components/button", files, config)
+ ).toBe("components/ui/button.tsx")
+ })
+
+ test("should return null when file not found", () => {
+ const files = ["components/card.tsx", "lib/utils.ts"]
+ const config = {
+ resolvedPaths: {
+ cwd: "/foo/bar",
+ },
+ }
+ expect(
+ resolveModuleByProbablePath("/foo/bar/components/button", files, config)
+ ).toBeNull()
+ })
+
+ test("should sort by extension priority", () => {
+ const files = [
+ "components/button.jsx",
+ "components/button.tsx",
+ "components/button.js",
+ ]
+ const config = {
+ resolvedPaths: {
+ cwd: "/foo/bar",
+ },
+ }
+ expect(
+ resolveModuleByProbablePath("/foo/bar/components/button", files, config, [
+ ".tsx",
+ ".jsx",
+ ".js",
+ ])
+ ).toBe("components/button.tsx")
+ })
+
+ test("should preserve extension if specified in path", () => {
+ const files = ["components/button.tsx", "components/button.css"]
+ const config = {
+ resolvedPaths: {
+ cwd: "/foo/bar",
+ },
+ }
+ expect(
+ resolveModuleByProbablePath(
+ "/foo/bar/components/button.css",
+ files,
+ config
+ )
+ ).toBe("components/button.css")
+ })
+})
+
+describe("toAliasedImport", () => {
+ test("should convert components path to aliased import", () => {
+ const filePath = "components/button.tsx"
+ const config = {
+ resolvedPaths: {
+ cwd: "/foo/bar",
+ components: "/foo/bar/components",
+ ui: "/foo/bar/components/ui",
+ lib: "/foo/bar/lib",
+ },
+ aliases: {
+ components: "@/components",
+ ui: "@/components/ui",
+ lib: "@/lib",
+ },
+ }
+ const projectInfo = {
+ aliasPrefix: "@",
+ }
+ expect(toAliasedImport(filePath, config, projectInfo)).toBe(
+ "@/components/button"
+ )
+ })
+
+ test("should convert ui path to aliased import", () => {
+ const filePath = "components/ui/button.tsx"
+ const config = {
+ resolvedPaths: {
+ cwd: "/foo/bar",
+ components: "/foo/bar/components",
+ ui: "/foo/bar/components/ui",
+ lib: "/foo/bar/lib",
+ },
+ aliases: {
+ components: "@/components",
+ ui: "@/components/ui",
+ lib: "@/lib",
+ },
+ }
+ const projectInfo = {
+ aliasPrefix: "@",
+ }
+ expect(toAliasedImport(filePath, config, projectInfo)).toBe(
+ "@/components/ui/button"
+ )
+ })
+
+ test("should collapse index files", () => {
+ const filePath = "components/ui/button/index.tsx"
+ const config = {
+ resolvedPaths: {
+ cwd: "/foo/bar",
+ components: "/foo/bar/components",
+ ui: "/foo/bar/components/ui",
+ lib: "/foo/bar/lib",
+ },
+ aliases: {
+ components: "@/components",
+ ui: "@/components/ui",
+ lib: "@/lib",
+ },
+ }
+ const projectInfo = {
+ aliasPrefix: "@",
+ }
+ expect(toAliasedImport(filePath, config, projectInfo)).toBe(
+ "@/components/ui/button"
+ )
+ })
+
+ test("should return null when no matching alias found", () => {
+ const filePath = "src/pages/index.tsx"
+ const config = {
+ resolvedPaths: {
+ cwd: "/foo/bar",
+ components: "/foo/bar/components",
+ ui: "/foo/bar/components/ui",
+ lib: "/foo/bar/lib",
+ },
+ aliases: {
+ components: "@/components",
+ ui: "@/components/ui",
+ lib: "@/lib",
+ },
+ }
+ const projectInfo = {
+ aliasPrefix: "@",
+ }
+ expect(toAliasedImport(filePath, config, projectInfo)).toBe("@/pages")
+ })
+
+ test("should handle nested directories", () => {
+ const filePath = "components/forms/inputs/text-input.tsx"
+ const config = {
+ resolvedPaths: {
+ cwd: "/foo/bar",
+ components: "/foo/bar/components",
+ ui: "/foo/bar/components/ui",
+ lib: "/foo/bar/lib",
+ },
+ aliases: {
+ components: "@/components",
+ ui: "@/components/ui",
+ lib: "@/lib",
+ },
+ }
+ const projectInfo = {
+ aliasPrefix: "@",
+ }
+ expect(toAliasedImport(filePath, config, projectInfo)).toBe(
+ "@/components/forms/inputs/text-input"
+ )
+ })
+
+ test("should keep non-code file extensions", () => {
+ const filePath = "components/styles/theme.css"
+ const config = {
+ resolvedPaths: {
+ cwd: "/foo/bar",
+ components: "/foo/bar/components",
+ ui: "/foo/bar/components/ui",
+ lib: "/foo/bar/lib",
+ },
+ aliases: {
+ components: "@/components",
+ ui: "@/components/ui",
+ lib: "@/lib",
+ },
+ }
+ const projectInfo = {
+ aliasPrefix: "@",
+ }
+ expect(toAliasedImport(filePath, config, projectInfo)).toBe(
+ "@/components/styles/theme.css"
+ )
+ })
+
+ test("should prefer longer matching paths", () => {
+ const filePath = "components/ui/button.tsx"
+ const config = {
+ resolvedPaths: {
+ cwd: "/foo/bar",
+ components: "/foo/bar/components",
+ ui: "/foo/bar/components/ui",
+ },
+ aliases: {
+ components: "@/components",
+ ui: "@/ui",
+ },
+ }
+ const projectInfo = {
+ aliasPrefix: "@",
+ }
+ expect(toAliasedImport(filePath, config, projectInfo)).toBe("@/ui/button")
+ })
+
+ test("should support tilde (~) alias prefix", () => {
+ const filePath = "components/button.tsx"
+ const config = {
+ resolvedPaths: {
+ cwd: "/foo/bar",
+ components: "/foo/bar/components",
+ },
+ aliases: {
+ components: "~components",
+ },
+ }
+ const projectInfo = {
+ aliasPrefix: "~",
+ }
+ expect(toAliasedImport(filePath, config, projectInfo)).toBe(
+ "~components/button"
+ )
+ })
+
+ test("should support @shadcn alias prefix", () => {
+ const filePath = "components/ui/button.tsx"
+ const config = {
+ resolvedPaths: {
+ cwd: "/foo/bar",
+ components: "/foo/bar/components",
+ ui: "/foo/bar/components/ui",
+ },
+ aliases: {
+ components: "@shadcn/components",
+ ui: "@shadcn/ui",
+ },
+ }
+ const projectInfo = {
+ aliasPrefix: "@shadcn",
+ }
+ expect(toAliasedImport(filePath, config, projectInfo)).toBe(
+ "@shadcn/ui/button"
+ )
+ })
+
+ test("should support ~cn alias prefix", () => {
+ const filePath = "lib/utils/index.tsx"
+ const config = {
+ resolvedPaths: {
+ cwd: "/foo/bar",
+ lib: "/foo/bar/lib",
+ },
+ aliases: {
+ lib: "~cn/lib",
+ },
+ }
+ const projectInfo = {
+ aliasPrefix: "~cn",
+ }
+ expect(toAliasedImport(filePath, config, projectInfo)).toBe("~cn/lib/utils")
+ })
+
+ test("should use project alias prefix when aliasKey is cwd", () => {
+ const filePath = "src/pages/home.tsx"
+ const config = {
+ resolvedPaths: {
+ cwd: "/foo/bar",
+ components: "/foo/bar/components",
+ ui: "/foo/bar/components/ui",
+ lib: "/foo/bar/lib",
+ },
+ aliases: {
+ components: "@/components",
+ ui: "@/components/ui",
+ lib: "@/lib",
+ },
+ }
+ const projectInfo = {
+ aliasPrefix: "@",
+ }
+ expect(toAliasedImport(filePath, config, projectInfo)).toBe("@/pages/home")
+ })
+})
diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml
index 1880dcd618..3e0add4113 100644
--- a/pnpm-lock.yaml
+++ b/pnpm-lock.yaml
@@ -58,7 +58,7 @@ importers:
version: 7.37.4(eslint@8.57.1)
eslint-plugin-tailwindcss:
specifier: 3.13.1
- version: 3.13.1(tailwindcss@3.4.6(ts-node@10.9.2(@types/node@20.5.1)(typescript@5.7.3)))
+ version: 3.13.1(tailwindcss@3.4.6(ts-node@10.9.2(@types/node@20.17.16)(typescript@5.7.3)))
postcss:
specifier: ^8.4.24
version: 8.5.1
@@ -73,10 +73,10 @@ importers:
version: 23.11.1(typescript@5.7.3)
tailwindcss:
specifier: 3.4.6
- version: 3.4.6(ts-node@10.9.2(@types/node@20.5.1)(typescript@5.7.3))
+ version: 3.4.6(ts-node@10.9.2(@types/node@20.17.16)(typescript@5.7.3))
tailwindcss-animate:
specifier: ^1.0.5
- version: 1.0.7(tailwindcss@3.4.6(ts-node@10.9.2(@types/node@20.5.1)(typescript@5.7.3)))
+ version: 1.0.7(tailwindcss@3.4.6(ts-node@10.9.2(@types/node@20.17.16)(typescript@5.7.3)))
tsx:
specifier: ^4.1.4
version: 4.19.2
@@ -283,7 +283,7 @@ importers:
specifier: ^6.0.1
version: 6.0.1
shadcn:
- specifier: 2.3.0
+ specifier: 2.5.0
version: link:../../packages/shadcn
sonner:
specifier: ^2.0.0
@@ -542,7 +542,7 @@ importers:
specifier: 2.12.7
version: 2.12.7(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
shadcn:
- specifier: 2.3.0
+ specifier: 2.5.0
version: link:../../packages/shadcn
sharp:
specifier: ^0.32.6
@@ -689,7 +689,7 @@ importers:
version: 4.1.5
msw:
specifier: ^2.7.1
- version: 2.7.1(@types/node@20.17.16)(typescript@4.9.5)
+ version: 2.7.1(@types/node@22.13.0)(typescript@4.9.5)
node-fetch:
specifier: ^3.3.0
version: 3.3.2
@@ -738,7 +738,7 @@ importers:
version: 6.0.1
tsup:
specifier: ^6.6.3
- version: 6.7.0(postcss@8.5.1)(ts-node@10.9.2(@types/node@20.17.16)(typescript@4.9.5))(typescript@4.9.5)
+ version: 6.7.0(postcss@8.5.1)(ts-node@10.9.2(@types/node@22.13.0)(typescript@4.9.5))(typescript@4.9.5)
type-fest:
specifier: ^3.8.0
version: 3.13.1
@@ -8813,7 +8813,7 @@ snapshots:
lodash.merge: 4.6.2
lodash.uniq: 4.5.0
resolve-from: 5.0.0
- ts-node: 10.9.2(@types/node@20.17.16)(typescript@5.7.3)
+ ts-node: 10.9.2(@types/node@20.5.1)(typescript@5.7.3)
typescript: 5.7.3
transitivePeerDependencies:
- '@swc/core'
@@ -9595,6 +9595,14 @@ snapshots:
'@inquirer/type': 3.0.4(@types/node@20.17.16)
optionalDependencies:
'@types/node': 20.17.16
+ optional: true
+
+ '@inquirer/confirm@5.1.6(@types/node@22.13.0)':
+ dependencies:
+ '@inquirer/core': 10.1.7(@types/node@22.13.0)
+ '@inquirer/type': 3.0.4(@types/node@22.13.0)
+ optionalDependencies:
+ '@types/node': 22.13.0
'@inquirer/core@10.1.7(@types/node@20.17.16)':
dependencies:
@@ -9608,12 +9616,31 @@ snapshots:
yoctocolors-cjs: 2.1.2
optionalDependencies:
'@types/node': 20.17.16
+ optional: true
+
+ '@inquirer/core@10.1.7(@types/node@22.13.0)':
+ dependencies:
+ '@inquirer/figures': 1.0.10
+ '@inquirer/type': 3.0.4(@types/node@22.13.0)
+ ansi-escapes: 4.3.2
+ cli-width: 4.1.0
+ mute-stream: 2.0.0
+ signal-exit: 4.1.0
+ wrap-ansi: 6.2.0
+ yoctocolors-cjs: 2.1.2
+ optionalDependencies:
+ '@types/node': 22.13.0
'@inquirer/figures@1.0.10': {}
'@inquirer/type@3.0.4(@types/node@20.17.16)':
optionalDependencies:
'@types/node': 20.17.16
+ optional: true
+
+ '@inquirer/type@3.0.4(@types/node@22.13.0)':
+ optionalDependencies:
+ '@types/node': 22.13.0
'@isaacs/cliui@8.0.2':
dependencies:
@@ -12610,7 +12637,7 @@ snapshots:
dependencies:
'@types/node': 20.5.1
cosmiconfig: 8.3.6(typescript@5.7.3)
- ts-node: 10.9.2(@types/node@20.17.16)(typescript@5.7.3)
+ ts-node: 10.9.2(@types/node@20.5.1)(typescript@5.7.3)
typescript: 5.7.3
cosmiconfig@8.3.6(typescript@4.9.5):
@@ -13329,7 +13356,7 @@ snapshots:
debug: 4.3.7
enhanced-resolve: 5.16.1
eslint: 8.57.1
- eslint-module-utils: 2.12.0(@typescript-eslint/parser@5.61.0(eslint@8.57.1)(typescript@5.7.3))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.6.1(@typescript-eslint/parser@5.61.0(eslint@8.57.1)(typescript@5.7.3))(eslint-import-resolver-node@0.3.9)(eslint-plugin-import@2.31.0)(eslint@8.57.1))(eslint@8.57.1)
+ eslint-module-utils: 2.12.0(@typescript-eslint/parser@5.61.0(eslint@8.57.1)(typescript@5.7.3))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.6.1)(eslint@8.57.1)
eslint-plugin-import: 2.31.0(@typescript-eslint/parser@5.61.0(eslint@8.57.1)(typescript@5.7.3))(eslint-import-resolver-typescript@3.6.1)(eslint@8.57.1)
fast-glob: 3.3.3
get-tsconfig: 4.7.5
@@ -13346,7 +13373,7 @@ snapshots:
debug: 4.3.7
enhanced-resolve: 5.16.1
eslint: 9.19.0(jiti@2.4.2)
- eslint-module-utils: 2.12.0(@typescript-eslint/parser@5.61.0(eslint@9.19.0(jiti@2.4.2))(typescript@5.7.3))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.6.1(@typescript-eslint/parser@5.61.0(eslint@9.19.0(jiti@2.4.2))(typescript@5.7.3))(eslint-import-resolver-node@0.3.9)(eslint-plugin-import@2.31.0)(eslint@9.19.0(jiti@2.4.2)))(eslint@9.19.0(jiti@2.4.2))
+ eslint-module-utils: 2.12.0(@typescript-eslint/parser@5.61.0(eslint@9.19.0(jiti@2.4.2))(typescript@5.7.3))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.6.1)(eslint@9.19.0(jiti@2.4.2))
eslint-plugin-import: 2.31.0(@typescript-eslint/parser@5.61.0(eslint@9.19.0(jiti@2.4.2))(typescript@5.7.3))(eslint-import-resolver-typescript@3.6.1)(eslint@9.19.0(jiti@2.4.2))
fast-glob: 3.3.3
get-tsconfig: 4.7.5
@@ -13358,7 +13385,7 @@ snapshots:
- eslint-import-resolver-webpack
- supports-color
- eslint-module-utils@2.12.0(@typescript-eslint/parser@5.61.0(eslint@8.57.1)(typescript@5.7.3))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.6.1(@typescript-eslint/parser@5.61.0(eslint@8.57.1)(typescript@5.7.3))(eslint-import-resolver-node@0.3.9)(eslint-plugin-import@2.31.0)(eslint@8.57.1))(eslint@8.57.1):
+ eslint-module-utils@2.12.0(@typescript-eslint/parser@5.61.0(eslint@8.57.1)(typescript@5.7.3))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.6.1)(eslint@8.57.1):
dependencies:
debug: 3.2.7
optionalDependencies:
@@ -13369,7 +13396,7 @@ snapshots:
transitivePeerDependencies:
- supports-color
- eslint-module-utils@2.12.0(@typescript-eslint/parser@5.61.0(eslint@9.19.0(jiti@2.4.2))(typescript@5.7.3))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.6.1(@typescript-eslint/parser@5.61.0(eslint@9.19.0(jiti@2.4.2))(typescript@5.7.3))(eslint-import-resolver-node@0.3.9)(eslint-plugin-import@2.31.0)(eslint@9.19.0(jiti@2.4.2)))(eslint@9.19.0(jiti@2.4.2)):
+ eslint-module-utils@2.12.0(@typescript-eslint/parser@5.61.0(eslint@9.19.0(jiti@2.4.2))(typescript@5.7.3))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.6.1)(eslint@9.19.0(jiti@2.4.2)):
dependencies:
debug: 3.2.7
optionalDependencies:
@@ -13391,7 +13418,7 @@ snapshots:
doctrine: 2.1.0
eslint: 8.57.1
eslint-import-resolver-node: 0.3.9
- eslint-module-utils: 2.12.0(@typescript-eslint/parser@5.61.0(eslint@8.57.1)(typescript@5.7.3))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.6.1(@typescript-eslint/parser@5.61.0(eslint@8.57.1)(typescript@5.7.3))(eslint-import-resolver-node@0.3.9)(eslint-plugin-import@2.31.0)(eslint@8.57.1))(eslint@8.57.1)
+ eslint-module-utils: 2.12.0(@typescript-eslint/parser@5.61.0(eslint@8.57.1)(typescript@5.7.3))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.6.1)(eslint@8.57.1)
hasown: 2.0.2
is-core-module: 2.16.1
is-glob: 4.0.3
@@ -13420,7 +13447,7 @@ snapshots:
doctrine: 2.1.0
eslint: 9.19.0(jiti@2.4.2)
eslint-import-resolver-node: 0.3.9
- eslint-module-utils: 2.12.0(@typescript-eslint/parser@5.61.0(eslint@9.19.0(jiti@2.4.2))(typescript@5.7.3))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.6.1(@typescript-eslint/parser@5.61.0(eslint@9.19.0(jiti@2.4.2))(typescript@5.7.3))(eslint-import-resolver-node@0.3.9)(eslint-plugin-import@2.31.0)(eslint@9.19.0(jiti@2.4.2)))(eslint@9.19.0(jiti@2.4.2))
+ eslint-module-utils: 2.12.0(@typescript-eslint/parser@5.61.0(eslint@9.19.0(jiti@2.4.2))(typescript@5.7.3))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.6.1)(eslint@9.19.0(jiti@2.4.2))
hasown: 2.0.2
is-core-module: 2.16.1
is-glob: 4.0.3
@@ -13528,11 +13555,11 @@ snapshots:
string.prototype.matchall: 4.0.12
string.prototype.repeat: 1.0.0
- eslint-plugin-tailwindcss@3.13.1(tailwindcss@3.4.6(ts-node@10.9.2(@types/node@20.5.1)(typescript@5.7.3))):
+ eslint-plugin-tailwindcss@3.13.1(tailwindcss@3.4.6(ts-node@10.9.2(@types/node@20.17.16)(typescript@5.7.3))):
dependencies:
fast-glob: 3.3.3
postcss: 8.5.1
- tailwindcss: 3.4.6(ts-node@10.9.2(@types/node@20.5.1)(typescript@5.7.3))
+ tailwindcss: 3.4.6(ts-node@10.9.2(@types/node@20.17.16)(typescript@5.7.3))
eslint-plugin-turbo@1.13.4(eslint@8.57.1):
dependencies:
@@ -15636,31 +15663,6 @@ snapshots:
ms@2.1.3: {}
- msw@2.7.1(@types/node@20.17.16)(typescript@4.9.5):
- dependencies:
- '@bundled-es-modules/cookie': 2.0.1
- '@bundled-es-modules/statuses': 1.0.1
- '@bundled-es-modules/tough-cookie': 0.1.6
- '@inquirer/confirm': 5.1.6(@types/node@20.17.16)
- '@mswjs/interceptors': 0.37.6
- '@open-draft/deferred-promise': 2.2.0
- '@open-draft/until': 2.1.0
- '@types/cookie': 0.6.0
- '@types/statuses': 2.0.5
- graphql: 16.10.0
- headers-polyfill: 4.0.3
- is-node-process: 1.2.0
- outvariant: 1.4.3
- path-to-regexp: 6.3.0
- picocolors: 1.1.1
- strict-event-emitter: 0.5.1
- type-fest: 4.33.0
- yargs: 17.7.2
- optionalDependencies:
- typescript: 4.9.5
- transitivePeerDependencies:
- - '@types/node'
-
msw@2.7.1(@types/node@20.17.16)(typescript@5.7.3):
dependencies:
'@bundled-es-modules/cookie': 2.0.1
@@ -15687,6 +15689,31 @@ snapshots:
- '@types/node'
optional: true
+ msw@2.7.1(@types/node@22.13.0)(typescript@4.9.5):
+ dependencies:
+ '@bundled-es-modules/cookie': 2.0.1
+ '@bundled-es-modules/statuses': 1.0.1
+ '@bundled-es-modules/tough-cookie': 0.1.6
+ '@inquirer/confirm': 5.1.6(@types/node@22.13.0)
+ '@mswjs/interceptors': 0.37.6
+ '@open-draft/deferred-promise': 2.2.0
+ '@open-draft/until': 2.1.0
+ '@types/cookie': 0.6.0
+ '@types/statuses': 2.0.5
+ graphql: 16.10.0
+ headers-polyfill: 4.0.3
+ is-node-process: 1.2.0
+ outvariant: 1.4.3
+ path-to-regexp: 6.3.0
+ picocolors: 1.1.1
+ strict-event-emitter: 0.5.1
+ type-fest: 4.33.0
+ yargs: 17.7.2
+ optionalDependencies:
+ typescript: 4.9.5
+ transitivePeerDependencies:
+ - '@types/node'
+
mute-stream@2.0.0: {}
mz@2.7.0:
@@ -16090,13 +16117,13 @@ snapshots:
camelcase-css: 2.0.1
postcss: 8.5.1
- postcss-load-config@3.1.4(postcss@8.5.1)(ts-node@10.9.2(@types/node@20.17.16)(typescript@4.9.5)):
+ postcss-load-config@3.1.4(postcss@8.5.1)(ts-node@10.9.2(@types/node@22.13.0)(typescript@4.9.5)):
dependencies:
lilconfig: 2.1.0
yaml: 1.10.2
optionalDependencies:
postcss: 8.5.1
- ts-node: 10.9.2(@types/node@20.17.16)(typescript@4.9.5)
+ ts-node: 10.9.2(@types/node@22.13.0)(typescript@4.9.5)
postcss-load-config@3.1.4(postcss@8.5.1)(ts-node@10.9.2(@types/node@22.13.0)(typescript@5.7.3)):
dependencies:
@@ -16114,13 +16141,13 @@ snapshots:
postcss: 8.5.1
ts-node: 10.9.2(@types/node@17.0.45)(typescript@5.7.3)
- postcss-load-config@4.0.2(postcss@8.5.1)(ts-node@10.9.2(@types/node@20.5.1)(typescript@5.7.3)):
+ postcss-load-config@4.0.2(postcss@8.5.1)(ts-node@10.9.2(@types/node@20.17.16)(typescript@5.7.3)):
dependencies:
lilconfig: 3.1.3
yaml: 2.7.0
optionalDependencies:
postcss: 8.5.1
- ts-node: 10.9.2(@types/node@20.17.16)(typescript@5.7.3)
+ ts-node: 10.9.2(@types/node@20.5.1)(typescript@5.7.3)
postcss-nested@6.2.0(postcss@8.5.1):
dependencies:
@@ -17316,9 +17343,9 @@ snapshots:
tailwind-merge@3.0.1: {}
- tailwindcss-animate@1.0.7(tailwindcss@3.4.6(ts-node@10.9.2(@types/node@20.5.1)(typescript@5.7.3))):
+ tailwindcss-animate@1.0.7(tailwindcss@3.4.6(ts-node@10.9.2(@types/node@20.17.16)(typescript@5.7.3))):
dependencies:
- tailwindcss: 3.4.6(ts-node@10.9.2(@types/node@20.5.1)(typescript@5.7.3))
+ tailwindcss: 3.4.6(ts-node@10.9.2(@types/node@20.17.16)(typescript@5.7.3))
tailwindcss@3.4.6(ts-node@10.9.2(@types/node@17.0.45)(typescript@5.7.3)):
dependencies:
@@ -17347,7 +17374,7 @@ snapshots:
transitivePeerDependencies:
- ts-node
- tailwindcss@3.4.6(ts-node@10.9.2(@types/node@20.5.1)(typescript@5.7.3)):
+ tailwindcss@3.4.6(ts-node@10.9.2(@types/node@20.17.16)(typescript@5.7.3)):
dependencies:
'@alloc/quick-lru': 5.2.0
arg: 5.0.2
@@ -17366,7 +17393,7 @@ snapshots:
postcss: 8.5.1
postcss-import: 15.1.0(postcss@8.5.1)
postcss-js: 4.0.1(postcss@8.5.1)
- postcss-load-config: 4.0.2(postcss@8.5.1)(ts-node@10.9.2(@types/node@20.5.1)(typescript@5.7.3))
+ postcss-load-config: 4.0.2(postcss@8.5.1)(ts-node@10.9.2(@types/node@20.17.16)(typescript@5.7.3))
postcss-nested: 6.2.0(postcss@8.5.1)
postcss-selector-parser: 6.1.2
resolve: 1.22.10
@@ -17534,14 +17561,32 @@ snapshots:
yn: 3.1.1
optional: true
- ts-node@10.9.2(@types/node@20.17.16)(typescript@4.9.5):
+ ts-node@10.9.2(@types/node@20.5.1)(typescript@5.7.3):
dependencies:
'@cspotcode/source-map-support': 0.8.1
'@tsconfig/node10': 1.0.11
'@tsconfig/node12': 1.0.11
'@tsconfig/node14': 1.0.3
'@tsconfig/node16': 1.0.4
- '@types/node': 20.17.16
+ '@types/node': 20.5.1
+ acorn: 8.14.0
+ acorn-walk: 8.3.4
+ arg: 4.1.3
+ create-require: 1.1.1
+ diff: 4.0.2
+ make-error: 1.3.6
+ typescript: 5.7.3
+ v8-compile-cache-lib: 3.0.1
+ yn: 3.1.1
+
+ ts-node@10.9.2(@types/node@22.13.0)(typescript@4.9.5):
+ dependencies:
+ '@cspotcode/source-map-support': 0.8.1
+ '@tsconfig/node10': 1.0.11
+ '@tsconfig/node12': 1.0.11
+ '@tsconfig/node14': 1.0.3
+ '@tsconfig/node16': 1.0.4
+ '@types/node': 22.13.0
acorn: 8.14.0
acorn-walk: 8.3.4
arg: 4.1.3
@@ -17553,24 +17598,6 @@ snapshots:
yn: 3.1.1
optional: true
- ts-node@10.9.2(@types/node@20.17.16)(typescript@5.7.3):
- dependencies:
- '@cspotcode/source-map-support': 0.8.1
- '@tsconfig/node10': 1.0.11
- '@tsconfig/node12': 1.0.11
- '@tsconfig/node14': 1.0.3
- '@tsconfig/node16': 1.0.4
- '@types/node': 20.17.16
- acorn: 8.14.0
- acorn-walk: 8.3.4
- arg: 4.1.3
- create-require: 1.1.1
- diff: 4.0.2
- make-error: 1.3.6
- typescript: 5.7.3
- v8-compile-cache-lib: 3.0.1
- yn: 3.1.1
-
ts-node@10.9.2(@types/node@22.13.0)(typescript@5.7.3):
dependencies:
'@cspotcode/source-map-support': 0.8.1
@@ -17615,7 +17642,7 @@ snapshots:
tslib@2.8.1: {}
- tsup@6.7.0(postcss@8.5.1)(ts-node@10.9.2(@types/node@20.17.16)(typescript@4.9.5))(typescript@4.9.5):
+ tsup@6.7.0(postcss@8.5.1)(ts-node@10.9.2(@types/node@22.13.0)(typescript@4.9.5))(typescript@4.9.5):
dependencies:
bundle-require: 4.2.1(esbuild@0.17.19)
cac: 6.7.14
@@ -17625,7 +17652,7 @@ snapshots:
execa: 5.1.1
globby: 11.1.0
joycon: 3.1.1
- postcss-load-config: 3.1.4(postcss@8.5.1)(ts-node@10.9.2(@types/node@20.17.16)(typescript@4.9.5))
+ postcss-load-config: 3.1.4(postcss@8.5.1)(ts-node@10.9.2(@types/node@22.13.0)(typescript@4.9.5))
resolve-from: 5.0.0
rollup: 3.29.5
source-map: 0.8.0-beta.0