mirror of
https://github.com/shadcn-ui/ui.git
synced 2026-07-02 00:54:15 +00:00
feat(cli): add support for custom Tailwind prefix transformer (#770)
* feat(cli): add support for custom Tailwind prefix * fix(cli): add tw prefix on classes applied in the css file * feat(cli): add support for custom tailwind prefix * chore: add changeset * style(shadcn-ui): code format --------- Co-authored-by: shadcn <m@shadcn.com>
This commit is contained in:
@@ -0,0 +1,118 @@
|
||||
// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html
|
||||
|
||||
exports[`transform tailwind prefix 1`] = `
|
||||
"import * as React from \\"react\\"
|
||||
export function Foo() {
|
||||
return (
|
||||
<div
|
||||
className=\\"tw-bg-background hover:tw-bg-muted tw-text-primary-foreground sm:focus:tw-text-accent-foreground\\">foo</div>
|
||||
);
|
||||
}
|
||||
"
|
||||
`;
|
||||
|
||||
exports[`transform tailwind prefix 2`] = `
|
||||
"import * as React from \\"react\\"
|
||||
export function Foo() {
|
||||
return (
|
||||
<div
|
||||
className=\\"tw-bg-white hover:tw-bg-stone-100 tw-text-stone-50 sm:focus:tw-text-stone-900 dark:tw-bg-stone-950 dark:hover:tw-bg-stone-800 dark:tw-text-stone-900 dark:sm:focus:tw-text-stone-50\\">foo</div>
|
||||
);
|
||||
}
|
||||
"
|
||||
`;
|
||||
|
||||
exports[`transform tailwind prefix 3`] = `
|
||||
"import * as React from \\"react\\"
|
||||
export function Foo() {
|
||||
return (
|
||||
<div
|
||||
className={cn(
|
||||
\\"tw-bg-white hover:tw-bg-stone-100 dark:tw-bg-stone-950 dark:hover:tw-bg-stone-800\\",
|
||||
true && \\"tw-text-stone-50 sm:focus:tw-text-stone-900 dark:tw-text-stone-900 dark:sm:focus:tw-text-stone-50\\"
|
||||
)}>foo</div>
|
||||
);
|
||||
}
|
||||
"
|
||||
`;
|
||||
|
||||
exports[`transform tailwind prefix 4`] = `
|
||||
"@tailwind base;
|
||||
@tailwind components;
|
||||
@tailwind utilities;
|
||||
|
||||
@layer base {
|
||||
:root {
|
||||
--background: 0 0% 100%;
|
||||
--foreground: 224 71.4% 4.1%;
|
||||
|
||||
--muted: 220 14.3% 95.9%;
|
||||
--muted-foreground: 220 8.9% 46.1%;
|
||||
|
||||
--popover: 0 0% 100%;
|
||||
--popover-foreground: 224 71.4% 4.1%;
|
||||
|
||||
--card: 0 0% 100%;
|
||||
--card-foreground: 224 71.4% 4.1%;
|
||||
|
||||
--border: 220 13% 91%;
|
||||
--input: 220 13% 91%;
|
||||
|
||||
--primary: 220.9 39.3% 11%;
|
||||
--primary-foreground: 210 20% 98%;
|
||||
|
||||
--secondary: 220 14.3% 95.9%;
|
||||
--secondary-foreground: 220.9 39.3% 11%;
|
||||
|
||||
--accent: 220 14.3% 95.9%;
|
||||
--accent-foreground: 220.9 39.3% 11%;
|
||||
|
||||
--destructive: 0 84.2% 60.2%;
|
||||
--destructive-foreground: 210 20% 98%;
|
||||
|
||||
--ring: 217.9 10.6% 64.9%;
|
||||
|
||||
--radius: 0.5rem;
|
||||
}
|
||||
|
||||
.dark {
|
||||
--background: 224 71.4% 4.1%;
|
||||
--foreground: 210 20% 98%;
|
||||
|
||||
--muted: 215 27.9% 16.9%;
|
||||
--muted-foreground: 217.9 10.6% 64.9%;
|
||||
|
||||
--popover: 224 71.4% 4.1%;
|
||||
--popover-foreground: 210 20% 98%;
|
||||
|
||||
--card: 224 71.4% 4.1%;
|
||||
--card-foreground: 210 20% 98%;
|
||||
|
||||
--border: 215 27.9% 16.9%;
|
||||
--input: 215 27.9% 16.9%;
|
||||
|
||||
--primary: 210 20% 98%;
|
||||
--primary-foreground: 220.9 39.3% 11%;
|
||||
|
||||
--secondary: 215 27.9% 16.9%;
|
||||
--secondary-foreground: 210 20% 98%;
|
||||
|
||||
--accent: 215 27.9% 16.9%;
|
||||
--accent-foreground: 210 20% 98%;
|
||||
|
||||
--destructive: 0 62.8% 30.6%;
|
||||
--destructive-foreground: 0 85.7% 97.3%;
|
||||
|
||||
--ring: 215 27.9% 16.9%;
|
||||
}
|
||||
}
|
||||
|
||||
@layer base {
|
||||
* {
|
||||
@apply tw-border-border;
|
||||
}
|
||||
body {
|
||||
@apply tw-bg-background tw-text-foreground;
|
||||
}
|
||||
}"
|
||||
`;
|
||||
42
packages/cli/test/utils/apply-prefix.test.ts
Normal file
42
packages/cli/test/utils/apply-prefix.test.ts
Normal file
@@ -0,0 +1,42 @@
|
||||
import { describe, expect, test } from "vitest"
|
||||
|
||||
import { applyPrefix } from "../../src/utils/transformers/transform-tw-prefix"
|
||||
|
||||
describe("apply tailwind prefix", () => {
|
||||
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: "hover:dark:tw-bg-background dark:tw-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 dark:tw-border-slate-800 dark:tw-bg-slate-950 dark:tw-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 dark:tw-border-red-500 [&>svg]:tw-text-red-500 tw-text-red-500 dark:tw-text-red-900 dark:tw-border-red-900/50 dark:dark:tw-border-red-900 dark:[&>svg]:tw-text-red-900 dark:tw-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 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)
|
||||
})
|
||||
})
|
||||
@@ -91,6 +91,7 @@ test("get config", async () => {
|
||||
baseColor: "zinc",
|
||||
css: "src/app/globals.css",
|
||||
cssVariables: true,
|
||||
prefix: "tw-"
|
||||
},
|
||||
aliases: {
|
||||
components: "~/components",
|
||||
|
||||
82
packages/cli/test/utils/transform-tw-prefix.test.ts
Normal file
82
packages/cli/test/utils/transform-tw-prefix.test.ts
Normal file
@@ -0,0 +1,82 @@
|
||||
import { expect, test } from "vitest"
|
||||
|
||||
import { transform } from "../../src/utils/transformers"
|
||||
import { applyPrefixesCss } from "../../src/utils/transformers/transform-tw-prefix"
|
||||
import stone from "../fixtures/colors/stone.json"
|
||||
|
||||
test("transform tailwind prefix", async () => {
|
||||
expect(
|
||||
await transform({
|
||||
filename: "test.ts",
|
||||
raw: `import * as React from "react"
|
||||
export function Foo() {
|
||||
return <div className="bg-background hover:bg-muted text-primary-foreground sm:focus:text-accent-foreground">foo</div>
|
||||
}
|
||||
`,
|
||||
config: {
|
||||
tailwind: {
|
||||
baseColor: "stone",
|
||||
prefix: "tw-",
|
||||
},
|
||||
aliases: {
|
||||
components: "@/components",
|
||||
utils: "@/lib/utils",
|
||||
},
|
||||
},
|
||||
baseColor: "stone",
|
||||
})
|
||||
).toMatchSnapshot()
|
||||
|
||||
expect(
|
||||
await transform({
|
||||
filename: "test.ts",
|
||||
raw: `import * as React from "react"
|
||||
export function Foo() {
|
||||
return <div className="bg-background hover:bg-muted text-primary-foreground sm:focus:text-accent-foreground">foo</div>
|
||||
}
|
||||
`,
|
||||
config: {
|
||||
tailwind: {
|
||||
baseColor: "stone",
|
||||
cssVariables: false,
|
||||
prefix: "tw-",
|
||||
},
|
||||
aliases: {
|
||||
components: "@/components",
|
||||
utils: "@/lib/utils",
|
||||
},
|
||||
},
|
||||
baseColor: stone,
|
||||
})
|
||||
).toMatchSnapshot()
|
||||
|
||||
expect(
|
||||
await transform({
|
||||
filename: "test.ts",
|
||||
raw: `import * as React from "react"
|
||||
export function Foo() {
|
||||
return <div className={cn("bg-background hover:bg-muted", true && "text-primary-foreground sm:focus:text-accent-foreground")}>foo</div>
|
||||
}
|
||||
`,
|
||||
config: {
|
||||
tailwind: {
|
||||
baseColor: "stone",
|
||||
cssVariables: false,
|
||||
prefix: "tw-",
|
||||
},
|
||||
aliases: {
|
||||
components: "@/components",
|
||||
utils: "@/lib/utils",
|
||||
},
|
||||
},
|
||||
baseColor: stone,
|
||||
})
|
||||
).toMatchSnapshot()
|
||||
|
||||
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-"
|
||||
)
|
||||
).toMatchSnapshot()
|
||||
})
|
||||
Reference in New Issue
Block a user