diff --git a/packages/cli/src/commands/registry/build.ts b/packages/cli/src/commands/registry/build.ts index 9d833e5d8e..0de9e2ae7d 100644 --- a/packages/cli/src/commands/registry/build.ts +++ b/packages/cli/src/commands/registry/build.ts @@ -25,7 +25,7 @@ type BuildOptions = z.infer; export const build = new Command() .command("build") - .description("build components for a shadcn registry") + .description("build components for a shadcn-svelte registry") .argument("[registry]", "path to registry.json file", "./registry.json") .option("-c, --cwd ", "the working directory", process.cwd()) .option("-o, --output ", "destination directory for json files", "./static/r") diff --git a/packages/registry/src/schemas.ts b/packages/registry/src/schemas.ts index 65a126288d..2fa9f30222 100644 --- a/packages/registry/src/schemas.ts +++ b/packages/registry/src/schemas.ts @@ -17,31 +17,71 @@ const registryItemComplexType = ["registry:block"] as const; const registryItemInternalType = ["registry:example", "registry:internal"] as const; export type RegistryItemType = z.infer; -const registryItemTypeSchema = z.enum([ - ...registryItemFileType, - ...registryItemComplexType, - ...registryItemInternalType, -]); +const registryItemTypeSchema = z + .enum([...registryItemFileType, ...registryItemComplexType, ...registryItemInternalType]) + .describe( + "The type of the item. Used to determine the type and target path of the item when resolved for a project." + ); export type RegistryItemFileType = z.infer; -const registryItemFileTypeSchema = z.enum(registryItemFileType); +const registryItemFileTypeSchema = z + .enum(registryItemFileType) + .describe("The type of the file. Used to resolve the file's path for a project."); export type RegistryItemFile = z.infer; -const registryItemFileSchema = z.object({ - content: z.string(), - type: registryItemFileTypeSchema, - target: z.string(), -}); +const registryItemFileSchema = z + .object({ + content: z.string().describe("The content of the file."), + type: registryItemFileTypeSchema, + target: z + .string() + .describe("The target path of the file. This is where the file will be installed."), + }) + .describe( + "The main payload of the registry item. This is an array of files that are part of the registry item. Each file is an object with a target, type, and content." + ); + +const registryDependenciesSchema = z + .string() + .array() + .describe( + "An array of registry items that this item depends on. Use the name of the item to reference shadcn/ui components and urls to reference other registries." + ); const baseIndexItemSchema = z.object({ - name: z.string(), - title: z.string().optional(), + name: z + .string() + .describe( + "The name of the item. Used to identify the item in the registry. It should be unique for your registry." + ), + title: z + .string() + .optional() + .describe( + "The human-readable title for your registry item. Keep it short and descriptive." + ), + type: registryItemTypeSchema, - author: z.string().min(2, "Author name must be at least 2 characters").optional(), - description: z.string().optional(), - dependencies: z.string().array().optional(), - devDependencies: z.string().array().optional(), - registryDependencies: z.string().array().optional(), + author: z + .string() + .min(2, "Author name must be at least 2 characters") + .optional() + .describe("The author of the item. Recommended format: username "), + description: z + .string() + .optional() + .describe("The description of the item. Used to provide a brief overview of the item."), + dependencies: z + .string() + .array() + .optional() + .describe("An array of NPM dependencies required by the registry item."), + devDependencies: z + .string() + .array() + .optional() + .describe("An array of NPM dev dependencies required by the registry item."), + registryDependencies: z.optional(registryDependenciesSchema), }); export type RegistryIndexItem = z.infer; @@ -62,28 +102,63 @@ export const registryBaseColorSchema = z.object({ }); export type CssVars = z.infer; -const registryItemCssVarsSchema = z.object({ - theme: z.optional(colorSchema), - light: z.optional(colorSchema), - dark: z.optional(colorSchema), -}); +const registryItemCssVarsSchema = z + .object({ + theme: z + .optional(colorSchema) + .describe( + "CSS variables for the @theme directive. For Tailwind v4 projects only. Use tailwind for older projects." + ), + light: z.optional(colorSchema).describe("CSS variables for the light theme."), + dark: z.optional(colorSchema).describe("CSS variables for the dark theme."), + }) + .describe( + "The css variables for the registry item. This will be merged with the project's css variables." + ); type CssSchema = { [x: string]: string | CssSchema }; -const registryItemCssSchema: z.ZodType = z.record( - z.string(), - z.lazy(() => z.union([z.string(), registryItemCssSchema])) -); +const registryItemCssSchema: z.ZodType = z + .record( + z + .string() + .describe("Direct CSS string (e.g., 'font-family: sans-serif; line-height: 1.5;')"), + z + .lazy(() => + z.union([ + z + .string() + .describe("CSS property value (e.g., 'blue', 'var(--color-primary)')"), + registryItemCssSchema.describe("CSS property value for nested rule"), + ]) + ) + .describe("CSS properties or nested selectors") + ) + .describe( + "CSS definitions to be added to the project's CSS file. Supports at-rules, selectors, nested rules, utilities, layers, and more." + ); export type RegistryItem = z.infer; /** Schema for registry item endpoints (e.g. `https://example.com/registry/item.json`) */ export const registryItemSchema = z.object({ $schema: z.string().optional(), ...baseIndexItemSchema.shape, - docs: z.string().optional(), - categories: z.string().array().optional(), + docs: z + .string() + .optional() + .describe("The documentation for the registry item. This is a markdown string."), + categories: z + .string() + .array() + .optional() + .describe("The categories of the registry item. This is an array of strings."), css: z.optional(registryItemCssSchema), cssVars: z.optional(registryItemCssVarsSchema), - meta: z.record(z.string(), z.any()).optional(), + meta: z + .record(z.string(), z.any()) + .optional() + .describe( + "Additional metadata for the registry item. This is an object with any key value pairs." + ), files: z.array(registryItemFileSchema), }); @@ -92,10 +167,16 @@ export type Registry = z.infer; /** Schema for `registry.json` */ export const registrySchema = z.object({ $schema: z.string().optional(), - name: z.string(), - homepage: z.string(), + name: z.string().describe("The name of the registry."), + homepage: z.string().describe("The homepage of the registry."), // installs specified versions of dependencies during auto-detection - overrideDependencies: z.string().array().optional(), + overrideDependencies: z + .string() + .array() + .optional() + .describe( + "An array of NPM dependencies that should have their versions overridden during registry `build`." + ), aliases: z .object({ lib: z.string().optional(), @@ -104,19 +185,28 @@ export const registrySchema = z.object({ utils: z.string().optional(), hooks: z.string().optional(), }) - .optional(), + .optional() + .describe( + "Defines which internal import paths should be transformed during registry `build`." + ), items: baseIndexItemSchema .extend({ files: registryItemFileSchema .partial() .extend({ - path: z.string(), + path: z + .string() + .describe("The path to the file relative to the registry root."), type: registryItemFileTypeSchema, }) - .array(), - registryDependencies: z.string().array(), + .array() + .describe( + "An array of files that instructs the `build` command on how to locate and parse the registry files." + ), + registryDependencies: registryDependenciesSchema, cssVars: z.optional(registryItemCssVarsSchema), css: z.optional(registryItemCssSchema), }) - .array(), + .array() + .describe("Defines a custom component registry."), }); diff --git a/sites/docs/src/content/cli.md b/sites/docs/src/content/cli.md index a3372fd0d4..7f8f0e12f2 100644 --- a/sites/docs/src/content/cli.md +++ b/sites/docs/src/content/cli.md @@ -93,35 +93,35 @@ Options: -h, --help display help for command ``` -## update +## build -Use the `update` command to update components in your project. This will overwrite any modifications you've made to the components, so be sure to commit your changes before running this command. +Use the `build` command to generate the registry JSON files. - + + +This command reads the `registry.json` file and generates the registry JSON files into the `static/r` directory. ### Options ```txt -Usage: shadcn-svelte update [options] [components...] +Usage: shadcn-svelte registry build [options] [registry] -update components in your project +build components for a shadcn-svelte registry Arguments: - components name of components + registry path to registry.json file (default: ./registry.json) Options: - -c, --cwd the working directory (default: the current directory) - -a, --all update all existing components (default: false) - -y, --yes skip confirmation prompt (default: false) - --proxy fetch components from registry using a proxy - -h, --help display help for command + -c, --cwd the working directory (default: the current directory) + -o, --output destination directory for json files (default: ./static/r) + -h, --help display help for command ``` ## Outgoing Requests ### Proxy -This enables the use of a proxy when sending out requests to fetch from the `shadcn` registry. If the `HTTP_PROXY` or `http_proxy` environment variables have been set, the request library underneath will respect the proxy settings. +This enables the use of a proxy when sending out requests to fetch from the `shadcn-svelte` registry. If the `HTTP_PROXY` or `http_proxy` environment variables have been set, the request library underneath will respect the proxy settings. ```bash HTTP_PROXY="" npx shadcn-svelte@next init diff --git a/sites/docs/src/content/registry/registry-item-json.md b/sites/docs/src/content/registry/registry-item-json.md index 2a1d6535d0..7583f78f94 100644 --- a/sites/docs/src/content/registry/registry-item-json.md +++ b/sites/docs/src/content/registry/registry-item-json.md @@ -9,8 +9,8 @@ The `registry-item.json` schema is used to define your custom registry items. { "$schema": "https://next.shadcn-svelte.com/schema/registry-item.json", "name": "hello-world", - "type": "registry:block", "title": "Hello World", + "type": "registry:block", "description": "A simple hello world component.", "files": [ { @@ -44,7 +44,7 @@ The `registry-item.json` schema is used to define your custom registry items. ## Definitions -You can see the JSON Schema for `registry-item.json` [here](https://next.shadcn-svelte.com/schema/registry-item.json). +You can see the JSON Schema for `registry-item.json` [here](/schema/registry-item.json). ### $schema @@ -199,7 +199,7 @@ The `target` property is used to indicate where the file should be placed in a p By default, the `shadcn-svelte` cli will read a project's `components.json` file to determine the target path. For some files, such as routes or config you can specify the target path manually. -TODO: (is this correct?) - Use `~` to refer to the root of the project e.g `~/foo.config.js`. +Use `~` to refer to the root of the project e.g `~/foo.config.js`. ### cssVars diff --git a/sites/docs/src/content/registry/registry-json.md b/sites/docs/src/content/registry/registry-json.md index 87110f8b5d..07ff048dab 100644 --- a/sites/docs/src/content/registry/registry-json.md +++ b/sites/docs/src/content/registry/registry-json.md @@ -3,12 +3,16 @@ title: registry.json description: Schema for running your own component registry. --- + + The `registry.json` schema is used to define your custom component registry. ```json title="registry.json" showLineNumbers { "$schema": "https://next.shadcn-svelte.com/schema/registry.json", - "name": "shadcn", + "name": "shadcn-svelte", "homepage": "https://next.shadcn-svelte.com", "items": [ { @@ -29,7 +33,7 @@ The `registry.json` schema is used to define your custom component registry. ## Definitions -You can see the JSON Schema for `registry.json` [here](https://next.shadcn-svelte.com/schema/registry.json). +You can see the JSON Schema for `registry.json` [here](/schema/registry.json). ### $schema @@ -63,7 +67,7 @@ The homepage of your registry. This is used for data attributes and other metada ### items -The `items` in your registry. Each item must implement the [registry-item schema specification](https://next.shadcn-svelte.com/schema/registry-item.json). +The `items` in your registry. Each item must implement the [registry-item schema specification](/schema/registry-item.json). ```json title="registry.json" showLineNumbers { @@ -85,3 +89,83 @@ The `items` in your registry. Each item must implement the [registry-item schema ``` See the [registry-item schema documentation](/docs/registry/registry-item-json) for more information. + +### aliases + +`aliases` define how your registry's internal import paths will be transformed when users install your components. These should match how you import components within your registry code. + +For example, if your registry's component has: + +```svelte + +``` + +Then your `registry.json` should have matching aliases: + +```json title="registry.json" showLineNumbers +{ + "aliases": { + "lib": "@/lib", // Matches your internal imports + "ui": "@/lib/registry/ui", // Matches your internal imports + "components": "@/lib/registry/components", // Matches your internal imports + "utils": "@/lib/utils", // Matches your internal imports + "hooks": "@/lib/hooks" // Matches your internal imports + } +} +``` + +When users install your component, these paths will be transformed according to their `components.json` configuration. The aliases you define here are the "source" paths that will be replaced. + +Default aliases (if you don't specify any): + +```json title="registry.json" showLineNumbers +{ + "aliases": { + "lib": "$lib/registry/lib", // For internal library code + "ui": "$lib/registry/ui", // For UI components + "components": "$lib/registry/components", // For component-specific code + "utils": "$lib/utils", // For utility functions + "hooks": "$lib/registry/hooks" // For reactive state and logic (.svelte.js|ts) + } +} +``` + +### overrideDependencies + +`overrideDependencies` lets you force specific version ranges for dependencies, overriding what `shadcn-svelte registry build` detects in your `package.json`. + +Common use cases: + +- Using latest pre-release versions: `"overrideDependencies": ["paneforge@next"]` +- Pinning to specific versions: `"overrideDependencies": ["dep@1.5.0"]` + + + +**Warning**: Overriding dependencies can lead to version conflicts if not carefully managed. This option should be used sparingly. + + + +Example transformation: + +```json +// Your registry's package.json +{ + "dependencies": { + "paneforge": "1.0.0-next.1" + } +} +``` + +When the user installs your component, the latest `@next` version will be used instead of `1.0.0-next.1` + +```json +{ + "dependencies": { + "paneforge": "1.0.0-next.1", // overrideDependencies: [] + "paneforge": "1.0.0-next.5" // overrideDependencies: ["paneforge@next"] + } +} +```