Compare commits

..

12 Commits

Author SHA1 Message Date
github-actions[bot]
061083006f chore(release): version packages (#4857)
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
2024-09-15 13:40:31 +04:00
Jack Herrington
1af66c2d08 Adding support for ~ in target specification (#4848)
* Adding support for ~ in target specification

* test(shadcn): add a test for srcDir false

* chore: changeset

---------

Co-authored-by: shadcn <m@shadcn.com>
2024-09-15 13:27:48 +04:00
shadcn
0993d98cc7 ci: update stale config (#4858) 2024-09-15 13:25:06 +04:00
Hichem Fantar
52d223393a (fix Input) choose file text color in dark mode (#4843)
This pull request fixes the issue with the choose file text color in dark mode. The changes ensure that the text color is correctly displayed in dark mode.

the reason this bug doesn't happen in the shadcn website is because it sets `color-scheme:dark` on the document;

this fix makes sure this always works even if color scheme isn't set.

Closes #4842

![image](https://github.com/user-attachments/assets/37cb3f2a-c1a7-49b3-8ef1-77823dd7bd45)

![image](https://github.com/user-attachments/assets/92913fec-5651-4cfc-8e16-2f12c06c33b8)
2024-09-15 09:20:19 +00:00
Shivang Rathore
207b69fe8d fix(cli): Ensure .scss files are considered in getTailwindCssFile (#4797)
* fix(cli): Ensure .scss files are considered in getTailwindCssFile

- Updated getTailwindCssFile function to include .scss files when checking for Tailwind CSS configuration.
- This change ensures that .scss files are properly identified and handled, improving compatibility with projects using SCSS.

* chore: add changeset

---------

Co-authored-by: shadcn <m@shadcn.com>
2024-09-15 12:55:08 +04:00
Rana Haris Ali
408760a93b fix: correct grammar in "path does not contain a package.json" message (#4815)
* fix: correct grammar in "path does not contain a package.json" message

* chore: add changeset

---------

Co-authored-by: shadcn <m@shadcn.com>
2024-09-15 12:51:23 +04:00
Devansh Mahant
a9ab7afebf Fix Incorrect Hook Import Path in Toast Component Example in ShadCN Docs (#4811)
#### Summary:
This pull request addresses a documentation error found in the ShadCN website's Toast component example. Specifically, the import route for the hook is incorrect in the example. and fixes [#4816](https://github.com/shadcn-ui/ui/issues/4816)

#### Issue:
Upon reviewing the [ShadCN Toast documentation](https://ui.shadcn.com/docs/components/toast), I found that the import path for the Toast component hook was wrongly mentioned as being located in the `components` folder. According to the `component.json` file, the correct location of the hook is within the `hooks` folder inside the main directory.

#### Fix:
- Corrected the import path in the Toast component example from `components` to `hooks`, as per the `component.json` file structure.

#### Example of Fix:
**Before:**
```js
import { useToast } from "@/components/use-toast";
```

**After:**
```js
import { useToast } from "@/hooks/use-toast";
```

#### Testing:
- Verified that the corrected path resolves correctly.
- Ensured the example works as expected after the change.

#### Impact:
This fix prevents confusion for users following the example and ensures that the import path accurately reflects the project structure, improving the overall developer experience.
2024-09-15 08:45:29 +00:00
Quinn Blenkinsop
b6221ea524 fix(www): update broken link to headless ui (#3542)
The link appears to have broken at some point, I've updated it

Co-authored-by: shadcn <m@shadcn.com>
2024-09-15 12:31:28 +04:00
github-actions[bot]
9ef7967b0d chore(release): version packages (#4821)
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
2024-09-12 17:54:41 +04:00
shadcn
64b2f1a5ad feat(shadcn): add experimental docs (#4820)
* feat(shadcn): add cli docs

* chore: add changeset

* fix: tests
2024-09-12 17:51:59 +04:00
github-actions[bot]
f4ca57a79c chore(release): version packages (#4788)
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
2024-09-09 12:34:19 +04:00
shadcn
99ff9caf71 fix(shadcn): add src to content in tailwind config (#4787)
* feat(shadcn): handle src dir

* chore: changeset
2024-09-09 12:32:12 +04:00
25 changed files with 421 additions and 19 deletions

View File

@@ -16,11 +16,12 @@ jobs:
name: "Close stale issues with no reproduction"
with:
repo-token: ${{ secrets.STALE_TOKEN }}
close-issue-message: "This issue has been automatically closed because it received no activity for a while. If you think it was closed by accident, please leave a comment. Thank you."
close-issue-message: "This issue has been automatically closed because it received no activity for a while. If you think it was closed by accident, please reopen or leave a comment. Thank you.\n(This is an automated message.)"
days-before-issue-close: 7
days-before-issue-stale: 15
days-before-issue-stale: 30
stale-pr-label: "stale?"
days-before-pr-close: -1
days-before-pr-stale: -1
days-before-pr-close: 7
days-before-pr-stale: 15
only-pr-labels: "postpone: more info or changes requested,please add a reproduction"
exempt-issue-labels: "roadmap,next,bug"
operations-per-run: 300 # 1 operation per 100 issues, the rest is to label/comment/close

View File

@@ -12,7 +12,7 @@ links:
Every data table or datagrid I've created has been unique. They all behave differently, have specific sorting and filtering requirements, and work with different data sources.
It doesn't make sense to combine all of these variations into a single component. If we do that, we'll lose the flexibility that [headless UI](https://tanstack.com/table/v8/docs/guide/introduction#what-is-headless-ui) provides.
It doesn't make sense to combine all of these variations into a single component. If we do that, we'll lose the flexibility that [headless UI](https://tanstack.com/table/v8/docs/introduction#what-is-headless-ui) provides.
So instead of a data-table component, I thought it would be more helpful to provide a guide on how to build your own.

View File

@@ -104,7 +104,7 @@ export default function RootLayout({ children }) {
The `useToast` hook returns a `toast` function that you can use to display a toast.
```tsx
import { useToast } from "@/components/hooks/use-toast"
import { useToast } from "@/hooks/use-toast"
```
```tsx {2,7-10}

View File

@@ -4,7 +4,7 @@
"files": [
{
"path": "ui/input.tsx",
"content": "import * as React from \"react\"\n\nimport { cn } from \"@/lib/utils\"\n\nexport interface InputProps\n extends React.InputHTMLAttributes<HTMLInputElement> {}\n\nconst Input = React.forwardRef<HTMLInputElement, InputProps>(\n ({ className, type, ...props }, ref) => {\n return (\n <input\n type={type}\n className={cn(\n \"flex h-10 w-full rounded-md border border-input bg-background px-3 py-2 text-sm ring-offset-background file:border-0 file:bg-transparent file:text-sm file:font-medium placeholder:text-muted-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50\",\n className\n )}\n ref={ref}\n {...props}\n />\n )\n }\n)\nInput.displayName = \"Input\"\n\nexport { Input }\n",
"content": "import * as React from \"react\"\n\nimport { cn } from \"@/lib/utils\"\n\nexport interface InputProps\n extends React.InputHTMLAttributes<HTMLInputElement> {}\n\nconst Input = React.forwardRef<HTMLInputElement, InputProps>(\n ({ className, type, ...props }, ref) => {\n return (\n <input\n type={type}\n className={cn(\n \"flex h-10 w-full rounded-md border border-input bg-background px-3 py-2 text-sm ring-offset-background file:border-0 file:bg-transparent file:text-sm file:font-medium file:text-foreground placeholder:text-muted-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50\",\n className\n )}\n ref={ref}\n {...props}\n />\n )\n }\n)\nInput.displayName = \"Input\"\n\nexport { Input }\n",
"type": "registry:ui",
"target": ""
}

View File

@@ -4,7 +4,7 @@
"files": [
{
"path": "ui/input.tsx",
"content": "import * as React from \"react\"\n\nimport { cn } from \"@/lib/utils\"\n\nexport interface InputProps\n extends React.InputHTMLAttributes<HTMLInputElement> {}\n\nconst Input = React.forwardRef<HTMLInputElement, InputProps>(\n ({ className, type, ...props }, ref) => {\n return (\n <input\n type={type}\n className={cn(\n \"flex h-9 w-full rounded-md border border-input bg-transparent px-3 py-1 text-sm shadow-sm transition-colors file:border-0 file:bg-transparent file:text-sm file:font-medium placeholder:text-muted-foreground focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring disabled:cursor-not-allowed disabled:opacity-50\",\n className\n )}\n ref={ref}\n {...props}\n />\n )\n }\n)\nInput.displayName = \"Input\"\n\nexport { Input }\n",
"content": "import * as React from \"react\"\n\nimport { cn } from \"@/lib/utils\"\n\nexport interface InputProps\n extends React.InputHTMLAttributes<HTMLInputElement> {}\n\nconst Input = React.forwardRef<HTMLInputElement, InputProps>(\n ({ className, type, ...props }, ref) => {\n return (\n <input\n type={type}\n className={cn(\n \"flex h-9 w-full rounded-md border border-input bg-transparent px-3 py-1 text-sm shadow-sm transition-colors file:border-0 file:bg-transparent file:text-sm file:font-medium file:text-foreground placeholder:text-muted-foreground focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring disabled:cursor-not-allowed disabled:opacity-50\",\n className\n )}\n ref={ref}\n {...props}\n />\n )\n }\n)\nInput.displayName = \"Input\"\n\nexport { Input }\n",
"type": "registry:ui",
"target": ""
}

View File

@@ -11,7 +11,7 @@ const Input = React.forwardRef<HTMLInputElement, InputProps>(
<input
type={type}
className={cn(
"flex h-10 w-full rounded-md border border-input bg-background px-3 py-2 text-sm ring-offset-background file:border-0 file:bg-transparent file:text-sm file:font-medium placeholder:text-muted-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50",
"flex h-10 w-full rounded-md border border-input bg-background px-3 py-2 text-sm ring-offset-background file:border-0 file:bg-transparent file:text-sm file:font-medium file:text-foreground placeholder:text-muted-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50",
className
)}
ref={ref}

View File

@@ -11,7 +11,7 @@ const Input = React.forwardRef<HTMLInputElement, InputProps>(
<input
type={type}
className={cn(
"flex h-9 w-full rounded-md border border-input bg-transparent px-3 py-1 text-sm shadow-sm transition-colors file:border-0 file:bg-transparent file:text-sm file:font-medium placeholder:text-muted-foreground focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring disabled:cursor-not-allowed disabled:opacity-50",
"flex h-9 w-full rounded-md border border-input bg-transparent px-3 py-1 text-sm shadow-sm transition-colors file:border-0 file:bg-transparent file:text-sm file:font-medium file:text-foreground placeholder:text-muted-foreground focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring disabled:cursor-not-allowed disabled:opacity-50",
className
)}
ref={ref}

View File

@@ -62,6 +62,7 @@ export const registryEntrySchema = z.object({
category: z.string().optional(),
subcategory: z.string().optional(),
chunks: z.array(blockChunkSchema).optional(),
docs: z.string().optional(),
})
export const registrySchema = z.array(registryEntrySchema)

View File

@@ -1,5 +1,11 @@
# @shadcn/ui
## 0.9.1
### Patch Changes
- [#4797](https://github.com/shadcn-ui/ui/pull/4797) [`207b69f`](https://github.com/shadcn-ui/ui/commit/207b69fe8dd59b10dddc9337d333416976e2a30d) Thanks [@Wiper-R](https://github.com/Wiper-R)! - add scss support
## 0.9.0
### Minor Changes

View File

@@ -1,6 +1,6 @@
{
"name": "shadcn-ui",
"version": "0.9.0",
"version": "0.9.1",
"description": "Add components to your apps.",
"publishConfig": {
"access": "public"

View File

@@ -133,7 +133,7 @@ export async function getProjectType(cwd: string): Promise<ProjectType | null> {
}
export async function getTailwindCssFile(cwd: string) {
const files = await fg.glob("**/*.css", {
const files = await fg.glob(["**/*.css", "**/*.scss"], {
cwd,
deep: 3,
ignore: PROJECT_SHARED_IGNORE,

View File

@@ -1,5 +1,25 @@
# @shadcn/ui
## 2.0.7
### Patch Changes
- [#4848](https://github.com/shadcn-ui/ui/pull/4848) [`1af66c2`](https://github.com/shadcn-ui/ui/commit/1af66c2d08df7dd7f6a8d4d1544d965e41a1fb0d) Thanks [@jherr](https://github.com/jherr)! - add support for ~ dir in target path
- [#4815](https://github.com/shadcn-ui/ui/pull/4815) [`408760a`](https://github.com/shadcn-ui/ui/commit/408760a93b398b7d02a0a522a74a7a195ccda7c4) Thanks [@rana-haris-ali](https://github.com/rana-haris-ali)! - fix typo in error message
## 2.0.6
### Patch Changes
- [#4820](https://github.com/shadcn-ui/ui/pull/4820) [`64b2f1a`](https://github.com/shadcn-ui/ui/commit/64b2f1a5ad865c831045c954fec85e0fec2289e7) Thanks [@shadcn](https://github.com/shadcn)! - add docs support
## 2.0.5
### Patch Changes
- [#4787](https://github.com/shadcn-ui/ui/pull/4787) [`99ff9ca`](https://github.com/shadcn-ui/ui/commit/99ff9caf7180c8c19df130969bdef3d0fb78b218) Thanks [@shadcn](https://github.com/shadcn)! - add src to content for tailwind
## 2.0.4
### Patch Changes

View File

@@ -1,6 +1,6 @@
{
"name": "shadcn",
"version": "2.0.4",
"version": "2.0.7",
"description": "Add components to your apps.",
"publishConfig": {
"access": "public"

View File

@@ -20,6 +20,7 @@ import { highlighter } from "@/src/utils/highlighter"
import { logger } from "@/src/utils/logger"
import { getRegistryBaseColors, getRegistryStyles } from "@/src/utils/registry"
import { spinner } from "@/src/utils/spinner"
import { updateTailwindContent } from "@/src/utils/updaters/update-tailwind-content"
import { Command } from "commander"
import prompts from "prompts"
import { z } from "zod"
@@ -137,6 +138,18 @@ export async function runInit(
options.isNewProject || projectInfo?.framework.name === "next-app",
})
// If a new project is using src dir, let's update the tailwind content config.
// TODO: Handle this per framework.
if (options.isNewProject && options.srcDir) {
await updateTailwindContent(
["./src/**/*.{js,ts,jsx,tsx,mdx}"],
fullConfig,
{
silent: options.silent,
}
)
}
return fullConfig
}

View File

@@ -1,5 +1,6 @@
import { type Config } from "@/src/utils/get-config"
import { handleError } from "@/src/utils/handle-error"
import { logger } from "@/src/utils/logger"
import { registryResolveItemsTree } from "@/src/utils/registry"
import { spinner } from "@/src/utils/spinner"
import { updateCssVars } from "@/src/utils/updaters/update-css-vars"
@@ -48,4 +49,8 @@ export async function addComponents(
overwrite: options.overwrite,
silent: options.silent,
})
if (tree.docs) {
logger.info(tree.docs)
}
}

View File

@@ -23,7 +23,7 @@ export async function createProject(
name: "proceed",
message: `The path ${highlighter.info(
options.cwd
)} is does not contain a package.json file. Would you like to start a new ${highlighter.info(
)} does not contain a package.json file. Would you like to start a new ${highlighter.info(
"Next.js"
)} project?`,
initial: true,

View File

@@ -321,6 +321,13 @@ export async function registryResolveItemsTree(
cssVars = deepmerge(cssVars, item.cssVars ?? {})
})
let docs = ""
payload.forEach((item) => {
if (item.docs) {
docs += `${item.docs}\n`
}
})
return registryResolvedItemsTreeSchema.parse({
dependencies: deepmerge.all(
payload.map((item) => item.dependencies ?? [])
@@ -331,6 +338,7 @@ export async function registryResolveItemsTree(
files: deepmerge.all(payload.map((item) => item.files ?? [])),
tailwind,
cssVars,
docs,
})
} catch (error) {
handleError(error)

View File

@@ -46,6 +46,7 @@ export const registryItemSchema = z.object({
tailwind: registryItemTailwindSchema.optional(),
cssVars: registryItemCssVarsSchema.optional(),
meta: z.record(z.string(), z.any()).optional(),
docs: z.string().optional(),
})
export type RegistryItem = z.infer<typeof registryItemSchema>
@@ -82,4 +83,5 @@ export const registryResolvedItemsTreeSchema = registryItemSchema.pick({
files: true,
tailwind: true,
cssVars: true,
docs: true,
})

View File

@@ -17,6 +17,19 @@ import { transformRsc } from "@/src/utils/transformers/transform-rsc"
import { transformTwPrefixes } from "@/src/utils/transformers/transform-tw-prefix"
import prompts from "prompts"
export function resolveTargetDir(
projectInfo: Awaited<ReturnType<typeof getProjectInfo>>,
config: Config,
target: string
) {
if (target.startsWith("~/")) {
return path.join(config.resolvedPaths.cwd, target.replace("~/", ""))
}
return projectInfo?.isSrcDir
? path.join(config.resolvedPaths.cwd, "src", target)
: path.join(config.resolvedPaths.cwd, target)
}
export async function updateFiles(
files: RegistryItem["files"],
config: Config,
@@ -58,9 +71,7 @@ export async function updateFiles(
let filePath = path.join(targetDir, fileName)
if (file.target) {
filePath = projectInfo?.isSrcDir
? path.join(config.resolvedPaths.cwd, "src", file.target)
: path.join(config.resolvedPaths.cwd, file.target)
filePath = resolveTargetDir(projectInfo, config, file.target)
targetDir = path.dirname(filePath)
}

View File

@@ -249,7 +249,7 @@ function addTailwindConfigPlugin(
return configObject
}
async function _createSourceFile(input: string, config: Config | null) {
export async function _createSourceFile(input: string, config: Config | null) {
const dir = await fs.mkdtemp(path.join(tmpdir(), "shadcn-"))
const resolvedPath =
config?.resolvedPaths?.tailwindConfig || "tailwind.config.ts"
@@ -268,7 +268,7 @@ async function _createSourceFile(input: string, config: Config | null) {
return sourceFile
}
function _getQuoteChar(configObject: ObjectLiteralExpression) {
export function _getQuoteChar(configObject: ObjectLiteralExpression) {
return configObject
.getFirstDescendantByKind(SyntaxKind.StringLiteral)
?.getQuoteKind() === QuoteKind.Single

View File

@@ -0,0 +1,121 @@
import { promises as fs } from "fs"
import path from "path"
import { Config } from "@/src/utils/get-config"
import { highlighter } from "@/src/utils/highlighter"
import { spinner } from "@/src/utils/spinner"
import {
_createSourceFile,
_getQuoteChar,
} from "@/src/utils/updaters/update-tailwind-config"
import { ObjectLiteralExpression, SyntaxKind } from "ts-morph"
export async function updateTailwindContent(
content: string[],
config: Config,
options: {
silent?: boolean
}
) {
if (!content) {
return
}
options = {
silent: false,
...options,
}
const tailwindFileRelativePath = path.relative(
config.resolvedPaths.cwd,
config.resolvedPaths.tailwindConfig
)
const tailwindSpinner = spinner(
`Updating ${highlighter.info(tailwindFileRelativePath)}`,
{
silent: options.silent,
}
).start()
const raw = await fs.readFile(config.resolvedPaths.tailwindConfig, "utf8")
const output = await transformTailwindContent(raw, content, config)
await fs.writeFile(config.resolvedPaths.tailwindConfig, output, "utf8")
tailwindSpinner?.succeed()
}
export async function transformTailwindContent(
input: string,
content: string[],
config: Config
) {
const sourceFile = await _createSourceFile(input, config)
// Find the object with content property.
// This is faster than traversing the default export.
// TODO: maybe we do need to traverse the default export?
const configObject = sourceFile
.getDescendantsOfKind(SyntaxKind.ObjectLiteralExpression)
.find((node) =>
node
.getProperties()
.some(
(property) =>
property.isKind(SyntaxKind.PropertyAssignment) &&
property.getName() === "content"
)
)
// We couldn't find the config object, so we return the input as is.
if (!configObject) {
return input
}
addTailwindConfigContent(configObject, content)
return sourceFile.getFullText()
}
async function addTailwindConfigContent(
configObject: ObjectLiteralExpression,
content: string[]
) {
const quoteChar = _getQuoteChar(configObject)
const existingProperty = configObject.getProperty("content")
if (!existingProperty) {
const newProperty = {
name: "content",
initializer: `[${quoteChar}${content.join(
`${quoteChar}, ${quoteChar}`
)}${quoteChar}]`,
}
configObject.addPropertyAssignment(newProperty)
return configObject
}
if (existingProperty.isKind(SyntaxKind.PropertyAssignment)) {
const initializer = existingProperty.getInitializer()
// If property is an array, append.
if (initializer?.isKind(SyntaxKind.ArrayLiteralExpression)) {
for (const contentItem of content) {
const newValue = `${quoteChar}${contentItem}${quoteChar}`
// Check if the array already contains the value.
if (
initializer
.getElements()
.map((element) => element.getText())
.includes(newValue)
) {
continue
}
initializer.addElement(newValue)
}
}
return configObject
}
return configObject
}

View File

@@ -20,6 +20,7 @@ exports[`registryResolveItemTree > should resolve index 1`] = `
"tailwind-merge",
],
"devDependencies": [],
"docs": "",
"files": [
{
"content": ""use client"
@@ -93,6 +94,7 @@ exports[`registryResolveItemTree > should resolve items tree 1`] = `
"@radix-ui/react-slot",
],
"devDependencies": [],
"docs": "",
"files": [
{
"content": "import * as React from "react"
@@ -171,6 +173,7 @@ exports[`registryResolveItemTree > should resolve multiple items tree 1`] = `
"@radix-ui/react-dialog",
],
"devDependencies": [],
"docs": "",
"files": [
{
"content": "import * as React from "react"

View File

@@ -0,0 +1,52 @@
// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html
exports[`transformTailwindContent -> content property > should NOT add content property if already in config 1`] = `
"import type { Config } from 'tailwindcss'
const config: Config = {
content: [
"./pages/**/*.{js,ts,jsx,tsx,mdx}",
"./components/**/*.{js,ts,jsx,tsx,mdx}",
"./app/**/*.{js,ts,jsx,tsx,mdx}",
"./bar/**/*.{js,ts,jsx,tsx,mdx}"
],
theme: {
extend: {
backgroundImage: {
"gradient-radial": "radial-gradient(var(--tw-gradient-stops))",
"gradient-conic":
"conic-gradient(from 180deg at 50% 50%, var(--tw-gradient-stops))",
},
},
},
plugins: [],
}
export default config
"
`;
exports[`transformTailwindContent -> content property > should add content property if not in config 1`] = `
"import type { Config } from 'tailwindcss'
const config: Config = {
content: [
"./pages/**/*.{js,ts,jsx,tsx,mdx}",
"./components/**/*.{js,ts,jsx,tsx,mdx}",
"./app/**/*.{js,ts,jsx,tsx,mdx}",
"./foo/**/*.{js,ts,jsx,tsx,mdx}",
"./bar/**/*.{js,ts,jsx,tsx,mdx}"
],
theme: {
extend: {
backgroundImage: {
"gradient-radial": "radial-gradient(var(--tw-gradient-stops))",
"gradient-conic":
"conic-gradient(from 180deg at 50% 50%, var(--tw-gradient-stops))",
},
},
},
plugins: [],
}
export default config
"
`;

View File

@@ -0,0 +1,65 @@
import { describe, expect, test } from "vitest"
import { resolveTargetDir } from "../../../src/utils/updaters/update-files"
describe("resolveTargetDir", () => {
test("should handle a home target without a src directory", () => {
const targetDir = resolveTargetDir(
{
isSrcDir: false,
},
{
resolvedPaths: {
cwd: "/foo/bar",
},
},
"~/.env"
)
expect(targetDir).toBe("/foo/bar/.env")
})
test("should handle a home target even with a src directory", () => {
const targetDir = resolveTargetDir(
{
isSrcDir: true,
},
{
resolvedPaths: {
cwd: "/foo/bar",
},
},
"~/.env"
)
expect(targetDir).toBe("/foo/bar/.env")
})
test("should handle a simple target", () => {
const targetDir = resolveTargetDir(
{
isSrcDir: false,
},
{
resolvedPaths: {
cwd: "/foo/bar",
},
},
"./components/ui/button.tsx"
)
expect(targetDir).toBe("/foo/bar/components/ui/button.tsx")
})
test("should handle a simple target with src directory", () => {
const targetDir = resolveTargetDir(
{
isSrcDir: true,
},
{
resolvedPaths: {
cwd: "/foo/bar",
},
},
"./components/ui/button.tsx"
)
expect(targetDir).toBe("/foo/bar/src/components/ui/button.tsx")
})
})

View File

@@ -0,0 +1,94 @@
import { describe, expect, test } from "vitest"
import { transformTailwindContent } from "../../../src/utils/updaters/update-tailwind-content"
const SHARED_CONFIG = {
$schema: "https://ui.shadcn.com/schema.json",
style: "new-york",
rsc: true,
tsx: true,
tailwind: {
config: "tailwind.config.ts",
css: "app/globals.css",
baseColor: "slate",
cssVariables: true,
},
aliases: {
components: "@/components",
utils: "@/lib/utils",
},
resolvedPaths: {
cwd: ".",
tailwindConfig: "tailwind.config.ts",
tailwindCss: "app/globals.css",
components: "./components",
utils: "./lib/utils",
ui: "./components/ui",
},
}
describe("transformTailwindContent -> content property", () => {
test("should add content property if not in config", async () => {
expect(
await transformTailwindContent(
`import type { Config } from 'tailwindcss'
const config: Config = {
content: [
"./pages/**/*.{js,ts,jsx,tsx,mdx}",
"./components/**/*.{js,ts,jsx,tsx,mdx}",
"./app/**/*.{js,ts,jsx,tsx,mdx}",
],
theme: {
extend: {
backgroundImage: {
"gradient-radial": "radial-gradient(var(--tw-gradient-stops))",
"gradient-conic":
"conic-gradient(from 180deg at 50% 50%, var(--tw-gradient-stops))",
},
},
},
plugins: [],
}
export default config
`,
["./foo/**/*.{js,ts,jsx,tsx,mdx}", "./bar/**/*.{js,ts,jsx,tsx,mdx}"],
{
config: SHARED_CONFIG,
}
)
).toMatchSnapshot()
})
test("should NOT add content property if already in config", async () => {
expect(
await transformTailwindContent(
`import type { Config } from 'tailwindcss'
const config: Config = {
content: [
"./pages/**/*.{js,ts,jsx,tsx,mdx}",
"./components/**/*.{js,ts,jsx,tsx,mdx}",
"./app/**/*.{js,ts,jsx,tsx,mdx}",
],
theme: {
extend: {
backgroundImage: {
"gradient-radial": "radial-gradient(var(--tw-gradient-stops))",
"gradient-conic":
"conic-gradient(from 180deg at 50% 50%, var(--tw-gradient-stops))",
},
},
},
plugins: [],
}
export default config
`,
["./app/**/*.{js,ts,jsx,tsx,mdx}", "./bar/**/*.{js,ts,jsx,tsx,mdx}"],
{
config: SHARED_CONFIG,
}
)
).toMatchSnapshot()
})
})