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:
Bereket Engida
2023-12-22 00:42:40 +03:00
committed by GitHub
parent 1cf5fad881
commit 4fb98d520f
11 changed files with 477 additions and 3 deletions

View File

@@ -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;
}
}"
`;

View 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)
})
})

View File

@@ -91,6 +91,7 @@ test("get config", async () => {
baseColor: "zinc",
css: "src/app/globals.css",
cssVariables: true,
prefix: "tw-"
},
aliases: {
components: "~/components",

View 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()
})