From aa4a97730a7b4bcdbb3a3b4e4f4b6416871bae75 Mon Sep 17 00:00:00 2001 From: shadcn Date: Wed, 4 Mar 2026 13:01:04 +0400 Subject: [PATCH] feat: use REGISTRY_URL --- packages/shadcn/src/commands/build.ts | 3 ++- packages/shadcn/src/commands/info.ts | 7 +++--- packages/shadcn/src/commands/init.ts | 6 ++--- .../shadcn/src/commands/registry/build.ts | 3 ++- packages/shadcn/src/migrations/migrate-rtl.ts | 3 ++- .../shadcn/src/preflights/preflight-add.ts | 3 ++- .../src/preflights/preflight-migrate.ts | 3 ++- packages/shadcn/src/preset/presets.ts | 6 ++--- packages/shadcn/src/registry/constants.ts | 22 ++++++++++++----- packages/shadcn/src/registry/errors.ts | 3 ++- packages/shadcn/src/templates/laravel.ts | 3 ++- packages/shadcn/src/utils/frameworks.ts | 24 ++++++++++--------- packages/shadcn/src/utils/get-project-info.ts | 3 ++- .../src/utils/updaters/update-dependencies.ts | 3 ++- skills/shadcn/SKILL.md | 8 ++++--- 15 files changed, 61 insertions(+), 39 deletions(-) diff --git a/packages/shadcn/src/commands/build.ts b/packages/shadcn/src/commands/build.ts index b6992ef33..2403ea966 100644 --- a/packages/shadcn/src/commands/build.ts +++ b/packages/shadcn/src/commands/build.ts @@ -1,6 +1,7 @@ import * as fs from "fs/promises" import * as path from "path" import { preFlightBuild } from "@/src/preflights/preflight-build" +import { SHADCN_URL } from "@/src/registry/constants" import { registryItemSchema, registrySchema } from "@/src/schema" import { handleError } from "@/src/utils/handle-error" import { highlighter } from "@/src/utils/highlighter" @@ -57,7 +58,7 @@ export const build = new Command() // Add the schema to the registry item. registryItem["$schema"] = - "https://ui.shadcn.com/schema/registry-item.json" + `${SHADCN_URL}/schema/registry-item.json` // Loop through each file in the files array. for (const file of registryItem.files ?? []) { diff --git a/packages/shadcn/src/commands/info.ts b/packages/shadcn/src/commands/info.ts index f9993d972..849e2561b 100644 --- a/packages/shadcn/src/commands/info.ts +++ b/packages/shadcn/src/commands/info.ts @@ -1,5 +1,6 @@ import { existsSync } from "fs" import path from "path" +import { SHADCN_URL } from "@/src/registry/constants" import { getBase, getConfig } from "@/src/utils/get-config" import { formatMonorepoMessage, @@ -143,11 +144,11 @@ function collectInfo( : null, components, links: { - docs: "https://ui.shadcn.com/docs", - components: `https://ui.shadcn.com/docs/components/${base}/[component].md`, + docs: `${SHADCN_URL}/docs`, + components: `${SHADCN_URL}/docs/components/${base}/[component].md`, ui: `${GITHUB_RAW_BASE}/${base}/ui/[component].tsx`, examples: `${GITHUB_RAW_BASE}/${base}/examples/[component]-example.tsx`, - schema: "https://ui.shadcn.com/schema.json", + schema: `${SHADCN_URL}/schema.json`, }, } } diff --git a/packages/shadcn/src/commands/init.ts b/packages/shadcn/src/commands/init.ts index 7bd414923..c3e260ddb 100644 --- a/packages/shadcn/src/commands/init.ts +++ b/packages/shadcn/src/commands/init.ts @@ -10,7 +10,7 @@ import { resolveRegistryBaseConfig, } from "@/src/preset/presets" import { getRegistryBaseColors, getRegistryStyles } from "@/src/registry/api" -import { BUILTIN_REGISTRIES } from "@/src/registry/constants" +import { BUILTIN_REGISTRIES, SHADCN_URL } from "@/src/registry/constants" import { clearRegistryContext } from "@/src/registry/context" import { registryConfigSchema } from "@/src/registry/schema" import { isUrl } from "@/src/registry/utils" @@ -317,7 +317,7 @@ export const init = new Command() ) logger.log( ` See ${highlighter.info( - "https://ui.shadcn.com/docs/installation/laravel" + `${SHADCN_URL}/docs/installation/laravel` )} for more information.` ) logger.break() @@ -813,7 +813,7 @@ async function promptForConfig(defaultConfig: Config | null = null) { } return rawConfigSchema.parse({ - $schema: "https://ui.shadcn.com/schema.json", + $schema: `${SHADCN_URL}/schema.json`, style: options.style, tailwind: { config: options.tailwindConfig, diff --git a/packages/shadcn/src/commands/registry/build.ts b/packages/shadcn/src/commands/registry/build.ts index f348e556a..94754dc62 100644 --- a/packages/shadcn/src/commands/registry/build.ts +++ b/packages/shadcn/src/commands/registry/build.ts @@ -1,6 +1,7 @@ import * as fs from "fs/promises" import * as path from "path" import { preFlightRegistryBuild } from "@/src/preflights/preflight-registry" +import { SHADCN_URL } from "@/src/registry/constants" import { recursivelyResolveFileImports } from "@/src/registry/utils" import { configSchema, registryItemSchema, registrySchema } from "@/src/schema" import * as ERRORS from "@/src/utils/errors" @@ -121,7 +122,7 @@ async function buildRegistry(opts: z.infer) { // Add the schema to the registry item. registryItem["$schema"] = - "https://ui.shadcn.com/schema/registry-item.json" + `${SHADCN_URL}/schema/registry-item.json` for (const file of registryItem.files) { const absPath = path.resolve(resolvePaths.cwd, file.path) diff --git a/packages/shadcn/src/migrations/migrate-rtl.ts b/packages/shadcn/src/migrations/migrate-rtl.ts index 8f1509bcc..ed55f9d1a 100644 --- a/packages/shadcn/src/migrations/migrate-rtl.ts +++ b/packages/shadcn/src/migrations/migrate-rtl.ts @@ -1,5 +1,6 @@ import { promises as fs } from "fs" import path from "path" +import { SHADCN_URL } from "@/src/registry/constants" import { Config } from "@/src/utils/get-config" import { highlighter } from "@/src/utils/highlighter" import { logger } from "@/src/utils/logger" @@ -15,7 +16,7 @@ const FILES_NEEDING_MANUAL_REVIEW = [ "calendar.tsx", ] -const RTL_DOCS_URL = "https://ui.shadcn.com/docs/rtl#manual-migration-optional" +const RTL_DOCS_URL = `${SHADCN_URL}/docs/rtl#manual-migration-optional` export async function migrateRtl( config: Config, diff --git a/packages/shadcn/src/preflights/preflight-add.ts b/packages/shadcn/src/preflights/preflight-add.ts index 0c43fe30e..450d1892b 100644 --- a/packages/shadcn/src/preflights/preflight-add.ts +++ b/packages/shadcn/src/preflights/preflight-add.ts @@ -1,5 +1,6 @@ import path from "path" import { addOptionsSchema } from "@/src/commands/add" +import { SHADCN_URL } from "@/src/registry/constants" import * as ERRORS from "@/src/utils/errors" import { getConfig } from "@/src/utils/get-config" import { @@ -66,7 +67,7 @@ export async function preFlightAdd(options: z.infer) { ) logger.error( `Learn more at ${highlighter.info( - "https://ui.shadcn.com/docs/components-json" + `${SHADCN_URL}/docs/components-json` )}.` ) logger.break() diff --git a/packages/shadcn/src/preflights/preflight-migrate.ts b/packages/shadcn/src/preflights/preflight-migrate.ts index 8c5f64715..ed9d9a343 100644 --- a/packages/shadcn/src/preflights/preflight-migrate.ts +++ b/packages/shadcn/src/preflights/preflight-migrate.ts @@ -1,6 +1,7 @@ import path from "path" import { addOptionsSchema } from "@/src/commands/add" import { migrateOptionsSchema } from "@/src/commands/migrate" +import { SHADCN_URL } from "@/src/registry/constants" import * as ERRORS from "@/src/utils/errors" import { getConfig } from "@/src/utils/get-config" import { highlighter } from "@/src/utils/highlighter" @@ -55,7 +56,7 @@ export async function preFlightMigrate( ) logger.error( `Learn more at ${highlighter.info( - "https://ui.shadcn.com/docs/components-json" + `${SHADCN_URL}/docs/components-json` )}.` ) logger.break() diff --git a/packages/shadcn/src/preset/presets.ts b/packages/shadcn/src/preset/presets.ts index 2ce8de9e8..f1a06c410 100644 --- a/packages/shadcn/src/preset/presets.ts +++ b/packages/shadcn/src/preset/presets.ts @@ -1,7 +1,7 @@ import { getRegistryItems } from "@/src/registry/api" import { buildUrlAndHeadersForRegistryItem } from "@/src/registry/builder" import { configWithDefaults } from "@/src/registry/config" -import { REGISTRY_URL } from "@/src/registry/constants" +import { REGISTRY_URL, SHADCN_URL } from "@/src/registry/constants" import { type registryConfigSchema } from "@/src/registry/schema" import { createConfig } from "@/src/utils/get-config" import { highlighter } from "@/src/utils/highlighter" @@ -11,8 +11,6 @@ import open from "open" import prompts from "prompts" import { type z } from "zod" -const SHADCN_URL = REGISTRY_URL.replace(/\/r\/?$/, "") - export const DEFAULT_PRESETS = { nova: { title: "Nova", @@ -174,7 +172,7 @@ export async function promptForPreset(options: { })), { title: "Custom", - description: "Build your own on https://ui.shadcn.com/create", + description: `Build your own at ${highlighter.info(`${SHADCN_URL}/create`)}`, value: "custom", }, ], diff --git a/packages/shadcn/src/registry/constants.ts b/packages/shadcn/src/registry/constants.ts index a11e90bd4..5075da7cb 100644 --- a/packages/shadcn/src/registry/constants.ts +++ b/packages/shadcn/src/registry/constants.ts @@ -4,6 +4,8 @@ import { z } from "zod" export const REGISTRY_URL = process.env.REGISTRY_URL ?? "https://ui.shadcn.com/r" +export const SHADCN_URL = REGISTRY_URL.replace(/\/r\/?$/, "") + export const FALLBACK_STYLE = "new-york-v4" export const BASE_COLORS = [ @@ -11,10 +13,6 @@ export const BASE_COLORS = [ name: "neutral", label: "Neutral", }, - { - name: "gray", - label: "Gray", - }, { name: "zinc", label: "Zinc", @@ -24,8 +22,20 @@ export const BASE_COLORS = [ label: "Stone", }, { - name: "slate", - label: "Slate", + name: "mauve", + label: "Mauve", + }, + { + name: "olive", + label: "Olive", + }, + { + name: "mist", + label: "Mist", + }, + { + name: "taupe", + label: "Taupe", }, ] as const diff --git a/packages/shadcn/src/registry/errors.ts b/packages/shadcn/src/registry/errors.ts index f92d73606..d866dfa29 100644 --- a/packages/shadcn/src/registry/errors.ts +++ b/packages/shadcn/src/registry/errors.ts @@ -1,3 +1,4 @@ +import { SHADCN_URL } from "@/src/registry/constants" import { z } from "zod" // Error codes for programmatic error handling @@ -245,7 +246,7 @@ export class RegistryParseError extends RegistryError { cause: parseError, context: { item }, suggestion: - "The registry item may be corrupted or have an invalid format. Please make sure it returns a valid JSON object. See https://ui.shadcn.com/schema/registry-item.json.", + `The registry item may be corrupted or have an invalid format. Please make sure it returns a valid JSON object. See ${SHADCN_URL}/schema/registry-item.json.`, }) this.parseError = parseError diff --git a/packages/shadcn/src/templates/laravel.ts b/packages/shadcn/src/templates/laravel.ts index 4d4a39b6f..6bc54d3c4 100644 --- a/packages/shadcn/src/templates/laravel.ts +++ b/packages/shadcn/src/templates/laravel.ts @@ -1,3 +1,4 @@ +import { SHADCN_URL } from "@/src/registry/constants" import { highlighter } from "@/src/utils/highlighter" import { logger } from "@/src/utils/logger" @@ -19,7 +20,7 @@ export const laravel = createTemplate({ ) logger.log( ` See ${highlighter.info( - "https://ui.shadcn.com/docs/installation/laravel" + `${SHADCN_URL}/docs/installation/laravel` )} for more information.` ) logger.break() diff --git a/packages/shadcn/src/utils/frameworks.ts b/packages/shadcn/src/utils/frameworks.ts index e9680e927..d81e09530 100644 --- a/packages/shadcn/src/utils/frameworks.ts +++ b/packages/shadcn/src/utils/frameworks.ts @@ -1,9 +1,11 @@ +import { SHADCN_URL } from "@/src/registry/constants" + export const FRAMEWORKS = { "next-app": { name: "next-app", label: "Next.js", links: { - installation: "https://ui.shadcn.com/docs/installation/next", + installation: `${SHADCN_URL}/docs/installation/next`, tailwind: "https://tailwindcss.com/docs/guides/nextjs", }, }, @@ -11,7 +13,7 @@ export const FRAMEWORKS = { name: "next-pages", label: "Next.js", links: { - installation: "https://ui.shadcn.com/docs/installation/next", + installation: `${SHADCN_URL}/docs/installation/next`, tailwind: "https://tailwindcss.com/docs/guides/nextjs", }, }, @@ -19,7 +21,7 @@ export const FRAMEWORKS = { name: "remix", label: "Remix", links: { - installation: "https://ui.shadcn.com/docs/installation/remix", + installation: `${SHADCN_URL}/docs/installation/remix`, tailwind: "https://tailwindcss.com/docs/guides/remix", }, }, @@ -27,7 +29,7 @@ export const FRAMEWORKS = { name: "react-router", label: "React Router", links: { - installation: "https://ui.shadcn.com/docs/installation/react-router", + installation: `${SHADCN_URL}/docs/installation/react-router`, tailwind: "https://tailwindcss.com/docs/installation/framework-guides/react-router", }, @@ -36,7 +38,7 @@ export const FRAMEWORKS = { name: "vite", label: "Vite", links: { - installation: "https://ui.shadcn.com/docs/installation/vite", + installation: `${SHADCN_URL}/docs/installation/vite`, tailwind: "https://tailwindcss.com/docs/guides/vite", }, }, @@ -44,7 +46,7 @@ export const FRAMEWORKS = { name: "astro", label: "Astro", links: { - installation: "https://ui.shadcn.com/docs/installation/astro", + installation: `${SHADCN_URL}/docs/installation/astro`, tailwind: "https://tailwindcss.com/docs/guides/astro", }, }, @@ -52,7 +54,7 @@ export const FRAMEWORKS = { name: "laravel", label: "Laravel", links: { - installation: "https://ui.shadcn.com/docs/installation/laravel", + installation: `${SHADCN_URL}/docs/installation/laravel`, tailwind: "https://tailwindcss.com/docs/guides/laravel", }, }, @@ -60,7 +62,7 @@ export const FRAMEWORKS = { name: "tanstack-start", label: "TanStack Start", links: { - installation: "https://ui.shadcn.com/docs/installation/tanstack", + installation: `${SHADCN_URL}/docs/installation/tanstack`, tailwind: "https://tailwindcss.com/docs/installation/using-postcss", }, }, @@ -68,7 +70,7 @@ export const FRAMEWORKS = { name: "gatsby", label: "Gatsby", links: { - installation: "https://ui.shadcn.com/docs/installation/gatsby", + installation: `${SHADCN_URL}/docs/installation/gatsby`, tailwind: "https://tailwindcss.com/docs/guides/gatsby", }, }, @@ -76,7 +78,7 @@ export const FRAMEWORKS = { name: "expo", label: "Expo", links: { - installation: "https://ui.shadcn.com/docs/installation/expo", + installation: `${SHADCN_URL}/docs/installation/expo`, tailwind: "https://www.nativewind.dev/docs/getting-started/installation", }, }, @@ -84,7 +86,7 @@ export const FRAMEWORKS = { name: "manual", label: "Manual", links: { - installation: "https://ui.shadcn.com/docs/installation/manual", + installation: `${SHADCN_URL}/docs/installation/manual`, tailwind: "https://tailwindcss.com/docs/installation", }, }, diff --git a/packages/shadcn/src/utils/get-project-info.ts b/packages/shadcn/src/utils/get-project-info.ts index a46f990d2..f4c4df30c 100644 --- a/packages/shadcn/src/utils/get-project-info.ts +++ b/packages/shadcn/src/utils/get-project-info.ts @@ -1,6 +1,7 @@ import { promises as fsPromises } from "fs" import path from "path" import { getShadcnRegistryIndex } from "@/src/registry/api" +import { SHADCN_URL } from "@/src/registry/constants" import { rawConfigSchema } from "@/src/schema" import { Framework, FRAMEWORKS } from "@/src/utils/frameworks" import { Config, getConfig, resolveConfigPaths } from "@/src/utils/get-config" @@ -384,7 +385,7 @@ export async function getProjectConfig( } const config: z.infer = { - $schema: "https://ui.shadcn.com/schema.json", + $schema: `${SHADCN_URL}/schema.json`, rsc: projectInfo.isRSC, tsx: projectInfo.isTsx, style: "new-york", diff --git a/packages/shadcn/src/utils/updaters/update-dependencies.ts b/packages/shadcn/src/utils/updaters/update-dependencies.ts index a73fd72fe..7b0eff915 100644 --- a/packages/shadcn/src/utils/updaters/update-dependencies.ts +++ b/packages/shadcn/src/utils/updaters/update-dependencies.ts @@ -1,3 +1,4 @@ +import { SHADCN_URL } from "@/src/registry/constants" import { RegistryItem } from "@/src/schema" import { Config } from "@/src/utils/get-config" import { getPackageInfo } from "@/src/utils/get-package-info" @@ -40,7 +41,7 @@ export async function updateDependencies( } else { dependenciesSpinner.stopAndPersist() logger.warn( - "\nIt looks like you are using React 19. \nSome packages may fail to install due to peer dependency issues in npm (see https://ui.shadcn.com/react-19).\n" + `\nIt looks like you are using React 19. \nSome packages may fail to install due to peer dependency issues in npm (see ${SHADCN_URL}/react-19).\n` ) const confirmation = await prompts([ { diff --git a/skills/shadcn/SKILL.md b/skills/shadcn/SKILL.md index 62a235101..c0d9846b3 100644 --- a/skills/shadcn/SKILL.md +++ b/skills/shadcn/SKILL.md @@ -92,14 +92,16 @@ npx shadcn@latest docs button dialog select ## Workflow 1. **Get project context** — already injected above. Run `npx shadcn@latest info` again if you need to refresh. -2. **Check installed components** — look in the `resolvedPaths.ui` directory before importing or adding. Don't import components that haven't been added, and don't re-add ones already installed. +2. **Check installed components first** — before running `add`, always check the `components` list from project context or list the `resolvedPaths.ui` directory. Don't import components that haven't been added, and don't re-add ones already installed. 3. **Find components** — `npx shadcn@latest search`. 4. **Get docs and examples** — run `npx shadcn@latest docs ` to get URLs, then fetch them. Use `npx shadcn@latest view` to browse registry items you haven't installed. To preview changes to installed components, use `npx shadcn@latest add --diff`. 5. **Install or update** — `npx shadcn@latest add`. When updating existing components, use `--dry-run` and `--diff` to preview changes first (see [Updating Components](#updating-components) below). 6. **Fix imports in third-party components** — After adding components from community registries (e.g. `@bundui`, `@magicui`), check the added non-UI files for hardcoded import paths like `@/components/ui/...`. These won't match the project's actual aliases. Use `npx shadcn@latest info` to get the correct `ui` alias (e.g. `@workspace/ui/components`) and rewrite the imports accordingly. The CLI rewrites imports for its own UI files, but third-party registry components may use default paths that don't match the project. -7. **Switching presets** — Ask the user first: **reinstall**, **merge**, or **skip**? +7. **Review added components** — After adding a component or block from any registry, **always read the added files and verify they are correct**. Check for missing sub-components (e.g. `SelectItem` without `SelectGroup`), missing imports, incorrect composition, or violations of the [Critical Rules](#critical-rules). Also replace any icon imports with the project's `iconLibrary` from the project context (e.g. if the registry item uses `lucide-react` but the project uses `hugeicons`, swap the imports and icon names accordingly). Fix all issues before moving on. +8. **Registry must be explicit** — When the user asks to add a block or component, **do not guess the registry**. If no registry is specified (e.g. user says "add a login block" without specifying `@shadcn`, `@tailark`, etc.), ask which registry to use. Never default to a registry on behalf of the user. +9. **Switching presets** — Ask the user first: **reinstall**, **merge**, or **skip**? - **Reinstall**: `npx shadcn@latest init --preset --force --reinstall`. Overwrites all components. - - **Merge**: `npx shadcn@latest init --preset --force --no-reinstall`, then `npx shadcn@latest info` to get installed components, then [smart merge](#updating-components) each one. + - **Merge**: `npx shadcn@latest init --preset --force --no-reinstall`, then run `npx shadcn@latest info` to list installed components, then for each installed component use `--dry-run` and `--diff` to [smart merge](#updating-components) it individually. - **Skip**: `npx shadcn@latest init --preset --force --no-reinstall`. Only updates config and CSS, leaves components as-is. ## Updating Components