diff --git a/apps/www/src/content/docs/components/data-table.md b/apps/www/src/content/docs/components/data-table.md
index b9201093..a001d652 100644
--- a/apps/www/src/content/docs/components/data-table.md
+++ b/apps/www/src/content/docs/components/data-table.md
@@ -4,7 +4,6 @@ description: Powerful table and datagrids built using TanStack Table.
primitive: https://tanstack.com/table/v8/docs/guide/introduction
---
-
## Introduction
@@ -56,7 +55,6 @@ npm install @tanstack/vue-table
-
## Prerequisites
We are going to build a table to show recent payments. Here's what our data looks like:
@@ -219,7 +217,6 @@ const table = useVueTable({
-
### Render the table
Finally, we'll render our table in our index component.
@@ -270,7 +267,6 @@ Let's format the amount cell to display the dollar amount. We'll also align the
Update the `header` and `cell` definitions for amount as follows:
-
```ts:line-numbers title="components/payments/columns.ts" {5-17}
import { h } from 'vue'
@@ -345,7 +341,6 @@ function copy(id: string) {
Update our columns definition to add a new `actions` column. The `actions` cell returns a `` component.
-
```ts:line-numbers showLineNumber{2,6-16}
import { ColumnDef } from "@tanstack/vue-table"
import DropdownAction from '@/components/DataTableDropDown.vue'
diff --git a/apps/www/src/public/schema.json b/apps/www/src/public/schema.json
index cb463b16..94567c95 100644
--- a/apps/www/src/public/schema.json
+++ b/apps/www/src/public/schema.json
@@ -42,6 +42,9 @@
},
"components": {
"type": "string"
+ },
+ "ui": {
+ "type": "string"
}
},
"required": ["utils", "components"]
diff --git a/eslint.config.js b/eslint.config.js
index fb24507c..ee2561fd 100644
--- a/eslint.config.js
+++ b/eslint.config.js
@@ -24,6 +24,7 @@ export default antfu(
'no-tabs': 0,
'import/first': 0,
'node/prefer-global/process': 0,
+ 'style/no-tabs': 0,
},
},
)
diff --git a/packages/cli/package.json b/packages/cli/package.json
index bb9ee887..0f88155a 100644
--- a/packages/cli/package.json
+++ b/packages/cli/package.json
@@ -32,7 +32,7 @@
"dev": "tsup --watch",
"build": "tsup",
"typecheck": "tsc --noEmit",
- "clean": "rimraf dist && rimraf components",
+ "clean": "node ./scripts/rimraf.js",
"lint": "eslint .",
"lint:fix": "eslint --fix .",
"start:dev": "COMPONENTS_REGISTRY_URL=http://localhost:3001 node dist/index.js",
@@ -45,41 +45,39 @@
"test:ui": "vitest --ui"
},
"dependencies": {
- "@antfu/ni": "^0.21.8",
- "@babel/core": "^7.22.17",
- "@babel/parser": "^7.22.16",
- "@babel/plugin-transform-typescript": "^7.22.15",
+ "@babel/core": "^7.24.0",
+ "@babel/parser": "^7.24.0",
"@vue/compiler-sfc": "^3.4",
- "chalk": "5.3.0",
- "commander": "^11.0.0",
- "cosmiconfig": "^8.3.6",
+ "c12": "^1.9.0",
+ "commander": "^12.0.0",
+ "consola": "^3.2.3",
"detype": "npm:detypes@^0.7.9",
- "diff": "^5.1.0",
- "execa": "^8.0.1",
- "fs-extra": "^11.1.1",
- "https-proxy-agent": "^7.0.2",
+ "diff": "^5.2.0",
+ "fs-extra": "^11.2.0",
+ "https-proxy-agent": "^7.0.4",
"lodash.template": "^4.5.0",
- "magic-string": "^0.30.3",
- "node-fetch": "^3.3.2",
- "ora": "^7.0.1",
+ "magic-string": "^0.30.8",
+ "nypm": "^0.3.8",
+ "ofetch": "^1.3.3",
+ "ora": "^8.0.1",
+ "pathe": "^1.1.2",
"prompts": "^2.4.2",
- "radix-vue": "^1.4.8",
- "recast": "^0.23.4",
- "rimraf": "^5.0.1",
- "ts-morph": "^19.0.0",
+ "radix-vue": "^1.4.9",
+ "ts-morph": "^21.0.1",
"tsconfig-paths": "^4.2.0",
- "vite-tsconfig-paths": "^4.2.1",
- "zod": "^3.22.2"
+ "zod": "^3.22.4"
},
"devDependencies": {
- "@types/babel__core": "^7.20.1",
- "@types/diff": "^5.0.3",
- "@types/fs-extra": "^11.0.1",
- "@types/lodash.template": "^4.5.1",
- "@types/prompts": "^2.4.4",
+ "@types/babel__core": "^7.20.5",
+ "@types/diff": "^5.0.9",
+ "@types/fs-extra": "^11.0.4",
+ "@types/lodash.template": "^4.5.3",
+ "@types/node": "^20.11.24",
+ "@types/prompts": "^2.4.9",
"@vitest/ui": "^0.34.4",
- "tsup": "^7.2.0",
- "type-fest": "^4.3.1",
- "typescript": "^5.2.2"
+ "tsup": "^8.0.2",
+ "type-fest": "^4.10.3",
+ "typescript": "^5.3.3",
+ "vite-tsconfig-paths": "^4.3.1"
}
}
diff --git a/packages/cli/scripts/rimraf.js b/packages/cli/scripts/rimraf.js
new file mode 100644
index 00000000..70a00e9a
--- /dev/null
+++ b/packages/cli/scripts/rimraf.js
@@ -0,0 +1,10 @@
+import fsp from 'node:fs/promises'
+
+function rmdir(dirs) {
+ dirs.forEach(async (dir) => {
+ await fsp.unlink(dir).catch(() => {})
+ await fsp.rm(dir, { recursive: true, force: true }).catch(() => {})
+ })
+}
+
+rmdir(['dist', 'components'])
diff --git a/packages/cli/src/commands/add.ts b/packages/cli/src/commands/add.ts
index 279ae085..6b331006 100644
--- a/packages/cli/src/commands/add.ts
+++ b/packages/cli/src/commands/add.ts
@@ -1,17 +1,16 @@
import { existsSync, promises as fs, rmSync } from 'node:fs'
-import path from 'node:path'
import process from 'node:process'
-import chalk from 'chalk'
+import path from 'pathe'
+import { consola } from 'consola'
+import { colors } from 'consola/utils'
import { Command } from 'commander'
-import { execa } from 'execa'
import ora from 'ora'
import prompts from 'prompts'
-import * as z from 'zod'
+import { z } from 'zod'
+import { addDependency, addDevDependency } from 'nypm'
import { transform } from '@/src/utils/transformers'
import { getConfig } from '@/src/utils/get-config'
-import { getPackageManager } from '@/src/utils/get-package-manager'
import { handleError } from '@/src/utils/handle-error'
-import { logger } from '@/src/utils/logger'
import {
fetchTree,
getItemTargetPath,
@@ -52,15 +51,15 @@ export const add = new Command()
const cwd = path.resolve(options.cwd)
if (!existsSync(cwd)) {
- logger.error(`The path ${cwd} does not exist. Please try again.`)
+ consola.error(`The path ${cwd} does not exist. Please try again.`)
process.exit(1)
}
const config = await getConfig(cwd)
+
if (!config) {
- logger.warn(
- `Configuration is missing. Please run ${chalk.green('init')} to create a components.json file.`,
- )
+ consola.warn(`Configuration is missing. Please run ${colors.green('init')} to create a components.json file.`)
+
process.exit(1)
}
@@ -88,7 +87,7 @@ export const add = new Command()
}
if (!selectedComponents?.length) {
- logger.warn('No components selected. Exiting.')
+ consola.warn('No components selected. Exiting.')
process.exit(0)
}
@@ -97,7 +96,7 @@ export const add = new Command()
const baseColor = await getRegistryBaseColor(config.tailwind.baseColor)
if (!payload.length) {
- logger.warn('Selected components not found. Exiting.')
+ consola.warn('Selected components not found. Exiting.')
process.exit(0)
}
@@ -114,7 +113,6 @@ export const add = new Command()
}
const spinner = ora('Installing components...').start()
- const skippedDeps = new Set()
for (const item of payload) {
spinner.text = `Installing ${item.name}...`
const targetDir = getItemTargetPath(
@@ -144,8 +142,8 @@ export const add = new Command()
})
if (!overwrite) {
- logger.info(
- `Skipped ${item.name}. To overwrite, run with the ${chalk.green(
+ consola.info(
+ `Skipped ${item.name}. To overwrite, run with the ${colors.green(
'--overwrite',
)} flag.`,
)
@@ -159,6 +157,20 @@ export const add = new Command()
}
}
+ // Install dependencies.
+ await Promise.allSettled(
+ [
+ item.dependencies?.length && await addDependency(item.dependencies, {
+ cwd,
+ silent: true,
+ }),
+ item.devDependencies?.length && await addDevDependency(item.devDependencies, {
+ cwd,
+ silent: true,
+ }),
+ ],
+ )
+
const componentDir = path.resolve(targetDir, item.name)
if (!existsSync(componentDir))
await fs.mkdir(componentDir, { recursive: true })
@@ -201,25 +213,6 @@ export const add = new Command()
await fs.writeFile(filePath, content)
}
-
- // Install dependencies.
- if (item.dependencies?.length) {
- item.dependencies.forEach(dep =>
- skippedDeps.add(dep),
- )
-
- const packageManager = await getPackageManager(cwd)
- await execa(
- packageManager,
- [
- packageManager === 'npm' ? 'install' : 'add',
- ...item.dependencies,
- ],
- {
- cwd,
- },
- )
- }
}
spinner.succeed('Done.')
}
diff --git a/packages/cli/src/commands/diff.ts b/packages/cli/src/commands/diff.ts
index a4fb5f4c..8bf17aa9 100644
--- a/packages/cli/src/commands/diff.ts
+++ b/packages/cli/src/commands/diff.ts
@@ -1,14 +1,14 @@
import { existsSync, promises as fs } from 'node:fs'
-import path from 'node:path'
import process from 'node:process'
-import chalk from 'chalk'
+import path from 'pathe'
+import { consola } from 'consola'
+import { colors } from 'consola/utils'
import { Command } from 'commander'
import { type Change, diffLines } from 'diff'
-import * as z from 'zod'
+import { z } from 'zod'
import type { Config } from '@/src/utils/get-config'
import { getConfig } from '@/src/utils/get-config'
import { handleError } from '@/src/utils/handle-error'
-import { logger } from '@/src/utils/logger'
import {
fetchTree,
getItemTargetPath,
@@ -45,14 +45,14 @@ export const diff = new Command()
const cwd = path.resolve(options.cwd)
if (!existsSync(cwd)) {
- logger.error(`The path ${cwd} does not exist. Please try again.`)
+ consola.error(`The path ${cwd} does not exist. Please try again.`)
process.exit(1)
}
const config = await getConfig(cwd)
if (!config) {
- logger.warn(
- `Configuration is missing. Please run ${chalk.green(
+ consola.warn(
+ `Configuration is missing. Please run ${colors.green(
'init',
)} to create a components.json file.`,
)
@@ -88,19 +88,20 @@ export const diff = new Command()
}
if (!componentsWithUpdates.length) {
- logger.info('No updates found.')
+ consola.info('No updates found.')
process.exit(0)
}
- logger.info('The following components have updates available:')
+ consola.info('The following components have updates available:')
for (const component of componentsWithUpdates) {
- logger.info(`- ${component.name}`)
+ consola.info(`- ${component.name}`)
for (const change of component.changes)
- logger.info(` - ${change.filePath}`)
+ consola.info(` - ${change.filePath}`)
}
- logger.break()
- logger.info(
- `Run ${chalk.green('diff ')} to see the changes.`,
+
+ consola.log('')
+ consola.info(
+ `Run ${colors.green('diff ')} to see the changes.`,
)
process.exit(0)
}
@@ -111,8 +112,8 @@ export const diff = new Command()
)
if (!component) {
- logger.error(
- `The component ${chalk.green(options.component)} does not exist.`,
+ consola.error(
+ `The component ${colors.green(options.component)} does not exist.`,
)
process.exit(1)
}
@@ -120,14 +121,14 @@ export const diff = new Command()
const changes = await diffComponent(component, config)
if (!changes.length) {
- logger.info(`No updates found for ${options.component}.`)
+ consola.info(`No updates found for ${options.component}.`)
process.exit(0)
}
for (const change of changes) {
- logger.info(`- ${change.filePath}`)
+ consola.info(`- ${change.filePath}`)
printDiff(change.patch)
- logger.info('')
+ consola.log('')
}
}
catch (error) {
@@ -184,10 +185,10 @@ function printDiff(diff: Change[]) {
diff.forEach((part) => {
if (part) {
if (part.added)
- return process.stdout.write(chalk.green(part.value))
+ return process.stdout.write(colors.green(part.value))
if (part.removed)
- return process.stdout.write(chalk.red(part.value))
+ return process.stdout.write(colors.red(part.value))
return process.stdout.write(part.value)
}
diff --git a/packages/cli/src/commands/init.ts b/packages/cli/src/commands/init.ts
index c20ddffb..0e96d1f7 100644
--- a/packages/cli/src/commands/init.ts
+++ b/packages/cli/src/commands/init.ts
@@ -1,22 +1,21 @@
import { existsSync, promises as fs } from 'node:fs'
-import path from 'node:path'
import process from 'node:process'
-import chalk from 'chalk'
+import path from 'pathe'
import { Command } from 'commander'
-import { execa } from 'execa'
import template from 'lodash.template'
import ora from 'ora'
import prompts from 'prompts'
-import * as z from 'zod'
+import { z } from 'zod'
+import { addDependency, addDevDependency } from 'nypm'
+import { consola } from 'consola'
+import { colors } from 'consola/utils'
import * as templates from '../utils/templates'
import {
getRegistryBaseColor,
getRegistryBaseColors,
getRegistryStyles,
} from '../utils/registry'
-import { logger } from '../utils/logger'
import { handleError } from '../utils/handle-error'
-import { getPackageManager } from '../utils/get-package-manager'
import { transformByDetype } from '../utils/transformers/transform-sfc'
import {
type Config,
@@ -29,6 +28,7 @@ import {
resolveConfigPaths,
} from '../utils/get-config'
import { transformCJSToESM } from '../utils/transformers/transform-cjs-to-esm'
+import { applyPrefixesCss } from '../utils/transformers/transform-tw-prefix'
const PROJECT_DEPENDENCIES = {
base: [
@@ -64,7 +64,7 @@ export const init = new Command()
// Ensure target directory exists.
if (!existsSync(cwd)) {
- logger.error(`The path ${cwd} does not exist. Please try again.`)
+ consola.error(`The path ${cwd} does not exist. Please try again.`)
process.exit(1)
}
@@ -74,11 +74,11 @@ export const init = new Command()
await runInit(cwd, config)
- logger.info('')
- logger.info(
- `${chalk.green('Success!')} Project initialization completed.`,
+ consola.log('')
+ consola.info(
+ `${colors.green('Success!')} Project initialization completed.`,
)
- logger.info('')
+ consola.log('')
}
catch (error) {
handleError(error)
@@ -90,7 +90,7 @@ export async function promptForConfig(
defaultConfig: Config | null = null,
skip = false,
) {
- const highlight = (text: string) => chalk.cyan(text)
+ const highlight = (text: string) => colors.cyan(text)
const styles = await getRegistryStyles()
const baseColors = await getRegistryBaseColors()
@@ -151,6 +151,14 @@ export async function promptForConfig(
active: 'yes',
inactive: 'no',
},
+ // {
+ // type: 'text',
+ // name: 'tailwindPrefix',
+ // message: `Are you using a custom ${highlight(
+ // 'tailwind prefix eg. tw-',
+ // )}? (Leave blank if not)`,
+ // initial: '',
+ // },
{
type: 'text',
name: 'tailwindConfig',
@@ -187,6 +195,7 @@ export async function promptForConfig(
css: options.tailwindCss,
baseColor: options.tailwindBaseColor,
cssVariables: options.tailwindCssVariables,
+ // prefix: options.tailwindPrefix,
},
aliases: {
utils: options.utils,
@@ -207,7 +216,7 @@ export async function promptForConfig(
}
// Write to file.
- logger.info('')
+ consola.log('')
const spinner = ora('Writing components.json...').start()
const targetPath = path.resolve(cwd, 'components.json')
await fs.writeFile(targetPath, JSON.stringify(config, null, 2), 'utf8')
@@ -247,8 +256,8 @@ export async function runInit(cwd: string, config: Config) {
transformCJSToESM(
config.resolvedPaths.tailwindConfig,
config.tailwind.cssVariables
- ? template(templates.TAILWIND_CONFIG_WITH_VARIABLES)({ extension, framework: config.framework })
- : template(templates.TAILWIND_CONFIG)({ extension, framework: config.framework }),
+ ? template(templates.TAILWIND_CONFIG_WITH_VARIABLES)({ extension, framework: config.framework, prefix: config.tailwind.prefix })
+ : template(templates.TAILWIND_CONFIG)({ extension, framework: config.framework, prefix: config.tailwind.prefix }),
),
'utf8',
)
@@ -259,7 +268,9 @@ export async function runInit(cwd: string, config: Config) {
await fs.writeFile(
config.resolvedPaths.tailwindCss,
config.tailwind.cssVariables
- ? baseColor.cssVarsTemplate
+ ? config.tailwind.prefix
+ ? applyPrefixesCss(baseColor.cssVarsTemplate, config.tailwind.prefix)
+ : baseColor.cssVarsTemplate
: baseColor.inlineColorsTemplate,
'utf8',
)
@@ -276,20 +287,29 @@ export async function runInit(cwd: string, config: Config) {
// Install dependencies.
const dependenciesSpinner = ora('Installing dependencies...')?.start()
- const packageManager = await getPackageManager(cwd)
const deps = PROJECT_DEPENDENCIES.base.concat(
- config.framework === 'nuxt' ? PROJECT_DEPENDENCIES.nuxt : [],
- ).concat(
config.style === 'new-york' ? ['@radix-icons/vue'] : ['lucide-vue-next'],
).filter(Boolean)
- await execa(
- packageManager,
- [packageManager === 'npm' ? 'install' : 'add', ...deps],
- {
- cwd,
- },
+ async function addNuxtDevDeps() {
+ if (config.framework === 'nuxt') {
+ await addDevDependency(PROJECT_DEPENDENCIES.nuxt, {
+ cwd,
+ silent: true,
+ })
+ }
+ }
+
+ await Promise.allSettled(
+ [
+ addNuxtDevDeps(),
+ addDependency(deps, {
+ cwd,
+ silent: true,
+ }),
+ ],
)
+
dependenciesSpinner?.succeed()
}
diff --git a/packages/cli/src/utils/get-config.ts b/packages/cli/src/utils/get-config.ts
index 68f7ebeb..2effd274 100644
--- a/packages/cli/src/utils/get-config.ts
+++ b/packages/cli/src/utils/get-config.ts
@@ -1,9 +1,9 @@
-import path from 'node:path'
import { existsSync } from 'node:fs'
-import { cosmiconfig } from 'cosmiconfig'
+import path from 'pathe'
+import { loadConfig as c12LoadConfig } from 'c12'
import type { ConfigLoaderResult } from 'tsconfig-paths'
import { loadConfig } from 'tsconfig-paths'
-import * as z from 'zod'
+import { z } from 'zod'
import { resolveImport } from '@/src/utils/resolve-import'
export const DEFAULT_STYLE = 'default'
@@ -19,12 +19,6 @@ export const TAILWIND_CSS_PATH = {
astro: 'src/styles/globals.css',
}
-// TODO: Figure out if we want to support all cosmiconfig formats.
-// A simple components.json file would be nice.
-const explorer = cosmiconfig('components', {
- searchPlaces: ['components.json'],
-})
-
export const rawConfigSchema = z
.object({
$schema: z.string().optional(),
@@ -35,11 +29,13 @@ export const rawConfigSchema = z
css: z.string(),
baseColor: z.string(),
cssVariables: z.boolean().default(true),
+ prefix: z.string().optional(),
}),
framework: z.string().default('Vite'),
aliases: z.object({
components: z.string(),
utils: z.string(),
+ ui: z.string().default('').optional(),
}),
})
.strict()
@@ -53,6 +49,7 @@ export const configSchema = rawConfigSchema
tailwindCss: z.string(),
utils: z.string(),
components: z.string(),
+ ui: z.string(),
}),
})
@@ -103,15 +100,22 @@ export async function resolveConfigPaths(cwd: string, config: RawConfig) {
tailwindCss: path.resolve(cwd, config.tailwind.css),
utils: resolveImport(config.aliases.utils, tsConfig),
components: resolveImport(config.aliases.components, tsConfig),
+ ui: config.aliases.ui
+ ? resolveImport(config.aliases.ui, tsConfig)
+ : resolveImport(config.aliases.components, tsConfig),
},
})
}
export async function getRawConfig(cwd: string): Promise {
try {
- const configResult = await explorer.search(cwd)
+ const configResult = await c12LoadConfig({
+ name: 'components',
+ configFile: 'components',
+ cwd,
+ })
- if (!configResult)
+ if (!configResult.config || Object.keys(configResult.config).length === 0)
return null
return rawConfigSchema.parse(configResult.config)
diff --git a/packages/cli/src/utils/get-package-info.ts b/packages/cli/src/utils/get-package-info.ts
index dde5c450..0add4075 100644
--- a/packages/cli/src/utils/get-package-info.ts
+++ b/packages/cli/src/utils/get-package-info.ts
@@ -1,5 +1,5 @@
-import path from 'node:path'
import { fileURLToPath } from 'node:url'
+import path from 'pathe'
import fs from 'fs-extra'
import { type PackageJson } from 'type-fest'
diff --git a/packages/cli/src/utils/get-package-manager.ts b/packages/cli/src/utils/get-package-manager.ts
deleted file mode 100644
index 1361bb5b..00000000
--- a/packages/cli/src/utils/get-package-manager.ts
+++ /dev/null
@@ -1,16 +0,0 @@
-import { detect } from '@antfu/ni'
-
-export async function getPackageManager(
- targetDir: string,
-): Promise<'yarn' | 'pnpm' | 'bun' | 'npm'> {
- const packageManager = await detect({ programmatic: true, cwd: targetDir })
-
- if (packageManager === 'yarn@berry')
- return 'yarn'
- if (packageManager === 'pnpm@6')
- return 'pnpm'
- if (packageManager === 'bun')
- return 'bun'
-
- return packageManager ?? 'npm'
-}
diff --git a/packages/cli/src/utils/get-project-info.ts b/packages/cli/src/utils/get-project-info.ts
index 3b08691e..a2219f6d 100644
--- a/packages/cli/src/utils/get-project-info.ts
+++ b/packages/cli/src/utils/get-project-info.ts
@@ -1,5 +1,5 @@
import { existsSync } from 'node:fs'
-import path from 'node:path'
+import path from 'pathe'
import fs from 'fs-extra'
export async function getProjectInfo() {
diff --git a/packages/cli/src/utils/handle-error.ts b/packages/cli/src/utils/handle-error.ts
index 8ca00d66..2280fd43 100644
--- a/packages/cli/src/utils/handle-error.ts
+++ b/packages/cli/src/utils/handle-error.ts
@@ -1,16 +1,16 @@
-import { logger } from './logger'
+import { consola } from 'consola'
export function handleError(error: unknown) {
if (typeof error === 'string') {
- logger.error(error)
+ consola.error(error)
process.exit(1)
}
if (error instanceof Error) {
- logger.error(error.message)
+ consola.error(error.message)
process.exit(1)
}
- logger.error('Something went wrong. Please try again.')
+ consola.error('Something went wrong. Please try again.')
process.exit(1)
}
diff --git a/packages/cli/src/utils/logger.ts b/packages/cli/src/utils/logger.ts
deleted file mode 100644
index 161973a3..00000000
--- a/packages/cli/src/utils/logger.ts
+++ /dev/null
@@ -1,19 +0,0 @@
-import chalk from 'chalk'
-
-export const logger = {
- error(...args: unknown[]) {
- console.log(chalk.red(...args))
- },
- warn(...args: unknown[]) {
- console.log(chalk.yellow(...args))
- },
- info(...args: unknown[]) {
- console.log(chalk.cyan(...args))
- },
- success(...args: unknown[]) {
- console.log(chalk.green(...args))
- },
- break() {
- console.log('')
- },
-}
diff --git a/packages/cli/src/utils/registry/index.ts b/packages/cli/src/utils/registry/index.ts
index 6d8a0962..bb1f9f8b 100644
--- a/packages/cli/src/utils/registry/index.ts
+++ b/packages/cli/src/utils/registry/index.ts
@@ -1,8 +1,9 @@
-import path from 'node:path'
import process from 'node:process'
+import path from 'pathe'
import { HttpsProxyAgent } from 'https-proxy-agent'
-import fetch from 'node-fetch'
+import { ofetch } from 'ofetch'
import type * as z from 'zod'
+import consola from 'consola'
import {
registryBaseColorSchema,
registryIndexSchema,
@@ -122,9 +123,12 @@ export function getItemTargetPath(
override?: string,
) {
// Allow overrides for all items but ui.
- if (override && item.type !== 'components:ui')
+ if (override)
return override
+ if (item.type === 'components:ui' && config.aliases.ui)
+ return config.resolvedPaths.ui
+
const [parent, type] = item.type.split(':')
if (!(parent in config.resolvedPaths))
return null
@@ -139,17 +143,18 @@ async function fetchRegistry(paths: string[]) {
try {
const results = await Promise.all(
paths.map(async (path) => {
- const response = await fetch(`${baseUrl}/registry/${path}`, {
+ const response = await ofetch(`${baseUrl}/registry/${path}`, {
+ // @ts-expect-error agent type
agent,
})
- return await response.json()
+
+ return response
}),
)
return results
}
catch (error) {
- // eslint-disable-next-line no-console
- console.log(error)
+ consola.error(error)
throw new Error(`Failed to fetch registry from ${baseUrl}.`)
}
}
diff --git a/packages/cli/src/utils/registry/schema.ts b/packages/cli/src/utils/registry/schema.ts
index 8b276326..14f0383c 100644
--- a/packages/cli/src/utils/registry/schema.ts
+++ b/packages/cli/src/utils/registry/schema.ts
@@ -1,9 +1,10 @@
-import * as z from 'zod'
+import { z } from 'zod'
// TODO: Extract this to a shared package.
export const registryItemSchema = z.object({
name: z.string(),
dependencies: z.array(z.string()).optional(),
+ devDependencies: z.array(z.string()).optional(),
registryDependencies: z.array(z.string()).optional(),
files: z.array(z.string()),
type: z.enum(['components:ui', 'components:component', 'components:example']),
diff --git a/packages/cli/src/utils/templates.ts b/packages/cli/src/utils/templates.ts
index 0f80fe78..47ca0648 100644
--- a/packages/cli/src/utils/templates.ts
+++ b/packages/cli/src/utils/templates.ts
@@ -17,6 +17,7 @@ module.exports = {
'./app/**/*.{<%- extension %>,<%- extension %>x,vue}',
'./src/**/*.{<%- extension %>,<%- extension %>x,vue}',
],
+ prefix: "<%- prefix %>",
theme: {
container: {
center: true,
@@ -51,6 +52,7 @@ export const TAILWIND_CONFIG_WITH_VARIABLES = `const animate = require("tailwind
module.exports = {
darkMode: ["class"],
safelist: ["dark"],
+ prefix: "<%- prefix %>",
<% if (framework === 'vite') { %>
content: [
'./pages/**/*.{<%- extension %>,<%- extension %>x,vue}',
diff --git a/packages/cli/src/utils/transformers/index.ts b/packages/cli/src/utils/transformers/index.ts
index ab2d0f04..72d03401 100644
--- a/packages/cli/src/utils/transformers/index.ts
+++ b/packages/cli/src/utils/transformers/index.ts
@@ -1,12 +1,13 @@
import { promises as fs } from 'node:fs'
import { tmpdir } from 'node:os'
-import path from 'node:path'
+import path from 'pathe'
import { Project, ScriptKind, type SourceFile } from 'ts-morph'
import type * as z from 'zod'
import type { Config } from '@/src/utils/get-config'
import type { registryBaseColorSchema } from '@/src/utils/registry/schema'
import { transformCssVars } from '@/src/utils/transformers/transform-css-vars'
import { transformImport } from '@/src/utils/transformers/transform-import'
+import { transformTwPrefixes } from '@/src/utils/transformers/transform-tw-prefix'
import { transformSFC } from '@/src/utils/transformers/transform-sfc'
export interface TransformOpts {
@@ -25,6 +26,7 @@ export type Transformer