Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion packages/cli/src/commands/registry/build.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ type BuildOptions = z.infer<typeof buildOptionsSchema>;

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 <path>", "the working directory", process.cwd())
.option("-o, --output <path>", "destination directory for json files", "./static/r")
Expand Down
166 changes: 128 additions & 38 deletions packages/registry/src/schemas.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,31 +17,71 @@ const registryItemComplexType = ["registry:block"] as const;
const registryItemInternalType = ["registry:example", "registry:internal"] as const;

export type RegistryItemType = z.infer<typeof registryItemTypeSchema>;
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<typeof registryItemFileTypeSchema>;
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<typeof registryItemFileSchema>;
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 <url>"),
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<typeof registryIndexItemSchema>;
Expand All @@ -62,28 +102,63 @@ export const registryBaseColorSchema = z.object({
});

export type CssVars = z.infer<typeof registryItemCssVarsSchema>;
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<CssSchema, CssSchema> = z.record(
z.string(),
z.lazy(() => z.union([z.string(), registryItemCssSchema]))
);
const registryItemCssSchema: z.ZodType<CssSchema, CssSchema> = 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<typeof registryItemSchema>;
/** 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),
});

Expand All @@ -92,10 +167,16 @@ export type Registry = z.infer<typeof registrySchema>;
/** 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(),
Expand All @@ -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."),
});
24 changes: 12 additions & 12 deletions sites/docs/src/content/cli.md
Original file line number Diff line number Diff line change
Expand Up @@ -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.

<PMExecute command="shadcn-svelte@next update [component]" />
<PMExecute command="shadcn-svelte@next registry build [registry.json]" />

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 <path> the working directory (default: the current directory)
-a, --all update all existing components (default: false)
-y, --yes skip confirmation prompt (default: false)
--proxy <proxy> fetch components from registry using a proxy
-h, --help display help for command
-c, --cwd <path> the working directory (default: the current directory)
-o, --output <path> 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="<proxy-url>" npx shadcn-svelte@next init
Expand Down
6 changes: 3 additions & 3 deletions sites/docs/src/content/registry/registry-item-json.md
Original file line number Diff line number Diff line change
Expand Up @@ -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": [
{
Expand Down Expand Up @@ -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

Expand Down Expand Up @@ -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

Expand Down
Loading